diff options
author | Philip Withnall <philip@tecnocode.co.uk> | 2013-08-17 01:30:50 (GMT) |
---|---|---|
committer | Philip Withnall <philip@tecnocode.co.uk> | 2013-08-17 01:31:21 (GMT) |
commit | 543f746a20340d7355b1b74c993c2262baac4c9c (patch) | |
tree | f97753b5b176a7d8781bf59b5c9ded0ef0504cb2 /PascalTriangle.activity/pascaltriangle.py | |
parent | 76ab880620fb36e3860360f60cd11ad45d04474d (diff) |
Add support for selecting a cell
This is one step on the way to supporting typing new values into cells.
Diffstat (limited to 'PascalTriangle.activity/pascaltriangle.py')
-rwxr-xr-x | PascalTriangle.activity/pascaltriangle.py | 117 |
1 files changed, 81 insertions, 36 deletions
diff --git a/PascalTriangle.activity/pascaltriangle.py b/PascalTriangle.activity/pascaltriangle.py index 6fd6f45..48441fc 100755 --- a/PascalTriangle.activity/pascaltriangle.py +++ b/PascalTriangle.activity/pascaltriangle.py @@ -1,36 +1,40 @@ from sugar3.activity import activity from sugar3.graphics.toolbarbox import ToolbarBox import math -from gi.repository import Gtk +from gi.repository import Gtk, Gdk import cairo class PascalTriangleActivity(activity.Activity): def __init__(self, handle): activity.Activity.__init__(self, handle) - # Create the standard activity toolbox. toolbar_box = ToolbarBox() self.set_toolbar_box(toolbar_box) toolbar_box.show() # Create a new GTK+ drawing area - self.drawing_area = Gtk.DrawingArea() - self.drawing_area.connect('button-press-event', - self._drawing_area_button_press_cb, None) - self.drawing_area.connect('draw', self._drawing_area_draw_cb, None) - - # Set the button to be our canvas. The canvas is the main section of - # every Sugar Window. It fills all the area below the toolbox. - self.set_canvas(self.drawing_area) + drawing_area = Gtk.DrawingArea() + drawing_area.add_events(Gdk.EventMask.BUTTON_PRESS_MASK) + drawing_area.connect('button-press-event', + self._drawing_area_button_press_cb, None) + drawing_area.connect('draw', self._drawing_area_draw_cb, None) - # The final step is to display this newly created widget. - self.drawing_area.show() + # Parent and show the drawing area. + self.set_canvas(drawing_area) + drawing_area.show() # Set the initial size of the Pascal triangle to be drawn. This is # the number of cells on its base (equivalently, the number of rows in # the triangle). - self.triangle_size = 5 + self._triangle_size = 5 + + # Padding around the edge of the drawing area. + self._padding = 10.0 # Cairo units + + # Set the currently selected cell (which the user's clicked on). + # Default to no selection (-1, -1). + self._current_cell = (-1, -1) """ @@ -45,37 +49,66 @@ class PascalTriangleActivity(activity.Activity): def _drawing_area_button_press_cb(self, widget, event, data = None): - pass + # Check whether the click fell within a cell; if so, change the cell + # selection. + if event.type != Gdk.EventType.BUTTON_PRESS: + return + + # There may be a more efficient way of doing this, but this works and + # is simple enough. Iterate through the cells and check whether the + # click was within a given radius of the cell centre. + widget_height = widget.get_allocated_height() + base_width = widget.get_allocated_width() - 2.0 * self._padding + triangle_height = widget_height - 2.0 * self._padding + cell_width = base_width / self._triangle_size + cell_height = 3.0 * (triangle_height / (2 * self._triangle_size + 1)) + radius = min(cell_width, cell_height) / 2.0 - def _drawing_area_draw_cb(self, widget, ctx, data = None): - # Default sizes (Cairo units). - padding = 10.0 + for row_index in range(self._triangle_size): + row_order = row_index + 1 + for column_index in range(row_order): + (cell_x, cell_y) = self._calculate_cell_position(base_width, + cell_width, cell_height, + row_index, column_index) + + actual_radius_sq = (cell_x - event.x) ** 2 + \ + (cell_y - event.y) ** 2 + + if actual_radius_sq <= radius ** 2: + # Found the cell. Update the current cell and queue a + # redraw. + self._current_cell = (row_index, column_index) + widget.queue_draw() + return True + # No cell found? Clear the current cell and queue a redraw. + self._current_cell = (-1, -1) + widget.queue_draw() + + return True + + + def _drawing_area_draw_cb(self, widget, ctx, data = None): # Widget allocation and sizes. The cell_height is calculated weirdly # because the cells interlock as they tesselate; so for 2 rows, the # bottom third of the top row overlaps with the top third of the bottom # row. widget_height = widget.get_allocated_height() - base_width = widget.get_allocated_width() - 2.0 * padding - triangle_height = widget_height - 2.0 * padding - cell_width = base_width / self.triangle_size - cell_height = 3.0 * (triangle_height / (2 * self.triangle_size + 1)) + base_width = widget.get_allocated_width() - 2.0 * self._padding + triangle_height = widget_height - 2.0 * self._padding + cell_width = base_width / self._triangle_size + cell_height = 3.0 * (triangle_height / (2 * self._triangle_size + 1)) # Draw the triangle rows from the top down. The row_order is the number # of cells in the row (increasing from 1 to triangle_size, inclusive). - row_order = 1 - # X position of the first cell on the row - cell_start_x = padding + base_width / 2.0 - - for row_index in range(self.triangle_size): + for row_index in range(self._triangle_size): + row_order = row_index + 1 for column_index in range(row_order): - # Calculate the cell position. Add an offset every odd row so - # the triangle is balanced. Each row is only 2/3 of cell_height - # because the hexagons interlock as they tesselate. - cell_x = cell_start_x + cell_width * column_index - cell_y = padding + cell_height / 2.0 + \ - (cell_height * row_index * (2.0 / 3.0)) + # Calculate the cell position. + (cell_x, cell_y) = self._calculate_cell_position(base_width, + cell_width, cell_height, + row_index, column_index) # Move to the cell position and draw the cell. ctx.move_to(cell_x, cell_y) @@ -83,14 +116,26 @@ class PascalTriangleActivity(activity.Activity): row_index, column_index, cell_width, cell_height) - cell_start_x -= cell_width / 2.0 - row_order += 1 - return True + def _calculate_cell_position(self, base_width, cell_width, + cell_height, row_index, column_index): + # Calculate the cell position. Add an offset every odd row so + # the triangle is balanced. Each row is only 2/3 of cell_height + # because the hexagons interlock as they tesselate. + cell_x = self._padding + \ + base_width / 2.0 - (cell_width / 2.0 * row_index) + \ + cell_width * column_index + cell_y = self._padding + cell_height / 2.0 + \ + (cell_height * row_index * (2.0 / 3.0)) + return (cell_x, cell_y) + + def _get_cell_background(self, row_index, column_index): - return cairo.SolidPattern(1.0, 1.0, 1.0) + if (row_index, column_index) == self._current_cell: + return cairo.SolidPattern(0.0, 0.7, 0.0) # green + return cairo.SolidPattern(1.0, 1.0, 1.0) # white def _draw_cell(self, ctx, row_index, column_index, cell_width, cell_height): |