From 59b95105a1e71ad6b62a1970e88a0390850e5bfe Mon Sep 17 00:00:00 2001 From: nyamatongwe Date: Wed, 18 Sep 2013 10:40:53 +1000 Subject: 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. --- cocoa/ScintillaCocoa.h | 4 ++ cocoa/ScintillaCocoa.mm | 34 ++++++++++-- cocoa/ScintillaView.h | 7 ++- cocoa/ScintillaView.mm | 140 +++++++++++++++++++++++------------------------- 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 delegate; + bool delegateHasCommand; + SciNotifyFunc notifyProc; intptr_t notifyObj; @@ -123,6 +126,7 @@ public: ScintillaCocoa(InnerView* view, MarginView* viewMargin); virtual ~ScintillaCocoa(); + void SetDelegate(id 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; @@ -1651,6 +1653,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 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 +@interface ScintillaView : NSView { @private // The back end is kind of a controller and model in one. @@ -126,6 +128,8 @@ extern NSString *const SCIUpdateUINotification; - (void) setCallback: (id ) 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 *) 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(lParam); - ScintillaCocoa *psc = reinterpret_cast(scn->nmhdr.hwndFrom); - editor = reinterpret_cast(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(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 @@

Scintilla Documentation

-

Last edited 7 September 2013 NH

+

Last edited 18 September 2013 NH

There is an overview of the internal design of Scintilla.
@@ -6437,7 +6437,12 @@ implemented and thus which methods may be called.

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 - WM_NOTIFY message on Windows and the "notify" signal on GTK+. The container is + WM_NOTIFY message on Windows and the "notify" signal on GTK+. + On Cocoa, a delegate implementing the ScintillaNotificationProtocol + may be set to receive notifications or the ScintillaView class may be subclassed and the + notification: method overridden. Overriding notification: allows the + subclass to control whether default handling is performed. + The container is passed a SCNotification structure containing information about the event.

 struct NotifyHeader {   // This matches the Win32 NMHDR structure
@@ -6523,7 +6528,10 @@ struct SCNotification {
     
 
     

The following additional notifications are sent using the WM_COMMAND 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 + ScintillaNotificationProtocol with a command:idFrom: 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.

SCEN_CHANGE
SCEN_SETFOCUS
-- cgit v1.2.3