diff --git a/src/gui/widgets/fanchart.py b/src/gui/widgets/fanchart.py index 391093d04..b9c46b95b 100644 --- a/src/gui/widgets/fanchart.py +++ b/src/gui/widgets/fanchart.py @@ -80,7 +80,7 @@ class FanChartWidget(Gtk.DrawingArea): (191,222,252), (183,219,197), (206,246,209)) - + TRANSLATE_PX = 10 COLLAPSED = 0 NORMAL = 1 EXPANDED = 2 @@ -232,8 +232,8 @@ class FanChartWidget(Gtk.DrawingArea): cr.restore() if child: # has at least one child cr.set_source_rgb(0, 0, 0) # black - cr.move_to(0,0) - cr.arc(0, 0, 10, 0, 2 * math.pi) + cr.move_to(0, 0) + cr.arc(0, 0, self.TRANSLATE_PX, 0, 2 * math.pi) cr.move_to(0,0) cr.fill() fontw, fonth = self.layout.get_pixel_size() @@ -393,6 +393,8 @@ class FanChartWidget(Gtk.DrawingArea): self.shrink_parents(generation + 1, selected+1, current) def change_slice(self, generation, selected): + if generation < 1: + return gstart, gstop, gmale, gstate = self.angle[generation][selected] if gstate == self.NORMAL: # let's expand if gmale: @@ -442,30 +444,8 @@ class FanChartWidget(Gtk.DrawingArea): def on_mouse_move(self, widget, event): self._mouse_click = False if self.last_x is None or self.last_y is None: - alloc = self.get_allocation() - x, y, w, h = alloc.x, alloc.y, alloc.width, alloc.height - cx = w/2 - self.center_xy[0] - cy = h/2 - self.center_xy[1] - radius = math.sqrt((event.x - cx) ** 2 + (event.y - cy) ** 2) - selected = None - if radius < self.center: - generation = 0 - selected = 0 - else: - generation = int((radius - self.center) / - self.pixels_per_generation) + 1 - rads = math.atan2( (event.y - cy), (event.x - cx) ) - if rads < 0: # second half of unit circle - rads = math.pi + (math.pi + rads) - pos = ((rads/(math.pi * 2) - self.rotate_value/360.) * 360.0) % 360 - if (0 < generation < self.generations): - for p in range(len(self.angle[generation])): - if self.data[generation][p][1]: # there is a person there - start, stop, male, state = self.angle[generation][p] - if state == self.COLLAPSED: continue - if start <= pos <= stop: - selected = p - break + # while mouse is moving, we must update the tooltip based on person + generation, selected = self.person_under_cursor(event.x, event.y) tooltip = "" if selected is not None: text, person, parents, child = self.data[generation][selected] @@ -474,42 +454,50 @@ class FanChartWidget(Gtk.DrawingArea): self.set_tooltip_text(tooltip) return False + #translate or rotate should happen alloc = self.get_allocation() x, y, w, h = alloc.x, alloc.y, alloc.width, alloc.height if self.translating: self.center_xy = w/2 - event.x, h/2 - event.y - self.queue_draw() - return True - cx = w/2 - self.center_xy[0] - cy = h/2 - self.center_xy[1] - # get the angles of the two points from the center: - start_angle = math.atan2(event.y - cy, event.x - cx) - end_angle = math.atan2(self.last_y - cy, self.last_x - cx) - if start_angle < 0: # second half of unit circle - start_angle = math.pi + (math.pi + start_angle) - if end_angle < 0: # second half of unit circle - end_angle = math.pi + (math.pi + end_angle) - # now look at change in angle: - diff_angle = (end_angle - start_angle) % (math.pi * 2.0) - self.rotate_value -= diff_angle * 180.0/ math.pi + else: + cx = w/2 - self.center_xy[0] + cy = h/2 - self.center_xy[1] + # get the angles of the two points from the center: + start_angle = math.atan2(event.y - cy, event.x - cx) + end_angle = math.atan2(self.last_y - cy, self.last_x - cx) + if start_angle < 0: # second half of unit circle + start_angle = math.pi + (math.pi + start_angle) + if end_angle < 0: # second half of unit circle + end_angle = math.pi + (math.pi + end_angle) + # now look at change in angle: + diff_angle = (end_angle - start_angle) % (math.pi * 2.0) + self.rotate_value -= diff_angle * 180.0/ math.pi + self.last_x, self.last_y = event.x, event.y self.queue_draw() - self.last_x, self.last_y = event.x, event.y return True - def on_mouse_down(self, widget, event): + def person_under_cursor(self, curx, cury): + """ + Determine the generation and the position in the generation at + position x and y. + generation = -1 on center black dot + generation >= self.generations outside of diagram + """ # compute angle, radius, find out who would be there (rotated) alloc = self.get_allocation() x, y, w, h = alloc.x, alloc.y, alloc.width, alloc.height - self.translating = False # keep track of up/down/left/right movement cx = w/2 - self.center_xy[0] cy = h/2 - self.center_xy[1] - radius = math.sqrt((event.x - cx) ** 2 + (event.y - cy) ** 2) - if radius < self.center: + radius = math.sqrt((curx - cx) ** 2 + (cury - cy) ** 2) + if radius < self.TRANSLATE_PX: + generation = -1 + elif radius < self.center: generation = 0 else: generation = int((radius - self.center) / self.pixels_per_generation) + 1 - rads = math.atan2( (event.y - cy), (event.x - cx) ) + + rads = math.atan2( (cury - cy), (curx - cx) ) if rads < 0: # second half of unit circle rads = math.pi + (math.pi + rads) pos = ((rads/(math.pi * 2) - self.rotate_value/360.) * 360.0) % 360 @@ -525,51 +513,54 @@ class FanChartWidget(Gtk.DrawingArea): if start <= pos <= stop: selected = p break - # Handle the click: - if generation == 0: - # left mouse on center: + elif generation == 0: + selected = 0 + return generation, selected + + def on_mouse_down(self, widget, event): + self.translating = False # keep track of up/down/left/right movement + generation, selected = self.person_under_cursor(event.x, event.y) + + # left mouse on center dot, we translate on left click + if generation == -1: if event.button == 1: # left mouse # save the mouse location for movements self.translating = True self.last_x, self.last_y = event.x, event.y return True - if selected is None: # clicked in open area, or center - if radius < self.center: - # right mouse - if gui.utils.is_right_click(event): - if self.data[0][0][1]: - self.context_popup_callback(widget, event, - self.data[0][0][1].handle) - return True - else: - return False - # else, what to do on left click? - else: - # save the mouse location for movements - self.last_x, self.last_y = event.x, event.y - return True - # Do things based on state, event.get_state(), or button, event.button - if event.button == 1: # left mouse + + #click in open area, prepare for a rotate + if selected is None: + # save the mouse location for movements + self.last_x, self.last_y = event.x, event.y + return True + + #left click on person, prepare for expand/collapse or drag + if event.button == 1: self._mouse_click = True self._mouse_click_gen = generation self._mouse_click_sel = selected return False - elif gui.utils.is_right_click(event): + + #right click on person, context menu + # Do things based on state, event.get_state(), or button, event.button + if gui.utils.is_right_click(event): text, person, parents, child = self.data[generation][selected] if person and self.context_popup_callback: self.context_popup_callback(widget, event, person.handle) return True - self.queue_draw() - return True + + return False def on_mouse_up(self, widget, event): - # Done with mouse movement if self._mouse_click: + # no drag occured, expand or collapse the section self.change_slice(self._mouse_click_gen, self._mouse_click_sel) self._mouse_click = False self.queue_draw() return True if self.last_x is None or self.last_y is None: + # No translate or rotate return True if self.translating: self.translating = False