diff options
| author | nyamatongwe <nyamatongwe@gmail.com> | 2013-09-18 10:40:53 +1000 | 
|---|---|---|
| committer | nyamatongwe <nyamatongwe@gmail.com> | 2013-09-18 10:40:53 +1000 | 
| commit | 59b95105a1e71ad6b62a1970e88a0390850e5bfe (patch) | |
| tree | b2b837ef548ae7550d9e0bafb68ad50dcddd3f3c | |
| parent | c7eca832e818dbaa7180822fdea6f3aabcd83a32 (diff) | |
| download | scintilla-mirror-59b95105a1e71ad6b62a1970e88a0390850e5bfe.tar.gz | |
Reimplement notifications from ScintillaCocoa to ScintillaView as a delegate relationship
using ScintillaNotificationProtocol.
Add optional command:idFrom: method to ScintillaNotificationProtocol for command
notifications.
In a future version registerNotifyCallback: and ScintillaCocoa::RegisterNotifyCallback
will be deprecated.
| -rw-r--r-- | cocoa/ScintillaCocoa.h | 4 | ||||
| -rw-r--r-- | cocoa/ScintillaCocoa.mm | 34 | ||||
| -rw-r--r-- | cocoa/ScintillaView.h | 7 | ||||
| -rw-r--r-- | cocoa/ScintillaView.mm | 140 | ||||
| -rw-r--r-- | doc/ScintillaDoc.html | 14 | 
5 files changed, 119 insertions, 80 deletions
| diff --git a/cocoa/ScintillaCocoa.h b/cocoa/ScintillaCocoa.h index 4842e2098..c857fd21a 100644 --- a/cocoa/ScintillaCocoa.h +++ b/cocoa/ScintillaCocoa.h @@ -86,6 +86,9 @@ private:    TimerTarget* timerTarget;    NSEvent* lastMouseEvent; +  id<ScintillaNotificationProtocol> delegate; +  bool delegateHasCommand; +    SciNotifyFunc	notifyProc;    intptr_t notifyObj; @@ -123,6 +126,7 @@ public:    ScintillaCocoa(InnerView* view, MarginView* viewMargin);    virtual ~ScintillaCocoa(); +  void SetDelegate(id<ScintillaNotificationProtocol> delegate_);    void RegisterNotifyCallback(intptr_t windowid, SciNotifyFunc callback);    sptr_t WndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam); diff --git a/cocoa/ScintillaCocoa.mm b/cocoa/ScintillaCocoa.mm index 07f29bd8e..ce1042e9b 100644 --- a/cocoa/ScintillaCocoa.mm +++ b/cocoa/ScintillaCocoa.mm @@ -384,6 +384,8 @@ ScintillaCocoa::ScintillaCocoa(InnerView* view, MarginView* viewMargin)    wMargin = viewMargin;    timerTarget = [[TimerTarget alloc] init: this];    lastMouseEvent = NULL; +  delegate = NULL; +  delegateHasCommand = false;    notifyObj = NULL;    notifyProc = NULL;    capturedMouse = false; @@ -1652,6 +1654,26 @@ void ScintillaCocoa::UpdateForScroll() {  //--------------------------------------------------------------------------------------------------  /** + * Register a delegate that will be called for notifications and commands. + * This provides similar functionality to RegisterNotifyCallback but in an + * Objective C way. + * + * @param delegate_ A pointer to an object that implements ScintillaNotificationProtocol. + */ + +void ScintillaCocoa::SetDelegate(id<ScintillaNotificationProtocol> delegate_) +{ +  delegate = delegate_; +  delegateHasCommand = false; +  if (delegate) +  { +    delegateHasCommand = [(id)delegate respondsToSelector: @selector(command:ctrlID:)]; +  } +} + +//-------------------------------------------------------------------------------------------------- + +/**   * Used to register a callback function for a given window. This is used to emulate the way   * Windows notifies other controls (mainly up in the view hierarchy) about certain events.   * @@ -1673,6 +1695,8 @@ void ScintillaCocoa::NotifyChange()    if (notifyProc != NULL)      notifyProc(notifyObj, WM_COMMAND, Platform::LongFromTwoShorts(GetCtrlID(), SCEN_CHANGE),  	       (uintptr_t) this); +  if (delegateHasCommand) +    [delegate command:SCEN_CHANGE idFrom:GetCtrlID()];  }  //-------------------------------------------------------------------------------------------------- @@ -1682,6 +1706,8 @@ void ScintillaCocoa::NotifyFocus(bool focus)    if (notifyProc != NULL)      notifyProc(notifyObj, WM_COMMAND, Platform::LongFromTwoShorts(GetCtrlID(), (focus ? SCEN_SETFOCUS : SCEN_KILLFOCUS)),  	       (uintptr_t) this); +  if (delegateHasCommand) +    [delegate command:(focus ? SCEN_SETFOCUS : SCEN_KILLFOCUS) idFrom:GetCtrlID()];  }  //-------------------------------------------------------------------------------------------------- @@ -1694,12 +1720,12 @@ void ScintillaCocoa::NotifyFocus(bool focus)   */  void ScintillaCocoa::NotifyParent(SCNotification scn)  {  +  scn.nmhdr.hwndFrom = (void*) this; +  scn.nmhdr.idFrom = GetCtrlID();    if (notifyProc != NULL) -  { -    scn.nmhdr.hwndFrom = (void*) this; -    scn.nmhdr.idFrom = GetCtrlID();      notifyProc(notifyObj, WM_NOTIFY, GetCtrlID(), (uintptr_t) &scn); -  } +  if (delegate) +    [delegate notification:&scn];  }  //-------------------------------------------------------------------------------------------------- diff --git a/cocoa/ScintillaView.h b/cocoa/ScintillaView.h index 02bdfac90..653f111d3 100644 --- a/cocoa/ScintillaView.h +++ b/cocoa/ScintillaView.h @@ -46,6 +46,8 @@ extern NSString *const SCIUpdateUINotification;  @protocol ScintillaNotificationProtocol  - (void)notification: (Scintilla::SCNotification*)notification; +@optional +- (void)command:(int)command idFrom:(int)idFrom;  @end  /** @@ -92,7 +94,7 @@ extern NSString *const SCIUpdateUINotification;  @end -@interface ScintillaView : NSView <InfoBarCommunicator> +@interface ScintillaView : NSView <InfoBarCommunicator, ScintillaNotificationProtocol>  {  @private    // The back end is kind of a controller and model in one. @@ -126,6 +128,8 @@ extern NSString *const SCIUpdateUINotification;  - (void) setCallback: (id <InfoBarCommunicator>) callback;  - (void) suspendDrawing: (BOOL) suspend; +- (void) notification: (Scintilla::SCNotification*) notification; +- (void) command:(int) command idFrom:(int) idFrom;  // Scroller handling  - (void) setMarginWidth: (int) width; @@ -172,6 +176,7 @@ extern NSString *const SCIUpdateUINotification;  - (void) setLexerProperty: (NSString*) name value: (NSString*) value;  - (NSString*) getLexerProperty: (NSString*) name; +// The delegate property should be used instead of registerNotifyCallback which will be deprecated.  - (void) registerNotifyCallback: (intptr_t) windowid value: (Scintilla::SciNotifyFunc) callback;  - (void) setInfoBar: (NSView <InfoBarCommunicator>*) aView top: (BOOL) top; diff --git a/cocoa/ScintillaView.mm b/cocoa/ScintillaView.mm index 9eae83718..ce0123982 100644 --- a/cocoa/ScintillaView.mm +++ b/cocoa/ScintillaView.mm @@ -956,93 +956,89 @@ static NSCursor *cursorFromEnum(Window::Cursor cursor)  //--------------------------------------------------------------------------------------------------  /** - * Notification function used by Scintilla to call us back (e.g. for handling clicks on the  + * Method receives notifications from Scintilla (e.g. for handling clicks on the   * folder margin or changes in the editor).   * A delegate can be set to receive all notifications. If set no handling takes place here, except   * for action pertaining to internal stuff (like the info bar).   */ -static void notification(intptr_t windowid, unsigned int iMessage, uintptr_t wParam, uintptr_t lParam) +- (void) notification: (Scintilla::SCNotification*)scn  { -  // WM_NOTIFY means we got a parent notification with a special notification structure. -  // Here we don't really differentiate between parent and own notifications and handle both. -  ScintillaView* editor; -  switch (iMessage) +  // Parent notification. Details are passed as SCNotification structure. +   +  if (mDelegate != nil) +  { +    [mDelegate notification: scn]; +    if (scn->nmhdr.code != SCN_ZOOM && scn->nmhdr.code != SCN_UPDATEUI) +      return; +  } +   +  switch (scn->nmhdr.code)    { -    case WM_NOTIFY: +    case SCN_MARGINCLICK:      { -      // Parent notification. Details are passed as SCNotification structure. -      SCNotification* scn = reinterpret_cast<SCNotification*>(lParam); -      ScintillaCocoa *psc = reinterpret_cast<ScintillaCocoa*>(scn->nmhdr.hwndFrom); -      editor = reinterpret_cast<InnerView*>(psc->ContentView()).owner; - -      if (editor.delegate != nil) -      { -        [editor.delegate notification: scn]; -        if (scn->nmhdr.code != SCN_ZOOM && scn->nmhdr.code != SCN_UPDATEUI) -          return; -      } -       -      switch (scn->nmhdr.code) +      if (scn->margin == 2)        { -        case SCN_MARGINCLICK: -        { -          if (scn->margin == 2) -          { -            // Click on the folder margin. Toggle the current line if possible. -            long line = [editor getGeneralProperty: SCI_LINEFROMPOSITION parameter: scn->position]; -            [editor setGeneralProperty: SCI_TOGGLEFOLD value: line]; -          } -          break; -          }; -        case SCN_MODIFIED: -        { -          // Decide depending on the modification type what to do. -          // There can be more than one modification carried by one notification. -          if (scn->modificationType & (SC_MOD_INSERTTEXT | SC_MOD_DELETETEXT)) -            [editor sendNotification: NSTextDidChangeNotification]; -          break; -        } -        case SCN_ZOOM: -        { -          // A zoom change happened. Notify info bar if there is one. -          float zoom = [editor getGeneralProperty: SCI_GETZOOM parameter: 0]; -          long fontSize = [editor getGeneralProperty: SCI_STYLEGETSIZE parameter: STYLE_DEFAULT]; -          float factor = (zoom / fontSize) + 1; -          [editor->mInfoBar notify: IBNZoomChanged message: nil location: NSZeroPoint value: factor]; -          break; -        } -        case SCN_UPDATEUI: -        { -          // Triggered whenever changes in the UI state need to be reflected. -          // These can be: caret changes, selection changes etc. -          NSPoint caretPosition = editor->mBackend->GetCaretPosition(); -          [editor->mInfoBar notify: IBNCaretChanged message: nil location: caretPosition value: 0]; -          [editor sendNotification: SCIUpdateUINotification]; -          if (scn->updated & (SC_UPDATE_SELECTION | SC_UPDATE_CONTENT)) -          { -            [editor sendNotification: NSTextViewDidChangeSelectionNotification]; -          } -          break; -      } +	// Click on the folder margin. Toggle the current line if possible. +	long line = [self getGeneralProperty: SCI_LINEFROMPOSITION parameter: scn->position]; +	[self setGeneralProperty: SCI_TOGGLEFOLD value: line];        }        break; +    }; +    case SCN_MODIFIED: +    { +      // Decide depending on the modification type what to do. +      // There can be more than one modification carried by one notification. +      if (scn->modificationType & (SC_MOD_INSERTTEXT | SC_MOD_DELETETEXT)) +	[self sendNotification: NSTextDidChangeNotification]; +      break; +    } +    case SCN_ZOOM: +    { +      // A zoom change happened. Notify info bar if there is one. +      float zoom = [self getGeneralProperty: SCI_GETZOOM parameter: 0]; +      long fontSize = [self getGeneralProperty: SCI_STYLEGETSIZE parameter: STYLE_DEFAULT]; +      float factor = (zoom / fontSize) + 1; +      [mInfoBar notify: IBNZoomChanged message: nil location: NSZeroPoint value: factor]; +      break;      } -    case WM_COMMAND: +    case SCN_UPDATEUI:      { -      // Notifications for the editor itself. -      ScintillaCocoa* backend = reinterpret_cast<ScintillaCocoa*>(lParam); -      editor = backend->TopContainer(); -      switch (wParam >> 16) +      // Triggered whenever changes in the UI state need to be reflected. +      // These can be: caret changes, selection changes etc. +      NSPoint caretPosition = mBackend->GetCaretPosition(); +      [mInfoBar notify: IBNCaretChanged message: nil location: caretPosition value: 0]; +      [self sendNotification: SCIUpdateUINotification]; +      if (scn->updated & (SC_UPDATE_SELECTION | SC_UPDATE_CONTENT))        { -        case SCEN_KILLFOCUS: -          [editor sendNotification: NSTextDidEndEditingNotification]; -          break; -        case SCEN_SETFOCUS: // Nothing to do for now. -          break; +	[self sendNotification: NSTextViewDidChangeSelectionNotification];        }        break;      } -  }; +  } +} + +//-------------------------------------------------------------------------------------------------- + +/** + * Method receives notifications from Scintilla for gaining and losing focus and for changes. + * A delegate can be set to receive all notifications. + */ +- (void) command:(int)command idFrom:(int)idFrom +{ +  if ((mDelegate != nil) && ([(id)mDelegate respondsToSelector:@selector(command:ctrlID:)])) +  { +    [mDelegate command:command idFrom:idFrom]; +  } +   +  // Notifications for the editor itself. +  switch (command) +  { +    case SCEN_KILLFOCUS: +      [self sendNotification: NSTextDidEndEditingNotification]; +      break; +    case SCEN_SETFOCUS: // Nothing to do for now. +      break; +  }  }  //-------------------------------------------------------------------------------------------------- @@ -1084,7 +1080,7 @@ static void notification(intptr_t windowid, unsigned int iMessage, uintptr_t wPa      // Establish a connection from the back end to this container so we can handle situations      // which require our attention. -    mBackend->RegisterNotifyCallback(nil, notification); +    mBackend->SetDelegate(self);      // Setup a special indicator used in the editor to provide visual feedback for       // input composition, depending on language, keyboard etc. diff --git a/doc/ScintillaDoc.html b/doc/ScintillaDoc.html index 137338146..272b0f4e0 100644 --- a/doc/ScintillaDoc.html +++ b/doc/ScintillaDoc.html @@ -82,7 +82,7 @@      <h1>Scintilla Documentation</h1> -    <p>Last edited 7 September 2013 NH</p> +    <p>Last edited 18 September 2013 NH</p>      <p>There is <a class="jump" href="Design.html">an overview of the internal design of      Scintilla</a>.<br /> @@ -6437,7 +6437,12 @@ implemented and thus which methods may be called.</p>      <p>Notifications are sent (fired) from the Scintilla control to its container when an event has      occurred that may interest the container. Notifications are sent using the -    <code>WM_NOTIFY</code> message on Windows and the "notify" signal on GTK+. The container is +    <code>WM_NOTIFY</code> message on Windows and the "notify" signal on GTK+. +    On Cocoa, a delegate implementing the <code>ScintillaNotificationProtocol</code> +    may be set to receive notifications or the <code>ScintillaView</code> class may be subclassed and the +    <code>notification:</code> method overridden. Overriding <code>notification:</code> allows the +    subclass to control whether default handling is performed. +    The container is      passed a <code>SCNotification</code> structure containing information about the event.</p>  <pre id="SCNotification">  struct NotifyHeader {   // This matches the Win32 NMHDR structure @@ -6523,7 +6528,10 @@ struct SCNotification {      </code>      <p>The following additional notifications are sent using the <code>WM_COMMAND</code> message on -    Windows and the "Command" signal on GTK+. This emulates the Windows Edit control. Only the lower +    Windows and the "Command" signal on GTK+. +    On Cocoa, a delegate implementing the +    <code>ScintillaNotificationProtocol</code> with a <code>command:idFrom:</code> method may be set. +    This emulates the Windows Edit control. Only the lower      16 bits of the control's ID is passed in these notifications.</p>      <code><a class="message" href="#SCEN_CHANGE">SCEN_CHANGE</a><br />       <a class="message" href="#SCEN_SETFOCUS">SCEN_SETFOCUS</a><br /> | 
