فهرست منبع

Merge pull request #68 from bmx-ng/task/event-callbacks

Added support for event callbacks.
Brucey 3 ماه پیش
والد
کامیت
1baef7a017

+ 6 - 0
sdlgraphics.mod/sdlgraphics.bmx

@@ -289,6 +289,12 @@ Type TSDLGraphicsDriver Extends TGraphicsDriver
 		End If
 	End Method
 
+	Method GetSDLWindow:TSDLWindow()
+		If _currentContext Then
+			Return _currentContext.window
+		End If
+	End Method
+
 End Type
 
 Rem

+ 1 - 0
sdlrender.mod/common.bmx

@@ -67,6 +67,7 @@ Extern
 	Function SDL_DestroyRenderer(handle:Byte Ptr)
 	Function SDL_CreateTexture:Byte Ptr(handle:Byte Ptr, format:UInt, access:Int, width:Int, height:Int)
 	Function SDL_CreateTextureFromSurface:Byte Ptr(handle:Byte Ptr, surface:Byte Ptr)
+	Function SDL_RenderGetWindow:Byte Ptr(handle:Byte Ptr)
 	Function SDL_RenderClear:Int(handle:Byte Ptr)
 	Function SDL_RenderDrawLine:Int(handle:Byte Ptr, x1:Int, y1:Int, x2:Int, y2:Int)
 	Function SDL_RenderDrawLines:Int(handle:Byte Ptr, points:Int Ptr, count:Int)

+ 7 - 0
sdlrender.mod/sdlrender.bmx

@@ -71,6 +71,13 @@ Type TSDLRenderer
 	Function GetRenderer:TSDLRenderer(window:TSDLWindow)
 		Return _create(SDL_GetRenderer(window.windowPtr))
 	End Function
+
+	Rem
+	bbdoc: Get the window associated with the renderer.
+	End Rem
+	Method GetWindow:TSDLWindow()
+		Return TSDLWindow._create(SDL_RenderGetWindow(rendererPtr))
+	End Method
 	
 	Rem
 	bbdoc: Creates a texture for a rendering context.

+ 8 - 0
sdlrendermax2d.mod/sdlrendermax2d.bmx

@@ -192,6 +192,14 @@ Type TSDLRenderMax2DDriver Extends TMax2DDriver
 		t.MakeCurrent
 	End Method
 
+	Method GetWindow:TSDLWindow()
+		Return SDLGraphicsDriver().GetSDLWindow()
+	End Method
+
+	Method GetRenderer:TSDLRenderer()
+		Return renderer
+	End Method
+
 	Method Flip:Int( sync:Int ) Override
 		renderer.Present()
 	End Method

+ 1 - 1
sdlsurface.mod/sdlsurface.bmx

@@ -37,7 +37,7 @@ Type TSDLSurface
 
 	Field surfacePtr:Byte Ptr
 	
-	Function _create:TSDLSurface(surfacePtr:Byte Ptr)
+	Function _create:TSDLSurface(surfacePtr:Byte Ptr) { nomangle }
 		If surfacePtr Then
 			Local this:TSDLSurface = New TSDLSurface
 			this.surfacePtr = surfacePtr

+ 99 - 3
sdlsystem.mod/glue.c

@@ -69,7 +69,7 @@ int bmx_SDL_GetDisplayhertz(int display) {
 	return mode.refresh_rate;
 }
 
