diff --git a/src/cpp/include/nodegui/core/Events/eventwidget.h b/src/cpp/include/nodegui/core/Events/eventwidget.h index eedc23807..b6e5935d2 100644 --- a/src/cpp/include/nodegui/core/Events/eventwidget.h +++ b/src/cpp/include/nodegui/core/Events/eventwidget.h @@ -15,7 +15,7 @@ class DLL_EXPORT EventWidget { void subscribeToQtEvent(std::string evtString); void unSubscribeToQtEvent(std::string evtString); - void event(QEvent* event); + bool event(QEvent* event); void connectSignalsToEventEmitter(); diff --git a/src/cpp/include/nodegui/core/Events/eventwidget_macro.h b/src/cpp/include/nodegui/core/Events/eventwidget_macro.h index f28a9acf9..709bbdb0b 100644 --- a/src/cpp/include/nodegui/core/Events/eventwidget_macro.h +++ b/src/cpp/include/nodegui/core/Events/eventwidget_macro.h @@ -52,7 +52,9 @@ #ifndef EVENTWIDGET_IMPLEMENTATIONS #define EVENTWIDGET_IMPLEMENTATIONS(BaseWidgetName) \ bool event(QEvent* event) override { \ - EventWidget::event(event); \ + if (EventWidget::event(event)) { \ + return true; \ + } \ return BaseWidgetName::event(event); \ } diff --git a/src/cpp/lib/core/Events/eventwidget.cpp b/src/cpp/lib/core/Events/eventwidget.cpp index ebffcdf07..ca753af25 100644 --- a/src/cpp/lib/core/Events/eventwidget.cpp +++ b/src/cpp/lib/core/Events/eventwidget.cpp @@ -28,7 +28,7 @@ void EventWidget::unSubscribeToQtEvent(std::string evtString) { } } -void EventWidget::event(QEvent* event) { +bool EventWidget::event(QEvent* event) { if (this->emitOnNode) { try { QEvent::Type evtType = event->type(); @@ -40,11 +40,13 @@ void EventWidget::event(QEvent* event) { std::vector args = {Napi::String::New(env, eventTypeString), nativeEvent}; - this->emitOnNode.Call(args); + Napi::Value returnCode = this->emitOnNode.Call(args); + return returnCode.As().Value(); } catch (...) { // Do nothing } } + return false; } void EventWidget::connectSignalsToEventEmitter() { diff --git a/src/lib/core/EventWidget.ts b/src/lib/core/EventWidget.ts index 711d883a2..fcee11dfb 100644 --- a/src/lib/core/EventWidget.ts +++ b/src/lib/core/EventWidget.ts @@ -35,19 +35,28 @@ view.addEventListener(WidgetEventTypes.MouseMove, () => { */ export abstract class EventWidget extends Component { private emitter: EventEmitter; + private _isEventProcessed = false; constructor(native: NativeElement) { super(); if (native.initNodeEventEmitter) { this.emitter = new EventEmitter(); this.emitter.emit = wrapWithActivateUvLoop(this.emitter.emit.bind(this.emitter)); const logExceptions = (event: string | symbol, ...args: any[]): boolean => { + // Preserve the value of `_isQObjectEventProcessed` as we dispatch this event + // to JS land, and restore it afterwards. This lets us support recursive event + // dispatches on the same object. + const previousEventProcessed = this._isEventProcessed; + this._isEventProcessed = false; try { - return this.emitter.emit(event, ...args); + this.emitter.emit(event, ...args); } catch (e) { console.log(`An exception was thrown while dispatching an event of type '${event.toString()}':`); console.log(e); } - return false; + + const returnCode = this._isEventProcessed; + this._isEventProcessed = previousEventProcessed; + return returnCode; }; native.initNodeEventEmitter(logExceptions); } else { @@ -56,12 +65,41 @@ export abstract class EventWidget extends Component { addDefaultErrorHandler(native, this.emitter); } + /** + * Get the state of the event processed flag + * + * See `setEventProcessed()`. + * + * @returns boolean True if the current event is flagged as processed. + */ + eventProcessed(): boolean { + return this._isEventProcessed; + } + + /** + * Mark the current event as having been processed + * + * This method is used to indicate that the currently dispatched event + * has been processed and no further processing by superclasses is + * required. It only makes sense to call this method from an event + * handler. + * + * When set, this flag will cause NodeGui's `QObject::event()` method to + * return true and not call the superclass `event()`, effectively preventing + * any further processing on this event. + * + * @param isProcessed true if the event has been processed. + */ + setEventProcessed(isProcessed: boolean): void { + this._isEventProcessed = isProcessed; + } + /** * @param signalType SignalType is a signal from the widgets signals interface. @param callback Corresponding callback for the signal as mentioned in the widget's signal interface @returns void - + For example in the case of QPushButton: ```js const button = new QPushButton();