summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSeth Hitefield <sdhitefield@gmail.com>2017-05-03 07:06:54 -0700
committerJohnathan Corgan <johnathan@corganlabs.com>2017-05-03 07:07:59 -0700
commit486e0a9d06e43f3b8669471bef13a5eeedbda4c6 (patch)
tree7d35c5e7fd530f7ff420b9d3bb77ff5fc9fb2ecf
parent97b842874193394285ca4cdc11da381647c285fd (diff)
grc: gtk3: Converted actions to Gio.Action instead of Gtk.Action
-rw-r--r--grc/core/Block.py2
-rw-r--r--grc/core/ParseXML.py2
-rw-r--r--grc/core/utils/expr_utils.py3
-rw-r--r--grc/gui/Actions.py633
-rw-r--r--grc/gui/Application.py281
-rw-r--r--grc/gui/Bars.py519
-rw-r--r--grc/gui/Config.py2
-rw-r--r--grc/gui/Console.py6
-rw-r--r--grc/gui/DrawingArea.py44
-rw-r--r--grc/gui/MainWindow.py25
-rw-r--r--grc/gui/Notebook.py44
-rw-r--r--grc/gui/ParamWidgets.py2
-rw-r--r--grc/gui/StateCache.py4
-rw-r--r--grc/gui/Utils.py6
-rw-r--r--grc/gui/VariableEditor.py4
-rw-r--r--grc/gui/canvas/param.py2
-rwxr-xr-xgrc/main.py16
17 files changed, 889 insertions, 706 deletions
diff --git a/grc/core/Block.py b/grc/core/Block.py
index 8350828092..087815b941 100644
--- a/grc/core/Block.py
+++ b/grc/core/Block.py
@@ -403,7 +403,7 @@ class Block(Element):
return itertools.chain(self.active_sources, self.active_sinks)
def get_children(self):
- return self.get_ports() + self.params.values()
+ return self.get_ports() + list(self.params.values())
def get_children_gui(self):
return self.get_ports_gui() + self.params.values()
diff --git a/grc/core/ParseXML.py b/grc/core/ParseXML.py
index 163289ba06..430ba5b474 100644
--- a/grc/core/ParseXML.py
+++ b/grc/core/ParseXML.py
@@ -156,7 +156,7 @@ def to_file(nested_data, xml_file):
), xml_declaration=True, pretty_print=True, encoding='utf-8')
xml_data += etree.tostring(_to_file(nested_data)[0],
pretty_print=True, encoding='utf-8')
- with open(xml_file, 'w') as fp:
+ with open(xml_file, 'wb') as fp:
fp.write(xml_data)
diff --git a/grc/core/utils/expr_utils.py b/grc/core/utils/expr_utils.py
index 555bd709b1..cc03e9cb1c 100644
--- a/grc/core/utils/expr_utils.py
+++ b/grc/core/utils/expr_utils.py
@@ -23,7 +23,7 @@ import string
import six
-VAR_CHARS = string.letters + string.digits + '_'
+VAR_CHARS = string.ascii_letters + string.digits + '_'
class graph(object):
@@ -194,4 +194,3 @@ def sort_objects(objects, get_id, get_expr):
sorted_ids = sort_variables(id2expr)
# Return list of sorted objects
return [id2obj[id] for id in sorted_ids]
-
diff --git a/grc/gui/Actions.py b/grc/gui/Actions.py
index 97162065a6..d214f28049 100644
--- a/grc/gui/Actions.py
+++ b/grc/gui/Actions.py
@@ -20,286 +20,323 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
from __future__ import absolute_import
import six
+import logging
-from gi.repository import Gtk, Gdk, GObject
+from gi.repository import Gtk, Gdk, Gio, GLib, GObject
-NO_MODS_MASK = 0
+log = logging.getLogger(__name__)
-########################################################################
-# Actions API
-########################################################################
-_actions_keypress_dict = dict()
-_keymap = Gdk.Keymap.get_default()
-_used_mods_mask = NO_MODS_MASK
-
-
-def handle_key_press(event):
- """
- Call the action associated with the key press event.
- Both the key value and the mask must have a match.
-
- Args:
- event: a gtk key press event
-
- Returns:
- true if handled
- """
- # extract the key value and the consumed modifiers
- _unused, keyval, egroup, level, consumed = _keymap.translate_keyboard_state(
- event.hardware_keycode, event.get_state(), event.group)
- # get the modifier mask and ignore irrelevant modifiers
- mod_mask = event.get_state() & ~consumed & _used_mods_mask
- # look up the keypress and call the action
- try:
- _actions_keypress_dict[(keyval, mod_mask)]()
- except KeyError:
- return False # not handled
- else:
- return True # handled here
-
-_all_actions_list = list()
-
-
-def get_all_actions():
- return _all_actions_list
-
-_accel_group = Gtk.AccelGroup()
-
-
-def get_accel_group():
- return _accel_group
-
-
-class _ActionBase(object):
- """
- Base class for Action and ToggleAction
- Register actions and keypresses with this module.
- """
- def __init__(self, label, keypresses):
- global _used_mods_mask
-
- _all_actions_list.append(self)
- for i in range(len(keypresses)/2):
- keyval, mod_mask = keypresses[i*2:(i+1)*2]
- # register this keypress
- if (keyval, mod_mask) in _actions_keypress_dict:
- raise KeyError('keyval/mod_mask pair already registered "%s"' % str((keyval, mod_mask)))
- _actions_keypress_dict[(keyval, mod_mask)] = self
- _used_mods_mask |= mod_mask
- # set the accelerator group, and accelerator path
- # register the key name and mod mask with the accelerator path
- if label is None:
- continue # dont register accel
- accel_path = '<main>/' + self.get_name()
- self.set_accel_group(get_accel_group())
- self.set_accel_path(accel_path)
- Gtk.AccelMap.add_entry(accel_path, keyval, mod_mask)
- self.args = None
+
+def filter_from_dict(vars):
+ return filter(lambda x: isinstance(x[1], Action), vars.items())
+
+
+class Namespace(object):
+
+ def __init__(self):
+ self._actions = {}
+
+ def add(self, action):
+ key = action.props.name
+ self._actions[key] = action
+
+ def connect(self, name, handler):
+ #log.debug("Connecting action <{}> to handler <{}>".format(name, handler.__name__))
+ self._actions[name].connect('activate', handler)
+
+ def register(self, name, parameter=None, handler=None, label=None, tooltip=None,
+ icon_name=None, keypresses=None, preference_name=None, default=None):
+ # Check types
+ if not isinstance(name, str):
+ raise TypeError("Cannot register fuction: 'name' must be a str")
+ if parameter and not isinstance(parameter, str):
+ raise TypeError("Cannot register fuction: 'parameter' must be a str")
+ if handler and not callable(handler):
+ raise TypeError("Cannot register fuction: 'handler' must be callable")
+
+ # Check if the name has a prefix.
+ prefix = None
+ if name.startswith("app.") or name.startswith("win."):
+ # Set a prefix for later and remove it
+ prefix = name[0:3]
+ name = name[4:]
+
+ if handler:
+ log.debug("Register action [{}, prefix={}, param={}, handler={}]".format(
+ name, prefix, parameter, handler.__name__))
+ else:
+ log.debug("Register action [{}, prefix={}, param={}, handler=None]".format(
+ name, prefix, parameter))
+
+ action = Action(name, parameter, label=label, tooltip=tooltip,
+ icon_name=icon_name, keypresses=keypresses, prefix=prefix,
+ preference_name=preference_name, default=default)
+ if handler:
+ action.connect('activate', handler)
+
+ key = name
+ if prefix:
+ key = "{}.{}".format(prefix, name)
+ if prefix == "app":
+ pass
+ #self.app.add_action(action)
+ elif prefix == "win":
+ pass
+ #self.win.add_action(action)
+
+ #log.debug("Registering action as '{}'".format(key))
+ self._actions[key] = action
+ return action
+
+
+ # If the actions namespace is called, trigger an action
+ def __call__(self, name):
+ # Try to parse the action string.
+ valid, action_name, target_value = Action.parse_detailed_name(name)
+ if not valid:
+ raise Exception("Invalid action string: '{}'".format(name))
+ if action_name not in self._actions:
+ raise Exception("Action '{}' is not registered!".format(action_name))
+
+ if target_value:
+ self._actions[action_name].activate(target_value)
+ else:
+ self._actions[action_name].activate()
+
+ def __getitem__(self, key):
+ return self._actions[key]
+
+ def __iter__(self):
+ return self._actions.itervalues()
+
+ def __repr__(self):
+ return str(self)
+
+ def get_actions(self):
+ return self._actions
def __str__(self):
- """
- The string representation should be the name of the action id.
- Try to find the action id for this action by searching this module.
- """
- for name, value in six.iteritems(globals()):
- if value == self:
- return name
- return self.get_name()
-
- def __repr__(self): return str(self)
-
- def __call__(self, *args):
- """
- Emit the activate signal when called with ().
- """
- self.args = args
- self.emit('activate')
-
-
-class Action(Gtk.Action, _ActionBase):
- """
- A custom Action class based on Gtk.Action.
- Pass additional arguments such as keypresses.
- """
-
- def __init__(self, keypresses=(), name=None, label=None, tooltip=None,
- stock_id=None):
- """
- Create a new Action instance.
-
- Args:
- key_presses: a tuple of (keyval1, mod_mask1, keyval2, mod_mask2, ...)
- the: regular Gtk.Action parameters (defaults to None)
- """
- if name is None:
- name = label
- GObject.GObject.__init__(self, name=name, label=label, tooltip=tooltip,
- stock_id=stock_id)
- _ActionBase.__init__(self, label, keypresses)
-
-
-class ToggleAction(Gtk.ToggleAction, _ActionBase):
- """
- A custom Action class based on Gtk.ToggleAction.
- Pass additional arguments such as keypresses.
- """
-
- def __init__(self, keypresses=(), name=None, label=None, tooltip=None,
- stock_id=None, preference_name=None, default=True):
- """
- Create a new ToggleAction instance.
-
- Args:
- key_presses: a tuple of (keyval1, mod_mask1, keyval2, mod_mask2, ...)
- the: regular Gtk.Action parameters (defaults to None)
- """
- if name is None:
- name = label
- GObject.GObject.__init__(self, name=name, label=label,
- tooltip=tooltip, stock_id=stock_id)
- _ActionBase.__init__(self, label, keypresses)
+ s = "{Actions:"
+ for key in self._actions:
+ s += " {},".format(key)
+ s = s.rstrip(",") + "}"
+ return s
+
+
+class Action(Gio.SimpleAction):
+
+ # Change these to normal python properties.
+ #prefs_name
+
+ def __init__(self, name, parameter=None, label=None, tooltip=None,
+ icon_name=None, keypresses=None, prefix=None,
+ preference_name=None, default=None):
+ self.name = name
+ self.label = label
+ self.tooltip = tooltip
+ self.icon_name = icon_name
+ self.keypresses = keypresses
+ self.prefix = prefix
self.preference_name = preference_name
self.default = default
- def load_from_preferences(self):
+ # Don't worry about checking types here, since it's done in register()
+ # Save the parameter type to use for converting in __call__
+ self.type = None
+
+ variant = None
+ state = None
+ if parameter:
+ variant = GLib.VariantType.new(parameter)
+ if preference_name:
+ state = GLib.Variant.new_boolean(True)
+ Gio.SimpleAction.__init__(self, name=name, parameter_type=variant, state=state)
+
+ def enable(self):
+ self.props.enabled = True
+
+ def disable(self):
+ self.props.enabled = False
+
+ def set_enabled(self, state):
+ if not isinstance(state, bool):
+ raise TypeError("State must be True/False.")
+ self.props.enabled = state
+
+ def __str__(self):
+ return self.props.name
+
+ def __repr__(self):
+ return str(self)
+
+ def get_active(self):
+ if self.props.state:
+ return self.props.state.get_boolean()
+ return False
+
+ def set_active(self, state):
+ if not isinstance(state, bool):
+ raise TypeError("State must be True/False.")
+ self.change_state(GLib.Variant.new_boolean(state))
+
+ # Allows actions to be directly called.
+ def __call__(self, parameter=None):
+ if self.type and parameter:
+ # Try to convert it to the correct type.
+ try:
+ param = GLib.Variant(self.type, parameter)
+ self.activate(param)
+ except TypeError:
+ raise TypeError("Invalid parameter type for action '{}'. Expected: '{}'".format(self.get_name(), self.type))
+ else:
+ self.activate()
+
+ def load_from_preferences(self, *args):
+ log.debug("load_from_preferences({})".format(args))
if self.preference_name is not None:
config = Gtk.Application.get_default().config
- self.set_active(config.entry(
- self.preference_name, default=bool(self.default)))
+ self.set_active(config.entry(self.preference_name, default=bool(self.default)))
- def save_to_preferences(self):
+ def save_to_preferences(self, *args):
+ log.debug("save_to_preferences({})".format(args))
if self.preference_name is not None:
config = Gtk.Application.get_default().config
config.entry(self.preference_name, value=self.get_active())
+
+actions = Namespace()
+
+
+def get_actions():
+ return actions.get_actions()
+
+
+def connect(action, handler=None):
+ return actions.connect(action, handler=handler)
+
+
########################################################################
-# Actions
+# Old Actions
########################################################################
-PAGE_CHANGE = Action()
-EXTERNAL_UPDATE = Action()
-VARIABLE_EDITOR_UPDATE = Action()
-FLOW_GRAPH_NEW = Action(
+PAGE_CHANGE = actions.register("win.page_change")
+EXTERNAL_UPDATE = actions.register("app.external_update")
+VARIABLE_EDITOR_UPDATE = actions.register("app.variable_editor_update")
+FLOW_GRAPH_NEW = actions.register("app.flowgraph.new",
label='_New',
tooltip='Create a new flow graph',
- stock_id=Gtk.STOCK_NEW,
- keypresses=(Gdk.KEY_n, Gdk.ModifierType.CONTROL_MASK),
+ icon_name='document-new',
+ keypresses=["<Ctrl>n"],
+ parameter="s",
)
-FLOW_GRAPH_OPEN = Action(
+FLOW_GRAPH_OPEN = actions.register("app.flowgraph.open",
label='_Open',
tooltip='Open an existing flow graph',
- stock_id=Gtk.STOCK_OPEN,
- keypresses=(Gdk.KEY_o, Gdk.ModifierType.CONTROL_MASK),
+ icon_name='document-open',
+ keypresses=["<Ctrl>o"],
)
-FLOW_GRAPH_OPEN_RECENT = Action(
+FLOW_GRAPH_OPEN_RECENT = actions.register("app.flowgraph.open_recent",
label='Open _Recent',
tooltip='Open a recently used flow graph',
- stock_id=Gtk.STOCK_OPEN,
+ icon_name='document-open-recent',
+ parameter="s",
)
-FLOW_GRAPH_SAVE = Action(
+FLOW_GRAPH_CLEAR_RECENT = actions.register("app.flowgraph.clear_recent")
+FLOW_GRAPH_SAVE = actions.register("app.flowgraph.save",
label='_Save',
tooltip='Save the current flow graph',
- stock_id=Gtk.STOCK_SAVE,
- keypresses=(Gdk.KEY_s, Gdk.ModifierType.CONTROL_MASK),
+ icon_name='document-save',
+ keypresses=["<Ctrl>s"],
)
-FLOW_GRAPH_SAVE_AS = Action(
+FLOW_GRAPH_SAVE_AS = actions.register("app.flowgraph.save_as",
label='Save _As',
tooltip='Save the current flow graph as...',
- stock_id=Gtk.STOCK_SAVE_AS,
- keypresses=(Gdk.KEY_s, Gdk.ModifierType.CONTROL_MASK | Gdk.ModifierType.SHIFT_MASK),
+ icon_name='document-save-as',
+ keypresses=["<Ctrl><Shift>s"],
)
-FLOW_GRAPH_SAVE_A_COPY = Action(
- label='Save A Copy',
- tooltip='Save the copy of current flow graph',
+FLOW_GRAPH_SAVE_COPY = actions.register("app.flowgraph.save_copy",
+ label='Save Copy',
+ tooltip='Save a copy of current flow graph',
)
-FLOW_GRAPH_DUPLICATE = Action(
+FLOW_GRAPH_DUPLICATE = actions.register("app.flowgraph.duplicate",
label='_Duplicate',
tooltip='Create a duplicate of current flow graph',
- stock_id=Gtk.STOCK_COPY,
- keypresses=(Gdk.KEY_d, Gdk.ModifierType.CONTROL_MASK | Gdk.ModifierType.SHIFT_MASK),
+ #stock_id=Gtk.STOCK_COPY,
+ keypresses=["<Ctrl><Shift>d"],
)
-FLOW_GRAPH_CLOSE = Action(
+FLOW_GRAPH_CLOSE = actions.register("app.flowgraph.close",
label='_Close',
tooltip='Close the current flow graph',
- stock_id=Gtk.STOCK_CLOSE,
- keypresses=(Gdk.KEY_w, Gdk.ModifierType.CONTROL_MASK),
+ icon_name='window-close',
+ keypresses=["<Ctrl>w"],
)
-APPLICATION_INITIALIZE = Action()
-APPLICATION_QUIT = Action(
+APPLICATION_INITIALIZE = actions.register("app.initialize")
+APPLICATION_QUIT = actions.register("app.quit",
label='_Quit',
tooltip='Quit program',
- stock_id=Gtk.STOCK_QUIT,
- keypresses=(Gdk.KEY_q, Gdk.ModifierType.CONTROL_MASK),
+ icon_name='application-exit',
+ keypresses=["<Ctrl>q"],
)
-FLOW_GRAPH_UNDO = Action(
+FLOW_GRAPH_UNDO = actions.register("win.undo",
label='_Undo',
tooltip='Undo a change to the flow graph',
- stock_id=Gtk.STOCK_UNDO,
- keypresses=(Gdk.KEY_z, Gdk.ModifierType.CONTROL_MASK),
+ icon_name='edit-undo',
+ keypresses=["<Ctrl>z"],
)
-FLOW_GRAPH_REDO = Action(
+FLOW_GRAPH_REDO = actions.register("win.redo",
label='_Redo',
tooltip='Redo a change to the flow graph',
- stock_id=Gtk.STOCK_REDO,
- keypresses=(Gdk.KEY_y, Gdk.ModifierType.CONTROL_MASK),
+ icon_name='edit-redo',
+ keypresses=["<Ctrl>y"],
)
-NOTHING_SELECT = Action()
-SELECT_ALL = Action(
+NOTHING_SELECT = actions.register("win.unselect")
+SELECT_ALL = actions.register("win.select_all",
label='Select _All',
tooltip='Select all blocks and connections in the flow graph',
- stock_id=Gtk.STOCK_SELECT_ALL,
- keypresses=(Gdk.KEY_a, Gdk.ModifierType.CONTROL_MASK),
+ icon_name='edit-select-all',
+ keypresses=["<Ctrl>a"],
)
-ELEMENT_SELECT = Action()
-ELEMENT_CREATE = Action()
-ELEMENT_DELETE = Action(
+ELEMENT_SELECT = actions.register("win.select")
+ELEMENT_CREATE = actions.register("win.add")
+ELEMENT_DELETE = actions.register("win.delete",
label='_Delete',
tooltip='Delete the selected blocks',
- stock_id=Gtk.STOCK_DELETE,
- keypresses=(Gdk.KEY_Delete, NO_MODS_MASK),
+ icon_name='edit-delete',
)
-BLOCK_MOVE = Action()
-BLOCK_ROTATE_CCW = Action(
+BLOCK_MOVE = actions.register("win.block_move")
+BLOCK_ROTATE_CCW = actions.register("win.block_rotate_ccw",
label='Rotate Counterclockwise',
tooltip='Rotate the selected blocks 90 degrees to the left',
- stock_id=Gtk.STOCK_GO_BACK,
- keypresses=(Gdk.KEY_Left, NO_MODS_MASK),
+ icon_name='object-rotate-left',
)
-BLOCK_ROTATE_CW = Action(
+BLOCK_ROTATE_CW = actions.register("win.block_rotate",
label='Rotate Clockwise',
tooltip='Rotate the selected blocks 90 degrees to the right',
- stock_id=Gtk.STOCK_GO_FORWARD,
- keypresses=(Gdk.KEY_Right, NO_MODS_MASK),
+ icon_name='object-rotate-right',
)
-BLOCK_VALIGN_TOP = Action(
+BLOCK_VALIGN_TOP = actions.register("win.block_align_top",
label='Vertical Align Top',
tooltip='Align tops of selected blocks',
- keypresses=(Gdk.KEY_t, Gdk.ModifierType.SHIFT_MASK),
)
-BLOCK_VALIGN_MIDDLE = Action(
+BLOCK_VALIGN_MIDDLE = actions.register("win.block_align_middle",
label='Vertical Align Middle',
tooltip='Align centers of selected blocks vertically',
- keypresses=(Gdk.KEY_m, Gdk.ModifierType.SHIFT_MASK),
)
-BLOCK_VALIGN_BOTTOM = Action(
+BLOCK_VALIGN_BOTTOM = actions.register("win.block_align_bottom",
label='Vertical Align Bottom',
tooltip='Align bottoms of selected blocks',
- keypresses=(Gdk.KEY_b, Gdk.ModifierType.SHIFT_MASK),
)
-BLOCK_HALIGN_LEFT = Action(
+BLOCK_HALIGN_LEFT = actions.register("win.block_align_left",
label='Horizontal Align Left',
tooltip='Align left edges of blocks selected blocks',
- keypresses=(Gdk.KEY_l, Gdk.ModifierType.SHIFT_MASK),
)
-BLOCK_HALIGN_CENTER = Action(
+BLOCK_HALIGN_CENTER = actions.register("win.block_align_center",
label='Horizontal Align Center',
tooltip='Align centers of selected blocks horizontally',
- keypresses=(Gdk.KEY_c, Gdk.ModifierType.SHIFT_MASK),
)
-BLOCK_HALIGN_RIGHT = Action(
+BLOCK_HALIGN_RIGHT = actions.register("win.block_align_right",
label='Horizontal Align Right',
tooltip='Align right edges of selected blocks',
- keypresses=(Gdk.KEY_r, Gdk.ModifierType.SHIFT_MASK),
)
BLOCK_ALIGNMENTS = [
BLOCK_VALIGN_TOP,
@@ -310,234 +347,222 @@ BLOCK_ALIGNMENTS = [
BLOCK_HALIGN_CENTER,
BLOCK_HALIGN_RIGHT,
]
-BLOCK_PARAM_MODIFY = Action(
+BLOCK_PARAM_MODIFY = actions.register("win.block_modify",
label='_Properties',
tooltip='Modify params for the selected block',
- stock_id=Gtk.STOCK_PROPERTIES,
- keypresses=(Gdk.KEY_Return, NO_MODS_MASK),
+ icon_name='document-properties',
)
-BLOCK_ENABLE = Action(
+BLOCK_ENABLE = actions.register("win.block_enable",
label='E_nable',
tooltip='Enable the selected blocks',
- stock_id=Gtk.STOCK_CONNECT,
- keypresses=(Gdk.KEY_e, NO_MODS_MASK),
+ icon_name='network-wired',
)
-BLOCK_DISABLE = Action(
+BLOCK_DISABLE = actions.register("win.block_disable",
label='D_isable',
tooltip='Disable the selected blocks',
- stock_id=Gtk.STOCK_DISCONNECT,
- keypresses=(Gdk.KEY_d, NO_MODS_MASK),
+ icon_name='network-wired-disconnected',
)
-BLOCK_BYPASS = Action(
+BLOCK_BYPASS = actions.register("win.block_bypass",
label='_Bypass',
tooltip='Bypass the selected block',
- stock_id=Gtk.STOCK_MEDIA_FORWARD,
- keypresses=(Gdk.KEY_b, NO_MODS_MASK),
+ icon_name='media-seek-forward',
)
-TOGGLE_SNAP_TO_GRID = ToggleAction(
+TOGGLE_SNAP_TO_GRID = actions.register("win.snap_to_grid",
label='_Snap to grid',
tooltip='Snap blocks to a grid for an easier connection alignment',
- preference_name='snap_to_grid'
+ preference_name='snap_to_grid',
)
-TOGGLE_HIDE_DISABLED_BLOCKS = ToggleAction(
+TOGGLE_HIDE_DISABLED_BLOCKS = actions.register("win.hide_disabled",
label='Hide _Disabled Blocks',
tooltip='Toggle visibility of disabled blocks and connections',
- stock_id=Gtk.STOCK_MISSING_IMAGE,
- keypresses=(Gdk.KEY_d, Gdk.ModifierType.CONTROL_MASK),
+ icon_name='image-missing',
+ keypresses=["<Ctrl>d"],
+ preference_name='hide_disabled',
)
-TOGGLE_HIDE_VARIABLES = ToggleAction(
+TOGGLE_HIDE_VARIABLES = actions.register("win.hide_variables",
label='Hide Variables',
tooltip='Hide all variable blocks',
preference_name='hide_variables',
default=False,
)
-TOGGLE_FLOW_GRAPH_VAR_EDITOR = ToggleAction(
+TOGGLE_FLOW_GRAPH_VAR_EDITOR = actions.register("win.toggle_variable_editor",
label='Show _Variable Editor',
tooltip='Show the variable editor. Modify variables and imports in this flow graph',
- stock_id=Gtk.STOCK_EDIT,
+ icon_name='accessories-text-editor',
default=True,
- keypresses=(Gdk.KEY_e, Gdk.ModifierType.CONTROL_MASK),
+ keypresses=["<Ctrl>e"],
preference_name='variable_editor_visable',
)
-TOGGLE_FLOW_GRAPH_VAR_EDITOR_SIDEBAR = ToggleAction(
+TOGGLE_FLOW_GRAPH_VAR_EDITOR_SIDEBAR = actions.register("win.toggle_variable_editor_sidebar",
label='Move the Variable Editor to the Sidebar',
tooltip='Move the variable editor to the sidebar',
default=False,
preference_name='variable_editor_sidebar',
)
-TOGGLE_AUTO_HIDE_PORT_LABELS = ToggleAction(
+TOGGLE_AUTO_HIDE_PORT_LABELS = actions.register("win.auto_hide_port_labels",
label='Auto-Hide _Port Labels',
tooltip='Automatically hide port labels',
preference_name='auto_hide_port_labels'
)
-TOGGLE_SHOW_BLOCK_COMMENTS = ToggleAction(
+TOGGLE_SHOW_BLOCK_COMMENTS = actions.register("win.show_block_comments",
label='Show Block Comments',
tooltip="Show comment beneath each block",
preference_name='show_block_comments'
)
-TOGGLE_SHOW_CODE_PREVIEW_TAB = ToggleAction(
+TOGGLE_SHOW_CODE_PREVIEW_TAB = actions.register("win.toggle_code_preview",
label='Generated Code Preview',
tooltip="Show a preview of the code generated for each Block in its "
"Properties Dialog",
preference_name='show_generated_code_tab',
default=False,
)
-TOGGLE_SHOW_FLOWGRAPH_COMPLEXITY = ToggleAction(
+TOGGLE_SHOW_FLOWGRAPH_COMPLEXITY = actions.register("win.show_flowgraph_complexity",
label='Show Flowgraph Complexity',
tooltip="How many Balints is the flowgraph...",
preference_name='show_flowgraph_complexity',
default=False,
)
-BLOCK_CREATE_HIER = Action(
+BLOCK_CREATE_HIER = actions.register("win.block_create_hier",
label='C_reate Hier',
tooltip='Create hier block from selected blocks',
- stock_id=Gtk.STOCK_CONNECT,
-# keypresses=(Gdk.KEY_c, NO_MODS_MASK),
+ icon_name='document-new',
)
-BLOCK_CUT = Action(
+BLOCK_CUT = actions.register("win.block_cut",
label='Cu_t',
tooltip='Cut',
- stock_id=Gtk.STOCK_CUT,
- keypresses=(Gdk.KEY_x, Gdk.ModifierType.CONTROL_MASK),
+ icon_name='edit-cut',
+ keypresses=["<Ctrl>x"],
)
-BLOCK_COPY = Action(
+BLOCK_COPY = actions.register("win.block_copy",
label='_Copy',
tooltip='Copy',
- stock_id=Gtk.STOCK_COPY,
- keypresses=(Gdk.KEY_c, Gdk.ModifierType.CONTROL_MASK),
+ icon_name='edit-copy',
+ keypresses=["<Ctrl>c"],
)
-BLOCK_PASTE = Action(
+BLOCK_PASTE = actions.register("win.block_paste",
label='_Paste',
tooltip='Paste',
- stock_id=Gtk.STOCK_PASTE,
- keypresses=(Gdk.KEY_v, Gdk.ModifierType.CONTROL_MASK),
+ icon_name='edit-paste',
+ keypresses=["<Ctrl>v"],
)
-ERRORS_WINDOW_DISPLAY = Action(
+ERRORS_WINDOW_DISPLAY = actions.register("app.errors",
label='Flowgraph _Errors',
tooltip='View flow graph errors',
- stock_id=Gtk.STOCK_DIALOG_ERROR,
+ icon_name='dialog-error',
)
-TOGGLE_CONSOLE_WINDOW = ToggleAction(
+TOGGLE_CONSOLE_WINDOW = actions.register("win.toggle_console_window",
label='Show _Console Panel',
tooltip='Toggle visibility of the console',
- keypresses=(Gdk.KEY_r, Gdk.ModifierType.CONTROL_MASK),
+ keypresses=["<Ctrl>r"],
preference_name='console_window_visible'
)
-TOGGLE_BLOCKS_WINDOW = ToggleAction(
+# TODO: Might be able to convert this to a Gio.PropertyAction eventually.
+# actions would need to be defined in the correct class and not globally
+TOGGLE_BLOCKS_WINDOW = actions.register("win.toggle_blocks_window",
label='Show _Block Tree Panel',
tooltip='Toggle visibility of the block tree widget',
- keypresses=(Gdk.KEY_b, Gdk.ModifierType.CONTROL_MASK),
+ keypresses=["<Ctrl>b"],
preference_name='blocks_window_visible'
)
-TOGGLE_SCROLL_LOCK = ToggleAction(
+TOGGLE_SCROLL_LOCK = actions.register("win.console.scroll_lock",
label='Console Scroll _Lock',
tooltip='Toggle scroll lock for the console window',
preference_name='scroll_lock'
)
-ABOUT_WINDOW_DISPLAY = Action(
+ABOUT_WINDOW_DISPLAY = actions.register("app.about",
label='_About',
tooltip='About this program',
- stock_id=Gtk.STOCK_ABOUT,
+ icon_name='help-about',
)
-HELP_WINDOW_DISPLAY = Action(
+HELP_WINDOW_DISPLAY = actions.register("app.help",
label='_Help',
tooltip='Usage tips',
- stock_id=Gtk.STOCK_HELP,
- keypresses=(Gdk.KEY_F1, NO_MODS_MASK),
+ icon_name='help-contents',
+ keypresses=["F1"],
)
-TYPES_WINDOW_DISPLAY = Action(
+TYPES_WINDOW_DISPLAY = actions.register("app.types",
label='_Types',
tooltip='Types color mapping',
- stock_id=Gtk.STOCK_DIALOG_INFO,
+ icon_name='dialog-information',
)
-FLOW_GRAPH_GEN = Action(
+FLOW_GRAPH_GEN = actions.register("app.flowgraph.generate",
label='_Generate',
tooltip='Generate the flow graph',
- stock_id=Gtk.STOCK_CONVERT,
- keypresses=(Gdk.KEY_F5, NO_MODS_MASK),
+ icon_name='insert-object',
+ keypresses=["F5"],
)
-FLOW_GRAPH_EXEC = Action(
+FLOW_GRAPH_EXEC = actions.register("app.flowgraph.execute",
label='_Execute',
tooltip='Execute the flow graph',
- stock_id=Gtk.STOCK_MEDIA_PLAY,
- keypresses=(Gdk.KEY_F6, NO_MODS_MASK),
+ icon_name='media-playback-start',
+ keypresses=["F6"],
)
-FLOW_GRAPH_KILL = Action(
+FLOW_GRAPH_KILL = actions.register("app.flowgraph.kill",
label='_Kill',
tooltip='Kill the flow graph',
- stock_id=Gtk.STOCK_STOP,
- keypresses=(Gdk.KEY_F7, NO_MODS_MASK),
+ icon_name='media-playback-stop',
+ keypresses=["F7"],
)
-FLOW_GRAPH_SCREEN_CAPTURE = Action(
+FLOW_GRAPH_SCREEN_CAPTURE = actions.register("app.flowgraph.screen_capture",
label='Screen Ca_pture',
tooltip='Create a screen capture of the flow graph',
- stock_id=Gtk.STOCK_PRINT,
- keypresses=(Gdk.KEY_p, Gdk.ModifierType.CONTROL_MASK),
-)
-PORT_CONTROLLER_DEC = Action(
- keypresses=(Gdk.KEY_minus, NO_MODS_MASK, Gdk.KEY_KP_Subtract, NO_MODS_MASK),
-)
-PORT_CONTROLLER_INC = Action(
- keypresses=(Gdk.KEY_plus, NO_MODS_MASK, Gdk.KEY_KP_Add, NO_MODS_MASK),
-)
-BLOCK_INC_TYPE = Action(
- keypresses=(Gdk.KEY_Down, NO_MODS_MASK),
-)
-BLOCK_DEC_TYPE = Action(
- keypresses=(Gdk.KEY_Up, NO_MODS_MASK),
-)
-RELOAD_BLOCKS = Action(
+ icon_name='printer',
+ keypresses=["<Ctrl>p"],
+)
+PORT_CONTROLLER_DEC = actions.register("win.port_controller_dec")
+PORT_CONTROLLER_INC = actions.register("win.port_controller_inc")
+BLOCK_INC_TYPE = actions.register("win.block_inc_type")
+BLOCK_DEC_TYPE = actions.register("win.block_dec_type")
+RELOAD_BLOCKS = actions.register("app.reload_blocks",
label='Reload _Blocks',
tooltip='Reload Blocks',
- stock_id=Gtk.STOCK_REFRESH
+ icon_name='view-refresh'
)
-FIND_BLOCKS = Action(
+FIND_BLOCKS = actions.register("win.find_blocks",
label='_Find Blocks',
tooltip='Search for a block by name (and key)',
- stock_id=Gtk.STOCK_FIND,
- keypresses=(Gdk.KEY_f, Gdk.ModifierType.CONTROL_MASK,
- Gdk.KEY_slash, NO_MODS_MASK),
+ icon_name='edit-find',
+ keypresses=["<Ctrl>f", "slash"],
)
-CLEAR_CONSOLE = Action(
+CLEAR_CONSOLE = actions.register("win.console.clear",
label='_Clear Console',
tooltip='Clear Console',
- stock_id=Gtk.STOCK_CLEAR,
+ icon_name='edit-clear',
)
-SAVE_CONSOLE = Action(
+SAVE_CONSOLE = actions.register("win.console.save",
label='_Save Console',
tooltip='Save Console',
- stock_id=Gtk.STOCK_SAVE,
+ icon_name='edit-save',
)
-OPEN_HIER = Action(
+OPEN_HIER = actions.register("win.open_hier",
label='Open H_ier',
tooltip='Open the source of the selected hierarchical block',
- stock_id=Gtk.STOCK_JUMP_TO,
+ icon_name='go-jump',
)
-BUSSIFY_SOURCES = Action(
+BUSSIFY_SOURCES = actions.register("win.bussify_sources",
label='Toggle So_urce Bus',
tooltip='Gang source ports into a single bus port',
- stock_id=Gtk.STOCK_JUMP_TO,
+ icon_name='go-jump',
)
-BUSSIFY_SINKS = Action(
+BUSSIFY_SINKS = actions.register("win.bussify_sinks",
label='Toggle S_ink Bus',
tooltip='Gang sink ports into a single bus port',
- stock_id=Gtk.STOCK_JUMP_TO,
+ icon_name='go-jump',
)
-XML_PARSER_ERRORS_DISPLAY = Action(
+XML_PARSER_ERRORS_DISPLAY = actions.register("app.xml_errors",
label='_Parser Errors',
tooltip='View errors that occurred while parsing XML files',
- stock_id=Gtk.STOCK_DIALOG_ERROR,
+ icon_name='dialog-error',
)
-FLOW_GRAPH_OPEN_QSS_THEME = Action(
+FLOW_GRAPH_OPEN_QSS_THEME = actions.register("app.open_qss_theme",
label='Set Default QT GUI _Theme',
tooltip='Set a default QT Style Sheet file to use for QT GUI',
- stock_id=Gtk.STOCK_OPEN,
+ icon_name='document-open',
)
-TOOLS_RUN_FDESIGN = Action(
+TOOLS_RUN_FDESIGN = actions.register("app.filter_design",
label='Filter Design Tool',
tooltip='Execute gr_filter_design',
- stock_id=Gtk.STOCK_EXECUTE,
-)
-TOOLS_MORE_TO_COME = Action(
- label='More to come',
+ icon_name='media-playback-start',
)
+POST_HANDLER = actions.register("app.post_handler")
+READY = actions.register("app.ready")
diff --git a/grc/gui/Application.py b/grc/gui/Application.py
index 9e89009dc9..c1456c3a8d 100644
--- a/grc/gui/Application.py
+++ b/grc/gui/Application.py
@@ -24,9 +24,9 @@ import os
import subprocess
import logging
-from gi.repository import Gtk, GObject
+from gi.repository import Gtk, Gio, GLib, GObject
-from . import Dialogs, Actions, Executor, FileDialogs, Utils
+from . import Dialogs, Actions, Executor, FileDialogs, Utils, Bars
from .MainWindow import MainWindow
from .ParserErrorsDialog import ParserErrorsDialog
from .PropsDialog import PropsDialog
@@ -56,54 +56,58 @@ class Application(Gtk.Application):
"""
self.clipboard = None
self.dialog = None
- for action in Actions.get_all_actions(): action.connect('activate', self._handle_action)
- #setup the main window
+
+ # Setup the main window
self.platform = platform
self.config = platform.config
- log.debug("__init__()")
-
- #initialize
+ log.debug("Application()")
+ # Connect all actions to _handle_action
+ for x in Actions.get_actions():
+ Actions.connect(x, handler=self._handle_action)
+ Actions.actions[x].enable()
+ if x.startswith("app."):
+ self.add_action(Actions.actions[x])
+ # Setup the shortcut keys
+ # These are the globally defined shortcuts
+ keypress = Actions.actions[x].keypresses
+ if keypress:
+ self.set_accels_for_action(x, keypress)
+
+ # Initialize
self.init_file_paths = [os.path.abspath(file_path) for file_path in file_paths]
self.init = False
def do_startup(self):
Gtk.Application.do_startup(self)
- log.debug("do_startup()")
+ log.debug("Application.do_startup()")
+
+ # Setup the menu
+ log.debug("Creating menu")
+ '''
+ self.menu = Bars.Menu()
+ self.set_menu()
+ if self.prefers_app_menu():
+ self.set_app_menu(self.menu)
+ else:
+ self.set_menubar(self.menu)
+ '''
def do_activate(self):
Gtk.Application.do_activate(self)
- log.debug("do_activate()")
+ log.debug("Application.do_activate()")
- self.main_window = MainWindow(self, self.platform, self._handle_action)
+ self.main_window = MainWindow(self, self.platform)
self.main_window.connect('delete-event', self._quit)
- self.main_window.connect('key-press-event', self._handle_key_press)
self.get_focus_flag = self.main_window.get_focus_flag
+
#setup the messages
Messages.register_messenger(self.main_window.add_console_line)
Messages.send_init(self.platform)
+ log.debug("Calling Actions.APPLICATION_INITIALIZE")
Actions.APPLICATION_INITIALIZE()
- def _handle_key_press(self, widget, event):
- """
- 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.
-
- Returns:
- false to let gtk handle the key action
- """
- # prevent key event stealing while the search box is active
- # .has_focus() only in newer versions 2.17+?
- # .is_focus() seems to work, but exactly the same
- if self.main_window.btwin.search_entry.has_focus():
- return False
- return Actions.handle_key_press(event)
-
def _quit(self, window, event):
"""
Handle the delete event from the main window.
@@ -117,7 +121,7 @@ class Application(Gtk.Application):
return True
def _handle_action(self, action, *args):
- #print action
+ log.debug("_handle_action({0}, {1})".format(action, args))
main = self.main_window
page = main.current_page
flow_graph = page.flow_graph if page else None
@@ -130,6 +134,7 @@ class Application(Gtk.Application):
# Initialize/Quit
##################################################
if action == Actions.APPLICATION_INITIALIZE:
+ log.debug("APPLICATION_INITIALIZE")
file_path_to_show = self.config.file_open()
for file_path in (self.init_file_paths or self.config.get_open_files()):
if os.path.exists(file_path):
@@ -139,35 +144,84 @@ class Application(Gtk.Application):
main.btwin.search_entry.hide()
- # Disable all actions, then re-enable a few
- for action in Actions.get_all_actions():
- action.set_sensitive(False) # set all actions disabled
+ """
+ Only disable certain actions on startup. Each of these actions are
+ conditionally enabled in _handle_action, so disable them first.
+ - FLOW_GRAPH_UNDO/REDO are set in gui/StateCache.py
+ - XML_PARSER_ERRORS_DISPLAY is set in RELOAD_BLOCKS
+
+ TODO: These 4 should probably be included, but they are not currently
+ enabled anywhere else:
+ - PORT_CONTROLLER_DEC, PORT_CONTROLLER_INC
+ - BLOCK_INC_TYPE, BLOCK_DEC_TYPE
+
+ TODO: These should be handled better. They are set in
+ update_exec_stop(), but not anywhere else
+ - FLOW_GRAPH_GEN, FLOW_GRAPH_EXEC, FLOW_GRAPH_KILL
+ """
+ for action in (
+ Actions.ERRORS_WINDOW_DISPLAY,
+ Actions.ELEMENT_DELETE,
+ Actions.BLOCK_PARAM_MODIFY,
+ Actions.BLOCK_ROTATE_CCW,
+ Actions.BLOCK_ROTATE_CW,
+ Actions.BLOCK_VALIGN_TOP,
+ Actions.BLOCK_VALIGN_MIDDLE,
+ Actions.BLOCK_VALIGN_BOTTOM,
+ Actions.BLOCK_HALIGN_LEFT,
+ Actions.BLOCK_HALIGN_CENTER,
+ Actions.BLOCK_HALIGN_RIGHT,
+ Actions.BLOCK_CUT,
+ Actions.BLOCK_COPY,
+ Actions.BLOCK_PASTE,
+ Actions.BLOCK_ENABLE,
+ Actions.BLOCK_DISABLE,
+ Actions.BLOCK_BYPASS,
+ Actions.BLOCK_CREATE_HIER,
+ Actions.OPEN_HIER,
+ Actions.BUSSIFY_SOURCES,
+ Actions.BUSSIFY_SINKS,
+ Actions.FLOW_GRAPH_SAVE,
+ Actions.FLOW_GRAPH_UNDO,
+ Actions.FLOW_GRAPH_REDO,
+ Actions.XML_PARSER_ERRORS_DISPLAY
+ ):
+ action.disable()
+
+ # Load preferences
for action in (
- Actions.APPLICATION_QUIT, Actions.FLOW_GRAPH_NEW,
- Actions.FLOW_GRAPH_OPEN, Actions.FLOW_GRAPH_SAVE_AS,
- Actions.FLOW_GRAPH_DUPLICATE, Actions.FLOW_GRAPH_SAVE_A_COPY,
- Actions.FLOW_GRAPH_CLOSE, Actions.ABOUT_WINDOW_DISPLAY,
- Actions.FLOW_GRAPH_SCREEN_CAPTURE, Actions.HELP_WINDOW_DISPLAY,
- Actions.TYPES_WINDOW_DISPLAY, Actions.TOGGLE_BLOCKS_WINDOW,
- Actions.TOGGLE_CONSOLE_WINDOW, Actions.TOGGLE_HIDE_DISABLED_BLOCKS,
- Actions.TOOLS_RUN_FDESIGN, Actions.TOGGLE_SCROLL_LOCK,
- Actions.CLEAR_CONSOLE, Actions.SAVE_CONSOLE,
- Actions.TOGGLE_AUTO_HIDE_PORT_LABELS, Actions.TOGGLE_SNAP_TO_GRID,
+ Actions.TOGGLE_BLOCKS_WINDOW,
+ Actions.TOGGLE_CONSOLE_WINDOW,
+ Actions.TOGGLE_HIDE_DISABLED_BLOCKS,
+ Actions.TOGGLE_SCROLL_LOCK,
+ Actions.TOGGLE_AUTO_HIDE_PORT_LABELS,
+ Actions.TOGGLE_SNAP_TO_GRID,
Actions.TOGGLE_SHOW_BLOCK_COMMENTS,
Actions.TOGGLE_SHOW_CODE_PREVIEW_TAB,
Actions.TOGGLE_SHOW_FLOWGRAPH_COMPLEXITY,
- Actions.FLOW_GRAPH_OPEN_QSS_THEME,
Actions.TOGGLE_FLOW_GRAPH_VAR_EDITOR,
Actions.TOGGLE_FLOW_GRAPH_VAR_EDITOR_SIDEBAR,
Actions.TOGGLE_HIDE_VARIABLES,
- Actions.SELECT_ALL,
):
- action.set_sensitive(True)
+ action.set_enabled(True)
if hasattr(action, 'load_from_preferences'):
action.load_from_preferences()
+
+ # Hide the panels *IF* it's saved in preferences
+ main.update_panel_visibility(main.BLOCKS, Actions.TOGGLE_BLOCKS_WINDOW.get_active())
+ main.update_panel_visibility(main.CONSOLE, Actions.TOGGLE_CONSOLE_WINDOW.get_active())
+ main.update_panel_visibility(main.VARIABLES, Actions.TOGGLE_FLOW_GRAPH_VAR_EDITOR.get_active())
+
if ParseXML.xml_failures:
Messages.send_xml_errors_if_any(ParseXML.xml_failures)
- Actions.XML_PARSER_ERRORS_DISPLAY.set_sensitive(True)
+ Actions.XML_PARSER_ERRORS_DISPLAY.set_enabled(True)
+
+ # Force an update on the current page to match loaded preferences.
+ # In the future, change the __init__ order to load preferences first
+ page = main.current_page
+ if page:
+ page.flow_graph.update()
+
self.init = True
elif action == Actions.APPLICATION_QUIT:
if main.close_pages():
@@ -400,12 +454,17 @@ class Application(Gtk.Application):
elif action == Actions.ERRORS_WINDOW_DISPLAY:
Dialogs.ErrorsDialog(main, flow_graph).run_and_destroy()
elif action == Actions.TOGGLE_CONSOLE_WINDOW:
+ action.set_active(not action.get_active())
main.update_panel_visibility(main.CONSOLE, action.get_active())
action.save_to_preferences()
elif action == Actions.TOGGLE_BLOCKS_WINDOW:
+ # This would be better matched to a Gio.PropertyAction, but to do
+ # this, actions would have to be defined in the window not globally
+ action.set_active(not action.get_active())
main.update_panel_visibility(main.BLOCKS, action.get_active())
action.save_to_preferences()
elif action == Actions.TOGGLE_SCROLL_LOCK:
+ action.set_active(not action.get_active())
active = action.get_active()
main.console.text_display.scroll_lock = active
if active:
@@ -418,41 +477,53 @@ class Application(Gtk.Application):
if file_path is not None:
main.console.text_display.save(file_path)
elif action == Actions.TOGGLE_HIDE_DISABLED_BLOCKS:
+ action.set_active(not action.get_active())
Actions.NOTHING_SELECT()
elif action == Actions.TOGGLE_AUTO_HIDE_PORT_LABELS:
+ action.set_active(not action.get_active())
action.save_to_preferences()
for page in main.get_pages():
page.flow_graph.create_shapes()
elif action in (Actions.TOGGLE_SNAP_TO_GRID,
Actions.TOGGLE_SHOW_BLOCK_COMMENTS,
Actions.TOGGLE_SHOW_CODE_PREVIEW_TAB):
+ action.set_active(not action.get_active())
action.save_to_preferences()
elif action == Actions.TOGGLE_SHOW_FLOWGRAPH_COMPLEXITY:
+ action.set_active(not action.get_active())
action.save_to_preferences()
for page in main.get_pages():
flow_graph_update(page.flow_graph)
elif action == Actions.TOGGLE_HIDE_VARIABLES:
- # Call the variable editor TOGGLE in case it needs to be showing
- Actions.TOGGLE_FLOW_GRAPH_VAR_EDITOR()
+ action.set_active(not action.get_active())
+ active = action.get_active()
+ # Either way, triggering this should simply trigger the variable editor
+ # to be visible.
+ varedit = Actions.TOGGLE_FLOW_GRAPH_VAR_EDITOR
+ if active:
+ log.debug("Variables are hidden. Forcing the variable panel to be visible.")
+ varedit.disable()
+ else:
+ varedit.enable()
+ # Just force it to show.
+ varedit.set_active(True)
+ main.update_panel_visibility(main.VARIABLES)
Actions.NOTHING_SELECT()
action.save_to_preferences()
+ varedit.save_to_preferences()
+ flow_graph_update()
elif action == Actions.TOGGLE_FLOW_GRAPH_VAR_EDITOR:
- # See if the variables are hidden
- if Actions.TOGGLE_HIDE_VARIABLES.get_active():
- # Force this to be shown
- main.update_panel_visibility(main.VARIABLES, True)
- action.set_active(True)
- action.set_sensitive(False)
- else:
- if action.get_sensitive():
- main.update_panel_visibility(main.VARIABLES, action.get_active())
- else: # This is occurring after variables are un-hidden
- # Leave it enabled
- action.set_sensitive(True)
- action.set_active(True)
- # Actions.TOGGLE_FLOW_GRAPH_VAR_EDITOR_SIDEBAR.set_sensitive(action.get_active())
+ # TODO: There may be issues at startup since these aren't triggered
+ # the same was as Gtk.Actions when loading preferences.
+ action.set_active(not action.get_active())
+ # Just assume this was triggered because it was enabled.
+ main.update_panel_visibility(main.VARIABLES, action.get_active())
+ action.save_to_preferences()
+
+ # Actions.TOGGLE_FLOW_GRAPH_VAR_EDITOR_SIDEBAR.set_enabled(action.get_active())
action.save_to_preferences()
elif action == Actions.TOGGLE_FLOW_GRAPH_VAR_EDITOR_SIDEBAR:
+ action.set_active(not action.get_active())
if self.init:
Dialogs.MessageDialogWrapper(
main, Gtk.MessageType.INFO, Gtk.ButtonsType.CLOSE,
@@ -463,7 +534,7 @@ class Application(Gtk.Application):
# Param Modifications
##################################################
elif action == Actions.BLOCK_PARAM_MODIFY:
- selected_block = action.args[0] if action.args else flow_graph.selected_block
+ selected_block = args[0] if args[0] else flow_graph.selected_block
if selected_block:
self.dialog = PropsDialog(self.main_window, selected_block)
response = Gtk.ResponseType.APPLY
@@ -520,17 +591,17 @@ class Application(Gtk.Application):
elif action == Actions.FLOW_GRAPH_NEW:
main.new_page()
if args:
- flow_graph = main.get_flow_graph()
+ flow_graph = main.current_page.flow_graph
flow_graph._options_block.get_param('generate_options').set_value(args[0])
flow_graph_update(flow_graph)
elif action == Actions.FLOW_GRAPH_OPEN:
- file_paths = args if args else FileDialogs.OpenFlowGraph(main, page.file_path).run()
+ file_paths = args[0] if args[0] else FileDialogs.OpenFlowGraph(main, page.file_path).run()
if file_paths: # Open a new page for each file, show only the first
for i,file_path in enumerate(file_paths):
main.new_page(file_path, show=(i==0))
self.config.add_recent_file(file_path)
main.tool_bar.refresh_submenus()
- main.menu_bar.refresh_submenus()
+ #main.menu_bar.refresh_submenus()
elif action == Actions.FLOW_GRAPH_OPEN_QSS_THEME:
file_paths = FileDialogs.OpenQSS(main, self.platform.config.install_prefix +
'/share/gnuradio/themes/').run()
@@ -558,33 +629,37 @@ class Application(Gtk.Application):
Actions.FLOW_GRAPH_SAVE()
self.config.add_recent_file(file_path)
main.tool_bar.refresh_submenus()
- main.menu_bar.refresh_submenus()
- elif action == Actions.FLOW_GRAPH_SAVE_A_COPY:
+ #TODO
+ #main.menu_bar.refresh_submenus()
+ elif action == Actions.FLOW_GRAPH_SAVE_COPY:
try:
- if not page.get_file_path():
+ if not page.file_path:
+ # Make sure the current flowgraph has been saved
Actions.FLOW_GRAPH_SAVE_AS()
else:
- dup_file_path = page.get_file_path()
+ dup_file_path = page.file_path
dup_file_name = '.'.join(dup_file_path.split('.')[:-1]) + "_copy" # Assuming .grc extension at the end of file_path
dup_file_path_temp = dup_file_name+'.grc'
count = 1
while os.path.exists(dup_file_path_temp):
dup_file_path_temp = dup_file_name+'('+str(count)+').grc'
count += 1
- dup_file_path_user = SaveFlowGraphFileDialog(dup_file_path_temp).run()
+ dup_file_path_user = FileDialogs.SaveFlowGraph(main, dup_file_path_temp).run()
if dup_file_path_user is not None:
ParseXML.to_file(flow_graph.export_data(), dup_file_path_user)
Messages.send('Saved Copy to: "' + dup_file_path_user + '"\n')
except IOError:
Messages.send_fail_save("Can not create a copy of the flowgraph\n")
elif action == Actions.FLOW_GRAPH_DUPLICATE:
- flow_graph = main.get_flow_graph()
+ previous = flow_graph
+ # Create a new page
main.new_page()
- curr_page = main.get_page()
- new_flow_graph = main.get_flow_graph()
- new_flow_graph.import_data(flow_graph.export_data())
+ page = main.current_page
+ new_flow_graph = page.flow_graph
+ # Import the old data and mark the current as not saved
+ new_flow_graph.import_data(previous.export_data())
flow_graph_update(new_flow_graph)
- curr_page.set_saved(False)
+ page.saved = False
elif action == Actions.FLOW_GRAPH_SCREEN_CAPTURE:
file_path, background_transparent = FileDialogs.SaveScreenShot(main, page.file_path).run()
if file_path is not None:
@@ -634,7 +709,7 @@ class Application(Gtk.Application):
elif action == Actions.RELOAD_BLOCKS:
self.platform.build_block_library()
main.btwin.repopulate()
- Actions.XML_PARSER_ERRORS_DISPLAY.set_sensitive(bool(
+ Actions.XML_PARSER_ERRORS_DISPLAY.set_enabled(bool(
ParseXML.xml_failures))
Messages.send_xml_errors_if_any(ParseXML.xml_failures)
# Force a redraw of the graph, by getting the current state and re-importing it
@@ -667,7 +742,7 @@ class Application(Gtk.Application):
shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
else:
- print('!!! Action "%s" not handled !!!' % action)
+ log.warning('!!! Action "%s" not handled !!!' % action)
##################################################
# Global Actions for all States
##################################################
@@ -678,19 +753,19 @@ class Application(Gtk.Application):
selected_block = selected_blocks[0] if selected_blocks else None
#update general buttons
- Actions.ERRORS_WINDOW_DISPLAY.set_sensitive(not flow_graph.is_valid())
- Actions.ELEMENT_DELETE.set_sensitive(bool(flow_graph.selected_elements))
- Actions.BLOCK_PARAM_MODIFY.set_sensitive(bool(selected_block))
- Actions.BLOCK_ROTATE_CCW.set_sensitive(bool(selected_blocks))
- Actions.BLOCK_ROTATE_CW.set_sensitive(bool(selected_blocks))
+ Actions.ERRORS_WINDOW_DISPLAY.set_enabled(not flow_graph.is_valid())
+ Actions.ELEMENT_DELETE.set_enabled(bool(flow_graph.selected_elements))
+ Actions.BLOCK_PARAM_MODIFY.set_enabled(bool(selected_block))
+ Actions.BLOCK_ROTATE_CCW.set_enabled(bool(selected_blocks))
+ Actions.BLOCK_ROTATE_CW.set_enabled(bool(selected_blocks))
#update alignment options
for act in Actions.BLOCK_ALIGNMENTS:
if act:
- act.set_sensitive(len(selected_blocks) > 1)
+ act.set_enabled(len(selected_blocks) > 1)
#update cut/copy/paste
- Actions.BLOCK_CUT.set_sensitive(bool(selected_blocks))
- Actions.BLOCK_COPY.set_sensitive(bool(selected_blocks))
- Actions.BLOCK_PASTE.set_sensitive(bool(self.clipboard))
+ Actions.BLOCK_CUT.set_enabled(bool(selected_blocks))
+ Actions.BLOCK_COPY.set_enabled(bool(selected_blocks))
+ Actions.BLOCK_PASTE.set_enabled(bool(self.clipboard))
#update enable/disable/bypass
can_enable = any(block.state != 'enabled'
for block in selected_blocks)
@@ -700,26 +775,26 @@ class Application(Gtk.Application):
all(block.can_bypass() for block in selected_blocks) and
any(not block.get_bypassed() for block in selected_blocks)
)
- Actions.BLOCK_ENABLE.set_sensitive(can_enable)
- Actions.BLOCK_DISABLE.set_sensitive(can_disable)
- Actions.BLOCK_BYPASS.set_sensitive(can_bypass_all)
+ Actions.BLOCK_ENABLE.set_enabled(can_enable)
+ Actions.BLOCK_DISABLE.set_enabled(can_disable)
+ Actions.BLOCK_BYPASS.set_enabled(can_bypass_all)
- Actions.BLOCK_CREATE_HIER.set_sensitive(bool(selected_blocks))
- Actions.OPEN_HIER.set_sensitive(bool(selected_blocks))
- Actions.BUSSIFY_SOURCES.set_sensitive(bool(selected_blocks))
- Actions.BUSSIFY_SINKS.set_sensitive(bool(selected_blocks))
- Actions.RELOAD_BLOCKS.set_sensitive(True)
- Actions.FIND_BLOCKS.set_sensitive(True)
+ Actions.BLOCK_CREATE_HIER.set_enabled(bool(selected_blocks))
+ Actions.OPEN_HIER.set_enabled(bool(selected_blocks))
+ Actions.BUSSIFY_SOURCES.set_enabled(bool(selected_blocks))
+ Actions.BUSSIFY_SINKS.set_enabled(bool(selected_blocks))
+ Actions.RELOAD_BLOCKS.enable()
+ Actions.FIND_BLOCKS.enable()
self.update_exec_stop()
- Actions.FLOW_GRAPH_SAVE.set_sensitive(not page.saved)
+ Actions.FLOW_GRAPH_SAVE.set_enabled(not page.saved)
main.update()
flow_graph.update_selected()
page.drawing_area.queue_draw()
- return True # action was handled
+ return True # Action was handled
def update_exec_stop(self):
"""
@@ -728,6 +803,6 @@ class Application(Gtk.Application):
"""
page = self.main_window.current_page
sensitive = page.flow_graph.is_valid() and not page.process
- Actions.FLOW_GRAPH_GEN.set_sensitive(sensitive)
- Actions.FLOW_GRAPH_EXEC.set_sensitive(sensitive)
- Actions.FLOW_GRAPH_KILL.set_sensitive(page.process is not None)
+ Actions.FLOW_GRAPH_GEN.set_enabled(sensitive)
+ Actions.FLOW_GRAPH_EXEC.set_enabled(sensitive)
+ Actions.FLOW_GRAPH_KILL.set_enabled(page.process is not None)
diff --git a/grc/gui/Bars.py b/grc/gui/Bars.py
index 1510e109d2..2a8040f5d5 100644
--- a/grc/gui/Bars.py
+++ b/grc/gui/Bars.py
@@ -1,5 +1,5 @@
"""
-Copyright 2007, 2008, 2009, 2015 Free Software Foundation, Inc.
+Copyright 2007, 2008, 2009, 2015, 2016 Free Software Foundation, Inc.
This file is part of GNU Radio
GNU Radio Companion is free software; you can redistribute it and/or
@@ -19,306 +19,299 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
from __future__ import absolute_import
-from gi.repository import Gtk, GObject
+import logging
+
+from gi.repository import Gtk, GObject, Gio, GLib
from . import Actions
+log = logging.getLogger(__name__)
+
+
+'''
+# Menu/Toolbar Lists:
+#
+# Sub items can be 1 of 3 types
+# - List Creates a section within the current menu
+# - Tuple Creates a submenu using a string or action as the parent. The child
+# can be another menu list or an identifier used to call a helper function.
+# - Action Appends a new menu item to the current menu
+#
+
+LIST_NAME = [
+ [Action1, Action2], # New section
+ (Action3, [Action4, Action5]), # Submenu with action as parent
+ ("Label", [Action6, Action7]), # Submenu with string as parent
+ ("Label2", "helper") # Submenu with helper function. Calls 'create_helper()'
+]
+'''
+
+
# The list of actions for the toolbar.
-TOOLBAR_LIST = (
- (Actions.FLOW_GRAPH_NEW, 'flow_graph_new'),
- (Actions.FLOW_GRAPH_OPEN, 'flow_graph_recent'),
- Actions.FLOW_GRAPH_SAVE,
- Actions.FLOW_GRAPH_CLOSE,
- None,
- Actions.TOGGLE_FLOW_GRAPH_VAR_EDITOR,
- Actions.FLOW_GRAPH_SCREEN_CAPTURE,
- None,
- Actions.BLOCK_CUT,
- Actions.BLOCK_COPY,
- Actions.BLOCK_PASTE,
- Actions.ELEMENT_DELETE,
- None,
- Actions.FLOW_GRAPH_UNDO,
- Actions.FLOW_GRAPH_REDO,
- None,
- Actions.ERRORS_WINDOW_DISPLAY,
- Actions.FLOW_GRAPH_GEN,
- Actions.FLOW_GRAPH_EXEC,
- Actions.FLOW_GRAPH_KILL,
- None,
- Actions.BLOCK_ROTATE_CCW,
- Actions.BLOCK_ROTATE_CW,
- None,
- Actions.BLOCK_ENABLE,
- Actions.BLOCK_DISABLE,
- Actions.BLOCK_BYPASS,
- Actions.TOGGLE_HIDE_DISABLED_BLOCKS,
- None,
- Actions.FIND_BLOCKS,
- Actions.RELOAD_BLOCKS,
- Actions.OPEN_HIER,
-)
+TOOLBAR_LIST = [
+ [(Actions.FLOW_GRAPH_NEW, 'flow_graph_new'), Actions.FLOW_GRAPH_OPEN,
+ (Actions.FLOW_GRAPH_OPEN_RECENT, 'flow_graph_recent'), Actions.FLOW_GRAPH_SAVE, Actions.FLOW_GRAPH_CLOSE],
+ [Actions.TOGGLE_FLOW_GRAPH_VAR_EDITOR, Actions.FLOW_GRAPH_SCREEN_CAPTURE],
+ [Actions.BLOCK_CUT, Actions.BLOCK_COPY, Actions.BLOCK_PASTE, Actions.ELEMENT_DELETE],
+ [Actions.FLOW_GRAPH_UNDO, Actions.FLOW_GRAPH_REDO],
+ [Actions.ERRORS_WINDOW_DISPLAY, Actions.FLOW_GRAPH_GEN, Actions.FLOW_GRAPH_EXEC, Actions.FLOW_GRAPH_KILL],
+ [Actions.BLOCK_ROTATE_CCW, Actions.BLOCK_ROTATE_CW],
+ [Actions.BLOCK_ENABLE, Actions.BLOCK_DISABLE, Actions.BLOCK_BYPASS, Actions.TOGGLE_HIDE_DISABLED_BLOCKS],
+ [Actions.FIND_BLOCKS, Actions.RELOAD_BLOCKS, Actions.OPEN_HIER]
+]
# The list of actions and categories for the menu bar.
-MENU_BAR_LIST = (
- (Gtk.Action(name='File', label='_File'), [
- 'flow_graph_new',
- Actions.FLOW_GRAPH_DUPLICATE,
- Actions.FLOW_GRAPH_OPEN,
- 'flow_graph_recent',
- None,
- Actions.FLOW_GRAPH_SAVE,
- Actions.FLOW_GRAPH_SAVE_AS,
- Actions.FLOW_GRAPH_SAVE_A_COPY,
- None,
- Actions.FLOW_GRAPH_SCREEN_CAPTURE,
- None,
- Actions.FLOW_GRAPH_CLOSE,
- Actions.APPLICATION_QUIT,
- ]),
- (Gtk.Action(name='Edit', label='_Edit'), [
- Actions.FLOW_GRAPH_UNDO,
- Actions.FLOW_GRAPH_REDO,
- None,
- Actions.BLOCK_CUT,
- Actions.BLOCK_COPY,
- Actions.BLOCK_PASTE,
- Actions.ELEMENT_DELETE,
- Actions.SELECT_ALL,
- None,
- Actions.BLOCK_ROTATE_CCW,
- Actions.BLOCK_ROTATE_CW,
- (Gtk.Action(name='Align', label='_Align', tooltip=None, stock_id=None), Actions.BLOCK_ALIGNMENTS),
- None,
- Actions.BLOCK_ENABLE,
- Actions.BLOCK_DISABLE,
- Actions.BLOCK_BYPASS,
- None,
- Actions.BLOCK_PARAM_MODIFY,
- ]),
- (Gtk.Action(name='View', label='_View'), [
- Actions.TOGGLE_BLOCKS_WINDOW,
- None,
- Actions.TOGGLE_CONSOLE_WINDOW,
- Actions.TOGGLE_SCROLL_LOCK,
- Actions.SAVE_CONSOLE,
- Actions.CLEAR_CONSOLE,
- None,
- Actions.TOGGLE_HIDE_VARIABLES,
- Actions.TOGGLE_FLOW_GRAPH_VAR_EDITOR,
- Actions.TOGGLE_FLOW_GRAPH_VAR_EDITOR_SIDEBAR,
- None,
- Actions.TOGGLE_HIDE_DISABLED_BLOCKS,
- Actions.TOGGLE_AUTO_HIDE_PORT_LABELS,
- Actions.TOGGLE_SNAP_TO_GRID,
- Actions.TOGGLE_SHOW_BLOCK_COMMENTS,
- None,
- Actions.TOGGLE_SHOW_CODE_PREVIEW_TAB,
- None,
- Actions.ERRORS_WINDOW_DISPLAY,
- Actions.FIND_BLOCKS,
- ]),
- (Gtk.Action(name='Run', label='_Run'), [
- Actions.FLOW_GRAPH_GEN,
- Actions.FLOW_GRAPH_EXEC,
- Actions.FLOW_GRAPH_KILL,
- ]),
- (Gtk.Action(name='Tools', label='_Tools'), [
- Actions.TOOLS_RUN_FDESIGN,
- Actions.FLOW_GRAPH_OPEN_QSS_THEME,
- None,
- Actions.TOGGLE_SHOW_FLOWGRAPH_COMPLEXITY,
- None,
- Actions.TOOLS_MORE_TO_COME,
- ]),
- (Gtk.Action(name='Help', label='_Help'), [
- Actions.HELP_WINDOW_DISPLAY,
- Actions.TYPES_WINDOW_DISPLAY,
- Actions.XML_PARSER_ERRORS_DISPLAY,
- None,
- Actions.ABOUT_WINDOW_DISPLAY,
- ]),
-)
+MENU_BAR_LIST = [
+ ('_File', [
+ [(Actions.FLOW_GRAPH_NEW, 'flow_graph_new'), Actions.FLOW_GRAPH_DUPLICATE,
+ Actions.FLOW_GRAPH_OPEN, (Actions.FLOW_GRAPH_OPEN_RECENT, 'flow_graph_recent')],
+ [Actions.FLOW_GRAPH_SAVE, Actions.FLOW_GRAPH_SAVE_AS, Actions.FLOW_GRAPH_SAVE_COPY],
+ [Actions.FLOW_GRAPH_SCREEN_CAPTURE],
+ [Actions.FLOW_GRAPH_CLOSE, Actions.APPLICATION_QUIT]
+ ]),
+ ('_Edit', [
+ [Actions.FLOW_GRAPH_UNDO, Actions.FLOW_GRAPH_REDO],
+ [Actions.BLOCK_CUT, Actions.BLOCK_COPY, Actions.BLOCK_PASTE, Actions.ELEMENT_DELETE, Actions.SELECT_ALL],
+ [Actions.BLOCK_ROTATE_CCW, Actions.BLOCK_ROTATE_CW, ('_Align', Actions.BLOCK_ALIGNMENTS)],
+ [Actions.BLOCK_ENABLE, Actions.BLOCK_DISABLE, Actions.BLOCK_BYPASS],
+ [Actions.BLOCK_PARAM_MODIFY]
+ ]),
+ ('_View', [
+ [Actions.TOGGLE_BLOCKS_WINDOW],
+ [Actions.TOGGLE_CONSOLE_WINDOW, Actions.TOGGLE_SCROLL_LOCK, Actions.SAVE_CONSOLE, Actions.CLEAR_CONSOLE],
+ [Actions.TOGGLE_HIDE_VARIABLES, Actions.TOGGLE_FLOW_GRAPH_VAR_EDITOR, Actions.TOGGLE_FLOW_GRAPH_VAR_EDITOR_SIDEBAR],
+ [Actions.TOGGLE_HIDE_DISABLED_BLOCKS, Actions.TOGGLE_AUTO_HIDE_PORT_LABELS, Actions.TOGGLE_SNAP_TO_GRID, Actions.TOGGLE_SHOW_BLOCK_COMMENTS],
+ [Actions.TOGGLE_SHOW_CODE_PREVIEW_TAB],
+ [Actions.ERRORS_WINDOW_DISPLAY, Actions.FIND_BLOCKS],
+ ]),
+ ('_Run', [
+ Actions.FLOW_GRAPH_GEN, Actions.FLOW_GRAPH_EXEC, Actions.FLOW_GRAPH_KILL
+ ]),
+ ('_Tools', [
+ [Actions.TOOLS_RUN_FDESIGN, Actions.FLOW_GRAPH_OPEN_QSS_THEME],
+ [Actions.TOGGLE_SHOW_FLOWGRAPH_COMPLEXITY]
+ ]),
+ ('_Help', [
+ [Actions.HELP_WINDOW_DISPLAY, Actions.TYPES_WINDOW_DISPLAY, Actions.XML_PARSER_ERRORS_DISPLAY],
+ [Actions.ABOUT_WINDOW_DISPLAY]
+ ])]
# The list of actions for the context menu.
CONTEXT_MENU_LIST = [
- Actions.BLOCK_CUT,
- Actions.BLOCK_COPY,
- Actions.BLOCK_PASTE,
- Actions.ELEMENT_DELETE,
- None,
- Actions.BLOCK_ROTATE_CCW,
- Actions.BLOCK_ROTATE_CW,
- Actions.BLOCK_ENABLE,
- Actions.BLOCK_DISABLE,
- Actions.BLOCK_BYPASS,
- None,
- (Gtk.Action(name='More', label='_More'), [
- Actions.BLOCK_CREATE_HIER,
- Actions.OPEN_HIER,
- None,
- Actions.BUSSIFY_SOURCES,
- Actions.BUSSIFY_SINKS,
- ]),
- Actions.BLOCK_PARAM_MODIFY
+ [Actions.BLOCK_CUT, Actions.BLOCK_COPY, Actions.BLOCK_PASTE, Actions.ELEMENT_DELETE],
+ [Actions.BLOCK_ROTATE_CCW, Actions.BLOCK_ROTATE_CW, Actions.BLOCK_ENABLE, Actions.BLOCK_DISABLE, Actions.BLOCK_BYPASS],
+ [("_More", [
+ [Actions.BLOCK_CREATE_HIER, Actions.OPEN_HIER],
+ [Actions.BUSSIFY_SOURCES, Actions.BUSSIFY_SINKS]]
+ )],
+ [Actions.BLOCK_PARAM_MODIFY],
]
-class SubMenuCreator(object):
+class SubMenuHelper(object):
+ ''' Generates custom submenus for the main menu or toolbar. '''
- def __init__(self, generate_modes, action_handler_callback):
- self.generate_modes = generate_modes
- self.action_handler_callback = action_handler_callback
- self.submenus = []
+ def __init__(self):
+ self.submenus = {}
- def create_submenu(self, action_tuple, item):
- func = getattr(self, '_fill_' + action_tuple[1] + "_submenu")
- self.submenus.append((action_tuple[0], func, item))
- self.refresh_submenus()
+ def build_submenu(self, name, obj, set_func):
+ # Get the correct helper function
+ create_func = getattr(self, "create_{}".format(name))
+ # Save the helper functions for rebuilding the menu later
+ self.submenus[name] = (create_func, obj, set_func)
+ # Actually build the menu
+ set_func(obj, create_func())
def refresh_submenus(self):
- for action, func, item in self.submenus:
- try:
- item.set_property("menu", func(action))
- except TypeError:
- item.set_property("submenu", func(action))
- item.set_property('sensitive', True)
-
- def callback_adaptor(self, item, action_key):
- action, key = action_key
- self.action_handler_callback(action, key)
-
- def _fill_flow_graph_new_submenu(self, action):
- """Sub menu to create flow-graph with pre-set generate mode"""
- menu = Gtk.Menu()
- for key, name, default in self.generate_modes:
- if default:
- item = Actions.FLOW_GRAPH_NEW.create_menu_item()
- item.set_label(name)
- else:
- item = Gtk.MenuItem(name=name, use_underline=False)
- item.connect('activate', self.callback_adaptor, (action, key))
- menu.append(item)
- menu.show_all()
+ for name in self.submenus:
+ create_func, obj, set_func = self.submenus[name]
+ print ("refresh", create_func, obj, set_func)
+ set_func(obj, create_func())
+
+ def create_flow_graph_new(self):
+ """ Different flowgraph types """
+ menu = Gio.Menu()
+ platform = Gtk.Application.get_default().platform
+ generate_modes = platform.get_generate_options()
+ for key, name, default in generate_modes:
+ target = "app.flowgraph.new::{}".format(key)
+ menu.append(name, target)
return menu
- def _fill_flow_graph_recent_submenu(self, action):
- """menu showing recent flow-graphs"""
- menu = Gtk.Menu()
+ def create_flow_graph_recent(self):
+ """ Recent flow graphs """
+
config = Gtk.Application.get_default().config
recent_files = config.get_recent_files()
+ menu = Gio.Menu()
if len(recent_files) > 0:
+ files = Gio.Menu()
for i, file_name in enumerate(recent_files):
- item = Gtk.MenuItem(name="%d. %s" % (i+1, file_name), use_underline=False)
- item.connect('activate', self.callback_adaptor,
- (action, file_name))
- menu.append(item)
- menu.show_all()
- return menu
- return None
+ target = "app.flowgraph.open_recent::{}".format(file_name)
+ files.append(file_name, target)
+ menu.append_section(None, files)
+ #clear = Gio.Menu()
+ #clear.append("Clear recent files", "app.flowgraph.clear_recent")
+ #menu.append_section(None, clear)
+ else:
+ # Show an empty menu
+ menuitem = Gio.MenuItem.new("No items found", "app.none")
+ menu.append_item(menuitem)
+ return menu
-class Toolbar(Gtk.Toolbar, SubMenuCreator):
- """The gtk toolbar with actions added from the toolbar list."""
+class MenuHelper(SubMenuHelper):
+ """
+ Recursively builds a menu from a given list of actions.
- def __init__(self, generate_modes, action_handler_callback):
- """
- 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.
- """
- GObject.GObject.__init__(self)
- self.set_style(Gtk.ToolbarStyle.ICONS)
- SubMenuCreator.__init__(self, generate_modes, action_handler_callback)
-
- for action in TOOLBAR_LIST:
- if isinstance(action, tuple) and isinstance(action[1], str):
- # create a button with a sub-menu
- # TODO: Fix later
- #action[0].set_tool_item_type(Gtk.MenuToolButton)
- item = action[0].create_tool_item()
- #self.create_submenu(action, item)
- #self.refresh_submenus()
-
- elif action is None:
- item = Gtk.SeparatorToolItem()
-
- else:
- #TODO: Fix later
- #action.set_tool_item_type(Gtk.ToolButton)
- item = action.create_tool_item()
- # this reset of the tooltip property is required
- # (after creating the tool item) for the tooltip to show
- action.set_property('tooltip', action.get_property('tooltip'))
- self.add(item)
-
-
-class MenuHelperMixin(object):
- """Mixin class to help build menus from the above action lists"""
-
- def _fill_menu(self, actions, menu=None):
- """Create a menu from list of actions"""
- menu = menu or Gtk.Menu()
+ Args:
+ - actions: List of actions to build the menu
+ - menu: Current menu being built
+
+ Notes:
+ - Tuple: Create a new submenu from the parent (1st) and child (2nd) elements
+ - Action: Append to current menu
+ - List: Start a new section
+ """
+
+ def __init__(self):
+ SubMenuHelper.__init__(self)
+
+ def build_menu(self, actions, menu):
for item in actions:
if isinstance(item, tuple):
- menu_item = self._make_sub_menu(*item)
- elif isinstance(item, str):
- menu_item = getattr(self, 'create_' + item)()
- elif item is None:
- menu_item = Gtk.SeparatorMenuItem()
- else:
- menu_item = item.create_menu_item()
- menu.append(menu_item)
- menu.show_all()
- return menu
-
- def _make_sub_menu(self, main, actions):
- """Create a submenu from a main action and a list of actions"""
- main = main.create_menu_item()
- main.set_submenu(self._fill_menu(actions))
- return main
+ # Create a new submenu
+ parent, child = (item[0], item[1])
+
+ # Create the parent
+ label, target = (parent, None)
+ if isinstance(parent, Actions.Action):
+ label = parent.label
+ target = "{}.{}".format(parent.prefix, parent.name)
+ menuitem = Gio.MenuItem.new(label, None)
+ if hasattr(parent, "icon_name"):
+ menuitem.set_icon(Gio.Icon.new_for_string(parent.icon_name))
+
+ # Create the new submenu
+ if isinstance(child, list):
+ submenu = Gio.Menu()
+ self.build_menu(child, submenu)
+ menuitem.set_submenu(submenu)
+ elif isinstance(child, str):
+ # Child is the name of the submenu to create
+ def set_func(obj, menu):
+ obj.set_submenu(menu)
+ self.build_submenu(child, menuitem, set_func)
+ menu.append_item(menuitem)
+
+ elif isinstance(item, list):
+ # Create a new section
+ section = Gio.Menu()
+ self.build_menu(item, section)
+ menu.append_section(None, section)
+
+ elif isinstance(item, Actions.Action):
+ # Append a new menuitem
+ target = "{}.{}".format(item.prefix, item.name)
+ menuitem = Gio.MenuItem.new(item.label, target)
+ if item.icon_name:
+ menuitem.set_icon(Gio.Icon.new_for_string(item.icon_name))
+ menu.append_item(menuitem)
+
+
+class ToolbarHelper(SubMenuHelper):
+ """
+ Builds a toolbar from a given list of actions.
+
+ Args:
+ - actions: List of actions to build the menu
+ - item: Current menu being built
+
+ Notes:
+ - Tuple: Create a new submenu from the parent (1st) and child (2nd) elements
+ - Action: Append to current menu
+ - List: Start a new section
+ """
+ def __init__(self):
+ SubMenuHelper.__init__(self)
-class MenuBar(Gtk.MenuBar, MenuHelperMixin, SubMenuCreator):
- """The gtk menu bar with actions added from the menu bar list."""
+ def build_toolbar(self, actions, current):
+ for item in actions:
+ if isinstance(item, list):
+ # Toolbar's don't have sections like menus, so call this function
+ # recursively with the "section" and just append a separator.
+ self.build_toolbar(item, self)
+ current.insert(Gtk.SeparatorToolItem.new(), -1)
+
+ elif isinstance(item, tuple):
+ parent, child = (item[0], item[1])
+ # Create an item with a submenu
+ # Generate the submenu and add to the item.
+ # Add the item to the toolbar
+ button = Gtk.MenuToolButton.new()
+ # The tuple should be made up of an Action and something.
+ button.set_label(parent.label)
+ button.set_tooltip_text(parent.tooltip)
+ button.set_icon_name(parent.icon_name)
+
+ target = "{}.{}".format(parent.prefix, parent.name)
+ button.set_action_name(target)
+
+ def set_func(obj, menu):
+ obj.set_menu(Gtk.Menu.new_from_model(menu))
+
+ self.build_submenu(child, button, set_func)
+ current.insert(button, -1)
+
+ elif isinstance(item, Actions.Action):
+ button = Gtk.ToolButton.new()
+ button.set_label(item.label)
+ button.set_tooltip_text(item.tooltip)
+ button.set_icon_name(item.icon_name)
+ target = "{}.{}".format(item.prefix, item.name)
+ button.set_action_name(target)
+ current.insert(button, -1)
+
+
+class Menu(Gio.Menu, MenuHelper):
+ """ Main Menu """
- def __init__(self, generate_modes, action_handler_callback):
- """
- 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 menu bar.
- """
+ def __init__(self):
GObject.GObject.__init__(self)
- SubMenuCreator.__init__(self, generate_modes, action_handler_callback)
- for main_action, actions in MENU_BAR_LIST:
- self.append(self._make_sub_menu(main_action, actions))
+ MenuHelper.__init__(self)
- def create_flow_graph_new(self):
- main = Gtk.ImageMenuItem(label=Gtk.STOCK_NEW)
- main.set_label(Actions.FLOW_GRAPH_NEW.get_label())
- func = self._fill_flow_graph_new_submenu
- self.submenus.append((Actions.FLOW_GRAPH_NEW, func, main))
- self.refresh_submenus()
- return main
+ log.debug("Building the main menu")
+ self.build_menu(MENU_BAR_LIST, self)
- def create_flow_graph_recent(self):
- main = Gtk.ImageMenuItem(label=Gtk.STOCK_OPEN)
- main.set_label(Actions.FLOW_GRAPH_OPEN_RECENT.get_label())
- func = self._fill_flow_graph_recent_submenu
- self.submenus.append((Actions.FLOW_GRAPH_OPEN, func, main))
- self.refresh_submenus()
- if main.get_submenu() is None:
- main.set_property('sensitive', False)
- return main
+class ContextMenu(Gio.Menu, MenuHelper):
+ """ Context menu for the drawing area """
+
+ def __init__(self):
+ GObject.GObject.__init__(self)
+
+ log.debug("Building the context menu")
+ self.build_menu(CONTEXT_MENU_LIST, self)
-class ContextMenu(Gtk.Menu, MenuHelperMixin):
- """The gtk menu with actions added from the context menu list."""
+
+class Toolbar(Gtk.Toolbar, ToolbarHelper):
+ """ The 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.
+ """
GObject.GObject.__init__(self)
- self._fill_menu(CONTEXT_MENU_LIST, self)
+ ToolbarHelper.__init__(self)
+
+ self.set_style(Gtk.ToolbarStyle.ICONS)
+ #self.get_style_context().add_class(Gtk.STYLE_CLASS_PRIMARY_TOOLBAR)
+
+ #SubMenuCreator.__init__(self)
+ self.build_toolbar(TOOLBAR_LIST, self)
diff --git a/grc/gui/Config.py b/grc/gui/Config.py
index c4d395c0b3..6135296660 100644
--- a/grc/gui/Config.py
+++ b/grc/gui/Config.py
@@ -48,7 +48,7 @@ class Config(CoreConfig):
self.install_prefix = install_prefix
Constants.update_font_size(self.font_size)
- self.parser = configparser.SafeConfigParser()
+ self.parser = configparser.ConfigParser()
for section in ['main', 'files_open', 'files_recent']:
try:
self.parser.add_section(section)
diff --git a/grc/gui/Console.py b/grc/gui/Console.py
index d40f300a8a..0ae862493d 100644
--- a/grc/gui/Console.py
+++ b/grc/gui/Console.py
@@ -20,6 +20,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
from __future__ import absolute_import
import os
+import logging
import gi
gi.require_version('Gtk', '3.0')
@@ -31,9 +32,14 @@ from .Dialogs import TextDisplay, MessageDialogWrapper
from ..core import Messages
+log = logging.getLogger(__name__)
+
+
class Console(Gtk.ScrolledWindow):
def __init__(self):
Gtk.ScrolledWindow.__init__(self)
+ log.debug("console()")
+ self.app = Gtk.Application.get_default()
self.text_display = TextDisplay()
diff --git a/grc/gui/DrawingArea.py b/grc/gui/DrawingArea.py
index 94dfcf1370..2403fa2844 100644
--- a/grc/gui/DrawingArea.py
+++ b/grc/gui/DrawingArea.py
@@ -23,6 +23,7 @@ from gi.repository import Gtk, Gdk
from .canvas.colors import FLOWGRAPH_BACKGROUND_COLOR
from . import Constants
+from . import Actions
class DrawingArea(Gtk.DrawingArea):
@@ -42,6 +43,7 @@ class DrawingArea(Gtk.DrawingArea):
Gtk.DrawingArea.__init__(self)
self._flow_graph = flow_graph
+ self.set_property('can_focus', True)
self.zoom_factor = 1.0
self._update_after_zoom = False
@@ -66,6 +68,11 @@ class DrawingArea(Gtk.DrawingArea):
# Gdk.EventMask.FOCUS_CHANGE_MASK
)
+ # This may not be the correct place to be handling the user events
+ # Should this be in the page instead?
+ # Or should more of the page functionality move here?
+ self.connect('key_press_event', self._handle_key_press)
+
# setup drag and drop
self.drag_dest_set(Gtk.DestDefaults.ALL, [], Gdk.DragAction.COPY)
self.connect('drag-data-received', self._handle_drag_data_received)
@@ -78,12 +85,14 @@ class DrawingArea(Gtk.DrawingArea):
def _handle_notify_event(widget, event, focus_flag):
self._focus_flag = focus_flag
+
self.connect('leave-notify-event', _handle_notify_event, False)
self.connect('enter-notify-event', _handle_notify_event, True)
# todo: fix
# self.set_flags(Gtk.CAN_FOCUS) # self.set_can_focus(True)
# self.connect('focus-out-event', self._handle_focus_lost_event)
+
##########################################################################
# Handlers
##########################################################################
@@ -155,6 +164,41 @@ class DrawingArea(Gtk.DrawingArea):
coordinate=self._translate_event_coords(event),
)
+ def _handle_key_press(self, widget, event):
+ """
+ Handle specific keypresses when the drawing area has focus that
+ triggers actions by the user.
+ """
+ key = event.keyval
+ mod = event.state
+
+ # Setup a map of the accelerator keys to the action to trigger
+ accels = {
+ Gtk.accelerator_parse('d'): Actions.BLOCK_DISABLE,
+ Gtk.accelerator_parse('e'): Actions.BLOCK_ENABLE,
+ Gtk.accelerator_parse('b'): Actions.BLOCK_BYPASS,
+ Gtk.accelerator_parse('c'): Actions.BLOCK_CREATE_HIER,
+ Gtk.accelerator_parse('Up'): Actions.BLOCK_DEC_TYPE,
+ Gtk.accelerator_parse('Down'): Actions.BLOCK_INC_TYPE,
+ Gtk.accelerator_parse('Left'): Actions.BLOCK_ROTATE_CCW,
+ Gtk.accelerator_parse('Right'): Actions.BLOCK_ROTATE_CW,
+ Gtk.accelerator_parse('minus'): Actions.PORT_CONTROLLER_DEC,
+ Gtk.accelerator_parse('plus'): Actions.PORT_CONTROLLER_INC,
+ Gtk.accelerator_parse('Add'): Actions.PORT_CONTROLLER_INC,
+ Gtk.accelerator_parse('Subtract'): Actions.PORT_CONTROLLER_DEC,
+ Gtk.accelerator_parse('Return'): Actions.BLOCK_PARAM_MODIFY,
+ Gtk.accelerator_parse('<Shift>t'): Actions.BLOCK_VALIGN_TOP,
+ Gtk.accelerator_parse('<Shift>m'): Actions.BLOCK_VALIGN_MIDDLE,
+ Gtk.accelerator_parse('<Shift>b'): Actions.BLOCK_VALIGN_BOTTOM,
+ Gtk.accelerator_parse('<Shift>l'): Actions.BLOCK_HALIGN_LEFT,
+ Gtk.accelerator_parse('<Shift>c'): Actions.BLOCK_HALIGN_CENTER,
+ Gtk.accelerator_parse('<Shift>r'): Actions.BLOCK_HALIGN_RIGHT,
+ }
+ # Not sold on this.
+ if (key, mod) in accels:
+ accels[(key, mod)]()
+ return True
+
def _update_size(self):
w, h = self._flow_graph.get_extents()[2:]
self.set_size_request(w * self.zoom_factor + 100, h * self.zoom_factor + 100)
diff --git a/grc/gui/MainWindow.py b/grc/gui/MainWindow.py
index 5bb4c52a07..c13a59a16d 100644
--- a/grc/gui/MainWindow.py
+++ b/grc/gui/MainWindow.py
@@ -35,6 +35,7 @@ from .Notebook import Notebook, Page
from ..core import Messages
+
log = logging.getLogger(__name__)
@@ -49,7 +50,7 @@ class MainWindow(Gtk.ApplicationWindow):
CONSOLE = 1
VARIABLES = 2
- def __init__(self, app, platform, action_handler_callback):
+ def __init__(self, app, platform):
"""
MainWindow constructor
Setup the menu, toolbar, flow graph editor notebook, block selection window...
@@ -58,18 +59,29 @@ class MainWindow(Gtk.ApplicationWindow):
log.debug("__init__()")
self._platform = platform
+ self.app = app
self.config = platform.config
+ # Add all "win" actions to the local
+ win_actions = filter(lambda x: x.startswith("win."), Actions.get_actions())
+ map(lambda x: self.add_action(Actions.actions[x]), win_actions)
+
# Setup window
vbox = Gtk.VBox()
self.add(vbox)
# Create the menu bar and toolbar
generate_modes = platform.get_generate_options()
- self.add_accel_group(Actions.get_accel_group())
- self.menu_bar = Bars.MenuBar(generate_modes, action_handler_callback)
+
+ # This needs to be replaced
+ # Have an option for either the application menu or this menu
+ self.menu_bar = Gtk.MenuBar.new_from_model(Bars.Menu())
vbox.pack_start(self.menu_bar, False, False, 0)
- self.tool_bar = Bars.Toolbar(generate_modes, action_handler_callback)
+
+ self.tool_bar = Bars.Toolbar()
+ self.tool_bar.set_hexpand(True)
+ # Show the toolbar
+ self.tool_bar.show()
vbox.pack_start(self.tool_bar, False, False, 0)
# Main parent container for the different panels
@@ -126,9 +138,7 @@ class MainWindow(Gtk.ApplicationWindow):
self.left_subpanel.set_position(self.config.variable_editor_position())
self.show_all()
- self.console.hide()
- self.vars.hide()
- self.btwin.hide()
+ log.debug("Main window ready")
############################################################
# Event Handlers
@@ -206,7 +216,6 @@ class MainWindow(Gtk.ApplicationWindow):
def current_page(self, page):
self.notebook.current_page = page
-
def add_console_line(self, line):
"""
Place line at the end of the text buffer, then scroll its window all the way down.
diff --git a/grc/gui/Notebook.py b/grc/gui/Notebook.py
index e78b748326..ef08961036 100644
--- a/grc/gui/Notebook.py
+++ b/grc/gui/Notebook.py
@@ -19,6 +19,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
from __future__ import absolute_import
import os
+import logging
from gi.repository import Gtk, Gdk, GObject
@@ -28,15 +29,24 @@ from .Constants import MIN_WINDOW_WIDTH, MIN_WINDOW_HEIGHT
from .DrawingArea import DrawingArea
+log = logging.getLogger(__name__)
+
+
class Notebook(Gtk.Notebook):
def __init__(self):
Gtk.Notebook.__init__(self)
-
+ log.debug("notebook()")
+ self.app = Gtk.Application.get_default()
self.current_page = None
+
self.set_show_border(False)
self.set_scrollable(True)
self.connect('switch-page', self._handle_page_change)
+ self.add_events(Gdk.EventMask.SCROLL_MASK)
+ self.connect('scroll-event', self._handle_scroll)
+ self._ignore_consecutive_scrolls = 0
+
def _handle_page_change(self, notebook, page, page_num):
"""
Handle a page change. When the user clicks on a new tab,
@@ -51,6 +61,26 @@ class Notebook(Gtk.Notebook):
self.current_page = self.get_nth_page(page_num)
Actions.PAGE_CHANGE()
+ def _handle_scroll(self, widget, event):
+ # Not sure how to handle this at the moment.
+ natural = True
+ # Slow it down
+ if self._ignore_consecutive_scrolls == 0:
+ if event.direction in (Gdk.ScrollDirection.UP, Gdk.ScrollDirection.LEFT):
+ if natural:
+ self.prev_page()
+ else:
+ self.next_page()
+ elif event.direction in (Gdk.ScrollDirection.DOWN, Gdk.ScrollDirection.RIGHT):
+ if natural:
+ self.next_page()
+ else:
+ self.prev_page()
+ self._ignore_consecutive_scrolls = 3
+ else:
+ self._ignore_consecutive_scrolls -= 1
+ return False
+
class Page(Gtk.HBox):
"""A page in the notebook."""
@@ -99,20 +129,12 @@ class Page(Gtk.HBox):
self.scrolled_window = Gtk.ScrolledWindow()
self.scrolled_window.set_size_request(MIN_WINDOW_WIDTH, MIN_WINDOW_HEIGHT)
self.scrolled_window.set_policy(Gtk.PolicyType.ALWAYS, Gtk.PolicyType.ALWAYS)
- self.scrolled_window.connect('key-press-event', self._handle_scroll_window_key_press)
+
self.scrolled_window.add(self.drawing_area)
self.pack_start(self.scrolled_window, True, True, 0)
-
self.show_all()
- def _handle_scroll_window_key_press(self, widget, event):
- """forward Ctrl-PgUp/Down to NotebookPage (switch fg instead of horiz. scroll"""
- is_ctrl_pg = (
- event.state & Gdk.ModifierType.CONTROL_MASK and
- event.keyval in (Gdk.KEY_Page_Up, Gdk.KEY_Page_Down)
- )
- if is_ctrl_pg:
- return self.get_parent().event(event)
+
def get_generator(self):
"""
diff --git a/grc/gui/ParamWidgets.py b/grc/gui/ParamWidgets.py
index b56eace402..71cb1b7a7d 100644
--- a/grc/gui/ParamWidgets.py
+++ b/grc/gui/ParamWidgets.py
@@ -25,7 +25,7 @@ from . import Utils
style_provider = Gtk.CssProvider()
-style_provider.load_from_data("""
+style_provider.load_from_data(b"""
#dtype_complex { background-color: #3399FF; }
#dtype_real { background-color: #FF8C69; }
#dtype_float { background-color: #FF8C69; }
diff --git a/grc/gui/StateCache.py b/grc/gui/StateCache.py
index b109a1281b..ef260d6091 100644
--- a/grc/gui/StateCache.py
+++ b/grc/gui/StateCache.py
@@ -99,5 +99,5 @@ class StateCache(object):
"""
Update the undo and redo actions based on the number of next and prev states.
"""
- Actions.FLOW_GRAPH_REDO.set_sensitive(self.num_next_states != 0)
- Actions.FLOW_GRAPH_UNDO.set_sensitive(self.num_prev_states != 0)
+ Actions.FLOW_GRAPH_REDO.set_enabled(self.num_next_states != 0)
+ Actions.FLOW_GRAPH_UNDO.set_enabled(self.num_prev_states != 0)
diff --git a/grc/gui/Utils.py b/grc/gui/Utils.py
index 3fffe6dd20..969f3759f2 100644
--- a/grc/gui/Utils.py
+++ b/grc/gui/Utils.py
@@ -21,6 +21,7 @@ from __future__ import absolute_import
from gi.repository import GLib
import cairo
+import six
from .canvas.colors import FLOWGRAPH_BACKGROUND_COLOR
from . import Constants
@@ -107,7 +108,10 @@ def encode(value):
Older versions of glib seg fault if the last byte starts a multi-byte
character.
"""
- valid_utf8 = value.decode('utf-8', errors='replace').encode('utf-8')
+ if six.PY2:
+ valid_utf8 = value.decode('utf-8', errors='replace').encode('utf-8')
+ else:
+ valid_utf8 = value
return GLib.markup_escape_text(valid_utf8)
diff --git a/grc/gui/VariableEditor.py b/grc/gui/VariableEditor.py
index 484395be8c..e310676420 100644
--- a/grc/gui/VariableEditor.py
+++ b/grc/gui/VariableEditor.py
@@ -254,7 +254,9 @@ class VariableEditor(Gtk.VBox):
elif key == self.ADD_VARIABLE:
self.emit('create_new_block', 'variable')
elif key == self.OPEN_PROPERTIES:
- Actions.BLOCK_PARAM_MODIFY(self._block)
+ # TODO: This probably isn't working because the action doesn't expect a parameter
+ #Actions.BLOCK_PARAM_MODIFY()
+ pass
elif key == self.DELETE_BLOCK:
self.emit('remove_block', self._block.get_id())
elif key == self.DELETE_CONFIRM:
diff --git a/grc/gui/canvas/param.py b/grc/gui/canvas/param.py
index 2ec99e70d8..b027b7653a 100644
--- a/grc/gui/canvas/param.py
+++ b/grc/gui/canvas/param.py
@@ -105,7 +105,7 @@ class Param(CoreParam):
if style < 0: # Front truncate
string = '...' + string[3-max_len:]
elif style == 0: # Center truncate
- string = string[:max_len/2 - 3] + '...' + string[-max_len/2:]
+ string = string[:max_len//2 - 3] + '...' + string[-max_len//2:]
elif style > 0: # Rear truncate
string = string[:max_len-3] + '...'
return string
diff --git a/grc/main.py b/grc/main.py
index 305e8b8f78..224a9b11e8 100755
--- a/grc/main.py
+++ b/grc/main.py
@@ -22,10 +22,6 @@ gi.require_version('Gtk', '3.0')
gi.require_version('PangoCairo', '1.0')
from gi.repository import Gtk
-from gnuradio import gr
-from .gui.Platform import Platform
-from .gui.Application import Application
-
VERSION_AND_DISCLAIMER_TEMPLATE = """\
GNU Radio Companion %s
@@ -45,6 +41,7 @@ LOG_LEVELS = {
def main():
+ from gnuradio import gr
parser = argparse.ArgumentParser(
description=VERSION_AND_DISCLAIMER_TEMPLATE % gr.version())
parser.add_argument('flow_graphs', nargs='*')
@@ -65,7 +62,8 @@ def main():
console = logging.StreamHandler()
console.setLevel(LOG_LEVELS[args.log])
- msg_format = '[%(asctime)s - %(levelname)8s] --- %(message)s (%(filename)s:%(lineno)s)'
+ #msg_format = '[%(asctime)s - %(levelname)8s] --- %(message)s (%(filename)s:%(lineno)s)'
+ msg_format = '[%(levelname)s] %(message)s (%(filename)s:%(lineno)s)'
date_format = '%I:%M'
formatter = logging.Formatter(msg_format, datefmt=date_format)
@@ -73,8 +71,14 @@ def main():
console.setFormatter(formatter)
log.addHandler(console)
- log.debug("Loading platform")
+ log.debug("Running main")
+ # Delay importing until the logging is setup
+ # Otherwise, the decorators could not use logging.
+ from .gui.Platform import Platform
+ from .gui.Application import Application
+
+ log.debug("Loading platform")
platform = Platform(
version=gr.version(),
version_parts=(gr.major_version(), gr.api_version(), gr.minor_version()),