-void bmx_SDL_EmitSDLEvent( SDL_Event *event, BBObject *source ) {
+static void bmx_SDL_EmitSDLEvent( SDL_Event *event, BBObject *source ) {
 	int data = 0;
 	int mods = 0;
 	int i = 0;
@@ -225,17 +225,113 @@ void bmx_SDL_EmitSDLEvent( SDL_Event *event, BBObject *source ) {
 	
 }
 
+typedef void (*EventCallback)(void * userdata, SDL_Event *event, int *ignoreKeyboard, int *ignoreMouse);
+
+typedef struct EventCallbackNode {
+    EventCallback              cb;
+	void * userdata;
+	int priority;
+    struct EventCallbackNode  *next;
+} EventCallbackNode;
+
+static EventCallbackNode *bmx_eventCallbacks = NULL;
+
+void bmx_SDL_AddEventCallback(EventCallback callback, void *userdata, int priority) {
+    EventCallbackNode *node = malloc(sizeof(EventCallbackNode));
+    node->cb       = callback;
+    node->userdata = userdata;
+    node->priority = priority;
+
+    // empty list or higher than head?
+    if (!bmx_eventCallbacks || priority > bmx_eventCallbacks->priority) {
+        node->next = bmx_eventCallbacks;
+        bmx_eventCallbacks = node;
+    }
+    else {
+        // find the insertion point
+        EventCallbackNode *cur = bmx_eventCallbacks;
+        while (cur->next && cur->next->priority >= priority) {
+            cur = cur->next;
+        }
+        node->next = cur->next;
+        cur->next = node;
+    }
+}
+
+void bmx_SDL_RemoveEventCallback(EventCallback callback) {
+    EventCallbackNode **walk = &bmx_eventCallbacks;
+    while (*walk) {
+        if ((*walk)->cb == callback) {
+            EventCallbackNode *toFree = *walk;
+            *walk = toFree->next;
+            free(toFree);
+            return;    // stop after first match
+        }
+        walk = &((*walk)->next);
+    }
+}
+
+static int isKeyboardEvent(const SDL_Event *event) {
+    return event->type == SDL_KEYDOWN
+        || event->type == SDL_KEYUP
+        || event->type == SDL_TEXTINPUT
+        || event->type == SDL_TEXTEDITING;
+}
+
+static int isMouseEvent(const SDL_Event *event) {
+    return event->type == SDL_MOUSEBUTTONDOWN
+        || event->type == SDL_MOUSEBUTTONUP
+        || event->type == SDL_MOUSEMOTION
+        || event->type == SDL_MOUSEWHEEL
+		|| event->type == SDL_FINGERMOTION
+		|| event->type == SDL_FINGERDOWN
+		|| event->type == SDL_FINGERUP;
+}
+
+static void bmx_SDL_handleEvent(SDL_Event * event) {
+	if (bmx_eventCallbacks) {
+		int eatKeyboard = 0;
+		int eatMouse    = 0;
+
+		int keyboardEvent = isKeyboardEvent(event);
+		int mouseEvent = isMouseEvent(event);
+
+		for (EventCallbackNode *n = bmx_eventCallbacks; n; n = n->next) {
+			// if already eaten, skip this handler
+			if (eatKeyboard && keyboardEvent) continue;
+			if (eatMouse && mouseEvent) continue;
+
+			int callbackAteKeyboard = 0;
+			int callbackAteMouse = 0;
+			n->cb(n->userdata, event, &callbackAteKeyboard, &callbackAteMouse);
+
+			// once any handler “eats” a keyboard/mouse event,
+			// lower-priority ones will be skipped above
+			if (callbackAteKeyboard) eatKeyboard = 1;
+			if (callbackAteMouse) eatMouse = 1;
+		}
+
+		if ((keyboardEvent && eatKeyboard) || (mouseEvent && eatMouse)) {
+			return; // event has been handled, no need to emit
+		}
+
+		bmx_SDL_EmitSDLEvent(event, &bbNullObject);
+	} else {
+		bmx_SDL_EmitSDLEvent(event, &bbNullObject);
+	}
+}
+
 void bmx_SDL_Poll() {
 	SDL_Event event;
 	while (SDL_PollEvent(&event)) {
-		bmx_SDL_EmitSDLEvent(&event, &bbNullObject);
+		bmx_SDL_handleEvent(&event);
 	}
 }
 
 void bmx_SDL_WaitEvent() {
 	SDL_Event event;
 	if (SDL_WaitEvent(&event)) {
-		bmx_SDL_EmitSDLEvent(&event, &bbNullObject);
+		bmx_SDL_handleEvent(&event);
 	}
 }