aboutsummaryrefslogtreecommitdiffhomepage
path: root/macosx/PlatMacOSX.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'macosx/PlatMacOSX.cxx')
-rw-r--r--macosx/PlatMacOSX.cxx1861
1 files changed, 0 insertions, 1861 deletions
diff --git a/macosx/PlatMacOSX.cxx b/macosx/PlatMacOSX.cxx
deleted file mode 100644
index 381be992d..000000000
--- a/macosx/PlatMacOSX.cxx
+++ /dev/null
@@ -1,1861 +0,0 @@
-// 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 <vector>
-#include <map>
-
-#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() : fid(0) {}
-
-Font::~Font() { Release(); }
-
-
-void Font::Create(const char *faceName, int /*characterSet*/,
- int size, bool bold, bool italic, int /*extraFontFlag*/) {
- // TODO: How should I handle the characterSet request?
- Release();
-
- fid = 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*>( fid )->setAttributes( attributes, sizeof( attributes ) / sizeof( *attributes ) );
-
- //ATSStyleRenderingOptions rendering = kATSStyleNoAntiAliasing;
- //reinterpret_cast<QuartzTextStyle*>( fid )->setAttribute( kATSUStyleRenderingOptionsTag, sizeof( rendering ), &rendering );
-
- // TODO: Why do I have to manually set this?
- reinterpret_cast<QuartzTextStyle*>( fid )->setFontFeature( kLigaturesType, kCommonLigaturesOffSelector );
-}
-
-void Font::Release() {
- if (fid)
- delete reinterpret_cast<QuartzTextStyle*>( fid );
-
- fid = 0;
-}
-
-SurfaceImpl::SurfaceImpl() {
- bitmapData = NULL; // Release will try and delete bitmapData if != NULL
- gc = NULL;
- textLayout = new QuartzTextLayout(NULL);
- Release();
-}
-
-SurfaceImpl::~SurfaceImpl() {
- Release();
- delete textLayout;
-}
-
-void SurfaceImpl::Release() {
- textLayout->setContext (NULL);
- if ( bitmapData != NULL )
- {
- delete[] bitmapData;
- // We only "own" the graphics context if we are a bitmap context
- if ( gc != NULL ) CGContextRelease( gc );
- }
- 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();
-}
-
-void SurfaceImpl::Init(SurfaceID sid, WindowID /*wid*/) {
- Release();
- gc = reinterpret_cast<CGContextRef>( sid );
- CGContextSetLineWidth( gc, 1.0 );
- textLayout->setContext (gc);
-}
-
-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();
- if( colorSpace == NULL )
- return;
-
- // create the bitmap
- bitmapData = new uint8_t[ bitmapByteCount ];
- 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;
- }
- textLayout->setContext (gc);
- }
-
- // the context retains the color space, so we can release it
- CGColorSpaceRelease( colorSpace );
-
- if ( 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();
- if( colorSpace == NULL )
- return 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 );
- CGImageRef image = NULL;
- if ( dataProvider != NULL )
- {
- // create the CGImage
- image = CGImageCreate( bitmapWidth,
- bitmapHeight,
- BITS_PER_COMPONENT,
- BITS_PER_PIXEL,
- bitmapBytesPerRow,
- colorSpace,
- kCGImageAlphaPremultipliedLast,
- dataProvider,
- NULL,
- 0,
- kCGRenderingIntentDefault );
- }
-
- // 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 );
- // 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.
- 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;
- }
-
- 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
- );
- if( pattern != NULL ) {
-
- // Create a pattern color space
- CGColorSpaceRef colorSpace = CGColorSpaceCreatePattern( NULL );
- if( 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 */
- colorSpace = NULL;
- CGPatternRelease( pattern );
- pattern = NULL;
- CGImageRelease( image );
- image = NULL;
- } /* pattern != NULL */
-}
-
-void SurfaceImpl::RoundedRectangle(PRectangle rc, ColourAllocated fore, ColourAllocated back) {
- // This is only called from the margin marker drawing code for SC_MARK_ROUNDRECT
- // The Win32 version does
- // ::RoundRect(hdc, rc.left + 1, rc.top, rc.right - 1, rc.bottom, 8, 8 );
- // which is a rectangle with rounded corners each having a radius of 4 pixels.
- // It would be almost as good just cutting off the corners with lines at
- // 45 degrees as is done on GTK+.
-
- // 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
- 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 Scintilla::SurfaceImpl::AlphaRectangle(PRectangle rc, int /*cornerSize*/, ColourAllocated fill, int alphaFill,
- ColourAllocated /*outline*/, int /*alphaOutline*/, int /*flags*/)
-{
- if ( gc ) {
- ColourDesired colour( fill.AsLong() );
-
- // Set the Fill color to match
- CGContextSetRGBFillColor( gc, colour.GetRed() / 255.0, colour.GetGreen() / 255.0, colour.GetBlue() / 255.0, alphaFill / 255.0 );
- CGRect rect = PRectangleToCGRect( rc );
- CGContextFillRect( gc, rect );
- }
-}
-
-void SurfaceImpl::DrawRGBAImage(PRectangle /* rc */, int /* width */, int /* height */, const unsigned char * /* pixelsImage*/) {
- // Not supported for Carbon
-}
-
-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;
- }
-
- // 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;
-}
-
-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) {
- textLayout->setText (reinterpret_cast<const UInt8*>(s), len, *reinterpret_cast<QuartzTextStyle*>(font_.GetID()));
-
- // 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 );
-}
-
-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.
- for (int i = 0; i < len; i++)
- positions [i] = 0;
-
- // We need the right X coords, so we have to append a char to get the left coord of thast extra char
- char* buf = (char*) malloc (len+1);
- if (!buf)
- return;
-
- memcpy (buf, s, len);
- buf [len] = '.';
-
- textLayout->setText (reinterpret_cast<const UInt8*>(buf), len+1, *reinterpret_cast<QuartzTextStyle*>(font_.GetID()));
- ATSUGlyphInfoArray* theGlyphInfoArrayPtr;
- ByteCount theArraySize;
-
- // Get the GlyphInfoArray
- ATSUTextLayout layout = textLayout->getLayout();
- if ( noErr == ATSUGetGlyphInfo (layout, 0, textLayout->getLength(), &theArraySize, NULL))
- {
- theGlyphInfoArrayPtr = (ATSUGlyphInfoArray *) malloc (theArraySize + sizeof(ItemCount) + sizeof(ATSUTextLayout));
- if (theGlyphInfoArrayPtr)
- {
- if (noErr == ATSUGetGlyphInfo (layout, 0, textLayout->getLength(), &theArraySize, theGlyphInfoArrayPtr))
- {
- // do not count the first item, which is at the beginning of the line
- for ( UniCharCount unicodePosition = 1, i = 0; i < len && unicodePosition < theGlyphInfoArrayPtr->numGlyphs; unicodePosition ++ )
- {
- // The ideal position is the x coordinate of the glyph, relative to the beginning of the line
- int position = (int)( theGlyphInfoArrayPtr->glyphs[unicodePosition].idealX + 0.5 ); // These older APIs return float values
- unsigned char 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 )
- {
- unsigned char mask = 0xc0;
- int count = 1;
- // Add one additonal byte for each extra high order one in the byte
- while ( uch >= mask && count < 8 )
- {
- positions[i++] = position;
- count ++;
- mask = mask >> 1 | 0x80; // add an additional one in the highest order position
- }
- }
- }
- }
-
- // Free the GlyphInfoArray
- free (theGlyphInfoArrayPtr);
- }
- }
- free (buf);
-}
-
-int SurfaceImpl::WidthText(Font &font_, const char *s, int len) {
- if (font_.GetID())
- {
- textLayout->setText (reinterpret_cast<const UInt8*>(s), len, *reinterpret_cast<QuartzTextStyle*>(font_.GetID()));
-
- // 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" );
- return 0;
- }
-
- //Platform::DebugPrintf( "WidthText: \"%*s\" = %ld\n", len, s, Fix2Long( glyphBounds.upperRight.x - glyphBounds.upperLeft.x ) );
- 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())
- {
- textLayout->setText (reinterpret_cast<const UInt8*>(str), 1, *reinterpret_cast<QuartzTextStyle*>(font_.GetID()));
-
- // 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" );
- return 0;
- }
-
- 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 for code pages != UTF-8
-}
-
-Surface *Surface::Allocate() {
- return new SurfaceImpl( );
-}
-
-Window::~Window() {
-}
-
-void Window::Destroy() {
- if (windowRef) {
- DisposeWindow(reinterpret_cast<WindowRef>( windowRef ));
- }
- wid = 0;
-}
-
-bool Window::HasFocus() {
- // TODO: Test this
- return HIViewSubtreeContainsFocus( reinterpret_cast<HIViewRef>( wid ) );
-}
-
-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 (wid) {
- HIRect controlFrame;
- HIViewGetFrame( reinterpret_cast<HIViewRef>( wid ), &controlFrame );
- rc = CGRectToPRectangle( controlFrame );
- }
-
- return rc;
-}
-
-void Window::SetPosition(PRectangle rc) {
- // Moves this view inside the parent view
- if ( wid )
- {
- // Set the frame on the view, the function handles the rest
- CGRect r = PRectangleToCGRect( rc );
- HIViewSetFrame( reinterpret_cast<HIViewRef>( wid ), &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 ( wid ) {
- HIViewSetVisible( reinterpret_cast<HIViewRef>( wid ), 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 ( wid ) {
- HIViewSetNeedsDisplay( reinterpret_cast<HIViewRef>( wid ), true );
- }
-}
-
-void Window::InvalidateRectangle(PRectangle rc) {
- if (wid) {
- // Create a rectangular region
- RgnHandle region = NewRgn();
- SetRectRgn( region, rc.left, rc.top, rc.right, rc.bottom );
-
- // Make that region invalid
- HIViewSetNeedsDisplayInRegion( reinterpret_cast<HIViewRef>( wid ), region, true );
- 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 (wid) {
- // 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:
- cursor = kThemeResizeUpDownCursor;
- break;
- case cursorReverseArrow:
- case cursorUp:
- default:
- cursor = kThemeArrowCursor;
- break;
- }
-
- SetThemeCursor( cursor );
- }
-}
-
-void Window::SetTitle(const char *s) {
- WindowRef window = GetControlOwner(reinterpret_cast<HIViewRef>( wid ));
- CFStringRef title = CFStringCreateWithCString(kCFAllocatorDefault, s, kCFStringEncodingMacRoman);
- SetWindowTitleWithCFString(window, title);
- CFRelease(title);
-}
-
-PRectangle Window::GetMonitorRect(Point) {
- return PRectangle();
-}
-
-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 maxItemWidth;
- 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), maxItemWidth(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 RegisterImage(int type, const char *xpm_data);
- void RegisterRGBAImage(int type, int width, int height, const unsigned char *pixelsImage);
- 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 = 2000;
-
- 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 );
-
- wid = 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 fontName255;
- char fontName[256];
- FMGetFontFamilyName(style.font, fontName255);
-
- CFStringRef fontNameCF = ::CFStringCreateWithPascalString( kCFAllocatorDefault, fontName255, kCFStringEncodingMacRoman );
- ::CFStringGetCString( fontNameCF, fontName, (CFIndex)255, kCFStringEncodingMacRoman );
-
- font.Create((const char *)fontName, 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;
- rcDesired.right = rcDesired.left + maxItemWidth + aveCharWidth;
-
- if (Length() > rows)
- rcDesired.right += kScrollBarWidth;
- rcDesired.right += IconWidth();
-
- // Set the column width
- ::SetDataBrowserTableViewColumnWidth (lb, UInt16 (rcDesired.right - rcDesired.left));
- 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
- maxItemWidth = 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);
-
- Scintilla::SurfaceImpl surface;
- unsigned int width = surface.WidthText (font, s, strlen (s));
- if (width > maxItemWidth)
- maxItemWidth = width;
-
- DataBrowserItemID items[1];
- items[0] = count + 1;
- AddDataBrowserItems (lb, kDataBrowserNoItem, 1, items, kDataBrowserItemNoProperty);
- ShowHideScrollbar();
-}
-
-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::RegisterImage(int type, const char *xpm_data) {
- xset.Add(type, xpm_data);
-}
-
-void ListBoxImpl::RegisterRGBAImage(int /* type */, int /* width */, int /* height */, const unsigned char * /*pixelsImage */) {
- // Not supported for Carbon
-}
-
-void ListBoxImpl::ClearRegisteredImages() {
- xset.Clear();
-}
-
-Menu::Menu() : mid(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*>( &mid ) );
-}
-
-void Menu::Destroy() {
- if ( mid != NULL )
- {
- ReleaseMenu( reinterpret_cast<MenuRef>( mid ) );
- mid = 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>( mid ), globalPoint,
- false, kCMHelpItemRemoveHelp, NULL,
- NULL, &userSelection,
- &menuId,
- &menuItem
- );
-}
-
-// ElapsedTime is used for precise performance measurements during development
-// and not for anything a user sees.
-
-ElapsedTime::ElapsedTime() {
- struct timeval curTime;
- int retVal;
- retVal = gettimeofday( &curTime, NULL );
-
- bigBit = curTime.tv_sec;
- littleBit = curTime.tv_usec;
-}
-
-double ElapsedTime::Duration(bool reset) {
- struct timeval curTime;
- int retVal;
- retVal = gettimeofday( &curTime, NULL );
- 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 fid = HighShortFromLong(GetScriptVariable(smCurrentScript, smScriptAppFondSize));
- FMGetFontFamilyName(fid, PlatformDefaultFontName);
- char* defaultFontName = (char*) PlatformDefaultFontName;
- defaultFontName[defaultFontName[0]+1] = 0;
- ++defaultFontName;
-
- return defaultFontName;
-}
-
-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::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 for code pages != UTF-8
- return false;
-}
-
-int Platform::DBCSCharLength(int /*codePage*/, const char* /*s*/) {
- // TODO: Implement this for code pages != UTF-8
- return 1;
-}
-
-int Platform::DBCSCharMaxLength() {
- // TODO: Implement this for code pages != UTF-8
- //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);
-#ifdef DEBUG
- // Jump into debugger in assert on Mac (CL269835)
- ::Debugger();
-#endif
-}
-
-int Platform::Clamp(int val, int minVal, int maxVal) {
- if (val > maxVal)
- val = maxVal;
- if (val < minVal)
- val = minVal;
- return val;
-}