diff options
-rw-r--r-- | gr-qtgui/doc/qtgui.dox | 48 | ||||
-rw-r--r-- | gr-qtgui/examples/CMakeLists.txt | 1 | ||||
-rw-r--r-- | gr-qtgui/examples/test_qtgui_msg.grc | 978 | ||||
-rw-r--r-- | gr-qtgui/grc/qtgui_block_tree.xml | 1 | ||||
-rw-r--r-- | gr-qtgui/grc/qtgui_edit_box_msg.xml | 152 | ||||
-rw-r--r-- | gr-qtgui/include/gnuradio/qtgui/CMakeLists.txt | 1 | ||||
-rw-r--r-- | gr-qtgui/include/gnuradio/qtgui/edit_box_msg.h | 151 | ||||
-rw-r--r-- | gr-qtgui/include/gnuradio/qtgui/qtgui_types.h | 20 | ||||
-rw-r--r-- | gr-qtgui/lib/CMakeLists.txt | 2 | ||||
-rw-r--r-- | gr-qtgui/lib/edit_box_msg_impl.cc | 571 | ||||
-rw-r--r-- | gr-qtgui/lib/edit_box_msg_impl.h | 93 | ||||
-rw-r--r-- | gr-qtgui/swig/qtgui_swig.i | 15 |
12 files changed, 2032 insertions, 1 deletions
diff --git a/gr-qtgui/doc/qtgui.dox b/gr-qtgui/doc/qtgui.dox index d95ab19f72..d0d7345f73 100644 --- a/gr-qtgui/doc/qtgui.dox +++ b/gr-qtgui/doc/qtgui.dox @@ -232,6 +232,54 @@ tb.msg_connect((msg_block, 'msg'), (tsnk, 'in')) \endcode +\section qtgui_widgets QTGUI Widgets + +The QTGUI component also includes a number of widgets that can be used +to perform live updates of variables through standard QT input +widgets. Most of the widgets are implemented directly in Python +through PyQT. However, GNU Radio is introducing more widgets, written +and therefore available in C++ that also produce messsages. The +Python-based widgets only act as variables and so as they are changed, +any block using those widgets to set paramters has the callback (i.e., +set_value()) function's called. + +\subsection qtgui_widgets_python Python widgets: + +\li Range: creates a slider and/or combo box to change to set/change +the value of a parameter. This widget can set either float of int +values. +\li Entry: An edit box that allows a user to directly set a +new value for the parameter. +\li Chooser: Creates a drop-down menu of pre-set values. +\li Check Box: Creates a check box. The user sets what the value of +the check means when enabled or disabled. +\li Push Button: Adds a button that changes state when pushed versus +released (no sticky). The user sets up what the value is when pressed +versus when released. +\li Label: Adds a Label widget to annotate the GUI. Generally not used +as a variable. +\li Tab Widget: Adds a tab widget that can house other GUI widgets to +format the interface. Use the GUI hint of the other QT widgets and +instruments to specify if and where they exist in the tab widget using +the format "tag widget name@index: row, col, row span, col +span". Simply using "tab widget name@index" will put that widget into +the specific index (starting at 0) of the tab widget while adding the +"row, col, row span, col span" will allow the user to place them in +the tab grid. +\li + + +\subsection qtgui_widgets_cpp C++ and Message-Passing Widgets + +\li \ref gr::qtgui::edit_box_msg "Message Edit Box": A QT edit box +that emits a message when editing is done (e.g., user presses enter, +tabs out of the widget, or mouse-clicks out of the widget). The +message type is settable as are the contents. Messages can be sent as +key:value pairs when Pair Mode is enabled. When Static Mode is +enabled, the data type and the pair key (if in Pair Mode) are set at +the start and cannot be changed at runtime. + + \section qtgui_configuration Configuration There is currently a single configuration option in the preferences diff --git a/gr-qtgui/examples/CMakeLists.txt b/gr-qtgui/examples/CMakeLists.txt index 3581bdaec1..5662dfa9c8 100644 --- a/gr-qtgui/examples/CMakeLists.txt +++ b/gr-qtgui/examples/CMakeLists.txt @@ -41,6 +41,7 @@ install( qtgui_tags_viewing.grc qtgui_vector_sink_example.grc qtgui_message_inputs.grc + test_qtgui_msg.grc DESTINATION ${GR_PKG_QTGUI_EXAMPLES_DIR} COMPONENT "qtgui_python" ) diff --git a/gr-qtgui/examples/test_qtgui_msg.grc b/gr-qtgui/examples/test_qtgui_msg.grc new file mode 100644 index 0000000000..12ca0e34c9 --- /dev/null +++ b/gr-qtgui/examples/test_qtgui_msg.grc @@ -0,0 +1,978 @@ +<?xml version='1.0' encoding='utf-8'?> +<?grc format='1' created='3.7.10'?> +<flow_graph> + <timestamp>Wed Feb 10 14:28:57 2016</timestamp> + <block> + <key>options</key> + <param> + <key>author</key> + <value></value> + </param> + <param> + <key>window_size</key> + <value></value> + </param> + <param> + <key>category</key> + <value>Custom</value> + </param> + <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>description</key> + <value></value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>_coordinate</key> + <value>(8, 11)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + <param> + <key>generate_options</key> + <value>qt_gui</value> + </param> + <param> + <key>hier_block_src_path</key> + <value>.:</value> + </param> + <param> + <key>id</key> + <value>test_qtgui_msg</value> + </param> + <param> + <key>max_nouts</key> + <value>0</value> + </param> + <param> + <key>qt_qss_theme</key> + <value></value> + </param> + <param> + <key>realtime_scheduling</key> + <value></value> + </param> + <param> + <key>run_command</key> + <value>{python} -u {filename}</value> + </param> + <param> + <key>run_options</key> + <value>prompt</value> + </param> + <param> + <key>run</key> + <value>True</value> + </param> + <param> + <key>thread_safe_setters</key> + <value></value> + </param> + <param> + <key>title</key> + <value></value> + </param> + </block> + <block> + <key>variable</key> + <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>_coordinate</key> + <value>(168, 11)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + <param> + <key>id</key> + <value>samp_rate</value> + </param> + <param> + <key>value</key> + <value>32000</value> + </param> + </block> + <block> + <key>analog_sig_source_x</key> + <param> + <key>amp</key> + <value>1</value> + </param> + <param> + <key>alias</key> + <value></value> + </param> + <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>affinity</key> + <value></value> + </param> + <param> + <key>_enabled</key> + <value>1</value> + </param> + <param> + <key>freq</key> + <value>1000</value> + </param> + <param> + <key>_coordinate</key> + <value>(80, 83)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + <param> + <key>id</key> + <value>analog_sig_source_x_0</value> + </param> + <param> + <key>maxoutbuf</key> + <value>0</value> + </param> + <param> + <key>minoutbuf</key> + <value>0</value> + </param> + <param> + <key>offset</key> + <value>0</value> + </param> + <param> + <key>type</key> + <value>complex</value> + </param> + <param> + <key>samp_rate</key> + <value>samp_rate</value> + </param> + <param> + <key>waveform</key> + <value>analog.GR_COS_WAVE</value> + </param> + </block> + <block> + <key>blocks_message_debug</key> + <param> + <key>alias</key> + <value></value> + </param> + <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>affinity</key> + <value></value> + </param> + <param> + <key>_enabled</key> + <value>1</value> + </param> + <param> + <key>_coordinate</key> + <value>(600, 481)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + <param> + <key>id</key> + <value>blocks_message_debug_0</value> + </param> + </block> + <block> + <key>qtgui_edit_box_msg</key> + <param> + <key>alias</key> + <value></value> + </param> + <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>affinity</key> + <value></value> + </param> + <param> + <key>_enabled</key> + <value>1</value> + </param> + <param> + <key>_coordinate</key> + <value>(104, 219)</value> + </param> + <param> + <key>gui_hint</key> + <value>0,0,1,1</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + <param> + <key>id</key> + <value>qtgui_edit_box_msg_0</value> + </param> + <param> + <key>key</key> + <value>freq</value> + </param> + <param> + <key>label</key> + <value>Frequency</value> + </param> + <param> + <key>maxoutbuf</key> + <value>0</value> + </param> + <param> + <key>minoutbuf</key> + <value>0</value> + </param> + <param> + <key>is_pair</key> + <value>True</value> + </param> + <param> + <key>is_static</key> + <value>True</value> + </param> + <param> + <key>type</key> + <value>float</value> + </param> + <param> + <key>value</key> + <value></value> + </param> + </block> + <block> + <key>qtgui_edit_box_msg</key> + <param> + <key>alias</key> + <value></value> + </param> + <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>affinity</key> + <value></value> + </param> + <param> + <key>_enabled</key> + <value>1</value> + </param> + <param> + <key>_coordinate</key> + <value>(88, 371)</value> + </param> + <param> + <key>gui_hint</key> + <value>3,1,1,1</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + <param> + <key>id</key> + <value>qtgui_edit_box_msg_0_0</value> + </param> + <param> + <key>key</key> + <value></value> + </param> + <param> + <key>label</key> + <value></value> + </param> + <param> + <key>maxoutbuf</key> + <value>0</value> + </param> + <param> + <key>minoutbuf</key> + <value>0</value> + </param> + <param> + <key>is_pair</key> + <value>False</value> + </param> + <param> + <key>is_static</key> + <value>False</value> + </param> + <param> + <key>type</key> + <value>int_vec</value> + </param> + <param> + <key>value</key> + <value></value> + </param> + </block> + <block> + <key>qtgui_edit_box_msg</key> + <param> + <key>alias</key> + <value></value> + </param> + <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>affinity</key> + <value></value> + </param> + <param> + <key>_enabled</key> + <value>1</value> + </param> + <param> + <key>_coordinate</key> + <value>(272, 499)</value> + </param> + <param> + <key>gui_hint</key> + <value>3,0,1,1</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + <param> + <key>id</key> + <value>qtgui_edit_box_msg_0_0_0</value> + </param> + <param> + <key>key</key> + <value></value> + </param> + <param> + <key>label</key> + <value></value> + </param> + <param> + <key>maxoutbuf</key> + <value>0</value> + </param> + <param> + <key>minoutbuf</key> + <value>0</value> + </param> + <param> + <key>is_pair</key> + <value>False</value> + </param> + <param> + <key>is_static</key> + <value>False</value> + </param> + <param> + <key>type</key> + <value>int_vec</value> + </param> + <param> + <key>value</key> + <value></value> + </param> + </block> + <block> + <key>qtgui_freq_sink_x</key> + <param> + <key>autoscale</key> + <value>False</value> + </param> + <param> + <key>average</key> + <value>1.0</value> + </param> + <param> + <key>bw</key> + <value>samp_rate</value> + </param> + <param> + <key>alias</key> + <value></value> + </param> + <param> + <key>fc</key> + <value>0</value> + </param> + <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>ctrlpanel</key> + <value>False</value> + </param> + <param> + <key>affinity</key> + <value></value> + </param> + <param> + <key>_enabled</key> + <value>1</value> + </param> + <param> + <key>fftsize</key> + <value>1024</value> + </param> + <param> + <key>_coordinate</key> + <value>(512, 195)</value> + </param> + <param> + <key>gui_hint</key> + <value>1,0,1,2</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + <param> + <key>grid</key> + <value>False</value> + </param> + <param> + <key>id</key> + <value>qtgui_freq_sink_x_0</value> + </param> + <param> + <key>legend</key> + <value>False</value> + </param> + <param> + <key>alpha1</key> + <value>1.0</value> + </param> + <param> + <key>color1</key> + <value>"blue"</value> + </param> + <param> + <key>label1</key> + <value></value> + </param> + <param> + <key>width1</key> + <value>1</value> + </param> + <param> + <key>alpha10</key> + <value>1.0</value> + </param> + <param> + <key>color10</key> + <value>"dark blue"</value> + </param> + <param> + <key>label10</key> + <value></value> + </param> + <param> + <key>width10</key> + <value>1</value> + </param> + <param> + <key>alpha2</key> + <value>1.0</value> + </param> + <param> + <key>color2</key> + <value>"red"</value> + </param> + <param> + <key>label2</key> + <value></value> + </param> + <param> + <key>width2</key> + <value>1</value> + </param> + <param> + <key>alpha3</key> + <value>1.0</value> + </param> + <param> + <key>color3</key> + <value>"green"</value> + </param> + <param> + <key>label3</key> + <value></value> + </param> + <param> + <key>width3</key> + <value>1</value> + </param> + <param> + <key>alpha4</key> + <value>1.0</value> + </param> + <param> + <key>color4</key> + <value>"black"</value> + </param> + <param> + <key>label4</key> + <value></value> + </param> + <param> + <key>width4</key> + <value>1</value> + </param> + <param> + <key>alpha5</key> + <value>1.0</value> + </param> + <param> + <key>color5</key> + <value>"cyan"</value> + </param> + <param> + <key>label5</key> + <value></value> + </param> + <param> + <key>width5</key> + <value>1</value> + </param> + <param> + <key>alpha6</key> + <value>1.0</value> + </param> + <param> + <key>color6</key> + <value>"magenta"</value> + </param> + <param> + <key>label6</key> + <value></value> + </param> + <param> + <key>width6</key> + <value>1</value> + </param> + <param> + <key>alpha7</key> + <value>1.0</value> + </param> + <param> + <key>color7</key> + <value>"yellow"</value> + </param> + <param> + <key>label7</key> + <value></value> + </param> + <param> + <key>width7</key> + <value>1</value> + </param> + <param> + <key>alpha8</key> + <value>1.0</value> + </param> + <param> + <key>color8</key> + <value>"dark red"</value> + </param> + <param> + <key>label8</key> + <value></value> + </param> + <param> + <key>width8</key> + <value>1</value> + </param> + <param> + <key>alpha9</key> + <value>1.0</value> + </param> + <param> + <key>color9</key> + <value>"dark green"</value> + </param> + <param> + <key>label9</key> + <value></value> + </param> + <param> + <key>width9</key> + <value>1</value> + </param> + <param> + <key>maxoutbuf</key> + <value>0</value> + </param> + <param> + <key>minoutbuf</key> + <value>0</value> + </param> + <param> + <key>name</key> + <value>""</value> + </param> + <param> + <key>nconnections</key> + <value>1</value> + </param> + <param> + <key>showports</key> + <value>False</value> + </param> + <param> + <key>freqhalf</key> + <value>True</value> + </param> + <param> + <key>tr_chan</key> + <value>0</value> + </param> + <param> + <key>tr_level</key> + <value>0.0</value> + </param> + <param> + <key>tr_mode</key> + <value>qtgui.TRIG_MODE_FREE</value> + </param> + <param> + <key>tr_tag</key> + <value>""</value> + </param> + <param> + <key>type</key> + <value>complex</value> + </param> + <param> + <key>update_time</key> + <value>0.10</value> + </param> + <param> + <key>wintype</key> + <value>firdes.WIN_BLACKMAN_hARRIS</value> + </param> + <param> + <key>ymax</key> + <value>10</value> + </param> + <param> + <key>ymin</key> + <value>-140</value> + </param> + </block> + <block> + <key>qtgui_waterfall_sink_x</key> + <param> + <key>bw</key> + <value>samp_rate</value> + </param> + <param> + <key>alias</key> + <value></value> + </param> + <param> + <key>fc</key> + <value>0</value> + </param> + <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>affinity</key> + <value></value> + </param> + <param> + <key>_enabled</key> + <value>1</value> + </param> + <param> + <key>fftsize</key> + <value>1024</value> + </param> + <param> + <key>_coordinate</key> + <value>(512, 115)</value> + </param> + <param> + <key>gui_hint</key> + <value>2,0,1,2</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + <param> + <key>grid</key> + <value>False</value> + </param> + <param> + <key>id</key> + <value>qtgui_waterfall_sink_x_0</value> + </param> + <param> + <key>int_max</key> + <value>10</value> + </param> + <param> + <key>int_min</key> + <value>-140</value> + </param> + <param> + <key>legend</key> + <value>True</value> + </param> + <param> + <key>alpha1</key> + <value>1.0</value> + </param> + <param> + <key>color1</key> + <value>0</value> + </param> + <param> + <key>label1</key> + <value></value> + </param> + <param> + <key>alpha10</key> + <value>1.0</value> + </param> + <param> + <key>color10</key> + <value>0</value> + </param> + <param> + <key>label10</key> + <value></value> + </param> + <param> + <key>alpha2</key> + <value>1.0</value> + </param> + <param> + <key>color2</key> + <value>0</value> + </param> + <param> + <key>label2</key> + <value></value> + </param> + <param> + <key>alpha3</key> + <value>1.0</value> + </param> + <param> + <key>color3</key> + <value>0</value> + </param> + <param> + <key>label3</key> + <value></value> + </param> + <param> + <key>alpha4</key> + <value>1.0</value> + </param> + <param> + <key>color4</key> + <value>0</value> + </param> + <param> + <key>label4</key> + <value></value> + </param> + <param> + <key>alpha5</key> + <value>1.0</value> + </param> + <param> + <key>color5</key> + <value>0</value> + </param> + <param> + <key>label5</key> + <value></value> + </param> + <param> + <key>alpha6</key> + <value>1.0</value> + </param> + <param> + <key>color6</key> + <value>0</value> + </param> + <param> + <key>label6</key> + <value></value> + </param> + <param> + <key>alpha7</key> + <value>1.0</value> + </param> + <param> + <key>color7</key> + <value>0</value> + </param> + <param> + <key>label7</key> + <value></value> + </param> + <param> + <key>alpha8</key> + <value>1.0</value> + </param> + <param> + <key>color8</key> + <value>0</value> + </param> + <param> + <key>label8</key> + <value></value> + </param> + <param> + <key>alpha9</key> + <value>1.0</value> + </param> + <param> + <key>color9</key> + <value>0</value> + </param> + <param> + <key>label9</key> + <value></value> + </param> + <param> + <key>maxoutbuf</key> + <value>0</value> + </param> + <param> + <key>minoutbuf</key> + <value>0</value> + </param> + <param> + <key>name</key> + <value>""</value> + </param> + <param> + <key>nconnections</key> + <value>1</value> + </param> + <param> + <key>showports</key> + <value>False</value> + </param> + <param> + <key>freqhalf</key> + <value>True</value> + </param> + <param> + <key>type</key> + <value>complex</value> + </param> + <param> + <key>update_time</key> + <value>0.10</value> + </param> + <param> + <key>wintype</key> + <value>firdes.WIN_BLACKMAN_hARRIS</value> + </param> + </block> + <connection> + <source_block_id>analog_sig_source_x_0</source_block_id> + <sink_block_id>qtgui_freq_sink_x_0</sink_block_id> + <source_key>0</source_key> + <sink_key>0</sink_key> + </connection> + <connection> + <source_block_id>analog_sig_source_x_0</source_block_id> + <sink_block_id>qtgui_waterfall_sink_x_0</sink_block_id> + <source_key>0</source_key> + <sink_key>0</sink_key> + </connection> + <connection> + <source_block_id>qtgui_edit_box_msg_0</source_block_id> + <sink_block_id>qtgui_freq_sink_x_0</sink_block_id> + <source_key>msg</source_key> + <sink_key>freq</sink_key> + </connection> + <connection> + <source_block_id>qtgui_edit_box_msg_0</source_block_id> + <sink_block_id>qtgui_waterfall_sink_x_0</sink_block_id> + <source_key>msg</source_key> + <sink_key>freq</sink_key> + </connection> + <connection> + <source_block_id>qtgui_edit_box_msg_0_0</source_block_id> + <sink_block_id>qtgui_edit_box_msg_0_0_0</sink_block_id> + <source_key>msg</source_key> + <sink_key>val</sink_key> + </connection> + <connection> + <source_block_id>qtgui_edit_box_msg_0_0_0</source_block_id> + <sink_block_id>blocks_message_debug_0</sink_block_id> + <source_key>msg</source_key> + <sink_key>print</sink_key> + </connection> + <connection> + <source_block_id>qtgui_edit_box_msg_0_0_0</source_block_id> + <sink_block_id>qtgui_edit_box_msg_0_0</sink_block_id> + <source_key>msg</source_key> + <sink_key>val</sink_key> + </connection> + <connection> + <source_block_id>qtgui_freq_sink_x_0</source_block_id> + <sink_block_id>qtgui_edit_box_msg_0</sink_block_id> + <source_key>freq</source_key> + <sink_key>val</sink_key> + </connection> + <connection> + <source_block_id>qtgui_freq_sink_x_0</source_block_id> + <sink_block_id>qtgui_freq_sink_x_0</sink_block_id> + <source_key>freq</source_key> + <sink_key>freq</sink_key> + </connection> + <connection> + <source_block_id>qtgui_waterfall_sink_x_0</source_block_id> + <sink_block_id>qtgui_edit_box_msg_0</sink_block_id> + <source_key>freq</source_key> + <sink_key>val</sink_key> + </connection> + <connection> + <source_block_id>qtgui_waterfall_sink_x_0</source_block_id> + <sink_block_id>qtgui_waterfall_sink_x_0</sink_block_id> + <source_key>freq</source_key> + <sink_key>freq</sink_key> + </connection> +</flow_graph> diff --git a/gr-qtgui/grc/qtgui_block_tree.xml b/gr-qtgui/grc/qtgui_block_tree.xml index 03db638d61..300c7a786d 100644 --- a/gr-qtgui/grc/qtgui_block_tree.xml +++ b/gr-qtgui/grc/qtgui_block_tree.xml @@ -55,6 +55,7 @@ <block>variable_qtgui_push_button</block> <block>variable_qtgui_entry</block> <block>variable_qtgui_label</block> + <block>qtgui_edit_box_msg</block> </cat> </cat> </cat> diff --git a/gr-qtgui/grc/qtgui_edit_box_msg.xml b/gr-qtgui/grc/qtgui_edit_box_msg.xml new file mode 100644 index 0000000000..c7c758a612 --- /dev/null +++ b/gr-qtgui/grc/qtgui_edit_box_msg.xml @@ -0,0 +1,152 @@ +<?xml version="1.0"?> +<!-- +################################################### +##QT GUI Edit Box that sends messages +################################################### + --> +<block> + <name>QT GUI Message Edit Box</name> + <key>qtgui_edit_box_msg</key> + <import>from PyQt4 import Qt</import> + <import>from gnuradio import qtgui</import> + <import>import sip</import> + <make>#set $win = 'self._%s_win'%$id +qtgui.edit_box_msg($(type.t), $value, $label, $is_pair, $is_static, $key) +self._$(id)_win = sip.wrapinstance(self.$(id).pyqwidget(), Qt.QWidget) +$(gui_hint()($win))</make> + + <param> + <name>Type</name> + <key>type</key> + <value>string</value> + <type>enum</type> + <option> + <name>String</name> + <key>string</key> + <opt>t:qtgui.STRING</opt> + </option> + <option> + <name>Int</name> + <key>int</key> + <opt>t:qtgui.INT</opt> + </option> + <option> + <name>Float</name> + <key>float</key> + <opt>t:qtgui.FLOAT</opt> + </option> + <option> + <name>Double</name> + <key>double</key> + <opt>t:qtgui.DOUBLE</opt> + </option> + <option> + <name>Complex</name> + <key>complex</key> + <opt>t:qtgui.COMPLEX</opt> + </option> + <option> + <name>Int (Vec)</name> + <key>int_vec</key> + <opt>t:qtgui.INT_VEC</opt> + </option> + <option> + <name>Float (Vec)</name> + <key>flt_vec</key> + <opt>t:qtgui.FLOAT_VEC</opt> + </option> + <option> + <name>Double (Vec)</name> + <key>dbl_vec</key> + <opt>t:qtgui.DOUBLE_VEC</opt> + </option> + <option> + <name>Complex (Vec)</name> + <key>cpx_vec</key> + <opt>t:qtgui.COMPLEX_VEC</opt> + </option> + </param> + + <param> + <name>Value</name> + <key>value</key> + <value></value> + <type>string</type> + </param> + + <param> + <name>Label</name> + <key>label</key> + <value></value> + <type>string</type> + </param> + + <param> + <name>Pair Mode</name> + <key>is_pair</key> + <value>True</value> + <type>enum</type> + <option> + <name>False</name> + <key>False</key> + </option> + <option> + <name>True</name> + <key>True</key> + </option> + </param> + + <param> + <name>Static Mode</name> + <key>is_static</key> + <value>True</value> + <type>enum</type> + <option> + <name>False</name> + <key>False</key> + </option> + <option> + <name>True</name> + <key>True</key> + </option> + </param> + + <param> + <name>Key</name> + <key>key</key> + <value></value> + <type>string</type> + <hide>#if $is_pair() == 'True' then 'none' else 'all'#</hide> + </param> + + <param> + <name>GUI Hint</name> + <key>gui_hint</key> + <value></value> + <type>gui_hint</type> + <hide>part</hide> + </param> + + <!-- If both is_pair and is_static are True, we require a default key. + If either or both are false, we don't care about a default key. + --> + <check>($is_pair and $is_static and len($key) > 0) or not ($is_pair and $is_static)</check> + + <sink> + <name>val</name> + <type>message</type> + <optional>1</optional> + </sink> + + <source> + <name>msg</name> + <type>message</type> + <optional>1</optional> + </source> + + <doc> +The GUI hint can be used to position the widget within the application. \ +The hint is of the form [tab_id@tab_index]: [row, col, row_span, col_span]. \ +Both the tab specification and the grid position are optional. + </doc> +</block> diff --git a/gr-qtgui/include/gnuradio/qtgui/CMakeLists.txt b/gr-qtgui/include/gnuradio/qtgui/CMakeLists.txt index 1e0c9f35f2..5d22f112af 100644 --- a/gr-qtgui/include/gnuradio/qtgui/CMakeLists.txt +++ b/gr-qtgui/include/gnuradio/qtgui/CMakeLists.txt @@ -38,6 +38,7 @@ install(FILES histogram_sink_f.h histogramdisplayform.h HistogramDisplayPlot.h + edit_box_msg.h number_sink.h numberdisplayform.h plot_raster.h diff --git a/gr-qtgui/include/gnuradio/qtgui/edit_box_msg.h b/gr-qtgui/include/gnuradio/qtgui/edit_box_msg.h new file mode 100644 index 0000000000..2976cfb2be --- /dev/null +++ b/gr-qtgui/include/gnuradio/qtgui/edit_box_msg.h @@ -0,0 +1,151 @@ +/* -*- c++ -*- */ +/* + * Copyright 2016 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio 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 3, or (at your option) + * any later version. + * + * GNU Radio 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 GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifndef INCLUDED_QTGUI_EDIT_BOX_MSG_H +#define INCLUDED_QTGUI_EDIT_BOX_MSG_H + +#ifdef ENABLE_PYTHON +#include <Python.h> +#endif + +#include <gnuradio/qtgui/qtgui_types.h> +#include <gnuradio/qtgui/api.h> +#include <gnuradio/block.h> +#include <qapplication.h> + +namespace gr { + namespace qtgui { + + /*! + * \brief Create a QT Edit Box widget where the value is posted as a message. + * \ingroup qtgui_blk + * + * \details + * This block creates a QT Edit Box widget that manages data + * through message passing interfaces. The 'msg' output port + * produces messages based on the text in the edit box and the + * data type set by the \p type argument (see + * gr::qtgui::data_type_t). The data types are checked, and WARN + * log messages are produced when the data is in the wrong + * format. Not all errors are explicitly checked for, only that + * conversions happen correctly. Failures are either produces as + * log messages or the action is simply silently dropped. + * + * The value of the edit boxes can be programmatically updated + * through the 'val' input message port. It is also checked for + * the correct data type. + * + * The \p is_pair argument to the constructor determines if the + * edit box handles a key:value pair. If set to True, two edit + * boxes are created with the left for the key and right for the + * value. The key is always assumed to be a string and the value + * is restricted by the data type setting as above. + * + * The block can take a default value. Because the block is + * capable of handling multiple different data types, we enter the + * default value as a string in the same way we expect the user to + * enter it into the Value edit box of the widget. We convert this + * default exactly the same way we convert the user-entered text + * in the edit box. See the next paragraph for an explanation for + * how to handle complex numbers. + * + * Complex numbers are currently handled a bit differently than + * expected. Because we use the Boost lexical_cast function, + * complex numbers MUST be in the form "(a,b)" to represent "a + + * jb". Note that you cannot even have a space after the comma, so + * "(1.23,10.56)" is correct while "(1.23, 10.56)" will not parse. + * + * The 'static' mode prevents the user from changing the data type + * or the key used in the widget. If also in 'pair' mode, the key + * is not displayed and so must be set in the constructor. It is + * an error if using static and pair modes with no default key + * set. + * + * Message Ports: + * + * - msg (output): + * Produces a PMT message from the data in the edit box. It + * is packaged in the PMT container determined by the \p + * type argument to the ctor. If the data in the box is not of + * the correct type and the conversion fails, the block + * produces a log WARN message but does nothing else with + * the data. If the \p is_pair flag is set on this block, it + * will produce a PMT pair object where the key (car) is + * assumed to be a string and the value (cdr) is determined + * by \p type. + * + * - val (input): + * Accepts messages to update the value in the edit + * boxes. The messages, as PMTs, are first checked to make + * sure that they are the correct type (integer, float, + * string, or complex), and unpacks them and converts them + * to QStrings to display in the edit box. When using \p + * is_pair, the PMT is checked to make sure it is a PMT + * pair. Then the key (car) is extracted as a string before + * the value (cdr) is processed based on the set data type + * of the box. + */ + class QTGUI_API edit_box_msg : virtual public block + { + public: + // gr::qtgui::edit_box_msg::sptr + typedef boost::shared_ptr<edit_box_msg> sptr; + + /*! + * \brief Constructs the Edit box block. + * + * \param type the data type of data in the value box. + * \param value the default value of the message. This is + * entered as a string regardless of the type and + * converted internally -- much like how the block + * extracts the value from the edit box and converts it. + * \param label a label to identify the box on screen. + * \param is_pair if we are using a key:value pair. + * \param is_static sets the key edit box as a static text box + * (cannot be edited live). + * \param key Set the key used in a key:value pair message. + * \param parent a QWidget parent in the QT app. + */ + static sptr make(gr::qtgui::data_type_t type, + const std::string &value="", + const std::string &label="", + bool is_pair=true, + bool is_static=true, + const std::string &key="", + QWidget *parent=NULL); + + virtual void exec_() = 0; + virtual QWidget* qwidget() = 0; + +#ifdef ENABLE_PYTHON + virtual PyObject* pyqwidget() = 0; +#else + virtual void* pyqwidget() = 0; +#endif + + QApplication *d_qApplication; + }; + + } /* namespace qtgui */ +} /* namespace gr */ + +#endif /* INCLUDED_QTGUI_EDIT_BOX_MSG_H */ diff --git a/gr-qtgui/include/gnuradio/qtgui/qtgui_types.h b/gr-qtgui/include/gnuradio/qtgui/qtgui_types.h index e55746c48c..ae7d081013 100644 --- a/gr-qtgui/include/gnuradio/qtgui/qtgui_types.h +++ b/gr-qtgui/include/gnuradio/qtgui/qtgui_types.h @@ -1,6 +1,6 @@ /* -*- c++ -*- */ /* - * Copyright 2012 Free Software Foundation, Inc. + * Copyright 2012,2016 Free Software Foundation, Inc. * * This file is part of GNU Radio * @@ -27,6 +27,24 @@ #include <qwt_scale_draw.h> #include <gnuradio/high_res_timer.h> +namespace gr { + namespace qtgui { + + enum data_type_t { + INT = 0, + FLOAT, + DOUBLE, + COMPLEX, + STRING, + INT_VEC, + FLOAT_VEC, + DOUBLE_VEC, + COMPLEX_VEC, + }; + + } /* namespace qtgui */ +} /* namespace gr */ + class FreqOffsetAndPrecisionClass { public: diff --git a/gr-qtgui/lib/CMakeLists.txt b/gr-qtgui/lib/CMakeLists.txt index a0af95bbbb..276c3e4856 100644 --- a/gr-qtgui/lib/CMakeLists.txt +++ b/gr-qtgui/lib/CMakeLists.txt @@ -43,6 +43,7 @@ set(qtgui_moc_hdrs ${qtgui_mod_includedir}/ConstellationDisplayPlot.h ${qtgui_mod_includedir}/HistogramDisplayPlot.h ${qtgui_mod_includedir}/VectorDisplayPlot.h + edit_box_msg_impl.h ) QT4_WRAP_CPP(qtgui_moc_sources ${qtgui_moc_hdrs}) QT4_WRAP_UI(qtgui_ui_hdrs spectrumdisplayform.ui) @@ -99,6 +100,7 @@ set(qtgui_sources ber_sink_b_impl.cc vectordisplayform.cc vector_sink_f_impl.cc + edit_box_msg_impl.cc ) #Add Windows DLL resource file if using MSVC diff --git a/gr-qtgui/lib/edit_box_msg_impl.cc b/gr-qtgui/lib/edit_box_msg_impl.cc new file mode 100644 index 0000000000..e0c5f64b3d --- /dev/null +++ b/gr-qtgui/lib/edit_box_msg_impl.cc @@ -0,0 +1,571 @@ +/* -*- c++ -*- */ +/* + * Copyright 2016 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio 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 3, or (at your option) + * any later version. + * + * GNU Radio 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 GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "edit_box_msg_impl.h" +#include <gnuradio/io_signature.h> +#include <gnuradio/prefs.h> +#include <gnuradio/qtgui/utils.h> +#include <boost/lexical_cast.hpp> + +namespace gr { + namespace qtgui { + + edit_box_msg::sptr + edit_box_msg::make(data_type_t type, const std::string &label, + const std::string &value, + bool is_pair, bool is_static, + const std::string &key, QWidget* parent) + { + return gnuradio::get_initial_sptr + (new edit_box_msg_impl(type, value, label, is_pair, + is_static, key, parent)); + } + + edit_box_msg_impl::edit_box_msg_impl(data_type_t type, const std::string &label, + const std::string &value, + bool is_pair, bool is_static, + const std::string &key, QWidget* parent) + : block("edit_box_msg", + io_signature::make(0, 0, 0), + io_signature::make(0, 0, 0)), + QObject(parent) + { + // Required now for Qt; argc must be greater than 0 and argv + // must have at least one valid character. Must be valid through + // life of the qApplication: + // http://harmattan-dev.nokia.com/docs/library/html/qt4/qapplication.html + d_argc = 1; + d_argv = new char; + d_argv[0] = '\0'; + + if(qApp != NULL) { + d_qApplication = qApp; + } + else { +#if QT_VERSION >= 0x040500 + std::string style = prefs::singleton()->get_string("qtgui", "style", "raster"); + QApplication::setGraphicsSystem(QString(style.c_str())); +#endif + d_qApplication = new QApplication(d_argc, &d_argv); + } + + // If a style sheet is set in the prefs file, enable it here. + std::string qssfile = prefs::singleton()->get_string("qtgui","qss",""); + if(qssfile.size() > 0) { + QString sstext = get_qt_style_sheet(QString(qssfile.c_str())); + d_qApplication->setStyleSheet(sstext); + } + + d_is_pair = is_pair; + d_is_static = is_static; + + d_val = new QLineEdit(); + d_val->setObjectName("qtgui_editboxmsg_val"); // used to set background color + d_val->setText(QString(value.c_str())); + + set_type(type); + + d_group = new QGroupBox(); + d_vlayout = new QVBoxLayout(parent); + d_hlayout = new QHBoxLayout(parent); + + if(d_is_pair) { + d_key = new QLineEdit(); + + QString key_text = QString(key.c_str()); + d_key->setText(key_text); + + // If static, we create the d_key object, which we use later + // to be consistent about getting the key string. But we do + // not add it to the layout. + if(d_is_static) { + d_key->setEnabled(false); + + QFontMetrics fm = d_key->fontMetrics(); + int width = 15 + fm.width(key_text); + + d_key->setFixedWidth(width); + + // Verify that a default key has been set or emit an error + if(key.size() == 0) { + throw std::runtime_error("When using static + pair mode, please set a default key."); + } + } + else { + // Adding it to the layout if in non-static mode so users + // can see and update the key. + d_hlayout->addWidget(d_key); + } + } + + d_label = NULL; + if(label != "") { + d_label = new QLabel(QString(label.c_str())); + d_vlayout->addWidget(d_label); + } + + d_hlayout->addWidget(d_val); + + if(!d_is_static) { + // If not static, we can change the key and the data type of + // the value box. + d_type_box = new QComboBox(); + d_type_box->setEditable(false); + + // Items listed in order of enum data_type_t + d_type_box->addItem("Int"); + d_type_box->addItem("Float"); + d_type_box->addItem("Double"); + d_type_box->addItem("Complex"); + d_type_box->addItem("String"); + d_type_box->addItem("Int (vec)"); + d_type_box->addItem("Float (vec)"); + d_type_box->addItem("Double (vec)"); + d_type_box->addItem("Complex (vec)"); + d_type_box->setCurrentIndex(d_type); + d_hlayout->addWidget(d_type_box); + + QObject::connect(d_type_box, SIGNAL(currentIndexChanged(int)), + this, SLOT(set_type(int))); + } + + d_vlayout->addItem(d_hlayout); + d_group->setLayout(d_vlayout); + + QObject::connect(d_val, SIGNAL(editingFinished()), + this, SLOT(edit_finished())); + + d_msg = pmt::PMT_NIL; + + message_port_register_out(pmt::mp("msg")); + message_port_register_in(pmt::mp("val")); + + set_msg_handler(pmt::mp("val"), + boost::bind(&edit_box_msg_impl::set_value, this, _1)); + } + + edit_box_msg_impl::~edit_box_msg_impl() + { + delete d_argv; + delete d_group; + delete d_hlayout; + delete d_vlayout; + delete d_val; + if(d_is_pair) + delete d_key; + if(d_label) + delete d_label; + } + + bool + edit_box_msg_impl::start() + { + QString text = d_val->text(); + if(!text.isEmpty()) { + edit_finished(); + } + + return block::start(); + } + + void + edit_box_msg_impl::exec_() + { + d_qApplication->exec(); + } + + QWidget* + edit_box_msg_impl::qwidget() + { + return (QWidget*)d_group; + } + +#ifdef ENABLE_PYTHON + PyObject* + edit_box_msg_impl::pyqwidget() + { + PyObject *w = PyLong_FromVoidPtr((void*)d_group); + PyObject *retarg = Py_BuildValue("N", w); + return retarg; + } +#else + void * + edit_box_msg_impl::pyqwidget() + { + return NULL; + } +#endif + + void + edit_box_msg_impl::set_type(int type) + { + set_type(static_cast<data_type_t>(type)); + } + + void + edit_box_msg_impl::set_type(gr::qtgui::data_type_t type) + { + d_type = type; + + switch(d_type) { + case INT: + case INT_VEC: + d_val->setStyleSheet("QLineEdit#qtgui_editboxmsg_val {background-color: #4CAF50;}"); + break; + case FLOAT: + case FLOAT_VEC: + d_val->setStyleSheet("QLineEdit#qtgui_editboxmsg_val {background-color: #F57C00;}"); + break; + case DOUBLE: + case DOUBLE_VEC: + d_val->setStyleSheet("QLineEdit#qtgui_editboxmsg_val {background-color: #00BCD4;}"); + break; + case COMPLEX: + case COMPLEX_VEC: + d_val->setStyleSheet("QLineEdit#qtgui_editboxmsg_val {background-color: #2196F3;}"); + break; + case STRING: + d_val->setStyleSheet("QLineEdit#qtgui_editboxmsg_val {background-color: #FFFFFF; color: #000000;}"); + break; + } + } + + void + edit_box_msg_impl::set_value(pmt::pmt_t val) + { + // If the contents of the new value are the same as we already + // had, don't update anything, just exit and move on. + if(pmt::eqv(val, d_msg)) { + return; + } + + int xi; + float xf; + double xd; + std::string xs; + gr_complex xc; + + d_msg = val; + + // Only update key if we're expecting a pair + if(d_is_pair) { + // If we are, make sure that the PMT is actually a pair + if(pmt::is_pair(val)) { + pmt::pmt_t key = pmt::car(val); + std::string skey = pmt::symbol_to_string(key); + + // If static, check to make sure that the key of the + // incoming message matches our key. If it doesn't, emit a + // warning and exit without changing anything. + if(d_is_static) { + std::string cur_key = d_key->text().toStdString(); + if(skey != cur_key) { + GR_LOG_WARN(d_logger, boost::format("Got key '%1%' but expected '%2%'") \ + % skey % cur_key); + return; + } + } + val = pmt::cdr(val); + d_key->setText(QString(skey.c_str())); + } + else { + GR_LOG_WARN(d_logger, "Did not find PMT pair"); + return; + } + } + + switch(d_type) { + case INT: + if(pmt::is_integer(val)) { + xi = pmt::to_long(val); + d_val->setText(QString::number(xi)); + } + else { + GR_LOG_WARN(d_logger, "Conversion from integer failed"); + return; + } + break; + case INT_VEC: + if(pmt::is_s32vector(val)) { + QStringList text_list; + const std::vector<int32_t> xv = pmt::s32vector_elements(val); + for(size_t i = 0; i < xv.size(); i++) { + text_list.append(QString::number(xv[i])); + } + d_val->setText(text_list.join(", ")); + } + else { + GR_LOG_WARN(d_logger, "Conversion from integer vector failed"); + return; + } + break; + case FLOAT: + if(pmt::is_real(val)) { + xf = pmt::to_float(val); + d_val->setText(QString::number(xf)); + } + else { + GR_LOG_WARN(d_logger, "Conversion from float failed"); + return; + } + break; + case FLOAT_VEC: + if(pmt::is_f32vector(val)) { + QStringList text_list; + const std::vector<float> xv = pmt::f32vector_elements(val); + for(size_t i = 0; i < xv.size(); i++) { + text_list.append(QString::number(xv[i])); + } + d_val->setText(text_list.join(", ")); + } + else { + GR_LOG_WARN(d_logger, "Conversion from float vector failed"); + return; + } + break; + case DOUBLE: + if(pmt::is_real(val)) { + xd = pmt::to_double(val); + d_val->setText(QString::number(xd)); + } + else { + GR_LOG_WARN(d_logger, "Conversion from double failed"); + return; + } + break; + case DOUBLE_VEC: + if(pmt::is_f64vector(val)) { + QStringList text_list; + const std::vector<double> xv = pmt::f64vector_elements(val); + for(size_t i = 0; i < xv.size(); i++) { + text_list.append(QString::number(xv[i])); + } + d_val->setText(text_list.join(", ")); + } + else { + GR_LOG_WARN(d_logger, "Conversion from double vector failed"); + return; + } + break; + case COMPLEX: + if(pmt::is_complex(val)) { + xc = pmt::to_complex(val); + d_val->setText(QString("(%1,%2)").arg(xc.real()).arg(xc.imag())); + } + else { + GR_LOG_WARN(d_logger, "Conversion from complex failed"); + return; + } + break; + case COMPLEX_VEC: + if(pmt::is_c32vector(val)) { + QStringList text_list; + const std::vector<gr_complex> xv = pmt::c32vector_elements(val); + for(size_t i = 0; i < xv.size(); i++) { + text_list.append(QString("(%1,%2)").arg(xv[i].real()).arg(xv[i].imag())); + } + d_val->setText(text_list.join(", ")); + } + else { + GR_LOG_WARN(d_logger, "Conversion from complex vector failed"); + return; + } + break; + case STRING: + if(pmt::is_symbol(val)) { + xs = pmt::symbol_to_string(val); + d_val->setText(QString(xs.c_str())); + } + else { + GR_LOG_WARN(d_logger, "Conversion from string failed"); + return; + } + break; + } + + // Emit the new message to pass updates downstream. + // Loops are prevented by the early exit if d_msg == val. + message_port_pub(pmt::mp("msg"), d_msg); + } + + void + edit_box_msg_impl::edit_finished() + { + QString text = d_val->text(); + bool conv_ok = true; + int xi; + float xf; + double xd; + std::string xs; + gr_complex xc; + + switch(d_type) { + case INT: + xi = text.toInt(&conv_ok); + if(conv_ok) { + d_msg = pmt::from_long(xi); + } + else { + GR_LOG_WARN(d_logger, "Conversion to integer failed"); + return; + } + break; + case INT_VEC: + { + std::vector<int32_t> xv; + QStringList text_list = text.split(","); + for(int i = 0; i < text_list.size(); ++i) { + QString s = text_list.at(i); + s = s.remove(QChar(' ')); + int t = s.toInt(&conv_ok); + if(conv_ok) { + xv.push_back(t); + } + else { + GR_LOG_WARN(d_logger, "Conversion to integer vector failed"); + return; + } + } + d_msg = pmt::init_s32vector(xv.size(), xv); + } + break; + case FLOAT: + xf = text.toFloat(&conv_ok); + if(conv_ok) { + d_msg = pmt::from_float(xf); + } + else { + GR_LOG_WARN(d_logger, "Conversion to float failed"); + return; + } + break; + case FLOAT_VEC: + { + std::vector<float> xv; + QStringList text_list = text.split(","); + for(int i = 0; i < text_list.size(); ++i) { + QString s = text_list.at(i); + s = s.remove(QChar(' ')); + float t = s.toFloat(&conv_ok); + if(conv_ok) { + xv.push_back(t); + } + else { + GR_LOG_WARN(d_logger, "Conversion to float vector failed"); + return; + } + } + d_msg = pmt::init_f32vector(xv.size(), xv); + } + break; + case DOUBLE: + xd = text.toDouble(&conv_ok); + if(conv_ok) { + d_msg = pmt::from_double(xd); + } + else { + GR_LOG_WARN(d_logger, "Conversion to double failed"); + return; + } + break; + case DOUBLE_VEC: + { + std::vector<double> xv; + QStringList text_list = text.split(","); + for(int i = 0; i < text_list.size(); ++i) { + QString s = text_list.at(i); + s = s.remove(QChar(' ')); + double t = s.toDouble(&conv_ok); + if(conv_ok) { + xv.push_back(t); + } + else { + GR_LOG_WARN(d_logger, "Conversion to double vector failed"); + return; + } + } + d_msg = pmt::init_f64vector(xv.size(), xv); + } + break; + case COMPLEX: + try { + xc = boost::lexical_cast<gr_complex>(text.toStdString()); + } + catch(boost::bad_lexical_cast const & e) { + GR_LOG_WARN(d_logger, boost::format("Conversion to complex failed (%1%)") \ + % e.what()); + return; + } + d_msg = pmt::from_complex(xc.real(), xc.imag()); + break; + case COMPLEX_VEC: + { + std::vector<gr_complex> xv; + QStringList text_list = text.split(","); + bool even = false; + gr_complex c; + float re, im; + for(int i = 0; i < text_list.size(); ++i) { + QString s = text_list.at(i); + s = s.remove(QChar(' ')); + s = s.remove(QChar(')')); + s = s.remove(QChar('(')); + float t = s.toFloat(&conv_ok); + if(conv_ok) { + if(even) { + im = t; + xv.push_back(gr_complex(re, im)); + even = false; + } + else { + re = t; + even = true; + } + } + else { + GR_LOG_WARN(d_logger, "Conversion to complex vector failed"); + return; + } + } + d_msg = pmt::init_c32vector(xv.size(), xv); + } + break; + case STRING: + xs = text.toStdString(); + d_msg = pmt::intern(xs); + break; + } + + if(d_is_pair) { + std::string key = d_key->text().toStdString(); + d_msg = pmt::cons(pmt::intern(key), d_msg); + } + + message_port_pub(pmt::mp("msg"), d_msg); + } + + } /* namespace qtgui */ +} /* namespace gr */ diff --git a/gr-qtgui/lib/edit_box_msg_impl.h b/gr-qtgui/lib/edit_box_msg_impl.h new file mode 100644 index 0000000000..c60b3de9b0 --- /dev/null +++ b/gr-qtgui/lib/edit_box_msg_impl.h @@ -0,0 +1,93 @@ +/* -*- c++ -*- */ +/* + * Copyright 2016 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio 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 3, or (at your option) + * any later version. + * + * GNU Radio 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 GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifndef INCLUDED_QTGUI_EDIT_BOX_MSG_IMPL_H +#define INCLUDED_QTGUI_EDIT_BOX_MSG_IMPL_H + +#include <gnuradio/qtgui/edit_box_msg.h> +#include <QGroupBox> +#include <QVBoxLayout> +#include <QHBoxLayout> +#include <QLineEdit> +#include <QComboBox> +#include <QLabel> + +namespace gr { + namespace qtgui { + + class QTGUI_API edit_box_msg_impl + : public QObject, public edit_box_msg + { + Q_OBJECT + + private: + int d_argc; + char *d_argv; + data_type_t d_type; + bool d_is_pair; + bool d_is_static; + + QGroupBox *d_group; + QVBoxLayout *d_vlayout; + QHBoxLayout *d_hlayout; + QLabel *d_label; + QLineEdit *d_val; + QLineEdit *d_key; + QComboBox *d_type_box; + + pmt::pmt_t d_msg; + + public: + edit_box_msg_impl(gr::qtgui::data_type_t type, + const std::string &value="", + const std::string &label="", + bool is_pair=false, + bool is_static=true, + const std::string &key="", + QWidget* parent=0); + ~edit_box_msg_impl(); + + // Overload the start method of gr::block to emit a message if a + // default value is provided. + bool start(); + + void exec_(); + QWidget* qwidget(); + +#ifdef ENABLE_PYTHON + PyObject* pyqwidget(); +#else + void* pyqwidget(); +#endif + + void set_value(pmt::pmt_t val); + + public slots: + void edit_finished(); + void set_type(int); + void set_type(gr::qtgui::data_type_t type); + }; + + } /* namespace qtgui */ +} /* namespace gr */ + +#endif /* INCLUDED_QTGUI_EDIT_BOX_MSG_IMPL_H */ diff --git a/gr-qtgui/swig/qtgui_swig.i b/gr-qtgui/swig/qtgui_swig.i index 9664a71786..d9595e4d66 100644 --- a/gr-qtgui/swig/qtgui_swig.i +++ b/gr-qtgui/swig/qtgui_swig.i @@ -37,6 +37,18 @@ namespace gr { NUM_GRAPH_VERT, }; + enum data_type_t { + INT = 0, + FLOAT, + DOUBLE, + COMPLEX, + STRING, + INT_VEC, + FLOAT_VEC, + DOUBLE_VEC, + COMPLEX_VEC, + }; + } /* namespace qtgui */ } /* namespace gr */ @@ -75,6 +87,7 @@ enum{ #include "gnuradio/qtgui/number_sink.h" #include "gnuradio/qtgui/ber_sink_b.h" #include "gnuradio/qtgui/vector_sink_f.h" +#include "gnuradio/qtgui/edit_box_msg.h" %} %include "gnuradio/qtgui/sink_c.h" @@ -92,6 +105,7 @@ enum{ %include "gnuradio/qtgui/number_sink.h" %include "gnuradio/qtgui/ber_sink_b.h" %include "gnuradio/qtgui/vector_sink_f.h" +%include "gnuradio/qtgui/edit_box_msg.h" GR_SWIG_BLOCK_MAGIC2(qtgui, sink_c); GR_SWIG_BLOCK_MAGIC2(qtgui, sink_f); @@ -108,3 +122,4 @@ GR_SWIG_BLOCK_MAGIC2(qtgui, histogram_sink_f); GR_SWIG_BLOCK_MAGIC2(qtgui, number_sink); GR_SWIG_BLOCK_MAGIC2(qtgui, ber_sink_b); GR_SWIG_BLOCK_MAGIC2(qtgui, vector_sink_f); +GR_SWIG_BLOCK_MAGIC2(qtgui, edit_box_msg); |