diff options
author | jblum | 2009-05-01 20:28:04 +0000 |
---|---|---|
committer | jblum | 2009-05-01 20:28:04 +0000 |
commit | a3ba8cf268816af51c4bb39ea7ecd7e85ea0807b (patch) | |
tree | 21dbd446e92672a56b323e005088d3c03edc238f /grc | |
parent | 6ce881caaacdd60a8bea37584c7286e08bea97a7 (diff) | |
download | gnuradio-a3ba8cf268816af51c4bb39ea7ecd7e85ea0807b.tar.gz gnuradio-a3ba8cf268816af51c4bb39ea7ecd7e85ea0807b.tar.bz2 gnuradio-a3ba8cf268816af51c4bb39ea7ecd7e85ea0807b.zip |
Merged grc developer branch r10679:10938
Misc fixes and internal changes.
Added help menu for usage tips.
Added drag and drop for blocks.
Removed callback controls, adopted forms.
Any type can have enumerated options.
git-svn-id: http://gnuradio.org/svn/gnuradio/trunk@10941 221aa14e-8319-0410-a670-987f0aec2ac5
Diffstat (limited to 'grc')
80 files changed, 2906 insertions, 1627 deletions
diff --git a/grc/Makefile.inc b/grc/Makefile.inc index 8acd4e107..4d78070da 100644 --- a/grc/Makefile.inc +++ b/grc/Makefile.inc @@ -23,7 +23,6 @@ include $(top_srcdir)/Makefile.common grc_gnuradio_prefix = $(pythondir)/grc_gnuradio grc_src_prefix = $(pythondir)/gnuradio/grc grc_data_prefix = $(datadir)/$(PACKAGE)/grc -grc_examples_prefix = $(exampledir)/grc grc_base_data_dir = $(grc_data_prefix)/platforms/base grc_python_data_dir = $(grc_data_prefix)/platforms/python grc_python_blocks_dir = $(grc_data_prefix)/platforms/python/blocks diff --git a/grc/data/platforms/python/blocks/audio_sink.xml b/grc/data/platforms/python/blocks/audio_sink.xml index decaf2a08..75d583470 100644 --- a/grc/data/platforms/python/blocks/audio_sink.xml +++ b/grc/data/platforms/python/blocks/audio_sink.xml @@ -13,7 +13,7 @@ <name>Sample Rate</name> <key>samp_rate</key> <value>32000</value> - <type>enum</type> + <type>int</type> <option> <name>16KHz</name> <key>16000</key> @@ -44,7 +44,7 @@ <key>device_name</key> <value></value> <type>string</type> - <hide>#if $device_name.eval then 'none' else 'part'#</hide> + <hide>#if $device_name() then 'none' else 'part'#</hide> </param> <param> <name>OK to Block</name> diff --git a/grc/data/platforms/python/blocks/audio_source.xml b/grc/data/platforms/python/blocks/audio_source.xml index 21407dccd..1f5d1033e 100644 --- a/grc/data/platforms/python/blocks/audio_source.xml +++ b/grc/data/platforms/python/blocks/audio_source.xml @@ -13,7 +13,7 @@ <name>Sample Rate</name> <key>samp_rate</key> <value>32000</value> - <type>enum</type> + <type>int</type> <option> <name>16KHz</name> <key>16000</key> @@ -44,7 +44,7 @@ <key>device_name</key> <value></value> <type>string</type> - <hide>#if $device_name.eval then 'none' else 'part'#</hide> + <hide>#if $device_name() then 'none' else 'part'#</hide> </param> <param> <name>OK to Block</name> diff --git a/grc/data/platforms/python/blocks/blks2_rational_resampler_xxx.xml b/grc/data/platforms/python/blocks/blks2_rational_resampler_xxx.xml index 2f81a50e5..b92ec8ec2 100644 --- a/grc/data/platforms/python/blocks/blks2_rational_resampler_xxx.xml +++ b/grc/data/platforms/python/blocks/blks2_rational_resampler_xxx.xml @@ -12,12 +12,12 @@ <make>blks2.rational_resampler_$(type)( interpolation=$interp, decimation=$decim, -#if $taps.eval +#if $taps() taps=$taps, #else taps=None, #end if -#if $fractional_bw.eval != 0 +#if $fractional_bw() != 0 fractional_bw=$fractional_bw, #else fractional_bw=None, diff --git a/grc/data/platforms/python/blocks/gr_fft_vxx.xml b/grc/data/platforms/python/blocks/gr_fft_vxx.xml index c2c13d0ae..d398486ef 100644 --- a/grc/data/platforms/python/blocks/gr_fft_vxx.xml +++ b/grc/data/platforms/python/blocks/gr_fft_vxx.xml @@ -9,7 +9,7 @@ <key>gr_fft_vxx</key> <import>from gnuradio import gr</import> <import>from gnuradio import window</import> - <make>#if $type.eval == "complex" + <make>#if $type() == "complex" gr.fft_vcc($fft_size, $forward, $window, $shift) #else gr.fft_vfc($fft_size, $forward, $window) diff --git a/grc/data/platforms/python/blocks/gr_mute_xx.xml b/grc/data/platforms/python/blocks/gr_mute_xx.xml index 668d7c599..a9a857c6a 100644 --- a/grc/data/platforms/python/blocks/gr_mute_xx.xml +++ b/grc/data/platforms/python/blocks/gr_mute_xx.xml @@ -41,6 +41,14 @@ <key>mute</key> <value>False</value> <type>raw</type> + <option> + <name>True</name> + <key>True</key> + </option> + <option> + <name>False</name> + <key>False</key> + </option> </param> <sink> <name>in</name> diff --git a/grc/data/platforms/python/blocks/gr_noise_source_x.xml b/grc/data/platforms/python/blocks/gr_noise_source_x.xml index 664a108d3..4fcef5148 100644 --- a/grc/data/platforms/python/blocks/gr_noise_source_x.xml +++ b/grc/data/platforms/python/blocks/gr_noise_source_x.xml @@ -9,6 +9,7 @@ <key>gr_noise_source_x</key> <import>from gnuradio import gr</import> <make>gr.noise_source_$(type.fcn)($noise_type, $amp, $seed)</make> + <callback>set_type($noise_type)</callback> <callback>set_amplitude($amp)</callback> <param> <name>Output Type</name> @@ -39,7 +40,7 @@ <name>Noise Type</name> <key>noise_type</key> <value>gr.GR_GAUSSIAN</value> - <type>enum</type> + <type>raw</type> <option> <name>Uniform</name> <key>gr.GR_UNIFORM</key> diff --git a/grc/data/platforms/python/blocks/gr_sig_source_x.xml b/grc/data/platforms/python/blocks/gr_sig_source_x.xml index 53434c430..c329dba67 100644 --- a/grc/data/platforms/python/blocks/gr_sig_source_x.xml +++ b/grc/data/platforms/python/blocks/gr_sig_source_x.xml @@ -10,6 +10,7 @@ <import>from gnuradio import gr</import> <make>gr.sig_source_$(type.fcn)($samp_rate, $waveform, $freq, $amp, $offset)</make> <callback>set_sampling_freq($samp_rate)</callback> + <callback>set_waveform($waveform)</callback> <callback>set_frequency($freq)</callback> <callback>set_amplitude($amp)</callback> <callback>set_offset($offset)</callback> @@ -52,7 +53,7 @@ <name>Waveform</name> <key>waveform</key> <value>gr.GR_COS_WAVE</value> - <type>enum</type> + <type>raw</type> <option> <name>Constant</name> <key>gr.GR_CONST_WAVE</key> diff --git a/grc/data/platforms/python/blocks/gr_vector_sink_x.xml b/grc/data/platforms/python/blocks/gr_vector_sink_x.xml index d901b1d78..3bd998698 100644 --- a/grc/data/platforms/python/blocks/gr_vector_sink_x.xml +++ b/grc/data/platforms/python/blocks/gr_vector_sink_x.xml @@ -8,7 +8,7 @@ <name>Vector Sink</name> <key>gr_vector_sink_x</key> <import>from gnuradio import gr</import> - <make>gr.vector_sink_$(type.fcn)()</make> + <make>gr.vector_sink_$(type.fcn)($vlen)</make> <param> <name>Input Type</name> <key>type</key> @@ -39,8 +39,16 @@ <opt>fcn:b</opt> </option> </param> + <param> + <name>Vec Length</name> + <key>vlen</key> + <value>1</value> + <type>int</type> + </param> + <check>$vlen > 0</check> <sink> <name>in</name> <type>$type</type> + <vlen>$vlen</vlen> </sink> </block> diff --git a/grc/data/platforms/python/blocks/gr_vector_source_x.xml b/grc/data/platforms/python/blocks/gr_vector_source_x.xml index 240273e42..7a6a3aeff 100644 --- a/grc/data/platforms/python/blocks/gr_vector_source_x.xml +++ b/grc/data/platforms/python/blocks/gr_vector_source_x.xml @@ -8,7 +8,7 @@ <name>Vector Source</name> <key>gr_vector_source_x</key> <import>from gnuradio import gr</import> - <make>gr.vector_source_$(type.fcn)($vector, $repeat)</make> + <make>gr.vector_source_$(type.fcn)($vector, $repeat, $vlen)</make> <param> <name>Output Type</name> <key>type</key> @@ -64,8 +64,16 @@ <key>False</key> </option> </param> + <param> + <name>Vec Length</name> + <key>vlen</key> + <value>1</value> + <type>int</type> + </param> + <check>$vlen > 0</check> <source> <name>out</name> <type>$type</type> + <vlen>$vlen</vlen> </source> </block> diff --git a/grc/data/platforms/python/blocks/options.xml b/grc/data/platforms/python/blocks/options.xml index 11e46bbe6..07f659af9 100644 --- a/grc/data/platforms/python/blocks/options.xml +++ b/grc/data/platforms/python/blocks/options.xml @@ -10,10 +10,14 @@ <name>Options</name> <key>options</key> <import>from gnuradio import gr -#if $generate_options.eval == 'wx_gui' +#if $generate_options() == 'wx_gui' from grc_gnuradio import wxgui as grc_wxgui import wx #end if +#if $generate_options() != 'hb' +from optparse import OptionParser +from gnuradio.eng_option import eng_option +#end if </import> <make></make> <param> @@ -64,16 +68,16 @@ import wx <key>category</key> <value>Custom</value> <type>string</type> - <hide>#if $generate_options.eval == 'hb' then 'none' else 'all'#</hide> + <hide>#if $generate_options() == 'hb' then 'none' else 'all'#</hide> </param> <param> <name>Realtime Scheduling</name> <key>realtime_scheduling</key> <value></value> <type>enum</type> - <hide>#if $generate_options.eval == 'hb' + <hide>#if $generate_options() == 'hb' all#slurp -#elif $realtime_scheduling.eval +#elif $realtime_scheduling() none#slurp #else part#slurp diff --git a/grc/data/platforms/python/blocks/parameter.xml b/grc/data/platforms/python/blocks/parameter.xml index de2085011..e7bf61564 100644 --- a/grc/data/platforms/python/blocks/parameter.xml +++ b/grc/data/platforms/python/blocks/parameter.xml @@ -7,13 +7,13 @@ <block> <name>Parameter</name> <key>parameter</key> - <import>from optparse import OptionParser</import> <make>$value</make> <param> <name>Label</name> <key>label</key> <value></value> <type>string</type> + <hide>#if $label() then 'none' else 'part'#</hide> </param> <param> <name>Value</name> @@ -41,7 +41,7 @@ </option> <option> <name>Float</name> - <key>float</key> + <key>eng_float</key> <opt>type:real</opt> <opt>hide:none</opt> </option> @@ -65,12 +65,14 @@ </option> </param> <doc> -This block represents a parameter to the flow graph, \ -used when the flow graph is instantiated as a hier block. +This block represents a parameter to the flow graph. \ +A parameter can be used to pass command line arguments into a top block. \ +Or, parameters can pass arguments into an instantiated hierarchical block. The paramater value cannot depend on any variables. -Leave the label blank to use the parameter id as the label. +Leave the label blank to use the parameter id as the label. \ +The label only applies when this flow graph is instantiated as a hierarchical block. When type is not None, this parameter also becomes a command line option of the form --[id] [value]. </doc> diff --git a/grc/data/platforms/python/blocks/probe_function.xml b/grc/data/platforms/python/blocks/probe_function.xml index d46878526..ac0b3dcde 100644 --- a/grc/data/platforms/python/blocks/probe_function.xml +++ b/grc/data/platforms/python/blocks/probe_function.xml @@ -9,7 +9,7 @@ <key>probe_function</key> <import>from grc_gnuradio import blks2 as grc_blks2</import> <make>grc_blks2.probe_function( - probe_callback=self.$(block_id.eval).$(function_name.eval), + probe_callback=self.$(block_id()).$(function_name()), probe_rate=$probe_rate, )</make> <callback>set_probe_rate($probe_rate)</callback> diff --git a/grc/data/platforms/python/blocks/usrp2_sink_xxxx.xml b/grc/data/platforms/python/blocks/usrp2_sink_xxxx.xml index e6e315786..264ed4f20 100644 --- a/grc/data/platforms/python/blocks/usrp2_sink_xxxx.xml +++ b/grc/data/platforms/python/blocks/usrp2_sink_xxxx.xml @@ -8,9 +8,9 @@ <name>USRP2 Sink</name> <key>usrp2_sink_xxxx</key> <import>from gnuradio import usrp2</import> - <make>#if not $interface.eval and not $mac_addr.eval + <make>#if not $interface() and not $mac_addr() usrp2.sink_$(type.fcn)() -#elif not $mac_addr.eval +#elif not $mac_addr() usrp2.sink_$(type.fcn)($interface) #else usrp2.sink_$(type.fcn)($interface, $mac_addr) diff --git a/grc/data/platforms/python/blocks/usrp2_source_xxxx.xml b/grc/data/platforms/python/blocks/usrp2_source_xxxx.xml index 8b8ae3248..54bea7a49 100644 --- a/grc/data/platforms/python/blocks/usrp2_source_xxxx.xml +++ b/grc/data/platforms/python/blocks/usrp2_source_xxxx.xml @@ -8,9 +8,9 @@ <name>USRP2 Source</name> <key>usrp2_source_xxxx</key> <import>from gnuradio import usrp2</import> - <make>#if not $interface.eval and not $mac_addr.eval + <make>#if not $interface() and not $mac_addr() usrp2.source_$(type.fcn)() -#elif not $mac_addr.eval +#elif not $mac_addr() usrp2.source_$(type.fcn)($interface) #else usrp2.source_$(type.fcn)($interface, $mac_addr) diff --git a/grc/data/platforms/python/blocks/usrp_dual_source_x.xml b/grc/data/platforms/python/blocks/usrp_dual_source_x.xml index 823850b52..cb75fcead 100644 --- a/grc/data/platforms/python/blocks/usrp_dual_source_x.xml +++ b/grc/data/platforms/python/blocks/usrp_dual_source_x.xml @@ -8,8 +8,8 @@ <name>USRP Dual Source</name> <key>usrp_dual_source_x</key> <import>from grc_gnuradio import usrp as grc_usrp</import> - <make>grc_usrp.dual_source_$(type.fcn)(which=$which, rx_ant_a='$rx_ant_a', rx_ant_b='$rx_ant_b') -#if $format.eval + <make>grc_usrp.dual_source_$(type.fcn)(which=$which, rx_ant_a=$rx_ant_a, rx_ant_b=$rx_ant_b) +#if $format() self.$(id).set_format(width=$format.width, shift=$format.shift) #end if self.$(id).set_decim_rate($decimation) @@ -42,7 +42,7 @@ self.$(id).set_gain_b($gain_b)</make> <key>format</key> <value></value> <type>enum</type> - <hide>#if $format.eval then '' else 'part'#</hide> + <hide>#if $format() then '' else 'part'#</hide> <option> <name>16 Bits (Default)</name> <key></key> @@ -95,7 +95,8 @@ self.$(id).set_gain_b($gain_b)</make> <param> <name>RX Antenna A</name> <key>rx_ant_a</key> - <type>enum</type> + <value>RXA</value> + <type>string</type> <option> <name>RXA</name> <key>RXA</key> @@ -125,7 +126,8 @@ self.$(id).set_gain_b($gain_b)</make> <param> <name>RX Antenna B</name> <key>rx_ant_b</key> - <type>enum</type> + <value>RXA</value> + <type>string</type> <option> <name>RXA</name> <key>RXA</key> diff --git a/grc/data/platforms/python/blocks/usrp_simple_sink_x.xml b/grc/data/platforms/python/blocks/usrp_simple_sink_x.xml index ca887997a..0c7fc53da 100644 --- a/grc/data/platforms/python/blocks/usrp_simple_sink_x.xml +++ b/grc/data/platforms/python/blocks/usrp_simple_sink_x.xml @@ -8,7 +8,7 @@ <name>USRP Sink</name> <key>usrp_simple_sink_x</key> <import>from grc_gnuradio import usrp as grc_usrp</import> - <make>grc_usrp.simple_sink_$(type.fcn)(which=$which, side='$side') + <make>grc_usrp.simple_sink_$(type.fcn)(which=$which, side=$side) self.$(id).set_interp_rate($interpolation) self.$(id).set_frequency($frequency, verbose=True) self.$(id).set_gain($gain) @@ -61,13 +61,13 @@ self.$(id).set_auto_tr(True) <name>Side</name> <key>side</key> <value>A</value> - <type>enum</type> + <type>string</type> <option> - <name>Side A</name> + <name>A</name> <key>A</key> </option> <option> - <name>Side B</name> + <name>B</name> <key>B</key> </option> </param> diff --git a/grc/data/platforms/python/blocks/usrp_simple_source_x.xml b/grc/data/platforms/python/blocks/usrp_simple_source_x.xml index d7f5475a6..8d7b9533d 100644 --- a/grc/data/platforms/python/blocks/usrp_simple_source_x.xml +++ b/grc/data/platforms/python/blocks/usrp_simple_source_x.xml @@ -8,8 +8,8 @@ <name>USRP Source</name> <key>usrp_simple_source_x</key> <import>from grc_gnuradio import usrp as grc_usrp</import> - <make>grc_usrp.simple_source_$(type.fcn)(which=$which, side='$side', rx_ant='$rx_ant'#if $hb_filters.eval then ', no_hb=True' else ''#) -#if $format.eval + <make>grc_usrp.simple_source_$(type.fcn)(which=$which, side=$side, rx_ant=$rx_ant#if $hb_filters() then ', no_hb=True' else ''#) +#if $format() self.$(id).set_format(width=$format.width, shift=$format.shift) #end if self.$(id).set_decim_rate($decimation) @@ -38,7 +38,7 @@ self.$(id).set_gain($gain)</make> <key>format</key> <value></value> <type>enum</type> - <hide>#if $format.eval then '' else 'part'#</hide> + <hide>#if $format() then '' else 'part'#</hide> <option> <name>16 Bits (Default)</name> <key></key> @@ -77,13 +77,13 @@ self.$(id).set_gain($gain)</make> <name>Side</name> <key>side</key> <value>A</value> - <type>enum</type> + <type>string</type> <option> - <name>Side A</name> + <name>A</name> <key>A</key> </option> <option> - <name>Side B</name> + <name>B</name> <key>B</key> </option> </param> @@ -91,7 +91,7 @@ self.$(id).set_gain($gain)</make> <name>RX Antenna</name> <key>rx_ant</key> <value>RXA</value> - <type>enum</type> + <type>string</type> <option> <name>RXA</name> <key>RXA</key> @@ -118,7 +118,7 @@ self.$(id).set_gain($gain)</make> <key>hb_filters</key> <value></value> <type>enum</type> - <hide>#if $hb_filters.eval then 'none' else 'part'#</hide> + <hide>#if $hb_filters() then 'none' else 'part'#</hide> <option> <name>Enable</name> <key></key> diff --git a/grc/data/platforms/python/blocks/variable_chooser.xml b/grc/data/platforms/python/blocks/variable_chooser.xml index 2a00a1cf2..6827c3675 100644 --- a/grc/data/platforms/python/blocks/variable_chooser.xml +++ b/grc/data/platforms/python/blocks/variable_chooser.xml @@ -1,42 +1,51 @@ <?xml version="1.0"?> <!-- ################################################### -##Variable Chooser: a grc variable with multiple choices +##Variable Chooser: +## a gui form with enumerated choices +## radio buttons, drop down, or button ################################################### --> <block> <name>Variable Chooser</name> <key>variable_chooser</key> - <make>$(choices)[$value_index] -_$(id)_control = grc_wxgui.$(chooser_type)_control( - window=self.GetWin(), - callback=self.set_$(id), - #if $label.eval + <import>from grc_gnuradio.wxgui import forms</import> + <make>$value +self['$id'] = $id +self.subscribe('$id', self.set_$(id)) +self._$(id)_control = forms.$(type)( + parent=self.GetWin(), + ps=self, + key='$id', + #if $label() label=$label, - #else + #else label='$id', - #end if - index=$value_index, + #end if choices=$choices, labels=$labels, +#if $type() == 'radio_buttons' + style=$style, +#end if ) -#set $grid_pos = $grid_pos.eval +#set $grid_pos = $grid_pos() #if not grid_pos -self.Add(_$(id)_control) +self.Add(self._$(id)_control) #else -self.GridAdd(_$(id)_control, $grid_pos[0], $grid_pos[1], $grid_pos[2], $grid_pos[3]) +self.GridAdd(self._$(id)_control, $grid_pos[0], $grid_pos[1], $grid_pos[2], $grid_pos[3]) #end if</make> <param> <name>Label</name> <key>label</key> <value></value> <type>string</type> + <hide>#if $label() then 'none' else 'part'#</hide> </param> <param> - <name>Value Index</name> - <key>value_index</key> - <value>0</value> - <type>int</type> + <name>Default Value</name> + <key>value</key> + <value>1</value> + <type>raw</type> </param> <param> <name>Choices</name> @@ -51,8 +60,8 @@ self.GridAdd(_$(id)_control, $grid_pos[0], $grid_pos[1], $grid_pos[2], $grid_pos <type>raw</type> </param> <param> - <name>Chooser Type</name> - <key>chooser_type</key> + <name>Type</name> + <key>type</key> <value>drop_down</value> <type>enum</type> <option> @@ -60,12 +69,8 @@ self.GridAdd(_$(id)_control, $grid_pos[0], $grid_pos[1], $grid_pos[2], $grid_pos <key>drop_down</key> </option> <option> - <name>Radio Buttons Horizontal</name> - <key>radio_buttons_horizontal</key> - </option> - <option> - <name>Radio Buttons Vertical</name> - <key>radio_buttons_vertical</key> + <name>Radio Buttons</name> + <key>radio_buttons</key> </option> <option> <name>Button</name> @@ -73,12 +78,27 @@ self.GridAdd(_$(id)_control, $grid_pos[0], $grid_pos[1], $grid_pos[2], $grid_pos </option> </param> <param> + <name>Style</name> + <key>style</key> + <value>wx.RA_HORIZONTAL</value> + <type>enum</type> + <hide>#if $type() == 'radio_buttons' then 'part' else 'all'#</hide> + <option> + <name>Horizontal</name> + <key>wx.RA_HORIZONTAL</key> + </option> + <option> + <name>Vertical</name> + <key>wx.RA_VERTICAL</key> + </option> + </param> + <param> <name>Grid Position</name> <key>grid_pos</key> <value></value> <type>grid_pos</type> </param> - <check>$value_index in range(len($choices))</check> + <check>$value in $choices</check> <check>not $labels or len($labels) == len($choices)</check> <doc> This block creates a variable with a drop down, radio buttons, or a button. \ diff --git a/grc/data/platforms/python/blocks/variable_sink.xml b/grc/data/platforms/python/blocks/variable_sink.xml index 87575ae1b..426bd34fb 100644 --- a/grc/data/platforms/python/blocks/variable_sink.xml +++ b/grc/data/platforms/python/blocks/variable_sink.xml @@ -15,13 +15,13 @@ def _$(id)_run(): while True: time.sleep(1.0/$samp_rate) data = self.$(id).data() -#if $vlen.eval == 0 +#if $vlen() == 0 if data: - self.set_$(variable.eval)(data[-1]) + self.set_$(variable())(data[-1]) self.$(id).clear() #else if len(data) >= $vlen: - self.set_$(variable.eval)(data[-($vlen):]) + self.set_$(variable())(data[-($vlen):]) self.$(id).clear() #end if threading.Thread(target=_$(id)_run).start()</make> diff --git a/grc/data/platforms/python/blocks/variable_slider.xml b/grc/data/platforms/python/blocks/variable_slider.xml index 635f3ed4c..9c8e7ece9 100644 --- a/grc/data/platforms/python/blocks/variable_slider.xml +++ b/grc/data/platforms/python/blocks/variable_slider.xml @@ -1,38 +1,55 @@ <?xml version="1.0"?> <!-- ################################################### -##Variable Slider: a grc variable with key, value, min, max, step +##Variable Slider: +## a combined slider and text box form ################################################### --> <block> <name>Variable Slider</name> <key>variable_slider</key> + <import>from grc_gnuradio.wxgui import forms</import> <make>$value -_$(id)_control = grc_wxgui.slider_$(slider_type)_control( - window=self.GetWin(), - callback=self.set_$(id), - #if $label.eval +self['$id'] = $id +self.subscribe('$id', self.set_$(id)) +self._$(id)_sizer = wx.BoxSizer(wx.VERTICAL) +forms.text_box( + parent=self.GetWin(), + sizer=self._$(id)_sizer, + ps=self, + key='$id', + #if $label() label=$label, - #else + #else label='$id', - #end if - value=$id, - min=$min, - max=$max, + #end if + converter=forms.$(converver)(), + proportion=0, +) +forms.slider( + parent=self.GetWin(), + sizer=self._$(id)_sizer, + ps=self, + key='$id', + minimum=$min, + maximum=$max, num_steps=$num_steps, - slider_length=$slider_length, + style=$style, + cast=$(converver.slider_cast), + proportion=1, ) -#set $grid_pos = $grid_pos.eval +#set $grid_pos = $grid_pos() #if not grid_pos -self.Add(_$(id)_control) +self.Add(self._$(id)_sizer) #else -self.GridAdd(_$(id)_control, $grid_pos[0], $grid_pos[1], $grid_pos[2], $grid_pos[3]) +self.GridAdd(self._$(id)_sizer, $grid_pos[0], $grid_pos[1], $grid_pos[2], $grid_pos[3]) #end if</make> <param> <name>Label</name> <key>label</key> <value></value> <type>string</type> + <hide>#if $label() then 'none' else 'part'#</hide> </param> <param> <name>Default Value</name> @@ -60,24 +77,34 @@ self.GridAdd(_$(id)_control, $grid_pos[0], $grid_pos[1], $grid_pos[2], $grid_pos <hide>part</hide> </param> <param> - <name>Slider Length (px)</name> - <key>slider_length</key> - <value>200</value> - <type>int</type> + <name>Style</name> + <key>style</key> + <value>wx.SL_HORIZONTAL</value> + <type>enum</type> <hide>part</hide> + <option> + <name>Horizontal</name> + <key>wx.SL_HORIZONTAL</key> + </option> + <option> + <name>Vertical</name> + <key>wx.SL_VERTICAL</key> + </option> </param> <param> - <name>Slider Type</name> - <key>slider_type</key> - <value>horizontal</value> + <name>Converter</name> + <key>converver</key> + <value>float_converter</value> <type>enum</type> <option> - <name>Horizontal</name> - <key>horizontal</key> + <name>Float</name> + <key>float_converter</key> + <opt>slider_cast:float</opt> </option> <option> - <name>Vertical</name> - <key>vertical</key> + <name>Integer</name> + <key>int_converter</key> + <opt>slider_cast:int</opt> </option> </param> <param> diff --git a/grc/data/platforms/python/blocks/variable_text_box.xml b/grc/data/platforms/python/blocks/variable_text_box.xml index 97c6aa0d9..2857fa366 100644 --- a/grc/data/platforms/python/blocks/variable_text_box.xml +++ b/grc/data/platforms/python/blocks/variable_text_box.xml @@ -1,34 +1,40 @@ <?xml version="1.0"?> <!-- ################################################### -##Variable Text Box: a grc variable with key, value +##Variable Text Box: +## a gui text box form ################################################### --> <block> <name>Variable Text Box</name> <key>variable_text_box</key> + <import>from grc_gnuradio.wxgui import forms</import> <make>$value -_$(id)_control = grc_wxgui.text_box_control( - window=self.GetWin(), - callback=self.set_$(id), - #if $label.eval +self['$id'] = $id +self.subscribe('$id', self.set_$(id)) +self._$(id)_control = forms.text_box( + parent=self.GetWin(), + ps=self, + key='$id', + #if $label() label=$label, - #else + #else label='$id', - #end if - value=$id, + #end if + converter=forms.$(converver)(), ) -#set $grid_pos = $grid_pos.eval +#set $grid_pos = $grid_pos() #if not grid_pos -self.Add(_$(id)_control) +self.Add(self._$(id)_control) #else -self.GridAdd(_$(id)_control, $grid_pos[0], $grid_pos[1], $grid_pos[2], $grid_pos[3]) +self.GridAdd(self._$(id)_control, $grid_pos[0], $grid_pos[1], $grid_pos[2], $grid_pos[3]) #end if</make> <param> <name>Label</name> <key>label</key> <value></value> <type>string</type> + <hide>#if $label() then 'none' else 'part'#</hide> </param> <param> <name>Default Value</name> @@ -37,6 +43,28 @@ self.GridAdd(_$(id)_control, $grid_pos[0], $grid_pos[1], $grid_pos[2], $grid_pos <type>raw</type> </param> <param> + <name>Converter</name> + <key>converver</key> + <value>float_converter</value> + <type>enum</type> + <option> + <name>Float</name> + <key>float_converter</key> + </option> + <option> + <name>Integer</name> + <key>int_converter</key> + </option> + <option> + <name>String</name> + <key>str_converter</key> + </option> + <option> + <name>Evaluate</name> + <key>eval_converter</key> + </option> + </param> + <param> <name>Grid Position</name> <key>grid_pos</key> <value></value> diff --git a/grc/data/platforms/python/blocks/wxgui_constellationsink2.xml b/grc/data/platforms/python/blocks/wxgui_constellationsink2.xml index 69869904f..471c9f4a8 100644 --- a/grc/data/platforms/python/blocks/wxgui_constellationsink2.xml +++ b/grc/data/platforms/python/blocks/wxgui_constellationsink2.xml @@ -23,7 +23,7 @@ symbol_rate=$symbol_rate, omega_limit=$omega_limit, ) -#set $grid_pos = $grid_pos.eval +#set $grid_pos = $grid_pos() #if not grid_pos self.Add(self.$(id).win) #else diff --git a/grc/data/platforms/python/blocks/wxgui_fftsink2.xml b/grc/data/platforms/python/blocks/wxgui_fftsink2.xml index c729bea4b..31680f7bd 100644 --- a/grc/data/platforms/python/blocks/wxgui_fftsink2.xml +++ b/grc/data/platforms/python/blocks/wxgui_fftsink2.xml @@ -17,11 +17,11 @@ fft_size=$fft_size, fft_rate=$fft_rate, average=$average, - avg_alpha=#if $avg_alpha.eval then $avg_alpha else 'None'#, + avg_alpha=#if $avg_alpha() then $avg_alpha else 'None'#, title=$title, peak_hold=$peak_hold, ) -#set $grid_pos = $grid_pos.eval +#set $grid_pos = $grid_pos() #if not grid_pos self.Add(self.$(id).win) #else @@ -112,7 +112,7 @@ self.GridAdd(self.$(id).win, $grid_pos[0], $grid_pos[1], $grid_pos[2], $grid_pos <key>peak_hold</key> <value>False</value> <type>enum</type> - <hide>#if $peak_hold.eval == 'True' then 'none' else 'part'#</hide> + <hide>#if $peak_hold() == 'True' then 'none' else 'part'#</hide> <option> <name>On</name> <key>True</key> @@ -127,7 +127,7 @@ self.GridAdd(self.$(id).win, $grid_pos[0], $grid_pos[1], $grid_pos[2], $grid_pos <key>average</key> <value>False</value> <type>enum</type> - <hide>#if $average.eval == 'True' then 'none' else 'part'#</hide> + <hide>#if $average() == 'True' then 'none' else 'part'#</hide> <option> <name>On</name> <key>True</key> @@ -142,7 +142,7 @@ self.GridAdd(self.$(id).win, $grid_pos[0], $grid_pos[1], $grid_pos[2], $grid_pos <key>avg_alpha</key> <value>0</value> <type>real</type> - <hide>#if $average.eval == 'True' then 'none' else 'all'#</hide> + <hide>#if $average() == 'True' then 'none' else 'all'#</hide> </param> <param> <name>Grid Position</name> diff --git a/grc/data/platforms/python/blocks/wxgui_histosink2.xml b/grc/data/platforms/python/blocks/wxgui_histosink2.xml index 3d694aedc..4de57b1c4 100644 --- a/grc/data/platforms/python/blocks/wxgui_histosink2.xml +++ b/grc/data/platforms/python/blocks/wxgui_histosink2.xml @@ -14,7 +14,7 @@ num_bins=$num_bins, frame_size=$frame_size, ) -#set $grid_pos = $grid_pos.eval +#set $grid_pos = $grid_pos() #if not grid_pos self.Add(self.$(id).win) #else diff --git a/grc/data/platforms/python/blocks/wxgui_numbersink2.xml b/grc/data/platforms/python/blocks/wxgui_numbersink2.xml index 1b32993e1..af0281f6a 100644 --- a/grc/data/platforms/python/blocks/wxgui_numbersink2.xml +++ b/grc/data/platforms/python/blocks/wxgui_numbersink2.xml @@ -20,12 +20,12 @@ sample_rate=$samp_rate, number_rate=$number_rate, average=$average, - avg_alpha=#if $avg_alpha.eval then $avg_alpha else 'None'#, + avg_alpha=#if $avg_alpha() then $avg_alpha else 'None'#, label=$title, peak_hold=$peak_hold, show_gauge=$show_gauge, ) -#set $grid_pos = $grid_pos.eval +#set $grid_pos = $grid_pos() #if not grid_pos self.Add(self.$(id).win) #else @@ -112,7 +112,7 @@ self.GridAdd(self.$(id).win, $grid_pos[0], $grid_pos[1], $grid_pos[2], $grid_pos <key>peak_hold</key> <value>False</value> <type>enum</type> - <hide>#if $peak_hold.eval == 'True' then 'none' else 'part'#</hide> + <hide>#if $peak_hold() == 'True' then 'none' else 'part'#</hide> <option> <name>On</name> <key>True</key> @@ -127,7 +127,7 @@ self.GridAdd(self.$(id).win, $grid_pos[0], $grid_pos[1], $grid_pos[2], $grid_pos <key>average</key> <value>False</value> <type>enum</type> - <hide>#if $average.eval == 'True' then 'none' else 'part'#</hide> + <hide>#if $average() == 'True' then 'none' else 'part'#</hide> <option> <name>On</name> <key>True</key> @@ -142,7 +142,7 @@ self.GridAdd(self.$(id).win, $grid_pos[0], $grid_pos[1], $grid_pos[2], $grid_pos <key>avg_alpha</key> <value>0</value> <type>real</type> - <hide>#if $average.eval == 'True' then 'none' else 'all'#</hide> + <hide>#if $average() == 'True' then 'none' else 'all'#</hide> </param> <param> <name>Show Gauge</name> diff --git a/grc/data/platforms/python/blocks/wxgui_scopesink2.xml b/grc/data/platforms/python/blocks/wxgui_scopesink2.xml index 1af0afb35..78c39f80d 100644 --- a/grc/data/platforms/python/blocks/wxgui_scopesink2.xml +++ b/grc/data/platforms/python/blocks/wxgui_scopesink2.xml @@ -19,7 +19,7 @@ xy_mode=$xy_mode, num_inputs=$num_inputs, ) -#set $grid_pos = $grid_pos.eval +#set $grid_pos = $grid_pos() #if not grid_pos self.Add(self.$(id).win) #else @@ -71,7 +71,7 @@ self.GridAdd(self.$(id).win, $grid_pos[0], $grid_pos[1], $grid_pos[2], $grid_pos <key>ac_couple</key> <value>False</value> <type>enum</type> - <hide>#if $ac_couple.eval == 'True' then 'none' else 'part'#</hide> + <hide>#if $ac_couple() == 'True' then 'none' else 'part'#</hide> <option> <name>Off</name> <key>False</key> @@ -86,7 +86,7 @@ self.GridAdd(self.$(id).win, $grid_pos[0], $grid_pos[1], $grid_pos[2], $grid_pos <key>xy_mode</key> <value>False</value> <type>enum</type> - <hide>#if $xy_mode.eval == 'True' then 'none' else 'part'#</hide> + <hide>#if $xy_mode() == 'True' then 'none' else 'part'#</hide> <option> <name>Off</name> <key>False</key> diff --git a/grc/data/platforms/python/blocks/wxgui_waterfallsink2.xml b/grc/data/platforms/python/blocks/wxgui_waterfallsink2.xml index 68d84dbba..6d76ee867 100644 --- a/grc/data/platforms/python/blocks/wxgui_waterfallsink2.xml +++ b/grc/data/platforms/python/blocks/wxgui_waterfallsink2.xml @@ -17,10 +17,10 @@ fft_size=$fft_size, fft_rate=$fft_rate, average=$options.average, - avg_alpha=#if $avg_alpha.eval then $avg_alpha else 'None'#, + avg_alpha=#if $avg_alpha() then $avg_alpha else 'None'#, title=$title, ) -#set $grid_pos = $grid_pos.eval +#set $grid_pos = $grid_pos() #if not grid_pos self.Add(self.$(id).win) #else diff --git a/grc/data/platforms/python/blocks/xmlrpc_client.xml b/grc/data/platforms/python/blocks/xmlrpc_client.xml index f132a7865..dc4d154d1 100644 --- a/grc/data/platforms/python/blocks/xmlrpc_client.xml +++ b/grc/data/platforms/python/blocks/xmlrpc_client.xml @@ -8,8 +8,8 @@ <name>XMLRPC Client</name> <key>xmlrpc_client</key> <import>import xmlrpclib</import> - <make>xmlrpclib.Server('http://$(addr.eval):$(port)')</make> - <callback>$(callback.eval)($variable)</callback> + <make>xmlrpclib.Server('http://$(addr()):$(port)')</make> + <callback>$(callback())($variable)</callback> <param> <name>Address</name> <key>addr</key> diff --git a/grc/data/platforms/python/flow_graph.tmpl b/grc/data/platforms/python/flow_graph.tmpl index a84b4eb0a..4c481dce4 100644 --- a/grc/data/platforms/python/flow_graph.tmpl +++ b/grc/data/platforms/python/flow_graph.tmpl @@ -39,13 +39,12 @@ $imp ## Setup the IO signature (hier block only). ######################################################## #set $class_name = $flow_graph.get_option('id') -#set $param_str = ', '.join(['self'] + ['%s=%s'%(param.get_id(), param.get_make()) for param in $parameters]) #if $generate_options == 'wx_gui' #import gtk #set $icon = gtk.IconTheme().lookup_icon('gnuradio-grc', 32, 0) class $(class_name)(grc_wxgui.top_block_gui): - def __init__($param_str): + def __init__(self, options): grc_wxgui.top_block_gui.__init__( self, title="$flow_graph.get_parent().get_name() - Executing: $flow_graph.get_option('title')", @@ -56,11 +55,12 @@ class $(class_name)(grc_wxgui.top_block_gui): #elif $generate_options == 'no_gui' class $(class_name)(gr.top_block): - def __init__($param_str): + def __init__(self, options): gr.top_block.__init__(self, "$flow_graph.get_option('title')") #elif $generate_options == 'hb' #set $in_sig = $flow_graph.get_input_signature() #set $out_sig = $flow_graph.get_output_signature() + #set $param_str = ', '.join(['self'] + ['%s=%s'%(param.get_id(), param.get_make()) for param in $parameters]) class $(class_name)(gr.hier_block2): def __init__($param_str): @@ -73,7 +73,7 @@ class $(class_name)(gr.hier_block2): #end if ######################################################## ##Create Parameters -## Set the parameter to a property of self.. +## Set the parameter to a property of self. ######################################################## #if $parameters @@ -82,7 +82,11 @@ class $(class_name)(gr.hier_block2): $DIVIDER #end if #for $param in $parameters + #if $generate_options != 'hb' + self.$param.get_id() = $param.get_id() = options.$param.get_id() + #else self.$param.get_id() = $param.get_id() + #end if #end for ######################################################## ##Create Variables @@ -179,23 +183,19 @@ class $(class_name)(gr.hier_block2): ######################################################## #if $generate_options != 'hb' if __name__ == '__main__': - #set $args = list() - #if $parameters - parser = OptionParser() - #for $param in $parameters - #set $type = $param.get_param('type').get_value() - #if $type + parser = OptionParser(option_class=eng_option, usage="%prog: [options]") + #for $param in $parameters + #set $type = $param.get_param('type').get_value() + #if $type parser.add_option("--$param.get_id()", dest="$param.get_id()", type="$type", default=$param.get_make()) - #silent $args.append('%s=options.%s'%($param.get_id(), $param.get_id())) - #end if - #end for + #end if + #end for (options, args) = parser.parse_args() - #end if #if $flow_graph.get_option('realtime_scheduling') if gr.enable_realtime_scheduling() != gr.RT_OK: print "Error: failed to enable realtime scheduling." #end if - tb = $(class_name)($(', '.join($args))) + tb = $(class_name)(options) #if $generate_options == 'wx_gui' tb.Run() #elif $generate_options == 'no_gui' diff --git a/grc/examples/Makefile.am b/grc/examples/Makefile.am index d129cf6ba..9a2fbd53d 100644 --- a/grc/examples/Makefile.am +++ b/grc/examples/Makefile.am @@ -1,5 +1,5 @@ # -# Copyright 2008 Free Software Foundation, Inc. +# Copyright 2009 Free Software Foundation, Inc. # # This file is part of GNU Radio # @@ -19,11 +19,35 @@ # Boston, MA 02110-1301, USA. # -include $(top_srcdir)/grc/Makefile.inc +include $(top_srcdir)/Makefile.common -SUBDIRS = \ - audio \ - simple \ - trellis \ - usrp \ - xmlrpc +grc_examples_prefix = $(exampledir)/grc + +audiodatadir = $(grc_examples_prefix)/audio +dist_audiodata_DATA = \ + audio/dial_tone.grc + +simpledatadir = $(grc_examples_prefix)/simple +dist_simpledata_DATA = \ + simple/ber_simulation.grc \ + simple/dpsk_loopback.grc + +trellisdatadir = $(grc_examples_prefix)/trellis +dist_trellisdata_DATA = \ + trellis/readme.txt \ + trellis/interference_cancellation.grc + +usrpdatadir = $(grc_examples_prefix)/usrp +dist_usrpdata_DATA = \ + usrp/usrp2_const_wave.grc \ + usrp/usrp2_dpsk_mod.grc \ + usrp/usrp2_fft.grc \ + usrp/usrp_two_tone_loopback.grc \ + usrp/usrp_wbfm_receive.grc + +xmlrpcdatadir = $(grc_examples_prefix)/xmlrpc +dist_xmlrpcdata_DATA = \ + xmlrpc/readme.txt \ + xmlrpc/xmlrpc_client.grc \ + xmlrpc/xmlrpc_client_script.py\ + xmlrpc/xmlrpc_server.grc diff --git a/grc/examples/audio/Makefile.am b/grc/examples/audio/Makefile.am deleted file mode 100644 index f9604c34f..000000000 --- a/grc/examples/audio/Makefile.am +++ /dev/null @@ -1,26 +0,0 @@ -# -# Copyright 2008 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. -# - -include $(top_srcdir)/grc/Makefile.inc - -ourdatadir = $(grc_examples_prefix)/audio - -dist_ourdata_DATA = dial_tone.grc diff --git a/grc/examples/simple/Makefile.am b/grc/examples/simple/Makefile.am deleted file mode 100644 index a56f98bdd..000000000 --- a/grc/examples/simple/Makefile.am +++ /dev/null @@ -1,28 +0,0 @@ -# -# Copyright 2008 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. -# - -include $(top_srcdir)/grc/Makefile.inc - -ourdatadir = $(grc_examples_prefix)/simple - -dist_ourdata_DATA = \ - ber_simulation.grc \ - dpsk_loopback.grc diff --git a/grc/examples/trellis/Makefile.am b/grc/examples/trellis/Makefile.am deleted file mode 100644 index 567773052..000000000 --- a/grc/examples/trellis/Makefile.am +++ /dev/null @@ -1,28 +0,0 @@ -# -# Copyright 2008 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. -# - -include $(top_srcdir)/grc/Makefile.inc - -ourdatadir = $(grc_examples_prefix)/trellis - -dist_ourdata_DATA = \ - readme.txt \ - interference_cancellation.grc diff --git a/grc/examples/usrp/Makefile.am b/grc/examples/usrp/Makefile.am deleted file mode 100644 index 4e969ebd4..000000000 --- a/grc/examples/usrp/Makefile.am +++ /dev/null @@ -1,30 +0,0 @@ -# -# Copyright 2008, 2009 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. -# - -include $(top_srcdir)/grc/Makefile.inc - -ourdatadir = $(grc_examples_prefix)/usrp - -dist_ourdata_DATA = \ - usrp2_const_wave.grc \ - usrp2_fft.grc \ - usrp_two_tone_loopback.grc \ - usrp_wbfm_receive.grc diff --git a/grc/examples/usrp/usrp2_const_wave.grc b/grc/examples/usrp/usrp2_const_wave.grc index ac9570349..fdbd7c1f3 100644 --- a/grc/examples/usrp/usrp2_const_wave.grc +++ b/grc/examples/usrp/usrp2_const_wave.grc @@ -1,43 +1,93 @@ <?xml version='1.0' encoding='ASCII'?> <flow_graph> - <timestamp>Fri Jan 23 11:26:26 2009</timestamp> + <timestamp>Wed Apr 15 11:22:56 2009</timestamp> <block> - <key>options</key> + <key>const_source_x</key> <param> <key>id</key> - <value>top_block</value> + <value>const_source_x_0</value> </param> <param> <key>_enabled</key> <value>True</value> </param> <param> - <key>title</key> - <value>USRP2 Const Wave</value> + <key>type</key> + <value>complex</value> </param> <param> - <key>author</key> - <value>Example</value> + <key>const</key> + <value>ampl</value> </param> <param> - <key>description</key> - <value>Carrier with constant amplitude</value> + <key>_coordinate</key> + <value>(284, 154)</value> </param> <param> - <key>window_size</key> - <value>1280, 1024</value> + <key>_rotation</key> + <value>0</value> </param> + </block> + <block> + <key>usrp2_sink_xxxx</key> <param> - <key>generate_options</key> - <value>wx_gui</value> + <key>id</key> + <value>usrp2_sink_xxxx_0</value> </param> <param> - <key>category</key> - <value>Custom</value> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>type</key> + <value>complex</value> + </param> + <param> + <key>interface</key> + <value></value> + </param> + <param> + <key>mac_addr</key> + <value></value> + </param> + <param> + <key>interpolation</key> + <value>interp</value> + </param> + <param> + <key>frequency</key> + <value>tun_freq</value> + </param> + <param> + <key>gain</key> + <value>0</value> </param> <param> <key>_coordinate</key> - <value>(10, 10)</value> + <value>(493, 106)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>variable</key> + <param> + <key>id</key> + <value>interp</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>value</key> + <value>16</value> + </param> + <param> + <key>_coordinate</key> + <value>(16, 255)</value> </param> <param> <key>_rotation</key> @@ -48,7 +98,7 @@ <key>variable_slider</key> <param> <key>id</key> - <value>freq</value> + <value>tun_freq</value> </param> <param> <key>_enabled</key> @@ -56,19 +106,19 @@ </param> <param> <key>label</key> - <value>Frequency (Hz)</value> + <value>USRP2 Freq (Hz)</value> </param> <param> <key>value</key> - <value>15e6</value> + <value>2.45e9</value> </param> <param> <key>min</key> - <value>10e6</value> + <value>2.4e9</value> </param> <param> <key>max</key> - <value>20e6</value> + <value>2.5e9</value> </param> <param> <key>num_steps</key> @@ -88,7 +138,7 @@ </param> <param> <key>_coordinate</key> - <value>(12, 144)</value> + <value>(30, 376)</value> </param> <param> <key>_rotation</key> @@ -96,42 +146,50 @@ </param> </block> <block> - <key>gr_sig_source_x</key> + <key>variable_slider</key> <param> <key>id</key> - <value>gr_sig_source_x_0</value> + <value>ampl</value> </param> <param> <key>_enabled</key> <value>True</value> </param> <param> - <key>type</key> - <value>complex</value> + <key>label</key> + <value>Amplitude</value> + </param> + <param> + <key>value</key> + <value>.1</value> </param> <param> - <key>samp_rate</key> + <key>min</key> <value>0</value> </param> <param> - <key>waveform</key> - <value>gr.GR_CONST_WAVE</value> + <key>max</key> + <value>1</value> </param> <param> - <key>freq</key> - <value>0</value> + <key>num_steps</key> + <value>100</value> + </param> + <param> + <key>slider_length</key> + <value>200</value> </param> <param> - <key>amp</key> - <value>10e3</value> + <key>slider_type</key> + <value>horizontal</value> </param> <param> - <key>offset</key> - <value>0</value> + <key>grid_pos</key> + <value></value> </param> <param> <key>_coordinate</key> - <value>(225, 27)</value> + <value>(204, 376)</value> </param> <param> <key>_rotation</key> @@ -139,50 +197,46 @@ </param> </block> <block> - <key>usrp2_sink_xxxx</key> + <key>options</key> <param> <key>id</key> - <value>usrp2_sink_xxxx_0</value> + <value>usrp2_const_wave</value> </param> <param> <key>_enabled</key> <value>True</value> </param> <param> - <key>type</key> - <value>complex</value> - </param> - <param> - <key>interface</key> - <value></value> + <key>title</key> + <value>USRP2 Constant Wave</value> </param> <param> - <key>mac_addr</key> - <value></value> + <key>author</key> + <value>Example</value> </param> <param> - <key>frequency</key> - <value>freq</value> + <key>description</key> + <value>Tune USRP2</value> </param> <param> - <key>interpolation</key> - <value>101</value> + <key>window_size</key> + <value>1280, 1024</value> </param> <param> - <key>gain</key> - <value>0</value> + <key>generate_options</key> + <value>wx_gui</value> </param> <param> - <key>auto_tr</key> - <value></value> + <key>category</key> + <value>Custom</value> </param> <param> - <key>tx_enb</key> + <key>realtime_scheduling</key> <value></value> </param> <param> <key>_coordinate</key> - <value>(391, 190)</value> + <value>(10, 10)</value> </param> <param> <key>_rotation</key> @@ -190,7 +244,7 @@ </param> </block> <connection> - <source_block_id>gr_sig_source_x_0</source_block_id> + <source_block_id>const_source_x_0</source_block_id> <sink_block_id>usrp2_sink_xxxx_0</sink_block_id> <source_key>0</source_key> <sink_key>0</sink_key> diff --git a/grc/examples/usrp/usrp2_dpsk_mod.grc b/grc/examples/usrp/usrp2_dpsk_mod.grc new file mode 100644 index 000000000..e9f9b41ea --- /dev/null +++ b/grc/examples/usrp/usrp2_dpsk_mod.grc @@ -0,0 +1,693 @@ +<?xml version='1.0' encoding='ASCII'?> +<flow_graph> + <timestamp>Wed Apr 15 17:31:00 2009</timestamp> + <block> + <key>options</key> + <param> + <key>id</key> + <value>usrp2_dpsk_mod</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>title</key> + <value>USRP2 DPSK Modulation</value> + </param> + <param> + <key>author</key> + <value>Example</value> + </param> + <param> + <key>description</key> + <value>Generate a DPSK signal</value> + </param> + <param> + <key>window_size</key> + <value>1280, 1024</value> + </param> + <param> + <key>generate_options</key> + <value>wx_gui</value> + </param> + <param> + <key>category</key> + <value>Custom</value> + </param> + <param> + <key>realtime_scheduling</key> + <value></value> + </param> + <param> + <key>_coordinate</key> + <value>(10, 10)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>variable</key> + <param> + <key>id</key> + <value>samp_rate</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>value</key> + <value>100e6/interp</value> + </param> + <param> + <key>_coordinate</key> + <value>(52, 166)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>usrp2_sink_xxxx</key> + <param> + <key>id</key> + <value>usrp2_sink_xxxx_0</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>type</key> + <value>complex</value> + </param> + <param> + <key>interface</key> + <value></value> + </param> + <param> + <key>mac_addr</key> + <value></value> + </param> + <param> + <key>interpolation</key> + <value>interp</value> + </param> + <param> + <key>frequency</key> + <value>tun_freq</value> + </param> + <param> + <key>gain</key> + <value>0</value> + </param> + <param> + <key>_coordinate</key> + <value>(1059, 56)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>gr_multiply_const_vxx</key> + <param> + <key>id</key> + <value>gr_multiply_const_vxx_0</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>type</key> + <value>complex</value> + </param> + <param> + <key>const</key> + <value>ampl</value> + </param> + <param> + <key>vlen</key> + <value>1</value> + </param> + <param> + <key>_coordinate</key> + <value>(679, 58)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>blks2_dxpsk_mod</key> + <param> + <key>id</key> + <value>blks2_dxpsk_mod_0</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>type</key> + <value>dqpsk</value> + </param> + <param> + <key>samples_per_symbol</key> + <value>samps_per_sym</value> + </param> + <param> + <key>excess_bw</key> + <value>0.35</value> + </param> + <param> + <key>gray_code</key> + <value>True</value> + </param> + <param> + <key>_coordinate</key> + <value>(468, 55)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>variable</key> + <param> + <key>id</key> + <value>interp</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>value</key> + <value>100</value> + </param> + <param> + <key>_coordinate</key> + <value>(31, 256)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>variable</key> + <param> + <key>id</key> + <value>samps_per_sym</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>value</key> + <value>8</value> + </param> + <param> + <key>_coordinate</key> + <value>(126, 250)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>random_source_x</key> + <param> + <key>id</key> + <value>random_source_x_0</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>type</key> + <value>byte</value> + </param> + <param> + <key>min</key> + <value>0</value> + </param> + <param> + <key>max</key> + <value>256</value> + </param> + <param> + <key>num_samps</key> + <value>1000</value> + </param> + <param> + <key>repeat</key> + <value>True</value> + </param> + <param> + <key>_coordinate</key> + <value>(255, 39)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>variable_slider</key> + <param> + <key>id</key> + <value>ampl</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>label</key> + <value>Amplitude</value> + </param> + <param> + <key>value</key> + <value>.1</value> + </param> + <param> + <key>min</key> + <value>0</value> + </param> + <param> + <key>max</key> + <value>1</value> + </param> + <param> + <key>num_steps</key> + <value>100</value> + </param> + <param> + <key>style</key> + <value>wx.SL_HORIZONTAL</value> + </param> + <param> + <key>converver</key> + <value>float_converter</value> + </param> + <param> + <key>grid_pos</key> + <value></value> + </param> + <param> + <key>_coordinate</key> + <value>(246, 372)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>variable_slider</key> + <param> + <key>id</key> + <value>rx_freq_off</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>label</key> + <value>RX Freq Offset (Hz)</value> + </param> + <param> + <key>value</key> + <value>-20e3</value> + </param> + <param> + <key>min</key> + <value>-50e3</value> + </param> + <param> + <key>max</key> + <value>+50e3</value> + </param> + <param> + <key>num_steps</key> + <value>100</value> + </param> + <param> + <key>style</key> + <value>wx.SL_HORIZONTAL</value> + </param> + <param> + <key>converver</key> + <value>float_converter</value> + </param> + <param> + <key>grid_pos</key> + <value></value> + </param> + <param> + <key>_coordinate</key> + <value>(247, 508)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>variable_slider</key> + <param> + <key>id</key> + <value>tun_freq</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>label</key> + <value>USRP2 Freq (Hz)</value> + </param> + <param> + <key>value</key> + <value>2.45e9</value> + </param> + <param> + <key>min</key> + <value>2.4e9</value> + </param> + <param> + <key>max</key> + <value>2.5e9</value> + </param> + <param> + <key>num_steps</key> + <value>100</value> + </param> + <param> + <key>style</key> + <value>wx.SL_HORIZONTAL</value> + </param> + <param> + <key>converver</key> + <value>float_converter</value> + </param> + <param> + <key>grid_pos</key> + <value></value> + </param> + <param> + <key>_coordinate</key> + <value>(49, 341)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>wxgui_constellationsink2</key> + <param> + <key>id</key> + <value>wxgui_constellationsink2_0</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>title</key> + <value>Constellation Plot</value> + </param> + <param> + <key>samp_rate</key> + <value>samp_rate</value> + </param> + <param> + <key>frame_rate</key> + <value>5</value> + </param> + <param> + <key>const_size</key> + <value>2048</value> + </param> + <param> + <key>M</key> + <value>4</value> + </param> + <param> + <key>theta</key> + <value>0</value> + </param> + <param> + <key>alpha</key> + <value>0.005</value> + </param> + <param> + <key>fmax</key> + <value>0.06</value> + </param> + <param> + <key>mu</key> + <value>0.5</value> + </param> + <param> + <key>gain_mu</key> + <value>0.005</value> + </param> + <param> + <key>symbol_rate</key> + <value>samp_rate/samps_per_sym</value> + </param> + <param> + <key>omega_limit</key> + <value>0.005</value> + </param> + <param> + <key>grid_pos</key> + <value></value> + </param> + <param> + <key>_coordinate</key> + <value>(920, 202)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>wxgui_fftsink2</key> + <param> + <key>id</key> + <value>wxgui_fftsink2_0</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>type</key> + <value>complex</value> + </param> + <param> + <key>title</key> + <value>FFT Plot</value> + </param> + <param> + <key>samp_rate</key> + <value>samp_rate</value> + </param> + <param> + <key>baseband_freq</key> + <value>tun_freq</value> + </param> + <param> + <key>y_per_div</key> + <value>10</value> + </param> + <param> + <key>ref_level</key> + <value>10</value> + </param> + <param> + <key>fft_size</key> + <value>1024</value> + </param> + <param> + <key>fft_rate</key> + <value>30</value> + </param> + <param> + <key>peak_hold</key> + <value>False</value> + </param> + <param> + <key>average</key> + <value>False</value> + </param> + <param> + <key>avg_alpha</key> + <value>0</value> + </param> + <param> + <key>grid_pos</key> + <value></value> + </param> + <param> + <key>_coordinate</key> + <value>(691, 155)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>wxgui_scopesink2</key> + <param> + <key>id</key> + <value>wxgui_scopesink2_0</value> + </param> + <param> + <key>_enabled</key> + <value>False</value> + </param> + <param> + <key>type</key> + <value>complex</value> + </param> + <param> + <key>title</key> + <value>Scope Plot</value> + </param> + <param> + <key>samp_rate</key> + <value>samp_rate</value> + </param> + <param> + <key>v_scale</key> + <value>0</value> + </param> + <param> + <key>t_scale</key> + <value>1e-6</value> + </param> + <param> + <key>ac_couple</key> + <value>False</value> + </param> + <param> + <key>xy_mode</key> + <value>True</value> + </param> + <param> + <key>num_inputs</key> + <value>1</value> + </param> + <param> + <key>grid_pos</key> + <value></value> + </param> + <param> + <key>_coordinate</key> + <value>(515, 272)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>usrp2_source_xxxx</key> + <param> + <key>id</key> + <value>usrp2_source_xxxx_0</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>type</key> + <value>complex</value> + </param> + <param> + <key>interface</key> + <value>eth1</value> + </param> + <param> + <key>mac_addr</key> + <value></value> + </param> + <param> + <key>decimation</key> + <value>interp</value> + </param> + <param> + <key>frequency</key> + <value>tun_freq + rx_freq_off</value> + </param> + <param> + <key>gain</key> + <value>30</value> + </param> + <param> + <key>_coordinate</key> + <value>(270, 200)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <connection> + <source_block_id>random_source_x_0</source_block_id> + <sink_block_id>blks2_dxpsk_mod_0</sink_block_id> + <source_key>0</source_key> + <sink_key>0</sink_key> + </connection> + <connection> + <source_block_id>blks2_dxpsk_mod_0</source_block_id> + <sink_block_id>gr_multiply_const_vxx_0</sink_block_id> + <source_key>0</source_key> + <sink_key>0</sink_key> + </connection> + <connection> + <source_block_id>gr_multiply_const_vxx_0</source_block_id> + <sink_block_id>usrp2_sink_xxxx_0</sink_block_id> + <source_key>0</source_key> + <sink_key>0</sink_key> + </connection> + <connection> + <source_block_id>usrp2_source_xxxx_0</source_block_id> + <sink_block_id>wxgui_constellationsink2_0</sink_block_id> + <source_key>0</source_key> + <sink_key>0</sink_key> + </connection> + <connection> + <source_block_id>usrp2_source_xxxx_0</source_block_id> + <sink_block_id>wxgui_scopesink2_0</sink_block_id> + <source_key>0</source_key> + <sink_key>0</sink_key> + </connection> + <connection> + <source_block_id>usrp2_source_xxxx_0</source_block_id> + <sink_block_id>wxgui_fftsink2_0</sink_block_id> + <source_key>0</source_key> + <sink_key>0</sink_key> + </connection> +</flow_graph> diff --git a/grc/examples/usrp/usrp2_fft.grc b/grc/examples/usrp/usrp2_fft.grc index e7e93b3ff..134bd4614 100644 --- a/grc/examples/usrp/usrp2_fft.grc +++ b/grc/examples/usrp/usrp2_fft.grc @@ -1,11 +1,11 @@ <?xml version='1.0' encoding='ASCII'?> <flow_graph> - <timestamp>Fri Jan 23 11:38:11 2009</timestamp> + <timestamp>Wed Apr 15 17:30:20 2009</timestamp> <block> <key>options</key> <param> <key>id</key> - <value>top_block</value> + <value>usrp2_fft</value> </param> <param> <key>_enabled</key> @@ -13,7 +13,7 @@ </param> <param> <key>title</key> - <value>USRP2 FFT</value> + <value>USRP2 FFT Plotter</value> </param> <param> <key>author</key> @@ -21,7 +21,7 @@ </param> <param> <key>description</key> - <value>FFT of Spectrum</value> + <value>FFT waveform plot</value> </param> <param> <key>window_size</key> @@ -36,6 +36,10 @@ <value>Custom</value> </param> <param> + <key>realtime_scheduling</key> + <value></value> + </param> + <param> <key>_coordinate</key> <value>(10, 10)</value> </param> @@ -48,6 +52,29 @@ <key>variable</key> <param> <key>id</key> + <value>samp_rate</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>value</key> + <value>100e6/decim</value> + </param> + <param> + <key>_coordinate</key> + <value>(10, 170)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>variable</key> + <param> + <key>id</key> <value>decim</value> </param> <param> @@ -56,11 +83,11 @@ </param> <param> <key>value</key> - <value>4</value> + <value>16</value> </param> <param> <key>_coordinate</key> - <value>(35, 149)</value> + <value>(24, 267)</value> </param> <param> <key>_rotation</key> @@ -68,50 +95,50 @@ </param> </block> <block> - <key>usrp2_source_xxxx</key> + <key>variable_slider</key> <param> <key>id</key> - <value>usrp2_source_xxxx_0</value> + <value>tun_freq</value> </param> <param> <key>_enabled</key> <value>True</value> </param> <param> - <key>type</key> - <value>complex</value> + <key>label</key> + <value>USRP2 Freq (Hz)</value> </param> <param> - <key>interface</key> - <value></value> + <key>value</key> + <value>2.45e9</value> </param> <param> - <key>mac_addr</key> - <value></value> + <key>min</key> + <value>2.4e9</value> </param> <param> - <key>frequency</key> - <value>freq</value> + <key>max</key> + <value>2.5e9</value> </param> <param> - <key>decimation</key> - <value>decim</value> + <key>num_steps</key> + <value>100</value> </param> <param> - <key>gain</key> - <value>0</value> + <key>style</key> + <value>wx.SL_HORIZONTAL</value> </param> <param> - <key>auto_tr</key> - <value></value> + <key>converver</key> + <value>float_converter</value> </param> <param> - <key>rx_ant</key> + <key>grid_pos</key> <value></value> </param> <param> <key>_coordinate</key> - <value>(177, 271)</value> + <value>(32, 365)</value> </param> <param> <key>_rotation</key> @@ -138,23 +165,19 @@ </param> <param> <key>samp_rate</key> - <value>100e6/decim</value> + <value>samp_rate</value> </param> <param> <key>baseband_freq</key> - <value>freq</value> + <value>tun_freq</value> </param> <param> <key>y_per_div</key> <value>10</value> </param> <param> - <key>y_divs</key> - <value>12</value> - </param> - <param> <key>ref_level</key> - <value>20</value> + <value>10</value> </param> <param> <key>fft_size</key> @@ -165,16 +188,16 @@ <value>30</value> </param> <param> - <key>avg_alpha</key> - <value>0</value> + <key>peak_hold</key> + <value>False</value> </param> <param> <key>average</key> <value>False</value> </param> <param> - <key>peak_hold</key> - <value>False</value> + <key>avg_alpha</key> + <value>0</value> </param> <param> <key>grid_pos</key> @@ -182,7 +205,7 @@ </param> <param> <key>_coordinate</key> - <value>(384, 72)</value> + <value>(466, 100)</value> </param> <param> <key>_rotation</key> @@ -190,50 +213,42 @@ </param> </block> <block> - <key>variable_slider</key> + <key>usrp2_source_xxxx</key> <param> <key>id</key> - <value>freq</value> + <value>usrp2_source_xxxx_0</value> </param> <param> <key>_enabled</key> <value>True</value> </param> <param> - <key>label</key> - <value>Frequency (Hz)</value> - </param> - <param> - <key>value</key> - <value>0</value> - </param> - <param> - <key>min</key> - <value>-100e6</value> + <key>type</key> + <value>complex</value> </param> <param> - <key>max</key> - <value>100e6</value> + <key>interface</key> + <value></value> </param> <param> - <key>num_steps</key> - <value>100</value> + <key>mac_addr</key> + <value></value> </param> <param> - <key>slider_length</key> - <value>200</value> + <key>decimation</key> + <value>decim</value> </param> <param> - <key>slider_type</key> - <value>horizontal</value> + <key>frequency</key> + <value>tun_freq</value> </param> <param> - <key>grid_pos</key> - <value></value> + <key>gain</key> + <value>0</value> </param> <param> <key>_coordinate</key> - <value>(139, 129)</value> + <value>(211, 200)</value> </param> <param> <key>_rotation</key> diff --git a/grc/examples/usrp/usrp_two_tone_loopback.grc b/grc/examples/usrp/usrp_two_tone_loopback.grc index e3c635d46..3df977044 100644 --- a/grc/examples/usrp/usrp_two_tone_loopback.grc +++ b/grc/examples/usrp/usrp_two_tone_loopback.grc @@ -1,43 +1,46 @@ <?xml version='1.0' encoding='ASCII'?> <flow_graph> - <timestamp>Mon Sep 8 21:47:19 2008</timestamp> + <timestamp>Fri Apr 17 18:23:35 2009</timestamp> <block> - <key>options</key> + <key>variable</key> <param> <key>id</key> - <value>top_block</value> + <value>samp_rate</value> </param> <param> <key>_enabled</key> <value>True</value> </param> <param> - <key>title</key> - <value>USRP Loopback - 2 Tone</value> + <key>value</key> + <value>64e6/200</value> </param> <param> - <key>author</key> - <value>Example</value> + <key>_coordinate</key> + <value>(9, 166)</value> </param> <param> - <key>description</key> - <value>Loopback test with basic rx and basic tx</value> + <key>_rotation</key> + <value>0</value> </param> + </block> + <block> + <key>variable</key> <param> - <key>window_size</key> - <value>1280, 1024</value> + <key>id</key> + <value>tun_freq</value> </param> <param> - <key>generate_options</key> - <value>wx_gui</value> + <key>_enabled</key> + <value>True</value> </param> <param> - <key>category</key> - <value>Custom</value> + <key>value</key> + <value>int(100e6)</value> </param> <param> <key>_coordinate</key> - <value>(10, 10)</value> + <value>(116, 166)</value> </param> <param> <key>_rotation</key> @@ -45,10 +48,10 @@ </param> </block> <block> - <key>usrp_simple_source_x</key> + <key>gr_sig_source_x</key> <param> <key>id</key> - <value>usrp_simple_source_x</value> + <value>gr_sig_source_x</value> </param> <param> <key>_enabled</key> @@ -59,40 +62,28 @@ <value>complex</value> </param> <param> - <key>number</key> - <value>0</value> - </param> - <param> - <key>subdev_spec</key> - <value>None</value> - </param> - <param> - <key>frequency</key> - <value>tun_freq</value> - </param> - <param> - <key>decimation</key> - <value>200</value> + <key>samp_rate</key> + <value>samp_rate</value> </param> <param> - <key>gain</key> - <value>20</value> + <key>waveform</key> + <value>gr.GR_COS_WAVE</value> </param> <param> - <key>mux</key> - <value>0x0</value> + <key>freq</key> + <value>tone1</value> </param> <param> - <key>auto_tr</key> - <value>None</value> + <key>amp</key> + <value>tone_ampl</value> </param> <param> - <key>rx_ant</key> - <value>None</value> + <key>offset</key> + <value>0</value> </param> <param> <key>_coordinate</key> - <value>(578, 319)</value> + <value>(258, 20)</value> </param> <param> <key>_rotation</key> @@ -100,10 +91,10 @@ </param> </block> <block> - <key>wxgui_fftsink2</key> + <key>gr_sig_source_x</key> <param> <key>id</key> - <value>wxgui_fftsink2</value> + <value>gr_sig_source_x0</value> </param> <param> <key>_enabled</key> @@ -114,56 +105,59 @@ <value>complex</value> </param> <param> - <key>title</key> - <value>FFT Plot</value> - </param> - <param> <key>samp_rate</key> <value>samp_rate</value> </param> <param> - <key>baseband_freq</key> - <value>0</value> + <key>waveform</key> + <value>gr.GR_COS_WAVE</value> </param> <param> - <key>y_per_div</key> - <value>10</value> + <key>freq</key> + <value>tone2</value> </param> <param> - <key>y_divs</key> - <value>8</value> + <key>amp</key> + <value>tone_ampl</value> </param> <param> - <key>ref_level</key> - <value>100</value> + <key>offset</key> + <value>0</value> </param> <param> - <key>fft_size</key> - <value>512*2</value> + <key>_coordinate</key> + <value>(255, 179)</value> </param> <param> - <key>fft_rate</key> - <value>15</value> + <key>_rotation</key> + <value>0</value> </param> + </block> + <block> + <key>gr_add_xx</key> <param> - <key>avg_alpha</key> - <value>0</value> + <key>id</key> + <value>gr_add_xx</value> </param> <param> - <key>average</key> - <value>False</value> + <key>_enabled</key> + <value>True</value> </param> <param> - <key>peak_hold</key> - <value>False</value> + <key>type</key> + <value>complex</value> </param> <param> - <key>grid_pos</key> - <value>1, 2, 2, 4</value> + <key>num_inputs</key> + <value>3</value> + </param> + <param> + <key>vlen</key> + <value>1</value> </param> <param> <key>_coordinate</key> - <value>(845, 228)</value> + <value>(528, 78)</value> </param> <param> <key>_rotation</key> @@ -171,10 +165,10 @@ </param> </block> <block> - <key>variable_slider</key> + <key>parameter</key> <param> <key>id</key> - <value>tone2</value> + <value>tx_side</value> </param> <param> <key>_enabled</key> @@ -182,35 +176,19 @@ </param> <param> <key>label</key> - <value>Tone 2</value> + <value></value> </param> <param> <key>value</key> - <value>75e3</value> + <value>A</value> </param> <param> - <key>min</key> - <value>0</value> - </param> - <param> - <key>max</key> - <value>150000</value> - </param> - <param> - <key>num_steps</key> - <value>100</value> - </param> - <param> - <key>slider_type</key> - <value>horizontal</value> - </param> - <param> - <key>grid_pos</key> - <value>0, 4, 1, 2</value> + <key>type</key> + <value>string</value> </param> <param> <key>_coordinate</key> - <value>(397, 478)</value> + <value>(688, 384)</value> </param> <param> <key>_rotation</key> @@ -218,46 +196,50 @@ </param> </block> <block> - <key>variable_slider</key> + <key>usrp_simple_sink_x</key> <param> <key>id</key> - <value>tone1</value> + <value>usrp_simple_sink_x</value> </param> <param> <key>_enabled</key> <value>True</value> </param> <param> - <key>label</key> - <value>Tone 1</value> + <key>type</key> + <value>complex</value> </param> <param> - <key>value</key> - <value>50e3</value> + <key>format</key> + <value></value> </param> <param> - <key>min</key> + <key>which</key> <value>0</value> </param> <param> - <key>max</key> - <value>150000</value> + <key>interpolation</key> + <value>400</value> </param> <param> - <key>num_steps</key> - <value>100</value> + <key>frequency</key> + <value>tun_freq</value> </param> <param> - <key>slider_type</key> - <value>horizontal</value> + <key>gain</key> + <value>0</value> </param> <param> - <key>grid_pos</key> - <value>0, 2, 1, 2</value> + <key>side</key> + <value>tx_side</value> + </param> + <param> + <key>transmit</key> + <value></value> </param> <param> <key>_coordinate</key> - <value>(220, 475)</value> + <value>(835, 5)</value> </param> <param> <key>_rotation</key> @@ -265,46 +247,54 @@ </param> </block> <block> - <key>variable_slider</key> + <key>usrp_simple_source_x</key> <param> <key>id</key> - <value>noise_ampl</value> + <value>usrp_simple_source_x</value> </param> <param> <key>_enabled</key> <value>True</value> </param> <param> - <key>label</key> - <value>Noise Ampl</value> + <key>type</key> + <value>complex</value> </param> <param> - <key>value</key> - <value>2000</value> + <key>format</key> + <value></value> </param> <param> - <key>min</key> + <key>which</key> <value>0</value> </param> <param> - <key>max</key> - <value>5000</value> + <key>decimation</key> + <value>200</value> </param> <param> - <key>num_steps</key> - <value>100</value> + <key>frequency</key> + <value>tun_freq</value> </param> <param> - <key>slider_type</key> - <value>vertical</value> + <key>gain</key> + <value>20</value> </param> <param> - <key>grid_pos</key> - <value>1, 1, 2, 1</value> + <key>side</key> + <value>rx_side</value> + </param> + <param> + <key>rx_ant</key> + <value>rx_ant</value> + </param> + <param> + <key>hb_filters</key> + <value></value> </param> <param> <key>_coordinate</key> - <value>(20, 243)</value> + <value>(479, 224)</value> </param> <param> <key>_rotation</key> @@ -312,22 +302,30 @@ </param> </block> <block> - <key>variable</key> + <key>parameter</key> <param> <key>id</key> - <value>samp_rate</value> + <value>rx_ant</value> </param> <param> <key>_enabled</key> <value>True</value> </param> <param> + <key>label</key> + <value></value> + </param> + <param> <key>value</key> - <value>64e6/200</value> + <value>RXA</value> + </param> + <param> + <key>type</key> + <value>string</value> </param> <param> <key>_coordinate</key> - <value>(9, 166)</value> + <value>(802, 384)</value> </param> <param> <key>_rotation</key> @@ -335,65 +333,66 @@ </param> </block> <block> - <key>variable</key> + <key>wxgui_fftsink2</key> <param> <key>id</key> - <value>tun_freq</value> + <value>wxgui_fftsink2</value> </param> <param> <key>_enabled</key> <value>True</value> </param> <param> - <key>value</key> - <value>int(100e6)</value> + <key>type</key> + <value>complex</value> </param> <param> - <key>_coordinate</key> - <value>(116, 166)</value> + <key>title</key> + <value>FFT Plot</value> </param> <param> - <key>_rotation</key> - <value>0</value> + <key>samp_rate</key> + <value>samp_rate</value> </param> - </block> - <block> - <key>gr_sig_source_x</key> <param> - <key>id</key> - <value>gr_sig_source_x</value> + <key>baseband_freq</key> + <value>0</value> </param> <param> - <key>_enabled</key> - <value>True</value> + <key>y_per_div</key> + <value>10</value> </param> <param> - <key>type</key> - <value>complex</value> + <key>ref_level</key> + <value>100</value> </param> <param> - <key>samp_rate</key> - <value>samp_rate</value> + <key>fft_size</key> + <value>512*2</value> </param> <param> - <key>waveform</key> - <value>gr.GR_COS_WAVE</value> + <key>fft_rate</key> + <value>15</value> </param> <param> - <key>freq</key> - <value>tone1</value> + <key>peak_hold</key> + <value>False</value> </param> <param> - <key>amp</key> - <value>tone_ampl</value> + <key>average</key> + <value>False</value> </param> <param> - <key>offset</key> + <key>avg_alpha</key> <value>0</value> </param> <param> + <key>grid_pos</key> + <value>1, 2, 2, 4</value> + </param> + <param> <key>_coordinate</key> - <value>(258, 20)</value> + <value>(746, 133)</value> </param> <param> <key>_rotation</key> @@ -401,42 +400,30 @@ </param> </block> <block> - <key>gr_sig_source_x</key> + <key>parameter</key> <param> <key>id</key> - <value>gr_sig_source_x0</value> + <value>rx_side</value> </param> <param> <key>_enabled</key> <value>True</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>gr.GR_COS_WAVE</value> - </param> - <param> - <key>freq</key> - <value>tone2</value> + <key>label</key> + <value></value> </param> <param> - <key>amp</key> - <value>tone_ampl</value> + <key>value</key> + <value>A</value> </param> <param> - <key>offset</key> - <value>0</value> + <key>type</key> + <value>string</value> </param> <param> <key>_coordinate</key> - <value>(255, 179)</value> + <value>(568, 382)</value> </param> <param> <key>_rotation</key> @@ -471,7 +458,7 @@ </param> <param> <key>_coordinate</key> - <value>(257, 337)</value> + <value>(276, 312)</value> </param> <param> <key>_rotation</key> @@ -479,30 +466,50 @@ </param> </block> <block> - <key>gr_add_xx</key> + <key>variable_slider</key> <param> <key>id</key> - <value>gr_add_xx</value> + <value>noise_ampl</value> </param> <param> <key>_enabled</key> <value>True</value> </param> <param> - <key>type</key> - <value>complex</value> + <key>label</key> + <value>Noise Ampl</value> </param> <param> - <key>num_inputs</key> - <value>3</value> + <key>value</key> + <value>2000</value> </param> <param> - <key>vlen</key> - <value>1</value> + <key>min</key> + <value>0</value> + </param> + <param> + <key>max</key> + <value>5000</value> + </param> + <param> + <key>num_steps</key> + <value>100</value> + </param> + <param> + <key>style</key> + <value>wx.SL_VERTICAL</value> + </param> + <param> + <key>converver</key> + <value>float_converter</value> + </param> + <param> + <key>grid_pos</key> + <value>1, 1, 2, 1</value> </param> <param> <key>_coordinate</key> - <value>(528, 78)</value> + <value>(20, 243)</value> </param> <param> <key>_rotation</key> @@ -510,54 +517,101 @@ </param> </block> <block> - <key>usrp_simple_sink_x</key> + <key>variable_slider</key> <param> <key>id</key> - <value>usrp_simple_sink_x</value> + <value>tone_ampl</value> </param> <param> <key>_enabled</key> <value>True</value> </param> <param> - <key>type</key> - <value>complex</value> + <key>label</key> + <value>Tone Ampl</value> </param> <param> - <key>number</key> + <key>value</key> + <value>5000</value> + </param> + <param> + <key>min</key> <value>0</value> </param> <param> - <key>subdev_spec</key> - <value>None</value> + <key>max</key> + <value>10e3</value> </param> <param> - <key>frequency</key> - <value>tun_freq</value> + <key>num_steps</key> + <value>100</value> </param> <param> - <key>interpolation</key> - <value>400</value> + <key>style</key> + <value>wx.SL_VERTICAL</value> </param> <param> - <key>gain</key> + <key>converver</key> + <value>float_converter</value> + </param> + <param> + <key>grid_pos</key> + <value>1, 0, 2, 1</value> + </param> + <param> + <key>_coordinate</key> + <value>(28, 437)</value> + </param> + <param> + <key>_rotation</key> <value>0</value> </param> + </block> + <block> + <key>variable_slider</key> <param> - <key>mux</key> - <value>0x0</value> + <key>id</key> + <value>tone1</value> </param> <param> - <key>auto_tr</key> - <value>None</value> + <key>_enabled</key> + <value>True</value> </param> <param> - <key>tx_enb</key> - <value>None</value> + <key>label</key> + <value>Tone 1</value> + </param> + <param> + <key>value</key> + <value>50e3</value> + </param> + <param> + <key>min</key> + <value>-samp_rate/2</value> + </param> + <param> + <key>max</key> + <value>samp_rate/2</value> + </param> + <param> + <key>num_steps</key> + <value>100</value> + </param> + <param> + <key>style</key> + <value>wx.SL_HORIZONTAL</value> + </param> + <param> + <key>converver</key> + <value>float_converter</value> + </param> + <param> + <key>grid_pos</key> + <value>0, 0, 1, 4</value> </param> <param> <key>_coordinate</key> - <value>(835, 5)</value> + <value>(190, 436)</value> </param> <param> <key>_rotation</key> @@ -568,7 +622,7 @@ <key>variable_slider</key> <param> <key>id</key> - <value>tone_ampl</value> + <value>tone2</value> </param> <param> <key>_enabled</key> @@ -576,11 +630,11 @@ </param> <param> <key>label</key> - <value>Tone Ampl</value> + <value>Tone 2</value> </param> <param> <key>value</key> - <value>5000</value> + <value>75e3</value> </param> <param> <key>min</key> @@ -595,16 +649,67 @@ <value>100</value> </param> <param> - <key>slider_type</key> - <value>vertical</value> + <key>style</key> + <value>wx.SL_HORIZONTAL</value> + </param> + <param> + <key>converver</key> + <value>float_converter</value> </param> <param> <key>grid_pos</key> - <value>1, 0, 2, 1</value> + <value>0, 4, 1, 4</value> </param> <param> <key>_coordinate</key> - <value>(21, 422)</value> + <value>(367, 439)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>options</key> + <param> + <key>id</key> + <value>usrp_two_tone_loopback</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>title</key> + <value>USRP Loopback - 2 Tone</value> + </param> + <param> + <key>author</key> + <value>Example</value> + </param> + <param> + <key>description</key> + <value>Loopback test with basic rx and basic tx</value> + </param> + <param> + <key>window_size</key> + <value>1280, 1024</value> + </param> + <param> + <key>generate_options</key> + <value>wx_gui</value> + </param> + <param> + <key>category</key> + <value>Custom</value> + </param> + <param> + <key>realtime_scheduling</key> + <value></value> + </param> + <param> + <key>_coordinate</key> + <value>(10, 10)</value> </param> <param> <key>_rotation</key> diff --git a/grc/examples/usrp/usrp_wbfm_receive.grc b/grc/examples/usrp/usrp_wbfm_receive.grc index 7fb621241..8f53475ab 100644 --- a/grc/examples/usrp/usrp_wbfm_receive.grc +++ b/grc/examples/usrp/usrp_wbfm_receive.grc @@ -1,11 +1,11 @@ <?xml version='1.0' encoding='ASCII'?> <flow_graph> - <timestamp>Thu Jul 24 14:27:45 2008</timestamp> + <timestamp>Fri Apr 17 19:06:07 2009</timestamp> <block> <key>options</key> <param> <key>id</key> - <value>top_block</value> + <value>usrp_wbfm_receive</value> </param> <param> <key>_enabled</key> @@ -36,6 +36,10 @@ <value>Custom</value> </param> <param> + <key>realtime_scheduling</key> + <value></value> + </param> + <param> <key>_coordinate</key> <value>(10, 10)</value> </param> @@ -45,54 +49,22 @@ </param> </block> <block> - <key>usrp_simple_source_x</key> + <key>variable</key> <param> <key>id</key> - <value>usrp_simple_source_x</value> + <value>decim</value> </param> <param> <key>_enabled</key> <value>True</value> </param> <param> - <key>type</key> - <value>complex</value> - </param> - <param> - <key>number</key> - <value>0</value> - </param> - <param> - <key>subdev_spec</key> - <value>None</value> - </param> - <param> - <key>frequency</key> - <value>(freq+fine)*1e6</value> - </param> - <param> - <key>decimation</key> - <value>decim</value> - </param> - <param> - <key>gain</key> - <value>20</value> - </param> - <param> - <key>mux</key> - <value>0x0</value> - </param> - <param> - <key>auto_tr</key> - <value>None</value> - </param> - <param> - <key>rx_ant</key> - <value>None</value> + <key>value</key> + <value>200</value> </param> <param> <key>_coordinate</key> - <value>(277, 29)</value> + <value>(14, 173)</value> </param> <param> <key>_rotation</key> @@ -103,7 +75,7 @@ <key>variable_slider</key> <param> <key>id</key> - <value>fine</value> + <value>volume</value> </param> <param> <key>_enabled</key> @@ -111,62 +83,39 @@ </param> <param> <key>label</key> - <value>Fine Freq</value> + <value>Volume</value> </param> <param> <key>value</key> - <value>0</value> + <value>1</value> </param> <param> <key>min</key> - <value>-.1</value> + <value>0</value> </param> <param> <key>max</key> - <value>.1</value> + <value>10</value> </param> <param> <key>num_steps</key> <value>100</value> </param> <param> - <key>slider_type</key> - <value>horizontal</value> - </param> - <param> - <key>grid_pos</key> - <value>0, 2, 1, 2</value> + <key>style</key> + <value>wx.SL_HORIZONTAL</value> </param> <param> - <key>_coordinate</key> - <value>(275, 246)</value> + <key>converver</key> + <value>float_converter</value> </param> <param> - <key>_rotation</key> - <value>0</value> - </param> - </block> - <block> - <key>blks2_wfm_rcv</key> - <param> - <key>id</key> - <value>blks2_wfm_rcv</value> - </param> - <param> - <key>_enabled</key> - <value>True</value> - </param> - <param> - <key>quad_rate</key> - <value>64e6/decim</value> - </param> - <param> - <key>audio_decimation</key> - <value>10</value> + <key>grid_pos</key> + <value>1, 0, 1, 4</value> </param> <param> <key>_coordinate</key> - <value>(510, 37)</value> + <value>(991, 40)</value> </param> <param> <key>_rotation</key> @@ -174,65 +123,54 @@ </param> </block> <block> - <key>audio_sink</key> + <key>usrp_simple_source_x</key> <param> <key>id</key> - <value>audio_sink</value> + <value>usrp_simple_source_x</value> </param> <param> <key>_enabled</key> <value>True</value> </param> <param> - <key>samp_rate</key> - <value>32000</value> - </param> - <param> - <key>device_name</key> - <value/> + <key>type</key> + <value>complex</value> </param> <param> - <key>ok_to_block</key> - <value>True</value> + <key>format</key> + <value></value> </param> <param> - <key>num_inputs</key> - <value>1</value> - </param> - <param> - <key>_coordinate</key> - <value>(703, 241)</value> + <key>which</key> + <value>0</value> </param> <param> - <key>_rotation</key> - <value>180</value> + <key>decimation</key> + <value>decim</value> </param> - </block> - <block> - <key>gr_multiply_const_vxx</key> <param> - <key>id</key> - <value>gr_multiply_const_vxx</value> + <key>frequency</key> + <value>(freq+fine)*1e6</value> </param> <param> - <key>_enabled</key> - <value>True</value> + <key>gain</key> + <value>20</value> </param> <param> - <key>type</key> - <value>float</value> + <key>side</key> + <value>A</value> </param> <param> - <key>const</key> - <value>volume</value> + <key>rx_ant</key> + <value>None</value> </param> <param> - <key>vlen</key> - <value>1</value> + <key>hb_filters</key> + <value></value> </param> <param> <key>_coordinate</key> - <value>(764, 55)</value> + <value>(277, 29)</value> </param> <param> <key>_rotation</key> @@ -263,17 +201,13 @@ </param> <param> <key>baseband_freq</key> - <value>0</value> + <value>(freq+fine)*1e6</value> </param> <param> <key>y_per_div</key> <value>10</value> </param> <param> - <key>y_divs</key> - <value>8</value> - </param> - <param> <key>ref_level</key> <value>50</value> </param> @@ -286,16 +220,16 @@ <value>15</value> </param> <param> - <key>avg_alpha</key> - <value>0</value> + <key>peak_hold</key> + <value>False</value> </param> <param> <key>average</key> <value>False</value> </param> <param> - <key>peak_hold</key> - <value>False</value> + <key>avg_alpha</key> + <value>0</value> </param> <param> <key>grid_pos</key> @@ -314,7 +248,7 @@ <key>variable_slider</key> <param> <key>id</key> - <value>volume</value> + <value>freq</value> </param> <param> <key>_enabled</key> @@ -322,35 +256,39 @@ </param> <param> <key>label</key> - <value>Volume</value> + <value>Frequency (MHz)</value> </param> <param> <key>value</key> - <value>1</value> + <value>100</value> </param> <param> <key>min</key> - <value>0</value> + <value>87.5</value> </param> <param> <key>max</key> - <value>10</value> + <value>108.0</value> </param> <param> <key>num_steps</key> - <value>100</value> + <value>1000</value> </param> <param> - <key>slider_type</key> - <value>horizontal</value> + <key>style</key> + <value>wx.SL_HORIZONTAL</value> + </param> + <param> + <key>converver</key> + <value>float_converter</value> </param> <param> <key>grid_pos</key> - <value>1, 1, 1, 2</value> + <value>0, 0, 1, 2</value> </param> <param> <key>_coordinate</key> - <value>(991, 40)</value> + <value>(104, 243)</value> </param> <param> <key>_rotation</key> @@ -361,7 +299,7 @@ <key>variable_slider</key> <param> <key>id</key> - <value>freq</value> + <value>fine</value> </param> <param> <key>_enabled</key> @@ -369,35 +307,39 @@ </param> <param> <key>label</key> - <value>Frequency</value> + <value>Fine Freq (MHz)</value> </param> <param> <key>value</key> - <value>100</value> + <value>0</value> </param> <param> <key>min</key> - <value>87.5</value> + <value>-.1</value> </param> <param> <key>max</key> - <value>108.0</value> + <value>.1</value> </param> <param> <key>num_steps</key> - <value>1000</value> + <value>100</value> + </param> + <param> + <key>style</key> + <value>wx.SL_HORIZONTAL</value> </param> <param> - <key>slider_type</key> - <value>horizontal</value> + <key>converver</key> + <value>float_converter</value> </param> <param> <key>grid_pos</key> - <value>0, 0, 1, 2</value> + <value>0, 2, 1, 2</value> </param> <param> <key>_coordinate</key> - <value>(104, 243)</value> + <value>(275, 246)</value> </param> <param> <key>_rotation</key> @@ -405,28 +347,98 @@ </param> </block> <block> - <key>variable</key> + <key>blks2_wfm_rcv</key> <param> <key>id</key> - <value>decim</value> + <value>blks2_wfm_rcv</value> </param> <param> <key>_enabled</key> <value>True</value> </param> <param> - <key>value</key> - <value>200</value> + <key>quad_rate</key> + <value>64e6/decim</value> + </param> + <param> + <key>audio_decimation</key> + <value>10</value> </param> <param> <key>_coordinate</key> - <value>(14, 173)</value> + <value>(510, 37)</value> </param> <param> <key>_rotation</key> <value>0</value> </param> </block> + <block> + <key>gr_multiply_const_vxx</key> + <param> + <key>id</key> + <value>gr_multiply_const_vxx</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>type</key> + <value>float</value> + </param> + <param> + <key>const</key> + <value>volume</value> + </param> + <param> + <key>vlen</key> + <value>1</value> + </param> + <param> + <key>_coordinate</key> + <value>(764, 55)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>audio_sink</key> + <param> + <key>id</key> + <value>audio_sink</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>samp_rate</key> + <value>32000</value> + </param> + <param> + <key>device_name</key> + <value></value> + </param> + <param> + <key>ok_to_block</key> + <value>True</value> + </param> + <param> + <key>num_inputs</key> + <value>1</value> + </param> + <param> + <key>_coordinate</key> + <value>(703, 241)</value> + </param> + <param> + <key>_rotation</key> + <value>180</value> + </param> + </block> <connection> <source_block_id>usrp_simple_source_x</source_block_id> <sink_block_id>blks2_wfm_rcv</sink_block_id> @@ -451,4 +463,4 @@ <source_key>0</source_key> <sink_key>0</sink_key> </connection> -</flow_graph>
\ No newline at end of file +</flow_graph> diff --git a/grc/examples/xmlrpc/Makefile.am b/grc/examples/xmlrpc/Makefile.am deleted file mode 100644 index cfe04a547..000000000 --- a/grc/examples/xmlrpc/Makefile.am +++ /dev/null @@ -1,30 +0,0 @@ -# -# Copyright 2008 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. -# - -include $(top_srcdir)/grc/Makefile.inc - -ourdatadir = $(grc_examples_prefix)/xmlrpc - -dist_ourdata_DATA = \ - readme.txt \ - xmlrpc_client.grc \ - xmlrpc_client_script.py\ - xmlrpc_server.grc diff --git a/grc/scripts/grc b/grc/scripts/grc index e74d98616..70c7ad1ad 100755 --- a/grc/scripts/grc +++ b/grc/scripts/grc @@ -22,6 +22,14 @@ import pygtk pygtk.require('2.0') import gtk +try: import gnuradio +except ImportError, e: + d = gtk.MessageDialog(type=gtk.MESSAGE_ERROR, buttons=gtk.BUTTONS_CLOSE, message_format=""" +Cannot find module gnuradio. Is your PYTHONPATH set correctly?""") + d.set_title(e.message) + d.run() + exit(-1) + from gnuradio.grc.platforms.base.Constants import VERSION from optparse import OptionParser diff --git a/grc/src/grc_gnuradio/wxgui/Makefile.am b/grc/src/grc_gnuradio/wxgui/Makefile.am index 6f731f2cb..b82ca4c90 100644 --- a/grc/src/grc_gnuradio/wxgui/Makefile.am +++ b/grc/src/grc_gnuradio/wxgui/Makefile.am @@ -22,8 +22,12 @@ include $(top_srcdir)/grc/Makefile.inc ourpythondir = $(grc_gnuradio_prefix)/wxgui - ourpython_PYTHON = \ __init__.py \ - callback_controls.py \ top_block_gui.py + +oursubpythondir = $(grc_gnuradio_prefix)/wxgui/forms +oursubpython_PYTHON = \ + forms/__init__.py \ + forms/converters.py \ + forms/forms.py diff --git a/grc/src/grc_gnuradio/wxgui/__init__.py b/grc/src/grc_gnuradio/wxgui/__init__.py index 0b13ead9e..94a0adb8a 100644 --- a/grc/src/grc_gnuradio/wxgui/__init__.py +++ b/grc/src/grc_gnuradio/wxgui/__init__.py @@ -18,12 +18,4 @@ # Boston, MA 02110-1301, USA. # -from callback_controls import \ - button_control, \ - drop_down_control, \ - radio_buttons_horizontal_control, \ - radio_buttons_vertical_control, \ - slider_horizontal_control, \ - slider_vertical_control, \ - text_box_control from top_block_gui import top_block_gui diff --git a/grc/src/grc_gnuradio/wxgui/callback_controls.py b/grc/src/grc_gnuradio/wxgui/callback_controls.py deleted file mode 100644 index 32e5d8842..000000000 --- a/grc/src/grc_gnuradio/wxgui/callback_controls.py +++ /dev/null @@ -1,303 +0,0 @@ -# Copyright 2008 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. -# - -import wx -import sys -from gnuradio import eng_notation - -class LabelText(wx.StaticText): - """Label text class for uniform labels among all controls.""" - - def __init__(self, window, label): - wx.StaticText.__init__(self, window, label=str(label)) - font = self.GetFont() - font.SetWeight(wx.FONTWEIGHT_BOLD) - self.SetFont(font) - -class _control_base(wx.BoxSizer): - """Control base class""" - - def __init__(self, window, callback): - self.window = window - self.callback = callback - wx.BoxSizer.__init__(self, wx.VERTICAL) - - def get_window(self): return self.window - - def call(self): return self.callback(self.get_value()) - - def get_value(self): raise NotImplementedError - - def set_value(self): raise NotImplementedError - -class _chooser_control_base(_control_base): - """House a drop down or radio buttons for variable control.""" - - def __init__(self, window, callback, label='Label', index=0, choices=[0], labels=[]): - """ - Chooser contructor. - Create the slider, text box, and label. - @param window the wx parent window - @param callback call the callback on changes - @param label the label title - @param index the default choice index - @param choices a list of choices - @param labels the choice labels or empty list - """ - #initialize - _control_base.__init__(self, window, callback) - label_text = LabelText(self.get_window(), label) - self.Add(label_text, 0, wx.ALIGN_CENTER) - self.index = index - self.choices = choices - self.labels = map(str, labels or choices) - self._init() - - def _handle_changed(self, event=None): - """ - A change is detected. Call the callback. - """ - try: self.call() - except Exception, e: print >> sys.stderr, 'Error in exec callback from handle changed.\n', e - - def get_value(self): - """ - Update the chooser. - @return one of the possible choices - """ - self._update() - return self.choices[self.index] - -############################################################################################## -# Button Control -############################################################################################## -class button_control(_chooser_control_base): - """House a button for variable control.""" - - def _init(self): - self.button = wx.Button(self.get_window(), label=self.labels[self.index]) - self.button.Bind(wx.EVT_BUTTON, self._handle_changed) - self.Add(self.button, 0, wx.ALIGN_CENTER) - - def _update(self): - self.index = (self.index + 1)%len(self.choices) #circularly increment index - self.button.SetLabel(self.labels[self.index]) - -############################################################################################## -# Drop Down Control -############################################################################################## -class drop_down_control(_chooser_control_base): - """House a drop down for variable control.""" - - def _init(self): - self.drop_down = wx.Choice(self.get_window(), choices=self.labels) - self.Add(self.drop_down, 0, wx.ALIGN_CENTER) - self.drop_down.Bind(wx.EVT_CHOICE, self._handle_changed) - self.drop_down.SetSelection(self.index) - - def _update(self): - self.index = self.drop_down.GetSelection() - -############################################################################################## -# Radio Buttons Control -############################################################################################## -class _radio_buttons_control_base(_chooser_control_base): - """House radio buttons for variable control.""" - - def _init(self): - #create box for radio buttons - radio_box = wx.BoxSizer(self.radio_box_orientation) - panel = wx.Panel(self.get_window()) - panel.SetSizer(radio_box) - self.Add(panel, 0, wx.ALIGN_CENTER) - #create radio buttons - self.radio_buttons = list() - for label in self.labels: - radio_button = wx.RadioButton(panel, label=label) - radio_button.SetValue(False) - self.radio_buttons.append(radio_button) - radio_box.Add(radio_button, 0, self.radio_button_align) - radio_button.Bind(wx.EVT_RADIOBUTTON, self._handle_changed) - #set one radio button active - self.radio_buttons[self.index].SetValue(True) - - def _update(self): - selected_radio_button = filter(lambda rb: rb.GetValue(), self.radio_buttons)[0] - self.index = self.radio_buttons.index(selected_radio_button) - -class radio_buttons_horizontal_control(_radio_buttons_control_base): - radio_box_orientation = wx.HORIZONTAL - radio_button_align = wx.ALIGN_CENTER -class radio_buttons_vertical_control(_radio_buttons_control_base): - radio_box_orientation = wx.VERTICAL - radio_button_align = wx.ALIGN_LEFT - -############################################################################################## -# Slider Control -############################################################################################## -class _slider_control_base(_control_base): - """House a Slider and a Text Box for variable control.""" - - def __init__(self, window, callback, label='Label', value=50, min=0, max=100, num_steps=100, slider_length=200): - """ - Slider contructor. - Create the slider, text box, and label. - @param window the wx parent window - @param callback call the callback on changes - @param label the label title - @param value the default value - @param min the min - @param max the max - @param num_steps the number of steps - @param slider_length the length of the slider bar in pixels - """ - #initialize - _control_base.__init__(self, window, callback) - self.min = float(min) - self.max = float(max) - self.num_steps = int(num_steps) - self.slider_length = slider_length - #create gui elements - label_text_sizer = wx.BoxSizer(self.label_text_orientation) #label and text box container - label_text = LabelText(self.get_window(), '%s: '%str(label)) - self.text_box = text_box = wx.TextCtrl(self.get_window(), style=wx.TE_PROCESS_ENTER) - text_box.Bind(wx.EVT_TEXT_ENTER, self._handle_enter) #bind this special enter hotkey event - for obj in (label_text, text_box): #fill the container with label and text entry box - label_text_sizer.Add(obj, 0, wx.ALIGN_CENTER) - self.Add(label_text_sizer, 0, wx.ALIGN_CENTER) - #make the slider - self.slider = slider = wx.Slider(self.get_window(), size=wx.Size(*self.get_slider_size()), style=self.slider_style) - try: slider.SetRange(0, num_steps) - except Exception, e: - print >> sys.stderr, 'Error in set slider range: "%s".'%e - exit(-1) - slider.Bind(wx.EVT_SCROLL, self._handle_scroll) #bind the scrolling event - self.Add(slider, 0, wx.ALIGN_CENTER) - #init slider and text box - self.set_value(value) - - def get_value(self): - """ - Get the current set value. - @return the value (float) - """ - return self._value - - def set_value(self, value): - """ - Set the current set value. - @param value the value (float) - """ - self._value = value - self._update_slider() - self._update_text_box() - - def _update_slider(self): - """ - Translate the real numerical value into a slider value. - """ - slider_value = (float(self.get_value()) - self.min)*self.num_steps/(self.max - self.min) - self.slider.SetValue(slider_value) - - def _update_text_box(self): - """ - Update the text box value. - Convert the value into engineering notation. - """ - self.text_box.SetValue(eng_notation.num_to_str(self.get_value())) - - def _handle_scroll(self, event=None): - """ - A scroll event is detected. Read the slider, call the callback. - """ - slider_value = self.slider.GetValue() - new_value = slider_value*(self.max - self.min)/self.num_steps + self.min - self.set_value(new_value) - try: self.call() - except Exception, e: print >> sys.stderr, 'Error in exec callback from handle scroll.\n', e - - def _handle_enter(self, event=None): - """ - An enter key was pressed. Read the text box, call the callback. - """ - new_value = eng_notation.str_to_num(self.text_box.GetValue()) - self.set_value(new_value) - try: self.call() - except Exception, e: print >> sys.stderr, 'Error in exec callback from handle enter.\n', e - -class slider_horizontal_control(_slider_control_base): - label_text_orientation = wx.HORIZONTAL - slider_style = wx.SL_HORIZONTAL - def get_slider_size(self): return self.slider_length, -1 -class slider_vertical_control(_slider_control_base): - label_text_orientation = wx.VERTICAL - slider_style = wx.SL_VERTICAL - def get_slider_size(self): return -1, self.slider_length - -############################################################################################## -# Text Box Control -############################################################################################## -class text_box_control(_control_base): - """House a Text Box for variable control.""" - - def __init__(self, window, callback, label='Label', value=50): - """ - Text box contructor. - Create the text box, and label. - @param window the wx parent window - @param callback call the callback on changes - @param label the label title - @param value the default value - """ - #initialize - _control_base.__init__(self, window, callback) - #create gui elements - label_text_sizer = wx.BoxSizer(wx.HORIZONTAL) #label and text box container - label_text = LabelText(self.get_window(), '%s: '%str(label)) - self.text_box = text_box = wx.TextCtrl(self.get_window(), value=str(value), style=wx.TE_PROCESS_ENTER) - text_box.Bind(wx.EVT_TEXT_ENTER, self._handle_enter) #bind this special enter hotkey event - for obj in (label_text, text_box): #fill the container with label and text entry box - label_text_sizer.Add(obj, 0, wx.ALIGN_CENTER) - self.Add(label_text_sizer, 0, wx.ALIGN_CENTER) - #detect string mode - self._string_mode = isinstance(value, str) - - def get_value(self): - """ - Get the current set value. - @return the value (float) - """ - return self._value - - def _handle_enter(self, event=None): - """ - An enter key was pressed. Read the text box, call the callback. - If the text cannot be evaluated, do not try callback. - Do not evaluate the text box value in string mode. - """ - if self._string_mode: - self._value = str(self.text_box.GetValue()) - else: - try: self._value = eval(self.text_box.GetValue()) - except Exception, e: - print >> sys.stderr, 'Error in evaluate value from handle enter.\n', e - return - try: self.call() - except Exception, e: print >> sys.stderr, 'Error in exec callback from handle enter.\n', e diff --git a/grc/src/grc_gnuradio/wxgui/forms/__init__.py b/grc/src/grc_gnuradio/wxgui/forms/__init__.py new file mode 100644 index 000000000..07226668b --- /dev/null +++ b/grc/src/grc_gnuradio/wxgui/forms/__init__.py @@ -0,0 +1,54 @@ +# +# Copyright 2009 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. +# + +""" +The following classes will be available through gnuradio.wxgui.forms: +""" + +######################################################################## +# External Converters +######################################################################## +from converters import \ + eval_converter, str_converter, \ + float_converter, int_converter + +######################################################################## +# External Forms +######################################################################## +from forms import \ + radio_buttons, drop_down, notebook, \ + button, toggle_button, single_button, \ + check_box, text_box, static_text, \ + slider, log_slider + +######################################################################## +# Helpful widgets +######################################################################## +import wx + +class static_box_sizer(wx.StaticBoxSizer): + def __init__(self, parent, label='', bold=False, orient=wx.VERTICAL): + box = wx.StaticBox(parent=parent, label=label) + if bold: + font = box.GetFont() + font.SetWeight(wx.FONTWEIGHT_BOLD) + box.SetFont(font) + wx.StaticBoxSizer.__init__(self, box=box, orient=orient) diff --git a/grc/src/grc_gnuradio/wxgui/forms/converters.py b/grc/src/grc_gnuradio/wxgui/forms/converters.py new file mode 100644 index 000000000..5971cfc09 --- /dev/null +++ b/grc/src/grc_gnuradio/wxgui/forms/converters.py @@ -0,0 +1,143 @@ +# +# Copyright 2009 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. +# + +from gnuradio import eng_notation +import math + +class abstract_converter(object): + def external_to_internal(self, v): + """ + Convert from user specified value to value acceptable to underlying primitive. + The underlying primitive usually expects strings. + """ + raise NotImplementedError + def internal_to_external(self, s): + """ + Convert from underlying primitive value to user specified value. + The underlying primitive usually expects strings. + """ + raise NotImplementedError + def help(self): + return "Any string is acceptable" + +class identity_converter(abstract_converter): + def external_to_internal(self,v): + return v + def internal_to_external(self, s): + return s + +######################################################################## +# Commonly used converters +######################################################################## +class chooser_converter(abstract_converter): + """ + Convert between a set of possible choices and an index. + Used in the chooser base and all sub-classes. + """ + def __init__(self, choices): + self._choices = choices + def external_to_internal(self, choice): + return self._choices.index(choice) + def internal_to_external(self, index): + return self._choices[index] + def help(self): + return 'Enter a possible value in choices: "%s"'%str(self._choices) + +class bool_converter(abstract_converter): + """ + The internal representation is boolean. + The external representation is specified. + Used in the check box form. + """ + def __init__(self, true, false): + self._true = true + self._false = false + def external_to_internal(self, v): + return bool(v) + def internal_to_external(self, v): + if v: return self._true + else: return self._false + def help(self): + return "Value must be cast-able to type bool." + +class eval_converter(abstract_converter): + """ + A catchall converter when int and float are not enough. + Evaluate the internal representation with python's eval(). + Possible uses, set a complex number, constellation points. + Used in text box. + """ + def external_to_internal(self, s): + return str(s) + def internal_to_external(self, s): + return eval(s) + def help(self): + return "Value must be evaluatable by python's eval." + +class str_converter(abstract_converter): + def external_to_internal(self, v): + return str(v) + def internal_to_external(self, s): + return str(s) + +class int_converter(abstract_converter): + def external_to_internal(self, v): + return str(int(round(v))) + def internal_to_external(self, s): + return int(s, 0) + def help(self): + return "Enter an integer. Leading 0x indicates hex" + +class float_converter(abstract_converter): + def external_to_internal(self, v): + return eng_notation.num_to_str(v) + def internal_to_external(self, s): + return eng_notation.str_to_num(s) + def help(self): + return "Enter a float with optional scale suffix. E.g., 100.1M" + +class slider_converter(abstract_converter): + """ + Scale values to and from the slider. + """ + def __init__(self, minimum, maximum, num_steps, cast): + assert minimum < maximum + assert num_steps > 0 + self._offset = minimum + self._scaler = float(maximum - minimum)/num_steps + self._cast = cast + def external_to_internal(self, v): + return (v - self._offset)/self._scaler + def internal_to_external(self, v): + return self._cast(v*self._scaler + self._offset) + def help(self): + return "Value should be within slider range" + +class log_slider_converter(slider_converter): + def __init__(self, min_exp, max_exp, num_steps, base): + assert min_exp < max_exp + assert num_steps > 0 + self._base = base + slider_converter.__init__(self, minimum=min_exp, maximum=max_exp, num_steps=num_steps, cast=float) + def external_to_internal(self, v): + return slider_converter.external_to_internal(self, math.log(v, self._base)) + def internal_to_external(self, v): + return self._base**slider_converter.internal_to_external(self, v) diff --git a/grc/src/grc_gnuradio/wxgui/forms/forms.py b/grc/src/grc_gnuradio/wxgui/forms/forms.py new file mode 100644 index 000000000..5c5b6bad5 --- /dev/null +++ b/grc/src/grc_gnuradio/wxgui/forms/forms.py @@ -0,0 +1,473 @@ +# +# Copyright 2009 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. +# + +""" +The forms module contains general purpose wx-gui forms for gnuradio apps. + +The forms follow a layered model: + * internal layer + * deals with the wxgui objects directly + * implemented in event handler and update methods + * translation layer + * translates the between the external and internal layers + * handles parsing errors between layers + * external layer + * provided external access to the user + * set_value, get_value, and optional callback + * set and get through optional pubsub and key +""" + +EXT_KEY = 'external' +INT_KEY = 'internal' + +import wx +import sys +from gnuradio.gr.pubsub import pubsub +import converters + +EVT_DATA = wx.PyEventBinder(wx.NewEventType()) +class DataEvent(wx.PyEvent): + def __init__(self, data): + wx.PyEvent.__init__(self, wx.NewId(), EVT_DATA.typeId) + self.data = data + +######################################################################## +# Base Class Form +######################################################################## +class _form_base(pubsub, wx.BoxSizer): + def __init__(self, parent=None, sizer=None, proportion=0, flag=wx.EXPAND, ps=None, key='', value=None, callback=None, converter=converters.identity_converter()): + pubsub.__init__(self) + wx.BoxSizer.__init__(self, wx.HORIZONTAL) + self._parent = parent + self._converter = converter + self._callback = callback + self._widgets = list() + #add to the sizer if provided + if sizer: sizer.Add(self, proportion, flag) + #proxy the pubsub and key into this form + if ps is not None: + assert key + self.proxy(EXT_KEY, ps, key) + #no pubsub passed, must set initial value + else: self.set_value(value) + + def _add_widget(self, widget, label='', flag=0): + """ + Add the main widget to this object sizer. + If label is passed, add a label as well. + Register the widget and the label in the widgets list (for enable/disable). + Bind the update handler to the widget for data events. + This ensures that the gui thread handles updating widgets. + Setup the pusub triggers for external and internal. + @param widget the main widget + @param label the optional label + @param flag additional flags for widget + """ + #setup data event + widget.Bind(EVT_DATA, lambda x: self._update(x.data)) + update = lambda x: wx.PostEvent(widget, DataEvent(x)) + #register widget + self._widgets.append(widget) + #create optional label + if not label: self.Add(widget, 1, wx.ALIGN_CENTER_VERTICAL | flag) + else: + label_text = wx.StaticText(self._parent, label='%s: '%label) + self._widgets.append(label_text) + self.Add(label_text, 0, wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_LEFT) + self.Add(widget, 1, wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_RIGHT | flag) + #initialize without triggering pubsubs + self._translate_external_to_internal(self[EXT_KEY]) + update(self[INT_KEY]) + #subscribe all the functions + self.subscribe(INT_KEY, update) + self.subscribe(INT_KEY, self._translate_internal_to_external) + self.subscribe(EXT_KEY, self._translate_external_to_internal) + if self._callback: self.subscribe(EXT_KEY, self._callback) + + def _translate_external_to_internal(self, external): + try: + internal = self._converter.external_to_internal(external) + #prevent infinite loop between internal and external pubsub keys by only setting if changed + if self[INT_KEY] != internal: self[INT_KEY] = internal + except Exception, e: + self._err_msg(external, e) + self[INT_KEY] = self[INT_KEY] #reset to last good setting + + def _translate_internal_to_external(self, internal): + try: + external = self._converter.internal_to_external(internal) + #prevent infinite loop between internal and external pubsub keys by only setting if changed + if self[EXT_KEY] != external: self[EXT_KEY] = external + except Exception, e: + self._err_msg(internal, e) + self[EXT_KEY] = self[EXT_KEY] #reset to last good setting + + def _err_msg(self, value, e): + print >> sys.stderr, 'Error translating value: "%s"\n\t%s\n\t%s'%(value, e, self._converter.help()) + + #override in subclasses to handle the wxgui object + def _update(self, value): raise NotImplementedError + def _handle(self, event): raise NotImplementedError + + #provide a set/get interface for this form + def get_value(self): return self[EXT_KEY] + def set_value(self, value): self[EXT_KEY] = value + + def Disable(self, disable=True): self.Enable(not disable) + def Enable(self, enable=True): + if enable: + for widget in self._widgets: widget.Enable() + else: + for widget in self._widgets: widget.Disable() + +######################################################################## +# Static Text Form +######################################################################## +class static_text(_form_base): + def __init__(self, label='', width=-1, bold=False, converter=converters.str_converter(), **kwargs): + _form_base.__init__(self, converter=converter, **kwargs) + self._static_text = wx.StaticText(self._parent, size=wx.Size(width, -1)) + if bold: + font = self._static_text.GetFont() + font.SetWeight(wx.FONTWEIGHT_BOLD) + self._static_text.SetFont(font) + self._add_widget(self._static_text, label) + + def _update(self, label): self._static_text.SetLabel(label) + +######################################################################## +# Text Box Form +######################################################################## +class text_box(_form_base): + def __init__(self, label='', width=-1, converter=converters.eval_converter(), **kwargs): + _form_base.__init__(self, converter=converter, **kwargs) + self._text_box = wx.TextCtrl(self._parent, size=wx.Size(width, -1), style=wx.TE_PROCESS_ENTER) + self._text_box.Bind(wx.EVT_TEXT_ENTER, self._handle) + self._add_widget(self._text_box, label) + + def _handle(self, event): self[INT_KEY] = self._text_box.GetValue() + def _update(self, value): self._text_box.SetValue(value) + +######################################################################## +# Slider Form +######################################################################## +class _slider_base(_form_base): + """ + Base class for linear and log slider. + @param length the length of the slider in px + @param style wx.SL_HORIZONTAL or wx.SL_VERTICAL + """ + def __init__(self, label='', length=-1, converter=None, num_steps=100, style=wx.SL_HORIZONTAL, **kwargs): + _form_base.__init__(self, converter=converter, **kwargs) + if style & wx.SL_HORIZONTAL: slider_size = wx.Size(length, -1) + elif style & wx.SL_VERTICAL: slider_size = wx.Size(-1, length) + else: raise NotImplementedError + self._slider = wx.Slider(self._parent, minValue=0, maxValue=num_steps, size=slider_size, style=style) + self._slider.Bind(wx.EVT_SCROLL, self._handle) + self._add_widget(self._slider, label, flag=wx.EXPAND) + + def _handle(self, event): self[INT_KEY] = self._slider.GetValue() + def _update(self, value): self._slider.SetValue(value) + +class slider(_slider_base): + """ + A generic linear slider. + @param cast a cast function, int, or float (default=float) + """ + def __init__(self, minimum=-100, maximum=100, num_steps=100, step_size=None, cast=float, **kwargs): + assert step_size or num_steps + if step_size is not None: num_steps = (maximum - minimum)/step_size + converter = converters.slider_converter(minimum=minimum, maximum=maximum, num_steps=num_steps, cast=cast) + _slider_base.__init__(self, converter=converter, num_steps=num_steps, **kwargs) + +class log_slider(_slider_base): + """ + A generic log slider. + """ + def __init__(self, min_exp=0, max_exp=1, base=10, num_steps=100, step_size=None, **kwargs): + assert step_size or num_steps + if step_size is not None: num_steps = (max_exp - min_exp)/step_size + converter = converters.log_slider_converter(min_exp=min_exp, max_exp=max_exp, num_steps=num_steps, base=base) + _slider_base.__init__(self, converter=converter, num_steps=num_steps, **kwargs) + +######################################################################## +# Check Box Form +######################################################################## +class check_box(_form_base): + def __init__(self, label='', true=True, false=False, **kwargs): + _form_base.__init__(self, converter=converters.bool_converter(true=true, false=false), **kwargs) + self._check_box = wx.CheckBox(self._parent, style=wx.CHK_2STATE, label=label) + self._check_box.Bind(wx.EVT_CHECKBOX, self._handle) + self._add_widget(self._check_box) + + def _handle(self, event): self[INT_KEY] = self._check_box.IsChecked() + def _update(self, checked): self._check_box.SetValue(checked) + +######################################################################## +# Base Class Chooser Form +######################################################################## +class _chooser_base(_form_base): + def __init__(self, choices=[], labels=None, **kwargs): + _form_base.__init__(self, converter=converters.chooser_converter(choices), **kwargs) + self._choices = choices + self._labels = map(str, labels or choices) + +######################################################################## +# Drop Down Chooser Form +######################################################################## +class drop_down(_chooser_base): + def __init__(self, label='', **kwargs): + _chooser_base.__init__(self, **kwargs) + self._drop_down = wx.Choice(self._parent, choices=self._labels) + self._drop_down.Bind(wx.EVT_CHOICE, self._handle) + self._add_widget(self._drop_down, label) + + def _handle(self, event): self[INT_KEY] = self._drop_down.GetSelection() + def _update(self, i): self._drop_down.SetSelection(i) + +######################################################################## +# Button Chooser Form +# Circularly move through the choices with each click. +# Can be a single-click button with one choice. +# Can be a 2-state button with two choices. +######################################################################## +class button(_chooser_base): + def __init__(self, label='', style=0, width=-1, **kwargs): + _chooser_base.__init__(self, **kwargs) + self._button = wx.Button(self._parent, size=wx.Size(width, -1), style=style) + self._button.Bind(wx.EVT_BUTTON, self._handle) + self._add_widget(self._button, label) + + def _handle(self, event): self[INT_KEY] = (self[INT_KEY] + 1)%len(self._choices) #circularly increment index + def _update(self, i): self._button.SetLabel(self._labels[i]); self.Layout() + +class toggle_button(button): + """ + Create a dual state button. + This button will alternate between True and False when clicked. + """ + def __init__(self, true_label='On (click to stop)', false_label='Off (click to start)', **kwargs): + button.__init__(self, choices=[True, False], labels=[true_label, false_label], **kwargs) + +class single_button(toggle_button): + """ + Create a single state button. + This button will callback() when clicked. + For use when state holding is not important. + """ + def __init__(self, label='click for callback', **kwargs): + toggle_button.__init__(self, true_label=label, false_label=label, value=True, **kwargs) + +######################################################################## +# Radio Buttons Chooser Form +######################################################################## +class radio_buttons(_chooser_base): + """ + Create a radio button form. + @param parent the parent widget + @param sizer add this widget to sizer if provided (optional) + @param proportion the proportion when added to the sizer (default=0) + @param ps the pubsub object (optional) + @param key the pubsub key (optional) + @param value the default value (optional) + @param choices list of possible values + @param labels list of labels for each choice (default=choices) + @param major_dimension the number of rows/cols (default=auto) + @param label title label for this widget (optional) + @param style useful style args: wx.RA_HORIZONTAL, wx.RA_VERTICAL, wx.NO_BORDER (default=wx.RA_HORIZONTAL) + """ + def __init__(self, style=wx.RA_HORIZONTAL, label='', major_dimension=0, **kwargs): + _chooser_base.__init__(self, **kwargs) + #create radio buttons + self._radio_buttons = wx.RadioBox(self._parent, choices=self._labels, style=style, label=label, majorDimension=major_dimension) + self._radio_buttons.Bind(wx.EVT_RADIOBOX, self._handle) + self._add_widget(self._radio_buttons) + + def _handle(self, event): self[INT_KEY] = self._radio_buttons.GetSelection() + def _update(self, i): self._radio_buttons.SetSelection(i) + +######################################################################## +# Notebook Chooser Form +# The notebook pages/tabs are for selecting between choices. +# A page must be added to the notebook for each choice. +######################################################################## +class notebook(_chooser_base): + def __init__(self, pages, notebook, **kwargs): + _chooser_base.__init__(self, **kwargs) + assert len(pages) == len(self._choices) + self._notebook = notebook + self._notebook.Bind(wx.EVT_NOTEBOOK_PAGE_CHANGED, self._handle) + #add pages, setting the label on each tab + for i, page in enumerate(pages): + self._notebook.AddPage(page, self._labels[i]) + self._add_widget(self._notebook) + + def _handle(self, event): self[INT_KEY] = self._notebook.GetSelection() + def _update(self, i): self._notebook.SetSelection(i) + +# ---------------------------------------------------------------- +# Stand-alone test application +# ---------------------------------------------------------------- + +import wx +from gnuradio.wxgui import gui + +class app_gui (object): + def __init__(self, frame, panel, vbox, top_block, options, args): + + def callback(v): print v + + radio_buttons( + sizer=vbox, + parent=panel, + choices=[2, 4, 8, 16], + labels=['two', 'four', 'eight', 'sixteen'], + value=4, + style=wx.RA_HORIZONTAL, + label='test radio long string', + callback=callback, + #major_dimension = 2, + ) + + radio_buttons( + sizer=vbox, + parent=panel, + choices=[2, 4, 8, 16], + labels=['two', 'four', 'eight', 'sixteen'], + value=4, + style=wx.RA_VERTICAL, + label='test radio long string', + callback=callback, + #major_dimension = 2, + ) + + radio_buttons( + sizer=vbox, + parent=panel, + choices=[2, 4, 8, 16], + labels=['two', 'four', 'eight', 'sixteen'], + value=4, + style=wx.RA_VERTICAL | wx.NO_BORDER, + callback=callback, + #major_dimension = 2, + ) + + button( + sizer=vbox, + parent=panel, + choices=[2, 4, 8, 16], + labels=['two', 'four', 'eight', 'sixteen'], + value=2, + label='button value', + callback=callback, + #width=100, + ) + + + drop_down( + sizer=vbox, + parent=panel, + choices=[2, 4, 8, 16], + value=2, + label='Choose One', + callback=callback, + ) + check_box( + sizer=vbox, + parent=panel, + value=False, + label='check me', + callback=callback, + ) + text_box( + sizer=vbox, + parent=panel, + value=3, + label='text box', + callback=callback, + width=200, + ) + + static_text( + sizer=vbox, + parent=panel, + value='bob', + label='static text', + width=-1, + bold=True, + ) + + slider( + sizer=vbox, + parent=panel, + value=12, + label='slider', + callback=callback, + ) + + log_slider( + sizer=vbox, + parent=panel, + value=12, + label='slider', + callback=callback, + ) + + slider( + sizer=vbox, + parent=panel, + value=12, + label='slider', + callback=callback, + style=wx.SL_VERTICAL, + length=30, + ) + + toggle_button( + sizer=vbox, + parent=panel, + value=True, + label='toggle it', + callback=callback, + ) + + single_button( + sizer=vbox, + parent=panel, + label='sig test', + callback=callback, + ) + +if __name__ == "__main__": + try: + + # Create the GUI application + app = gui.app( + gui=app_gui, # User interface class + title="Test Forms", # Top window title + ) + + # And run it + app.MainLoop() + + except RuntimeError, e: + print e + sys.exit(1) diff --git a/grc/src/grc_gnuradio/wxgui/top_block_gui.py b/grc/src/grc_gnuradio/wxgui/top_block_gui.py index fef9d18ce..f3305d7c5 100644 --- a/grc/src/grc_gnuradio/wxgui/top_block_gui.py +++ b/grc/src/grc_gnuradio/wxgui/top_block_gui.py @@ -21,10 +21,11 @@ import wx import sys, os from gnuradio import gr +from gnuradio.gr.pubsub import pubsub default_gui_size = (200, 100) -class top_block_gui(gr.top_block): +class top_block_gui(gr.top_block, pubsub): """gr top block with wx gui app and grid sizer.""" def __init__(self, title='', size=default_gui_size, icon=None): @@ -37,6 +38,7 @@ class top_block_gui(gr.top_block): """ #initialize gr.top_block.__init__(self) + pubsub.__init__(self) self._size = size #set the icon if icon and os.path.isfile(icon): self._icon = icon diff --git a/grc/src/gui/ActionHandler.py b/grc/src/gui/ActionHandler.py index 91dd0fb45..da0909a64 100644 --- a/grc/src/gui/ActionHandler.py +++ b/grc/src/gui/ActionHandler.py @@ -1,5 +1,5 @@ """ -Copyright 2007 Free Software Foundation, Inc. +Copyright 2007, 2008, 2009 Free Software Foundation, Inc. This file is part of GNU Radio GNU Radio Companion is free software; you can redistribute it and/or @@ -19,7 +19,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA import os import signal -from Constants import DIR_LEFT, DIR_RIGHT, IMAGE_FILE_EXTENSION +from Constants import IMAGE_FILE_EXTENSION import Actions import pygtk pygtk.require('2.0') @@ -32,7 +32,8 @@ from .. utils import ParseXML import random from .. platforms.gui.Platform import Platform from MainWindow import MainWindow -from Dialogs import AboutDialog +from ParamsDialog import ParamsDialog +import Dialogs from FileDialogs import OpenFlowGraphFileDialog, SaveFlowGraphFileDialog, SaveImageFileDialog gobject.threads_init() @@ -57,7 +58,7 @@ class ActionHandler: #setup the main window self.main_window = MainWindow(self.handle_states, platform) self.main_window.connect('delete_event', self._quit) - self.main_window.connect('key_press_event', self._handle_key_press) + self.main_window.connect('key-press-event', self._handle_key_press) self.get_page = self.main_window.get_page self.get_flow_graph = self.main_window.get_flow_graph self.get_focus_flag = self.main_window.drawing_area.get_focus_flag @@ -72,32 +73,25 @@ class ActionHandler: def _handle_key_press(self, widget, event): """ - Handle key presses from the keyboard and translate key combos into actions. - This key press handler is called before the gtk accelerators kick in. - This handler ensures that key presses without a mod mask, - only pass to the accelerators if the flow graph is in focus. - This function also handles keys that accelerators refuse to handle: left/right, - and keys that are not registered with an accelerator: +/-. - @return false to let the accelerators handle the key action + Handle key presses from the keyboard and translate key combinations into actions. + This key press handler is called prior to the gtk key press handler. + This handler bypasses built in accelerator key handling when in focus because + * some keys are ignored by the accelerators like the direction keys, + * some keys are not registered to any accelerators but are still used. + When not in focus, gtk and the accelerators handle the the key press. + @return false to let gtk handle the key action """ - if self.get_focus_flag(): - try: - self.handle_states({ - 'Left': Actions.BLOCK_ROTATE_LEFT, - 'Right': Actions.BLOCK_ROTATE_RIGHT, - 'Up': Actions.BLOCK_DEC_TYPE, - 'Down': Actions.BLOCK_INC_TYPE, - 'equal': Actions.PORT_CONTROLLER_INC, - 'plus': Actions.PORT_CONTROLLER_INC, - 'KP_Add': Actions.PORT_CONTROLLER_INC, - 'minus': Actions.PORT_CONTROLLER_DEC, - 'KP_Subtract': Actions.PORT_CONTROLLER_DEC, - }[gtk.gdk.keyval_name(event.keyval)]) - return True - #focus: always return false for accelerator to handle - except: return False - #no focus: only allow accelerator to handle when a mod is used - return not event.state + #dont allow key presses to queue up + if gtk.events_pending(): return True + #extract action name from this key press + key_name = gtk.gdk.keyval_name(event.keyval) + mod_mask = event.state + action_name = Actions.get_action_name_from_key_name(key_name, mod_mask) + #handle the action if flow graph is in focus + if action_name and self.get_focus_flag(): + self.handle_states(action_name) + return True #handled by this method + return False #let gtk handle the key press def _quit(self, window, event): """ @@ -138,7 +132,7 @@ class ActionHandler: Actions.APPLICATION_QUIT, Actions.FLOW_GRAPH_NEW, Actions.FLOW_GRAPH_OPEN, Actions.FLOW_GRAPH_SAVE_AS, Actions.FLOW_GRAPH_CLOSE, Actions.ABOUT_WINDOW_DISPLAY, - Actions.FLOW_GRAPH_SCREEN_CAPTURE, + Actions.FLOW_GRAPH_SCREEN_CAPTURE, Actions.HELP_WINDOW_DISPLAY, ): Actions.get_action_from_name(action).set_sensitive(True) if not self.init_file_paths: self.init_file_paths = Preferences.files_open() @@ -193,13 +187,13 @@ class ActionHandler: elif state == Actions.BLOCK_MOVE: self.get_page().get_state_cache().save_new_state(self.get_flow_graph().export_data()) self.get_page().set_saved(False) - elif state == Actions.BLOCK_ROTATE_LEFT: - if self.get_flow_graph().rotate_selected(DIR_LEFT): + elif state == Actions.BLOCK_ROTATE_CCW: + if self.get_flow_graph().rotate_selected(90): self.get_flow_graph().update() self.get_page().get_state_cache().save_new_state(self.get_flow_graph().export_data()) self.get_page().set_saved(False) - elif state == Actions.BLOCK_ROTATE_RIGHT: - if self.get_flow_graph().rotate_selected(DIR_RIGHT): + elif state == Actions.BLOCK_ROTATE_CW: + if self.get_flow_graph().rotate_selected(-90): self.get_flow_graph().update() self.get_page().get_state_cache().save_new_state(self.get_flow_graph().export_data()) self.get_page().set_saved(False) @@ -238,12 +232,15 @@ class ActionHandler: # Window stuff ################################################## elif state == Actions.ABOUT_WINDOW_DISPLAY: - AboutDialog() + Dialogs.AboutDialog() + elif state == Actions.HELP_WINDOW_DISPLAY: + Dialogs.HelpDialog() ################################################## # Param Modifications ################################################## elif state == Actions.BLOCK_PARAM_MODIFY: - if self.get_flow_graph().param_modify_selected(): + selected_block = self.get_flow_graph().get_selected_block() + if selected_block and ParamsDialog(selected_block).run(): self.get_flow_graph().update() self.get_page().get_state_cache().save_new_state(self.get_flow_graph().export_data()) self.get_page().set_saved(False) @@ -296,7 +293,7 @@ class ActionHandler: elif state == Actions.FLOW_GRAPH_SCREEN_CAPTURE: file_path = SaveImageFileDialog(self.get_page().get_file_path()).run() if file_path is not None: - pixmap = self.get_flow_graph().get_drawing_area().pixmap + pixmap = self.get_flow_graph().get_pixmap() width, height = pixmap.get_size() pixbuf = gtk.gdk.Pixbuf(gtk.gdk.COLORSPACE_RGB, 0, 8, width, height) pixbuf.get_from_drawable(pixmap, pixmap.get_colormap(), 0, 0, 0, 0, width, height) @@ -333,8 +330,8 @@ class ActionHandler: #update general buttons Actions.get_action_from_name(Actions.ELEMENT_DELETE).set_sensitive(bool(self.get_flow_graph().get_selected_elements())) Actions.get_action_from_name(Actions.BLOCK_PARAM_MODIFY).set_sensitive(bool(self.get_flow_graph().get_selected_block())) - Actions.get_action_from_name(Actions.BLOCK_ROTATE_RIGHT).set_sensitive(bool(self.get_flow_graph().get_selected_blocks())) - Actions.get_action_from_name(Actions.BLOCK_ROTATE_LEFT).set_sensitive(bool(self.get_flow_graph().get_selected_blocks())) + Actions.get_action_from_name(Actions.BLOCK_ROTATE_CCW).set_sensitive(bool(self.get_flow_graph().get_selected_blocks())) + Actions.get_action_from_name(Actions.BLOCK_ROTATE_CW).set_sensitive(bool(self.get_flow_graph().get_selected_blocks())) #update cut/copy/paste Actions.get_action_from_name(Actions.BLOCK_CUT).set_sensitive(bool(self.get_flow_graph().get_selected_blocks())) Actions.get_action_from_name(Actions.BLOCK_COPY).set_sensitive(bool(self.get_flow_graph().get_selected_blocks())) @@ -348,7 +345,7 @@ class ActionHandler: Actions.get_action_from_name(Actions.FLOW_GRAPH_SAVE).set_sensitive(not self.get_page().get_saved()) self.main_window.update() #draw the flow graph - self.get_flow_graph().draw() + self.get_flow_graph().queue_draw() def update_exec_stop(self): """ diff --git a/grc/src/gui/Actions.py b/grc/src/gui/Actions.py index 16f12dd4c..9b687df7e 100644 --- a/grc/src/gui/Actions.py +++ b/grc/src/gui/Actions.py @@ -1,5 +1,5 @@ """ -Copyright 2007 Free Software Foundation, Inc. +Copyright 2007, 2008, 2009 Free Software Foundation, Inc. This file is part of GNU Radio GNU Radio Companion is free software; you can redistribute it and/or @@ -28,8 +28,8 @@ APPLICATION_INITIALIZE = 'app init' APPLICATION_QUIT = 'app quit' PARAM_MODIFY = 'param modify' BLOCK_MOVE = 'block move' -BLOCK_ROTATE_LEFT = 'block rotate left' -BLOCK_ROTATE_RIGHT = 'block rotate right' +BLOCK_ROTATE_CCW = 'block rotate ccw' +BLOCK_ROTATE_CW = 'block rotate cw' BLOCK_PARAM_MODIFY = 'block param modify' BLOCK_INC_TYPE = 'block increment type' BLOCK_DEC_TYPE = 'block decrement type' @@ -56,60 +56,85 @@ FLOW_GRAPH_EXEC = 'flow graph exec' FLOW_GRAPH_KILL = 'flow graph kill' FLOW_GRAPH_SCREEN_CAPTURE = 'flow graph screen capture' ABOUT_WINDOW_DISPLAY = 'about window display' +HELP_WINDOW_DISPLAY = 'help window display' ###################################################################################################### # Action Key Map ###################################################################################################### -_actions_key_map = { - #action name: (key name, mask) - FLOW_GRAPH_NEW: ('n', gtk.gdk.CONTROL_MASK), - FLOW_GRAPH_OPEN: ('o', gtk.gdk.CONTROL_MASK), - FLOW_GRAPH_SAVE: ('s', gtk.gdk.CONTROL_MASK), - FLOW_GRAPH_CLOSE: ('w', gtk.gdk.CONTROL_MASK), - APPLICATION_QUIT: ('q', gtk.gdk.CONTROL_MASK), - FLOW_GRAPH_UNDO: ('z', gtk.gdk.CONTROL_MASK), - FLOW_GRAPH_REDO: ('y', gtk.gdk.CONTROL_MASK), - ELEMENT_DELETE: ('Delete', 0), - BLOCK_ROTATE_LEFT: ('Left', 0), - BLOCK_ROTATE_RIGHT: ('Right', 0), - BLOCK_PARAM_MODIFY: ('Return', 0), - BLOCK_ENABLE: ('e', 0), - BLOCK_DISABLE: ('d', 0), - BLOCK_CUT: ('x', gtk.gdk.CONTROL_MASK), - BLOCK_COPY: ('c', gtk.gdk.CONTROL_MASK), - BLOCK_PASTE: ('v', gtk.gdk.CONTROL_MASK), - FLOW_GRAPH_GEN: ('F5', 0), - FLOW_GRAPH_EXEC: ('F6', 0), - FLOW_GRAPH_KILL: ('F7', 0), - FLOW_GRAPH_SCREEN_CAPTURE: ('Print', 0), -} +_actions_key_list = ( + #action name, key name, mod mask + (FLOW_GRAPH_NEW, 'n', gtk.gdk.CONTROL_MASK), + (FLOW_GRAPH_OPEN, 'o', gtk.gdk.CONTROL_MASK), + (FLOW_GRAPH_SAVE, 's', gtk.gdk.CONTROL_MASK), + (FLOW_GRAPH_SAVE_AS, 's', gtk.gdk.CONTROL_MASK | gtk.gdk.SHIFT_MASK), + (FLOW_GRAPH_CLOSE, 'w', gtk.gdk.CONTROL_MASK), + (APPLICATION_QUIT, 'q', gtk.gdk.CONTROL_MASK), + (FLOW_GRAPH_UNDO, 'z', gtk.gdk.CONTROL_MASK), + (FLOW_GRAPH_REDO, 'y', gtk.gdk.CONTROL_MASK), + (ELEMENT_DELETE, 'Delete', 0), + (BLOCK_ROTATE_CCW, 'Left', 0), + (BLOCK_ROTATE_CW, 'Right', 0), + (BLOCK_DEC_TYPE, 'Up', 0), + (BLOCK_INC_TYPE, 'Down', 0), + (BLOCK_PARAM_MODIFY, 'Return', 0), + (BLOCK_ENABLE, 'e', 0), + (BLOCK_DISABLE, 'd', 0), + (BLOCK_CUT, 'x', gtk.gdk.CONTROL_MASK), + (BLOCK_COPY, 'c', gtk.gdk.CONTROL_MASK), + (BLOCK_PASTE, 'v', gtk.gdk.CONTROL_MASK), + (FLOW_GRAPH_GEN, 'F5', 0), + (FLOW_GRAPH_EXEC, 'F6', 0), + (FLOW_GRAPH_KILL, 'F7', 0), + (FLOW_GRAPH_SCREEN_CAPTURE, 'Print', 0), + (HELP_WINDOW_DISPLAY, 'F1', 0), + #the following have no associated gtk.Action + (PORT_CONTROLLER_INC, 'equal', 0), + (PORT_CONTROLLER_INC, 'plus', 0), + (PORT_CONTROLLER_INC, 'KP_Add', 0), + (PORT_CONTROLLER_DEC, 'minus', 0), + (PORT_CONTROLLER_DEC, 'KP_Subtract', 0), +) + +_actions_key_dict = dict(((key_name, mod_mask), action_name) for action_name, key_name, mod_mask in _actions_key_list) +def get_action_name_from_key_name(key_name, mod_mask=0): + """ + Get the action name associated with the key name and mask. + Both keyname and mask have to match. + @param key_name the name of the key + @param mod_mask the key press mask (shift, ctrl) 0 for none + @return the action name or blank string + """ + key_name_mod_mask = (key_name, mod_mask) + if key_name_mod_mask in _actions_key_dict: return _actions_key_dict[key_name_mod_mask] + return '' ###################################################################################################### # Actions ###################################################################################################### _actions_list = ( - gtk.Action(FLOW_GRAPH_NEW, '_New', 'Create a new flow graph', 'gtk-new'), - gtk.Action(FLOW_GRAPH_OPEN, '_Open', 'Open an existing flow graph', 'gtk-open'), - gtk.Action(FLOW_GRAPH_SAVE, '_Save', 'Save the current flow graph', 'gtk-save'), - gtk.Action(FLOW_GRAPH_SAVE_AS, 'Save _As', 'Save the current flow graph as...', 'gtk-save-as'), - gtk.Action(FLOW_GRAPH_CLOSE, '_Close', 'Close the current flow graph', 'gtk-close'), - gtk.Action(APPLICATION_QUIT, '_Quit', 'Quit program', 'gtk-quit'), - gtk.Action(FLOW_GRAPH_UNDO, '_Undo', 'Undo a change to the flow graph', 'gtk-undo'), - gtk.Action(FLOW_GRAPH_REDO, '_Redo', 'Redo a change to the flow graph', 'gtk-redo'), - gtk.Action(ELEMENT_DELETE, '_Delete', 'Delete the selected blocks', 'gtk-delete'), - gtk.Action(BLOCK_ROTATE_LEFT, 'Rotate _Left', 'Rotate the selected blocks 90 degrees', 'gtk-go-back'), - gtk.Action(BLOCK_ROTATE_RIGHT, 'Rotate _Right', 'Rotate the selected blocks -90 degrees', 'gtk-go-forward'), - gtk.Action(BLOCK_PARAM_MODIFY, '_Properties', 'Modify params for the selected block', 'gtk-properties'), - gtk.Action(BLOCK_ENABLE, 'E_nable', 'Enable the selected blocks', 'gtk-connect'), - gtk.Action(BLOCK_DISABLE, 'D_isable', 'Disable the selected blocks', 'gtk-disconnect'), - gtk.Action(BLOCK_CUT, 'Cu_t', 'Cut', 'gtk-cut'), - gtk.Action(BLOCK_COPY, '_Copy', 'Copy', 'gtk-copy'), - gtk.Action(BLOCK_PASTE, '_Paste', 'Paste', 'gtk-paste'), - gtk.Action(ABOUT_WINDOW_DISPLAY, '_About', 'About this program', 'gtk-about'), - gtk.Action(FLOW_GRAPH_GEN, '_Generate', 'Generate the flow graph', 'gtk-convert'), - gtk.Action(FLOW_GRAPH_EXEC, '_Execute', 'Execute the flow graph', 'gtk-execute'), - gtk.Action(FLOW_GRAPH_KILL, '_Kill', 'Kill the flow graph', 'gtk-stop'), - gtk.Action(FLOW_GRAPH_SCREEN_CAPTURE, 'S_creen Capture', 'Create a screen capture of the flow graph', 'gtk-print'), + gtk.Action(FLOW_GRAPH_NEW, '_New', 'Create a new flow graph', gtk.STOCK_NEW), + gtk.Action(FLOW_GRAPH_OPEN, '_Open', 'Open an existing flow graph', gtk.STOCK_OPEN), + gtk.Action(FLOW_GRAPH_SAVE, '_Save', 'Save the current flow graph', gtk.STOCK_SAVE), + gtk.Action(FLOW_GRAPH_SAVE_AS, 'Save _As', 'Save the current flow graph as...', gtk.STOCK_SAVE_AS), + gtk.Action(FLOW_GRAPH_CLOSE, '_Close', 'Close the current flow graph', gtk.STOCK_CLOSE), + gtk.Action(APPLICATION_QUIT, '_Quit', 'Quit program', gtk.STOCK_QUIT), + gtk.Action(FLOW_GRAPH_UNDO, '_Undo', 'Undo a change to the flow graph', gtk.STOCK_UNDO), + gtk.Action(FLOW_GRAPH_REDO, '_Redo', 'Redo a change to the flow graph', gtk.STOCK_REDO), + gtk.Action(ELEMENT_DELETE, '_Delete', 'Delete the selected blocks', gtk.STOCK_DELETE), + gtk.Action(BLOCK_ROTATE_CCW, 'Rotate Counterclockwise', 'Rotate the selected blocks 90 degrees to the left', gtk.STOCK_GO_BACK), + gtk.Action(BLOCK_ROTATE_CW, 'Rotate Clockwise', 'Rotate the selected blocks 90 degrees to the right', gtk.STOCK_GO_FORWARD), + gtk.Action(BLOCK_PARAM_MODIFY, '_Properties', 'Modify params for the selected block', gtk.STOCK_PROPERTIES), + gtk.Action(BLOCK_ENABLE, 'E_nable', 'Enable the selected blocks', gtk.STOCK_CONNECT), + gtk.Action(BLOCK_DISABLE, 'D_isable', 'Disable the selected blocks', gtk.STOCK_DISCONNECT), + gtk.Action(BLOCK_CUT, 'Cu_t', 'Cut', gtk.STOCK_CUT), + gtk.Action(BLOCK_COPY, '_Copy', 'Copy', gtk.STOCK_COPY), + gtk.Action(BLOCK_PASTE, '_Paste', 'Paste', gtk.STOCK_PASTE), + gtk.Action(ABOUT_WINDOW_DISPLAY, '_About', 'About this program', gtk.STOCK_ABOUT), + gtk.Action(HELP_WINDOW_DISPLAY, '_Help', 'Usage Tips', gtk.STOCK_HELP), + gtk.Action(FLOW_GRAPH_GEN, '_Generate', 'Generate the flow graph', gtk.STOCK_CONVERT), + gtk.Action(FLOW_GRAPH_EXEC, '_Execute', 'Execute the flow graph', gtk.STOCK_EXECUTE), + gtk.Action(FLOW_GRAPH_KILL, '_Kill', 'Kill the flow graph', gtk.STOCK_STOP), + gtk.Action(FLOW_GRAPH_SCREEN_CAPTURE, 'S_creen Capture', 'Create a screen capture of the flow graph', gtk.STOCK_PRINT), ) def get_all_actions(): return _actions_list @@ -122,16 +147,21 @@ def get_action_from_name(action_name): @throw KeyError bad action name @return a gtk action object """ - if _actions_dict.has_key(action_name): return _actions_dict[action_name] + if action_name in _actions_dict: return _actions_dict[action_name] raise KeyError('Action Name: "%s" does not exist'%action_name) +###################################################################################################### +# Accelerators +###################################################################################################### _accel_group = gtk.AccelGroup() def get_accel_group(): return _accel_group -#load the actions key map #set the accelerator group, and accelerator path -#register the key and mod with the accelerator path -for action_name, (key_name, mod) in _actions_key_map.iteritems(): - get_action_from_name(action_name).set_accel_group(get_accel_group()) - get_action_from_name(action_name).set_accel_path('<main>/'+action_name) - gtk.accel_map_add_entry('<main>/'+action_name, gtk.gdk.keyval_from_name(key_name),mod) +#register the key name and mod mask with the accelerator path +for action_name, key_name, mod_mask in _actions_key_list: + try: + accel_path = '<main>/'+action_name + get_action_from_name(action_name).set_accel_group(get_accel_group()) + get_action_from_name(action_name).set_accel_path(accel_path) + gtk.accel_map_add_entry(accel_path, gtk.gdk.keyval_from_name(key_name), mod_mask) + except KeyError: pass #no action was created for this action name diff --git a/grc/src/gui/Bars.py b/grc/src/gui/Bars.py index c89aea580..52e7ba1f8 100644 --- a/grc/src/gui/Bars.py +++ b/grc/src/gui/Bars.py @@ -1,5 +1,5 @@ """ -Copyright 2007 Free Software Foundation, Inc. +Copyright 2007, 2008, 2009 Free Software Foundation, Inc. This file is part of GNU Radio GNU Radio Companion is free software; you can redistribute it and/or @@ -43,8 +43,8 @@ TOOLBAR_LIST = ( Actions.FLOW_GRAPH_EXEC, Actions.FLOW_GRAPH_KILL, None, - Actions.BLOCK_ROTATE_LEFT, - Actions.BLOCK_ROTATE_RIGHT, + Actions.BLOCK_ROTATE_CCW, + Actions.BLOCK_ROTATE_CW, None, Actions.BLOCK_ENABLE, Actions.BLOCK_DISABLE, @@ -73,8 +73,8 @@ MENU_BAR_LIST = ( Actions.BLOCK_PASTE, Actions.ELEMENT_DELETE, None, - Actions.BLOCK_ROTATE_LEFT, - Actions.BLOCK_ROTATE_RIGHT, + Actions.BLOCK_ROTATE_CCW, + Actions.BLOCK_ROTATE_CW, None, Actions.BLOCK_ENABLE, Actions.BLOCK_DISABLE, @@ -87,6 +87,8 @@ MENU_BAR_LIST = ( Actions.FLOW_GRAPH_KILL, ]), (gtk.Action('Help', '_Help', None, None), [ + Actions.HELP_WINDOW_DISPLAY, + None, Actions.ABOUT_WINDOW_DISPLAY, ]), ) diff --git a/grc/src/gui/BlockTreeWindow.py b/grc/src/gui/BlockTreeWindow.py index 94b9476c5..9e4bec3f9 100644 --- a/grc/src/gui/BlockTreeWindow.py +++ b/grc/src/gui/BlockTreeWindow.py @@ -1,5 +1,5 @@ """ -Copyright 2007 Free Software Foundation, Inc. +Copyright 2007, 2008, 2009 Free Software Foundation, Inc. This file is part of GNU Radio GNU Radio Companion is free software; you can redistribute it and/or @@ -17,7 +17,7 @@ along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA """ -from Constants import DEFAULT_BLOCKS_WINDOW_WIDTH +from Constants import DEFAULT_BLOCKS_WINDOW_WIDTH, DND_TARGETS import pygtk pygtk.require('2.0') import gtk @@ -53,6 +53,9 @@ class BlockTreeWindow(gtk.VBox): renderer = gtk.CellRendererText() column = gtk.TreeViewColumn('Blocks', renderer, text=NAME_INDEX) self.treeview.append_column(column) + #setup drag and drop + self.treeview.enable_model_drag_source(gtk.gdk.BUTTON1_MASK, DND_TARGETS, gtk.gdk.ACTION_COPY) + self.treeview.connect('drag-data-get', self._handle_drag_get_data) #make the scrolled window to hold the tree view scrolled_window = gtk.ScrolledWindow() scrolled_window.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC) @@ -60,12 +63,11 @@ class BlockTreeWindow(gtk.VBox): scrolled_window.set_size_request(DEFAULT_BLOCKS_WINDOW_WIDTH, -1) self.pack_start(scrolled_window) #add button - self.add_button = gtk.Button(None, 'gtk-add') + self.add_button = gtk.Button(None, gtk.STOCK_ADD) self.add_button.connect('clicked', self._handle_add_button) self.pack_start(self.add_button, False) - #map categories to iters - self.categories = dict() - self.categories[tuple()] = None + #map categories to iters, automatic mapping for root + self._categories = {tuple(): None} #add blocks and categories self.platform.load_block_tree(self) #initialize @@ -78,22 +80,21 @@ class BlockTreeWindow(gtk.VBox): """ Add a block with category to this selection window. Add only the category when block is None. - @param category the category string + @param category the category list @param block the block object or None """ - #rectify category - category = filter(lambda x: x, category.split('/')) + category = tuple(category)[1:] #tuple is hashable #add category and all sub categories - for i in range(len(category)): - sub_category = tuple(category[:i+1]) - if sub_category not in self.categories.keys(): - iter = self.treestore.insert_before(self.categories[tuple(category[:i])], None) - self.treestore.set_value(iter, NAME_INDEX, '[ %s ]'%category[i]) + for i, cat_name in enumerate(category): + sub_category = category[:i+1] + if sub_category not in self._categories: + iter = self.treestore.insert_before(self._categories[sub_category[:-1]], None) + self.treestore.set_value(iter, NAME_INDEX, '[ %s ]'%cat_name) self.treestore.set_value(iter, KEY_INDEX, '') - self.categories[sub_category] = iter + self._categories[sub_category] = iter #add block if block is None: return - iter = self.treestore.insert_before(self.categories[tuple(category)], None) + iter = self.treestore.insert_before(self._categories[category], None) self.treestore.set_value(iter, NAME_INDEX, block.get_name()) self.treestore.set_value(iter, KEY_INDEX, block.get_key()) @@ -127,6 +128,15 @@ class BlockTreeWindow(gtk.VBox): ############################################################ ## Event Handlers ############################################################ + def _handle_drag_get_data(self, widget, drag_context, selection_data, info, time): + """ + Handle a drag and drop by setting the key to the selection object. + This will call the destination handler for drag and drop. + Only call set when the key is valid to ignore DND from categories. + """ + key = self._get_selected_block_key() + if key: selection_data.set(selection_data.target, 8, key) + def _handle_mouse_button_press(self, widget, event): """ Handle the mouse button press. diff --git a/grc/src/gui/Constants.py b/grc/src/gui/Constants.py index 70e6b6b6e..f23ab8b13 100644 --- a/grc/src/gui/Constants.py +++ b/grc/src/gui/Constants.py @@ -1,5 +1,5 @@ """ -Copyright 2008 Free Software Foundation, Inc. +Copyright 2008, 2009 Free Software Foundation, Inc. This file is part of GNU Radio GNU Radio Companion is free software; you can redistribute it and/or @@ -17,6 +17,9 @@ along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA """ +import pygtk +pygtk.require('2.0') +import gtk import os ##default path for the open/save dialogs @@ -28,10 +31,6 @@ IMAGE_FILE_EXTENSION = '.png' ##name for new/unsaved flow graphs NEW_FLOGRAPH_TITLE = 'untitled' -##rotation constants -DIR_LEFT = 'left' -DIR_RIGHT = 'right' - ##main window constraints MIN_WINDOW_WIDTH = 600 MIN_WINDOW_HEIGHT = 400 @@ -42,16 +41,8 @@ MIN_DIALOG_HEIGHT = 500 DEFAULT_BLOCKS_WINDOW_WIDTH = 100 DEFAULT_REPORTS_WINDOW_WIDTH = 100 -##How close can the mouse get to the window border before mouse events are ignored. -BORDER_PROXIMITY_SENSITIVITY = 50 -##How close the mouse can get to the edge of the visible window before scrolling is invoked. -SCROLL_PROXIMITY_SENSITIVITY = 30 -##When the window has to be scrolled, move it this distance in the required direction. -SCROLL_DISTANCE = 15 -##The redrawing sensitivity, how many seconds must pass between motion events before a redraw? -MOTION_DETECT_REDRAWING_SENSITIVITY = .02 -##How close the mouse click can be to a connection and register a connection select. -CONNECTION_SELECT_SENSITIVITY = 5 - ##The size of the state saving cache in the flow graph (for undo/redo functionality) STATE_CACHE_SIZE = 42 + +##Shared targets for drag and drop of blocks +DND_TARGETS = [('STRING', gtk.TARGET_SAME_APP, 0)] diff --git a/grc/src/gui/Dialogs.py b/grc/src/gui/Dialogs.py index e15f8c574..d526b97b4 100644 --- a/grc/src/gui/Dialogs.py +++ b/grc/src/gui/Dialogs.py @@ -1,5 +1,5 @@ """ -Copyright 2008 Free Software Foundation, Inc. +Copyright 2008, 2009 Free Software Foundation, Inc. This file is part of GNU Radio GNU Radio Companion is free software; you can redistribute it and/or @@ -20,7 +20,6 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA import pygtk pygtk.require('2.0') import gtk -from Constants import MIN_DIALOG_WIDTH, MIN_DIALOG_HEIGHT from .. platforms.base.Constants import PACKAGE, VERSION import Preferences @@ -82,3 +81,20 @@ Achilleas Anastasopoulos -> trellis support -----""") self.run() self.destroy() + +def HelpDialog(): + MessageDialogHelper( + type=gtk.MESSAGE_INFO, + buttons=gtk.BUTTONS_CLOSE, + title='Help', + markup="""\ +<b>Usage Tips</b> + +<u>Add block</u>: drag and drop or double click a block in the block selection window. +<u>Rotate block</u>: Select a block, press left/right on the keyboard. +<u>Change type</u>: Select a block, press up/down on the keyboard. +<u>Edit parameters</u>: double click on a block in the flow graph. +<u>Make connection</u>: click on the source port of one block, then click on the sink port of another block. +<u>Remove connection</u>: select the connection and press delete, or drag the connection. + +* See the menu for other keyboard shortcuts.""") diff --git a/grc/src/gui/DrawingArea.py b/grc/src/gui/DrawingArea.py index 3588e122d..5258979d8 100644 --- a/grc/src/gui/DrawingArea.py +++ b/grc/src/gui/DrawingArea.py @@ -1,5 +1,5 @@ """ -Copyright 2007 Free Software Foundation, Inc. +Copyright 2007, 2008, 2009 Free Software Foundation, Inc. This file is part of GNU Radio GNU Radio Companion is free software; you can redistribute it and/or @@ -20,7 +20,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA import pygtk pygtk.require('2.0') import gtk -from Constants import MIN_WINDOW_WIDTH, MIN_WINDOW_HEIGHT +from Constants import MIN_WINDOW_WIDTH, MIN_WINDOW_HEIGHT, DND_TARGETS class DrawingArea(gtk.DrawingArea): """ @@ -51,24 +51,26 @@ class DrawingArea(gtk.DrawingArea): gtk.gdk.LEAVE_NOTIFY_MASK | \ gtk.gdk.ENTER_NOTIFY_MASK ) + #setup drag and drop + self.drag_dest_set(gtk.DEST_DEFAULT_ALL, DND_TARGETS, gtk.gdk.ACTION_COPY) + self.connect('drag-data-received', self._handle_drag_data_received) #setup the focus flag self._focus_flag = False self.get_focus_flag = lambda: self._focus_flag - self.connect("leave-notify-event", self._handle_focus_event, False) - self.connect("enter-notify-event", self._handle_focus_event, True) + self.connect('leave-notify-event', self._handle_focus_event, False) + self.connect('enter-notify-event', self._handle_focus_event, True) #pixmap for drawing self.pixmap = None - self.gc = None - - def draw(self): - """ - Draw the pixmap onto this drawing area. - """ - self.window.draw_drawable(self.gc, self.pixmap, 0, 0, 0, 0, -1, -1) ########################################################################## ## Handlers ########################################################################## + def _handle_drag_data_received(self, widget, drag_context, x, y, selection_data, info, time): + """ + Handle a drag and drop by adding a block at the given coordinate. + """ + self._main_window.get_flow_graph().add_new_block(selection_data.data, (x, y)) + def _handle_focus_event(self, widget, event, focus_flag): """Record the focus state of the flow graph window.""" self._focus_flag = focus_flag @@ -83,7 +85,6 @@ class DrawingArea(gtk.DrawingArea): double_click=(event.type == gtk.gdk._2BUTTON_PRESS), coordinate=(event.x, event.y), ) - return True def _handle_mouse_button_release(self, widget, event): """ @@ -94,7 +95,6 @@ class DrawingArea(gtk.DrawingArea): left_click=(event.button == 1), coordinate=(event.x, event.y), ) - return True def _handle_mouse_motion(self, widget, event): """ @@ -104,15 +104,15 @@ class DrawingArea(gtk.DrawingArea): self._main_window.get_flow_graph().handle_mouse_motion( coordinate=(event.x, event.y), ) - return True def _handle_window_expose(self, widget, event): """ - Called when the window initially appears or is resized: create a new pixmap, draw the flow graph. + Called when window is exposed, resized, or queue_draw is called. """ - self.gc = self.window.new_gc() + gc = self.window.new_gc() width, height = self.get_size_request() if not self.pixmap or (width, height) != self.pixmap.get_size(): self.pixmap = gtk.gdk.Pixmap(self.window, width, height, -1) - self._main_window.get_flow_graph().draw() - return True + #double buffering: draw to pixmap, then draw pixmap + self._main_window.get_flow_graph().draw(gc, self.pixmap) + self.window.draw_drawable(gc, self.pixmap, 0, 0, 0, 0, -1, -1) diff --git a/grc/src/gui/ParamsDialog.py b/grc/src/gui/ParamsDialog.py index 5837ab7c4..6cc42e8fc 100644 --- a/grc/src/gui/ParamsDialog.py +++ b/grc/src/gui/ParamsDialog.py @@ -1,5 +1,5 @@ """ -Copyright 2007 Free Software Foundation, Inc. +Copyright 2007, 2008, 2009 Free Software Foundation, Inc. This file is part of GNU Radio GNU Radio Companion is free software; you can redistribute it and/or @@ -45,9 +45,11 @@ class ParamsDialog(gtk.Dialog): SignalBlockParamsDialog contructor. @param block the signal block """ - gtk.Dialog.__init__(self, buttons=('gtk-close', gtk.RESPONSE_CLOSE)) + gtk.Dialog.__init__(self, + title='Properties: %s'%block.get_name(), + buttons=(gtk.STOCK_CLOSE, gtk.RESPONSE_CLOSE), + ) self.block = block - self.set_title('Properties: %s'%block.get_name()) self.set_size_request(MIN_DIALOG_WIDTH, MIN_DIALOG_HEIGHT) vbox = gtk.VBox() #Add the title label diff --git a/grc/src/platforms/base/Block.py b/grc/src/platforms/base/Block.py index bc9b58a5e..25688472c 100644 --- a/grc/src/platforms/base/Block.py +++ b/grc/src/platforms/base/Block.py @@ -1,5 +1,5 @@ """ -Copyright 2008 Free Software Foundation, Inc. +Copyright 2008, 2009 Free Software Foundation, Inc. This file is part of GNU Radio GNU Radio Companion is free software; you can redistribute it and/or @@ -17,7 +17,6 @@ along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA """ -from ... import utils from ... utils import odict from Element import Element from Param import Param @@ -31,7 +30,7 @@ class TemplateArg(UserDict): A cheetah template argument created from a param. The str of this class evaluates to the param's to code method. The use of this class as a dictionary (enum only) will reveal the enum opts. - The eval method can return the param evaluated to a raw python data type. + The __call__ or () method can return the param evaluated to a raw python data type. """ def __init__(self, param): @@ -44,7 +43,7 @@ class TemplateArg(UserDict): def __str__(self): return str(self._param.to_code()) - def eval(self): + def __call__(self): return self._param.evaluate() class Block(Element): @@ -59,33 +58,33 @@ class Block(Element): #build the block Element.__init__(self, flow_graph) #grab the data - params = utils.listify(n, 'param') - sources = utils.listify(n, 'source') - sinks = utils.listify(n, 'sink') - self._name = n['name'] - self._key = n['key'] - self._category = utils.exists_or_else(n, 'category', '') - self._block_wrapper_path = n['block_wrapper_path'] + params = n.findall('param') + sources = n.findall('source') + sinks = n.findall('sink') + self._name = n.find('name') + self._key = n.find('key') + self._category = n.find('category') or '' + self._block_wrapper_path = n.find('block_wrapper_path') #create the param objects self._params = odict() #add the id param self._params['id'] = self.get_parent().get_parent().Param( self, - { + odict({ 'name': 'ID', 'key': 'id', 'type': 'id', - } + }) ) self._params['_enabled'] = self.get_parent().get_parent().Param( self, - { + odict({ 'name': 'Enabled', 'key': '_enabled', 'type': 'raw', 'value': 'True', 'hide': 'all', - } + }) ) for param in map(lambda n: self.get_parent().get_parent().Param(self, n), params): key = param.get_key() @@ -250,13 +249,11 @@ class Block(Element): Any param keys that do not exist will be ignored. @param n the nested data odict """ - params_n = utils.listify(n, 'param') + params_n = n.findall('param') for param_n in params_n: - #key and value must exist in the n data - if 'key' in param_n.keys() and 'value' in param_n.keys(): - key = param_n['key'] - value = param_n['value'] - #the key must exist in this block's params - if key in self.get_param_keys(): - self.get_param(key).set_value(value) + key = param_n.find('key') + value = param_n.find('value') + #the key must exist in this block's params + if key in self.get_param_keys(): + self.get_param(key).set_value(value) self.validate() diff --git a/grc/src/platforms/base/FlowGraph.py b/grc/src/platforms/base/FlowGraph.py index aeb66ac7e..747038bfb 100644 --- a/grc/src/platforms/base/FlowGraph.py +++ b/grc/src/platforms/base/FlowGraph.py @@ -1,5 +1,5 @@ """ -Copyright 2008 Free Software Foundation, Inc. +Copyright 2008, 2009 Free Software Foundation, Inc. This file is part of GNU Radio GNU Radio Companion is free software; you can redistribute it and/or @@ -17,7 +17,6 @@ along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA """ -from ... import utils from ... utils import odict from Element import Element from Block import Block @@ -37,7 +36,7 @@ class FlowGraph(Element): #initialize Element.__init__(self, platform) #inital blank import - self.import_data({'flow_graph': {}}) + self.import_data() def _get_unique_id(self, base_id=''): """ @@ -179,9 +178,9 @@ class FlowGraph(Element): n['timestamp'] = time.ctime() n['block'] = [block.export_data() for block in self.get_blocks()] n['connection'] = [connection.export_data() for connection in self.get_connections()] - return {'flow_graph': n} + return odict({'flow_graph': n}) - def import_data(self, n): + def import_data(self, n=None): """ Import blocks and connections into this flow graph. Clear this flowgraph of all previous blocks and connections. @@ -190,19 +189,16 @@ class FlowGraph(Element): """ #remove previous elements self._elements = list() - #the flow graph tag must exists, or use blank data - if 'flow_graph' in n.keys(): fg_n = n['flow_graph'] - else: - Messages.send_error_load('Flow graph data not found, loading blank flow graph.') - fg_n = {} - blocks_n = utils.listify(fg_n, 'block') - connections_n = utils.listify(fg_n, 'connection') + #use blank data if none provided + fg_n = n and n.find('flow_graph') or odict() + blocks_n = fg_n.findall('block') + connections_n = fg_n.findall('connection') #create option block self._options_block = self.get_parent().get_new_block(self, 'options') self._options_block.get_param('id').set_value('options') #build the blocks for block_n in blocks_n: - key = block_n['key'] + key = block_n.find('key') if key == 'options': block = self._options_block else: block = self.get_new_block(key) #only load the block when the block key was valid @@ -210,21 +206,14 @@ class FlowGraph(Element): else: Messages.send_error_load('Block key "%s" not found in %s'%(key, self.get_parent())) #build the connections for connection_n in connections_n: - #test that the data tags exist - try: - assert('source_block_id' in connection_n.keys()) - assert('sink_block_id' in connection_n.keys()) - assert('source_key' in connection_n.keys()) - assert('sink_key' in connection_n.keys()) - except AssertionError: continue #try to make the connection try: #get the block ids - source_block_id = connection_n['source_block_id'] - sink_block_id = connection_n['sink_block_id'] + source_block_id = connection_n.find('source_block_id') + sink_block_id = connection_n.find('sink_block_id') #get the port keys - source_key = connection_n['source_key'] - sink_key = connection_n['sink_key'] + source_key = connection_n.find('source_key') + sink_key = connection_n.find('sink_key') #verify the blocks block_ids = map(lambda b: b.get_id(), self.get_blocks()) assert(source_block_id in block_ids) diff --git a/grc/src/platforms/base/Param.py b/grc/src/platforms/base/Param.py index ebc9977fc..81783c791 100644 --- a/grc/src/platforms/base/Param.py +++ b/grc/src/platforms/base/Param.py @@ -1,5 +1,5 @@ """ -Copyright 2008 Free Software Foundation, Inc. +Copyright 2008, 2009 Free Software Foundation, Inc. This file is part of GNU Radio GNU Radio Companion is free software; you can redistribute it and/or @@ -17,13 +17,11 @@ along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA """ -from ... import utils from ... utils import odict from Element import Element import pygtk pygtk.require('2.0') import gtk -import gobject class InputParam(gtk.HBox): """The base class for an input parameter inside the input parameters dialog.""" @@ -60,37 +58,60 @@ class EnumParam(InputParam): def __init__(self, *args, **kwargs): InputParam.__init__(self, *args, **kwargs) - input = gtk.ComboBox(gtk.ListStore(gobject.TYPE_STRING)) - cell = gtk.CellRendererText() - input.pack_start(cell, True) - input.add_attribute(cell, 'text', 0) - for option in self.param.get_options(): input.append_text(option.get_name()) - input.set_active(int(self.param.get_option_keys().index(self.param.get_value()))) - input.connect("changed", self._handle_changed) - self.pack_start(input, False) - self.get_text = lambda: str(input.get_active()) #the get text parses the selected index to a string + self._input = gtk.combo_box_new_text() + for option in self.param.get_options(): self._input.append_text(option.get_name()) + self._input.set_active(self.param.get_option_keys().index(self.param.get_value())) + self._input.connect('changed', self._handle_changed) + self.pack_start(self._input, False) + def get_text(self): return self.param.get_option_keys()[self._input.get_active()] + +class EnumEntryParam(InputParam): + """Provide an entry box and drop down menu for Raw Enum types.""" + + def __init__(self, *args, **kwargs): + InputParam.__init__(self, *args, **kwargs) + self._input = gtk.combo_box_entry_new_text() + for option in self.param.get_options(): self._input.append_text(option.get_name()) + try: self._input.set_active(self.param.get_option_keys().index(self.param.get_value())) + except: + self._input.set_active(-1) + self._input.get_child().set_text(self.param.get_value()) + self._input.connect('changed', self._handle_changed) + self._input.get_child().connect('changed', self._handle_changed) + self.pack_start(self._input, False) + def get_text(self): + if self._input.get_active() == -1: return self._input.get_child().get_text() + return self.param.get_option_keys()[self._input.get_active()] + def set_color(self, color): + if self._input.get_active() == -1: #custom entry, use color + self._input.get_child().modify_base(gtk.STATE_NORMAL, gtk.gdk.color_parse(color)) + else: #from enum, make white background + self._input.get_child().modify_base(gtk.STATE_NORMAL, gtk.gdk.color_parse('#ffffff')) class Option(Element): - def __init__(self, param, name, key, opts): + def __init__(self, param, n): Element.__init__(self, param) - self._name = name - self._key = key + self._name = n.find('name') + self._key = n.find('key') self._opts = dict() + opts = n.findall('opt') + #test against opts when non enum + try: assert self.get_parent().is_enum() or not opts + except AssertionError: self._exit_with_error('Options for non-enum types cannot have sub-options') + #extract opts for opt in opts: #separate the key:value try: key, value = opt.split(':') except: self._exit_with_error('Error separating "%s" into key:value'%opt) #test against repeated keys - try: assert(not self._opts.has_key(key)) + try: assert not self._opts.has_key(key) except AssertionError: self._exit_with_error('Key "%s" already exists in option'%key) #store the option self._opts[key] = value def __str__(self): return 'Option %s(%s)'%(self.get_name(), self.get_key()) - def get_name(self): return self._name - def get_key(self): return self._key ############################################## @@ -100,29 +121,6 @@ class Option(Element): def get_opt(self, key): return self._opts[key] def get_opts(self): return self._opts.values() - ############################################## - ## Static Make Methods - ############################################## - def make_option_from_n(param, n): - """ - Make a new option from nested data. - @param param the parent element - @param n the nested odict - @return a new option - """ - #grab the data - name = n['name'] - key = n['key'] - opts = utils.listify(n, 'opt') - #build the option - return Option( - param=param, - name=name, - key=key, - opts=opts, - ) - make_option_from_n = staticmethod(make_option_from_n) - class Param(Element): ##possible param types @@ -136,21 +134,16 @@ class Param(Element): @return a new param """ #grab the data - name = n['name'] - key = n['key'] - value = utils.exists_or_else(n, 'value', '') - type = n['type'] - hide = utils.exists_or_else(n, 'hide', '') - options = utils.listify(n, 'option') + self._name = n.find('name') + self._key = n.find('key') + value = n.find('value') or '' + self._type = n.find('type') + self._hide = n.find('hide') or '' #build the param Element.__init__(self, block) - self._name = name - self._key = key - self._type = type - self._hide = hide #create the Option objects from the n data self._options = odict() - for option in map(lambda o: Option.make_option_from_n(self, o), options): + for option in map(lambda o: Option(self, o), n.findall('option')): key = option.get_key() #test against repeated keys try: assert(key not in self.get_option_keys()) @@ -226,7 +219,7 @@ class Param(Element): self._value = str(value) #must be a string def get_type(self): return self.get_parent().resolve_dependencies(self._type) - def is_enum(self): return bool(self.get_options()) + def is_enum(self): return self._type == 'enum' def __repr__(self): """ @@ -241,9 +234,13 @@ class Param(Element): def get_input_class(self): """ Get the graphical gtk class to represent this parameter. + An enum requires and combo parameter. + A non-enum with options gets a combined entry/combo parameter. + All others get a standard entry parameter. @return gtk input class """ if self.is_enum(): return EnumParam + if self.get_options(): return EnumEntryParam return EntryParam ############################################## diff --git a/grc/src/platforms/base/Platform.py b/grc/src/platforms/base/Platform.py index 1a96594bb..1f04fa0a6 100644 --- a/grc/src/platforms/base/Platform.py +++ b/grc/src/platforms/base/Platform.py @@ -1,5 +1,5 @@ """ -Copyright 2008 Free Software Foundation, Inc. +Copyright 2008, 2009 Free Software Foundation, Inc. This file is part of GNU Radio GNU Radio Companion is free software; you can redistribute it and/or @@ -19,7 +19,6 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA import os from ... utils import ParseXML -from ... import utils from Element import Element as _Element from FlowGraph import FlowGraph as _FlowGraph from Connection import Connection as _Connection @@ -73,17 +72,17 @@ class Platform(_Element): """ try: ParseXML.validate_dtd(f, self._block_dtd) except ParseXML.XMLSyntaxError, e: self._exit_with_error('Block definition "%s" failed: \n\t%s'%(f, e)) - for n in utils.listify(ParseXML.from_file(f), 'block'): - #inject block wrapper path - n['block_wrapper_path'] = f - block = self.Block(self._flow_graph, n) - key = block.get_key() - #test against repeated keys - try: assert(key not in self.get_block_keys()) - except AssertionError: self._exit_with_error('Key "%s" already exists in blocks'%key) - #store the block - self._blocks[key] = block - self._blocks_n[key] = n + n = ParseXML.from_file(f).find('block') + #inject block wrapper path + n['block_wrapper_path'] = f + block = self.Block(self._flow_graph, n) + key = block.get_key() + #test against repeated keys + try: assert(key not in self.get_block_keys()) + except AssertionError: self._exit_with_error('Key "%s" already exists in blocks'%key) + #store the block + self._blocks[key] = block + self._blocks_n[key] = n def load_block_tree(self, block_tree): """ @@ -93,21 +92,21 @@ class Platform(_Element): @param block_tree the block tree object """ #recursive function to load categories and blocks - def load_category(cat_n, parent=''): + def load_category(cat_n, parent=[]): #add this category - parent = '%s/%s'%(parent, cat_n['name']) + parent = parent + [cat_n.find('name')] block_tree.add_block(parent) #recursive call to load sub categories - map(lambda c: load_category(c, parent), utils.listify(cat_n, 'cat')) + map(lambda c: load_category(c, parent), cat_n.findall('cat')) #add blocks in this category - for block_key in utils.listify(cat_n, 'block'): + for block_key in cat_n.findall('block'): block_tree.add_block(parent, self.get_block(block_key)) #load the block tree f = self._block_tree try: ParseXML.validate_dtd(f, BLOCK_TREE_DTD) except ParseXML.XMLSyntaxError, e: self._exit_with_error('Block tree "%s" failed: \n\t%s'%(f, e)) #add all blocks in the tree - load_category(ParseXML.from_file(f)['cat']) + load_category(ParseXML.from_file(f).find('cat')) #add all other blocks, use the catgory for block in self.get_blocks(): #blocks with empty categories are in the xml block tree or hidden diff --git a/grc/src/platforms/base/Port.py b/grc/src/platforms/base/Port.py index 26ad1fc4a..f46a81195 100644 --- a/grc/src/platforms/base/Port.py +++ b/grc/src/platforms/base/Port.py @@ -1,5 +1,5 @@ """ -Copyright 2008 Free Software Foundation, Inc. +Copyright 2008, 2009 Free Software Foundation, Inc. This file is part of GNU Radio GNU Radio Companion is free software; you can redistribute it and/or @@ -17,7 +17,6 @@ along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA """ -from ... import utils from Element import Element class Port(Element): diff --git a/grc/src/platforms/gui/Block.py b/grc/src/platforms/gui/Block.py index ab6a6d0b2..4aa35bf03 100644 --- a/grc/src/platforms/gui/Block.py +++ b/grc/src/platforms/gui/Block.py @@ -1,5 +1,5 @@ """ -Copyright 2007 Free Software Foundation, Inc. +Copyright 2007, 2008, 2009 Free Software Foundation, Inc. This file is part of GNU Radio GNU Radio Companion is free software; you can redistribute it and/or @@ -20,15 +20,19 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA from Element import Element import Utils import Colors -from ... gui.Constants import BORDER_PROXIMITY_SENSITIVITY +from ... utils import odict +from Constants import BORDER_PROXIMITY_SENSITIVITY from Constants import \ - BLOCK_FONT, BLOCK_LABEL_PADDING, \ + BLOCK_LABEL_PADDING, \ PORT_SEPARATION, LABEL_SEPARATION, \ PORT_BORDER_SEPARATION, POSSIBLE_ROTATIONS import pygtk pygtk.require('2.0') import gtk -import pango + +BLOCK_MARKUP_TMPL="""\ +#set $foreground = $block.is_valid() and 'black' or 'red' +<span foreground="$foreground" font_desc="Sans 8"><b>$encode($block.get_name())</b></span>""" class Block(Element): """The graphical signal block.""" @@ -41,23 +45,23 @@ class Block(Element): #add the position param self._params['_coordinate'] = self.get_parent().get_parent().Param( self, - { + odict({ 'name': 'GUI Coordinate', 'key': '_coordinate', 'type': 'raw', 'value': '(0, 0)', 'hide': 'all', - } + }) ) self._params['_rotation'] = self.get_parent().get_parent().Param( self, - { + odict({ 'name': 'GUI Rotation', 'key': '_rotation', 'type': 'raw', 'value': '0', 'hide': 'all', - } + }) ) Element.__init__(self) @@ -130,10 +134,7 @@ class Block(Element): #create the main layout layout = gtk.DrawingArea().create_pango_layout('') layouts.append(layout) - if self.is_valid(): layout.set_markup('<b>'+Utils.xml_encode(self.get_name())+'</b>') - else: layout.set_markup('<span foreground="red"><b>'+Utils.xml_encode(self.get_name())+'</b></span>') - desc = pango.FontDescription(BLOCK_FONT) - layout.set_font_description(desc) + layout.set_markup(Utils.parse_template(BLOCK_MARKUP_TMPL, block=self)) self.label_width, self.label_height = layout.get_pixel_size() #display the params for param in filter(lambda p: p.get_hide() not in ('all', 'part'), self.get_params()): @@ -166,22 +167,22 @@ class Block(Element): for j in range(height): vimage.put_pixel(j, width-i-1, image.get_pixel(i, j)) map(lambda p: p._create_labels(), self.get_ports()) - def draw(self, window): + def draw(self, gc, window): """ Draw the signal block with label and inputs/outputs. + @param gc the graphics context @param window the gtk window to draw on """ x, y = self.get_coordinate() #draw main block - Element.draw(self, window, BG_color=self.bg_color) + Element.draw(self, gc, window, BG_color=self.bg_color) #draw label image - gc = self.get_gc() if self.is_horizontal(): window.draw_image(gc, self.horizontal_label, 0, 0, x+BLOCK_LABEL_PADDING, y+(self.H-self.label_height)/2, -1, -1) elif self.is_vertical(): window.draw_image(gc, self.vertical_label, 0, 0, x+(self.H-self.label_height)/2, y+BLOCK_LABEL_PADDING, -1, -1) #draw ports - map(lambda p: p.draw(window), self.get_ports()) + for port in self.get_ports(): port.draw(gc, window) def what_is_selected(self, coor, coor_m=None): """ diff --git a/grc/src/platforms/gui/Connection.py b/grc/src/platforms/gui/Connection.py index b130611fb..9f243215e 100644 --- a/grc/src/platforms/gui/Connection.py +++ b/grc/src/platforms/gui/Connection.py @@ -106,9 +106,10 @@ class Connection(Element): self.add_line((x1, y1), points[0]) self.add_line((x2, y2), points[0]) - def draw(self, window): + def draw(self, gc, window): """ Draw the connection. + @param gc the graphics context @param window the gtk window to draw on """ sink = self.get_sink() @@ -123,8 +124,7 @@ class Connection(Element): self._source_coor = source.get_coordinate() #draw fg_color = self.get_enabled() and Colors.FG_COLOR or Colors.DISABLED_FG_COLOR - Element.draw(self, window, FG_color=fg_color) - gc = self.get_gc() + Element.draw(self, gc, window, FG_color=fg_color) gc.foreground = self._foreground #draw arrow on sink port window.draw_polygon(gc, True, self._arrow) diff --git a/grc/src/platforms/gui/Constants.py b/grc/src/platforms/gui/Constants.py index 00899cb78..90c8c1c38 100644 --- a/grc/src/platforms/gui/Constants.py +++ b/grc/src/platforms/gui/Constants.py @@ -1,23 +1,21 @@ -# -# Copyright 2008 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. -# +""" +Copyright 2008, 2009 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 +""" #label constraint dimensions LABEL_SEPARATION = 3 @@ -27,11 +25,6 @@ PORT_LABEL_PADDING = 2 PORT_SEPARATION = 17 PORT_BORDER_SEPARATION = 9 PORT_MIN_WIDTH = 20 -#fonts -PARAM_LABEL_FONT = 'Sans 9.5' -PARAM_FONT = 'Sans 7.5' -BLOCK_FONT = 'Sans 8' -PORT_FONT = 'Sans 7.5' #minimal length of connector CONNECTOR_EXTENSION_MINIMAL = 11 #increment length for connector @@ -41,3 +34,11 @@ CONNECTOR_ARROW_BASE = 13 CONNECTOR_ARROW_HEIGHT = 17 #possible rotations in degrees POSSIBLE_ROTATIONS = (0, 90, 180, 270) +#How close can the mouse get to the window border before mouse events are ignored. +BORDER_PROXIMITY_SENSITIVITY = 50 +#How close the mouse can get to the edge of the visible window before scrolling is invoked. +SCROLL_PROXIMITY_SENSITIVITY = 30 +#When the window has to be scrolled, move it this distance in the required direction. +SCROLL_DISTANCE = 15 +#How close the mouse click can be to a line and register a connection select. +LINE_SELECT_SENSITIVITY = 5 diff --git a/grc/src/platforms/gui/Element.py b/grc/src/platforms/gui/Element.py index f97d85ff6..8ef288ed1 100644 --- a/grc/src/platforms/gui/Element.py +++ b/grc/src/platforms/gui/Element.py @@ -22,7 +22,7 @@ import pygtk pygtk.require('2.0') import gtk import pango -from ... gui.Constants import CONNECTION_SELECT_SENSITIVITY +from Constants import LINE_SELECT_SENSITIVITY from Constants import POSSIBLE_ROTATIONS class Element(object): @@ -61,17 +61,14 @@ class Element(object): rotation = rotation or self.get_rotation() return rotation in (90, 270) - def get_gc(self): return self._gc - - def draw(self, window, BG_color=Colors.BG_COLOR, FG_color=Colors.FG_COLOR): + def draw(self, gc, window, BG_color=Colors.BG_COLOR, FG_color=Colors.FG_COLOR): """ Draw in the given window. + @param gc the graphics context @param window the gtk window to draw on @param BG_color the background color @param FG_color the foreground color """ - gc = self.get_parent().get_gc() - self._gc = gc X,Y = self.get_coordinate() for (rX,rY),(W,H) in self.areas_dict[self.get_rotation()]: aX = X + rX @@ -84,12 +81,12 @@ class Element(object): gc.foreground = self.is_highlighted() and Colors.H_COLOR or FG_color window.draw_line(gc, X+x1, Y+y1, X+x2, Y+y2) - def rotate(self, direction): + def rotate(self, rotation): """ Rotate all of the areas by 90 degrees. - @param direction 90 or 270 degrees + @param rotation multiple of 90 degrees """ - self.set_rotation((self.get_rotation() + direction)%360) + self.set_rotation((self.get_rotation() + rotation)%360) def clear(self): """Empty the lines and areas.""" @@ -204,8 +201,8 @@ class Element(object): if in_between(x, x1, x1+w) and in_between(y, y1, y1+h): return self #handle horizontal or vertical lines for (x1, y1), (x2, y2) in self.lines_dict[self.get_rotation()]: - if x1 == x2: x1, x2 = x1-CONNECTION_SELECT_SENSITIVITY, x2+CONNECTION_SELECT_SENSITIVITY - if y1 == y2: y1, y2 = y1-CONNECTION_SELECT_SENSITIVITY, y2+CONNECTION_SELECT_SENSITIVITY + if x1 == x2: x1, x2 = x1-LINE_SELECT_SENSITIVITY, x2+LINE_SELECT_SENSITIVITY + if y1 == y2: y1, y2 = y1-LINE_SELECT_SENSITIVITY, y2+LINE_SELECT_SENSITIVITY if in_between(x, x1, x2) and in_between(y, y1, y2): return self return None diff --git a/grc/src/platforms/gui/FlowGraph.py b/grc/src/platforms/gui/FlowGraph.py index cc2e27163..31d90984d 100644 --- a/grc/src/platforms/gui/FlowGraph.py +++ b/grc/src/platforms/gui/FlowGraph.py @@ -1,5 +1,5 @@ """ -Copyright 2007 Free Software Foundation, Inc. +Copyright 2007, 2008, 2009 Free Software Foundation, Inc. This file is part of GNU Radio GNU Radio Companion is free software; you can redistribute it and/or @@ -17,25 +17,19 @@ along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA """ -from ... gui.Constants import \ - DIR_LEFT, DIR_RIGHT, \ - SCROLL_PROXIMITY_SENSITIVITY, SCROLL_DISTANCE, \ - MOTION_DETECT_REDRAWING_SENSITIVITY +from Constants import SCROLL_PROXIMITY_SENSITIVITY, SCROLL_DISTANCE from ... gui.Actions import \ ELEMENT_CREATE, ELEMENT_SELECT, \ BLOCK_PARAM_MODIFY, BLOCK_MOVE, \ ELEMENT_DELETE import Colors import Utils -from ... import utils -from ... gui.ParamsDialog import ParamsDialog from Element import Element from .. base import FlowGraph as _FlowGraph import pygtk pygtk.require('2.0') import gtk import random -import time from ... gui import Messages class FlowGraph(Element): @@ -57,7 +51,6 @@ class FlowGraph(Element): self.element_moved = False self.mouse_pressed = False self.unselect() - self.time = 0 self.press_coor = (0, 0) #selected ports self._old_selected_port = None @@ -67,28 +60,31 @@ class FlowGraph(Element): # Access Drawing Area ########################################################################### def get_drawing_area(self): return self.drawing_area - def get_gc(self): return self.get_drawing_area().gc - def get_pixmap(self): return self.get_drawing_area().pixmap + def queue_draw(self): self.get_drawing_area().queue_draw() def get_size(self): return self.get_drawing_area().get_size_request() def set_size(self, *args): self.get_drawing_area().set_size_request(*args) def get_window(self): return self.get_drawing_area().window + def get_pixmap(self): return self.get_drawing_area().pixmap def get_scroll_pane(self): return self.drawing_area.get_parent() def get_ctrl_mask(self): return self.drawing_area.ctrl_mask - def add_new_block(self, key): + def add_new_block(self, key, coor=None): """ Add a block of the given key to this flow graph. @param key the block key + @param coor an optional coordinate or None for random """ id = self._get_unique_id(key) #calculate the position coordinate h_adj = self.get_scroll_pane().get_hadjustment() v_adj = self.get_scroll_pane().get_vadjustment() - x = int(random.uniform(.25, .75)*h_adj.page_size + h_adj.get_value()) - y = int(random.uniform(.25, .75)*v_adj.page_size + v_adj.get_value()) + if coor is None: coor = ( + int(random.uniform(.25, .75)*h_adj.page_size + h_adj.get_value()), + int(random.uniform(.25, .75)*v_adj.page_size + v_adj.get_value()), + ) #get the new block block = self.get_new_block(key) - block.set_coordinate((x, y)) + block.set_coordinate(coor) block.set_rotation(0) block.get_param('id').set_value(id) self.handle_states(ELEMENT_CREATE) @@ -137,15 +133,15 @@ class FlowGraph(Element): y_off = v_adj.get_value() - y_min + v_adj.page_size/4 #create blocks for block_n in blocks_n: - block_key = block_n['key'] + block_key = block_n.find('key') if block_key == 'options': continue block = self.get_new_block(block_key) selected.add(block) #set params - params_n = utils.listify(block_n, 'param') + params_n = block_n.findall('param') for param_n in params_n: - param_key = param_n['key'] - param_value = param_n['value'] + param_key = param_n.find('key') + param_value = param_n.find('value') #setup id parameter if param_key == 'id': old_id2block[param_value] = block @@ -160,8 +156,8 @@ class FlowGraph(Element): self.update() #create connections for connection_n in connections_n: - source = old_id2block[connection_n['source_block_id']].get_source(connection_n['source_key']) - sink = old_id2block[connection_n['sink_block_id']].get_sink(connection_n['sink_key']) + source = old_id2block[connection_n.find('source_block_id')].get_source(connection_n.find('source_key')) + sink = old_id2block[connection_n.find('sink_block_id')].get_sink(connection_n.find('sink_key')) self.connect(source, sink) #set all pasted elements selected for block in selected: selected = selected.union(set(block.get_connections())) @@ -186,14 +182,6 @@ class FlowGraph(Element): """ return any([sb.port_controller_modify(direction) for sb in self.get_selected_blocks()]) - def param_modify_selected(self): - """ - Create and show a param modification dialog for the selected block. - @return true if parameters were changed - """ - if not self.get_selected_block(): return False - return ParamsDialog(self.get_selected_block()).run() - def enable_selected(self, enable): """ Enable/disable the selected blocks. @@ -216,15 +204,13 @@ class FlowGraph(Element): selected_block.move(delta_coordinate) self.element_moved = True - def rotate_selected(self, direction): + def rotate_selected(self, rotation): """ - Rotate the selected blocks by 90 degrees. - @param direction DIR_LEFT or DIR_RIGHT + Rotate the selected blocks by multiples of 90 degrees. + @param rotation the rotation in degrees @return true if changed, otherwise false. """ if not self.get_selected_blocks(): return False - #determine the number of degrees to rotate - rotation = {DIR_LEFT: 90, DIR_RIGHT:270}[direction] #initialize min and max coordinates min_x, min_y = self.get_selected_block().get_coordinate() max_x, max_y = self.get_selected_block().get_coordinate() @@ -255,55 +241,49 @@ class FlowGraph(Element): changed = True return changed - def draw(self): + def draw(self, gc, window): """ Draw the background and grid if enabled. Draw all of the elements in this flow graph onto the pixmap. Draw the pixmap to the drawable window of this flow graph. """ - if self.get_gc(): - W,H = self.get_size() - #draw the background - self.get_gc().foreground = Colors.BACKGROUND_COLOR - self.get_pixmap().draw_rectangle(self.get_gc(), True, 0, 0, W, H) - #draw multi select rectangle - if self.mouse_pressed and (not self.get_selected_elements() or self.get_ctrl_mask()): - #coordinates - x1, y1 = self.press_coor - x2, y2 = self.get_coordinate() - #calculate top-left coordinate and width/height - x, y = int(min(x1, x2)), int(min(y1, y2)) - w, h = int(abs(x1 - x2)), int(abs(y1 - y2)) - #draw - self.get_gc().foreground = Colors.H_COLOR - self.get_pixmap().draw_rectangle(self.get_gc(), True, x, y, w, h) - self.get_gc().foreground = Colors.TXT_COLOR - self.get_pixmap().draw_rectangle(self.get_gc(), False, x, y, w, h) - #draw blocks on top of connections - for element in self.get_connections() + self.get_blocks(): - element.draw(self.get_pixmap()) - #draw selected blocks on top of selected connections - for selected_element in self.get_selected_connections() + self.get_selected_blocks(): - selected_element.draw(self.get_pixmap()) - self.get_drawing_area().draw() + try: #set the size of the flow graph area (if changed) + new_size = self.get_option('window_size') + if self.get_size() != tuple(new_size): self.set_size(*new_size) + except: pass + W,H = self.get_size() + #draw the background + gc.foreground = Colors.BACKGROUND_COLOR + window.draw_rectangle(gc, True, 0, 0, W, H) + #draw multi select rectangle + if self.mouse_pressed and (not self.get_selected_elements() or self.get_ctrl_mask()): + #coordinates + x1, y1 = self.press_coor + x2, y2 = self.get_coordinate() + #calculate top-left coordinate and width/height + x, y = int(min(x1, x2)), int(min(y1, y2)) + w, h = int(abs(x1 - x2)), int(abs(y1 - y2)) + #draw + gc.foreground = Colors.H_COLOR + window.draw_rectangle(gc, True, x, y, w, h) + gc.foreground = Colors.TXT_COLOR + window.draw_rectangle(gc, False, x, y, w, h) + #draw blocks on top of connections + for element in self.get_connections() + self.get_blocks(): + element.draw(gc, window) + #draw selected blocks on top of selected connections + for selected_element in self.get_selected_connections() + self.get_selected_blocks(): + selected_element.draw(gc, window) def update(self): """ Update highlighting so only the selected is highlighted. Call update on all elements. - Resize the window if size changed. """ - #update highlighting - map(lambda e: e.set_highlighted(False), self.get_elements()) - for selected_element in self.get_selected_elements(): - selected_element.set_highlighted(True) - #update all elements - map(lambda e: e.update(), self.get_elements()) - #set the size of the flow graph area - old_x, old_y = self.get_size() - try: new_x, new_y = self.get_option('window_size') - except: new_x, new_y = old_x, old_y - if new_x != old_x or new_y != old_y: self.set_size(new_x, new_y) + selected_elements = self.get_selected_elements() + for element in self.get_elements(): + element.set_highlighted(element in selected_elements) + element.update() ########################################################################## ## Get Selected @@ -466,7 +446,6 @@ class FlowGraph(Element): self.handle_states(BLOCK_MOVE) self.element_moved = False self.update_selected_elements() - self.draw() def handle_mouse_motion(self, coordinate): """ @@ -474,9 +453,8 @@ class FlowGraph(Element): Move a selected element to the new coordinate. Auto-scroll the scroll bars at the boundaries. """ - #to perform a movement, the mouse must be pressed, timediff large enough - if not self.mouse_pressed: return - if time.time() - self.time < MOTION_DETECT_REDRAWING_SENSITIVITY: return + #to perform a movement, the mouse must be pressed, no pending events + if gtk.events_pending() or not self.mouse_pressed: return #perform autoscrolling width, height = self.get_size() x, y = coordinate @@ -499,7 +477,6 @@ class FlowGraph(Element): #move the selected elements and record the new coordinate X, Y = self.get_coordinate() if not self.get_ctrl_mask(): self.move_selected((int(x - X), int(y - Y))) - self.draw() self.set_coordinate((x, y)) - #update time - self.time = time.time() + #queue draw for animation + self.queue_draw() diff --git a/grc/src/platforms/gui/Param.py b/grc/src/platforms/gui/Param.py index 2afe18c57..33a9b1f52 100644 --- a/grc/src/platforms/gui/Param.py +++ b/grc/src/platforms/gui/Param.py @@ -1,5 +1,5 @@ """ -Copyright 2007 Free Software Foundation, Inc. +Copyright 2007, 2008, 2009 Free Software Foundation, Inc. This file is part of GNU Radio GNU Radio Companion is free software; you can redistribute it and/or @@ -22,8 +22,30 @@ from Element import Element import pygtk pygtk.require('2.0') import gtk -import pango -from Constants import PARAM_LABEL_FONT, PARAM_FONT + +PARAM_MARKUP_TMPL="""\ +#set $foreground = $param.is_valid() and 'black' or 'red' +#set $value = not $param.is_valid() and 'error' or repr($param) +<span foreground="$foreground" font_desc="Sans 7.5"><b>$encode($param.get_name()): </b>$encode($value)</span>""" + +PARAM_LABEL_MARKUP_TMPL="""\ +#set $foreground = $param.is_valid() and 'black' or 'red' +#set $underline = $has_cb and 'low' or 'none' +<span underline="$underline" foreground="$foreground" font_desc="Sans 9">$encode($param.get_name())</span>""" + +TIP_MARKUP_TMPL="""\ +Key: $param.get_key() +Type: $param.get_type() +#if $param.is_valid() +Value: $param.evaluate() +#elif len($param.get_error_messages()) == 1 +Error: $(param.get_error_messages()[0]) +#else +Error: + #for $error_msg in $param.get_error_messages() + * $error_msg + #end for +#end if""" class Param(Element): """The graphical parameter.""" @@ -52,24 +74,12 @@ class Param(Element): When the input changes, write the inputs to the data type. Finish by calling the exteral callback. """ - value = self._input.get_text() - if self.is_enum(): value = self.get_option_keys()[int(value)] - self.set_value(value) - #set the markup on the label, red for errors in corresponding data type. - name = '<span font_desc="%s">%s</span>'%( - PARAM_LABEL_FONT, - Utils.xml_encode(self.get_name()), - ) - #special markups if param is involved in a callback - if hasattr(self.get_parent(), 'get_callbacks') and \ - filter(lambda c: self.get_key() in c, self.get_parent()._callbacks): - name = '<span underline="low">%s</span>'%name - if not self.is_valid(): - self._input.set_markup('<span foreground="red">%s</span>'%name) - tip = 'Error: ' + ' '.join(self.get_error_messages()) - else: - self._input.set_markup(name) - tip = 'Value: %s'%str(self.evaluate()) + self.set_value(self._input.get_text()) + #is param is involved in a callback? #FIXME: messy + has_cb = \ + hasattr(self.get_parent(), 'get_callbacks') and \ + filter(lambda c: self.get_key() in c, self.get_parent()._callbacks) + self._input.set_markup(Utils.parse_template(PARAM_LABEL_MARKUP_TMPL, param=self, has_cb=has_cb)) #hide/show if self.get_hide() == 'all': self._input.hide_all() else: self._input.show_all() @@ -78,30 +88,16 @@ class Param(Element): #set the tooltip if self._input.tp: self._input.tp.set_tip( self._input.entry, - 'Key: %s\nType: %s\n%s'%(self.get_key(), self.get_type(), tip), + Utils.parse_template(TIP_MARKUP_TMPL, param=self).strip(), ) #execute the external callback if self._callback: self._callback(self) - def get_markup(self): - """ - Create a markup to display the param as a label on the block. - If the param is valid, use the param's repr representation. - Otherwise, create a markup for error. - @return pango markup string - """ - if self.is_valid(): - return '<b>%s:</b> %s'%(Utils.xml_encode(self.get_name()), Utils.xml_encode(repr(self))) - else: - return '<span foreground="red"><b>%s:</b> error</span>'%Utils.xml_encode(self.get_name()) - def get_layout(self): """ Create a layout based on the current markup. @return the pango layout """ layout = gtk.DrawingArea().create_pango_layout('') - layout.set_markup(self.get_markup()) - desc = pango.FontDescription(PARAM_FONT) - layout.set_font_description(desc) + layout.set_markup(Utils.parse_template(PARAM_MARKUP_TMPL, param=self)) return layout diff --git a/grc/src/platforms/gui/Port.py b/grc/src/platforms/gui/Port.py index 85d9fea5a..3aec6e4a7 100644 --- a/grc/src/platforms/gui/Port.py +++ b/grc/src/platforms/gui/Port.py @@ -20,13 +20,16 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA from Element import Element from Constants import \ PORT_SEPARATION, CONNECTOR_EXTENSION_MINIMAL, \ - CONNECTOR_EXTENSION_INCREMENT, PORT_FONT, \ + CONNECTOR_EXTENSION_INCREMENT, \ PORT_LABEL_PADDING, PORT_MIN_WIDTH +import Utils import Colors import pygtk pygtk.require('2.0') import gtk -import pango + +PORT_MARKUP_TMPL="""\ +<span foreground="black" font_desc="Sans 7.5">$encode($port.get_name())</span>""" class Port(Element): """The graphical port.""" @@ -83,9 +86,8 @@ class Port(Element): """Create the labels for the socket.""" self.BG_color = Colors.get_color(self.get_color()) #create the layout - layout = gtk.DrawingArea().create_pango_layout(self.get_name()) - desc = pango.FontDescription(PORT_FONT) - layout.set_font_description(desc) + layout = gtk.DrawingArea().create_pango_layout('') + layout.set_markup(Utils.parse_template(PORT_MARKUP_TMPL, port=self)) self.w, self.h = layout.get_pixel_size() self.W, self.H = 2*PORT_LABEL_PADDING+self.w, 2*PORT_LABEL_PADDING+self.h #create the pixmap @@ -102,13 +104,13 @@ class Port(Element): for i in range(self.w): for j in range(self.h): vimage.put_pixel(j, self.w-i-1, image.get_pixel(i, j)) - def draw(self, window): + def draw(self, gc, window): """ Draw the socket with a label. + @param gc the graphics context @param window the gtk window to draw on """ - Element.draw(self, window, BG_color=self.BG_color) - gc = self.get_gc() + Element.draw(self, gc, window, BG_color=self.BG_color) gc.foreground = Colors.TXT_COLOR X,Y = self.get_coordinate() (x,y),(w,h) = self.areas_dict[self.get_rotation()][0] #use the first area's sizes to place the labels diff --git a/grc/src/platforms/gui/Utils.py b/grc/src/platforms/gui/Utils.py index 17750ef45..ee6dc6cdc 100644 --- a/grc/src/platforms/gui/Utils.py +++ b/grc/src/platforms/gui/Utils.py @@ -1,5 +1,5 @@ """ -Copyright 2008 Free Software Foundation, Inc. +Copyright 2008, 2009 Free Software Foundation, Inc. This file is part of GNU Radio GNU Radio Companion is free software; you can redistribute it and/or @@ -18,6 +18,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA """ from Constants import POSSIBLE_ROTATIONS +from Cheetah.Template import Template def get_rotated_coordinate(coor, rotation): """ @@ -69,3 +70,13 @@ def xml_encode(string): ("'", '''), ): string = string.replace(char, safe) return string + +def parse_template(tmpl_str, **kwargs): + """ + Parse the template string with the given args. + Pass in the xml encode method for pango escape chars. + @param tmpl_str the template as a string + @return a string of the parsed template + """ + kwargs['encode'] = xml_encode + return str(Template(tmpl_str, kwargs)) diff --git a/grc/src/platforms/python/Block.py b/grc/src/platforms/python/Block.py index 3c45117a3..38a0ce492 100644 --- a/grc/src/platforms/python/Block.py +++ b/grc/src/platforms/python/Block.py @@ -19,7 +19,6 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA from .. base.Block import Block as _Block from utils import extract_docs -from ... import utils class Block(_Block): @@ -36,11 +35,11 @@ class Block(_Block): @return block a new block """ #grab the data - doc = utils.exists_or_else(n, 'doc', '') - imports = map(lambda i: i.strip(), utils.listify(n, 'import')) - make = n['make'] - checks = utils.listify(n, 'check') - callbacks = utils.listify(n, 'callback') + doc = n.find('doc') or '' + imports = map(lambda i: i.strip(), n.findall('import')) + make = n.find('make') + checks = n.findall('check') + callbacks = n.findall('callback') #build the block _Block.__init__( self, diff --git a/grc/src/platforms/python/Constants.py.in b/grc/src/platforms/python/Constants.py.in index 199b24223..502f41550 100644 --- a/grc/src/platforms/python/Constants.py.in +++ b/grc/src/platforms/python/Constants.py.in @@ -50,3 +50,4 @@ FLOAT_VECTOR_COLOR_SPEC = '#CC8C69' INT_VECTOR_COLOR_SPEC = '#00CC99' SHORT_VECTOR_COLOR_SPEC = '#CCCC33' BYTE_VECTOR_COLOR_SPEC = '#CC66CC' +ID_COLOR_SPEC = '#DDDDDD' diff --git a/grc/src/platforms/python/FlowGraph.py b/grc/src/platforms/python/FlowGraph.py index cd5635b95..95c0b38cb 100644 --- a/grc/src/platforms/python/FlowGraph.py +++ b/grc/src/platforms/python/FlowGraph.py @@ -1,5 +1,5 @@ """ -Copyright 2008 Free Software Foundation, Inc. +Copyright 2008, 2009 Free Software Foundation, Inc. This file is part of GNU Radio GNU Radio Companion is free software; you can redistribute it and/or @@ -22,21 +22,15 @@ from .. base.FlowGraph import FlowGraph as _FlowGraph from Block import Block from Connection import Connection -def get_variable_code(variable): +def _get_value_expr(variable_block): """ - Get the code representation for a variable. - Normally this is the value parameter. - For the variable chooser, use the index and choices. - Avoid using the to_code method of the variables, - as this forces evaluation before the variables are evaluated. - @param variable the variable block - @return the code string + Get the expression to evaluate from the value param. + @param variable_block the variable or parameter block + @return the expression string """ - if variable.get_key() == 'variable_chooser': - choices = variable.get_param('choices').get_value() - value_index = variable.get_param('value_index').get_value() - return "(%s)[%s]"%(choices, value_index) - return variable.get_param('value').get_value() + value_param = variable_block.get_param('value') + value_param.evaluate() #evaluate prior to code + return value_param.to_code() class FlowGraph(_FlowGraph): @@ -117,7 +111,7 @@ class FlowGraph(_FlowGraph): id2var = dict([(var.get_id(), var) for var in variables]) #map var id to variable code #variable code is a concatenation of all param code (without the id param) - id2expr = dict([(var.get_id(), get_variable_code(var)) for var in variables]) + id2expr = dict([(var.get_id(), var.get_param('value').get_value()) for var in variables]) #sort according to dependency sorted_ids = expr_utils.sort_variables(id2expr) #create list of sorted variable blocks @@ -151,14 +145,14 @@ class FlowGraph(_FlowGraph): np = dict() for parameter in self.get_parameters(): try: - e = self._eval(parameter.get_param('value').to_code(), n) + e = self._eval(_get_value_expr(parameter), n) np[parameter.get_id()] = e except: pass n.update(np) #merge param namespace #load variables for variable in self.get_variables(): try: - e = self._eval(get_variable_code(variable), n) + e = self._eval(_get_value_expr(variable), n) n[variable.get_id()] = e except: pass #make namespace public diff --git a/grc/src/platforms/python/Generator.py b/grc/src/platforms/python/Generator.py index 83dd186c3..93321404a 100644 --- a/grc/src/platforms/python/Generator.py +++ b/grc/src/platforms/python/Generator.py @@ -53,7 +53,7 @@ class Generator(object): def write(self): #do throttle warning all_keys = ' '.join(map(lambda b: b.get_key(), self._flow_graph.get_enabled_blocks())) - if ('usrp' not in all_keys) and ('audio' not in all_keys) and ('throttle' not in all_keys): + if ('usrp' not in all_keys) and ('audio' not in all_keys) and ('throttle' not in all_keys) and self._generate_options != 'hb': Messages.send_warning('''\ This flow graph may not have flow control: no audio or usrp blocks found. \ Add a Misc->Throttle block to your flow graph to avoid CPU congestion.''') diff --git a/grc/src/platforms/python/Param.py b/grc/src/platforms/python/Param.py index efebe92e5..e75a882a4 100644 --- a/grc/src/platforms/python/Param.py +++ b/grc/src/platforms/python/Param.py @@ -1,5 +1,5 @@ """ -Copyright 2008 Free Software Foundation, Inc. +Copyright 2008, 2009 Free Software Foundation, Inc. This file is part of GNU Radio GNU Radio Companion is free software; you can redistribute it and/or @@ -94,7 +94,7 @@ class Param(_Param): Get the repr (nice string format) for this param. @return the string representation """ - if self.is_enum(): return _Param.__repr__(self) + if self.get_value() in self.get_option_keys(): return self.get_option(self.get_value()).get_name() ################################################## # display logic for numbers ################################################## @@ -158,7 +158,7 @@ class Param(_Param): #special 'hex': Constants.INT_COLOR_SPEC, 'string': Constants.BYTE_VECTOR_COLOR_SPEC, - 'id': '#DDDDDD', + 'id': Constants.ID_COLOR_SPEC, 'grid_pos': Constants.INT_VECTOR_COLOR_SPEC, }[self.get_type()] except: return _Param.get_color(self) diff --git a/grc/src/platforms/python/Port.py b/grc/src/platforms/python/Port.py index 109eecb62..b5bc9696b 100644 --- a/grc/src/platforms/python/Port.py +++ b/grc/src/platforms/python/Port.py @@ -1,5 +1,5 @@ """ -Copyright 2008 Free Software Foundation, Inc. +Copyright 2008, 2009 Free Software Foundation, Inc. This file is part of GNU Radio GNU Radio Companion is free software; you can redistribute it and/or @@ -18,7 +18,6 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA """ from .. base.Port import Port as _Port -from ... import utils import Constants class Port(_Port): @@ -33,9 +32,9 @@ class Port(_Port): @param n the nested odict @return a new port """ - vlen = utils.exists_or_else(n, 'vlen', '1') - nports = utils.exists_or_else(n, 'nports', '') - optional = utils.exists_or_else(n, 'optional', '') + vlen = n.find('vlen') or '1' + nports = n.find('nports') or '' + optional = n.find('optional') or '' #build the port _Port.__init__( self, diff --git a/grc/src/utils/Makefile.am b/grc/src/utils/Makefile.am index c00102f98..a48904796 100644 --- a/grc/src/utils/Makefile.am +++ b/grc/src/utils/Makefile.am @@ -1,5 +1,5 @@ # -# Copyright 2008 Free Software Foundation, Inc. +# Copyright 2008, 2009 Free Software Foundation, Inc. # # This file is part of GNU Radio # @@ -25,5 +25,6 @@ ourpythondir = $(grc_src_prefix)/utils ourpython_PYTHON = \ converter.py \ + odict.py \ ParseXML.py \ __init__.py diff --git a/grc/src/utils/__init__.py b/grc/src/utils/__init__.py index 73a2ed562..2682db812 100644 --- a/grc/src/utils/__init__.py +++ b/grc/src/utils/__init__.py @@ -1,5 +1,5 @@ """ -Copyright 2008 Free Software Foundation, Inc. +Copyright 2009 Free Software Foundation, Inc. This file is part of GNU Radio GNU Radio Companion is free software; you can redistribute it and/or @@ -17,66 +17,4 @@ along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA """ -from UserDict import DictMixin - -class odict(DictMixin): - - def __init__(self, d={}): - self._keys = list(d.keys()) - self._data = dict(d.copy()) - - def __setitem__(self, key, value): - if key not in self._data: - self._keys.append(key) - self._data[key] = value - - def __getitem__(self, key): - return self._data[key] - - def __delitem__(self, key): - del self._data[key] - self._keys.remove(key) - - def keys(self): - return list(self._keys) - - def copy(self): - copy_dict = odict() - copy_dict._data = self._data.copy() - copy_dict._keys = list(self._keys) - return copy_dict - - def insert_after(self, pos_key, key, val): - """ - Insert the new key, value entry after the entry given by the position key. - If the positional key is None, insert at the end. - @param pos_key the positional key - @param key the key for the new entry - @param val the value for the new entry - """ - index = (pos_key is None) and len(self._keys) or self._keys.index(pos_key) - assert key not in self._keys - self._keys.insert(index+1, key) - self._data[key] = val - - def insert_before(self, pos_key, key, val): - """ - Insert the new key, value entry before the entry given by the position key. - If the positional key is None, insert at the begining. - @param pos_key the positional key - @param key the key for the new entry - @param val the value for the new entry - """ - index = (pos_key is not None) and self._keys.index(pos_key) or 0 - assert key not in self._keys - self._keys.insert(index, key) - self._data[key] = val - -def exists_or_else(d, key, alt): - if d.has_key(key): return d[key] - else: return alt - -def listify(d, key): - obj = exists_or_else(d, key, []) - if isinstance(obj, list): return obj - return [obj] +from odict import odict diff --git a/grc/src/utils/odict.py b/grc/src/utils/odict.py new file mode 100644 index 000000000..ac3cb2070 --- /dev/null +++ b/grc/src/utils/odict.py @@ -0,0 +1,93 @@ +""" +Copyright 2008, 2009 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 +""" + +from UserDict import DictMixin + +class odict(DictMixin): + + def __init__(self, d={}): + self._keys = list(d.keys()) + self._data = dict(d.copy()) + + def __setitem__(self, key, value): + if key not in self._data: + self._keys.append(key) + self._data[key] = value + + def __getitem__(self, key): + return self._data[key] + + def __delitem__(self, key): + del self._data[key] + self._keys.remove(key) + + def keys(self): + return list(self._keys) + + def copy(self): + copy_dict = odict() + copy_dict._data = self._data.copy() + copy_dict._keys = list(self._keys) + return copy_dict + + def insert_after(self, pos_key, key, val): + """ + Insert the new key, value entry after the entry given by the position key. + If the positional key is None, insert at the end. + @param pos_key the positional key + @param key the key for the new entry + @param val the value for the new entry + """ + index = (pos_key is None) and len(self._keys) or self._keys.index(pos_key) + assert key not in self._keys + self._keys.insert(index+1, key) + self._data[key] = val + + def insert_before(self, pos_key, key, val): + """ + Insert the new key, value entry before the entry given by the position key. + If the positional key is None, insert at the begining. + @param pos_key the positional key + @param key the key for the new entry + @param val the value for the new entry + """ + index = (pos_key is not None) and self._keys.index(pos_key) or 0 + assert key not in self._keys + self._keys.insert(index, key) + self._data[key] = val + + def find(self, key): + """ + Get the value for this key if exists. + @param key the key to search for + @return the value or None + """ + if self.has_key(key): return self[key] + return None + + def findall(self, key): + """ + Get a list of values for this key. + @param key the key to search for + @return a list of values or empty list + """ + obj = self.find(key) + if obj is None: obj = list() + if isinstance(obj, list): return obj + return [obj] diff --git a/grc/todo.txt b/grc/todo.txt index 904128872..33cf58e65 100644 --- a/grc/todo.txt +++ b/grc/todo.txt @@ -14,8 +14,6 @@ -search for blocks -click and drag on whitespace to scroll -gui grid editor for configuring grid params/placing wxgui plots and controls --grid param chooser gui --histogram plot ################################################## # Problems |