diff options
author | scaraveo <unknown> | 2007-06-01 00:57:26 +0000 |
---|---|---|
committer | scaraveo <unknown> | 2007-06-01 00:57:26 +0000 |
commit | 710f716e96f6e9ee9eb410b343b78b3c4d95bc46 (patch) | |
tree | 55e5547869daa67b6a639c89825058baf75545c7 /macosx | |
parent | cac98b923422b91839f7c285a9b78ea282cd6f0a (diff) | |
download | scintilla-mirror-710f716e96f6e9ee9eb410b343b78b3c4d95bc46.tar.gz |
integrate OS X support for scintilla. a big patch with a little commit message :)
- now uses namespaces (optionally for non-os x) to avoid conflicts with OS X libraries
- several fixes in the OS X layer since the branch was commited in 2005
- used in Komodo since 2005, so pretty stable
Diffstat (limited to 'macosx')
-rw-r--r-- | macosx/PlatMacOSX.cxx | 1922 | ||||
-rw-r--r-- | macosx/PlatMacOSX.h | 101 | ||||
-rw-r--r-- | macosx/QuartzTextLayout.h | 130 | ||||
-rw-r--r-- | macosx/QuartzTextStyle.h | 105 | ||||
-rw-r--r-- | macosx/QuartzTextStyleAttribute.h | 146 | ||||
-rw-r--r-- | macosx/SciTest/English.lproj/InfoPlist.strings | bin | 0 -> 256 bytes | |||
-rw-r--r-- | macosx/SciTest/Info.plist | 24 | ||||
-rw-r--r-- | macosx/SciTest/SciTest.xcode/project.pbxproj | 287 | ||||
-rw-r--r-- | macosx/SciTest/SciTest_Prefix.pch | 5 | ||||
-rw-r--r-- | macosx/SciTest/main.cpp | 225 | ||||
-rw-r--r-- | macosx/SciTest/version.plist | 16 | ||||
-rw-r--r-- | macosx/ScintillaCallTip.cxx | 117 | ||||
-rw-r--r-- | macosx/ScintillaCallTip.h | 64 | ||||
-rw-r--r-- | macosx/ScintillaListBox.cxx | 103 | ||||
-rw-r--r-- | macosx/ScintillaListBox.h | 63 | ||||
-rw-r--r-- | macosx/ScintillaMacOSX.cxx | 2118 | ||||
-rw-r--r-- | macosx/ScintillaMacOSX.h | 192 | ||||
-rw-r--r-- | macosx/TCarbonEvent.cxx | 519 | ||||
-rw-r--r-- | macosx/TCarbonEvent.h | 230 | ||||
-rw-r--r-- | macosx/TRect.h | 496 | ||||
-rw-r--r-- | macosx/TView.cxx | 1462 | ||||
-rw-r--r-- | macosx/TView.h | 286 | ||||
-rw-r--r-- | macosx/deps.mak | 315 | ||||
-rw-r--r-- | macosx/makefile | 95 |
24 files changed, 9021 insertions, 0 deletions
diff --git a/macosx/PlatMacOSX.cxx b/macosx/PlatMacOSX.cxx new file mode 100644 index 000000000..149b99ceb --- /dev/null +++ b/macosx/PlatMacOSX.cxx @@ -0,0 +1,1922 @@ +// Scintilla source code edit control +// PlatMacOSX.cxx - implementation of platform facilities on MacOS X/Carbon +// Based on work by Evan Jones (c) 2002 <ejones@uwaterloo.ca> +// Based on PlatGTK.cxx Copyright 1998-2002 by Neil Hodgson <neilh@scintilla.org> +// The License.txt file describes the conditions under which this software may be distributed. + +#include <cstring> +#include <cstdio> +#include <cstdlib> + +#include <assert.h> + +#include <sys/time.h> + +#include <Carbon/Carbon.h> +#include "QuartzTextLayout.h" +#include "TCarbonEvent.h" + +#include "Platform.h" +#include "Scintilla.h" +#include "PlatMacOSX.h" +#include "XPM.h" + +using namespace Scintilla; + +#include "ScintillaWidget.h" + + +extern sptr_t scintilla_send_message(void* sci, unsigned int iMessage, uptr_t wParam, sptr_t lParam); + +inline CGRect PRectangleToCGRect( PRectangle& rc ) { + return CGRectMake( rc.left, rc.top, rc.Width(), rc.Height() ); +} + +inline PRectangle CGRectToPRectangle( const CGRect& rect ) { + PRectangle rc; + rc.left = (int)( rect.origin.x + 0.5 ); + rc.top = (int)( rect.origin.y + 0.5 ); + rc.right = (int)( rect.origin.x + rect.size.width + 0.5 ); + rc.bottom = (int)( rect.origin.y + rect.size.height + 0.5 ); + return rc; +} + +Scintilla::Point Scintilla::Point::FromLong(long lpoint) { + return Scintilla::Point( + Platform::LowShortFromLong(lpoint), + Platform::HighShortFromLong(lpoint)); +} + +// The Palette is just ignored on Mac OS X. OS X runs "Millions" or "Thousands" of colours. +Scintilla::Palette::Palette() { +} + +Scintilla::Palette::~Palette() { +} + +void Scintilla::Palette::Release() { +} + +// Do nothing if it "wants" a colour. Copy the colour from desired to allocated if it is "finding" a colour. +void Scintilla::Palette::WantFind(ColourPair &cp, bool want) { + if (want) { + } else { + cp.allocated.Set(cp.desired.AsLong()); + } +} + +void Scintilla::Palette::Allocate(Window &/*w*/) { + // OS X always runs in thousands or millions of colours +} + +Font::Font() : id(0) {} + +Font::~Font() { Release(); } + + +void Font::Create(const char *faceName, int /*characterSet*/, + int size, bool bold, bool italic, bool /*extraFontFlag*/) { + // TODO: How should I handle the characterSet request? + Release(); + + id = new QuartzTextStyle(); + + // Find the font + QuartzFont font( faceName, strlen( faceName ) ); + + // We set Font, Size, Bold, Italic + QuartzTextSize textSize( size ); + QuartzTextBold isBold( bold ); + QuartzTextItalic isItalic( italic ); + + // Actually set the attributes + QuartzTextStyleAttribute* attributes[] = { &font, &textSize, &isBold, &isItalic }; + reinterpret_cast<QuartzTextStyle*>( id )->setAttributes( attributes, sizeof( attributes ) / sizeof( *attributes ) ); + + //ATSStyleRenderingOptions rendering = kATSStyleNoAntiAliasing; + //reinterpret_cast<QuartzTextStyle*>( id )->setAttribute( kATSUStyleRenderingOptionsTag, sizeof( rendering ), &rendering ); + + // TODO: Why do I have to manually set this? + reinterpret_cast<QuartzTextStyle*>( id )->setFontFeature( kLigaturesType, kCommonLigaturesOffSelector ); +} + +void Font::Release() { + if (id) + delete reinterpret_cast<QuartzTextStyle*>( id ); + + id = 0; +} + +SurfaceImpl::SurfaceImpl() { + bitmapData = NULL; // Release will try and delete bitmapData if != NULL +#ifdef SUPPORT_PORT + port = NULL; +#endif + gc = NULL; + Release(); +} + +SurfaceImpl::~SurfaceImpl() { + Release(); +} + +void SurfaceImpl::Release() { + if ( bitmapData != NULL ) + { + delete[] bitmapData; + // We only "own" the graphics context if we are a bitmap context + if ( gc != NULL ) CGContextRelease( gc ); + } +#ifdef SUPPORT_PORT + if ( port != NULL && gc != NULL) { + QDEndCGContext(port, &gc); + } +#endif + bitmapData = NULL; + gc = NULL; + + bitmapWidth = 0; + bitmapHeight = 0; + x = 0; + y = 0; + //inited = false; +} + +bool SurfaceImpl::Initialised() { + // We are initalised if the graphics context is not null + return gc != NULL;// || port != NULL; +} + +void SurfaceImpl::Init(WindowID /*wid*/) { + // To be able to draw, the surface must get a CGContext handle. We save the graphics port, + // then aquire/release the context on an as-need basis (see above). + // XXX Docs on QDBeginCGContext are light, a better way to do this would be good. + // AFAIK we should not hold onto a context retrieved this way, thus the need for + // aquire/release of the context. + + Release(); +#ifdef SUPPORT_PORT + // Note, this seems to be unecessary, I have not seen any functionality loss by + // doing nothing in this method. + + WindowRef window = GetControlOwner(reinterpret_cast<HIViewRef>(wid)); + port = GetWindowPort(window); + QDBeginCGContext(port, &gc); +#endif +} + +void SurfaceImpl::Init(SurfaceID sid, WindowID /*wid*/) { + Release(); + gc = reinterpret_cast<CGContextRef>( sid ); + CGContextSetLineWidth( gc, 1.0 ); +} + +void SurfaceImpl::InitPixMap(int width, int height, Surface* /*surface_*/, WindowID /*wid*/) { + Release(); + // Create a new bitmap context, along with the RAM for the bitmap itself + bitmapWidth = width; + bitmapHeight = height; + + const int bitmapBytesPerRow = (width * BYTES_PER_PIXEL); + const int bitmapByteCount = (bitmapBytesPerRow * height); + + // create an RGB color space + CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); + assert( colorSpace != NULL ); + + // create the bitmap + bitmapData = new uint8_t[ bitmapByteCount ]; + assert( bitmapData != NULL ); + if( bitmapData != NULL ) + { + // create the context + gc = CGBitmapContextCreate( bitmapData, + width, + height, + BITS_PER_COMPONENT, + bitmapBytesPerRow, + colorSpace, + kCGImageAlphaPremultipliedLast); + + if( gc == NULL ) + { + // the context couldn't be created for some reason, + // and we have no use for the bitmap without the context + delete[] bitmapData; + bitmapData = NULL; + } + } + + // the context retains the color space, so we can release it + CGColorSpaceRelease( colorSpace ); + + assert( gc != NULL && bitmapData != NULL ); + + // "Erase" to white + CGContextClearRect( gc, CGRectMake( 0, 0, width, height ) ); + CGContextSetRGBFillColor( gc, 1.0, 1.0, 1.0, 1.0 ); + CGContextFillRect( gc, CGRectMake( 0, 0, width, height ) ); +} + +void SurfaceImpl::PenColour(ColourAllocated fore) { + if (gc) { + ColourDesired colour( fore.AsLong() ); + + // Set the Stroke color to match + CGContextSetRGBStrokeColor( gc, colour.GetRed() / 255.0, colour.GetGreen() / 255.0, colour.GetBlue() / 255.0, 1.0 ); + } +} + +void SurfaceImpl::FillColour(const ColourAllocated& back) { + if (gc) { + ColourDesired colour( back.AsLong() ); + + // Set the Fill color to match + CGContextSetRGBFillColor( gc, colour.GetRed() / 255.0, colour.GetGreen() / 255.0, colour.GetBlue() / 255.0, 1.0 ); + } +} + +CGImageRef SurfaceImpl::GetImage() { + // For now, assume that GetImage can only be called on PixMap surfaces + if ( bitmapData == NULL ) return NULL; + + CGContextFlush( gc ); + + // create an RGB color space + CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); + assert( colorSpace != NULL ); + + const int bitmapBytesPerRow = ((int) bitmapWidth * BYTES_PER_PIXEL); + const int bitmapByteCount = (bitmapBytesPerRow * (int) bitmapHeight); + + // Create a data provider + CGDataProviderRef dataProvider = CGDataProviderCreateWithData( NULL, bitmapData, bitmapByteCount, NULL ); + assert( dataProvider != NULL ); + + // create the CGImage + CGImageRef image = CGImageCreate( bitmapWidth, + bitmapHeight, + BITS_PER_COMPONENT, + BITS_PER_PIXEL, + bitmapBytesPerRow, + colorSpace, + kCGImageAlphaPremultipliedLast, + dataProvider, + NULL, + 0, + kCGRenderingIntentDefault ); + assert( image != NULL ); + + // the image retains the color space, so we can release it + CGColorSpaceRelease( colorSpace ); + colorSpace = NULL; + + // Done with the data provider + CGDataProviderRelease( dataProvider ); + dataProvider = NULL; + + return image; +} + +int SurfaceImpl::LogPixelsY() { + return 72; +} + +int SurfaceImpl::DeviceHeightFont(int points) { + int logPix = LogPixelsY(); + return (points * logPix + logPix / 2) / 72; +} + +void SurfaceImpl::MoveTo(int x_, int y_) { + x = x_; + y = y_; +} + +void SurfaceImpl::LineTo(int x_, int y_) { + CGContextBeginPath( gc ); + // Because Quartz is based on floating point, lines are drawn with half their colour + // on each side of the line. Integer coordinates specify the INTERSECTION of the pixel + // divison lines. If you specify exact pixel values, you get a line that + // is twice as thick but half as intense. To get pixel aligned rendering, + // we render the "middle" of the pixels by adding 0.5 to the coordinates. + CGContextMoveToPoint( gc, x + 0.5, y + 0.5 ); + CGContextAddLineToPoint( gc, x_ + 0.5, y_ + 0.5 ); + CGContextStrokePath( gc ); + x = x_; + y = y_; +} + +void SurfaceImpl::Polygon(Scintilla::Point *pts, int npts, ColourAllocated fore, + ColourAllocated back) { + // Allocate memory for the array of points + CGPoint *points = new CGPoint[ npts ]; + + for (int i = 0;i < npts;i++) { + // Quartz floating point issues: plot the MIDDLE of the pixels + points[i].x = pts[i].x + 0.5; + points[i].y = pts[i].y + 0.5; + } + + CGContextBeginPath( gc ); + + // Set colours + FillColour(back); + PenColour(fore); + + // Draw the polygon + CGContextAddLines( gc, points, npts ); + // TODO: Should the path be automatically closed, or is that the caller's responsability? + // Explicitly close the path, so it is closed for stroking AND filling (implicit close = filling only) + CGContextClosePath( gc ); + CGContextDrawPath( gc, kCGPathFillStroke ); + + // Deallocate memory + delete points; + points = NULL; +} + +void SurfaceImpl::RectangleDraw(PRectangle rc, ColourAllocated fore, ColourAllocated back) { + if ( gc ) { + CGContextBeginPath( gc ); + FillColour(back); + PenColour(fore); + + // Quartz integer -> float point conversion fun (see comment in SurfaceImpl::LineTo) + // We subtract 1 from the Width() and Height() so that all our drawing is within the area defined + // by the PRectangle. Otherwise, we draw one pixel too far to the right and bottom. + // TODO: Create some version of PRectangleToCGRect to do this conversion for us? + CGContextAddRect( gc, CGRectMake( rc.left + 0.5, rc.top + 0.5, rc.Width() - 1, rc.Height() - 1 ) ); + CGContextDrawPath( gc, kCGPathFillStroke ); + } +} + +void SurfaceImpl::FillRectangle(PRectangle rc, ColourAllocated back) { + if ( gc ) { + //CGContextBeginPath( gc ); + FillColour(back); + + CGRect rect = PRectangleToCGRect( rc ); + + CGContextFillRect( gc, rect ); + //CGContextDrawPath( gc, kCGPathFill ); + } +} + +void drawImageRefCallback( CGImageRef pattern, CGContextRef gc ) +{ + CGContextDrawImage( gc, CGRectMake( 0, 0, CGImageGetWidth( pattern ), CGImageGetHeight( pattern ) ), pattern ); +} + +void SurfaceImpl::FillRectangle(PRectangle rc, Surface &surfacePattern) { + SurfaceImpl& patternSurface = static_cast<SurfaceImpl &>(surfacePattern); + + // For now, assume that copy can only be called on PixMap surfaces + // Shows up black + CGImageRef image = patternSurface.GetImage(); + if ( image == NULL ) + { + FillRectangle(rc, ColourAllocated(0)); + return; + } + + assert( image != NULL ); + + const CGPatternCallbacks drawImageCallbacks = { 0, reinterpret_cast<CGPatternDrawPatternCallback>( drawImageRefCallback ), NULL }; + + CGPatternRef pattern = CGPatternCreate( image, + CGRectMake( 0, 0, patternSurface.bitmapWidth, patternSurface.bitmapHeight ), + CGAffineTransformIdentity, + patternSurface.bitmapWidth, + patternSurface.bitmapHeight, + kCGPatternTilingNoDistortion, + true, + &drawImageCallbacks + ); + assert( pattern != NULL ); + + // Create a pattern color space + CGColorSpaceRef colorSpace = CGColorSpaceCreatePattern( NULL ); + assert( colorSpace != NULL ); + + CGContextSaveGState( gc ); + CGContextSetFillColorSpace( gc, colorSpace ); + + // Unlike the documentation, you MUST pass in a "components" parameter: + // For coloured patterns it is the alpha value. + const float alpha = 1.0; + CGContextSetFillPattern( gc, pattern, &alpha ); + CGContextFillRect( gc, PRectangleToCGRect( rc ) ); + + CGContextRestoreGState( gc ); + + // Free the color space, the pattern and image + CGColorSpaceRelease( colorSpace ); + colorSpace = NULL; + CGPatternRelease( pattern ); + pattern = NULL; + CGImageRelease( image ); + image = NULL; +} + +void SurfaceImpl::RoundedRectangle(PRectangle rc, ColourAllocated fore, ColourAllocated back) { + // TODO: Look at the Win32 API to determine what this is supposed to do: + // ::RoundRect(hdc, rc.left + 1, rc.top, rc.right - 1, rc.bottom, 8, 8 ); + + // Create a rectangle with semicircles at the corners + const int MAX_RADIUS = 4; + int radius = Platform::Minimum( MAX_RADIUS, rc.Height()/2 ); + radius = Platform::Minimum( radius, rc.Width()/2 ); + + // Points go clockwise, starting from just below the top left + // Corners are kept together, so we can easily create arcs to connect them + CGPoint corners[4][3] = + { + { + { rc.left, rc.top + radius }, + { rc.left, rc.top }, + { rc.left + radius, rc.top }, + }, + { + { rc.right - radius - 1, rc.top }, + { rc.right - 1, rc.top }, + { rc.right - 1, rc.top + radius }, + }, + { + { rc.right - 1, rc.bottom - radius - 1 }, + { rc.right - 1, rc.bottom - 1 }, + { rc.right - radius - 1, rc.bottom - 1 }, + }, + { + { rc.left + radius, rc.bottom - 1 }, + { rc.left, rc.bottom - 1 }, + { rc.left, rc.bottom - radius - 1 }, + }, + }; + + // Align the points in the middle of the pixels + // TODO: Should I include these +0.5 in the array creation code above? + for( int i = 0; i < 4*3; ++ i ) + { + CGPoint* c = (CGPoint*) corners; + c[i].x += 0.5; + c[i].y += 0.5; + } + + PenColour( fore ); + FillColour( back ); + + // Move to the last point to begin the path + CGContextBeginPath( gc ); + CGContextMoveToPoint( gc, corners[3][2].x, corners[3][2].y ); + + for ( int i = 0; i < 4; ++ i ) + { + CGContextAddLineToPoint( gc, corners[i][0].x, corners[i][0].y ); + CGContextAddArcToPoint( gc, corners[i][1].x, corners[i][1].y, corners[i][2].x, corners[i][2].y, radius ); + } + + // Close the path to enclose it for stroking and for filling, then draw it + CGContextClosePath( gc ); + CGContextDrawPath( gc, kCGPathFillStroke ); +} + +void SurfaceImpl::AlphaRectangle(PRectangle rc, int cornerSize, ColourAllocated fill, int alphaFill, + ColourAllocated outline, int alphaOutline, int flags) { + // XXX TODO + if ( gc ) { + CGContextBeginPath( gc ); + //FillColour(fill); + PenColour(outline); + + // Quartz integer -> float point conversion fun (see comment in SurfaceImpl::LineTo) + // We subtract 1 from the Width() and Height() so that all our drawing is within the area defined + // by the PRectangle. Otherwise, we draw one pixel too far to the right and bottom. + // TODO: Create some version of PRectangleToCGRect to do this conversion for us? + CGContextAddRect( gc, CGRectMake( rc.left + 0.5, rc.top + 0.5, rc.Width() - 1, rc.Height() - 1 ) ); + CGContextDrawPath( gc, kCGPathFill ); + } +} + +void SurfaceImpl::Ellipse(PRectangle rc, ColourAllocated fore, ColourAllocated back) { + // Drawing an ellipse with bezier curves. Code modified from: + // http://www.codeguru.com/gdi/ellipse.shtml + // MAGICAL CONSTANT to map ellipse to beziers 2/3*(sqrt(2)-1) + const double EToBConst = 0.2761423749154; + + CGSize offset = CGSizeMake((int)(rc.Width() * EToBConst), (int)(rc.Height() * EToBConst)); + CGPoint centre = CGPointMake((rc.left + rc.right) / 2, (rc.top + rc.bottom) / 2); + + // The control point array + CGPoint cCtlPt[13]; + + // Assign values to all the control points + cCtlPt[0].x = + cCtlPt[1].x = + cCtlPt[11].x = + cCtlPt[12].x = rc.left + 0.5; + cCtlPt[5].x = + cCtlPt[6].x = + cCtlPt[7].x = rc.right - 0.5; + cCtlPt[2].x = + cCtlPt[10].x = centre.x - offset.width + 0.5; + cCtlPt[4].x = + cCtlPt[8].x = centre.x + offset.width + 0.5; + cCtlPt[3].x = + cCtlPt[9].x = centre.x + 0.5; + + cCtlPt[2].y = + cCtlPt[3].y = + cCtlPt[4].y = rc.top + 0.5; + cCtlPt[8].y = + cCtlPt[9].y = + cCtlPt[10].y = rc.bottom - 0.5; + cCtlPt[7].y = + cCtlPt[11].y = centre.y + offset.height + 0.5; + cCtlPt[1].y = + cCtlPt[5].y = centre.y - offset.height + 0.5; + cCtlPt[0].y = + cCtlPt[12].y = + cCtlPt[6].y = centre.y + 0.5; + + FillColour(back); + PenColour(fore); + + CGContextBeginPath( gc ); + CGContextMoveToPoint( gc, cCtlPt[0].x, cCtlPt[0].y ); + + for ( int i = 1; i < 13; i += 3 ) + { + CGContextAddCurveToPoint( gc, cCtlPt[i].x, cCtlPt[i].y, cCtlPt[i+1].x, cCtlPt[i+1].y, cCtlPt[i+2].x, cCtlPt[i+2].y ); + } + + // Close the path to enclose it for stroking and for filling, then draw it + CGContextClosePath( gc ); + CGContextDrawPath( gc, kCGPathFillStroke ); +} + +void SurfaceImpl::CopyImageRectangle(Surface &surfaceSource, PRectangle srcRect, PRectangle dstRect) +{ + SurfaceImpl& source = static_cast<SurfaceImpl &>(surfaceSource); + CGImageRef image = source.GetImage(); + + CGRect src = PRectangleToCGRect(srcRect); + CGRect dst = PRectangleToCGRect(dstRect); + + /* source from QuickDrawToQuartz2D.pdf on developer.apple.com */ + float w = (float) CGImageGetWidth(image); + float h = (float) CGImageGetHeight(image); + CGRect drawRect = CGRectMake (0, 0, w, h); + if (!CGRectEqualToRect (src, dst)) + { + float sx = CGRectGetWidth(dst) / CGRectGetWidth(src); + float sy = CGRectGetHeight(dst) / CGRectGetHeight(src); + float dx = CGRectGetMinX(dst) - (CGRectGetMinX(src) * sx); + float dy = CGRectGetMinY(dst) - (CGRectGetMinY(src) * sy); + drawRect = CGRectMake (dx, dy, w*sx, h*sy); + } + CGContextSaveGState (gc); + CGContextClipToRect (gc, dst); + CGContextDrawImage (gc, drawRect, image); + CGContextRestoreGState (gc); +} + +void SurfaceImpl::Copy(PRectangle rc, Scintilla::Point from, Surface &surfaceSource) { + // Maybe we have to make the Surface two contexts: + // a bitmap context which we do all the drawing on, and then a "real" context + // which we copy the output to when we call "Synchronize". Ugh! Gross and slow! + + // For now, assume that copy can only be called on PixMap surfaces + SurfaceImpl& source = static_cast<SurfaceImpl &>(surfaceSource); + + // Get the CGImageRef + CGImageRef image = source.GetImage(); + // If we could not get an image reference, fill the rectangle black + if ( image == NULL ) + { + FillRectangle( rc, ColourAllocated( 0 ) ); + return; + } + + assert( image != NULL ); + + // Now draw the image on the surface + + // Some fancy clipping work is required here: draw only inside of rc + CGContextSaveGState( gc ); + CGContextClipToRect( gc, PRectangleToCGRect( rc ) ); + + //Platform::DebugPrintf(stderr, "Copy: CGContextDrawImage: (%d, %d) - (%d X %d)\n", rc.left - from.x, rc.top - from.y, source.bitmapWidth, source.bitmapHeight ); + CGContextDrawImage( gc, CGRectMake( rc.left - from.x, rc.top - from.y, source.bitmapWidth, source.bitmapHeight ), image ); + + // Undo the clipping fun + CGContextRestoreGState( gc ); + + // Done with the image + CGImageRelease( image ); + image = NULL; +} + +QuartzTextLayout* SurfaceImpl::GetTextLayout( Font &font_, const char *s, int len ) +{ + // create the text layout + QuartzTextLayout* textLayout = new QuartzTextLayout( gc ); + OSStatus err = textLayout->setText( reinterpret_cast<const UInt8*>( s ), len, ( unicodeMode ? kCFStringEncodingUTF8 : kCFStringEncodingASCII ) ); + if (err != noErr) { + fprintf(stderr, "SurfaceImpl::GetTextLayout error calling textLayout->setText %d %s\n", err, unicodeMode?"Invalid UTF8":"Unknown error"); + if (unicodeMode) + err = textLayout->setText( reinterpret_cast<const UInt8*>( s ), len, kCFStringEncodingASCII ); + if (err != noErr) + return NULL; + } + + textLayout->setStyle( *reinterpret_cast<QuartzTextStyle*>( font_.GetID() ) ); + + // TODO: If I could modify Scintilla to use ATSUHighlightText, this would not be required. + // However, using this setting makes Scintilla's rendering match TextEdit's (except for the antialiasing rules) + ATSLineLayoutOptions rendering = kATSLineUseDeviceMetrics; + textLayout->setControl( kATSULineLayoutOptionsTag, sizeof( rendering ), &rendering ); + + return textLayout; +} + +void SurfaceImpl::DrawTextNoClip(PRectangle rc, Font &font_, int ybase, const char *s, int len, + ColourAllocated fore, ColourAllocated back) { + + FillRectangle(rc, back); + DrawTextTransparent( rc, font_, ybase, s, len, fore ); +} + +void SurfaceImpl::DrawTextClipped(PRectangle rc, Font &font_, int ybase, const char *s, int len, + ColourAllocated fore, ColourAllocated back) { + + CGContextSaveGState( gc ); + CGContextClipToRect( gc, PRectangleToCGRect( rc ) ); + DrawTextNoClip( rc, font_, ybase, s, len, fore, back ); + CGContextRestoreGState( gc ); +} + +void SurfaceImpl::DrawTextTransparent(PRectangle rc, Font &font_, int ybase, const char *s, int len, ColourAllocated fore) { + PLATFORM_ASSERT( gc != NULL ); + QuartzTextLayout* textLayout = GetTextLayout( font_, s, len ); + if (!textLayout) return; + // The Quartz RGB fill color influences the ATSUI color + FillColour(fore); + + // Draw the text, with the Y axis flipped + textLayout->draw( rc.left, ybase, true ); + + // Get rid of the layout object + delete textLayout; + textLayout = NULL; +} + +void SurfaceImpl::MeasureWidths(Font &font_, const char *s, int len, int *positions) { + // sample at http://developer.apple.com/samplecode/ATSUICurveAccessDemo/listing1.html + // sample includes use of ATSUGetGlyphInfo which would be better for older + // OSX systems. We should expand to using that on older systems as well. + QuartzTextLayout* textLayout = GetTextLayout( font_, s, len ); + if (!textLayout) return; + + // Get the UNICODE character length + UniCharCount unicodeLength, unicodePosition; + OSStatus err; + err = ATSUGetTextLocation( textLayout->getLayout(), NULL, NULL, NULL, &unicodeLength, NULL ); + assert( err == noErr ); + + ATSLayoutRecord *layoutRecords; + ItemCount numRecords; + // Get the arrays of glyph information + verify_noerr( ATSUDirectGetLayoutDataArrayPtrFromTextLayout( + textLayout->getLayout(), 0, + kATSUDirectDataLayoutRecordATSLayoutRecordCurrent, + (void **)&layoutRecords, &numRecords) ); + + int i, count; + long position; + unsigned char uch; + unsigned char mask; + FontID fontid = font_.GetID(); + + for ( unicodePosition = 0, i = 0; i < len && unicodePosition < numRecords; unicodePosition ++ ) { + if (fontid) { + + // note: an extra layoutRecord is provided (eg. numRecords will be one + // more than unicodeLength). Each record contains the left x + // coordinate, but we need the right x coordinate, so we skip + // the first layoutRecord, thus unicodePosition+1. + position = Fix2Long( layoutRecords[unicodePosition+1].realPos ); + uch = s[i]; + positions[i++] = position; + + // If we are using unicode (UTF8), map the Unicode position back to the UTF8 characters, + // as 1 unicode character can map to multiple UTF8 characters. + // See: http://www.tbray.org/ongoing/When/200x/2003/04/26/UTF + // Or: http://www.cl.cam.ac.uk/~mgk25/unicode.html + if ( unicodeMode ) { + mask = 0xc0; + count = 1; + // Add one additonal byte for each extra high order one in the byte + while ( uch >= mask && count < 8 ) { + assert( i < len ); + positions[i++] = position; + count ++; + mask = mask >> 1 | 0x80; // add an additional one in the highest order position + } + assert( count <= 8 ); + } + } else { + positions[i++] = (i == 0) ? 1 : positions[i-1] + 1; + } + } + verify_noerr( ATSUDirectReleaseLayoutDataArrayPtr(NULL, kATSUDirectDataLayoutRecordATSLayoutRecordCurrent, (void **)&layoutRecords) ); + // Get rid of the layout object + delete textLayout; + textLayout = NULL; +} + +int SurfaceImpl::WidthText(Font &font_, const char *s, int len) { + if (font_.GetID()) + { + QuartzTextLayout* textLayout = GetTextLayout( font_, s, len ); + if (!textLayout) return 0; + + // TODO: Maybe I should add some sort of text measurement features to QuartzTextLayout? + unsigned long actualNumberOfBounds = 0; + ATSTrapezoid glyphBounds; + + // We get a single bound, since the text should only require one. If it requires more, there is an issue + if ( ATSUGetGlyphBounds( textLayout->getLayout(), 0, 0, kATSUFromTextBeginning, kATSUToTextEnd, kATSUseDeviceOrigins, 1, &glyphBounds, &actualNumberOfBounds ) != noErr || actualNumberOfBounds != 1 ) + { + Platform::DebugDisplay( "ATSUGetGlyphBounds failed in WidthText" ); + // Get rid of the layout object + delete textLayout; + textLayout = NULL; + return 0; + } + + //Platform::DebugPrintf( "WidthText: \"%*s\" = %ld\n", len, s, Fix2Long( glyphBounds.upperRight.x - glyphBounds.upperLeft.x ) ); + + // Get rid of the layout object + delete textLayout; + textLayout = NULL; + return Fix2Long( glyphBounds.upperRight.x - glyphBounds.upperLeft.x ); + } + return 1; +} + +int SurfaceImpl::WidthChar(Font &font_, char ch) { + char str[2] = { ch, '\0' }; + if (font_.GetID()) + { + QuartzTextLayout* textLayout = GetTextLayout( font_, str, 1 ); + if (!textLayout) return 0; + + // TODO: Maybe I should add some sort of text measurement features to QuartzTextLayout? + unsigned long actualNumberOfBounds = 0; + ATSTrapezoid glyphBounds; + + // We get a single bound, since the text should only require one. If it requires more, there is an issue + if ( ATSUGetGlyphBounds( textLayout->getLayout(), 0, 0, kATSUFromTextBeginning, kATSUToTextEnd, kATSUseDeviceOrigins, 1, &glyphBounds, &actualNumberOfBounds ) != noErr || actualNumberOfBounds != 1 ) + { + Platform::DebugDisplay( "ATSUGetGlyphBounds failed in WidthChar" ); + // Get rid of the layout object + delete textLayout; + textLayout = NULL; + return 0; + } + + // Get rid of the layout object + delete textLayout; + textLayout = NULL; + return Fix2Long( glyphBounds.upperRight.x - glyphBounds.upperLeft.x ); + } + else + return 1; +} + +// Three possible strategies for determining ascent and descent of font: +// 1) Call ATSUGetGlyphBounds with string containing all letters, numbers and punctuation. +// 2) Use the ascent and descent fields of the font. +// 3) Call ATSUGetGlyphBounds with string as 1 but also including accented capitals. +// Smallest values given by 1 and largest by 3 with 2 in between. +// Techniques 1 and 2 sometimes chop off extreme portions of ascenders and +// descenders but are mostly OK except for accented characters which are +// rarely used in code. + +// This string contains a good range of characters to test for size. +const char sizeString[] = "`~!@#$%^&*()-_=+\\|[]{};:\"\'<,>.?/1234567890" + "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; + +int SurfaceImpl::Ascent(Font &font_) { + if (!font_.GetID()) + return 1; + + ATSUTextMeasurement ascent = reinterpret_cast<QuartzTextStyle*>( font_.GetID() )->getAttribute<ATSUTextMeasurement>( kATSUAscentTag ); + return Fix2Long( ascent ); +} + +int SurfaceImpl::Descent(Font &font_) { + if (!font_.GetID()) + return 1; + + ATSUTextMeasurement descent = reinterpret_cast<QuartzTextStyle*>( font_.GetID() )->getAttribute<ATSUTextMeasurement>( kATSUDescentTag ); + return Fix2Long( descent ); +} + +int SurfaceImpl::InternalLeading(Font &) { + // TODO: How do we get EM_Size? + // internal leading = ascent - descent - EM_size + return 0; +} + +int SurfaceImpl::ExternalLeading(Font &font_) { + if (!font_.GetID()) + return 1; + + ATSUTextMeasurement lineGap = reinterpret_cast<QuartzTextStyle*>( font_.GetID() )->getAttribute<ATSUTextMeasurement>( kATSULeadingTag ); + return Fix2Long( lineGap ); +} + +int SurfaceImpl::Height(Font &font_) { + return Ascent(font_) + Descent(font_); +} + +int SurfaceImpl::AverageCharWidth(Font &font_) { + + if (!font_.GetID()) + return 1; + + const int sizeStringLength = (sizeof( sizeString ) / sizeof( sizeString[0] ) - 1); + int width = WidthText( font_, sizeString, sizeStringLength ); + + return (int) ((width / (float) sizeStringLength) + 0.5); + + /* + ATSUStyle textStyle = reinterpret_cast<QuartzTextStyle*>( font_.GetID() )->getATSUStyle(); + ATSUFontID fontID; + + ByteCount actualSize = 0; + if ( ATSUGetAttribute( textStyle, kATSUFontTag, sizeof( fontID ), &fontID, &actualSize ) != noErr ) + { +Platform::DebugDisplay( "ATSUGetAttribute failed" ); + return 1; + } + + ATSFontMetrics metrics; + memset( &metrics, 0, sizeof( metrics ) ); + if ( ATSFontGetHorizontalMetrics( fontID, kATSOptionFlagsDefault, &metrics ) != noErr ) + { + Platform::DebugDisplay( "ATSFontGetHorizontalMetrics failed in AverageCharWidth" ); + return 1; + } + + printf( "%f %f %f\n", metrics.avgAdvanceWidth * 32, metrics.ascent * 32, metrics.descent * 32 ); + + return (int) (metrics.avgAdvanceWidth + 0.5);*/ +} + +int SurfaceImpl::SetPalette(Scintilla::Palette *, bool) { + // Mac OS X is always true colour (I think) so this doesn't matter + return 0; +} + +void SurfaceImpl::SetClip(PRectangle rc) { + CGContextClipToRect( gc, PRectangleToCGRect( rc ) ); +} + +void SurfaceImpl::FlushCachedState() { + CGContextSynchronize( gc ); +} + +void SurfaceImpl::SetUnicodeMode(bool unicodeMode_) { + unicodeMode = unicodeMode_; +} + +void SurfaceImpl::SetDBCSMode(int codePage) { + // TODO: Implement this +} + +Surface *Surface::Allocate() { + return new SurfaceImpl( ); +} + +Window::~Window() {} + +void Window::Destroy() { + if (windowRef) { + DisposeWindow(reinterpret_cast<WindowRef>( windowRef )); + } + id = 0; +} + +bool Window::HasFocus() { + // TODO: Test this + return HIViewSubtreeContainsFocus( reinterpret_cast<HIViewRef>( id ) ); +} + +PRectangle Window::GetPosition() { + // Before any size allocated pretend its 1000 wide so not scrolled + PRectangle rc(0, 0, 1000, 1000); + + // The frame rectangle gives the position of this view inside the parent view + if (id) { + HIRect controlFrame; + HIViewGetFrame( reinterpret_cast<HIViewRef>( id ), &controlFrame ); + rc = CGRectToPRectangle( controlFrame ); + } + + return rc; +} + +void Window::SetPosition(PRectangle rc) { + // Moves this view inside the parent view + if ( id ) + { + // Set the frame on the view, the function handles the rest + CGRect r = PRectangleToCGRect( rc ); + HIViewSetFrame( reinterpret_cast<HIViewRef>( id ), &r ); + } +} + +void Window::SetPositionRelative(PRectangle rc, Window window) { + // used to actually move child windows (ie. listbox/calltip) so we have to move + // the window, not the hiview + if (windowRef) { + // we go through some contortions here to get an accurate location for our + // child windows. This is necessary due to the multiple ways an embedding + // app may be setup. See SciTest/main.c (GOOD && BAD) for test case. + WindowRef relativeWindow = GetControlOwner(reinterpret_cast<HIViewRef>( window.GetID() )); + WindowRef thisWindow = reinterpret_cast<WindowRef>( windowRef ); + + Rect portBounds; + ::GetWindowBounds(relativeWindow, kWindowStructureRgn, &portBounds); + //fprintf(stderr, "portBounds %d %d %d %d\n", portBounds.left, portBounds.top, portBounds.right, portBounds.bottom); + PRectangle hbounds = window.GetPosition(); + //fprintf(stderr, "hbounds %d %d %d %d\n", hbounds.left, hbounds.top, hbounds.right, hbounds.bottom); + HIViewRef parent = HIViewGetSuperview(reinterpret_cast<HIViewRef>( window.GetID() )); + Rect pbounds; + GetControlBounds(parent, &pbounds); + //fprintf(stderr, "pbounds %d %d %d %d\n", pbounds.left, pbounds.top, pbounds.right, pbounds.bottom); + + PRectangle bounds; + bounds.top = portBounds.top + pbounds.top + hbounds.top + rc.top; + bounds.bottom = bounds.top + rc.Height(); + bounds.left = portBounds.left + pbounds.left + hbounds.left + rc.left; + bounds.right = bounds.left + rc.Width(); + //fprintf(stderr, "bounds %d %d %d %d\n", bounds.left, bounds.top, bounds.right, bounds.bottom); + + MoveWindow(thisWindow, bounds.left, bounds.top, false); + SizeWindow(thisWindow, bounds.Width(), bounds.Height(), true); + + SetPosition(PRectangle(0,0,rc.Width(),rc.Height())); + } else { + SetPosition(rc); + } +} + +PRectangle Window::GetClientPosition() { + // This means, in MacOS X terms, get the "frame bounds". Call GetPosition, just like on Win32. + return GetPosition(); +} + +void Window::Show(bool show) { + if ( id ) { + HIViewSetVisible( reinterpret_cast<HIViewRef>( id ), show ); + } + // this is necessary for calltip/listbox + if (windowRef) { + WindowRef thisWindow = reinterpret_cast<WindowRef>( windowRef ); + if (show) { + ShowWindow( thisWindow ); + DrawControls( thisWindow ); + } else + HideWindow( thisWindow ); + } +} + +void Window::InvalidateAll() { + if ( id ) { + OSStatus err; + err = HIViewSetNeedsDisplay( reinterpret_cast<HIViewRef>( id ), true ); + assert( err == noErr ); + } +} + +void Window::InvalidateRectangle(PRectangle rc) { + if (id) { + // Create a rectangular region + RgnHandle region = NewRgn(); + assert( region != NULL ); + SetRectRgn( region, rc.left, rc.top, rc.right, rc.bottom ); + + // Make that region invalid + OSStatus err; + err = HIViewSetNeedsDisplayInRegion( reinterpret_cast<HIViewRef>( id ), region, true ); + assert( err == noErr ); + DisposeRgn( region ); + } +} + +void Window::SetFont(Font &) { + // TODO: Do I need to implement this? MSDN: specifies the font that a control is to use when drawing text. +} + +void Window::SetCursor(Cursor curs) { + if (id) { + // TODO: This isn't really implemented correctly. I should be using + // mouse tracking rectangles to only set the mouse cursor when it is over the control + ThemeCursor cursor; + + switch ( curs ) { + case cursorText: + cursor = kThemeIBeamCursor; + break; + case cursorArrow: + cursor = kThemeArrowCursor; + break; + case cursorWait: + cursor = kThemeWatchCursor; + break; + case cursorHoriz: + cursor = kThemeResizeLeftRightCursor; + break; + case cursorVert: + case cursorReverseArrow: + case cursorUp: + default: + cursor = kThemeArrowCursor; + break; + } + + SetThemeCursor( cursor ); + } +} + +void Window::SetTitle(const char *s) { + WindowRef window = GetControlOwner(reinterpret_cast<HIViewRef>( id )); + CFStringRef title = CFStringCreateWithCString(kCFAllocatorDefault, s, kCFStringEncodingMacRoman); + SetWindowTitleWithCFString(window, title); + CFRelease(title); +} + +ListBox::ListBox() {} + +ListBox::~ListBox() {} + +static const OSType scintillaListBoxType = 'sclb'; + +enum { + kItemsPerContainer = 1, + kIconColumn = 'icon', + kTextColumn = 'text' +}; +static SInt32 kScrollBarWidth = 0; + +class LineData { + int *types; + CFStringRef *strings; + int len; + int maximum; +public: + LineData() :types(0), strings(0), len(0), maximum(0) {} + ~LineData() { + Clear(); + } + void Clear() { + delete []types; + types = 0; + for (int i=0; i<maximum; i++) { + if (strings[i]) CFRelease(strings[i]); + } + delete []strings; + strings = 0; + len = 0; + maximum = 0; + } + void Add(int index, int type, CFStringRef str ) { + if (index >= maximum) { + if (index >= len) { + int lenNew = (index+1) * 2; + int *typesNew = new int[lenNew]; + CFStringRef *stringsNew = new CFStringRef[lenNew]; + for (int i=0; i<maximum; i++) { + typesNew[i] = types[i]; + stringsNew[i] = strings[i]; + } + delete []types; + delete []strings; + types = typesNew; + strings = stringsNew; + len = lenNew; + } + while (maximum < index) { + types[maximum] = 0; + strings[maximum] = 0; + maximum++; + } + } + types[index] = type; + strings[index] = str; + if (index == maximum) { + maximum++; + } + } + int GetType(int index) { + if (index < maximum) { + return types[index]; + } else { + return 0; + } + } + CFStringRef GetString(int index) { + if (index < maximum) { + return strings[index]; + } else { + return 0; + } + } +}; + +class ListBoxImpl : public ListBox { +private: + ControlRef lb; + XPMSet xset; + int lineHeight; + bool unicodeMode; + int desiredVisibleRows; + unsigned int maxItemCharacters; + unsigned int aveCharWidth; + Font font; + int maxWidth; + + void InstallDataBrowserCustomCallbacks(); + void ConfigureDataBrowser(); + + static pascal OSStatus WindowEventHandler(EventHandlerCallRef inCallRef, + EventRef inEvent, + void *inUserData ); + EventHandlerRef eventHandler; + +protected: + WindowRef windowRef; + +public: + LineData ld; + CallBackAction doubleClickAction; + void *doubleClickActionData; + + ListBoxImpl() : lb(NULL), lineHeight(10), unicodeMode(false), + desiredVisibleRows(5), maxItemCharacters(0), aveCharWidth(8), + doubleClickAction(NULL), doubleClickActionData(NULL) + { + if (kScrollBarWidth == 0) + GetThemeMetric(kThemeMetricScrollBarWidth, &kScrollBarWidth); + } + + ~ListBoxImpl() {}; + void SetFont(Font &font); + void Create(Window &parent, int ctrlID, Scintilla::Point pt, int lineHeight_, bool unicodeMode_); + void SetAverageCharWidth(int width); + void SetVisibleRows(int rows); + int GetVisibleRows() const; + PRectangle GetDesiredRect(); + int CaretFromEdge(); + void Clear(); + void Append(char *s, int type = -1); + int Length(); + void Select(int n); + int GetSelection(); + int Find(const char *prefix); + void GetValue(int n, char *value, int len); + void Sort(); + void RegisterImage(int type, const char *xpm_data); + void ClearRegisteredImages(); + void SetDoubleClickAction(CallBackAction action, void *data) { + doubleClickAction = action; + doubleClickActionData = data; + } + + int IconWidth(); + void ShowHideScrollbar(); +#ifdef DB_TABLE_ROW_HEIGHT + void SetRowHeight(DataBrowserItemID itemID); +#endif + + void DrawRow(DataBrowserItemID item, + DataBrowserPropertyID property, + DataBrowserItemState itemState, + const Rect *theRect); + + void SetList(const char* list, char separator, char typesep); +}; + +ListBox *ListBox::Allocate() { + ListBoxImpl *lb = new ListBoxImpl(); + return lb; +} + +void ListBoxImpl::Create(Window &/*parent*/, int /*ctrlID*/, Scintilla::Point /*pt*/, + int lineHeight_, bool unicodeMode_) { + lineHeight = lineHeight_; + unicodeMode = unicodeMode_; + maxWidth = 1000; + + WindowClass windowClass = kHelpWindowClass; + WindowAttributes attributes = kWindowNoAttributes; + Rect contentBounds; + WindowRef outWindow; + + contentBounds.top = contentBounds.left = 0; + contentBounds.right = 100; + contentBounds.bottom = lineHeight * desiredVisibleRows; + + CreateNewWindow(windowClass, attributes, &contentBounds, &outWindow); + + InstallStandardEventHandler(GetWindowEventTarget(outWindow)); + + ControlRef root; + CreateRootControl(outWindow, &root); + + CreateDataBrowserControl(outWindow, &contentBounds, kDataBrowserListView, &lb); + +#ifdef DB_TABLE_ROW_HEIGHT + // XXX does not seem to have any effect + SetDataBrowserTableViewRowHeight(lb, lineHeight); +#endif + + // get rid of the frame, forces databrowser to the full size + // of the window + Boolean frameAndFocus = false; + SetControlData(lb, kControlNoPart, kControlDataBrowserIncludesFrameAndFocusTag, + sizeof(frameAndFocus), &frameAndFocus); + + ListBoxImpl* lbThis = this; + SetControlProperty( lb, scintillaListBoxType, 0, sizeof( this ), &lbThis ); + + ConfigureDataBrowser(); + InstallDataBrowserCustomCallbacks(); + + // install event handlers + static const EventTypeSpec kWindowEvents[] = + { + { kEventClassMouse, kEventMouseDown }, + { kEventClassMouse, kEventMouseMoved }, + }; + + eventHandler = NULL; + InstallWindowEventHandler( outWindow, WindowEventHandler, + GetEventTypeCount( kWindowEvents ), + kWindowEvents, this, &eventHandler ); + + id = lb; + SetControlVisibility(lb, true, true); + SetControl(lb); + SetWindow(outWindow); +} + +pascal OSStatus ListBoxImpl::WindowEventHandler( + EventHandlerCallRef inCallRef, + EventRef inEvent, + void* inUserData ) +{ + + switch (GetEventClass(inEvent)) { + case kEventClassMouse: + switch (GetEventKind(inEvent)) + { + case kEventMouseMoved: + { + SetThemeCursor( kThemeArrowCursor ); + break; + } + case kEventMouseDown: + { + // we cannot handle the double click from the databrowser notify callback as + // calling doubleClickAction causes the listbox to be destroyed. It is + // safe to do it from this event handler since the destroy event will be queued + // until we're done here. + TCarbonEvent event( inEvent ); + EventMouseButton inMouseButton; + event.GetParameter<EventMouseButton>( kEventParamMouseButton, typeMouseButton, &inMouseButton ); + + UInt32 inClickCount; + event.GetParameter( kEventParamClickCount, &inClickCount ); + if (inMouseButton == kEventMouseButtonPrimary && inClickCount == 2) { + // handle our single mouse click now + ListBoxImpl* listbox = reinterpret_cast<ListBoxImpl*>( inUserData ); + const WindowRef window = GetControlOwner(listbox->lb); + const HIViewRef rootView = HIViewGetRoot( window ); + HIViewRef targetView = NULL; + HIViewGetViewForMouseEvent( rootView, inEvent, &targetView ); + if ( targetView == listbox->lb ) + { + if (listbox->doubleClickAction != NULL) { + listbox->doubleClickAction(listbox->doubleClickActionData); + } + } + } + } + } + } + return eventNotHandledErr; +} + +#ifdef DB_TABLE_ROW_HEIGHT +void ListBoxImpl::SetRowHeight(DataBrowserItemID itemID) +{ + // XXX does not seem to have any effect + SetDataBrowserTableViewItemRowHeight(lb, itemID, lineHeight); +} +#endif + +void ListBoxImpl::DrawRow(DataBrowserItemID item, + DataBrowserPropertyID property, + DataBrowserItemState itemState, + const Rect *theRect) +{ + Rect row = *theRect; + row.left = 0; + + ColourPair fore; + + if (itemState == kDataBrowserItemIsSelected) { + long systemVersion; + Gestalt( gestaltSystemVersion, &systemVersion ); + // Panther DB starts using kThemeBrushSecondaryHighlightColor for inactive browser hilighting + if ( (systemVersion >= 0x00001030) && (IsControlActive( lb ) == false) ) + SetThemePen( kThemeBrushSecondaryHighlightColor, 32, true ); + else + //SetThemePen( kThemeBrushPrimaryHighlightColor, 32, true ); + SetThemePen( kThemeBrushAlternatePrimaryHighlightColor, 32, true ); + + PaintRect(&row); + fore = ColourDesired(0xff,0xff,0xff); + } + + int widthPix = xset.GetWidth() + 2; + int pixId = ld.GetType(item - 1); + XPM *pxpm = xset.Get(pixId); + + char s[255]; + GetValue(item - 1, s, 255); + + Surface *surfaceItem = Surface::Allocate(); + if (surfaceItem) { + CGContextRef cgContext; + GrafPtr port; + Rect bounds; + + GetControlBounds(lb, &bounds); + GetPort( &port ); + QDBeginCGContext( port, &cgContext ); + + CGContextSaveGState( cgContext ); + CGContextTranslateCTM(cgContext, 0, bounds.bottom - bounds.top); + CGContextScaleCTM(cgContext, 1.0, -1.0); + + surfaceItem->Init(cgContext, NULL); + + int left = row.left; + if (pxpm) { + PRectangle rc(left + 1, row.top, + left + 1 + widthPix, row.bottom); + pxpm->Draw(surfaceItem, rc); + } + + // draw the text + PRectangle trc(left + 2 + widthPix, row.top, row.right, row.bottom); + int ascent = surfaceItem->Ascent(font) - surfaceItem->InternalLeading(font); + int ytext = trc.top + ascent + 1; + trc.bottom = ytext + surfaceItem->Descent(font) + 1; + surfaceItem->DrawTextTransparent( trc, font, ytext, s, strlen(s), fore.allocated ); + + CGContextRestoreGState( cgContext ); + QDEndCGContext( port, &cgContext ); + delete surfaceItem; + } +} + + +pascal void ListBoxDrawItemCallback(ControlRef browser, DataBrowserItemID item, + DataBrowserPropertyID property, + DataBrowserItemState itemState, + const Rect *theRect, SInt16 gdDepth, + Boolean colorDevice) +{ + if (property != kIconColumn) return; + ListBoxImpl* lbThis = NULL; + OSStatus err; + err = GetControlProperty( browser, scintillaListBoxType, 0, sizeof( lbThis ), NULL, &lbThis ); + // adjust our rect + lbThis->DrawRow(item, property, itemState, theRect); + +} + +void ListBoxImpl::ConfigureDataBrowser() +{ + DataBrowserViewStyle viewStyle; + DataBrowserSelectionFlags selectionFlags; + ::GetDataBrowserViewStyle(lb, &viewStyle); + + ::SetDataBrowserHasScrollBars(lb, false, true); + ::SetDataBrowserListViewHeaderBtnHeight(lb, 0); + ::GetDataBrowserSelectionFlags(lb, &selectionFlags); + ::SetDataBrowserSelectionFlags(lb, selectionFlags |= kDataBrowserSelectOnlyOne); + // if you change the hilite style, also change the style in ListBoxDrawItemCallback + ::SetDataBrowserTableViewHiliteStyle(lb, kDataBrowserTableViewFillHilite); + + Rect insetRect; + ::GetDataBrowserScrollBarInset(lb, &insetRect); + + insetRect.right = kScrollBarWidth - 1; + ::SetDataBrowserScrollBarInset(lb, &insetRect); + + switch (viewStyle) + { + case kDataBrowserListView: + { + DataBrowserListViewColumnDesc iconCol; + iconCol.headerBtnDesc.version = kDataBrowserListViewLatestHeaderDesc; + iconCol.headerBtnDesc.minimumWidth = 0; + iconCol.headerBtnDesc.maximumWidth = maxWidth; + iconCol.headerBtnDesc.titleOffset = 0; + iconCol.headerBtnDesc.titleString = NULL; + iconCol.headerBtnDesc.initialOrder = kDataBrowserOrderIncreasing; + + iconCol.headerBtnDesc.btnFontStyle.flags = kControlUseJustMask; + iconCol.headerBtnDesc.btnFontStyle.just = teFlushLeft; + + iconCol.headerBtnDesc.btnContentInfo.contentType = kControlContentTextOnly; + + iconCol.propertyDesc.propertyID = kIconColumn; + iconCol.propertyDesc.propertyType = kDataBrowserCustomType; + iconCol.propertyDesc.propertyFlags = kDataBrowserListViewSelectionColumn; + + ::AddDataBrowserListViewColumn(lb, &iconCol, kDataBrowserListViewAppendColumn); + } break; + + } +} + +void ListBoxImpl::InstallDataBrowserCustomCallbacks() +{ + DataBrowserCustomCallbacks callbacks; + + callbacks.version = kDataBrowserLatestCustomCallbacks; + verify_noerr(InitDataBrowserCustomCallbacks(&callbacks)); + callbacks.u.v1.drawItemCallback = NewDataBrowserDrawItemUPP(ListBoxDrawItemCallback); + callbacks.u.v1.hitTestCallback = NULL;//NewDataBrowserHitTestUPP(ListBoxHitTestCallback); + callbacks.u.v1.trackingCallback = NULL;//NewDataBrowserTrackingUPP(ListBoxTrackingCallback); + callbacks.u.v1.editTextCallback = NULL; + callbacks.u.v1.dragRegionCallback = NULL; + callbacks.u.v1.acceptDragCallback = NULL; + callbacks.u.v1.receiveDragCallback = NULL; + + SetDataBrowserCustomCallbacks(lb, &callbacks); +} + +void ListBoxImpl::SetFont(Font &font_) { + // Having to do this conversion is LAME + QuartzTextStyle *ts = reinterpret_cast<QuartzTextStyle*>( font_.GetID() ); + ControlFontStyleRec style; + ATSUAttributeValuePtr value; + ATSUFontID fontID; + style.flags = kControlUseFontMask | kControlUseSizeMask | kControlAddToMetaFontMask; + ts->getAttribute( kATSUFontTag, sizeof(fontID), &fontID, NULL ); + ATSUFontIDtoFOND(fontID, &style.font, NULL); + ts->getAttribute( kATSUSizeTag, sizeof(Fixed), &value, NULL ); + style.size = ((SInt16)FixRound((SInt32)value)); + SetControlFontStyle(lb, &style); + +#ifdef DB_TABLE_ROW_HEIGHT + // XXX this doesn't *stick* + ATSUTextMeasurement ascent = ts->getAttribute<ATSUTextMeasurement>( kATSUAscentTag ); + ATSUTextMeasurement descent = ts->getAttribute<ATSUTextMeasurement>( kATSUDescentTag ); + lineHeight = Fix2Long( ascent ) + Fix2Long( descent ); + SetDataBrowserTableViewRowHeight(lb, lineHeight + lineLeading); +#endif + + // !@&^#%$ we cant copy Font, but we need one for our custom drawing + Str255 fontName; + if (FMGetFontFamilyName(style.font, fontName) != kFMInvalidFontFamilyErr) { + // make sure we conver to a proper C string first. + char cFontName[255]; + CopyPascalStringToC(fontName, cFontName); + font.Create((const char *)cFontName, 0, style.size, false, false); + } +} + +void ListBoxImpl::SetAverageCharWidth(int width) { + aveCharWidth = width; +} + +void ListBoxImpl::SetVisibleRows(int rows) { + desiredVisibleRows = rows; +} + +int ListBoxImpl::GetVisibleRows() const { + // XXX Windows & GTK do this, but it seems incorrect to me. Other logic + // to do with visible rows is essentially the same across platforms. + return desiredVisibleRows; + /* + // This would be more correct + int rows = Length(); + if ((rows == 0) || (rows > desiredVisibleRows)) + rows = desiredVisibleRows; + return rows; + */ +} + +PRectangle ListBoxImpl::GetDesiredRect() { + PRectangle rcDesired = GetPosition(); + + // XXX because setting the line height on the table doesnt + // *stick*, we'll have to suffer and just use whatever + // the table desides is the correct height. + UInt16 itemHeight;// = lineHeight; + GetDataBrowserTableViewRowHeight(lb, &itemHeight); + + int rows = Length(); + if ((rows == 0) || (rows > desiredVisibleRows)) + rows = desiredVisibleRows; + + rcDesired.bottom = itemHeight * rows; + int width = maxItemCharacters; + if (width < 12) + width = 12; + // XXX use the quartz text stuff to figure out the correct string width + rcDesired.right = rcDesired.left + width * (aveCharWidth+aveCharWidth/4); + if (rcDesired.right > maxWidth) { + rcDesired.right = maxWidth; + } + if (Length() > rows) + rcDesired.right += kScrollBarWidth; + rcDesired.right += IconWidth(); + return rcDesired; +} + +void ListBoxImpl::ShowHideScrollbar() { + int rows = Length(); + if (rows > desiredVisibleRows) { + ::SetDataBrowserHasScrollBars(lb, false, true); + } else { + ::SetDataBrowserHasScrollBars(lb, false, false); + } +} + +int ListBoxImpl::IconWidth() { + return xset.GetWidth() + 2; +} + +int ListBoxImpl::CaretFromEdge() { + return 0; +} + +void ListBoxImpl::Clear() { + // passing NULL to "items" arg 4 clears the list + maxItemCharacters = 0; + ld.Clear(); + AddDataBrowserItems (lb, kDataBrowserNoItem, 0, NULL, kDataBrowserItemNoProperty); +} + +void ListBoxImpl::Append(char *s, int type) { + int count = Length(); + CFStringRef r = CFStringCreateWithCString(NULL, s, kTextEncodingMacRoman); + ld.Add(count, type, r); + + DataBrowserItemID items[1]; + items[0] = count + 1; + AddDataBrowserItems (lb, kDataBrowserNoItem, 1, items, kDataBrowserItemNoProperty); + ShowHideScrollbar(); + + size_t len = strlen(s); + if (maxItemCharacters < len) + maxItemCharacters = len; + +} + +void ListBoxImpl::SetList(const char* list, char separator, char typesep) { + // XXX copied from PlatGTK, should be in base class + Clear(); + int count = strlen(list) + 1; + char *words = new char[count]; + if (words) { + memcpy(words, list, count); + char *startword = words; + char *numword = NULL; + int i = 0; + for (; words[i]; i++) { + if (words[i] == separator) { + words[i] = '\0'; + if (numword) + *numword = '\0'; + Append(startword, numword?atoi(numword + 1):-1); + startword = words + i + 1; + numword = NULL; + } else if (words[i] == typesep) { + numword = words + i; + } + } + if (startword) { + if (numword) + *numword = '\0'; + Append(startword, numword?atoi(numword + 1):-1); + } + delete []words; + } +} + +int ListBoxImpl::Length() { + UInt32 numItems = 0; + GetDataBrowserItemCount(lb, kDataBrowserNoItem, false, kDataBrowserItemAnyState, &numItems); + return (int)numItems; +} + +void ListBoxImpl::Select(int n) { + DataBrowserItemID items[1]; + items[0] = n + 1; + SetDataBrowserSelectedItems(lb, 1, items, kDataBrowserItemsAssign); + RevealDataBrowserItem(lb, items[0], kIconColumn, kDataBrowserRevealOnly); + // force update on selection + Draw1Control(lb); +} + +int ListBoxImpl::GetSelection() { + Handle selectedItems = NewHandle(0); + GetDataBrowserItems(lb, kDataBrowserNoItem, true, kDataBrowserItemIsSelected, selectedItems); + UInt32 numSelectedItems = GetHandleSize(selectedItems)/sizeof(DataBrowserItemID); + if (numSelectedItems == 0) { + return -1; + } + HLock( selectedItems ); + DataBrowserItemID *individualItem = (DataBrowserItemID*)( *selectedItems ); + DataBrowserItemID selected[numSelectedItems]; + selected[0] = *individualItem; + HUnlock( selectedItems ); + return selected[0] - 1; +} + +int ListBoxImpl::Find(const char *prefix) { + int count = Length(); + char s[255]; + for (int i = 0; i < count; i++) { + GetValue(i, s, 255); + if (s[0] != NULL && (0 == strncmp(prefix, s, strlen(prefix)))) { + return i; + } + } + return - 1; +} + +void ListBoxImpl::GetValue(int n, char *value, int len) { + CFStringRef textString = ld.GetString(n); + if (textString == NULL) { + value[0] = '\0'; + return; + } + CFIndex numUniChars = CFStringGetLength( textString ); + + // XXX how do we know the encoding of the listbox? + CFStringEncoding encoding = kCFStringEncodingUTF8; //( IsUnicodeMode() ? kCFStringEncodingUTF8 : kCFStringEncodingASCII); + CFIndex maximumByteLength = CFStringGetMaximumSizeForEncoding( numUniChars, encoding ) + 1; + char* text = new char[maximumByteLength]; + CFIndex usedBufferLength = 0; + CFStringGetBytes( textString, CFRangeMake( 0, numUniChars ), encoding, + '?', false, reinterpret_cast<UInt8*>( text ), + maximumByteLength, &usedBufferLength ); + text[usedBufferLength] = '\0'; // null terminate the ASCII/UTF8 string + + if (text && len > 0) { + strncpy(value, text, len); + value[len - 1] = '\0'; + } else { + value[0] = '\0'; + } + delete text; +} + +void ListBoxImpl::Sort() { + // TODO: Implement this + fprintf(stderr, "ListBox::Sort\n"); +} + +void ListBoxImpl::RegisterImage(int type, const char *xpm_data) { + xset.Add(type, xpm_data); +} + +void ListBoxImpl::ClearRegisteredImages() { + xset.Clear(); +} + +Menu::Menu() : id(0) { } + +void Menu::CreatePopUp() { + // TODO: Could I just feed a constant menu ID parameter, or does + // it really need to be unique? + static int nextMenuID = 1; + Destroy(); + OSStatus err; + err = CreateNewMenu( nextMenuID++, 0, reinterpret_cast<MenuRef*>( &id ) ); + assert( noErr == err && id != NULL ); +} + +void Menu::Destroy() { + if ( id != NULL ) + { + ReleaseMenu( reinterpret_cast<MenuRef>( id ) ); + id = NULL; + } +} + +void Menu::Show(Point pt, Window &) { + UInt32 userSelection = 0; + SInt16 menuId = 0; + MenuItemIndex menuItem = 0; + ::Point globalPoint; + globalPoint.h = pt.x; + globalPoint.v = pt.y; + OSStatus err; + err = ContextualMenuSelect( reinterpret_cast<MenuRef>( id ), globalPoint, + false, kCMHelpItemRemoveHelp, NULL, + NULL, &userSelection, + &menuId, + &menuItem + ); + // The system should always handle the command for us, so we should get userCanceledErr + assert( /*noErr == err ||*/ userCanceledErr == err ); +} + +// TODO: Consider if I should be using GetCurrentEventTime instead of gettimeoday +ElapsedTime::ElapsedTime() { + struct timeval curTime; + int retVal; + retVal = gettimeofday( &curTime, NULL ); + assert( retVal == 0 ); + + bigBit = curTime.tv_sec; + littleBit = curTime.tv_usec; +} + +double ElapsedTime::Duration(bool reset) { + struct timeval curTime; + int retVal; + retVal = gettimeofday( &curTime, NULL ); + assert( retVal == 0 ); + long endBigBit = curTime.tv_sec; + long endLittleBit = curTime.tv_usec; + double result = 1000000.0 * (endBigBit - bigBit); + result += endLittleBit - littleBit; + result /= 1000000.0; + if (reset) { + bigBit = endBigBit; + littleBit = endLittleBit; + } + return result; +} + +ColourDesired Platform::Chrome() { + RGBColor c; + GetThemeBrushAsColor(kThemeBrushButtonActiveDarkShadow , 24, true, &c); + return ColourDesired(c.red>>8, c.green>>8, c.blue>>8); +} + +ColourDesired Platform::ChromeHighlight() { + RGBColor c; + GetThemeBrushAsColor(kThemeBrushButtonInactiveLightShadow , 24, true, &c); + return ColourDesired(c.red>>8, c.green>>8, c.blue>>8); +} + +static Str255 PlatformDefaultFontName; +const char *Platform::DefaultFont() { + long id = HighShortFromLong(GetScriptVariable(smCurrentScript, smScriptAppFondSize)); + FMGetFontFamilyName(id, PlatformDefaultFontName); + return (const char *)PlatformDefaultFontName; +} + +int Platform::DefaultFontSize() { + return LowShortFromLong(GetScriptVariable(smCurrentScript, smScriptAppFondSize)); +} + +unsigned int Platform::DoubleClickTime() { + // Convert from ticks to milliseconds. I think it would be better to use the events to tell us + // when we have a double and triple click, but what do I know? + return static_cast<unsigned int>( TicksToEventTime( GetDblTime() ) / kEventDurationMillisecond ); +} + +bool Platform::MouseButtonBounce() { + return false; +} + +bool Platform::WaitMouseMoved(Scintilla::Point pt) { + ::Point mpt; + mpt.v = pt.x; + mpt.h = pt.y; + return ::WaitMouseMoved(mpt); +} + +bool Platform::IsKeyDown(int keyCode) { + return false; + // TODO: Map Scintilla/Windows key codes to Mac OS X key codes + // TODO: Do I need this? + /* + // Inspired by code at: http://www.sover.net/~jams/Morgan/docs/GameInputMethods.txt + + // Get the keys + KeyMap keys; + GetKeys( keys ); + + // Calculate the key map index + long keyMapIndex = keys[keyCode/8]; + // Calculate the individual bit to check + short bitToCheck = keyCode % 8; + // Check the status of the key + return ( keyMapIndex >> bitToCheck ) & 0x01; + */ +} + +long Platform::SendScintilla(WindowID w, unsigned int msg, unsigned long wParam, long lParam) { + return scintilla_send_message( w, msg, wParam, lParam ); +} + +bool Platform::IsDBCSLeadByte(int /*codePage*/, char /*ch*/) { + // TODO: Implement this + return false; +} + +int Platform::DBCSCharLength(int /*codePage*/, const char* /*s*/) { + // TODO: Implement this + return 1; +} + +int Platform::DBCSCharMaxLength() { + // TODO: Implement this + //return CFStringGetMaximumSizeForEncoding( 1, CFStringEncoding encoding ); + return 2; +} + +// These are utility functions not really tied to a platform +int Platform::Minimum(int a, int b) { + if (a < b) + return a; + else + return b; +} + +int Platform::Maximum(int a, int b) { + if (a > b) + return a; + else + return b; +} + +//#define TRACE +#ifdef TRACE + +void Platform::DebugDisplay(const char *s) { + fprintf( stderr, s ); +} + +void Platform::DebugPrintf(const char *format, ...) { + const int BUF_SIZE = 2000; + char buffer[BUF_SIZE]; + + va_list pArguments; + va_start(pArguments, format); + vsnprintf(buffer, BUF_SIZE, format, pArguments); + va_end(pArguments); + Platform::DebugDisplay(buffer); +} + +#else + +void Platform::DebugDisplay(const char *) {} + +void Platform::DebugPrintf(const char *, ...) {} + +#endif + +// Not supported for GTK+ +static bool assertionPopUps = true; + +bool Platform::ShowAssertionPopUps(bool assertionPopUps_) { + bool ret = assertionPopUps; + assertionPopUps = assertionPopUps_; + return ret; +} + +void Platform::Assert(const char *c, const char *file, int line) { + char buffer[2000]; + sprintf(buffer, "Assertion [%s] failed at %s %d", c, file, line); + strcat(buffer, "\r\n"); + Platform::DebugDisplay(buffer); + abort(); +} + +int Platform::Clamp(int val, int minVal, int maxVal) { + assert( minVal <= maxVal ); + if (val > maxVal) + val = maxVal; + if (val < minVal) + val = minVal; + return val; +} diff --git a/macosx/PlatMacOSX.h b/macosx/PlatMacOSX.h new file mode 100644 index 000000000..168ba74ee --- /dev/null +++ b/macosx/PlatMacOSX.h @@ -0,0 +1,101 @@ +#ifndef PLATMACOSX_H +#define PLATMACOSX_H + +#include <cstring> +#include <cstdio> +#include <cstdlib> + +#include <assert.h> + +#include <sys/time.h> + +#include <Carbon/Carbon.h> +#include "QuartzTextLayout.h" + +#include "Platform.h" +#include "Scintilla.h" + +namespace Scintilla { + +class SurfaceImpl : public Surface { +private: + bool unicodeMode; + float x; + float y; + +#ifdef SUPPORT_PORT + CGrafPtr port; +#endif + CGContextRef gc; + + + /** If the surface is a bitmap context, contains a reference to the bitmap data. */ + uint8_t* bitmapData; + /** If the surface is a bitmap context, stores the dimensions of the bitmap. */ + int bitmapWidth; + int bitmapHeight; + + /** Set the CGContext's fill colour to the specified allocated colour. */ + void FillColour( const ColourAllocated& back ); + + + // 24-bit RGB+A bitmap data constants + static const int BITS_PER_COMPONENT = 8; + static const int BITS_PER_PIXEL = BITS_PER_COMPONENT * 4; + static const int BYTES_PER_PIXEL = BITS_PER_PIXEL / 8; +public: + SurfaceImpl(); + ~SurfaceImpl(); + + void Init(WindowID wid); + void Init(SurfaceID sid, WindowID wid); + void InitPixMap(int width, int height, Surface *surface_, WindowID wid); + CGContextRef GetContext() { return gc; } + + void Release(); + bool Initialised(); + void PenColour(ColourAllocated fore); + + /** Returns a CGImageRef that represents the surface. Returns NULL if this is not possible. */ + CGImageRef GetImage(); + void CopyImageRectangle(Surface &surfaceSource, PRectangle srcRect, PRectangle dstRect); + + int LogPixelsY(); + int DeviceHeightFont(int points); + void MoveTo(int x_, int y_); + void LineTo(int x_, int y_); + void Polygon(Scintilla::Point *pts, int npts, ColourAllocated fore, ColourAllocated back); + void RectangleDraw(PRectangle rc, ColourAllocated fore, ColourAllocated back); + void FillRectangle(PRectangle rc, ColourAllocated back); + void FillRectangle(PRectangle rc, Surface &surfacePattern); + void RoundedRectangle(PRectangle rc, ColourAllocated fore, ColourAllocated back); + void AlphaRectangle(PRectangle rc, int cornerSize, ColourAllocated fill, int alphaFill, + ColourAllocated outline, int alphaOutline, int flags); + void Ellipse(PRectangle rc, ColourAllocated fore, ColourAllocated back); + void Copy(PRectangle rc, Scintilla::Point from, Surface &surfaceSource); + + QuartzTextLayout* GetTextLayout( Font &font_, const char *s, int len ); + void DrawTextNoClip(PRectangle rc, Font &font_, int ybase, const char *s, int len, ColourAllocated fore, ColourAllocated back); + void DrawTextClipped(PRectangle rc, Font &font_, int ybase, const char *s, int len, ColourAllocated fore, ColourAllocated back); + void DrawTextTransparent(PRectangle rc, Font &font_, int ybase, const char *s, int len, ColourAllocated fore); + void MeasureWidths(Font &font_, const char *s, int len, int *positions); + int WidthText(Font &font_, const char *s, int len); + int WidthChar(Font &font_, char ch); + int Ascent(Font &font_); + int Descent(Font &font_); + int InternalLeading(Font &font_); + int ExternalLeading(Font &font_); + int Height(Font &font_); + int AverageCharWidth(Font &font_); + + int SetPalette(Scintilla::Palette *pal, bool inBackGround); + void SetClip(PRectangle rc); + void FlushCachedState(); + + void SetUnicodeMode(bool unicodeMode_); + void SetDBCSMode(int codePage); +}; + +} + +#endif diff --git a/macosx/QuartzTextLayout.h b/macosx/QuartzTextLayout.h new file mode 100644 index 000000000..1461a078f --- /dev/null +++ b/macosx/QuartzTextLayout.h @@ -0,0 +1,130 @@ +/* + * QuartzTextLayout.h + * wtf + * + * Created by Evan Jones on Wed Oct 02 2002. + * Copyright (c) 2002 __MyCompanyName__. All rights reserved. + * + */ + +#ifndef _QUARTZ_TEXT_LAYOUT_H +#define _QUARTZ_TEXT_LAYOUT_H + +#include <Carbon/Carbon.h> + +#include "QuartzTextStyle.h" + +class QuartzTextLayout +{ +public: + /** Create a text layout for drawing on the specified context. */ + QuartzTextLayout( CGContextRef context ) : layout( NULL ), unicode_string( NULL ), unicode_length( 0 ) + { + gc = context; + + OSStatus err; + err = ATSUCreateTextLayout( &layout ); + assert( err == noErr && layout != NULL ); + + setControl( kATSUCGContextTag, sizeof( gc ), &gc ); + + /*ATSUAttributeTag tag = kATSULineLayoutOptionsTag; + ByteCount size = sizeof( ATSLineLayoutOptions ); + ATSLineLayoutOptions rendering = kATSLineHasNoOpticalAlignment; // kATSLineUseDeviceMetrics; | kATSLineFractDisable | kATSLineUseQDRendering + ATSUAttributeValuePtr valuePtr = &rendering; + err = ATSUSetLayoutControls( layout, 1, &tag, &size, &valuePtr ); + assert( err == noErr );*/ + } + + ~QuartzTextLayout() + { + assert( layout != NULL ); + ATSUDisposeTextLayout( layout ); + layout = NULL; + + if ( unicode_string != NULL ) + { + delete[] unicode_string; + unicode_string = NULL; + unicode_length = 0; + } + } + + /** Assign a string to the text layout object. */ + // TODO: Create a UTF8 version + // TODO: Optimise the ASCII version by not copying so much + OSStatus setText( const UInt8* buffer, size_t byteLength, CFStringEncoding encoding ) + { + assert( buffer != NULL && byteLength > 0 ); + + CFStringRef str = CFStringCreateWithBytes( NULL, buffer, byteLength, encoding, false ); + if (!str) + return -1; + + unicode_length = CFStringGetLength( str ); + unicode_string = new UniChar[ unicode_length ]; + CFStringGetCharacters( str, CFRangeMake( 0, unicode_length ), unicode_string ); + + CFRelease( str ); + str = NULL; + + OSStatus err; + err = ATSUSetTextPointerLocation( layout, unicode_string, kATSUFromTextBeginning, kATSUToTextEnd, unicode_length ); + if( err != noErr ) return err; + + // Turn on the default font fallbacks + return ATSUSetTransientFontMatching( layout, true ); + } + + /** Apply the specified text style on the entire range of text. */ + void setStyle( const QuartzTextStyle& style ) + { + OSStatus err; + err = ATSUSetRunStyle( layout, style.getATSUStyle(), kATSUFromTextBeginning, kATSUToTextEnd ); + assert( err == noErr ); + } + + /** Draw the text layout into the current CGContext at the specified position, flipping the CGContext's Y axis if required. + * @param x The x axis position to draw the baseline in the current CGContext. + * @param y The y axis position to draw the baseline in the current CGContext. + * @param flipTextYAxis If true, the CGContext's Y axis will be flipped before drawing the text, and restored afterwards. Use this when drawing in an HIView's CGContext, where the origin is the top left corner. */ + void draw( float x, float y, bool flipTextYAxis = false ) + { + if ( flipTextYAxis ) + { + CGContextSaveGState( gc ); + CGContextScaleCTM( gc, 1.0, -1.0 ); + y = -y; + } + + OSStatus err; + err = ATSUDrawText( layout, kATSUFromTextBeginning, kATSUToTextEnd, X2Fix( x ), X2Fix( y ) ); + assert( err == noErr ); + + if ( flipTextYAxis ) CGContextRestoreGState( gc ); + } + + /** Sets a single text layout control on the ATSUTextLayout object. + * @param tag The control to set. + * @param size The size of the parameter pointed to by value. + * @param value A pointer to the new value for the control. + */ + void setControl( ATSUAttributeTag tag, ByteCount size, ATSUAttributeValuePtr value ) + { + OSStatus err; + err = ATSUSetLayoutControls( layout, 1, &tag, &size, &value ); + assert( noErr == err ); + } + + ATSUTextLayout getLayout() { + return layout; + } + +private: + ATSUTextLayout layout; + UniChar* unicode_string; + int unicode_length; + CGContextRef gc; +}; + +#endif diff --git a/macosx/QuartzTextStyle.h b/macosx/QuartzTextStyle.h new file mode 100644 index 000000000..d3a5db5dc --- /dev/null +++ b/macosx/QuartzTextStyle.h @@ -0,0 +1,105 @@ +/* + * QuartzTextStyle.h + * wtf + * + * Created by Evan Jones on Wed Oct 02 2002. + * Copyright (c) 2002 __MyCompanyName__. All rights reserved. + * + */ + +#include <Carbon/Carbon.h> + +#ifndef _QUARTZ_TEXT_STYLE_H +#define _QUARTZ_TEXT_STYLE_H + +#include "QuartzTextStyleAttribute.h" + +class QuartzTextStyle +{ +public: + QuartzTextStyle() + { + OSStatus err; + err = ATSUCreateStyle( &style ); + assert( err == noErr ); + } + + ~QuartzTextStyle() + { + assert( style != NULL ); + ATSUDisposeStyle( style ); + style = NULL; + } + + void setAttribute( ATSUAttributeTag tag, ByteCount size, ATSUAttributeValuePtr value ) + { + OSStatus err; + err = ATSUSetAttributes( style, 1, &tag, &size, &value ); + assert( err == noErr ); + } + + void setAttribute( QuartzTextStyleAttribute& attribute ) + { + setAttribute( attribute.getTag(), attribute.getSize(), attribute.getValuePtr() ); + } + + void getAttribute( ATSUAttributeTag tag, ByteCount size, ATSUAttributeValuePtr value, ByteCount* actualSize ) + { + OSStatus err; err = ATSUGetAttribute( style, tag, size, value, actualSize ); + assert( err == noErr ); + } + + template <class T> + T getAttribute( ATSUAttributeTag tag ) + { + T value; + ByteCount actualSize; + OSStatus err; + err = ATSUGetAttribute( style, tag, sizeof( T ), &value, &actualSize ); + assert( (err == noErr || err == kATSUNotSetErr) && actualSize == sizeof( T ) ); + return value; + } + + // TODO: Is calling this actually faster than calling setAttribute multiple times? + void setAttributes( QuartzTextStyleAttribute* attributes[], int number ) + { + // Create the parallel arrays and initialize them properly + ATSUAttributeTag* tags = new ATSUAttributeTag[ number ]; + ByteCount* sizes = new ByteCount[ number ]; + ATSUAttributeValuePtr* values = new ATSUAttributeValuePtr[ number ]; + + for ( int i = 0; i < number; ++ i ) + { + tags[i] = attributes[i]->getTag(); + sizes[i] = attributes[i]->getSize(); + values[i] = attributes[i]->getValuePtr(); + } + + OSStatus err; + err = ATSUSetAttributes( style, number, tags, sizes, values ); + //assert( err == noErr ); + + // Free the arrays that were allocated + delete[] tags; + delete[] sizes; + delete[] values; + } + + void setFontFeature( ATSUFontFeatureType featureType, ATSUFontFeatureSelector selector ) + { + OSStatus err; + err = ATSUSetFontFeatures( style, 1, &featureType, &selector ); + assert( err == noErr ); + } + + const ATSUStyle& getATSUStyle() const + { + return style; + } + +private: + ATSUStyle style; +}; + +#endif + diff --git a/macosx/QuartzTextStyleAttribute.h b/macosx/QuartzTextStyleAttribute.h new file mode 100644 index 000000000..490ef7d02 --- /dev/null +++ b/macosx/QuartzTextStyleAttribute.h @@ -0,0 +1,146 @@ +/* + * QuartzTextStyleAttribute.h + * wtf + * + * Created by Evan Jones on Wed Oct 02 2002. + * Copyright (c) 2002 __MyCompanyName__. All rights reserved. + * + */ + + +#include <Carbon/Carbon.h> + +#ifndef _QUARTZ_TEXT_STYLE_ATTRIBUTE_H +#define _QUARTZ_TEXT_STYLE_ATTRIBUTE_H + +class QuartzTextStyleAttribute +{ +public: + virtual ByteCount getSize() const = 0; + virtual ATSUAttributeValuePtr getValuePtr() = 0; + virtual ATSUAttributeTag getTag() const = 0; +}; + +class QuartzTextSize : public QuartzTextStyleAttribute +{ +public: + QuartzTextSize( float points ) + { + size = X2Fix( points ); + } + + ByteCount getSize() const + { + return sizeof( size ); + } + + ATSUAttributeValuePtr getValuePtr() + { + return &size; + } + + ATSUAttributeTag getTag() const + { + return kATSUSizeTag; + } + +private: + Fixed size; +}; + +class QuartzTextStyleAttributeBoolean : public QuartzTextStyleAttribute +{ +public: + QuartzTextStyleAttributeBoolean( bool newVal ) : value( newVal ) {} + + ByteCount getSize() const + { + return sizeof( value ); + } + ATSUAttributeValuePtr getValuePtr() + { + return &value; + } + + virtual ATSUAttributeTag getTag() const = 0; + +private: + Boolean value; +}; + +class QuartzTextBold : public QuartzTextStyleAttributeBoolean +{ +public: + QuartzTextBold( bool newVal ) : QuartzTextStyleAttributeBoolean( newVal ) {} + ATSUAttributeTag getTag() const + { + return kATSUQDBoldfaceTag; + } +}; + +class QuartzTextItalic : public QuartzTextStyleAttributeBoolean +{ +public: + QuartzTextItalic( bool newVal ) : QuartzTextStyleAttributeBoolean( newVal ) {} + ATSUAttributeTag getTag() const + { + return kATSUQDItalicTag; + } +}; + +class QuartzTextUnderline : public QuartzTextStyleAttributeBoolean +{ +public: + QuartzTextUnderline( bool newVal ) : QuartzTextStyleAttributeBoolean( newVal ) {} + ATSUAttributeTag getTag() const { + return kATSUQDUnderlineTag; + } +}; + +class QuartzFont : public QuartzTextStyleAttribute +{ +public: + /** Create a font style from a name. */ + QuartzFont( const char* name, int length ) + { + assert( name != NULL && length > 0 && name[length] == '\0' ); + /*CFStringRef fontName = CFStringCreateWithCString( NULL, name, kCFStringEncodingMacRoman ); + + ATSFontRef fontRef = ATSFontFindFromName( fontName, kATSOptionFlagsDefault ); + assert( fontRef != NULL ); + fontid = fontRef; + + CFRelease( fontName );*/ + + OSStatus err; + err = ATSUFindFontFromName( const_cast<char*>( name ), length, kFontFullName, (unsigned) kFontNoPlatform, kFontRomanScript, (unsigned) kFontNoLanguage, &fontid ); + //assert( err == noErr && fontid != kATSUInvalidFontID ); + } + + ByteCount getSize() const + { + return sizeof( fontid ); + } + + ATSUAttributeValuePtr getValuePtr() + { + return &fontid; + } + + ATSUAttributeTag getTag() const + { + return kATSUFontTag; + } + + ATSUFontID getFontID() const + { + return fontid; + } + +private: + ATSUFontID fontid; +}; + + +#endif + diff --git a/macosx/SciTest/English.lproj/InfoPlist.strings b/macosx/SciTest/English.lproj/InfoPlist.strings Binary files differnew file mode 100644 index 000000000..4dcb4fe03 --- /dev/null +++ b/macosx/SciTest/English.lproj/InfoPlist.strings diff --git a/macosx/SciTest/Info.plist b/macosx/SciTest/Info.plist new file mode 100644 index 000000000..7163dff62 --- /dev/null +++ b/macosx/SciTest/Info.plist @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> +<plist version="1.0"> +<dict> + <key>CFBundleDevelopmentRegion</key> + <string>English</string> + <key>CFBundleExecutable</key> + <string>SciTest</string> + <key>CFBundleIconFile</key> + <string></string> + <key>CFBundleIdentifier</key> + <string>com.apple.myCarbonApp</string> + <key>CFBundleInfoDictionaryVersion</key> + <string>6.0</string> + <key>CFBundlePackageType</key> + <string>APPL</string> + <key>CFBundleSignature</key> + <string>????</string> + <key>CFBundleVersion</key> + <string>1.0</string> + <key>CSResourcesFileMapped</key> + <true/> +</dict> +</plist> diff --git a/macosx/SciTest/SciTest.xcode/project.pbxproj b/macosx/SciTest/SciTest.xcode/project.pbxproj new file mode 100644 index 000000000..9ef8fd9bb --- /dev/null +++ b/macosx/SciTest/SciTest.xcode/project.pbxproj @@ -0,0 +1,287 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 42; + objects = { + +/* Begin PBXBuildFile section */ + 3002B123087DCEC600CEAF79 /* main.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3002B122087DCEC600CEAF79 /* main.cpp */; }; + 30973FF8086B7F4F0088809C /* libscintilla.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 30973FF7086B7F4F0088809C /* libscintilla.a */; }; + 8D0C4E8D0486CD37000505A6 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 0867D6AAFE840B52C02AAC07 /* InfoPlist.strings */; }; + 8D0C4E8E0486CD37000505A6 /* main.nib in Resources */ = {isa = PBXBuildFile; fileRef = 02345980000FD03B11CA0E72 /* main.nib */; }; + 8D0C4E920486CD37000505A6 /* Carbon.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 20286C33FDCF999611CA2CEA /* Carbon.framework */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 0867D6ABFE840B52C02AAC07 /* English */ = {isa = PBXFileReference; fileEncoding = 10; lastKnownFileType = text.plist.strings; name = English; path = English.lproj/InfoPlist.strings; sourceTree = "<group>"; }; + 1870340FFE93FCAF11CA0CD7 /* English */ = {isa = PBXFileReference; lastKnownFileType = wrapper.nib; name = English; path = English.lproj/main.nib; sourceTree = "<group>"; }; + 20286C33FDCF999611CA2CEA /* Carbon.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Carbon.framework; path = /System/Library/Frameworks/Carbon.framework; sourceTree = "<absolute>"; }; + 3002B122087DCEC600CEAF79 /* main.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = main.cpp; sourceTree = "<group>"; }; + 30973FF7086B7F4F0088809C /* libscintilla.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libscintilla.a; path = ../../bin/libscintilla.a; sourceTree = SOURCE_ROOT; }; + 32DBCF6D0370B57F00C91783 /* SciTest_Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SciTest_Prefix.pch; sourceTree = "<group>"; }; + 4A9504C8FFE6A3BC11CA0CBA /* ApplicationServices.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = ApplicationServices.framework; path = /System/Library/Frameworks/ApplicationServices.framework; sourceTree = "<absolute>"; }; + 4A9504CAFFE6A41611CA0CBA /* CoreServices.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreServices.framework; path = /System/Library/Frameworks/CoreServices.framework; sourceTree = "<absolute>"; }; + 8D0C4E960486CD37000505A6 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist; path = Info.plist; sourceTree = "<group>"; }; + 8D0C4E970486CD37000505A6 /* SciTest.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = SciTest.app; sourceTree = BUILT_PRODUCTS_DIR; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 8D0C4E910486CD37000505A6 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 8D0C4E920486CD37000505A6 /* Carbon.framework in Frameworks */, + 30973FF8086B7F4F0088809C /* libscintilla.a in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 195DF8CFFE9D517E11CA2CBB /* Products */ = { + isa = PBXGroup; + children = ( + 8D0C4E970486CD37000505A6 /* SciTest.app */, + ); + name = Products; + sourceTree = "<group>"; + }; + 20286C29FDCF999611CA2CEA /* SciTest */ = { + isa = PBXGroup; + children = ( + 20286C2AFDCF999611CA2CEA /* Sources */, + 20286C2CFDCF999611CA2CEA /* Resources */, + 20286C32FDCF999611CA2CEA /* External Frameworks and Libraries */, + 195DF8CFFE9D517E11CA2CBB /* Products */, + ); + name = SciTest; + sourceTree = "<group>"; + }; + 20286C2AFDCF999611CA2CEA /* Sources */ = { + isa = PBXGroup; + children = ( + 3002B122087DCEC600CEAF79 /* main.cpp */, + 32DBCF6D0370B57F00C91783 /* SciTest_Prefix.pch */, + ); + name = Sources; + sourceTree = "<group>"; + }; + 20286C2CFDCF999611CA2CEA /* Resources */ = { + isa = PBXGroup; + children = ( + 8D0C4E960486CD37000505A6 /* Info.plist */, + 0867D6AAFE840B52C02AAC07 /* InfoPlist.strings */, + 02345980000FD03B11CA0E72 /* main.nib */, + ); + name = Resources; + sourceTree = "<group>"; + }; + 20286C32FDCF999611CA2CEA /* External Frameworks and Libraries */ = { + isa = PBXGroup; + children = ( + 30973FF7086B7F4F0088809C /* libscintilla.a */, + 20286C33FDCF999611CA2CEA /* Carbon.framework */, + 4A9504CAFFE6A41611CA0CBA /* CoreServices.framework */, + 4A9504C8FFE6A3BC11CA0CBA /* ApplicationServices.framework */, + ); + name = "External Frameworks and Libraries"; + sourceTree = "<group>"; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 8D0C4E890486CD37000505A6 /* SciTest */ = { + isa = PBXNativeTarget; + buildConfigurationList = 304E977D0C0519E500702100 /* Build configuration list for PBXNativeTarget "SciTest" */; + buildPhases = ( + 8D0C4E8C0486CD37000505A6 /* Resources */, + 8D0C4E8F0486CD37000505A6 /* Sources */, + 8D0C4E910486CD37000505A6 /* Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = SciTest; + productInstallPath = "$(HOME)/Applications"; + productName = SciTest; + productReference = 8D0C4E970486CD37000505A6 /* SciTest.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 20286C28FDCF999611CA2CEA /* Project object */ = { + isa = PBXProject; + buildConfigurationList = 304E97810C0519E500702100 /* Build configuration list for PBXProject "SciTest" */; + hasScannedForEncodings = 1; + mainGroup = 20286C29FDCF999611CA2CEA /* SciTest */; + projectDirPath = ""; + targets = ( + 8D0C4E890486CD37000505A6 /* SciTest */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 8D0C4E8C0486CD37000505A6 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 8D0C4E8D0486CD37000505A6 /* InfoPlist.strings in Resources */, + 8D0C4E8E0486CD37000505A6 /* main.nib in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 8D0C4E8F0486CD37000505A6 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 3002B123087DCEC600CEAF79 /* main.cpp in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 02345980000FD03B11CA0E72 /* main.nib */ = { + isa = PBXVariantGroup; + children = ( + 1870340FFE93FCAF11CA0CD7 /* English */, + ); + name = main.nib; + sourceTree = "<group>"; + }; + 0867D6AAFE840B52C02AAC07 /* InfoPlist.strings */ = { + isa = PBXVariantGroup; + children = ( + 0867D6ABFE840B52C02AAC07 /* English */, + ); + name = InfoPlist.strings; + sourceTree = "<group>"; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 304E977E0C0519E500702100 /* Development */ = { + isa = XCBuildConfiguration; + buildSettings = { + COPY_PHASE_STRIP = NO; + GCC_DYNAMIC_NO_PIC = NO; + GCC_ENABLE_FIX_AND_CONTINUE = YES; + GCC_GENERATE_DEBUGGING_SYMBOLS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PRECOMPILE_PREFIX_HEADER = YES; + GCC_PREFIX_HEADER = SciTest_Prefix.pch; + HEADER_SEARCH_PATHS = ( + .., + ../../include, + ../../src, + ); + INFOPLIST_FILE = Info.plist; + INSTALL_PATH = "$(HOME)/Applications"; + LIBRARY_SEARCH_PATHS = ../../bin; + OTHER_CFLAGS = ( + "-DSCI_NAMESPACE=1", + "-DSCI_NAMESPACE", + "-DMACOSX", + "-DSCI_LEXER", + ); + OTHER_CPLUSPLUSFLAGS = ( + "-DSCI_NAMESPACE=1", + "-DSCI_NAMESPACE", + "-DMACOSX", + "-DSCI_LEXER", + ); + PRODUCT_NAME = SciTest; + WRAPPER_EXTENSION = app; + ZERO_LINK = YES; + }; + name = Development; + }; + 304E977F0C0519E500702100 /* Deployment */ = { + isa = XCBuildConfiguration; + buildSettings = { + COPY_PHASE_STRIP = YES; + GCC_ENABLE_FIX_AND_CONTINUE = NO; + GCC_GENERATE_DEBUGGING_SYMBOLS = NO; + GCC_PRECOMPILE_PREFIX_HEADER = YES; + GCC_PREFIX_HEADER = SciTest_Prefix.pch; + HEADER_SEARCH_PATHS = ( + .., + ../../include, + ../../src, + ); + INFOPLIST_FILE = Info.plist; + INSTALL_PATH = "$(HOME)/Applications"; + LIBRARY_SEARCH_PATHS = ""; + PRODUCT_NAME = SciTest; + WRAPPER_EXTENSION = app; + ZERO_LINK = NO; + }; + name = Deployment; + }; + 304E97800C0519E500702100 /* Default */ = { + isa = XCBuildConfiguration; + buildSettings = { + GCC_GENERATE_DEBUGGING_SYMBOLS = NO; + GCC_PRECOMPILE_PREFIX_HEADER = YES; + GCC_PREFIX_HEADER = SciTest_Prefix.pch; + INFOPLIST_FILE = Info.plist; + INSTALL_PATH = "$(HOME)/Applications"; + LIBRARY_SEARCH_PATHS = ""; + PRODUCT_NAME = SciTest; + WRAPPER_EXTENSION = app; + }; + name = Default; + }; + 304E97820C0519E500702100 /* Development */ = { + isa = XCBuildConfiguration; + buildSettings = { + }; + name = Development; + }; + 304E97830C0519E500702100 /* Deployment */ = { + isa = XCBuildConfiguration; + buildSettings = { + }; + name = Deployment; + }; + 304E97840C0519E500702100 /* Default */ = { + isa = XCBuildConfiguration; + buildSettings = { + }; + name = Default; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 304E977D0C0519E500702100 /* Build configuration list for PBXNativeTarget "SciTest" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 304E977E0C0519E500702100 /* Development */, + 304E977F0C0519E500702100 /* Deployment */, + 304E97800C0519E500702100 /* Default */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Default; + }; + 304E97810C0519E500702100 /* Build configuration list for PBXProject "SciTest" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 304E97820C0519E500702100 /* Development */, + 304E97830C0519E500702100 /* Deployment */, + 304E97840C0519E500702100 /* Default */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Default; + }; +/* End XCConfigurationList section */ + }; + rootObject = 20286C28FDCF999611CA2CEA /* Project object */; +} diff --git a/macosx/SciTest/SciTest_Prefix.pch b/macosx/SciTest/SciTest_Prefix.pch new file mode 100644 index 000000000..552cf97fc --- /dev/null +++ b/macosx/SciTest/SciTest_Prefix.pch @@ -0,0 +1,5 @@ +// +// Prefix header for all source files of the 'SciTest' target in the 'SciTest' project. +// + +#include <Carbon/Carbon.h> diff --git a/macosx/SciTest/main.cpp b/macosx/SciTest/main.cpp new file mode 100644 index 000000000..374038005 --- /dev/null +++ b/macosx/SciTest/main.cpp @@ -0,0 +1,225 @@ +//
+// main.c
+// SciTest
+//
+// Copyright (c) 2005-2006 ActiveState Software Inc.
+// All rights reserved.
+//
+// Created by Shane Caraveo on 3/20/05.
+//
+
+#include <Carbon/Carbon.h>
+#include "TView.h"
+#include "TCarbonEvent.h"
+#include "ScintillaMacOSX.h"
+
+extern "C" HIViewRef scintilla_new(void);
+
+const HILayoutInfo kBindToParentLayout = {
+ kHILayoutInfoVersionZero,
+ { { NULL, kHILayoutBindTop }, { NULL, kHILayoutBindLeft }, { NULL, kHILayoutBindBottom }, { NULL, kHILayoutBindRight } },
+ { { NULL, kHILayoutScaleAbsolute, 0 }, { NULL, kHILayoutScaleAbsolute, 0 } },
+ { { NULL, kHILayoutPositionTop, 0 }, { NULL, kHILayoutPositionLeft, 0 } }
+};
+
+using namespace Scintilla;
+
+/* XPM */
+static char *ac_class[] = {
+/* columns rows colors chars-per-pixel */
+"18 12 24 1",
+" c black",
+". c #403030",
+"X c #473636",
+"o c #4E3C3C",
+"O c #474141",
+"+ c #5F4C4C",
+"@ c #756362",
+"# c #98342C",
+"$ c #A0392F",
+"% c #B24235",
+"& c #B2443C",
+"* c #B34E3E",
+"= c #B54E44",
+"- c #B65146",
+"; c #B7584F",
+": c #B8554C",
+"> c #B75A50",
+", c #B95852",
+"< c #B96259",
+"1 c #B89B9B",
+"2 c #BCA0A0",
+"3 c #C1A5A5",
+"4 c gray100",
+"5 c None",
+/* pixels */
+"555555555555555555",
+"55553$$$$$$$#@5555",
+"55552;%&&==;=o5555",
+"55551>&&*=;:=.5555",
+"55551>&*=;::=.5555",
+"55551>*==:::-X5555",
+"55551>==:::,;.5555",
+"55551<==:;,<>.5555",
+"55551<;;;;<<;.5555",
+"55551;-==;;;;X5555",
+"55555+XX..X..O5555",
+"555555555555555555"
+};
+
+pascal OSStatus WindowEventHandler(EventHandlerCallRef inCallRef,
+ EventRef inEvent,
+ void* inUserData )
+{
+ HIViewRef sciView = *reinterpret_cast<HIViewRef*>( inUserData );
+ WindowRef window = GetControlOwner(sciView);
+ ScintillaMacOSX* scintilla;
+ GetControlProperty( sciView, scintillaMacOSType, 0, sizeof( scintilla ), NULL, &scintilla );
+ TCarbonEvent event( inEvent );
+
+ // If the window is not active, let the standard window handler execute.
+ if ( ! IsWindowActive( window ) ) return eventNotHandledErr;
+
+ const HIViewRef rootView = HIViewGetRoot( window );
+ assert( rootView != NULL );
+
+ if ( event.GetKind() == kEventMouseDown )
+ {
+ UInt32 inKeyModifiers;
+ event.GetParameter( kEventParamKeyModifiers, &inKeyModifiers );
+
+ EventMouseButton inMouseButton;
+ event.GetParameter<EventMouseButton>( kEventParamMouseButton, typeMouseButton, &inMouseButton );
+ if (inMouseButton == kEventMouseButtonTertiary) {
+ if (inKeyModifiers & optionKey) {
+ const char *test = "\001This is a test calltip This is a test calltip This is a test calltip";
+ scintilla->WndProc( SCI_CALLTIPSHOW, 0, (long int)test );
+ } else {
+ char *list = "test_1?0 test_2 test_3 test_4 test_5 test_6 test_7 test_8 test_9 test_10 test_11 test_12";
+ scintilla->WndProc( SCI_AUTOCSHOW, 0, (long int)list );
+ }
+ return noErr;
+ }
+ }
+
+ return eventNotHandledErr;
+}
+
+int main(int argc, char* argv[])
+{
+ IBNibRef nibRef;
+ WindowRef window;
+
+ OSStatus err;
+
+ // Create a Nib reference passing the name of the nib file (without the .nib extension)
+ // CreateNibReference only searches into the application bundle.
+ err = CreateNibReference(CFSTR("main"), &nibRef);
+ require_noerr( err, CantGetNibRef );
+
+ // Once the nib reference is created, set the menu bar. "MainMenu" is the name of the menu bar
+ // object. This name is set in InterfaceBuilder when the nib is created.
+ err = SetMenuBarFromNib(nibRef, CFSTR("MenuBar"));
+ require_noerr( err, CantSetMenuBar );
+
+ // Then create a window. "MainWindow" is the name of the window object. This name is set in
+ // InterfaceBuilder when the nib is created.
+ err = CreateWindowFromNib(nibRef, CFSTR("MainWindow"), &window);
+ require_noerr( err, CantCreateWindow );
+
+ // We don't need the nib reference anymore.
+ DisposeNibReference(nibRef);
+
+
+ HIRect boundsRect;
+ // GOOD and BAD methods off embedding into a window. This is used
+ // to test Window::SetPositionRelative under different situations.
+#define GOOD
+#ifdef GOOD
+#ifdef USE_CONTROL
+ ControlRef root;
+ GetRootControl(window, &root);
+#else
+ HIViewRef root;
+ HIViewFindByID(HIViewGetRoot(window),
+ kHIViewWindowContentID,
+ &root);
+#endif
+ HIViewGetBounds(root, &boundsRect);
+
+#else // BAD like mozilla
+ HIViewRef root;
+ root = HIViewGetRoot(window);
+
+ Rect cBounds, sBounds;
+ GetWindowBounds(window, kWindowContentRgn, &cBounds);
+ GetWindowBounds(window, kWindowStructureRgn, &sBounds);
+ boundsRect.origin.x = cBounds.left - sBounds.left;
+ boundsRect.origin.y = cBounds.top - sBounds.top;
+ boundsRect.size.width = cBounds.right - cBounds.left;
+ boundsRect.size.height = cBounds.bottom - cBounds.top;
+#endif
+
+ // get a scintilla control, and add it to it's parent container
+ HIViewRef sciView;
+ sciView = scintilla_new();
+ HIViewAddSubview(root, sciView);
+
+ // some scintilla init
+ ScintillaMacOSX* scintilla;
+ GetControlProperty( sciView, scintillaMacOSType, 0, sizeof( scintilla ), NULL, &scintilla );
+
+ scintilla->WndProc( SCI_SETLEXER, SCLEX_CPP, 0);
+ scintilla->WndProc( SCI_SETSTYLEBITS, 5, 0);
+ /*
+ these fail compilation on osx now
+ scintilla->WndProc( SCI_SETPROPERTY, "fold", (long int)"1");
+ scintilla->WndProc( SCI_SETPROPERTY, "fold.compact", (long int)"0");
+ scintilla->WndProc( SCI_SETPROPERTY, "fold.comment", (long int)"1");
+ scintilla->WndProc( SCI_SETPROPERTY, "fold.preprocessor", (long int)"1");
+ */
+
+ scintilla->WndProc( SCI_REGISTERIMAGE, 0, (long int)ac_class);
+
+ scintilla->WndProc( SCI_SETMARGINTYPEN, 0, (long int)SC_MARGIN_NUMBER);
+ scintilla->WndProc( SCI_SETMARGINWIDTHN, 0, (long int)30);
+ scintilla->WndProc( SCI_SETMARGINTYPEN, 1, (long int)SC_MARGIN_SYMBOL);
+ scintilla->WndProc( SCI_SETMARGINMASKN, 1, (long int)SC_MASK_FOLDERS);
+ scintilla->WndProc( SCI_SETMARGINWIDTHN, 1, (long int)20);
+ scintilla->WndProc( SCI_SETMARGINTYPEN, 2, (long int)SC_MARGIN_SYMBOL);
+ scintilla->WndProc( SCI_SETMARGINWIDTHN, 2, (long int)16);
+ //scintilla->WndProc( SCI_SETWRAPMODE, SC_WRAP_WORD, 0);
+ //scintilla->WndProc( SCI_SETWRAPVISUALFLAGS, SC_WRAPVISUALFLAG_END | SC_WRAPVISUALFLAG_START, 0);
+
+ // set the size of scintilla to the size of the container
+ HIViewSetFrame( sciView, &boundsRect );
+
+ // bind the size of scintilla to the size of it's container window
+ HIViewSetLayoutInfo(sciView, &kBindToParentLayout);
+
+ // setup some event handling
+ static const EventTypeSpec kWindowMouseEvents[] =
+ {
+ { kEventClassMouse, kEventMouseDown },
+ };
+
+ InstallEventHandler( GetWindowEventTarget( window ), WindowEventHandler,
+ GetEventTypeCount( kWindowMouseEvents ), kWindowMouseEvents, &sciView, NULL );
+
+ // show scintilla
+ ShowControl(sciView);
+
+ SetAutomaticControlDragTrackingEnabledForWindow(window, true);
+
+ // The window was created hidden so show it.
+ ShowWindow( window );
+
+ // Call the event loop
+ RunApplicationEventLoop();
+
+CantCreateWindow:
+CantSetMenuBar:
+CantGetNibRef:
+ return err;
+}
+
diff --git a/macosx/SciTest/version.plist b/macosx/SciTest/version.plist new file mode 100644 index 000000000..df8c3dc7d --- /dev/null +++ b/macosx/SciTest/version.plist @@ -0,0 +1,16 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> +<plist version="1.0"> +<dict> + <key>BuildVersion</key> + <string>92</string> + <key>CFBundleVersion</key> + <string>1.0</string> + <key>ProductBuildVersion</key> + <string>7K571</string> + <key>ProjectName</key> + <string>NibPBTemplates</string> + <key>SourceVersion</key> + <string>1200000</string> +</dict> +</plist> diff --git a/macosx/ScintillaCallTip.cxx b/macosx/ScintillaCallTip.cxx new file mode 100644 index 000000000..6799b435a --- /dev/null +++ b/macosx/ScintillaCallTip.cxx @@ -0,0 +1,117 @@ + +#include "ScintillaMacOSX.h" +#include "ScintillaCallTip.h" +#include "CallTip.h" + +using namespace Scintilla; + +const CFStringRef ScintillaCallTip::kScintillaCallTipClassID = CFSTR( "org.scintilla.calltip" ); +const ControlKind ScintillaCallTip::kScintillaCallTipKind = { 'ejon', 'Scct' }; + +ScintillaCallTip::ScintillaCallTip( void* windowid ) : + TView( reinterpret_cast<HIViewRef>( windowid ) ) +{ + ActivateInterface( kMouse ); + // debugPrint = true; +} + +void ScintillaCallTip::Draw( + RgnHandle /*inLimitRgn*/, + CGContextRef inContext ) +{ + // Get a reference to the Scintilla C++ object + CallTip* ctip = NULL; + OSStatus err; + err = GetControlProperty( GetViewRef(), scintillaCallTipType, 0, sizeof( ctip ), NULL, &ctip ); + assert(err == noErr); + if (ctip == NULL) return; + + Rect contentBounds; + GetControlBounds(GetViewRef(), &contentBounds); + + HIRect controlFrame; + HIViewGetFrame( GetViewRef(), &controlFrame ); + + // what is the global pos? + Surface *surfaceWindow = Surface::Allocate(); + if (surfaceWindow) { + surfaceWindow->Init(inContext, GetViewRef()); + ctip->PaintCT(surfaceWindow); + surfaceWindow->Release(); + delete surfaceWindow; + } + +} + +ControlPartCode ScintillaCallTip::HitTest( const HIPoint& where ) +{ + if ( CGRectContainsPoint( Bounds(), where ) ) + return 1; + else + return kControlNoPart; +} + +OSStatus ScintillaCallTip::MouseDown(HIPoint& location, UInt32 /*inKeyModifiers*/, EventMouseButton button, UInt32 /*inClickCount*/ ) +{ + if ( button != kEventMouseButtonPrimary ) return eventNotHandledErr; + CallTip* ctip = NULL; + ScintillaMacOSX *sciThis = NULL; + OSStatus err = GetControlProperty( GetViewRef(), scintillaCallTipType, 0, sizeof( ctip ), NULL, &ctip ); + err = GetControlProperty( GetViewRef(), scintillaMacOSType, 0, sizeof( sciThis ), NULL, &sciThis ); + ctip->MouseClick( Scintilla::Point( static_cast<int>( location.x ), static_cast<int>( location.y ) )); + sciThis->CallTipClick(); + return noErr; +} + +OSStatus ScintillaCallTip::MouseUp(HIPoint& /*inMouseLocation*/, UInt32 /*inKeyModifiers*/, EventMouseButton button, UInt32 /*inClickCount*/ ) +{ + if ( button != kEventMouseButtonPrimary ) return eventNotHandledErr; + return noErr; +} + +OSStatus ScintillaCallTip::MouseDragged( HIPoint& location, UInt32 /*modifiers*/, EventMouseButton /*button*/, UInt32 /*clickCount*/ ) +{ + SetThemeCursor( kThemeArrowCursor ); + return noErr; +} + +HIViewRef ScintillaCallTip::Create() +{ + // Register the HIView, if needed + static bool registered = false; + + if ( not registered ) + { + TView::RegisterSubclass( kScintillaCallTipClassID, Construct ); + registered = true; + } + + OSStatus err = noErr; + EventRef event = CreateInitializationEvent(); + assert( event != NULL ); + + HIViewRef control = NULL; + err = HIObjectCreate( kScintillaCallTipClassID, event, reinterpret_cast<HIObjectRef*>( &control ) ); + ReleaseEvent( event ); + if ( err == noErr ) { + Platform::DebugPrintf("ScintillaCallTip::Create control %08X\n",control); + return control; + } + return NULL; +} + +OSStatus ScintillaCallTip::Construct( HIViewRef inControl, TView** outView ) +{ + *outView = new ScintillaCallTip( inControl ); + Platform::DebugPrintf("ScintillaCallTip::Construct scintilla %08X\n",*outView); + if ( *outView != NULL ) + return noErr; + else + return memFullErr; +} + +extern "C" { +HIViewRef scintilla_calltip_new() { + return ScintillaCallTip::Create(); +} +} diff --git a/macosx/ScintillaCallTip.h b/macosx/ScintillaCallTip.h new file mode 100644 index 000000000..525804942 --- /dev/null +++ b/macosx/ScintillaCallTip.h @@ -0,0 +1,64 @@ +/* + * ScintillaMacOSX.h + * tutorial + * + * Created by Evan Jones on Sun Sep 01 2002. + * Copyright (c) 2002 __MyCompanyName__. All rights reserved. + * + */ +#ifndef SCINTILLA_CALLTIP_H +#define SCINTILLA_CALLTIP_H + +#include "TView.h" + +#include <stdlib.h> +#include <string.h> +#include <stdio.h> +#include <ctype.h> +#include <time.h> + +#include "Platform.h" +#include "Scintilla.h" + +static const OSType scintillaCallTipType = 'Scct'; + +namespace Scintilla { + +class ScintillaCallTip : public TView +{ +public: + // Private so ScintillaCallTip objects can not be copied + ScintillaCallTip(const ScintillaCallTip &) : TView( NULL ) {} + ScintillaCallTip &operator=(const ScintillaCallTip &) { return * this; } + ~ScintillaCallTip() {}; + +public: + /** This is the class ID that we've assigned to Scintilla. */ + static const CFStringRef kScintillaCallTipClassID; + static const ControlKind kScintillaCallTipKind; + + ScintillaCallTip( void* windowid ); + + /** Returns the HIView object kind, needed to subclass TView. */ + virtual ControlKind GetKind() { return kScintillaCallTipKind; } + +private: + + virtual ControlPartCode HitTest( const HIPoint& where ); + virtual void Draw( RgnHandle rgn, CGContextRef gc ); + virtual OSStatus MouseDown( HIPoint& location, UInt32 modifiers, EventMouseButton button, UInt32 clickCount ); + virtual OSStatus MouseUp( HIPoint& location, UInt32 modifiers, EventMouseButton button, UInt32 clickCount ); + virtual OSStatus MouseDragged( HIPoint& location, UInt32 modifiers, EventMouseButton button, UInt32 clickCount ); + +public: + static HIViewRef Create(); +private: + static OSStatus Construct( HIViewRef inControl, TView** outView ); + +}; + + +} + + +#endif diff --git a/macosx/ScintillaListBox.cxx b/macosx/ScintillaListBox.cxx new file mode 100644 index 000000000..90c72d857 --- /dev/null +++ b/macosx/ScintillaListBox.cxx @@ -0,0 +1,103 @@ + +#include "ScintillaMacOSX.h" +#include "ScintillaListBox.h" + +using namespace Scintilla; + +const CFStringRef ScintillaListBox::kScintillaListBoxClassID = CFSTR( "org.scintilla.listbox" ); +const ControlKind ScintillaListBox::kScintillaListBoxKind = { 'ejon', 'Sclb' }; + +ScintillaListBox::ScintillaListBox( void* windowid ) : + TView( reinterpret_cast<HIViewRef>( windowid ) ) +{ + ActivateInterface( kMouse ); + // debugPrint = true; +} + +void ScintillaListBox::Draw( + RgnHandle /*inLimitRgn*/, + CGContextRef inContext ) +{ + Rect contentBounds; + GetControlBounds(GetViewRef(), &contentBounds); + + HIRect controlFrame; + HIViewGetFrame( GetViewRef(), &controlFrame ); + + // what is the global pos? + Surface *surfaceWindow = Surface::Allocate(); + if (surfaceWindow) { + surfaceWindow->Init(inContext, GetViewRef()); + ctip->PaintCT(surfaceWindow); + surfaceWindow->Release(); + delete surfaceWindow; + } + +} + +ControlPartCode ScintillaListBox::HitTest( const HIPoint& where ) +{ + if ( CGRectContainsPoint( Bounds(), where ) ) + return 1; + else + return kControlNoPart; +} + +OSStatus ScintillaListBox::MouseDown(HIPoint& location, UInt32 /*inKeyModifiers*/, EventMouseButton button, UInt32 /*inClickCount*/ ) +{ + if ( button != kEventMouseButtonPrimary ) return eventNotHandledErr; + ListBox* ctip = NULL; + ScintillaMacOSX *sciThis = NULL; + OSStatus err = GetControlProperty( GetViewRef(), scintillaListBoxType, 0, sizeof( ctip ), NULL, &ctip ); + err = GetControlProperty( GetViewRef(), scintillaMacOSType, 0, sizeof( sciThis ), NULL, &sciThis ); + ctip->MouseClick( Scintilla::Point( static_cast<int>( location.x ), static_cast<int>( location.y ) )); + sciThis->ListBoxClick(); + return noErr; +} + +OSStatus ScintillaListBox::MouseUp(HIPoint& /*inMouseLocation*/, UInt32 /*inKeyModifiers*/, EventMouseButton button, UInt32 /*inClickCount*/ ) +{ + if ( button != kEventMouseButtonPrimary ) return eventNotHandledErr; + return noErr; +} + +HIViewRef ScintillaListBox::Create() +{ + // Register the HIView, if needed + static bool registered = false; + + if ( not registered ) + { + TView::RegisterSubclass( kScintillaListBoxClassID, Construct ); + registered = true; + } + + OSStatus err = noErr; + EventRef event = CreateInitializationEvent(); + assert( event != NULL ); + + HIViewRef control = NULL; + err = HIObjectCreate( kScintillaListBoxClassID, event, reinterpret_cast<HIObjectRef*>( &control ) ); + ReleaseEvent( event ); + if ( err == noErr ) { + Platform::DebugPrintf("ScintillaListBox::Create control %08X\n",control); + return control; + } + return NULL; +} + +OSStatus ScintillaListBox::Construct( HIViewRef inControl, TView** outView ) +{ + *outView = new ScintillaListBox( inControl ); + Platform::DebugPrintf("ScintillaListBox::Construct scintilla %08X\n",*outView); + if ( *outView != NULL ) + return noErr; + else + return memFullErr; +} + +extern "C" { +HIViewRef scintilla_listbox_new() { + return ScintillaListBox::Create(); +} +} diff --git a/macosx/ScintillaListBox.h b/macosx/ScintillaListBox.h new file mode 100644 index 000000000..e26d354eb --- /dev/null +++ b/macosx/ScintillaListBox.h @@ -0,0 +1,63 @@ +/* + * ScintillaMacOSX.h + * tutorial + * + * Created by Evan Jones on Sun Sep 01 2002. + * Copyright (c) 2002 __MyCompanyName__. All rights reserved. + * + */ +#ifndef SCINTILLA_LISTBOX_H +#define SCINTILLA_LISTBOX_H + +#include "TView.h" + +#include <stdlib.h> +#include <string.h> +#include <stdio.h> +#include <ctype.h> +#include <time.h> + +#include "Platform.h" +#include "Scintilla.h" + +static const OSType scintillaListBoxType = 'sclb'; + +namespace Scintilla { + +class ScintillaListBox : public TView +{ +public: + // Private so ScintillaListBox objects can not be copied + ScintillaListBox(const ScintillaListBox &) : TView( NULL ) {} + ScintillaListBox &operator=(const ScintillaListBox &) { return * this; } + ~ScintillaListBox() {}; + +public: + /** This is the class ID that we've assigned to Scintilla. */ + static const CFStringRef kScintillaListBoxClassID; + static const ControlKind kScintillaListBoxKind; + + ScintillaListBox( void* windowid ); + + /** Returns the HIView object kind, needed to subclass TView. */ + virtual ControlKind GetKind() { return kScintillaListBoxKind; } + +private: + + virtual ControlPartCode HitTest( const HIPoint& where ); + virtual void Draw( RgnHandle rgn, CGContextRef gc ); + virtual OSStatus MouseDown( HIPoint& location, UInt32 modifiers, EventMouseButton button, UInt32 clickCount ); + virtual OSStatus MouseUp( HIPoint& location, UInt32 modifiers, EventMouseButton button, UInt32 clickCount ); + +public: + static HIViewRef Create(); +private: + static OSStatus Construct( HIViewRef inControl, TView** outView ); + +}; + + +} + + +#endif diff --git a/macosx/ScintillaMacOSX.cxx b/macosx/ScintillaMacOSX.cxx new file mode 100644 index 000000000..9ac746f4b --- /dev/null +++ b/macosx/ScintillaMacOSX.cxx @@ -0,0 +1,2118 @@ +// Scintilla source code edit control +// ScintillaMacOSX.cxx - Mac OS X subclass of ScintillaBase +// Copyright 2003 by Evan Jones <ejones@uwaterloo.ca> +// Based on ScintillaGTK.cxx Copyright 1998-2002 by Neil Hodgson <neilh@scintilla.org> +// The License.txt file describes the conditions under which this software may be distributed. + + +#include "ScintillaMacOSX.h" +#include "UniConversion.h" + +using namespace Scintilla; + +const CFStringRef ScintillaMacOSX::kScintillaClassID = CFSTR( "org.scintilla.scintilla" ); +const ControlKind ScintillaMacOSX::kScintillaKind = { 'ejon', 'Scin' }; + +extern "C" HIViewRef scintilla_calltip_new(void); + +#ifndef WM_UNICHAR +#define WM_UNICHAR 0x0109 +#endif + +// required for paste/dragdrop, see comment in paste function below +static int BOMlen(unsigned char *cstr) { + switch(cstr[0]) { + case 0xEF: // BOM_UTF8 + if (cstr[1] == 0xBB && cstr[2] == 0xBF) { + return 3; + } + break; + case 0xFE: + if (cstr[1] == 0xFF) { + if (cstr[2] == 0x00 && cstr[3] == 0x00) { + return 4; + } + return 2; + } + break; + case 0xFF: + if (cstr[1] == 0xFE) { + if (cstr[2] == 0x00 && cstr[3] == 0x00) { + return 4; + } + return 2; + } + break; + case 0x00: + if (cstr[1] == 0x00) { + if (cstr[2] == 0xFE && cstr[3] == 0xFF) { + return 4; + } + if (cstr[2] == 0xFF && cstr[3] == 0xFE) { + return 4; + } + return 2; + } + break; + } + + return 0; +} + +ScintillaMacOSX::ScintillaMacOSX( void* windowid ) : + TView( reinterpret_cast<HIViewRef>( windowid ) ) +{ + wMain = windowid; + OSStatus err; + err = GetThemeMetric( kThemeMetricScrollBarWidth, &scrollBarFixedSize ); + assert( err == noErr ); + + mouseTrackingRef = NULL; + mouseTrackingID.signature = scintillaMacOSType; + mouseTrackingID.id = (SInt32)this; + capturedMouse = false; + + // Enable keyboard events and mouse events +#if !defined(CONTAINER_HANDLES_EVENTS) + ActivateInterface( kKeyboardFocus ); + ActivateInterface( kMouse ); + ActivateInterface( kDragAndDrop ); +#endif + ActivateInterface( kMouseTracking ); + + Initialise(); + + // Create some bounds rectangle which will just get reset to the correct rectangle later + Rect tempScrollRect; + tempScrollRect.top = -1; + tempScrollRect.left = 400; + tempScrollRect.bottom = 300; + tempScrollRect.right = 450; + + // Create the scroll bar with fake values that will get set correctly later + err = CreateScrollBarControl( this->GetOwner(), &tempScrollRect, 0, 0, 100, 100, true, LiveScrollHandler, &vScrollBar ); + assert( vScrollBar != NULL && err == noErr ); + err = CreateScrollBarControl( this->GetOwner(), &tempScrollRect, 0, 0, 100, 100, true, LiveScrollHandler, &hScrollBar ); + assert( hScrollBar != NULL && err == noErr ); + + // Set a property on the scrollbars to store a pointer to the Scintilla object + ScintillaMacOSX* objectPtr = this; + err = SetControlProperty( vScrollBar, scintillaMacOSType, 0, sizeof( this ), &objectPtr ); + assert( err == noErr ); + err = SetControlProperty( hScrollBar, scintillaMacOSType, 0, sizeof( this ), &objectPtr ); + assert( err == noErr ); + + // set this into our parent control so we can be retrieved easily at a later time + // (see scintilla_send below) + err = SetControlProperty( reinterpret_cast<HIViewRef>( windowid ), scintillaMacOSType, 0, sizeof( this ), &objectPtr ); + assert( err == noErr ); + + // Tell Scintilla not to buffer: Quartz buffers drawing for us + // TODO: Can we disable this option on Mac OS X? + WndProc( SCI_SETBUFFEREDDRAW, 0, 0 ); + // Turn on UniCode mode + WndProc( SCI_SETCODEPAGE, SC_CP_UTF8, 0 ); + + const EventTypeSpec commandEventInfo[] = { + { kEventClassCommand, kEventProcessCommand }, + { kEventClassCommand, kEventCommandUpdateStatus }, + }; + + err = InstallEventHandler( GetControlEventTarget( reinterpret_cast<HIViewRef>( windowid ) ), + CommandEventHandler, + GetEventTypeCount( commandEventInfo ), + commandEventInfo, + this, NULL); + assert( err == noErr ); +} + +ScintillaMacOSX::~ScintillaMacOSX() { + // If the window is closed and the timer is not removed, + // A segment violation will occur when it attempts to fire the timer next. + if ( mouseTrackingRef != NULL ) { + ReleaseMouseTrackingRegion(mouseTrackingRef); + } + mouseTrackingRef = NULL; + SetTicking(false); +} + +void ScintillaMacOSX::Initialise() { + // TODO: Do anything here? Maybe this stuff should be here instead of the constructor? +} + +void ScintillaMacOSX::Finalise() { + SetTicking(false); + ScintillaBase::Finalise(); +} + +// -------------------------------------------------------------------------------------------------------------- +// +// IsDropInFinderTrash - Returns true if the given dropLocation AEDesc is a descriptor of the Finder's Trash. +// +#pragma segment Drag + +Boolean IsDropInFinderTrash(AEDesc *dropLocation) +{ + OSErr result; + AEDesc dropSpec; + FSSpec *theSpec; + CInfoPBRec thePB; + short trashVRefNum; + long trashDirID; + + // Coerce the dropLocation descriptor into an FSSpec. If there's no dropLocation or + // it can't be coerced into an FSSpec, then it couldn't have been the Trash. + + if ((dropLocation->descriptorType != typeNull) && + (AECoerceDesc(dropLocation, typeFSS, &dropSpec) == noErr)) + { + unsigned char flags = HGetState((Handle)dropSpec.dataHandle); + + HLock((Handle)dropSpec.dataHandle); + theSpec = (FSSpec *) *dropSpec.dataHandle; + + // Get the directory ID of the given dropLocation object. + + thePB.dirInfo.ioCompletion = 0L; + thePB.dirInfo.ioNamePtr = (StringPtr) &theSpec->name; + thePB.dirInfo.ioVRefNum = theSpec->vRefNum; + thePB.dirInfo.ioFDirIndex = 0; + thePB.dirInfo.ioDrDirID = theSpec->parID; + + result = PBGetCatInfoSync(&thePB); + + HSetState((Handle)dropSpec.dataHandle, flags); + AEDisposeDesc(&dropSpec); + + if (result != noErr) + return false; + + // If the result is not a directory, it must not be the Trash. + + if (!(thePB.dirInfo.ioFlAttrib & (1 << 4))) + return false; + + // Get information about the Trash folder. + + FindFolder(theSpec->vRefNum, kTrashFolderType, kCreateFolder, &trashVRefNum, &trashDirID); + + // If the directory ID of the dropLocation object is the same as the directory ID + // returned by FindFolder, then the drop must have occurred into the Trash. + + if (thePB.dirInfo.ioDrDirID == trashDirID) + return true; + } + + return false; + +} // IsDropInFinderTrash + +HIPoint ScintillaMacOSX::GetLocalPoint(::Point pt) +{ + // get the mouse position so we can offset it + Rect bounds; + GetWindowBounds( GetOwner(), kWindowStructureRgn, &bounds ); + + PRectangle hbounds = wMain.GetPosition(); + HIViewRef parent = HIViewGetSuperview(GetViewRef()); + Rect pbounds; + GetControlBounds(parent, &pbounds); + + bounds.left += pbounds.left + hbounds.left; + bounds.top += pbounds.top + hbounds.top; + + HIPoint offset = { pt.h - bounds.left, pt.v - bounds.top }; + return offset; +} + +void ScintillaMacOSX::StartDrag() { +#define DRAG_DROP_PASTEBOARD + if (currentPos == anchor) return; + + SelectionText selectedText; + CopySelectionRange(&selectedText); + + // some of this taken from copytoclipboard + if (selectedText.len == 0) + return; + + CFStringEncoding encoding = ( IsUnicodeMode() ? kCFStringEncodingUTF8 : kCFStringEncodingASCII); + + // Create a CFString from the ASCII/UTF8 data, convert it to UTF16 + CFStringRef string = CFStringCreateWithBytes( NULL, reinterpret_cast<UInt8*>( selectedText.s ), selectedText.len - 1, encoding, false ); + assert( string != NULL ); + +#ifndef DRAG_DROP_PASTEBOARD + CFIndex numUniChars = CFStringGetLength( string ); + UniChar* buffer = new UniChar[ numUniChars ]; + CFStringGetCharacters( string, CFRangeMake( 0, numUniChars ), buffer ); + + // Create an c string byte buffer + CFIndex maximumByteLength = CFStringGetMaximumSizeForEncoding( numUniChars, encoding ) + 1; + char* cstring = new char[maximumByteLength]; + CFIndex usedBufferLength = 0; + CFIndex numCharsConverted; + numCharsConverted = CFStringGetBytes( string, CFRangeMake( 0, numUniChars ), encoding, + '?', false, reinterpret_cast<UInt8*>( cstring ), + maximumByteLength, &usedBufferLength ); + cstring[usedBufferLength] = '\0'; // null terminate the ASCII/UTF8 string + assert( numCharsConverted == numUniChars ); +#endif + + // calculate the bounds of the selection + PRectangle client = GetTextRectangle(); + int selStart = Platform::Minimum(anchor, currentPos); + int selEnd = Platform::Maximum(anchor, currentPos); + int startLine = pdoc->LineFromPosition(selStart); + int endLine = pdoc->LineFromPosition(selEnd); + Point pt; + int startPos, endPos, ep; + Rect rcSel; + rcSel.top = rcSel.bottom = rcSel.right = rcSel.left = -1; + for (int l = startLine; l <= endLine; l++) { + startPos = WndProc(SCI_GETLINESELSTARTPOSITION, l, 0); + endPos = WndProc(SCI_GETLINESELENDPOSITION, l, 0); + if (endPos == startPos) continue; + // step back a position if we're counting the newline + ep = WndProc(SCI_GETLINEENDPOSITION, l, 0); + if (endPos > ep) endPos = ep; + + pt = LocationFromPosition(startPos); // top left of line selection + if (pt.x < rcSel.left || rcSel.left < 0) rcSel.left = pt.x; + if (pt.y < rcSel.top || rcSel.top < 0) rcSel.top = pt.y; + + pt = LocationFromPosition(endPos); // top right of line selection + pt.y += vs.lineHeight; // get to the bottom of the line + if (pt.x > rcSel.right || rcSel.right < 0) { + if (pt.x > client.right) + rcSel.right = client.right; + else + rcSel.right = pt.x; + } + if (pt.y > rcSel.bottom || rcSel.bottom < 0) { + if (pt.y > client.bottom) + rcSel.bottom = client.bottom; + else + rcSel.bottom = pt.y; + } + } + + // must convert to global coordinates for drag regions, but also save the + // image rectangle for further calculations and copy operations + PRectangle imageRect = PRectangle(rcSel.left, rcSel.top, rcSel.right, rcSel.bottom); + QDLocalToGlobalRect(GetWindowPort(GetOwner()), &rcSel); + + // get the mouse position so we can offset it + HIPoint offset = GetLocalPoint(mouseDownEvent.where); + offset.y = (imageRect.top * 1.0) - offset.y; + offset.x = (imageRect.left * 1.0) - offset.x; + + // to get a bitmap of the text we're dragging, we just use Paint on a + // pixmap surface. + SurfaceImpl *sw = new SurfaceImpl(); + SurfaceImpl *pixmap = NULL; + + if (sw) { + pixmap = new SurfaceImpl(); + if (pixmap) { + client = GetClientRectangle(); + paintState = painting; + sw->InitPixMap( client.Width(), client.Height(), NULL, NULL ); + + Paint(sw, imageRect); + paintState = notPainting; + + pixmap->InitPixMap( imageRect.Width(), imageRect.Height(), NULL, NULL ); + + CGContextRef gc = pixmap->GetContext(); + + // to make Paint() work on a bitmap, we have to flip our coordinates + // and translate the origin + //fprintf(stderr, "translate to %d\n", client.Height() ); + CGContextTranslateCTM(gc, 0, imageRect.Height()); + CGContextScaleCTM(gc, 1.0, -1.0); + + pixmap->CopyImageRectangle( *sw, imageRect, PRectangle( 0, 0, imageRect.Width(), imageRect.Height() )); + // XXX TODO: overwrite any part of the image that is not part of the + // selection to make it transparent. right now we just use + // the full rectangle which may include non-selected text. + } + sw->Release(); + delete sw; + } + + // now we initiate the drag session + + RgnHandle dragRegion = NewRgn(); + RgnHandle tempRegion; + DragRef inDrag; + DragAttributes attributes; + AEDesc dropLocation; + SInt16 mouseDownModifiers, mouseUpModifiers; + bool copyText; + CGImageRef image = NULL; + + RectRgn(dragRegion, &rcSel); + +#ifdef DRAG_DROP_PASTEBOARD + PasteboardRef theClipboard; + PasteboardCreate( kPasteboardClipboard, &theClipboard ); + PasteboardClear( theClipboard ); + + CFDataRef data = NULL; + data = CFStringCreateExternalRepresentation ( kCFAllocatorDefault, string, kCFStringEncodingMacRoman, 0 ); + PasteboardPutItemFlavor( theClipboard, (PasteboardItemID)1, + CFSTR("com.apple.traditional-mac-plain-text"), + data, 0 ); + CFRelease(data); + data = CFStringCreateExternalRepresentation ( kCFAllocatorDefault, string, kCFStringEncodingUnicode, 0 ); + PasteboardPutItemFlavor( theClipboard, (PasteboardItemID)1, + CFSTR("public.utf16-plain-text"), + data, 0 ); + CFRelease(data); + NewDragWithPasteboard( theClipboard, &inDrag); +#else + NewDrag(&inDrag); + AddDragItemFlavor(inDrag, 1, 'utxt', buffer, sizeof( UniChar ) * numUniChars, 0); + AddDragItemFlavor(inDrag, 1, 'txt', cstring, sizeof( char ) * usedBufferLength, 0); +#endif + + // Set the item's bounding rectangle in global coordinates. + SetDragItemBounds(inDrag, 1, &rcSel); + + // Prepare the drag region. + tempRegion = NewRgn(); + CopyRgn(dragRegion, tempRegion); + InsetRgn(tempRegion, 1, 1); + DiffRgn(dragRegion, tempRegion, dragRegion); + DisposeRgn(tempRegion); + + // if we have a pixmap, lets use that + if (pixmap) { + image = pixmap->GetImage(); + SetDragImageWithCGImage (inDrag, image, &offset, kDragStandardTranslucency); + } + + // Drag the text. TrackDrag will return userCanceledErr if the drop whooshed back for any reason. + inDragSession = true; + OSErr error = TrackDrag(inDrag, &mouseDownEvent, dragRegion); + inDragSession = false; + + // Check to see if the drop occurred in the Finder's Trash. If the drop occurred + // in the Finder's Trash and a copy operation wasn't specified, delete the + // source selection. Note that we can continute to get the attributes, drop location + // modifiers, etc. of the drag until we dispose of it using DisposeDrag. + if (error == noErr) { + GetDragAttributes(inDrag, &attributes); + if (!(attributes & kDragInsideSenderApplication)) + { + GetDropLocation(inDrag, &dropLocation); + + GetDragModifiers(inDrag, 0L, &mouseDownModifiers, &mouseUpModifiers); + copyText = (mouseDownModifiers | mouseUpModifiers) & optionKey; + + if ((!copyText) && (IsDropInFinderTrash(&dropLocation))) + { + // delete the selected text from the buffer + ClearSelection(); + } + + AEDisposeDesc(&dropLocation); + } + } + + // Dispose of this drag, 'cause we're done. + DisposeDrag(inDrag); + DisposeRgn(dragRegion); + CFRelease( string ); + + if (pixmap) { + CGImageRelease(image); + pixmap->Release(); + delete pixmap; + } + + // Done with the UniChar* buffer +#ifdef DRAG_DROP_PASTEBOARD + CFRelease( theClipboard ); +#else + delete[] buffer; + buffer = NULL; + delete[] cstring; + cstring = NULL; +#endif +} + +void ScintillaMacOSX::SetDragCursor(DragRef inDrag) +{ + DragAttributes attributes; + SInt16 modifiers = 0; + ThemeCursor cursor = kThemeCopyArrowCursor; + GetDragAttributes( inDrag, &attributes ); + + if ( attributes & kDragInsideSenderWindow ) { + GetDragModifiers(inDrag, &modifiers, NULL, NULL); + switch (modifiers & ~btnState) // Filter out btnState (on for drop) + { + case optionKey: + // it's a copy, leave it as a copy arrow + break; + + case cmdKey: + case cmdKey | optionKey: + default: + // what to do with these? rectangular drag? + cursor = kThemeArrowCursor; + break; + } + } + SetThemeCursor(cursor); +} + +bool ScintillaMacOSX::DragEnter(DragRef inDrag ) +{ + if (!DragWithin(inDrag)) + return false; + + DragAttributes attributes; + GetDragAttributes( inDrag, &attributes ); + + // only show the drag hilight if the drag has left the sender window per HI spec + if( attributes & kDragHasLeftSenderWindow ) + { + HIRect textFrame; + RgnHandle hiliteRgn = NewRgn(); + + // get the text view's frame ... + HIViewGetFrame( GetViewRef(), &textFrame ); + + // ... and convert it into a region for ShowDragHilite + HIShapeRef textShape = HIShapeCreateWithRect( &textFrame ); + HIShapeGetAsQDRgn( textShape, hiliteRgn ); + CFRelease( textShape ); + + // add the drag hilight to the inside of the text view + ShowDragHilite( inDrag, hiliteRgn, true ); + + DisposeRgn( hiliteRgn ); + } + SetDragCursor(inDrag); + return true; +} + +Scintilla::Point ScintillaMacOSX::GetDragPoint(DragRef inDrag) +{ + ::Point mouse, globalMouse; + GetDragMouse(inDrag, &mouse, &globalMouse); + QDGlobalToLocalPoint(GetWindowPort(GetOwner()), &globalMouse); + HIPoint hiPoint = {globalMouse.h, globalMouse.v}; + return Point(static_cast<int>(hiPoint.x), static_cast<int>(hiPoint.y)); +} + + +void ScintillaMacOSX::DragScroll() +{ +#define RESET_SCROLL_TIMER(lines) \ + scrollSpeed = (lines); \ + scrollTicks = 2000; + + if (posDrag == invalidPosition) { + RESET_SCROLL_TIMER(1); + return; + } + Point dragMouse = LocationFromPosition(posDrag); + int line = pdoc->LineFromPosition(posDrag); + int currentVisibleLine = cs.DisplayFromDoc(line); + int lastVisibleLine = Platform::Minimum(topLine + LinesOnScreen() - 1, pdoc->LinesTotal() - 1); + + if (currentVisibleLine <= topLine && topLine > 0) { + ScrollTo( topLine - scrollSpeed ); + } else if (currentVisibleLine >= lastVisibleLine) { + ScrollTo( topLine + scrollSpeed ); + } else { + RESET_SCROLL_TIMER(1); + return; + } + if (scrollSpeed == 1) { + scrollTicks -= timer.tickSize; + if (scrollTicks <= 0) { + RESET_SCROLL_TIMER(5); + } + } + + SetDragPosition(PositionFromLocation(dragMouse)); + +#undef RESET_SCROLL_TIMER +} + +bool ScintillaMacOSX::DragWithin(DragRef inDrag ) +{ + PasteboardRef pasteBoard; + OSStatus status = GetDragData(inDrag, pasteBoard, NULL); + if (status != noErr) { + return false; + } + + ::Point mouse, globalMouse; + GetDragMouse(inDrag, &mouse, &globalMouse); + QDGlobalToLocalPoint(GetWindowPort(GetOwner()), &globalMouse); + HIPoint globalHit = {globalMouse.h, globalMouse.v}; + // HIPoint localHit = {mouse.h, mouse.v}; + + if (!CGRectContainsPoint( Bounds(), globalHit )) { + return false; + } + + SetDragPosition(PositionFromLocation(Point(static_cast<int>(globalHit.x),static_cast<int>(globalHit.y)))); + SetDragCursor(inDrag); + + return true; +} + +bool ScintillaMacOSX::DragLeave(DragRef inDrag ) +{ + HideDragHilite( inDrag ); + SetDragPosition(invalidPosition); + WndProc(SCI_SETCURSOR, Window::cursorArrow, 0); + return true; +} + +OSStatus ScintillaMacOSX::GetDragData(DragRef inDrag, PasteboardRef &pasteBoard, CFStringRef *textString) +{ + // TODO: add support for special flavors: flavorTypeHFS and flavorTypePromiseHFS so we + // can handle files being dropped on the editor + OSStatus status; + status = GetDragPasteboard(inDrag, &pasteBoard); + if (status != noErr) { + return dragNotAcceptedErr; + } + + // how many items in the pasteboard? + ItemCount i, itemCount; + status = PasteboardGetItemCount(pasteBoard, &itemCount); + if (status != noErr) { + return dragNotAcceptedErr; + } + + // as long as we didn't get our text, let's loop on the items. We stop as soon as we get it + CFArrayRef flavorTypeArray = NULL; + bool haveMatch = false; + for (i = 1; i <= itemCount; i++) + { + PasteboardItemID itemID; + CFIndex j, flavorCount = 0; + + status = PasteboardGetItemIdentifier(pasteBoard, i, &itemID); + if (status != noErr) { + return dragNotAcceptedErr; + } + + // how many flavors in this item? + status = PasteboardCopyItemFlavors(pasteBoard, itemID, &flavorTypeArray); + if (status != noErr) { + return dragNotAcceptedErr; + } + + if (flavorTypeArray != NULL) + flavorCount = CFArrayGetCount(flavorTypeArray); + + // as long as we didn't get our text, let's loop on the flavors. We stop as soon as we get it + for(j = 0; j < flavorCount; j++) + { + CFDataRef flavorData; + CFStringRef flavorType = (CFStringRef)CFArrayGetValueAtIndex(flavorTypeArray, j); + if (flavorType != NULL) { + if (UTTypeConformsTo(flavorType, CFSTR("public.utf16-plain-text"))) // this is 'utxt' + { + // if we got a flavor match, and we have no textString, we just want + // to know that we can accept this drag data, so jump out now + if (textString == NULL) { + haveMatch = true; + goto DragDataRetrieved; + } + if (PasteboardCopyItemFlavorData(pasteBoard, itemID, flavorType, &flavorData) == noErr) + { + CFIndex flavorDataSize = CFDataGetLength(flavorData); + + // getting the text + *textString = CFStringCreateWithCharacters(NULL, + (UniChar *)CFDataGetBytePtr(flavorData), + flavorDataSize >> 1); + CFRelease(flavorData); + goto DragDataRetrieved; + } + } + } + } + } +DragDataRetrieved: + if (flavorTypeArray != NULL) CFRelease(flavorTypeArray); + if (haveMatch || textString != NULL && *textString != NULL) + return noErr; + return dragNotAcceptedErr; +} + +OSStatus ScintillaMacOSX::DragReceive(DragRef inDrag ) +{ + OSStatus status; + PasteboardRef pasteBoard; + CFStringRef textString = NULL; + status = GetDragData(inDrag, pasteBoard, &textString); + if (status != noErr) { + return dragNotAcceptedErr; + } + + // getting the length of the text and setting the value + if (textString == NULL) { + return noErr; + } + + // XXX the following is identical (ALMOST) to code in Paste + + // Allocate a buffer, plus the null byte + CFIndex numUniChars = CFStringGetLength( textString ); + CFStringEncoding encoding = ( IsUnicodeMode() ? kCFStringEncodingUTF8 : kCFStringEncodingASCII); + CFIndex maximumByteLength = CFStringGetMaximumSizeForEncoding( numUniChars, encoding ) + 1; + char* cstring = new char[maximumByteLength]; + CFIndex usedBufferLength = 0; + CFIndex numCharsConverted; + numCharsConverted = CFStringGetBytes( textString, CFRangeMake( 0, numUniChars ), encoding, + '?', false, reinterpret_cast<UInt8*>( cstring ), + maximumByteLength, &usedBufferLength ); + cstring[usedBufferLength] = '\0'; // null terminate the ASCII/UTF8 string + assert( numCharsConverted == numUniChars ); + + // Default allocator releases both the CFString and the UniChar buffer (text) + CFRelease( textString ); + textString = NULL; + + // determine whether a BOM is in the string. Apps like Emacs prepends a BOM + // to the string, CFStrinGetBytes reflects that (though it may change in the conversion) + // so we need to remove it before pasting into our buffer. TextWrangler has no + // problem dealing with BOM when pasting into it. + int bomLen = BOMlen((unsigned char *)cstring); + + // convert line endings to the document line ending + int droppedLen = 0; + char *droppedText = Document::TransformLineEnds(&droppedLen, + cstring + bomLen, + usedBufferLength - bomLen, + pdoc->eolMode); + + pdoc->BeginUndoAction(); + + // figure out if this is a move or a paste + DragAttributes attributes; + SInt16 modifiers = 0; + GetDragAttributes( inDrag, &attributes ); + + int position = PositionFromLocation(GetDragPoint(inDrag)); + int selStart = Platform::Minimum(anchor, currentPos); + int selEnd = Platform::Maximum(anchor, currentPos); + if ( attributes & kDragInsideSenderWindow ) { + if (position >= selStart && position <= selEnd) { + // droping on top of what we dragged, we should ignore this + goto endDrag; + } + GetDragModifiers(inDrag, NULL, NULL, &modifiers); + switch (modifiers & ~btnState) // Filter out btnState (on for drop) + { + case optionKey: + // default is copy text + break; + + case cmdKey: + case cmdKey | optionKey: + default: + // what to do with these? rectangular drag? + position = selStart; + ClearSelection(); + break; + } + } else { + if (position >= selStart && position <= selEnd) { + // droping on top of a selection from another app or control, clear it + position = selStart; + ClearSelection(); + } + } + + // lets put the text in our document now + if ( pdoc->InsertString( position, droppedText, droppedLen ) ) + { + SetEmptySelection( currentPos + droppedLen ); + } + +endDrag: + delete[] droppedText; + delete[] cstring; + cstring = NULL; + + pdoc->EndUndoAction(); + NotifyChange(); + + // dragleave IS called, but for some reason (probably to do with inDrag) + // the hide hilite does not happen unless we do it here + HideDragHilite( inDrag ); + + return noErr; +} + +/** The simulated message loop. */ +sptr_t ScintillaMacOSX::WndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam) { + switch (iMessage) { + case SCI_GETDIRECTFUNCTION: + Platform::DebugDisplay( "ScintillaMacOSX::WndProc: Returning DirectFunction address.\n" ); + return reinterpret_cast<sptr_t>( DirectFunction ); + + case SCI_GETDIRECTPOINTER: + Platform::DebugDisplay( "ScintillaMacOSX::WndProc: Returning Direct pointer address.\n" ); + return reinterpret_cast<sptr_t>( this ); + + case SCI_GRABFOCUS: + Platform::DebugDisplay( "ScintillaMacOSX::WndProc: Got an unhandled message. Ignoring it.\n" ); + break; + case WM_UNICHAR: + if (IsUnicodeMode()) { + char utfval[4]; + wchar_t wcs[2] = {wParam, 0}; + unsigned int len = UTF8Length(wcs, 1); + UTF8FromUTF16(wcs, 1, utfval, len); + AddCharUTF(utfval, len); + return 1; + } else { + return 0; + } + + default: + unsigned int r = ScintillaBase::WndProc(iMessage, wParam, lParam); + + return r; + } + return 0l; +} + +sptr_t ScintillaMacOSX::DefWndProc(unsigned int, uptr_t, sptr_t) { + return 0; +} + +void ScintillaMacOSX::SetTicking(bool on) { + if (timer.ticking != on) { + timer.ticking = on; + if (timer.ticking) { + // Scintilla ticks = milliseconds + EventLoopTimerRef timerRef = NULL; + InstallTimer( timer.tickSize * kEventDurationMillisecond, &timerRef ); + assert( timerRef != NULL ); + timer.tickerID = reinterpret_cast<TickerID>( timerRef ); + } else if ( timer.tickerID != NULL ) { + RemoveEventLoopTimer( reinterpret_cast<EventLoopTimerRef>( timer.tickerID ) ); + } + } + timer.ticksToWait = caret.period; +} + +bool ScintillaMacOSX::SetIdle(bool on) { + if (on) { + // Start idler, if it's not running. + if (idler.state == false) { + idler.state = true; + EventLoopTimerRef idlTimer; + InstallEventLoopIdleTimer(GetCurrentEventLoop(), + timer.tickSize * kEventDurationMillisecond, + 75 * kEventDurationMillisecond, + IdleTimerEventHandler, this, &idlTimer); + idler.idlerID = reinterpret_cast<IdlerID>( idlTimer ); + } + } else { + // Stop idler, if it's running + if (idler.state == true) { + idler.state = false; + if (idler.idlerID != NULL) + RemoveEventLoopTimer( reinterpret_cast<EventLoopTimerRef>( idler.idlerID ) ); + } + } + return true; +} + +pascal void ScintillaMacOSX::IdleTimerEventHandler( EventLoopTimerRef inTimer, + EventLoopIdleTimerMessage inState, + void *scintilla ) +{ + ScintillaMacOSX *sciThis = reinterpret_cast<ScintillaMacOSX*>( scintilla ); + bool ret = sciThis->Idle(); + if (ret == false) { + sciThis->SetIdle(false); + } +} + +void ScintillaMacOSX::SetMouseCapture(bool on) { + capturedMouse = on; + if (mouseDownCaptures) { + if (capturedMouse) { + WndProc(SCI_SETCURSOR, Window::cursorArrow, 0); + } else { + // reset to normal, buttonmove will change for other area's in the editor + WndProc(SCI_SETCURSOR, (long int)SC_CURSORNORMAL, 0); + } + } +} + +bool ScintillaMacOSX::HaveMouseCapture() { + return capturedMouse; +} + +// The default GetClientRectangle calls GetClientPosition on wMain. +// We override it to return "view local" co-ordinates so we can draw properly +// plus we need to remove the space occupied by the scroll bars +PRectangle ScintillaMacOSX::GetClientRectangle() { + PRectangle rc = wMain.GetClientPosition(); + if (verticalScrollBarVisible) + rc.right -= scrollBarFixedSize + 1; + if (horizontalScrollBarVisible && (wrapState == eWrapNone)) + rc.bottom -= scrollBarFixedSize + 1; + // Move to origin + rc.right -= rc.left; + rc.bottom -= rc.top; + rc.left = 0; + rc.top = 0; + return rc; +} + +// Synchronously paint a rectangle of the window. +void ScintillaMacOSX::SyncPaint(void* gc, PRectangle rc) { + paintState = painting; + rcPaint = rc; + PRectangle rcText = GetTextRectangle(); + paintingAllText = rcPaint.Contains(rcText); + //Platform::DebugPrintf("ScintillaMacOSX::SyncPaint %0d,%0d %0d,%0d\n", + // rcPaint.left, rcPaint.top, rcPaint.right, rcPaint.bottom); + Surface *sw = Surface::Allocate(); + if (sw) { + sw->Init( gc, wMain.GetID() ); + Paint(sw, rc); + if (paintState == paintAbandoned) { + // XXX a bit of a hack to avoid excesive flashing when typing. + paintState = painting; + paintingAllText = true; + Paint(sw, rc); + // TODO: There is a chance that this causes an infinite drawing loop... + wMain.InvalidateAll(); + } + sw->Release(); + delete sw; + } + paintState = notPainting; +} + +void ScintillaMacOSX::ScrollText(int /*linesToMove*/) { + // This function will invalidate the correct regions of the view, + // So shortly after this happens, draw will be called. + // But I'm not quite sure how this works ... + // I have a feeling that it is only supposed to work in conjunction with an HIScrollView. + // TODO: Cook up my own bitblt scroll: Grab the bits on screen, blit them shifted, invalidate the remaining stuff + //CGRect r = CGRectMake( 0, 0, rc.Width(), rc.Height() ); + //HIViewScrollRect( reinterpret_cast<HIViewRef>( wMain.GetID() ), NULL, 0, vs.lineHeight * linesToMove ); + wMain.InvalidateAll(); +} + +void ScintillaMacOSX::SetVerticalScrollPos() { + SetControl32BitValue( vScrollBar, topLine ); +} + +void ScintillaMacOSX::SetHorizontalScrollPos() { + SetControl32BitValue( hScrollBar, xOffset ); +} + +bool ScintillaMacOSX::ModifyScrollBars(int nMax, int nPage) { + Platform::DebugPrintf( "nMax: %d nPage: %d hScroll (%d -> %d) page: %d\n", nMax, nPage, 0, scrollWidth, GetTextRectangle().Width() ); + // Minimum value = 0 + // TODO: This is probably not needed, since we set this when the scroll bars are created + SetControl32BitMinimum( vScrollBar, 0 ); + SetControl32BitMinimum( hScrollBar, 0 ); + + // Maximum vertical value = nMax + 1 - nPage (lines available to scroll) + SetControl32BitMaximum( vScrollBar, Platform::Maximum( nMax + 1 - nPage, 0 ) ); + // Maximum horizontal value = scrollWidth - GetTextRectangle().Width() (pixels available to scroll) + SetControl32BitMaximum( hScrollBar, Platform::Maximum( scrollWidth - GetTextRectangle().Width(), 0 ) ); + + // Vertical page size = nPage + SetControlViewSize( vScrollBar, nPage ); + // Horizontal page size = TextRectangle().Width() + SetControlViewSize( hScrollBar, GetTextRectangle().Width() ); + + // TODO: Verify what this return value is for + // The scroll bar components will handle if they need to be rerendered or not + return false; +} + +void ScintillaMacOSX::ReconfigureScrollBars() { + PRectangle rc = wMain.GetClientPosition(); + Resize(rc.Width(), rc.Height()); +} + +void ScintillaMacOSX::Resize(int width, int height) { + // Get the horizontal/vertical size of the scroll bars + GetThemeMetric( kThemeMetricScrollBarWidth, &scrollBarFixedSize ); + + bool showSBHorizontal = horizontalScrollBarVisible && (wrapState == eWrapNone); + HIRect scrollRect; + if (verticalScrollBarVisible) { + scrollRect.origin.x = width - scrollBarFixedSize; + scrollRect.origin.y = 0; + scrollRect.size.width = scrollBarFixedSize; + if (showSBHorizontal) { + scrollRect.size.height = Platform::Maximum(1, height - scrollBarFixedSize); + } else { + scrollRect.size.height = height; + } + + HIViewSetFrame( vScrollBar, &scrollRect ); + if (HIViewGetSuperview(vScrollBar) == NULL) { + HIViewSetDrawingEnabled( vScrollBar, true ); + HIViewSetVisible(vScrollBar, true); + HIViewAddSubview(GetViewRef(), vScrollBar ); + Draw1Control(vScrollBar); + } + } else if (HIViewGetSuperview(vScrollBar) != NULL) { + HIViewSetDrawingEnabled( vScrollBar, false ); + HIViewRemoveFromSuperview(vScrollBar); + } + + if (showSBHorizontal) { + scrollRect.origin.x = 0; + // Always draw the scrollbar to avoid the "potiential" horizontal scroll bar and to avoid the resize box. + // This should be "good enough". Best would be to avoid the resize box. + // Even better would be to embed Scintilla inside an HIScrollView, which would handle this for us. + scrollRect.origin.y = height - scrollBarFixedSize; + if (verticalScrollBarVisible) { + scrollRect.size.width = Platform::Maximum( 1, width - scrollBarFixedSize ); + } else { + scrollRect.size.width = width; + } + scrollRect.size.height = scrollBarFixedSize; + + HIViewSetFrame( hScrollBar, &scrollRect ); + if (HIViewGetSuperview(hScrollBar) == NULL) { + HIViewSetDrawingEnabled( hScrollBar, true ); + HIViewAddSubview( GetViewRef(), hScrollBar ); + Draw1Control(hScrollBar); + } + } else if (HIViewGetSuperview(hScrollBar) != NULL) { + HIViewSetDrawingEnabled( hScrollBar, false ); + HIViewRemoveFromSuperview(hScrollBar); + } + + ChangeSize(); +} + +void ScintillaMacOSX::NotifyChange() { + // TODO: How should this be implemented on OS X? Should it be? +} + +pascal void ScintillaMacOSX::LiveScrollHandler( HIViewRef control, SInt16 part ) +{ + SInt16 currentValue = GetControl32BitValue( control ); + SInt16 min = GetControl32BitMinimum( control ); + SInt16 max = GetControl32BitMaximum( control ); + SInt16 page = GetControlViewSize( control ); + + // Get a reference to the Scintilla C++ object + ScintillaMacOSX* scintilla = NULL; + OSStatus err; + err = GetControlProperty( control, scintillaMacOSType, 0, sizeof( scintilla ), NULL, &scintilla ); + assert( err == noErr && scintilla != NULL ); + + int singleScroll = 0; + if ( control == scintilla->vScrollBar ) + { + // Vertical single scroll = one line + // TODO: Is there a Scintilla preference for this somewhere? + singleScroll = 1; + } else { + assert( control == scintilla->hScrollBar ); + // Horizontal single scroll = 20 pixels (hardcoded from ScintillaWin) + // TODO: Is there a Scintilla preference for this somewhere? + singleScroll = 20; + } + + // Determine the new value + int newValue = 0; + switch ( part ) + { + case kControlUpButtonPart: + newValue = Platform::Maximum( currentValue - singleScroll, min ); + break; + + case kControlDownButtonPart: + // the the user scrolls to the right, allow more scroll space + if ( control == scintilla->hScrollBar && currentValue >= max) { + // change the max value + scintilla->scrollWidth += singleScroll; + SetControl32BitMaximum( control, + Platform::Maximum( scintilla->scrollWidth - scintilla->GetTextRectangle().Width(), 0 ) ); + max = GetControl32BitMaximum( control ); + scintilla->SetScrollBars(); + } + newValue = Platform::Minimum( currentValue + singleScroll, max ); + break; + + case kControlPageUpPart: + newValue = Platform::Maximum( currentValue - page, min ); + break; + + case kControlPageDownPart: + newValue = Platform::Minimum( currentValue + page, max ); + break; + + case kControlIndicatorPart: + newValue = currentValue; + break; + + default: + assert( false ); + return; + } + + // Set the new value + if ( control == scintilla->vScrollBar ) + { + scintilla->ScrollTo( newValue ); + } else { + assert( control == scintilla->hScrollBar ); + scintilla->HorizontalScrollTo( newValue ); + } +} + +bool ScintillaMacOSX::ScrollBarHit(HIPoint location) { + // is this on our scrollbars? If so, track them + HIViewRef view; + // view is null if on editor, otherwise on scrollbar + HIViewGetSubviewHit(reinterpret_cast<ControlRef>(wMain.GetID()), + &location, true, &view); + if (view) { + HIViewPartCode part; + + // make the point local to a scrollbar + PRectangle client = GetClientRectangle(); + if (view == vScrollBar) { + location.x -= client.Width(); + } else if (view == hScrollBar) { + location.y -= client.Height(); + } else { + fprintf(stderr, "got a subview hit, but not a scrollbar???\n"); + return false; + } + + HIViewGetPartHit(view, &location, &part); + + switch (part) + { + case kControlUpButtonPart: + case kControlDownButtonPart: + case kControlPageUpPart: + case kControlPageDownPart: + case kControlIndicatorPart: + ::Point p; + p.h = location.x; + p.v = location.y; + // We are assuming Appearance 1.1 or later, so we + // have the "live scroll" variant of the scrollbar, + // which lets you pass the action proc to TrackControl + // for the thumb (this was illegal in previous + // versions of the defproc). + isTracking = true; + ::TrackControl(view, p, ScintillaMacOSX::LiveScrollHandler); + ::HiliteControl(view, 0); + isTracking = false; + // The mouseup was eaten by TrackControl, however if we + // do not get a mouseup in the scintilla xbl widget, + // many bad focus issues happen. Simply post a mouseup + // and this firey pit becomes a bit cooler. + PostEvent(mouseUp, 0); + break; + default: + fprintf(stderr, "PlatformScrollBarHit part %d\n", part); + } + return true; + } + return false; +} + + +void ScintillaMacOSX::NotifyFocus(bool /*focus*/) { + // TODO: How should this be implemented on OS X? Should it be? +} + +typedef void (*SciNotifyFunc)(sptr_t *, long); +void ScintillaMacOSX::NotifyParent(SCNotification scn) { + OSStatus err; + sptr_t *ptr = NULL; + SciNotifyFunc fn = NULL; + + // XXX do this at some other point, or otherwise cache the results + err = GetControlProperty(GetViewRef(), + scintillaNotifyObject, 0, + sizeof( sptr_t * ), NULL, &ptr ); + if (err != noErr) return; + err = GetControlProperty(GetViewRef(), + scintillaNotifyFN, 0, + sizeof( SciNotifyFunc ), NULL, &fn ); + if (err != noErr || !fn) return; + + scn.nmhdr.hwndFrom = GetViewRef(); + scn.nmhdr.idFrom = (unsigned int)wMain.GetID(); + fn(ptr, (long int)&scn); +} + +void ScintillaMacOSX::NotifyKey(int key, int modifiers) { + SCNotification scn; + scn.nmhdr.code = SCN_KEY; + scn.ch = key; + scn.modifiers = modifiers; + + NotifyParent(scn); +} + +void ScintillaMacOSX::NotifyURIDropped(const char *list) { + SCNotification scn; + scn.nmhdr.code = SCN_URIDROPPED; + scn.text = list; + + NotifyParent(scn); +} + +int ScintillaMacOSX::KeyDefault(int key, int modifiers) { + if (!(modifiers & SCI_CTRL) && !(modifiers & SCI_ALT) && (key < 256)) { + AddChar(key); + return 1; + } else { + // Pass up to container in case it is an accelerator + NotifyKey(key, modifiers); + return 0; + } + //Platform::DebugPrintf("SK-key: %d %x %x\n",key, modifiers); +} + +template <class T, class U> +struct StupidMap +{ +public: + T key; + U value; +}; + +template <class T, class U> +inline static U StupidMapFindFunction( const StupidMap<T, U>* elements, size_t length, const T& desiredKey ) +{ + for ( size_t i = 0; i < length; ++ i ) + { + if ( elements[i].key == desiredKey ) + { + return elements[i].value; + } + } + + return NULL; +} + +// NOTE: If this macro is used on a StupidMap that isn't defined by StupidMap x[] = ... +// The size calculation will fail! +#define StupidMapFind( x, y ) StupidMapFindFunction( x, sizeof(x)/sizeof(*x), y ) + +pascal OSStatus ScintillaMacOSX::CommandEventHandler( EventHandlerCallRef /*inCallRef*/, EventRef event, void* data ) +{ + // TODO: Verify automatically that each constant only appears once? + const StupidMap<UInt32, void (ScintillaMacOSX::*)()> processCommands[] = { + { kHICommandCopy, &ScintillaMacOSX::Copy }, + { kHICommandPaste, &ScintillaMacOSX::Paste }, + { kHICommandCut, &ScintillaMacOSX::Cut }, + { kHICommandUndo, &ScintillaMacOSX::Undo }, + { kHICommandRedo, &ScintillaMacOSX::Redo }, + { kHICommandClear, &ScintillaMacOSX::ClearSelection }, + { kHICommandSelectAll, &ScintillaMacOSX::SelectAll }, + }; + const StupidMap<UInt32, bool (ScintillaMacOSX::*)()> canProcessCommands[] = { + { kHICommandCopy, &ScintillaMacOSX::HasSelection }, + { kHICommandPaste, &ScintillaMacOSX::CanPaste }, + { kHICommandCut, &ScintillaMacOSX::HasSelection }, + { kHICommandUndo, &ScintillaMacOSX::CanUndo }, + { kHICommandRedo, &ScintillaMacOSX::CanRedo }, + { kHICommandClear, &ScintillaMacOSX::HasSelection }, + { kHICommandSelectAll, &ScintillaMacOSX::AlwaysTrue }, + }; + + HICommand command; + OSStatus result = GetEventParameter( event, kEventParamDirectObject, typeHICommand, NULL, sizeof( command ), NULL, &command ); + assert( result == noErr ); + + UInt32 kind = GetEventKind( event ); + Platform::DebugPrintf("ScintillaMacOSX::CommandEventHandler kind %d\n", kind); + + ScintillaMacOSX* scintilla = reinterpret_cast<ScintillaMacOSX*>( data ); + assert( scintilla != NULL ); + + if ( kind == kEventProcessCommand ) + { + // Find the method pointer that matches this command + void (ScintillaMacOSX::*methodPtr)() = StupidMapFind( processCommands, command.commandID ); + + if ( methodPtr != NULL ) + { + // Call the method if we found it, and tell the caller that we handled this event + (scintilla->*methodPtr)(); + result = noErr; + } else { + // tell the caller that we did not handle the event + result = eventNotHandledErr; + } + } + // The default Mac OS X text editor does not handle these events to enable/disable menu items + // Why not? I think it should, so Scintilla does. + else if ( kind == kEventCommandUpdateStatus && ( command.attributes & kHICommandFromMenu ) ) + { + // Find the method pointer that matches this command + bool (ScintillaMacOSX::*methodPtr)() = StupidMapFind( canProcessCommands, command.commandID ); + + if ( methodPtr != NULL ) { + // Call the method if we found it: enabling/disabling menu items + if ( (scintilla->*methodPtr)() ) { + EnableMenuItem( command.menu.menuRef, command.menu.menuItemIndex ); + } else { + DisableMenuItem( command.menu.menuRef, command.menu.menuItemIndex ); + } + result = noErr; + } else { + // tell the caller that we did not handle the event + result = eventNotHandledErr; + } + } else { + // Unhandled event: We should never get here + assert( false ); + result = eventNotHandledErr; + } + + return result; +} + +bool ScintillaMacOSX::HasSelection() +{ + return ( SelectionEnd() - SelectionStart() > 0 ); +} + +bool ScintillaMacOSX::CanUndo() +{ + return pdoc->CanUndo(); +} + +bool ScintillaMacOSX::CanRedo() +{ + return pdoc->CanRedo(); +} + +bool ScintillaMacOSX::AlwaysTrue() +{ + return true; +} + +void ScintillaMacOSX::CopyToClipboard(const SelectionText &selectedText) { + if (selectedText.len == 0) + return; + + CFStringEncoding encoding = ( IsUnicodeMode() ? kCFStringEncodingUTF8 : kCFStringEncodingASCII); + + // Create a CFString from the ASCII/UTF8 data, convert it to UTF16 + CFStringRef string = CFStringCreateWithBytes( NULL, reinterpret_cast<UInt8*>( selectedText.s ), selectedText.len - 1, encoding, false ); + assert( string != NULL ); + + CFIndex numUniChars = CFStringGetLength( string ); + UniChar* buffer = new UniChar[ numUniChars ]; + CFStringGetCharacters( string, CFRangeMake( 0, numUniChars ), buffer ); + + // Done with the CFString + CFRelease( string ); + string = NULL; + + OSStatus err; + err = ClearCurrentScrap(); + assert( err == noErr ); + + ScrapRef scrap = NULL; + err = GetCurrentScrap( &scrap ); + assert( err == noErr && scrap != NULL ); + + err = PutScrapFlavor( scrap, kScrapFlavorTypeUnicode, 0, sizeof( UniChar ) * numUniChars, buffer ); + assert( err == noErr ); + err = PutScrapFlavor( scrap, kScrapFlavorTypeText, 0, sizeof( char ) * selectedText.len, reinterpret_cast<UInt8*>( selectedText.s ) ); + assert( err == noErr ); + + // Done with the UniChar* buffer + delete[] buffer; + buffer = NULL; +} + +void ScintillaMacOSX::Copy() +{ + if (currentPos != anchor) { + SelectionText selectedText; + CopySelectionRange(&selectedText); + CopyToClipboard(selectedText); + } +} + +bool ScintillaMacOSX::CanPaste() +{ + ScrapRef scrap = NULL; + OSStatus err; + err = GetCurrentScrap( &scrap ); + assert( err == noErr && scrap != NULL ); + + ScrapFlavorFlags flavorFlags; + return GetScrapFlavorFlags ( scrap, kScrapFlavorTypeUnicode, &flavorFlags ) == noErr || + GetScrapFlavorFlags ( scrap, kScrapFlavorTypeText, &flavorFlags ) == noErr; +} + +void ScintillaMacOSX::Paste() +{ + Paste(false); +} + +// XXX there is no system flag (I can find) to tell us that a paste is rectangular, so +// applications must implement an additional command (eg. option-V like BBEdit) +// in order to provide rectangular paste +void ScintillaMacOSX::Paste(bool isRectangular) +{ + // Make sure that we CAN paste + if ( ! CanPaste() ) return; + + // Get the clipboard reference + ScrapRef scrap = NULL; + OSStatus err; + err = GetCurrentScrap( &scrap ); + assert( err == noErr && scrap != NULL ); + + ScrapFlavorFlags flavorFlags; + Size bytes = 0; + CFStringRef string = NULL; + if (GetScrapFlavorFlags ( scrap, kScrapFlavorTypeUnicode, &flavorFlags ) == noErr) + { + // No error, we have unicode data in a Scrap. Find out how many bytes of data it is. + err = GetScrapFlavorSize( scrap, kScrapFlavorTypeUnicode, &bytes ); + assert( err == noErr && bytes != 0 ); + Size numUniChars = bytes / sizeof( UniChar ); + + // Allocate a buffer for the text using Core Foundation + UniChar* buffer = reinterpret_cast<UniChar*>( CFAllocatorAllocate( NULL, bytes, 0 ) ); + assert( buffer != NULL ); + + // Get a copy of the text + Size nextBytes = bytes; + err = GetScrapFlavorData( scrap, kScrapFlavorTypeUnicode, &nextBytes, buffer ); + assert( err == noErr && nextBytes == bytes ); + + // Create a CFString which wraps and takes ownership of the buffer + string = CFStringCreateWithCharactersNoCopy( NULL, buffer, numUniChars, NULL ); + assert( string != NULL ); + buffer = NULL; // string now owns this buffer + } else if (GetScrapFlavorFlags ( scrap, kScrapFlavorTypeText, &flavorFlags ) == noErr) { + // No error, we have unicode data in a Scrap. Find out how many bytes of data it is. + err = GetScrapFlavorSize( scrap, kScrapFlavorTypeText, &bytes ); + assert( err == noErr && bytes != 0 ); + + // Allocate a buffer for the text using Core Foundation + char* buffer = reinterpret_cast<char*>( CFAllocatorAllocate( NULL, bytes + 1, 0 ) ); + assert( buffer != NULL ); + + // Get a copy of the text + Size nextBytes = bytes; + err = GetScrapFlavorData( scrap, kScrapFlavorTypeText, &nextBytes, buffer ); + assert( err == noErr && nextBytes == bytes ); + buffer[bytes]=0; + // Create a CFString which wraps and takes ownership of the buffer + string = CFStringCreateWithCStringNoCopy( NULL, buffer, kCFStringEncodingMacRoman, NULL ); + assert( string != NULL ); + buffer = NULL; // string now owns this buffer + } else { + // a flavor we do not understand + return; + } + + + // Allocate a buffer, plus the null byte + CFIndex numUniChars = CFStringGetLength( string ); + CFStringEncoding encoding = ( IsUnicodeMode() ? kCFStringEncodingUTF8 : kCFStringEncodingASCII); + CFIndex maximumByteLength = CFStringGetMaximumSizeForEncoding( numUniChars, encoding ) + 1; + char* cstring = new char[maximumByteLength]; + CFIndex usedBufferLength = 0; + CFIndex numCharsConverted; + numCharsConverted = CFStringGetBytes( string, CFRangeMake( 0, numUniChars ), encoding, + '?', false, reinterpret_cast<UInt8*>( cstring ), + maximumByteLength, &usedBufferLength ); + cstring[usedBufferLength] = '\0'; // null terminate the ASCII/UTF8 string + assert( numCharsConverted == numUniChars ); + + // Default allocator releases both the CFString and the UniChar buffer (text) + CFRelease( string ); + string = NULL; + + // determine whether a BOM is in the string. Apps like Emacs prepends a BOM + // to the string, CFStrinGetBytes reflects that (though it may change in the conversion) + // so we need to remove it before pasting into our buffer. TextWrangler has no + // problem dealing with BOM when pasting into it. + int bomLen = BOMlen((unsigned char *)cstring); + + // convert line endings to the document line ending + int newlen = 0; + char *pasted = Document::TransformLineEnds(&newlen, + cstring + bomLen, + usedBufferLength - bomLen, + pdoc->eolMode); + + pdoc->BeginUndoAction(); + ClearSelection(); + + if (isRectangular) { + int selStart = SelectionStart(); + PasteRectangular(selStart, pasted, newlen); + } else + if ( pdoc->InsertString( currentPos, pasted, newlen ) ) { + SetEmptySelection( currentPos + newlen ); + } + + delete[] pasted; + delete[] cstring; + cstring = NULL; + + pdoc->EndUndoAction(); + NotifyChange(); + Redraw(); +} + +void ScintillaMacOSX::CreateCallTipWindow(PRectangle rc) { + // create a calltip window + if (!ct.wCallTip.Created()) { + WindowClass windowClass = kHelpWindowClass; + WindowAttributes attributes = kWindowNoAttributes; + Rect contentBounds; + WindowRef outWindow; + + // convert PRectangle to Rect + // this adjustment gets the calltip window placed in the correct location relative + // to our editor window + Rect bounds; + OSStatus err; + err = GetWindowBounds( this->GetOwner(), kWindowGlobalPortRgn, &bounds ); + assert( err == noErr ); + contentBounds.top = rc.top + bounds.top; + contentBounds.bottom = rc.bottom + bounds.top; + contentBounds.right = rc.right + bounds.left; + contentBounds.left = rc.left + bounds.left; + + // create our calltip hiview + HIViewRef ctw = scintilla_calltip_new(); + CallTip* objectPtr = &ct; + ScintillaMacOSX* sciThis = this; + SetControlProperty( ctw, scintillaMacOSType, 0, sizeof( this ), &sciThis ); + SetControlProperty( ctw, scintillaCallTipType, 0, sizeof( objectPtr ), &objectPtr ); + + CreateNewWindow(windowClass, attributes, &contentBounds, &outWindow); + ControlRef root; + CreateRootControl(outWindow, &root); + + HIViewRef hiroot = HIViewGetRoot (outWindow); + HIViewAddSubview(hiroot, ctw); + + HIRect boundsRect; + HIViewGetFrame(hiroot, &boundsRect); + HIViewSetFrame( ctw, &boundsRect ); + + // bind the size of the calltip to the size of it's container window + HILayoutInfo layout = { + kHILayoutInfoVersionZero, + { + { NULL, kHILayoutBindTop, 0 }, + { NULL, kHILayoutBindLeft, 0 }, + { NULL, kHILayoutBindBottom, 0 }, + { NULL, kHILayoutBindRight, 0 } + }, + { + { NULL, kHILayoutScaleAbsolute, 0 }, + { NULL, kHILayoutScaleAbsolute, 0 } + + }, + { + { NULL, kHILayoutPositionTop, 0 }, + { NULL, kHILayoutPositionLeft, 0 } + } + }; + HIViewSetLayoutInfo(ctw, &layout); + + ct.wCallTip = root; + ct.wDraw = ctw; + ct.wCallTip.SetWindow(outWindow); + HIViewSetVisible(ctw,true); + + } +} + +void ScintillaMacOSX::CallTipClick() +{ + ScintillaBase::CallTipClick(); +} + +void ScintillaMacOSX::AddToPopUp( const char *label, int cmd, bool enabled ) +{ + // Translate stuff into menu item attributes + MenuItemAttributes attributes = 0; + if ( label[0] == '\0' ) attributes |= kMenuItemAttrSeparator; + if ( ! enabled ) attributes |= kMenuItemAttrDisabled; + + // Translate Scintilla commands into Mac OS commands + // TODO: If I create an AEDesc, OS X may insert these standard + // text editing commands into the menu for me + MenuCommand macCommand; + switch( cmd ) + { + case idcmdUndo: + macCommand = kHICommandUndo; + break; + case idcmdRedo: + macCommand = kHICommandRedo; + break; + case idcmdCut: + macCommand = kHICommandCut; + break; + case idcmdCopy: + macCommand = kHICommandCopy; + break; + case idcmdPaste: + macCommand = kHICommandPaste; + break; + case idcmdDelete: + macCommand = kHICommandClear; + break; + case idcmdSelectAll: + macCommand = kHICommandSelectAll; + break; + case 0: + macCommand = 0; + break; + default: + assert( false ); + return; + } + + CFStringRef string = CFStringCreateWithCString( NULL, label, kTextEncodingMacRoman ); + OSStatus err; + err = AppendMenuItemTextWithCFString( reinterpret_cast<MenuRef>( popup.GetID() ), + string, attributes, macCommand, NULL ); + assert( err == noErr ); + + CFRelease( string ); + string = NULL; +} + +void ScintillaMacOSX::ClaimSelection() { + // Mac OS X does not have a primary selection +} + +/** A wrapper function to permit external processes to directly deliver messages to our "message loop". */ +sptr_t ScintillaMacOSX::DirectFunction( + ScintillaMacOSX *sciThis, unsigned int iMessage, uptr_t wParam, sptr_t lParam) { + return sciThis->WndProc(iMessage, wParam, lParam); +} + +sptr_t scintilla_send_message(void* sci, unsigned int iMessage, uptr_t wParam, sptr_t lParam) { + HIViewRef control = reinterpret_cast<HIViewRef>(sci); + // Platform::DebugPrintf("scintilla_send_message %08X control %08X\n",sci,control); + // Get a reference to the Scintilla C++ object + ScintillaMacOSX* scintilla = NULL; + OSStatus err; + err = GetControlProperty( control, scintillaMacOSType, 0, sizeof( scintilla ), NULL, &scintilla ); + assert( err == noErr && scintilla != NULL ); + //Platform::DebugPrintf("scintilla_send_message scintilla %08X\n",scintilla); + + return scintilla->WndProc(iMessage, wParam, lParam); +} + +void ScintillaMacOSX::TimerFired( EventLoopTimerRef ) +{ + Tick(); + DragScroll(); +} + +OSStatus ScintillaMacOSX::BoundsChanged( UInt32 /*inOptions*/, const HIRect& inOriginalBounds, const HIRect& inCurrentBounds, RgnHandle /*inInvalRgn*/ ) +{ + // If the width or height changed, modify the scroll bars and notify Scintilla + // This event is also delivered when the window moves, and we don't care about that + if ( inOriginalBounds.size.width != inCurrentBounds.size.width || inOriginalBounds.size.height != inCurrentBounds.size.height ) + { + Resize( static_cast<int>( inCurrentBounds.size.width ), static_cast<int>( inCurrentBounds.size.height ) ); + } + return noErr; +} + +void ScintillaMacOSX::Draw( RgnHandle rgn, CGContextRef gc ) +{ + Rect invalidRect; + GetRegionBounds( rgn, &invalidRect ); + + // NOTE: We get draw events that include the area covered by the scroll bar. No fear: Scintilla correctly ignores them + SyncPaint( gc, PRectangle( invalidRect.left, invalidRect.top, invalidRect.right, invalidRect.bottom ) ); +} + +ControlPartCode ScintillaMacOSX::HitTest( const HIPoint& where ) +{ + if ( CGRectContainsPoint( Bounds(), where ) ) + return 1; + else + return kControlNoPart; +} + +OSStatus ScintillaMacOSX::SetFocusPart( ControlPartCode desiredFocus, RgnHandle /*invalidRgn*/, Boolean /*inFocusEverything*/, ControlPartCode* outActualFocus ) +{ + assert( outActualFocus != NULL ); + + if ( desiredFocus == 0 ) { + // We are losing the focus + SetFocusState(false); + } else { + // We are getting the focus + SetFocusState(true); + } + + *outActualFocus = desiredFocus; + return noErr; +} + +// Map Mac Roman character codes to their equivalent Scintilla codes +static inline int KeyTranslate( UniChar unicodeChar ) +{ + switch ( unicodeChar ) + { + case kDownArrowCharCode: + return SCK_DOWN; + case kUpArrowCharCode: + return SCK_UP; + case kLeftArrowCharCode: + return SCK_LEFT; + case kRightArrowCharCode: + return SCK_RIGHT; + case kHomeCharCode: + return SCK_HOME; + case kEndCharCode: + return SCK_END; + case kPageUpCharCode: + return SCK_PRIOR; + case kPageDownCharCode: + return SCK_NEXT; + case kDeleteCharCode: + return SCK_DELETE; + // TODO: Is there an insert key in the mac world? My insert key is the "help" key + case kHelpCharCode: + return SCK_INSERT; + case kEnterCharCode: + case kReturnCharCode: + return SCK_RETURN; + case kEscapeCharCode: + return SCK_ESCAPE; + case kBackspaceCharCode: + return SCK_BACK; + case '\t': + return SCK_TAB; + case '+': + return SCK_ADD; + case '-': + return SCK_SUBTRACT; + case '/': + return SCK_DIVIDE; + case kFunctionKeyCharCode: + return kFunctionKeyCharCode; + default: + return 0; + } +} + +static inline UniChar GetCharacterWithoutModifiers( EventRef rawKeyboardEvent ) +{ + UInt32 keyCode; + // Get the key code from the raw key event + GetEventParameter( rawKeyboardEvent, kEventParamKeyCode, typeUInt32, NULL, sizeof( keyCode ), NULL, &keyCode ); + + // Get the current keyboard layout + // TODO: If this is a performance sink, we need to cache these values + SInt16 lastKeyLayoutID = GetScriptVariable( /*currentKeyScript*/ GetScriptManagerVariable(smKeyScript), smScriptKeys); + Handle uchrHandle = GetResource('uchr', lastKeyLayoutID); + + // Translate the key press ignoring ctrl and option + UInt32 ignoredDeadKeys = 0; + UInt32 ignoredActualLength = 0; + UniChar unicodeKey = 0; + // (((modifiers & shiftKey) >> 8) & 0xFF) + OSStatus err; + err = UCKeyTranslate( reinterpret_cast<UCKeyboardLayout*>( *uchrHandle ), keyCode, kUCKeyActionDown, + /* modifierKeyState */ 0, LMGetKbdType(), kUCKeyTranslateNoDeadKeysMask, &ignoredDeadKeys, + /* buffer length */ 1, + /* actual length */ &ignoredActualLength, + /* string */ &unicodeKey ); + assert( err == noErr ); + + return unicodeKey; +} + +// Text input is very annoying: +// If the control key is pressed, or if the key is a "special" key (eg. arrow keys, function keys, whatever) +// we let Scintilla handle it. If scintilla does not handle it, we do nothing (eventNotHandledErr). +// Otherwise, the event is just some text and we add it to the buffer +OSStatus ScintillaMacOSX::TextInput( TCarbonEvent& event ) +{ + // Obtain the number of bytes of text + UInt32 actualSize = 0; + OSStatus err; + err = event.GetParameterSize( kEventParamTextInputSendText, &actualSize ); + assert( err == noErr ); + assert( actualSize != 0 ); + + const int numUniChars = actualSize / sizeof( UniChar ); + + // Allocate a buffer for the text using Core Foundation + UniChar* text = reinterpret_cast<UniChar*>( CFAllocatorAllocate( CFAllocatorGetDefault(), actualSize, 0 ) ); + assert( text != NULL ); + + // Get a copy of the text + err = event.GetParameter( kEventParamTextInputSendText, typeUnicodeText, actualSize, text ); + assert( err == noErr ); + + // TODO: This is a gross hack to ignore function keys + // Surely we can do better? + if ( numUniChars == 1 && text[0] == kFunctionKeyCharCode ) return eventNotHandledErr; + int modifiers = GetCurrentEventKeyModifiers(); + int scintillaKey = KeyTranslate( text[0] ); + + // Create a CFString which wraps and takes ownership of the "text" buffer + CFStringRef string = CFStringCreateWithCharactersNoCopy( NULL, text, numUniChars, NULL ); + assert( string != NULL ); + //delete text; + text = NULL; + + // If we have a single unicode character that is special or + // to process a command. Try to do some translation. + if ( numUniChars == 1 && ( modifiers & controlKey || scintillaKey != 0 ) ) { + // If we have a modifier, we need to get the character without modifiers + if ( modifiers & controlKey ) { + EventRef rawKeyboardEvent = NULL; + event.GetParameter( + kEventParamTextInputSendKeyboardEvent, + typeEventRef, + sizeof( EventRef ), + &rawKeyboardEvent ); + assert( rawKeyboardEvent != NULL ); + scintillaKey = GetCharacterWithoutModifiers( rawKeyboardEvent ); + + // Make sure that we still handle special characters correctly + int temp = KeyTranslate( scintillaKey ); + if ( temp != 0 ) scintillaKey = temp; + + // TODO: This is a gross Unicode hack: ASCII chars have a value < 127 + if ( scintillaKey <= 127 ) { + scintillaKey = toupper( (char) scintillaKey ); + } + } + + // Code taken from Editor::KeyDown + // It is copied here because we don't want to feed the key via + // KeyDefault if there is no special action + DwellEnd(false); + int scintillaModifiers = ( (modifiers & shiftKey) ? SCI_SHIFT : 0) | ( (modifiers & controlKey) ? SCI_CTRL : 0) | + ( (modifiers & optionKey) ? SCI_ALT : 0); + int msg = kmap.Find( scintillaKey, scintillaModifiers ); + if (msg) { + // The keymap has a special event for this key: perform the operation + WndProc(msg, 0, 0); + err = noErr; + } else { + // We do not handle this event + err = eventNotHandledErr; + } + } else { + CFStringEncoding encoding = ( IsUnicodeMode() ? kCFStringEncodingUTF8 : kCFStringEncodingASCII); + + // Allocate the buffer (don't forget the null!) + CFIndex maximumByteLength = CFStringGetMaximumSizeForEncoding( numUniChars, encoding ) + 1; + char* buffer = new char[maximumByteLength]; + + CFIndex usedBufferLength = 0; + CFIndex numCharsConverted; + numCharsConverted = CFStringGetBytes( string, CFRangeMake( 0, numUniChars ), encoding, + '?', false, reinterpret_cast<UInt8*>( buffer ), + maximumByteLength, &usedBufferLength ); + assert( numCharsConverted == numUniChars ); + buffer[usedBufferLength] = '\0'; // null terminate + + // Add all the characters to the document + // NOTE: OS X doesn't specify that text input events provide only a single character + // if we get a single character, add it as a character + // otherwise, we insert the entire string + if ( numUniChars == 1 ) { + AddCharUTF( buffer, usedBufferLength ); + } else { + // WARNING: This is an untested code path as with my US keyboard, I only enter a single character at a time + if (pdoc->InsertString(currentPos, buffer, usedBufferLength)) { + SetEmptySelection(currentPos + usedBufferLength); + } + } + + // Free the buffer that was allocated + delete[] buffer; + buffer = NULL; + err = noErr; + } + + // Default allocator releases both the CFString and the UniChar buffer (text) + CFRelease( string ); + string = NULL; + + return err; +} + +UInt32 ScintillaMacOSX::GetBehaviors() +{ + return TView::GetBehaviors() | kControlGetsFocusOnClick | kControlSupportsEmbedding; +} + +OSStatus ScintillaMacOSX::MouseEntered(HIPoint& location, UInt32 /*inKeyModifiers*/, EventMouseButton /*inMouseButton*/, UInt32 /*inClickCount*/ ) +{ + if (!HaveMouseCapture() && HIViewGetSuperview(GetViewRef()) != NULL) { + HIViewRef view; + HIViewGetSubviewHit(reinterpret_cast<ControlRef>(wMain.GetID()), &location, true, &view); + if (view) { + // the hit is on a subview (ie. scrollbars) + WndProc(SCI_SETCURSOR, Window::cursorArrow, 0); + } else { + // reset to normal, buttonmove will change for other area's in the editor + WndProc(SCI_SETCURSOR, (long int)SC_CURSORNORMAL, 0); + } + return noErr; + } + return eventNotHandledErr; +} + +OSStatus ScintillaMacOSX::MouseExited(HIPoint& location, UInt32 modifiers, EventMouseButton button, UInt32 clickCount ) +{ + if (HIViewGetSuperview(GetViewRef()) != NULL) { + if (HaveMouseCapture()) { + ButtonUp( Scintilla::Point( static_cast<int>( location.x ), static_cast<int>( location.y ) ), + static_cast<int>( GetCurrentEventTime() / kEventDurationMillisecond ), + (modifiers & controlKey) != 0 ); + } + WndProc(SCI_SETCURSOR, Window::cursorArrow, 0); + return noErr; + } + return eventNotHandledErr; +} + + +OSStatus ScintillaMacOSX::MouseDown( HIPoint& location, UInt32 modifiers, EventMouseButton button, UInt32 clickCount , TCarbonEvent& inEvent) +{ + ConvertEventRefToEventRecord( inEvent.GetEventRef(), &mouseDownEvent ); + return MouseDown(location, modifiers, button, clickCount); +} + +OSStatus ScintillaMacOSX::MouseDown( EventRecord *event ) +{ + HIPoint pt = GetLocalPoint(event->where); + int button = kEventMouseButtonPrimary; + mouseDownEvent = *event; + + if ( event->modifiers & controlKey ) + button = kEventMouseButtonSecondary; + return MouseDown(pt, event->modifiers, button, 1); +} + +OSStatus ScintillaMacOSX::MouseDown( HIPoint& location, UInt32 modifiers, EventMouseButton button, UInt32 /*clickCount*/ ) +{ + // We only deal with the first mouse button + if ( button != kEventMouseButtonPrimary ) return eventNotHandledErr; + // TODO: Verify that Scintilla wants the time in milliseconds + if (!HaveMouseCapture() && HIViewGetSuperview(GetViewRef()) != NULL) { + if (ScrollBarHit(location)) return noErr; + } + ButtonDown( Scintilla::Point( static_cast<int>( location.x ), static_cast<int>( location.y ) ), + static_cast<int>( GetCurrentEventTime() / kEventDurationMillisecond ), + (modifiers & shiftKey) != 0, + (modifiers & controlKey) != 0, + (modifiers & cmdKey) ); +#if !defined(CONTAINER_HANDLES_EVENTS) + OSStatus err; + err = SetKeyboardFocus( this->GetOwner(), this->GetViewRef(), 1 ); + assert( err == noErr ); + return noErr; +#else + return eventNotHandledErr; // allow event to go to container +#endif +} + +OSStatus ScintillaMacOSX::MouseUp( EventRecord *event ) +{ + HIPoint pt = GetLocalPoint(event->where); + int button = kEventMouseButtonPrimary; + if ( event->modifiers & controlKey ) + button = kEventMouseButtonSecondary; + return MouseUp(pt, event->modifiers, button, 1); +} + +OSStatus ScintillaMacOSX::MouseUp( HIPoint& location, UInt32 modifiers, EventMouseButton button, UInt32 /*clickCount*/ ) +{ + // We only deal with the first mouse button + if ( button != kEventMouseButtonPrimary ) return eventNotHandledErr; + ButtonUp( Scintilla::Point( static_cast<int>( location.x ), static_cast<int>( location.y ) ), + static_cast<int>( GetCurrentEventTime() / kEventDurationMillisecond ), + (modifiers & controlKey) != 0 ); + +#if !defined(CONTAINER_HANDLES_EVENTS) + return noErr; +#else + return eventNotHandledErr; // allow event to go to container +#endif +} + +OSStatus ScintillaMacOSX::MouseDragged( EventRecord *event ) +{ + HIPoint pt = GetLocalPoint(event->where); + int button = 0; + if ( event->modifiers & btnStateBit ) { + button = kEventMouseButtonPrimary; + if ( event->modifiers & controlKey ) + button = kEventMouseButtonSecondary; + } + return MouseDragged(pt, event->modifiers, button, 1); +} + +OSStatus ScintillaMacOSX::MouseDragged( HIPoint& location, UInt32 modifiers, EventMouseButton button, UInt32 clickCount ) +{ +#if !defined(CONTAINER_HANDLES_EVENTS) + ButtonMove( Scintilla::Point( static_cast<int>( location.x ), static_cast<int>( location.y ) ) ); + return noErr; +#else + if (HaveMouseCapture() && !inDragDrop) { + MouseTrackingResult mouseStatus = 0; + ::Point theQDPoint; + UInt32 outModifiers; + EventTimeout inTimeout=0.1; + while (mouseStatus != kMouseTrackingMouseReleased) { + ButtonMove( Scintilla::Point( static_cast<int>( location.x ), static_cast<int>( location.y ) ) ); + TrackMouseLocationWithOptions((GrafPtr)-1, + kTrackMouseLocationOptionDontConsumeMouseUp, + inTimeout, + &theQDPoint, + &outModifiers, + &mouseStatus); + location = GetLocalPoint(theQDPoint); + } + ButtonUp( Scintilla::Point( static_cast<int>( location.x ), static_cast<int>( location.y ) ), + static_cast<int>( GetCurrentEventTime() / kEventDurationMillisecond ), + (modifiers & controlKey) != 0 ); + } else { + if (!HaveMouseCapture() && HIViewGetSuperview(GetViewRef()) != NULL) { + HIViewRef view; + HIViewGetSubviewHit(reinterpret_cast<ControlRef>(wMain.GetID()), &location, true, &view); + if (view) { + // the hit is on a subview (ie. scrollbars) + WndProc(SCI_SETCURSOR, Window::cursorArrow, 0); + return eventNotHandledErr; + } else { + // reset to normal, buttonmove will change for other area's in the editor + WndProc(SCI_SETCURSOR, (long int)SC_CURSORNORMAL, 0); + } + } + ButtonMove( Scintilla::Point( static_cast<int>( location.x ), static_cast<int>( location.y ) ) ); + } + return eventNotHandledErr; // allow event to go to container +#endif +} + +OSStatus ScintillaMacOSX::MouseWheelMoved( EventMouseWheelAxis axis, SInt32 delta, UInt32 modifiers ) +{ + if ( axis != 1 ) return eventNotHandledErr; + + if ( modifiers & controlKey ) { + // Zoom! We play with the font sizes in the styles. + // Number of steps/line is ignored, we just care if sizing up or down + if ( delta > 0 ) { + KeyCommand( SCI_ZOOMIN ); + } else { + KeyCommand( SCI_ZOOMOUT ); + } + } else { + // Decide if this should be optimized? + ScrollTo( topLine - delta ); + } + + return noErr; +} + +OSStatus ScintillaMacOSX::ContextualMenuClick( HIPoint& location ) +{ + // convert screen coords to window relative + Rect bounds; + OSStatus err; + err = GetWindowBounds( this->GetOwner(), kWindowContentRgn, &bounds ); + assert( err == noErr ); + location.x += bounds.left; + location.y += bounds.top; + ContextMenu( Scintilla::Point( static_cast<int>( location.x ), static_cast<int>( location.y ) ) ); + return noErr; +} + +OSStatus ScintillaMacOSX::ActiveStateChanged() +{ + // If the window is being deactivated, lose the focus and turn off the ticking + if ( ! this->IsActive() ) { + DropCaret(); + //SetFocusState( false ); + SetTicking( false ); + } else { + ShowCaretAtCurrentPosition(); + } + return noErr; +} + +HIViewRef ScintillaMacOSX::Create() +{ + // Register the HIView, if needed + static bool registered = false; + + if ( not registered ) { + TView::RegisterSubclass( kScintillaClassID, Construct ); + registered = true; + } + + OSStatus err = noErr; + EventRef event = CreateInitializationEvent(); + assert( event != NULL ); + + HIViewRef control = NULL; + err = HIObjectCreate( kScintillaClassID, event, reinterpret_cast<HIObjectRef*>( &control ) ); + ReleaseEvent( event ); + if ( err == noErr ) { + Platform::DebugPrintf("ScintillaMacOSX::Create control %08X\n",control); + return control; + } + return NULL; +} + +OSStatus ScintillaMacOSX::Construct( HIViewRef inControl, TView** outView ) +{ + *outView = new ScintillaMacOSX( inControl ); + Platform::DebugPrintf("ScintillaMacOSX::Construct scintilla %08X\n",*outView); + if ( *outView != NULL ) + return noErr; + else + return memFullErr; // could be a lie +} + +extern "C" { +HIViewRef scintilla_new() { + return ScintillaMacOSX::Create(); +} +} diff --git a/macosx/ScintillaMacOSX.h b/macosx/ScintillaMacOSX.h new file mode 100644 index 000000000..0f02042f5 --- /dev/null +++ b/macosx/ScintillaMacOSX.h @@ -0,0 +1,192 @@ +/* + * ScintillaMacOSX.h + * tutorial + * + * Created by Evan Jones on Sun Sep 01 2002. + * Copyright (c) 2002 __MyCompanyName__. All rights reserved. + * + */ +#include "TView.h" + +#include <stdlib.h> +#include <string.h> +#include <stdio.h> +#include <ctype.h> +#include <time.h> + +#include "Platform.h" +#include "Scintilla.h" +#include "PlatMacOSX.h" + + +#include "ScintillaWidget.h" +#ifdef SCI_LEXER +#include "SciLexer.h" +#include "PropSet.h" +#include "Accessor.h" +#include "KeyWords.h" +#endif +#include "ContractionState.h" +#include "SVector.h" +#include "SplitVector.h" +#include "Partitioning.h" +#include "RunStyles.h" +#include "CellBuffer.h" +#include "CallTip.h" +#include "KeyMap.h" +#include "Indicator.h" +#include "XPM.h" +#include "LineMarker.h" +#include "Style.h" +#include "AutoComplete.h" +#include "ViewStyle.h" +#include "CharClassify.h" +#include "Decoration.h" +#include "Document.h" +#include "Editor.h" +#include "SString.h" +#include "ScintillaBase.h" +#include "ScintillaCallTip.h" + +static const OSType scintillaMacOSType = 'Scin'; +static const OSType scintillaNotifyObject = 'Snob'; +static const OSType scintillaNotifyFN = 'Snfn'; + +namespace Scintilla { + +class ScintillaMacOSX : public ScintillaBase, public TView +{ + public: + HIViewRef vScrollBar; + HIViewRef hScrollBar; + SInt32 scrollBarFixedSize; + + bool capturedMouse; + bool inDragSession; // true if scintilla initiated the drag session + bool isTracking; + + // Private so ScintillaMacOSX objects can not be copied + ScintillaMacOSX(const ScintillaMacOSX &) : ScintillaBase(), TView( NULL ) {} + ScintillaMacOSX &operator=(const ScintillaMacOSX &) { return * this; } + +public: + /** This is the class ID that we've assigned to Scintilla. */ + static const CFStringRef kScintillaClassID; + static const ControlKind kScintillaKind; + + ScintillaMacOSX( void* windowid ); + virtual ~ScintillaMacOSX(); + //~ static void ClassInit(GtkObjectClass* object_class, GtkWidgetClass *widget_class); + + /** Returns the HIView object kind, needed to subclass TView. */ + virtual ControlKind GetKind() { return kScintillaKind; } + +private: + virtual void Initialise(); + virtual void Finalise(); + virtual void StartDrag(); + Scintilla::Point GetDragPoint(DragRef inDrag); + OSStatus GetDragData(DragRef inDrag, PasteboardRef &pasteBoard, CFStringRef *textString); + void SetDragCursor(DragRef inDrag); + + // Drag and drop + virtual bool DragEnter(DragRef inDrag ); + virtual bool DragWithin(DragRef inDrag ); + virtual bool DragLeave(DragRef inDrag ); + virtual OSStatus DragReceive(DragRef inDrag ); + void DragScroll(); + int scrollSpeed; + int scrollTicks; + + EventRecord mouseDownEvent; + MouseTrackingRef mouseTrackingRef; + MouseTrackingRegionID mouseTrackingID; + HIPoint GetLocalPoint(::Point pt); + + static pascal void IdleTimerEventHandler(EventLoopTimerRef inTimer, + EventLoopIdleTimerMessage inState, + void *scintilla ); + +public: // Public for scintilla_send_message + virtual sptr_t WndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam); + + void SyncPaint( void* gc, PRectangle rc); + //void FullPaint( void* gc ); + virtual void Draw( RgnHandle rgn, CGContextRef gc ); + + virtual sptr_t DefWndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam); + virtual void SetTicking(bool on); + virtual bool SetIdle(bool on); + virtual void SetMouseCapture(bool on); + virtual bool HaveMouseCapture(); + virtual PRectangle GetClientRectangle(); + + virtual void ScrollText(int linesToMove); + virtual void SetVerticalScrollPos(); + virtual void SetHorizontalScrollPos(); + virtual bool ModifyScrollBars(int nMax, int nPage); + virtual void ReconfigureScrollBars(); + void Resize(int width, int height); + static pascal void LiveScrollHandler( ControlHandle control, SInt16 part ); + bool ScrollBarHit(HIPoint location); + + virtual void NotifyChange(); + virtual void NotifyFocus(bool focus); + virtual void NotifyParent(SCNotification scn); + void NotifyKey(int key, int modifiers); + void NotifyURIDropped(const char *list); + virtual int KeyDefault(int key, int modifiers); + static pascal OSStatus CommandEventHandler( EventHandlerCallRef inCallRef, EventRef inEvent, void* data ); + + bool HasSelection(); + bool CanUndo(); + bool CanRedo(); + bool AlwaysTrue(); + virtual void CopyToClipboard(const SelectionText &selectedText); + virtual void Copy(); + virtual bool CanPaste(); + virtual void Paste(); + virtual void Paste(bool rectangular); + virtual void CreateCallTipWindow(PRectangle rc); + virtual void AddToPopUp(const char *label, int cmd = 0, bool enabled = true); + virtual void ClaimSelection(); + + static sptr_t DirectFunction(ScintillaMacOSX *sciThis, + unsigned int iMessage, uptr_t wParam, sptr_t lParam); + + /** Timer event handler. Simply turns around and calls Tick. */ + virtual void TimerFired( EventLoopTimerRef ); + virtual OSStatus BoundsChanged( UInt32 inOptions, const HIRect& inOriginalBounds, const HIRect& inCurrentBounds, RgnHandle inInvalRgn ); + virtual ControlPartCode HitTest( const HIPoint& where ); + virtual OSStatus SetFocusPart( ControlPartCode desiredFocus, RgnHandle, Boolean, ControlPartCode* outActualFocus ); + virtual OSStatus TextInput( TCarbonEvent& event ); + + // Configure the features of this control + virtual UInt32 GetBehaviors(); + + virtual OSStatus MouseDown( HIPoint& location, UInt32 modifiers, EventMouseButton button, UInt32 clickCount, TCarbonEvent& inEvent ); + virtual OSStatus MouseDown( HIPoint& location, UInt32 modifiers, EventMouseButton button, UInt32 clickCount ); + virtual OSStatus MouseDown( EventRecord *rec ); + virtual OSStatus MouseUp( HIPoint& location, UInt32 modifiers, EventMouseButton button, UInt32 clickCount ); + virtual OSStatus MouseUp( EventRecord *rec ); + virtual OSStatus MouseDragged( HIPoint& location, UInt32 modifiers, EventMouseButton button, UInt32 clickCount ); + virtual OSStatus MouseDragged( EventRecord *rec ); + virtual OSStatus MouseEntered( HIPoint& location, UInt32 modifiers, EventMouseButton button, UInt32 clickCount ); + virtual OSStatus MouseExited( HIPoint& location, UInt32 modifiers, EventMouseButton button, UInt32 clickCount ); + virtual OSStatus MouseWheelMoved( EventMouseWheelAxis axis, SInt32 delta, UInt32 modifiers ); + virtual OSStatus ContextualMenuClick( HIPoint& location ); + + virtual OSStatus ActiveStateChanged(); + + virtual void CallTipClick(); + + +public: + static HIViewRef Create(); +private: + static OSStatus Construct( HIViewRef inControl, TView** outView ); + +}; + + +} diff --git a/macosx/TCarbonEvent.cxx b/macosx/TCarbonEvent.cxx new file mode 100644 index 000000000..eca31e569 --- /dev/null +++ b/macosx/TCarbonEvent.cxx @@ -0,0 +1,519 @@ +/* + File: TCarbonEvent.cp + + Version: 1.0 + + Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Computer, Inc. + ("Apple") in consideration of your agreement to the following terms, and your + use, installation, modification or redistribution of this Apple software + constitutes acceptance of these terms. If you do not agree with these terms, + please do not use, install, modify or redistribute this Apple software. + + In consideration of your agreement to abide by the following terms, and subject + to these terms, Apple grants you a personal, non-exclusive license, under AppleÕs + copyrights in this original Apple software (the "Apple Software"), to use, + reproduce, modify and redistribute the Apple Software, with or without + modifications, in source and/or binary forms; provided that if you redistribute + the Apple Software in its entirety and without modifications, you must retain + this notice and the following text and disclaimers in all such redistributions of + the Apple Software. Neither the name, trademarks, service marks or logos of + Apple Computer, Inc. may be used to endorse or promote products derived from the + Apple Software without specific prior written permission from Apple. Except as + expressly stated in this notice, no other rights or licenses, express or implied, + are granted by Apple herein, including but not limited to any patent rights that + may be infringed by your derivative works or by other works in which the Apple + Software may be incorporated. + + The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO + WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED + WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR + PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN + COMBINATION WITH YOUR PRODUCTS. + + IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION + OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT + (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN + ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + Copyright © 2002 Apple Computer, Inc., All Rights Reserved +*/ + +#include "TCarbonEvent.h" + +//----------------------------------------------------------------------------------- +// TCarbonEvent constructor +//----------------------------------------------------------------------------------- +// +TCarbonEvent::TCarbonEvent( + UInt32 inClass, + UInt32 inKind ) +{ + CreateEvent( NULL, inClass, inKind, GetCurrentEventTime(), 0, &fEvent ); +} + +//----------------------------------------------------------------------------------- +// TCarbonEvent constructor +//----------------------------------------------------------------------------------- +// +TCarbonEvent::TCarbonEvent( + EventRef inEvent ) +{ + fEvent = inEvent; + RetainEvent( fEvent ); +} + +//----------------------------------------------------------------------------------- +// TCarbonEvent destructor +//----------------------------------------------------------------------------------- +// +TCarbonEvent::~TCarbonEvent() +{ + ReleaseEvent( fEvent ); +} + +//----------------------------------------------------------------------------------- +// GetClass +//----------------------------------------------------------------------------------- +// +UInt32 TCarbonEvent::GetClass() const +{ + return GetEventClass( fEvent ); +} + +//----------------------------------------------------------------------------------- +// GetKind +//----------------------------------------------------------------------------------- +// +UInt32 TCarbonEvent::GetKind() const +{ + return GetEventKind( fEvent ); +} + +//----------------------------------------------------------------------------------- +// SetTime +//----------------------------------------------------------------------------------- +// +void TCarbonEvent::SetTime( + EventTime inTime ) +{ + SetEventTime( fEvent, inTime ); +} + +//----------------------------------------------------------------------------------- +// GetTime +//----------------------------------------------------------------------------------- +// +EventTime TCarbonEvent::GetTime() const +{ + return GetEventTime( fEvent ); +} + +//----------------------------------------------------------------------------------- +// Retain +//----------------------------------------------------------------------------------- +// +void TCarbonEvent::Retain() +{ + RetainEvent( fEvent ); +} + +//----------------------------------------------------------------------------------- +// Release +//----------------------------------------------------------------------------------- +// +void TCarbonEvent::Release() +{ + ReleaseEvent( fEvent ); +} + +//----------------------------------------------------------------------------------- +// PostToQueue +//----------------------------------------------------------------------------------- +// +OSStatus TCarbonEvent::PostToQueue( + EventQueueRef inQueue, + EventPriority inPriority ) +{ + return PostEventToQueue( inQueue, fEvent, inPriority ); +} + +//----------------------------------------------------------------------------------- +// SetParameter +//----------------------------------------------------------------------------------- +// +OSStatus TCarbonEvent::SetParameter( + EventParamName inName, + EventParamType inType, + UInt32 inSize, + const void* inData ) +{ + return SetEventParameter( fEvent, inName, inType, inSize, inData ); +} + +//----------------------------------------------------------------------------------- +// GetParameter +//----------------------------------------------------------------------------------- +// +OSStatus TCarbonEvent::GetParameter( + EventParamName inName, + EventParamType inType, + UInt32 inBufferSize, + void* outData ) +{ + return GetEventParameter( fEvent, inName, inType, NULL, inBufferSize, NULL, outData ); +} + +//----------------------------------------------------------------------------------- +// GetParameterType +//----------------------------------------------------------------------------------- +// +OSStatus TCarbonEvent::GetParameterType( + EventParamName inName, + EventParamType* outType ) +{ + return GetEventParameter( fEvent, inName, typeWildCard, outType, 0, NULL, NULL ); +} + +//----------------------------------------------------------------------------------- +// GetParameterSize +//----------------------------------------------------------------------------------- +// +OSStatus TCarbonEvent::GetParameterSize( + EventParamName inName, + UInt32* outSize ) +{ + return GetEventParameter( fEvent, inName, typeWildCard, NULL, 0, outSize, NULL ); +} + +//----------------------------------------------------------------------------------- +// SetParameter +//----------------------------------------------------------------------------------- +// +OSStatus TCarbonEvent::SetParameter( + EventParamName inName, + Boolean inValue ) +{ + return SetParameter<Boolean>( inName, typeBoolean, inValue ); +} + +//----------------------------------------------------------------------------------- +// GetParameter +//----------------------------------------------------------------------------------- +// +OSStatus TCarbonEvent::GetParameter( + EventParamName inName, + Boolean* outValue ) +{ + return GetParameter<Boolean>( inName, typeBoolean, outValue ); +} + +//----------------------------------------------------------------------------------- +// SetParameter +//----------------------------------------------------------------------------------- +// +OSStatus TCarbonEvent::SetParameter( + EventParamName inName, + bool inValue ) +{ + return SetParameter<Boolean>( inName, typeBoolean, (Boolean) inValue ); +} + +//----------------------------------------------------------------------------------- +// GetParameter +//----------------------------------------------------------------------------------- +// +OSStatus TCarbonEvent::GetParameter( + EventParamName inName, + bool* outValue ) +{ + return GetParameter<Boolean>( inName, sizeof( Boolean ), (Boolean*) outValue ); +} + +//----------------------------------------------------------------------------------- +// SetParameter +//----------------------------------------------------------------------------------- +// +OSStatus TCarbonEvent::SetParameter( + EventParamName inName, + Point inPt ) +{ + return SetParameter<Point>( inName, typeQDPoint, inPt ); +} + +//----------------------------------------------------------------------------------- +// GetParameter +//----------------------------------------------------------------------------------- +// +OSStatus TCarbonEvent::GetParameter( + EventParamName inName, + Point* outPt ) +{ + return GetParameter<Point>( inName, typeQDPoint, outPt ); +} + +//----------------------------------------------------------------------------------- +// SetParameter +//----------------------------------------------------------------------------------- +// +OSStatus TCarbonEvent::SetParameter( + EventParamName inName, + const HIPoint& inPt ) +{ + return SetParameter<HIPoint>( inName, typeHIPoint, inPt ); +} + +//----------------------------------------------------------------------------------- +// GetParameter +//----------------------------------------------------------------------------------- +// +OSStatus TCarbonEvent::GetParameter( + EventParamName inName, + HIPoint* outPt ) +{ + return GetParameter<HIPoint>( inName, typeHIPoint, outPt ); +} + +//----------------------------------------------------------------------------------- +// SetParameter +//----------------------------------------------------------------------------------- +// +OSStatus TCarbonEvent::SetParameter( + EventParamName inName, + const Rect& inRect ) +{ + return SetParameter<Rect>( inName, typeQDRectangle, inRect ); +} + +//----------------------------------------------------------------------------------- +// GetParameter +//----------------------------------------------------------------------------------- +// +OSStatus TCarbonEvent::GetParameter( + EventParamName inName, + Rect* outRect ) +{ + return GetParameter<Rect>( inName, typeQDRectangle, outRect ); +} + +//----------------------------------------------------------------------------------- +// SetParameter +//----------------------------------------------------------------------------------- +// +OSStatus TCarbonEvent::SetParameter( + EventParamName inName, + const HIRect& inRect ) +{ + return SetParameter<HIRect>( inName, typeHIRect, inRect ); +} + +//----------------------------------------------------------------------------------- +// GetParameter +//----------------------------------------------------------------------------------- +// +OSStatus TCarbonEvent::GetParameter( + EventParamName inName, + HIRect* outRect ) +{ + return GetParameter<HIRect>( inName, typeHIRect, outRect ); +} + +//----------------------------------------------------------------------------------- +// SetParameter +//----------------------------------------------------------------------------------- +// +OSStatus TCarbonEvent::SetParameter( + EventParamName inName, + const HISize& inSize ) +{ + return SetParameter<HISize>( inName, typeHISize, inSize ); +} + +//----------------------------------------------------------------------------------- +// GetParameter +//----------------------------------------------------------------------------------- +// +OSStatus TCarbonEvent::GetParameter( + EventParamName inName, + HISize* outSize ) +{ + return GetParameter<HISize>( inName, typeHISize, outSize ); +} + +//----------------------------------------------------------------------------------- +// SetParameter +//----------------------------------------------------------------------------------- +// +OSStatus TCarbonEvent::SetParameter( + EventParamName inName, + RgnHandle inRegion ) +{ + return SetParameter<RgnHandle>( inName, typeQDRgnHandle, inRegion ); +} + +//----------------------------------------------------------------------------------- +// GetParameter +//----------------------------------------------------------------------------------- +// +OSStatus TCarbonEvent::GetParameter( + EventParamName inName, + RgnHandle* outRegion ) +{ + return GetParameter<RgnHandle>( inName, typeQDRgnHandle, outRegion ); +} + +//----------------------------------------------------------------------------------- +// SetParameter +//----------------------------------------------------------------------------------- +// +OSStatus TCarbonEvent::SetParameter( + EventParamName inName, + WindowRef inWindow ) +{ + return SetParameter<WindowRef>( inName, typeWindowRef, inWindow ); +} + +//----------------------------------------------------------------------------------- +// GetParameter +//----------------------------------------------------------------------------------- +// +OSStatus TCarbonEvent::GetParameter( + EventParamName inName, + WindowRef* outWindow ) +{ + return GetParameter<WindowRef>( inName, typeWindowRef, outWindow ); +} + +//----------------------------------------------------------------------------------- +// SetParameter +//----------------------------------------------------------------------------------- +// +OSStatus TCarbonEvent::SetParameter( + EventParamName inName, + ControlRef inControl ) +{ + return SetParameter<ControlRef>( inName, typeControlRef, inControl ); +} + +//----------------------------------------------------------------------------------- +// GetParameter +//----------------------------------------------------------------------------------- +// +OSStatus TCarbonEvent::GetParameter( + EventParamName inName, + ControlRef* outControl ) +{ + return GetParameter<ControlRef>( inName, typeControlRef, outControl ); +} + +//----------------------------------------------------------------------------------- +// SetParameter +//----------------------------------------------------------------------------------- +// +OSStatus TCarbonEvent::SetParameter( + EventParamName inName, + MenuRef inMenu ) +{ + return SetParameter<MenuRef>( inName, typeMenuRef, inMenu ); +} + +//----------------------------------------------------------------------------------- +// GetParameter +//----------------------------------------------------------------------------------- +// +OSStatus TCarbonEvent::GetParameter( + EventParamName inName, + MenuRef* outMenu ) +{ + return GetParameter<MenuRef>( inName, typeMenuRef, outMenu ); +} + +//----------------------------------------------------------------------------------- +// SetParameter +//----------------------------------------------------------------------------------- +// +OSStatus TCarbonEvent::SetParameter( + EventParamName inName, + DragRef inDrag ) +{ + return SetParameter<DragRef>( inName, typeDragRef, inDrag ); +} + +//----------------------------------------------------------------------------------- +// GetParameter +//----------------------------------------------------------------------------------- +// +OSStatus TCarbonEvent::GetParameter( + EventParamName inName, + DragRef* outDrag ) +{ + return GetParameter<DragRef>( inName, typeDragRef, outDrag ); +} + +//----------------------------------------------------------------------------------- +// SetParameter +//----------------------------------------------------------------------------------- +// +OSStatus TCarbonEvent::SetParameter( + EventParamName inName, + UInt32 inValue ) +{ + return SetParameter<UInt32>( inName, typeUInt32, inValue ); +} + +//----------------------------------------------------------------------------------- +// GetParameter +//----------------------------------------------------------------------------------- +// +OSStatus TCarbonEvent::GetParameter( + EventParamName inName, + UInt32* outValue ) +{ + return GetParameter<UInt32>( inName, typeUInt32, outValue ); +} + +//----------------------------------------------------------------------------------- +// SetParameter +//----------------------------------------------------------------------------------- +// +OSStatus TCarbonEvent::SetParameter( + EventParamName inName, + const HICommand& inValue ) +{ + return SetParameter<HICommand>( inName, typeHICommand, inValue ); +} + +//----------------------------------------------------------------------------------- +// GetParameter +//----------------------------------------------------------------------------------- +// +OSStatus TCarbonEvent::GetParameter( + EventParamName inName, + HICommand* outValue ) +{ + return GetParameter<HICommand>( inName, typeHICommand, outValue ); +} + +//----------------------------------------------------------------------------------- +// SetParameter +//----------------------------------------------------------------------------------- +// +OSStatus TCarbonEvent::SetParameter( + EventParamName inName, + const ControlPartCode& inValue ) +{ + return SetParameter<ControlPartCode>( inName, typeControlPartCode, inValue ); +} + +//----------------------------------------------------------------------------------- +// GetParameter +//----------------------------------------------------------------------------------- +// +OSStatus TCarbonEvent::GetParameter( + EventParamName inName, + ControlPartCode* outValue ) +{ + return GetParameter<ControlPartCode>( inName, typeControlPartCode, outValue ); +} diff --git a/macosx/TCarbonEvent.h b/macosx/TCarbonEvent.h new file mode 100644 index 000000000..d40da9795 --- /dev/null +++ b/macosx/TCarbonEvent.h @@ -0,0 +1,230 @@ +/* + File: TCarbonEvent.h + + Version: 1.0 + + Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Computer, Inc. + ("Apple") in consideration of your agreement to the following terms, and your + use, installation, modification or redistribution of this Apple software + constitutes acceptance of these terms. If you do not agree with these terms, + please do not use, install, modify or redistribute this Apple software. + + In consideration of your agreement to abide by the following terms, and subject + to these terms, Apple grants you a personal, non-exclusive license, under AppleÕs + copyrights in this original Apple software (the "Apple Software"), to use, + reproduce, modify and redistribute the Apple Software, with or without + modifications, in source and/or binary forms; provided that if you redistribute + the Apple Software in its entirety and without modifications, you must retain + this notice and the following text and disclaimers in all such redistributions of + the Apple Software. Neither the name, trademarks, service marks or logos of + Apple Computer, Inc. may be used to endorse or promote products derived from the + Apple Software without specific prior written permission from Apple. Except as + expressly stated in this notice, no other rights or licenses, express or implied, + are granted by Apple herein, including but not limited to any patent rights that + may be infringed by your derivative works or by other works in which the Apple + Software may be incorporated. + + The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO + WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED + WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR + PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN + COMBINATION WITH YOUR PRODUCTS. + + IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION + OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT + (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN + ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + Copyright © 2002 Apple Computer, Inc., All Rights Reserved +*/ + +#ifndef TCarbonEvent_H_ +#define TCarbonEvent_H_ + +#include <Carbon/Carbon.h> + +class TCarbonEvent +{ +public: + // Construction/Destruction + TCarbonEvent( + UInt32 inClass, + UInt32 inKind ); + TCarbonEvent( + EventRef inEvent ); + virtual ~TCarbonEvent(); + + UInt32 GetClass() const; + UInt32 GetKind() const; + + // Time + void SetTime( + EventTime inTime ); + EventTime GetTime() const; + + // Retention + void Retain(); + void Release(); + + // Accessors + operator EventRef&() + { return fEvent; }; + EventRef GetEventRef() + { return fEvent; } + + // Posting + OSStatus PostToQueue( + EventQueueRef inQueue, + EventPriority inPriority = kEventPriorityStandard ); + + // Parameters + OSStatus SetParameter( + EventParamName inName, + EventParamType inType, + UInt32 inSize, + const void* inData ); + OSStatus GetParameter( + EventParamName inName, + EventParamType inType, + UInt32 inBufferSize, + void* outData ); + + OSStatus GetParameterType( + EventParamName inName, + EventParamType* outType ); + OSStatus GetParameterSize( + EventParamName inName, + UInt32* outSize ); + + // Simple parameters + OSStatus SetParameter( + EventParamName inName, + Boolean inValue ); + OSStatus GetParameter( + EventParamName inName, + Boolean* outValue ); + + OSStatus SetParameter( + EventParamName inName, + bool inValue ); + OSStatus GetParameter( + EventParamName inName, + bool* outValue ); + + OSStatus SetParameter( + EventParamName inName, + Point inPt ); + OSStatus GetParameter( + EventParamName inName, + Point* outPt ); + + OSStatus SetParameter( + EventParamName inName, + const HIPoint& inPt ); + + OSStatus GetParameter( + EventParamName inName, + HIPoint* outPt ); + + OSStatus SetParameter( + EventParamName inName, + const Rect& inRect ); + OSStatus GetParameter( + EventParamName inName, + Rect* outRect ); + + OSStatus SetParameter( + EventParamName inName, + const HIRect& inRect ); + OSStatus GetParameter( + EventParamName inName, + HIRect* outRect ); + + OSStatus SetParameter( + EventParamName inName, + const HISize& inSize ); + OSStatus GetParameter( + EventParamName inName, + HISize* outSize ); + + OSStatus SetParameter( + EventParamName inName, + RgnHandle inRegion ); + OSStatus GetParameter( + EventParamName inName, + RgnHandle* outRegion ); + + OSStatus SetParameter( + EventParamName inName, + WindowRef inWindow ); + OSStatus GetParameter( + EventParamName inName, + WindowRef* outWindow ); + + OSStatus SetParameter( + EventParamName inName, + ControlRef inControl ); + OSStatus GetParameter( + EventParamName inName, + ControlRef* outControl ); + + OSStatus SetParameter( + EventParamName inName, + MenuRef inMenu ); + OSStatus GetParameter( + EventParamName inName, + MenuRef* outMenu ); + + OSStatus SetParameter( + EventParamName inName, + DragRef inDrag ); + OSStatus GetParameter( + EventParamName inName, + DragRef* outDrag ); + + OSStatus SetParameter( + EventParamName inName, + UInt32 inValue ); + OSStatus GetParameter( + EventParamName inName, + UInt32* outValue ); + + OSStatus SetParameter( + EventParamName inName, + const HICommand& inValue ); + OSStatus GetParameter( + EventParamName inName, + HICommand* outValue ); + + OSStatus SetParameter( + EventParamName inName, + const ControlPartCode& inValue ); + OSStatus GetParameter( + EventParamName inName, + ControlPartCode* outValue ); + + // Template parameters + template <class T> OSStatus SetParameter( + EventParamName inName, + EventParamType inType, + const T& inValue ) + { + return SetParameter( inName, inType, sizeof( T ), &inValue ); + } + + template <class T> OSStatus GetParameter( + EventParamName inName, + EventParamType inType, + T* outValue ) + { + return GetParameter( inName, inType, sizeof( T ), outValue ); + } + +private: + EventRef fEvent; +}; + +#endif // TCarbonEvent_H_ diff --git a/macosx/TRect.h b/macosx/TRect.h new file mode 100644 index 000000000..5a4199300 --- /dev/null +++ b/macosx/TRect.h @@ -0,0 +1,496 @@ +/* + File: TRect.h + + Version: 1.0 + + Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Computer, Inc. + ("Apple") in consideration of your agreement to the following terms, and your + use, installation, modification or redistribution of this Apple software + constitutes acceptance of these terms. If you do not agree with these terms, + please do not use, install, modify or redistribute this Apple software. + + In consideration of your agreement to abide by the following terms, and subject + to these terms, Apple grants you a personal, non-exclusive license, under AppleÕs + copyrights in this original Apple software (the "Apple Software"), to use, + reproduce, modify and redistribute the Apple Software, with or without + modifications, in source and/or binary forms; provided that if you redistribute + the Apple Software in its entirety and without modifications, you must retain + this notice and the following text and disclaimers in all such redistributions of + the Apple Software. Neither the name, trademarks, service marks or logos of + Apple Computer, Inc. may be used to endorse or promote products derived from the + Apple Software without specific prior written permission from Apple. Except as + expressly stated in this notice, no other rights or licenses, express or implied, + are granted by Apple herein, including but not limited to any patent rights that + may be infringed by your derivative works or by other works in which the Apple + Software may be incorporated. + + The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO + WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED + WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR + PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN + COMBINATION WITH YOUR PRODUCTS. + + IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION + OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT + (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN + ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + Copyright © 2002 Apple Computer, Inc., All Rights Reserved +*/ + +#ifndef TRect_H_ +#define TRect_H_ + +#include <Carbon/Carbon.h> + +class TRect + : public HIRect +{ +public: + // Construction/Destruction + TRect(); + TRect( + const HIRect* inRect ); + TRect( + const HIRect& inRect ); + TRect( + const HIPoint& inOrigin, + const HISize& inSize ); + TRect( + float inX, + float inY, + float inWidth, + float inHeight ); + TRect( + const Rect& inRect ); + ~TRect(); + + // Operators + operator HIRect*() + { return this; } + operator Rect() const; + + // Accessors + float MinX() const + { return CGRectGetMinX( *this ); } + float MaxX() const + { return CGRectGetMaxX( *this ); } + float MinY() const + { return CGRectGetMinY( *this ); } + float MaxY() const + { return CGRectGetMaxY( *this ); } + + float Width() const + { return CGRectGetWidth( *this ); } + float Height() const + { return CGRectGetHeight( *this ); } + + const HIPoint& Origin() const + { return origin; } + const HISize& Size() const + { return size; } + + float CenterX() const + { return CGRectGetMidX( *this ); } + float CenterY() const + { return CGRectGetMidY( *this ); } + HIPoint Center() const; + + // Modifiers + const HIRect& Inset( + float inX, + float inY ); + const HIRect& Outset( + float inX, + float inY ); + const HIRect& MoveBy( + float inDx, + float inDy ); + const HIRect& MoveTo( + float inX, + float inY ); + + const HIRect& Set( + const HIRect* inRect ); + const HIRect& Set( + const HIRect& inRect ); + const HIRect& Set( + float inX, + float inY, + float inWidth, + float inHeight ); + const HIRect& Set( + const Rect* inRect ); + + const HIRect& SetAroundCenter( + float inCenterX, + float inCenterY, + float inWidth, + float inHeight ); + + const HIRect& SetWidth( + float inWidth ); + const HIRect& SetHeight( + float inHeight ); + + const HIRect& SetOrigin( + const HIPoint& inOrigin ); + const HIRect& SetOrigin( + float inX, + float inY ); + const HIRect& SetSize( + const HISize& inSize ); + const HIRect& SetSize( + float inWidth, + float inHeight ); + + // Tests + bool Contains( + const HIPoint& inPoint ); + bool Contains( + const HIRect& inRect ); + bool Contains( + const Point& inPoint ); + bool Contains( + const Rect& inRect ); +}; + +//----------------------------------------------------------------------------------- +// TRect constructor +//----------------------------------------------------------------------------------- +// +inline TRect::TRect() +{ +} + +//----------------------------------------------------------------------------------- +// TRect constructor +//----------------------------------------------------------------------------------- +// +inline TRect::TRect( + const HIRect* inRect ) +{ + *this = *inRect; +} + +//----------------------------------------------------------------------------------- +// TRect constructor +//----------------------------------------------------------------------------------- +// +inline TRect::TRect( + const HIRect& inRect ) +{ + origin = inRect.origin; + size = inRect.size; +} + +//----------------------------------------------------------------------------------- +// TRect constructor +//----------------------------------------------------------------------------------- +// +inline TRect::TRect( + const HIPoint& inOrigin, + const HISize& inSize ) +{ + origin = inOrigin; + size = inSize; +} + +//----------------------------------------------------------------------------------- +// TRect constructor +//----------------------------------------------------------------------------------- +// +inline TRect::TRect( + float inX, + float inY, + float inWidth, + float inHeight ) +{ + *this = CGRectMake( inX, inY, inWidth, inHeight ); +} + +//----------------------------------------------------------------------------------- +// TRect destructor +//----------------------------------------------------------------------------------- +// +inline TRect::~TRect() +{ +} + +//----------------------------------------------------------------------------------- +// TRect constructor +//----------------------------------------------------------------------------------- +// +inline TRect::TRect( + const Rect& inRect ) +{ + Set( &inRect ); +} + +//----------------------------------------------------------------------------------- +// Rect operator +//----------------------------------------------------------------------------------- +// Converts the HIRect to a QD rect and returns it +// +inline TRect::operator Rect() const +{ + Rect qdRect; + + qdRect.top = (SInt16) MinY(); + qdRect.left = (SInt16) MinX(); + qdRect.bottom = (SInt16) MaxY(); + qdRect.right = (SInt16) MaxX(); + + return qdRect; +} + +//----------------------------------------------------------------------------------- +// Center +//----------------------------------------------------------------------------------- +// +inline HIPoint TRect::Center() const +{ + return CGPointMake( CGRectGetMidX( *this ), CGRectGetMidY( *this ) ); +} + +//----------------------------------------------------------------------------------- +// Inset +//----------------------------------------------------------------------------------- +// +inline const HIRect& TRect::Inset( + float inX, + float inY ) +{ + *this = CGRectInset( *this, inX, inY ); + + return *this; +} + +//----------------------------------------------------------------------------------- +// Outset +//----------------------------------------------------------------------------------- +// +inline const HIRect& TRect::Outset( + float inX, + float inY ) +{ + *this = CGRectInset( *this, -inX, -inY ); + + return *this; +} + +//----------------------------------------------------------------------------------- +// MoveBy +//----------------------------------------------------------------------------------- +// +inline const HIRect& TRect::MoveBy( + float inDx, + float inDy ) +{ + origin = CGPointMake( MinX() + inDx, MinY() + inDy ); + + return *this; +} + +//----------------------------------------------------------------------------------- +// MoveTo +//----------------------------------------------------------------------------------- +// +inline const HIRect& TRect::MoveTo( + float inX, + float inY ) +{ + origin = CGPointMake( inX, inY ); + + return *this; +} + +//----------------------------------------------------------------------------------- +// Set +//----------------------------------------------------------------------------------- +// +inline const HIRect& TRect::Set( + const HIRect* inRect ) +{ + *this = *inRect; + + return *this; +} + +//----------------------------------------------------------------------------------- +// Set +//----------------------------------------------------------------------------------- +// +inline const HIRect& TRect::Set( + const HIRect& inRect ) +{ + *this = inRect; + + return *this; +} + +//----------------------------------------------------------------------------------- +// Set +//----------------------------------------------------------------------------------- +// +inline const HIRect& TRect::Set( + float inX, + float inY, + float inWidth, + float inHeight ) +{ + *this = CGRectMake( inX, inY, inWidth, inHeight ); + + return *this; +} + +//----------------------------------------------------------------------------------- +// Set +//----------------------------------------------------------------------------------- +// +inline const HIRect& TRect::Set( + const Rect* inRect ) +{ + origin.x = inRect->left; + origin.y = inRect->top; + size.width = inRect->right - inRect->left; + size.height = inRect->bottom - inRect->top; + + return *this; +} + +//----------------------------------------------------------------------------------- +// SetAroundCenter +//----------------------------------------------------------------------------------- +// Sets the rectangle by specifying dimensions around a center point +// +inline const HIRect& TRect::SetAroundCenter( + float inCenterX, + float inCenterY, + float inWidth, + float inHeight ) +{ + *this = CGRectMake( inCenterX - inWidth/2, inCenterY - inHeight/2, inWidth, inHeight ); + + return *this; +} + +//----------------------------------------------------------------------------------- +// SetWidth +//----------------------------------------------------------------------------------- +// +inline const HIRect& TRect::SetWidth( + float inWidth ) +{ + size.width = inWidth; + + return *this; +} + +//----------------------------------------------------------------------------------- +// SetHeight +//----------------------------------------------------------------------------------- +// +inline const HIRect& TRect::SetHeight( + float inHeight ) +{ + size.height = inHeight; + + return *this; +} + +//----------------------------------------------------------------------------------- +// SetOrigin +//----------------------------------------------------------------------------------- +// +inline const HIRect& TRect::SetOrigin( + const HIPoint& inOrigin ) +{ + origin = inOrigin; + + return *this; +} + +//----------------------------------------------------------------------------------- +// SetOrigin +//----------------------------------------------------------------------------------- +// +inline const HIRect& TRect::SetOrigin( + float inX, + float inY ) +{ + origin = CGPointMake( inX, inY ); + + return *this; +} + +//----------------------------------------------------------------------------------- +// SetSize +//----------------------------------------------------------------------------------- +// +inline const HIRect& TRect::SetSize( + const HISize& inSize ) +{ + size = inSize; + + return *this; +} + +//----------------------------------------------------------------------------------- +// SetSize +//----------------------------------------------------------------------------------- +// +inline const HIRect& TRect::SetSize( + float inWidth, + float inHeight ) +{ + size = CGSizeMake( inWidth, inHeight ); + + return *this; +} + +//----------------------------------------------------------------------------------- +// Contains +//----------------------------------------------------------------------------------- +// +inline bool TRect::Contains( + const HIPoint& inPoint ) +{ + return CGRectContainsPoint( *this, inPoint ); +} + +//----------------------------------------------------------------------------------- +// Contains +//----------------------------------------------------------------------------------- +// +inline bool TRect::Contains( + const HIRect& inRect ) +{ + return CGRectContainsRect( *this, inRect ); +} + +//----------------------------------------------------------------------------------- +// Contains +//----------------------------------------------------------------------------------- +// +inline bool TRect::Contains( + const Point& inPoint ) +{ + return Contains( CGPointMake( inPoint.h, inPoint.v ) ); +} + +//----------------------------------------------------------------------------------- +// Contains +//----------------------------------------------------------------------------------- +// +inline bool TRect::Contains( + const Rect& inRect ) +{ + return Contains( CGRectMake( inRect.left, inRect.top, + inRect.right - inRect.left, inRect.bottom - inRect.top ) ); +} + +#endif // TRect_H_ diff --git a/macosx/TView.cxx b/macosx/TView.cxx new file mode 100644 index 000000000..9ed02b110 --- /dev/null +++ b/macosx/TView.cxx @@ -0,0 +1,1462 @@ +/* + File: TView.cp + + Version: 1.0 + + Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Computer, Inc. + ("Apple") in consideration of your agreement to the following terms, and your + use, installation, modification or redistribution of this Apple software + constitutes acceptance of these terms. If you do not agree with these terms, + please do not use, install, modify or redistribute this Apple software. + + In consideration of your agreement to abide by the following terms, and subject + to these terms, Apple grants you a personal, non-exclusive license, under AppleÕs + copyrights in this original Apple software (the "Apple Software"), to use, + reproduce, modify and redistribute the Apple Software, with or without + modifications, in source and/or binary forms; provided that if you redistribute + the Apple Software in its entirety and without modifications, you must retain + this notice and the following text and disclaimers in all such redistributions of + the Apple Software. Neither the name, trademarks, service marks or logos of + Apple Computer, Inc. may be used to endorse or promote products derived from the + Apple Software without specific prior written permission from Apple. Except as + expressly stated in this notice, no other rights or licenses, express or implied, + are granted by Apple herein, including but not limited to any patent rights that + may be infringed by your derivative works or by other works in which the Apple + Software may be incorporated. + + The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO + WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED + WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR + PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN + COMBINATION WITH YOUR PRODUCTS. + + IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION + OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT + (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN + ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + Copyright © 2002 Apple Computer, Inc., All Rights Reserved +*/ + +/* + NOTE: This is NOWHERE near a completely exhaustive implementation of a view. There are + many more carbon events one could intercept and hook into this. +*/ + +#include "TView.h" + +//----------------------------------------------------------------------------------- +// constants +//----------------------------------------------------------------------------------- +// +const EventTypeSpec kHIObjectEvents[] = +{ { kEventClassHIObject, kEventHIObjectConstruct }, + { kEventClassHIObject, kEventHIObjectInitialize }, + { kEventClassHIObject, kEventHIObjectDestruct } +}; + +const EventTypeSpec kHIViewEvents[] = +{ { kEventClassCommand, kEventCommandProcess }, + { kEventClassCommand, kEventCommandUpdateStatus }, + + { kEventClassControl, kEventControlInitialize }, + { kEventClassControl, kEventControlDraw }, + { kEventClassControl, kEventControlHitTest }, + { kEventClassControl, kEventControlGetPartRegion }, + { kEventClassControl, kEventControlGetData }, + { kEventClassControl, kEventControlSetData }, + { kEventClassControl, kEventControlGetOptimalBounds }, + { kEventClassControl, kEventControlBoundsChanged }, + { kEventClassControl, kEventControlTrack }, + { kEventClassControl, kEventControlGetSizeConstraints }, + { kEventClassControl, kEventControlHit }, + + { kEventClassControl, kEventControlHiliteChanged }, + { kEventClassControl, kEventControlActivate }, + { kEventClassControl, kEventControlDeactivate }, + { kEventClassControl, kEventControlValueFieldChanged }, + { kEventClassControl, kEventControlTitleChanged }, + { kEventClassControl, kEventControlEnabledStateChanged }, +}; + +// This param name was accidentally left unexported for +// the release of Jaguar. +const EventParamName kEventParamControlLikesDrag = 'cldg'; + +//----------------------------------------------------------------------------------- +// TView constructor +//----------------------------------------------------------------------------------- +// +TView::TView( + HIViewRef inControl ) + : fViewRef( inControl ) +{ + verify_noerr( InstallEventHandler( GetControlEventTarget( fViewRef ), ViewEventHandler, + GetEventTypeCount( kHIViewEvents ), kHIViewEvents, this, &fHandler ) ); + + mouseEventHandler = NULL; + fAutoInvalidateFlags = 0; + debugPrint = false; +} + +//----------------------------------------------------------------------------------- +// TView destructor +//----------------------------------------------------------------------------------- +// +TView::~TView() +{ + // If we have installed our custom mouse events handler on the window, + // go forth and remove it. Note: -1 is used to indicate that no handler has + // been installed yet, but we want to once we get a window. + if ( mouseEventHandler != NULL && mouseEventHandler != reinterpret_cast<void*>( -1 ) ) + { + OSStatus err; + err = RemoveEventHandler( mouseEventHandler ); + assert( err == noErr ); + } + mouseEventHandler = NULL; +} + +//----------------------------------------------------------------------------------- +// Initialize +//----------------------------------------------------------------------------------- +// Called during HIObject construction, this is your subclasses' chance to extract +// any parameters it might have added to the initialization event passed into the +// HIObjectCreate call. +// +OSStatus TView::Initialize( TCarbonEvent& /*inEvent*/ ) +{ + return noErr; +} + +//----------------------------------------------------------------------------------- +// GetBehaviors +//----------------------------------------------------------------------------------- +// Returns our behaviors. Any subclass that overrides this should OR in its behaviors +// into the inherited behaviors. +// +UInt32 TView::GetBehaviors() +{ + return kControlSupportsDataAccess | kControlSupportsGetRegion; +} + +//----------------------------------------------------------------------------------- +// Draw +//----------------------------------------------------------------------------------- +// Draw your view. You should draw based on VIEW coordinates, not frame coordinates. +// +void TView::Draw( + RgnHandle /*inLimitRgn*/, + CGContextRef /*inContext*/ ) +{ +} + +//----------------------------------------------------------------------------------- +// HitTest +//----------------------------------------------------------------------------------- +// Asks your view to return what part of itself (if any) is hit by the point given +// to it. The point is in VIEW coordinates, so you should get the view rect to do +// bounds checking. +// +ControlPartCode TView::HitTest( + const HIPoint& /*inWhere*/ ) +{ + return kControlNoPart; +} + +//----------------------------------------------------------------------------------- +// GetRegion +//----------------------------------------------------------------------------------- +// This is called when someone wants to know certain metrics regarding this view. +// The base class does nothing. Subclasses should handle their own parts, such as +// the content region by overriding this method. The structure region is, by default, +// the view's bounds. If a subclass does not have a region for a given part, it +// should always call the inherited method. +// +OSStatus TView::GetRegion( + ControlPartCode inPart, + RgnHandle outRgn ) +{ +#pragma unused( inPart, outRgn ) + + return eventNotHandledErr; +} + +//----------------------------------------------------------------------------------- +// PrintDebugInfo +//----------------------------------------------------------------------------------- +// This is called when asked to print debugging information. +// +void TView::PrintDebugInfo() +{ +} + +//----------------------------------------------------------------------------------- +// GetData +//----------------------------------------------------------------------------------- +// Gets some data from our view. Subclasses should override to handle their own +// defined data tags. If a tag is not understood by the subclass, it should call the +// inherited method. As a convienience, we map the request for ControlKind into our +// GetKind method. +// +OSStatus TView::GetData( + OSType inTag, + ControlPartCode inPart, + Size inSize, + Size* outSize, + void* inPtr ) +{ +#pragma unused( inPart ) + + OSStatus err = noErr; + + switch( inTag ) + { + case kControlKindTag: + if ( inPtr ) + { + if ( inSize != sizeof( ControlKind ) ) + err = errDataSizeMismatch; + else + ( *(ControlKind *) inPtr ) = GetKind(); + } + *outSize = sizeof( ControlKind ); + break; + + default: + err = eventNotHandledErr; + break; + } + + return err; +} + +//----------------------------------------------------------------------------------- +// SetData +//----------------------------------------------------------------------------------- +// Sets some data on our control. Subclasses should override to handle their own +// defined data tags. If a tag is not understood by the subclass, it should call the +// inherited method. +// +OSStatus TView::SetData( + OSType inTag, + ControlPartCode inPart, + Size inSize, + const void* inPtr ) +{ +#pragma unused( inTag, inPart, inSize, inPtr ) + + return eventNotHandledErr; +} + +//----------------------------------------------------------------------------------- +// GetOptimalSize +//----------------------------------------------------------------------------------- +// Someone wants to know this view's optimal size and text baseline, probably to help +// do some type of layout. The base class does nothing, but subclasses should +// override and do something meaningful here. +// +OSStatus TView::GetOptimalSize( + HISize* outSize, + float* outBaseLine ) +{ +#pragma unused( outSize, outBaseLine ) + + return eventNotHandledErr; +} + +//----------------------------------------------------------------------------------- +// GetSizeConstraints +//----------------------------------------------------------------------------------- +// Someone wants to know this view's minimum and maximum sizes, probably to help +// do some type of layout. The base class does nothing, but subclasses should +// override and do something meaningful here. +// +OSStatus TView::GetSizeConstraints( + HISize* outMin, + HISize* outMax ) +{ +#pragma unused( outMin, outMax ) + + return eventNotHandledErr; +} + +//----------------------------------------------------------------------------------- +// BoundsChanged +//----------------------------------------------------------------------------------- +// The bounds of our view have changed. Subclasses can override here to make note +// of it and flush caches, etc. The base class does nothing. +// +OSStatus TView::BoundsChanged( + UInt32 inOptions, + const HIRect& inOriginalBounds, + const HIRect& inCurrentBounds, + RgnHandle inInvalRgn ) +{ +#pragma unused( inOptions, inOriginalBounds, inCurrentBounds, inInvalRgn ) + + return eventNotHandledErr; +} + +//----------------------------------------------------------------------------------- +// ControlHit +//----------------------------------------------------------------------------------- +// The was hit. Subclasses can overide to care about what part was hit. +// +OSStatus TView::ControlHit( + ControlPartCode inPart, + UInt32 inModifiers ) +{ +#pragma unused( inPart, inModifiers ) + + return eventNotHandledErr; +} + +//----------------------------------------------------------------------------------- +// HiliteChanged +//----------------------------------------------------------------------------------- +// The hilite of our view has changed. Subclasses can override here to make note +// of it and flush caches, etc. The base class does nothing. +// +OSStatus TView::HiliteChanged( + ControlPartCode inOriginalPart, + ControlPartCode inCurrentPart, + RgnHandle inInvalRgn ) +{ +#pragma unused( inOriginalPart, inCurrentPart, inInvalRgn ) + + return eventNotHandledErr; +} + +//----------------------------------------------------------------------------------- +// DragEnter +//----------------------------------------------------------------------------------- +// A drag has entered our bounds. The Drag and Drop interface also should have been +// activated or else this method will NOT be called. If true is returned, this view +// likes the drag and will receive drag within/leave/receive messages as appropriate. +// If false is returned, it is assumed the drag is not valid for this view, and no +// further drag activity will flow into this view unless the drag leaves and is +// re-entered. +// +bool TView::DragEnter( + DragRef inDrag ) +{ +#pragma unused( inDrag ) + + return false; +} + +//----------------------------------------------------------------------------------- +// DragWithin +//----------------------------------------------------------------------------------- +// A drag has moved within our bounds. In order for this method to be called, the +// view must have signaled the drag as being desirable in the DragEnter method. The +// Drag and Drop interface also should have been activated. +// +bool TView::DragWithin( + DragRef inDrag ) +{ +#pragma unused( inDrag ) + + return false; +} + +//----------------------------------------------------------------------------------- +// DragLeave +//----------------------------------------------------------------------------------- +// A drag has left. Deal with it. Subclasses should override as necessary. The +// Drag and Drop interface should be activated in order for this method to be valid. +// The drag must have also been accepted in the DragEnter method, else this method +// will NOT be called. +// +bool TView::DragLeave( + DragRef inDrag ) +{ +#pragma unused( inDrag ) + + return false; +} + +//----------------------------------------------------------------------------------- +// DragReceive +//----------------------------------------------------------------------------------- +// Deal with receiving a drag. By default we return dragNotAcceptedErr. I'm not sure +// if this is correct, or eventNotHandledErr. Time will tell... +// +OSStatus TView::DragReceive( + DragRef inDrag ) +{ +#pragma unused( inDrag ) + + return dragNotAcceptedErr; +} + +//----------------------------------------------------------------------------------- +// Track +//----------------------------------------------------------------------------------- +// Default tracking method. Subclasses should override as necessary. We do nothing +// here in the base class, so we return eventNotHandledErr. +// +OSStatus TView::Track( + TCarbonEvent& inEvent, + ControlPartCode* outPart ) +{ +#pragma unused( inEvent, outPart ) + + return eventNotHandledErr; +} + +//----------------------------------------------------------------------------------- +// SetFocusPart +//----------------------------------------------------------------------------------- +// Handle focusing. Our base behavior is to punt. +// +OSStatus TView::SetFocusPart( + ControlPartCode inDesiredFocus, + RgnHandle inInvalidRgn, + Boolean inFocusEverything, + ControlPartCode* outActualFocus ) +{ +#pragma unused( inDesiredFocus, inInvalidRgn, inFocusEverything, outActualFocus ) + + return eventNotHandledErr; +} + +//----------------------------------------------------------------------------------- +// ProcessCommand +//----------------------------------------------------------------------------------- +// Process a command. Subclasses should override as necessary. +// +OSStatus TView::ProcessCommand( + const HICommand& inCommand ) +{ +#pragma unused( inCommand ) + + return eventNotHandledErr; +} + +//----------------------------------------------------------------------------------- +// UpdateCommandStatus +//----------------------------------------------------------------------------------- +// Update the status for a command. Subclasses should override as necessary. +// +OSStatus +TView::UpdateCommandStatus( + const HICommand& inCommand ) +{ +#pragma unused( inCommand ) + + return eventNotHandledErr; +} + +OSStatus TView::MouseDown(HIPoint& /*inMouseLocation*/, UInt32 /*inKeyModifiers*/, EventMouseButton /*inMouseButton*/, UInt32 /*inClickCount*/ , + TCarbonEvent& /*inEvent*/) +{ + return eventNotHandledErr; +} + +OSStatus TView::MouseUp(HIPoint& /*inMouseLocation*/, UInt32 /*inKeyModifiers*/, EventMouseButton /*inMouseButton*/, UInt32 /*inClickCount*/ ) +{ + return eventNotHandledErr; +} + +OSStatus TView::MouseDragged(HIPoint& /*inMouseLocation*/, UInt32 /*inKeyModifiers*/, EventMouseButton /*inMouseButton*/, UInt32 /*inClickCount*/ ) +{ + return eventNotHandledErr; +} + +OSStatus TView::MouseEntered(HIPoint& /*inMouseLocation*/, UInt32 /*inKeyModifiers*/, EventMouseButton /*inMouseButton*/, UInt32 /*inClickCount*/ ) +{ + return eventNotHandledErr; +} + +OSStatus TView::MouseExited(HIPoint& /*inMouseLocation*/, UInt32 /*inKeyModifiers*/, EventMouseButton /*inMouseButton*/, UInt32 /*inClickCount*/ ) +{ + return eventNotHandledErr; +} + +OSStatus TView::MouseWheelMoved( EventMouseWheelAxis /*inAxis*/, SInt32 /*inDelta*/, UInt32 /*inKeyModifiers*/ ) +{ + return eventNotHandledErr; +} + +OSStatus TView::ContextualMenuClick( HIPoint& /*inMouseLocation*/ ) +{ + return eventNotHandledErr; +} + + +//----------------------------------------------------------------------------------- +// ActivateInterface +//----------------------------------------------------------------------------------- +// This routine is used to allow a subclass to turn on a specific event or suite of +// events, like Drag and Drop. This allows us to keep event traffic down if we are +// not interested, but register for the events if we are. +// +OSStatus TView::ActivateInterface( + TView::Interface inInterface ) +{ + OSStatus result = noErr; + + switch( inInterface ) + { + case kDragAndDrop: + { + static const EventTypeSpec kDragEvents[] = + { + { kEventClassControl, kEventControlDragEnter }, + { kEventClassControl, kEventControlDragLeave }, + { kEventClassControl, kEventControlDragWithin }, + { kEventClassControl, kEventControlDragReceive } + }; + + result = AddEventTypesToHandler( fHandler, GetEventTypeCount( kDragEvents ), + kDragEvents ); + + SetControlDragTrackingEnabled( GetViewRef(), true); + } + break; + + case kKeyboardFocus: + { + static const EventTypeSpec kKeyboardFocusEvents[] = + { + { kEventClassControl, kEventControlSetFocusPart }, + { kEventClassTextInput, kEventTextInputUnicodeForKeyEvent }, + }; + + result = AddEventTypesToHandler( fHandler, GetEventTypeCount( kKeyboardFocusEvents ), + kKeyboardFocusEvents ); + } + break; + + case kMouse: + { + if ( mouseEventHandler == NULL ) + { + // This case is quite different: Mouse events are delivered to the window, not the controls. + // mouse wheel events are the exception: They ARE delivered to the control + static const EventTypeSpec kControlMouseEvents[] = + { + { kEventClassMouse, kEventMouseWheelMoved }, + { kEventClassControl, kEventControlContextualMenuClick }, + // So we can reinstall our events when the window changes + { kEventClassControl, kEventControlOwningWindowChanged }, + }; + + result = AddEventTypesToHandler( fHandler, GetEventTypeCount( kControlMouseEvents ), + kControlMouseEvents ); + assert( result == noErr ); + } + + if ( this->GetOwner() != NULL ) + { + // We use "-1" to indicate that we want to install an event handler once we get a window + if ( mouseEventHandler != NULL && mouseEventHandler != reinterpret_cast<void*>( -1 ) ) + { + result = RemoveEventHandler( mouseEventHandler ); + assert( result != NULL ); + } + mouseEventHandler = NULL; + + static const EventTypeSpec kWindowMouseEvents[] = + { + { kEventClassMouse, kEventMouseDown }, + { kEventClassMouse, kEventMouseUp }, + { kEventClassMouse, kEventMouseMoved }, + { kEventClassMouse, kEventMouseDragged }, + }; + + assert( mouseEventHandler == NULL ); + result = InstallEventHandler( GetWindowEventTarget( this->GetOwner() ), WindowEventHandler, + GetEventTypeCount( kWindowMouseEvents ), kWindowMouseEvents, + this, &mouseEventHandler ); + assert( result == noErr && mouseEventHandler != NULL ); + } + // If we have no window yet. Set the mouseEventHandler to -1 so when we get one we + // will install the event handler + else + { + mouseEventHandler = reinterpret_cast<EventHandlerRef>( -1 ); + } + } + break; + case kMouseTracking: + { + { + static const EventTypeSpec kControlMouseEvents[] = + { + { kEventClassMouse, kEventMouseEntered }, // only works if mousetracking is started + { kEventClassMouse, kEventMouseExited }, // only works if mousetracking is started + }; + + result = AddEventTypesToHandler( fHandler, GetEventTypeCount( kControlMouseEvents ), + kControlMouseEvents ); + assert( result == noErr ); + } + } + + //default: + // assert( false ); + } + + return result; +} + +OSStatus TView::InstallTimer( EventTimerInterval inFireDelay, EventLoopTimerRef* outTimer ) +{ + return InstallEventLoopTimer( GetCurrentEventLoop(), inFireDelay, inFireDelay, TimerEventHandler, this, outTimer ); +} + +//----------------------------------------------------------------------------------- +// RegisterSubclass +//----------------------------------------------------------------------------------- +// This routine should be called by subclasses so they can be created as HIObjects. +// +OSStatus TView::RegisterSubclass( + CFStringRef inID, + ConstructProc inProc ) +{ + return HIObjectRegisterSubclass( inID, kHIViewClassID, 0, ObjectEventHandler, + GetEventTypeCount( kHIObjectEvents ), kHIObjectEvents, (void*) inProc, NULL ); +} + +//----------------------------------------------------------------------------------- +// ObjectEventHandler +//----------------------------------------------------------------------------------- +// Our static event handler proc. We handle any HIObject based events directly in +// here at present. +// +pascal OSStatus TView::ObjectEventHandler( + EventHandlerCallRef inCallRef, + EventRef inEvent, + void* inUserData ) +{ + OSStatus result = eventNotHandledErr; + TView* view = (TView*) inUserData; + TCarbonEvent event( inEvent ); + + switch ( event.GetClass() ) + { + case kEventClassHIObject: + switch ( event.GetKind() ) + { + case kEventHIObjectConstruct: + { + ControlRef control; // ControlRefs are HIObjectRefs + TView* view; + + result = event.GetParameter<HIObjectRef>( kEventParamHIObjectInstance, + typeHIObjectRef, (HIObjectRef*)&control ); + require_noerr( result, ParameterMissing ); + + // on entry for our construct event, we're passed the + // creation proc we registered with for this class. + // we use it now to create the instance, and then we + // replace the instance parameter data with said instance + // as type void. + + result = (*(ConstructProc)inUserData)( control, &view ); + if ( result == noErr ) + event.SetParameter<TViewPtr>( kEventParamHIObjectInstance, + typeVoidPtr, view ); + } + break; + + case kEventHIObjectInitialize: + result = CallNextEventHandler( inCallRef, inEvent ); + if ( result == noErr ) + result = view->Initialize( event ); + break; + + case kEventHIObjectDestruct: + delete view; + break; + } + break; + } + +ParameterMissing: + + return result; +} + +//----------------------------------------------------------------------------------- +// ViewEventHandler +//----------------------------------------------------------------------------------- +// Our static event handler proc. We handle all non-HIObject events here. +// +pascal OSStatus TView::ViewEventHandler( + EventHandlerCallRef inCallRef, + EventRef inEvent, + void* inUserData ) +{ + OSStatus result; + TView* view = (TView*) inUserData; + TCarbonEvent event( inEvent ); + if (view->debugPrint) + fprintf(stderr,"TView::ViewEventHandler\n"); + result = view->HandleEvent( inCallRef, event ); + + return result; +} + + +pascal OSStatus TView::WindowEventHandler( + EventHandlerCallRef inCallRef, + EventRef inEvent, + void* inUserData ) +{ + TView* view = reinterpret_cast<TView*>( inUserData ); + TCarbonEvent event( inEvent ); + + const WindowRef window = view->GetOwner(); + assert( window != NULL ); + + // If the window is not active, let the standard window handler execute. + if ( ! IsWindowActive( window ) ) return eventNotHandledErr; + if (view->debugPrint) + fprintf(stderr,"TView::WindowEventHandler\n"); + + const HIViewRef rootView = HIViewGetRoot( window ); + assert( rootView != NULL ); + + // TODO: On OS X 10.3, test if this bug still exists + // This is a hack to work around a bug in the OS. See: + // http://lists.apple.com/archives/carbon-development/2002/Sep/29/keventmousemovedeventsno.004.txt + OSStatus err; + if ( event.GetKind() == kEventMouseMoved ) + { + // We need to set some parameters correctly + event.SetParameter( kEventParamWindowRef, window ); + + HIPoint ptMouse; + event.GetParameter( kEventParamMouseLocation, &ptMouse ); + + // convert screen coords to window relative + Rect bounds; + err = GetWindowBounds( window, kWindowStructureRgn, &bounds ); + assert( err == noErr ); + + ptMouse.x -= bounds.left; + ptMouse.y -= bounds.top; + + event.SetParameter( kEventParamWindowMouseLocation, ptMouse ); + } + + HIViewRef targetView = NULL; + err = HIViewGetViewForMouseEvent( rootView, inEvent, &targetView ); + assert( err == noErr && targetView != NULL ); + if (view->debugPrint) + fprintf(stderr,"TView::WindowEventHandler root[%08X] viewRef[%08X] targetView[%08X]\n", rootView, view->GetViewRef(), targetView); + if ( targetView == view->GetViewRef() || event.GetKind() == kEventMouseDragged ) + { + return view->HandleEvent( inCallRef, event ); + } + + return eventNotHandledErr; +} + +pascal void TView::TimerEventHandler( EventLoopTimerRef inTimer, void* view ) +{ + reinterpret_cast<TView*>( view )->TimerFired( inTimer ); +} + +//----------------------------------------------------------------------------------- +// HandleEvent +//----------------------------------------------------------------------------------- +// Our object's virtual event handler method. I'm not sure if we need this these days. +// We used to do various things with it, but those days are long gone... +// +OSStatus TView::HandleEvent( + EventHandlerCallRef inCallRef, + TCarbonEvent& inEvent ) +{ +#pragma unused( inCallRef ) + + OSStatus result = eventNotHandledErr; + HIPoint where; + OSType tag; + void * ptr; + Size size, outSize; + UInt32 features; + RgnHandle region = NULL; + ControlPartCode part; + RgnHandle invalRgn; + + switch ( inEvent.GetClass() ) + { + case kEventClassCommand: + { + HICommand command; + + result = inEvent.GetParameter( kEventParamDirectObject, &command ); + require_noerr( result, MissingParameter ); + + switch ( inEvent.GetKind() ) + { + case kEventCommandProcess: + result = ProcessCommand( command ); + break; + + case kEventCommandUpdateStatus: + result = UpdateCommandStatus( command ); + break; + } + } + break; + + case kEventClassControl: + switch ( inEvent.GetKind() ) + { + case kEventControlInitialize: + features = GetBehaviors(); + inEvent.SetParameter( kEventParamControlFeatures, features ); + result = noErr; + break; + + case kEventControlDraw: + { + CGContextRef context = NULL; + + inEvent.GetParameter( kEventParamRgnHandle, ®ion ); + inEvent.GetParameter<CGContextRef>( kEventParamCGContextRef, typeCGContextRef, &context ); + + Draw( region, context ); + result = noErr; + } + break; + + case kEventControlHitTest: + inEvent.GetParameter<HIPoint>( kEventParamMouseLocation, typeHIPoint, &where ); + part = HitTest( where ); + inEvent.SetParameter<ControlPartCode>( kEventParamControlPart, typeControlPartCode, part ); + result = noErr; + break; + + case kEventControlGetPartRegion: + inEvent.GetParameter<ControlPartCode>( kEventParamControlPart, typeControlPartCode, &part ); + inEvent.GetParameter( kEventParamControlRegion, ®ion ); + result = GetRegion( part, region ); + break; + + case kEventControlGetData: + inEvent.GetParameter<ControlPartCode>( kEventParamControlPart, typeControlPartCode, &part ); + inEvent.GetParameter<OSType>( kEventParamControlDataTag, typeEnumeration, &tag ); + inEvent.GetParameter<Ptr>( kEventParamControlDataBuffer, typePtr, (Ptr*)&ptr ); + inEvent.GetParameter<Size>( kEventParamControlDataBufferSize, typeLongInteger, &size ); + + result = GetData( tag, part, size, &outSize, ptr ); + + if ( result == noErr ) + verify_noerr( inEvent.SetParameter<Size>( kEventParamControlDataBufferSize, typeLongInteger, outSize ) ); + break; + + case kEventControlSetData: + inEvent.GetParameter<ControlPartCode>( kEventParamControlPart, typeControlPartCode, &part ); + inEvent.GetParameter<OSType>( kEventParamControlDataTag, typeEnumeration, &tag ); + inEvent.GetParameter<Ptr>( kEventParamControlDataBuffer, typePtr, (Ptr*)&ptr ); + inEvent.GetParameter<Size>( kEventParamControlDataBufferSize, typeLongInteger, &size ); + + result = SetData( tag, part, size, ptr ); + break; + + case kEventControlGetOptimalBounds: + { + HISize size; + float floatBaseLine; + + result = GetOptimalSize( &size, &floatBaseLine ); + if ( result == noErr ) + { + Rect bounds; + SInt16 baseLine; + + GetControlBounds( GetViewRef(), &bounds ); + + bounds.bottom = bounds.top + (SInt16)size.height; + bounds.right = bounds.left + (SInt16)size.width; + baseLine = (SInt16)floatBaseLine; + + inEvent.SetParameter( kEventParamControlOptimalBounds, bounds ); + inEvent.SetParameter<SInt16>( kEventParamControlOptimalBaselineOffset, typeShortInteger, baseLine ); + } + } + break; + + case kEventControlBoundsChanged: + { + HIRect prevRect, currRect; + UInt32 attrs; + + inEvent.GetParameter( kEventParamAttributes, &attrs ); + inEvent.GetParameter( kEventParamOriginalBounds, &prevRect ); + inEvent.GetParameter( kEventParamCurrentBounds, &currRect ); + inEvent.GetParameter( kEventParamControlInvalRgn, &invalRgn ); + + result = BoundsChanged( attrs, prevRect, currRect, invalRgn ); + + if ( mouseEventHandler != NULL ) + { + ActivateInterface( kMouse ); + } + + } + break; + + case kEventControlHit: + { + UInt32 modifiers; + + inEvent.GetParameter<ControlPartCode>( kEventParamControlPart, typeControlPartCode, &part ); + inEvent.GetParameter( kEventParamKeyModifiers, &modifiers ); + + result = ControlHit( part, modifiers ); + } + break; + + case kEventControlHiliteChanged: + { + ControlPartCode prevPart, currPart; + + inEvent.GetParameter<ControlPartCode>( kEventParamControlPreviousPart, typeControlPartCode, &prevPart ); + inEvent.GetParameter<ControlPartCode>( kEventParamControlCurrentPart, typeControlPartCode, &currPart ); + inEvent.GetParameter( kEventParamControlInvalRgn, &invalRgn ); + + result = HiliteChanged( prevPart, currPart, invalRgn ); + + if ( GetAutoInvalidateFlags() & kAutoInvalidateOnHilite ) + Invalidate(); + } + break; + + case kEventControlActivate: + result = ActiveStateChanged(); + + if ( GetAutoInvalidateFlags() & kAutoInvalidateOnActivate ) + Invalidate(); + break; + + case kEventControlDeactivate: + result = ActiveStateChanged(); + + if ( GetAutoInvalidateFlags() & kAutoInvalidateOnActivate ) + Invalidate(); + break; + + case kEventControlValueFieldChanged: + result = ValueChanged(); + + if ( GetAutoInvalidateFlags() & kAutoInvalidateOnValueChange ) + Invalidate(); + break; + + case kEventControlTitleChanged: + result = TitleChanged(); + + if ( GetAutoInvalidateFlags() & kAutoInvalidateOnTitleChange ) + Invalidate(); + break; + + case kEventControlEnabledStateChanged: + result = EnabledStateChanged(); + + if ( GetAutoInvalidateFlags() & kAutoInvalidateOnEnable ) + Invalidate(); + break; + + case kEventControlDragEnter: + case kEventControlDragLeave: + case kEventControlDragWithin: + { + DragRef drag; + bool likesDrag; + + inEvent.GetParameter( kEventParamDragRef, &drag ); + + switch ( inEvent.GetKind() ) + { + case kEventControlDragEnter: + likesDrag = DragEnter( drag ); + // Why only if likesDrag? What if it doesn't? No parameter? + if ( likesDrag ) + result = inEvent.SetParameter( kEventParamControlLikesDrag, likesDrag ); + break; + + case kEventControlDragLeave: + DragLeave( drag ); + result = noErr; + break; + + case kEventControlDragWithin: + DragWithin( drag ); + result = noErr; + break; + } + } + break; + + case kEventControlDragReceive: + { + DragRef drag; + + inEvent.GetParameter( kEventParamDragRef, &drag ); + + result = DragReceive( drag ); + } + break; + + case kEventControlTrack: + { + ControlPartCode part; + + result = Track( inEvent, &part ); + if ( result == noErr ) + verify_noerr( inEvent.SetParameter<ControlPartCode>( kEventParamControlPart, typeControlPartCode, part ) ); + } + break; + + case kEventControlGetSizeConstraints: + { + HISize minSize, maxSize; + + result = GetSizeConstraints( &minSize, &maxSize ); + + if ( result == noErr ) + { + verify_noerr( inEvent.SetParameter( kEventParamMinimumSize, minSize ) ); + verify_noerr( inEvent.SetParameter( kEventParamMaximumSize, maxSize ) ); + } + } + break; + + case kEventControlSetFocusPart: + { + ControlPartCode desiredFocus; + RgnHandle invalidRgn; + Boolean focusEverything; + ControlPartCode actualFocus; + + result = inEvent.GetParameter<ControlPartCode>( kEventParamControlPart, typeControlPartCode, &desiredFocus ); + require_noerr( result, MissingParameter ); + + inEvent.GetParameter( kEventParamControlInvalRgn, &invalidRgn ); + + focusEverything = false; // a good default in case the parameter doesn't exist + + inEvent.GetParameter( kEventParamControlFocusEverything, &focusEverything ); + + result = SetFocusPart( desiredFocus, invalidRgn, focusEverything, &actualFocus ); + + if ( result == noErr ) + verify_noerr( inEvent.SetParameter<ControlPartCode>( kEventParamControlPart, typeControlPartCode, actualFocus ) ); + } + break; + + case kEventControlOwningWindowChanged: + { + // If our owning window has changed, reactivate the mouse interface + if ( mouseEventHandler != NULL ) + { + ActivateInterface( kMouse ); + } + } + break; + + case kEventControlContextualMenuClick: + { + HIPoint ptMouse; + inEvent.GetParameter( kEventParamMouseLocation, &ptMouse ); + result = ContextualMenuClick( ptMouse ); + } + break; + + // some other kind of Control event + default: + assert( false ); + break; + } + break; + + case kEventClassTextInput: + result = TextInput( inEvent ); + break; + + case kEventClassMouse: + result = inEvent.GetParameter<HIPoint>( kEventParamWindowMouseLocation, typeHIPoint, &where ); + HIViewConvertPoint( &where, NULL, fViewRef ); + assert( result == noErr ); + + UInt32 inKeyModifiers; + result = inEvent.GetParameter( kEventParamKeyModifiers, &inKeyModifiers ); + assert( result == noErr ); + + switch ( inEvent.GetKind() ) + { + case kEventMouseWheelMoved: + { + EventMouseWheelAxis inAxis; + result = inEvent.GetParameter<EventMouseWheelAxis>( kEventParamMouseWheelAxis, typeMouseWheelAxis, &inAxis ); + assert( noErr == result ); + + SInt32 inDelta; + result = inEvent.GetParameter<SInt32>( kEventParamMouseWheelDelta, typeSInt32, &inDelta ); + assert( noErr == result ); + + result = MouseWheelMoved( inAxis, inDelta, inKeyModifiers ); + } + break; + + + // some other kind of Mouse event: This is (in my opinion) an error + // TODO: There is also a MouseMoved event that we do not handle + default: + { + EventMouseButton inMouseButton; + result = inEvent.GetParameter<EventMouseButton>( kEventParamMouseButton, typeMouseButton, &inMouseButton ); + assert( result == noErr ); + + UInt32 inClickCount; + result = inEvent.GetParameter( kEventParamClickCount, &inClickCount ); + assert( result == noErr ); + + switch ( inEvent.GetKind() ) + { + case kEventMouseDown: + result = MouseDown( where, inKeyModifiers, inMouseButton, inClickCount, inEvent ); + break; + case kEventMouseUp: + result = MouseUp( where, inKeyModifiers, inMouseButton, inClickCount ); + break; + case kEventMouseExited: + result = MouseExited( where, inKeyModifiers, inMouseButton, inClickCount ); + break; + case kEventMouseEntered: + result = MouseEntered( where, inKeyModifiers, inMouseButton, inClickCount ); + break; + case kEventMouseMoved: + case kEventMouseDragged: + result = MouseDragged( where, inKeyModifiers, inMouseButton, inClickCount ); + break; + } + } + break; + } + break; + + // some other event class + default: + assert( false ); + break; + } + +MissingParameter: + return result; +} + +//----------------------------------------------------------------------------------- +// CreateInitializationEvent +//----------------------------------------------------------------------------------- +// Create a basic intialization event containing the parent control and bounds. At +// present we set the bounds to empty and the parent to NULL. In theory, after creating +// this event, any subclass could add its own parameter to receive in its +// Initialize method. +// +EventRef TView::CreateInitializationEvent() +{ + OSStatus result = noErr; + EventRef event; + + result = CreateEvent( NULL, kEventClassHIObject, kEventHIObjectInitialize, + GetCurrentEventTime(), 0, &event ); + require_noerr_action( result, CantCreateEvent, event = NULL ); + +CantCreateEvent: + return event; +} + +//----------------------------------------------------------------------------------- +// Frame +//----------------------------------------------------------------------------------- +// +HIRect TView::Frame() +{ + HIRect frame; + + HIViewGetFrame( GetViewRef(), &frame ); + + return frame; +} + +//----------------------------------------------------------------------------------- +// SetFrame +//----------------------------------------------------------------------------------- +// +OSStatus TView::SetFrame( + const HIRect& inFrame ) +{ + OSStatus err; + + err = HIViewSetFrame( GetViewRef(), &inFrame ); + + return err; +} + +//----------------------------------------------------------------------------------- +// Bounds +//----------------------------------------------------------------------------------- +// +HIRect TView::Bounds() +{ + HIRect bounds; + + HIViewGetBounds( GetViewRef(), &bounds ); + + return bounds; +} + +//----------------------------------------------------------------------------------- +// Show +//----------------------------------------------------------------------------------- +// +OSStatus TView::Show() +{ + return HIViewSetVisible( GetViewRef(), true ); +} + +//----------------------------------------------------------------------------------- +// Hide +//----------------------------------------------------------------------------------- +// +OSStatus TView::Hide() +{ + return HIViewSetVisible( GetViewRef(), false ); +} + +//----------------------------------------------------------------------------------- +// GetEventTarget +//----------------------------------------------------------------------------------- +// +EventTargetRef TView::GetEventTarget() +{ + return HIObjectGetEventTarget( (HIObjectRef) GetViewRef() ); +} + +//----------------------------------------------------------------------------------- +// AddSubView +//----------------------------------------------------------------------------------- +// +OSStatus TView::AddSubView( + TView* inSubView ) +{ + return HIViewAddSubview( GetViewRef(), inSubView->GetViewRef() );; +} + +//----------------------------------------------------------------------------------- +// RemoveFromSuperView +//----------------------------------------------------------------------------------- +// +OSStatus TView::RemoveFromSuperView() +{ + return HIViewRemoveFromSuperview( GetViewRef() ); +} + +//----------------------------------------------------------------------------------- +// GetHilite +//----------------------------------------------------------------------------------- +// +ControlPartCode TView::GetHilite() +{ + return GetControlHilite( GetViewRef() ); +} + +//----------------------------------------------------------------------------------- +// GetValue +//----------------------------------------------------------------------------------- +// +SInt32 TView::GetValue() +{ + return GetControl32BitValue( GetViewRef() ); +} + +//----------------------------------------------------------------------------------- +// SetValue +//----------------------------------------------------------------------------------- +// +void TView::SetValue( + SInt32 inValue ) +{ + SetControl32BitValue( GetViewRef(), inValue ); +} + +//----------------------------------------------------------------------------------- +// GetMinimum +//----------------------------------------------------------------------------------- +// +SInt32 TView::GetMinimum() +{ + return GetControlMinimum( GetViewRef() ); +} + +//----------------------------------------------------------------------------------- +// SetMinimum +//----------------------------------------------------------------------------------- +// +void TView::SetMinimum( + SInt32 inMinimum ) +{ + SetControlMinimum( GetViewRef(), inMinimum ); +} + +//----------------------------------------------------------------------------------- +// GetMaximum +//----------------------------------------------------------------------------------- +// +SInt32 TView::GetMaximum() +{ + return GetControlMaximum( GetViewRef() ); +} + +//----------------------------------------------------------------------------------- +// SetMaximum +//----------------------------------------------------------------------------------- +// +void TView::SetMaximum( + SInt32 inMaximum ) +{ + SetControlMaximum( GetViewRef(), inMaximum ); +} + +//----------------------------------------------------------------------------------- +// GetOwner +//----------------------------------------------------------------------------------- +// +WindowRef TView::GetOwner() +{ + return GetControlOwner( GetViewRef() ); +} + +//----------------------------------------------------------------------------------- +// Hilite +//----------------------------------------------------------------------------------- +// +void TView::Hilite( + ControlPartCode inPart) +{ + return HiliteControl( GetViewRef(), inPart ); +} + +//----------------------------------------------------------------------------------- +// Invalidate +//----------------------------------------------------------------------------------- +// +OSStatus TView::Invalidate() +{ + return HIViewSetNeedsDisplay( GetViewRef(), true ); +} + +void TView::TimerFired( EventLoopTimerRef inTimer ) +{ +#pragma unused( inTimer ) +} + + +//----------------------------------------------------------------------------------- +// IsVisible +//----------------------------------------------------------------------------------- +// +Boolean TView::IsVisible() +{ + return IsControlVisible( GetViewRef() ); +} + +//----------------------------------------------------------------------------------- +// IsEnabled +//----------------------------------------------------------------------------------- +// +Boolean TView::IsEnabled() +{ + return IsControlEnabled( GetViewRef() ); +} + +//----------------------------------------------------------------------------------- +// IsActive +//----------------------------------------------------------------------------------- +// +Boolean TView::IsActive() +{ + return IsControlActive( GetViewRef() ); +} + +//----------------------------------------------------------------------------------- +// ActiveStateChanged +//----------------------------------------------------------------------------------- +// Default activation method. Subclasses should override as necessary. We do nothing +// here in the base class, so we return eventNotHandledErr. +// +OSStatus TView::ActiveStateChanged() +{ + return eventNotHandledErr; +} + +//----------------------------------------------------------------------------------- +// ValueChanged +//----------------------------------------------------------------------------------- +// Default value changed method. Subclasses should override as necessary. We do +// nothing here in the base class, so we return eventNotHandledErr. +// +OSStatus TView::ValueChanged() +{ + return eventNotHandledErr; +} + +//----------------------------------------------------------------------------------- +// TitleChanged +//----------------------------------------------------------------------------------- +// Default title changed method. Subclasses should override as necessary. We +// do nothing here in the base class, so we return eventNotHandledErr. +// +OSStatus TView::TitleChanged() +{ + return eventNotHandledErr; +} + +//----------------------------------------------------------------------------------- +// EnabledStateChanged +//----------------------------------------------------------------------------------- +// Default enable method. Subclasses should override as necessary. We +// do nothing here in the base class, so we return eventNotHandledErr. +// +OSStatus TView::EnabledStateChanged() +{ + return eventNotHandledErr; +} + +//----------------------------------------------------------------------------------- +// TextInput +//----------------------------------------------------------------------------------- +// Default text (Unicode) input method. Subclasses should override as necessary. We +// do nothing here in the base class, so we return eventNotHandledErr. +// +OSStatus TView::TextInput( + TCarbonEvent& inEvent ) +{ +#pragma unused( inEvent ) + + return eventNotHandledErr; +} + +//----------------------------------------------------------------------------------- +// ChangeAutoInvalidateFlags +//----------------------------------------------------------------------------------- +// Change behavior for auto-invalidating views on certain actions. +// +void TView::ChangeAutoInvalidateFlags( + OptionBits inSetThese, + OptionBits inClearThese ) +{ + fAutoInvalidateFlags = ( ( fAutoInvalidateFlags | inSetThese ) & ( ~inClearThese ) ); +} diff --git a/macosx/TView.h b/macosx/TView.h new file mode 100644 index 000000000..97c8f7b55 --- /dev/null +++ b/macosx/TView.h @@ -0,0 +1,286 @@ +/* + File: TView.h + + Version: 1.0 + + Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Computer, Inc. + ("Apple") in consideration of your agreement to the following terms, and your + use, installation, modification or redistribution of this Apple software + constitutes acceptance of these terms. If you do not agree with these terms, + please do not use, install, modify or redistribute this Apple software. + + In consideration of your agreement to abide by the following terms, and subject + to these terms, Apple grants you a personal, non-exclusive license, under AppleÕs + copyrights in this original Apple software (the "Apple Software"), to use, + reproduce, modify and redistribute the Apple Software, with or without + modifications, in source and/or binary forms; provided that if you redistribute + the Apple Software in its entirety and without modifications, you must retain + this notice and the following text and disclaimers in all such redistributions of + the Apple Software. Neither the name, trademarks, service marks or logos of + Apple Computer, Inc. may be used to endorse or promote products derived from the + Apple Software without specific prior written permission from Apple. Except as + expressly stated in this notice, no other rights or licenses, express or implied, + are granted by Apple herein, including but not limited to any patent rights that + may be infringed by your derivative works or by other works in which the Apple + Software may be incorporated. + + The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO + WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED + WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR + PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN + COMBINATION WITH YOUR PRODUCTS. + + IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION + OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT + (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN + ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + Copyright © 2002 Apple Computer, Inc., All Rights Reserved +*/ + +#ifndef TView_H_ +#define TView_H_ + +#include <Carbon/Carbon.h> + +#include "TCarbonEvent.h" +#include "TRect.h" + +#define PURE_VIRTUAL 0 + +class TView +{ +public: + // Bounds and Frame + OSStatus SetFrame( + const HIRect& inBounds ); + HIRect Frame(); + HIRect Bounds(); + + // Visibility + OSStatus Show(); + OSStatus Hide(); + + EventTargetRef GetEventTarget(); + + OSStatus AddSubView( + TView* inSubView ); + OSStatus RemoveFromSuperView(); + + // Accessors + HIViewRef GetViewRef() const + { return fViewRef; } + void Hilite( + ControlPartCode inPart ); + ControlPartCode GetHilite(); + WindowRef GetOwner(); + SInt32 GetValue(); + void SetValue( + SInt32 inValue ); + SInt32 GetMinimum(); + void SetMinimum( + SInt32 inMinimum ); + SInt32 GetMaximum(); + void SetMaximum( + SInt32 inMaximum ); + + // State + Boolean IsVisible(); + Boolean IsEnabled(); + Boolean IsActive(); + + OSStatus Invalidate(); // was SetNeedsDisplay() + + // A "fake" event handler + virtual void TimerFired( EventLoopTimerRef inTimer ); + +protected: + // Autoinvalidation + enum { + kAutoInvalidateOnActivate = (1 << 0), + kAutoInvalidateOnHilite = (1 << 1), + kAutoInvalidateOnEnable = (1 << 2), + kAutoInvalidateOnValueChange = (1 << 3), + kAutoInvalidateOnTitleChange = (1 << 4) + }; + void ChangeAutoInvalidateFlags( + OptionBits inSetFlags, + OptionBits inClearFlags ); + OptionBits GetAutoInvalidateFlags() + { return fAutoInvalidateFlags; } + + // Types + typedef OSStatus (*ConstructProc)( + ControlRef inBaseControl, + TView** outView ); + + // Construction/Destruction + TView( HIViewRef inControl ); + virtual ~TView(); + + virtual ControlKind GetKind() = PURE_VIRTUAL; + virtual UInt32 GetBehaviors(); + + // Handlers + virtual OSStatus ActiveStateChanged(); + virtual OSStatus BoundsChanged( + UInt32 inOptions, + const HIRect& inOriginalBounds, + const HIRect& inCurrentBounds, + RgnHandle inInvalRgn ); + virtual OSStatus ControlHit( + ControlPartCode inPart, + UInt32 inModifiers ); + virtual OSStatus EnabledStateChanged(); + virtual void Draw( + RgnHandle inLimitRgn, + CGContextRef inContext ); + virtual OSStatus GetData( + OSType inTag, + ControlPartCode inPart, + Size inSize, + Size* outSize, + void* inPtr ); + virtual OSStatus GetRegion( + ControlPartCode inPart, + RgnHandle outRgn ); + virtual OSStatus HiliteChanged( + ControlPartCode inOriginalPart, + ControlPartCode inCurrentPart, + RgnHandle inInvalRgn ); + virtual ControlPartCode HitTest( + const HIPoint& inWhere ); + virtual OSStatus Initialize( + TCarbonEvent& inEvent ); + virtual OSStatus SetData( + OSType inTag, + ControlPartCode inPart, + Size inSize, + const void* inPtr ); + virtual OSStatus SetFocusPart( + ControlPartCode inDesiredFocus, + RgnHandle inNnvalidRgn, + Boolean inFocusEverything, + ControlPartCode* outActualFocus ); + virtual OSStatus TextInput( + TCarbonEvent& inEvent ); + virtual OSStatus TitleChanged(); + virtual OSStatus Track( + TCarbonEvent& inEvent, + ControlPartCode* outPartHit ); + virtual OSStatus ValueChanged(); + + // Sizing + virtual OSStatus GetSizeConstraints( + HISize* outMin, + HISize* outMax ); + virtual OSStatus GetOptimalSize( + HISize* outSize, + float* outBaseLine ); + + // Accessors + WindowRef GetWindowRef() + { return GetControlOwner( GetViewRef() ); } + + + // Drag and drop + virtual bool DragEnter( + DragRef inDrag ); + virtual bool DragWithin( + DragRef inDrag ); + virtual bool DragLeave( + DragRef inDrag ); + virtual OSStatus DragReceive( + DragRef inDrag ); + + // Command processing + virtual OSStatus ProcessCommand( + const HICommand& inCommand ); + virtual OSStatus UpdateCommandStatus( + const HICommand& inCommand ); + + // Mouse events + virtual OSStatus MouseDown( + HIPoint& inMouseLocation, + UInt32 inKeyModifiers, + EventMouseButton inMouseButton, + UInt32 inClickCount, + TCarbonEvent& inEvent); + virtual OSStatus MouseUp( + HIPoint& inMouseLocation, + UInt32 inKeyModifiers, + EventMouseButton inMouseButton, + UInt32 inClickCount ); + virtual OSStatus MouseDragged( + HIPoint& inMouseLocation, + UInt32 inKeyModifiers, + EventMouseButton inMouseButton, + UInt32 inClickCount ); + virtual OSStatus MouseEntered( + HIPoint& inMouseLocation, + UInt32 inKeyModifiers, + EventMouseButton inMouseButton, + UInt32 inClickCount ); + virtual OSStatus MouseExited( + HIPoint& inMouseLocation, + UInt32 inKeyModifiers, + EventMouseButton inMouseButton, + UInt32 inClickCount ); + virtual OSStatus MouseWheelMoved( EventMouseWheelAxis inAxis, SInt32 inDelta, UInt32 inKeyModifiers ); + virtual OSStatus ContextualMenuClick( HIPoint& inMouseLocation ); + + // Utility + static OSStatus RegisterSubclass( + CFStringRef inID, + ConstructProc inProc ); + static EventRef CreateInitializationEvent(); + enum Interface { + kDragAndDrop = 1, + kKeyboardFocus, + kMouse, + kMouseTracking + }; + virtual OSStatus ActivateInterface( + Interface inInterface ); + + OSStatus InstallTimer( + EventTimerInterval inFireDelay, + EventLoopTimerRef* outTimer ); + + // Debugging + virtual void PrintDebugInfo(); + Boolean debugPrint; +private: + static pascal OSStatus ObjectEventHandler( + EventHandlerCallRef inCallRef, + EventRef inEvent, + void* inUserData ); + static pascal OSStatus ViewEventHandler( + EventHandlerCallRef inCallRef, + EventRef inEvent, + void* inUserData ); + static pascal OSStatus WindowEventHandler( + EventHandlerCallRef inCallRef, + EventRef inEvent, + void* inUserData ); + static pascal void TimerEventHandler( + EventLoopTimerRef inTimer, + void* inUserData ); + OSStatus HandleEvent( + EventHandlerCallRef inCallRef, + TCarbonEvent& inEvent ); + + HIViewRef fViewRef; + EventHandlerRef fHandler; + + EventHandlerRef mouseEventHandler; + OptionBits fAutoInvalidateFlags; + +}; + +typedef TView* TViewPtr; + +#endif // TView_H_ diff --git a/macosx/deps.mak b/macosx/deps.mak new file mode 100644 index 000000000..5c65dcc1f --- /dev/null +++ b/macosx/deps.mak @@ -0,0 +1,315 @@ +PlatMacOSX.o: PlatMacOSX.cxx QuartzTextLayout.h QuartzTextStyle.h \ + QuartzTextStyleAttribute.h TCarbonEvent.h ../include/Platform.h \ + ../include/Scintilla.h PlatMacOSX.h ../src/XPM.h \ + ../include/ScintillaWidget.h +ScintillaCallTip.o: ScintillaCallTip.cxx ScintillaMacOSX.h TView.h \ + TCarbonEvent.h TRect.h ../include/Platform.h ../include/Scintilla.h \ + PlatMacOSX.h QuartzTextLayout.h QuartzTextStyle.h \ + QuartzTextStyleAttribute.h ../include/ScintillaWidget.h \ + ../include/SciLexer.h ../include/PropSet.h ../include/SString.h \ + ../include/Accessor.h ../include/KeyWords.h ../src/ContractionState.h \ + ../src/SVector.h ../src/CellBuffer.h ../src/CallTip.h ../src/KeyMap.h \ + ../src/Indicator.h ../src/XPM.h ../src/LineMarker.h ../src/Style.h \ + ../src/AutoComplete.h ../src/ViewStyle.h ../src/Document.h \ + ../src/Editor.h ../src/ScintillaBase.h ScintillaCallTip.h +ScintillaListBox.o: ScintillaListBox.cxx ScintillaMacOSX.h TView.h \ + TCarbonEvent.h TRect.h ../include/Platform.h ../include/Scintilla.h \ + PlatMacOSX.h QuartzTextLayout.h QuartzTextStyle.h \ + QuartzTextStyleAttribute.h ../include/ScintillaWidget.h \ + ../include/SciLexer.h ../include/PropSet.h ../include/SString.h \ + ../include/Accessor.h ../include/KeyWords.h ../src/ContractionState.h \ + ../src/SVector.h ../src/CellBuffer.h ../src/CallTip.h ../src/KeyMap.h \ + ../src/Indicator.h ../src/XPM.h ../src/LineMarker.h ../src/Style.h \ + ../src/AutoComplete.h ../src/ViewStyle.h ../src/Document.h \ + ../src/Editor.h ../src/ScintillaBase.h ScintillaCallTip.h \ + ScintillaListBox.h +ScintillaMacOSX.o: ScintillaMacOSX.cxx ScintillaMacOSX.h TView.h \ + TCarbonEvent.h TRect.h ../include/Platform.h ../include/Scintilla.h \ + PlatMacOSX.h QuartzTextLayout.h QuartzTextStyle.h \ + QuartzTextStyleAttribute.h ../include/ScintillaWidget.h \ + ../include/SciLexer.h ../include/PropSet.h ../include/SString.h \ + ../include/Accessor.h ../include/KeyWords.h ../src/ContractionState.h \ + ../src/SVector.h ../src/CellBuffer.h ../src/CallTip.h ../src/KeyMap.h \ + ../src/Indicator.h ../src/XPM.h ../src/LineMarker.h ../src/Style.h \ + ../src/AutoComplete.h ../src/ViewStyle.h ../src/Document.h \ + ../src/Editor.h ../src/ScintillaBase.h ScintillaCallTip.h \ + ../src/UniConversion.h +TCarbonEvent.o: TCarbonEvent.cxx TCarbonEvent.h +TView.o: TView.cxx TView.h TCarbonEvent.h TRect.h +AutoComplete.o: ../src/AutoComplete.cxx ../include/Platform.h \ + ../include/PropSet.h ../include/SString.h ../src/AutoComplete.h +CallTip.o: ../src/CallTip.cxx ../include/Platform.h \ + ../include/Scintilla.h ../src/CallTip.h +CellBuffer.o: ../src/CellBuffer.cxx ../include/Platform.h \ + ../include/Scintilla.h ../src/SVector.h ../src/SplitVector.h \ + ../src/Partitioning.h ../src/CellBuffer.h +CharClassify.o: ../src/CharClassify.cxx ../src/CharClassify.h +ContractionState.o: ../src/ContractionState.cxx ../include/Platform.h \ + ../src/ContractionState.h +Decoration.o: ../src/Decoration.cxx ../include/Platform.h \ + ../include/Scintilla.h ../src/SplitVector.h ../src/Partitioning.h \ + ../src/RunStyles.h ../src/Decoration.h +Document.o: ../src/Document.cxx ../include/Platform.h \ + ../include/Scintilla.h ../src/SVector.h ../src/SplitVector.h \ + ../src/Partitioning.h ../src/RunStyles.h ../src/CellBuffer.h \ + ../src/CharClassify.h ../src/Decoration.h ../src/Document.h \ + ../src/RESearch.h +DocumentAccessor.o: ../src/DocumentAccessor.cxx ../include/Platform.h \ + ../include/PropSet.h ../include/SString.h ../src/SVector.h \ + ../include/Accessor.h ../src/DocumentAccessor.h ../src/SplitVector.h \ + ../src/Partitioning.h ../src/RunStyles.h ../src/CellBuffer.h \ + ../include/Scintilla.h ../src/CharClassify.h ../src/Decoration.h \ + ../src/Document.h +Editor.o: ../src/Editor.cxx ../include/Platform.h ../include/Scintilla.h \ + ../src/ContractionState.h ../src/SVector.h ../src/SplitVector.h \ + ../src/Partitioning.h ../src/CellBuffer.h ../src/KeyMap.h \ + ../src/RunStyles.h ../src/Indicator.h ../src/XPM.h ../src/LineMarker.h \ + ../src/Style.h ../src/ViewStyle.h ../src/CharClassify.h \ + ../src/Decoration.h ../src/Document.h ../src/Editor.h +ExternalLexer.o: ../src/ExternalLexer.cxx ../include/Platform.h \ + ../include/Scintilla.h ../include/SciLexer.h ../include/PropSet.h \ + ../include/SString.h ../include/Accessor.h ../src/DocumentAccessor.h \ + ../include/KeyWords.h ../src/ExternalLexer.h +Indicator.o: ../src/Indicator.cxx ../include/Platform.h \ + ../include/Scintilla.h ../src/Indicator.h +KeyMap.o: ../src/KeyMap.cxx ../include/Platform.h ../include/Scintilla.h \ + ../src/KeyMap.h +KeyWords.o: ../src/KeyWords.cxx ../include/Platform.h \ + ../include/PropSet.h ../include/SString.h ../include/Accessor.h \ + ../include/KeyWords.h ../include/Scintilla.h ../include/SciLexer.h +LexAPDL.o: ../src/LexAPDL.cxx ../include/Platform.h ../include/PropSet.h \ + ../include/SString.h ../include/Accessor.h ../src/StyleContext.h \ + ../include/KeyWords.h ../include/Scintilla.h ../include/SciLexer.h +LexAU3.o: ../src/LexAU3.cxx ../include/Platform.h ../include/PropSet.h \ + ../include/SString.h ../include/Accessor.h ../src/StyleContext.h \ + ../include/KeyWords.h ../include/Scintilla.h ../include/SciLexer.h +LexAVE.o: ../src/LexAVE.cxx ../include/Platform.h ../include/PropSet.h \ + ../include/SString.h ../include/Accessor.h ../src/StyleContext.h \ + ../include/KeyWords.h ../include/Scintilla.h ../include/SciLexer.h +LexAda.o: ../src/LexAda.cxx ../include/Platform.h ../include/Accessor.h \ + ../src/StyleContext.h ../include/PropSet.h ../include/SString.h \ + ../include/KeyWords.h ../include/SciLexer.h +LexAsm.o: ../src/LexAsm.cxx ../include/Platform.h ../include/PropSet.h \ + ../include/SString.h ../include/Accessor.h ../src/StyleContext.h \ + ../include/KeyWords.h ../include/Scintilla.h ../include/SciLexer.h +LexAsn1.o: ../src/LexAsn1.cxx ../include/Platform.h ../include/PropSet.h \ + ../include/SString.h ../include/Accessor.h ../src/StyleContext.h \ + ../include/KeyWords.h ../include/Scintilla.h ../include/SciLexer.h +LexBaan.o: ../src/LexBaan.cxx ../include/Platform.h ../include/PropSet.h \ + ../include/SString.h ../include/Accessor.h ../src/StyleContext.h \ + ../include/KeyWords.h ../include/Scintilla.h ../include/SciLexer.h +LexBash.o: ../src/LexBash.cxx ../include/Platform.h ../include/PropSet.h \ + ../include/SString.h ../include/Accessor.h ../include/KeyWords.h \ + ../include/Scintilla.h ../include/SciLexer.h +LexBasic.o: ../src/LexBasic.cxx ../include/Platform.h \ + ../include/PropSet.h ../include/SString.h ../include/Accessor.h \ + ../src/StyleContext.h ../include/KeyWords.h ../include/Scintilla.h \ + ../include/SciLexer.h +LexBullant.o: ../src/LexBullant.cxx ../include/Platform.h \ + ../include/PropSet.h ../include/SString.h ../include/Accessor.h \ + ../include/KeyWords.h ../include/Scintilla.h ../include/SciLexer.h +LexCLW.o: ../src/LexCLW.cxx ../include/Platform.h ../include/PropSet.h \ + ../include/SString.h ../include/Accessor.h ../src/StyleContext.h \ + ../include/KeyWords.h ../include/Scintilla.h ../include/SciLexer.h +LexCPP.o: ../src/LexCPP.cxx ../include/Platform.h ../include/PropSet.h \ + ../include/SString.h ../include/Accessor.h ../src/StyleContext.h \ + ../include/KeyWords.h ../include/Scintilla.h ../include/SciLexer.h +LexCSS.o: ../src/LexCSS.cxx ../include/Platform.h ../include/PropSet.h \ + ../include/SString.h ../include/Accessor.h ../src/StyleContext.h \ + ../include/KeyWords.h ../include/Scintilla.h ../include/SciLexer.h +LexCaml.o: ../src/LexCaml.cxx ../include/Platform.h ../include/PropSet.h \ + ../include/SString.h ../include/Accessor.h ../src/StyleContext.h \ + ../include/KeyWords.h ../include/Scintilla.h ../include/SciLexer.h +LexCmake.o: ../src/LexCmake.cxx ../include/Platform.h \ + ../include/PropSet.h ../include/SString.h ../include/Accessor.h \ + ../include/KeyWords.h ../include/Scintilla.h ../include/SciLexer.h +LexConf.o: ../src/LexConf.cxx ../include/Platform.h ../include/PropSet.h \ + ../include/SString.h ../include/Accessor.h ../include/KeyWords.h \ + ../include/Scintilla.h ../include/SciLexer.h +LexCrontab.o: ../src/LexCrontab.cxx ../include/Platform.h \ + ../include/PropSet.h ../include/SString.h ../include/Accessor.h \ + ../include/KeyWords.h ../include/Scintilla.h ../include/SciLexer.h +LexCsound.o: ../src/LexCsound.cxx ../include/Platform.h \ + ../include/PropSet.h ../include/SString.h ../include/Accessor.h \ + ../src/StyleContext.h ../include/KeyWords.h ../include/Scintilla.h \ + ../include/SciLexer.h +LexD.o: ../src/LexD.cxx ../include/Platform.h ../include/PropSet.h \ + ../include/SString.h ../include/Accessor.h ../src/StyleContext.h \ + ../include/KeyWords.h ../include/Scintilla.h ../include/SciLexer.h +LexEScript.o: ../src/LexEScript.cxx ../include/Platform.h \ + ../include/PropSet.h ../include/SString.h ../include/Accessor.h \ + ../src/StyleContext.h ../include/KeyWords.h ../include/Scintilla.h \ + ../include/SciLexer.h +LexEiffel.o: ../src/LexEiffel.cxx ../include/Platform.h \ + ../include/PropSet.h ../include/SString.h ../include/Accessor.h \ + ../src/StyleContext.h ../include/KeyWords.h ../include/Scintilla.h \ + ../include/SciLexer.h +LexErlang.o: ../src/LexErlang.cxx ../include/Platform.h \ + ../include/PropSet.h ../include/SString.h ../include/Accessor.h \ + ../src/StyleContext.h ../include/KeyWords.h ../include/Scintilla.h \ + ../include/SciLexer.h +LexFlagship.o: ../src/LexFlagship.cxx ../include/Platform.h \ + ../include/PropSet.h ../include/SString.h ../include/Accessor.h \ + ../src/StyleContext.h ../include/KeyWords.h ../include/Scintilla.h \ + ../include/SciLexer.h +LexForth.o: ../src/LexForth.cxx ../include/Platform.h \ + ../include/PropSet.h ../include/SString.h ../include/Accessor.h \ + ../include/KeyWords.h ../include/Scintilla.h ../include/SciLexer.h +LexFortran.o: ../src/LexFortran.cxx ../include/Platform.h \ + ../include/PropSet.h ../include/SString.h ../include/Accessor.h \ + ../src/StyleContext.h ../include/KeyWords.h ../include/Scintilla.h \ + ../include/SciLexer.h +LexGAP.o: ../src/LexGAP.cxx ../include/Platform.h ../include/PropSet.h \ + ../include/SString.h ../include/Accessor.h ../src/StyleContext.h \ + ../include/KeyWords.h ../include/Scintilla.h ../include/SciLexer.h +LexGui4Cli.o: ../src/LexGui4Cli.cxx ../include/Platform.h \ + ../include/PropSet.h ../include/SString.h ../include/Accessor.h \ + ../src/StyleContext.h ../include/KeyWords.h ../include/Scintilla.h \ + ../include/SciLexer.h +LexHTML.o: ../src/LexHTML.cxx ../include/Platform.h ../include/PropSet.h \ + ../include/SString.h ../include/Accessor.h ../src/StyleContext.h \ + ../include/KeyWords.h ../include/Scintilla.h ../include/SciLexer.h +LexHaskell.o: ../src/LexHaskell.cxx ../include/Platform.h \ + ../include/PropSet.h ../include/SString.h ../include/Accessor.h \ + ../src/StyleContext.h ../include/KeyWords.h ../include/Scintilla.h \ + ../include/SciLexer.h +LexInno.o: ../src/LexInno.cxx ../include/Platform.h ../include/PropSet.h \ + ../include/SString.h ../include/Accessor.h ../src/StyleContext.h \ + ../include/KeyWords.h ../include/Scintilla.h ../include/SciLexer.h +LexKix.o: ../src/LexKix.cxx ../include/Platform.h ../include/PropSet.h \ + ../include/SString.h ../include/Accessor.h ../src/StyleContext.h \ + ../include/KeyWords.h ../include/Scintilla.h ../include/SciLexer.h +LexLisp.o: ../src/LexLisp.cxx ../include/Platform.h ../include/PropSet.h \ + ../include/SString.h ../include/Accessor.h ../include/KeyWords.h \ + ../include/Scintilla.h ../include/SciLexer.h ../src/StyleContext.h +LexLout.o: ../src/LexLout.cxx ../include/Platform.h ../include/PropSet.h \ + ../include/SString.h ../include/Accessor.h ../src/StyleContext.h \ + ../include/KeyWords.h ../include/Scintilla.h ../include/SciLexer.h +LexLua.o: ../src/LexLua.cxx ../include/Platform.h ../include/PropSet.h \ + ../include/SString.h ../include/Accessor.h ../src/StyleContext.h \ + ../include/KeyWords.h ../include/Scintilla.h ../include/SciLexer.h +LexMMIXAL.o: ../src/LexMMIXAL.cxx ../include/Platform.h \ + ../include/PropSet.h ../include/SString.h ../include/Accessor.h \ + ../src/StyleContext.h ../include/KeyWords.h ../include/Scintilla.h \ + ../include/SciLexer.h +LexMPT.o: ../src/LexMPT.cxx ../include/Platform.h ../include/PropSet.h \ + ../include/SString.h ../include/Accessor.h ../include/KeyWords.h \ + ../include/Scintilla.h ../include/SciLexer.h +LexMSSQL.o: ../src/LexMSSQL.cxx ../include/Platform.h \ + ../include/PropSet.h ../include/SString.h ../include/Accessor.h \ + ../include/KeyWords.h ../include/Scintilla.h ../include/SciLexer.h +LexMatlab.o: ../src/LexMatlab.cxx ../include/Platform.h \ + ../include/PropSet.h ../include/SString.h ../include/Accessor.h \ + ../src/StyleContext.h ../include/KeyWords.h ../include/Scintilla.h \ + ../include/SciLexer.h +LexMetapost.o: ../src/LexMetapost.cxx ../include/Platform.h \ + ../include/PropSet.h ../include/SString.h ../include/Accessor.h \ + ../include/KeyWords.h ../include/Scintilla.h ../include/SciLexer.h \ + ../src/StyleContext.h +LexNsis.o: ../src/LexNsis.cxx ../include/Platform.h ../include/PropSet.h \ + ../include/SString.h ../include/Accessor.h ../include/KeyWords.h \ + ../include/Scintilla.h ../include/SciLexer.h +LexOpal.o: ../src/LexOpal.cxx ../include/Platform.h ../include/PropSet.h \ + ../include/SString.h ../include/Accessor.h ../include/KeyWords.h \ + ../include/Scintilla.h ../include/SciLexer.h ../src/StyleContext.h +LexOthers.o: ../src/LexOthers.cxx ../include/Platform.h \ + ../include/PropSet.h ../include/SString.h ../include/Accessor.h \ + ../include/KeyWords.h ../include/Scintilla.h ../include/SciLexer.h +LexPB.o: ../src/LexPB.cxx ../include/Platform.h ../include/PropSet.h \ + ../include/SString.h ../include/Accessor.h ../src/StyleContext.h \ + ../include/KeyWords.h ../include/Scintilla.h ../include/SciLexer.h +LexPOV.o: ../src/LexPOV.cxx ../include/Platform.h ../include/PropSet.h \ + ../include/SString.h ../include/Accessor.h ../src/StyleContext.h \ + ../include/KeyWords.h ../include/Scintilla.h ../include/SciLexer.h +LexPS.o: ../src/LexPS.cxx ../include/Platform.h ../include/PropSet.h \ + ../include/SString.h ../include/Accessor.h ../src/StyleContext.h \ + ../include/KeyWords.h ../include/Scintilla.h ../include/SciLexer.h +LexPascal.o: ../src/LexPascal.cxx ../include/Platform.h \ + ../include/PropSet.h ../include/SString.h ../include/Accessor.h \ + ../include/KeyWords.h ../include/Scintilla.h ../include/SciLexer.h \ + ../src/StyleContext.h +LexPerl.o: ../src/LexPerl.cxx ../include/Platform.h ../include/PropSet.h \ + ../include/SString.h ../include/Accessor.h ../include/KeyWords.h \ + ../include/Scintilla.h ../include/SciLexer.h +LexPython.o: ../src/LexPython.cxx ../include/Platform.h \ + ../include/PropSet.h ../include/SString.h ../include/Accessor.h \ + ../src/StyleContext.h ../include/KeyWords.h ../include/Scintilla.h \ + ../include/SciLexer.h +LexRebol.o: ../src/LexRebol.cxx ../include/Platform.h \ + ../include/PropSet.h ../include/SString.h ../include/Accessor.h \ + ../include/KeyWords.h ../include/Scintilla.h ../include/SciLexer.h \ + ../src/StyleContext.h +LexRuby.o: ../src/LexRuby.cxx ../include/Platform.h ../include/PropSet.h \ + ../include/SString.h ../include/Accessor.h ../include/KeyWords.h \ + ../include/Scintilla.h ../include/SciLexer.h +LexSQL.o: ../src/LexSQL.cxx ../include/Platform.h ../include/PropSet.h \ + ../include/SString.h ../include/Accessor.h ../src/StyleContext.h \ + ../include/KeyWords.h ../include/Scintilla.h ../include/SciLexer.h +LexScriptol.o: ../src/LexScriptol.cxx ../include/Platform.h \ + ../include/PropSet.h ../include/SString.h ../include/Accessor.h \ + ../include/KeyWords.h ../include/Scintilla.h ../include/SciLexer.h +LexSmalltalk.o: ../src/LexSmalltalk.cxx ../include/Platform.h \ + ../include/PropSet.h ../include/SString.h ../include/Accessor.h \ + ../src/StyleContext.h ../include/KeyWords.h ../include/Scintilla.h \ + ../include/SciLexer.h +LexSpecman.o: ../src/LexSpecman.cxx ../include/Platform.h \ + ../include/PropSet.h ../include/SString.h ../include/Accessor.h \ + ../src/StyleContext.h ../include/KeyWords.h ../include/Scintilla.h \ + ../include/SciLexer.h +LexSpice.o: ../src/LexSpice.cxx ../include/Platform.h \ + ../include/Accessor.h ../src/StyleContext.h ../include/PropSet.h \ + ../include/SString.h ../include/KeyWords.h ../include/SciLexer.h +LexTADS3.o: ../src/LexTADS3.cxx ../include/Platform.h \ + ../include/PropSet.h ../include/SString.h ../include/Accessor.h \ + ../src/StyleContext.h ../include/KeyWords.h ../include/Scintilla.h \ + ../include/SciLexer.h +LexTCL.o: ../src/LexTCL.cxx ../include/Platform.h ../include/PropSet.h \ + ../include/SString.h ../include/Accessor.h ../src/StyleContext.h \ + ../include/KeyWords.h ../include/Scintilla.h ../include/SciLexer.h +LexTeX.o: ../src/LexTeX.cxx ../include/Platform.h ../include/PropSet.h \ + ../include/SString.h ../include/Accessor.h ../include/KeyWords.h \ + ../include/Scintilla.h ../include/SciLexer.h ../src/StyleContext.h +LexVB.o: ../src/LexVB.cxx ../include/Platform.h ../include/PropSet.h \ + ../include/SString.h ../include/Accessor.h ../src/StyleContext.h \ + ../include/KeyWords.h ../include/Scintilla.h ../include/SciLexer.h +LexVHDL.o: ../src/LexVHDL.cxx ../include/Platform.h ../include/PropSet.h \ + ../include/SString.h ../include/Accessor.h ../src/StyleContext.h \ + ../include/KeyWords.h ../include/Scintilla.h ../include/SciLexer.h +LexVerilog.o: ../src/LexVerilog.cxx ../include/Platform.h \ + ../include/PropSet.h ../include/SString.h ../include/Accessor.h \ + ../src/StyleContext.h ../include/KeyWords.h ../include/Scintilla.h \ + ../include/SciLexer.h +LexYAML.o: ../src/LexYAML.cxx ../include/Platform.h ../include/PropSet.h \ + ../include/SString.h ../include/Accessor.h ../src/StyleContext.h \ + ../include/KeyWords.h ../include/Scintilla.h ../include/SciLexer.h +LineMarker.o: ../src/LineMarker.cxx ../include/Platform.h \ + ../include/Scintilla.h ../src/XPM.h ../src/LineMarker.h +PropSet.o: ../src/PropSet.cxx ../include/Platform.h ../include/PropSet.h \ + ../include/SString.h +RESearch.o: ../src/RESearch.cxx ../src/CharClassify.h ../src/RESearch.h +RunStyles.o: ../src/RunStyles.cxx ../include/Platform.h \ + ../include/Scintilla.h ../src/SplitVector.h ../src/Partitioning.h \ + ../src/RunStyles.h +ScintillaBase.o: ../src/ScintillaBase.cxx ../include/Platform.h \ + ../include/Scintilla.h ../include/PropSet.h ../include/SString.h \ + ../include/SciLexer.h ../include/Accessor.h ../src/DocumentAccessor.h \ + ../include/KeyWords.h ../src/ContractionState.h ../src/SVector.h \ + ../src/SplitVector.h ../src/Partitioning.h ../src/RunStyles.h \ + ../src/CellBuffer.h ../src/CallTip.h ../src/KeyMap.h ../src/Indicator.h \ + ../src/XPM.h ../src/LineMarker.h ../src/Style.h ../src/ViewStyle.h \ + ../src/AutoComplete.h ../src/CharClassify.h ../src/Decoration.h \ + ../src/Document.h ../src/Editor.h ../src/ScintillaBase.h +Style.o: ../src/Style.cxx ../include/Platform.h ../include/Scintilla.h \ + ../src/Style.h +StyleContext.o: ../src/StyleContext.cxx ../include/Platform.h \ + ../include/PropSet.h ../include/SString.h ../include/Accessor.h \ + ../src/StyleContext.h +UniConversion.o: ../src/UniConversion.cxx ../src/UniConversion.h +ViewStyle.o: ../src/ViewStyle.cxx ../include/Platform.h \ + ../include/Scintilla.h ../src/SplitVector.h ../src/Partitioning.h \ + ../src/RunStyles.h ../src/Indicator.h ../src/XPM.h ../src/LineMarker.h \ + ../src/Style.h ../src/ViewStyle.h +WindowAccessor.o: ../src/WindowAccessor.cxx ../include/Platform.h \ + ../include/PropSet.h ../include/SString.h ../include/Accessor.h \ + ../include/WindowAccessor.h ../include/Scintilla.h +XPM.o: ../src/XPM.cxx ../include/Platform.h ../src/XPM.h diff --git a/macosx/makefile b/macosx/makefile new file mode 100644 index 000000000..0ddbb9ccc --- /dev/null +++ b/macosx/makefile @@ -0,0 +1,95 @@ +# Make file for Scintilla on Mac OS X +# Copyright 2002 by Evan Jones <ejones@uwaterloo.ca> +# Based on the GTK makefile Copyright 1998-2001 by Neil Hodgson <neilh@scintilla.org> +# The License.txt file describes the conditions under which this software may be distributed. +# This makefile assumes that Apple's version of GCC 3.1 is used and changes will be needed to use other compilers. +# GNU make does not like \r\n line endings so should be saved to CVS in binary form. + +.SUFFIXES: .cxx .c .o .h .a +CC = c++ +CCOMP = gcc +LIBTOOL = libtool + +GCC_MAJOR := $(shell $(CC) -v 2>&1 | \ + grep version | cut -d' ' -f3 | cut -d'.' -f1) + +# We call it "libscintilla" so when you add it to a Project Builder project, +# Project Builder will link it correctly. +COMPLIB=../bin/libscintilla.a + +vpath %.h ../src ../include +vpath %.cxx ../src + +INCLUDEDIRS=-I ../include -I ../src + +ifeq ($(GCC_MAJOR),3) +# 10.4 will have GCC 4 or better, so this should only ever happen +# on a 10.3 or older PPC box +ARCHFLAGS=-arch ppc -faltivec -mcpu=7400 -mtune=7400 -mpowerpc -mpowerpc-gfxopt +else +ARCHFLAGS=-isysroot /Developer/SDKs/MacOSX10.4u.sdk -arch ppc -arch i386 +LDFLAGS=/usr/include/Developer/SDKs/MacOSX10.4u.sdk -arch ppc -arch i386 +endif + +OPTIONS=-Wall -Wno-missing-braces -Wno-char-subscripts -DSCI_NAMESPACE -DMACOSX -DSCI_LEXER + +#DEBUG = 1 + +ifdef DEBUG +DFLAGS=-DDEBUG -g +else +DFLAGS=-DNDEBUG -Os +endif + +ifdef CONTAINER_HANDLES_EVENTS +CONTAINER=-DCONTAINER_HANDLES_EVENTS=1 +endif + +.cxx.o: + $(CC) $(CXXFLAGS) $(OPTIONS) $(DFLAGS) $(CONTAINER) $(ARCHFLAGS) $(INCLUDEDIRS) -c $< +.c.o: + $(CCOMP) $(CXXFLAGS) $(OPTIONS) $(DFLAGS) $(CONTAINER) $(ARCHFLAGS) $(INCLUDEDIRS) -w -c $< + +#++Autogenerated -- run src/LexGen.py to regenerate +#**LEXOBJS=\\\n\(\*.o \) +LEXOBJS=\ +LexAda.o LexAPDL.o LexAsm.o LexAsn1.o LexAU3.o LexAVE.o LexBaan.o LexBash.o \ +LexBasic.o LexBullant.o LexCaml.o LexCLW.o LexCmake.o LexConf.o LexCPP.o \ +LexCrontab.o LexCsound.o LexCSS.o LexD.o LexEiffel.o LexErlang.o LexEScript.o \ +LexFlagship.o LexForth.o LexFortran.o LexGAP.o LexGui4Cli.o LexHaskell.o \ +LexHTML.o LexInno.o LexKix.o LexLisp.o LexLout.o LexLua.o LexMatlab.o \ +LexMetapost.o LexMMIXAL.o LexMPT.o LexMSSQL.o LexNsis.o LexOpal.o LexOthers.o \ +LexPascal.o LexPB.o LexPerl.o LexPOV.o LexPS.o LexPython.o LexRebol.o \ +LexRuby.o LexScriptol.o LexSmalltalk.o LexSpecman.o LexSpice.o LexSQL.o \ +LexTADS3.o LexTCL.o LexTeX.o LexVB.o LexVerilog.o LexVHDL.o LexYAML.o +#--Autogenerated -- end of automatically generated section + +# The LEXOBJS have to be treated specially as the functions in them are not called from external code + +all: $(COMPLIB) $(LEXOBJS) + +clean: + rm -f *.o $(COMPLIB) + +deps: + $(CC) -MM $(CXXFLAGS) *.cxx ../src/*.cxx >deps.mak + +$(COMPLIB): DocumentAccessor.o WindowAccessor.o KeyWords.o StyleContext.o \ + CharClassify.o Decoration.o Document.o CallTip.o \ + ScintillaBase.o ContractionState.o Editor.o ExternalLexer.o PropSet.o PlatMacOSX.o \ + KeyMap.o LineMarker.o ScintillaMacOSX.o CellBuffer.o ViewStyle.o \ + RESearch.o RunStyles.o Style.o Indicator.o AutoComplete.o UniConversion.o XPM.o \ + TCarbonEvent.o TView.o ScintillaCallTip.o \ + $(LEXOBJS) + $(LIBTOOL) -o $@ $^ + +# Generate header files from Scintilla.iface +../include/Scintilla_gen.h: ../include/HFacer.py ../include/Face.py ../include/Scintilla.iface + cd ../include && python HFacer.py +../include/SciLexer_gen.h: ../include/HFacer.py ../include/Face.py ../include/Scintilla.iface + cd ../include && python HFacer.py +../include/Scintilla.h: ../include/Scintilla_gen.h +../include/SciLexer.h: ../include/SciLexer_gen.h + +# Automatically generate header dependencies with "make deps" +include deps.mak |