diff options
Diffstat (limited to 'cocoa/PlatCocoa.mm')
| -rw-r--r-- | cocoa/PlatCocoa.mm | 1108 | 
1 files changed, 521 insertions, 587 deletions
| diff --git a/cocoa/PlatCocoa.mm b/cocoa/PlatCocoa.mm index 24c74c70e..80cc5a43b 100644 --- a/cocoa/PlatCocoa.mm +++ b/cocoa/PlatCocoa.mm @@ -22,6 +22,7 @@  #include <assert.h>  #include <sys/time.h>  #include <stdexcept> +#include <map>  #include "XPM.h" @@ -915,16 +916,26 @@ Surface *Surface::Allocate()  //----------------- Window ------------------------------------------------------------------------- -Window::~Window() { +// Cocoa uses different types for windows and views, so a Window may +// be either an NSWindow or NSView and the code will check the type +// before performing an action. + +Window::~Window() +{  }  //--------------------------------------------------------------------------------------------------  void Window::Destroy()  { -  if (windowRef) +  if (wid)    { -    // not used +    id idWin = reinterpret_cast<id>(wid); +    if ([idWin isKindOfClass: [NSWindow class]]) +    { +      NSWindow* win = reinterpret_cast<NSWindow*>(idWin); +      [win release]; +    }    }    wid = 0;  } @@ -939,62 +950,85 @@ bool Window::HasFocus()  //-------------------------------------------------------------------------------------------------- +static int ScreenMax(NSWindow* win) +{ +  NSScreen* screen = [win screen]; +  NSRect frame = [screen frame]; +  return frame.origin.y + frame.size.height; +} +  PRectangle Window::GetPosition()  { -  NSRect rect= [reinterpret_cast<NSView*>(wid) frame]; -   -  return PRectangle(NSMinX(rect), NSMinY(rect), NSMaxX(rect), NSMaxY(rect)); +  if (wid) +  { +    NSRect rect; +    id idWin = reinterpret_cast<id>(wid); +    NSWindow* win; +    if ([idWin isKindOfClass: [NSView class]]) +    { +      // NSView +      NSView* view = reinterpret_cast<NSView*>(idWin); +      win = [view window]; +      rect = [view bounds]; +      rect = [view convertRectToBase: rect]; +      rect.origin = [win convertBaseToScreen:rect.origin]; +    } +    else +    { +      // NSWindow +      win = reinterpret_cast<NSWindow*>(idWin); +      rect = [win frame]; +    } +    int screenHeight = ScreenMax(win); +    // Invert screen positions to match Scintilla +    return PRectangle( +        NSMinX(rect), screenHeight - NSMaxY(rect), +        NSMaxX(rect), screenHeight - NSMinY(rect)); +  } +  else +  { +    return PRectangle(0, 0, 1, 1); +  }  }  //--------------------------------------------------------------------------------------------------  void Window::SetPosition(PRectangle rc)  { -  // Moves this view inside the parent view -  if ( wid ) +  if (wid)    { -    // Set the frame on the view, the function handles the rest -    //        CGRect r = PRectangleToCGRect( rc ); -    //        HIViewSetFrame( reinterpret_cast<HIViewRef>( wid ), &r ); +    id idWin = reinterpret_cast<id>(wid); +    if ([idWin isKindOfClass: [NSView class]]) +    { +      // NSView +      // Moves this view inside the parent view +      NSRect nsrc = NSMakeRect(rc.left, rc.bottom, rc.Width(), rc.Height()); +      NSView* view = reinterpret_cast<NSView*>(idWin); +      nsrc.origin = [[view window] convertScreenToBase:nsrc.origin]; +      [view setFrame: nsrc]; +    } +    else +    { +      // NSWindow +      NSWindow* win = reinterpret_cast<NSWindow*>(idWin); +      int screenHeight = ScreenMax(win); +      NSRect nsrc = NSMakeRect(rc.left, screenHeight - rc.bottom, +          rc.Width(), rc.Height()); +      [win setFrame: nsrc display:YES]; +    }    }  }  //-------------------------------------------------------------------------------------------------- -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); -  //    } +void Window::SetPositionRelative(PRectangle rc, Window window) +{ +  PRectangle rcOther = window.GetPosition(); +  rc.left += rcOther.left; +  rc.right += rcOther.left; +  rc.top += rcOther.top; +  rc.bottom += rcOther.top; +  SetPosition(rc);  }  //-------------------------------------------------------------------------------------------------- @@ -1009,30 +1043,46 @@ PRectangle Window::GetClientPosition()  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 ); -  //    } +  if (wid) +  { +    id idWin = reinterpret_cast<id>(wid); +    if ([idWin isKindOfClass: [NSWindow class]]) +    { +      NSWindow* win = reinterpret_cast<NSWindow*>(idWin); +      if (show) +      { +        [win orderFront:nil]; +      } +      else +      { +        [win orderOut:nil]; +      } +    } +  }  }  //--------------------------------------------------------------------------------------------------  /** - * Invalidates the entire window (here an NSView) so it is completely redrawn. + * Invalidates the entire window or view so it is completely redrawn.   */  void Window::InvalidateAll()  {    if (wid)    { -    NSView* container = reinterpret_cast<NSView*>(wid); +    id idWin = reinterpret_cast<id>(wid); +    NSView* container; +    if ([idWin isKindOfClass: [NSView class]]) +    { +      container = reinterpret_cast<NSView*>(idWin); +    } +    else +    { +      // NSWindow +      NSWindow* win = reinterpret_cast<NSWindow*>(idWin); +      container = reinterpret_cast<NSView*>([win contentView]); +      container.needsDisplay = YES; +    }      container.needsDisplay = YES;    }  } @@ -1040,22 +1090,33 @@ void Window::InvalidateAll()  //--------------------------------------------------------------------------------------------------  /** - * Invalidates part of the window (here an NSView) so only this part redrawn. + * Invalidates part of the window or view so only this part redrawn.   */  void Window::InvalidateRectangle(PRectangle rc)  {    if (wid)    { -    NSView* container = reinterpret_cast<NSView*>(wid); +    id idWin = reinterpret_cast<id>(wid); +    NSView* container; +    if ([idWin isKindOfClass: [NSView class]]) +    { +      container = reinterpret_cast<NSView*>(idWin); +    } +    else +    { +      // NSWindow +      NSWindow* win = reinterpret_cast<NSWindow*>(idWin); +      container = reinterpret_cast<NSView*>([win contentView]); +    }      [container setNeedsDisplayInRect: PRectangleToNSRect(rc)];    }  }  //-------------------------------------------------------------------------------------------------- -void Window::SetFont(Font &) +void Window::SetFont(Font&)  { -  // TODO: Do I need to implement this? MSDN: specifies the font that a control is to use when drawing text. +  // Implemented on list subclass on Cocoa.  }  //-------------------------------------------------------------------------------------------------- @@ -1068,26 +1129,81 @@ void Window::SetCursor(Cursor curs)  {    if (wid)    { -    InnerView* container = reinterpret_cast<InnerView*>(wid); -    [container setCursor: curs]; +    id idWin = reinterpret_cast<id>(wid); +    if ([idWin isMemberOfClass: [InnerView class]]) +    { +      InnerView* container = reinterpret_cast<InnerView*>(idWin); +      [container setCursor: curs]; +    }    }  }  //-------------------------------------------------------------------------------------------------- -void Window::SetTitle(const char *s) +void Window::SetTitle(const char* s)  { -  //    WindowRef window = GetControlOwner(reinterpret_cast<HIViewRef>( wid )); -  //    CFStringRef title = CFStringCreateWithCString(kCFAllocatorDefault, s, kCFStringEncodingMacRoman); -  //    SetWindowTitleWithCFString(window, title); -  //    CFRelease(title); +  if (wid) +  { +    id idWin = reinterpret_cast<id>(wid); +    if ([idWin isKindOfClass: [NSWindow class]]) +    { +      NSWindow* win = reinterpret_cast<NSWindow*>(idWin); +      NSString* sTitle = [NSString stringWithUTF8String:s]; +      [win setTitle:sTitle]; +    } +  }  }  //--------------------------------------------------------------------------------------------------  PRectangle Window::GetMonitorRect(Point)  { -	return PRectangle(); +  if (wid) +  { +    id idWin = reinterpret_cast<id>(wid); +    if ([idWin isKindOfClass: [NSWindow class]]) +    { +      NSWindow* win = reinterpret_cast<NSWindow*>(idWin); +      NSScreen* screen = [win screen]; +      NSRect rect = [screen frame]; +      int screenHeight = rect.origin.y + rect.size.height; +      // Invert screen positions to match Scintilla +      return PRectangle( +          NSMinX(rect), screenHeight - NSMaxY(rect), +          NSMaxX(rect), screenHeight - NSMinY(rect)); +    } +  } +  return PRectangle(); +} + +//----------------- ImageFromXPM ------------------------------------------------------------------- + +// Convert an XPM image into an NSImage for use with Cocoa + +static NSImage* ImageFromXPM(XPM* pxpm) +{ +  NSImage* img = nil; +  if (pxpm) +  { +    const int width = pxpm->GetWidth(); +    const int height = pxpm->GetHeight(); +    PRectangle rcxpm(0, 0, width, height); +    Surface* surfaceXPM = Surface::Allocate(); +    if (surfaceXPM) +    { +      surfaceXPM->InitPixMap(width, height, NULL, NULL); +      SurfaceImpl* surfaceIXPM = static_cast<SurfaceImpl*>(surfaceXPM); +      CGContextClearRect(surfaceIXPM->GetContext(), CGRectMake(0, 0, width, height)); +      pxpm->Draw(surfaceXPM, rcxpm); +      img = [NSImage alloc]; +      [img autorelease]; +      CGImageRef imageRef = surfaceIXPM->GetImage(); +      [img initWithCGImage:imageRef size:NSZeroSize]; +      CGImageRelease(imageRef); +      delete surfaceXPM; +    } +  } +  return img;  }  //----------------- ListBox ------------------------------------------------------------------------ @@ -1104,665 +1220,483 @@ ListBox::~ListBox()  //-------------------------------------------------------------------------------------------------- -static const OSType scintillaListBoxType = 'sclb'; - -enum { -  kItemsPerContainer = 1, -  kIconColumn = 'icon', -  kTextColumn = 'text' +struct RowData +{ +  int type; +  std::string text; +  RowData(int type_, const char* text_) : +    type(type_), text(text_) +  { +  }  }; -static SInt32 kScrollBarWidth = 0; -class LineData { -  int *types; -  CFStringRef *strings; -  int len; -  int maximum; +class LinesData +{ +  std::vector<RowData> lines;  public: -  LineData() :types(0), strings(0), len(0), maximum(0) {} -  ~LineData() { -    Clear(); +  LinesData() +  {    } -  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; +  ~LinesData() +  {    } -  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 Length() const +  { +    return lines.size(); +  } +  void Clear() +  { +    lines.clear(); +  } +  void Add(int index, int type, char* str) +  { +    lines.push_back(RowData(type, str));    } -  int GetType(int index) { -    if (index < maximum) { -      return types[index]; -    } else { +  int GetType(int index) const +  { +    if (index < lines.size()) +    { +      return lines[index].type; +    } +    else +    {        return 0;      }    } -  CFStringRef GetString(int index) { -    if (index < maximum) { -      return strings[index]; -    } else { +  const char* GetString(int index) const +  { +    if (index < lines.size()) +    { +      return lines[index].text.c_str(); +    } +    else +    {        return 0;      }    }  }; +class ListBoxImpl; + +@interface AutoCompletionDataSource : +NSObject <NSTableViewDataSource> +{ +  ListBoxImpl* box; +} + +@end +  //----------------- ListBoxImpl -------------------------------------------------------------------- +// Map from icon type to an NSImage* +typedef std::map<int, NSImage*> ImageMap; +  class ListBoxImpl : public ListBox  {  private:    ControlRef lb; -  XPMSet xset; +  ImageMap images;    int lineHeight;    bool unicodeMode;    int desiredVisibleRows;    unsigned int maxItemWidth;    unsigned int aveCharWidth; +  unsigned int maxIconWidth;    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; + +  NSTableView* table; +  NSScrollView* scroller; +  NSTableColumn* colIcon; +  NSTableColumn* colText; + +  LinesData ld;    CallBackAction doubleClickAction; -  void *doubleClickActionData; -   +  void* doubleClickActionData; + +public:    ListBoxImpl() : lb(NULL), lineHeight(10), unicodeMode(false), -  desiredVisibleRows(5), maxItemWidth(0), aveCharWidth(8), -  doubleClickAction(NULL), doubleClickActionData(NULL) +    desiredVisibleRows(5), maxItemWidth(0), aveCharWidth(8), maxIconWidth(0), +    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_); + +  // ListBox methods +  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); +  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); +  int Find(const char* prefix); +  void GetValue(int n, char* value, int len); +  void RegisterImage(int type, const char* xpm_data);    void ClearRegisteredImages(); -  void SetDoubleClickAction(CallBackAction action, void *data) { +  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); + +  // For access from AutoCompletionDataSource +  int Rows(); +  NSImage* ImageForRow(int row); +  NSString* TextForRow(int row); +  void DoubleClick();  }; -ListBox *ListBox::Allocate() { -  ListBoxImpl *lb = new ListBoxImpl(); -  return lb; +@implementation AutoCompletionDataSource + +- (void)setBox: (ListBoxImpl*)box_ +{ +  box = box_;  } -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 -  // TODO: 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[] = +- (void) doubleClick: (id) sender +{ +  if (box)    { -    { kEventClassMouse, kEventMouseDown }, -    { kEventClassMouse, kEventMouseMoved }, -  }; -   */ -   -  eventHandler = NULL; -  //InstallWindowEventHandler( outWindow, WindowEventHandler, -  //               GetEventTypeCount( kWindowEvents ), -  //               kWindowEvents, this, &eventHandler ); -   -  wid = lb; -  //SetControlVisibility(lb, true, true); -  SetControl(lb); -  SetWindow(outWindow); +    box->DoubleClick(); +  }  } -pascal OSStatus ListBoxImpl::WindowEventHandler( -                                                EventHandlerCallRef inCallRef, -                                                EventRef            inEvent, -                                                void*               inUserData ) +- (id)tableView: (NSTableView*)aTableView objectValueForTableColumn: (NSTableColumn*)aTableColumn row: (NSInteger)rowIndex  { -   -  switch (kEventClassMouse /* GetEventClass(inEvent) */) { -    case kEventClassMouse: -      switch (kEventMouseDown /* 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); -         } -         } -         } -         */ -      } -    } +#pragma unused(aTableView) +  if (!box) +    return nil; +  if ([(NSString*)[aTableColumn identifier] isEqualToString: @"icon"]) +  { +    return box->ImageForRow(rowIndex); +  } +  else { +    return box->TextForRow(rowIndex);    } -  return eventNotHandledErr;  } -#ifdef DB_TABLE_ROW_HEIGHT -void ListBoxImpl::SetRowHeight(DataBrowserItemID itemID) +- (void)tableView: (NSTableView*)aTableView setObjectValue: anObject forTableColumn: (NSTableColumn*)aTableColumn row: (NSInteger)rowIndex  { -  // XXX does not seem to have any effect -  //SetDataBrowserTableViewItemRowHeight(lb, itemID, lineHeight); +#pragma unused(aTableView) +#pragma unused(anObject) +#pragma unused(aTableColumn) +#pragma unused(rowIndex)  } -#endif -void ListBoxImpl::DrawRow(DataBrowserItemID item, -                          DataBrowserPropertyID property, -                          DataBrowserItemState itemState, -                          const Rect *theRect) +- (NSInteger)numberOfRowsInTableView: +(NSTableView*)aTableView  { -// ListBox does not work on Cocoa -// Just make compile for now -#if 0 -  Rect row = *theRect; -  row.left = 0; -   -  ColourPair fore; -   -  if (itemState == kDataBrowserItemIsSelected) { -    SInt32        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( 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; -  } -#endif +#pragma unused(aTableView) +  if (!box) +    return 0; +  return box->Rows();  } +@end -pascal void ListBoxDrawItemCallback(ControlRef browser, DataBrowserItemID item, -                                    DataBrowserPropertyID property, -                                    DataBrowserItemState itemState, -                                    const Rect *theRect, SInt16 gdDepth, -                                    Boolean colorDevice) +ListBox* ListBox::Allocate()  { -  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); -   +  ListBoxImpl* lb = new ListBoxImpl(); +  return lb;  } -void ListBoxImpl::ConfigureDataBrowser() +void ListBoxImpl::Create(Window& /*parent*/, int /*ctrlID*/, Scintilla::Point pt, +    int lineHeight_, bool unicodeMode_)  { -  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_) { -// ListBox does not work on Cocoa -// Just make compile for now -#if 0 -  // 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((uintptr_t)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); -#else -    font.Create("Monaco", 0, 10, false, false); -#endif -} +  lineHeight = lineHeight_; +  unicodeMode = unicodeMode_; +  maxWidth = 2000; -void ListBoxImpl::SetAverageCharWidth(int width) { +  NSRect lbRect = NSMakeRect(pt.x,pt.y, 120, lineHeight * desiredVisibleRows); +  NSWindow* winLB = [[NSWindow alloc] initWithContentRect: lbRect +    styleMask: NSBorderlessWindowMask +    backing: NSBackingStoreBuffered +    defer: NO]; +  [winLB setLevel:NSFloatingWindowLevel]; +  [winLB setHasShadow:YES]; +  scroller = [NSScrollView alloc]; +  NSRect scRect = NSMakeRect(0, 0, lbRect.size.width, lbRect.size.height); +  [scroller initWithFrame: scRect]; +  [scroller setHasVerticalScroller:YES]; +  table = [NSTableView alloc]; +  [table initWithFrame: scRect]; +  [table setHeaderView:nil]; +  [scroller setDocumentView: table]; +  colIcon = [[NSTableColumn alloc] initWithIdentifier:@"icon"]; +  [colIcon setWidth: 20]; +  [colIcon setEditable:NO]; +  [colIcon setHidden:YES]; +  NSImageCell* imCell = [[NSImageCell alloc] init]; +  [colIcon setDataCell:imCell]; +  [table addTableColumn:colIcon]; +  colText = [[NSTableColumn alloc] initWithIdentifier:@"name"]; +  [colText setResizingMask:NSTableColumnAutoresizingMask]; +  [colText setEditable:NO]; +  [table addTableColumn:colText]; +  AutoCompletionDataSource* ds = [[AutoCompletionDataSource alloc] init]; +  [ds setBox:this]; +  [table setDataSource: ds]; +  [scroller setAutoresizingMask: NSViewWidthSizable | NSViewHeightSizable]; +  [[winLB contentView] addSubview: scroller]; + +  [table setTarget:ds]; +  [table setDoubleAction:@selector(doubleClick:)]; +  wid = winLB; +} + +void ListBoxImpl::SetFont(Font& font_) +{ +  font.SetID(font_.GetID()); +  // NSCell setFont takes an NSFont* rather than a CTFontRef but they +  // are the same thing toll-free bridged. +  NSFont* pfont = (NSFont*)FontRef(font_); +  [[colText dataCell] setFont: pfont]; +  CGFloat itemHeight = lround([pfont ascender] - [pfont descender]); +  [table setRowHeight:itemHeight]; +} + +void ListBoxImpl::SetAverageCharWidth(int width) +{    aveCharWidth = width;  } -void ListBoxImpl::SetVisibleRows(int rows) { +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. +int ListBoxImpl::GetVisibleRows() const +{    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); -   +PRectangle ListBoxImpl::GetDesiredRect() +{ +  PRectangle rcDesired; +  rcDesired = GetPosition(); + +  // There appears to be an extra pixel above and below the row contents +  int itemHeight = [table rowHeight] + 2; +    int rows = Length();    if ((rows == 0) || (rows > desiredVisibleRows))      rows = desiredVisibleRows; -   -  rcDesired.bottom = itemHeight * rows; + +  rcDesired.bottom = rcDesired.top + 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); +  if (Length() > rows) +  { +    [scroller setHasVerticalScroller:YES]; +    rcDesired.right += [NSScroller scrollerWidth];    } -} +  else +  { +    [scroller setHasVerticalScroller:NO]; +  } +  rcDesired.right += maxIconWidth; +  rcDesired.right += 6; -int ListBoxImpl::IconWidth() { -  return xset.GetWidth() + 2; +  return rcDesired;  } -int ListBoxImpl::CaretFromEdge() { -  return 0; +int ListBoxImpl::CaretFromEdge() +{ +  if ([colIcon isHidden]) +    return 3; +  else +    return 6 + [colIcon width];  } -void ListBoxImpl::Clear() { -  // passing NULL to "items" arg 4 clears the list +void ListBoxImpl::Clear() +{    maxItemWidth = 0; +  maxIconWidth = 0;    ld.Clear(); -  //AddDataBrowserItems (lb, kDataBrowserNoItem, 0, NULL, kDataBrowserItemNoProperty);  } -void ListBoxImpl::Append(char *s, int type) { +void ListBoxImpl::Append(char* s, int type) +{    int count = Length(); -  CFStringRef r = CFStringCreateWithCString(NULL, s, kTextEncodingMacRoman); -  ld.Add(count, type, r); -   +  ld.Add(count, type, s); +    Scintilla::SurfaceImpl surface; -  unsigned int width = surface.WidthText (font, s, strlen (s)); +  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(); +    [colText setWidth: maxItemWidth]; +  } +  ImageMap::iterator it = images.find(type); +  if (it != images.end()) +  { +    NSImage* img = it->second; +    if (img) +    { +      unsigned int widthIcon = img.size.width; +      if (widthIcon > maxIconWidth) +      { +        [colIcon setHidden: NO]; +        maxIconWidth = widthIcon; +        [colIcon setWidth: maxIconWidth]; +      } +    } +  }  } -void ListBoxImpl::SetList(const char* list, char separator, char typesep) { -  // XXX copied from PlatGTK, should be in base class +void ListBoxImpl::SetList(const char* list, char separator, char typesep) +{    Clear();    int count = strlen(list) + 1; -  char *words = new char[count]; -  if (words) { +  char* words = new char[count]; +  if (words) +  {      memcpy(words, list, count); -    char *startword = words; -    char *numword = NULL; +    char* startword = words; +    char* numword = NULL;      int i = 0; -    for (; words[i]; i++) { -      if (words[i] == separator) { +    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) { +      } +      else if (words[i] == typesep) +      {          numword = words + i;        }      } -    if (startword) { +    if (startword) +    {        if (numword)          *numword = '\0';        Append(startword, numword?atoi(numword + 1):-1);      }      delete []words;    } +  [table reloadData];  } -int ListBoxImpl::Length() { -  UInt32 numItems = 0; -  //GetDataBrowserItemCount(lb, kDataBrowserNoItem, false, kDataBrowserItemAnyState, &numItems); -  return (int)numItems; +int ListBoxImpl::Length() +{ +  return ld.Length();  } -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); +void ListBoxImpl::Select(int n) +{ +  [table selectRowIndexes:[NSIndexSet indexSetWithIndex:n] byExtendingSelection:NO]; +  [table scrollRowToVisible:n];  } -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::GetSelection() +{ +  return [table selectedRow];  } -int ListBoxImpl::Find(const char *prefix) { +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] != '\0') && (0 == strncmp(prefix, s, strlen(prefix)))) { +  for (int i = 0; i < count; i++) +  { +    const char* s = ld.GetString(i); +    if (s && (s[0] != '\0') && (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) { +void ListBoxImpl::GetValue(int n, char* value, int len) +{ +  const char* 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'; +  strncpy(value, textString, len); +  value[len - 1] = '\0'; +} + +void ListBoxImpl::RegisterImage(int type, const char* xpm_data) +{ +  XPM xpm(xpm_data); +  xpm.CopyDesiredColours(); +  NSImage* img = ImageFromXPM(&xpm); +  [img retain]; +  ImageMap::iterator it=images.find(type); +  if (it == images.end()) +  { +    images[type] = img; +  } +  else +  { +    [it->second release]; +    it->second = img; +  } +} + +void ListBoxImpl::ClearRegisteredImages() +{ +  for (ImageMap::iterator it=images.begin(); +      it != images.end(); ++it) +  { +    [it->second release]; +    it->second = nil;    } -  delete text; +  images.clear();  } -void ListBoxImpl::Sort() { -  // TODO: Implement this -  fprintf(stderr, "ListBox::Sort\n"); +int ListBoxImpl::Rows() +{ +  return ld.Length();  } -void ListBoxImpl::RegisterImage(int type, const char *xpm_data) { -  xset.Add(type, xpm_data); +NSImage* ListBoxImpl::ImageForRow(int row) +{ +  ImageMap::iterator it = images.find(ld.GetType(row)); +  if (it != images.end()) +  { +    NSImage* img = it->second; +    [img retain]; +    return img; +  } +  else +  { +    return nil; +  } +} + +NSString* ListBoxImpl::TextForRow(int row) +{ +  const char* textString = ld.GetString(row); +  NSString* sTitle; +  if (unicodeMode) +    sTitle = [NSString stringWithUTF8String:textString]; +  else +    sTitle = [NSString stringWithCString:textString encoding:NSWindowsCP1252StringEncoding]; +  return sTitle;  } -void ListBoxImpl::ClearRegisteredImages() { -  xset.Clear(); +void ListBoxImpl::DoubleClick() +{ +  if (doubleClickAction) +  { +    doubleClickAction(doubleClickActionData); +  }  }  //----------------- ScintillaContextMenu ----------------------------------------------------------- | 
