From 9c684ee9066f55244fed6d3056d9f4e4f01170de Mon Sep 17 00:00:00 2001 From: Julian Winkler Date: Sat, 17 Feb 2024 15:30:44 +0100 Subject: [PATCH] implement PopupWindow using GtkPopover --- meson.build | 1 + .../android_widget_PopupWindow.h | 61 +++++++++++++++++++ .../widgets/android_widget_PopupWindow.c | 60 ++++++++++++++++++ src/api-impl/android/widget/PopupWindow.java | 57 ++++++++++++++++- 4 files changed, 177 insertions(+), 2 deletions(-) create mode 100644 src/api-impl-jni/generated_headers/android_widget_PopupWindow.h create mode 100644 src/api-impl-jni/widgets/android_widget_PopupWindow.c diff --git a/meson.build b/meson.build index 19e5a270..d9872ad0 100644 --- a/meson.build +++ b/meson.build @@ -98,6 +98,7 @@ libtranslationlayer_so = shared_library('translation_layer_main', [ 'src/api-impl-jni/widgets/android_widget_ImageButton.c', 'src/api-impl-jni/widgets/android_widget_ScrollView.c', 'src/api-impl-jni/widgets/android_widget_ImageView.c', + 'src/api-impl-jni/widgets/android_widget_PopupWindow.c', 'src/api-impl-jni/widgets/WrapperWidget.c', 'src/api-impl-jni/widgets/android_widget_TextView.c', 'src/api-impl-jni/widgets/android_widget_Progressbar.c', diff --git a/src/api-impl-jni/generated_headers/android_widget_PopupWindow.h b/src/api-impl-jni/generated_headers/android_widget_PopupWindow.h new file mode 100644 index 00000000..6547e7f8 --- /dev/null +++ b/src/api-impl-jni/generated_headers/android_widget_PopupWindow.h @@ -0,0 +1,61 @@ +/* DO NOT EDIT THIS FILE - it is machine generated */ +#include +/* Header for class android_widget_PopupWindow */ + +#ifndef _Included_android_widget_PopupWindow +#define _Included_android_widget_PopupWindow +#ifdef __cplusplus +extern "C" { +#endif +/* + * Class: android_widget_PopupWindow + * Method: native_constructor + * Signature: ()J + */ +JNIEXPORT jlong JNICALL Java_android_widget_PopupWindow_native_1constructor + (JNIEnv *, jobject); + +/* + * Class: android_widget_PopupWindow + * Method: native_setContentView + * Signature: (JJ)V + */ +JNIEXPORT void JNICALL Java_android_widget_PopupWindow_native_1setContentView + (JNIEnv *, jobject, jlong, jlong); + +/* + * Class: android_widget_PopupWindow + * Method: native_showAsDropDown + * Signature: (JJIII)V + */ +JNIEXPORT void JNICALL Java_android_widget_PopupWindow_native_1showAsDropDown + (JNIEnv *, jobject, jlong, jlong, jint, jint, jint); + +/* + * Class: android_widget_PopupWindow + * Method: setOnDismissListener + * Signature: (Landroid/widget/PopupWindow/OnDismissListener;)V + */ +JNIEXPORT void JNICALL Java_android_widget_PopupWindow_setOnDismissListener + (JNIEnv *, jobject, jobject); + +/* + * Class: android_widget_PopupWindow + * Method: setWidth + * Signature: (I)V + */ +JNIEXPORT void JNICALL Java_android_widget_PopupWindow_setWidth + (JNIEnv *, jobject, jint); + +/* + * Class: android_widget_PopupWindow + * Method: setHeight + * Signature: (I)V + */ +JNIEXPORT void JNICALL Java_android_widget_PopupWindow_setHeight + (JNIEnv *, jobject, jint); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/api-impl-jni/widgets/android_widget_PopupWindow.c b/src/api-impl-jni/widgets/android_widget_PopupWindow.c new file mode 100644 index 00000000..59836eb1 --- /dev/null +++ b/src/api-impl-jni/widgets/android_widget_PopupWindow.c @@ -0,0 +1,60 @@ +#include + +#include "../defines.h" +#include "../util.h" + +#include "WrapperWidget.h" + +#include "../generated_headers/android_widget_PopupWindow.h" + +JNIEXPORT jlong JNICALL Java_android_widget_PopupWindow_native_1constructor(JNIEnv *env, jobject this) +{ + GtkWidget *popover = gtk_popover_new(); + gtk_widget_set_name(popover, "PopupWindow"); + return _INTPTR(popover); +} + +JNIEXPORT void JNICALL Java_android_widget_PopupWindow_native_1setContentView(JNIEnv *env, jobject this, jlong popover_ptr, jlong content_ptr) +{ + WrapperWidget *content = WRAPPER_WIDGET(gtk_widget_get_parent(GTK_WIDGET(_PTR(content_ptr)))); + gtk_popover_set_child(GTK_POPOVER(_PTR(popover_ptr)), GTK_WIDGET(content)); +} + +JNIEXPORT void JNICALL Java_android_widget_PopupWindow_native_1showAsDropDown(JNIEnv *env, jobject this, jlong popover_ptr, jlong anchor_ptr, jint x, jint y, jint gravity) +{ + GtkPopover *popover = GTK_POPOVER(_PTR(popover_ptr)); + WrapperWidget *anchor = WRAPPER_WIDGET(gtk_widget_get_parent(GTK_WIDGET(_PTR(anchor_ptr)))); + + gtk_widget_insert_before(GTK_WIDGET(popover), GTK_WIDGET(anchor), NULL); + gtk_popover_present(GTK_POPOVER(popover)); + gtk_popover_popup(popover); +} + +JNIEXPORT void JNICALL Java_android_widget_PopupWindow_setWidth(JNIEnv *env, jobject this, jint width) +{ + int height; + GtkWidget *popover = GTK_WIDGET(_PTR(_GET_LONG_FIELD(this, "popover"))); + gtk_widget_get_size_request(popover, NULL, &height); + gtk_widget_set_size_request(popover, width, height); +} + +JNIEXPORT void JNICALL Java_android_widget_PopupWindow_setHeight(JNIEnv *env, jobject this, jint height) +{ + int width; + GtkWidget *popover = GTK_WIDGET(_PTR(_GET_LONG_FIELD(this, "popover"))); + gtk_widget_get_size_request(popover, &width, NULL); + gtk_widget_set_size_request(popover, width, height); +} + +static void on_closed_cb(GtkPopover *popover, jobject listener) +{ + JNIEnv *env = get_jni_env(); + jmethodID onDismiss = _METHOD(_CLASS(listener), "onDismiss", "()V"); + (*env)->CallVoidMethod(env, listener, onDismiss); +} + +JNIEXPORT void JNICALL Java_android_widget_PopupWindow_setOnDismissListener(JNIEnv *env, jobject this, jobject listener) +{ + GtkWidget *popover = GTK_WIDGET(_PTR(_GET_LONG_FIELD(this, "popover"))); + g_signal_connect(popover, "closed", G_CALLBACK(on_closed_cb), _REF(listener)); +} diff --git a/src/api-impl/android/widget/PopupWindow.java b/src/api-impl/android/widget/PopupWindow.java index bd9a0364..a0031260 100644 --- a/src/api-impl/android/widget/PopupWindow.java +++ b/src/api-impl/android/widget/PopupWindow.java @@ -1,6 +1,59 @@ package android.widget; +import android.content.Context; +import android.graphics.drawable.Drawable; +import android.util.AttributeSet; +import android.view.View; + public class PopupWindow { - - public interface OnDismissListener {} + + public PopupWindow(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { + popover = native_constructor(); + } + + private View contentView; + private long popover; // native pointer to GtkPopover + + public interface OnDismissListener { + public void onDismiss(); + } + + protected native long native_constructor(); + protected native void native_setContentView(long widget, long contentView); + protected native void native_showAsDropDown(long widget, long anchor, int xoff, int yoff, int gravity); + + public void setBackgroundDrawable(Drawable background) {} + + public void setInputMethodMode(int mode) {} + + public boolean isShowing() {return false;} + + public native void setOnDismissListener(OnDismissListener listener); + + public void setFocusable(boolean focusable) {} + + public Drawable getBackground() {return null;} + + public void setContentView(View view) { + contentView = view; + native_setContentView(popover, view.widget); + } + + public int getInputMethodMode() {return 0;} + + public int getMaxAvailableHeight(View anchor, int yOffset) {return 500;} + + public native void setWidth(int width); + + public native void setHeight(int height); + + public void setOutsideTouchable(boolean touchable) {} + + public void setTouchInterceptor(View.OnTouchListener listener) {} + + public void showAsDropDown(View anchor, int xoff, int yoff, int gravity) { + native_showAsDropDown(popover, anchor.widget, xoff, yoff, gravity); + } + + public View getContentView() {return contentView;} }