diff options
author | Sebastian Koslowski <koslowski@kit.edu> | 2016-05-27 15:19:11 +0200 |
---|---|---|
committer | Sebastian Koslowski <koslowski@kit.edu> | 2016-05-30 15:46:37 +0200 |
commit | d290917e982ba4473a03e5a7e1acaa1e50c59f3d (patch) | |
tree | 2cc68a254358155085a4522d2a59f08a5518c180 /grc/gui | |
parent | 498715deea12451bd271d20b51c02f01530acd14 (diff) |
grc: gtk3: update props dialog
Diffstat (limited to 'grc/gui')
-rw-r--r-- | grc/gui/ActionHandler.py | 2 | ||||
-rw-r--r-- | grc/gui/Block.py | 2 | ||||
-rw-r--r-- | grc/gui/Constants.py | 2 | ||||
-rw-r--r-- | grc/gui/Param.py | 149 | ||||
-rw-r--r-- | grc/gui/ParamWidgets.py | 288 | ||||
-rw-r--r-- | grc/gui/PropsDialog.py | 137 |
6 files changed, 422 insertions, 158 deletions
diff --git a/grc/gui/ActionHandler.py b/grc/gui/ActionHandler.py index e25fa19030..7dc37cc91d 100644 --- a/grc/gui/ActionHandler.py +++ b/grc/gui/ActionHandler.py @@ -461,7 +461,7 @@ class ActionHandler: else: selected_block = flow_graph.get_selected_block() if selected_block: - self.dialog = PropsDialog(selected_block) + self.dialog = PropsDialog(self.main_window, selected_block) response = Gtk.ResponseType.APPLY while response == Gtk.ResponseType.APPLY: # rerun the dialog if Apply was hit response = self.dialog.run() diff --git a/grc/gui/Block.py b/grc/gui/Block.py index f8687be42f..5e5c5c402c 100644 --- a/grc/gui/Block.py +++ b/grc/gui/Block.py @@ -180,7 +180,7 @@ class Block(Element, _Block): font=PARAM_FONT, key=self._key )] else: - markups = [param.get_markup() for param in self.get_params() if param.get_hide() not in ('all', 'part')] + markups = [param.format_block_surface_markup() for param in self.get_params() if param.get_hide() not in ('all', 'part')] if markups: layout = Gtk.DrawingArea().create_pango_layout('') layout.set_spacing(LABEL_SEPARATION*Pango.SCALE) diff --git a/grc/gui/Constants.py b/grc/gui/Constants.py index 4508efcb47..4ab644e8a1 100644 --- a/grc/gui/Constants.py +++ b/grc/gui/Constants.py @@ -38,7 +38,7 @@ NEW_FLOGRAPH_TITLE = 'untitled' MIN_WINDOW_WIDTH = 600 MIN_WINDOW_HEIGHT = 400 # dialog constraints -MIN_DIALOG_WIDTH = 500 +MIN_DIALOG_WIDTH = 600 MIN_DIALOG_HEIGHT = 500 # default sizes DEFAULT_BLOCKS_WINDOW_WIDTH = 100 diff --git a/grc/gui/Param.py b/grc/gui/Param.py index 1c5b0c9c8c..a087d4b337 100644 --- a/grc/gui/Param.py +++ b/grc/gui/Param.py @@ -19,12 +19,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA import os -import gi -gi.require_version('Gtk', '3.0') -from gi.repository import Gtk -from gi.repository import Gdk -from gi.repository import GObject - +from gi.repository import Gtk, Gdk from . import Colors, Utils, Constants from .Element import Element @@ -37,17 +32,20 @@ class InputParam(Gtk.HBox): expand = False def __init__(self, param, changed_callback=None, editing_callback=None): - GObject.GObject.__init__(self) + Gtk.HBox.__init__(self) + self.param = param self._changed_callback = changed_callback self._editing_callback = editing_callback - self.label = Gtk.Label() #no label, markup is added by set_markup + + self.label = Gtk.Label() self.label.set_size_request(150, -1) - self.pack_start(self.label, False) - self.set_markup = lambda m: self.label.set_markup(m) + self.label.show() + self.pack_start(self.label, False, False, 0) + self.tp = None self._have_pending_changes = False - #connect events + self.connect('show', self._update_gui) def set_color(self, color): @@ -63,40 +61,17 @@ class InputParam(Gtk.HBox): """ Set the markup, color, tooltip, show/hide. """ - param = self.param + self.label.set_markup(self.param.format_label_markup(self._have_pending_changes)) - has_callback = \ - hasattr(param.get_parent(), 'get_callbacks') and \ - any(param.get_key() in callback for callback in param.get_parent()._callbacks) + # fixme: find a non-deprecated way to change colors + # self.set_color(Colors.PARAM_ENTRY_COLORS.get( + # self.param.get_type(), Colors.PARAM_ENTRY_DEFAULT_COLOR) + # ) - self.set_markup('<span underline="{line}" foreground="{color}" font_desc="Sans 9">{label}</span>'.format( - line='low' if has_callback else 'none', - color='blue' if self._have_pending_changes else - 'black' if param.is_valid() else - 'red', - label=Utils.encode(self.param.get_name()) - )) - - self.set_color(Colors.PARAM_ENTRY_COLORS.get( - self.param.get_type(), Colors.PARAM_ENTRY_DEFAULT_COLOR) - ) - - errors = param.get_error_messages() - tooltip_lines = ['Key: ' + param.get_key(), 'Type: ' + param.get_type()] - if param.is_valid(): - value = str(param.get_evaluated()) - if len(value) > 100: - value = '{}...{}'.format(value[:50], value[-50:]) - tooltip_lines.append('Value: ' + value) - elif len(errors) == 1: - tooltip_lines.append('Error: ' + errors[0]) - elif len(errors) > 1: - tooltip_lines.append('Error:') - tooltip_lines.extend(' * ' + msg for msg in errors) - self.set_tooltip_text('\n'.join(tooltip_lines)) + self.set_tooltip_text(self.param.format_tooltip_text()) if self.param.get_hide() == 'all': - self.hide_all() + self.hide() else: self.show_all() @@ -146,7 +121,7 @@ class EntryParam(InputParam): self._input.connect('changed', self._mark_changed) self._input.connect('focus-out-event', self._apply_change) self._input.connect('key-press-event', self._handle_key_press) - self.pack_start(self._input, True) + self.pack_start(self._input, True, True, 0) def get_text(self): return self._input.get_text() @@ -155,10 +130,7 @@ class EntryParam(InputParam): self._input.override_background_color(Gtk.StateType.NORMAL, color) def set_tooltip_text(self, text): - try: - self._input.set_tooltip_text(text) - except AttributeError: - pass # no tooltips for old GTK + self._input.set_tooltip_text(text) class MultiLineEntryParam(InputParam): @@ -171,29 +143,29 @@ class MultiLineEntryParam(InputParam): self._buffer.set_text(self.param.get_value()) self._buffer.connect('changed', self._mark_changed) - self._view = Gtk.TextView(self._buffer) + self._view = Gtk.TextView() + self._view.set_buffer(self._buffer) self._view.connect('focus-out-event', self._apply_change) self._view.connect('key-press-event', self._handle_key_press) + # fixme: add border to TextView self._sw = Gtk.ScrolledWindow() self._sw.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC) self._sw.add_with_viewport(self._view) - self.pack_start(self._sw, True) + self.pack_start(self._sw, True, True, True) def get_text(self): buf = self._buffer - return buf.get_text(buf.get_start_iter(), - buf.get_end_iter()).strip() + text = buf.get_text(buf.get_start_iter(), buf.get_end_iter(), + include_hidden_chars=False) + return text.strip() def set_color(self, color): self._view.override_background_color(Gtk.StateType.NORMAL, color) def set_tooltip_text(self, text): - try: - self._view.set_tooltip_text(text) - except AttributeError: - pass # no tooltips for old GTK + self._view.set_tooltip_text(text) # try: @@ -264,16 +236,13 @@ class EnumParam(InputParam): self._input.set_active(self.param.get_option_keys().index(self.param.get_value())) self._input.connect('changed', self._editing_callback) self._input.connect('changed', self._apply_change) - self.pack_start(self._input, False) + self.pack_start(self._input, False, False, 0) def get_text(self): return self.param.get_option_keys()[self._input.get_active()] def set_tooltip_text(self, text): - try: - self._input.set_tooltip_text(text) - except AttributeError: - pass # no tooltips for old GTK + self._input.set_tooltip_text(text) class EnumEntryParam(InputParam): @@ -281,17 +250,23 @@ class EnumEntryParam(InputParam): def __init__(self, *args, **kwargs): InputParam.__init__(self, *args, **kwargs) - self._input = Gtk.combo_box_entry_new_text() - for option in self.param.get_options(): self._input.append_text(option.get_name()) - try: self._input.set_active(self.param.get_option_keys().index(self.param.get_value())) - except: + self._input = Gtk.ComboBoxText.new_with_entry() + for option in self.param.get_options(): + self._input.append_text(option.get_name()) + + value = self.param.get_value() + try: + active_index = self.param.get_option_keys().index(value) + self._input.set_active(active_index) + except ValueError: self._input.set_active(-1) - self._input.get_child().set_text(self.param.get_value()) + self._input.get_child().set_text(value) + self._input.connect('changed', self._apply_change) self._input.get_child().connect('changed', self._mark_changed) self._input.get_child().connect('focus-out-event', self._apply_change) self._input.get_child().connect('key-press-event', self._handle_key_press) - self.pack_start(self._input, False) + self.pack_start(self._input, False, False, 0) @property def has_custom_value(self): @@ -302,13 +277,10 @@ class EnumEntryParam(InputParam): return self.param.get_option_keys()[self._input.get_active()] def set_tooltip_text(self, text): - try: - if self._input.get_active() == -1: #custom entry - self._input.get_child().set_tooltip_text(text) - else: - self._input.set_tooltip_text(text) - except AttributeError: - pass # no tooltips for old GTK + if self.has_custom_value: # custom entry + self._input.get_child().set_tooltip_text(text) + else: + self._input.set_tooltip_text(text) def set_color(self, color): self._input.get_child().modify_base( @@ -324,7 +296,7 @@ class FileParam(EntryParam): EntryParam.__init__(self, *args, **kwargs) input = Gtk.Button('...') input.connect('clicked', self._handle_clicked) - self.pack_start(input, False) + self.pack_start(input, False, False, 0) def _handle_clicked(self, widget=None): """ @@ -403,7 +375,36 @@ class Param(Element, _Param): return input_widget - def get_markup(self): + def format_label_markup(self, have_pending_changes=False): + block = self.get_parent() + has_callback = \ + hasattr(block, 'get_callbacks') and \ + any(self.get_key() in callback for callback in block._callbacks) + + return '<span underline="{line}" foreground="{color}" font_desc="Sans 9">{label}</span>'.format( + line='low' if has_callback else 'none', + color='blue' if have_pending_changes else + 'black' if self.is_valid() else + 'red', + label=Utils.encode(self.get_name()) + ) + + def format_tooltip_text(self): + errors = self.get_error_messages() + tooltip_lines = ['Key: ' + self.get_key(), 'Type: ' + self.get_type()] + if self.is_valid(): + value = str(self.get_evaluated()) + if len(value) > 100: + value = '{}...{}'.format(value[:50], value[-50:]) + tooltip_lines.append('Value: ' + value) + elif len(errors) == 1: + tooltip_lines.append('Error: ' + errors[0]) + elif len(errors) > 1: + tooltip_lines.append('Error:') + tooltip_lines.extend(' * ' + msg for msg in errors) + return '\n'.join(tooltip_lines) + + def format_block_surface_markup(self): """ Get the markup for this param. diff --git a/grc/gui/ParamWidgets.py b/grc/gui/ParamWidgets.py new file mode 100644 index 0000000000..eab6a315b9 --- /dev/null +++ b/grc/gui/ParamWidgets.py @@ -0,0 +1,288 @@ +# -*- coding: utf-8 -*- +"""${FILE_NAME}""" +import os + +from grc.gui import Colors + +__author__ = "Sebastian Koslowski" +__email__ = "sebastian.koslowski@gmail.com" +__copyright__ = "Copyright 2016, Sebastian Koslowski" + + +class InputParam(Gtk.HBox): + """The base class for an input parameter inside the input parameters dialog.""" + expand = False + + def __init__(self, param, changed_callback=None, editing_callback=None): + Gtk.HBox.__init__(self) + + self.param = param + self._changed_callback = changed_callback + self._editing_callback = editing_callback + + self.label = Gtk.Label() + self.label.set_size_request(150, -1) + self.label.show() + self.pack_start(self.label, False, False, 0) + + self.tp = None + self._have_pending_changes = False + + self.connect('show', self._update_gui) + + def set_color(self, color): + pass + + def set_tooltip_text(self, text): + pass + + def get_text(self): + raise NotImplementedError() + + def _update_gui(self, *args): + """ + Set the markup, color, tooltip, show/hide. + """ + self.label.set_markup(self.param.format_label_markup(self._have_pending_changes)) + + # fixme: find a non-deprecated way to change colors + # self.set_color(Colors.PARAM_ENTRY_COLORS.get( + # self.param.get_type(), Colors.PARAM_ENTRY_DEFAULT_COLOR) + # ) + + self.set_tooltip_text(self.param.format_tooltip_text()) + + if self.param.get_hide() == 'all': + self.hide() + else: + self.show_all() + + def _mark_changed(self, *args): + """ + Mark this param as modified on change, but validate only on focus-lost + """ + self._have_pending_changes = True + self._update_gui() + if self._editing_callback: + self._editing_callback(self, None) + + def _apply_change(self, *args): + """ + Handle a gui change by setting the new param value, + calling the callback (if applicable), and updating. + """ + #set the new value + self.param.set_value(self.get_text()) + #call the callback + if self._changed_callback: + self._changed_callback(self, None) + else: + self.param.validate() + #gui update + self._have_pending_changes = False + self._update_gui() + + def _handle_key_press(self, widget, event): + if event.keyval == Gdk.KEY_Return and event.get_state() & Gdk.ModifierType.CONTROL_MASK: + self._apply_change(widget, event) + return True + return False + + def apply_pending_changes(self): + if self._have_pending_changes: + self._apply_change() + + +class EntryParam(InputParam): + """Provide an entry box for strings and numbers.""" + + def __init__(self, *args, **kwargs): + InputParam.__init__(self, *args, **kwargs) + self._input = Gtk.Entry() + self._input.set_text(self.param.get_value()) + self._input.connect('changed', self._mark_changed) + self._input.connect('focus-out-event', self._apply_change) + self._input.connect('key-press-event', self._handle_key_press) + self.pack_start(self._input, True, True, 0) + + def get_text(self): + return self._input.get_text() + + def set_color(self, color): + self._input.override_background_color(Gtk.StateType.NORMAL, color) + + def set_tooltip_text(self, text): + self._input.set_tooltip_text(text) + + +class MultiLineEntryParam(InputParam): + """Provide an multi-line box for strings.""" + expand = True + + def __init__(self, *args, **kwargs): + InputParam.__init__(self, *args, **kwargs) + self._buffer = Gtk.TextBuffer() + self._buffer.set_text(self.param.get_value()) + self._buffer.connect('changed', self._mark_changed) + + self._view = Gtk.TextView() + self._view.set_buffer(self._buffer) + self._view.connect('focus-out-event', self._apply_change) + self._view.connect('key-press-event', self._handle_key_press) + # fixme: add border to TextView + + self._sw = Gtk.ScrolledWindow() + self._sw.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC) + self._sw.add_with_viewport(self._view) + + self.pack_start(self._sw, True, True, True) + + def get_text(self): + buf = self._buffer + text = buf.get_text(buf.get_start_iter(), buf.get_end_iter(), + include_hidden_chars=False) + return text.strip() + + def set_color(self, color): + self._view.override_background_color(Gtk.StateType.NORMAL, color) + + def set_tooltip_text(self, text): + self._view.set_tooltip_text(text) + + +class PythonEditorParam(InputParam): + + def __init__(self, *args, **kwargs): + InputParam.__init__(self, *args, **kwargs) + button = self._button = Gtk.Button('Open in Editor') + button.connect('clicked', self.open_editor) + self.pack_start(button, True) + + def open_editor(self, widget=None): + flowgraph = self.param.get_parent().get_parent() + flowgraph.install_external_editor(self.param) + + def get_text(self): + pass # we never update the value from here + + def _apply_change(self, *args): + pass + + +class EnumParam(InputParam): + """Provide an entry box for Enum types with a drop down menu.""" + + def __init__(self, *args, **kwargs): + InputParam.__init__(self, *args, **kwargs) + self._input = Gtk.ComboBoxText() + for option in self.param.get_options(): + self._input.append_text(option.get_name()) + + value = self.param.get_value() + active_index = self.param.get_option_keys().index(value) + self._input.set_active(active_index) + + self._input.connect('changed', self._editing_callback) + self._input.connect('changed', self._apply_change) + self.pack_start(self._input, False, False, 0) + + def get_text(self): + return self.param.get_option_keys()[self._input.get_active()] + + def set_tooltip_text(self, text): + self._input.set_tooltip_text(text) + + +class EnumEntryParam(InputParam): + """Provide an entry box and drop down menu for Raw Enum types.""" + + def __init__(self, *args, **kwargs): + InputParam.__init__(self, *args, **kwargs) + self._input = Gtk.ComboBoxText.new_with_entry() + for option in self.param.get_options(): + self._input.append_text(option.get_name()) + + value = self.param.get_value() + try: + active_index = self.param.get_option_keys().index(value) + self._input.set_active(active_index) + except ValueError: + self._input.set_active(-1) + self._input.get_child().set_text(value) + + self._input.connect('changed', self._apply_change) + self._input.get_child().connect('changed', self._mark_changed) + self._input.get_child().connect('focus-out-event', self._apply_change) + self._input.get_child().connect('key-press-event', self._handle_key_press) + self.pack_start(self._input, False, False, 0) + + @property + def has_custom_value(self): + return self._input.get_active() == -1 + + def get_text(self): + if self.has_custom_value: + return self._input.get_child().get_text() + else: + return self.param.get_option_keys()[self._input.get_active()] + + def set_tooltip_text(self, text): + if self.has_custom_value: # custom entry + self._input.get_child().set_tooltip_text(text) + else: + self._input.set_tooltip_text(text) + + def set_color(self, color): + self._input.get_child().modify_base( + Gtk.StateType.NORMAL, + color if not self.has_custom_value else Colors.PARAM_ENTRY_ENUM_CUSTOM_COLOR + ) + + +class FileParam(EntryParam): + """Provide an entry box for filename and a button to browse for a file.""" + + def __init__(self, *args, **kwargs): + EntryParam.__init__(self, *args, **kwargs) + self._open_button = Gtk.Button(label='...') + self._open_button.connect('clicked', self._handle_clicked) + self.pack_start(self._open_button, False, False, 0) + + def _handle_clicked(self, widget=None): + """ + If the button was clicked, open a file dialog in open/save format. + Replace the text in the entry with the new filename from the file dialog. + """ + #get the paths + file_path = self.param.is_valid() and self.param.get_evaluated() or '' + (dirname, basename) = os.path.isfile(file_path) and os.path.split(file_path) or (file_path, '') + # check for qss theme default directory + if self.param.get_key() == 'qt_qss_theme': + dirname = os.path.dirname(dirname) # trim filename + if not os.path.exists(dirname): + platform = self.param.get_parent().get_parent().get_parent() + dirname = os.path.join(platform.config.install_prefix, + '/share/gnuradio/themes') + if not os.path.exists(dirname): + dirname = os.getcwd() # fix bad paths + + #build the dialog + if self.param.get_type() == 'file_open': + file_dialog = Gtk.FileChooserDialog('Open a Data File...', None, + Gtk.FileChooserAction.OPEN, ('gtk-cancel',Gtk.ResponseType.CANCEL,'gtk-open',Gtk.ResponseType.OK)) + elif self.param.get_type() == 'file_save': + file_dialog = Gtk.FileChooserDialog('Save a Data File...', None, + Gtk.FileChooserAction.SAVE, ('gtk-cancel',Gtk.ResponseType.CANCEL, 'gtk-save',Gtk.ResponseType.OK)) + file_dialog.set_do_overwrite_confirmation(True) + file_dialog.set_current_name(basename) #show the current filename + else: + raise ValueError("Can't open file chooser dialog for type " + repr(self.param.get_type())) + file_dialog.set_current_folder(dirname) #current directory + file_dialog.set_select_multiple(False) + file_dialog.set_local_only(True) + if Gtk.ResponseType.OK == file_dialog.run(): #run the dialog + file_path = file_dialog.get_filename() #get the file path + self._input.set_text(file_path) + self._editing_callback() + self._apply_change() + file_dialog.destroy() # destroy the dialog diff --git a/grc/gui/PropsDialog.py b/grc/gui/PropsDialog.py index d6f3cb4efe..e7576dddff 100644 --- a/grc/gui/PropsDialog.py +++ b/grc/gui/PropsDialog.py @@ -19,33 +19,11 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA import gi gi.require_version('Gtk', '3.0') -from gi.repository import Gtk -from gi.repository import Gdk -from gi.repository import GObject - -import Actions -from Dialogs import SimpleTextDisplay -from Constants import MIN_DIALOG_WIDTH, MIN_DIALOG_HEIGHT, FONT_SIZE -import Utils +from gi.repository import Gtk, Gdk, GObject from gi.repository import Pango - -def get_title_label(title): - """ - Get a title label for the params window. - The title will be bold, underlined, and left justified. - - Args: - title: the text of the title - - Returns: - a gtk object - """ - label = Gtk.Label() - label.set_markup('\n<b><span underline="low">{title}</span>:</b>\n'.format(title)) - hbox = Gtk.HBox() - hbox.pack_start(label, False, False, padding=11) - return hbox +from . import Actions, Utils, Constants +from .Dialogs import SimpleTextDisplay class PropsDialog(Gtk.Dialog): @@ -53,25 +31,30 @@ class PropsDialog(Gtk.Dialog): A dialog to set block parameters, view errors, and view documentation. """ - def __init__(self, block): + def __init__(self, parent, block): """ Properties dialog constructor. - Args: + Args:% block: a block instance """ - self._hash = 0 - GObject.GObject.__init__( + Gtk.Dialog.__init__( self, - title='Properties: %s' % block.get_name(), - buttons=(Gtk.STOCK_OK, Gtk.ResponseType.ACCEPT, - Gtk.STOCK_CANCEL, Gtk.ResponseType.REJECT, - Gtk.STOCK_APPLY, Gtk.ResponseType.APPLY) + title='Properties: ' + block.get_name(), + transient_for=parent, + modal=True, + ) + self.add_buttons( + Gtk.STOCK_OK, Gtk.ResponseType.ACCEPT, + Gtk.STOCK_CANCEL, Gtk.ResponseType.REJECT, + Gtk.STOCK_APPLY, Gtk.ResponseType.APPLY, ) self.set_response_sensitive(Gtk.ResponseType.APPLY, False) - self.set_size_request(MIN_DIALOG_WIDTH, MIN_DIALOG_HEIGHT) + self.set_size_request(Constants.MIN_DIALOG_WIDTH, Constants.MIN_DIALOG_HEIGHT) + self._block = block + self._hash = 0 vpaned = Gtk.VPaned() self.vbox.pack_start(vpaned, True, True, 0) @@ -107,8 +90,7 @@ class PropsDialog(Gtk.Dialog): self._code_text_display = code_view = SimpleTextDisplay() code_view.set_wrap_mode(Gtk.WrapMode.NONE) code_view.get_buffer().create_tag('b', weight=Pango.Weight.BOLD) - code_view.modify_font(Pango.FontDescription( - 'monospace %d' % FONT_SIZE)) + code_view.override_font(Pango.FontDescription('monospace %d' % Constants.FONT_SIZE)) code_box = Gtk.ScrolledWindow() code_box.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC) code_box.add_with_viewport(self._code_text_display) @@ -122,7 +104,7 @@ class PropsDialog(Gtk.Dialog): self._error_box.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC) self._error_box.add_with_viewport(self._error_messages_text_display) vpaned.pack2(self._error_box) - vpaned.set_position(int(0.65 * MIN_DIALOG_HEIGHT)) + vpaned.set_position(int(0.65 * Constants.MIN_DIALOG_HEIGHT)) # Connect events self.connect('key-press-event', self._handle_key_press) @@ -142,19 +124,17 @@ class PropsDialog(Gtk.Dialog): true if changed """ old_hash = self._hash - # create a tuple of things from each param that affects the params box - self._hash = hash(tuple([( - hash(param), param.get_name(), param.get_type(), - param.get_hide() == 'all', - ) for param in self._block.get_params()])) - return self._hash != old_hash + new_hash = self._hash = hash(tuple( + (hash(param), param.get_name(), param.get_type(), param.get_hide() == 'all',) + for param in self._block.get_params() + )) + return new_hash != old_hash def _handle_changed(self, *args): """ A change occurred within a param: Rewrite/validate the block and update the gui. """ - # update for the block self._block.rewrite() self._block.validate() self.update_gui() @@ -171,47 +151,46 @@ class PropsDialog(Gtk.Dialog): Update the documentation block. Hide the box if there are no docs. """ - # update the params box if force or self._params_changed(): # hide params box before changing for tab, label, vbox in self._params_boxes: - vbox.hide_all() + vbox.hide() # empty the params box for child in vbox.get_children(): vbox.remove(child) - child.destroy() + # child.destroy() # disabled because it throw errors... # repopulate the params box box_all_valid = True for param in filter(lambda p: p.get_tab_label() == tab, self._block.get_params()): + # fixme: why do we even rebuild instead of really hiding params? if param.get_hide() == 'all': continue box_all_valid = box_all_valid and param.is_valid() + input_widget = param.get_input(self._handle_changed, self._activate_apply) - vbox.pack_start(input_widget, input_widget.expand) - label.set_markup( - '<span foreground="{color}">{name}</span>'.format( - color='black' if box_all_valid else 'red', name=Utils.encode(tab) - ) - ) - # show params box with new params - vbox.show_all() - # update the errors box + input_widget.show_all() + vbox.pack_start(input_widget, input_widget.expand, True, 1) + + label.set_markup('<span foreground="{color}">{name}</span>'.format( + color='black' if box_all_valid else 'red', name=Utils.encode(tab) + )) + vbox.show() # show params box with new params + if self._block.is_valid(): self._error_box.hide() else: self._error_box.show() messages = '\n\n'.join(self._block.get_error_messages()) self._error_messages_text_display.set_text(messages) - # update the docs box + self._update_docs_page() - # update the generated code self._update_generated_code_page() def _update_docs_page(self): """Show documentation from XML and try to display best matching docstring""" - buffer = self._docs_text_display.get_buffer() - buffer.delete(buffer.get_start_iter(), buffer.get_end_iter()) - pos = buffer.get_end_iter() + buf = self._docs_text_display.get_buffer() + buf.delete(buf.get_start_iter(), buf.get_end_iter()) + pos = buf.get_end_iter() docstrings = self._block.get_doc() if not docstrings: @@ -221,11 +200,11 @@ class PropsDialog(Gtk.Dialog): from_xml = docstrings.pop('', '') for line in from_xml.splitlines(): if line.lstrip() == line and line.endswith(':'): - buffer.insert_with_tags_by_name(pos, line + '\n', 'b') + buf.insert_with_tags_by_name(pos, line + '\n', 'b') else: - buffer.insert(pos, line + '\n') + buf.insert(pos, line + '\n') if from_xml: - buffer.insert(pos, '\n') + buf.insert(pos, '\n') # if given the current parameters an exact match can be made block_constructor = self._block.get_make().rsplit('.', 2)[-1] @@ -235,16 +214,16 @@ class PropsDialog(Gtk.Dialog): # show docstring(s) extracted from python sources for cls_name, docstring in docstrings.iteritems(): - buffer.insert_with_tags_by_name(pos, cls_name + '\n', 'b') - buffer.insert(pos, docstring + '\n\n') + buf.insert_with_tags_by_name(pos, cls_name + '\n', 'b') + buf.insert(pos, docstring + '\n\n') pos.backward_chars(2) - buffer.delete(pos, buffer.get_end_iter()) + buf.delete(pos, buf.get_end_iter()) def _update_generated_code_page(self): if not self._code_text_display: return # user disabled code preview - buffer = self._code_text_display.get_buffer() + buf = self._code_text_display.get_buffer() block = self._block key = block.get_key() @@ -258,31 +237,27 @@ class PropsDialog(Gtk.Dialog): def insert(header, text): if not text: return - buffer.insert_with_tags_by_name(buffer.get_end_iter(), header, 'b') - buffer.insert(buffer.get_end_iter(), text) + buf.insert_with_tags_by_name(buf.get_end_iter(), header, 'b') + buf.insert(buf.get_end_iter(), text) - buffer.delete(buffer.get_start_iter(), buffer.get_end_iter()) + buf.delete(buf.get_start_iter(), buf.get_end_iter()) insert('# Imports\n', '\n'.join(block.get_imports())) - if key.startswith('variable'): + if block.is_variable: insert('\n\n# Variables\n', block.get_var_make()) insert('\n\n# Blocks\n', block.get_make()) if src: insert('\n\n# External Code ({}.py)\n'.format(block.get_id()), src) def _handle_key_press(self, widget, event): - """ - Handle key presses from the keyboard. - Call the ok response when enter is pressed. - - Returns: - false to forward the keypress - """ - if (event.keyval == Gdk.KEY_Return and + close_dialog = ( + event.keyval == Gdk.KEY_Return and event.get_state() & Gdk.ModifierType.CONTROL_MASK == 0 and not isinstance(widget.get_focus(), Gtk.TextView) - ): + ) + if close_dialog: self.response(Gtk.ResponseType.ACCEPT) return True # handled here + return False # forward the keypress def _handle_response(self, widget, response): |