]> git.xonotic.org Git - xonotic/netradiant.git/commitdiff
Initial python support DefaultUser/pybind
authorSebastian Schmidt <schro.sb@gmail.com>
Sat, 15 Dec 2018 18:57:23 +0000 (19:57 +0100)
committerSebastian Schmidt <schro.sb@gmail.com>
Sat, 15 Dec 2018 18:57:23 +0000 (19:57 +0100)
.gitmodules
CMakeLists.txt
libs/CMakeLists.txt
libs/pybind11 [new submodule]
radiant/CMakeLists.txt
radiant/main.cpp
radiant/mainframe.cpp
radiant/pybindconnector.cpp [new file with mode: 0644]
radiant/pybindconnector.h [new file with mode: 0644]
radiant/pythonconsole.cpp [new file with mode: 0644]
radiant/pythonconsole.h [new file with mode: 0644]

index d20f6e35835027edcedd18a4d484cbf4841ded21..7b14d4d89a8ee06db7944812b03958f9e03aafe6 100644 (file)
@@ -1,3 +1,6 @@
 [submodule "libs/crunch"]
        path = libs/crunch
        url = https://github.com/DaemonEngine/crunch.git
+[submodule "libs/pybind11"]
+       path = libs/pybind11
+       url = https://github.com/pybind/pybind11
index e920fd6216c4e3522bedc5814d6d51c012e91015..cb56420e90a9f38a671af482a10d6f0c247ba987 100644 (file)
@@ -4,6 +4,7 @@ project(NetRadiant C CXX)
 
 option(BUILD_RADIANT "Build the GUI" ON)
 option(BUILD_CRUNCH "Build Crunch image support" OFF)
+option(EMBED_PYTHON "Embed python" ON)
 option(USE_WERROR "Build with -Werror -pedantic-errors" OFF)
 
 if (CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT)
@@ -65,7 +66,8 @@ endif ()
 # Flags
 #-----------------------------------------------------------------------
 
-set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-exceptions -fno-rtti")
+# TODO: check why these CXX flags were set
+# set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-exceptions -fno-rtti")
 macro(addflags_c args)
     set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${args}")
 endmacro()
@@ -145,6 +147,9 @@ else ()
             -DPOSIX=1
     )
 endif ()
+if (EMBED_PYTHON)
+    add_definitions(-D_EMBED_PYTHON)
+endif ()
 
 if (XWINDOWS)
     find_package(X11 REQUIRED)
index 633b965f2b1c253fde4858182300040f57c7816f..49227a23b9bc79776d028eff6dfee3176a101c40 100644 (file)
@@ -19,6 +19,9 @@ add_subdirectory(modulesystem)
 add_subdirectory(os)
 add_subdirectory(picomodel)
 add_subdirectory(profile)
+if (EMBED_PYTHON)
+    add_subdirectory(pybind11)
+endif ()
 add_subdirectory(script)
 add_subdirectory(signal)
 add_subdirectory(splines)
