summaryrefslogtreecommitdiff
path: root/grc/src/gui
diff options
context:
space:
mode:
authorjblum2009-05-01 20:28:04 +0000
committerjblum2009-05-01 20:28:04 +0000
commita3ba8cf268816af51c4bb39ea7ecd7e85ea0807b (patch)
tree21dbd446e92672a56b323e005088d3c03edc238f /grc/src/gui
parent6ce881caaacdd60a8bea37584c7286e08bea97a7 (diff)
downloadgnuradio-a3ba8cf268816af51c4bb39ea7ecd7e85ea0807b.tar.gz
gnuradio-a3ba8cf268816af51c4bb39ea7ecd7e85ea0807b.tar.bz2
gnuradio-a3ba8cf268816af51c4bb39ea7ecd7e85ea0807b.zip
Merged grc developer branch r10679:10938
Misc fixes and internal changes. Added help menu for usage tips. Added drag and drop for blocks. Removed callback controls, adopted forms. Any type can have enumerated options. git-svn-id: http://gnuradio.org/svn/gnuradio/trunk@10941 221aa14e-8319-0410-a670-987f0aec2ac5
Diffstat (limited to 'grc/src/gui')
-rw-r--r--grc/src/gui/ActionHandler.py77
-rw-r--r--grc/src/gui/Actions.py140
-rw-r--r--grc/src/gui/Bars.py12
-rw-r--r--grc/src/gui/BlockTreeWindow.py42
-rw-r--r--grc/src/gui/Constants.py23
-rw-r--r--grc/src/gui/Dialogs.py20
-rw-r--r--grc/src/gui/DrawingArea.py36
-rw-r--r--grc/src/gui/ParamsDialog.py8
8 files changed, 203 insertions, 155 deletions
diff --git a/grc/src/gui/ActionHandler.py b/grc/src/gui/ActionHandler.py
index 91dd0fb45..da0909a64 100644
--- a/grc/src/gui/ActionHandler.py
+++ b/grc/src/gui/ActionHandler.py
@@ -1,5 +1,5 @@
"""
-Copyright 2007 Free Software Foundation, Inc.
+Copyright 2007, 2008, 2009 Free Software Foundation, Inc.
This file is part of GNU Radio
GNU Radio Companion is free software; you can redistribute it and/or
@@ -19,7 +19,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
import os
import signal
-from Constants import DIR_LEFT, DIR_RIGHT, IMAGE_FILE_EXTENSION
+from Constants import IMAGE_FILE_EXTENSION
import Actions
import pygtk
pygtk.require('2.0')
@@ -32,7 +32,8 @@ from .. utils import ParseXML
import random
from .. platforms.gui.Platform import Platform
from MainWindow import MainWindow
-from Dialogs import AboutDialog
+from ParamsDialog import ParamsDialog
+import Dialogs
from FileDialogs import OpenFlowGraphFileDialog, SaveFlowGraphFileDialog, SaveImageFileDialog
gobject.threads_init()
@@ -57,7 +58,7 @@ class ActionHandler:
#setup the main window
self.main_window = MainWindow(self.handle_states, platform)
self.main_window.connect('delete_event', self._quit)
- self.main_window.connect('key_press_event', self._handle_key_press)
+ self.main_window.connect('key-press-event', self._handle_key_press)
self.get_page = self.main_window.get_page
self.get_flow_graph = self.main_window.get_flow_graph
self.get_focus_flag = self.main_window.drawing_area.get_focus_flag
@@ -72,32 +73,25 @@ class ActionHandler:
def _handle_key_press(self, widget, event):
"""
- Handle key presses from the keyboard and translate key combos into actions.
- This key press handler is called before the gtk accelerators kick in.
- This handler ensures that key presses without a mod mask,
- only pass to the accelerators if the flow graph is in focus.
- This function also handles keys that accelerators refuse to handle: left/right,
- and keys that are not registered with an accelerator: +/-.
- @return false to let the accelerators handle the key action
+ Handle key presses from the keyboard and translate key combinations into actions.
+ This key press handler is called prior to the gtk key press handler.
+ This handler bypasses built in accelerator key handling when in focus because
+ * some keys are ignored by the accelerators like the direction keys,
+ * some keys are not registered to any accelerators but are still used.
+ When not in focus, gtk and the accelerators handle the the key press.
+ @return false to let gtk handle the key action
"""
- if self.get_focus_flag():
- try:
- self.handle_states({
- 'Left': Actions.BLOCK_ROTATE_LEFT,
- 'Right': Actions.BLOCK_ROTATE_RIGHT,
- 'Up': Actions.BLOCK_DEC_TYPE,
- 'Down': Actions.BLOCK_INC_TYPE,
- 'equal': Actions.PORT_CONTROLLER_INC,
- 'plus': Actions.PORT_CONTROLLER_INC,
- 'KP_Add': Actions.PORT_CONTROLLER_INC,
- 'minus': Actions.PORT_CONTROLLER_DEC,
- 'KP_Subtract': Actions.PORT_CONTROLLER_DEC,
- }[gtk.gdk.keyval_name(event.keyval)])
- return True
- #focus: always return false for accelerator to handle
- except: return False
- #no focus: only allow accelerator to handle when a mod is used
- return not event.state
+ #dont allow key presses to queue up
+ if gtk.events_pending(): return True
+ #extract action name from this key press
+ key_name = gtk.gdk.keyval_name(event.keyval)
+ mod_mask = event.state
+ action_name = Actions.get_action_name_from_key_name(key_name, mod_mask)
+ #handle the action if flow graph is in focus
+ if action_name and self.get_focus_flag():
+ self.handle_states(action_name)
+ return True #handled by this method
+ return False #let gtk handle the key press
def _quit(self, window, event):
"""
@@ -138,7 +132,7 @@ class ActionHandler:
Actions.APPLICATION_QUIT, Actions.FLOW_GRAPH_NEW,
Actions.FLOW_GRAPH_OPEN, Actions.FLOW_GRAPH_SAVE_AS,
Actions.FLOW_GRAPH_CLOSE, Actions.ABOUT_WINDOW_DISPLAY,
- Actions.FLOW_GRAPH_SCREEN_CAPTURE,
+ Actions.FLOW_GRAPH_SCREEN_CAPTURE, Actions.HELP_WINDOW_DISPLAY,
): Actions.get_action_from_name(action).set_sensitive(True)
if not self.init_file_paths:
self.init_file_paths = Preferences.files_open()
@@ -193,13 +187,13 @@ class ActionHandler:
elif state == Actions.BLOCK_MOVE:
self.get_page().get_state_cache().save_new_state(self.get_flow_graph().export_data())
self.get_page().set_saved(False)
- elif state == Actions.BLOCK_ROTATE_LEFT:
- if self.get_flow_graph().rotate_selected(DIR_LEFT):
+ elif state == Actions.BLOCK_ROTATE_CCW:
+ if self.get_flow_graph().rotate_selected(90):
self.get_flow_graph().update()
self.get_page().get_state_cache().save_new_state(self.get_flow_graph().export_data())
self.get_page().set_saved(False)
- elif state == Actions.BLOCK_ROTATE_RIGHT:
- if self.get_flow_graph().rotate_selected(DIR_RIGHT):
+ elif state == Actions.BLOCK_ROTATE_CW:
+ if self.get_flow_graph().rotate_selected(-90):
self.get_flow_graph().update()
self.get_page().get_state_cache().save_new_state(self.get_flow_graph().export_data())
self.get_page().set_saved(False)
@@ -238,12 +232,15 @@ class ActionHandler:
# Window stuff
##################################################
elif state == Actions.ABOUT_WINDOW_DISPLAY:
- AboutDialog()
+ Dialogs.AboutDialog()
+ elif state == Actions.HELP_WINDOW_DISPLAY:
+ Dialogs.HelpDialog()
##################################################
# Param Modifications
##################################################
elif state == Actions.BLOCK_PARAM_MODIFY:
- if self.get_flow_graph().param_modify_selected():
+ selected_block = self.get_flow_graph().get_selected_block()
+ if selected_block and ParamsDialog(selected_block).run():
self.get_flow_graph().update()
self.get_page().get_state_cache().save_new_state(self.get_flow_graph().export_data())
self.get_page().set_saved(False)
@@ -296,7 +293,7 @@ class ActionHandler:
elif state == Actions.FLOW_GRAPH_SCREEN_CAPTURE:
file_path = SaveImageFileDialog(self.get_page().get_file_path()).run()
if file_path is not None:
- pixmap = self.get_flow_graph().get_drawing_area().pixmap
+ pixmap = self.get_flow_graph().get_pixmap()
width, height = pixmap.get_size()
pixbuf = gtk.gdk.Pixbuf(gtk.gdk.COLORSPACE_RGB, 0, 8, width, height)
pixbuf.get_from_drawable(pixmap, pixmap.get_colormap(), 0, 0, 0, 0, width, height)
@@ -333,8 +330,8 @@ class ActionHandler:
#update general buttons
Actions.get_action_from_name(Actions.ELEMENT_DELETE).set_sensitive(bool(self.get_flow_graph().get_selected_elements()))
Actions.get_action_from_name(Actions.BLOCK_PARAM_MODIFY).set_sensitive(bool(self.get_flow_graph().get_selected_block()))
- Actions.get_action_from_name(Actions.BLOCK_ROTATE_RIGHT).set_sensitive(bool(self.get_flow_graph().get_selected_blocks()))
- Actions.get_action_from_name(Actions.BLOCK_ROTATE_LEFT).set_sensitive(bool(self.get_flow_graph().get_selected_blocks()))
+ Actions.get_action_from_name(Actions.BLOCK_ROTATE_CCW).set_sensitive(bool(self.get_flow_graph().get_selected_blocks()))
+ Actions.get_action_from_name(Actions.BLOCK_ROTATE_CW).set_sensitive(bool(self.get_flow_graph().get_selected_blocks()))
#update cut/copy/paste
Actions.get_action_from_name(Actions.BLOCK_CUT).set_sensitive(bool(self.get_flow_graph().get_selected_blocks()))
Actions.get_action_from_name(Actions.BLOCK_COPY).set_sensitive(bool(self.get_flow_graph().get_selected_blocks()))
@@ -348,7 +345,7 @@ class ActionHandler:
Actions.get_action_from_name(Actions.FLOW_GRAPH_SAVE).set_sensitive(not self.get_page().get_saved())
self.main_window.update()
#draw the flow graph
- self.get_flow_graph().draw()
+ self.get_flow_graph().queue_draw()
def update_exec_stop(self):
"""
diff --git a/grc/src/gui/Actions.py b/grc/src/gui/Actions.py
index 16f12dd4c..9b687df7e 100644
--- a/grc/src/gui/Actions.py
+++ b/grc/src/gui/Actions.py
@@ -1,5 +1,5 @@
"""
-Copyright 2007 Free Software Foundation, Inc.
+Copyright 2007, 2008, 2009 Free Software Foundation, Inc.
This file is part of GNU Radio
GNU Radio Companion is free software; you can redistribute it and/or
@@ -28,8 +28,8 @@ APPLICATION_INITIALIZE = 'app init'
APPLICATION_QUIT = 'app quit'
PARAM_MODIFY = 'param modify'
BLOCK_MOVE = 'block move'
-BLOCK_ROTATE_LEFT = 'block rotate left'
-BLOCK_ROTATE_RIGHT = 'block rotate right'
+BLOCK_ROTATE_CCW = 'block rotate ccw'
+BLOCK_ROTATE_CW = 'block rotate cw'
BLOCK_PARAM_MODIFY = 'block param modify'
BLOCK_INC_TYPE = 'block increment type'
BLOCK_DEC_TYPE = 'block decrement type'
@@ -56,60 +56,85 @@ FLOW_GRAPH_EXEC = 'flow graph exec'
FLOW_GRAPH_KILL = 'flow graph kill'
FLOW_GRAPH_SCREEN_CAPTURE = 'flow graph screen capture'
ABOUT_WINDOW_DISPLAY = 'about window display'
+HELP_WINDOW_DISPLAY = 'help window display'
######################################################################################################
# Action Key Map
######################################################################################################
-_actions_key_map = {
- #action name: (key name, mask)
- FLOW_GRAPH_NEW: ('n', gtk.gdk.CONTROL_MASK),
- FLOW_GRAPH_OPEN: ('o', gtk.gdk.CONTROL_MASK),
- FLOW_GRAPH_SAVE: ('s', gtk.gdk.CONTROL_MASK),
- FLOW_GRAPH_CLOSE: ('w', gtk.gdk.CONTROL_MASK),
- APPLICATION_QUIT: ('q', gtk.gdk.CONTROL_MASK),
- FLOW_GRAPH_UNDO: ('z', gtk.gdk.CONTROL_MASK),
- FLOW_GRAPH_REDO: ('y', gtk.gdk.CONTROL_MASK),
- ELEMENT_DELETE: ('Delete', 0),
- BLOCK_ROTATE_LEFT: ('Left', 0),
- BLOCK_ROTATE_RIGHT: ('Right', 0),
- BLOCK_PARAM_MODIFY: ('Return', 0),
- BLOCK_ENABLE: ('e', 0),
- BLOCK_DISABLE: ('d', 0),
- BLOCK_CUT: ('x', gtk.gdk.CONTROL_MASK),
- BLOCK_COPY: ('c', gtk.gdk.CONTROL_MASK),
- BLOCK_PASTE: ('v', gtk.gdk.CONTROL_MASK),
- FLOW_GRAPH_GEN: ('F5', 0),
- FLOW_GRAPH_EXEC: ('F6', 0),
- FLOW_GRAPH_KILL: ('F7', 0),
- FLOW_GRAPH_SCREEN_CAPTURE: ('Print', 0),
-}
+_actions_key_list = (
+ #action name, key name, mod mask
+ (FLOW_GRAPH_NEW, 'n', gtk.gdk.CONTROL_MASK),
+ (FLOW_GRAPH_OPEN, 'o', gtk.gdk.CONTROL_MASK),
+ (FLOW_GRAPH_SAVE, 's', gtk.gdk.CONTROL_MASK),
+ (FLOW_GRAPH_SAVE_AS, 's', gtk.gdk.CONTROL_MASK | gtk.gdk.SHIFT_MASK),
+ (FLOW_GRAPH_CLOSE, 'w', gtk.gdk.CONTROL_MASK),
+ (APPLICATION_QUIT, 'q', gtk.gdk.CONTROL_MASK),
+ (FLOW_GRAPH_UNDO, 'z', gtk.gdk.CONTROL_MASK),
+ (FLOW_GRAPH_REDO, 'y', gtk.gdk.CONTROL_MASK),
+ (ELEMENT_DELETE, 'Delete', 0),
+ (BLOCK_ROTATE_CCW, 'Left', 0),
+ (BLOCK_ROTATE_CW, 'Right', 0),
+ (BLOCK_DEC_TYPE, 'Up', 0),
+ (BLOCK_INC_TYPE, 'Down', 0),
+ (BLOCK_PARAM_MODIFY, 'Return', 0),
+ (BLOCK_ENABLE, 'e', 0),
+ (BLOCK_DISABLE, 'd', 0),
+ (BLOCK_CUT, 'x', gtk.gdk.CONTROL_MASK),
+ (BLOCK_COPY, 'c', gtk.gdk.CONTROL_MASK),
+ (BLOCK_PASTE, 'v', gtk.gdk.CONTROL_MASK),
+ (FLOW_GRAPH_GEN, 'F5', 0),
+ (FLOW_GRAPH_EXEC, 'F6', 0),
+ (FLOW_GRAPH_KILL, 'F7', 0),
+ (FLOW_GRAPH_SCREEN_CAPTURE, 'Print', 0),
+ (HELP_WINDOW_DISPLAY, 'F1', 0),
+ #the following have no associated gtk.Action
+ (PORT_CONTROLLER_INC, 'equal', 0),
+ (PORT_CONTROLLER_INC, 'plus', 0),
+ (PORT_CONTROLLER_INC, 'KP_Add', 0),
+ (PORT_CONTROLLER_DEC, 'minus', 0),
+ (PORT_CONTROLLER_DEC, 'KP_Subtract', 0),
+)
+
+_actions_key_dict = dict(((key_name, mod_mask), action_name) for action_name, key_name, mod_mask in _actions_key_list)
+def get_action_name_from_key_name(key_name, mod_mask=0):
+ """
+ Get the action name associated with the key name and mask.
+ Both keyname and mask have to match.
+ @param key_name the name of the key
+ @param mod_mask the key press mask (shift, ctrl) 0 for none
+ @return the action name or blank string
+ """
+ key_name_mod_mask = (key_name, mod_mask)
+ if key_name_mod_mask in _actions_key_dict: return _actions_key_dict[key_name_mod_mask]
+ return ''
######################################################################################################
# Actions
######################################################################################################
_actions_list = (
- gtk.Action(FLOW_GRAPH_NEW, '_New', 'Create a new flow graph', 'gtk-new'),
- gtk.Action(FLOW_GRAPH_OPEN, '_Open', 'Open an existing flow graph', 'gtk-open'),
- gtk.Action(FLOW_GRAPH_SAVE, '_Save', 'Save the current flow graph', 'gtk-save'),
- gtk.Action(FLOW_GRAPH_SAVE_AS, 'Save _As', 'Save the current flow graph as...', 'gtk-save-as'),
- gtk.Action(FLOW_GRAPH_CLOSE, '_Close', 'Close the current flow graph', 'gtk-close'),
- gtk.Action(APPLICATION_QUIT, '_Quit', 'Quit program', 'gtk-quit'),
- gtk.Action(FLOW_GRAPH_UNDO, '_Undo', 'Undo a change to the flow graph', 'gtk-undo'),
- gtk.Action(FLOW_GRAPH_REDO, '_Redo', 'Redo a change to the flow graph', 'gtk-redo'),
- gtk.Action(ELEMENT_DELETE, '_Delete', 'Delete the selected blocks', 'gtk-delete'),
- gtk.Action(BLOCK_ROTATE_LEFT, 'Rotate _Left', 'Rotate the selected blocks 90 degrees', 'gtk-go-back'),
- gtk.Action(BLOCK_ROTATE_RIGHT, 'Rotate _Right', 'Rotate the selected blocks -90 degrees', 'gtk-go-forward'),
- gtk.Action(BLOCK_PARAM_MODIFY, '_Properties', 'Modify params for the selected block', 'gtk-properties'),
- gtk.Action(BLOCK_ENABLE, 'E_nable', 'Enable the selected blocks', 'gtk-connect'),
- gtk.Action(BLOCK_DISABLE, 'D_isable', 'Disable the selected blocks', 'gtk-disconnect'),
- gtk.Action(BLOCK_CUT, 'Cu_t', 'Cut', 'gtk-cut'),
- gtk.Action(BLOCK_COPY, '_Copy', 'Copy', 'gtk-copy'),
- gtk.Action(BLOCK_PASTE, '_Paste', 'Paste', 'gtk-paste'),
- gtk.Action(ABOUT_WINDOW_DISPLAY, '_About', 'About this program', 'gtk-about'),
- gtk.Action(FLOW_GRAPH_GEN, '_Generate', 'Generate the flow graph', 'gtk-convert'),
- gtk.Action(FLOW_GRAPH_EXEC, '_Execute', 'Execute the flow graph', 'gtk-execute'),
- gtk.Action(FLOW_GRAPH_KILL, '_Kill', 'Kill the flow graph', 'gtk-stop'),
- gtk.Action(FLOW_GRAPH_SCREEN_CAPTURE, 'S_creen Capture', 'Create a screen capture of the flow graph', 'gtk-print'),
+ gtk.Action(FLOW_GRAPH_NEW, '_New', 'Create a new flow graph', gtk.STOCK_NEW),
+ gtk.Action(FLOW_GRAPH_OPEN, '_Open', 'Open an existing flow graph', gtk.STOCK_OPEN),
+ gtk.Action(FLOW_GRAPH_SAVE, '_Save', 'Save the current flow graph', gtk.STOCK_SAVE),
+ gtk.Action(FLOW_GRAPH_SAVE_AS, 'Save _As', 'Save the current flow graph as...', gtk.STOCK_SAVE_AS),
+ gtk.Action(FLOW_GRAPH_CLOSE, '_Close', 'Close the current flow graph', gtk.STOCK_CLOSE),
+ gtk.Action(APPLICATION_QUIT, '_Quit', 'Quit program', gtk.STOCK_QUIT),
+ gtk.Action(FLOW_GRAPH_UNDO, '_Undo', 'Undo a change to the flow graph', gtk.STOCK_UNDO),
+ gtk.Action(FLOW_GRAPH_REDO, '_Redo', 'Redo a change to the flow graph', gtk.STOCK_REDO),
+ gtk.Action(ELEMENT_DELETE, '_Delete', 'Delete the selected blocks', gtk.STOCK_DELETE),
+ gtk.Action(BLOCK_ROTATE_CCW, 'Rotate Counterclockwise', 'Rotate the selected blocks 90 degrees to the left', gtk.STOCK_GO_BACK),
+ gtk.Action(BLOCK_ROTATE_CW, 'Rotate Clockwise', 'Rotate the selected blocks 90 degrees to the right', gtk.STOCK_GO_FORWARD),
+ gtk.Action(BLOCK_PARAM_MODIFY, '_Properties', 'Modify params for the selected block', gtk.STOCK_PROPERTIES),
+ gtk.Action(BLOCK_ENABLE, 'E_nable', 'Enable the selected blocks', gtk.STOCK_CONNECT),
+ gtk.Action(BLOCK_DISABLE, 'D_isable', 'Disable the selected blocks', gtk.STOCK_DISCONNECT),
+ gtk.Action(BLOCK_CUT, 'Cu_t', 'Cut', gtk.STOCK_CUT),
+ gtk.Action(BLOCK_COPY, '_Copy', 'Copy', gtk.STOCK_COPY),
+ gtk.Action(BLOCK_PASTE, '_Paste', 'Paste', gtk.STOCK_PASTE),
+ gtk.Action(ABOUT_WINDOW_DISPLAY, '_About', 'About this program', gtk.STOCK_ABOUT),
+ gtk.Action(HELP_WINDOW_DISPLAY, '_Help', 'Usage Tips', gtk.STOCK_HELP),
+ gtk.Action(FLOW_GRAPH_GEN, '_Generate', 'Generate the flow graph', gtk.STOCK_CONVERT),
+ gtk.Action(FLOW_GRAPH_EXEC, '_Execute', 'Execute the flow graph', gtk.STOCK_EXECUTE),
+ gtk.Action(FLOW_GRAPH_KILL, '_Kill', 'Kill the flow graph', gtk.STOCK_STOP),
+ gtk.Action(FLOW_GRAPH_SCREEN_CAPTURE, 'S_creen Capture', 'Create a screen capture of the flow graph', gtk.STOCK_PRINT),
)
def get_all_actions(): return _actions_list
@@ -122,16 +147,21 @@ def get_action_from_name(action_name):
@throw KeyError bad action name
@return a gtk action object
"""
- if _actions_dict.has_key(action_name): return _actions_dict[action_name]
+ if action_name in _actions_dict: return _actions_dict[action_name]
raise KeyError('Action Name: "%s" does not exist'%action_name)
+######################################################################################################
+# Accelerators
+######################################################################################################
_accel_group = gtk.AccelGroup()
def get_accel_group(): return _accel_group
-#load the actions key map
#set the accelerator group, and accelerator path
-#register the key and mod with the accelerator path
-for action_name, (key_name, mod) in _actions_key_map.iteritems():
- get_action_from_name(action_name).set_accel_group(get_accel_group())
- get_action_from_name(action_name).set_accel_path('<main>/'+action_name)
- gtk.accel_map_add_entry('<main>/'+action_name, gtk.gdk.keyval_from_name(key_name),mod)
+#register the key name and mod mask with the accelerator path
+for action_name, key_name, mod_mask in _actions_key_list:
+ try:
+ accel_path = '<main>/'+action_name
+ get_action_from_name(action_name).set_accel_group(get_accel_group())
+ get_action_from_name(action_name).set_accel_path(accel_path)
+ gtk.accel_map_add_entry(accel_path, gtk.gdk.keyval_from_name(key_name), mod_mask)
+ except KeyError: pass #no action was created for this action name
diff --git a/grc/src/gui/Bars.py b/grc/src/gui/Bars.py
index c89aea580..52e7ba1f8 100644
--- a/grc/src/gui/Bars.py
+++ b/grc/src/gui/Bars.py
@@ -1,5 +1,5 @@
"""
-Copyright 2007 Free Software Foundation, Inc.
+Copyright 2007, 2008, 2009 Free Software Foundation, Inc.
This file is part of GNU Radio
GNU Radio Companion is free software; you can redistribute it and/or
@@ -43,8 +43,8 @@ TOOLBAR_LIST = (
Actions.FLOW_GRAPH_EXEC,
Actions.FLOW_GRAPH_KILL,
None,
- Actions.BLOCK_ROTATE_LEFT,
- Actions.BLOCK_ROTATE_RIGHT,
+ Actions.BLOCK_ROTATE_CCW,
+ Actions.BLOCK_ROTATE_CW,
None,
Actions.BLOCK_ENABLE,
Actions.BLOCK_DISABLE,
@@ -73,8 +73,8 @@ MENU_BAR_LIST = (
Actions.BLOCK_PASTE,
Actions.ELEMENT_DELETE,
None,
- Actions.BLOCK_ROTATE_LEFT,
- Actions.BLOCK_ROTATE_RIGHT,
+ Actions.BLOCK_ROTATE_CCW,
+ Actions.BLOCK_ROTATE_CW,
None,
Actions.BLOCK_ENABLE,
Actions.BLOCK_DISABLE,
@@ -87,6 +87,8 @@ MENU_BAR_LIST = (
Actions.FLOW_GRAPH_KILL,
]),
(gtk.Action('Help', '_Help', None, None), [
+ Actions.HELP_WINDOW_DISPLAY,
+ None,
Actions.ABOUT_WINDOW_DISPLAY,
]),
)
diff --git a/grc/src/gui/BlockTreeWindow.py b/grc/src/gui/BlockTreeWindow.py
index 94b9476c5..9e4bec3f9 100644
--- a/grc/src/gui/BlockTreeWindow.py
+++ b/grc/src/gui/BlockTreeWindow.py
@@ -1,5 +1,5 @@
"""
-Copyright 2007 Free Software Foundation, Inc.
+Copyright 2007, 2008, 2009 Free Software Foundation, Inc.
This file is part of GNU Radio
GNU Radio Companion is free software; you can redistribute it and/or
@@ -17,7 +17,7 @@ along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
"""
-from Constants import DEFAULT_BLOCKS_WINDOW_WIDTH
+from Constants import DEFAULT_BLOCKS_WINDOW_WIDTH, DND_TARGETS
import pygtk
pygtk.require('2.0')
import gtk
@@ -53,6 +53,9 @@ class BlockTreeWindow(gtk.VBox):
renderer = gtk.CellRendererText()
column = gtk.TreeViewColumn('Blocks', renderer, text=NAME_INDEX)
self.treeview.append_column(column)
+ #setup drag and drop
+ self.treeview.enable_model_drag_source(gtk.gdk.BUTTON1_MASK, DND_TARGETS, gtk.gdk.ACTION_COPY)
+ self.treeview.connect('drag-data-get', self._handle_drag_get_data)
#make the scrolled window to hold the tree view
scrolled_window = gtk.ScrolledWindow()
scrolled_window.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
@@ -60,12 +63,11 @@ class BlockTreeWindow(gtk.VBox):
scrolled_window.set_size_request(DEFAULT_BLOCKS_WINDOW_WIDTH, -1)
self.pack_start(scrolled_window)
#add button
- self.add_button = gtk.Button(None, 'gtk-add')
+ self.add_button = gtk.Button(None, gtk.STOCK_ADD)
self.add_button.connect('clicked', self._handle_add_button)
self.pack_start(self.add_button, False)
- #map categories to iters
- self.categories = dict()
- self.categories[tuple()] = None
+ #map categories to iters, automatic mapping for root
+ self._categories = {tuple(): None}
#add blocks and categories
self.platform.load_block_tree(self)
#initialize
@@ -78,22 +80,21 @@ class BlockTreeWindow(gtk.VBox):
"""
Add a block with category to this selection window.
Add only the category when block is None.
- @param category the category string
+ @param category the category list
@param block the block object or None
"""
- #rectify category
- category = filter(lambda x: x, category.split('/'))
+ category = tuple(category)[1:] #tuple is hashable
#add category and all sub categories
- for i in range(len(category)):
- sub_category = tuple(category[:i+1])
- if sub_category not in self.categories.keys():
- iter = self.treestore.insert_before(self.categories[tuple(category[:i])], None)
- self.treestore.set_value(iter, NAME_INDEX, '[ %s ]'%category[i])
+ for i, cat_name in enumerate(category):
+ sub_category = category[:i+1]
+ if sub_category not in self._categories:
+ iter = self.treestore.insert_before(self._categories[sub_category[:-1]], None)
+ self.treestore.set_value(iter, NAME_INDEX, '[ %s ]'%cat_name)
self.treestore.set_value(iter, KEY_INDEX, '')
- self.categories[sub_category] = iter
+ self._categories[sub_category] = iter
#add block
if block is None: return
- iter = self.treestore.insert_before(self.categories[tuple(category)], None)
+ iter = self.treestore.insert_before(self._categories[category], None)
self.treestore.set_value(iter, NAME_INDEX, block.get_name())
self.treestore.set_value(iter, KEY_INDEX, block.get_key())
@@ -127,6 +128,15 @@ class BlockTreeWindow(gtk.VBox):
############################################################
## Event Handlers
############################################################
+ def _handle_drag_get_data(self, widget, drag_context, selection_data, info, time):
+ """
+ Handle a drag and drop by setting the key to the selection object.
+ This will call the destination handler for drag and drop.
+ Only call set when the key is valid to ignore DND from categories.
+ """
+ key = self._get_selected_block_key()
+ if key: selection_data.set(selection_data.target, 8, key)
+
def _handle_mouse_button_press(self, widget, event):
"""
Handle the mouse button press.
diff --git a/grc/src/gui/Constants.py b/grc/src/gui/Constants.py
index 70e6b6b6e..f23ab8b13 100644
--- a/grc/src/gui/Constants.py
+++ b/grc/src/gui/Constants.py
@@ -1,5 +1,5 @@
"""
-Copyright 2008 Free Software Foundation, Inc.
+Copyright 2008, 2009 Free Software Foundation, Inc.
This file is part of GNU Radio
GNU Radio Companion is free software; you can redistribute it and/or
@@ -17,6 +17,9 @@ along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
"""
+import pygtk
+pygtk.require('2.0')
+import gtk
import os
##default path for the open/save dialogs
@@ -28,10 +31,6 @@ IMAGE_FILE_EXTENSION = '.png'
##name for new/unsaved flow graphs
NEW_FLOGRAPH_TITLE = 'untitled'
-##rotation constants
-DIR_LEFT = 'left'
-DIR_RIGHT = 'right'
-
##main window constraints
MIN_WINDOW_WIDTH = 600
MIN_WINDOW_HEIGHT = 400
@@ -42,16 +41,8 @@ MIN_DIALOG_HEIGHT = 500
DEFAULT_BLOCKS_WINDOW_WIDTH = 100
DEFAULT_REPORTS_WINDOW_WIDTH = 100
-##How close can the mouse get to the window border before mouse events are ignored.
-BORDER_PROXIMITY_SENSITIVITY = 50
-##How close the mouse can get to the edge of the visible window before scrolling is invoked.
-SCROLL_PROXIMITY_SENSITIVITY = 30
-##When the window has to be scrolled, move it this distance in the required direction.
-SCROLL_DISTANCE = 15
-##The redrawing sensitivity, how many seconds must pass between motion events before a redraw?
-MOTION_DETECT_REDRAWING_SENSITIVITY = .02
-##How close the mouse click can be to a connection and register a connection select.
-CONNECTION_SELECT_SENSITIVITY = 5
-
##The size of the state saving cache in the flow graph (for undo/redo functionality)
STATE_CACHE_SIZE = 42
+
+##Shared targets for drag and drop of blocks
+DND_TARGETS = [('STRING', gtk.TARGET_SAME_APP, 0)]
diff --git a/grc/src/gui/Dialogs.py b/grc/src/gui/Dialogs.py
index e15f8c574..d526b97b4 100644
--- a/grc/src/gui/Dialogs.py
+++ b/grc/src/gui/Dialogs.py
@@ -1,5 +1,5 @@
"""
-Copyright 2008 Free Software Foundation, Inc.
+Copyright 2008, 2009 Free Software Foundation, Inc.
This file is part of GNU Radio
GNU Radio Companion is free software; you can redistribute it and/or
@@ -20,7 +20,6 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
import pygtk
pygtk.require('2.0')
import gtk
-from Constants import MIN_DIALOG_WIDTH, MIN_DIALOG_HEIGHT
from .. platforms.base.Constants import PACKAGE, VERSION
import Preferences
@@ -82,3 +81,20 @@ Achilleas Anastasopoulos -> trellis support
-----""")
self.run()
self.destroy()
+
+def HelpDialog():
+ MessageDialogHelper(
+ type=gtk.MESSAGE_INFO,
+ buttons=gtk.BUTTONS_CLOSE,
+ title='Help',
+ markup="""\
+<b>Usage Tips</b>
+
+<u>Add block</u>: drag and drop or double click a block in the block selection window.
+<u>Rotate block</u>: Select a block, press left/right on the keyboard.
+<u>Change type</u>: Select a block, press up/down on the keyboard.
+<u>Edit parameters</u>: double click on a block in the flow graph.
+<u>Make connection</u>: click on the source port of one block, then click on the sink port of another block.
+<u>Remove connection</u>: select the connection and press delete, or drag the connection.
+
+* See the menu for other keyboard shortcuts.""")
diff --git a/grc/src/gui/DrawingArea.py b/grc/src/gui/DrawingArea.py
index 3588e122d..5258979d8 100644
--- a/grc/src/gui/DrawingArea.py
+++ b/grc/src/gui/DrawingArea.py
@@ -1,5 +1,5 @@
"""
-Copyright 2007 Free Software Foundation, Inc.
+Copyright 2007, 2008, 2009 Free Software Foundation, Inc.
This file is part of GNU Radio
GNU Radio Companion is free software; you can redistribute it and/or
@@ -20,7 +20,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
import pygtk
pygtk.require('2.0')
import gtk
-from Constants import MIN_WINDOW_WIDTH, MIN_WINDOW_HEIGHT
+from Constants import MIN_WINDOW_WIDTH, MIN_WINDOW_HEIGHT, DND_TARGETS
class DrawingArea(gtk.DrawingArea):
"""
@@ -51,24 +51,26 @@ class DrawingArea(gtk.DrawingArea):
gtk.gdk.LEAVE_NOTIFY_MASK | \
gtk.gdk.ENTER_NOTIFY_MASK
)
+ #setup drag and drop
+ self.drag_dest_set(gtk.DEST_DEFAULT_ALL, DND_TARGETS, gtk.gdk.ACTION_COPY)
+ self.connect('drag-data-received', self._handle_drag_data_received)
#setup the focus flag
self._focus_flag = False
self.get_focus_flag = lambda: self._focus_flag
- self.connect("leave-notify-event", self._handle_focus_event, False)
- self.connect("enter-notify-event", self._handle_focus_event, True)
+ self.connect('leave-notify-event', self._handle_focus_event, False)
+ self.connect('enter-notify-event', self._handle_focus_event, True)
#pixmap for drawing
self.pixmap = None
- self.gc = None
-
- def draw(self):
- """
- Draw the pixmap onto this drawing area.
- """
- self.window.draw_drawable(self.gc, self.pixmap, 0, 0, 0, 0, -1, -1)
##########################################################################
## Handlers
##########################################################################
+ def _handle_drag_data_received(self, widget, drag_context, x, y, selection_data, info, time):
+ """
+ Handle a drag and drop by adding a block at the given coordinate.
+ """
+ self._main_window.get_flow_graph().add_new_block(selection_data.data, (x, y))
+
def _handle_focus_event(self, widget, event, focus_flag):
"""Record the focus state of the flow graph window."""
self._focus_flag = focus_flag
@@ -83,7 +85,6 @@ class DrawingArea(gtk.DrawingArea):
double_click=(event.type == gtk.gdk._2BUTTON_PRESS),
coordinate=(event.x, event.y),
)
- return True
def _handle_mouse_button_release(self, widget, event):
"""
@@ -94,7 +95,6 @@ class DrawingArea(gtk.DrawingArea):
left_click=(event.button == 1),
coordinate=(event.x, event.y),
)
- return True
def _handle_mouse_motion(self, widget, event):
"""
@@ -104,15 +104,15 @@ class DrawingArea(gtk.DrawingArea):
self._main_window.get_flow_graph().handle_mouse_motion(
coordinate=(event.x, event.y),
)
- return True
def _handle_window_expose(self, widget, event):
"""
- Called when the window initially appears or is resized: create a new pixmap, draw the flow graph.
+ Called when window is exposed, resized, or queue_draw is called.
"""
- self.gc = self.window.new_gc()
+ gc = self.window.new_gc()
width, height = self.get_size_request()
if not self.pixmap or (width, height) != self.pixmap.get_size():
self.pixmap = gtk.gdk.Pixmap(self.window, width, height, -1)
- self._main_window.get_flow_graph().draw()
- return True
+ #double buffering: draw to pixmap, then draw pixmap
+ self._main_window.get_flow_graph().draw(gc, self.pixmap)
+ self.window.draw_drawable(gc, self.pixmap, 0, 0, 0, 0, -1, -1)
diff --git a/grc/src/gui/ParamsDialog.py b/grc/src/gui/ParamsDialog.py
index 5837ab7c4..6cc42e8fc 100644
--- a/grc/src/gui/ParamsDialog.py
+++ b/grc/src/gui/ParamsDialog.py
@@ -1,5 +1,5 @@
"""
-Copyright 2007 Free Software Foundation, Inc.
+Copyright 2007, 2008, 2009 Free Software Foundation, Inc.
This file is part of GNU Radio
GNU Radio Companion is free software; you can redistribute it and/or
@@ -45,9 +45,11 @@ class ParamsDialog(gtk.Dialog):
SignalBlockParamsDialog contructor.
@param block the signal block
"""
- gtk.Dialog.__init__(self, buttons=('gtk-close', gtk.RESPONSE_CLOSE))
+ gtk.Dialog.__init__(self,
+ title='Properties: %s'%block.get_name(),
+ buttons=(gtk.STOCK_CLOSE, gtk.RESPONSE_CLOSE),
+ )
self.block = block
- self.set_title('Properties: %s'%block.get_name())
self.set_size_request(MIN_DIALOG_WIDTH, MIN_DIALOG_HEIGHT)
vbox = gtk.VBox()
#Add the title label