From 3c989f90c1991195b793b53a28aa4c1f9c4d2d9c Mon Sep 17 00:00:00 2001
From: Kartik Patel <kartikpatel1995@gmail.com>
Date: Wed, 14 Jun 2017 02:37:06 +0530
Subject: grc: Modifications in GRC to allow BokehGUI

grc: Updated template for bokehgui

grc: Removed import from template file

grc: Added a condition to load bokeh based on installed library

grc: Allowed display from remote PC

grc: Added default layout option

grc: Added WidgetPlacement, Sizing Mode options in Options block

grc: Add terminate handler in main function

grc: default rowspan, colspan = 1

grc: Updated Document title and session id from the parameters of Options block

grc: Layout indexing starts from 0

grc: Allowed dynamic port selection

grc: Added a URL path for flow_graph

grc: Reviews incorporated
---
 grc/blocks/options.xml                             | 51 ++++++++++++++++++-
 grc/core/Platform.py                               |  4 +-
 grc/core/generator/flow_graph.tmpl                 | 58 +++++++++++++++++++++-
 grc/core/utils/__init__.py                         |  1 +
 .../hide_bokeh_gui_options_if_not_installed.py     | 28 +++++++++++
 5 files changed, 138 insertions(+), 4 deletions(-)
 create mode 100644 grc/core/utils/hide_bokeh_gui_options_if_not_installed.py

(limited to 'grc')

diff --git a/grc/blocks/options.xml b/grc/blocks/options.xml
index 1dee986c5c..6f3c8d5cf0 100644
--- a/grc/blocks/options.xml
+++ b/grc/blocks/options.xml
@@ -19,6 +19,13 @@ import wx
 from PyQt4 import Qt
 import sys
 #end if
+#if $generate_options() == 'bokeh_gui'
+import time
+import signal
+import functools
+from bokeh.client import push_session
+from bokeh.plotting import curdoc
+#end if
 #if not $generate_options().startswith('hb')
 from optparse import OptionParser
 from gnuradio.eng_option import eng_option
@@ -60,6 +67,10 @@ else: self.stop(); self.wait()</callback>
 		<key>generate_options</key>
 		<value>qt_gui</value>
 		<type>enum</type>
+		<option>
+			<name>Bokeh GUI</name>
+			<key>bokeh_gui</key>
+		</option>
 		<option>
 			<name>QT GUI</name>
 			<key>qt_gui</key>
@@ -104,12 +115,46 @@ else: self.stop(); self.wait()</callback>
 		</option>
 	</param>
 	<param>
+		<name>Widget Placement</name>
+		<key>placement</key>
+		<value>(0,0)</value>
+		<type>int_vector</type>
+		<hide>#if $generate_options() == 'bokeh_gui' then 'part' else 'all'#</hide>
+	</param>
+  <param>
+    <name>Sizing Mode</name>
+    <key>sizing_mode</key>
+    <value>fixed</value>
+    <type>enum</type>
+		<hide>#if $generate_options() == 'bokeh_gui' then 'part' else 'all'#</hide>
+    <option>
+      <name>Fixed</name>
+      <key>fixed</key>
+    </option>
+    <option>
+      <name>Stretch Both</name>
+      <key>stretch_both</key>
+    </option>
+    <option>
+      <name>Scale Width</name>
+      <key>scale_width</key>
+    </option>
+    <option>
+      <name>Scale Height</name>
+      <key>scale_height</key>
+    </option>
+    <option>
+      <name>Scale Both</name>
+      <key>scale_both</key>
+    </option>
+  </param>
+  <param>
 		<name>Run</name>
 		<key>run</key>
 		<value>True</value>
 		<type>bool</type>
 		<hide>
-#if $generate_options() in ('qt_gui', 'wx_gui')
+#if $generate_options() in ('qt_gui', 'wx_gui', 'bokeh_gui')
 	#if $run()
 		part
 	#else
@@ -218,7 +263,9 @@ part#slurp
 	<check>not $window_size or len($window_size) == 2</check>
 	<check>not $window_size or 300 &lt;= $(window_size)[0] &lt;= 4096</check>
 	<check>not $window_size or 300 &lt;= $(window_size)[1] &lt;= 4096</check>
-	<doc>
+  <check>len($placement) == 4 or len($placement) == 2</check>
+  <check>all(i &gt;= 0 for i in $(placement))</check>
+  <doc>
 The options block sets special parameters for the flow graph. \
 Only one option block is allowed per flow graph.
 
diff --git a/grc/core/Platform.py b/grc/core/Platform.py
index 297e8b0ae5..258f38cc62 100644
--- a/grc/core/Platform.py
+++ b/grc/core/Platform.py
@@ -31,7 +31,7 @@ from .Block import Block
 from .Port import Port
 from .Param import Param
 
-from .utils import odict, extract_docs
+from .utils import odict, extract_docs, hide_bokeh_gui_options_if_not_installed
 
 
 class Platform(Element):
@@ -172,6 +172,8 @@ class Platform(Element):
         self._docstring_extractor.finish()
         # self._docstring_extractor.wait()
 
