[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Commit-gnuradio] r5486 - in grc/branches/gtk_separation/src: . Graphics
From: |
jblum |
Subject: |
[Commit-gnuradio] r5486 - in grc/branches/gtk_separation/src: . Graphics Graphics/Windows |
Date: |
Thu, 17 May 2007 07:52:29 -0600 (MDT) |
Author: jblum
Date: 2007-05-17 07:52:28 -0600 (Thu, 17 May 2007)
New Revision: 5486
Added:
grc/branches/gtk_separation/src/Graphics/ActionHandler.py
grc/branches/gtk_separation/src/Graphics/Actions.py
grc/branches/gtk_separation/src/Graphics/Colors.py
grc/branches/gtk_separation/src/Graphics/Elements/
grc/branches/gtk_separation/src/Graphics/Messages.py
grc/branches/gtk_separation/src/Graphics/Preferences.py
grc/branches/gtk_separation/src/Graphics/StateCache.py
grc/branches/gtk_separation/src/Graphics/Windows/
grc/branches/gtk_separation/src/Graphics/Windows/Bars.py
grc/branches/gtk_separation/src/Graphics/Windows/Dialogs.py
grc/branches/gtk_separation/src/Graphics/Windows/FlowGraph.py
grc/branches/gtk_separation/src/Graphics/Windows/FlowGraphFileDialog.py
grc/branches/gtk_separation/src/Graphics/Windows/MainWindow.py
grc/branches/gtk_separation/src/Graphics/Windows/SignalBlockParamsDialog.py
grc/branches/gtk_separation/src/Graphics/Windows/SignalBlockSelectionWindow.py
grc/branches/gtk_separation/src/Graphics/Windows/USRPDiagnostics.py
grc/branches/gtk_separation/src/Graphics/Windows/VariableModificationWindow.py
grc/branches/gtk_separation/src/Graphics/Windows/__init__.py
Removed:
grc/branches/gtk_separation/src/ActionHandler.py
grc/branches/gtk_separation/src/Actions.py
grc/branches/gtk_separation/src/Colors.py
grc/branches/gtk_separation/src/Graphics/Bars.py
grc/branches/gtk_separation/src/Graphics/Dialogs.py
grc/branches/gtk_separation/src/Graphics/FlowGraph.py
grc/branches/gtk_separation/src/Graphics/FlowGraphFileDialog.py
grc/branches/gtk_separation/src/Graphics/MainWindow.py
grc/branches/gtk_separation/src/Graphics/SignalBlockParamsDialog.py
grc/branches/gtk_separation/src/Graphics/SignalBlockSelectionWindow.py
grc/branches/gtk_separation/src/Graphics/USRPDiagnostics.py
grc/branches/gtk_separation/src/Graphics/VariableModificationWindow.py
grc/branches/gtk_separation/src/Graphics/__init__.py
grc/branches/gtk_separation/src/Messages.py
grc/branches/gtk_separation/src/Preferences.py
grc/branches/gtk_separation/src/StateCache.py
Log:
reorganized python source into graphical and non graphical folders
Deleted: grc/branches/gtk_separation/src/ActionHandler.py
Deleted: grc/branches/gtk_separation/src/Actions.py
Deleted: grc/branches/gtk_separation/src/Colors.py
Copied: grc/branches/gtk_separation/src/Graphics/ActionHandler.py (from rev
5485, grc/branches/gtk_separation/src/ActionHandler.py)
===================================================================
--- grc/branches/gtk_separation/src/Graphics/ActionHandler.py
(rev 0)
+++ grc/branches/gtk_separation/src/Graphics/ActionHandler.py 2007-05-17
13:52:28 UTC (rev 5486)
@@ -0,0 +1,375 @@
+"""
+GNU Radio Companion is a graphical interface into the GNU Radio project.
+Copyright (C) 2007 Josh Blum
+
+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
+"""
+"""
+ ActionHandler.py
+ Josh Blum
+ ActionHandler puts the entire application together by setting up all
the windows
+ including the flow graph and ActionHandler handles most of the
user inputs.
+"""
+import os, sys
+from Constants import *
+from Actions import *
+import pygtk
+pygtk.require('2.0')
+import gtk
+import Graphics
+from StateCache import StateCache
+import ParseXML
+import Preferences
+from threading import Thread
+import Messages
+
+class ActionHandler:
+ """ The action handler will create all the major window components
and handle state changes.
+ The action handler also contains methods to handle the action buttons
and state changes. """
+ def __init__(self, input_arg_file_path=''):
+ """ Parse the config files for signals blocks and gtk actions.
Connect the actions to the handler method.
+ Create a new Flow Graph and main_window as well as a few misc
dialog boxes. Enter the gtk main loop. """
+ if PY_GTK_ICON:
gtk.window_set_default_icon_from_file(PY_GTK_ICON)
+ for action in ACTIONS_LIST: action.connect('activate',
self.handle_actions)
+ self.pid_file = None
+ ### create the main window and setup the Messages ###
+ self.main_window = Graphics.MainWindow(self.handle_states)
+ Messages.register_messenger(self.main_window.add_report_line)
+ Messages.register_messenger(sys.stdout.write)
+ Messages.send_init()
+ self.flow_graph = self.main_window.flow_graph
+ self.main_window.connect('delete_event', self.quit)
+ self.main_window.connect('key_press_event',
self.handle_key_press)
+ Preferences.load(self.main_window)
+ self.main_window.show()#show after resize in preferences
+ # determine the initial flow graph file, preference to
command line input #
+ if input_arg_file_path: self.flow_graph_file_path =
os.path.abspath(input_arg_file_path)
+ else: self.flow_graph_file_path =
Preferences.get_default_flow_graph()
+ self.handle_states(APPLICATION_INITIALIZE)
+ # enter the mainloop
+ gtk.gdk.threads_init()
+ gtk.gdk.threads_enter()
+ gtk.main()
+ gtk.gdk.threads_leave()
+
+ def handle_key_press(self, widget, event):
+ """ Handle key press events and translate key combos into
actions.
+ Key combinations that do not include special keys, such
as ctrl or Fcn*,
+ require that the flow graph has mouse focus."""
+ keyname = gtk.gdk.keyval_name(event.keyval)
+ #print 'Key "%s" (%d) was pressed' % (keyname, event.keyval)
+ if event.state & gtk.gdk.CONTROL_MASK: print "Control was being
held down"
+ if event.state & gtk.gdk.MOD1_MASK: print "Alt was being held
down"
+ if event.state & gtk.gdk.SHIFT_MASK: print "Shift was being
held down"
+ #################### save/open/new/undo/redo
###############################
+ if event.state & gtk.gdk.CONTROL_MASK and keyname == 's':
+ self.handle_states(FLOW_GRAPH_SAVE)
+ elif event.state & gtk.gdk.CONTROL_MASK and keyname == 'z':
+ self.handle_states(FLOW_GRAPH_UNDO)
+ elif event.state & gtk.gdk.CONTROL_MASK and (keyname in ('y',
'Z')):
+ self.handle_states(FLOW_GRAPH_REDO)
+ elif event.state & gtk.gdk.CONTROL_MASK and keyname == 'o':
+ self.handle_states(FLOW_GRAPH_OPEN)
+ elif event.state & gtk.gdk.CONTROL_MASK and keyname == 'n':
+ self.handle_states(FLOW_GRAPH_NEW)
+ #################### Delete ###############################
+ elif self.flow_graph.get_focus_flag() and keyname == 'Delete':
#mouse focus
+ self.handle_states(ELEMENT_DELETE)
+ #################### Rotate ###############################
+ elif self.flow_graph.get_focus_flag() and keyname == 'Right':
#mouse focus
+ self.handle_states(SIGNAL_BLOCK_ROTATE_RIGHT)
+ elif self.flow_graph.get_focus_flag() and keyname == 'Left':
#mouse focus
+ self.handle_states(SIGNAL_BLOCK_ROTATE_LEFT)
+ #################### Data Type
###############################
+ elif self.flow_graph.get_focus_flag() and keyname == 'Down':
#mouse focus
+ self.handle_states(SIGNAL_BLOCK_INC_TYPE)
+ elif self.flow_graph.get_focus_flag() and keyname == 'Up':
#mouse focus
+ self.handle_states(SIGNAL_BLOCK_DEC_TYPE)
+ #################### Socket Controllers
###############################
+ elif self.flow_graph.get_focus_flag() and keyname in
('equal','plus', 'KP_Add'): #mouse focus
+ self.handle_states(SOCKET_CONTROLLER_INC)
+ elif self.flow_graph.get_focus_flag() and keyname in ('minus',
'KP_Subtract'): #mouse focus
+ self.handle_states(SOCKET_CONTROLLER_DEC)
+ #################### Run/Stop/Print
###############################
+ elif keyname == 'F5':
+ self.handle_states(FLOW_GRAPH_RUN)
+ elif keyname == 'F7':
+ self.handle_states(FLOW_GRAPH_STOP)
+ elif keyname == 'Print':
+ self.handle_states(FLOW_GRAPH_SNAP_SHOT)
+ #propagate this if the fg is not in focus or nothing is selected
+ return self.flow_graph.get_focus_flag() and
self.flow_graph.is_selected()
+
+ def quit(self, window, event):
+ """ Handle the delete event from the main window, like
pressing X to close, alt+f4, or right click+close.
+ This method in turns calls the state handler with a 'quit'
string so all quitting can be handled in one place. """
+ self.handle_states(APPLICATION_QUIT)
+ return True
+
+ def handle_actions(self, event):
+ """ Handle all of the activate signals from the gtk actions.
The action signals derive from clicking on a
+ toolbar or menu bar button. The name of the action is
passed through the event and a series of
+ if/elif statements handle the action appropriately.
"""
+ name = event.get_name()
+ self.handle_states(name)
+
+ def handle_states(self, state):
+ """ Handle all of the state changes that arise from the action
handler or other Graphics and
+ inputs in the application. The state passed to the
handle_states method is a string descriping
+ the change. A series of if/elif statements handle the
state by greying out action buttons, causing
+ changes in the flow graph, saving/opening files...
The handle_states method is passed to the
+ contructors of many of the classes used in this
application enabling them to report any state change. """
+ print '>>>',state
+
##############################################################################################
+ # Initalize/Quit
+
##############################################################################################
+ if state == APPLICATION_INITIALIZE:
+ for action in ACTIONS_LIST: action.set_sensitive(False)
#set all actions disabled
+ # enable a select few actions
+ Graphics.enable_usrp_diagnostics() #try to enable
usrp diagnostics
+ for action in (APPLICATION_QUIT, FLOW_GRAPH_NEW,
FLOW_GRAPH_OPEN, FLOW_GRAPH_SAVE_AS,
+
ABOUT_WINDOW_DISPLAY, COLORS_WINDOW_DISPLAY, HOTKEYS_WINDOW_DISPLAY,
+
FLOW_GRAPH_WINDOW_RESIZE, PREFS_WINDOW_DISPLAY, FLOW_GRAPH_SNAP_SHOT):
+ get_action_from_name(action).set_sensitive(True)
+ if self.flow_graph_file_path == '':
+ initial_state =
ParseXML.from_xml(ParseXML.from_file(INITIAL_FLOW_GRAPH_FILE))
+ self.flow_graph.from_nested_data(initial_state)
+ self.state_cache = StateCache(initial_state)
+ else: #otherwise try to use the file path
+ try:
+ self.handle_states(NOTHING_SELECT)
+
Messages.send_start_load(self.flow_graph_file_path)
+ initial_state =
ParseXML.from_xml(ParseXML.from_file(self.flow_graph_file_path))
+ errors =
self.flow_graph.from_nested_data(initial_state)
+ Messages.send_end_load(errors)
+ self.state_cache =
StateCache(initial_state)
+ except Exception, e: #if the data is bad,
display error and call INIT with None for the file path
+ Messages.send_fail_load(e)
+ self.flow_graph_file_path = ''
+
self.handle_states(APPLICATION_INITIALIZE)
+ self.set_saved_state(True)
+ elif state == APPLICATION_QUIT:
+ if self.loose_changes():
+ self.handle_states(FLOW_GRAPH_STOP)
+
Preferences.set_default_flow_graph(self.flow_graph_file_path)
+ Preferences.save(self.main_window)
+ gtk.main_quit()
+
##############################################################################################
+ # Selections
+
##############################################################################################
+ elif state == SIGNAL_BLOCK_SELECT or state == SOCKET_SELECT:
+ for action in (ELEMENT_DELETE,
SIGNAL_BLOCK_PARAM_MODIFY, SIGNAL_BLOCK_ROTATE_RIGHT,
SIGNAL_BLOCK_ROTATE_LEFT):
+ get_action_from_name(action).set_sensitive(True)
+ elif state == CONNECTION_SELECT:
+ get_action_from_name(ELEMENT_DELETE).set_sensitive(True)
+ for action in (SIGNAL_BLOCK_PARAM_MODIFY,
SIGNAL_BLOCK_ROTATE_RIGHT, SIGNAL_BLOCK_ROTATE_LEFT):
+
get_action_from_name(action).set_sensitive(False)
+ elif state == NOTHING_SELECT:
+ for action in (ELEMENT_DELETE,
SIGNAL_BLOCK_PARAM_MODIFY, SIGNAL_BLOCK_ROTATE_RIGHT,
SIGNAL_BLOCK_ROTATE_LEFT):
+
get_action_from_name(action).set_sensitive(False)
+ self.flow_graph.unselect()
+
##############################################################################################
+ # Move/Rotate/Delete/Create
+
##############################################################################################
+ elif state == SIGNAL_BLOCK_MOVE:
+
self.state_cache.save_new_state(self.flow_graph.to_nested_data())
+ self.set_saved_state(False)
+ elif state == SIGNAL_BLOCK_ROTATE_LEFT:
+ if self.flow_graph.rotate_selected(gtk.DIR_LEFT):
+
self.state_cache.save_new_state(self.flow_graph.to_nested_data())
+ self.set_saved_state(False)
+ elif state == SIGNAL_BLOCK_ROTATE_RIGHT:
+ if self.flow_graph.rotate_selected(gtk.DIR_RIGHT):
+
self.state_cache.save_new_state(self.flow_graph.to_nested_data())
+ self.set_saved_state(False)
+ elif state == ELEMENT_DELETE:
+ if self.flow_graph.delete_selected():
+
self.state_cache.save_new_state(self.flow_graph.to_nested_data())
+ self.handle_states(NOTHING_SELECT)
+ self.set_saved_state(False)
+ elif state == CONNECTION_CREATE or state ==
SIGNAL_BLOCK_CREATE:
+
self.state_cache.save_new_state(self.flow_graph.to_nested_data())
+ self.handle_states(NOTHING_SELECT)
+ self.set_saved_state(False)
+ elif state == SIGNAL_BLOCK_INC_TYPE:
+ if self.flow_graph.type_controller_modify_selected(1):
+
self.state_cache.save_new_state(self.flow_graph.to_nested_data())
+ self.set_saved_state(False)
+ elif state == SIGNAL_BLOCK_DEC_TYPE:
+ if self.flow_graph.type_controller_modify_selected(-1):
+
self.state_cache.save_new_state(self.flow_graph.to_nested_data())
+ self.set_saved_state(False)
+ elif state == SOCKET_CONTROLLER_INC:
+ if self.flow_graph.socket_controller_modify_selected(1):
+
self.state_cache.save_new_state(self.flow_graph.to_nested_data())
+ self.set_saved_state(False)
+ elif state == SOCKET_CONTROLLER_DEC:
+ if
self.flow_graph.socket_controller_modify_selected(-1):
+
self.state_cache.save_new_state(self.flow_graph.to_nested_data())
+ self.set_saved_state(False)
+
##############################################################################################
+ # Window stuff
+
##############################################################################################
+ elif state == USRP_DIAGNOSTICS_DISPLAY:
+ Graphics.USRPDiagnosticsDialog()
+ elif state == PREFS_WINDOW_DISPLAY:
+ Graphics.PreferencesDialog()
+ self.flow_graph.update()
+ elif state == ABOUT_WINDOW_DISPLAY:
+ Graphics.AboutDialog()
+ elif state == COLORS_WINDOW_DISPLAY:
+ Graphics.DataTypeColorsDialog()
+ elif state == HOTKEYS_WINDOW_DISPLAY:
+ Graphics.HotKeysDialog()
+ elif state == FLOW_GRAPH_WINDOW_RESIZE:
+ dimensions =
Graphics.FlowGraphWindowSizeDialog(self.flow_graph).run()
+ if dimensions != None:
+ self.flow_graph.set_size_request(dimensions[0],
dimensions[1])
+
self.state_cache.save_new_state(self.flow_graph.to_nested_data())
+ self.set_saved_state(False)
+
##############################################################################################
+ # Variable and Param Modifications
+
##############################################################################################
+ elif state == SIGNAL_BLOCK_PARAM_MODIFY:
+ if self.flow_graph.param_modify_selected():
+
self.state_cache.save_new_state(self.flow_graph.to_nested_data())
+ self.set_saved_state(False)
+ elif state == VARIABLE_MODIFY:
+
self.state_cache.save_new_state(self.flow_graph.to_nested_data())
+ self.set_saved_state(False)
+ self.flow_graph.update()
+
##############################################################################################
+ # Undo/Redo
+
##############################################################################################
+ elif state == FLOW_GRAPH_UNDO:
+ nested_data = self.state_cache.get_prev_state()
+ if nested_data != None:
+ self.handle_states(NOTHING_SELECT)
+ self.flow_graph.from_nested_data(nested_data)
+ self.set_saved_state(False)
+ elif state == FLOW_GRAPH_REDO:
+ nested_data = self.state_cache.get_next_state()
+ if nested_data != None:
+ self.handle_states(NOTHING_SELECT)
+ self.flow_graph.from_nested_data(nested_data)
+ self.set_saved_state(False)
+
##############################################################################################
+ # New/Open/Save
+
##############################################################################################
+ elif state == FLOW_GRAPH_NEW:
+ if self.loose_changes():
+ self.flow_graph_file_path = ''
+ self.handle_states(APPLICATION_INITIALIZE)
+ elif state == FLOW_GRAPH_OPEN:
+ if self.loose_changes():
+ fc = Graphics.FlowGraphFileDialog('open',
self.flow_graph_file_path)
+ file_path = fc.run()
+ if file_path != None:
+ self.flow_graph_file_path = file_path
+
self.handle_states(APPLICATION_INITIALIZE)
+ elif state == FLOW_GRAPH_SAVE:
+ if self.flow_graph_file_path == '':
self.handle_states(FLOW_GRAPH_SAVE_AS)
+ else:
+ try:
+
ParseXML.to_file(ParseXML.to_xml(self.flow_graph.to_nested_data()),
self.flow_graph_file_path)
+ self.set_saved_state(True)
+ except IOError:
+
Messages.send_fail_save(self.flow_graph_file_path)
+ self.set_saved_state(False)
+ elif state == FLOW_GRAPH_SAVE_AS:
+ fc = Graphics.FlowGraphFileDialog('save',
self.flow_graph_file_path)
+ file_path = fc.run()
+ if file_path != None:
+ self.flow_graph_file_path = file_path
+ self.handle_states(FLOW_GRAPH_SAVE)
+ elif state == FLOW_GRAPH_SNAP_SHOT:
+ fc = Graphics.FlowGraphFileDialog('save image',
self.flow_graph_file_path)
+ file_path = fc.run()
+ if file_path != None:
+ pixmap = self.flow_graph.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)
+ pixbuf.save(file_path,
IMAGE_FILE_EXTENSION[1:])
+
##############################################################################################
+ # Run/Stop
+
##############################################################################################
+ elif state == FLOW_GRAPH_RUN:
+ if self.pid_file == None:
+ self.handle_states(FLOW_GRAPH_SAVE)
+ if self.flow_graph_file_path != '': RUN(self)
+ elif state == FLOW_GRAPH_STOP:
+ while not MUTEX.testandset(): pass #try to lock
repeatedly until lock is aquired
+ if self.pid_file!= None:
+ try: os.kill(int(open(self.pid_file,
'r').read()), 9)
+ except: print "could not kill pid file:
%s"%self.pid_file
+ MUTEX.unlock()
+ else: print "!!! State not handled !!!"
+ # set the running button if the flow graph is valid and is not
already running #
+ while not MUTEX.testandset(): pass #try to lock repeatedly
until lock is aquired
+
get_action_from_name(FLOW_GRAPH_RUN).set_sensitive(self.flow_graph.is_valid()
and self.pid_file == None)
+ MUTEX.unlock()
+ # hide/show the reports window based on the preferences #
+
self.main_window.show_reports_window(Preferences.show_reports_window())
+
+ def set_saved_state(self, saved):
+ ''' If saved is True, disable the save button and modify the
title.
+ If saved is False, enable the save button and modify the title
with a *. '''
+ if saved:
+
get_action_from_name(FLOW_GRAPH_SAVE).set_sensitive(False)
+ if self.flow_graph_file_path == '':
+ self.main_window.set_title(NEW_FLOGRAPH_TITLE)
+ else:
self.main_window.set_title(self.flow_graph_file_path)
+ else:
+
get_action_from_name(FLOW_GRAPH_SAVE).set_sensitive(True)
+ if self.flow_graph_file_path == '':
+ self.main_window.set_title(NEW_FLOGRAPH_TITLE +
'*')
+ else:
self.main_window.set_title(self.flow_graph_file_path + '*')
+
+ def loose_changes(self):
+ ''' True if the save is disabled or the user says to discard
changes. '''
+ return not
get_action_from_name(FLOW_GRAPH_SAVE).get_sensitive() or\
+ (Graphics.LooseChangesMessage().run())
+
+class RUN(Thread):
+ ''' Run the flow graph as a new process and wait on it to finish
'''
+ def __init__ (self, action_handler):
+ Thread.__init__(self)
+ self.action_handler = action_handler
+ self.pid_file = self.action_handler.pid_file =
'/tmp/grc-%d.pid'%os.getpid()
+ self.report_file = '/tmp/grc-%d.report'%os.getpid()
+ self.flow_graph_file_path =
self.action_handler.flow_graph_file_path
+ get_action_from_name(FLOW_GRAPH_RUN).set_sensitive(False)
+ get_action_from_name(FLOW_GRAPH_STOP).set_sensitive(True)
+ Messages.send_start_run(self.flow_graph_file_path)
+ self.start()
+
+ def run(self):
+ cmd = '%s "%s" --pid_file="%s" 2>
"%s"'%(DEFAULT_FLOW_GRAPH_EXEC, self.flow_graph_file_path, self.pid_file,
self.report_file)
+ os.system(cmd)
+ try:
+ report = open(self.report_file, 'r')
+ # read all the lines of the report file into a
list #
+ Messages.send_end_run(report.readlines())
+ report.close()
+ os.remove(self.report_file)
+ except IOError: print "could not read report file:
%s"%self.report_file
+ try: os.remove(self.pid_file)
+ except: print "could not remove pid file: %s"%self.pid_file
+ while not MUTEX.testandset(): pass #try to lock repeatedly
until lock is aquired
+ self.action_handler.pid_file = None
+ get_action_from_name(FLOW_GRAPH_STOP).set_sensitive(False)
+ get_action_from_name(FLOW_GRAPH_RUN).set_sensitive(True)
+ MUTEX.unlock()
Copied: grc/branches/gtk_separation/src/Graphics/Actions.py (from rev 5485,
grc/branches/gtk_separation/src/Actions.py)
===================================================================
--- grc/branches/gtk_separation/src/Graphics/Actions.py
(rev 0)
+++ grc/branches/gtk_separation/src/Graphics/Actions.py 2007-05-17 13:52:28 UTC
(rev 5486)
@@ -0,0 +1,110 @@
+"""
+GNU Radio Companion is a graphical interface into the GNU Radio project.
+Copyright (C) 2007 Josh Blum
+
+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
+"""
+"""
+ Actions.py
+ Josh Blum
+ Global actions for gui elements to communicate state changes to the
action handler.
+"""
+
+import pygtk
+pygtk.require('2.0')
+import gtk
+
+######################################################################################################
+# states
+######################################################################################################
+
+APPLICATION_INITIALIZE = 'app init'
+APPLICATION_QUIT = 'app quit'
+
+SOCKET_SELECT = 'socket select'
+
+NOTHING_SELECT = 'nothing select'
+
+PARAM_MODIFY = 'param modify'
+
+SIGNAL_BLOCK_SELECT = 'signal block select'
+SIGNAL_BLOCK_MOVE = 'signal block move'
+SIGNAL_BLOCK_ROTATE_LEFT = 'signal block rotate left'
+SIGNAL_BLOCK_ROTATE_RIGHT = 'signal block rotate right'
+SIGNAL_BLOCK_CREATE = 'signal block create'
+SIGNAL_BLOCK_PARAM_MODIFY = 'signal block param modify'
+SIGNAL_BLOCK_INC_TYPE = 'signal block increment type'
+SIGNAL_BLOCK_DEC_TYPE = 'signal block decrement type'
+
+SOCKET_CONTROLLER_INC = 'socket controller increment'
+SOCKET_CONTROLLER_DEC = 'socket controller decrement'
+
+CONNECTION_SELECT = 'connection select'
+CONNECTION_CREATE = 'conection create'
+ELEMENT_DELETE = 'element delete'
+
+VARIABLE_MODIFY = 'variable modify'
+
+FLOW_GRAPH_OPEN = 'flow graph open'
+FLOW_GRAPH_UNDO = 'flow graph undo'
+FLOW_GRAPH_REDO = 'flow graph redo'
+FLOW_GRAPH_SAVE = 'flow graph save'
+FLOW_GRAPH_SAVE_AS = 'flow graph save as'
+FLOW_GRAPH_NEW = 'flow graph new'
+FLOW_GRAPH_WINDOW_RESIZE = 'flow graph window resize'
+FLOW_GRAPH_RUN = 'flow graph run'
+FLOW_GRAPH_STOP = 'flow graph stop'
+FLOW_GRAPH_SNAP_SHOT = 'flow graph snap shot'
+
+ABOUT_WINDOW_DISPLAY = 'about window display'
+COLORS_WINDOW_DISPLAY = 'colors window display'
+HOTKEYS_WINDOW_DISPLAY = 'hotkeys window display'
+USRP_DIAGNOSTICS_DISPLAY = 'usrp diagnostics display'
+PREFS_WINDOW_DISPLAY = 'prefs window display'
+
+######################################################################################################
+# actions
+######################################################################################################
+
+ACTIONS_LIST = [
+ gtk.Action(FLOW_GRAPH_NEW, '_New', 'Create a new flow graph',
'gtk-new'),
+ gtk.Action(FLOW_GRAPH_OPEN, '_Open', 'Open a flow graph from file',
'gtk-open'),
+ gtk.Action(FLOW_GRAPH_SAVE, '_Save', 'Save this flow graph',
'gtk-save'),
+ gtk.Action(FLOW_GRAPH_SAVE_AS, 'Save _As', 'Save the open flow graph
as...', 'gtk-save-as'),
+ 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 signal
block', 'gtk-delete'),
+ gtk.Action(SIGNAL_BLOCK_ROTATE_LEFT, 'Rotate _Left', 'Rotate the signal
block 90 degrees', 'gtk-go-back'),
+ gtk.Action(SIGNAL_BLOCK_ROTATE_RIGHT, 'Rotate _Right', 'Rotate the
signal block -90 degrees', 'gtk-go-forward'),
+ gtk.Action(SIGNAL_BLOCK_PARAM_MODIFY, '_Properties', 'Modify params for
the selected signal block', 'gtk-properties'),
+ gtk.Action(FLOW_GRAPH_WINDOW_RESIZE, '_Window Size', 'Set the window
size', 'gtk-edit'),
+ gtk.Action(USRP_DIAGNOSTICS_DISPLAY, '_USRP Diagnostics', 'Analyze the
USRP', 'gtk-dialog-info'),
+ gtk.Action(PREFS_WINDOW_DISPLAY, '_Preferences', 'Configure
Preferences', 'gtk-preferences'),
+ gtk.Action(ABOUT_WINDOW_DISPLAY, '_About', 'About this program',
'gtk-about'),
+ gtk.Action(COLORS_WINDOW_DISPLAY, '_Colors', 'Data Type Colors',
'gtk-select-color'),
+ gtk.Action(HOTKEYS_WINDOW_DISPLAY, '_HotKeys', 'Hot Keys', 'gtk-info'),
+ gtk.Action(FLOW_GRAPH_RUN, '_Run', 'Run the flow graph', 'gtk-execute'),
+ gtk.Action(FLOW_GRAPH_STOP, '_Stop', 'Stop the flow graph', 'gtk-stop'),
+ gtk.Action(FLOW_GRAPH_SNAP_SHOT, 'S_nap Shot', 'Take a snap shot image
of the flow graph', 'gtk-print'),
+]
+
+def get_action_from_name(action_name):
+ """ Retrieve the action from the above list given its name. """
+ for action in ACTIONS_LIST:
+ if action.get_name() == action_name: return action
+ return None
+
+
\ No newline at end of file
Deleted: grc/branches/gtk_separation/src/Graphics/Bars.py
Copied: grc/branches/gtk_separation/src/Graphics/Colors.py (from rev 5485,
grc/branches/gtk_separation/src/Colors.py)
===================================================================
--- grc/branches/gtk_separation/src/Graphics/Colors.py
(rev 0)
+++ grc/branches/gtk_separation/src/Graphics/Colors.py 2007-05-17 13:52:28 UTC
(rev 5486)
@@ -0,0 +1,63 @@
+"""
+GNU Radio Companion is a graphical interface into the GNU Radio project.
+Copyright (C) 2007 Josh Blum
+
+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
+"""
+"""
+ Colors.py
+ Josh Blum
+ Colors and color-specs used to identify a socket's data type.
+"""
+
+import pygtk
+pygtk.require('2.0')
+import gtk
+
+######################################################################################################
+# color codes for signal blocks
+######################################################################################################
+
+COMPLEX_COLOR_SPEC = '#3399FF'
+FLOAT_COLOR_SPEC = '#FF8C69'
+INT_COLOR_SPEC = '#00FF99'
+SHORT_COLOR_SPEC = '#FFFF66'
+BYTE_COLOR_SPEC = '#FF66FF'
+# and for vectors #
+COMPLEX_VECTOR_COLOR_SPEC = '#3399AA'
+FLOAT_VECTOR_COLOR_SPEC = '#CC8C69'
+INT_VECTOR_COLOR_SPEC = '#00CC99'
+SHORT_VECTOR_COLOR_SPEC = '#CCCC33'
+BYTE_VECTOR_COLOR_SPEC = '#CC66CC'
+
+COLORMAP = gtk.gdk.colormap_get_system() #create all of the colors
+BACKGROUND_COLOR = COLORMAP.alloc_color('#FFF9FF', True, True) #main window
background
+FG_COLOR = COLORMAP.alloc_color('black', True, True) #normal border color
+BG_COLOR = COLORMAP.alloc_color('#F1ECFF', True, True) #default background
+H_COLOR = COLORMAP.alloc_color('#00FFFF', True, True) #Highlight border color
+TXT_COLOR = COLORMAP.alloc_color('black', True, True) #text color
+ERROR_COLOR = COLORMAP.alloc_color('red', True, True) #error color
+FLOAT_COLOR = COLORMAP.alloc_color(FLOAT_COLOR_SPEC, True, True)
#background for floats (redish)
+COMPLEX_COLOR = COLORMAP.alloc_color(COMPLEX_COLOR_SPEC, True, True)
#background for complex (blueish)
+SHORT_COLOR = COLORMAP.alloc_color(SHORT_COLOR_SPEC, True, True)
#background for shorts (yellowish)
+INT_COLOR = COLORMAP.alloc_color(INT_COLOR_SPEC, True, True) #background for
ints (greenish)
+BYTE_COLOR = COLORMAP.alloc_color(BYTE_COLOR_SPEC, True, True) #background for
bytes (purplish)
+# and for vectors #
+FLOAT_VECTOR_COLOR = COLORMAP.alloc_color(FLOAT_VECTOR_COLOR_SPEC, True, True)
#background for floats (redish)
+COMPLEX_VECTOR_COLOR = COLORMAP.alloc_color(COMPLEX_VECTOR_COLOR_SPEC, True,
True) #background for complex (blueish)
+SHORT_VECTOR_COLOR = COLORMAP.alloc_color(SHORT_VECTOR_COLOR_SPEC, True, True)
#background for shorts (yellowish)
+INT_VECTOR_COLOR = COLORMAP.alloc_color(INT_VECTOR_COLOR_SPEC, True, True)
#background for ints (greenish)
+BYTE_VECTOR_COLOR = COLORMAP.alloc_color(BYTE_VECTOR_COLOR_SPEC, True, True)
#background for bytes (purplish)
+
Deleted: grc/branches/gtk_separation/src/Graphics/Dialogs.py
Copied: grc/branches/gtk_separation/src/Graphics/Elements (from rev 5485,
grc/branches/gtk_separation/src/Elements)
Deleted: grc/branches/gtk_separation/src/Graphics/FlowGraph.py
Deleted: grc/branches/gtk_separation/src/Graphics/FlowGraphFileDialog.py
Deleted: grc/branches/gtk_separation/src/Graphics/MainWindow.py
Copied: grc/branches/gtk_separation/src/Graphics/Messages.py (from rev 5485,
grc/branches/gtk_separation/src/Messages.py)
===================================================================
--- grc/branches/gtk_separation/src/Graphics/Messages.py
(rev 0)
+++ grc/branches/gtk_separation/src/Graphics/Messages.py 2007-05-17
13:52:28 UTC (rev 5486)
@@ -0,0 +1,86 @@
+"""
+GNU Radio Companion is a graphical interface into the GNU Radio project.
+Copyright (C) 2007 Josh Blum
+
+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
+"""
+"""
+ Messages.py
+ Josh Blum
+ Handle all of the system messages and error reports.
+"""
+
+from Constants import VERSION,PREFERENCES_FILE_PATH
+
+# A list of methods that can receive a message. #
+MESSENGERS_LIST = list()
+
+def register_messenger(messenger):
+ """ Append the given messenger to the list of messengers. """
+ MESSENGERS_LIST.append(messenger)
+
+def send(message):
+ """ Give the given message to each of the messengers. """
+ for messenger in MESSENGERS_LIST: messenger(message)
+
+###########################################################################
+# Special methods for specific program functionalities
+###########################################################################
+def send_init():
+ send("""\
+ --------------------------- Welcome
to GRC %s ---------------------------\n"""%VERSION)
+
+################# methods for loading flow graphs
########################################
+def send_start_load(file_path):
+ send("""\
+ ------------------
Loading Flow Graph ------------------\n""")
+ send('Trying to load: "%s"'%file_path + '\n')
+
+def send_end_load(errors):
+ if errors: send('>>> Errors:\n%s'%errors)
+ send(">>> Done\n")
+
+def send_fail_load(error):
+ send('Parser Error: %s\n'%error)
+ send(">>> Failue\n")
+
+################# methods for running flow graphs
########################################
+def send_start_run(file_path):
+ send("""\
+ ------------------
Running Flow Graph ------------------\n""")
+ send('Trying to run: "%s"'%file_path + '\n')
+
+def send_end_run(verbose):
+ if verbose:
+ send(">>> Verbose: \n")
+ for verb in verbose: send(verb)
+ send("\n")
+ send(">>> Done\n")
+
+################# methods for saving flow graphs
########################################
+def send_fail_save(file_path):
+ send('>>> Error: Cannot save: %s\n'%file_path)
+
+################# methods for connections
########################################
+def send_fail_connection():
+ send('>>> Warning: A connection can only be created between an output
socket and an unconnected input socket.\n')
+
+################# methods for preferences
########################################
+def send_fail_load_preferences():
+ send('>>> Error: Cannot load preferences file:
"%s"\n'%PREFERENCES_FILE_PATH)
+
+def send_fail_save_preferences():
+ send('>>> Error: Cannot save preferences file:
"%s"\n'%PREFERENCES_FILE_PATH)
+
Copied: grc/branches/gtk_separation/src/Graphics/Preferences.py (from rev 5485,
grc/branches/gtk_separation/src/Preferences.py)
===================================================================
--- grc/branches/gtk_separation/src/Graphics/Preferences.py
(rev 0)
+++ grc/branches/gtk_separation/src/Graphics/Preferences.py 2007-05-17
13:52:28 UTC (rev 5486)
@@ -0,0 +1,177 @@
+"""
+GNU Radio Companion is a graphical interface into the GNU Radio project.
+Copyright (C) 2007 Josh Blum
+
+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
+"""
+"""
+ Preferences.py
+ Josh Blum
+ Holds global preferences stored as Params.
+"""
+
+from DataType import Bool,FileOpen,Enum,Int
+from Elements import Param
+import time,socket #for tagging saved files
+from Constants import *
+import ParseXML
+import Messages
+
+CONNECTION_CHECKING_PREF = Param('Connection Checking', Bool(true='Match Data
Types', false='Ignore Data Types', default=True))
+PARAM_CHECKING_PREF = Param('Parameter Checking', Bool(true='Verify
Parameters', false='Ignore Invalid Params', default=True))
+SOCKET_CHECKING_PREF = Param('Socket Checking', Bool(true='Require
Connections', false='Allow Open Sockets', default=True))
+RESTORE_FLOW_GRAPH_PREF = Param('Restore Flow Graph', Bool(true='Overwrite
Default Flow Graph', false='Keep Default Flow Graph', default=True))
+DEFAULT_FLOW_GRAPH_PREF = Param('Default Flow Graph', FileOpen('',
allow_blank=True))
+SNAP_TO_GRID_PREF = Param('Snap to Grid', Bool(true='On', false='Off',
default=False))
+GRID_SIZE_PREF = Param('Grid Size (pixels)', Enum([
+ ('10 pixels', 10),
+ ('20 pixels', 20),
+ ('30 pixels', 30),
+ ('40 pixels', 40),
+ ('50 pixels', 50),
+ ('60 pixels', 60),
+ ('70 pixels', 70),
+ ('80 pixels', 80),
+ ('90 pixels', 90),
+ ('100 pixels', 100),], 2))
+SHOW_GRID_PREF = Param('Grid Points', Bool(true='Show Grid', false='Hide
Grid', default=False))
+REPORTS_WIN_SHOW_PREF = Param('Reports Window', Bool(true='Show Reports
Window', false='Hide Reports Window', default=True))
+MAIN_WINDOW_WIDTH_PREF = Param('Main Window Width',
Int(DEFAULT_MAIN_WINDOW_WIDTH))
+MAIN_WINDOW_HEIGHT_PREF = Param('Main Window Height',
Int(DEFAULT_MAIN_WINDOW_HEIGHT))
+
+###########################################################################
+# List of Preferences
+###########################################################################
+
+PREFS_LIST = [ #list of all prefs the be saved, restored, and displayed in the
pref's dialog
+#(title, notes, list of preferences)
+ ("Verification", '', [
+ CONNECTION_CHECKING_PREF,
+ PARAM_CHECKING_PREF,
+ SOCKET_CHECKING_PREF,
+ ]),
+ ("File Paths", '''\
+The default flow graph controls which flow graph will be loaded when the
program is started. \
+If the default flow graph is left blank, a blank flow graph will be loaded at
start-up. \
+File paths passed via a command line argument always proceed the default flow
graph. \
+Upon exit, if the overwrite option is set, the default flow graph will be
overwritten with the current flow graph. \
+''', [
+ RESTORE_FLOW_GRAPH_PREF,
+ DEFAULT_FLOW_GRAPH_PREF,
+ ]),
+ ("Grid Options", '''\
+Snap to Grid forces the upper right corner of the signal block to align with a
grid point. \
+''', [
+ SNAP_TO_GRID_PREF,
+ GRID_SIZE_PREF,
+ SHOW_GRID_PREF,
+ ]),
+ ("Misc Options", '', [
+ REPORTS_WIN_SHOW_PREF,
+ ]),
+ ('', '', [ #put hidden prefs here
+ MAIN_WINDOW_WIDTH_PREF,
+ MAIN_WINDOW_HEIGHT_PREF,
+ ]),
+ ]
+
+###########################################################################
+# Preference Access Methods
+###########################################################################
+
+def get_value(param):
+ """ If the param is valid, return the parsed value of the param.
+ Otherwise return a blank string. """
+ if param.get_data_type().is_valid(): return
param.get_data_type().parse()
+ else: return ''
+
+def to_nested():
+ """ Convert the param's data to nested format """
+ categories = list()
+ nested_data = ('preferences', [
+
('timestamp', str(time.time())),
+
('hostname', socket.gethostname()),
+
('version', VERSION),
+
('categories', categories),])
+ for title,notes,params in PREFS_LIST:
+ prefs = list()
+ categories.append(('category', [('title', title), ('prefs',
prefs)]))
+ for param in params: prefs.append(('pref',
param.get_data_type().get_data()))
+ return nested_data
+
+def from_nested(nested_data):
+ """ Parse the nested data to retrieve each preference. """
+ find_data = ParseXML.find_data
+ preferences = find_data([nested_data], 'preferences')
+ categories = find_data(preferences, 'categories')
+ for i,category in enumerate(categories):
+ category = find_data([category], 'category')
+ title = find_data(category, 'title')
+ prefs = find_data(category, 'prefs')
+ for j,pref in enumerate(prefs):
+ pref = find_data([pref], 'pref')
+ try: PREFS_LIST[i][2][j].get_data_type().set_data(pref)
+ except: pass
+
+def load(window=None):
+ try:
+
from_nested(ParseXML.from_xml(ParseXML.from_file(PREFERENCES_FILE_PATH)))
+ if window: window.resize(get_value(MAIN_WINDOW_WIDTH_PREF),
get_value(MAIN_WINDOW_HEIGHT_PREF))
+ except: Messages.send_fail_load_preferences()
+
+def save(window=None):
+ if window:
+ width,height = window.get_size()
+ MAIN_WINDOW_WIDTH_PREF.get_data_type().set_data(width)
+ MAIN_WINDOW_HEIGHT_PREF.get_data_type().set_data(height)
+ try: ParseXML.to_file(ParseXML.to_xml(to_nested()),
PREFERENCES_FILE_PATH)
+ except IOError: Messages.send_fail_save_preferences()
+
+###########################################################################
+# Special methods for specific program functionalities
+###########################################################################
+def set_default_flow_graph(file_path):
+ ''' Set the new default flow graph path, only if the restore option is
true. '''
+ if get_value(RESTORE_FLOW_GRAPH_PREF):
+ DEFAULT_FLOW_GRAPH_PREF.get_data_type().set_data(file_path)
+
+def get_default_flow_graph():
+ ''' Get the default flow graph path. Return a blank string if the path
is invalid. '''
+ if DEFAULT_FLOW_GRAPH_PREF.get_data_type().is_valid():
+ return get_value(DEFAULT_FLOW_GRAPH_PREF)
+ return ''
+
+def check_connections():
+ return get_value(CONNECTION_CHECKING_PREF)
+
+def check_sockets():
+ return get_value(SOCKET_CHECKING_PREF)
+
+def check_params():
+ return get_value(PARAM_CHECKING_PREF)
+
+def show_reports_window():
+ return get_value(REPORTS_WIN_SHOW_PREF)
+
+def get_grid_size():
+ return get_value(GRID_SIZE_PREF)
+
+def snap_to_grid():
+ return get_value(SNAP_TO_GRID_PREF)
+
+def show_grid():
+ return get_value(SHOW_GRID_PREF)
+
+
\ No newline at end of file
Deleted: grc/branches/gtk_separation/src/Graphics/SignalBlockParamsDialog.py
Deleted: grc/branches/gtk_separation/src/Graphics/SignalBlockSelectionWindow.py
Copied: grc/branches/gtk_separation/src/Graphics/StateCache.py (from rev 5485,
grc/branches/gtk_separation/src/StateCache.py)
===================================================================
--- grc/branches/gtk_separation/src/Graphics/StateCache.py
(rev 0)
+++ grc/branches/gtk_separation/src/Graphics/StateCache.py 2007-05-17
13:52:28 UTC (rev 5486)
@@ -0,0 +1,81 @@
+"""
+GNU Radio Companion is a graphical interface into the GNU Radio project.
+Copyright (C) 2007 Josh Blum
+
+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
+"""
+"""
+ StateCache.py
+ Josh Blum
+ Stores the flow graph states to drive the undo/redo and save interface.
+"""
+
+from Actions import FLOW_GRAPH_UNDO, FLOW_GRAPH_REDO, get_action_from_name
+from Constants import STATE_CACHE_SIZE
+
+class StateCache:
+ """ The state cache is an interface to a list to record data/states and
to revert to previous states. """
+ def __init__(self, initial_state):
+ """ The initial state is given as well as the handler for the
windows
+ so that redo/undo/save can be properly handled. """
+ self.states = list()
+ for i in range(STATE_CACHE_SIZE):
+ self.states.append(None)
+ self.current_state_index = 0
+ self.num_prev_states = 0
+ self.num_next_states = 0
+ self.states[0] = initial_state
+ get_action_from_name(FLOW_GRAPH_UNDO).set_sensitive(False)
+ get_action_from_name(FLOW_GRAPH_REDO).set_sensitive(False)
+
+ def save_new_state(self, state):
+ """ Place the new state at the next index and add one to the
number of previous states. """
+ self.current_state_index = (self.current_state_index +
1)%STATE_CACHE_SIZE
+ self.states[self.current_state_index] = state
+ self.num_prev_states = self.num_prev_states + 1
+ if self.num_prev_states == STATE_CACHE_SIZE:
+ self.num_prev_states = STATE_CACHE_SIZE - 1
+ self.num_next_states = 0
+ get_action_from_name(FLOW_GRAPH_UNDO).set_sensitive(True)
+ get_action_from_name(FLOW_GRAPH_REDO).set_sensitive(False)
+
+ def get_current_state(self):
+ """ get the state at the current index """
+ return self.states[self.current_state_index]
+
+ def get_prev_state(self):
+ """ get the previous state if possible and decrement the
current index. """
+ if self.num_prev_states > 0:
+ self.current_state_index = (self.current_state_index +
STATE_CACHE_SIZE -1)%STATE_CACHE_SIZE
+ self.num_next_states = self.num_next_states + 1
+ self.num_prev_states = self.num_prev_states - 1
+ if self.num_prev_states == 0:
+
get_action_from_name(FLOW_GRAPH_UNDO).set_sensitive(False)
+
get_action_from_name(FLOW_GRAPH_REDO).set_sensitive(True)
+ return self.get_current_state()
+ return None
+
+ def get_next_state(self):
+ """ get the next state if possible and increment the
current index. """
+ if self.num_next_states > 0:
+ self.current_state_index = (self.current_state_index +
1)%STATE_CACHE_SIZE
+ self.num_next_states = self.num_next_states - 1
+ self.num_prev_states = self.num_prev_states + 1
+ if self.num_next_states == 0:
+
get_action_from_name(FLOW_GRAPH_REDO).set_sensitive(False)
+
get_action_from_name(FLOW_GRAPH_UNDO).set_sensitive(True)
+ return self.get_current_state()
+ return None
+
\ No newline at end of file
Deleted: grc/branches/gtk_separation/src/Graphics/USRPDiagnostics.py
Deleted: grc/branches/gtk_separation/src/Graphics/VariableModificationWindow.py
Copied: grc/branches/gtk_separation/src/Graphics/Windows/Bars.py (from rev
5485, grc/branches/gtk_separation/src/Graphics/Bars.py)
===================================================================
--- grc/branches/gtk_separation/src/Graphics/Windows/Bars.py
(rev 0)
+++ grc/branches/gtk_separation/src/Graphics/Windows/Bars.py 2007-05-17
13:52:28 UTC (rev 5486)
@@ -0,0 +1,136 @@
+"""
+GNU Radio Companion is a graphical interface into the GNU Radio project.
+Copyright (C) 2007 Josh Blum
+
+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
+"""
+"""
+ Graphics/Bars.py
+ Josh Blum
+ this file will create the GUI's toolbar and menubar
+"""
+
+from Actions import *
+import pygtk
+pygtk.require('2.0')
+import gtk
+
+TOOLBAR_LIST = [
+ FLOW_GRAPH_NEW,
+ FLOW_GRAPH_OPEN,
+ FLOW_GRAPH_SAVE,
+ None,
+ FLOW_GRAPH_SNAP_SHOT,
+ None,
+ FLOW_GRAPH_UNDO,
+ FLOW_GRAPH_REDO,
+ None,
+ FLOW_GRAPH_RUN,
+ FLOW_GRAPH_STOP,
+ None,
+ ELEMENT_DELETE,
+ SIGNAL_BLOCK_ROTATE_LEFT,
+ SIGNAL_BLOCK_ROTATE_RIGHT,
+ ]
+
+MENU_BAR_LIST = [
+ (gtk.Action('File', '_File',
None, None),
+ [
+ FLOW_GRAPH_NEW,
+ FLOW_GRAPH_OPEN,
+ None,
+ FLOW_GRAPH_SAVE,
+
FLOW_GRAPH_SAVE_AS,
+ None,
+
FLOW_GRAPH_SNAP_SHOT,
+ None,
+
APPLICATION_QUIT,
+ ]),
+ (gtk.Action('Edit', '_Edit',
None, None),
+ [
+ FLOW_GRAPH_UNDO,
+ FLOW_GRAPH_REDO,
+ None,
+ ELEMENT_DELETE,
+
SIGNAL_BLOCK_ROTATE_LEFT,
+
SIGNAL_BLOCK_ROTATE_RIGHT,
+
SIGNAL_BLOCK_PARAM_MODIFY,
+ ]),
+ (gtk.Action('Run', '_Run',
None, None),
+ [
+ FLOW_GRAPH_RUN,
+ FLOW_GRAPH_STOP,
+ ]),
+ (gtk.Action('Options',
'_Options', None, None),
+ [
+
FLOW_GRAPH_WINDOW_RESIZE,
+
USRP_DIAGNOSTICS_DISPLAY,
+
PREFS_WINDOW_DISPLAY,
+ ]),
+ (gtk.Action('Help', '_Help',
None, None),
+ [
+
ABOUT_WINDOW_DISPLAY,
+
COLORS_WINDOW_DISPLAY,
+
HOTKEYS_WINDOW_DISPLAY,
+ ])
+
+ ]
+
+
+
+class Toolbar(gtk.Toolbar):
+ """ Toolbar is a gtk Toolbar with actions added from the toolbar
list """
+ def __init__(self):
+ """ Parse the list of action names in the toolbar list.
Look up the action for each name
+ in the action list and add it to the toolbar """
+ gtk.Toolbar.__init__(self)
+ self.set_style(gtk.TOOLBAR_ICONS)
+ for action_name in TOOLBAR_LIST:
+ if action_name == None:
+ spacer = gtk.SeparatorToolItem()
+ spacer.show()
+ self.add(spacer)
+ else:
+ action = get_action_from_name(action_name)
+ toolitem = action.create_tool_item()
+ self.add(toolitem)
+ action.set_property('tooltip',
action.get_property('tooltip'))
+
+
+class MenuBar(gtk.MenuBar):
+ """ MenuBar is a gtk MenuBar with actions added from the menuBar
list """
+ def __init__(self):
+ """ Parse the list of submenus from the menubar list. For
each submenu, get a list of action names.
+ Look up the action for each name in the action list and add it
to the submenu.
+ Add the submenu to the menuBar """
+ gtk.MenuBar.__init__(self)
+ for main_action,action_names in MENU_BAR_LIST:
+ # Create the MenuItem
+ main_menu_item = main_action.create_menu_item()
+ self.append(main_menu_item)
+ # Create the Menu
+ main_menu = gtk.Menu()
+ main_menu_item.set_submenu(main_menu)
+ for action_name in action_names:
+ if action_name == None:
+ spacer = gtk.SeparatorMenuItem()
+ spacer.show()
+ main_menu.append(spacer)
+ else:
+ # Create a proxy MenuItem
+ menu_item =
get_action_from_name(action_name).create_menu_item()
+ main_menu.append(menu_item)
+
+
\ No newline at end of file
Copied: grc/branches/gtk_separation/src/Graphics/Windows/Dialogs.py (from rev
5485, grc/branches/gtk_separation/src/Graphics/Dialogs.py)
===================================================================
--- grc/branches/gtk_separation/src/Graphics/Windows/Dialogs.py
(rev 0)
+++ grc/branches/gtk_separation/src/Graphics/Windows/Dialogs.py 2007-05-17
13:52:28 UTC (rev 5486)
@@ -0,0 +1,193 @@
+"""
+GNU Radio Companion is a graphical interface into the GNU Radio project.
+Copyright (C) 2007 Josh Blum
+
+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
+"""
+"""
+ Graphics/Dialogs.py
+ Josh Blum
+ Misc Dialogs
+"""
+
+import Colors
+import pygtk
+pygtk.require('2.0')
+import gtk
+from DataType import *
+from Constants import *
+from Elements import Param
+import Preferences
+
+class TextDisplay(gtk.TextView):
+ """ A non editable gtk text view. """
+ def __init__(self, text=''):
+ """ Create a new TextDisplay with the given text. """
+ text_buffer = gtk.TextBuffer()
+ text_buffer.set_text(text)
+ self.set_text = text_buffer.set_text
+ self.insert = lambda line:
text_buffer.insert(text_buffer.get_end_iter(), line)
+ gtk.TextView.__init__(self, text_buffer)
+ self.set_editable(False)
+ self.set_cursor_visible(False)
+ self.set_wrap_mode(gtk.WRAP_WORD)
+ self.show()
+
+######################################################################################################
+class PreferencesDialog(gtk.Dialog):
+ """ A dialog box to display each preference parameter. """
+ def __init__(self):
+ gtk.Dialog.__init__(self, buttons=('gtk-close',
gtk.RESPONSE_CLOSE))
+ self.set_title("Preferences")
+ self.set_size_request(MIN_DIALOG_WIDTH, MIN_DIALOG_HEIGHT)
+ vbox = gtk.VBox()
+ vbox.show()
+ for title,notes,params in Preferences.PREFS_LIST:
+ if title:
+ label = gtk.Label()
+ label.set_markup('<b> ----- '+title+' -----
</b>')
+ label.show()
+ vbox.pack_start(label, False, padding=5)
+ for param in params:
vbox.pack_start(param.get_input_object(), False)
+ if notes: vbox.pack_start(TextDisplay(notes),
False, padding=5)
+ #add the scrolled window for the preferences
+ scrolled_window = gtk.ScrolledWindow()
+ scrolled_window.set_policy(gtk.POLICY_AUTOMATIC,
gtk.POLICY_AUTOMATIC)
+ scrolled_window.add_with_viewport(vbox)
+ scrolled_window.show()
+ self.vbox.pack_start(scrolled_window, True)
+ self.run()
+ self.destroy()
+
+######################################################################################################
+class FlowGraphWindowSizeDialog(gtk.Dialog):
+ """ A dialog box to set the window size, width and heigh in pixels.
"""
+ def __init__(self, flow_graph):
+ gtk.Dialog.__init__(self, buttons=('gtk-close',
gtk.RESPONSE_CLOSE))
+ self.flow_graph = flow_graph
+ self.set_title("Set the Window Size")
+ # the helpful dimension constraints label #
+ windowSizeDesc = '''
+Minimum window (width/height) in pixels is (%d/%d).
+Maximum window (width/height) in pixels is (%d/%d).
+'''%(MIN_WINDOW_WIDTH, MIN_WINDOW_HEIGHT, MAX_WINDOW_WIDTH, MAX_WINDOW_HEIGHT)
+ windowSizeDescLabel = gtk.Label()
+ windowSizeDescLabel.set_markup('<i>'+windowSizeDesc+'</i>')
+ windowSizeDescLabel.show()
+ self.vbox.pack_end(windowSizeDescLabel, False)
+ self.original_dimensions = width,height =
self.flow_graph.get_size_request() # get the window dimensions
+ self.width = Int(width, min=MIN_WINDOW_WIDTH,
max=MAX_WINDOW_WIDTH)
+ self.height = Int(height, min=MIN_WINDOW_HEIGHT,
max=MAX_WINDOW_HEIGHT)
+ self.vbox.pack_start(Param('width (pixels)',
self.width).get_input_object(), False)
+ self.vbox.pack_start(Param('height (pixels)',
self.height).get_input_object(), False)
+
+ def run(self):
+ ''' Return the new dimensions rather than a response.
+ If the dimensions were invalid, return None. '''
+ self.dimensions = None
+ gtk.Dialog.run(self)
+ if self.width.is_valid() and self.height.is_valid():
+ self.dimensions = (self.width.parse(),
self.height.parse())
+ self.destroy()
+ if self.original_dimensions == self.dimensions: return None
# do not return dimensions if no change
+ return self.dimensions
+
+######################################################################################################
+class LooseChangesMessage(gtk.MessageDialog):
+ """ This message dialog will ask about discarding unsaved changes.
"""
+ def __init__(self):
+ gtk.MessageDialog.__init__(self, None, gtk.DIALOG_MODAL,
gtk.MESSAGE_WARNING,
+ gtk.BUTTONS_OK_CANCEL, "Would you like to discard your
unsaved changes?")
+ self.set_title('Unsaved Changes!')
+
+ def run(self):
+ """ call parent class run(), destroy the dialog. Return
True if OK was clicked, or False. """
+ response = gtk.MessageDialog.run(self)
+ self.destroy()
+ if response == gtk.RESPONSE_OK: return True
+ return False
+
+######################################################################################################
+class AboutDialog(gtk.AboutDialog):
+ """ cute little about dialog """
+ def __init__(self):
+ gtk.AboutDialog.__init__(self)
+ self.set_version(VERSION)
+ self.set_name(MAIN_WINDOW_PREFIX)
+ self.set_comments("""\
+Thank you to all those from the mailing list who tested GNU Radio Companion
and offered advice.
+--
+GNU Radio Companion, \
+Copyright (C) 2007 Josh Blum
+GRC comes with ABSOLUTELY NO WARRANTY. \
+This is free software, \
+and you are welcome to redistribute it.""")
+ self.run()
+ self.destroy()
+
+######################################################################################################
+class DataTypeColorsDialog(gtk.Dialog):
+ """ Display each data type with its associated color. """
+ def __init__(self):
+ gtk.Dialog.__init__(self, buttons=('gtk-close',
gtk.RESPONSE_CLOSE))
+ self.set_title('Colors')
+ self.set_size_request(150, -1)
+ for dt_name, color in (('Complex', Colors.COMPLEX_COLOR_SPEC),
+
('Float', Colors.FLOAT_COLOR_SPEC),
+
('Int', Colors.INT_COLOR_SPEC),
+
('Short', Colors.SHORT_COLOR_SPEC),
+
('Byte', Colors.BYTE_COLOR_SPEC),
+
# and for the vectors #
+
('Complex Vector', Colors.COMPLEX_VECTOR_COLOR_SPEC),
+
('Float Vector', Colors.FLOAT_VECTOR_COLOR_SPEC),
+
('Int Vector', Colors.INT_VECTOR_COLOR_SPEC),
+
('Short Vector', Colors.SHORT_VECTOR_COLOR_SPEC),
+
('Byte Vector', Colors.BYTE_VECTOR_COLOR_SPEC),):
+ label = gtk.Label('')
+ label.set_markup('<span
background="%s">%s</span>'%(color, dt_name))
+ label.show()
+ self.vbox.pack_start(label)
+ self.run()
+ self.destroy()
+
+######################################################################################################
+class HotKeysDialog(gtk.Dialog):
+ """ Display each action with the associated hotkey. """
+ def __init__(self):
+ gtk.Dialog.__init__(self, buttons=('gtk-close',
gtk.RESPONSE_CLOSE))
+ self.set_title('Hot Keys')
+ for action, hotkey in (('New Flow Graph', 'Ctrl + n'),
+
('Open Flow Graph', 'Ctrl + o'),
+
('Save Flow Graph', 'Ctrl + s'),
+
('Undo Change', 'Ctrl + z'),
+
('Redo Change', 'Ctrl + y'),
+
('Redo Change', 'Ctrl + Z'),
+
('Delete Block', 'Delete'),
+
('Rotate Block', 'Right'),
+
('Rotate Block', 'Left'),
+
('Modify Data Type', 'Up'),
+
('Modify Data Type', 'Down'),
+
('Add a Socket', '+'),
+
('Remove a Socket', '-'),
+
('Close Params Dialog', 'Esc'),
+
('Flow Graph Run', 'F5'),
+
('Flow Graph Stop', 'F7'),
+
('Screen Shot', 'PrintScreen'),):
+ label = gtk.Label('')
+ label.set_markup('<b>%s:</b> %s'%(action, hotkey))
+ label.show()
+ self.vbox.pack_start(label)
+ self.run()
+ self.destroy()
Copied: grc/branches/gtk_separation/src/Graphics/Windows/FlowGraph.py (from rev
5485, grc/branches/gtk_separation/src/Graphics/FlowGraph.py)
===================================================================
--- grc/branches/gtk_separation/src/Graphics/Windows/FlowGraph.py
(rev 0)
+++ grc/branches/gtk_separation/src/Graphics/Windows/FlowGraph.py
2007-05-17 13:52:28 UTC (rev 5486)
@@ -0,0 +1,430 @@
+"""
+GNU Radio Companion is a graphical interface into the GNU Radio project.
+Copyright (C) 2007 Josh Blum
+
+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
+"""
+"""
+ Graphics/FlowGraph.py
+ Josh Blum
+ flow graph structure for storing signal blocks and their connections
+"""
+
+from Constants import *
+from Elements import *
+from Actions import *
+from Colors import BACKGROUND_COLOR, TXT_COLOR
+import pygtk
+pygtk.require('2.0')
+import gtk
+import time,socket #for tagging saved files
+import SignalBlockDefs
+from SignalBlockParamsDialog import SignalBlockParamsDialog
+import random
+import Messages
+import Preferences
+import ParseXML
+
+class FlowGraph(gtk.DrawingArea):
+ """ FlowGraph is the data structure to store graphical signal
blocks, their graphical input/output
+ parameters, and the connections between inputs and outputs. """
+ def __init__(self, handle_states, variable_modification_window):
+ """ Create a list for signal blocks and connections. Connect
mouse handlers. """
+ self.elements = list()
+ self.remove_element = lambda e: self.elements.remove(e)
+ self.gc = None
+ self.handle_states = handle_states
+ self.variable_modification_window = variable_modification_window
+ gtk.DrawingArea.__init__(self)
+ self.connect('expose-event', self.__on_expose)
+ self.connect('motion-notify-event',
self.__motion_notify_event_cb)
+ self.connect('button-press-event',
self.__button_press_event_cb)
+ self.connect('button-release-event',
self.__button_release_event_cb)
+ self.set_events(gtk.gdk.BUTTON_PRESS_MASK |
gtk.gdk.POINTER_MOTION_MASK | gtk.gdk.BUTTON_RELEASE_MASK\
+ | gtk.gdk.LEAVE_NOTIFY_MASK | gtk.gdk.ENTER_NOTIFY_MASK)
+ # 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)
+ # important vars dealing with mouse event tracking
#
+ self.has_moved = False
+ self.mouse_pressed = False
+ self.coordinate = (0,0)
+ self.selected_element = None
+ self.is_selected = lambda: self.selected_element != None
+ self.count = 0
+ self.pixmap = None
+ self.show()
+
+ def handle_focus_event(self, widget, event, focus_flag):
+ """ Record the focus state of the flow graph window. """
+ self.focus_flag = focus_flag
+
+ def add_signal_block(self, tag):
+ ''' Add a signal block of the given tag to this flow graph.
'''
+ index = 0
+ while True:
+ id = tag+str(index)
+ index = index + 1
+ id_found = False
+ for element in self.elements:
+ if is_signal_block(element) and id ==
element.get_id():
+ id_found = True
+ break
+ if not id_found: #make sure that a
unique id was created
+ rot = 0#(0, 180)[random.randint(0,1)]
+ vAdj =
self.get_parent().get_vadjustment().get_value()
+ hAdj =
self.get_parent().get_hadjustment().get_value()
+ x = random.randint(100,400)+int(hAdj)
+ y = random.randint(100,400)+int(vAdj)
+
self.elements.append(SignalBlockDefs.get_signal_block(self, (x, y), rot, tag,
id)[0])
+ self.handle_states(SIGNAL_BLOCK_CREATE)
+ self.update()
+ return
+
+ def type_controller_modify_selected(self, direction):
+ """ Change the registered type controller for the selected
signal block.
+ direction may be +1 or -1 """
+ if is_socket(self.selected_element): self.selected_element =
self.selected_element.get_parent()
+ if is_signal_block(self.selected_element): return
self.selected_element.modify_type_controller(direction)
+ return False
+
+ def socket_controller_modify_selected(self, direction):
+ """ Change socket controller for the selected signal block.
+ direction may be +1 or -1 """
+ if is_socket(self.selected_element): self.selected_element =
self.selected_element.get_parent()
+ if is_signal_block(self.selected_element): return
self.selected_element.modify_socket_controller(direction)
+ return False
+
+ def param_modify_selected(self):
+ """ Create and show a param modification dialog for the
selected element (socket and signal block only) """
+ if is_socket(self.selected_element): self.selected_element =
self.selected_element.get_parent()
+ if is_signal_block(self.selected_element):
+ signal_block_params_dialog =
SignalBlockParamsDialog(self.selected_element)
+ changed = signal_block_params_dialog.run()
+ self.update()
+ return changed #changes were made?
+ return False
+
+ def connect_sockets(self, s1, s2):
+ """ Connect input and output sockets. Ignore state change
if creation of connection fails. """
+ try:
+ connection = Connection(self, s1, s2)
+ self.elements.append(connection)
+ self.selected_element = None
+ self.handle_states(CONNECTION_CREATE)
+ self.update()
+ except Exception, e:
+ Messages.send_fail_connection()
+ self.handle_states(NOTHING_SELECT)
+
+ def move_selected(self, delta_coordinate):
+ """ Move the element and by the change in coordinate
(delta_coordinate) """
+ if self.selected_element != None:
+ self.selected_element.move(delta_coordinate)
+ self.has_moved = True
+ self.draw()
+
+ def rotate_selected(self, direction):
+ """ Rotate the selected element by 90 degrees, direction
can be "left"/"right"
+ True if rotated, otherwise False. Only rotate
SignalBlocks and Sockets. """
+ if self.selected_element != None and
(is_signal_block(self.selected_element) or is_socket(self.selected_element)):
+ self.selected_element.rotate(direction)
+ self.draw()
+ return True
+ return False
+
+ def delete_selected(self):
+ """ If an element is selected, remove it and its attached
parts from the element list.
+ True if the element was deleted, otherwise False.
"""
+ if self.selected_element != None:
+ if is_socket(self.selected_element): # found a
socket, set to parent signal block
+ self.selected_element =
self.selected_element.get_parent()
+ if is_signal_block(self.selected_element): #
delete a signal block
+ connections =
self.selected_element.get_connections()
+ for connection in connections:
connection.disconnect()
+ self.remove_element(self.selected_element)
+ elif is_connection(self.selected_element): #
delete a connection
+ self.selected_element.disconnect()
+ self.selected_element = None
+ self.update()
+ return True
+ return False
+
+ def unselect(self):
+ """ If an element is selected, un-highlight it and set selected
to None. """
+ if self.selected_element != None:
+ self.selected_element.set_highlighted(False)
+ self.selected_element = None
+ self.update()
+
+ def what_is_selected(self, coor):
+ """ At the given coordinate, return the first element found
to be selected
+ - iterate though the elements backwards since top elements are
at the end of the list
+ - if an element is selected, place it at the end of the list so
that is is drawn last,
+ and hence on top. """
+ # check the elements #
+ for i,element in enumerate(reversed(self.elements)):
+ if element.what_is_selected(coor) != None:
+ self.elements.remove(element)
+ self.elements.append(element)
+ return element.what_is_selected(coor)
+ return None
+
+ def __button_press_event_cb(self, widget, event):
+ """ A mouse button is pressed. Record the state of the
mouse, find the selected element,
+ set the Element highlighted, handle the state change, and
redraw the FlowGraph. """
+ # unselect anything in the vars mod window #
+ self.variable_modification_window.unselect_all()
+ if event.button == 1:
+ if self.selected_element != None:
self.selected_element.set_highlighted(False)
+ self.count = 0
+ self.mouse_pressed = True
+ self.coordinate = (event.x, event.y)
+ old_selection = self.selected_element
+ self.selected_element = self.what_is_selected((event.x,
event.y))
+ # handle the state change with the new selection
#
+ if is_connection(self.selected_element):
self.handle_states(CONNECTION_SELECT)
+ elif is_socket(self.selected_element):
self.handle_states(SOCKET_SELECT)
+ elif is_signal_block(self.selected_element):
self.handle_states(SIGNAL_BLOCK_SELECT)
+ elif self.selected_element == None:
self.handle_states(NOTHING_SELECT)
+ # this selection and the last were Sockets, try
to connect them #
+ if is_socket(old_selection) and
is_socket(self.selected_element) and\
+ old_selection is not self.selected_element:
#cannot be the same socket
+ self.connect_sockets(old_selection,
self.selected_element)
+ if self.selected_element != None:
self.selected_element.set_highlighted(True)
+ # double click detected, bring up params dialog
if possible #
+ if event.type == gtk.gdk._2BUTTON_PRESS and
is_signal_block(self.selected_element):
+ self.mouse_pressed = False
+ self.handle_states(SIGNAL_BLOCK_PARAM_MODIFY)
+ self.draw()
+ return True
+
+ def __button_release_event_cb(self, widget, event):
+ """ A mouse button is released, record the state. """
+ if event.button == 1:
+ self.mouse_pressed = False
+ if self.has_moved:
+ if Preferences.snap_to_grid():
+ grid_size = Preferences.get_grid_size()
+ X,Y =
self.selected_element.get_coordinate()
+ deltaX = X%grid_size
+ if deltaX < grid_size/2: deltaX = -1 *
deltaX
+ else: deltaX = grid_size - deltaX
+ deltaY = Y%grid_size
+ if deltaY < grid_size/2: deltaY = -1 *
deltaY
+ else: deltaY = grid_size - deltaY
+ self.move_selected((deltaX,deltaY))
+ self.handle_states(SIGNAL_BLOCK_MOVE)
+ self.has_moved = False
+ return True
+
+ def is_valid(self):
+ """ is the flow graph valid, ie: are all elements valid?
"""
+ for element in self.elements:
+ if not element.is_valid(): return False
+ return True
+
+ def update(self):
+ '''call update on all elements'''
+ print "Updating entire flow graph..."
+ for element in self.elements: element.update()
+ self.draw()
+
+ def __motion_notify_event_cb(self, widget, event):
+ """ The mouse is moved. If mouse_pressed is true, react to the
motions:
+ - if an Element is highlighted, this will move the
Element by
+ redrawing it at the new position """
+ fgW,fgH = self.get_size_request()
+ self.count = (1 +
self.count)%MOTION_DETECT_REDRAWING_SENSITIVITY
+ # to perform a movement, the mouse must be pressed, an
element selected, count of zero. #
+ if self.mouse_pressed and\
+ self.count == 0 and\
+ self.selected_element != None:
+ # The event coordinates must be within 10 pixels
away from the bounds of the flow graph. #
+ x = event.x
+ if x <= BORDER_PROXIMITY_SENSITIVITY:
+ x = BORDER_PROXIMITY_SENSITIVITY
+ if x >= fgW - BORDER_PROXIMITY_SENSITIVITY:
+ x = fgW - BORDER_PROXIMITY_SENSITIVITY
+ y = event.y
+ if y <= BORDER_PROXIMITY_SENSITIVITY:
+ y = BORDER_PROXIMITY_SENSITIVITY
+ if y >= fgH - BORDER_PROXIMITY_SENSITIVITY:
+ y = fgH - BORDER_PROXIMITY_SENSITIVITY
+ # get the change in coordinates #
+ X,Y = self.coordinate
+ deltaX = int(x - X)
+ deltaY = int(y - Y)
+ vAdj = self.get_parent().get_vadjustment().get_value()
+ hAdj = self.get_parent().get_hadjustment().get_value()
+ width = self.get_parent().get_hadjustment().page_size
+ height = self.get_parent().get_vadjustment().page_size
+ # scroll horizontal if we moved near the border #
+ if x-hAdj > width-SCROLL_PROXIMITY_SENSITIVITY and\
+ hAdj+SCROLL_DISTANCE < fgW - width:
+
self.get_parent().get_hadjustment().set_value(hAdj+SCROLL_DISTANCE)
+ elif x-hAdj < SCROLL_PROXIMITY_SENSITIVITY:
+
self.get_parent().get_hadjustment().set_value(hAdj-SCROLL_DISTANCE)
+ # scroll vertical if we moved near the border #
+ if y-vAdj > height-SCROLL_PROXIMITY_SENSITIVITY and\
+ vAdj+SCROLL_DISTANCE < fgH - height:
+
self.get_parent().get_vadjustment().set_value(vAdj+SCROLL_DISTANCE)
+ elif y-vAdj < SCROLL_PROXIMITY_SENSITIVITY:
+
self.get_parent().get_vadjustment().set_value(vAdj-SCROLL_DISTANCE)
+ # move the selected element and record the new
coordinate #
+ self.move_selected((deltaX, deltaY))
+ self.coordinate = (x, y)
+
+ def __on_expose(self, widget, event):
+ """ The window initially appears or is resized, create a
new pixmap, draw the flow graph. """
+ self.gc = self.window.new_gc()
+ width, height = self.get_size_request()
+ if self.pixmap == None or (width, height) !=
self.pixmap.get_size():
+ self.pixmap = gtk.gdk.Pixmap(self.window, width,
height, -1)
+ print "Main Pixmap Created!"
+ self.draw()
+
+ def draw(self, drawable=None):
+ """ draw the background and then all of the Elements in
this FlowGraph on the pixmap,
+ then draw the pixmap to the drawable window of this FlowGraph.
"""
+ if self.gc != None:
+ # draw the background #
+ W,H = self.get_size_request()
+ self.gc.foreground = BACKGROUND_COLOR
+ self.pixmap.draw_rectangle(self.gc, True, 0, 0, W, H)
+ if Preferences.show_grid():
+ grid_size = Preferences.get_grid_size()
+ points = list()
+ for i in range(W/grid_size):
+ for j in range(H/grid_size):
+
points.append((i*grid_size,j*grid_size))
+ self.gc.foreground = TXT_COLOR
+ self.pixmap.draw_points(self.gc, points)
+ # draw the foreground #
+ for element in filter(is_signal_block, self.elements) +
filter(is_connection, self.elements):
+ element.draw(self.pixmap) # draw signal
blocks first, then connections on the top
+ if self.mouse_pressed and self.selected_element != None:
+ self.selected_element.draw(self.pixmap)
+ self.window.draw_drawable(self.gc, self.pixmap, 0, 0,
0, 0, -1, -1)
+
+ def to_nested_data(self):
+ ''' Dump all the values in this flow graph into a nested
data format. '''
+ vars_list = list()
+ signal_blocks_list = list()
+ connections_list = list()
+ W,H = self.get_size_request()
+ nested_data = ('flow_graph', [
+ ('timestamp', str(time.time())),
+ ('hostname', socket.gethostname()),
+ ('version', VERSION),
+ ('valid', str(self.is_valid())),
+ ('window_width', str(W)),
+ ('window_height', str(H)),
+ ('vars', vars_list),
+ ('signal_blocks', signal_blocks_list),
+ ('connections', connections_list)
+ ])
+ for row in self.variable_modification_window.to_row_list():
+ vars_list.append(('var', [
+
('key', row[0]),
+
('value', row[1]),
+
('min', row[2]),
+
('max', row[3]),
+
('step', row[4]),
+
]))
+ for element in filter(is_signal_block, self.elements):
+ params_list = list()
+ signal_blocks_list.append(('signal_block', [
+
('tag', element.get_tag()),
+
('id', element.get_id()),
+
('x_coordinate', str(element.get_coordinate()[0])),
+
('y_coordinate', str(element.get_coordinate()[1])),
+
('rotation', str(element.get_rotation())),
+
('params', params_list)
+
]))
+ for param in element.get_params():
+ params_list.append(('param',
str(param.get_data_type().get_data())) )
+ for element in filter(is_connection, self.elements):
+ connections_list.append(('connection', [
+ ('input_signal_block_id',
str(element.get_input_socket().get_parent().get_id())),
+ ('input_socket_index',
str(element.get_input_socket().get_index())),
+ ('output_signal_block_id',
str(element.get_output_socket().get_parent().get_id())),
+ ('output_socket_index',
str(element.get_output_socket().get_index()))
+ ]))
+ #print 'To',nested_data
+ return nested_data
+
+ def from_nested_data(self, nested_data):
+ ''' Set all the values in this flow graph using the nested
data. '''
+ #print 'From',nested_data
+ errors = ''
+ self.elements = list() #clear the elements
+ find_data = ParseXML.find_data
+ flow_graph = find_data([nested_data], 'flow_graph')
+ window_width = find_data(flow_graph, 'window_width')
+ window_height = find_data(flow_graph, 'window_height')
+ self.set_size_request(int(window_width),int(window_height))
+ vars = find_data(flow_graph, 'vars')
+ signal_blocks = find_data(flow_graph, 'signal_blocks')
+ connections = find_data(flow_graph, 'connections')
+ row_list = list()
+ for var in vars:
+ var = find_data([var], 'var')
+ row_list.append((
+
find_data(var, 'key'),
+
find_data(var, 'value'),
+
find_data(var, 'min'),
+
find_data(var, 'max'),
+
find_data(var, 'step'),
+ ))
+ self.variable_modification_window.from_row_list(row_list)
+ for signal_block in signal_blocks:
+ signal_block = find_data([signal_block], 'signal_block')
+ tag = find_data(signal_block, 'tag')
+ id = find_data(signal_block, 'id')
+ x_coordinate = int(find_data(signal_block,
'x_coordinate'))
+ y_coordinate = int(find_data(signal_block,
'y_coordinate'))
+ rotation = int(find_data(signal_block, 'rotation'))
+ params = find_data(signal_block, 'params')
+ try:
+ signal_block =
SignalBlockDefs.get_signal_block(self, (x_coordinate,y_coordinate), rotation,
tag, id)[0]
+ for i,param in enumerate(params):
+ try:
+ param = find_data([param],
'param')
+
signal_block.get_params()[i].get_data_type().set_data(param)
+ except: errors = errors + 'An invalid
parameter was parsed, ignoring parameter "%d" in block "%s".\n'%(i, id)
+ signal_block._adjust_sockets() #we have to
adjust now just in case the number of sockets changed from default
+ self.elements.append(signal_block)
+ except SignalBlockDefs.TagNotFoundException:
+ errors = errors + 'The definition for "%s" was
not found, ignoring block "%s".\n'%(tag, id)
+ for connection in connections:
+ connection = find_data([connection], 'connection')
+ input_signal_block_id = find_data(connection,
'input_signal_block_id')
+ input_socket_index = int(find_data(connection,
'input_socket_index'))
+ output_signal_block_id = find_data(connection,
'output_signal_block_id')
+ output_socket_index = int(find_data(connection,
'output_socket_index'))
+ input_socket = output_socket = None
+ for element in filter(is_signal_block, self.elements):
+ if element.get_id() == input_signal_block_id:
input_socket = element.get_input_socket(input_socket_index)
+ if element.get_id() == output_signal_block_id:
output_socket = element.get_output_socket(output_socket_index)
+ try: self.elements.append(Connection(self,
input_socket, output_socket))
+ except: errors = errors + 'Could not connect "%s"
input[%d] and "%s" output[%d].\n'%(input_signal_block_id, input_socket_index,
+
output_signal_block_id,
output_socket_index)
+ self.selected_element = None
+ self.update()
+ return errors
+
Copied: grc/branches/gtk_separation/src/Graphics/Windows/FlowGraphFileDialog.py
(from rev 5485, grc/branches/gtk_separation/src/Graphics/FlowGraphFileDialog.py)
===================================================================
--- grc/branches/gtk_separation/src/Graphics/Windows/FlowGraphFileDialog.py
(rev 0)
+++ grc/branches/gtk_separation/src/Graphics/Windows/FlowGraphFileDialog.py
2007-05-17 13:52:28 UTC (rev 5486)
@@ -0,0 +1,95 @@
+"""
+GNU Radio Companion is a graphical interface into the GNU Radio project.
+Copyright (C) 2007 Josh Blum
+
+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
+"""
+"""
+ Graphics/FlowGraphFileDialog.py
+ Josh Blum
+ The open/save dialog for flow graph files and screen shots
+"""
+
+import pygtk
+pygtk.require('2.0')
+import gtk
+from Constants import
DEFAULT_FILE_PATH,DEFAULT_FILE_EXTENSION,IMAGE_FILE_EXTENSION,NEW_FLOGRAPH_TITLE
+from os import path
+
+class FlowGraphFileDialog(gtk.FileChooserDialog):
+ """ A dialog box to save or open flow graph files. """
+
+ flow_graph_files_filter = gtk.FileFilter()
+ flow_graph_files_filter.set_name('FG Files')
+ flow_graph_files_filter.add_pattern('*'+DEFAULT_FILE_EXTENSION)
+
+ image_files_filter = gtk.FileFilter()
+ image_files_filter.set_name('Image Files')
+ image_files_filter.add_pattern('*'+IMAGE_FILE_EXTENSION)
+ #image_files_filter.add_pixbuf_formats()
+
+ all_files_filter = gtk.FileFilter()
+ all_files_filter.set_name('All Files')
+ all_files_filter.add_pattern('*')
+
+ def __init__(self, type, current_file_path):
+ """ Create a new gtk.FileChooserDialog, type can be ('open',
'save', or 'save image')
+ open and save are for flow graphs, save image is for
screenshots"""
+ if current_file_path == '': current_file_path =
DEFAULT_FILE_PATH+NEW_FLOGRAPH_TITLE+DEFAULT_FILE_EXTENSION
+ if type == 'open':
+ gtk.FileChooserDialog.__init__(self, 'Open a Flow Graph
from a File...', None,
+ gtk.FILE_CHOOSER_ACTION_OPEN,
('gtk-cancel',gtk.RESPONSE_CANCEL,'gtk-open',gtk.RESPONSE_OK))
+ self.add_filter(self.flow_graph_files_filter)
+ self.set_filter(self.flow_graph_files_filter)
+ self.add_filter(self.all_files_filter)
+ elif type == 'save':
+ gtk.FileChooserDialog.__init__(self, 'Save a Flow Graph
to a File...', None,
+ gtk.FILE_CHOOSER_ACTION_SAVE,
('gtk-cancel',gtk.RESPONSE_CANCEL, 'gtk-save',gtk.RESPONSE_OK))
+ #self.set_do_overwrite_confirmation(True) #enable this
when u get it working with auto-extension
+ self.add_filter(self.flow_graph_files_filter)
+ self.set_filter(self.flow_graph_files_filter)
+ self.add_filter(self.all_files_filter)
+ self.set_current_name(path.basename(current_file_path))
#show the current filename
+ elif type == 'save image':
+ gtk.FileChooserDialog.__init__(self, 'Save a Flow Graph
Screen Shot...', None,
+ gtk.FILE_CHOOSER_ACTION_SAVE,
('gtk-cancel',gtk.RESPONSE_CANCEL, 'gtk-save',gtk.RESPONSE_OK))
+ #self.set_do_overwrite_confirmation(True) #enable this
when u get it working with auto-extension
+ self.add_filter(self.image_files_filter)
+ self.set_filter(self.image_files_filter)
+ self.add_filter(self.all_files_filter)
+ current_file_path = current_file_path +
IMAGE_FILE_EXTENSION
+ self.set_current_name(path.basename(current_file_path))
#show the current filename
+ self.set_current_folder(path.dirname(current_file_path))
#current directory
+ #self.set_show_hidden(False) #doesnt seem to work ;-)
+ self.set_select_multiple(False)
+ self.set_local_only(True)
+
+ def get_filename(self):
+ """ retrieve the filename from the dialog, append the extension
if missing. """
+ filename = gtk.FileChooserDialog.get_filename(self)
+ if filename[len(filename)-len(DEFAULT_FILE_EXTENSION):] !=
DEFAULT_FILE_EXTENSION and\
+ self.flow_graph_files_filter == self.get_filter():
filename = filename + DEFAULT_FILE_EXTENSION
+ elif filename[len(filename)-len(IMAGE_FILE_EXTENSION):] !=
IMAGE_FILE_EXTENSION and\
+ self.image_files_filter == self.get_filter(): filename
= filename + IMAGE_FILE_EXTENSION
+ return filename
+
+ def run(self):
+ """ retrieve the filename from get_filename, None if a
close/cancel occured, and destroy the dialog. """
+ response = gtk.FileChooserDialog.run(self)
+ if response == gtk.RESPONSE_OK: filename = self.get_filename()
+ else: filename = None
+ self.destroy()
+ return filename
+
\ No newline at end of file
Copied: grc/branches/gtk_separation/src/Graphics/Windows/MainWindow.py (from
rev 5485, grc/branches/gtk_separation/src/Graphics/MainWindow.py)
===================================================================
--- grc/branches/gtk_separation/src/Graphics/Windows/MainWindow.py
(rev 0)
+++ grc/branches/gtk_separation/src/Graphics/Windows/MainWindow.py
2007-05-17 13:52:28 UTC (rev 5486)
@@ -0,0 +1,103 @@
+"""
+GNU Radio Companion is a graphical interface into the GNU Radio project.
+Copyright (C) 2007 Josh Blum
+
+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
+"""
+"""
+ Graphics/MainWindow.py
+ Josh Blum
+ The main window, containing all windows, tool bars, and menu bars.
+"""
+
+from Constants import *
+import pygtk
+pygtk.require('2.0')
+import gtk
+import Bars
+from FlowGraph import FlowGraph
+from SignalBlockSelectionWindow import SignalBlockSelectionWindow
+from VariableModificationWindow import VariableModificationWindow
+from Dialogs import TextDisplay
+
+class MainWindow(gtk.Window):
+ """ The main topmost window with menus and toolbars and flow graph
"""
+ def __init__(self, handle_states):
+ """ add menu bar, toolbar, and flowgraph """
+ self.handle_states = handle_states
+ gtk.Window.__init__(self, gtk.WINDOW_TOPLEVEL)
+ vbox = gtk.VBox()
+ hbox = gtk.HBox()
+ vbox.show()
+ hbox.show()
+ self.add(vbox)
+ self.set_title("")
+ #create the menu bar
+ menuBar = Bars.MenuBar()
+ menuBar.show()
+ vbox.pack_start(menuBar, False)
+ #create the toolbar
+ toolbar = Bars.Toolbar()
+ toolbar.show()
+ vbox.pack_start(toolbar, False)
+ # create variable modification window #
+ variable_modification_window =
VariableModificationWindow(self.handle_states)
+ # create a flow_graph #
+ self.flow_graph = FlowGraph(self.handle_states,
variable_modification_window)
+ #add the scrolled window for the flow graph
+ scrolled_window = gtk.ScrolledWindow()
+ scrolled_window.set_size_request(MIN_WINDOW_WIDTH,
MIN_WINDOW_HEIGHT)
+ scrolled_window.set_policy(gtk.POLICY_AUTOMATIC,
gtk.POLICY_AUTOMATIC)
+ scrolled_window.add_with_viewport(self.flow_graph)
+ scrolled_window.show()
+ fg_and_report_box = gtk.VBox()
+ fg_and_report_box.show()
+ fg_and_report_box.pack_start(scrolled_window)
+ hbox.pack_start(fg_and_report_box)
+ vbox.pack_start(hbox)
+ #create the side windows
+ side_box = gtk.VBox()
+ side_box.show()
+ hbox.pack_start(side_box, False)
+ side_box.pack_start(variable_modification_window, False)
#dont allow resize
+
side_box.pack_start(SignalBlockSelectionWindow(self.flow_graph)) #all resize,
selection window can have more space
+ #create the reports window
+ self.text_display = TextDisplay()
+ #house the reports in a scrolled window
+ self.reports_scrolled_window = gtk.ScrolledWindow()
+ self.reports_scrolled_window.set_size_request(-1,
REPORTS_WINDOW_HEIGHT)
+ self.reports_scrolled_window.set_policy(gtk.POLICY_AUTOMATIC,
gtk.POLICY_AUTOMATIC)
+
self.reports_scrolled_window.add_with_viewport(self.text_display)
+ self.show_reports_window(False) #hide the window by default
+ fg_and_report_box.pack_end(self.reports_scrolled_window, False)
#dont allow resize, fg should get all the space
+ #self.show()
+
+ def add_report_line(self, line):
+ """ place line plus a newline at the end of the text buffer,
then scroll its window all the way down. """
+ self.text_display.insert(line)
+ vadj = self.reports_scrolled_window.get_vadjustment()
+ vadj.set_value(vadj.upper)
+
+ def set_title(self, title):
+ """ set the title and prepend the program name """
+ prepend_str = MAIN_WINDOW_PREFIX + ' - '
+ gtk.Window.set_title(self, prepend_str + str(title))
+
+ def show_reports_window(self, show):
+ """ Show the reports window when show is True.
+ Hide the reports window when show is False. """
+ if show: self.reports_scrolled_window.show()
+ else: self.reports_scrolled_window.hide()
+
\ No newline at end of file
Copied:
grc/branches/gtk_separation/src/Graphics/Windows/SignalBlockParamsDialog.py
(from rev 5485,
grc/branches/gtk_separation/src/Graphics/SignalBlockParamsDialog.py)
===================================================================
--- grc/branches/gtk_separation/src/Graphics/Windows/SignalBlockParamsDialog.py
(rev 0)
+++ grc/branches/gtk_separation/src/Graphics/Windows/SignalBlockParamsDialog.py
2007-05-17 13:52:28 UTC (rev 5486)
@@ -0,0 +1,74 @@
+"""
+GNU Radio Companion is a graphical interface into the GNU Radio project.
+Copyright (C) 2007 Josh Blum
+
+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
+"""
+"""
+ Graphics/SignalBlockParamsDialog.py
+ Josh Blum
+ A dialog for editing a signal block's parameters.
+"""
+
+import pygtk
+pygtk.require('2.0')
+import gtk
+from Dialogs import TextDisplay
+from Constants import MIN_DIALOG_WIDTH,MIN_DIALOG_HEIGHT
+
+class SignalBlockParamsDialog(gtk.Dialog):
+ """ A dialog box to set signal block parameters such as sampling
rate and decimation values. """
+ def __init__(self, signal_block):
+ gtk.Dialog.__init__(self, buttons=('gtk-close',
gtk.RESPONSE_CLOSE))
+ self.signal_block = signal_block
+ self.set_title(signal_block.get_id()+' properties')
+ self.set_size_request(MIN_DIALOG_WIDTH, MIN_DIALOG_HEIGHT)
+ vbox = gtk.VBox()
+ vbox.show()
+ # Create the title label #
+ label = gtk.Label()
+ label.set_markup('<b>'+self.signal_block.get_id()+'
Parameters:</b>')
+ label.show()
+ self.vbox.pack_start(label, False)
+ # Create the scrolled window to hold all the parameters #
+ scrolled_window = gtk.ScrolledWindow()
+ scrolled_window.set_policy(gtk.POLICY_AUTOMATIC,
gtk.POLICY_AUTOMATIC)
+ scrolled_window.add_with_viewport(vbox)
+ scrolled_window.show()
+ self.vbox.pack_start(scrolled_window, True)
+ self.original_data = list()
+ # Add all the parameters #
+ for param in self.signal_block.get_params():
+
self.original_data.append(param.get_data_type().get_data())
+ vbox.pack_start(param.get_input_object(), False)
+ # Done adding parameters #
+ if self.signal_block.get_docs() != None:
+ # Create the title label #
+ label = gtk.Label()
+ label.set_markup('<b>'+self.signal_block.get_cname()+'
Documentation:</b>')
+ label.show()
+ self.vbox.pack_start(label, False)
+ # Create the text box to display notes about the
block #
+
self.vbox.pack_start(TextDisplay(self.signal_block.get_docs()), False)
+
+ def run(self):
+ ''' Call the parent class run and return True if a change
occured. '''
+ gtk.Dialog.run(self)
+ self.destroy()
+ self.data = list()
+ for param in self.signal_block.get_params():
+ self.data.append(param.get_data_type().get_data())
+ return self.original_data != self.data
+
\ No newline at end of file
Copied:
grc/branches/gtk_separation/src/Graphics/Windows/SignalBlockSelectionWindow.py
(from rev 5485,
grc/branches/gtk_separation/src/Graphics/SignalBlockSelectionWindow.py)
===================================================================
---
grc/branches/gtk_separation/src/Graphics/Windows/SignalBlockSelectionWindow.py
(rev 0)
+++
grc/branches/gtk_separation/src/Graphics/Windows/SignalBlockSelectionWindow.py
2007-05-17 13:52:28 UTC (rev 5486)
@@ -0,0 +1,99 @@
+"""
+GNU Radio Companion is a graphical interface into the GNU Radio project.
+Copyright (C) 2007 Josh Blum
+
+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
+"""
+"""
+ Graphics/SignalBlockSelectionWindow.py
+ Josh Blum
+ The signal block selection window.
+ Gives the user a tree selection to choose a signal block.
+"""
+
+from Constants import *
+import pygtk
+pygtk.require('2.0')
+import gtk
+import gobject
+import SignalBlockDefs
+
+class SignalBlockSelectionWindow(gtk.VBox):
+ """ The signal block selection window. """
+ def __init__(self, flow_graph):
+ """ Show all possible signal blocks in this dialog. Each
signal block is represented by a
+ gtk label of its CNAME and an add button. The add
button tells the flow graph to add the chosen block. """
+ gtk.VBox.__init__(self)
+ self.flow_graph = flow_graph
+ #title label
+ label = gtk.Label()
+ label.set_markup('<b>Signal Blocks</b>')
+ label.show()
+ self.pack_start(label, False)
+ # make the tree model for holding blocks #
+ self.model = gtk.TreeStore(gobject.TYPE_STRING)
+ self.treeview = gtk.TreeView(self.model)
+ self.treeview.set_enable_search(False) #disable pop up search
box
+ self.treeview.add_events(gtk.gdk.BUTTON_PRESS_MASK)
+ self.treeview.connect('button_press_event',
self.handle_button_press)
+ selection = self.treeview.get_selection()
+ selection.set_mode('single')
+ selection.connect('changed', self.handle_selection_change)
+ renderer = gtk.CellRendererText()
+ column = gtk.TreeViewColumn("Category", renderer, text=0)
+ self.treeview.append_column(column)
+ self.treeview.show()
+ # make the scrolled window to hold the tree view #
+ scrolled_window = gtk.ScrolledWindow()
+ scrolled_window.set_policy(gtk.POLICY_AUTOMATIC,
gtk.POLICY_AUTOMATIC)
+ scrolled_window.add_with_viewport(self.treeview)
+
scrolled_window.set_size_request(SIGNAL_BLOCK_SELECTION_WINDOW_WIDTH,
+
SIGNAL_BLOCK_SELECTION_WINDOW_HEIGHT)
+ scrolled_window.show()
+ self.pack_start(scrolled_window)
+ # add button #
+ self.add_button = gtk.Button(None, 'gtk-add')
+ self.add_button.connect('clicked', self.handle_add_button)
+ self.add_button.show()
+ self.pack_start(self.add_button, False)
+ # add blocks and categories #
+ for category, tags in SignalBlockDefs.TAGS:
+ iter = self.model.insert_before(None, None)
+ self.model.set_value(iter, 0, category)
+ for tag in tags:
+ new_iter = self.model.insert_before(iter, None)
+ self.model.set_value(new_iter, 0, tag[0])
+ self.handle_selection_change(None)
+ self.show()
+
+ def handle_button_press(self, widget, event):
+ ''' If a left double click is detected, let the handler for the
add button decide to add a block. '''
+ if event.button == 1 and event.type == gtk.gdk._2BUTTON_PRESS:
+ self.handle_add_button(widget)
+
+ def handle_selection_change(self, event):
+ ''' If a selection changes, set the add button sensitive.
'''
+ selection = self.treeview.get_selection()
+ model, iter = selection.get_selected()
+ if iter != None and not model.iter_has_child(iter):
self.add_button.set_sensitive(True)
+ else: self.add_button.set_sensitive(False)
+
+ def handle_add_button(self, widget):
+ """ add the signal block to the flow graph and redraw the
flow graph """
+ selection = self.treeview.get_selection()
+ model, iter = selection.get_selected()
+ if iter != None and not model.iter_has_child(iter):
self.flow_graph.add_signal_block(model.get_value(iter, 0))
+
+
\ No newline at end of file
Copied: grc/branches/gtk_separation/src/Graphics/Windows/USRPDiagnostics.py
(from rev 5485, grc/branches/gtk_separation/src/Graphics/USRPDiagnostics.py)
===================================================================
--- grc/branches/gtk_separation/src/Graphics/Windows/USRPDiagnostics.py
(rev 0)
+++ grc/branches/gtk_separation/src/Graphics/Windows/USRPDiagnostics.py
2007-05-17 13:52:28 UTC (rev 5486)
@@ -0,0 +1,95 @@
+"""
+GNU Radio Companion is a graphical interface into the GNU Radio project.
+Copyright (C) 2007 Josh Blum
+
+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
+"""
+"""
+ Graphics/USRPDiagnostics.py
+ Josh Blum
+ A dialog for querying USRP subdevices. USRP interfacing methods
encapsulated here.
+"""
+
+import pygtk
+pygtk.require('2.0')
+import gtk
+from Actions import USRP_DIAGNOSTICS_DISPLAY,get_action_from_name
+from Elements import Param
+from DataType import *
+from Dialogs import TextDisplay
+
+def enable_usrp_diagnostics():
+ """ Only enable the action for USRP diganostics if gnuradio.usrp
can be imported. """
+ try:
+ from gnuradio import usrp
+
get_action_from_name(USRP_DIAGNOSTICS_DISPLAY).set_sensitive(True)
+ except ImportError: print "USRP support missing -> USRP diagnostics
disabled..."
+
+class USRPDiagnosticsDialog(gtk.Dialog):
+ """ The main dialog window for USRP Dignostics.
+ The USRP parameters and feedback will be located inside this dialog.
"""
+ def __init__(self):
+ """ Create a new gtk Dialog with a close button, USRP input
paramaters, and output labels. """
+ gtk.Dialog.__init__(self, buttons=('gtk-close',
gtk.RESPONSE_CLOSE))
+ # Create the title label #
+ self.set_title('USRP Diagnostics')
+ self.USRP_number = Int(0, min=0)
+ self.USRP_type = Enum([('Receive', 'rx'), ('Transmit', 'tx'),])
+ self.USRP_subdev = Enum([('Side A:0', (0, 0)),
+
('Side B:0', (1, 0)),
+
('Side A:1', (0, 1)),
+
('Side B:1', (1, 1)),])
+ self.vbox.pack_start(Param('Unit Number',
self.USRP_number).get_input_object(), False)
+ self.vbox.pack_start(Param('Transmit/Receive',
self.USRP_type).get_input_object(), False)
+ self.vbox.pack_start(Param('Side:Subdevice',
self.USRP_subdev).get_input_object(), False)
+ self.diagnose_button = gtk.Button('Query')
+ self.diagnose_button.connect('clicked', self.diagnose_usrp)
+ self.diagnose_button.show()
+ self.vbox.pack_start(self.diagnose_button, False)
+ # Create a text box for USRP queries #
+ self.query_buffer = TextDisplay()
+ self.query_buffer.set_text('Press "Query" to retrieve USRP
information...')
+ self.vbox.pack_start(self.query_buffer)
+ self.run()
+ self.destroy()
+
+ def diagnose_usrp(self, widget=None):
+ """ Query the USRP device and append the results into the query
text box. """
+ from gnuradio import usrp
+ type = self.USRP_type.parse()
+ if type == 'rx': #for the rx query, use the source and
rx methods
+ make = usrp.source_c
+ get_mux = usrp.determine_rx_mux_value
+ elif type == 'tx': #for the tx query, use the sink and tx
methods
+ make = usrp.sink_c
+ get_mux = usrp.determine_tx_mux_value
+ try:
+ u = make(self.USRP_number.parse())
+ subdev_spec = self.USRP_subdev.parse()
+ subdev = usrp.selected_subdev(u, subdev_spec)#get the
subdev
+ msg = ">>> USRP Query\n"
+ msg = "%s\nName:\n\t%s\n"%(msg,str(subdev.name()))
+ msg = "%s\nAutomated Mux:\n\t0x%08x\n"%(msg,
0xFFFFFFFFL & long(get_mux(u, subdev_spec))) #ensure that the value is
displayed as: 8 nibbles, unsigned, hex
+ msg = "%s\nConverter
Rate:\n\t%s\n"%(msg,u.converter_rate())
+ msg = "%s\nUses Quadrature:\n\t%s\n"%(msg,
str(subdev.is_quadrature()))
+ gain_min, gain_max, gain_step = subdev.gain_range()
+ msg = "%s\nGain Range (min, max, step
size):\n\t%s\n\t%s\n\t%s\n"%(msg, gain_min, gain_max, gain_step)
+ freq_min, freq_max, freq_step = subdev.freq_range()
+ msg = "%s\nFreq Range (min, max, step
size):\n\t%s\n\t%s\n\t%s\n"%(msg, freq_min, freq_max, freq_step)
+ self.query_buffer.set_text(msg)
+ except Exception, e: #display the error message
+ self.query_buffer.set_text('>>> Error\n%s'%str(e))
+
+
\ No newline at end of file
Copied:
grc/branches/gtk_separation/src/Graphics/Windows/VariableModificationWindow.py
(from rev 5485,
grc/branches/gtk_separation/src/Graphics/VariableModificationWindow.py)
===================================================================
---
grc/branches/gtk_separation/src/Graphics/Windows/VariableModificationWindow.py
(rev 0)
+++
grc/branches/gtk_separation/src/Graphics/Windows/VariableModificationWindow.py
2007-05-17 13:52:28 UTC (rev 5486)
@@ -0,0 +1,176 @@
+"""
+GNU Radio Companion is a graphical interface into the GNU Radio project.
+Copyright (C) 2007 Josh Blum
+
+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
+"""
+"""
+ Graphics/VariableModificationWindow.py
+ Josh Blum
+ The variable modification window.
+ Allows the user to enter variables and slider information.
+"""
+
+from Constants import *
+from Actions import VARIABLE_MODIFY, NOTHING_SELECT
+import pygtk
+pygtk.require('2.0')
+import gtk
+import gobject
+import Variables
+
+class VariableModificationWindow(gtk.VBox):
+ ''' A scrollable window to add/remove variables in the variable
registry '''
+ def __init__(self, handle_states):
+ ''' create a scrolled window, and add buttons and lists '''
+ gtk.VBox.__init__(self)
+ self.handle_states = handle_states
+ #title label
+ label = gtk.Label()
+ label.set_markup('<b>Variables</b>')
+ label.show()
+ self.pack_start(label, False)
+ # create a srolled window to hold the vars #
+ scrolled_window = gtk.ScrolledWindow()
+ scrolled_window.show()
+ scrolled_window.set_policy(gtk.POLICY_AUTOMATIC,
gtk.POLICY_AUTOMATIC)
+
scrolled_window.set_size_request(VARIABLE_MODIFICATION_WINDOW_WIDTH,
+
VARIABLE_MODIFICATION_WINDOW_HEIGHT)
+ self.pack_start(scrolled_window)
+ # liststore hold the graphical list #
+ self.liststore = gtk.ListStore(
+ gobject.TYPE_STRING, #key
+ gobject.TYPE_STRING, #value
+ gobject.TYPE_STRING, #min
+ gobject.TYPE_STRING, #max
+ gobject.TYPE_STRING #step
+ )
+ self.treeview = gtk.TreeView(self.liststore)
+ self.treeview.set_enable_search(False) #disable pop up search
box
+ self.renderers = list()
+ for i,title in enumerate(['Variable', 'Default', 'Min', 'Max',
'Step']): #create each data column
+ renderer = gtk.CellRendererText()
+ renderer.set_property('editable', True)
+ renderer.connect('edited', self.handle_renderer_edited)
+ self.renderers.append(renderer)
+ tree_view_column = gtk.TreeViewColumn(title, renderer,
text=i)
+
tree_view_column.set_sizing(gtk.TREE_VIEW_COLUMN_AUTOSIZE) #allow the column to
shrink
+ self.treeview.append_column(tree_view_column)
+ self.treeview.set_reorderable(True)
+ selection = self.treeview.get_selection()
+ selection.set_mode('single')
+ selection.connect('changed', self.handle_selection_change)
+ self.treeview.show()
+ scrolled_window.add_with_viewport(self.treeview)
+ # buttons #
+ buttons_hbox = gtk.HBox()
+ buttons_hbox.show()
+ self.pack_start(buttons_hbox, False)
+ # add, edit, and remove buttons #
+ add_button = gtk.Button(None, 'gtk-add')
+ add_button.connect('clicked', self.handle_add_button)
+ add_button.show()
+ buttons_hbox.pack_start(add_button, False)
+ self.remove_button = gtk.Button(None, 'gtk-remove')
+ self.remove_button.connect('clicked', self.handle_remove_button)
+ self.remove_button.show()
+ buttons_hbox.pack_start(self.remove_button, False)
+ self.treeview.connect("cursor-changed",
self.handle_cursor_changed)
+ self.handle_selection_change()
+ self.show()
+
+ def unselect_all(self):
+ ''' Stop editing in each renderer and unselect every row in the
tree view. '''
+ for renderer in self.renderers: renderer.stop_editing(True)
+ self.treeview.get_selection().unselect_all()
+
+ def handle_cursor_changed(self, event=None):
+ ''' Called when the cursor is placed on a row or in a cell.
+ Unselect any selected element in the flow graph. '''
+ self.handle_states(NOTHING_SELECT)
+
+ def handle_selection_change(self, event=None):
+ ''' If a selection changes, set the edit and remove buttons
sensitive. '''
+ selection = self.treeview.get_selection()
+ model, iter = selection.get_selected()
+ if iter != None: self.remove_button.set_sensitive(True)
+ else: self.remove_button.set_sensitive(False)
+
+ def handle_renderer_edited(self, renderer, row_index, new_text):
+ ''' A cell was edited, determine what was edited and how to
handle it. '''
+ column_index = self.renderers.index(renderer)
+ if new_text == self.liststore[row_index][column_index]: return
#no change
+ old_list = self.liststore[row_index]
+ new_list = list()
+ for i,var in enumerate(old_list): #fill the new list
+ if i == column_index: new_list.append(new_text)
+ # blank the step to regenerate it, only if
min/max was changed to a non-blank #
+ elif new_text != '' and i == 4 and column_index in
(2,3): new_list.append('')
+ else: new_list.append(var)
+ Variables.unregister(old_list[0]) #use the key to remove the
entry
+ try: Variables.register(*new_list)
+ except Exception, e: #register failed, restore values and end
+ Variables.register(*old_list)
+ print e
+ return
+ #register succeeded, reload the values in the window
+ values = list(Variables.get_values(new_list[0]))
+ for i,value in enumerate([new_list[0]]+values):
+ self.liststore[row_index][i] = value
+ self.handle_states(VARIABLE_MODIFY)
+
+ def handle_remove_button(self, widget, data=None):
+ ''' Remove the selected element from the list and from the
VarReg. '''
+ selection = self.treeview.get_selection()
+ model, iter = selection.get_selected()
+ if iter != None:
+ Variables.unregister(model.get_value(iter, 0))
+ model.remove(iter)
+ self.handle_states(VARIABLE_MODIFY)
+
+ def handle_add_button(self, widget, data=None):
+ ''' Handle the add button by adding a variable with key and
value.
+ The key will be unique in the form 'new_var' + index.
'''
+ new_key_index = 0
+ while True:
+ new_key_name = 'new_var'+str(new_key_index)
+ if Variables.has_key(new_key_name):
+ new_key_index = new_key_index + 1
+ else:
+ var_info = (new_key_name, '0', '', '', '')
+ Variables.register(*var_info)
+ self.liststore.append(var_info)
+ self.handle_states(VARIABLE_MODIFY)
+ return
+
+ def to_row_list(self):
+ ''' Return a list of the keys in the current order.
'''
+ row_list = list()
+ for row in self.liststore: row_list.append(tuple(row))
+ return row_list
+
+ def from_row_list(self, row_list):
+ ''' Clear the rows and refill the list with keys from the list.
'''
+ Variables.clear_vars()
+ self.liststore.clear()
+ for row in row_list:
+ try: #try to register the var with min, max, step
+ Variables.register(*row)
+ self.liststore.append(row)
+ except: #otherwise just use the key and value
+ Variables.register(row[0], row[1], '', '', '')
+ self.liststore.append((row[0], row[1], '', '',
''))
+
+
\ No newline at end of file
Copied: grc/branches/gtk_separation/src/Graphics/Windows/__init__.py (from rev
5485, grc/branches/gtk_separation/src/Graphics/__init__.py)
===================================================================
--- grc/branches/gtk_separation/src/Graphics/Windows/__init__.py
(rev 0)
+++ grc/branches/gtk_separation/src/Graphics/Windows/__init__.py
2007-05-17 13:52:28 UTC (rev 5486)
@@ -0,0 +1,28 @@
+"""
+GNU Radio Companion is a graphical interface into the GNU Radio project.
+Copyright (C) 2007 Josh Blum
+
+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
+"""
+"""
+ Graphics/__init__.py
+ gtk based classes go into this package
+"""
+
+# only import the modules that need external access #
+from MainWindow import MainWindow
+from FlowGraphFileDialog import FlowGraphFileDialog
+from Dialogs import
PreferencesDialog,FlowGraphWindowSizeDialog,LooseChangesMessage,AboutDialog,DataTypeColorsDialog,HotKeysDialog
+from USRPDiagnostics import USRPDiagnosticsDialog,enable_usrp_diagnostics
Deleted: grc/branches/gtk_separation/src/Graphics/__init__.py
Deleted: grc/branches/gtk_separation/src/Messages.py
Deleted: grc/branches/gtk_separation/src/Preferences.py
Deleted: grc/branches/gtk_separation/src/StateCache.py
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- [Commit-gnuradio] r5486 - in grc/branches/gtk_separation/src: . Graphics Graphics/Windows,
jblum <=