PopupWindow: implement more stuff, mainly offset

This commit is contained in:
Mis012 2025-03-26 20:18:16 +01:00
parent 5c29d2d297
commit 340fae107e
3 changed files with 177 additions and 32 deletions

View file

@ -39,6 +39,22 @@ JNIEXPORT void JNICALL Java_android_widget_PopupWindow_native_1showAsDropDown
JNIEXPORT jboolean JNICALL Java_android_widget_PopupWindow_native_1isShowing
(JNIEnv *, jobject, jlong);
/*
* Class: android_widget_PopupWindow
* Method: native_setTouchable
* Signature: (JZ)V
*/
JNIEXPORT void JNICALL Java_android_widget_PopupWindow_native_1setTouchable
(JNIEnv *, jobject, jlong, jboolean);
/*
* Class: android_widget_PopupWindow
* Method: native_setTouchModal
* Signature: (JZ)V
*/
JNIEXPORT void JNICALL Java_android_widget_PopupWindow_native_1setTouchModal
(JNIEnv *, jobject, jlong, jboolean);
/*
* Class: android_widget_PopupWindow
* Method: native_dismiss
@ -65,19 +81,43 @@ JNIEXPORT void JNICALL Java_android_widget_PopupWindow_setOnDismissListener
/*
* Class: android_widget_PopupWindow
* Method: setWidth
* Signature: (I)V
* Method: native_setWidth
* Signature: (JI)V
*/
JNIEXPORT void JNICALL Java_android_widget_PopupWindow_setWidth
(JNIEnv *, jobject, jint);
JNIEXPORT void JNICALL Java_android_widget_PopupWindow_native_1setWidth
(JNIEnv *, jobject, jlong, jint);
/*
* Class: android_widget_PopupWindow
* Method: setHeight
* Signature: (I)V
* Method: native_setHeight
* Signature: (JI)V
*/
JNIEXPORT void JNICALL Java_android_widget_PopupWindow_setHeight
(JNIEnv *, jobject, jint);
JNIEXPORT void JNICALL Java_android_widget_PopupWindow_native_1setHeight
(JNIEnv *, jobject, jlong, jint);
/*
* Class: android_widget_PopupWindow
* Method: native_getWidth
* Signature: (J)I
*/
JNIEXPORT jint JNICALL Java_android_widget_PopupWindow_native_1getWidth
(JNIEnv *, jobject, jlong);
/*
* Class: android_widget_PopupWindow
* Method: native_getHeight
* Signature: (J)I
*/
JNIEXPORT jint JNICALL Java_android_widget_PopupWindow_native_1getHeight
(JNIEnv *, jobject, jlong);
/*
* Class: android_widget_PopupWindow
* Method: native_isTouchable
* Signature: (J)Z
*/
JNIEXPORT jboolean JNICALL Java_android_widget_PopupWindow_native_1isTouchable
(JNIEnv *, jobject, jlong);
#ifdef __cplusplus
}

View file

