blob: bb4f2577337c780da06d291938cc6eb3bb73edf1 [file] [log] [blame]
# Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
"""This module provides GUI for touch device firmware test using GTK."""
import re
import gobject
import gtk
import gtk.gdk
import pango
import firmware_utils
import test_conf as conf
from firmware_constants import TFK
TITLE = "Touch Firmware Test"
class BaseFrame(object):
"""A simple base frame class."""
def __init__(self, label=None, size=None, aspect=False):
# Create a regular/aspect frame
self.frame = gtk.AspectFrame() if aspect else gtk.Frame()
self.frame.set_shadow_type(gtk.SHADOW_ETCHED_OUT)
self.size = size
if label:
self.frame.set_label(label)
self.frame.set_label_align(0.0, 0.0)
frame_label = self.frame.get_label_widget()
markup_str = '<span foreground="%s" size="x-large">%s</span>'
frame_label.set_markup(markup_str % ('black', label))
if size:
width, height = size
self.frame.set_size_request(width, height)
if aspect:
self.frame.set(ratio=(float(width) / height))
class PromptFrame(BaseFrame):
"""A simple frame widget to display the prompt.
It consists of:
- A frame
- a label showing the gesture name
- a label showing the prompt
- a label showing the keyboard interactions
"""
def __init__(self, label=None, size=None):
super(PromptFrame, self).__init__(label, size)
# Create a vertical packing box.
self.vbox = gtk.VBox(False, 0)
self.frame.add(self.vbox)
# Create a label to show the gesture name
self.label_gesture = gtk.Label('Gesture Name')
self.label_gesture.set_justify(gtk.JUSTIFY_LEFT)
self.vbox.pack_start(self.label_gesture, True, True, 0)
# Expand the lable to be wider and wrap the line if necessary.
if self.size:
_, label_height = self.label_gesture.get_size_request()
width, _ = self.size
label_width = int(width * 0.9)
self.label_gesture.set_size_request(label_width, label_height)
self.label_gesture.set_line_wrap(True)
# Pack a horizontal separator
self.vbox.pack_start(gtk.HSeparator(), True, True, 0)
# Create a label to show the prompt
self.label_prompt = gtk.Label('Prompt')
self.label_prompt.set_justify(gtk.JUSTIFY_CENTER)
self.vbox.pack_start(self.label_prompt, True, True, 0)
# Create a label to show the choice
self.label_choice = gtk.Label('')
self.label_choice.set_justify(gtk.JUSTIFY_LEFT)
self.vbox.pack_start(self.label_choice, True, True, 0)
# Show all widgets added to this frame
self.frame.show_all()
def set_gesture_name(self, string, color='blue'):
"""Set the gesture name in label_gesture."""
markup_str = '<b><span foreground="%s" size="xx-large"> %s </span></b>'
self.label_gesture.set_markup(markup_str % (color, string))
def set_prompt(self, string, color='black'):
"""Set the prompt in label_prompt."""
markup_str = '<span foreground="%s" size="x-large"> %s </span>'
self.label_prompt.set_markup(markup_str % (color, string))
def set_choice(self, string):
"""Set the choice in label_choice."""
self.label_choice.set_text(string)
class ResultFrame(BaseFrame):
"""A simple frame widget to display the test result.
It consists of:
- A frame
- a scrolled window
- a label showing the test result
"""
SCROLL_STEP = 100.0
def __init__(self, label=None, size=None):
super(ResultFrame, self).__init__(label, size)
# Create a scrolled window widget
self.scrolled_window = gtk.ScrolledWindow()
self.scrolled_window.set_policy(gtk.POLICY_AUTOMATIC,
gtk.POLICY_AUTOMATIC)
self.frame.add(self.scrolled_window)
# Create a vertical packing box.
self.vbox = gtk.VBox(False, 0)
self.scrolled_window.add_with_viewport(self.vbox)
# Create a label to show the gesture name
self.result = gtk.Label()
self.vbox.pack_start(self.result , False, False, 0)
# Show all widgets added to this frame
self.frame.show_all()
# Get the vertical and horizontal adjustments
self.vadj = self.scrolled_window.get_vadjustment()
self.hadj = self.scrolled_window.get_hadjustment()
self._scroll_func_dict = {TFK.UP: self._scroll_up,
TFK.DOWN: self._scroll_down,
TFK.LEFT: self._scroll_left,
TFK.RIGHT: self._scroll_right}
def _calc_result_font_size(self):
"""Calculate the font size so that it does not overflow."""
label_width_in_px, _ = self.size
font_size = int(float(label_width_in_px) / conf.num_chars_per_row *
pango.SCALE)
return font_size
def set_result(self, text, color='black'):
"""Set the text in the result label."""
mod_text = re.sub('<', '&lt;', text)
mod_text = re.sub('>', '&gt;', mod_text)
markup_str = '<b><span foreground="%s" size="%d"> %s </span></b>'
font_size = self._calc_result_font_size()
self.result.set_markup(markup_str % (color, font_size, mod_text))
def _calc_inc_value(self, adj):
"""Calculate new increased value of the specified adjustement object."""
value = adj.get_value()
new_value = min(value + self.SCROLL_STEP, adj.upper - adj.page_size)
return new_value
def _calc_dec_value(self, adj):
"""Calculate new decreased value of the specified adjustement object."""
value = adj.get_value()
new_value = max(value - self.SCROLL_STEP, adj.lower)
return new_value
def _scroll_down(self):
"""Scroll the scrolled_window down."""
self.vadj.set_value(self._calc_inc_value(self.vadj))
def _scroll_up(self):
"""Scroll the scrolled_window up."""
self.vadj.set_value(self._calc_dec_value(self.vadj))
def _scroll_right(self):
"""Scroll the scrolled_window to the right."""
self.hadj.set_value(self._calc_inc_value(self.hadj))
def _scroll_left(self):
"""Scroll the scrolled_window to the left."""
self.hadj.set_value(self._calc_dec_value(self.hadj))
def scroll(self, choice):
"""Scroll the result frame using the choice key."""
scroll_method = self._scroll_func_dict.get(choice)
if scroll_method:
scroll_method()
else:
print 'Warning: the key choice "%s" is not legal!' % choice
class ImageFrame(BaseFrame):
"""A simple frame widget to display the mtplot window.
It consists of:
- An aspect frame
- an image widget showing mtplot
"""
def __init__(self, label=None, size=None):
super(ImageFrame, self).__init__(label, size, aspect=True)
# Use a fixed widget to display the image.
self.fixed = gtk.Fixed()
self.frame.add(self.fixed)
# Create an image widget.
self.image = gtk.Image()
self.fixed.put(self.image, 0, 0)
# Show all widgets added to this frame
self.frame.show_all()
def set_from_file(self, filename):
"""Set the image file."""
self.image.set_from_file(filename)
self.frame.show_all()
class FirmwareWindow(object):
"""A simple window class to display the touch firmware test window."""
def __init__(self, size=None, prompt_size=None, result_size=None,
image_size=None):
# Create a new window
self.win = gtk.Window(gtk.WINDOW_TOPLEVEL)
if size:
self.win_size = size
self.win.resize(*size)
self.win.set_title(TITLE)
self.win.set_border_width(0)
# Create the prompt frame
self.prompt_frame = PromptFrame(TITLE, prompt_size)
# Create the result frame
self.result_frame = ResultFrame("Test results:", size=result_size)
# Create the image frame for mtplot
self.image_frame = ImageFrame(size=image_size)
# Handle layout below
self.box0 = gtk.VBox(False, 0)
self.box1 = gtk.HBox(False, 0)
# Arrange the layout about box0
self.win.add(self.box0)
self.box0.pack_start(self.prompt_frame.frame, True, True, 0)
self.box0.pack_start(self.box1, True, True, 0)
# Arrange the layout about box1
self.box1.pack_start(self.image_frame.frame, True, True, 0)
self.box1.pack_start(self.result_frame.frame, True, True, 0)
# Capture keyboard events.
self.win.add_events(gtk.gdk.KEY_PRESS_MASK | gtk.gdk.KEY_RELEASE_MASK)
# Set a handler for delete_event that immediately exits GTK.
self.win.connect("delete_event", self.delete_event)
# Show all widgets.
self.win.show_all()
def register_callback(self, event, callback):
"""Register a callback function for an event."""
self.win.connect(event, callback)
def register_timeout_add(self, callback, timeout):
"""Register a callback function for gobject.timeout_add."""
return gobject.timeout_add(timeout, callback)
def register_io_add_watch(self, callback, fd, data=None,
condition=gobject.IO_IN):
"""Register a callback function for gobject.io_add_watch."""
if data:
return gobject.io_add_watch(fd, condition, callback, data)
else:
return gobject.io_add_watch(fd, condition, callback)
def create_key_press_event(self, keyval):
"""Create a key_press_event."""
event = gtk.gdk.Event(gtk.gdk.KEY_PRESS)
# Assign current time to the event
event.time = 0
event.keyval = keyval
self.win.emit('key_press_event', event)
def remove_event_source(self, tag):
"""Remove the registered callback."""
gobject.source_remove(tag)
def delete_event(self, widget, event, data=None):
"""A handler to exit the window."""
self.stop()
return False
def set_input_focus(self):
"""Set input focus to this window."""
x = firmware_utils.SimpleX(TITLE)
x.set_input_focus()
def set_gesture_name(self, string, color='blue'):
"""A helper method to set gesture name."""
self.prompt_frame.set_gesture_name(string, color)
def set_prompt(self, string, color='black'):
"""A helper method to set the prompt."""
self.prompt_frame.set_prompt(string, color)
def set_choice(self, string):
"""A helper method to set the choice."""
self.prompt_frame.set_choice(string)
def set_result(self, text):
"""A helper method to set the text in the result."""
self.result_frame.set_result(text)
def set_image(self, filename):
"""Set an image in the image frame."""
self.image_frame.set_from_file(filename)
def scroll(self, choice):
"""Scroll the result frame using the choice key."""
self.result_frame.scroll(choice)
def stop(self):
"""Quit the window."""
gtk.main_quit()
def main(self):
"""Main function of the window."""
gtk.main()