changeset 2543:f9367eb9a6e7

Android: Initial menu support, incomplete but basics functional.
author bsmith@81767d24-ef19-dc11-ae90-00e081727c95
date Thu, 13 May 2021 19:54:15 +0000
parents bb75e64e6138
children dbfcc0e357d6
files android/DWindows.kt android/dw.cpp
diffstat 2 files changed, 158 insertions(+), 6 deletions(-) [+]
line wrap: on
line diff
--- 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<DWMenuItem>()
+    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
--- 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;");