diff --git a/libs/pybind11 b/libs/pybind11
new file mode 160000 (submodule)
index 0000000..e2b884c
--- /dev/null
@@ -0,0 +1 @@
+Subproject commit e2b884c33bcde70b2ea562ffa52dd7ebee276d50
index c8672d4962e66af467dd7a8cee8044a1fdfbe3b1..ea809891d347c93a849d12c93d271bb0ddcd1ede 100644 (file)
@@ -93,6 +93,11 @@ set(RADIANTLIST
 if (WIN32)
     list(APPEND RADIANTLIST multimon.cpp multimon.h)
 endif ()
+if (EMBED_PYTHON)
+    list(APPEND RADIANTLIST
+         pybindconnector.cpp pybindconnector.h
+         pythonconsole.cpp pythonconsole.h)
+endif ()
 
 radiant_tool(radiant WIN32 radiant.rc ${RADIANTLIST})
 add_dependencies(radiant modules)
@@ -129,5 +134,8 @@ target_link_libraries(radiant
 if (X11_LIBRARIES)
     target_link_libraries(radiant ${X11_LIBRARIES})
 endif ()
+if (EMBED_PYTHON)
+    target_link_libraries(radiant pybind11::embed)
+endif ()
 
 copy_dlls(radiant)
index 006842a954ecd09f4eb29d9ce373061f082c2390..55205359ad0cbf34f67bc5a474745f8de6f932b7 100644 (file)
 #include <windows.h>
 #endif
 
+#ifdef _EMBED_PYTHON
+#include "pybindconnector.h"
+#endif // _EMBED_PYTHON
+
 void show_splash();
 
 void hide_splash();
@@ -645,6 +649,9 @@ int main(int argc, char *argv[])
         g_GamesDialog.m_bForceLogConsole = false;
     }
 
+#ifdef _EMBED_PYTHON
+    PYBIND_initializeInterpreter();
+#endif // _EMBED_PYTHON
 
     Radiant_Initialise();
 
@@ -690,6 +697,10 @@ int main(int argc, char *argv[])
 
     Radiant_Shutdown();
 
+#ifdef _EMBED_PYTHON
+    PYBIND_finalizeInterpreter();
+#endif // _EMBED_PYTHON
+
     // close the log file if any
     Sys_LogFile(false);
 
index 11fc3784ad2b49874caf4de899880017bffc55bd..c4712aa1ef88fdd5201250fa066df866cbf3c3e1 100644 (file)
@@ -86,6 +86,9 @@
 #include "pluginmenu.h"
 #include "plugintoolbar.h"
 #include "preferences.h"
+#ifdef _EMBED_PYTHON
+    #include "pythonconsole.h"
+#endif // _EMBED_PYTHON
 #include "qe3.h"
 #include "qgl.h"
 #include "select.h"
@@ -1210,6 +1213,15 @@ void Console_ToggleShow()
     GroupDialog_showPage(g_page_console);
 }
 
+#ifdef _EMBED_PYTHON
+ui::Widget g_page_pythonconsole{ui::null};
+
+void PythonConsole_ToggleShow()
+{
+    GroupDialog_showPage(g_page_pythonconsole);
+}
+#endif // _EMBED_PYTHON
+
 ui::Widget g_page_entity{ui::null};
 
 void EntityInspector_ToggleShow()
@@ -3115,6 +3127,13 @@ void MainFrame::Create()
                                              RawStringExportCaller("Console"));
     }
 
