//----------------------------------------------------------------------------- // VST Plug-Ins SDK // VSTGUI: Graphical User Interface Framework for VST plugins : // // Version 3.0 $Date: 2006/02/08 17:31:19 $ // // Added Motif/Windows vers.: Yvan Grabit 01.98 // Added Mac version : Charlie Steinberg 02.98 // Added BeOS version : Georges-Edouard Berenger 05.99 // Added new functions : Matthias Juwan 12.01 // Added MacOSX version : Arne Scheffler 02.03 // Added Quartz stuff : Arne Scheffler 08.03 // Added Win Alpha Blending : Arne Scheffler 04.04 // //----------------------------------------------------------------------------- // VSTGUI LICENSE // © 2004, Steinberg Media Technologies, All Rights Reserved //----------------------------------------------------------------------------- // Redistribution and use in source and binary forms, with or without modification, // are permitted provided that the following conditions are met: // // * Redistributions of source code must retain the above copyright notice, // this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above copyright notice, // this list of conditions and the following disclaimer in the documentation // and/or other materials provided with the distribution. // * Neither the name of the Steinberg Media Technologies nor the names of its // contributors may be used to endorse or promote products derived from this // software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. // IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, // INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, // BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE // OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED // OF THE POSSIBILITY OF SUCH DAMAGE. //----------------------------------------------------------------------------- #ifndef __vstgui__ #include "vstgui.h" #endif #if !PLUGGUI #ifndef __audioeffectx__ #include "audioeffectx.h" #endif #endif #include "vstkeycode.h" #include #include #include #include //---Some defines------------------------------------- #define USE_ALPHA_BLEND QUARTZ || USE_LIBPNG #define USE_CLIPPING_DRAWRECT 1 #define MAC_OLD_DRAG 1 #define NEW_UPDATE_MECHANISM 1 #define USE_VST_WINDOW (!PLUGGUI && !VST_FORCE_DEPRECATED) #if !WINDOWS // For OS which allows a lot of Drawing contexts #define USE_GLOBAL_CONTEXT 1 #endif //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- #if USE_NAMESPACE #define VSTGUI_CFrame VSTGUI::CFrame #define VSTGUI_CPoint VSTGUI::CPoint #define VSTGUI_CTextEdit VSTGUI::CTextEdit #define VSTGUI_CColor VSTGUI::CColor #define VSTGUI_CDrawContext VSTGUI::CDrawContext #define VSTGUI_COffscreenContext VSTGUI::COffscreenContext #define VSTGUI_COptionMenu VSTGUI::COptionMenu #define VSTGUI_COptionMenuScheme VSTGUI::COptionMenuScheme #define VSTGUI_CDragContainer VSTGUI::CDragContainer #else #define VSTGUI_CFrame CFrame #define VSTGUI_CPoint CPoint #define VSTGUI_CTextEdit CTextEdit #define VSTGUI_CColor CColor #define VSTGUI_CDrawContext CDrawContext #define VSTGUI_COffscreenContext COffscreenContext #define VSTGUI_COptionMenu COptionMenu #define VSTGUI_COptionMenuScheme COptionMenuScheme #define VSTGUI_CDragContainer CDragContainer #endif static VSTGUI_CDragContainer* gDragContainer = 0; //---For Debugging------------------------ #if DEBUG long gNbCBitmap = 0; long gNbCView = 0; long gNbCDrawContext = 0; long gNbCOffscreenContext = 0; long gBitmapAllocation = 0; long gNbDC = 0; #include void DebugPrint (char *format, ...); void DebugPrint (char *format, ...) { char string[300]; va_list marker; va_start (marker, format); vsprintf (string, format, marker); if (!string) strcpy (string, "Empty string\n"); #if WINDOWS OutputDebugString (string); #elif MAC && !MACX Str255 pStr; c2pstrcpy (pStr, string); DebugStr (pStr); #else fprintf (stderr, string); #endif } #endif //---End For Debugging------------------------ #if WINDOWS static bool bSwapped_mouse_buttons = false; OSVERSIONINFOEX gSystemVersion; // Alpha blending for Windows using library : msimg32.dll #define DYNAMICALPHABLEND 1 #define WIN32_LEAN_AND_MEAN 1 #include #include #include #include #include #if DYNAMICALPHABLEND typedef BOOL (WINAPI *PFNALPHABLEND)( HDC hdcDest, // handle to destination DC int nXOriginDest, // x-coord of upper-left corner int nYOriginDest, // y-coord of upper-left corner int nWidthDest, // destination width int nHeightDest, // destination height HDC hdcSrc, // handle to source DC int nXOriginSrc, // x-coord of upper-left corner int nYOriginSrc, // y-coord of upper-left corner int nWidthSrc, // source width int nHeightSrc, // source height BLENDFUNCTION blendFunction // alpha-blending function ); PFNALPHABLEND pfnAlphaBlend = NULL; typedef BOOL (WINAPI *PFNTRANSPARENTBLT)( HDC hdcDest, // handle to destination DC int nXOriginDest, // x-coord of destination upper-left corner int nYOriginDest, // y-coord of destination upper-left corner int nWidthDest, // width of destination rectangle int hHeightDest, // height of destination rectangle HDC hdcSrc, // handle to source DC int nXOriginSrc, // x-coord of source upper-left corner int nYOriginSrc, // y-coord of source upper-left corner int nWidthSrc, // width of source rectangle int nHeightSrc, // height of source rectangle UINT crTransparent // color to make transparent ); PFNTRANSPARENTBLT pfnTransparentBlt = NULL; #endif #if PLUGGUI extern HINSTANCE ghInst; inline HINSTANCE GetInstance () { return ghInst; } #else extern void* hInstance; inline HINSTANCE GetInstance () { return (HINSTANCE)hInstance; } #endif static long gUseCount = 0; static char gClassName[100] = {0}; static bool InitWindowClass (); static void ExitWindowClass (); LONG_PTR WINAPI WindowProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam); static HANDLE CreateMaskBitmap (CDrawContext* pContext, CRect& rect, CColor transparentColor); static void DrawTransparent (CDrawContext* pContext, CRect& rect, const CPoint& offset, HDC hdcBitmap, POINT ptSize, HBITMAP pMask, COLORREF color); static bool checkResolveLink (const char* nativePath, char* resolved); static void *createDropTarget (VSTGUI_CFrame* pFrame); BEGIN_NAMESPACE_VSTGUI long gStandardFontSize[] = { 12, 18, 14, 12, 11, 10, 9, 13 }; const char* gStandardFontName[] = { "Arial", "Arial", "Arial", "Arial", "Arial", "Arial", "Arial", "Symbol" }; END_NAMESPACE_VSTGUI #if USE_LIBPNG #include "png.h" #endif //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- #elif MOTIF #define USE_XPM 0 #define TEST_REGION 0 #if USE_XPM #include #endif #include #include #include #include #include #include #if SGI #include #elif SUN #elif LINUX #endif #define XDRAWPARAM pDisplay, (Window)pWindow, (GC)pSystemContext #define XWINPARAM pDisplay, (Window)pWindow #define XGCPARAM pDisplay, (GC)pSystemContext // init the static variable about font bool gFontInit = false; XFontStruct *gFontStructs[] = {0, 0, 0, 0, 0, 0, 0}; struct SFontTable {char* name; char* string;}; static SFontTable gFontTable[] = { {"SystemFont", "-adobe-helvetica-bold-r-*-*-12-*-*-*-*-*-*-*"}, // kSystemFont {"NormalFontVeryBig", "-adobe-helvetica-medium-r-*-*-18-*-*-*-*-*-*-*"}, // kNormalFontVeryBig {"NormalFontBig", "-adobe-helvetica-medium-r-normal-*-14-*-*-*-*-*-*-*"}, // kNormalFontBig {"NormalFont", "-adobe-helvetica-medium-r-*-*-12-*-*-*-*-*-*-*"}, // kNormalFont {"NormalFontSmall", "-adobe-helvetica-medium-r-*-*-10-*-*-*-*-*-*-*"}, // kNormalFontSmall {"NormalFontSmaller", "-adobe-helvetica-medium-r-*-*-9-*-*-*-*-*-*-*"}, // kNormalFontSmaller {"NormalFontVerySmall", "-adobe-helvetica-medium-r-*-*-8-*-*-*-*-*-*-*"}, // kNormalFontVerySmall {"SymbolFont", "-adobe-symbol-medium-r-*-*-12-*-*-*-*-*-*-*"} // kSymbolFont }; long gStandardFontSize[] = { 12, 16, 14, 12, 10, 9, 8, 10 }; //----------------------------------------------------------------------------- // declaration of different local functions long convertPoint2Angle (CPoint &pm, CPoint &pt); // callback for the frame void _drawingAreaCallback (Widget widget, XtPointer clientData, XtPointer callData); void _eventHandler (Widget w, XtPointer clientData, XEvent *event, char *p); void _destroyCallback (Widget widget, XtPointer clientData, XtPointer callData); // stuff for color long getIndexColor8Bit (CColor color, Display *pDisplay, Colormap colormap); long CDrawContext::nbNewColor = 0; static CColor paletteNewColor[256]; //------ our user-defined XPM functions bool xpmGetValues (char **ppDataXpm, long *pWidth, long *pHeight, long *pNcolor, long *pCpp); #if !USE_XPM #include "xpmloader.cpp" #endif //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- #elif MAC BEGIN_NAMESPACE_VSTGUI long pSystemVersion; #if MACX //----------------------------------------------------------------------------- #include #if QUARTZ const char* gMacXfontNames[] = { "Helvetica", "Helvetica", "Helvetica", "Helvetica", "Helvetica", "Helvetica", "Helvetica", "Symbol" }; #ifndef M_PI #define M_PI 3.14159265358979323846 /* pi */ #endif static inline void QuartzSetLineDash (CGContextRef context, CLineStyle style, CCoord lineWidth); static inline void QuartzSetupClip (CGContextRef context, const CRect clipRect); static inline double radians (double degrees) { return degrees * M_PI / 180; } CGColorSpaceRef GetGenericRGBColorSpace (); typedef void (*CGContextStrokeLineSegmentsProc) (CGContextRef c, const CGPoint points[], size_t count); typedef CGImageRef (*CGImageCreateWithImageInRectProc) (CGImageRef image, CGRect rect); static CGImageCreateWithImageInRectProc _CGImageCreateWithImageInRect = NULL; static CGContextStrokeLineSegmentsProc _CGContextStrokeLineSegments = NULL; // cache graphics importer static ComponentInstance bmpGI = 0; static ComponentInstance pngGI = 0; static ComponentInstance jpgGI = 0; static ComponentInstance pictGI = 0; #else const unsigned char* gMacXfontNames[] = { "\pArial", "\pArial", "\pArial", "\pArial", "\pArial", "\pArial", "\pArial", "\pSymbol" }; #endif //----------------------------------------------------------------------------- #else #include #include #include #include #endif long gStandardFontSize[] = { 12, 18, 14, 12, 10, 9, 9, 12 }; long convertPoint2Angle (CPoint &pm, CPoint &pt); void RectNormalize (Rect& rect); void CRect2Rect (const CRect &cr, Rect &rr); void Rect2CRect (Rect &rr, CRect &cr); void CColor2RGBColor (const CColor &cc, RGBColor &rgb); void RGBColor2CColor (const RGBColor &rgb, CColor &cc); #if MAC_OLD_DRAG static void install_drop (CFrame *frame); static void remove_drop (CFrame *frame); #endif //----------------------------------------------------------------------------- void RectNormalize (Rect& rect) { if (rect.left > rect.right) { long temp = rect.right; rect.right = rect.left; rect.left = temp; } if (rect.top > rect.bottom) { long temp = rect.bottom; rect.bottom = rect.top; rect.top = temp; } } //----------------------------------------------------------------------------- void CRect2Rect (const CRect &cr, Rect &rr) { rr.left = (short)cr.left; rr.right = (short)cr.right; rr.top = (short)cr.top; rr.bottom = (short)cr.bottom; RectNormalize (rr); } //----------------------------------------------------------------------------- void Rect2CRect (Rect &rr, CRect &cr) { cr.left = rr.left; cr.right = rr.right; cr.top = rr.top; cr.bottom = rr.bottom; } //----------------------------------------------------------------------------- void CColor2RGBColor (const CColor &cc, RGBColor &rgb) { rgb.red = cc.red * 257; rgb.green = cc.green * 257; rgb.blue = cc.blue * 257; } //----------------------------------------------------------------------------- void RGBColor2CColor (const RGBColor &rgb, CColor &cc) { cc.red = rgb.red / 257; cc.green = rgb.green / 257; cc.blue = rgb.blue / 257; } END_NAMESPACE_VSTGUI //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- #elif BEOS #include #include #include #include #include #include #include #include #include //-------------------------- class PlugView: public BView { public: PlugView (BRect frame, CFrame* cframe); void Draw (BRect updateRect); void MouseDown (BPoint where); void MessageReceived (BMessage *msg); private: CFrame* cframe; }; long convertPoint2Angle (CPoint &pm, CPoint &pt); drawing_mode modeToPlatform [] = { // kCopyMode kOrMode kXorMode B_OP_COPY, B_OP_OVER, B_OP_INVERT }; long gStandardFontSize[] = { 12, 18, 14, 12, 11, 10, 9, 12 }; const char* standardFont = "Swis721 BT"; const char* standardFontS = "Roman"; const char* systemFont = "Swis721 BT"; const char* systemFontS = "Bold"; const char* gStandardFontName[] = { systemFont, standardFont, standardFont, standardFont, standardFont, standardFont, standardFont }; const char* gStandardFontStyle[] = { systemFontS, standardFontS, standardFontS, standardFontS, standardFontS, standardFontS, standardFontS }; #endif //----------------------------------------------------------------------------- bool CRect::pointInside (const CPoint& where) const { return where.h >= left && where.h < right && where.v >= top && where.v < bottom; } //----------------------------------------------------------------------------- bool CRect::isEmpty () const { if (right <= left) return true; if (bottom <= top) return true; return false; } //----------------------------------------------------------------------------- void CRect::bound (const CRect& rect) { if (left < rect.left) left = rect.left; if (top < rect.top) top = rect.top; if (right > rect.right) right = rect.right; if (bottom > rect.bottom) bottom = rect.bottom; if (bottom < top) bottom = top; if (right < left) right = left; } BEGIN_NAMESPACE_VSTGUI CColor kTransparentCColor = {255, 255, 255, 0}; CColor kBlackCColor = {0, 0, 0, 255}; CColor kWhiteCColor = {255, 255, 255, 255}; CColor kGreyCColor = {127, 127, 127, 255}; CColor kRedCColor = {255, 0, 0, 255}; CColor kGreenCColor = {0 , 255, 0, 255}; CColor kBlueCColor = {0 , 0, 255, 255}; CColor kYellowCColor = {255, 255, 0, 255}; CColor kMagentaCColor= {255, 0, 255, 255}; CColor kCyanCColor = {0 , 255, 255, 255}; #define kDragDelay 0 //----------------------------------------------------------------------------- // CDrawContext Implementation //----------------------------------------------------------------------------- /** * CDrawContext constructor. * @param inFrame the parent CFrame * @param inSystemContext the platform system context, can be NULL * @param inWindow the platform window object */ CDrawContext::CDrawContext (CFrame *inFrame, void *inSystemContext, void *inWindow) : pSystemContext (inSystemContext) , pWindow (inWindow) , pFrame (inFrame) , fontSize (-1) , fontStyle (0) , fontId (kNumStandardFonts) , frameWidth (0) , lineStyle (kLineOnOffDash) , drawMode (kAntialias) #if WINDOWS , pBrush (0), pFont (0), pPen (0) , pOldBrush (0), pOldFont (0), pOldPen (0) #elif MAC && !QUARTZ , bInitialized (false) #endif { #if DEBUG gNbCDrawContext++; #endif // initialize values if (pFrame) pFrame->getViewSize (clipRect); else clipRect (0, 0, 1000, 1000); const CColor notInitalized = {0, 0, 0, 0}; frameColor = notInitalized; fillColor = notInitalized; fontColor = notInitalized; // offsets use by offscreen offset (0, 0); offsetScreen (0, 0); #if WINDOWS pHDC = 0; if (!pSystemContext && pWindow) pSystemContext = pHDC = GetDC ((HWND)pWindow); if (pSystemContext) { pOldBrush = GetCurrentObject ((HDC)pSystemContext, OBJ_BRUSH); pOldPen = GetCurrentObject ((HDC)pSystemContext, OBJ_PEN); pOldFont = GetCurrentObject ((HDC)pSystemContext, OBJ_FONT); SetBkMode ((HDC)pSystemContext, TRANSPARENT); } iPenStyle = PS_SOLID; // get position if (pWindow) { RECT rctTempWnd; GetWindowRect ((HWND)pWindow, &rctTempWnd); offsetScreen.h = rctTempWnd.left; offsetScreen.v = rctTempWnd.top; } #elif MAC #if QUARTZ if (pFrame && (pSystemContext || pWindow)) { HIRect bounds; HIViewGetFrame ((HIViewRef)pFrame->getPlatformControl (), &bounds); if (pWindow || !pSystemContext) { WindowAttributes attr; GetWindowAttributes ((WindowRef)pWindow, &attr); if (attr & kWindowCompositingAttribute) { HIViewRef contentView; HIViewFindByID (HIViewGetRoot ((WindowRef)pWindow), kHIViewWindowContentID, &contentView); if (HIViewGetSuperview ((HIViewRef)pFrame->getPlatformControl ()) != contentView) HIViewConvertRect (&bounds, (HIViewRef)pFrame->getPlatformControl (), contentView); bounds.origin.x += pFrame->hiScrollOffset.x; bounds.origin.y += pFrame->hiScrollOffset.y; } } offsetScreen.x = (CCoord)bounds.origin.x; offsetScreen.y = (CCoord)bounds.origin.y; clipRect (0, 0, (CCoord)bounds.size.width, (CCoord)bounds.size.height); clipRect.offset (pFrame->hiScrollOffset.x, pFrame->hiScrollOffset.y); } gCGContext = 0; if (pSystemContext) { gCGContext = (CGContextRef) pSystemContext; CGContextSaveGState (gCGContext); // save the original state CGContextScaleCTM (gCGContext, 1, -1); CGContextSetShouldAntialias (gCGContext, false); CGContextSetFillColorSpace (gCGContext, GetGenericRGBColorSpace ()); CGContextSetStrokeColorSpace (gCGContext, GetGenericRGBColorSpace ()); CGContextSaveGState (gCGContext); setClipRect (clipRect); if (pFrame) pFrame->setDrawContext (this); } else if (pWindow) { GrafPtr port = GetWindowPort ((WindowRef)pWindow); OSStatus err = QDBeginCGContext (port, &gCGContext); if (err == noErr) { CGContextSaveGState (gCGContext); // save the original state SyncCGContextOriginWithPort (gCGContext, port); Rect rect; GetPortBounds (port, &rect); CGContextTranslateCTM (gCGContext, 0, rect.bottom - rect.top); CGContextTranslateCTM (gCGContext, offsetScreen.x, -offsetScreen.y); CGContextTranslateCTM (gCGContext, -pFrame->hiScrollOffset.x, pFrame->hiScrollOffset.y); CGContextSetShouldAntialias (gCGContext, false); CGContextSetFillColorSpace (gCGContext, GetGenericRGBColorSpace ()); CGContextSetStrokeColorSpace (gCGContext, GetGenericRGBColorSpace ()); CGContextScaleCTM (gCGContext, 1, -1); QuartzSetupClip (gCGContext, clipRect); CGContextScaleCTM (gCGContext, 1, -1); CGContextSaveGState (gCGContext); setClipRect (clipRect); if (pFrame) pFrame->setDrawContext (this); } } if (gCGContext) { CGAffineTransform cgCTM = CGAffineTransformMake (1.0, 0.0, 0.0, -1.0, 0.0, 0.0); CGContextSetTextMatrix (gCGContext, cgCTM); } needToSynchronizeCGContext = false; #else pSystemContext = pWindow; #endif #elif MOTIF if (pFrame) pDisplay = pFrame->getDisplay (); // set the current font if (pSystemContext) setFont (kNormalFont); else fprintf (stderr, "Error in CDrawContext::CDrawContext : pSystemContext must not be Null!!!\n"); #elif BEOS pView = (BView*) pSystemContext; if (pView) pView->LockLooper (); #endif if (1 || pSystemContext) { // set the default values setFrameColor (kWhiteCColor); setLineStyle (kLineSolid); setLineWidth (1); #if !MOTIF setFillColor (kBlackCColor); setFontColor (kWhiteCColor); #endif setFont (kSystemFont); setDrawMode (kCopyMode); } } //----------------------------------------------------------------------------- CDrawContext::~CDrawContext () { #if DEBUG gNbCDrawContext--; #endif #if WINDOWS if (pOldBrush) SelectObject ((HDC)pSystemContext, pOldBrush); if (pOldPen) SelectObject ((HDC)pSystemContext, pOldPen); if (pOldFont) SelectObject ((HDC)pSystemContext, pOldFont); if (pBrush) DeleteObject (pBrush); if (pPen) DeleteObject (pPen); if (pFont) DeleteObject (pFont); if (pHDC) { ReleaseDC ((HWND)pWindow, pHDC); #if DEBUG gNbDC--; #endif } #elif (MAC && QUARTZ) if (gCGContext) { CGContextRestoreGState (gCGContext); // restore the original state CGContextRestoreGState (gCGContext); // we need to do it twice !!! CGContextSynchronize (gCGContext); if (!pSystemContext && pWindow) QDEndCGContext (GetWindowPort ((WindowRef)pWindow), &gCGContext); if (pFrame) pFrame->setDrawContext (0); } #elif MOTIF #elif BEOS if (pView) { pView->Flush (); pView->UnlockLooper (); } #endif } //----------------------------------------------------------------------------- void CDrawContext::setLineStyle (CLineStyle style) { if (lineStyle == style) return; lineStyle = style; #if WINDOWS switch (lineStyle) { case kLineOnOffDash: iPenStyle = PS_DOT; break; default: iPenStyle = PS_SOLID; break; } LOGPEN logPen = {iPenStyle, {frameWidth, frameWidth}, RGB (frameColor.red, frameColor.green, frameColor.blue)}; HANDLE newPen = CreatePenIndirect (&logPen); SelectObject ((HDC)pSystemContext, newPen); if (pPen) DeleteObject (pPen); pPen = newPen; #elif MAC #if QUARTZ // nothing to do here #else CGrafPtr OrigPort; GDHandle OrigDevice; if (pWindow) { GetGWorld (&OrigPort, &OrigDevice); SetGWorld (getPort (), NULL); PenState penState; GetPenState (&penState); switch (lineStyle) { case kLineOnOffDash: StuffHex (&penState.pnPat, "\pF0F0F0F00F0F0F0F"); // dashed line 4 pixel break; default: StuffHex (&penState.pnPat, "\pFFFFFFFFFFFFFFFF"); break; } SetPenState (&penState); SetGWorld (OrigPort, OrigDevice); } #endif #elif MOTIF long line_width; long line_style; if (frameWidth == 1) line_width = 0; else line_width = frameWidth; switch (lineStyle) { case kLineOnOffDash: line_style = LineOnOffDash; break; default: line_style = LineSolid; break; } XSetLineAttributes (XGCPARAM, line_width, line_style, CapNotLast, JoinRound); #endif } //----------------------------------------------------------------------------- void CDrawContext::setLineWidth (CCoord width) { if (frameWidth == width) return; frameWidth = width; #if WINDOWS LOGPEN logPen = {iPenStyle, {frameWidth, frameWidth}, RGB (frameColor.red, frameColor.green, frameColor.blue)}; HANDLE newPen = CreatePenIndirect (&logPen); SelectObject ((HDC)pSystemContext, newPen); if (pPen) DeleteObject (pPen); pPen = newPen; #elif MAC #if QUARTZ if (gCGContext) CGContextSetLineWidth (gCGContext, width); #else CGrafPtr OrigPort; GDHandle OrigDevice; if (pWindow) { GetGWorld (&OrigPort, &OrigDevice); SetGWorld (getPort (), NULL); PenState penState; GetPenState (&penState); penState.pnSize.h = width; penState.pnSize.v = width; SetPenState (&penState); SetGWorld (OrigPort, OrigDevice); } #endif #elif MOTIF setLineStyle (lineStyle); #endif } //----------------------------------------------------------------------------- void CDrawContext::setDrawMode (CDrawMode mode) { if (drawMode == mode) return; drawMode = mode; #if WINDOWS long iMode = 0; switch (drawMode) { case kXorMode : iMode = R2_NOTXORPEN; // Pixel is the inverse of the R2_XORPEN color (final pixel = ~ (pen ^ screen pixel)). break; case kOrMode : iMode = R2_MERGEPEN; // Pixel is a combination of the pen color and the screen color (final pixel = pen | screen pixel). break; default: iMode = R2_COPYPEN; break; } SetROP2 ((HDC)pSystemContext, iMode); #elif MAC #if QUARTZ // quartz only support antialias if (gCGContext) CGContextSetShouldAntialias (gCGContext, drawMode == kAntialias ? true : false); #else if (pWindow) { CGrafPtr OrigPort; GDHandle OrigDevice; GetGWorld (&OrigPort, &OrigDevice); SetGWorld (getPort (), NULL); long iMode = 0; switch (drawMode) { case kXorMode : iMode = patXor; break; case kOrMode : iMode = patOr; break; default: iMode = patCopy; } PenMode (mode); SetGWorld (OrigPort, OrigDevice); } #endif #elif MOTIF long iMode = 0; switch (drawMode) { case kXorMode : iMode = GXinvert; break; case kOrMode : iMode = GXor; break; default: iMode = GXcopy; } ((XGCValues*)pSystemContext)->function = iMode; XChangeGC (XGCPARAM, GCFunction, (XGCValues*)pSystemContext); #endif } //------------------------------------------------------------------------------ void CDrawContext::setClipRect (const CRect &clip) { CRect _clip (clip); _clip.offset (offset.h, offset.v); if (clipRect == _clip) return; clipRect = _clip; #if MAC #if QUARTZ if (0 && gCGContext) { CGContextRestoreGState (gCGContext); CGContextSaveGState (gCGContext); CGContextScaleCTM (gCGContext, 1, -1); CGRect cgClipRect = CGRectMake (clipRect.left, clipRect.top, clipRect.width ()-1.f, clipRect.height ()-1.f); CGContextClipToRect (gCGContext, cgClipRect); CGContextScaleCTM (gCGContext, 1, -1); setLineWidth (frameWidth); setLineStyle (lineStyle); setFrameColor (frameColor); setFillColor (fillColor); setFont (fontId, fontSize); setDrawMode (drawMode); } #else Rect r; CRect2Rect (_clip, r); CGrafPtr OrigPort; GDHandle OrigDevice; GetGWorld (&OrigPort, &OrigDevice); SetGWorld (getPort (), NULL); ClipRect (&r); SetGWorld (OrigPort, OrigDevice); #endif #elif WINDOWS RECT r = {clipRect.left, clipRect.top, clipRect.right, clipRect.bottom}; HRGN hRgn = CreateRectRgn (r.left, r.top, r.right, r.bottom); SelectClipRgn ((HDC)pSystemContext, hRgn); DeleteObject (hRgn); #elif MOTIF XRectangle r; r.x = 0; r.y = 0; r.width = clipRect.right - clipRect.left; r.height = clipRect.bottom - clipRect.top; XSetClipRectangles (XGCPARAM, clipRect.left, clipRect.top, &r, 1, Unsorted); #elif BEOS clipping_rect r = {clipRect.left, clipRect.top, clipRect.right - 1, clipRect.bottom - 1}; BRegion region; region.Set (r); pView->ConstrainClippingRegion (®ion); #endif } //------------------------------------------------------------------------------ void CDrawContext::resetClipRect () { CRect newClip; if (pFrame) pFrame->getViewSize (newClip); else newClip (0, 0, 1000, 1000); #if (MAC && QUARTZ) if (0 && gCGContext) { CGContextRestoreGState (gCGContext); CGContextScaleCTM (gCGContext, 1, -1); CGRect cgClipRect = CGRectMake (newClip.left, newClip.top, newClip.width (), newClip.height ()); CGContextClipToRect (gCGContext, cgClipRect); CGContextScaleCTM (gCGContext, 1, -1); CGContextSaveGState (gCGContext); setLineWidth (frameWidth); setLineStyle (lineStyle); setFrameColor (frameColor); setFillColor (fillColor); setFont (fontId, fontSize); setDrawMode (drawMode); } #elif MAC || WINDOWS || MOTIF setClipRect (newClip); #elif BEOS pView->ConstrainClippingRegion (NULL); #endif clipRect = newClip; } //----------------------------------------------------------------------------- void CDrawContext::moveTo (const CPoint &_point) { CPoint point (_point); point.offset (offset.h, offset.v); #if WINDOWS MoveToEx ((HDC)pSystemContext, point.h, point.v, NULL); #elif MAC #if QUARTZ #else CGrafPtr OrigPort; GDHandle OrigDevice; GetGWorld (&OrigPort, &OrigDevice); // get current GrafPort SetGWorld (getPort (), NULL); // activate our GWorld MoveTo (point.h, point.v); SetGWorld (OrigPort, OrigDevice); #endif penLoc = point; #elif MOTIF || BEOS penLoc = point; #endif } //----------------------------------------------------------------------------- void CDrawContext::lineTo (const CPoint& _point) { CPoint point (_point); point.offset (offset.h, offset.v); #if WINDOWS LineTo ((HDC)pSystemContext, point.h, point.v); #elif MAC #if QUARTZ CGContextRef context = beginCGContext (true); { QuartzSetLineDash (context, lineStyle, frameWidth); CGContextBeginPath (context); CGContextMoveToPoint (context, penLoc.h, penLoc.v); CGContextAddLineToPoint (context, point.h, point.v); CGContextDrawPath (context, kCGPathStroke); releaseCGContext (context); } penLoc = point; #else CGrafPtr OrigPort; GDHandle OrigDevice; GetGWorld (&OrigPort, &OrigDevice); // get current GrafPort SetGWorld (getPort (), NULL); // activate our GWorld RGBColor col; CColor2RGBColor (frameColor, col); RGBForeColor (&col); #if 1 if (point.v == penLoc.v) { CPoint old = point; if (point.h > penLoc.h) point.h--; else point.h++; penLoc = old; LineTo (point.h, point.v); MoveTo (penLoc.h, penLoc.v); } else if (point.h == penLoc.h) { CPoint old = point; if (point.v > penLoc.v) point.v--; else point.v++; penLoc = old; LineTo (point.h, point.v); MoveTo (penLoc.h, penLoc.v); } else { penLoc = point; LineTo (point.h, point.v); } #else if (point.v > penLoc.v) point.v--; else if (point.v < penLoc.v) point.v++; if (point.h > penLoc.h) point.h--; else if (point.h < penLoc.h) point.h++; penLoc = point; LineTo (point.h, point.v); #endif SetGWorld (OrigPort, OrigDevice); #endif #elif MOTIF CPoint start (penLoc); CPoint end (point); if (start.h == end.h) { if (start.v < -5) start.v = -5; else if (start.v > 10000) start.v = 10000; if (end.v < -5) end.v = -5; else if (end.v > 10000) end.v = 10000; } if (start.v == end.v) { if (start.h < -5) start.h = -5; else if (start.h > 10000) start.h = 10000; if (end.h < -5) end.h = -5; else if (end.h > 10000) end.h = 10000; } XDrawLine (XDRAWPARAM, start.h, start.v, end.h, end.v); // keep trace of the new position penLoc = point; #elif BEOS rgb_color c = { frameColor.red, frameColor.green, frameColor.blue, 255 }; pView->SetHighColor (c); pView->SetDrawingMode (modeToPlatform [drawMode]); pView->SetPenSize (frameWidth); lineFromTo (penLoc, point); penLoc = point; #endif } //----------------------------------------------------------------------------- void CDrawContext::drawLines (const CPoint* points, const long& numLines) { #if QUARTZ CGContextRef context = beginCGContext (true); if (context) { QuartzSetLineDash (context, lineStyle, frameWidth); #ifdef MAC_OS_X_VERSION_10_4 if (_CGContextStrokeLineSegments) { CGPoint* cgPoints = new CGPoint[numLines*2]; for (long i = 0; i < numLines * 2; i += 2) { cgPoints[i].x = points[i].x + offset.x; cgPoints[i+1].x = points[i+1].x + offset.x; cgPoints[i].y = points[i].y + offset.y; cgPoints[i+1].y = points[i+1].y + offset.y; } _CGContextStrokeLineSegments (context, cgPoints, numLines*2); delete [] cgPoints; } else #endif { CGContextBeginPath (context); for (long i = 0; i < numLines * 2; i += 2) { CGContextMoveToPoint (context, points[i].x + offset.x, points[i].y + offset.y); CGContextAddLineToPoint (context, points[i+1].x + offset.x, points[i+1].y + offset.y); } CGContextDrawPath (context, kCGPathStroke); } releaseCGContext (context); } #else // default implementation, when no platform optimized code is implemented for (long i = 0; i < numLines * 2; i+=2) { moveTo (points[i]); lineTo (points[i+1]); } #endif } //----------------------------------------------------------------------------- void CDrawContext::drawPolygon (const CPoint *pPoints, long numberOfPoints, const CDrawStyle drawStyle) { #if MAC && QUARTZ CGContextRef context = beginCGContext (true); { CGPathDrawingMode m; switch (drawStyle) { case kDrawFilled : m = kCGPathFill; break; case kDrawFilledAndStroked : m = kCGPathFillStroke; break; default : m = kCGPathStroke; break; } QuartzSetLineDash (context, lineStyle, frameWidth); CGContextBeginPath (context); CGContextMoveToPoint (context, pPoints[0].h + offset.h, pPoints[0].v + offset.v); for (long i = 1; i < numberOfPoints; i++) CGContextAddLineToPoint (context, pPoints[i].h + offset.h, pPoints[i].v + offset.v); CGContextDrawPath (context, m); releaseCGContext (context); } #else if (drawStyle == kDrawFilled || drawStyle == kDrawFilledAndStroked) fillPolygon (pPoints, numberOfPoints); if (drawStyle == kDrawStroked || drawStyle == kDrawFilledAndStroked) polyLine (pPoints, numberOfPoints); #endif } //----------------------------------------------------------------------------- void CDrawContext::polyLine (const CPoint *pPoints, long numberOfPoints) { #if WINDOWS POINT points[30]; POINT *polyPoints; bool allocated = false; if (numberOfPoints > 30) { polyPoints = (POINT*)new char [numberOfPoints * sizeof (POINT)]; if (!polyPoints) return; allocated = true; } else polyPoints = points; for (long i = 0; i < numberOfPoints; i++) { polyPoints[i].x = pPoints[i].h + offset.h; polyPoints[i].y = pPoints[i].v + offset.v; } Polyline ((HDC)pSystemContext, polyPoints, numberOfPoints); if (allocated) delete[] polyPoints; #elif MAC #if QUARTZ drawPolygon (pPoints, numberOfPoints); #else CGrafPtr OrigPort; GDHandle OrigDevice; GetGWorld (&OrigPort, &OrigDevice); SetGWorld (getPort (), NULL); RGBColor col; CColor2RGBColor (frameColor, col); RGBForeColor (&col); MoveTo (pPoints[0].h, pPoints[0].v); for (long i = 1; i < numberOfPoints; i++) LineTo (pPoints[i].h + offset.h, pPoints[i].v + offset.v); SetGWorld (OrigPort, OrigDevice); #endif #elif MOTIF XPoint* pt = (XPoint*)malloc (numberOfPoints * sizeof (XPoint)); if (!pt) return; for (long i = 0; i < numberOfPoints; i++) { pt[i].x = (short)pPoints[i].h + offset.h; pt[i].y = (short)pPoints[i].v + offset.v; } XDrawLines (XDRAWPARAM, pt, numberOfPoints, CoordModeOrigin); free (pt); #elif BEOS rgb_color c = { frameColor.red, frameColor.green, frameColor.blue, 255 }; pView->SetHighColor (c); pView->SetDrawingMode (modeToPlatform [drawMode]); pView->SetPenSize (frameWidth); CPoint begin (pPoints[0]); begin.offset (offset.h, offset.v); CPoint end; for (long i = 1; i < numberOfPoints; i++) { end = pPoints[i]; end.offset (offset.h, offset.v); lineFromTo (begin, end); begin = end; } #endif } //----------------------------------------------------------------------------- void CDrawContext::fillPolygon (const CPoint *pPoints, long numberOfPoints) { // Don't draw boundary #if WINDOWS POINT points[30]; POINT *polyPoints; bool allocated = false; if (numberOfPoints > 30) { polyPoints = (POINT*)new char [numberOfPoints * sizeof (POINT)]; if (!polyPoints) return; allocated = true; } else polyPoints = points; for (long i = 0; i < numberOfPoints; i++) { polyPoints[i].x = pPoints[i].h + offset.h; polyPoints[i].y = pPoints[i].v + offset.v; } HANDLE nullPen = GetStockObject (NULL_PEN); HANDLE oldPen = SelectObject ((HDC)pSystemContext, nullPen); Polygon ((HDC)pSystemContext, polyPoints, numberOfPoints); SelectObject ((HDC)pSystemContext, oldPen); if (allocated) delete[] polyPoints; #elif MAC #if QUARTZ drawPolygon (pPoints, numberOfPoints, kDrawFilled); #else CGrafPtr OrigPort; GDHandle OrigDevice; PolyHandle thePoly; RGBColor col; GetGWorld (&OrigPort, &OrigDevice); SetGWorld (getPort (), NULL); CColor2RGBColor (fillColor, col); RGBForeColor (&col); thePoly = OpenPoly (); // start recording polyLine (pPoints, numberOfPoints); // draw polygon LineTo (pPoints[0].h + offset.h, pPoints[0].v + offset.v); // close the boundary ClosePoly (); // stop recording PixPatHandle pixPatHandle = NewPixPat (); CColor2RGBColor (fillColor, col); MakeRGBPat (pixPatHandle, &col); // create pixel pattern with fill color FillCPoly (thePoly, pixPatHandle); // fill inside KillPoly (thePoly); // deallocate all memory used here DisposePixPat (pixPatHandle); SetGWorld (OrigPort, OrigDevice); #endif #elif MOTIF // convert the points XPoint* pt = (XPoint*)malloc (numberOfPoints * sizeof (XPoint)); for (long i = 0; i < numberOfPoints; i++) { pt[i].x = (short)pPoints[i].h + offset.h; pt[i].y = (short)pPoints[i].v + offset.v; } XFillPolygon (XDRAWPARAM, pt, numberOfPoints, Convex, CoordModeOrigin); free (pt); #elif BEOS BPoint bpoints[30]; BPoint* polyPoints; bool allocated = false; if (numberOfPoints > 30) { polyPoints = new BPoint [numberOfPoints]; if (!polyPoints) return; allocated = true; } else polyPoints = bpoints; for (long i = 0; i < numberOfPoints; i++) polyPoints[i].Set (pPoints[i].h + offset.h, pPoints[i].v + offset.v); rgb_color c = { fillColor.red, fillColor.green, fillColor.blue, 255 }; pView->SetHighColor (c); pView->SetDrawingMode (modeToPlatform [drawMode]); pView->FillPolygon (polyPoints, numberOfPoints); if (allocated) delete[] polyPoints; #endif } //----------------------------------------------------------------------------- void CDrawContext::drawRect (const CRect &_rect, const CDrawStyle drawStyle) { CRect rect (_rect); rect.offset (offset.h, offset.v); #if WINDOWS if (drawStyle == kDrawFilled || drawStyle == kDrawFilledAndStroked) { RECT wr = {rect.left, rect.top, rect.right, rect.bottom}; HANDLE nullPen = GetStockObject (NULL_PEN); HANDLE oldPen = SelectObject ((HDC)pSystemContext, nullPen); FillRect ((HDC)pSystemContext, &wr, (HBRUSH)pBrush); SelectObject ((HDC)pSystemContext, oldPen); } if (drawStyle == kDrawStroked || drawStyle == kDrawFilledAndStroked) { MoveToEx ((HDC)pSystemContext, rect.left, rect.top, NULL); LineTo ((HDC)pSystemContext, rect.right-1, rect.top); LineTo ((HDC)pSystemContext, rect.right-1, rect.bottom-1); LineTo ((HDC)pSystemContext, rect.left, rect.bottom-1); LineTo ((HDC)pSystemContext, rect.left, rect.top); } #elif MAC #if QUARTZ CGContextRef context = beginCGContext (true); { CGPathDrawingMode m; switch (drawStyle) { case kDrawFilled : m = kCGPathFill; break; case kDrawFilledAndStroked : m = kCGPathFillStroke; break; default : m = kCGPathStroke; break; } CGRect r = CGRectMake (rect.left, rect.top+1, rect.width () - 1, rect.height () - 1); QuartzSetLineDash (context, lineStyle, frameWidth); CGContextBeginPath (context); CGContextMoveToPoint (context, r.origin.x, r.origin.y); CGContextAddLineToPoint (context, r.origin.x + r.size.width, r.origin.y); CGContextAddLineToPoint (context, r.origin.x + r.size.width, r.origin.y + r.size.height); CGContextAddLineToPoint (context, r.origin.x, r.origin.y + r.size.height); CGContextClosePath (context); CGContextDrawPath (context, m); releaseCGContext (context); } #else CGrafPtr OrigPort; GDHandle OrigDevice; GetGWorld (&OrigPort, &OrigDevice); // get current GrafPort SetGWorld (getPort (), NULL); // activate our GWorld if (drawStyle == kDrawFilled || drawStyle == kDrawFilledAndStroked) { Rect rr; RGBColor col; CColor2RGBColor (fillColor, col); RGBForeColor (&col); CRect2Rect (rect, rr); FillRect (&rr, &fillPattern); } if (drawStyle == kDrawStroked || drawStyle == kDrawFilledAndStroked) { RGBColor col; CColor2RGBColor (frameColor, col); RGBForeColor (&col); MoveTo (rect.left, rect.top); LineTo (rect.right-1, rect.top); LineTo (rect.right-1, rect.bottom-1); LineTo (rect.left, rect.bottom-1); LineTo (rect.left, rect.top); } SetGWorld (OrigPort, OrigDevice); #endif #elif MOTIF XDrawRectangle (XDRAWPARAM, rect.left, rect.top, rect.width (), rect.height ()); #elif BEOS rgb_color c = { frameColor.red, frameColor.green, frameColor.blue, 255 }; pView->SetHighColor (c); pView->SetDrawingMode (modeToPlatform [drawMode]); BRect r (rect.left, rect.top, rect.right, rect.bottom); pView->SetPenSize (frameWidth); pView->StrokeRect (r); #endif } //----------------------------------------------------------------------------- void CDrawContext::fillRect (const CRect &_rect) { CRect rect (_rect); rect.offset (offset.h, offset.v); // Don't draw boundary #if WINDOWS RECT wr = {rect.left + 1, rect.top + 1, rect.right, rect.bottom}; HANDLE nullPen = GetStockObject (NULL_PEN); HANDLE oldPen = SelectObject ((HDC)pSystemContext, nullPen); FillRect ((HDC)pSystemContext, &wr, (HBRUSH)pBrush); SelectObject ((HDC)pSystemContext, oldPen); #elif MAC #if QUARTZ CGContextRef context = beginCGContext (true); { CGRect r = CGRectMake (rect.left, rect.top, rect.width (), rect.height ()); CGContextFillRect (context, r); releaseCGContext (context); } #else Rect rr; CGrafPtr OrigPort; GDHandle OrigDevice; GetGWorld (&OrigPort, &OrigDevice); SetGWorld (getPort (), NULL); RGBColor col; CColor2RGBColor (fillColor, col); RGBForeColor (&col); CRect2Rect (rect, rr); rr.left++; rr.top++; FillRect (&rr, &fillPattern); SetGWorld (OrigPort, OrigDevice); #endif #elif MOTIF XFillRectangle (XDRAWPARAM, rect.left + 1, rect.top + 1, rect.width () - 1, rect.height () - 1); #elif BEOS rgb_color c = { fillColor.red, fillColor.green, fillColor.blue, 255 }; pView->SetHighColor (c); pView->SetDrawingMode (modeToPlatform [drawMode]); BRect r (rect.left + 1, rect.top + 1, rect.right - 1, rect.bottom - 1); pView->FillRect (r); #endif } //----------------------------------------------------------------------------- void CDrawContext::drawEllipse (const CRect &_rect, const CDrawStyle drawStyle) { #if QUARTZ CRect rect (_rect); rect.offset (offset.h, offset.v); CGContextRef context = beginCGContext (true); { CGPathDrawingMode m; switch (drawStyle) { case kDrawFilled : m = kCGPathFill; break; case kDrawFilledAndStroked : m = kCGPathFillStroke; break; default : m = kCGPathStroke; break; } if (rect.width () != rect.height ()) { CGContextSaveGState (context); QuartzSetLineDash (context, lineStyle, frameWidth); CGContextBeginPath (context); CGRect cgRect = CGRectMake (rect.left, rect.top, rect.width (), rect.height ()); CGPoint center = CGPointMake (CGRectGetMidX (cgRect), CGRectGetMidY (cgRect)); float a = CGRectGetWidth (cgRect) / 2; float b = CGRectGetHeight (cgRect) / 2; CGContextTranslateCTM (context, center.x, center.y); CGContextScaleCTM (context, a, b); CGContextMoveToPoint (context, 1, 0); CGContextAddArc (context, 0, 0, 1, radians (0), radians (360), 0); CGContextClosePath (context); CGContextRestoreGState (context); CGContextDrawPath (context, m); } else { float radius = rect.width () * 0.5f; CGContextBeginPath (context); CGContextAddArc (context, rect.left + radius, rect.top + radius, radius, radians (0), radians (360), 0); CGContextClosePath (context); CGContextDrawPath (context, m); } releaseCGContext (context); } #else CPoint point (_rect.left + (_rect.right - _rect.left) / 2, _rect.top); drawArc (_rect, point, point); #endif } //----------------------------------------------------------------------------- void CDrawContext::fillEllipse (const CRect &_rect) { CRect rect (_rect); rect.offset (offset.h, offset.v); // Don't draw boundary #if WINDOWS HANDLE nullPen = GetStockObject (NULL_PEN); HANDLE oldPen = SelectObject ((HDC)pSystemContext, nullPen); Ellipse ((HDC)pSystemContext, rect.left + 1, rect.top + 1, rect.right + 1, rect.bottom + 1); SelectObject ((HDC)pSystemContext, oldPen); #elif QUARTZ CGContextRef context = beginCGContext (true); { CGContextSaveGState (context); CGContextBeginPath (context); CGRect cgRect = CGRectMake (rect.left, rect.top, rect.width (), rect.height ()); CGPoint center = CGPointMake (CGRectGetMidX (cgRect), CGRectGetMidY (cgRect)); float a = CGRectGetWidth (cgRect) / 2; float b = CGRectGetHeight (cgRect) / 2; CGContextTranslateCTM (context, center.x, center.y); CGContextScaleCTM (context, a, b); CGContextMoveToPoint (context, 1, 0); CGContextAddArc (context, 0, 0, 1, radians (0), radians (360), 0); CGContextClosePath (context); CGContextRestoreGState (context); CGContextDrawPath (context, kCGPathFill); releaseCGContext (context); } #else CPoint point (_rect.left + ((_rect.right - _rect.left) / 2), _rect.top); fillArc (_rect, point, point); #endif } //----------------------------------------------------------------------------- void CDrawContext::drawPoint (const CPoint &_point, CColor color) { CPoint point (_point); #if WINDOWS point.offset (offset.h, offset.v); SetPixel ((HDC)pSystemContext, point.h, point.v, RGB(color.red, color.green, color.blue)); #elif MOTIF CColor oldframecolor = frameColor; setFrameColor (color); XDrawPoint (XDRAWPARAM, point.h, point.v); setFrameColor (oldframecolor); #elif MAC CCoord oldframeWidth = frameWidth; CColor oldframecolor = frameColor; setLineWidth (1); setFrameColor (color); CPoint point2 (point); point2.h++; moveTo (point); lineTo (point2); setFrameColor (oldframecolor); setLineWidth (oldframeWidth); #else int oldframeWidth = frameWidth; CColor oldframecolor = frameColor; setLineWidth (1); setFrameColor (color); moveTo (point); lineTo (point); setFrameColor (oldframecolor); setLineWidth (oldframeWidth); #endif } //----------------------------------------------------------------------------- CColor CDrawContext::getPoint (const CPoint& _point) { CPoint point (_point); point.offset (offset.h, offset.v); CColor color = kBlackCColor; #if WINDOWS COLORREF c = GetPixel ((HDC)pSystemContext, point.h, point.v); color.red = GetRValue (c); color.green = GetGValue (c); color.blue = GetBValue (c); #elif MAC #if QUARTZ // no quartz equivalent #else CGrafPtr OrigPort; GDHandle OrigDevice; GetGWorld (&OrigPort, &OrigDevice); SetGWorld (getPort (), NULL); RGBColor cPix; GetCPixel (point.h, point.v, &cPix); RGBColor2CColor (cPix, color); SetGWorld (OrigPort, OrigDevice); #endif #endif return color; } //----------------------------------------------------------------------------- void CDrawContext::floodFill (const CPoint& _start) { CPoint start (_start); start.offset (offset.h, offset.v); #if WINDOWS COLORREF c = GetPixel ((HDC)pSystemContext, start.h, start.v); ExtFloodFill ((HDC)pSystemContext, start.h, start.v, c, FLOODFILLSURFACE); #elif MAC #if QUARTZ // no quartz equivalent #else CGrafPtr oldPort; GDHandle oldDevice; GetGWorld (&oldPort, &oldDevice); SetGWorld (getPort (), 0); Rect r; GetPortBounds (getPort (), &r); GWorldPtr pMask; OSErr err = NewGWorld ((GWorldPtr*)&pMask, 1, &r, 0, 0, 0); // create monochrome GWorld if (!err) { // generate fill mask PixMapHandle srcBits = GetGWorldPixMap (getPort ()); PixMapHandle dstBits = GetGWorldPixMap (pMask); if (srcBits && dstBits) { LockPixels (srcBits); LockPixels (dstBits); SeedCFill ((BitMapPtr)*srcBits, (BitMapPtr)*dstBits, &r, &r, start.h, start.v, 0, 0); // fill destination RGBColor oldForeColor, oldBackColor; GetForeColor (&oldForeColor); GetBackColor (&oldBackColor); ::BackColor (whiteColor); RGBColor col; CColor2RGBColor (fillColor, col); RGBForeColor (&col); CopyMask ((BitMapPtr)*dstBits, (BitMapPtr)*dstBits, (BitMapPtr)*srcBits, &r, &r, &r); RGBForeColor (&oldForeColor); RGBBackColor (&oldBackColor); // cleanup UnlockPixels (srcBits); UnlockPixels (dstBits); } DisposeGWorld (pMask); } SetGWorld (oldPort, oldDevice); #endif #endif } #if QUARTZ void addOvalToPath(CGContextRef c, CPoint center, float a, float b, float start_angle, float end_angle) { CGContextSaveGState (c); CGContextTranslateCTM (c, center.x, center.y); CGContextScaleCTM (c, a, b); CGContextMoveToPoint (c, cos (radians (start_angle)), sin (radians (start_angle))); CGContextAddArc(c, 0, 0, 1, radians (start_angle), radians (end_angle), 1); CGContextRestoreGState(c); } #endif //----------------------------------------------------------------------------- void CDrawContext::drawArc (const CRect &_rect, const float _startAngle, const float _endAngle, const CDrawStyle drawStyle) // in degree { CRect rect (_rect); rect.offset (offset.h, offset.v); #if WINDOWS float startRad = (float)(k2PI * _startAngle / 360.f); float endRad = (float)(k2PI * _endAngle / 360.f); CPoint point1, point2; long midX = _rect.width () / 2; long midY = _rect.height () / 2; point1.x = (long)(midX + midX * cosf (startRad)); point1.y = (long)(midY - midY * sinf (startRad)); point2.x = (long)(midX + midX * cosf (endRad)); point2.y = (long)(midY - midY * sinf (endRad)); point1.offset (offset.h, offset.v); point2.offset (offset.h, offset.v); if (drawStyle == kDrawFilled || drawStyle == kDrawFilledAndStroked) { HANDLE nullPen = GetStockObject (NULL_PEN); HANDLE oldPen = SelectObject ((HDC)pSystemContext, nullPen); Pie ((HDC)pSystemContext, rect.left, rect.top, rect.right + 1, rect.bottom + 1, point1.h, point1.v, point2.h, point2.v); SelectObject ((HDC)pSystemContext, oldPen); } if (drawStyle == kDrawStroked || drawStyle == kDrawFilledAndStroked) { Arc ((HDC)pSystemContext, rect.left, rect.top, rect.right + 1, rect.bottom + 1, point1.h, point1.v, point2.h, point2.v); } #elif MOTIF XDrawArc (XDRAWPARAM, rect.left, rect.top, rect.width (), rect.height (), _startAngle * 64, _endAngle * 64); #elif MAC #if QUARTZ CGContextRef context = beginCGContext (true); { CGPathDrawingMode m; switch (drawStyle) { case kDrawFilled : m = kCGPathFill; break; case kDrawFilledAndStroked : m = kCGPathFillStroke; break; default : m = kCGPathStroke; break; } QuartzSetLineDash (context, lineStyle, frameWidth); CGContextBeginPath (context); addOvalToPath (context, CPoint (rect.left + rect.width () / 2, rect.top + rect.height () / 2), rect.width () / 2, rect.height () / 2, -_startAngle, -_endAngle); CGContextDrawPath (context, m); releaseCGContext (context); } #else Rect rr; CGrafPtr OrigPort; GDHandle OrigDevice; GetGWorld (&OrigPort, &OrigDevice); SetGWorld (getPort (), NULL); RGBColor col; CColor2RGBColor (frameColor, col); RGBForeColor (&col); CRect2Rect (rect, rr); FrameArc (&rr, 90 - _startAngle, -_endAngle); SetGWorld (OrigPort, OrigDevice); #endif #elif BEOS rgb_color c = { frameColor.red, frameColor.green, frameColor.blue, 255 }; pView->SetHighColor (c); pView->SetDrawingMode (modeToPlatform [drawMode]); BRect r (rect.left, rect.top, rect.right, rect.bottom); pView->SetPenSize (frameWidth); pView->StrokeArc (r, _startAngle, _endAngle); #endif } //----------------------------------------------------------------------------- void CDrawContext::drawArc (const CRect &_rect, const CPoint &_point1, const CPoint &_point2) { CRect rect (_rect); rect.offset (offset.h, offset.v); CPoint point1 (_point1); point1.offset (offset.h, offset.v); CPoint point2 (_point2); point2.offset (offset.h, offset.v); // draws from point1 to point2 counterclockwise #if WINDOWS Arc ((HDC)pSystemContext, rect.left, rect.top, rect.right + 1, rect.bottom + 1, point1.h, point1.v, point2.h, point2.v); #elif MAC || MOTIF || BEOS int angle1, angle2; if ((point1.v == point2.v) && (point1.h == point2.h)) { angle1 = 0; angle2 = 23040; // 360 * 64 } else { CPoint pm ((rect.left + rect.right) / 2, (rect.top + rect.bottom) / 2); angle1 = convertPoint2Angle (pm, point1); angle2 = convertPoint2Angle (pm, point2) - angle1; if (angle2 < 0) angle2 += 23040; // 360 * 64 } #if MAC #if QUARTZ angle1 /= 64; angle2 /= 64; CGContextRef context = beginCGContext (true); { QuartzSetLineDash (context, lineStyle, frameWidth); CGContextBeginPath (context); addOvalToPath (context, CPoint (rect.left + rect.width () / 2, rect.top + rect.height () / 2), rect.width () / 2, rect.height () / 2, 90-angle1, (90-angle1)-angle2); CGContextDrawPath (context, kCGPathStroke); releaseCGContext (context); } #else Rect rr; CGrafPtr OrigPort; GDHandle OrigDevice; GetGWorld (&OrigPort, &OrigDevice); SetGWorld (getPort (), NULL); RGBColor col; CColor2RGBColor (frameColor, col); RGBForeColor (&col); CRect2Rect (rect, rr); FrameArc (&rr, 90 - (angle1 / 64), -angle2 / 64); SetGWorld (OrigPort, OrigDevice); #endif #elif MOTIF XDrawArc (XDRAWPARAM, rect.left, rect.top, rect.width (), rect.height (), angle1, angle2); #elif BEOS rgb_color c = { frameColor.red, frameColor.green, frameColor.blue, 255 }; pView->SetHighColor (c); pView->SetDrawingMode (modeToPlatform [drawMode]); BRect r (rect.left, rect.top, rect.right, rect.bottom); pView->SetPenSize (frameWidth); pView->StrokeArc (r, angle1 / 64, angle2 / 64); #endif #endif } //----------------------------------------------------------------------------- void CDrawContext::fillArc (const CRect &_rect, const CPoint &_point1, const CPoint &_point2) { CRect rect (_rect); rect.offset (offset.h, offset.v); CPoint point1 (_point1); point1.offset (offset.h, offset.v); CPoint point2 (_point2); point2.offset (offset.h, offset.v); // Don't draw boundary #if WINDOWS HANDLE nullPen = GetStockObject (NULL_PEN); HANDLE oldPen = SelectObject ((HDC)pSystemContext, nullPen); Pie ((HDC)pSystemContext, offset.h + rect.left + 1, offset.v + rect.top + 1, offset.h + rect.right, offset.v + rect.bottom, point1.h, point1.v, point2.h, point2.v); SelectObject ((HDC)pSystemContext, oldPen); #elif MAC || MOTIF || BEOS int angle1, angle2; if ((point1.v == point2.v) && (point1.h == point2.h)) { angle1 = 0; angle2 = 23040; // 360 * 64 } else { CPoint pm ((rect.left + rect.right) / 2, (rect.top + rect.bottom) / 2); angle1 = convertPoint2Angle (pm, point1); angle2 = convertPoint2Angle (pm, point2); } #if MAC #if QUARTZ angle1 /= 64; angle2 /= 64; CGContextRef context = beginCGContext (true); { CGContextBeginPath (context); addOvalToPath (context, CPoint (rect.left + rect.width () / 2, rect.top + rect.height () / 2), rect.width () / 2, rect.height () / 2, -angle1, -angle2); CGContextClosePath (context); CGContextDrawPath (context, kCGPathFill); releaseCGContext (context); } #else Rect rr; CGrafPtr OrigPort; GDHandle OrigDevice; GetGWorld (&OrigPort, &OrigDevice); SetGWorld (getPort (), NULL); RGBColor col; CColor2RGBColor (fillColor, col); RGBForeColor (&col); CRect2Rect (rect, rr); angle2 = angle2 - angle1; if (angle2 < 0) angle2 = -angle2; FillArc (&rr, 90 - (angle1 / 64), -angle2 / 64, &fillPattern); SetGWorld (OrigPort, OrigDevice); #endif #elif MOTIF XFillArc (XDRAWPARAM, rect.left, rect.top, rect.width (), rect.height (), angle1, angle2); #elif BEOS rgb_color c = { fillColor.red, fillColor.green, fillColor.blue, 255 }; pView->SetHighColor (c); pView->SetDrawingMode (modeToPlatform [drawMode]); BRect r (rect.left + 1, rect.top + 1, rect.right - 1, rect.bottom - 1); pView->FillArc (r, angle1 / 64, angle2 / 64); #endif #endif } //----------------------------------------------------------------------------- void CDrawContext::setFontColor (const CColor color) { fontColor = color; #if WINDOWS SetTextColor ((HDC)pSystemContext, RGB (fontColor.red, fontColor.green, fontColor.blue)); #elif MAC #if QUARTZ // on quartz the fill color is the font color #else RGBColor col; CGrafPtr OrigPort; GDHandle OrigDevice; if (pWindow) { GetGWorld (&OrigPort, &OrigDevice); SetGWorld (getPort (), NULL); CColor2RGBColor (fontColor, col); RGBForeColor (&col); SetGWorld (OrigPort, OrigDevice); } #endif #elif MOTIF setFrameColor (fontColor); #endif } //----------------------------------------------------------------------------- void CDrawContext::setFrameColor (const CColor color) { if (frameColor == color) return; frameColor = color; #if WINDOWS LOGPEN logPen = {iPenStyle, {frameWidth, frameWidth}, RGB (frameColor.red, frameColor.green, frameColor.blue)}; HANDLE newPen = CreatePenIndirect (&logPen); SelectObject ((HDC)pSystemContext, newPen); if (pPen) DeleteObject (pPen); pPen = newPen; #elif MAC #if QUARTZ if (gCGContext) CGContextSetRGBStrokeColor (gCGContext, color.red/255.f, color.green/255.f, color.blue/255.f, color.alpha/255.f); #else RGBColor col; CGrafPtr OrigPort; GDHandle OrigDevice; if (pWindow) { GetGWorld (&OrigPort, &OrigDevice); SetGWorld (getPort (), NULL); CColor2RGBColor (frameColor, col); RGBForeColor (&col); SetGWorld (OrigPort, OrigDevice); } #endif #elif MOTIF XSetForeground (XGCPARAM, getIndexColor (frameColor)); #endif } //----------------------------------------------------------------------------- void CDrawContext::setFillColor (const CColor color) { if (fillColor == color) return; fillColor = color; #if WINDOWS SetBkColor ((HDC)pSystemContext, RGB (color.red, color.green, color.blue)); LOGBRUSH logBrush = {BS_SOLID, RGB (color.red, color.green, color.blue), 0 }; HANDLE newBrush = CreateBrushIndirect (&logBrush); if (newBrush == 0) { DWORD err = GetLastError (); return; } SelectObject ((HDC)pSystemContext, newBrush); if (pBrush) DeleteObject (pBrush); pBrush = newBrush; #elif MAC #if QUARTZ if (gCGContext) CGContextSetRGBFillColor (gCGContext, color.red/255.f, color.green/255.f, color.blue/255.f, color.alpha/255.f); #else RGBColor col; CGrafPtr OrigPort; GDHandle OrigDevice; if (pWindow) { GetGWorld (&OrigPort, &OrigDevice); SetGWorld (getPort (), NULL); CColor2RGBColor (fillColor, col); RGBForeColor (&col); SetGWorld (OrigPort, OrigDevice); } #endif #elif MOTIF // set the background for the text XSetBackground (XGCPARAM, getIndexColor (fillColor)); // set the foreground for the fill setFrameColor (fillColor); #endif } //----------------------------------------------------------------------------- void CDrawContext::setFont (CFont fontID, const long size, long style) { if (fontID < 0 || fontID >= kNumStandardFonts) fontID = kSystemFont; if (fontId == fontID && fontSize == (size != 0 ? size : gStandardFontSize[fontID]) && fontStyle == style) return; fontStyle = style; fontId = fontID; if (size != 0) fontSize = size; else fontSize = gStandardFontSize[fontID]; #if WINDOWS LOGFONT logfont = {0}; if (style & kBoldFace) logfont.lfWeight = FW_BOLD; else logfont.lfWeight = FW_NORMAL; if (style & kItalicFace) logfont.lfItalic = true; if (style & kUnderlineFace) logfont.lfUnderline = true; logfont.lfHeight = -fontSize; logfont.lfPitchAndFamily = VARIABLE_PITCH | FF_SWISS; strcpy (logfont.lfFaceName, gStandardFontName[fontID]); if (fontID == kSymbolFont) logfont.lfPitchAndFamily = DEFAULT_PITCH | FF_DECORATIVE; else if (fontID == kSystemFont) logfont.lfWeight = FW_BOLD; logfont.lfClipPrecision = CLIP_STROKE_PRECIS; logfont.lfOutPrecision = OUT_STRING_PRECIS; logfont.lfQuality = DEFAULT_QUALITY; logfont.lfCharSet = ANSI_CHARSET; HANDLE newFont = CreateFontIndirect (&logfont); SelectObject ((HDC)pSystemContext, newFont); if (pFont) DeleteObject (pFont); pFont = newFont; #elif MAC #if QUARTZ char myMacXFontName[255]; strcpy(myMacXFontName, gMacXfontNames[fontId]); if (style & kBoldFace) strcat(myMacXFontName, " Bold"); if (style & kItalicFace) strcat(myMacXFontName, " Italic"); if (style & kUnderlineFace) strcat(myMacXFontName, " Underline"); if (gCGContext) CGContextSelectFont (gCGContext, (const char*)myMacXFontName, fontSize, kCGEncodingMacRoman); #else CGrafPtr OrigPort; GDHandle OrigDevice; if (pWindow) { GetGWorld (&OrigPort, &OrigDevice); SetGWorld (getPort (), NULL); TextFace (style); // normal, bold, italic, underline... TextMode (0); TextSize (fontSize); #if MACX short familyID; GetFNum (gMacXfontNames[fontID], &familyID); TextFont (familyID); #else if (fontID == kSymbolFont) TextFont (kFontIDSymbol); else if (fontID == kSystemFont) TextFont (0); // system else if (fontID == kNormalFontSmaller) TextFont (kFontIDGeneva); // Geneva else TextFont (kFontIDHelvetica); #endif GetFontInfo (&fontInfoStruct); SetGWorld (OrigPort, OrigDevice); } #endif #elif MOTIF XSetFont (XGCPARAM, gFontStructs[fontID]->fid); // keep trace of the current font pFontInfoStruct = gFontStructs[fontID]; #elif BEOS font.SetFamilyAndStyle (gStandardFontName[fontID], gStandardFontStyle[fontID]); font.SetSize (fontSize); pView->SetFont (&font, B_FONT_FAMILY_AND_STYLE | B_FONT_SIZE); #endif } //------------------------------------------------------------------------------ CCoord CDrawContext::getStringWidth (const char *pStr) { CCoord result = 0; #if MAC #if QUARTZ CGContextRef context = beginCGContext (true); if (context) { CGContextSetTextDrawingMode (context, kCGTextInvisible); CGContextSetTextPosition (context, 0.f, 0.f); CGContextShowText (context, pStr, strlen (pStr)); CGPoint p = CGContextGetTextPosition (context); result = (CCoord)p.x; releaseCGContext (context); } #else CGrafPtr OrigPort; GDHandle OrigDevice; GetGWorld (&OrigPort, &OrigDevice); SetGWorld (getPort (), NULL); result = (long)TextWidth (pStr, 0, strlen (pStr)); SetGWorld (OrigPort, OrigDevice); #endif #elif WINDOWS SIZE size; GetTextExtentPoint32 ((HDC)pSystemContext, pStr, (int)strlen (pStr), &size); result = (long)size.cx; #elif MOTIF result = (long)XTextWidth (pFontInfoStruct, pStr, strlen (pStr)); #elif BEOS result = (long)(ceil (pView->StringWidth (pStr))); #endif return result; } //----------------------------------------------------------------------------- void CDrawContext::drawString (const char *string, const CRect &_rect, const short opaque, const CHoriTxtAlign hAlign) { if (!string) return; CRect rect (_rect); rect.offset (offset.h, offset.v); #if WINDOWS // set the visibility mask SetBkMode ((HDC)pSystemContext, opaque ? OPAQUE : TRANSPARENT); RECT Rect = {rect.left, rect.top, rect.right, rect.bottom}; UINT flag = DT_VCENTER + DT_SINGLELINE + DT_NOPREFIX; switch (hAlign) { case kCenterText: // without DT_SINGLELINE no vertical center alignment here DrawText ((HDC)pSystemContext, string, (int)strlen (string), &Rect, flag + DT_CENTER); break; case kRightText: DrawText ((HDC)pSystemContext, string, (int)strlen (string), &Rect, flag + DT_RIGHT); break; default : // left adjust Rect.left++; DrawText ((HDC)pSystemContext, string, (int)strlen (string), &Rect, flag + DT_LEFT); } SetBkMode ((HDC)pSystemContext, TRANSPARENT); #elif MAC #if QUARTZ CGContextRef context = beginCGContext (true); if (context) { CCoord strWidth = getStringWidth (string); rect.bottom -= rect.height ()/2 - fontSize / 2 + 1; switch (hAlign) { case kCenterText: { rect.left += rect.width () / 2 - strWidth/2; break; } case kRightText: rect.left = rect.right - strWidth; break; default : // left adjust rect.left++; } CGContextSetShouldAntialias (context, true); CGContextSetTextDrawingMode (context, kCGTextFill); CGContextSetRGBFillColor (context, fontColor.red/255.f, fontColor.green/255.f, fontColor.blue/255.f, fontColor.alpha/255.f); CGContextSetTextPosition (context, rect.left, rect.bottom); CGContextShowText (context, string, strlen (string)); releaseCGContext (context); } #else CGrafPtr OrigPort; GDHandle OrigDevice; int width; int xPos, yPos; int fontHeight; int rectHeight; int stringLength; Rect stringsRect; Rect contextsClip; Rect compositeClip; CRect2Rect (rect, stringsRect); CRect2Rect (clipRect, contextsClip); if (SectRect (&stringsRect, &contextsClip, &compositeClip)) { GetGWorld (&OrigPort, &OrigDevice); SetGWorld (getPort (), NULL); if (opaque) TextMode (srcCopy); else TextMode (srcOr); RGBColor col; CColor2RGBColor (fontColor, col); RGBForeColor (&col); CColor2RGBColor (fillColor, col); RGBBackColor (&col); rectHeight = rect.height (); fontHeight = fontInfoStruct.ascent + fontInfoStruct.descent; yPos = rect.bottom - fontInfoStruct.descent; if (rectHeight >= fontHeight) yPos -= (rectHeight - fontHeight) / 2; stringLength = strlen (string); width = TextWidth ((Ptr)string, 0, stringLength); switch (hAlign) { case kCenterText: xPos = (rect.right + rect.left - width) / 2; break; case kRightText: xPos = rect.right - width; break; default: // left adjust xPos = rect.left; } RgnHandle saveRgn = NewRgn (); GetClip (saveRgn); ClipRect (&compositeClip); #if TARGET_API_MAC_CARBON CFStringRef str; // Create a unicode string str = CFStringCreateWithCString(NULL, string, kCFStringEncodingMacRoman); // Initialize proper text box options TXNTextBoxOptionsData myOptions; myOptions.optionTags = kTXNSetJustificationMask; myOptions.justification = kTXNFlushLeft; // Determine the vertical alignment of the text box. // It is centered vertically. // Somehow, the yPos calculation above doesn't work here // or I am too stupid to understand it. Therefore I calculate // the text position in the surrounding control rect myself. long myHeight = (rect.height () - fontHeight) / 2; if (myHeight>0) { stringsRect.top += myHeight; stringsRect.bottom += myHeight; } stringsRect.left = xPos; stringsRect.right = xPos + width;//rect.width (); // Draw the unicode string TXNDrawCFStringTextBox (str, &stringsRect, NULL, &myOptions); // Release the unicode string CFRelease (str); #else MoveTo (xPos, yPos); DrawText ((Ptr)string, 0, stringLength); #endif SetClip (saveRgn); DisposeRgn (saveRgn); TextMode (srcOr); SetGWorld (OrigPort, OrigDevice); } #endif #elif MOTIF int width; int fontHeight = pFontInfoStruct->ascent + pFontInfoStruct->descent; int xPos; int yPos; int rectHeight = rect.height (); if (rectHeight >= fontHeight) yPos = rect.bottom - (rectHeight - fontHeight) / 2; else yPos = rect.bottom; yPos -= pFontInfoStruct->descent; switch (hAlign) { case kCenterText: width = XTextWidth (pFontInfoStruct, string, strlen (string)); xPos = (rect.right + rect.left - width) / 2; break; case kRightText: width = XTextWidth (pFontInfoStruct, string, strlen (string)); xPos = rect.right - width; break; default: // left adjust xPos = rect.left + 1; } if (opaque) XDrawImageString (XDRAWPARAM, xPos, yPos, string, strlen (string)); else XDrawString (XDRAWPARAM, xPos, yPos, string, strlen (string)); #elif BEOS BRect r (rect.left, rect.top, rect.right - 1, rect.bottom - 1); BRegion LocalRegion (r); pView->ConstrainClippingRegion (&LocalRegion); pView->SetFontSize (fontSize); float width = -1; if (opaque) { width = ceil (pView->StringWidth (string)); CRect cr (rect.left, rect.top, rect.left + width, rect.bottom); fillRect (cr); } rgb_color c = { fontColor.red, fontColor.green, fontColor.blue, 255 }; pView->SetHighColor (c); if (drawMode == kXorMode) pView->SetDrawingMode (B_OP_INVERT); else pView->SetDrawingMode (B_OP_OVER); BPoint p; font_height height; pView->GetFontHeight (&height); p.y = r.bottom - (rect.height () - height.ascent) / 2; if (hAlign == kCenterText || hAlign == kRightText) { if (width < 0) width = ceil (pView->StringWidth (string)); if (hAlign == kCenterText) p.x = rect.left + (rect.right - rect.left - width) / 2; else p.x = rect.right - width - 1; } else p.x = rect.left + 1; pView->DrawString (string, p); pView->ConstrainClippingRegion (NULL); #endif } //----------------------------------------------------------------------------- long CDrawContext::getMouseButtons () { long buttons = 0; #if WINDOWS if (GetAsyncKeyState (VK_LBUTTON) < 0) buttons |= (bSwapped_mouse_buttons ? kRButton : kLButton); if (GetAsyncKeyState (VK_MBUTTON) < 0) buttons |= kMButton; if (GetAsyncKeyState (VK_RBUTTON) < 0) buttons |= (bSwapped_mouse_buttons ? kLButton : kRButton); if (GetAsyncKeyState (VK_SHIFT) < 0) buttons |= kShift; if (GetAsyncKeyState (VK_CONTROL) < 0) buttons |= kControl; if (GetAsyncKeyState (VK_MENU) < 0) buttons |= kAlt; #elif MAC #if MACX // this works for MacOSX 10.2 and later UInt32 state = GetCurrentButtonState (); if (state & kEventMouseButtonPrimary) buttons |= kLButton; if (state & kEventMouseButtonSecondary) buttons |= kRButton; if (state & 4)//kEventMouseButtonTertiary) this define is false...Apple ? buttons |= kMButton; state = GetCurrentKeyModifiers (); if (state & cmdKey) buttons |= kControl; if (state & shiftKey) buttons |= kShift; if (state & optionKey) buttons |= kAlt; if (state & controlKey) buttons |= kApple; // for the one buttons if (buttons & kApple && buttons & kLButton) { buttons &= ~(kApple | kLButton); buttons |= kRButton; } #else if (Button ()) buttons |= kLButton; KeyMap Keys; unsigned char *BytePtr = (unsigned char*)Keys; GetKeys (Keys); if (BytePtr[7] & 1) // Shift 0x38 == 56 = (7 * 8) + 0 buttons |= kShift; if (BytePtr[7] & 8) // Control (extra Mac) 0x3B == 59 = (7 * 8) + 3 buttons |= kApple; if (BytePtr[7] & 4) // Alt 0x3A == 58 = (7 * 8) + 2 buttons |= kAlt; if (BytePtr[6] & 128) // Apple => ctrl (PC) 0x37 == 55 = (6 * 8) + 7 buttons |= kControl; #endif #elif MOTIF Window root, child; long rootX, rootY, childX, childY; unsigned int mask; int result = XQueryPointer (XWINPARAM, &root, &child, &rootX, &rootY, &childX, &childY, &mask); if (mask & Button1Mask) buttons |= kLButton; if (mask & Button2Mask) buttons |= kMButton; if (mask & Button3Mask) buttons |= kRButton; if (mask & ShiftMask) buttons |= kShift; if (mask & ControlMask) buttons |= kControl; if (mask & Mod1Mask) buttons |= kAlt; #elif BEOS BPoint where; uint32 b; pView->GetMouse (&where, &b); if (b & B_PRIMARY_MOUSE_BUTTON) buttons |= kLButton; if (b & B_SECONDARY_MOUSE_BUTTON) buttons |= kRButton; if (b & B_TERTIARY_MOUSE_BUTTON) buttons |= kMButton; int32 m = modifiers (); if (m & B_SHIFT_KEY) buttons |= kShift; if (m & B_COMMAND_KEY) buttons |= kControl; if (m & B_OPTION_KEY) buttons |= kApple; if (m & B_CONTROL_KEY) buttons |= kAlt; #endif return buttons; } //----------------------------------------------------------------------------- void CDrawContext::getMouseLocation (CPoint &point) { #if WINDOWS POINT where; GetCursorPos (&where); point (where.x, where.y); #elif MACX #if 0 // QUARTZ // does not work sic! Point where; UInt32 mod; MouseTrackingResult result; if (TrackMouseLocationWithOptions ((CGrafPtr)-1, 0, kEventDurationNoWait, &where, &mod, &result) == noErr) { QDGlobalToLocalPoint (getPort (), &where); point (where.h, where.v); } #else Point where; CGrafPtr savedPort; Boolean portChanged = QDSwapPort (getPort (), &savedPort); GetMouse (&where); if (portChanged) QDSwapPort (savedPort, NULL); point (where.h, where.v); #endif #if QUARTZ point.offset (pFrame->hiScrollOffset.x,pFrame->hiScrollOffset.y); #endif #elif MAC Point where; GetMouse (&where); point (where.h, where.v); #elif MOTIF Window root, child; int rootX, rootY, childX, childY; unsigned int mask; int result = XQueryPointer (XWINPARAM, &root, &child, &rootX, &rootY, &childX, &childY, &mask); point (childX, childY); #elif BEOS BPoint where; uint32 b; pView->GetMouse (&where, &b); point (where.x, where.y); #endif point.offset (-offsetScreen.h, -offsetScreen.v); } //----------------------------------------------------------------------------- bool CDrawContext::waitDoubleClick () { bool doubleClick = false; #if WINDOWS CPoint mouseLoc; getMouseLocation (mouseLoc); CRect observe (mouseLoc.h - 2, mouseLoc.v - 2, mouseLoc.h + 2, mouseLoc.v + 2); DWORD currentTime = GetTickCount (); DWORD clickTime = GetMessageTime () + (DWORD)GetDoubleClickTime (); MSG message; while (currentTime < clickTime) { getMouseLocation (mouseLoc); if (!observe.pointInside (mouseLoc)) break; if (PeekMessage (&message, 0, WM_LBUTTONDOWN, WM_LBUTTONDOWN, PM_REMOVE | PM_NOYIELD)) { doubleClick = true; break; } currentTime = GetTickCount (); } #elif MAC #if MACX #if QUARTZ EventTimeout timeout = GetDblTime () * kEventDurationSecond / 60; const EventTypeSpec eventTypes[] = { { kEventClassMouse, kEventMouseDown }, { kEventClassMouse, kEventMouseDragged } }; EventRef event; if (ReceiveNextEvent (GetEventTypeCount (eventTypes), eventTypes, timeout, true, &event) == noErr) { if (GetEventKind (event) == kEventMouseDown) { doubleClick = true; } ReleaseEvent (event); } #else unsigned long clickTime, doubletime; EventRecord downEvent; doubletime = GetDblTime (); clickTime = TickCount () + doubletime; while (TickCount () < clickTime) { if (GetNextEvent (mDownMask, &downEvent)) { doubleClick = true; break; } } #endif // !QUARTZ #else long clickTime, doubleTime; EventRecord downEvent; #define MOUSE_IS_DOWN ((* (char*)0x172) >= 0) doubleTime = GetDblTime () / 2; clickTime = TickCount () + doubleTime; while (TickCount () < clickTime) if (!MOUSE_IS_DOWN) break; /* look for mouse up! */ if (GetNextEvent (mUpMask, &downEvent)) { clickTime += doubleTime; while (TickCount () < clickTime) if (MOUSE_IS_DOWN) break; /* look for mouse down! */ if (GetNextEvent (mDownMask, &downEvent)) doubleClick = true; } #endif #elif MOTIF long currentTime = _getTicks (); long clickTime = currentTime + XtGetMultiClickTime (pDisplay); XEvent e; while (currentTime < clickTime) { if (XCheckTypedEvent (pDisplay, ButtonPress, &e)) { doubleClick = true; break; } currentTime = _getTicks (); } #elif BEOS const bigtime_t snoozeTime = 5000; bigtime_t latest = system_time (); bigtime_t doubleclicktime; get_click_speed (&doubleclicktime); latest += doubleclicktime; BPoint location; uint32 buttons; pView->GetMouse (&location, &buttons); while (buttons) // user should release the mouse button { if (system_time () > latest) return false; snooze (snoozeTime); pView->GetMouse (&location, &buttons); } while (!buttons) { if (system_time () > latest) return false; snooze (snoozeTime); pView->GetMouse (&location, &buttons); } doubleClick = true; #endif return doubleClick; } //----------------------------------------------------------------------------- bool CDrawContext::waitDrag () { #if MACX && QUARTZ bool dragged = false; if (GetCurrentEventButtonState () & kEventMouseButtonPrimary) { const EventTypeSpec eventTypes[] = { { kEventClassMouse, kEventMouseUp }, { kEventClassMouse, kEventMouseDown }, { kEventClassMouse, kEventMouseDragged } }; EventRef event; if (ReceiveNextEvent (GetEventTypeCount (eventTypes), eventTypes, kEventDurationForever, true, &event) == noErr) { if (GetEventKind (event) == kEventMouseDragged) { dragged = true; } ReleaseEvent (event); } } return dragged; #else if (!pFrame) return false; CPoint mouseLoc; getMouseLocation (mouseLoc); CRect observe (mouseLoc.h - 2, mouseLoc.v - 2, mouseLoc.h + 2, mouseLoc.v + 2); long currentTime = pFrame->getTicks (); bool wasOutside = false; while (((getMouseButtons () & ~(kMButton|kRButton)) & kLButton) != 0) { pFrame->doIdleStuff (); if (!wasOutside) { getMouseLocation (mouseLoc); if (!observe.pointInside (mouseLoc)) { if (kDragDelay <= 0) return true; wasOutside = true; } } if (wasOutside && (pFrame->getTicks () - currentTime > kDragDelay)) return true; } return false; #endif } //----------------------------------------------------------------------------- void CDrawContext::forget () { #if QUARTZ synchronizeCGContext (); #endif CReferenceCounter::forget (); } //----------------------------------------------------------------------------- #if MOTIF //----------------------------------------------------------------------------- long CDrawContext::getIndexColor (CColor color) { // 24bit visual ? if (pFrame->getDepth () == 24) return (unsigned int)color.blue << 16 | (unsigned int)color.green << 8 | (unsigned int)color.red; // 8bit stuff return getIndexColor8Bit (color, pDisplay, pFrame->getColormap ()); } //----------------------------------------------------------------------------- Colormap CDrawContext::getColormap () { if (pFrame) return pFrame->getColormap (); else return NULL; } //----------------------------------------------------------------------------- Visual* CDrawContext::getVisual () { if (pFrame) return pFrame->getVisual (); else return NULL; } //----------------------------------------------------------------------------- unsigned int CDrawContext::getDepth () { if (pFrame) return pFrame->getDepth (); else return NULL; } //----------------------------------------------------------------------------- #elif BEOS //----------------------------------------------------------------------------- void CDrawContext::lineFromTo (CPoint& cstart, CPoint& cend) { BPoint start (cstart.h, cstart.v); BPoint end (cend.h, cend.v); if (start.x == end.x) { if (start.y < end.y) end.y--; else if (end.y < start.y) start.y--; } else if (start.y == end.y) { if (start.x < end.x) end.x--; else if (end.x < start.x) start.x--; } else { if (start.x > end.x) { BPoint t = end; end = start; start = t; } end.x--; if (end.y > start.y) end.y--; else end.y++; } pView->MovePenTo (start); if (lineStyle == kLineSolid) pView->StrokeLine (end); else { pattern stripes = { {0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3} }; pView->StrokeLine (end, stripes); } } //----------------------------------------------------------------------------- #elif MAC #if QUARTZ //----------------------------------------------------------------------------- CGContextRef CDrawContext::beginCGContext (bool swapYAxis) { if (gCGContext) { CGContextSaveGState (gCGContext); CGContextScaleCTM (gCGContext, 1, -1); QuartzSetupClip (gCGContext, clipRect); if (!swapYAxis) CGContextScaleCTM (gCGContext, 1, -1); return gCGContext; } return 0; } //----------------------------------------------------------------------------- void CDrawContext::releaseCGContext (CGContextRef context) { if (context) { CGContextRestoreGState (context); needToSynchronizeCGContext = true; } } //----------------------------------------------------------------------------- void CDrawContext::synchronizeCGContext () { if (needToSynchronizeCGContext && gCGContext) { CGContextSynchronize (gCGContext); needToSynchronizeCGContext = false; } } //----------------------------------------------------------------------------- CGImageRef CDrawContext::getCGImage () const { return 0; } //----------------------------------------------------------------------------- void QuartzSetupClip (CGContextRef context, const CRect clipRect) { CGRect cgClipRect = CGRectMake (clipRect.left, clipRect.top, clipRect.width (), clipRect.height ()); CGContextClipToRect (context, cgClipRect); } //----------------------------------------------------------------------------- void QuartzSetLineDash (CGContextRef context, CLineStyle style, CCoord lineWidth) { if (style == kLineOnOffDash) { float offset = 0; float dotf[2] = { lineWidth, lineWidth }; CGContextSetLineDash (context, offset, dotf, 2); } } #endif //----------------------------------------------------------------------------- BitMapPtr CDrawContext::getBitmap () { #if QUARTZ return (BitMapPtr)GetPortBitMapForCopyBits (GetWindowPort ((WindowRef)pWindow)); #else PixMapHandle pixMap = GetPortPixMap (GetWindowPort ((WindowRef)pWindow)); if (pixMap) { LockPixels (pixMap); return (BitMapPtr)*pixMap; } #endif return 0; } //----------------------------------------------------------------------------- void CDrawContext::releaseBitmap () { #if !QUARTZ PixMapHandle pixMap = GetPortPixMap (GetWindowPort ((WindowRef)pWindow)); UnlockPixels (pixMap); #endif } //----------------------------------------------------------------------------- CGrafPtr CDrawContext::getPort () { #if QUARTZ if (pWindow) return (CGrafPtr)GetWindowPort ((WindowRef)pWindow); return 0; #else if (!bInitialized) { CGrafPtr OrigPort; GDHandle OrigDevice; GetGWorld (&OrigPort, &OrigDevice); SetGWorld ((CGrafPtr)GetWindowPort ((WindowRef)pWindow), NULL); TextMode (srcOr); PenMode (patCopy); StuffHex (&fillPattern, "\pFFFFFFFFFFFFFFFF"); SetGWorld (OrigPort, OrigDevice); bInitialized = true; } return (CGrafPtr)GetWindowPort ((WindowRef)pWindow); #endif } #endif //----------------------------------------------------------------------------- // COffscreenContext Implementation //----------------------------------------------------------------------------- COffscreenContext::COffscreenContext (CDrawContext *pContext, CBitmap *pBitmapBg, bool drawInBitmap) : CDrawContext (pContext->pFrame, NULL, NULL) , pBitmap (0) , pBitmapBg (pBitmapBg) , height (20) , width (20) { if (pBitmapBg) { height = pBitmapBg->getHeight (); width = pBitmapBg->getWidth (); clipRect (0, 0, width, height); } #if DEBUG gNbCOffscreenContext++; gBitmapAllocation += (long)height * (long)width; #endif bDestroyPixmap = false; #if WINDOWS if (pOldBrush) SelectObject ((HDC)getSystemContext (), pOldBrush); if (pOldPen) SelectObject ((HDC)getSystemContext (), pOldPen); if (pOldFont) SelectObject ((HDC)getSystemContext (), pOldFont); pOldBrush = pOldPen = pOldFont = 0; pSystemContext = CreateCompatibleDC ((HDC)pContext->getSystemContext ()); if (drawInBitmap) pWindow = pBitmapBg->getHandle (); else // create bitmap if no bitmap handle exists { bDestroyPixmap = true; pWindow = CreateCompatibleBitmap ((HDC)pContext->getSystemContext (), width, height); } oldBitmap = SelectObject ((HDC)pSystemContext, pWindow); #elif MAC #if QUARTZ offscreenBitmap = 0; if (drawInBitmap) { if (pBitmapBg->getHandle ()) { PixMapHandle pixMap = GetGWorldPixMap ((GWorldPtr)pBitmapBg->getHandle ()); LockPixels (pixMap); size_t pixDepth = GetPixDepth (pixMap) / 4; size_t rowBytes = GetPixRowBytes (pixMap); gCGContext = CGBitmapContextCreate (GetPixBaseAddr (pixMap), (size_t)width, (size_t)height, pixDepth, rowBytes, GetGenericRGBColorSpace (), kCGImageAlphaPremultipliedFirst); if (gCGContext) { CGContextTranslateCTM (gCGContext, 0, (float)height); CGContextSetFillColorSpace (gCGContext, GetGenericRGBColorSpace ()); CGContextSetStrokeColorSpace (gCGContext, GetGenericRGBColorSpace ()); CGAffineTransform cgCTM = CGAffineTransformMake (1.0, 0.0, 0.0, -1.0, 0.0, 0.0); CGContextSetTextMatrix (gCGContext, cgCTM); CGContextSaveGState (gCGContext); } } } else { // todo !!! } #else if (drawInBitmap) pWindow = pBitmapBg->getHandle (); else { Rect GWRect; GWRect.top = 0; GWRect.left = 0; GWRect.right = width; GWRect.bottom = height; NewGWorld ((GWorldPtr*)&pWindow, 0, &GWRect, NULL, NULL, 0); bDestroyPixmap = true; } StuffHex (&fillPattern, "\pFFFFFFFFFFFFFFFF"); #endif #elif MOTIF // if no bitmap handle => create one if (!pWindow) { Drawable dWindow = pContext->pFrame->getWindow (); pWindow = (void*)XCreatePixmap (pDisplay, dWindow, width, height, pFrame->getDepth ()); bDestroyPixmap = true; } // set the current font if (pSystemContext) setFont (kNormalFont); #elif BEOS bDestroyPixmap = true; offscreenBitmap = new BBitmap (BRect (0, 0, width - 1, height - 1), B_RGB16, true, false); pView = new BView (BRect (0, 0, width - 1, height - 1), NULL, 0, 0); offscreenBitmap->Lock (); offscreenBitmap->AddChild (pView); #endif if (!drawInBitmap) { // draw bitmap to Offscreen CRect r (0, 0, width, height); if (pBitmapBg) pBitmapBg->draw (this, r); else { setFillColor (kBlackCColor); fillRect (r); } } } //----------------------------------------------------------------------------- COffscreenContext::COffscreenContext (CFrame *pFrame, long width, long height, const CColor backgroundColor) : CDrawContext (pFrame, NULL, NULL) , pBitmap (0) , pBitmapBg (0) , height (height) , width (width) , backgroundColor (backgroundColor) { clipRect (0, 0, width, height); #if DEBUG gNbCOffscreenContext++; gBitmapAllocation += height * width; #endif bDestroyPixmap = true; #if WINDOWS void *SystemWindow = pFrame->getSystemWindow (); void *SystemContext = GetDC ((HWND)SystemWindow); pSystemContext = CreateCompatibleDC ((HDC)SystemContext); #if DEBUG gNbDC++; #endif pWindow = CreateCompatibleBitmap ((HDC)SystemContext, width, height); oldBitmap = SelectObject ((HDC)pSystemContext, pWindow); ReleaseDC ((HWND)SystemWindow, (HDC)SystemContext); CRect r (0, 0, width, height); setFillColor (backgroundColor); setFrameColor (backgroundColor); fillRect (r); drawRect (r); #elif MAC #if QUARTZ CGContextRef context = NULL; int bitmapByteCount; int bitmapBytesPerRow; // each pixel is represented by four bytes // (8 bits each of alpha, R, G, B) bitmapBytesPerRow = width * 4; bitmapByteCount = bitmapBytesPerRow * height; // create the bitmap offscreenBitmap = malloc (bitmapByteCount); if (offscreenBitmap != NULL) { memset (offscreenBitmap, 0, bitmapByteCount); // create the context context = CGBitmapContextCreate (offscreenBitmap, width, height, 8, // bits per component bitmapBytesPerRow, GetGenericRGBColorSpace (), kCGImageAlphaPremultipliedFirst); if (context == NULL) { // the context couldn't be created for some reason, // and we have no use for the bitmap without the context free (offscreenBitmap); offscreenBitmap = 0; } else { CGContextTranslateCTM (context, 0, (float)height); CGContextSetFillColorSpace (context, GetGenericRGBColorSpace ()); CGContextSetStrokeColorSpace (context, GetGenericRGBColorSpace ()); CGAffineTransform cgCTM = CGAffineTransformMake (1.0, 0.0, 0.0, -1.0, 0.0, 0.0); CGContextSetTextMatrix (context, cgCTM); CGContextSaveGState (context); CGRect r = CGRectMake (0, 0, width, height); CGContextClearRect (context, r); } } gCGContext = context; CRect r (0, 0, width, height); setFillColor (backgroundColor); setFrameColor (backgroundColor); fillRect (r); drawRect (r); #else QDErr err; Rect GWRect; GWRect.top = GWRect.left = 0; GWRect.right = width; GWRect.bottom = height; err = NewGWorld ((GWorldPtr*) &pWindow, 0, &GWRect, NULL, NULL, 0); if (err) pWindow = NULL; StuffHex (&fillPattern, "\pFFFFFFFFFFFFFFFF"); CRect r (0, 0, width, height); setFillColor (backgroundColor); setFrameColor (backgroundColor); fillRect (r); drawRect (r); #endif #elif MOTIF Drawable dWindow = pFrame->getWindow (); pWindow = (void*)XCreatePixmap (pDisplay, dWindow, width, height, pFrame->getDepth ()); // clear the pixmap XGCValues values; values.foreground = getIndexColor (backgroundColor); GC gc = XCreateGC (pDisplay, (Drawable)pWindow, GCForeground, &values); XFillRectangle (pDisplay, (Drawable)pWindow, gc, 0, 0, width, height); XFreeGC (pDisplay, gc); // set the current font if (pSystemContext) setFont (kNormalFont); #elif BEOS BRect frame (0, 0, width - 1, height - 1); offscreenBitmap = new BBitmap (frame, B_RGB16, true, false); pView = new BView (BRect (0, 0, width - 1, height - 1), NULL, 0, 0); offscreenBitmap->Lock (); offscreenBitmap->AddChild (pView); if (backgroundColor.red != 255 || backgroundColor.green != 255 || backgroundColor.blue != 255) { rgb_color c = { backgroundColor.red, backgroundColor.green, backgroundColor.blue, 255 }; pView->SetHighColor (c); pView->FillRect (frame); } #endif } //----------------------------------------------------------------------------- COffscreenContext::~COffscreenContext () { #if DEBUG gNbCOffscreenContext--; gBitmapAllocation -= (long)height * (long)width; #endif if (pBitmap) pBitmap->forget (); #if WINDOWS if (pSystemContext) { DeleteDC ((HDC)pSystemContext); pSystemContext = 0; #if DEBUG gNbDC--; #endif } if (bDestroyPixmap && pWindow) DeleteObject (pWindow); #elif MAC #if QUARTZ if (gCGContext) { CGContextRestoreGState (gCGContext); CGContextRelease (gCGContext); } gCGContext = 0; if (offscreenBitmap) free (offscreenBitmap); else if (pBitmapBg && pBitmapBg->getHandle ()) { PixMapHandle pixMap = GetGWorldPixMap ((GWorldPtr)pBitmapBg->getHandle ()); UnlockPixels (pixMap); } #else if (bDestroyPixmap && pWindow) DisposeGWorld ((GWorldPtr)pWindow); #endif #elif MOTIF if (bDestroyPixmap && pWindow) XFreePixmap (pDisplay, (Pixmap)pWindow); #elif BEOS delete offscreenBitmap; pView = 0; // deleted because attached to the offscreen #endif } //----------------------------------------------------------------------------- void COffscreenContext::copyTo (CDrawContext* pContext, CRect& srcRect, CPoint destOffset) { #if WINDOWS BitBlt ((HDC)pSystemContext, destOffset.h, destOffset.v, srcRect.width (), srcRect.height (), (HDC)pContext->getSystemContext (), srcRect.left + pContext->offset.h, srcRect.top + pContext->offset.v, SRCCOPY); #elif MAC #if QUARTZ if (!pBitmapBg) return; #else if (!pWindow) return; #endif Rect source, dest; RGBColor savedForeColor, savedBackColor; source.left = (short)(srcRect.left + pContext->offset.h + pContext->offsetScreen.h); source.top = (short)(srcRect.top + pContext->offset.v + pContext->offsetScreen.v); source.right = (short)(source.left + srcRect.right - srcRect.left); source.bottom = (short)(source.top + srcRect.bottom - srcRect.top); dest.left = (short)destOffset.h; dest.top = (short)destOffset.v; dest.right = (short)(dest.left + srcRect.right - srcRect.left); dest.bottom = (short)(dest.top + srcRect.bottom - srcRect.top); GetForeColor (&savedForeColor); GetBackColor (&savedBackColor); ::BackColor (whiteColor); ::ForeColor (blackColor); CopyBits (pContext->getBitmap (), getBitmap (), &source, &dest, srcCopy, 0L); releaseBitmap (); pContext->releaseBitmap (); RGBForeColor (&savedForeColor); RGBBackColor (&savedBackColor); #endif } //----------------------------------------------------------------------------- void COffscreenContext::copyFrom (CDrawContext *pContext, CRect destRect, CPoint srcOffset) { #if WINDOWS BitBlt ((HDC)pContext->getSystemContext (), // hdcDest destRect.left + pContext->offset.h, // xDest destRect.top + pContext->offset.v, // yDest destRect.right - destRect.left, // xWidth, destRect.bottom - destRect.top, // yHeight (HDC)pSystemContext, // hdcSrc srcOffset.h, // xSrc srcOffset.v, // ySrc SRCCOPY); // dwROP #elif MAC #if QUARTZ if (!gCGContext) return; CGContextRef context = pContext->beginCGContext (); if (context) { size_t pixRowBytes = CGBitmapContextGetBytesPerRow (gCGContext); short pixDepth = CGBitmapContextGetBitsPerPixel (gCGContext); size_t size = pixRowBytes * CGBitmapContextGetHeight (gCGContext); CGImageRef image = 0; CGDataProviderRef provider = CGDataProviderCreateWithData (NULL, CGBitmapContextGetData (gCGContext), size, NULL); CGImageAlphaInfo alphaInfo = CGBitmapContextGetAlphaInfo (gCGContext); image = CGImageCreate (CGBitmapContextGetWidth (gCGContext), CGBitmapContextGetHeight (gCGContext), 8 , pixDepth, pixRowBytes, GetGenericRGBColorSpace (), alphaInfo, provider, NULL, 0, kCGRenderingIntentDefault); if (image) { CGRect dest; dest.origin.x = destRect.left - srcOffset.h + pContext->offset.h; dest.origin.y = (destRect.top + pContext->offset.v) * -1 - (getHeight () - srcOffset.v); dest.size.width = getWidth (); dest.size.height = getHeight (); CGRect clipRect; clipRect.origin.x = destRect.left + pContext->offset.h; clipRect.origin.y = (destRect.top + pContext->offset.v) * -1 - destRect.height (); clipRect.size.width = destRect.width (); clipRect.size.height = destRect.height (); CGContextClipToRect (context, clipRect); CGContextDrawImage (context, dest, image); CGImageRelease (image); } CGDataProviderRelease (provider); pContext->releaseCGContext (context); } #else if (!pWindow) return; Rect source, dest; RGBColor savedForeColor, savedBackColor; source.left = srcOffset.h; source.top = srcOffset.v; source.right = source.left + destRect.right - destRect.left; source.bottom = source.top + destRect.bottom - destRect.top; dest.top = destRect.top + pContext->offset.v; dest.left = destRect.left + pContext->offset.h; dest.bottom = destRect.bottom + pContext->offset.v; dest.right = destRect.right + pContext->offset.h; GetForeColor (&savedForeColor); GetBackColor (&savedBackColor); ::BackColor (whiteColor); ::ForeColor (blackColor); CopyBits (getBitmap (), pContext->getBitmap (), &source, &dest, srcCopy, 0L); #if MACX QDAddRectToDirtyRegion (pContext->getPort (), &dest); #endif releaseBitmap (); pContext->releaseBitmap (); RGBForeColor (&savedForeColor); RGBBackColor (&savedBackColor); #endif #elif MOTIF XCopyArea (pDisplay, (Drawable)pWindow, (Drawable)pContext->getWindow (), (GC)pSystemContext, srcOffset.h, srcOffset.v, destRect.width (), destRect.height (), destRect.left, destRect.top); #elif BEOS pContext->pView->SetDrawingMode (B_OP_COPY); BRect destination (destRect.left, destRect.top, destRect.right - 1, destRect.bottom - 1); BRect source = destination; source.OffsetTo (srcOffset.h, srcOffset.v); pView->Sync (); pContext->pView->DrawBitmap (offscreenBitmap, source, destination); #endif } //----------------------------------------------------------------------------- #if MAC #if QUARTZ //----------------------------------------------------------------------------- CGImageRef COffscreenContext::getCGImage () const { #ifdef MAC_OS_X_VERSION_10_4 if (CGBitmapContextCreateImage && gCGContext) { return CGBitmapContextCreateImage (gCGContext); } #endif return 0; } #endif //----------------------------------------------------------------------------- BitMapPtr COffscreenContext::getBitmap () { #if QUARTZ return pBitmapBg ? (BitMapPtr)GetPortBitMapForCopyBits ((GWorldPtr)pBitmapBg->getHandle ()) : 0; #else PixMapHandle pixMap = GetGWorldPixMap ((GWorldPtr)pWindow); if (pixMap) { LockPixels (pixMap); return (BitMapPtr)*pixMap; } return 0; #endif } //----------------------------------------------------------------------------- void COffscreenContext::releaseBitmap () { #if QUARTZ #else PixMapHandle pixMap = GetGWorldPixMap ((GWorldPtr)pWindow); UnlockPixels (pixMap); #endif } #if !QUARTZ //----------------------------------------------------------------------------- CGrafPtr COffscreenContext::getPort () { if (!bInitialized) bInitialized = true; return (CGrafPtr)pWindow; } #endif // QUARTZ #endif // MAC //----------------------------------------------------------------------------- class CAttributeListEntry { public: CAttributeListEntry (long size, CViewAttributeID id) : nextEntry (0) , pointer (0) , sizeOfPointer (size) , id (id) { pointer = malloc (size); } ~CAttributeListEntry () { if (pointer) free (pointer); } const CViewAttributeID getID () const { return id; } const long getSize () const { return sizeOfPointer; } void* getPointer () const { return pointer; } CAttributeListEntry* getNext () const { return nextEntry; } void setNext (CAttributeListEntry* entry) { nextEntry = entry; } protected: CAttributeListEntry () : nextEntry (0), pointer (0), sizeOfPointer (0), id (0) {} CAttributeListEntry* nextEntry; void* pointer; long sizeOfPointer; CViewAttributeID id; }; //----------------------------------------------------------------------------- char* kMsgCheckIfViewContainer = "kMsgCheckIfViewContainer"; //----------------------------------------------------------------------------- // CView //----------------------------------------------------------------------------- /*! @class CView base class of all view objects */ //----------------------------------------------------------------------------- CView::CView (const CRect& size) : size (size) , mouseableArea (size) , pParentFrame (0) , pParentView (0) , bDirty (false) , bMouseEnabled (true) , bTransparencyEnabled (false) , bWantsFocus (false) , pBackground (0) , pAttributeList (0) { #if DEBUG gNbCView++; #endif } //----------------------------------------------------------------------------- CView::~CView () { if (pBackground) pBackground->forget (); if (pAttributeList) { CAttributeListEntry* entry = pAttributeList; while (entry) { CAttributeListEntry* nextEntry = entry->getNext (); delete entry; entry = nextEntry; } } #if DEBUG gNbCView--; #endif } //----------------------------------------------------------------------------- void CView::getMouseLocation (CDrawContext* context, CPoint &point) { if (context) { if (pParentView && pParentView->notify (this, kMsgCheckIfViewContainer) == kMessageNotified) { CCoord save[4]; ((CViewContainer*)pParentView)->modifyDrawContext (save, context); pParentView->getMouseLocation (context, point); ((CViewContainer*)pParentView)->restoreDrawContext (context, save); } else context->getMouseLocation (point); } } #if ENABLE_DEPRECATED_METHODS //----------------------------------------------------------------------------- void CView::getFrameTopLeftPos (CPoint& topLeft) const { topLeft.h += size.left; topLeft.v += size.top; if (pParentView && pParentView->notify (0, kMsgCheckIfViewContainer) == kMessageNotified) pParentView->getFrameTopLeftPos (topLeft); } #endif //----------------------------------------------------------------------------- CPoint& CView::frameToLocal (CPoint& point) const { if (pParentView && pParentView->isTypeOf ("CViewContainer")) return pParentView->frameToLocal (point); return point; } //----------------------------------------------------------------------------- CPoint& CView::localToFrame (CPoint& point) const { if (pParentView && pParentView->isTypeOf ("CViewContainer")) return pParentView->localToFrame (point); return point; } //----------------------------------------------------------------------------- void CView::redraw () { if (pParentFrame) pParentFrame->draw (this); } //----------------------------------------------------------------------------- void CView::redrawRect (CDrawContext* context, const CRect& rect) { // we always pass it on to the parent view as it knows what else must be drawn (needed for nested view containers) if (pParentView) pParentView->redrawRect (context, rect); else if (pParentFrame) pParentFrame->drawRect (context, rect); } //----------------------------------------------------------------------------- void CView::draw (CDrawContext *pContext) { if (pBackground) { if (bTransparencyEnabled) pBackground->drawTransparent (pContext, size); else pBackground->draw (pContext, size); } setDirty (false); } //----------------------------------------------------------------------------- void CView::mouse (CDrawContext *pContext, CPoint &where, long buttons) {} //----------------------------------------------------------------------------- bool CView::onWheel (CDrawContext *pContext, const CPoint &where, float distance) { return false; } //------------------------------------------------------------------------ bool CView::onWheel (CDrawContext *pContext, const CPoint &where, const CMouseWheelAxis axis, float distance) { return onWheel (pContext, where, distance); } //------------------------------------------------------------------------ void CView::update (CDrawContext *pContext) { if (isDirty ()) { #if NEW_UPDATE_MECHANISM if (pContext) redrawRect (pContext, size); else redraw (); #else #if USE_ALPHA_BLEND if (pContext) { if (bTransparencyEnabled) getFrame ()->drawRect (pContext, size); else draw (pContext); } #else if (pContext) draw (pContext); #endif else redraw (); #endif // !NEW_UPDATE_MECHANISM setDirty (false); } } //------------------------------------------------------------------------------ long CView::onKeyDown (VstKeyCode& keyCode) { return -1; } //------------------------------------------------------------------------------ long CView::onKeyUp (VstKeyCode& keyCode) { return -1; } //------------------------------------------------------------------------------ long CView::notify (CView* sender, const char* message) { return kMessageUnknown; } //------------------------------------------------------------------------------ void CView::looseFocus (CDrawContext *pContext) {} //------------------------------------------------------------------------------ void CView::takeFocus (CDrawContext *pContext) {} //------------------------------------------------------------------------------ void CView::setViewSize (CRect &rect) { size = rect; setDirty (); } //----------------------------------------------------------------------------- void *CView::getEditor () const { return pParentFrame ? pParentFrame->getEditor () : 0; } //----------------------------------------------------------------------------- void CView::setBackground (CBitmap *background) { if (pBackground) pBackground->forget (); pBackground = background; if (pBackground) pBackground->remember (); setDirty (true); } //----------------------------------------------------------------------------- const CViewAttributeID kCViewAttributeReferencePointer = 'cvrp'; //----------------------------------------------------------------------------- /** * @param id the ID of the Attribute * @param outSize on return the size of the attribute */ bool CView::getAttributeSize (const CViewAttributeID id, long& outSize) const { if (pAttributeList) { CAttributeListEntry* entry = pAttributeList; while (entry) { if (entry->getID () == id) break; entry = entry->getNext (); } if (entry) { outSize = entry->getSize (); return true; } } return false; } //----------------------------------------------------------------------------- /** * @param id the ID of the Attribute * @param inSize the size of the outData pointer * @param outData a pointer where to copy the attribute data * @param outSize the size in bytes which was copied into outData */ bool CView::getAttribute (const CViewAttributeID id, const long inSize, void* outData, long& outSize) const { if (pAttributeList) { CAttributeListEntry* entry = pAttributeList; while (entry) { if (entry->getID () == id) break; entry = entry->getNext (); } if (entry && inSize >= entry->getSize ()) { outSize = entry->getSize (); memcpy (outData, entry->getPointer (), outSize); return true; } } return false; } //----------------------------------------------------------------------------- /** * copies data into the attribute. If it does not exist, creates a new attribute. * @param id the ID of the Attribute * @param inSize the size of the outData pointer * @param inData a pointer to the data */ bool CView::setAttribute (const CViewAttributeID id, const long inSize, void* inData) { CAttributeListEntry* lastEntry = 0; if (pAttributeList) { CAttributeListEntry* entry = pAttributeList; while (entry) { if (entry->getID () == id) break; if (entry->getNext () == 0) lastEntry = entry; entry = entry->getNext (); } if (entry) { if (entry->getSize () >= inSize) { memcpy (entry->getPointer (), inData, inSize); return true; } else return false; } } // create a new attribute CAttributeListEntry* newEntry = new CAttributeListEntry (inSize, id); memcpy (newEntry->getPointer (), inData, inSize); if (lastEntry) lastEntry->setNext (newEntry); else if (!pAttributeList) pAttributeList = newEntry; else { delete newEntry; return false; } return true; } #if DEBUG //----------------------------------------------------------------------------- void CView::dumpInfo () { CRect viewRect = getViewSize (viewRect); DebugPrint ("left:%4d, top:%4d, width:%4d, height:%4d ", viewRect.left, viewRect.top, viewRect.getWidth (), viewRect.getHeight ()); if (getMouseEnabled ()) DebugPrint ("(Mouse Enabled) "); if (getTransparency ()) DebugPrint ("(Transparent) "); CRect mouseRect = getMouseableArea (mouseRect); if (mouseRect != viewRect) DebugPrint (" (Mouseable Area: left:%4d, top:%4d, width:%4d, height:%4d ", mouseRect.left, mouseRect.top, mouseRect.getWidth (), mouseRect.getHeight ()); } #endif #define FOREACHSUBVIEW for (CCView *pSv = pFirstView; pSv; pSv = pSv->pNext) {CView *pV = pSv->pView; #define FOREACHSUBVIEW_REVERSE(reverse) for (CCView *pSv = reverse ? pLastView : pFirstView; pSv; pSv = reverse ? pSv->pPrevious : pSv->pNext) {CView *pV = pSv->pView; #define ENDFOR } //----------------------------------------------------------------------------- // CFrame Implementation //----------------------------------------------------------------------------- /*! @class CFrame It creates a platform dependend view object. On classic Mac OS it just draws into the provided window. On Mac OS X it is a ControlRef. On Windows it's a WS_CHILD Window. */ CFrame::CFrame (const CRect &inSize, void *inSystemWindow, void *inEditor) : CViewContainer (inSize, 0, 0) , pEditor (inEditor) , pSystemWindow (inSystemWindow) , pModalView (0) , pFocusView (0) , bFirstDraw (true) , bDropActive (false) , bUpdatesDisabled (false) , pFrameContext (0) , bAddedWindow (false) , pVstWindow (0) , defaultCursor (0) { setOpenFlag (true); pParentFrame = this; #if WINDOWS pHwnd = 0; dropTarget = 0; backBuffer = 0; OleInitialize (0); #if DYNAMICALPHABLEND pfnAlphaBlend = 0; pfnTransparentBlt = 0; hInstMsimg32dll = LoadLibrary ("msimg32.dll"); if (hInstMsimg32dll) { pfnAlphaBlend = (PFNALPHABLEND)GetProcAddress (hInstMsimg32dll, "AlphaBlend"); // get OS version memset (&gSystemVersion, 0, sizeof (gSystemVersion)); gSystemVersion.dwOSVersionInfoSize = sizeof (gSystemVersion); if (GetVersionEx ((OSVERSIONINFO *)&gSystemVersion)) { // Is this win NT or better? if (gSystemVersion.dwPlatformId >= VER_PLATFORM_WIN32_NT) { // Yes, then TransparentBlt doesn't have the memory-leak and can be safely used pfnTransparentBlt = (PFNTRANSPARENTBLT)GetProcAddress (hInstMsimg32dll, "TransparentBlt"); } } } #endif // DYNAMICALPHABLEND #elif MOTIF gc = 0; depth = 0; pDisplay = 0; pVisual = 0; window = 0; #elif BEOS pPlugView = NULL; #endif initFrame (pSystemWindow); #if WINDOWS #if USE_GLOBAL_CONTEXT pFrameContext = new CDrawContext (this, 0, getSystemWindow ()); #endif #elif MAC Gestalt (gestaltSystemVersion, &pSystemVersion); #if QUARTZ pFrameContext = 0; #else pFrameContext = new CDrawContext (this, getSystemWindow (), getSystemWindow ()); pFrameContext->offset.h = size.left; pFrameContext->offset.v = size.top; #endif #elif MOTIF pFrameContext = new CDrawContext (this, gc, (void*)window); #endif } //----------------------------------------------------------------------------- CFrame::CFrame (const CRect& inSize, const char* inTitle, void* inEditor, const long inStyle) : CViewContainer (inSize, 0, 0) , pEditor (inEditor) , pSystemWindow (0) , pModalView (0) , pFocusView (0) , bFirstDraw (true) , bDropActive (false) , bUpdatesDisabled (false) , pFrameContext (0) , pVstWindow (0) , defaultCursor (0) { bAddedWindow = true; setOpenFlag (false); pParentFrame = this; #if WINDOWS pHwnd = 0; dropTarget = 0; backBuffer = 0; OleInitialize (0); #if DYNAMICALPHABLEND pfnAlphaBlend = 0; pfnTransparentBlt = 0; hInstMsimg32dll = LoadLibrary ("msimg32.dll"); if (hInstMsimg32dll) { pfnAlphaBlend = (PFNALPHABLEND)GetProcAddress (hInstMsimg32dll, "AlphaBlend"); // get OS version OSVERSIONINFOEX osvi; memset (&osvi, 0, sizeof (osvi)); osvi.dwOSVersionInfoSize = sizeof (osvi); if (GetVersionEx ((OSVERSIONINFO *)&osvi)) { // Is this win NT or better? if (osvi.dwPlatformId >= VER_PLATFORM_WIN32_NT) { // Yes, then TransparentBlt doesn't have the memory-leak and can be safely used pfnTransparentBlt = (PFNTRANSPARENTBLT)GetProcAddress (hInstMsimg32dll, "TransparentBlt"); } } } #endif #elif MOTIF gc = 0; depth = 0; pDisplay = 0; pVisual = 0; window = 0; #elif BEOS pPlugView = NULL; #endif #if USE_VST_WINDOW pVstWindow = (VstWindow*)malloc (sizeof (VstWindow)); strcpy (((VstWindow*)pVstWindow)->title, inTitle); ((VstWindow*)pVstWindow)->xPos = (short)size.left; ((VstWindow*)pVstWindow)->yPos = (short)size.top; ((VstWindow*)pVstWindow)->width = (short)size.width (); ((VstWindow*)pVstWindow)->height = (short)size.height (); ((VstWindow*)pVstWindow)->style = inStyle; ((VstWindow*)pVstWindow)->parent = 0; ((VstWindow*)pVstWindow)->userHandle = 0; ((VstWindow*)pVstWindow)->winHandle = 0; #endif } //----------------------------------------------------------------------------- CFrame::~CFrame () { if (pModalView) removeView (pModalView, false); setCursor (kCursorDefault); setDropActive (false); if (pFrameContext) pFrameContext->forget (); #if WINDOWS OleUninitialize (); if (backBuffer) backBuffer->forget (); #if DYNAMICALPHABLEND if (hInstMsimg32dll) FreeLibrary (hInstMsimg32dll); #endif if (pHwnd) { SetWindowLongPtr ((HWND)pHwnd, GWLP_USERDATA, (long)NULL); DestroyWindow ((HWND)pHwnd); ExitWindowClass (); } #elif MOTIF #if TEST_REGION XDestroyRegion (region); #endif // remove callbacks to avoid undesirable update if (pSystemWindow) { XtRemoveCallback ((Widget)pSystemWindow, XmNexposeCallback, _drawingAreaCallback, this); XtRemoveCallback ((Widget)pSystemWindow, XmNinputCallback, _drawingAreaCallback, this); XtRemoveCallback ((Widget)pSystemWindow, XmNdestroyCallback, _destroyCallback, this); freeGc (); } #endif if (bAddedWindow) close (); if (pVstWindow) free (pVstWindow); #if BEOS CBitmap::closeResource (); // must be done only once at the end of the story. #endif #if MAC && QUARTZ if (controlRef) DisposeControl (controlRef); if (controlSpec.u.classRef) { OSStatus status = UnregisterToolboxObjectClass ((ToolboxObjectClassRef)controlSpec.u.classRef); if (status != noErr) fprintf (stderr, "UnregisterToolboxObjectClass failed : %d\n", (int)status); } #endif } //----------------------------------------------------------------------------- bool CFrame::open (CPoint *point) { #if PLUGGUI return false; #else if (!bAddedWindow) return false; if (getOpenFlag ()) { #if WINDOWS BringWindowToTop (GetParent (GetParent ((HWND)getSystemWindow ()))); #elif MOTIF Widget widget = (Widget)getSystemWindow (); while (widget && !XtIsTopLevelShell (widget)) widget = XtParent (widget); if (widget) XRaiseWindow (getDisplay (), XtWindow (widget)); #elif BEOS pPlugView->Window ()->Activate (true); #endif return false; } #if USE_VST_WINDOW if (pVstWindow) { if (point) { ((VstWindow*)pVstWindow)->xPos = (short)point->h; ((VstWindow*)pVstWindow)->yPos = (short)point->v; } AudioEffectX *pAudioEffectX = (AudioEffectX*)(((AEffGUIEditor*)pEditor)->getEffect ()); pSystemWindow = pAudioEffectX->openWindow ((VstWindow*)pVstWindow); } #endif if (pSystemWindow) { if (initFrame (pSystemWindow)) setOpenFlag (true); } return getOpenFlag (); #endif } //----------------------------------------------------------------------------- bool CFrame::close () { #if PLUGGUI return false; #else if (!bAddedWindow || !getOpenFlag () || !pSystemWindow) return false; #if USE_VST_WINDOW AudioEffectX *pAudioEffectX = (AudioEffectX*)(((AEffGUIEditor*)pEditor)->getEffect ()); pAudioEffectX->closeWindow ((VstWindow*)pVstWindow); #endif pSystemWindow = 0; return true; #endif } //----------------------------------------------------------------------------- bool CFrame::initFrame (void *systemWin) { if (!systemWin) return false; #if WINDOWS InitWindowClass (); pHwnd = CreateWindowEx (0, gClassName, "Window", WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS, 0, 0, size.width (), size.height (), (HWND)pSystemWindow, NULL, GetInstance (), NULL); SetWindowLongPtr ((HWND)pHwnd, GWLP_USERDATA, (LONG_PTR)this); #elif MAC #if QUARTZ dragEventHandler = 0; if (!registerWithToolbox ()) return false; hasFocus = false; Rect r = {(short)size.top, (short)size.left, (short)size.bottom, (short)size.right}; OSStatus status = CreateCustomControl (NULL, &r, &controlSpec, NULL, &controlRef); if (status != noErr) { fprintf (stderr, "Could not create Control : %d\n", (int)status); return false; } EventTypeSpec keyWorkaroundEvents[] = { { kEventClassTextInput, kEventTextInputUnicodeForKeyEvent } }; InstallWindowEventHandler ((WindowRef)systemWin, carbonEventHandler, GetEventTypeCount (keyWorkaroundEvents), keyWorkaroundEvents, this, NULL); SetControlDragTrackingEnabled (controlRef, true); SetAutomaticControlDragTrackingEnabledForWindow ((WindowRef)systemWin, true); #if !AU // for AudioUnits define AU and embed the controlRef at your AUCarbonViewBase WindowAttributes attributes; GetWindowAttributes ((WindowRef)systemWin, &attributes); if (attributes & kWindowCompositingAttribute) { HIViewRef contentView; HIViewRef rootView = HIViewGetRoot ((WindowRef)systemWin); if (HIViewFindByID (rootView, kHIViewWindowContentID, &contentView) != noErr) contentView = rootView; HIViewAddSubview (contentView, controlRef); } else { ControlRef rootControl; GetRootControl ((WindowRef)systemWin, &rootControl); if (rootControl == NULL) CreateRootControl ((WindowRef)systemWin, &rootControl); EmbedControl(controlRef, rootControl); } #endif size.offset (-size.left, -size.top); mouseableArea.offset (-size.left, -size.top); #endif #elif MOTIF // attach the callbacks XtAddCallback ((Widget)systemWin, XmNexposeCallback, _drawingAreaCallback, this); XtAddCallback ((Widget)systemWin, XmNinputCallback, _drawingAreaCallback, this); XtAddCallback ((Widget)systemWin, XmNdestroyCallback, _destroyCallback, this); XtAddEventHandler ((Widget)systemWin, LeaveWindowMask, true, _eventHandler, this); // init a default gc window = XtWindow ((Widget)systemWin); pDisplay = XtDisplay ((Widget)systemWin); XGCValues values; values.foreground = 1; gc = XCreateGC (pDisplay, (Drawable)window, GCForeground, &values); #if TEST_REGION region = XCreateRegion (); #endif // get the std colormap XWindowAttributes attr; XGetWindowAttributes (pDisplay, window, &attr); colormap = attr.colormap; pVisual = attr.visual; depth = attr.depth; // init and load the fonts if (!gFontInit) { for (long i = 0; i < kNumStandardFonts; i++) { gFontStructs[i] = XLoadQueryFont (pDisplay, gFontTable[i].string); assert (gFontStructs[i] != 0); } gFontInit = true; } #elif BEOS BView* parentView = (BView*) pSystemWindow; BRect frame = parentView->Frame (); frame.OffsetTo (B_ORIGIN); pPlugView = new PlugView (frame, this); parentView->AddChild (pPlugView); #endif setDropActive (true); return true; } //----------------------------------------------------------------------------- bool CFrame::setDropActive (bool val) { if (!bDropActive && !val) return true; #if WINDOWS if (!pHwnd) return false; if (dropTarget) { RevokeDragDrop ((HWND)pHwnd); dropTarget = 0; } if (val) { dropTarget = createDropTarget (this); RegisterDragDrop ((HWND)pHwnd, (IDropTarget*)dropTarget); } #elif MAC #if MAC_OLD_DRAG if (val) install_drop (this); else remove_drop (this); #endif #endif bDropActive = val; return true; } #if MOTIF //----------------------------------------------------------------------------- void CFrame::freeGc () { if (gc) XFreeGC (pDisplay, gc); gc = 0; } #endif //----------------------------------------------------------------------------- CDrawContext* CFrame::createDrawContext () { if (pFrameContext) { pFrameContext->remember (); return pFrameContext; } CDrawContext* pContext = 0; #if WINDOWS || MAC pContext = new CDrawContext (this, NULL, getSystemWindow ()); #elif MOTIF pContext = new CDrawContext (this, gc, (void*)window); #elif BEOS pContext = new CDrawContext (this, pPlugView, 0); #endif return pContext; } //----------------------------------------------------------------------------- void CFrame::draw (CDrawContext *pContext) { if (bFirstDraw) bFirstDraw = false; if (!pContext) pContext = pFrameContext; // draw the background and the children CViewContainer::draw (pContext); } //----------------------------------------------------------------------------- void CFrame::drawRect (CDrawContext *pContext, const CRect& updateRect) { if (bFirstDraw) bFirstDraw = false; bool localContext = false; if (!pContext) { localContext = true; pContext = createDrawContext (); } #if USE_CLIPPING_DRAWRECT CRect oldClip; pContext->getClipRect (oldClip); CRect newClip (updateRect); newClip.bound (oldClip); pContext->setClipRect (newClip); #endif // draw the background and the children if (updateRect.getWidth () > 0 && updateRect.getHeight () > 0) CViewContainer::drawRect (pContext, updateRect); #if USE_CLIPPING_DRAWRECT pContext->setClipRect (oldClip); #endif if (localContext) pContext->forget (); } //----------------------------------------------------------------------------- void CFrame::draw (CView *pView) { CView *pViewToDraw = 0; // Search it in the view list if (pView && isChild(pView)) pViewToDraw = pView; CDrawContext *pContext = createDrawContext (); if (pContext) { if (pViewToDraw) pViewToDraw->draw (pContext); else draw (pContext); pContext->forget (); } } //----------------------------------------------------------------------------- void CFrame::mouse (CDrawContext *pContext, CPoint &where, long buttons) { if (!pContext) pContext = pFrameContext; if (pFocusView) setFocusView (NULL); if (buttons == -1 && pContext) buttons = pContext->getMouseButtons (); if (pModalView) { if (pModalView->hitTest (where, buttons)) pModalView->mouse (pContext, where, buttons); } else { CViewContainer::mouse (pContext, where, buttons); } } //----------------------------------------------------------------------------- long CFrame::onKeyDown (VstKeyCode& keyCode) { long result = -1; if (pFocusView) result = pFocusView->onKeyDown (keyCode); if (result == -1 && pModalView) result = pModalView->onKeyDown (keyCode); if (result == -1 && keyCode.virt == VKEY_TAB) result = advanceNextFocusView (pFocusView, (keyCode.modifier & MODIFIER_SHIFT) ? true : false) ? 1 : -1; return result; } //----------------------------------------------------------------------------- long CFrame::onKeyUp (VstKeyCode& keyCode) { long result = -1; if (pFocusView) result = pFocusView->onKeyUp (keyCode); if (result == -1 && pModalView) result = pModalView->onKeyUp (keyCode); return result; } //------------------------------------------------------------------------ bool CFrame::onWheel (CDrawContext *pContext, const CPoint &where, const CMouseWheelAxis axis, float distance) { bool result = false; CView *view = pModalView ? pModalView : getViewAt (where); if (view) { bool localContext = false; if (!pContext) { localContext = true; pContext = createDrawContext (); } result = view->onWheel (pContext, where, axis, distance); if (localContext) pContext->forget (); #if BEOS pPlugView->UnlockLooper (); #endif } return result; } //----------------------------------------------------------------------------- bool CFrame::onWheel (CDrawContext *pContext, const CPoint &where, float distance) { return onWheel (pContext, where, kMouseWheelAxisY, distance); } //----------------------------------------------------------------------------- void CFrame::update (CDrawContext *pContext) { if (!getOpenFlag () || updatesDisabled ()) return; #if WINDOWS && USE_ALPHA_BLEND CDrawContext* oldFrameContext = pFrameContext; CDrawContext* dc = pFrameContext = getBackBuffer (); #else CDrawContext* dc = pContext; #endif if (bDirty) { draw (dc); setDirty (false); } else { #if USE_CLIPPING_DRAWRECT CRect oldClipRect; dc->getClipRect (oldClipRect); #endif #if NEW_UPDATE_MECHANISM if (pModalView && pModalView->isDirty ()) pModalView->update (dc); #endif FOREACHSUBVIEW #if USE_CLIPPING_DRAWRECT CRect viewSize (pV->size); viewSize.bound (oldClipRect); dc->setClipRect (viewSize); #endif pV->update (dc); ENDFOR #if USE_CLIPPING_DRAWRECT dc->setClipRect (oldClipRect); #endif } #if MACX && !QUARTZ if (QDIsPortBufferDirty (GetWindowPort ((WindowRef)pSystemWindow))) { QDFlushPortBuffer (GetWindowPort ((WindowRef)pSystemWindow), NULL); } #endif #if WINDOWS && USE_ALPHA_BLEND backBuffer->copyFrom (pContext, size); pFrameContext = oldFrameContext; #endif } //----------------------------------------------------------------------------- void CFrame::idle () { if (!getOpenFlag ()) return; #if MAC // if the window is collapsed, we don't need to draw anything if (pSystemWindow && IsWindowCollapsed ((WindowRef)pSystemWindow)) return; #endif // don't do an idle before a draw if (bFirstDraw) return; if (!isDirty ()) return; #if BEOS if (pPlugView->LockLooperWithTimeout (0) != B_OK) return; #endif CDrawContext *pContext = createDrawContext (); update (pContext); pContext->forget (); #if BEOS pPlugView->UnlockLooper (); #endif } //----------------------------------------------------------------------------- void CFrame::doIdleStuff () { #if PLUGGUI if (pEditor) ((PluginGUIEditor*)pEditor)->doIdleStuff (); #else if (pEditor) ((AEffGUIEditor*)pEditor)->doIdleStuff (); #endif #if (MAC && QUARTZ) if (pFrameContext) pFrameContext->synchronizeCGContext (); #endif } //----------------------------------------------------------------------------- unsigned long CFrame::getTicks () const { #if PLUGGUI if (pEditor) return ((PluginGUIEditor*)pEditor)->getTicks (); #else if (pEditor) return ((AEffGUIEditor*)pEditor)->getTicks (); #endif return 0; } //----------------------------------------------------------------------------- long CFrame::getKnobMode () const { #if PLUGGUI return PluginGUIEditor::getKnobMode (); #else return AEffGUIEditor::getKnobMode (); #endif } //----------------------------------------------------------------------------- #if WINDOWS COffscreenContext* CFrame::getBackBuffer () { #if WINDOWS && USE_ALPHA_BLEND if (!backBuffer) backBuffer = new COffscreenContext (this, size.width (), size.height ()); #endif return backBuffer; } HWND CFrame::getOuterWindow () const { int diffWidth, diffHeight; RECT rctTempWnd, rctPluginWnd; HWND hTempWnd = (HWND)pHwnd; GetWindowRect (hTempWnd, &rctPluginWnd); while (hTempWnd != NULL) { // Looking for caption bar if (GetWindowLong (hTempWnd, GWL_STYLE) & WS_CAPTION) return hTempWnd; // Looking for last parent if (!GetParent (hTempWnd)) return hTempWnd; // get difference between plugin-window and current parent GetWindowRect (GetParent (hTempWnd), &rctTempWnd); diffWidth = (rctTempWnd.right - rctTempWnd.left) - (rctPluginWnd.right - rctPluginWnd.left); diffHeight = (rctTempWnd.bottom - rctTempWnd.top) - (rctPluginWnd.bottom - rctPluginWnd.top); // Looking for size mismatch if ((abs (diffWidth) > 60) || (abs (diffHeight) > 60)) // parent belongs to host return (hTempWnd); if (diffWidth < 0) diffWidth = 0; if (diffHeight < 0) diffHeight = 0; // get the next parent window hTempWnd = GetParent (hTempWnd); } return NULL; } #endif //----------------------------------------------------------------------------- bool CFrame::setPosition (CCoord x, CCoord y) { if (!getOpenFlag ()) return false; #if MAC #if QUARTZ if (controlRef) { HIRect r; if (HIViewGetFrame (controlRef, &r) != noErr) return false; if (HIViewMoveBy (controlRef, x - r.origin.x, y - r.origin.y) != noErr) return false; return true; } #else return false; #endif #elif WINDOWS // not implemented yet #else // not implemented yet #endif return false; } //----------------------------------------------------------------------------- bool CFrame::getPosition (CCoord &x, CCoord &y) const { if (!getOpenFlag ()) return false; // get the position of the Window including this frame in the main pWindow #if WINDOWS HWND wnd = (HWND)getOuterWindow (); HWND wndParent = GetParent (wnd); RECT rctTempWnd; GetWindowRect (wnd, &rctTempWnd); POINT point; point.x = rctTempWnd.left; point.y = rctTempWnd.top; MapWindowPoints (HWND_DESKTOP, wndParent, &point, 1); x = point.x; y = point.y; #elif MAC Rect bounds; GetWindowBounds ((WindowRef)pSystemWindow, kWindowContentRgn, &bounds); x = bounds.left; y = bounds.top; #if QUARTZ WindowAttributes attr; GetWindowAttributes ((WindowRef)pSystemWindow, &attr); if (attr & kWindowCompositingAttribute) { /* HIPoint hip = { 0.f, 0.f }; HIViewRef contentView; HIViewFindByID (HIViewGetRoot ((WindowRef)pSystemWindow), kHIViewWindowContentID, &contentView); if (HIViewGetSuperview ((HIViewRef)controlRef) != contentView) HIViewConvertPoint (&hip, controlRef, contentView); x += hip.x; y += hip.y;*/ } else { HIRect hirect; HIViewGetFrame ((HIViewRef)controlRef, &hirect); x += (CCoord)hirect.origin.x; y += (CCoord)hirect.origin.y; } x -= hiScrollOffset.x; y -= hiScrollOffset.y; #endif #elif MOTIF Position xWin, yWin; // get the topLevelShell of the pSystemWindow Widget parent = (Widget)getSystemWindow (); Widget parentOld = parent; while (parent != 0 && !XtIsTopLevelShell (parent)) { parentOld = parent; parent = XtParent (parent); } if (parent == 0) parent = parentOld; if (parent) { XtVaGetValues (parent, XtNx, &xWin, XtNy, &yWin, NULL); x = xWin - 8; y = yWin - 30; } #elif BEOS BRect frame = pPlugView->Window ()->Frame (); x = (long) frame.left; y = (long) frame.top; #endif return true; } //----------------------------------------------------------------------------- void CFrame::setViewSize (CRect& inRect) { setSize (inRect.width (), inRect.height ()); } //----------------------------------------------------------------------------- bool CFrame::setSize (CCoord width, CCoord height) { if (!getOpenFlag ()) return false; if ((width == size.width ()) && (height == size.height ())) return false; #if WINDOWS if (backBuffer) backBuffer->forget (); backBuffer = 0; #endif #if !PLUGGUI if (pEditor) { AudioEffectX* effect = (AudioEffectX*)((AEffGUIEditor*)pEditor)->getEffect (); if (effect && effect->canHostDo ("sizeWindow")) { if (effect->sizeWindow ((long)width, (long)height)) { size.right = size.left + width; size.bottom = size.top + height; #if WINDOWS SetWindowPos ((HWND)pHwnd, HWND_TOP, 0, 0, width, height, SWP_NOMOVE); #elif (MAC && QUARTZ) Rect bounds; CRect2Rect (size, bounds); SetControlBounds (controlRef, &bounds); #endif return true; } } } #endif // keep old values CCoord oldWidth = size.width (); CCoord oldHeight = size.height (); // set the new size size.right = size.left + width; size.bottom = size.top + height; #if WINDOWS RECT rctTempWnd, rctParentWnd; HWND hTempWnd; long iFrame = (2 * GetSystemMetrics (SM_CYFIXEDFRAME)); long diffWidth = 0; long diffHeight = 0; hTempWnd = (HWND)pHwnd; while ((diffWidth != iFrame) && (hTempWnd != NULL)) // look for FrameWindow { HWND hTempParentWnd = GetParent (hTempWnd); char buffer[1024]; GetClassName (hTempParentWnd, buffer, 1024); if (!hTempParentWnd || !strcmp (buffer, "MDIClient")) break; GetWindowRect (hTempWnd, &rctTempWnd); GetWindowRect (hTempParentWnd, &rctParentWnd); SetWindowPos (hTempWnd, HWND_TOP, 0, 0, width + diffWidth, height + diffHeight, SWP_NOMOVE); diffWidth += (rctParentWnd.right - rctParentWnd.left) - (rctTempWnd.right - rctTempWnd.left); diffHeight += (rctParentWnd.bottom - rctParentWnd.top) - (rctTempWnd.bottom - rctTempWnd.top); if ((diffWidth > 80) || (diffHeight > 80)) // parent belongs to host return true; if (diffWidth < 0) diffWidth = 0; if (diffHeight < 0) diffHeight = 0; hTempWnd = hTempParentWnd; } if (hTempWnd) SetWindowPos (hTempWnd, HWND_TOP, 0, 0, width + diffWidth, height + diffHeight, SWP_NOMOVE); #elif MAC #if QUARTZ if (getSystemWindow ()) { WindowAttributes windowAttributes; GetWindowAttributes ((WindowRef)getSystemWindow (), &windowAttributes); if (!(windowAttributes & kWindowCompositingAttribute)) { Rect bounds; GetPortBounds (GetWindowPort ((WindowRef)getSystemWindow ()), &bounds); SizeWindow ((WindowRef)getSystemWindow (), (short)((bounds.right - bounds.left) - oldWidth + width), (short)((bounds.bottom - bounds.top) - oldHeight + height), true); } } if (controlRef) { HIRect frameRect; HIViewGetFrame (controlRef, &frameRect); frameRect.size.width = width; frameRect.size.height = height; HIViewSetFrame (controlRef, &frameRect); } #else if (getSystemWindow ()) { Rect bounds; GetPortBounds (GetWindowPort ((WindowRef)getSystemWindow ()), &bounds); SizeWindow ((WindowRef)getSystemWindow (), (bounds.right - bounds.left) - oldWidth + width, (bounds.bottom - bounds.top) - oldHeight + height, true); #if MACX && !QUARTZ SetPort (GetWindowPort ((WindowRef)getSystemWindow ())); #endif #if QUARTZ CRect2Rect (size, bounds); SetControlBounds (controlRef, &bounds); #endif } #endif #elif MOTIF Dimension heightWin, widthWin; // get the topLevelShell of the pSystemWindow Widget parent = (Widget)getSystemWindow (); Widget parentOld = parent; while (parent != 0 && !XtIsTopLevelShell (parent)) { parentOld = parent; parent = XtParent (parent); } if (parent == 0) parent = parentOld; if (parent) { XtVaGetValues (parent, XtNwidth, &widthWin, XtNheight, &heightWin, NULL); long diffWidth = widthWin - oldWidth; long diffHeight = heightWin - oldHeight; XtVaSetValues (parent, XmNwidth, width + diffWidth, XmNheight, height + diffHeight, NULL); } #elif BEOS BView* parent = pPlugView->Parent (); parent->SetResizingMode (B_FOLLOW_ALL_SIDES); BRect frame = pPlugView->Frame (); pPlugView->Window ()->ResizeBy (width - frame.Width () - 1, height - frame.Height () - 1); parent->SetResizingMode (B_FOLLOW_NONE); #endif CRect myViewSize (0, 0, size.width (), size.height ()); CViewContainer::setViewSize (myViewSize); return true; } //----------------------------------------------------------------------------- bool CFrame::getSize (CRect *pRect) const { if (!getOpenFlag ()) return false; #if WINDOWS // return the size relative to the client rect of this window // get the main window HWND wnd = GetParent ((HWND)getSystemWindow ()); HWND wndParent = GetParent (wnd); HWND wndParentParent = GetParent (wndParent); RECT rctTempWnd; GetWindowRect (wnd, &rctTempWnd); POINT point; point.x = rctTempWnd.left; point.y = rctTempWnd.top; MapWindowPoints (HWND_DESKTOP, wndParentParent, &point, 1); pRect->left = point.x; pRect->top = point.y; pRect->right = pRect->left + rctTempWnd.right - rctTempWnd.left; pRect->bottom = pRect->top + rctTempWnd.bottom - rctTempWnd.top; #elif MAC #if QUARTZ HIRect hiRect; if (HIViewGetFrame (controlRef, &hiRect) == noErr) { pRect->left = (CCoord)hiRect.origin.x; pRect->top = (CCoord)hiRect.origin.y; pRect->setWidth ((CCoord)hiRect.size.width); pRect->setHeight ((CCoord)hiRect.size.height); return true; } #endif Rect bounds; GetPortBounds (GetWindowPort ((WindowRef)getSystemWindow ()), &bounds); pRect->left = bounds.left; pRect->top = bounds.top; pRect->right = bounds.right; pRect->bottom = bounds.bottom; #elif MOTIF Dimension height, width; XtVaGetValues ((Widget)getSystemWindow (), XtNwidth, &width, XtNheight, &height, NULL); Position x, y; Position xTotal = 0, yTotal = 0; Widget parent = (Widget)getSystemWindow (); while (parent != 0 && !XtIsTopLevelShell (parent) && !XmIsDialogShell (parent)) { XtVaGetValues (parent, XtNx, &x, XtNy, &y, NULL); xTotal += x; yTotal += y; parent = XtParent (parent); } pRect->left = xTotal; pRect->top = yTotal; pRect->right = width + pRect->left; pRect->bottom = height + pRect->top; #elif BEOS BRect v = pPlugView->Frame (); (*pRect) (v.left, v.top, v.right + 1, v.bottom + 1); #endif return true; } //----------------------------------------------------------------------------- bool CFrame::getSize (CRect& outSize) const { return getSize (&outSize); } //----------------------------------------------------------------------------- long CFrame::setModalView (CView *pView) { // There's already a modal view so we get out if (pView && pModalView) return 0; if (pModalView) removeView (pModalView, false); pModalView = pView; if (pModalView) addView (pModalView); return 1; } //----------------------------------------------------------------------------- void CFrame::beginEdit (long index) { #if PLUGGUI #if AU if (pEditor) ((PluginGUIEditor*)pEditor)->beginEdit (index); #endif #else if (pEditor) ((AEffGUIEditor*)pEditor)->beginEdit (index); #endif } //----------------------------------------------------------------------------- void CFrame::endEdit (long index) { #if PLUGGUI #if AU if (pEditor) ((PluginGUIEditor*)pEditor)->endEdit (index); #endif #else if (pEditor) ((AEffGUIEditor*)pEditor)->endEdit (index); #endif } //----------------------------------------------------------------------------- CView *CFrame::getCurrentView () const { if (pModalView) return pModalView; return CViewContainer::getCurrentView (); } //----------------------------------------------------------------------------- bool CFrame::getCurrentLocation (CPoint &where) { #if WINDOWS HWND hwnd = (HWND)this->getSystemWindow (); POINT _where; GetCursorPos (&_where); where (_where.x, _where.y); if (hwnd) { RECT rctTempWnd; GetWindowRect (hwnd, &rctTempWnd); where.offset (-rctTempWnd.left, -rctTempWnd.top); } return true; #endif // create a local context CDrawContext *pContext = createDrawContext (); if (pContext) { // get the current position pContext->getMouseLocation (where); pContext->forget (); } return true; } #if MACX #define kThemeResizeUpDownCursor 21 #define kThemeNotAllowedCursor 18 #endif //----------------------------------------------------------------------------- void CFrame::setCursor (CCursorType type) { #if WINDOWS if (!defaultCursor) defaultCursor = GetCursor (); switch (type) { case kCursorWait: SetCursor (LoadCursor (0, IDC_WAIT)); break; case kCursorHSize: SetCursor (LoadCursor (0, IDC_SIZEWE)); break; case kCursorVSize: SetCursor (LoadCursor (0, IDC_SIZENS)); break; case kCursorNESWSize: SetCursor (LoadCursor (0, IDC_SIZENESW)); break; case kCursorNWSESize: SetCursor (LoadCursor (0, IDC_SIZENWSE)); break; case kCursorSizeAll: SetCursor (LoadCursor (0, IDC_SIZEALL)); break; case kCursorNotAllowed: SetCursor (LoadCursor (0, IDC_NO)); break; case kCursorHand: SetCursor (LoadCursor (0, IDC_HAND)); break; default: SetCursor ((HCURSOR)defaultCursor); break; } #elif MAC #if MACX switch (type) { case kCursorWait: SetThemeCursor (kThemeWatchCursor); break; case kCursorHSize: SetThemeCursor (pSystemVersion < 0x1030 ? kThemeCrossCursor : kThemeResizeLeftRightCursor); break; case kCursorVSize: SetThemeCursor (pSystemVersion < 0x1030 ? kThemeCrossCursor : kThemeResizeUpDownCursor); break; case kCursorNESWSize: SetThemeCursor (kThemeCrossCursor); break; case kCursorNWSESize: SetThemeCursor (kThemeCrossCursor); break; case kCursorSizeAll: SetThemeCursor (kThemeCrossCursor); break; case kCursorCopy: SetThemeCursor (kThemeCopyArrowCursor); break; case kCursorNotAllowed: SetThemeCursor (pSystemVersion < 0x1020 ? kThemeArrowCursor : kThemeNotAllowedCursor); break; case kCursorHand: SetThemeCursor (kThemeOpenHandCursor); break; default: SetThemeCursor (kThemeArrowCursor); break; } #else //if (!defaultCursor) // defaultCursor = GetCursor (0); switch (type) { case kCursorWait: SetCursor (*GetCursor (watchCursor)); break; case kCursorHSize: SetCursor (*GetCursor (crossCursor)); break; case kCursorVSize: SetCursor (*GetCursor (crossCursor)); break; case kCursorNESWSize: SetCursor (*GetCursor (crossCursor)); break; case kCursorNWSESize: SetCursor (*GetCursor (crossCursor)); break; case kCursorSizeAll: SetCursor (*GetCursor (plusCursor)); break; default: InitCursor (); break; } #endif #endif } //----------------------------------------------------------------------------- void CFrame::setFocusView (CView *pView) { CView *pOldFocusView = pFocusView; pFocusView = pView; if (pFocusView && pFocusView->wantsFocus ()) pFocusView->setDirty (); if (pOldFocusView) { pOldFocusView->looseFocus (); if (pOldFocusView->wantsFocus ()) pOldFocusView->setDirty (); } } //----------------------------------------------------------------------------- bool CFrame::advanceNextFocusView (CView* oldFocus, bool reverse) { if (pModalView) return false; // currently not supported, but should be done sometime if (oldFocus == 0) { if (pFocusView == 0) return CViewContainer::advanceNextFocusView (0, reverse); oldFocus = pFocusView; } if (isChild (oldFocus)) { if (CViewContainer::advanceNextFocusView (oldFocus, reverse)) return true; else { setFocusView (NULL); return false; } } CView* parentView = oldFocus->getParentView (); if (parentView && parentView->isTypeOf ("CViewContainer")) { CView* tempOldFocus = oldFocus; CViewContainer* vc = (CViewContainer*)parentView; while (vc) { if (vc->advanceNextFocusView (tempOldFocus, reverse)) return true; else { tempOldFocus = vc; if (vc->getParentView () && vc->getParentView ()->isTypeOf ("CViewContainer")) vc = (CViewContainer*)vc->getParentView (); else vc = 0; } } } return CViewContainer::advanceNextFocusView (oldFocus, reverse); } //----------------------------------------------------------------------------- void CFrame::invalidate (const CRect &rect) { CRect rectView; FOREACHSUBVIEW if (pV) { pV->getViewSize (rectView); if (rect.rectOverlap (rectView)) pV->setDirty (true); } ENDFOR } #if DEBUG //----------------------------------------------------------------------------- void CFrame::dumpHierarchy () { dumpInfo (); DebugPrint ("\n"); CViewContainer::dumpHierarchy (); } #endif //----------------------------------------------------------------------------- // CCView Implementation //----------------------------------------------------------------------------- CCView::CCView (CView *pView) : pView (pView), pNext (0), pPrevious (0) { if (pView) pView->remember (); } //----------------------------------------------------------------------------- CCView::~CCView () { if (pView) pView->forget (); } //----------------------------------------------------------------------------- // CViewContainer Implementation //----------------------------------------------------------------------------- /** * CViewContainer constructor. * @param rect the size of the container * @param pParent the parent CFrame * @param pBackground the background bitmap, can be NULL */ CViewContainer::CViewContainer (const CRect &rect, CFrame *pParent, CBitmap *pBackground) : CView (rect), pFirstView (0), pLastView (0), mode (kNormalUpdate), pOffscreenContext (0), bDrawInOffscreen (true), currentDragView (0) { #if MACX || USE_ALPHA_BLEND bDrawInOffscreen = false; #endif backgroundOffset (0, 0); this->pParentFrame = pParent; setBackground (pBackground); backgroundColor = kBlackCColor; #if NEW_UPDATE_MECHANISM mode = kOnlyDirtyUpdate; #endif } //----------------------------------------------------------------------------- CViewContainer::~CViewContainer () { // remove all views removeAll (true); #if !BEOS if (pOffscreenContext) pOffscreenContext->forget (); pOffscreenContext = 0; #endif } //----------------------------------------------------------------------------- /** * @param rect the new size of the container */ void CViewContainer::setViewSize (CRect &rect) { CView::setViewSize (rect); #if !BEOS if (pOffscreenContext && bDrawInOffscreen) { pOffscreenContext->forget (); pOffscreenContext = new COffscreenContext (pParentFrame, (long)size.width (), (long)size.height (), kBlackCColor); } #endif } //----------------------------------------------------------------------------- /** * @param color the new background color of the container */ void CViewContainer::setBackgroundColor (CColor color) { backgroundColor = color; setDirty (true); } //------------------------------------------------------------------------------ long CViewContainer::notify (CView* sender, const char* message) { if (message == kMsgCheckIfViewContainer) return kMessageNotified; return kMessageUnknown; } //----------------------------------------------------------------------------- /** * @param pView the view object to add to this container */ void CViewContainer::addView (CView *pView) { if (!pView) return; CCView *pSv = new CCView (pView); pView->pParentFrame = pParentFrame; pView->pParentView = this; CCView *pV = pFirstView; if (!pV) { pLastView = pFirstView = pSv; } else { while (pV->pNext) pV = pV->pNext; pV->pNext = pSv; pSv->pPrevious = pV; pLastView = pSv; } pView->attached (this); pView->setDirty (); } //----------------------------------------------------------------------------- /** * @param pView the view object to add to this container * @param mouseableArea the view area in where the view will get mouse events * @param mouseEnabled bool to set if view will get mouse events */ void CViewContainer::addView (CView *pView, CRect &mouseableArea, bool mouseEnabled) { if (!pView) return; pView->setMouseEnabled (mouseEnabled); pView->setMouseableArea (mouseableArea); addView (pView); } //----------------------------------------------------------------------------- /** * @param withForget bool to indicate if the view's reference counter should be decreased after removed from the container */ void CViewContainer::removeAll (const bool &withForget) { CCView *pV = pFirstView; while (pV) { CCView *pNext = pV->pNext; if (pV->pView) { pV->pView->removed (this); if (withForget) pV->pView->forget (); } delete pV; pV = pNext; } pFirstView = 0; pLastView = 0; } //----------------------------------------------------------------------------- /** * @param pView the view which should be removed from the container * @param withForget bool to indicate if the view's reference counter should be decreased after removed from the container */ void CViewContainer::removeView (CView *pView, const bool &withForget) { if (pParentFrame && pParentFrame->getFocusView () == pView) pParentFrame->setFocusView (0); CCView *pV = pFirstView; while (pV) { if (pView == pV->pView) { CCView *pNext = pV->pNext; CCView *pPrevious = pV->pPrevious; if (pV->pView) { pV->pView->removed (this); if (withForget) pV->pView->forget (); } delete pV; if (pPrevious) { pPrevious->pNext = pNext; if (pNext) pNext->pPrevious = pPrevious; else pLastView = pPrevious; } else { pFirstView = pNext; if (pNext) pNext->pPrevious = 0; else pLastView = 0; } break; } else pV = pV->pNext; } } //----------------------------------------------------------------------------- /** * @param pView the view which should be checked if it is a child of this container */ bool CViewContainer::isChild (CView *pView) const { bool found = false; CCView *pV = pFirstView; while (pV) { if (pView == pV->pView) { found = true; break; } pV = pV->pNext; } return found; } //----------------------------------------------------------------------------- long CViewContainer::getNbViews () const { long nb = 0; CCView *pV = pFirstView; while (pV) { pV = pV->pNext; nb++; } return nb; } //----------------------------------------------------------------------------- /** * @param index the index of the view to return */ CView *CViewContainer::getView (long index) const { long nb = 0; CCView *pV = pFirstView; while (pV) { if (nb == index) return pV->pView; pV = pV->pNext; nb++; } return 0; } //----------------------------------------------------------------------------- /** * @param pContext the context which to use to draw this container and its subviews */ void CViewContainer::draw (CDrawContext *pContext) { CDrawContext *pC; CCoord save[4]; #if BEOS // create offscreen if (pBackground) pC = new COffscreenContext (pContext, pBackground); else pC = new COffscreenContext (pParentFrame, size.width (), size.height (), backgroundColor); #else if (!pOffscreenContext && bDrawInOffscreen) pOffscreenContext = new COffscreenContext (pParentFrame, (long)size.width (), (long)size.height (), kBlackCColor); #if USE_ALPHA_BLEND if (pOffscreenContext && bTransparencyEnabled) pOffscreenContext->copyTo (pContext, size); #endif if (bDrawInOffscreen) pC = pOffscreenContext; else { pC = pContext; modifyDrawContext (save, pContext); } CRect r (0, 0, size.width (), size.height ()); #if USE_CLIPPING_DRAWRECT CRect oldClip; pContext->getClipRect (oldClip); CRect oldClip2 (oldClip); if (bDrawInOffscreen && getFrame () != this) oldClip.offset (-oldClip.left, -oldClip.top); CRect newClip (r); newClip.bound (oldClip); pC->setClipRect (newClip); #endif // draw the background if (pBackground) { if (bTransparencyEnabled) pBackground->drawTransparent (pC, r, backgroundOffset); else pBackground->draw (pC, r, backgroundOffset); } else if (!bTransparencyEnabled) { pC->setFillColor (backgroundColor); pC->fillRect (r); } #endif // draw each view FOREACHSUBVIEW #if USE_CLIPPING_DRAWRECT CRect vSize (pV->size); vSize.bound (oldClip); pC->setClipRect (vSize); #endif pV->draw (pC); ENDFOR #if USE_CLIPPING_DRAWRECT pC->setClipRect (oldClip2); #endif // transfert offscreen if (bDrawInOffscreen) ((COffscreenContext*)pC)->copyFrom (pContext, size); else restoreDrawContext (pContext, save); #if BEOS delete pC; #endif setDirty (false); } //----------------------------------------------------------------------------- /** * @param pContext the context which to use to draw the background * @param _updateRect the area which to draw */ void CViewContainer::drawBackgroundRect (CDrawContext *pContext, CRect& _updateRect) { if (pBackground) { CRect oldClip; pContext->getClipRect (oldClip); CRect newClip (_updateRect); newClip.bound (oldClip); pContext->setClipRect (newClip); CRect tr (0, 0, pBackground->getWidth (), pBackground->getHeight ()); if (bTransparencyEnabled) pBackground->drawTransparent (pContext, tr, backgroundOffset); else pBackground->draw (pContext, tr, backgroundOffset); pContext->setClipRect (oldClip); } else if (!bTransparencyEnabled) { pContext->setFillColor (backgroundColor); pContext->fillRect (_updateRect); } } //----------------------------------------------------------------------------- /** * @param pContext the context which to use to draw * @param _updateRect the area which to draw */ void CViewContainer::drawRect (CDrawContext *pContext, const CRect& _updateRect) { CDrawContext *pC; CCoord save[4]; #if BEOS // create offscreen if (pBackground) pC = new COffscreenContext (pContext, pBackground); else pC = new COffscreenContext (pParentFrame, size.width (), size.height (), backgroundColor); #else if (!pOffscreenContext && bDrawInOffscreen) pOffscreenContext = new COffscreenContext (pParentFrame, (long)size.width (), (long)size.height (), kBlackCColor); #if USE_ALPHA_BLEND if (pOffscreenContext && bTransparencyEnabled) pOffscreenContext->copyTo (pContext, size); #endif if (bDrawInOffscreen) pC = pOffscreenContext; else { pC = pContext; modifyDrawContext (save, pContext); } CRect updateRect (_updateRect); updateRect.bound (size); CRect clientRect (updateRect); clientRect.offset (-size.left, -size.top); #if USE_CLIPPING_DRAWRECT CRect oldClip; pContext->getClipRect (oldClip); CRect oldClip2 (oldClip); if (bDrawInOffscreen && getFrame () != this) oldClip.offset (-oldClip.left, -oldClip.top); CRect newClip (clientRect); newClip.bound (oldClip); pC->setClipRect (newClip); #endif // draw the background drawBackgroundRect (pC, clientRect); #endif // draw each view FOREACHSUBVIEW if (pV->checkUpdate (clientRect)) { #if USE_CLIPPING_DRAWRECT CRect viewSize (pV->size); viewSize.bound (newClip); if (viewSize.getWidth () == 0 || viewSize.getHeight () == 0) continue; pC->setClipRect (viewSize); #endif bool wasDirty = pV->isDirty (); pV->drawRect (pC, clientRect); #if DEBUG_FOCUS_DRAWING if (getFrame ()->getFocusView() == pV && pV->wantsFocus ()) { pC->setDrawMode (kCopyMode); pC->setFrameColor (kRedCColor); pC->drawRect (pV->size); } #endif if (wasDirty && pV->size != viewSize && !isTypeOf ("CScrollContainer")) { pV->setDirty (true); } } ENDFOR #if USE_CLIPPING_DRAWRECT pC->setClipRect (oldClip2); #endif // transfer offscreen if (bDrawInOffscreen) ((COffscreenContext*)pC)->copyFrom (pContext, updateRect, CPoint (clientRect.left, clientRect.top)); else restoreDrawContext (pContext, save); #if BEOS delete pC; #endif #if EVENT_DRAW_FIX if (bDirty && newClip == size) #endif setDirty (false); } //----------------------------------------------------------------------------- /** * @param context the context which to use to redraw this container * @param rect the area which to redraw */ void CViewContainer::redrawRect (CDrawContext* context, const CRect& rect) { CRect _rect (rect); _rect.offset (size.left, size.top); if (bTransparencyEnabled) { // as this is transparent, we call the parentview to redraw this area. if (pParentView) pParentView->redrawRect (context, _rect); else if (pParentFrame) pParentFrame->drawRect (context, _rect); } else { CCoord save[4]; if (pParentView) { CPoint off; pParentView->localToFrame (off); // store save[0] = context->offsetScreen.h; save[1] = context->offsetScreen.v; save[2] = context->offset.h; save[3] = context->offset.v; context->offsetScreen.h += off.x; context->offsetScreen.v += off.y; context->offset.h += off.x; context->offset.v += off.y; } drawRect (context, _rect); if (pParentView) { // restore context->offsetScreen.h = save[0]; context->offsetScreen.v = save[1]; context->offset.h = save[2]; context->offset.v = save[3]; } } } //----------------------------------------------------------------------------- bool CViewContainer::hitTestSubViews (const CPoint& where, const long buttons) { CPoint where2 (where); where2.offset (-size.left, -size.top); CCView *pSv = pLastView; while (pSv) { CView *pV = pSv->pView; if (pV && pV->getMouseEnabled () && pV->hitTest (where2, buttons)) return true; pSv = pSv->pPrevious; } return false; } //----------------------------------------------------------------------------- bool CViewContainer::hitTest (const CPoint& where, const long buttons) { //return hitTestSubViews (where); would change default behavior return CView::hitTest (where, buttons); } //----------------------------------------------------------------------------- void CViewContainer::mouse (CDrawContext *pContext, CPoint &where, long buttons) { // convert to relativ pos CPoint where2 (where); where2.offset (-size.left, -size.top); if (buttons == -1 && pContext) buttons = pContext->getMouseButtons (); CCView *pSv = pLastView; while (pSv) { CView *pV = pSv->pView; if (pV && pV->getMouseEnabled () && pV->hitTest (where2, buttons)) { pV->mouse (pContext, where2, buttons); break; } pSv = pSv->pPrevious; } } //----------------------------------------------------------------------------- long CViewContainer::onKeyDown (VstKeyCode& keyCode) { long result = -1; CCView* pSv = pLastView; while (pSv) { long result = pSv->pView->onKeyDown (keyCode); if (result != -1) break; pSv = pSv->pPrevious; } return result; } //----------------------------------------------------------------------------- long CViewContainer::onKeyUp (VstKeyCode& keyCode) { long result = -1; CCView* pSv = pLastView; while (pSv) { long result = pSv->pView->onKeyUp (keyCode); if (result != -1) break; pSv = pSv->pPrevious; } return result; } //----------------------------------------------------------------------------- bool CViewContainer::onWheel (CDrawContext *pContext, const CPoint &where, const CMouseWheelAxis axis, float distance) { bool result = false; CView *view = getViewAt (where); if (view) { // convert to relativ pos CPoint where2 (where); where2.offset (-size.left, -size.top); CCoord save[4]; modifyDrawContext (save, pContext); result = view->onWheel (pContext, where2, axis, distance); restoreDrawContext (pContext, save); } return result; } //----------------------------------------------------------------------------- bool CViewContainer::onWheel (CDrawContext *pContext, const CPoint &where, float distance) { return onWheel (pContext, where, kMouseWheelAxisY, distance); } //----------------------------------------------------------------------------- bool CViewContainer::onDrop (CDrawContext* context, CDragContainer* drag, const CPoint& where) { if (!pParentFrame) return false; bool result = false; CCoord save[4]; modifyDrawContext (save, context); // convert to relativ pos CPoint where2 (where); where2.offset (-size.left, -size.top); CView* view = getViewAt (where); if (view != currentDragView) { if (currentDragView) currentDragView->onDragLeave (context, drag, where2); currentDragView = view; } if (currentDragView) { result = currentDragView->onDrop (context, drag, where2); currentDragView->onDragLeave (context, drag, where2); } currentDragView = 0; restoreDrawContext (context, save); return result; } //----------------------------------------------------------------------------- void CViewContainer::onDragEnter (CDrawContext* context, CDragContainer* drag, const CPoint& where) { if (!pParentFrame) return; CCoord save[4]; modifyDrawContext (save, context); // convert to relativ pos CPoint where2 (where); where2.offset (-size.left, -size.top); if (currentDragView) currentDragView->onDragLeave (context, drag, where2); CView* view = getViewAt (where); currentDragView = view; if (view) view->onDragEnter (context, drag, where2); restoreDrawContext (context, save); } //----------------------------------------------------------------------------- void CViewContainer::onDragLeave (CDrawContext* context, CDragContainer* drag, const CPoint& where) { if (!pParentFrame) return; CCoord save[4]; modifyDrawContext (save, context); // convert to relativ pos CPoint where2 (where); where2.offset (-size.left, -size.top); if (currentDragView) currentDragView->onDragLeave (context, drag, where2); currentDragView = 0; restoreDrawContext (context, save); } //----------------------------------------------------------------------------- void CViewContainer::onDragMove (CDrawContext* context, CDragContainer* drag, const CPoint& where) { if (!pParentFrame) return; CCoord save[4]; modifyDrawContext (save, context); // convert to relativ pos CPoint where2 (where); where2.offset (-size.left, -size.top); CView* view = getViewAt (where); if (view != currentDragView) { if (currentDragView) currentDragView->onDragLeave (context, drag, where2); if (view) view->onDragEnter (context, drag, where2); currentDragView = view; } else if (currentDragView) currentDragView->onDragMove (context, drag, where2); restoreDrawContext (context, save); } //----------------------------------------------------------------------------- void CViewContainer::update (CDrawContext *pContext) { switch (mode) { //---Normal : redraw all... case kNormalUpdate: if (isDirty ()) { #if NEW_UPDATE_MECHANISM CRect ur (0, 0, size.width (), size.height ()); redrawRect (pContext, ur); #else #if USE_ALPHA_BLEND if (bTransparencyEnabled) { CRect updateRect (size); CPoint offset (0,0); localToFrame (offset); updateRect.offset (offset.x, offset.y); getFrame ()->drawRect (pContext, updateRect); } else #endif draw (pContext); #endif // !NEW_UPDATE_MECHANISM setDirty (false); } break; //---Redraw only dirty controls----- case kOnlyDirtyUpdate: { #if NEW_UPDATE_MECHANISM if (bDirty) { CRect ur (0, 0, size.width (), size.height ()); redrawRect (pContext, ur); } else { CRect updateRect (size); updateRect.offset (-size.left, -size.top); FOREACHSUBVIEW if (pV->isDirty () && pV->checkUpdate (updateRect)) { if (pV->notify (this, kMsgCheckIfViewContainer)) pV->update (pContext); else { CRect drawSize (pV->size); drawSize.bound (updateRect); pV->redrawRect (pContext, drawSize); } } ENDFOR } #else #if USE_ALPHA_BLEND if (bTransparencyEnabled) { if (bDirty) { CRect updateRect (size); CPoint offset (0,0); localToFrame (offset); updateRect.offset (offset.x, offset.y); getFrame ()->drawRect (pContext, updateRect); } else { CRect updateRect (size); updateRect.offset (-size.left, -size.top); FOREACHSUBVIEW if (pV->isDirty () && pV->checkUpdate (updateRect)) { if (pV->notify (this, kMsgCheckIfViewContainer)) { pV->update (pContext); } else { CPoint offset; CRect viewSize (pV->size); pV->localToFrame (offset); viewSize.offset (offset.x, offset.y); getFrame ()->drawRect (pContext, viewSize); } } ENDFOR } setDirty (false); return; } #endif if (bDirty) draw (pContext); else if (bDrawInOffscreen && pOffscreenContext) { bool doCopy = false; if (isDirty ()) doCopy = true; FOREACHSUBVIEW pV->update (pOffscreenContext); ENDFOR // transfert offscreen if (doCopy) pOffscreenContext->copyFrom (pContext, size); } else { long save[4]; modifyDrawContext (save, pContext); FOREACHSUBVIEW if (pV->isDirty ()) { long oldMode = 0; CViewContainer* child = 0; if (pV->notify (this, kMsgCheckIfViewContainer)) { child = (CViewContainer*)pV; oldMode = child->getMode (); child->setMode (kNormalUpdate); } CRect viewSize (pV->size); drawBackgroundRect (pContext, viewSize); pV->update (pContext); if (child) child->setMode (oldMode); } ENDFOR restoreDrawContext (pContext, save); } #endif // !NEW_UPDATE_MECHANISM setDirty (false); break; } } } //----------------------------------------------------------------------------- void CViewContainer::looseFocus (CDrawContext *pContext) { FOREACHSUBVIEW pV->looseFocus (pContext); ENDFOR } //----------------------------------------------------------------------------- void CViewContainer::takeFocus (CDrawContext *pContext) { FOREACHSUBVIEW pV->takeFocus (pContext); ENDFOR } //----------------------------------------------------------------------------- bool CViewContainer::advanceNextFocusView (CView* oldFocus, bool reverse) { bool foundOld = false; FOREACHSUBVIEW_REVERSE(reverse) if (oldFocus && !foundOld) { if (oldFocus == pV) { foundOld = true; continue; } } else { if (pV->wantsFocus ()) { getFrame ()->setFocusView (pV); return true; } else if (pV->isTypeOf ("CViewContainer")) { if (((CViewContainer*)pV)->advanceNextFocusView (0, reverse)) return true; } } ENDFOR return false; } //----------------------------------------------------------------------------- bool CViewContainer::isDirty () const { if (bDirty) return true; CRect viewSize (size); viewSize.offset (-size.left, -size.top); FOREACHSUBVIEW if (pV->isDirty ()) { CRect r (pV->size); r.bound (viewSize); if (r.getWidth () > 0 && r.getHeight () > 0) return true; } ENDFOR return false; } //----------------------------------------------------------------------------- CView *CViewContainer::getCurrentView () const { if (!pParentFrame) return 0; // get the current position CPoint where; pParentFrame->getCurrentLocation (where); frameToLocal (where); CCView *pSv = pLastView; while (pSv) { CView *pV = pSv->pView; if (pV && where.isInside (pV->mouseableArea)) return pV; pSv = pSv->pPrevious; } return 0; } //----------------------------------------------------------------------------- CView *CViewContainer::getViewAt (const CPoint& p, bool deep) const { if (!pParentFrame) return 0; CPoint where (p); // convert to relativ pos where.offset (-size.left, -size.top); CCView *pSv = pLastView; while (pSv) { CView *pV = pSv->pView; if (pV && where.isInside (pV->mouseableArea)) { if (deep) { if (pV->isTypeOf ("CViewContainer")) return ((CViewContainer*)pV)->getViewAt (where, deep); } return pV; } pSv = pSv->pPrevious; } return 0; } //----------------------------------------------------------------------------- CPoint& CViewContainer::frameToLocal (CPoint& point) const { point.offset (-size.left, -size.top); if (pParentView && pParentView->isTypeOf ("CViewContainer")) return pParentView->frameToLocal (point); return point; } //----------------------------------------------------------------------------- CPoint& CViewContainer::localToFrame (CPoint& point) const { point.offset (size.left, size.top); if (pParentView && pParentView->isTypeOf ("CViewContainer")) return pParentView->localToFrame (point); return point; } //----------------------------------------------------------------------------- bool CViewContainer::removed (CView* parent) { #if !BEOS if (pOffscreenContext) pOffscreenContext->forget (); pOffscreenContext = 0; #endif return true; } //----------------------------------------------------------------------------- bool CViewContainer::attached (CView* view) { #if !BEOS // create offscreen bitmap if (!pOffscreenContext && bDrawInOffscreen) pOffscreenContext = new COffscreenContext (pParentFrame, (long)size.width (), (long)size.height (), kBlackCColor); #endif return true; } //----------------------------------------------------------------------------- void CViewContainer::useOffscreen (bool b) { bDrawInOffscreen = b; #if !BEOS if (!bDrawInOffscreen && pOffscreenContext) { pOffscreenContext->forget (); pOffscreenContext = 0; } #endif } //----------------------------------------------------------------------------- void CViewContainer::modifyDrawContext (CCoord save[4], CDrawContext* pContext) { // store save[0] = pContext->offsetScreen.h; save[1] = pContext->offsetScreen.v; save[2] = pContext->offset.h; save[3] = pContext->offset.v; pContext->offsetScreen.h += size.left; pContext->offsetScreen.v += size.top; pContext->offset.h += size.left; pContext->offset.v += size.top; } //----------------------------------------------------------------------------- void CViewContainer::restoreDrawContext (CDrawContext* pContext, CCoord save[4]) { // restore pContext->offsetScreen.h = save[0]; pContext->offsetScreen.v = save[1]; pContext->offset.h = save[2]; pContext->offset.v = save[3]; } #if DEBUG static long _debugDumpLevel = 0; //----------------------------------------------------------------------------- void CViewContainer::dumpInfo () { static const char* modeString[] = { "Normal Update Mode", "Only Dirty Update Mode"}; DebugPrint ("CViewContainer: Mode: %s, Offscreen:%s ", modeString[mode], bDrawInOffscreen ? "Yes" : "No"); CView::dumpInfo (); } //----------------------------------------------------------------------------- void CViewContainer::dumpHierarchy () { _debugDumpLevel++; FOREACHSUBVIEW for (long i = 0; i < _debugDumpLevel; i++) DebugPrint ("\t"); pV->dumpInfo (); DebugPrint ("\n"); if (pV->isTypeOf ("CViewContainer")) ((CViewContainer*)pV)->dumpHierarchy (); ENDFOR _debugDumpLevel--; } #endif #if WINDOWS && USE_LIBPNG class PNGResourceStream { public: PNGResourceStream () : streamPos (0) , resData (0) , resSize (0) { } ~PNGResourceStream () { } bool open (long resourceID) { HRSRC rsrc = FindResource (GetInstance (), MAKEINTRESOURCE (resourceID), "PNG"); if (rsrc) { resSize = SizeofResource (GetInstance (), rsrc); HGLOBAL resDataLoad = LoadResource (GetInstance (), rsrc); if (resDataLoad) { resData = LockResource (resDataLoad); return true; } } return false; } void read (unsigned char* ptr, size_t size) { if (streamPos + size <= resSize) { memcpy (ptr, ((unsigned char*)resData+streamPos), size); streamPos += (unsigned long)size; } } static void readCallback (png_struct* pngPtr, unsigned char* ptr, size_t size) { void* obj = png_get_io_ptr (pngPtr); if (obj) ((PNGResourceStream*)obj)->read (ptr, size); } protected: HGLOBAL resData; unsigned long streamPos; unsigned long resSize; }; #endif //----------------------------------------------------------------------------- // CBitmap Implementation //----------------------------------------------------------------------------- /*! @class CBitmap @section cbitmap_alphablend Alpha Blend and Transparency With Version 3.0 of VSTGUI it is possible to use alpha blended bitmaps. This comes free on Mac OS X and with Windows you need to include libpng. Per default PNG images will be rendered alpha blended. If you want to use a transparency color with PNG Bitmaps, you need to call setNoAlpha(true) on the bitmap and set the transparency color. @section cbitmap_macos Classic Apple Mac OS The Bitmaps are PICTs and stored inside the resource fork. @section cbitmap_macosx Apple Mac OS X The Bitmaps can be of type PNG, JPEG, PICT, BMP and are stored in the Resources folder of the plugin bundle. They must be named bmp00100.png (or bmp00100.jpg, etc). The number is the resource id. @section cbitmap_windows Microsoft Windows The Bitmaps are .bmp files and must be included in the plug (usually using a .rc file). It's also possible to use png as of version 3.0 if you define the macro USE_LIBPNG and include the libpng and zlib libraries/sources to your project. */ CBitmap::CBitmap (long resourceID) : resourceID (resourceID), width (0), height (0), noAlpha (true) { #if DEBUG gNbCBitmap++; #endif #if WINDOWS || MAC pMask = 0; pHandle = 0; #if QUARTZ cgImage = 0; #endif loadFromResource (resourceID); #elif MOTIF bool found = false; long i = 0; long ncolors, cpp; pHandle = 0; pMask = 0; // find the good pixmap resource while (xpmResources[i].id != 0) { if (xpmResources[i].id == resourceID) { if (xpmResources[i].xpm != NULL) { found = true; ppDataXpm = xpmResources[i].xpm; xpmGetValues (ppDataXpm, &width, &height, &ncolors, &cpp); break; } } i++; } if (!found) ppDataXpm = 0; #elif BEOS bbitmap = 0; transparencySet = false; if (resourceFile == 0) { // this is a hack to find the plug-in on the disk to access resources. const char* locate_me = ""; int32 cookie = 0; image_info iinfo; uint32 here = uint32 (locate_me); while (get_next_image_info (0, &cookie, &iinfo) == B_OK) { uint32 begin = uint32 (iinfo.text); if (begin <= here && here <= begin + iinfo.text_size) break; } BFile resource (iinfo.name, B_READ_ONLY); resourceFile = new BResources (&resource); resourceFile->PreloadResourceType (); } size_t outSize; const char* res = (const char*) resourceFile->LoadResource ('RAWT', resourceID, &outSize); if (res) { BMemoryIO memoryIO (res, outSize); bbitmap = BTranslationUtils::GetBitmap (&memoryIO); if (bbitmap) { BRect rect = bbitmap->Bounds (); width = (long) rect.Width () + 1; height = (long) rect.Height () + 1; } } if (!bbitmap) fprintf (stderr, "********* Resource %d could NOT be loaded!\n", (int)resourceID); #endif setTransparentColor (kTransparentCColor); #if DEBUG gBitmapAllocation += (long)height * (long)width; #endif } //----------------------------------------------------------------------------- CBitmap::CBitmap (CFrame &frame, CCoord width, CCoord height) : width (width), height (height), noAlpha (true) { #if DEBUG gNbCBitmap++; #endif #if WINDOWS HDC hScreen = GetDC (0); pHandle = CreateCompatibleBitmap (hScreen, width, height); ReleaseDC (0, hScreen); pMask = 0; #elif MAC pHandle = 0; pMask = 0; Rect r; r.left = r.top = 0; r.right = (short)width; r.bottom = (short)height; #if QUARTZ NewGWorld ((GWorldPtr*)&pHandle, 32, &r, 0, 0, 0); cgImage = 0; #else NewGWorld ((GWorldPtr*)&pHandle, 0, &r, 0, 0, 0); #endif #elif MOTIF pXdisplay = frame.getDisplay (); Drawable pWindow = frame.getWindow (); pMask = 0; pHandle = (void*)XCreatePixmap (pXdisplay, (Drawable)pWindow, width, height, frame.getDepth ()); #elif BEOS bbitmap = 0; transparencySet = false; #endif setTransparentColor (kTransparentCColor); } //----------------------------------------------------------------------------- CBitmap::CBitmap () : resourceID (0) , width (0) , height (0) , noAlpha (true) { #if WINDOWS pHandle = 0; pMask = 0; #elif MAC pHandle = 0; pMask = 0; #if QUARTZ cgImage = 0; #endif #elif MOTIF pMask = 0; pHandle = 0; #elif BEOS bbitmap = 0; #endif } //----------------------------------------------------------------------------- CBitmap::~CBitmap () { dispose (); } //----------------------------------------------------------------------------- void CBitmap::dispose () { #if DEBUG gNbCBitmap--; gBitmapAllocation -= (long)height * (long)width; #endif #if WINDOWS if (pHandle) DeleteObject (pHandle); if (pMask) DeleteObject (pMask); pHandle = 0; pMask = 0; noAlpha = false; #elif MAC #if QUARTZ if (cgImage) CGImageRelease ((CGImageRef)cgImage); cgImage = 0; #endif if (pHandle) DisposeGWorld ((GWorldPtr)pHandle); if (pMask) DisposeGWorld ((GWorldPtr)pMask); pHandle = 0; pMask = 0; #elif MOTIF if (pHandle) XFreePixmap (pXdisplay, (Pixmap)pHandle); if (pMask) XFreePixmap (pXdisplay, (Pixmap)pMask); pHandle = 0; pMask = 0; #elif BEOS if (bbitmap) delete bbitmap; bbitmap = 0; #endif width = 0; height = 0; } //----------------------------------------------------------------------------- void *CBitmap::getHandle () const { #if WINDOWS||MOTIF return pHandle; #elif MAC return pHandle; #elif BEOS return bbitmap; #endif } //----------------------------------------------------------------------------- bool CBitmap::loadFromResource (long resourceID) { bool result = false; dispose (); //--------------------------------------------------------------------------------------------- #if WINDOWS //--------------------------------------------------------------------------------------------- #if USE_LIBPNG PNGResourceStream resStream; if (resStream.open (resourceID)) { // setup libpng png_structp png_ptr; png_infop info_ptr; png_ptr = png_create_read_struct (PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (png_ptr) { info_ptr = png_create_info_struct (png_ptr); if (info_ptr) { if (setjmp (png_jmpbuf (png_ptr)) == 0) { int bit_depth, color_type; png_set_read_fn (png_ptr, (void *)&resStream, PNGResourceStream::readCallback); png_read_info (png_ptr, info_ptr); png_get_IHDR (png_ptr, info_ptr, (png_uint_32*)&width, (png_uint_32*)&height, &bit_depth, &color_type, 0, 0, 0); long bytesPerRow = width * (32 / 8); while (bytesPerRow & 0x03) bytesPerRow++; // create BITMAP BITMAPINFO* bmInfo = new BITMAPINFO; BITMAPINFOHEADER* header = (BITMAPINFOHEADER*)bmInfo; memset (header, 0, sizeof(BITMAPINFOHEADER)); header->biSize = sizeof(BITMAPINFOHEADER); header->biWidth = width; header->biHeight = height; header->biPlanes = 1; header->biBitCount = 32; header->biCompression = BI_RGB; header->biClrUsed = 0; void* bits; HDC dstDC = 0; //CreateCompatibleDC (0); pHandle = CreateDIBSection (dstDC, bmInfo, DIB_RGB_COLORS, &bits, NULL, 0); delete bmInfo; if (pHandle) { if (color_type == PNG_COLOR_TYPE_PALETTE) png_set_palette_to_rgb (png_ptr); if (color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA) png_set_gray_to_rgb (png_ptr); if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) png_set_gray_1_2_4_to_8 (png_ptr); if (png_get_valid (png_ptr, info_ptr, PNG_INFO_tRNS)) png_set_tRNS_to_alpha (png_ptr); else png_set_filler (png_ptr, 0xFF, PNG_FILLER_AFTER); if (bit_depth == 16) { png_set_swap (png_ptr); png_set_strip_16 (png_ptr); } if (color_type == PNG_COLOR_TYPE_RGB || color_type == PNG_COLOR_TYPE_RGB_ALPHA) png_set_bgr (png_ptr); png_read_update_info (png_ptr, info_ptr); unsigned char** rows = new unsigned char*[1]; rows[0] = (unsigned char*)bits + (height-1) * bytesPerRow; for (long i = 0; i < height; i++) { png_read_rows (png_ptr, rows, NULL, 1); rows[0] -= bytesPerRow; } delete [] rows; png_read_end (png_ptr, 0); // premultiply alpha unsigned long* pixelPtr = (unsigned long*)bits; for (int y = 0; y > 8); pixel[1] = ((pixel[1] * pixel[3]) >> 8); pixel[2] = ((pixel[2] * pixel[3]) >> 8); } else *pixelPtr = 0UL; pixelPtr++; } } if (dstDC) DeleteDC (dstDC); #if 0 HDC srcDC = CreateCompatibleDC (0); SelectObject (srcDC, pHandle); HDC dstDC = CreateCompatibleDC (0); this->pHandle = CreateCompatibleBitmap (dstDC, width, height); SelectObject (dstDC, this->pHandle); BLENDFUNCTION blendFunction; blendFunction.BlendOp = AC_SRC_OVER; blendFunction.BlendFlags = 0; blendFunction.SourceConstantAlpha = 255; #if USE_ALPHA_BLEND if (noAlpha) blendFunction.AlphaFormat = 0;//AC_SRC_NO_ALPHA; else blendFunction.AlphaFormat = AC_SRC_ALPHA; #else blendFunction.AlphaFormat = 0;//AC_SRC_NO_ALPHA; #endif #if DYNAMICALPHABLEND (*pfnAlphaBlend) (dstDC, 0, 0, width, height, srcDC, 0, 0, width, height, blendFunction); #else #endif DeleteDC (srcDC); DeleteDC (dstDC); DeleteObject (pHandle); #endif } } } png_destroy_read_struct (&png_ptr, &info_ptr, NULL); } noAlpha = false; return true; } #endif pHandle = LoadBitmap (GetInstance (), MAKEINTRESOURCE (resourceID)); BITMAP bm; if (pHandle && GetObject (pHandle, sizeof (bm), &bm)) { width = bm.bmWidth; height = bm.bmHeight; noAlpha = true; return true; } //--------------------------------------------------------------------------------------------- #elif MAC //--------------------------------------------------------------------------------------------- pHandle = 0; pMask = 0; #if QUARTZ cgImage = 0; #endif #if MACX if (gBundleRef) { // find the bitmap in our Bundle. It must be in the form of bmp00123.png, where the resource id would be 123. char filename [PATH_MAX]; sprintf (filename, "bmp%05d", (int)resourceID); CFStringRef cfStr = CFStringCreateWithCString (NULL, filename, kCFStringEncodingASCII); if (cfStr) { CFURLRef url = NULL; int i = 0; while (url == NULL) { static CFStringRef resTypes [] = { CFSTR("png"), CFSTR("bmp"), CFSTR("jpg"), CFSTR("pict"), NULL }; url = CFBundleCopyResourceURL ((CFBundleRef)gBundleRef, cfStr, resTypes[i], NULL); if (resTypes[++i] == NULL) break; } CFRelease (cfStr); if (url) { result = loadFromPath (url); CFRelease (url); } else { #if DEVELOPMENT fprintf (stderr, "Bitmap Nr.:%d not found.\n", resourceID); #endif } } } #endif if (!result && pHandle == 0) { Handle picHandle = GetResource ('PICT', resourceID); if (picHandle) { HLock (picHandle); PictInfo info; GetPictInfo ((PicHandle)picHandle, &info, recordComments, 0, systemMethod, 0); width = info.sourceRect.right; height = info.sourceRect.bottom; OSErr err = NewGWorld ((GWorldPtr*)&pHandle, 32, &info.sourceRect, 0, 0, 0); if (!err) { GWorldPtr oldPort; GDHandle oldDevice; GetGWorld (&oldPort, &oldDevice); SetGWorld ((GWorldPtr)pHandle, 0); DrawPicture ((PicHandle)picHandle, &info.sourceRect); SetGWorld (oldPort, oldDevice); result = true; } HUnlock (picHandle); ReleaseResource (picHandle); } } #else // other platforms go here #endif return result; } //----------------------------------------------------------------------------- bool CBitmap::loadFromPath (const void* platformPath) { bool result = false; dispose (); #if QUARTZ CFURLRef url = (CFURLRef)platformPath; FSRef fsRef; if (CFURLGetFSRef (url, &fsRef)) { FSSpec fsSpec; FSCatalogInfoBitmap infoBitmap = kFSCatInfoNone; if (FSGetCatalogInfo (&fsRef, infoBitmap, NULL, NULL, &fsSpec, NULL) == noErr) { ComponentInstance* gi = 0; CFStringRef ext = CFURLCopyPathExtension (url); if (ext == 0) return false; if (CFStringCompare (ext, CFSTR("bmp"), 0) == kCFCompareEqualTo) gi = &bmpGI; else if (CFStringCompare (ext, CFSTR("png"), 0) == kCFCompareEqualTo) { gi = &pngGI; noAlpha = false; } else if (CFStringCompare (ext, CFSTR("jpg"), 0) == kCFCompareEqualTo) gi = &jpgGI; else if (CFStringCompare (ext, CFSTR("pict"), 0) == kCFCompareEqualTo) gi = &pictGI; CFRelease (ext); if (*gi == 0) GetGraphicsImporterForFile (&fsSpec, gi); else if (GraphicsImportSetDataFile (*gi, &fsSpec) != noErr) return false; if (*gi) { #ifdef MAC_OS_X_VERSION_10_3 if (!noAlpha && GraphicsImportCreateCGImage) { if (GraphicsImportCreateCGImage (*gi, (CGImageRef*)&cgImage, 0) == noErr) { width = CGImageGetWidth ((CGImageRef)cgImage); height = CGImageGetHeight ((CGImageRef)cgImage); result = true; } } else #endif { Rect r; GraphicsImportGetSourceRect (*gi, &r); OSErr err = NewGWorld ((GWorldPtr*)&pHandle, 32, &r, 0, 0, 0); if (!err) { width = r.right; height = r.bottom; GraphicsImportSetGWorld (*gi, (GWorldPtr)pHandle, 0); GraphicsImportDraw (*gi); result = true; } } } } } #elif WINDOWS // todo #endif return result; } //----------------------------------------------------------------------------- bool CBitmap::isLoaded () const { #if MOTIF if (ppDataXpm) return true; #elif QUARTZ if (cgImage || getHandle ()) return true; #else if (getHandle ()) return true; #endif return false; } #if QUARTZ class CDataProvider { public: CDataProvider (CBitmap* bitmap) : bmp (bitmap) { pos = 0; PixMapHandle pixMap = GetGWorldPixMap ((GWorldPtr)bmp->getHandle ()); ptr = (unsigned char*)GetPixBaseAddr (pixMap); color = bmp->getTransparentColor (); } static size_t getBytes (void *info, void *buffer, size_t count) { // this could be optimized ;-) CDataProvider* p = (CDataProvider*)info; unsigned char* dst = (unsigned char*)buffer; unsigned char* src = p->ptr + p->pos; for (unsigned long i = 0; i < count / 4; i++) { if (src[1] == p->color.red && src[2] == p->color.green && src[3] == p->color.blue) { *dst++ = 0; src++; } else *dst++ = *src++; *dst++ = *src++; *dst++ = *src++; *dst++ = *src++; } p->pos += count; return count; } static void skipBytes (void *info, size_t count) { CDataProvider* p = (CDataProvider*)info; p->pos += count; } static void rewind (void *info) { CDataProvider* p = (CDataProvider*)info; p->pos = 0; } static void releaseProvider (void *info) { CDataProvider* p = (CDataProvider*)info; delete p; } unsigned long pos; CBitmap* bmp; unsigned char* ptr; CColor color; }; //----------------------------------------------------------------------------- CGImageRef CBitmap::createCGImage (bool transparent) { if (cgImage) { CGImageRetain ((CGImageRef)cgImage); return (CGImageRef)cgImage; } if (!pHandle) return NULL; PixMapHandle pixMap = GetGWorldPixMap ((GWorldPtr)pHandle); Rect bounds; GetPixBounds (pixMap, &bounds); size_t pixRowBytes = GetPixRowBytes (pixMap); short pixDepth = GetPixDepth (pixMap); size_t size = pixRowBytes * (bounds.bottom - bounds.top); CGImageRef image = 0; CGDataProviderRef provider = 0; static CGDataProviderCallbacks callbacks = { CDataProvider::getBytes, CDataProvider::skipBytes, CDataProvider::rewind, CDataProvider::releaseProvider }; if (transparent) provider = CGDataProviderCreate (new CDataProvider (this), &callbacks); else provider = CGDataProviderCreateWithData (NULL, GetPixBaseAddr (pixMap), size, NULL); CGImageAlphaInfo alphaInfo = kCGImageAlphaFirst; if (GetPixDepth (pixMap) != 32) alphaInfo = kCGImageAlphaNone; image = CGImageCreate (bounds.right - bounds.left, bounds.bottom - bounds.top, 8 , pixDepth, pixRowBytes, GetGenericRGBColorSpace (), alphaInfo, provider, NULL, false, kCGRenderingIntentDefault); CGDataProviderRelease (provider); cgImage = image; CGImageRetain (image); return image; } #endif //----------------------------------------------------------------------------- void CBitmap::draw (CDrawContext *pContext, CRect &rect, const CPoint &offset) { #if WINDOWS #if USE_ALPHA_BLEND if (!noAlpha) { drawAlphaBlend (pContext, rect, offset, 255); return; } #endif if (pHandle) { HGDIOBJ hOldObj; HDC hdcMemory = CreateCompatibleDC ((HDC)pContext->pSystemContext); hOldObj = SelectObject (hdcMemory, pHandle); BitBlt ((HDC)pContext->pSystemContext, rect.left + pContext->offset.h, rect.top + pContext->offset.v, rect.width (), rect.height (), (HDC)hdcMemory, offset.h, offset.v, SRCCOPY); SelectObject (hdcMemory, hOldObj); DeleteDC (hdcMemory); } #elif MAC #if QUARTZ drawAlphaBlend (pContext, rect, offset, 255); #else Rect source, dest; dest.top = rect.top + pContext->offset.v; dest.left = rect.left + pContext->offset.h; dest.bottom = dest.top + rect.height (); dest.right = dest.left + rect.width (); source.top = offset.v; source.left = offset.h; source.bottom = source.top + rect.height (); source.right = source.left + rect.width (); pContext->getPort (); BitMapPtr bitmapPtr = pContext->getBitmap (); if (pHandle && bitmapPtr) { PixMapHandle pmHandle = GetGWorldPixMap ((GWorldPtr)pHandle); if (pmHandle && LockPixels (pmHandle)) { RGBColor oldForeColor, oldBackColor; GetForeColor (&oldForeColor); GetBackColor (&oldBackColor); ::BackColor (whiteColor); ::ForeColor (blackColor); CopyBits ((BitMapPtr)*pmHandle, bitmapPtr, &source, &dest, srcCopy, 0L); #if MACX QDAddRectToDirtyRegion (pContext->getPort (), &dest); #endif RGBForeColor (&oldForeColor); RGBBackColor (&oldBackColor); UnlockPixels (pmHandle); } } pContext->releaseBitmap (); #endif #elif MOTIF if (!pHandle) { // the first time try to decode the pixmap pHandle = createPixmapFromXpm (pContext); if (!pHandle) return; // keep a trace of the display for deletion pXdisplay = pContext->pDisplay; } #if DEVELOPMENT if (!(offset.h >= 0 && offset.v >= 0 && rect.width () <= (getWidth () - offset.h) && rect.height () <= (getHeight () - offset.v))) { fprintf (stderr, "%s(%d) -> Assert failed: try to display outside from the bitmap\n", __FILE__, __LINE__); return; } #endif XCopyArea (pContext->pDisplay, (Drawable)pHandle, (Drawable)pContext->pWindow, (GC)pContext->pSystemContext, offset.h, offset.v, rect.width (), rect.height (), rect.left, rect.top); #elif BEOS BRect brect (rect.left, rect.top, rect.right - 1, rect.bottom - 1); BRect drect = brect; brect.OffsetTo (offset.h, offset.v); drect.OffsetBy (pContext->offset.h, pContext->offset.v); pContext->pView->SetDrawingMode (B_OP_COPY); pContext->pView->DrawBitmap (bbitmap, brect, drect); #endif } //----------------------------------------------------------------------------- void CBitmap::drawTransparent (CDrawContext *pContext, CRect &rect, const CPoint &offset) { #if WINDOWS #if USE_ALPHA_BLEND if (!noAlpha) { drawAlphaBlend (pContext, rect, offset, 255); return; } #endif BITMAP bm; HDC hdcBitmap; POINT ptSize; hdcBitmap = CreateCompatibleDC ((HDC)pContext->pSystemContext); SelectObject (hdcBitmap, pHandle); // Select the bitmap GetObject (pHandle, sizeof (BITMAP), (LPSTR)&bm); ptSize.x = bm.bmWidth; // Get width of bitmap ptSize.y = bm.bmHeight; // Get height of bitmap DPtoLP (hdcBitmap, &ptSize, 1); // Convert from device to logical points DrawTransparent (pContext, rect, offset, hdcBitmap, ptSize, (HBITMAP)pMask, RGB(transparentCColor.red, transparentCColor.green, transparentCColor.blue)); DeleteDC (hdcBitmap); #elif MAC #if QUARTZ if (noAlpha) { CGImageRef image = createCGImage (true); if (image) { drawAlphaBlend (pContext, rect, offset, 255); CGImageRelease (image); } } else drawAlphaBlend (pContext, rect, offset, 255); #else Rect source, dest; dest.top = rect.top + pContext->offset.v; dest.left = rect.left + pContext->offset.h; dest.bottom = dest.top + rect.height (); dest.right = dest.left + rect.width (); source.top = offset.v; source.left = offset.h; source.bottom = source.top + rect.height (); source.right = source.left + rect.width (); pContext->getPort (); BitMapPtr bitmapPtr = pContext->getBitmap (); if (pHandle && bitmapPtr) { PixMapHandle pmHandle = GetGWorldPixMap ((GWorldPtr)pHandle); if (pmHandle && LockPixels (pmHandle)) { RGBColor oldForeColor, oldBackColor; GetForeColor (&oldForeColor); GetBackColor (&oldBackColor); RGBColor col; CColor2RGBColor (transparentCColor, col); RGBBackColor (&col); ::ForeColor (blackColor); if (pMask) { PixMapHandle pmHandleMask = GetGWorldPixMap ((GWorldPtr)pMask); if (pmHandleMask && LockPixels (pmHandleMask)) { CopyMask ((BitMapPtr)*pmHandle, (BitMapPtr)*pmHandleMask, bitmapPtr, &source, &source, &dest); UnlockPixels (pmHandleMask); } } else CopyBits ((BitMapPtr)*pmHandle, bitmapPtr, &source, &dest, transparent, 0L); RGBForeColor (&oldForeColor); RGBBackColor (&oldBackColor); #if MACX QDAddRectToDirtyRegion (pContext->getPort (), &dest); #endif UnlockPixels (pmHandle); } } pContext->releaseBitmap (); #endif #elif MOTIF if (!pHandle) { // the first time try to decode the pixmap pHandle = createPixmapFromXpm (pContext); if (!pHandle) return; // keep a trace of the display for deletion pXdisplay = pContext->pDisplay; } if (pMask == 0) { // get image from the pixmap XImage* image = XGetImage (pContext->pDisplay, (Drawable)pHandle, 0, 0, width, height, AllPlanes, ZPixmap); assert (image); // create the bitmap mask pMask = (void*)XCreatePixmap (pContext->pDisplay, (Drawable)pContext->pWindow, width, height, 1); assert (pMask); // create a associated GC XGCValues values; values.foreground = 1; GC gc = XCreateGC (pContext->pDisplay, (Drawable)pMask, GCForeground, &values); // clear the mask XFillRectangle (pContext->pDisplay, (Drawable)pMask, gc, 0, 0, width, height); // get the transparent color index int color = pContext->getIndexColor (transparentCColor); // inverse the color values.foreground = 0; XChangeGC (pContext->pDisplay, gc, GCForeground, &values); // compute the mask XPoint *points = new XPoint [height * width]; int x, y, nbPoints = 0; switch (image->depth) { case 8: for (y = 0; y < height; y++) { char* src = image->data + (y * image->bytes_per_line); for (x = 0; x < width; x++) { if (src[x] == color) { points[nbPoints].x = x; points[nbPoints].y = y; nbPoints++; } } } break; case 24: { int bytesPerPixel = image->bits_per_pixel >> 3; char *lp = image->data; for (y = 0; y < height; y++) { char* cp = lp; for (x = 0; x < width; x++) { if (*(int*)cp == color) { points[nbPoints].x = x; points[nbPoints].y = y; nbPoints++; } cp += bytesPerPixel; } lp += image->bytes_per_line; } } break; default : break; } XDrawPoints (pContext->pDisplay, (Drawable)pMask, gc, points, nbPoints, CoordModeOrigin); // free XFreeGC (pContext->pDisplay, gc); delete []points; // delete XDestroyImage (image); } // set the new clipmask XGCValues value; value.clip_mask = (Pixmap)pMask; value.clip_x_origin = rect.left - offset.h; value.clip_y_origin = rect.top - offset.v; XChangeGC (pContext->pDisplay, (GC)pContext->pSystemContext, GCClipMask|GCClipXOrigin|GCClipYOrigin, &value); XCopyArea (pContext->pDisplay, (Drawable)pHandle, (Drawable)pContext->pWindow, (GC)pContext->pSystemContext, offset.h, offset.v, rect.width (), rect.height (), rect.left, rect.top); // unset the clipmask XSetClipMask (pContext->pDisplay, (GC)pContext->pSystemContext, None); #elif BEOS if (!transparencySet) { uint32 c32 = transparentCColor.red | (transparentCColor.green << 8) | (transparentCColor.blue << 16); uint32 *pix = (uint32*) bbitmap->Bits (); uint32 ctr = B_TRANSPARENT_32_BIT.red | (B_TRANSPARENT_32_BIT.green << 8) | (B_TRANSPARENT_32_BIT.blue << 16) | (B_TRANSPARENT_32_BIT.alpha << 24); for (int32 z = 0, count = bbitmap->BitsLength () / 4; z < count; z++) { if ((pix[z] & 0xffffff) == c32) pix[z] = ctr; } transparencySet = true; } BRect brect (rect.left, rect.top, rect.right - 1, rect.bottom - 1); BRect drect = brect; brect.OffsetTo (offset.h, offset.v); drect.OffsetBy (pContext->offset.h, pContext->offset.v); pContext->pView->SetDrawingMode (B_OP_OVER); pContext->pView->DrawBitmap (bbitmap, brect, drect); #endif } //----------------------------------------------------------------------------- void CBitmap::drawAlphaBlend (CDrawContext *pContext, CRect &rect, const CPoint &offset, unsigned char alpha) { #if WINDOWS if (pHandle) { HGDIOBJ hOldObj; HDC hdcMemory = CreateCompatibleDC ((HDC)pContext->pSystemContext); hOldObj = SelectObject (hdcMemory, pHandle); BLENDFUNCTION blendFunction; blendFunction.BlendOp = AC_SRC_OVER; blendFunction.BlendFlags = 0; blendFunction.SourceConstantAlpha = alpha; #if USE_ALPHA_BLEND if (noAlpha) blendFunction.AlphaFormat = 0;//AC_SRC_NO_ALPHA; else blendFunction.AlphaFormat = AC_SRC_ALPHA; #else blendFunction.AlphaFormat = 0;//AC_SRC_NO_ALPHA; #endif #if DYNAMICALPHABLEND // check for Win98 as it has a bug in AlphaBlend if (gSystemVersion.dwMajorVersion == 4 && gSystemVersion.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS && gSystemVersion.dwMinorVersion == 10) { HGDIOBJ hOldObj1; HDC hdcMemory1 = CreateCompatibleDC ((HDC)pContext->pSystemContext); HBITMAP hbmp = CreateCompatibleBitmap(hdcMemory, rect.width(), rect.height()); //this does NOT work: //HBITMAP hbmp = CreateCompatibleBitmap(hdcMemory1, rect.width(), rect.height()); hOldObj1 = SelectObject (hdcMemory1, hbmp); //copy contents of original picture in hdcMemory //from the offset to hdcMemory1 (0,0) long res = BitBlt((HDC)hdcMemory1, 0, 0, rect.width(), rect.height(), (HDC)hdcMemory, offset.h, offset.v, SRCCOPY); //Copy the resulting image with alpha blending: (*pfnAlphaBlend) ((HDC)pContext->pSystemContext, rect.left + pContext->offset.h, rect.top + pContext->offset.v, rect.width (), rect.height (), hdcMemory1, 0, 0,//the offset is done in BitBlt rect.width (), rect.height (), blendFunction); SelectObject (hdcMemory1, hOldObj1); DeleteDC(hdcMemory1); DeleteObject(hbmp); } else { (*pfnAlphaBlend) ((HDC)pContext->pSystemContext, rect.left + pContext->offset.h, rect.top + pContext->offset.v, rect.width (), rect.height (), (HDC)hdcMemory, offset.h, offset.v, rect.width (), rect.height (), blendFunction); } #else AlphaBlend ((HDC)pContext->pSystemContext, rect.left + pContext->offset.h, rect.top + pContext->offset.v, rect.width (), rect.height (), (HDC)hdcMemory, offset.h, offset.v, rect.width (), rect.height (), blendFunction); #endif SelectObject (hdcMemory, hOldObj); DeleteDC (hdcMemory); } #elif MAC #if QUARTZ if (_CGImageCreateWithImageInRect) // this is much faster on Mac OS X 10.4 and above { if (pHandle || cgImage) { CGContextRef context = pContext->beginCGContext (); if (context) { if (alpha != 255) CGContextSetAlpha (context, (float)alpha / 255.f); CGImageRef image = createCGImage (); if (image) { CRect ccr; pContext->getClipRect (ccr); CGRect clipRect = CGRectMake (ccr.left - rect.left + offset.h, ccr.top - rect.top + offset.v, ccr.width (), ccr.height ()); CGRect subRect = CGRectMake (offset.h, offset.v, rect.getWidth (), rect.getHeight ()); subRect = CGRectIntersection (clipRect, subRect); if (subRect.size.width && subRect.size.height) { CGImageRef subImage = _CGImageCreateWithImageInRect (image, subRect); if (subImage) { CGRect dest; dest.origin.x = subRect.origin.x + pContext->offset.h - offset.h + rect.left; dest.origin.y = subRect.origin.y + pContext->offset.v - offset.v + rect.top; dest.size.width = subRect.size.width; dest.size.height = subRect.size.height; CGContextScaleCTM (context, 1, -1); HIViewDrawCGImage (context, &dest, subImage); CGImageRelease (subImage); } } CGImageRelease (image); } pContext->releaseCGContext (context); } } return; } if (pHandle || cgImage) { CGContextRef context = pContext->beginCGContext (); if (context) { if (alpha != 255) CGContextSetAlpha (context, (float)alpha / 255.f); CGImageRef image = createCGImage (); if (image) { CGRect dest; dest.origin.x = rect.left - offset.h + pContext->offset.h; dest.origin.y = (rect.top + pContext->offset.v) * -1 - (getHeight () - offset.v); dest.size.width = getWidth (); dest.size.height = getHeight (); CRect ccr; pContext->getClipRect (ccr); CGRect cgClipRect = CGRectMake (ccr.left + pContext->offset.h, (ccr.top + pContext->offset.v) * -1 - ccr.height (), ccr.width (), ccr.height ()); CGContextClipToRect (context, cgClipRect); CGRect clipRect; clipRect.origin.x = rect.left + pContext->offset.h; clipRect.origin.y = (rect.top + pContext->offset.v) * -1 - rect.height (); clipRect.size.width = rect.width (); clipRect.size.height = rect.height (); CGContextClipToRect (context, clipRect); CGContextDrawImage (context, dest, image); CGImageRelease (image); } pContext->releaseCGContext (context); } } #else Rect source, dest; dest.top = rect.top + pContext->offset.v; dest.left = rect.left + pContext->offset.h; dest.bottom = dest.top + rect.height (); dest.right = dest.left + rect.width (); source.top = offset.v; source.left = offset.h; source.bottom = source.top + rect.height (); source.right = source.left + rect.width (); pContext->getPort (); BitMapPtr bitmapPtr = pContext->getBitmap (); if (bitmapPtr) { RGBColor col; CColor color = {alpha, alpha, alpha, 0}; CColor2RGBColor (color, col); OpColor (&col); if (pHandle) { PixMapHandle pmHandle = GetGWorldPixMap ((GWorldPtr)pHandle); if (pmHandle && LockPixels (pmHandle)) { RGBColor oldForeColor, oldBackColor; GetForeColor (&oldForeColor); GetBackColor (&oldBackColor); ::BackColor (whiteColor); ::ForeColor (blackColor); CopyBits ((BitMapPtr)*pmHandle, bitmapPtr, &source, &dest, blend, 0L); #if MACX QDAddRectToDirtyRegion (pContext->getPort (), &dest); #endif RGBForeColor (&oldForeColor); RGBBackColor (&oldBackColor); UnlockPixels (pmHandle); } } } pContext->releaseBitmap (); #endif #endif } //----------------------------------------------------------------------------- void CBitmap::setTransparentColor (const CColor color) { transparentCColor = color; #if QUARTZ if (noAlpha) { if (cgImage) CGImageRelease ((CGImageRef)cgImage); cgImage = 0; } #endif } //----------------------------------------------------------------------------- void CBitmap::setTransparencyMask (CDrawContext* pContext, const CPoint& offset) { #if WINDOWS if (pMask) DeleteObject (pMask); CRect r (0, 0, width, height); r.offset (offset.h, offset.v); pMask = CreateMaskBitmap (pContext, r, transparentCColor); #elif MAC #if QUARTZ #else if (pMask) DisposeGWorld ((GWorldPtr)pMask); pMask = 0; Rect r; r.left = r.top = 0; r.right = width; r.bottom = height; OSErr err = NewGWorld ((GWorldPtr*)&pMask, 1, &r, 0, 0, 0); // create monochrome GWorld if (!err) { GWorldPtr oldPort; GDHandle oldDevice; GetGWorld (&oldPort, &oldDevice); SetGWorld ((GWorldPtr)pMask, 0); PixMapHandle pmHandle = GetGWorldPixMap ((GWorldPtr)pMask); BitMapPtr sourcePtr = pContext->getBitmap (); if (sourcePtr && pmHandle && LockPixels (pmHandle)) { RGBColor oldForeColor, oldBackColor; GetForeColor (&oldForeColor); GetBackColor (&oldBackColor); RGBColor col; CColor2RGBColor (transparentCColor, col); RGBBackColor (&col); ::ForeColor (blackColor); Rect src = r; src.left += offset.h; src.right += offset.h; src.top += offset.v; src.bottom += offset.v; CopyBits (sourcePtr, (BitMapPtr)*pmHandle, &src, &r, srcCopy, 0L); RGBForeColor (&oldForeColor); RGBBackColor (&oldBackColor); UnlockPixels (pmHandle); } pContext->releaseBitmap (); SetGWorld (oldPort, oldDevice); } #endif #else // todo: implement me! #endif } //----------------------------------------------------------------------------- //---------------------------------------------------------------------------- #if MOTIF //----------------------------------------------------------------------------- void* CBitmap::createPixmapFromXpm (CDrawContext *pContext) { if (!ppDataXpm) return NULL; Pixmap pixmap = 0; XpmAttributes attributes; attributes.valuemask = XpmCloseness|XpmColormap|XpmVisual|XpmDepth; attributes.closeness = 100000; attributes.visual = pContext->getVisual (); attributes.depth = pContext->getDepth (); // use the pContext colormap instead of the DefaultColormapOfScreen attributes.colormap = pContext->getColormap (); int status; if (attributes.depth == 8 || attributes.depth == 24) { #if USE_XPM status = XpmCreatePixmapFromData (pContext->pDisplay, (Drawable)pContext->pWindow, ppDataXpm, &pixmap, NULL, &attributes); if (status != XpmSuccess) { fprintf (stderr, "createPixmapFromXpm-> XpmError: %s\n", XpmGetErrorString(status)); return NULL; } #else status = createPixmapFromData (pContext->pDisplay, (Drawable)pContext->pWindow, ppDataXpm, &pixmap, &attributes); if (!status) { fprintf (stderr, "createPixmapFromXpm-> Error\n"); return NULL; } #endif } else { fprintf (stderr, "createPixmapFromXpm-> Depth %d not supported\n", attributes.depth); return NULL; } #if DEVELOPMENT fprintf (stderr, "createPixmapFromXpm-> There are %d requested colors\n", attributes.ncolors); #endif return (void*)pixmap; } #endif //---------------------------------------------------------------------------- //---------------------------------------------------------------------------- #if BEOS //---------------------------------------------------------------------------- BResources* CBitmap::resourceFile = 0; //---------------------------------------------------------------------------- void CBitmap::closeResource () { if (resourceFile) { delete resourceFile; resourceFile = 0; } } //---------------------------------------------------------------------------- #endif //----------------------------------------------------------------------------- // CDragContainer Implementation //----------------------------------------------------------------------------- CDragContainer::CDragContainer (void* platformDrag) : platformDrag (platformDrag) , nbItems (0) , iterator (0) , lastItem (0) { #if MAC DragRef dragRef = (DragRef)platformDrag; UInt16 numItems; CountDragItems (dragRef, &numItems); nbItems = numItems; #elif WINDOWS IDataObject* dataObject = (IDataObject*)platformDrag; STGMEDIUM medium; FORMATETC formatTEXTDrop = {CF_TEXT, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL}; FORMATETC formatHDrop = {CF_HDROP, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL}; long type = 0; // 0 = file, 1 = text HRESULT hr = dataObject->GetData (&formatTEXTDrop, &medium); if (hr != S_OK) hr = dataObject->GetData (&formatHDrop, &medium); else type = 1; if (type == 0) nbItems = (long)DragQueryFile ((HDROP)medium.hGlobal, 0xFFFFFFFFL, 0, 0); else nbItems = 1; #else #endif } //----------------------------------------------------------------------------- CDragContainer::~CDragContainer () { if (lastItem) { free (lastItem); lastItem = 0; } } //----------------------------------------------------------------------------- long CDragContainer::getType (long idx) const { #if MACX DragItemRef itemRef; if (GetDragItemReferenceNumber ((DragRef)platformDrag, idx+1, &itemRef) == noErr) { FlavorType type; if (GetFlavorType ((DragRef)platformDrag, itemRef, 1, &type) == noErr) { if (type == flavorTypeHFS || type == typeFileURL) return kFile; else if (type == 'TEXT' || type == 'XML ') return kText; } } #elif WINDOWS IDataObject* dataObject = (IDataObject*)platformDrag; STGMEDIUM medium; FORMATETC formatTEXTDrop = {CF_TEXT, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL}; FORMATETC formatHDrop = {CF_HDROP, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL}; long type = 0; // 0 = file, 1 = text HRESULT hr = dataObject->GetData (&formatTEXTDrop, &medium); if (hr != S_OK) hr = dataObject->GetData (&formatHDrop, &medium); else type = 1; if (type == 0) return kFile; else return kText; #else // not implemented #endif return kUnknown; } //----------------------------------------------------------------------------- void* CDragContainer::first (long& size, long& type) { iterator = 0; return next (size, type); } //----------------------------------------------------------------------------- void* CDragContainer::next (long& size, long& type) { if (lastItem) { free (lastItem); lastItem = 0; } size = 0; type = kUnknown; #if MACX long flavorSize; DragItemRef itemRef; if (GetDragItemReferenceNumber ((DragRef)platformDrag, ++iterator, &itemRef) == noErr) { FlavorType flavorType; if (GetFlavorType ((DragRef)platformDrag, itemRef, 1, &flavorType) == noErr) { if (flavorType == flavorTypeHFS) { HFSFlavor hfs; if (GetFlavorDataSize ((DragRef)platformDrag, itemRef, flavorTypeHFS, &flavorSize) == noErr) { GetFlavorData ((DragRef)platformDrag, itemRef, flavorTypeHFS, &hfs, &flavorSize, 0L); FSRef fsRef; if (FSpMakeFSRef (&hfs.fileSpec, &fsRef) == noErr) { lastItem = malloc (PATH_MAX); if (FSRefMakePath (&fsRef, (unsigned char*)lastItem, PATH_MAX) == noErr) { size = strlen ((const char*)lastItem); type = kFile; return lastItem; } } } } else if (flavorType == typeFileURL) { if (GetFlavorDataSize ((DragRef)platformDrag, itemRef, typeFileURL, &flavorSize) == noErr) { void* bytes = malloc (flavorSize); if (GetFlavorData ((DragRef)platformDrag, itemRef, typeFileURL, bytes, &flavorSize, 0L) == noErr) { CFURLRef url = CFURLCreateWithBytes (NULL, (const unsigned char*)bytes, flavorSize, kCFStringEncodingUTF8, NULL); lastItem = malloc (PATH_MAX); CFURLGetFileSystemRepresentation (url, false, (unsigned char*)lastItem, PATH_MAX); CFRelease (url); type = kFile; } free (bytes); return lastItem; } } else { if (GetFlavorDataSize ((DragRef)platformDrag, itemRef, flavorType, &flavorSize) == noErr) { lastItem = malloc (flavorSize + 1); ((char*)lastItem)[0] = 0; if (GetFlavorData ((DragRef)platformDrag, itemRef, flavorType, lastItem, &flavorSize, 0) == noErr) { ((char*)lastItem)[flavorSize] = 0; size = flavorSize; if (flavorType == 'TEXT' || flavorType == 'XML ') type = kText; return lastItem; } } else { if (GetFlavorDataSize ((DragRef)platformDrag, itemRef, 'TEXT', &flavorSize) == noErr) { lastItem = malloc (flavorSize + 1); ((char*)lastItem)[0] = 0; if (GetFlavorData ((DragRef)platformDrag, itemRef, 'TEXT', lastItem, &flavorSize, 0) == noErr) { ((char*)lastItem)[flavorSize] = 0; size = flavorSize; type = kText; return lastItem; } } } } } } #elif WINDOWS IDataObject* dataObject = (IDataObject*)platformDrag; void* hDrop = 0; STGMEDIUM medium; FORMATETC formatTEXTDrop = {CF_TEXT, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL}; FORMATETC formatHDrop = {CF_HDROP, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL}; long wintype = 0; // 0 = file, 1 = text HRESULT hr = dataObject->GetData (&formatTEXTDrop, &medium); if (hr != S_OK) hr = dataObject->GetData (&formatHDrop, &medium); else wintype = 1; if (hr == S_OK) hDrop = medium.hGlobal; if (hDrop) { if (wintype == 0) { char fileDropped[1024]; long nbRealItems = 0; if (DragQueryFile ((HDROP)hDrop, iterator++, fileDropped, sizeof (fileDropped))) { // resolve link checkResolveLink (fileDropped, fileDropped); lastItem = malloc (strlen (fileDropped)+1); strcpy ((char*)lastItem, fileDropped); size = (long)strlen ((const char*)lastItem); type = kFile; return lastItem; } } else if (iterator++ == 0) //---TEXT---------------------------- { void* data = GlobalLock (medium.hGlobal); long dataSize = (long)GlobalSize (medium.hGlobal); if (data && dataSize) { lastItem = malloc (dataSize+1); memcpy (lastItem, data, dataSize); size = dataSize; type = kText; } GlobalUnlock (medium.hGlobal); if (medium.pUnkForRelease) medium.pUnkForRelease->Release (); else GlobalFree (medium.hGlobal); return lastItem; } } #else // not implemented #endif return NULL; } END_NAMESPACE_VSTGUI #if WINDOWS #if USE_MOUSE_HOOK HHOOK MouseHook = 0L; LRESULT CALLBACK MouseProc (int nCode, WPARAM wParam, LPARAM lParam) { if (nCode < 0) return CallNextHookEx (MouseHook, nCode, wParam, lParam); if (wParam == 522) { MOUSEHOOKSTRUCT* struct2 = (MOUSEHOOKSTRUCT*) lParam; if (struct2->hwnd == ???) { return -1; } } return CallNextHookEx (MouseHook, nCode, wParam, lParam); } #endif //----------------------------------------------------------------------------- bool InitWindowClass () { gUseCount++; if (gUseCount == 1) { sprintf (gClassName, "Plugin%p", GetInstance ()); WNDCLASS windowClass; windowClass.style = CS_GLOBALCLASS;//|CS_OWNDC; // add Private-DC constant windowClass.lpfnWndProc = WindowProc; windowClass.cbClsExtra = 0; windowClass.cbWndExtra = 0; windowClass.hInstance = GetInstance (); windowClass.hIcon = 0; windowClass.hCursor = LoadCursor (NULL, IDC_ARROW); windowClass.hbrBackground = GetSysColorBrush (COLOR_BTNFACE); windowClass.lpszMenuName = 0; windowClass.lpszClassName = gClassName; RegisterClass (&windowClass); #if USE_MOUSE_HOOK MouseHook = SetWindowsHookEx (WH_MOUSE, MouseProc, GetInstance (), 0); #endif bSwapped_mouse_buttons = GetSystemMetrics (SM_SWAPBUTTON) > 0; } return true; } //----------------------------------------------------------------------------- void ExitWindowClass () { gUseCount--; if (gUseCount == 0) { UnregisterClass (gClassName, GetInstance ()); #if USE_MOUSE_HOOK if (MouseHook) { UnhookWindowsHookEx (MouseHook); MouseHook = 0L; } #endif } } //----------------------------------------------------------------------------- LONG_PTR WINAPI WindowProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { USING_NAMESPACE_VSTGUI CFrame* pFrame = (CFrame*)GetWindowLongPtr (hwnd, GWLP_USERDATA); switch (message) { case WM_MOUSEWHEEL: { if (pFrame) { VSTGUI_CDrawContext context (pFrame, 0, hwnd); VSTGUI_CPoint where (LOWORD (lParam), HIWORD (lParam)); short zDelta = (short) HIWORD(wParam); pFrame->onWheel (&context, where, (float)zDelta / WHEEL_DELTA); } break; } case WM_CTLCOLOREDIT: { if (pFrame) { VSTGUI_CTextEdit *textEdit = (VSTGUI_CTextEdit*)pFrame->getFocusView (); if (textEdit) { VSTGUI_CColor fontColor = textEdit->getFontColor (); SetTextColor ((HDC) wParam, RGB (fontColor.red, fontColor.green, fontColor.blue)); VSTGUI_CColor backColor = textEdit->getBackColor (); SetBkColor ((HDC) wParam, RGB (backColor.red, backColor.green, backColor.blue)); if (textEdit->platformFontColor) DeleteObject (textEdit->platformFontColor); textEdit->platformFontColor = CreateSolidBrush (RGB (backColor.red, backColor.green, backColor.blue)); return (LRESULT)(textEdit->platformFontColor); } } } break; case WM_PAINT: { RECT r; if (pFrame && GetUpdateRect (hwnd, &r, false)) { PAINTSTRUCT ps; HDC hdc = BeginPaint (hwnd, &ps); VSTGUI_CDrawContext* context = pFrame->getBackBuffer (); if (!context) context = new VSTGUI_CDrawContext (pFrame, hdc, hwnd); CRect updateRect (ps.rcPaint.left, ps.rcPaint.top, ps.rcPaint.right, ps.rcPaint.bottom); pFrame->drawRect (context, updateRect); if (pFrame->getBackBuffer ()) { VSTGUI_CDrawContext localContext (pFrame, hdc, hwnd); pFrame->getBackBuffer ()->copyFrom (&localContext, updateRect, CPoint (ps.rcPaint.left, ps.rcPaint.top)); } else context->forget (); EndPaint (hwnd, &ps); return 0; } } break; case WM_MEASUREITEM : { MEASUREITEMSTRUCT* ms = (MEASUREITEMSTRUCT*)lParam; if (pFrame && ms && ms->CtlType == ODT_MENU && ms->itemData) { VSTGUI_COptionMenu* optMenu = (VSTGUI_COptionMenu*)pFrame->getFocusView (); if (optMenu && optMenu->getScheme ()) { VSTGUI_CPoint size; VSTGUI_CDrawContext context (pFrame, 0, hwnd); optMenu->getScheme ()->getItemSize ((const char*)ms->itemData, &context, size); ms->itemWidth = size.h; ms->itemHeight = size.v; return TRUE; } } } break; case WM_DRAWITEM : { DRAWITEMSTRUCT* ds = (DRAWITEMSTRUCT*)lParam; if (pFrame && ds && ds->CtlType == ODT_MENU && ds->itemData) { VSTGUI_COptionMenu* optMenu = (VSTGUI_COptionMenu*)pFrame->getFocusView (); if (optMenu && optMenu->getScheme ()) { long state = 0; if (ds->itemState & ODS_CHECKED) state |= VSTGUI_COptionMenuScheme::kChecked; if (ds->itemState & ODS_DISABLED) // ODS_GRAYED? state |= VSTGUI_COptionMenuScheme::kDisabled; if (ds->itemState & ODS_SELECTED) state |= VSTGUI_COptionMenuScheme::kSelected; CRect r (ds->rcItem.left, ds->rcItem.top, ds->rcItem.right, ds->rcItem.bottom); r.bottom++; VSTGUI_CDrawContext* pContext = new VSTGUI_CDrawContext (pFrame, ds->hDC, 0); optMenu->getScheme ()->drawItem ((const char*)ds->itemData, ds->itemID, state, pContext, r); delete pContext; return TRUE; } } } break; case WM_RBUTTONDOWN: case WM_MBUTTONDOWN: case WM_LBUTTONDOWN: if (pFrame) { #if 1 VSTGUI_CDrawContext context (pFrame, 0, hwnd); VSTGUI_CPoint where (LOWORD (lParam), HIWORD (lParam)); pFrame->mouse (&context, where); #else VSTGUI_CPoint where (LOWORD (lParam), HIWORD (lParam)); pFrame->mouse ((VSTGUI_CDrawContext*)0, where); #endif return 0; } break; case WM_DESTROY: if (pFrame) { pFrame->setOpenFlag (false); pFrame->setParentSystemWindow (0); } break; } return DefWindowProc (hwnd, message, wParam, lParam); } //----------------------------------------------------------------------------- HANDLE CreateMaskBitmap (CDrawContext* pContext, CRect& rect, CColor transparentColor) { HBITMAP pMask = CreateBitmap (rect.width (), rect.height (), 1, 1, 0); HDC hSrcDC = (HDC)pContext->getSystemContext (); HDC hDstDC = CreateCompatibleDC (hSrcDC); SelectObject (hDstDC, pMask); COLORREF oldBkColor = SetBkColor (hSrcDC, RGB (transparentColor.red, transparentColor.green, transparentColor.blue)); BitBlt (hDstDC, 0, 0, rect.width (), rect.height (), hSrcDC, rect.left, rect.top, SRCCOPY); SetBkColor (hSrcDC, oldBkColor); DeleteDC (hDstDC); return pMask; } //----------------------------------------------------------------------------- void DrawTransparent (CDrawContext* pContext, CRect& rect, const CPoint& offset, HDC hdcBitmap, POINT ptSize, HBITMAP pMask, COLORREF color) { if (pMask == NULL) { if (pfnTransparentBlt) { HDC hdcSystemContext = (HDC)pContext->getSystemContext (); long x, y; long width = rect.width (); long height = rect.height (); x = rect.x + pContext->offset.x; y = rect.y + pContext->offset.y; pfnTransparentBlt (hdcSystemContext, x, y, width, height, hdcBitmap, offset.x, offset.y, width, height, color); } else { // OPTIMIZATION: we only do four instead of EIGHT blits HDC hdcSystemContext = (HDC)pContext->getSystemContext (); HDC hdcMask = CreateCompatibleDC (hdcSystemContext); COLORREF crOldBack = SetBkColor (hdcSystemContext, 0xFFFFFF); COLORREF crOldText = SetTextColor (hdcSystemContext, 0x000000); HBITMAP bmMaskOld, maskMap; long x, y; long width = rect.width (); long height = rect.height (); x = rect.x + pContext->offset.x; y = rect.y + pContext->offset.y; // Create mask-bitmap in memory maskMap = CreateBitmap (width, height, 1, 1, NULL); bmMaskOld = (HBITMAP)SelectObject (hdcMask, maskMap); // Copy bitmap into mask-bitmap and converting it into a black'n'white mask SetBkColor (hdcBitmap, color); BitBlt (hdcMask, 0, 0, width, height, hdcBitmap, offset.x, offset.y, SRCCOPY); // Copy image masked to screen BitBlt (hdcSystemContext, x, y, width, height, hdcBitmap, offset.x, offset.y, SRCINVERT); BitBlt (hdcSystemContext, x, y, width, height, hdcMask, 0, 0, SRCAND); BitBlt (hdcSystemContext, x, y, width, height, hdcBitmap, offset.x, offset.y, SRCINVERT); DeleteObject (SelectObject (hdcMask, bmMaskOld)); DeleteDC (hdcMask); SetBkColor (hdcSystemContext, crOldBack); SetTextColor (hdcSystemContext, crOldText); } } else { // OPTIMIZATION: we only do five instead of EIGHT blits HDC hdcSystemContext = (HDC)pContext->getSystemContext (); HDC hdcMask = CreateCompatibleDC (hdcSystemContext); HDC hdcMem = CreateCompatibleDC (hdcSystemContext); HBITMAP bmAndMem; HBITMAP bmMemOld, bmMaskOld; long x, y; long width = rect.width (); long height = rect.height (); x = rect.x + pContext->offset.x; y = rect.y + pContext->offset.y; bmAndMem = CreateCompatibleBitmap(hdcSystemContext, width, height); bmMaskOld = (HBITMAP)SelectObject (hdcMask, pMask); bmMemOld = (HBITMAP)SelectObject (hdcMem, bmAndMem); BitBlt (hdcMem, 0, 0, width, height, hdcSystemContext, x, y, SRCCOPY); BitBlt (hdcMem, 0, 0, width, height, hdcBitmap, offset.x, offset.y, SRCINVERT); BitBlt (hdcMem, 0, 0, width, height, hdcMask, offset.x, offset.y, SRCAND); BitBlt (hdcMem, 0, 0, width, height, hdcBitmap, offset.x, offset.y, SRCINVERT); BitBlt (hdcSystemContext, x, y, width, height, hdcMem, 0, 0, SRCCOPY); DeleteObject (SelectObject (hdcMem, bmMemOld)); SelectObject (hdcMask, bmMaskOld); DeleteDC (hdcMem); DeleteDC(hdcMask); } } #endif //----------------------------------------------------------------------------- #if MAC || MOTIF || BEOS BEGIN_NAMESPACE_VSTGUI // return a degre value between [0, 360 * 64[ long convertPoint2Angle (CPoint &pm, CPoint &pt) { long angle; if (pt.h == pm.h) { if (pt.v < pm.v) angle = 5760; // 90 * 64 else angle = 17280; // 270 * 64 } else if (pt.v == pm.v) { if (pt.h < pm.h) angle = 11520; // 180 * 64 else angle = 0; } else { // 3666.9299 = 180 * 64 / pi angle = (long)(3666.9298 * atan ((double)(pm.v - pt.v) / (double)(pt.h - pm.h))); if (pt.v < pm.v) { if (pt.h < pm.h) angle += 11520; // 180 * 64 } else { if (pt.h < pm.h) angle += 11520; // 180 * 64 else angle += 23040; // 360 * 64 } } return angle; } END_NAMESPACE_VSTGUI #endif //----------------------------------------------------------------------------- #if MOTIF XRectangle rect; static bool first = true; //----------------------------------------------------------------------------- void _destroyCallback (Widget widget, XtPointer clientData, XtPointer callData) { CFrame* pFrame = (CFrame*)clientData; if (pFrame) { pFrame->freeGc (); pFrame->setOpenFlag (false); pFrame->pSystemWindow = 0; } } //----------------------------------------------------------------------------- void _drawingAreaCallback (Widget widget, XtPointer clientData, XtPointer callData) { CFrame* pFrame = (CFrame*)clientData; XmDrawingAreaCallbackStruct *cbs = (XmDrawingAreaCallbackStruct *)callData; XEvent *event = cbs->event; //------------------------------------- if (cbs->reason == XmCR_INPUT) { if (event->xbutton.type == ButtonRelease) return; if (event->xbutton.type != ButtonPress && event->xbutton.type != KeyPress) return; Window pWindow = pFrame->getWindow (); CDrawContext context (pFrame, pFrame->getGC (), (void*)pWindow); CPoint where (event->xbutton.x, event->xbutton.y); pFrame->mouse (&context, where); } //------------------------------------ else if (cbs->reason == XmCR_EXPOSE) { XExposeEvent *expose = (XExposeEvent*)event; #if TEST_REGION rect.x = expose->x; rect.y = expose->y; rect.width = expose->width; rect.height = expose->height; if (first) { pFrame->region = XCreateRegion (); first = false; } XUnionRectWithRegion (&rect, pFrame->region, pFrame->region); #endif if (expose->count == 0) { #if TEST_REGION XSetRegion (expose->pDisplay, pFrame->getGC (), pFrame->region); // add processus of static first to set the region to max after a total draw and destroy it the first time... #endif pFrame->draw (); #if TEST_REGION rect.x = 0; rect.y = 0; rect.width = pFrame->getWidth (); rect.height = pFrame->getHeight (); XUnionRectWithRegion (&rect, pFrame->region, pFrame->region); XSetRegion (expose->pDisplay, pFrame->getGC (), pFrame->region); XDestroyRegion (pFrame->region); first = true; #endif } } } //----------------------------------------------------------------------------- void _eventHandler (Widget w, XtPointer clientData, XEvent *event, char *p) { switch (event->type) { case EnterNotify: break; case LeaveNotify: XCrossingEvent *xevent = (XCrossingEvent*)event; CFrame* pFrame = (CFrame*)clientData; if (pFrame && pFrame->getFocusView ()) { if (xevent->x < 0 || xevent->x >= pFrame->getWidth () || xevent->y < 0 || xevent->y >= pFrame->getHeight ()) { // if button pressed => don't defocus if (xevent->state & (Button1Mask|Button2Mask|Button3Mask)) break; pFrame->getFocusView ()->looseFocus (); pFrame->setFocusView (0); } } break; } } //----------------------------------------------------------------------------- long getIndexColor8Bit (CColor color, Display *pDisplay, Colormap colormap) { long i; // search in pre-loaded color for (i = 0; i < CDrawContext::nbNewColor; i++) { if ((paletteNewColor[i].red == color.red) && (paletteNewColor[i].green == color.green) && (paletteNewColor[i].blue == color.blue)) return paletteNewColor[i].alpha; } // Allocate new color cell XColor xcolor; int red = color.red << 8; int green = color.green << 8; int blue = color.blue << 8; xcolor.red = red; xcolor.green = green; xcolor.blue = blue; if (XAllocColor (pDisplay, colormap, &xcolor)) { // store this new color if (CDrawContext::nbNewColor < 255) { paletteNewColor[CDrawContext::nbNewColor].red = color.red; paletteNewColor[CDrawContext::nbNewColor].green = color.green; paletteNewColor[CDrawContext::nbNewColor].blue = color.blue; paletteNewColor[CDrawContext::nbNewColor].alpha = xcolor.pixel; CDrawContext::nbNewColor++; } return xcolor.pixel; } // take the nearest color int diff; int min = 3 * 65536; int index = 0; XColor xcolors[256]; for (i = 0; i < 256; i++) xcolors[i].pixel = i; XQueryColors (pDisplay, colormap, xcolors, 256); for (i = 0; i < 256; i++) { diff = fabs (xcolors[i].red - red) + fabs (xcolors[i].green - green) + fabs (xcolors[i].blue - blue); if (diff < min) { min = diff; index = i; } } // store this new color if (CDrawContext::nbNewColor < 255) { paletteNewColor[CDrawContext::nbNewColor].red = color.red; paletteNewColor[CDrawContext::nbNewColor].green = color.green; paletteNewColor[CDrawContext::nbNewColor].blue = color.blue; paletteNewColor[CDrawContext::nbNewColor].alpha = index; CDrawContext::nbNewColor++; } return (index); } //----------------------------------------------------------------------------- bool xpmGetValues (char **ppDataXpm, long *pWidth, long *pHeight, long *pNcolor, long *pCpp) { // get the size of the pixmap sscanf (ppDataXpm[0], "%d %d %d %d", pWidth, pHeight, pNcolor, pCpp); return true; } //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- #elif BEOS //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- PlugView::PlugView (BRect frame, CFrame* cframe) : BView (frame, NULL, B_FOLLOW_ALL, B_WILL_DRAW), cframe (cframe) { SetViewColor (B_TRANSPARENT_COLOR); } //----------------------------------------------------------------------------- void PlugView::Draw (BRect updateRect) { cframe->draw (); } //----------------------------------------------------------------------------- void PlugView::MouseDown (BPoint where) { BMessage* m = Window ()->CurrentMessage (); int32 buttons; m->FindInt32 ("buttons", &buttons); if (buttons & B_SECONDARY_MOUSE_BUTTON && !Window ()->IsFront () && !Window ()->IsFloating ()) { Window ()->Activate (true); return; } CDrawContext context (cframe, this, NULL); CPoint here (where.x, where.y); cframe->mouse (&context, here); } //----------------------------------------------------------------------------- void PlugView::MessageReceived (BMessage *msg) { if (msg->what == B_SIMPLE_DATA) { int32 countMax = 0; // max number of references. Possibly not all valid... type_code typeFound; msg->GetInfo ("refs", &typeFound, &countMax); if (countMax > 0) { entry_ref item; int nbRealItems = 0; char ** ptrItems = new char* [countMax]; for (int k = 0; k < countMax; k++) if (msg->FindRef ("refs", k, &item) == B_OK) { BPath path (&item); if (path.InitCheck () == B_OK) ptrItems[nbRealItems++] = strdup (path.Path ()); } BPoint bwhere = msg->DropPoint (); ConvertFromScreen (&bwhere); CPoint where (bwhere.x, bwhere.y); cframe->onDrop ((void**)ptrItems, nbRealItems, kDropFiles, where); for (long i = 0; i < nbRealItems; i++) free (ptrItems[i]); delete []ptrItems; } } else BView::MessageReceived (msg); } #endif //----------------------------------------------------------------------------- #if WINDOWS //----------------------------------------------------------------------------- // Drop Implementation //----------------------------------------------------------------------------- class CDropTarget : public IDropTarget { public: CDropTarget (VSTGUI_CFrame* pFrame); virtual ~CDropTarget (); // IUnknown STDMETHOD (QueryInterface) (REFIID riid, void** object); STDMETHOD_ (ULONG, AddRef) (void); STDMETHOD_ (ULONG, Release) (void); // IDropTarget STDMETHOD (DragEnter) (IDataObject *dataObject, DWORD keyState, POINTL pt, DWORD *effect); STDMETHOD (DragOver) (DWORD keyState, POINTL pt, DWORD *effect); STDMETHOD (DragLeave) (void); STDMETHOD (Drop) (IDataObject *dataObject, DWORD keyState, POINTL pt, DWORD *effect); private: long refCount; bool accept; VSTGUI_CFrame* pFrame; }; //----------------------------------------------------------------------------- // CDropTarget //----------------------------------------------------------------------------- void* createDropTarget (VSTGUI_CFrame* pFrame) { return new CDropTarget (pFrame); } //----------------------------------------------------------------------------- CDropTarget::CDropTarget (VSTGUI_CFrame* pFrame) : refCount (0), pFrame (pFrame) { } //----------------------------------------------------------------------------- CDropTarget::~CDropTarget () { } //----------------------------------------------------------------------------- STDMETHODIMP CDropTarget::QueryInterface (REFIID riid, void** object) { if (riid == IID_IDropTarget || riid == IID_IUnknown) { *object = this; AddRef (); return NOERROR; } *object = 0; return E_NOINTERFACE; } //----------------------------------------------------------------------------- STDMETHODIMP_(ULONG) CDropTarget::AddRef (void) { return ++refCount; } //----------------------------------------------------------------------------- STDMETHODIMP_(ULONG) CDropTarget::Release (void) { refCount--; if (refCount <= 0) { delete this; return 0; } return refCount; } //----------------------------------------------------------------------------- STDMETHODIMP CDropTarget::DragEnter (IDataObject *dataObject, DWORD keyState, POINTL pt, DWORD *effect) { if (dataObject && pFrame) { gDragContainer = new CDragContainer (dataObject); CDrawContext* context = pFrame->createDrawContext (); VSTGUI_CPoint where; pFrame->getMouseLocation (context, where); pFrame->onDragEnter (context, gDragContainer, where); context->forget (); *effect = DROPEFFECT_MOVE; } else *effect = DROPEFFECT_NONE; return S_OK; } //----------------------------------------------------------------------------- STDMETHODIMP CDropTarget::DragOver (DWORD keyState, POINTL pt, DWORD *effect) { if (gDragContainer && pFrame) { CDrawContext* context = pFrame->createDrawContext (); VSTGUI_CPoint where; pFrame->getMouseLocation (context, where); pFrame->onDragMove (context, gDragContainer, where); context->forget (); *effect = DROPEFFECT_MOVE; } return S_OK; } //----------------------------------------------------------------------------- STDMETHODIMP CDropTarget::DragLeave (void) { if (gDragContainer && pFrame) { CDrawContext* context = pFrame->createDrawContext (); VSTGUI_CPoint where; pFrame->getMouseLocation (context, where); pFrame->onDragLeave (context, gDragContainer, where); context->forget (); gDragContainer->forget (); gDragContainer = 0; } return S_OK; } //----------------------------------------------------------------------------- STDMETHODIMP CDropTarget::Drop (IDataObject *dataObject, DWORD keyState, POINTL pt, DWORD *effect) { if (gDragContainer && pFrame) { CDrawContext* context = pFrame->createDrawContext (); VSTGUI_CPoint where; pFrame->getMouseLocation (context, where); pFrame->onDrop (context, gDragContainer, where); context->forget (); gDragContainer->forget (); gDragContainer = 0; } return S_OK; } //----------------------------------------------------------------------------- bool checkResolveLink (const char* nativePath, char* resolved) { const char* ext = strrchr (nativePath, '.'); if (ext && _stricmp (ext, ".lnk") == NULL) { IShellLink* psl; IPersistFile* ppf; WIN32_FIND_DATA wfd; HRESULT hres; WORD wsz[2048]; // Get a pointer to the IShellLink interface. hres = CoCreateInstance (CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_IShellLink, (void**)&psl); if (SUCCEEDED (hres)) { // Get a pointer to the IPersistFile interface. hres = psl->QueryInterface (IID_IPersistFile, (void**)&ppf); if (SUCCEEDED (hres)) { // Ensure string is Unicode. MultiByteToWideChar (CP_ACP, 0, nativePath, -1, (LPWSTR)wsz, 2048); // Load the shell link. hres = ppf->Load ((LPWSTR)wsz, STGM_READ); if (SUCCEEDED (hres)) { hres = psl->Resolve (0, MAKELONG (SLR_ANY_MATCH | SLR_NO_UI, 500)); if (SUCCEEDED (hres)) { // Get the path to the link target. hres = psl->GetPath (resolved, 2048, &wfd, SLGP_SHORTPATH); } } // Release pointer to IPersistFile interface. ppf->Release (); } // Release pointer to IShellLink interface. psl->Release (); } return SUCCEEDED(hres); } return false; } #elif MAC BEGIN_NAMESPACE_VSTGUI #if MAC_OLD_DRAG //----------------------------------------------------------------------------- // Drop Implementation //----------------------------------------------------------------------------- #if !MACX #include "Drag.h" #endif pascal static short drag_receiver (WindowPtr w, void* ref, DragReference drag); pascal static OSErr drag_tracker (DragTrackingMessage message, WindowRef theWindow, void *handlerRefCon, DragRef theDrag); static DragReceiveHandlerUPP drh; static DragTrackingHandlerUPP dth; static bool gEventDragWorks = false; //------------------------------------------------------------------------------------------- void install_drop (CFrame *frame) { drh = NewDragReceiveHandlerUPP (drag_receiver); dth = NewDragTrackingHandlerUPP (drag_tracker); #if TARGET_API_MAC_CARBON InstallReceiveHandler (drh, (WindowRef)(frame->getSystemWindow ()), (void*)frame); InstallTrackingHandler (dth, (WindowRef)(frame->getSystemWindow ()), (void*)frame); #else InstallReceiveHandler (drh, (GrafPort*)(frame->getSystemWindow ()), (void*)frame); InstallTrackingHandler (dth, (GrafPort*)(frame->getSystemWindow ()), (void*)frame); #endif } //------------------------------------------------------------------------------------------- void remove_drop (CFrame *frame) { #if TARGET_API_MAC_CARBON RemoveReceiveHandler (drh, (WindowRef)(frame->getSystemWindow ())); RemoveTrackingHandler (dth, (WindowRef)(frame->getSystemWindow ())); #else RemoveReceiveHandler (drh, (GrafPort*)(frame->getSystemWindow ())); RemoveTrackingHandler (dth, (GrafPort*)(frame->getSystemWindow ())); #endif DisposeDragReceiveHandlerUPP (drh); DisposeDragTrackingHandlerUPP (dth); } // drag tracking for visual feedback pascal OSErr drag_tracker (DragTrackingMessage message, WindowRef theWindow, void *handlerRefCon, DragRef dragRef) { #if QUARTZ if (gEventDragWorks) return noErr; #endif CFrame* frame = (CFrame*)handlerRefCon; switch (message) { case kDragTrackingEnterWindow: { if (gDragContainer) gDragContainer->forget (); gDragContainer = new CDragContainer (dragRef); CDrawContext* context = frame->createDrawContext (); VSTGUI_CPoint where; frame->setCursor (kCursorNotAllowed); frame->getMouseLocation (context, where); frame->onDragEnter (context, gDragContainer, where); context->forget (); break; } case kDragTrackingLeaveWindow: { CDrawContext* context = frame->createDrawContext (); VSTGUI_CPoint where; frame->getMouseLocation (context, where); frame->onDragLeave (context, gDragContainer, where); frame->setCursor (kCursorDefault); context->forget (); gDragContainer->forget (); gDragContainer = NULL; break; } case kDragTrackingInWindow: { CDrawContext* context = frame->createDrawContext (); VSTGUI_CPoint where; frame->getMouseLocation (context, where); frame->onDragMove (context, gDragContainer, where); context->forget (); break; } } return noErr; } //------------------------------------------------------------------------------------------- // Drop has happened in one of our's windows. // The data is either of our own type (flavour type stCA), or comes from // another app. The only data from outside that is currently accepted are // HFS-files //------------------------------------------------------------------------------------------- pascal short drag_receiver (WindowPtr w, void* ref, DragReference drag) { #if QUARTZ if (gEventDragWorks) return noErr; #endif if (!gDragContainer) return noErr; CFrame* frame = (CFrame*) ref; CDrawContext* context = frame->createDrawContext (); VSTGUI_CPoint where; frame->getMouseLocation (context, where); frame->onDrop (context, gDragContainer, where); frame->setCursor (kCursorDefault); context->forget (); gDragContainer->forget (); gDragContainer = NULL; return noErr; } #endif // MAC_OLD_DRAG #if QUARTZ #define defControlStringMask CFSTR ("net.sourceforge.vstgui.%d") bool CFrame::registerWithToolbox () { CFStringRef defControlString = CFStringCreateWithFormat (NULL, NULL, defControlStringMask, this); controlSpec.defType = kControlDefObjectClass; controlSpec.u.classRef = NULL; EventTypeSpec eventTypes[] = { {kEventClassControl, kEventControlDraw}, {kEventClassControl, kEventControlHitTest}, {kEventClassControl, kEventControlClick}, {kEventClassControl, kEventControlTrack}, {kEventClassControl, kEventControlContextualMenuClick}, {kEventClassKeyboard, kEventRawKeyDown}, {kEventClassKeyboard, kEventRawKeyRepeat}, {kEventClassMouse, kEventMouseWheelMoved}, {kEventClassControl, kEventControlDragEnter}, {kEventClassControl, kEventControlDragWithin}, {kEventClassControl, kEventControlDragLeave}, {kEventClassControl, kEventControlDragReceive}, {kEventClassControl, kEventControlInitialize}, {kEventClassControl, kEventControlGetClickActivation}, {kEventClassControl, kEventControlGetOptimalBounds}, {kEventClassScrollable, kEventScrollableGetInfo}, {kEventClassScrollable, kEventScrollableScrollTo}, {kEventClassControl, kEventControlSetFocusPart}, {kEventClassControl, kEventControlGetFocusPart}, }; ToolboxObjectClassRef controlClass = NULL; OSStatus status = RegisterToolboxObjectClass ( defControlString, NULL, GetEventTypeCount (eventTypes), eventTypes, CFrame::carbonEventHandler, this, &controlClass); if (status == noErr) controlSpec.u.classRef = controlClass; CFRelease (defControlString); return (controlSpec.u.classRef != NULL); } //------------------------------------------------------------------------------ static short keyTable[] = { VKEY_BACK, 0x33, VKEY_TAB, 0x30, VKEY_RETURN, 0x24, VKEY_PAUSE, 0x71, VKEY_ESCAPE, 0x35, VKEY_SPACE, 0x31, VKEY_END, 0x77, VKEY_HOME, 0x73, VKEY_LEFT, 0x7B, VKEY_UP, 0x7E, VKEY_RIGHT, 0x7C, VKEY_DOWN, 0x7D, VKEY_PAGEUP, 0x74, VKEY_PAGEDOWN, 0x79, VKEY_PRINT, 0x69, VKEY_ENTER, 0x4C, VKEY_HELP, 0x72, VKEY_DELETE, 0x75, VKEY_NUMPAD0, 0x52, VKEY_NUMPAD1, 0x53, VKEY_NUMPAD2, 0x54, VKEY_NUMPAD3, 0x55, VKEY_NUMPAD4, 0x56, VKEY_NUMPAD5, 0x57, VKEY_NUMPAD6, 0x58, VKEY_NUMPAD7, 0x59, VKEY_NUMPAD8, 0x5B, VKEY_NUMPAD9, 0x5C, VKEY_MULTIPLY, 0x43, VKEY_ADD, 0x45, VKEY_SUBTRACT, 0x4E, VKEY_DECIMAL, 0x41, VKEY_DIVIDE, 0x4B, VKEY_F1, 0x7A, VKEY_F2, 0x78, VKEY_F3, 0x63, VKEY_F4, 0x76, VKEY_F5, 0x60, VKEY_F6, 0x61, VKEY_F7, 0x62, VKEY_F8, 0x64, VKEY_F9, 0x65, VKEY_F10, 0x6D, VKEY_F11, 0x67, VKEY_F12, 0x6F, VKEY_NUMLOCK, 0x47, VKEY_EQUALS, 0x51 }; #ifndef kHIViewFeatureGetsFocusOnClick #define kHIViewFeatureGetsFocusOnClick (1 << 8) #endif bool hiToolboxAllowFocusChange = false; //--------------------------------------------------------------------------------------- pascal OSStatus CFrame::carbonEventHandler (EventHandlerCallRef inHandlerCallRef, EventRef inEvent, void *inUserData) { OSStatus result = eventNotHandledErr; CFrame* frame = (CFrame*)inUserData; UInt32 eventClass = GetEventClass (inEvent); UInt32 eventKind = GetEventKind (inEvent); WindowRef window = (WindowRef)frame->getSystemWindow (); // WARNING : // I've not implemented the old style resource file handling. // Use the CFBundleCopyResourceURL... functions to get your resources. switch (eventClass) { case kEventClassScrollable: { switch (eventKind) { case kEventScrollableGetInfo: { HISize cs = {frame->getWidth (), frame->getHeight ()}; SetEventParameter (inEvent, kEventParamImageSize, typeHISize, sizeof (HISize), &cs); HIPoint origin = {frame->hiScrollOffset.x, frame->hiScrollOffset.y}; SetEventParameter (inEvent, kEventParamOrigin, typeHIPoint, sizeof (HIPoint), &origin); HISize lineSize = {50.0, 20.0}; SetEventParameter(inEvent, kEventParamLineSize, typeHISize, sizeof(lineSize), &lineSize); HIRect bounds; HIViewGetBounds ((HIViewRef)frame->controlRef, &bounds); SetEventParameter(inEvent, kEventParamViewSize, typeHISize, sizeof(bounds.size), &bounds.size); result = noErr; break; } case kEventScrollableScrollTo: { HIPoint where; GetEventParameter(inEvent, kEventParamOrigin, typeHIPoint, NULL, sizeof(where), NULL, &where); frame->hiScrollOffset.x = (CCoord)where.x; frame->hiScrollOffset.y = (CCoord)where.y; HIViewSetBoundsOrigin((HIViewRef)frame->controlRef, where.x, where.y); HIViewSetNeedsDisplay((HIViewRef)frame->controlRef, true); result = noErr; break; } } break; } case kEventClassControl: { switch (eventKind) { case kEventControlInitialize: { UInt32 controlFeatures = kControlSupportsDragAndDrop | kControlSupportsFocus | kControlHandlesTracking | kControlSupportsEmbedding | kHIViewFeatureGetsFocusOnClick; SetEventParameter (inEvent, kEventParamControlFeatures, typeUInt32, sizeof (UInt32), &controlFeatures); result = noErr; break; } case kEventControlDraw: { CDrawContext* context = 0; if (frame->pFrameContext) { context = frame->pFrameContext; context->remember (); } else { CGContextRef cgcontext = 0; OSStatus res = GetEventParameter (inEvent, kEventParamCGContextRef, typeCGContextRef, NULL, sizeof (cgcontext), NULL, &cgcontext); context = new CDrawContext (frame, (res == noErr) ? cgcontext : NULL, window); } RgnHandle dirtyRegion; if (GetEventParameter (inEvent, kEventParamRgnHandle, typeQDRgnHandle, NULL, sizeof (RgnHandle), NULL, &dirtyRegion) == noErr) { bool frameWasDirty = frame->bDirty; Rect bounds; GetRegionBounds (dirtyRegion, &bounds); CRect updateRect; Rect2CRect (bounds, updateRect); WindowAttributes windowAttributes; GetWindowAttributes (window, &windowAttributes); if (!(windowAttributes & kWindowCompositingAttribute)) updateRect.offset (-context->offsetScreen.x, -context->offsetScreen.y); frame->drawRect (context, updateRect); if (frameWasDirty && updateRect != frame->size) frame->setDirty (true); } else frame->draw (context); context->forget (); result = noErr; break; } case kEventControlGetClickActivation: { ClickActivationResult activation = kActivateAndHandleClick; SetEventParameter (inEvent, kEventParamClickActivation, typeClickActivationResult, sizeof (ClickActivationResult), &activation); result = noErr; break; } case kEventControlHitTest: { ControlPartCode code = kControlContentMetaPart; SetEventParameter (inEvent, kEventParamControlPart, typeControlPartCode, sizeof (ControlPartCode), &code); result = noErr; break; } case kEventControlClick: { EventMouseButton buttonState; GetEventParameter (inEvent, kEventParamMouseButton, typeMouseButton, NULL, sizeof (EventMouseButton), NULL, &buttonState); if (buttonState == kEventMouseButtonPrimary) { result = CallNextEventHandler (inHandlerCallRef, inEvent); break; } } case kEventControlTrack: case kEventControlContextualMenuClick: { long buttons = 0; EventMouseButton buttonState; HIPoint hipoint; UInt32 modifiers; GetEventParameter (inEvent, kEventParamMouseLocation, typeHIPoint, NULL, sizeof (HIPoint), NULL, &hipoint); if (eventKind == kEventControlContextualMenuClick) buttons = kRButton; else if (eventKind == kEventControlTrack) { buttons = kLButton; GetEventParameter (inEvent, kEventParamKeyModifiers, typeUInt32, NULL, sizeof (UInt32), NULL, &modifiers); if (modifiers & cmdKey) buttons |= kControl; if (modifiers & shiftKey) buttons |= kShift; if (modifiers & optionKey) buttons |= kAlt; if (modifiers & controlKey) buttons |= kApple; } else { GetEventParameter (inEvent, kEventParamKeyModifiers, typeUInt32, NULL, sizeof (UInt32), NULL, &modifiers); GetEventParameter (inEvent, kEventParamMouseButton, typeMouseButton, NULL, sizeof (EventMouseButton), NULL, &buttonState); if (buttonState == kEventMouseButtonPrimary) buttons |= kLButton; if (buttonState == kEventMouseButtonSecondary) buttons |= kRButton; if (buttonState == kEventMouseButtonTertiary) buttons |= kMButton; if (modifiers & cmdKey) buttons |= kControl; if (modifiers & shiftKey) buttons |= kShift; if (modifiers & optionKey) buttons |= kAlt; if (modifiers & controlKey) buttons |= kApple; } //SetUserFocusWindow (window); //AdvanceKeyboardFocus (window); //SetKeyboardFocus (window, frame->controlRef, kControlFocusNextPart); WindowAttributes windowAttributes; GetWindowAttributes (window, &windowAttributes); Point point = {(short)hipoint.y, (short)hipoint.x}; if (eventKind == kEventControlClick && !(windowAttributes & kWindowCompositingAttribute)) QDGlobalToLocalPoint (GetWindowPort (window), &point); CDrawContext* context = frame->createDrawContext (); CPoint p (point.h, point.v); if (!(windowAttributes & kWindowCompositingAttribute)) p.offset (-context->offsetScreen.x, -context->offsetScreen.y); frame->mouse (context, p, buttons); context->forget (); result = noErr; break; } case kEventControlGetOptimalBounds: { HIRect optimalBounds = { {0, 0}, { frame->getWidth (), frame->getHeight ()}}; SetEventParameter (inEvent, kEventParamControlOptimalBounds, typeHIRect, sizeof (HIRect), &optimalBounds); result = noErr; break; } case kEventControlGetFocusPart: { if (hiToolboxAllowFocusChange) { ControlPartCode code = frame->hasFocus ? 127 : kControlFocusNoPart; SetEventParameter (inEvent, kEventParamControlPart, typeControlPartCode, sizeof (ControlPartCode), &code); result = noErr; } break; } case kEventControlSetFocusPart: { if (hiToolboxAllowFocusChange) { ControlPartCode code; GetEventParameter (inEvent, kEventParamControlPart, typeControlPartCode, NULL, sizeof (ControlPartCode), NULL, &code); if (code == kControlFocusNoPart) { frame->hasFocus = false; frame->setFocusView (NULL); } else { bool anfResult = false; if (code == kControlFocusNextPart) anfResult = frame->advanceNextFocusView (frame->pFocusView); else if (code == kControlFocusPrevPart) anfResult = frame->advanceNextFocusView (frame->pFocusView, true); if (anfResult) { frame->hasFocus = true; code = 127; } else { frame->hasFocus = false; code = kControlFocusNoPart; } } SetEventParameter (inEvent, kEventParamControlPart, typeControlPartCode, sizeof (code), &code); result = noErr; } break; } case kEventControlDragEnter: { #if MAC_OLD_DRAG gEventDragWorks = true; #endif DragRef dragRef; if (GetEventParameter (inEvent, kEventParamDragRef, typeDragRef, NULL, sizeof (DragRef), NULL, &dragRef) == noErr) { gDragContainer = new CDragContainer (dragRef); CDrawContext* context = frame->createDrawContext (); VSTGUI_CPoint where; frame->setCursor (kCursorNotAllowed); frame->getMouseLocation (context, where); frame->onDragEnter (context, gDragContainer, where); context->forget (); bool acceptDrop = true; SetEventParameter (inEvent, kEventParamControlWouldAcceptDrop, typeBoolean, sizeof (bool), &acceptDrop); } result = noErr; break; } case kEventControlDragWithin: { if (gDragContainer) { CDrawContext* context = frame->createDrawContext (); VSTGUI_CPoint where; frame->getMouseLocation (context, where); frame->onDragMove (context, gDragContainer, where); context->forget (); } result = noErr; break; } case kEventControlDragLeave: { if (gDragContainer) { CDrawContext* context = frame->createDrawContext (); VSTGUI_CPoint where; frame->getMouseLocation (context, where); frame->onDragLeave (context, gDragContainer, where); frame->setCursor (kCursorDefault); context->forget (); } result = noErr; break; } case kEventControlDragReceive: { if (gDragContainer) { CDrawContext* context = frame->createDrawContext (); VSTGUI_CPoint where; frame->getMouseLocation (context, where); frame->onDrop (context, gDragContainer, where); frame->setCursor (kCursorDefault); context->forget (); gDragContainer->forget (); gDragContainer = 0; } result = noErr; break; } } break; } case kEventClassMouse: { switch (eventKind) { case kEventMouseWheelMoved: { UInt32 modifiers; HIPoint windowHIPoint; SInt32 wheelDelta; EventMouseWheelAxis wheelAxis; WindowRef windowRef; GetEventParameter (inEvent, kEventParamWindowRef, typeWindowRef, NULL, sizeof (WindowRef), NULL, &windowRef); GetEventParameter (inEvent, kEventParamMouseWheelAxis, typeMouseWheelAxis, NULL, sizeof (EventMouseWheelAxis), NULL, &wheelAxis); GetEventParameter (inEvent, kEventParamMouseWheelDelta, typeLongInteger, NULL, sizeof (SInt32), NULL, &wheelDelta); GetEventParameter (inEvent, kEventParamWindowMouseLocation, typeHIPoint, NULL, sizeof (HIPoint), NULL, &windowHIPoint); GetEventParameter (inEvent, kEventParamKeyModifiers, typeUInt32, NULL, sizeof (UInt32), NULL, &modifiers); HIViewConvertPoint (&windowHIPoint, HIViewGetRoot (windowRef), frame->controlRef); CPoint p ((CCoord)windowHIPoint.x, (CCoord)windowHIPoint.y); CDrawContext* context = frame->createDrawContext (); CMouseWheelAxis axis = kMouseWheelAxisX; if (wheelAxis == kEventMouseWheelAxisY && !(modifiers & cmdKey)) axis = kMouseWheelAxisY; frame->onWheel (context, p, axis, wheelDelta); context->forget (); result = noErr; break; } } break; } case kEventClassTextInput: { switch (eventKind) { case kEventTextInputUnicodeForKeyEvent: { // The "Standard Event Handler" of a window would return noErr even though no one has handled the key event. // This prevents the "Standard Handler" to be called for this event, with the exception of the tab key as it is used for control focus changes. EventRef rawKeyEvent; GetEventParameter (inEvent, kEventParamTextInputSendKeyboardEvent, typeEventRef, NULL, sizeof (EventRef), NULL, &rawKeyEvent); if (rawKeyEvent) { UInt32 keyCode = 0; GetEventParameter (rawKeyEvent, kEventParamKeyCode, typeUInt32, NULL, sizeof (UInt32), NULL, &keyCode); if (keyCode == keyTable[VKEY_TAB+1]) return result; } result = eventPassToNextTargetErr; break; } } break; } case kEventClassKeyboard: { if (frame->hasFocus) { switch (eventKind) { case kEventRawKeyDown: case kEventRawKeyRepeat: { // todo: make this work char character = 0; UInt32 keyCode = 0; UInt32 modifiers = 0; GetEventParameter (inEvent, kEventParamKeyMacCharCodes, typeChar, NULL, sizeof (char), NULL, &character); GetEventParameter (inEvent, kEventParamKeyCode, typeUInt32, NULL, sizeof (UInt32), NULL, &keyCode); GetEventParameter (inEvent, kEventParamKeyModifiers, typeUInt32, NULL, sizeof (UInt32), NULL, &modifiers); char scanCode = keyCode; VstKeyCode vstKeyCode; memset (&vstKeyCode, 0, sizeof (VstKeyCode)); KeyboardLayoutRef layout; if (KLGetCurrentKeyboardLayout (&layout) == noErr) { const void* pKCHR = 0; KLGetKeyboardLayoutProperty (layout, kKLKCHRData, &pKCHR); if (pKCHR) { static UInt32 keyTranslateState = 0; vstKeyCode.character = KeyTranslate (pKCHR, keyCode, &keyTranslateState); if (modifiers & shiftKey) { vstKeyCode.character = toupper (vstKeyCode.character); } } } short entries = sizeof (keyTable) / (sizeof (short)); for (int i = 0; i < entries; i += 2) { if (keyTable[i + 1] == scanCode) { vstKeyCode.virt = keyTable[i]; vstKeyCode.character = 0; break; } } if (modifiers & cmdKey) vstKeyCode.modifier |= MODIFIER_CONTROL; if (modifiers & shiftKey) vstKeyCode.modifier |= MODIFIER_SHIFT; if (modifiers & optionKey) vstKeyCode.modifier |= MODIFIER_ALTERNATE; if (modifiers & controlKey) vstKeyCode.modifier |= MODIFIER_COMMAND; if (frame->onKeyDown (vstKeyCode) != -1) result = noErr; break; } } } break; } } return result; } // code from CarbonSketch Example Code #define kGenericRGBProfilePathStr "/System/Library/ColorSync/Profiles/Generic RGB Profile.icc" class QuartzStatics { public: //----------------------------------------------------------------------------- QuartzStatics () : genericRGBColorSpace (0) { CreateGenericRGBColorSpace (); CFBundleRef coregraphicsBundle = CFBundleGetBundleWithIdentifier (CFSTR("com.apple.CoreGraphics")); if (coregraphicsBundle) { _CGImageCreateWithImageInRect = (CGImageCreateWithImageInRectProc)CFBundleGetFunctionPointerForName (coregraphicsBundle, CFSTR("CGImageCreateWithImageInRect")); _CGContextStrokeLineSegments = (CGContextStrokeLineSegmentsProc)CFBundleGetFunctionPointerForName (coregraphicsBundle, CFSTR("CGContextStrokeLineSegments")); } } //----------------------------------------------------------------------------- ~QuartzStatics () { // we don't want to leak ;-) CGColorSpaceRelease (genericRGBColorSpace); if (bmpGI) CloseComponent (bmpGI); if (pngGI) CloseComponent (pngGI); if (jpgGI) CloseComponent (jpgGI); if (pictGI) CloseComponent (pictGI); bmpGI = 0; pngGI = 0; jpgGI = 0; pictGI = 0; } inline CGColorSpaceRef getGenericRGBColorSpace () { return genericRGBColorSpace; } protected: //----------------------------------------------------------------------------- CMProfileRef OpenGenericProfile(void) { CMProfileLocation loc; CMProfileRef cmProfile; loc.locType = cmPathBasedProfile; strcpy(loc.u.pathLoc.path, kGenericRGBProfilePathStr); if (CMOpenProfile(&cmProfile, &loc) != noErr) cmProfile = NULL; return cmProfile; } //----------------------------------------------------------------------------- void CreateGenericRGBColorSpace(void) { CMProfileRef genericRGBProfile = OpenGenericProfile(); if (genericRGBProfile) { genericRGBColorSpace = CGColorSpaceCreateWithPlatformColorSpace(genericRGBProfile); // we opened the profile so it is up to us to close it CMCloseProfile(genericRGBProfile); } if (genericRGBColorSpace == NULL) genericRGBColorSpace = CGColorSpaceCreateDeviceRGB (); } CGColorSpaceRef genericRGBColorSpace; }; static QuartzStatics _gQuartzStatics; inline CGColorSpaceRef GetGenericRGBColorSpace () { return _gQuartzStatics.getGenericRGBColorSpace (); } END_NAMESPACE_VSTGUI #endif #endif