scripts/pybootchart: Port to python3

This updates the pybootchart code (used for viewing build timing profiles)
to use python3. The bulk of the changes are to use gi instead of pygtk, i.e.
port from gtk+2 to gtk+3.

The main change is to make the bootchart widget inherit gtk.Scrollable
and change the way the scrollbars are implemented to match the new method
upstream. The drawing code used cairo already so can remain unchanged,

(From OE-Core rev: 949144681ad7f536732169351cab6d0612e9c566)

Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
This commit is contained in:
Richard Purdie
2019-05-08 11:48:35 +01:00
parent d13b904305
commit 020911ab59
4 changed files with 113 additions and 113 deletions

View File

@@ -13,64 +13,83 @@
# You should have received a copy of the GNU General Public License
# along with pybootchartgui. If not, see <http://www.gnu.org/licenses/>.
import gobject
import gtk
import gtk.gdk
import gtk.keysyms
import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk as gtk
from gi.repository import Gtk
from gi.repository import Gdk
from gi.repository import GObject as gobject
from gi.repository import GObject
from . import draw
from .draw import RenderOptions
class PyBootchartWidget(gtk.DrawingArea):
class PyBootchartWidget(gtk.DrawingArea, gtk.Scrollable):
__gsignals__ = {
'expose-event': 'override',
'clicked' : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_STRING, gtk.gdk.Event)),
'clicked' : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_STRING, Gdk.Event)),
'position-changed' : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_INT, gobject.TYPE_INT)),
'set-scroll-adjustments' : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gtk.Adjustment, gtk.Adjustment))
}
hadjustment = GObject.property(type=Gtk.Adjustment,
default=Gtk.Adjustment(),
flags=GObject.PARAM_READWRITE)
hscroll_policy = GObject.property(type=Gtk.ScrollablePolicy,
default=Gtk.ScrollablePolicy.MINIMUM,
flags=GObject.PARAM_READWRITE)
vadjustment = GObject.property(type=Gtk.Adjustment,
default=Gtk.Adjustment(),
flags=GObject.PARAM_READWRITE)
vscroll_policy = GObject.property(type=Gtk.ScrollablePolicy,
default=Gtk.ScrollablePolicy.MINIMUM,
flags=GObject.PARAM_READWRITE)
def __init__(self, trace, options, xscale):
gtk.DrawingArea.__init__(self)
self.trace = trace
self.options = options
self.set_flags(gtk.CAN_FOCUS)
self.set_can_focus(True)
self.add_events(gtk.gdk.BUTTON_PRESS_MASK | gtk.gdk.BUTTON_RELEASE_MASK)
self.add_events(Gdk.EventMask.BUTTON_PRESS_MASK | Gdk.EventMask.BUTTON_RELEASE_MASK)
self.connect("button-press-event", self.on_area_button_press)
self.connect("button-release-event", self.on_area_button_release)
self.add_events(gtk.gdk.POINTER_MOTION_MASK | gtk.gdk.POINTER_MOTION_HINT_MASK | gtk.gdk.BUTTON_RELEASE_MASK)
self.add_events(Gdk.EventMask.POINTER_MOTION_MASK | Gdk.EventMask.POINTER_MOTION_HINT_MASK | Gdk.EventMask.BUTTON_RELEASE_MASK)
self.connect("motion-notify-event", self.on_area_motion_notify)
self.connect("scroll-event", self.on_area_scroll_event)
self.connect('key-press-event', self.on_key_press_event)
self.connect('set-scroll-adjustments', self.on_set_scroll_adjustments)
self.connect("size-allocate", self.on_allocation_size_changed)
self.connect("position-changed", self.on_position_changed)
self.connect("draw", self.on_draw)
self.zoom_ratio = 1.0
self.xscale = xscale
self.x, self.y = 0.0, 0.0
self.chart_width, self.chart_height = draw.extents(self.options, self.xscale, self.trace)
self.hadj = None
self.vadj = None
self.hadj_changed_signal_id = None
self.vadj_changed_signal_id = None
self.our_width, self.our_height = self.chart_width, self.chart_height
def do_expose_event(self, event):
cr = self.window.cairo_create()
self.hadj = gtk.Adjustment(0.0, 0.0, 0.0, 0.0, 0.0, 0.0)
self.vadj = gtk.Adjustment(0.0, 0.0, 0.0, 0.0, 0.0, 0.0)
self.vadj.connect('value-changed', self.on_adjustments_changed)
self.hadj.connect('value-changed', self.on_adjustments_changed)
# set a clip region for the expose event
cr.rectangle(
event.area.x, event.area.y,
event.area.width, event.area.height
)
cr.clip()
self.draw(cr, self.get_allocation())
return False
def bound_vals(self):
self.x = max(0, self.x)
self.y = max(0, self.y)
self.x = min(self.chart_width - self.our_width, self.x)
self.y = min(self.chart_height - self.our_height, self.y)
def draw(self, cr, rect):
def on_draw(self, darea, cr):
# set a clip region
#cr.rectangle(
# self.x, self.y,
# self.chart_width, self.chart_height
#)
#cr.clip()
cr.set_source_rgba(1.0, 1.0, 1.0, 1.0)
cr.paint()
cr.scale(self.zoom_ratio, self.zoom_ratio)
@@ -84,7 +103,7 @@ class PyBootchartWidget(gtk.DrawingArea):
def zoom_image (self, zoom_ratio):
self.zoom_ratio = zoom_ratio
self._set_scroll_adjustments (self.hadj, self.vadj)
self._set_scroll_adjustments()
self.queue_draw()
def zoom_to_rect (self, rect):
@@ -122,126 +141,101 @@ class PyBootchartWidget(gtk.DrawingArea):
def show_toggled(self, button):
self.options.app_options.show_all = button.get_property ('active')
self.chart_width, self.chart_height = draw.extents(self.options, self.xscale, self.trace)
self._set_scroll_adjustments(self.hadj, self.vadj)
self._set_scroll_adjustments()
self.queue_draw()
POS_INCREMENT = 100
def on_key_press_event(self, widget, event):
if event.keyval == gtk.keysyms.Left:
if event.keyval == Gdk.keyval_from_name("Left"):
self.x -= self.POS_INCREMENT/self.zoom_ratio
elif event.keyval == gtk.keysyms.Right:
elif event.keyval == Gdk.keyval_from_name("Right"):
self.x += self.POS_INCREMENT/self.zoom_ratio
elif event.keyval == gtk.keysyms.Up:
elif event.keyval == Gdk.keyval_from_name("Up"):
self.y -= self.POS_INCREMENT/self.zoom_ratio
elif event.keyval == gtk.keysyms.Down:
elif event.keyval == Gdk.keyval_from_name("Down"):
self.y += self.POS_INCREMENT/self.zoom_ratio
else:
return False
self.bound_vals()
self.queue_draw()
self.position_changed()
return True
def on_area_button_press(self, area, event):
if event.button == 2 or event.button == 1:
area.window.set_cursor(gtk.gdk.Cursor(gtk.gdk.FLEUR))
window = self.get_window()
window.set_cursor(Gdk.Cursor(Gdk.CursorType.FLEUR))
self.prevmousex = event.x
self.prevmousey = event.y
if event.type not in (gtk.gdk.BUTTON_PRESS, gtk.gdk.BUTTON_RELEASE):
if event.type not in (Gdk.EventType.BUTTON_PRESS, Gdk.EventType.BUTTON_RELEASE):
return False
return False
def on_area_button_release(self, area, event):
if event.button == 2 or event.button == 1:
area.window.set_cursor(gtk.gdk.Cursor(gtk.gdk.ARROW))
window = self.get_window()
window.set_cursor(Gdk.Cursor(Gdk.CursorType.ARROW))
self.prevmousex = None
self.prevmousey = None
return True
return False
def on_area_scroll_event(self, area, event):
if event.state & gtk.gdk.CONTROL_MASK:
if event.direction == gtk.gdk.SCROLL_UP:
if event.state & Gdk.CONTROL_MASK:
if event.direction == Gdk.SCROLL_UP:
self.zoom_image(self.zoom_ratio * self.ZOOM_INCREMENT)
return True
if event.direction == gtk.gdk.SCROLL_DOWN:
if event.direction == Gdk.SCROLL_DOWN:
self.zoom_image(self.zoom_ratio / self.ZOOM_INCREMENT)
return True
return False
def on_area_motion_notify(self, area, event):
state = event.state
if state & gtk.gdk.BUTTON2_MASK or state & gtk.gdk.BUTTON1_MASK:
if state & Gdk.ModifierType.BUTTON2_MASK or state & Gdk.ModifierType.BUTTON1_MASK:
x, y = int(event.x), int(event.y)
# pan the image
self.x += (self.prevmousex - x)/self.zoom_ratio
self.y += (self.prevmousey - y)/self.zoom_ratio
self.bound_vals()
self.queue_draw()
self.prevmousex = x
self.prevmousey = y
self.position_changed()
return True
def on_set_scroll_adjustments(self, area, hadj, vadj):
self._set_scroll_adjustments (hadj, vadj)
def on_allocation_size_changed(self, widget, allocation):
self.hadj.page_size = allocation.width
self.hadj.page_increment = allocation.width * 0.9
self.vadj.page_size = allocation.height
self.vadj.page_increment = allocation.height * 0.9
self.our_width = allocation.width
if self.chart_width < self.our_width:
self.our_width = self.chart_width
self.our_height = allocation.height
if self.chart_height < self.our_height:
self.our_height = self.chart_height
self._set_scroll_adjustments()
def _set_adj_upper(self, adj, upper):
changed = False
value_changed = False
if adj.upper != upper:
adj.upper = upper
changed = True
if adj.get_upper() != upper:
adj.set_upper(upper)
max_value = max(0.0, upper - adj.page_size)
if adj.value > max_value:
adj.value = max_value
value_changed = True
if changed:
adj.changed()
if value_changed:
adj.value_changed()
def _set_scroll_adjustments(self, hadj, vadj):
if hadj == None:
hadj = gtk.Adjustment(0.0, 0.0, 0.0, 0.0, 0.0, 0.0)
if vadj == None:
vadj = gtk.Adjustment(0.0, 0.0, 0.0, 0.0, 0.0, 0.0)
if self.hadj_changed_signal_id != None and \
self.hadj != None and hadj != self.hadj:
self.hadj.disconnect (self.hadj_changed_signal_id)
if self.vadj_changed_signal_id != None and \
self.vadj != None and vadj != self.vadj:
self.vadj.disconnect (self.vadj_changed_signal_id)
if hadj != None:
self.hadj = hadj
self._set_adj_upper (self.hadj, self.zoom_ratio * self.chart_width)
self.hadj_changed_signal_id = self.hadj.connect('value-changed', self.on_adjustments_changed)
if vadj != None:
self.vadj = vadj
self._set_adj_upper (self.vadj, self.zoom_ratio * self.chart_height)
self.vadj_changed_signal_id = self.vadj.connect('value-changed', self.on_adjustments_changed)
def _set_scroll_adjustments(self):
self._set_adj_upper (self.hadj, self.zoom_ratio * (self.chart_width - self.our_width))
self._set_adj_upper (self.vadj, self.zoom_ratio * (self.chart_height - self.our_height))
def on_adjustments_changed(self, adj):
self.x = self.hadj.value / self.zoom_ratio
self.y = self.vadj.value / self.zoom_ratio
self.x = self.hadj.get_value() / self.zoom_ratio
self.y = self.vadj.get_value() / self.zoom_ratio
self.queue_draw()
def on_position_changed(self, widget, x, y):
self.hadj.value = x * self.zoom_ratio
self.vadj.value = y * self.zoom_ratio
PyBootchartWidget.set_set_scroll_adjustments_signal('set-scroll-adjustments')
self.hadj.set_value(x * self.zoom_ratio)
#self.hadj.value_changed()
self.vadj.set_value(y * self.zoom_ratio)
class PyBootchartShell(gtk.VBox):
ui = '''
@@ -260,7 +254,7 @@ class PyBootchartShell(gtk.VBox):
def __init__(self, window, trace, options, xscale):
gtk.VBox.__init__(self)
self.widget = PyBootchartWidget(trace, options, xscale)
self.widget2 = PyBootchartWidget(trace, options, xscale)
# Create a UIManager instance
uimanager = self.uimanager = gtk.UIManager()
@@ -275,12 +269,12 @@ class PyBootchartShell(gtk.VBox):
# Create actions
actiongroup.add_actions((
('Expand', gtk.STOCK_ADD, None, None, None, self.widget.on_expand),
('Contract', gtk.STOCK_REMOVE, None, None, None, self.widget.on_contract),
('ZoomIn', gtk.STOCK_ZOOM_IN, None, None, None, self.widget.on_zoom_in),
('ZoomOut', gtk.STOCK_ZOOM_OUT, None, None, None, self.widget.on_zoom_out),
('ZoomFit', gtk.STOCK_ZOOM_FIT, 'Fit Width', None, None, self.widget.on_zoom_fit),
('Zoom100', gtk.STOCK_ZOOM_100, None, None, None, self.widget.on_zoom_100),
('Expand', gtk.STOCK_ADD, None, None, None, self.widget2.on_expand),
('Contract', gtk.STOCK_REMOVE, None, None, None, self.widget2.on_contract),
('ZoomIn', gtk.STOCK_ZOOM_IN, None, None, None, self.widget2.on_zoom_in),
('ZoomOut', gtk.STOCK_ZOOM_OUT, None, None, None, self.widget2.on_zoom_out),
('ZoomFit', gtk.STOCK_ZOOM_FIT, 'Fit Width', None, None, self.widget2.on_zoom_fit),
('Zoom100', gtk.STOCK_ZOOM_100, None, None, None, self.widget2.on_zoom_100),
))
# Add the actiongroup to the uimanager
@@ -290,29 +284,33 @@ class PyBootchartShell(gtk.VBox):
uimanager.add_ui_from_string(self.ui)
# Scrolled window
scrolled = gtk.ScrolledWindow()
scrolled.add(self.widget)
scrolled = gtk.ScrolledWindow(self.widget2.hadj, self.widget2.vadj)
scrolled.add(self.widget2)
#scrolled.set_hadjustment()
#scrolled.set_vadjustment(self.widget2.vadj)
scrolled.set_policy(gtk.PolicyType.ALWAYS, gtk.PolicyType.ALWAYS)
# toolbar / h-box
hbox = gtk.HBox(False, 8)
# Create a Toolbar
toolbar = uimanager.get_widget('/ToolBar')
hbox.pack_start(toolbar, True, True)
hbox.pack_start(toolbar, True, True, 0)
if not options.kernel_only:
# Misc. options
button = gtk.CheckButton("Show more")
button.connect ('toggled', self.widget.show_toggled)
button.connect ('toggled', self.widget2.show_toggled)
button.set_active(options.app_options.show_all)
hbox.pack_start (button, False, True)
hbox.pack_start (button, False, True, 0)
self.pack_start(hbox, False)
self.pack_start(scrolled)
self.pack_start(hbox, False, True, 0)
self.pack_start(scrolled, True, True, 0)
self.show_all()
def grab_focus(self, window):
window.set_focus(self.widget)
window.set_focus(self.widget2)
class PyBootchartWindow(gtk.Window):