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 /> |