mirror of
https://github.com/gnuradio/gnuradio-companion.git
synced 2025-12-10 15:57:35 -06:00
gtk3: add flowgraph draw code and other gtk3 fixes (WIP)
This commit is contained in:
parent
f337362360
commit
59cb4ebdd2
@ -219,10 +219,9 @@ class Platform(Element):
|
||||
|
||||
color = n.find('color') or ''
|
||||
try:
|
||||
import gi # ugly but handy
|
||||
from gi.repository import Gdk
|
||||
Gdk.color_parse(color)
|
||||
except (ValueError, ImportError):
|
||||
chars_per_color = 2 if len(color) > 4 else 1
|
||||
tuple(int(color[o:o + 2], 16) / 255.0 for o in range(1, 3 * chars_per_color, chars_per_color))
|
||||
except ValueError:
|
||||
if color: # no color is okay, default set in GUI
|
||||
print >> sys.stderr, 'Warning: Can\'t parse color code "{}" for domain "{}" '.format(color, key)
|
||||
color = None
|
||||
|
||||
@ -84,9 +84,8 @@ class ActionHandler:
|
||||
# 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.flags() & Gtk.HAS_FOCUS:
|
||||
if self.main_window.btwin.search_entry.has_focus():
|
||||
return False
|
||||
if not self.get_focus_flag(): return False
|
||||
return Actions.handle_key_press(event)
|
||||
|
||||
def _quit(self, window, event):
|
||||
@ -447,9 +446,9 @@ class ActionHandler:
|
||||
action.save_to_preferences()
|
||||
elif action == Actions.TOGGLE_FLOW_GRAPH_VAR_EDITOR_SIDEBAR:
|
||||
if self.init:
|
||||
md = gtk.MessageDialog(main,
|
||||
gtk.DIALOG_DESTROY_WITH_PARENT, gtk.MESSAGE_INFO,
|
||||
gtk.BUTTONS_CLOSE, "Moving the variable editor requires a restart of GRC.")
|
||||
md = Gtk.MessageDialog(main,
|
||||
Gtk.DIALOG_DESTROY_WITH_PARENT, Gtk.MESSAGE_INFO,
|
||||
Gtk.BUTTONS_CLOSE, "Moving the variable editor requires a restart of GRC.")
|
||||
md.run()
|
||||
md.destroy()
|
||||
action.save_to_preferences()
|
||||
|
||||
@ -27,6 +27,7 @@ import Preferences
|
||||
|
||||
NO_MODS_MASK = 0
|
||||
|
||||
|
||||
########################################################################
|
||||
# Actions API
|
||||
########################################################################
|
||||
@ -48,7 +49,7 @@ def handle_key_press(event):
|
||||
"""
|
||||
_used_mods_mask = reduce(lambda x, y: x | y, [mod_mask for keyval, mod_mask in _actions_keypress_dict], NO_MODS_MASK)
|
||||
# extract the key value and the consumed modifiers
|
||||
keyval, egroup, level, consumed = _keymap.translate_keyboard_state(
|
||||
_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
|
||||
@ -261,32 +262,32 @@ BLOCK_ROTATE_CW = Action(
|
||||
BLOCK_VALIGN_TOP = Action(
|
||||
label='Vertical Align Top',
|
||||
tooltip='Align tops of selected blocks',
|
||||
keypresses=(gtk.keysyms.t, gtk.gdk.SHIFT_MASK),
|
||||
keypresses=(Gdk.KEY_t, Gdk.ModifierType.SHIFT_MASK),
|
||||
)
|
||||
BLOCK_VALIGN_MIDDLE = Action(
|
||||
label='Vertical Align Middle',
|
||||
tooltip='Align centers of selected blocks vertically',
|
||||
keypresses=(gtk.keysyms.m, gtk.gdk.SHIFT_MASK),
|
||||
keypresses=(Gdk.KEY_m, Gdk.ModifierType.SHIFT_MASK),
|
||||
)
|
||||
BLOCK_VALIGN_BOTTOM = Action(
|
||||
label='Vertical Align Bottom',
|
||||
tooltip='Align bottoms of selected blocks',
|
||||
keypresses=(gtk.keysyms.b, gtk.gdk.SHIFT_MASK),
|
||||
keypresses=(Gdk.KEY_b, Gdk.ModifierType.SHIFT_MASK),
|
||||
)
|
||||
BLOCK_HALIGN_LEFT = Action(
|
||||
label='Horizontal Align Left',
|
||||
tooltip='Align left edges of blocks selected blocks',
|
||||
keypresses=(gtk.keysyms.l, gtk.gdk.SHIFT_MASK),
|
||||
keypresses=(Gdk.KEY_l, Gdk.ModifierType.SHIFT_MASK),
|
||||
)
|
||||
BLOCK_HALIGN_CENTER = Action(
|
||||
label='Horizontal Align Center',
|
||||
tooltip='Align centers of selected blocks horizontally',
|
||||
keypresses=(gtk.keysyms.c, gtk.gdk.SHIFT_MASK),
|
||||
keypresses=(Gdk.KEY_c, Gdk.ModifierType.SHIFT_MASK),
|
||||
)
|
||||
BLOCK_HALIGN_RIGHT = Action(
|
||||
label='Horizontal Align Right',
|
||||
tooltip='Align right edges of selected blocks',
|
||||
keypresses=(gtk.keysyms.r, gtk.gdk.SHIFT_MASK),
|
||||
keypresses=(Gdk.KEY_r, Gdk.ModifierType.SHIFT_MASK),
|
||||
)
|
||||
BLOCK_ALIGNMENTS = [
|
||||
BLOCK_VALIGN_TOP,
|
||||
@ -341,9 +342,9 @@ TOGGLE_HIDE_VARIABLES = ToggleAction(
|
||||
TOGGLE_FLOW_GRAPH_VAR_EDITOR = ToggleAction(
|
||||
label='Show _Variable Editor',
|
||||
tooltip='Show the variable editor. Modify variables and imports in this flow graph',
|
||||
stock_id=gtk.STOCK_EDIT,
|
||||
stock_id=Gtk.STOCK_EDIT,
|
||||
default=True,
|
||||
keypresses=(gtk.keysyms.e, gtk.gdk.CONTROL_MASK),
|
||||
keypresses=(Gdk.KEY_e, Gdk.ModifierType.CONTROL_MASK),
|
||||
preference_name='variable_editor_visable',
|
||||
)
|
||||
TOGGLE_FLOW_GRAPH_VAR_EDITOR_SIDEBAR = ToggleAction(
|
||||
@ -407,7 +408,7 @@ ERRORS_WINDOW_DISPLAY = Action(
|
||||
TOGGLE_CONSOLE_WINDOW = ToggleAction(
|
||||
label='Show _Console Panel',
|
||||
tooltip='Toggle visibility of the console',
|
||||
keypresses=(Gdk.KEY_c, Gdk.ModifierType.CONTROL_MASK),
|
||||
keypresses=(Gdk.KEY_r, Gdk.ModifierType.CONTROL_MASK),
|
||||
preference_name='console_window_visible'
|
||||
)
|
||||
TOGGLE_BLOCKS_WINDOW = ToggleAction(
|
||||
|
||||
@ -61,6 +61,7 @@ TOOLBAR_LIST = (
|
||||
Actions.OPEN_HIER,
|
||||
)
|
||||
|
||||
|
||||
# The list of actions and categories for the menu bar.
|
||||
MENU_BAR_LIST = (
|
||||
(Gtk.Action(name='File', label='_File'), [
|
||||
@ -88,7 +89,7 @@ MENU_BAR_LIST = (
|
||||
None,
|
||||
Actions.BLOCK_ROTATE_CCW,
|
||||
Actions.BLOCK_ROTATE_CW,
|
||||
(gtk.Action('Align', '_Align', None, None), Actions.BLOCK_ALIGNMENTS),
|
||||
(Gtk.Action('Align', '_Align', None, None), Actions.BLOCK_ALIGNMENTS),
|
||||
None,
|
||||
Actions.BLOCK_ENABLE,
|
||||
Actions.BLOCK_DISABLE,
|
||||
@ -140,6 +141,7 @@ MENU_BAR_LIST = (
|
||||
]),
|
||||
)
|
||||
|
||||
|
||||
# The list of actions for the context menu.
|
||||
CONTEXT_MENU_LIST = [
|
||||
Actions.BLOCK_CUT,
|
||||
|
||||
91
gui/Block.py
91
gui/Block.py
@ -17,10 +17,11 @@ along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
"""
|
||||
|
||||
import math
|
||||
import gi
|
||||
gi.require_version('Gtk', '3.0')
|
||||
from gi.repository import Gtk
|
||||
from gi.repository import Pango
|
||||
gi.require_version('PangoCairo', '1.0')
|
||||
from gi.repository import Gtk, Pango, PangoCairo
|
||||
|
||||
from . import Actions, Colors, Utils
|
||||
|
||||
@ -89,7 +90,9 @@ class Block(Element, _Block):
|
||||
))
|
||||
Element.__init__(self)
|
||||
self._comment_pixmap = None
|
||||
self._bg_color = Colors.BLOCK_ENABLED_COLOR
|
||||
self.has_busses = [False, False] # source, sink
|
||||
self.layouts = []
|
||||
|
||||
def get_coordinate(self):
|
||||
"""
|
||||
@ -196,14 +199,14 @@ class Block(Element, _Block):
|
||||
def create_labels(self):
|
||||
"""Create the labels for the signal block."""
|
||||
Element.create_labels(self)
|
||||
self._bg_color = self.is_dummy_block and Colors.MISSING_BLOCK_BACKGROUND_COLOR or \
|
||||
self.get_bypassed() and Colors.BLOCK_BYPASSED_COLOR or \
|
||||
self.get_enabled() and Colors.BLOCK_ENABLED_COLOR or Colors.BLOCK_DISABLED_COLOR
|
||||
|
||||
layouts = list()
|
||||
self._bg_color = Colors.MISSING_BLOCK_BACKGROUND_COLOR if self.is_dummy_block else \
|
||||
Colors.BLOCK_BYPASSED_COLOR if self.get_bypassed() else \
|
||||
Colors.BLOCK_ENABLED_COLOR if self.get_enabled() else \
|
||||
Colors.BLOCK_DISABLED_COLOR
|
||||
del self.layouts[:]
|
||||
#create the main layout
|
||||
layout = Gtk.DrawingArea().create_pango_layout('')
|
||||
layouts.append(layout)
|
||||
self.layouts.append(layout)
|
||||
layout.set_markup(Utils.parse_template(BLOCK_MARKUP_TMPL, block=self, font=BLOCK_FONT))
|
||||
self.label_width, self.label_height = layout.get_pixel_size()
|
||||
#display the params
|
||||
@ -217,30 +220,11 @@ class Block(Element, _Block):
|
||||
layout = Gtk.DrawingArea().create_pango_layout('')
|
||||
layout.set_spacing(LABEL_SEPARATION*Pango.SCALE)
|
||||
layout.set_markup('\n'.join(markups))
|
||||
layouts.append(layout)
|
||||
self.layouts.append(layout)
|
||||
w, h = layout.get_pixel_size()
|
||||
self.label_width = max(w, self.label_width)
|
||||
self.label_height += h + LABEL_SEPARATION
|
||||
width = self.label_width
|
||||
height = self.label_height
|
||||
#setup the pixmap
|
||||
pixmap = self.get_parent().new_pixmap(width, height)
|
||||
gc = pixmap.new_gc()
|
||||
gc.set_foreground(self._bg_color)
|
||||
pixmap.draw_rectangle(gc, True, 0, 0, width, height)
|
||||
#draw the layouts
|
||||
h_off = 0
|
||||
for i,layout in enumerate(layouts):
|
||||
w,h = layout.get_pixel_size()
|
||||
if i == 0: w_off = (width-w)/2
|
||||
else: w_off = 0
|
||||
pixmap.draw_layout(gc, w_off, h_off, layout)
|
||||
h_off = h + h_off + LABEL_SEPARATION
|
||||
#create vertical and horizontal pixmaps
|
||||
self.horizontal_label = pixmap
|
||||
if self.is_vertical():
|
||||
self.vertical_label = self.get_parent().new_pixmap(height, width)
|
||||
Utils.rotate_pixmap(gc, self.horizontal_label, self.vertical_label)
|
||||
|
||||
#calculate width and height needed
|
||||
W = self.label_width + 2 * BLOCK_LABEL_PADDING
|
||||
|
||||
@ -301,29 +285,50 @@ class Block(Element, _Block):
|
||||
else:
|
||||
self._comment_pixmap = None
|
||||
|
||||
def draw(self, gc, window):
|
||||
def draw(self, widget, cr):
|
||||
"""
|
||||
Draw the signal block with label and inputs/outputs.
|
||||
|
||||
Args:
|
||||
gc: the graphics context
|
||||
window: the gtk window to draw on
|
||||
"""
|
||||
# draw ports
|
||||
for port in self.get_ports_gui():
|
||||
port.draw(gc, window)
|
||||
port.draw(widget, cr)
|
||||
# draw main block
|
||||
x, y = self.get_coordinate()
|
||||
Element.draw(
|
||||
self, gc, window, bg_color=self._bg_color,
|
||||
border_color=self.is_highlighted() and Colors.HIGHLIGHT_COLOR or
|
||||
self.is_dummy_block and Colors.MISSING_BLOCK_BORDER_COLOR or Colors.BORDER_COLOR,
|
||||
border_color = (
|
||||
Colors.HIGHLIGHT_COLOR if self.is_highlighted() else
|
||||
Colors.MISSING_BLOCK_BORDER_COLOR if self.is_dummy_block else
|
||||
Colors.BORDER_COLOR
|
||||
)
|
||||
#draw label image
|
||||
Element.draw(self, widget, cr, border_color, self._bg_color)
|
||||
x, y = self.get_coordinate()
|
||||
# create the image surface
|
||||
width = self.label_width
|
||||
height = self.label_height
|
||||
cr.set_source_rgb(*self._bg_color)
|
||||
cr.save()
|
||||
if self.is_horizontal():
|
||||
window.draw_drawable(gc, self.horizontal_label, 0, 0, x+BLOCK_LABEL_PADDING, y+(self.H-self.label_height)/2, -1, -1)
|
||||
cr.translate(x + BLOCK_LABEL_PADDING, y + (self.H - self.label_height) / 2)
|
||||
elif self.is_vertical():
|
||||
window.draw_drawable(gc, self.vertical_label, 0, 0, x+(self.H-self.label_height)/2, y+BLOCK_LABEL_PADDING, -1, -1)
|
||||
cr.translate(x + (self.H - self.label_height) / 2, y + BLOCK_LABEL_PADDING)
|
||||
cr.rotate(-90 * math.pi / 180.)
|
||||
cr.translate(-width, 0)
|
||||
|
||||
# cr.rectangle(0, 0, width, height)
|
||||
# cr.fill()
|
||||
|
||||
# draw the layouts
|
||||
h_off = 0
|
||||
for i, layout in enumerate(self.layouts):
|
||||
w, h = layout.get_pixel_size()
|
||||
if i == 0:
|
||||
w_off = (width - w) / 2
|
||||
else:
|
||||
w_off = 0
|
||||
cr.translate(w_off, h_off)
|
||||
PangoCairo.update_layout(cr, layout)
|
||||
PangoCairo.show_layout(cr, layout)
|
||||
cr.translate(-w_off, -h_off)
|
||||
h_off = h + h_off + LABEL_SEPARATION
|
||||
cr.restore()
|
||||
|
||||
def what_is_selected(self, coor, coor_m=None):
|
||||
"""
|
||||
|
||||
@ -16,26 +16,30 @@ You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
"""
|
||||
|
||||
try:
|
||||
import gi
|
||||
gi.require_version('Gtk', '3.0')
|
||||
from gi.repository import Gtk
|
||||
from gi.repository import Gdk
|
||||
|
||||
# Not gtk3?
|
||||
#COLORMAP = Gdk.colormap_get_system() #create all of the colors
|
||||
#def get_color(color_code): return _COLORMAP.alloc_color(color_code, True, True)
|
||||
|
||||
def get_color(color_code):
|
||||
color = Gdk.RGBA()
|
||||
color.parse(color_code)
|
||||
return color
|
||||
chars_per_color = 2 if len(color_code) > 4 else 1
|
||||
offsets = range(1, 3 * chars_per_color + 1, chars_per_color)
|
||||
return tuple(int(color_code[o:o + 2], 16) / 255.0 for o in offsets)
|
||||
|
||||
HIGHLIGHT_COLOR = get_color('#00FFFF')
|
||||
BORDER_COLOR = get_color('#444444')
|
||||
|
||||
# Missing blocks stuff
|
||||
MISSING_BLOCK_BACKGROUND_COLOR = get_color('#FFF2F2')
|
||||
MISSING_BLOCK_BORDER_COLOR = get_color('red')
|
||||
MISSING_BLOCK_BORDER_COLOR = get_color('#FF0000')
|
||||
|
||||
# Param entry boxes
|
||||
PARAM_ENTRY_TEXT_COLOR = get_color('black')
|
||||
PARAM_ENTRY_TEXT_COLOR = get_color('#000000')
|
||||
ENTRYENUM_CUSTOM_COLOR = get_color('#EEEEEE')
|
||||
|
||||
# Flow graph color constants
|
||||
@ -49,12 +53,9 @@ try:
|
||||
BLOCK_BYPASSED_COLOR = get_color('#F4FF81')
|
||||
|
||||
# Connection color constants
|
||||
CONNECTION_ENABLED_COLOR = get_color('black')
|
||||
CONNECTION_ENABLED_COLOR = get_color('#000000')
|
||||
CONNECTION_DISABLED_COLOR = get_color('#BBBBBB')
|
||||
CONNECTION_ERROR_COLOR = get_color('red')
|
||||
CONNECTION_ERROR_COLOR = get_color('#FF0000')
|
||||
|
||||
except Exception as e:
|
||||
print 'Unable to import Colors'
|
||||
|
||||
|
||||
DEFAULT_DOMAIN_COLOR_CODE = '#777777'
|
||||
print 'Unable to import Colors', e
|
||||
|
||||
@ -91,10 +91,10 @@ class Connection(Element, _Connection):
|
||||
]
|
||||
source_domain = self.get_source().get_domain()
|
||||
sink_domain = self.get_sink().get_domain()
|
||||
self.line_attributes[0] = 2 if source_domain != sink_domain else 0
|
||||
self.line_attributes[1] = Gdk.LINE_DOUBLE_DASH \
|
||||
if not source_domain == sink_domain == GR_MESSAGE_DOMAIN \
|
||||
else Gdk.LINE_ON_OFF_DASH
|
||||
# self.line_attributes[0] = 2 if source_domain != sink_domain else 0
|
||||
# self.line_attributes[1] = Gdk.LINE_DOUBLE_DASH \
|
||||
# if not source_domain == sink_domain == GR_MESSAGE_DOMAIN \
|
||||
# else Gdk.LINE_ON_OFF_DASH
|
||||
get_domain_color = lambda d: Colors.get_color((
|
||||
self.get_parent().get_parent().domains.get(d, {})
|
||||
).get('color') or Colors.DEFAULT_DOMAIN_COLOR_CODE)
|
||||
@ -147,13 +147,9 @@ class Connection(Element, _Connection):
|
||||
self.add_line((x1, y1), points[0])
|
||||
self.add_line((x2, y2), points[0])
|
||||
|
||||
def draw(self, gc, window):
|
||||
def draw(self, widget, cr):
|
||||
"""
|
||||
Draw the connection.
|
||||
|
||||
Args:
|
||||
gc: the graphics context
|
||||
window: the gtk window to draw on
|
||||
"""
|
||||
sink = self.get_sink()
|
||||
source = self.get_source()
|
||||
@ -175,11 +171,12 @@ class Connection(Element, _Connection):
|
||||
Colors.CONNECTION_DISABLED_COLOR if not self.get_enabled() else
|
||||
color
|
||||
)
|
||||
Element.draw(self, gc, window, mod_color(self._color), mod_color(self._bg_color))
|
||||
Element.draw(self, widget, cr, mod_color(self._color), mod_color(self._bg_color))
|
||||
# draw arrow on sink port
|
||||
try:
|
||||
gc.set_foreground(mod_color(self._arrow_color))
|
||||
gc.set_line_attributes(0, Gdk.LINE_SOLID, Gdk.CAP_BUTT, Gdk.JOIN_MITER)
|
||||
window.draw_polygon(gc, True, self._arrow)
|
||||
except:
|
||||
pass
|
||||
cr.set_source_rgb(*self._arrow_color)
|
||||
# TODO: gc.set_line_attributes(0, Gdk.LINE_SOLID, Gdk.CAP_BUTT, Gdk.JOIN_MITER)
|
||||
cr.move_to(*self._arrow[0])
|
||||
cr.line_to(*self._arrow[1])
|
||||
cr.line_to(*self._arrow[2])
|
||||
cr.close_path()
|
||||
cr.fill()
|
||||
|
||||
@ -48,8 +48,7 @@ class DrawingArea(Gtk.DrawingArea):
|
||||
GObject.GObject.__init__(self)
|
||||
self.set_size_request(MIN_WINDOW_WIDTH, MIN_WINDOW_HEIGHT)
|
||||
self.connect('realize', self._handle_window_realize)
|
||||
self.connect('configure-event', self._handle_window_configure)
|
||||
self.connect('expose-event', self._handle_window_expose)
|
||||
self.connect('draw', self.draw)
|
||||
self.connect('motion-notify-event', self._handle_mouse_motion)
|
||||
self.connect('button-press-event', self._handle_mouse_button_press)
|
||||
self.connect('button-release-event', self._handle_mouse_button_release)
|
||||
@ -59,35 +58,22 @@ class DrawingArea(Gtk.DrawingArea):
|
||||
Gdk.EventMask.POINTER_MOTION_MASK | \
|
||||
Gdk.EventMask.BUTTON_RELEASE_MASK | \
|
||||
Gdk.EventMask.LEAVE_NOTIFY_MASK | \
|
||||
Gdk.EventMask.ENTER_NOTIFY_MASK | \
|
||||
Gdk.EventMask.FOCUS_CHANGE_MASK
|
||||
Gdk.EventMask.ENTER_NOTIFY_MASK #| \
|
||||
#Gdk.EventMask.FOCUS_CHANGE_MASK
|
||||
)
|
||||
#setup drag and drop
|
||||
self.drag_dest_set(Gtk.DestDefaults.ALL, DND_TARGETS, Gdk.DragAction.COPY)
|
||||
self.drag_dest_set(Gtk.DestDefaults.ALL, [], Gdk.DragAction.COPY)
|
||||
self.connect('drag-data-received', self._handle_drag_data_received)
|
||||
self.drag_dest_set_target_list(None)
|
||||
self.drag_dest_add_text_targets()
|
||||
#setup the focus flag
|
||||
self._focus_flag = False
|
||||
self.get_focus_flag = lambda: self._focus_flag
|
||||
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)
|
||||
self.set_flags(Gtk.CAN_FOCUS) # self.set_can_focus(True)
|
||||
self.connect('focus-out-event', self._handle_focus_lost_event)
|
||||
|
||||
def new_pixmap(self, width, height):
|
||||
return Gdk.Pixmap(self.window, width, height, -1)
|
||||
|
||||
def get_screenshot(self, transparent_bg=False):
|
||||
pixmap = self._pixmap
|
||||
W, H = pixmap.get_size()
|
||||
pixbuf = GdkPixbuf.Pixbuf(GdkPixbuf.Colorspace.RGB, 0, 8, W, H)
|
||||
pixbuf.fill(0xFF + Colors.FLOWGRAPH_BACKGROUND_COLOR.pixel << 8)
|
||||
pixbuf.get_from_drawable(pixmap, pixmap.get_colormap(), 0, 0, 0, 0, W-1, H-1)
|
||||
if transparent_bg:
|
||||
bgc = Colors.FLOWGRAPH_BACKGROUND_COLOR
|
||||
pixbuf = pixbuf.add_alpha(True, bgc.red, bgc.green, bgc.blue)
|
||||
return pixbuf
|
||||
|
||||
# self.set_flags(Gtk.CAN_FOCUS) # self.set_can_focus(True)
|
||||
# self.connect('focus-out-event', self._handle_focus_lost_event)
|
||||
|
||||
##########################################################################
|
||||
## Handlers
|
||||
@ -96,7 +82,7 @@ class DrawingArea(Gtk.DrawingArea):
|
||||
"""
|
||||
Handle a drag and drop by adding a block at the given coordinate.
|
||||
"""
|
||||
self._flow_graph.add_new_block(selection_data.data, (x, y))
|
||||
self._flow_graph.add_new_block(selection_data.get_text(), (x, y))
|
||||
|
||||
def _handle_mouse_scroll(self, widget, event):
|
||||
if event.get_state() & Gdk.ModifierType.SHIFT_MASK:
|
||||
@ -113,7 +99,7 @@ class DrawingArea(Gtk.DrawingArea):
|
||||
self.ctrl_mask = event.get_state() & Gdk.ModifierType.CONTROL_MASK
|
||||
self.mod1_mask = event.get_state() & Gdk.ModifierType.MOD1_MASK
|
||||
if event.button == 1: self._flow_graph.handle_mouse_selector_press(
|
||||
double_click=(event.type == Gdk._2BUTTON_PRESS),
|
||||
double_click=(event.type == Gdk.EventType._2BUTTON_PRESS),
|
||||
coordinate=(event.x, event.y),
|
||||
)
|
||||
if event.button == 3: self._flow_graph.handle_mouse_context_press(
|
||||
@ -148,27 +134,8 @@ class DrawingArea(Gtk.DrawingArea):
|
||||
"""
|
||||
self._flow_graph.update()
|
||||
|
||||
def _handle_window_configure(self, widget, event):
|
||||
"""
|
||||
Called when the window is resized.
|
||||
Create a new pixmap for background buffer.
|
||||
"""
|
||||
self._pixmap = self.new_pixmap(*self.get_size_request())
|
||||
|
||||
def _handle_window_expose(self, widget, event):
|
||||
"""
|
||||
Called when window is exposed, or queue_draw is called.
|
||||
Double buffering: draw to pixmap, then draw pixmap to window.
|
||||
"""
|
||||
gc = self.window.new_gc()
|
||||
self._flow_graph.draw(gc, self._pixmap)
|
||||
self.window.draw_drawable(gc, self._pixmap, 0, 0, 0, 0, -1, -1)
|
||||
# draw a light grey line on the bottom and right end of the canvas.
|
||||
# this is useful when the theme uses the same panel bg color as the canvas
|
||||
W, H = self._pixmap.get_size()
|
||||
gc.set_foreground(Colors.FLOWGRAPH_EDGE_COLOR)
|
||||
self.window.draw_line(gc, 0, H-1, W, H-1)
|
||||
self.window.draw_line(gc, W-1, 0, W-1, H)
|
||||
def draw(self, widget, cr):
|
||||
self._flow_graph.draw(widget, cr)
|
||||
|
||||
def _handle_focus_lost_event(self, widget, event):
|
||||
# don't clear selection while context menu is active
|
||||
|
||||
@ -90,29 +90,33 @@ class Element(object):
|
||||
self.clear()
|
||||
for child in self.get_children(): child.create_shapes()
|
||||
|
||||
def draw(self, gc, window, border_color, bg_color):
|
||||
def draw(self, widget, cr, border_color, bg_color):
|
||||
"""
|
||||
Draw in the given window.
|
||||
|
||||
Args:
|
||||
gc: the graphics context
|
||||
window: the gtk window to draw on
|
||||
widget:
|
||||
cr:
|
||||
border_color: the color for lines and rectangle borders
|
||||
bg_color: the color for the inside of the rectangle
|
||||
"""
|
||||
X, Y = self.get_coordinate()
|
||||
gc.set_line_attributes(*self.line_attributes)
|
||||
# TODO: gc.set_line_attributes(*self.line_attributes)
|
||||
for (rX, rY), (W, H) in self._areas_list:
|
||||
aX = X + rX
|
||||
aY = Y + rY
|
||||
gc.set_foreground(bg_color)
|
||||
window.draw_rectangle(gc, True, aX, aY, W, H)
|
||||
gc.set_foreground(border_color)
|
||||
window.draw_rectangle(gc, False, aX, aY, W, H)
|
||||
cr.set_source_rgb(*bg_color)
|
||||
cr.rectangle(aX, aY, W, H)
|
||||
cr.fill()
|
||||
cr.set_source_rgb(*border_color)
|
||||
cr.rectangle(aX, aY, W, H)
|
||||
cr.stroke()
|
||||
|
||||
for (x1, y1), (x2, y2) in self._lines_list:
|
||||
gc.set_foreground(border_color)
|
||||
gc.set_background(bg_color)
|
||||
window.draw_line(gc, X+x1, Y+y1, X+x2, Y+y2)
|
||||
cr.set_source_rgb(*border_color)
|
||||
cr.move_to(X + x1, Y + y1)
|
||||
cr.line_to(X + x2, Y + y2)
|
||||
cr.stroke()
|
||||
|
||||
def rotate(self, rotation):
|
||||
"""
|
||||
|
||||
@ -397,23 +397,21 @@ class FlowGraph(Element, _Flowgraph):
|
||||
changed = True
|
||||
return changed
|
||||
|
||||
def draw(self, gc, window):
|
||||
def draw(self, widget, cr):
|
||||
"""
|
||||
Draw the background and grid if enabled.
|
||||
Draw all of the elements in this flow graph onto the pixmap.
|
||||
Draw the pixmap to the drawable window of this flow graph.
|
||||
"""
|
||||
|
||||
W,H = self.get_size()
|
||||
#draw the background
|
||||
gc.set_foreground(Colors.FLOWGRAPH_BACKGROUND_COLOR)
|
||||
window.draw_rectangle(gc, True, 0, 0, W, H)
|
||||
cr.set_source_rgb(*Colors.FLOWGRAPH_BACKGROUND_COLOR)
|
||||
cr.rectangle(0, 0, *self.get_size())
|
||||
cr.fill()
|
||||
|
||||
# draw comments first
|
||||
if Actions.TOGGLE_SHOW_BLOCK_COMMENTS.get_active():
|
||||
for block in self.blocks:
|
||||
if block.get_enabled():
|
||||
block.draw_comment(gc, window)
|
||||
# block.draw_comment(widget, cr)
|
||||
pass
|
||||
#draw multi select rectangle
|
||||
if self.mouse_pressed and (not self.get_selected_elements() or self.get_ctrl_mask()):
|
||||
#coordinates
|
||||
@ -423,10 +421,13 @@ class FlowGraph(Element, _Flowgraph):
|
||||
x, y = int(min(x1, x2)), int(min(y1, y2))
|
||||
w, h = int(abs(x1 - x2)), int(abs(y1 - y2))
|
||||
#draw
|
||||
gc.set_foreground(Colors.HIGHLIGHT_COLOR)
|
||||
window.draw_rectangle(gc, True, x, y, w, h)
|
||||
gc.set_foreground(Colors.BORDER_COLOR)
|
||||
window.draw_rectangle(gc, False, x, y, w, h)
|
||||
cr.set_source_rgb(*Colors.HIGHLIGHT_COLOR)
|
||||
cr.rectangle(x, y, w, h)
|
||||
cr.fill()
|
||||
cr.set_source_rgb(*Colors.BORDER_COLOR)
|
||||
cr.rectangle(x, y, w, h)
|
||||
cr.stroke()
|
||||
|
||||
#draw blocks on top of connections
|
||||
hide_disabled_blocks = Actions.TOGGLE_HIDE_DISABLED_BLOCKS.get_active()
|
||||
hide_variables = Actions.TOGGLE_HIDE_VARIABLES.get_active()
|
||||
@ -437,10 +438,10 @@ class FlowGraph(Element, _Flowgraph):
|
||||
continue # skip hidden disabled blocks and connections
|
||||
if hide_variables and (element.is_variable or element.is_import):
|
||||
continue # skip hidden disabled blocks and connections
|
||||
element.draw(gc, window)
|
||||
element.draw(widget, cr)
|
||||
#draw selected blocks on top of selected connections
|
||||
for selected_element in self.get_selected_connections() + self.get_selected_blocks():
|
||||
selected_element.draw(gc, window)
|
||||
selected_element.draw(widget, cr)
|
||||
|
||||
def update_selected(self):
|
||||
"""
|
||||
|
||||
@ -36,6 +36,7 @@ from .NotebookPage import NotebookPage
|
||||
|
||||
from ..core import Messages
|
||||
|
||||
|
||||
MAIN_WINDOW_TITLE_TMPL = """\
|
||||
#if not $saved
|
||||
*#slurp
|
||||
@ -104,8 +105,8 @@ class MainWindow(Gtk.Window):
|
||||
vbox.pack_start(self.tool_bar, False, False, 0)
|
||||
|
||||
# Main parent container for the different panels
|
||||
self.container = Gtk.HPaned()
|
||||
vbox.pack_start(self.container)
|
||||
self.main = Gtk.HPaned() #(orientation=Gtk.Orientation.HORIZONTAL)
|
||||
vbox.pack_start(self.main, True, True, 0)
|
||||
|
||||
# Create the notebook
|
||||
self.notebook = Gtk.Notebook()
|
||||
@ -127,9 +128,9 @@ class MainWindow(Gtk.Window):
|
||||
self.vars = VariableEditor(platform, self.get_flow_graph)
|
||||
|
||||
# Figure out which place to put the variable editor
|
||||
self.left = Gtk.VPaned()
|
||||
self.right = Gtk.VPaned()
|
||||
self.left_subpanel = Gtk.HPaned()
|
||||
self.left = Gtk.VPaned() #orientation=Gtk.Orientation.VERTICAL)
|
||||
self.right = Gtk.VPaned() #orientation=Gtk.Orientation.VERTICAL)
|
||||
self.left_subpanel = Gtk.HPaned() #orientation=Gtk.Orientation.HORIZONTAL)
|
||||
|
||||
self.variable_panel_sidebar = Preferences.variable_editor_sidebar()
|
||||
if self.variable_panel_sidebar:
|
||||
@ -147,12 +148,12 @@ class MainWindow(Gtk.Window):
|
||||
# Create the right panel
|
||||
self.right.pack1(self.btwin)
|
||||
|
||||
self.container.pack1(self.left)
|
||||
self.container.pack2(self.right, False)
|
||||
self.main.pack1(self.left)
|
||||
self.main.pack2(self.right, False)
|
||||
|
||||
# Load preferences and show the main window
|
||||
self.resize(*Preferences.main_window_size())
|
||||
self.container.set_position(Preferences.blocks_window_position())
|
||||
self.main.set_position(Preferences.blocks_window_position())
|
||||
self.left.set_position(Preferences.console_window_position())
|
||||
if self.variable_panel_sidebar:
|
||||
self.right.set_position(Preferences.variable_editor_position(sidebar=True))
|
||||
@ -276,9 +277,7 @@ class MainWindow(Gtk.Window):
|
||||
return
|
||||
#add this page to the notebook
|
||||
self.notebook.append_page(page, page.get_tab())
|
||||
try: self.notebook.set_tab_reorderable(page, True)
|
||||
except: pass #gtk too old
|
||||
self.notebook.set_tab_label_packing(page, False, False, Gtk.PACK_START)
|
||||
self.notebook.set_tab_reorderable(page, True)
|
||||
#only show if blank or manual
|
||||
if not file_path or show: self._set_page(page)
|
||||
|
||||
@ -303,7 +302,7 @@ class MainWindow(Gtk.Window):
|
||||
Preferences.file_open(open_file)
|
||||
Preferences.main_window_size(self.get_size())
|
||||
Preferences.console_window_position(self.left.get_position())
|
||||
Preferences.blocks_window_position(self.container.get_position())
|
||||
Preferences.blocks_window_position(self.main.get_position())
|
||||
if self.variable_panel_sidebar:
|
||||
Preferences.variable_editor_position(self.right.get_position(), sidebar=True)
|
||||
else:
|
||||
@ -405,14 +404,11 @@ class MainWindow(Gtk.Window):
|
||||
Returns:
|
||||
the selected flow graph
|
||||
"""
|
||||
return None
|
||||
# TODO: Issues with flowgraphs
|
||||
#return self.get_page().get_flow_graph()
|
||||
return self.get_page().get_flow_graph()
|
||||
|
||||
def get_focus_flag(self):
|
||||
"""
|
||||
Get the focus flag from the current page.
|
||||
|
||||
Returns:
|
||||
the focus flag
|
||||
"""
|
||||
|
||||
@ -54,7 +54,7 @@ class NotebookPage(Gtk.HBox):
|
||||
GObject.GObject.__init__(self)
|
||||
self.show()
|
||||
#tab box to hold label and close button
|
||||
self.tab = Gtk.HBox(False, 0)
|
||||
self.tab = Gtk.HBox(homogeneous=False, spacing=0)
|
||||
#setup tab label
|
||||
self.label = Gtk.Label()
|
||||
self.tab.pack_start(self.label, False, False, 0)
|
||||
@ -62,7 +62,7 @@ class NotebookPage(Gtk.HBox):
|
||||
image = Gtk.Image()
|
||||
image.set_from_stock('gtk-close', Gtk.IconSize.MENU)
|
||||
#setup image box
|
||||
image_box = Gtk.HBox(False, 0)
|
||||
image_box = Gtk.HBox(homogeneous=False, spacing=0)
|
||||
image_box.pack_start(image, True, False, 0)
|
||||
#setup the button
|
||||
button = Gtk.Button()
|
||||
@ -79,20 +79,18 @@ class NotebookPage(Gtk.HBox):
|
||||
self.scrolled_window.set_size_request(MIN_WINDOW_WIDTH, MIN_WINDOW_HEIGHT)
|
||||
self.scrolled_window.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC)
|
||||
self.scrolled_window.connect('key-press-event', self._handle_scroll_window_key_press)
|
||||
#self.drawing_area = DrawingArea(self.get_flow_graph())
|
||||
#self.scrolled_window.add_with_viewport(self.get_drawing_area())
|
||||
self.drawing_area = DrawingArea(self.get_flow_graph())
|
||||
self.scrolled_window.add_with_viewport(self.drawing_area)
|
||||
self.pack_start(self.scrolled_window, True, True, 0)
|
||||
#inject drawing area into flow graph
|
||||
#self.get_flow_graph().drawing_area = self.get_drawing_area()
|
||||
self.get_flow_graph().drawing_area = self.drawing_area
|
||||
self.show_all()
|
||||
|
||||
def get_drawing_area(self): return self.drawing_area
|
||||
|
||||
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 & gtk.gdk.CONTROL_MASK and
|
||||
event.keyval in (gtk.keysyms.Page_Up, gtk.keysyms.Page_Down)
|
||||
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)
|
||||
|
||||
61
gui/Port.py
61
gui/Port.py
@ -17,9 +17,10 @@ along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
"""
|
||||
|
||||
import math
|
||||
import gi
|
||||
gi.require_version('Gtk', '3.0')
|
||||
from gi.repository import Gtk
|
||||
from gi.repository import Gtk, PangoCairo
|
||||
|
||||
from . import Actions, Colors, Utils
|
||||
from .Constants import (
|
||||
@ -45,15 +46,19 @@ class Port(_Port, Element):
|
||||
"""
|
||||
_Port.__init__(self, block, n, dir)
|
||||
Element.__init__(self)
|
||||
self.W = self.H = self.w = self.h = 0
|
||||
self.W = self.w = self.h = 0
|
||||
self.H = 20 # todo: fix
|
||||
self._connector_coordinate = (0, 0)
|
||||
self._connector_length = 0
|
||||
self._hovering = True
|
||||
self._force_label_unhidden = False
|
||||
self.layout = Gtk.DrawingArea().create_pango_layout('')
|
||||
self._bg_color = Colors.get_color(self.get_color())
|
||||
|
||||
def create_shapes(self):
|
||||
"""Create new areas and labels for the port."""
|
||||
Element.create_shapes(self)
|
||||
self._bg_color = Colors.get_color(self.get_color())
|
||||
if self.get_hide():
|
||||
return # this port is hidden, no need to create shapes
|
||||
if self.get_domain() == GR_MESSAGE_DOMAIN:
|
||||
@ -112,50 +117,34 @@ class Port(_Port, Element):
|
||||
|
||||
def create_labels(self):
|
||||
"""Create the labels for the socket."""
|
||||
Element.create_labels(self)
|
||||
self._bg_color = Colors.get_color(self.get_color())
|
||||
# create the layout
|
||||
layout = Gtk.DrawingArea().create_pango_layout('')
|
||||
layout.set_markup(Utils.parse_template(PORT_MARKUP_TMPL, port=self, font=PORT_FONT))
|
||||
self.w, self.h = layout.get_pixel_size()
|
||||
self.W = 2 * PORT_LABEL_PADDING + self.w
|
||||
self.H = 2 * PORT_LABEL_PADDING + self.h * (
|
||||
3 if self.get_type() == 'bus' else 1)
|
||||
self.H += self.H % 2
|
||||
# create the pixmap
|
||||
pixmap = self.get_parent().get_parent().new_pixmap(self.w, self.h)
|
||||
gc = pixmap.new_gc()
|
||||
gc.set_foreground(self._bg_color)
|
||||
pixmap.draw_rectangle(gc, True, 0, 0, self.w, self.h)
|
||||
pixmap.draw_layout(gc, 0, 0, layout)
|
||||
# create vertical and horizontal pixmaps
|
||||
self.horizontal_label = pixmap
|
||||
if self.is_vertical():
|
||||
self.vertical_label = self.get_parent().get_parent().new_pixmap(self.h, self.w)
|
||||
Utils.rotate_pixmap(gc, self.horizontal_label, self.vertical_label)
|
||||
self.layout.set_markup(Utils.parse_template(PORT_MARKUP_TMPL, port=self, font=PORT_FONT))
|
||||
|
||||
def draw(self, gc, window):
|
||||
def draw(self, widget, cr):
|
||||
"""
|
||||
Draw the socket with a label.
|
||||
|
||||
Args:
|
||||
gc: the graphics context
|
||||
window: the gtk window to draw on
|
||||
"""
|
||||
Element.draw(
|
||||
self, gc, window, bg_color=self._bg_color,
|
||||
border_color=self.is_highlighted() and Colors.HIGHLIGHT_COLOR or
|
||||
self.get_parent().is_dummy_block and Colors.MISSING_BLOCK_BORDER_COLOR or
|
||||
Colors.BORDER_COLOR,
|
||||
border_color = (
|
||||
Colors.HIGHLIGHT_COLOR if self.is_highlighted() else
|
||||
Colors.MISSING_BLOCK_BORDER_COLOR if self.get_parent().is_dummy_block else
|
||||
Colors.BORDER_COLOR
|
||||
)
|
||||
Element.draw(self, widget, cr, border_color, self._bg_color)
|
||||
|
||||
if not self._areas_list or self._label_hidden():
|
||||
return # this port is either hidden (no areas) or folded (no label)
|
||||
X, Y = self.get_coordinate()
|
||||
(x, y), (w, h) = self._areas_list[0] # use the first area's sizes to place the labels
|
||||
(x, y), _ = self._areas_list[0]
|
||||
cr.set_source_rgb(*self._bg_color)
|
||||
cr.save()
|
||||
if self.is_horizontal():
|
||||
window.draw_drawable(gc, self.horizontal_label, 0, 0, x+X+(self.W-self.w)/2, y+Y+(self.H-self.h)/2, -1, -1)
|
||||
cr.translate(x + X + (self.W - self.w) / 2, y + Y + (self.H - self.h) / 2)
|
||||
elif self.is_vertical():
|
||||
window.draw_drawable(gc, self.vertical_label, 0, 0, x+X+(self.H-self.h)/2, y+Y+(self.W-self.w)/2, -1, -1)
|
||||
cr.translate(x + X + (self.H - self.h) / 2, y + Y + (self.W - self.w) / 2)
|
||||
cr.rotate(-90 * math.pi / 180.)
|
||||
cr.translate(-self.w, 0)
|
||||
PangoCairo.update_layout(cr, self.layout)
|
||||
PangoCairo.show_layout(cr, self.layout)
|
||||
cr.restore()
|
||||
|
||||
def get_connector_coordinate(self):
|
||||
"""
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
"""
|
||||
Copyright 2015 Free Software Foundation, Inc.
|
||||
Copyright 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,10 +19,11 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
|
||||
from operator import attrgetter
|
||||
|
||||
import pygtk
|
||||
pygtk.require('2.0')
|
||||
import gtk
|
||||
import gobject
|
||||
import gi
|
||||
gi.require_version('Gtk', '3.0')
|
||||
from gi.repository import Gtk
|
||||
from gi.repository import Gdk
|
||||
from gi.repository import GObject
|
||||
|
||||
from . import Actions
|
||||
from . import Preferences
|
||||
@ -32,34 +33,34 @@ BLOCK_INDEX = 0
|
||||
ID_INDEX = 1
|
||||
|
||||
|
||||
class VariableEditorContextMenu(gtk.Menu):
|
||||
class VariableEditorContextMenu(Gtk.Menu):
|
||||
""" A simple context menu for our variable editor """
|
||||
def __init__(self, var_edit):
|
||||
gtk.Menu.__init__(self)
|
||||
Gtk.Menu.__init__(self)
|
||||
|
||||
self.imports = gtk.MenuItem("Add _Import")
|
||||
self.imports = Gtk.MenuItem("Add _Import")
|
||||
self.imports.connect('activate', var_edit.handle_action, var_edit.ADD_IMPORT)
|
||||
self.add(self.imports)
|
||||
|
||||
self.variables = gtk.MenuItem("Add _Variable")
|
||||
self.variables = Gtk.MenuItem("Add _Variable")
|
||||
self.variables.connect('activate', var_edit.handle_action, var_edit.ADD_VARIABLE)
|
||||
self.add(self.variables)
|
||||
self.add(gtk.SeparatorMenuItem())
|
||||
self.add(Gtk.SeparatorMenuItem())
|
||||
|
||||
self.enable = gtk.MenuItem("_Enable")
|
||||
self.enable = Gtk.MenuItem("_Enable")
|
||||
self.enable.connect('activate', var_edit.handle_action, var_edit.ENABLE_BLOCK)
|
||||
self.disable = gtk.MenuItem("_Disable")
|
||||
self.disable = Gtk.MenuItem("_Disable")
|
||||
self.disable.connect('activate', var_edit.handle_action, var_edit.DISABLE_BLOCK)
|
||||
self.add(self.enable)
|
||||
self.add(self.disable)
|
||||
self.add(gtk.SeparatorMenuItem())
|
||||
self.add(Gtk.SeparatorMenuItem())
|
||||
|
||||
self.delete = gtk.MenuItem("_Delete")
|
||||
self.delete = Gtk.MenuItem("_Delete")
|
||||
self.delete.connect('activate', var_edit.handle_action, var_edit.DELETE_BLOCK)
|
||||
self.add(self.delete)
|
||||
self.add(gtk.SeparatorMenuItem())
|
||||
self.add(Gtk.SeparatorMenuItem())
|
||||
|
||||
self.properties = gtk.MenuItem("_Properties...")
|
||||
self.properties = Gtk.MenuItem("_Properties...")
|
||||
self.properties.connect('activate', var_edit.handle_action, var_edit.OPEN_PROPERTIES)
|
||||
self.add(self.properties)
|
||||
self.show_all()
|
||||
@ -71,7 +72,7 @@ class VariableEditorContextMenu(gtk.Menu):
|
||||
self.disable.set_sensitive(selected and enabled)
|
||||
|
||||
|
||||
class VariableEditor(gtk.VBox):
|
||||
class VariableEditor(Gtk.VBox):
|
||||
|
||||
# Actions that are handled by the editor
|
||||
ADD_IMPORT = 0
|
||||
@ -83,7 +84,7 @@ class VariableEditor(gtk.VBox):
|
||||
DISABLE_BLOCK = 6
|
||||
|
||||
def __init__(self, platform, get_flow_graph):
|
||||
gtk.VBox.__init__(self)
|
||||
Gtk.VBox.__init__(self)
|
||||
self.platform = platform
|
||||
self.get_flow_graph = get_flow_graph
|
||||
self._block = None
|
||||
@ -91,14 +92,14 @@ class VariableEditor(gtk.VBox):
|
||||
|
||||
# Only use the model to store the block reference and name.
|
||||
# Generate everything else dynamically
|
||||
self.treestore = gtk.TreeStore(gobject.TYPE_PYOBJECT, # Block reference
|
||||
gobject.TYPE_STRING) # Category and block name
|
||||
self.treeview = gtk.TreeView(self.treestore)
|
||||
self.treestore = Gtk.TreeStore(GObject.TYPE_PYOBJECT, # Block reference
|
||||
GObject.TYPE_STRING) # Category and block name
|
||||
self.treeview = Gtk.TreeView(self.treestore)
|
||||
self.treeview.set_enable_search(False)
|
||||
self.treeview.set_search_column(-1)
|
||||
#self.treeview.set_enable_search(True)
|
||||
#self.treeview.set_search_column(ID_INDEX)
|
||||
self.treeview.get_selection().set_mode('single')
|
||||
self.treeview.get_selection().set_mode(Gtk.SelectionMode.SINGLE)
|
||||
self.treeview.set_headers_visible(True)
|
||||
self.treeview.connect('button-press-event', self._handle_mouse_button_press)
|
||||
self.treeview.connect('button-release-event', self._handle_mouse_button_release)
|
||||
@ -106,67 +107,67 @@ class VariableEditor(gtk.VBox):
|
||||
self.treeview.connect('key-press-event', self._handle_key_button_press)
|
||||
|
||||
# Block Name or Category
|
||||
self.id_cell = gtk.CellRendererText()
|
||||
self.id_cell = Gtk.CellRendererText()
|
||||
self.id_cell.connect('edited', self._handle_name_edited_cb)
|
||||
id_column = gtk.TreeViewColumn("Id", self.id_cell, text=ID_INDEX)
|
||||
id_column = Gtk.TreeViewColumn("Id", self.id_cell, text=ID_INDEX)
|
||||
id_column.set_name("id")
|
||||
id_column.set_resizable(True)
|
||||
id_column.set_max_width(300)
|
||||
id_column.set_min_width(80)
|
||||
id_column.set_fixed_width(100)
|
||||
id_column.set_sizing(gtk.TREE_VIEW_COLUMN_FIXED)
|
||||
id_column.set_sizing(Gtk.TreeViewColumnSizing.FIXED)
|
||||
id_column.set_cell_data_func(self.id_cell, self.set_properties)
|
||||
self.id_column = id_column
|
||||
self.treeview.append_column(id_column)
|
||||
self.treestore.set_sort_column_id(ID_INDEX, gtk.SORT_ASCENDING)
|
||||
self.treestore.set_sort_column_id(ID_INDEX, Gtk.SortType.ASCENDING)
|
||||
# For forcing resize
|
||||
self._col_width = 0
|
||||
|
||||
# Block Value
|
||||
self.value_cell = gtk.CellRendererText()
|
||||
self.value_cell = Gtk.CellRendererText()
|
||||
self.value_cell.connect('edited', self._handle_value_edited_cb)
|
||||
value_column = gtk.TreeViewColumn("Value", self.value_cell)
|
||||
value_column = Gtk.TreeViewColumn("Value", self.value_cell)
|
||||
value_column.set_name("value")
|
||||
value_column.set_resizable(False)
|
||||
value_column.set_expand(True)
|
||||
value_column.set_min_width(100)
|
||||
value_column.set_sizing(gtk.TREE_VIEW_COLUMN_AUTOSIZE)
|
||||
value_column.set_sizing(Gtk.TreeViewColumnSizing.AUTOSIZE)
|
||||
value_column.set_cell_data_func(self.value_cell, self.set_value)
|
||||
self.value_column = value_column
|
||||
self.treeview.append_column(value_column)
|
||||
|
||||
# Block Actions (Add, Remove)
|
||||
self.action_cell = gtk.CellRendererPixbuf()
|
||||
self.action_cell = Gtk.CellRendererPixbuf()
|
||||
value_column.pack_start(self.action_cell, False)
|
||||
value_column.set_cell_data_func(self.action_cell, self.set_icon)
|
||||
|
||||
# Make the scrolled window to hold the tree view
|
||||
scrolled_window = gtk.ScrolledWindow()
|
||||
scrolled_window.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
|
||||
scrolled_window = Gtk.ScrolledWindow()
|
||||
scrolled_window.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC)
|
||||
scrolled_window.add_with_viewport(self.treeview)
|
||||
scrolled_window.set_size_request(DEFAULT_BLOCKS_WINDOW_WIDTH, -1)
|
||||
self.pack_start(scrolled_window)
|
||||
self.pack_start(scrolled_window, True, True, 0)
|
||||
|
||||
# Context menus
|
||||
self._context_menu = VariableEditorContextMenu(self)
|
||||
self._confirm_delete = Preferences.variable_editor_confirm_delete()
|
||||
|
||||
# Sets cell contents
|
||||
def set_icon(self, col, cell, model, iter):
|
||||
def set_icon(self, col, cell, model, iter, data):
|
||||
block = model.get_value(iter, BLOCK_INDEX)
|
||||
if block:
|
||||
pb = self.treeview.render_icon(gtk.STOCK_CLOSE, gtk.ICON_SIZE_MENU, None)
|
||||
pb = self.treeview.render_icon(Gtk.STOCK_CLOSE, 16, None)
|
||||
else:
|
||||
pb = self.treeview.render_icon(gtk.STOCK_ADD, gtk.ICON_SIZE_MENU, None)
|
||||
pb = self.treeview.render_icon(Gtk.STOCK_ADD, 16, None)
|
||||
cell.set_property('pixbuf', pb)
|
||||
|
||||
def set_value(self, col, cell, model, iter):
|
||||
def set_value(self, col, cell, model, iter, data):
|
||||
sp = cell.set_property
|
||||
block = model.get_value(iter, BLOCK_INDEX)
|
||||
|
||||
# Set the default properties for this column first.
|
||||
# Some set in set_properties() may be overridden (editable for advanced variable blocks)
|
||||
self.set_properties(col, cell, model, iter)
|
||||
self.set_properties(col, cell, model, iter, data)
|
||||
|
||||
# Set defaults
|
||||
value = None
|
||||
@ -198,7 +199,7 @@ class VariableEditor(gtk.VBox):
|
||||
# Always set the text value.
|
||||
sp('text', value)
|
||||
|
||||
def set_properties(self, col, cell, model, iter):
|
||||
def set_properties(self, col, cell, model, iter, data):
|
||||
sp = cell.set_property
|
||||
block = model.get_value(iter, BLOCK_INDEX)
|
||||
# Set defaults
|
||||
@ -268,13 +269,13 @@ class VariableEditor(gtk.VBox):
|
||||
elif key == self.DELETE_CONFIRM:
|
||||
if self._confirm_delete:
|
||||
# Create a context menu to confirm the delete operation
|
||||
confirmation_menu = gtk.Menu()
|
||||
confirmation_menu = Gtk.Menu()
|
||||
block_id = self._block.get_param('id').get_value().replace("_", "__")
|
||||
confirm = gtk.MenuItem("Delete {}".format(block_id))
|
||||
confirm = Gtk.MenuItem("Delete {}".format(block_id))
|
||||
confirm.connect('activate', self.handle_action, self.DELETE_BLOCK)
|
||||
confirmation_menu.add(confirm)
|
||||
confirmation_menu.show_all()
|
||||
confirmation_menu.popup(None, None, None, event.button, event.time)
|
||||
confirmation_menu.popup(None, None, None, None, event.button, event.time)
|
||||
else:
|
||||
self.handle_action(None, self.DELETE_BLOCK, None)
|
||||
elif key == self.ENABLE_BLOCK:
|
||||
@ -302,12 +303,12 @@ class VariableEditor(gtk.VBox):
|
||||
|
||||
if event.button == 1 and col.get_name() == "value":
|
||||
# Make sure this has a block (not the import/variable rows)
|
||||
if self._block and event.type == gtk.gdk._2BUTTON_PRESS:
|
||||
if self._block and event.type == Gdk.EventType._2BUTTON_PRESS:
|
||||
# Open the advanced dialog if it is a gui variable
|
||||
if self._block.get_key() not in ("variable", "import"):
|
||||
self.handle_action(None, self.OPEN_PROPERTIES, event=event)
|
||||
return True
|
||||
if event.type == gtk.gdk.BUTTON_PRESS:
|
||||
if event.type == Gdk.EventType.BUTTON_PRESS:
|
||||
# User is adding/removing blocks
|
||||
# Make sure this is the action cell (Add/Remove Icons)
|
||||
if path[2] > col.cell_get_position(self.action_cell)[0]:
|
||||
@ -320,15 +321,15 @@ class VariableEditor(gtk.VBox):
|
||||
else:
|
||||
self.handle_action(None, self.DELETE_CONFIRM, event=event)
|
||||
return True
|
||||
elif event.button == 3 and event.type == gtk.gdk.BUTTON_PRESS:
|
||||
elif event.button == 3 and event.type == Gdk.EventType.BUTTON_PRESS:
|
||||
if self._block:
|
||||
self._context_menu.update_sensitive(True, enabled=self._block.get_enabled())
|
||||
else:
|
||||
self._context_menu.update_sensitive(False)
|
||||
self._context_menu.popup(None, None, None, event.button, event.time)
|
||||
self._context_menu.popup(None, None, None, None, event.button, event.time)
|
||||
|
||||
# Null handler. Stops the treeview from handling double click events.
|
||||
if event.type == gtk.gdk._2BUTTON_PRESS:
|
||||
if event.type == Gdk.EventType._2BUTTON_PRESS:
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user