summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSebastian Koslowski <koslowski@kit.edu>2016-05-27 15:19:11 +0200
committerSebastian Koslowski <koslowski@kit.edu>2016-05-30 15:46:37 +0200
commitd290917e982ba4473a03e5a7e1acaa1e50c59f3d (patch)
tree2cc68a254358155085a4522d2a59f08a5518c180
parent498715deea12451bd271d20b51c02f01530acd14 (diff)
grc: gtk3: update props dialog
-rwxr-xr-xgrc/checks.py2
-rw-r--r--grc/gui/ActionHandler.py2
-rw-r--r--grc/gui/Block.py2
-rw-r--r--grc/gui/Constants.py2
-rw-r--r--grc/gui/Param.py149
-rw-r--r--grc/gui/ParamWidgets.py288
-rw-r--r--grc/gui/PropsDialog.py137
7 files changed, 424 insertions, 158 deletions
diff --git a/grc/checks.py b/grc/checks.py
index cfff10e7d8..66c114d723 100755
--- a/grc/checks.py
+++ b/grc/checks.py
@@ -53,6 +53,8 @@ def check_gtk():
warnings.filterwarnings("error")
import gi
gi.require_version('Gtk', '3.0')
+ gi.require_version('PangoCairo', '1.0')
+
from gi.repository import Gtk
Gtk.init_check()
warnings.filterwarnings("always")
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):