@ -11,6 +11,8 @@ JNIEXPORT jlong JNICALL Java_android_widget_PopupWindow_native_1constructor(JNIE
{
GtkWidget *popover = gtk_popover_new();
gtk_widget_set_name(popover, "PopupWindow");
/* autohiding works by the widget grabbing events, which is not something apps expect */
gtk_popover_set_autohide(GTK_POPOVER(popover), false);
return _INTPTR(popover);
}
@ -20,32 +22,76 @@ JNIEXPORT void JNICALL Java_android_widget_PopupWindow_native_1setContentView(JN
gtk_popover_set_child(GTK_POPOVER(_PTR(popover_ptr)), GTK_WIDGET(content));
}
static inline void set_offset(GtkPopover *popover, GtkWidget *anchor, int x, int y)
{
/* FIXME: assumes GTK_POS_BOTTOM */
gtk_popover_set_offset(popover, x - gtk_widget_get_width(anchor) / 2, y - gtk_widget_get_height(anchor));
}
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);
set_offset(popover, GTK_WIDGET(anchor), x, y);
gtk_popover_present(GTK_POPOVER(popover));
gtk_popover_popup(popover);
}
JNIEXPORT void JNICALL Java_android_widget_PopupWindow_setWidth(JNIEnv *env, jobject this, jint width)
JNIEXPORT void JNICALL Java_android_widget_PopupWindow_native_1setWidth(JNIEnv *env, jobject this, jlong popover_ptr, jint width)
{
int height;
GtkWidget *popover = GTK_WIDGET(_PTR(_GET_LONG_FIELD(this, "popover")));
GtkWidget *popover = GTK_WIDGET(_PTR(popover_ptr));
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)
JNIEXPORT void JNICALL Java_android_widget_PopupWindow_native_1setHeight(JNIEnv *env, jobject this, jlong popover_ptr, jint height)
{
int width;
GtkWidget *popover = GTK_WIDGET(_PTR(_GET_LONG_FIELD(this, "popover")));
GtkWidget *popover = GTK_WIDGET(_PTR(popover_ptr));
gtk_widget_get_size_request(popover, &width, NULL);
gtk_widget_set_size_request(popover, width, height);
}
JNIEXPORT jint JNICALL Java_android_widget_PopupWindow_native_1getWidth(JNIEnv *env, jobject this, jlong popover_ptr)
{
GtkWidget *popover = GTK_WIDGET(_PTR(popover_ptr));
GtkRequisition natural_size;
gtk_widget_get_preferred_size(popover, &natural_size, NULL);
return natural_size.width;
}
JNIEXPORT jint JNICALL Java_android_widget_PopupWindow_native_1getHeight(JNIEnv *env, jobject this, jlong popover_ptr)
{
GtkWidget *popover = GTK_WIDGET(_PTR(popover_ptr));
GtkRequisition natural_size;
gtk_widget_get_preferred_size(popover, &natural_size, NULL);
return natural_size.height;
}
JNIEXPORT void JNICALL Java_android_widget_PopupWindow_native_1setTouchable(JNIEnv *env, jobject this, jlong popover_ptr, jboolean touchable)
{
GtkWidget *popover = GTK_WIDGET(_PTR(popover_ptr));
gtk_widget_set_sensitive(popover, touchable);
}
JNIEXPORT jboolean JNICALL Java_android_widget_PopupWindow_native_1isTouchable(JNIEnv *env, jobject this, jlong popover_ptr)
{
GtkWidget *popover = GTK_WIDGET(_PTR(popover_ptr));
return gtk_widget_is_sensitive(popover);
}
JNIEXPORT void JNICALL Java_android_widget_PopupWindow_native_1setTouchModal(JNIEnv *env, jobject this, jlong popover_ptr, jboolean touch_modal)
{
GtkPopover *popover = GTK_POPOVER(_PTR(popover_ptr));
/* FIXME: we should only add grab (not autohide), however we need to remove it again in umap;
* GtkPopover is not final, so we should subclass it and check whether it's modal in map/unmap
* to add/remove grab, which is the desired part of what GtkPopover does with autohide enabled */
gtk_popover_set_autohide(popover, touch_modal);
}
static void on_closed_cb(GtkPopover *popover, jobject listener)
{
JNIEnv *env = get_jni_env();
@ -74,6 +120,7 @@ JNIEXPORT void JNICALL Java_android_widget_PopupWindow_native_1update(JNIEnv *en
GtkPopover *popover = GTK_POPOVER(_PTR(popover_ptr));
WrapperWidget *anchor = WRAPPER_WIDGET(gtk_widget_get_parent(GTK_WIDGET(_PTR(anchor_ptr))));
gtk_widget_set_size_request(GTK_WIDGET(popover), width, height);
set_offset(popover, GTK_WIDGET(anchor), x, y);
gtk_widget_insert_before(GTK_WIDGET(popover), GTK_WIDGET(anchor), NULL);
gtk_popover_present(GTK_POPOVER(popover));
gtk_popover_popup(popover);

View file

@ -10,6 +10,8 @@ import android.view.View;
public class PopupWindow {
int input_method_mode = 0;
public PopupWindow(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
popover = native_constructor();
}
@ -41,23 +43,25 @@ public class PopupWindow {
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);
protected native boolean native_isShowing(long widget);
protected native void native_dismiss(long widget);
protected native void native_update(long widget, long anchor, int xoff, int yoff, int width, int height);
public void setBackgroundDrawable(Drawable background) {
/* FIXME: use a decorview? */
if(contentView != null) {
contentView.setBackgroundDrawable(background);
}
}
public void setBackgroundDrawable(Drawable background) {}
public void setInputMethodMode(int mode) {
input_method_mode = mode;
}
public void setInputMethodMode(int mode) {}
public int getInputMethodMode() {
return input_method_mode;
}
public boolean isShowing() {
return native_isShowing(popover);
}
public native void setOnDismissListener(OnDismissListener listener);
public void setFocusable(boolean focusable) {}
public Drawable getBackground() {return null;}
@ -70,17 +74,16 @@ public class PopupWindow {
native_setContentView(popover, view == null ? 0 : view.widget);
}
public int getInputMethodMode() {return 0;}
public int getMaxAvailableHeight(View anchor, int yOffset) {return 500;}
public int getMaxAvailableHeight(View anchor, int yOffset, boolean ignoreKeyboard) {return 500;}
public native void setWidth(int width);
public native void setHeight(int height);
public void setOutsideTouchable(boolean touchable) {}
public void setOutsideTouchable(boolean touchable) {
/* FIXME: the semantics are different, this seems to specifically exist for cases
* where the popup is *not* modal, so that in addition to the window behind getting
* the real event, the popup gets a special MotionEvent.ACTION_OUTSIDE event */
native_setTouchModal(popover, touchable);
}
public void setTouchInterceptor(View.OnTouchListener listener) {}
@ -88,9 +91,13 @@ public class PopupWindow {
native_showAsDropDown(popover, anchor.widget, xoff, yoff, gravity);
}
public View getContentView() {return contentView;}
public View getContentView() {
return contentView;
}
public void setTouchable(boolean touchable) {}
public void setTouchable(boolean touchable) {
native_setTouchable(popover, touchable);
}
public void showAsDropDown(View anchor, int xoff, int yoff) {
if (!anchor.isAttachedToWindow()) {
@ -110,7 +117,9 @@ public class PopupWindow {
public void setAnimationStyle(int animationStyle) {}
public void setTouchModal(boolean touchModal) {}
public void setTouchModal(boolean touchModal) {
native_setTouchModal(popover, touchModal);
}
public void setElevation(float elevation) {}
@ -123,4 +132,53 @@ public class PopupWindow {
public void setIsClippedToScreen(boolean isClippedToScreen) {}
public void setEpicenterBounds(Rect bounds) {}
public void setClippingEnabled(boolean enabled) {}
/* TODO: handle LayoutParams.WRAP_CONTENT and LayoutParams.MATCH_PARENT */
public void setWidth(int width) {
if(width < 0)
return;
native_setWidth(popover, width);
}
public void setHeight(int height) {
if(height < 0)
return;
native_setHeight(popover, height);
}
public int getWidth() {
return native_getWidth(popover);
}
public int getHeight() {
return native_getHeight(popover);
}
public void update(int x, int y, int width, int height) {}
public void setWindowLayoutMode(int widthSpec, int heightSpec) {}
public boolean isTouchable() {
return native_isTouchable(popover);
}
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);
protected native boolean native_isShowing(long widget);
protected native void native_setTouchable(long widget, boolean touchable);
protected native void native_setTouchModal(long widget, boolean touchable);
protected native void native_dismiss(long widget);
protected native void native_update(long widget, long anchor, int xoff, int yoff, int width, int height);
public native void setOnDismissListener(OnDismissListener listener);
public native void native_setWidth(long widget, int width);
public native void native_setHeight(long widget, int height);
public native int native_getWidth(long widget);
public native int native_getHeight(long widget);
public native boolean native_isTouchable(long widget);
}