"""
Copyright 2007 Free Software Foundation, Inc.
This file is part of GNU Radio
GNU Radio Companion is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
GNU Radio Companion is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
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
"""
from Element import Element
import Utils
import Colors
from ... gui.Constants import BORDER_PROXIMITY_SENSITIVITY
from Constants import \
BLOCK_FONT, BLOCK_LABEL_PADDING, \
PORT_SEPARATION, LABEL_SEPARATION, \
PORT_BORDER_SEPARATION, POSSIBLE_ROTATIONS
import pygtk
pygtk.require('2.0')
import gtk
import pango
class Block(Element):
"""The graphical signal block."""
def __init__(self, *args, **kwargs):
"""
Block contructor.
Add graphics related params to the block.
"""
#add the position param
self._params['_coordinate'] = self.get_parent().get_parent().Param(
self,
{
'name': 'GUI Coordinate',
'key': '_coordinate',
'type': 'raw',
'value': '(0, 0)',
'hide': 'all',
}
)
self._params['_rotation'] = self.get_parent().get_parent().Param(
self,
{
'name': 'GUI Rotation',
'key': '_rotation',
'type': 'raw',
'value': '0',
'hide': 'all',
}
)
Element.__init__(self)
def get_coordinate(self):
"""
Get the coordinate from the position param.
@return the coordinate tuple (x, y) or (0, 0) if failure
"""
try: #should evaluate to tuple
coor = eval(self.get_param('_coordinate').get_value())
x, y = map(int, coor)
fgW,fgH = self.get_parent().get_size()
if x <= 0:
x = 0
elif x >= fgW - BORDER_PROXIMITY_SENSITIVITY:
x = fgW - BORDER_PROXIMITY_SENSITIVITY
if y <= 0:
y = 0
elif y >= fgH - BORDER_PROXIMITY_SENSITIVITY:
y = fgH - BORDER_PROXIMITY_SENSITIVITY
return (x, y)
except:
self.set_coordinate((0, 0))
return (0, 0)
def set_coordinate(self, coor):
"""
Set the coordinate into the position param.
@param coor the coordinate tuple (x, y)
"""
self.get_param('_coordinate').set_value(str(coor))
def get_rotation(self):
"""
Get the rotation from the position param.
@return the rotation in degrees or 0 if failure
"""
try: #should evaluate to dict
rotation = eval(self.get_param('_rotation').get_value())
return int(rotation)
except:
self.set_rotation(POSSIBLE_ROTATIONS[0])
return POSSIBLE_ROTATIONS[0]
def set_rotation(self, rot):
"""
Set the rotation into the position param.
@param rot the rotation in degrees
"""
self.get_param('_rotation').set_value(str(rot))
def update(self):
"""Update the block, parameters, and ports when a change occurs."""
self.bg_color = self.get_enabled() and Colors.BG_COLOR or Colors.DISABLED_BG_COLOR
self.clear()
self._create_labels()
self.W = self.label_width + 2*BLOCK_LABEL_PADDING
self.H = max(*(
[self.label_height+2*BLOCK_LABEL_PADDING] + [2*PORT_BORDER_SEPARATION + \
sum([port.H + PORT_SEPARATION for port in ports]) - PORT_SEPARATION
for ports in (self.get_sources(), self.get_sinks())]
))
if self.is_horizontal(): self.add_area((0, 0), (self.W, self.H))
elif self.is_vertical(): self.add_area((0, 0), (self.H, self.W))
map(lambda p: p.update(), self.get_ports())
def _create_labels(self):
"""Create the labels for the signal block."""
layouts = list()
#create the main layout
layout = gtk.DrawingArea().create_pango_layout('')
layouts.append(layout)
if self.is_valid(): layout.set_markup(''+Utils.xml_encode(self.get_name())+'')
else: layout.set_markup(''+Utils.xml_encode(self.get_name())+'')
desc = pango.FontDescription(BLOCK_FONT)
layout.set_font_description(desc)
self.label_width, self.label_height = layout.get_pixel_size()
#display the params
for param in filter(lambda p: p.get_hide() not in ('all', 'part'), self.get_params()):
layout = param.get_layout()
layouts.append(layout)
w,h = layout.get_pixel_size()
self.label_width = max(w, self.label_width)
self.label_height = self.label_height + h + LABEL_SEPARATION
width = self.label_width
height = self.label_height
#setup the pixmap
pixmap = gtk.gdk.Pixmap(self.get_parent().get_window(), width, height, -1)
gc = pixmap.new_gc()
gc.foreground = self.bg_color
pixmap.draw_rectangle(gc, True, 0, 0, width, height)
gc.foreground = Colors.TXT_COLOR
#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 images
self.horizontal_label = image = pixmap.get_image(0, 0, width, height)
if self.is_vertical():
self.vertical_label = vimage = gtk.gdk.Image(gtk.gdk.IMAGE_NORMAL, pixmap.get_visual(), height, width)
for i in range(width):
for j in range(height): vimage.put_pixel(j, width-i-1, image.get_pixel(i, j))
map(lambda p: p._create_labels(), self.get_ports())
def draw(self, window):
"""
Draw the signal block with label and inputs/outputs.
@param window the gtk window to draw on
"""
x, y = self.get_coordinate()
#draw main block
Element.draw(self, window, BG_color=self.bg_color)
#draw label image
gc = self.get_gc()
if self.is_horizontal():
window.draw_image(gc, self.horizontal_label, 0, 0, x+BLOCK_LABEL_PADDING, y+(self.H-self.label_height)/2, -1, -1)
elif self.is_vertical():
window.draw_image(gc, self.vertical_label, 0, 0, x+(self.H-self.label_height)/2, y+BLOCK_LABEL_PADDING, -1, -1)
#draw ports
map(lambda p: p.draw(window), self.get_ports())
def what_is_selected(self, coor, coor_m=None):
"""
Get the element that is selected.
@param coor the (x,y) tuple
@param coor_m the (x_m, y_m) tuple
@return this block, a port, or None
"""
for port in self.get_ports():
port_selected = port.what_is_selected(coor, coor_m)
if port_selected: return port_selected
return Element.what_is_selected(self, coor, coor_m)