+#ifdef _EMBED_PYTHON
+    if (FloatingGroupDialog()) {
+        g_page_pythonconsole = GroupDialog_addPage("Python", PythonConsole_constructWindow(GroupDialog_getWindow()),
+                                                   RawStringExportCaller("Python"));
+    }
+#endif // _EMBED_PYTHON
+
 #if GDEF_OS_WINDOWS
                                                                                                                             if ( g_multimon_globals.m_bStartOnPrimMon ) {
                PositionWindowOnPrimaryScreen( g_layout_globals.m_position );
diff --git a/radiant/pybindconnector.cpp b/radiant/pybindconnector.cpp
new file mode 100644 (file)
index 0000000..ce36c6b
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+   Copyright (C) 2018, Sebastian Schmidt
+   All Rights Reserved.
+
+   This file is part of NetRadiant.
+
+   NetRadiant is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   NetRadiant is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with NetRadiant; if not, write to the Free Software
+   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+#include <cstdlib>
+#include <string>
+
+#include "pybindconnector.h"
+#include "../libs/pybind11/include/pybind11/embed.h"
+#include <../libs/pybind11/include/pybind11/eval.h>
+
+
+namespace py = pybind11;
+
+static py::dict scope;
+
+
+
+// // TODO: embedded modules
+// PYBIND11_EMBEDDED_MODULE(radiant, m) {
+//     m.def("TODO", [](){});
+// }
+
+
+void PYBIND_initializeInterpreter() {
+    py::initialize_interpreter();
+    scope = py::module::import("__main__").attr("__dict__");
+}
+
+std::string PYBIND_callfunction(std::string modulename,std::string functionname) {
+    py::object module = py::module::import(modulename.c_str());
+    py::object f = module.attr(functionname.c_str());
+    py::str result = f();
+    return result.cast<std::string>();
+}
+
+void PYBIND_exec(std::string code)
+{
+    py::exec(code.c_str(), scope);
+}
+
+std::string PYBIND_scope_as_string()
+{
+    return py::str(scope).cast<std::string>();
+}
+
+void PYBIND_finalizeInterpreter() {
+    scope.release();
+    py::finalize_interpreter();
+}
+
diff --git a/radiant/pybindconnector.h b/radiant/pybindconnector.h
new file mode 100644 (file)
index 0000000..50868c8
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+   Copyright (C) 2018, Sebastian Schmidt
+   All Rights Reserved.
+
+   This file is part of NetRadiant.
+
+   NetRadiant is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   NetRadiant is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with NetRadiant; if not, write to the Free Software
+   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+#if !defined(PYBIND_CONNECTOR_H)
+#define PYBIND_CONNECTOR_H
+
+
+void PYBIND_initializeInterpreter();
+std::string PYBIND_callfunction(std::string modulename, std::string functionname); // TODO: support for arguments
+void PYBIND_exec(std::string code);
+std::string PYBIND_scope_as_string();
+void PYBIND_finalizeInterpreter();
+
+#endif // PYBIND_CONNECTOR_H
+
diff --git a/radiant/pythonconsole.cpp b/radiant/pythonconsole.cpp
new file mode 100644 (file)
index 0000000..097c8ae
--- /dev/null
@@ -0,0 +1,96 @@
+/*
+   Copyright (C) 2018, Sebastian Schmidt
+   All Rights Reserved.
+
+   This file is part of NetRadiant.
+
+   NetRadiant is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   NetRadiant is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with NetRadiant; if not, write to the Free Software
+   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include "pythonconsole.h"
+
+#include <uilib/uilib.h>
+#include <gtk/gtk.h>
+#include <gdk/gdkkeysyms.h>
+
+#include "gtkutil/accelerator.h"
+#include "gtkutil/messagebox.h"
+#include "gtkutil/container.h"
+#include "gtkutil/menu.h"
+#include "gtkutil/nonmodal.h"
+
+#include "pybindconnector.h"
+
+
+ui::TextView g_pythonconsole_output{ui::null};
+
+static gint Input_keypress(ui::Entry widget, GdkEventKey *event, gpointer data)
+{
+    if (event->keyval == GDK_KEY_Return) {
+        try
+        {
+//             auto result = PYBIND_callfunction("os", std::string(widget.text()));
+            PYBIND_exec(std::string(widget.text()));
+            std::string result = PYBIND_scope_as_string();
+            g_pythonconsole_output.text(result.c_str());
+        }
+        catch (const std::exception& e)
+        {
+            g_pythonconsole_output.text(e.what());
+        }
+        widget.text("");
+        return TRUE;
+    }
+    if (event->keyval == GDK_KEY_Escape) {
+        gtk_window_set_focus(widget.window(), NULL);
+        return TRUE;
+    }
+
+    return FALSE;
+}
+
+ui::Widget PythonConsole_constructWindow(ui::Window toplevel)
+{
+    auto vBox = ui::VBox(FALSE, 2);
+    vBox.show();
+    gtk_container_set_border_width(GTK_CONTAINER(vBox), 2);
+    auto scr = ui::ScrolledWindow(ui::New);
+    scr.overflow(ui::Policy::AUTOMATIC, ui::Policy::AUTOMATIC);
+    gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scr), GTK_SHADOW_IN);
+    scr.show();
+
+    {
+        auto text = ui::TextView(ui::New);
+        text.dimensions(0, -1); // allow shrinking
+        gtk_text_view_set_wrap_mode(text, GTK_WRAP_WORD);
+        gtk_text_view_set_editable(text, FALSE);
+        scr.add(text);
+        text.show();
+        g_pythonconsole_output = text;
+
+    }
+
+    auto input = ui::Entry(ui::New);
+    input.show();
+    gtk_widget_set_events(input, GDK_KEY_PRESS_MASK);
+    input.connect("key_press_event", G_CALLBACK(Input_keypress), 0);
+
+    vBox.pack_start(scr, TRUE, TRUE, 0);
+    vBox.pack_end(input, FALSE, FALSE, 0);
+
+    gtk_container_set_focus_chain(GTK_CONTAINER(vBox), NULL);
+
+    return vBox;
+}
diff --git a/radiant/pythonconsole.h b/radiant/pythonconsole.h
new file mode 100644 (file)
index 0000000..5574afe
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+   Copyright (C) 2018, Sebastian Schmidt
+   All Rights Reserved.
+
+   This file is part of NetRadiant.
+
+   NetRadiant is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   NetRadiant is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with NetRadiant; if not, write to the Free Software
+   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#if !defined( INCLUDED_PYTHONCONSOLE_H )
+#define INCLUDED_PYTHONCONSOLE_H
+
+#include <uilib/uilib.h>
+
+
+ui::Widget PythonConsole_constructWindow(ui::Window toplevel);
+
+#endif // INCLUDED_PYTHONCONSOLE_H