# HG changeset patch # User bsmith@81767d24-ef19-dc11-ae90-00e081727c95 # Date 1620935655 0 # Node ID f9367eb9a6e7db68881b93892bda0c5a740c2649 # Parent bb75e64e613852a8f71fc6373db6367d2c7cd9aa Android: Initial menu support, incomplete but basics functional. diff -r bb75e64e6138 -r f9367eb9a6e7 android/DWindows.kt --- a/android/DWindows.kt Thu May 13 07:43:31 2021 +0000 +++ b/android/DWindows.kt Thu May 13 19:54:15 2021 +0000 @@ -25,11 +25,8 @@ import android.util.Base64 import android.util.Log import android.util.SparseBooleanArray -import android.view.Gravity -import android.view.MotionEvent -import android.view.View +import android.view.* import android.view.View.OnTouchListener -import android.view.ViewGroup import android.view.inputmethod.EditorInfo import android.webkit.WebView import android.webkit.WebViewClient @@ -397,6 +394,48 @@ } } +// On Android we can't pre-create submenus... +// So create our own placeholder classes, and create the actual menus +// on demand when required by Android +class DWMenuItem +{ + var title: String? = null + var menu: DWMenu? = null + var submenu: DWMenu? = null + var checked: Boolean = false + var check: Boolean = false + var menuitem: MenuItem? = null + var submenuitem: SubMenu? = null + var id: Int = 0 +} + +class DWMenu { + var menu: Menu? = null + var children = mutableListOf() + var id: Int = 0 + + fun createMenu(newmenu: Menu?) { + if(menu == null) { + menu = newmenu + } + if(menu != null) { + for (menuitem in children) { + // Submenus on Android can't have submenus, so stop at depth 1 + if (menuitem.submenu != null && menu !is SubMenu) { + if(menuitem.submenuitem == null) { + menuitem.submenuitem = menu?.addSubMenu(0, menuitem.id, 0, menuitem.title) + } + menuitem.submenu!!.createMenu(menuitem.submenuitem) + } else if(menuitem.submenu == null) { + if(menuitem.menuitem == null) { + menuitem.menuitem = menu?.add(0, menuitem.id, 0, menuitem.title) + } + } + } + } + } +} + class DWindows : AppCompatActivity() { var firstWindow: Boolean = true var windowLayout: LinearLayout? = null @@ -405,6 +444,7 @@ var notificationID: Int = 0 private var paint = Paint() private var bgcolor: Int = 0 + private var menuBar: DWMenu? = null // Our version of runOnUiThread that waits for execution fun waitOnUiThread(runnable: Runnable) @@ -459,6 +499,57 @@ } } + override fun onCreateOptionsMenu(menu: Menu?): Boolean { + if(menuBar == null) { + menuBar = DWMenu() + menuBar!!.menu = menu + } + return super.onCreateOptionsMenu(menu) + } + + override fun onPrepareOptionsMenu(menu: Menu?): Boolean { + if(menuBar != null) { + menuBar!!.createMenu(menu) + } else { + menuBar = DWMenu() + menuBar!!.createMenu(menu) + } + return super.onPrepareOptionsMenu(menu) + } + + fun menuBarNew(location: View): DWMenu? + { + // TODO: Make sure location is this activity + return menuBar + } + + fun menuNew(cid: Int): DWMenu + { + val menu = DWMenu() + menu.id = cid + return menu + } + + fun menuAppendItem(menu: DWMenu, title: String, cid: Int, flags: Int, end: Int, check: Int, submenu: DWMenu?): DWMenuItem + { + val menuitem = DWMenuItem() + menuitem.id = cid + menuitem.title = title + menuitem.check = check != 0 + if(submenu != null) { + menuitem.submenu = submenu + } + if((flags and (1 shl 2)) != 0) { + menuitem.checked = true + } + if(end == 0) { + menu.children.add(0, menuitem) + } else { + menu.children.add(menuitem) + } + return menuitem + } + /* * These are the Android calls to actually create the UI... * forwarded from the C Dynamic Windows API @@ -2278,6 +2369,14 @@ return Build.VERSION.SDK_INT } + fun dwMain() + { + runOnUiThread { + // Trigger the options menu to update when dw_main() is called + invalidateOptionsMenu() + } + } + fun androidGetRelease(): String { return Build.VERSION.RELEASE diff -r bb75e64e6138 -r f9367eb9a6e7 android/dw.cpp --- a/android/dw.cpp Thu May 13 07:43:31 2021 +0000 +++ b/android/dw.cpp Thu May 13 19:54:15 2021 +0000 @@ -585,6 +585,19 @@ */ void API dw_main(void) { + JNIEnv *env; + + if((env = (JNIEnv *)pthread_getspecific(_dw_env_key))) + { + // First get the class that contains the method you need to call + jclass clazz = _dw_find_class(env, DW_CLASS_NAME); + // Get the method that you want to call + jmethodID dwMain = env->GetMethodID(clazz, "dwMain", + "()V"); + // Call the method on the object + env->CallVoidMethod(_dw_obj, dwMain); + } + /* We don't actually run a loop here, * we launched a new thread to run the loop there. * Just wait for dw_main_quit() on the DWMainEvent. @@ -3896,6 +3909,19 @@ */ HMENUI API dw_menu_new(ULONG cid) { + JNIEnv *env; + + if((env = (JNIEnv *)pthread_getspecific(_dw_env_key))) + { + // First get the class that contains the method you need to call + jclass clazz = _dw_find_class(env, DW_CLASS_NAME); + // Get the method that you want to call + jmethodID menuNew = env->GetMethodID(clazz, "menuNew", + "(I)Lorg/dbsoft/dwindows/DWMenu;"); + // Call the method on the object + jobject result = env->NewWeakGlobalRef(env->CallObjectMethod(_dw_obj, menuNew, (int)cid)); + return result; + } return nullptr; } @@ -3908,6 +3934,19 @@ */ HMENUI API dw_menubar_new(HWND location) { + JNIEnv *env; + + if((env = (JNIEnv *)pthread_getspecific(_dw_env_key))) + { + // First get the class that contains the method you need to call + jclass clazz = _dw_find_class(env, DW_CLASS_NAME); + // Get the method that you want to call + jmethodID menuBarNew = env->GetMethodID(clazz, "menuBarNew", + "(Landroid/view/View;)Lorg/dbsoft/dwindows/DWMenu;"); + // Call the method on the object + jobject result = env->NewWeakGlobalRef(env->CallObjectMethod(_dw_obj, menuBarNew, location)); + return result; + } return nullptr; } @@ -3960,6 +3999,21 @@ */ HWND API dw_menu_append_item(HMENUI menux, const char *title, ULONG itemid, ULONG flags, int end, int check, HMENUI submenux) { + JNIEnv *env; + + if((env = (JNIEnv *)pthread_getspecific(_dw_env_key))) + { + // Create a string + jstring jstr = env->NewStringUTF(title); + // First get the class that contains the method you need to call + jclass clazz = _dw_find_class(env, DW_CLASS_NAME); + // Get the method that you want to call + jmethodID menuAppendItem = env->GetMethodID(clazz, "menuAppendItem", + "(Lorg/dbsoft/dwindows/DWMenu;Ljava/lang/String;IIIILorg/dbsoft/dwindows/DWMenu;)Lorg/dbsoft/dwindows/DWMenuItem;"); + // Call the method on the object + jobject result = env->NewWeakGlobalRef(env->CallObjectMethod(_dw_obj, menuAppendItem, menux, jstr, (int)itemid, (int)flags, end, check, submenux)); + return result; + } return nullptr; } @@ -4803,8 +4857,7 @@ if((env = (JNIEnv *)pthread_getspecific(_dw_env_key))) { // First get the class that contains the method you need to call - //jclass clazz = _dw_find_class(env, DW_CLASS_NAME); - jclass clazz = env->FindClass(DW_CLASS_NAME); + jclass clazz = _dw_find_class(env, DW_CLASS_NAME); // Get the method that you want to call jmethodID androidGetRelease = env->GetMethodID(clazz, "androidGetRelease", "()Ljava/lang/String;");