You've already forked android_translation_layer
mirror of
https://gitlab.com/android_translation_layer/android_translation_layer.git
synced 2025-10-27 11:48:10 -07:00
add support for ViewGroups with custom onLayout()
A custom GtkLayoutManager is set to these objects, which calls into the java handlers when measure or layout is requested. Androids onMeasure method is quite different from GTKs measure method, because Android already defines the final size during onMeasure. Therefore, we call onMeasure from GTKs allocate callback instead of the measure callback.
This commit is contained in:
@@ -196,3 +196,44 @@ JNIEXPORT void JNICALL Java_android_view_View_native_1destructor(JNIEnv *env, jo
|
||||
{
|
||||
g_object_unref(gtk_widget_get_parent(_PTR(widget_ptr)));
|
||||
}
|
||||
|
||||
#define MEASURE_SPEC_UNSPECIFIED (0 << 30)
|
||||
#define MEASURE_SPEC_EXACTLY (1 << 30)
|
||||
#define MEASURE_SPEC_MASK (0x3 << 30)
|
||||
|
||||
JNIEXPORT void JNICALL Java_android_view_View_native_1measure(JNIEnv *env, jobject this, jlong widget_ptr, jint width_spec, jint height_spec) {
|
||||
int width;
|
||||
int height;
|
||||
int for_size;
|
||||
GtkWidget *widget = gtk_widget_get_parent(GTK_WIDGET(_PTR(widget_ptr)));
|
||||
|
||||
if (((height_spec & MEASURE_SPEC_MASK) == MEASURE_SPEC_EXACTLY) && ((width_spec & MEASURE_SPEC_MASK) == MEASURE_SPEC_EXACTLY)) {
|
||||
width = width_spec & ~MEASURE_SPEC_MASK;
|
||||
height = height_spec & ~MEASURE_SPEC_MASK;
|
||||
} else {
|
||||
for_size = ((height_spec & MEASURE_SPEC_MASK) == MEASURE_SPEC_EXACTLY) ? (height_spec & ~MEASURE_SPEC_MASK) : -1;
|
||||
gtk_widget_measure(widget, GTK_ORIENTATION_HORIZONTAL, for_size, NULL, &width, NULL, NULL);
|
||||
|
||||
for_size = ((width_spec & MEASURE_SPEC_MASK) == MEASURE_SPEC_EXACTLY) ? (width_spec & ~MEASURE_SPEC_MASK) : -1;
|
||||
gtk_widget_measure(widget, GTK_ORIENTATION_VERTICAL, for_size, NULL, &height, NULL, NULL);
|
||||
}
|
||||
(*env)->CallVoidMethod(env, this, handle_cache.view.setMeasuredDimension, width, height);
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL Java_android_view_View_native_1layout(JNIEnv *env, jobject this, jlong widget_ptr, jint l, jint t, jint r, jint b) {
|
||||
GtkWidget *widget = gtk_widget_get_parent(GTK_WIDGET(_PTR(widget_ptr)));
|
||||
|
||||
GtkAllocation allocation = {
|
||||
.x=l,
|
||||
.y=t,
|
||||
.width=r-l,
|
||||
.height=b-t,
|
||||
};
|
||||
gtk_widget_size_allocate(widget, &allocation, -1);
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL Java_android_view_View_native_1requestLayout(JNIEnv *env, jobject this, jlong widget_ptr) {
|
||||
GtkWidget *widget = GTK_WIDGET(_PTR(widget_ptr));
|
||||
|
||||
gtk_widget_queue_resize(widget);
|
||||
}
|
||||
|
||||
@@ -8,6 +8,62 @@
|
||||
#include "../generated_headers/android_view_ViewGroup.h"
|
||||
#include "../generated_headers/android_view_View.h"
|
||||
|
||||
#define MEASURE_SPEC_EXACTLY (1 << 30)
|
||||
|
||||
struct _AndroidLayout {
|
||||
GtkLayoutManager parent_instance;
|
||||
jobject view;
|
||||
};
|
||||
G_DECLARE_FINAL_TYPE(AndroidLayout, android_layout, ATL, ANDROID_LAYOUT, GtkLayoutManager);
|
||||
|
||||
static void android_layout_measure(GtkLayoutManager *layout_manager, GtkWidget *widget, GtkOrientation orientation, int for_size, int *minimum, int *natural, int *minimum_baseline, int *natural_baseline) {
|
||||
AndroidLayout *layout = ATL_ANDROID_LAYOUT(layout_manager);
|
||||
JNIEnv *env = get_jni_env();
|
||||
|
||||
if (orientation == GTK_ORIENTATION_HORIZONTAL) {
|
||||
*minimum = (*env)->CallIntMethod(env, layout->view, handle_cache.view.getSuggestedMinimumWidth);
|
||||
*natural = (*env)->CallIntMethod(env, layout->view, handle_cache.view.getMeasuredWidth);
|
||||
}
|
||||
if (orientation == GTK_ORIENTATION_VERTICAL) {
|
||||
*minimum = (*env)->CallIntMethod(env, layout->view, handle_cache.view.getSuggestedMinimumHeight);
|
||||
*natural = (*env)->CallIntMethod(env, layout->view, handle_cache.view.getMeasuredHeight);
|
||||
}
|
||||
if (*natural < *minimum)
|
||||
*natural = *minimum;
|
||||
|
||||
*minimum_baseline = -1;
|
||||
*natural_baseline = -1;
|
||||
}
|
||||
|
||||
static void android_layout_allocate(GtkLayoutManager *layout_manager, GtkWidget *widget, int width, int height, int baseline) {
|
||||
AndroidLayout *layout = ATL_ANDROID_LAYOUT(layout_manager);
|
||||
JNIEnv *env = get_jni_env();
|
||||
|
||||
(*env)->CallVoidMethod(env, layout->view, handle_cache.view.onMeasure, MEASURE_SPEC_EXACTLY | width, MEASURE_SPEC_EXACTLY | height);
|
||||
if((*env)->ExceptionCheck(env))
|
||||
(*env)->ExceptionDescribe(env);
|
||||
|
||||
(*env)->CallVoidMethod(env, layout->view, handle_cache.view.onLayout, TRUE, 0, 0, width, height);
|
||||
if((*env)->ExceptionCheck(env))
|
||||
(*env)->ExceptionDescribe(env);
|
||||
}
|
||||
|
||||
static void android_layout_class_init(AndroidLayoutClass *klass) {
|
||||
klass->parent_class.measure = android_layout_measure;
|
||||
klass->parent_class.allocate = android_layout_allocate;
|
||||
}
|
||||
|
||||
static void android_layout_init(AndroidLayout *self) {
|
||||
}
|
||||
|
||||
G_DEFINE_TYPE(AndroidLayout, android_layout, GTK_TYPE_LAYOUT_MANAGER)
|
||||
|
||||
static GtkLayoutManager *android_layout_new(jobject view) {
|
||||
AndroidLayout *layout = g_object_new(android_layout_get_type(), NULL);
|
||||
layout->view = view;
|
||||
return &layout->parent_instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Should be overwritten by ViewGroup subclasses.
|
||||
* Fall back to vertical GtkBox if subclass is not implemented yet
|
||||
@@ -17,7 +73,17 @@ JNIEXPORT jlong JNICALL Java_android_view_ViewGroup_native_1constructor(JNIEnv *
|
||||
GtkWidget *wrapper = g_object_ref(wrapper_widget_new());
|
||||
GtkWidget *box = gtk_box_new(GTK_ORIENTATION_VERTICAL, 1); // spacing of 1
|
||||
wrapper_widget_set_child(WRAPPER_WIDGET(wrapper), box);
|
||||
gtk_widget_set_name(GTK_WIDGET(box), "ViewGroup");
|
||||
|
||||
const char *name = _CSTRING((*env)->CallObjectMethod(env, _CLASS(this),
|
||||
_METHOD((*env)->FindClass(env, "java/lang/Class"), "getName", "()Ljava/lang/String;")));
|
||||
gtk_widget_set_name(box, name);
|
||||
|
||||
jmethodID measure_method = _METHOD(_CLASS(this), "onMeasure", "(II)V");
|
||||
jmethodID layout_method = _METHOD(_CLASS(this), "onLayout", "(ZIIII)V");
|
||||
if (measure_method != handle_cache.view.onMeasure || layout_method != handle_cache.view.onLayout) {
|
||||
gtk_widget_set_layout_manager(box, android_layout_new(_REF(this)));
|
||||
}
|
||||
|
||||
return _INTPTR(box);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user