+        hide_bokeh_gui_options_if_not_installed(self.blocks['options'])
+
     def iter_xml_files(self):
         """Iterator for block descriptions and category trees"""
         for block_path in self.config.block_paths:
diff --git a/grc/core/generator/flow_graph.tmpl b/grc/core/generator/flow_graph.tmpl
index 1ef251c46b..5550dca823 100644
--- a/grc/core/generator/flow_graph.tmpl
+++ b/grc/core/generator/flow_graph.tmpl
@@ -38,7 +38,7 @@ import threading
 
 ## Call XInitThreads as the _very_ first thing.
 ## After some Qt import, it's too late
-#if $generate_options in ('wx_gui', 'qt_gui')
+#if $generate_options in ('wx_gui', 'qt_gui', 'bokeh_gui')
 if __name__ == '__main__':
     import ctypes
     import sys
@@ -119,6 +119,15 @@ class $(class_name)(gr.top_block, Qt.QWidget):
 
         self.settings = Qt.QSettings("GNU Radio", "$class_name")
         self.restoreGeometry(self.settings.value("geometry").toByteArray())
+
+#elif $generate_options == 'bokeh_gui'
+
+class $(class_name)(gr.top_block):
+    def __init__(self, doc):
+        gr.top_block.__init__(self, "$title")
+        self.doc = doc
+        self.plot_lst = []
+        self.widget_lst = []
 #elif $generate_options == 'no_gui'
 
 
@@ -237,6 +246,22 @@ gr.io_signaturev($(len($io_sigs)), $(len($io_sigs)), [$(', '.join($size_strs))])
         #end if
     #end if
 #end for
+
+##########################################################
+## Create a layout entry if not manually done for BokehGUI
+##########################################################
+#if $generate_options == 'bokeh_gui'
+        if self.widget_lst:
+            input_t = bokehgui.BokehLayout.widgetbox(self.widget_lst)
+            widgetbox = bokehgui.BokehLayout.WidgetLayout(input_t)
+            widgetbox.set_layout(*($flow_graph.get_option('placement')))
+            list_obj = [widgetbox] + self.plot_lst
+        else:
+            list_obj = self.plot_lst
+        layout_t = bokehgui.BokehLayout.create_layout(list_obj, "$flow_graph.get_option('sizing_mode')")
+        self.doc.add_root(layout_t)
+#end if
+
 ########################################################
 ##Create Connections
 ##  The port name should be the id of the parent block.
@@ -378,6 +403,37 @@ def main(top_block_cls=$(class_name), options=None):
         #end for
     tb.Wait()
         #end if
+    #elif $generate_options == 'bokeh_gui'
+    serverProc, port = bokehgui.utils.create_server()
+    def killProc(signum, frame, tb):
+        tb.stop()
+        tb.wait()
+        serverProc.terminate()
+        serverProc.kill()
+    time.sleep(1)
+    try:
+        \# Define the document instance
+        doc = curdoc()
+        #if $flow_graph.get_option('author')
+        doc.title = "$title - $flow_graph.get_option('author')"
+        #else
+        doc.title = "$title"
+        #end if
+        session = push_session(doc, session_id="$flow_graph.get_option('id')",
+                               url = "http://localhost:" + port + "/bokehgui")
+        \# Create Top Block instance
+        tb = top_block_cls(doc)
+        try:
+            tb.start()
+            signal.signal(signal.SIGTERM, functools.partial(killProc, tb=tb))
+            session.loop_until_closed()
+        finally:
+            print "Exiting the simulation. Stopping Bokeh Server"
+            tb.stop()
+            tb.wait()
+    finally:
+        serverProc.terminate()
+        serverProc.kill()
     #elif $generate_options == 'qt_gui'
     from distutils.version import StrictVersion
     if StrictVersion(Qt.qVersion()) >= StrictVersion("4.5.0"):
diff --git a/grc/core/utils/__init__.py b/grc/core/utils/__init__.py
index 6b23da2723..2aed42d762 100644
--- a/grc/core/utils/__init__.py
+++ b/grc/core/utils/__init__.py
@@ -20,3 +20,4 @@ import epy_block_io
 import extract_docs
 
 from odict import odict
+from hide_bokeh_gui_options_if_not_installed import hide_bokeh_gui_options_if_not_installed
diff --git a/grc/core/utils/hide_bokeh_gui_options_if_not_installed.py b/grc/core/utils/hide_bokeh_gui_options_if_not_installed.py
new file mode 100644
index 0000000000..fc0141851a
--- /dev/null
+++ b/grc/core/utils/hide_bokeh_gui_options_if_not_installed.py
@@ -0,0 +1,28 @@
+# Copyright 2008-2017 Free Software Foundation, Inc.
+# This file is part of GNU Radio
+#
+# GNU Radio Companion 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.
+#
+# GNU Radio Companion 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 this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
+
+
+def hide_bokeh_gui_options_if_not_installed(options):
+    try:
+        import bokehgui
+    except ImportError:
+        generate_option = options.get_param('generate_options')
+        list_generate_option = generate_option.get_options()
+        for option in list_generate_option:
+            if option.get_key() == 'bokeh_gui':
+                list_generate_option.remove(option)
+                return
-- 
cgit v1.2.3