From f70b1af2f325576c5aab4534cd236684e0061e2c Mon Sep 17 00:00:00 2001 From: Sylvain Tricot Date: Mon, 25 Jan 2021 13:59:03 +0100 Subject: [PATCH] Continue with wx->gtk portage. Callbacks for mouse events are "almost" working in this commit. --- .../msspecgui/msspec/gui/clusterviewer_gi.py | 144 ++++++++++++++---- 1 file changed, 114 insertions(+), 30 deletions(-) diff --git a/src/msspec/msspecgui/msspec/gui/clusterviewer_gi.py b/src/msspec/msspecgui/msspec/gui/clusterviewer_gi.py index 412126e..7796a42 100644 --- a/src/msspec/msspecgui/msspec/gui/clusterviewer_gi.py +++ b/src/msspec/msspecgui/msspec/gui/clusterviewer_gi.py @@ -1,8 +1,8 @@ # -*- encoding: utf-8 -*- -# vim: set fdm=indent ts=2 sw=2 sts=2 et tw=80 cc=+1 mouse=a nu : # # import wx import numpy as np +from threading import Timer # from time import clock # import copy @@ -11,7 +11,8 @@ import wx.lib.wxcairo import gi gi.require_version("Gtk", "3.0") -from gi.repository import GLib, Gio, Gtk, Gdk +from gi.repository import GLib, Gio, Gtk, Gdk, GObject +GObject.threads_init() # import ase from ase.data import covalent_radii @@ -101,16 +102,22 @@ class ClusterViewer(Gtk.Window): #self.Bind(wx.EVT_TIMER, self.__evt_timer_cb, self.timer) self.drawing_area.add_events(Gdk.EventMask.SCROLL_MASK | - Gdk.EventMask.POINTER_MOTION_MASK | - Gdk.EventMask.BUTTON1_MOTION_MASK) + #Gdk.EventMask.POINTER_MOTION_MASK | + Gdk.EventMask.BUTTON_PRESS_MASK | + Gdk.EventMask.BUTTON_RELEASE_MASK | + Gdk.EventMask.BUTTON1_MOTION_MASK | + Gdk.EventMask.BUTTON3_MOTION_MASK) self.connect("size-allocate", self.__evt_size_cb) self.drawing_area.connect("draw", self.__evt_draw_cb) self.drawing_area.connect("scroll-event", self.__evt_mousewheel_cb) self.drawing_area.connect("motion-notify-event", self.__evt_motion_cb) - #self.drawing_area.connect("button-press-event", self.__evt_press_cb) + self.drawing_area.connect("button-press-event", self.__evt_press_cb) + self.drawing_area.connect("button-release-event", self.__evt_release_cb) #self.drawing_area.connect("button-release-event", self.__evt_release_cb) + self.timer_id = None + def show_emitter(self, show=True, alpha=0.25): _opts = self.sprites_opts.copy() if show: @@ -123,11 +130,11 @@ class ClusterViewer(Gtk.Window): """ Attach an Atoms object to the view. - This will translate the model to the center of mass, move the model - center to the center of screen and adjust the scale to the largest + This will translate the model to the center of mass, move the model + center to the center of screen and adjust the scale to the largest dimension of the model - :param rescale: if True, the zoom is computed to view the atoms; if + :param rescale: if True, the zoom is computed to view the atoms; if False, a fixed zoom value is used """ if atoms is None: @@ -149,7 +156,7 @@ class ClusterViewer(Gtk.Window): self.atoms_center_of_mass = atoms.get_center_of_mass() # get the largest dimension p = atoms.get_positions() - self.atoms_largest_dimension = np.max(np.amax(p, axis=0) - + self.atoms_largest_dimension = np.max(np.amax(p, axis=0) - np.amin(p, axis=0)) if self.atoms_largest_dimension == 0: self.atoms_largest_dimension = 1.0 @@ -203,8 +210,8 @@ class ClusterViewer(Gtk.Window): self.translation_matrix[-1, (0, 1)] = (x, y) self.update_projection_matrix() - def select_atoms(self, x, y, w=None, h=None, append=False, - toggle=False): + def select_atoms(self, x, y, w=None, h=None, append=False, toggle=False): + print("Append=", append, "Toggle=", toggle) selection = np.array([]) if w is None and h is None: # get the projections @@ -237,10 +244,10 @@ class ClusterViewer(Gtk.Window): selection = p[:, -1].astype(int) if toggle: - #print(self.selection) + print(self.selection) # whether atoms in the current selection were previously selected i = np.in1d(self.selection, selection) - #print(i) + print(i) self.selection = self.selection[np.invert(i)] if append: @@ -261,8 +268,9 @@ class ClusterViewer(Gtk.Window): self.update_drawing() def __evt_size_cb(self, widget, data): - #self.timer.Stop() - #self.timer.Start(self.refresh_delay) + #self.timer.cancel() + #self.timer.start() + self._postpone_drawing() size = self.get_size() self.back_buffer = cairo.ImageSurface(cairo.FORMAT_RGB24, *size) self.create_background_sprite(*size) @@ -283,6 +291,53 @@ class ClusterViewer(Gtk.Window): if event.AltDown(): self.mode |= self.MODE_SELECTION_TOGGLE + def __evt_press_cb(self, widget, event): + if event.button == 1: + print("press_cb", event.state) + self.mx = event.x + self.my = event.y + self.capture_screen() + if event.state & Gdk.ModifierType.CONTROL_MASK: + self.mode |= self.MODE_SELECTION + if event.state & Gdk.ModifierType.SHIFT_MASK: + self.mode |= self.MODE_SELECTION_APPEND + if event.state & Gdk.ModifierType.MOD1_MASK: + self.mode |= self.MODE_SELECTION_TOGGLE + + def __evt_release_cb(self, widget, event): + if event.button not in (1,3): + return + + if self.mode & self.MODE_SELECTION: + self.mode ^= self.MODE_SELECTION + # search for atoms in the selection box + x, y = event.x, event.y + w = h = None + if self.mode & self.MODE_SELECTION_BOX: + self.mode ^= self.MODE_SELECTION_BOX + x, y, w, h = self.selection_box + + append = False + if self.mode & self.MODE_SELECTION_APPEND: + self.mode ^= self.MODE_SELECTION_APPEND + append = True + + toggle = False + if self.mode & self.MODE_SELECTION_TOGGLE: + self.mode ^= self.MODE_SELECTION_TOGGLE + toggle = True + + self.select_atoms(x, y, w, h, append=append, toggle=toggle) + + if self.mode == self.MODE_TRANSLATION: + self.mode ^= self.MODE_TRANSLATION + + if self.mode & self.MODE_ROTATION: + self.mode ^= self.MODE_ROTATION + + self.update_drawing(light=False) + + def __evt_left_up_cb(self, event): if self.mode & self.MODE_SELECTION: self.mode ^= self.MODE_SELECTION @@ -351,9 +406,12 @@ class ClusterViewer(Gtk.Window): self.update_drawing() def __evt_motion_cb(self, widget, event): - #self.timer.Stop() - #self.timer.Start(self.refresh_delay) - if True:#event.state & Gdk.ModifierType.BUTTON1_MASK: + #self.timer.cancel() + #self.timer.start() + self._postpone_drawing() + self._update_flag = True + GLib.timeout_add(self.refresh_delay, self.update_drawing, False) + if event.state & Gdk.ModifierType.BUTTON1_MASK: print("motion cb...", bool(event.state & Gdk.ModifierType.BUTTON1_MASK)) mx, my = event.x, event.y @@ -374,11 +432,11 @@ class ClusterViewer(Gtk.Window): self.translate_atoms(self.ox, self.oy) self.update_drawing() #elif event.RightIsDown(): - elif event.state & Gdk.ModifierType.BUTTON2_MASK: + elif event.state & Gdk.ModifierType.BUTTON3_MASK: self.mode = self.MODE_ROTATION theta = 2. * (float(self.scale0) / self.scale) theta = max(1., theta) - mx, my = event.GetPosition() + mx, my = event.x, event.y dx, dy = (mx - self.mx, my - self.my) self.mx, self.my = (mx, my) @@ -433,8 +491,9 @@ class ClusterViewer(Gtk.Window): else: #rot = event.GetWheelRotation() rot = event.direction - #self.timer.Stop() - #self.timer.Start(self.refresh_delay) + #self.timer.cancel() + #self.timer.start() + self._postpone_drawing() if rot == Gdk.ScrollDirection.UP: factor = self.scale * 1.1 im_factor = 1 * 1.1 @@ -445,6 +504,29 @@ class ClusterViewer(Gtk.Window): self.scale_atoms(factor) self.update_drawing() + + def target_fn(self): + print("Timer function!!") + return True + + def _postpone_drawing(self): + if self.timer_id: + GLib.source_remove(self.timer_id) + self.timer_id = GLib.timeout_add(self.refresh_delay, + self.update_drawing, False) + + + def __postpone_drawing(self): + return + try: + self.timer.cancel() + except: + #self.timer = Timer(self.refresh_delay, self.update_drawing, + # kwargs={'light_mode': False}) + self.timer = Timer(self.refresh_delay, self.target_fn) + self.timer.start() + print("Timer created") + def capture_screen(self): # get size of screen w, h = self.get_size() @@ -514,7 +596,7 @@ class ClusterViewer(Gtk.Window): return surface, overlay for i, a in enumerate(atom_numbers): - surface, overlay = create_surface(a, + surface, overlay = create_surface(a, alpha=self.sprites_opts['alpha'], glow=self.sprites_opts['glow']) atom_surfaces[0, i] = surface @@ -565,7 +647,7 @@ class ClusterViewer(Gtk.Window): self.atom_surfaces = atom_surfaces try: absorber_number = self.atoms[self.atoms.info['absorber']].number - self.absorber_surface = create_surface(absorber_number, alpha=1, + self.absorber_surface = create_surface(absorber_number, alpha=1, glow=True) except: self.atoms.info['absorber'] = -1 @@ -622,10 +704,10 @@ class ClusterViewer(Gtk.Window): @classmethod def create_v2p_matrix(cls, left, right, bottom, top, near, far): """ - creates the matrix that transforms coordinates from view space (space + creates the matrix that transforms coordinates from view space (space defined by the bounding box passed as argument) to projection space - this transformation is a scale and offset that maps [left; right], + this transformation is a scale and offset that maps [left; right], [bottom; top], [near; far] to [-1;1], [-1;1], [0;1] """ v2p_matrix = np.eye(4) * -1 @@ -685,12 +767,12 @@ class ClusterViewer(Gtk.Window): scalebar_bb_width = 200 scalebar_bb_height = 20 ctx.set_source_rgba(0., 0., 0., 0.7) - ctx.rectangle(x + w - scalebar_bb_width - 6, h - scalebar_bb_height - 6, + ctx.rectangle(x + w - scalebar_bb_width - 6, h - scalebar_bb_height - 6, scalebar_bb_width, scalebar_bb_height) ctx.fill() ctx.set_source_rgb(1, 1, 1) - ctx.rectangle(x + w - scalebar_bb_width, h - scalebar_bb_height, 100, + ctx.rectangle(x + w - scalebar_bb_width, h - scalebar_bb_height, 100, scalebar_bb_height - 12) ctx.fill() @@ -890,7 +972,7 @@ class ClusterViewer(Gtk.Window): v2 = projections[f[3], :3] - projections[f[0], :3] # cross multiply them to get the normal n = np.cross(v2, v1) - # If the normal z coordinate is <0, the plane is not visible, so, + # If the normal z coordinate is <0, the plane is not visible, so, # draw it first, otherwise draw it last if n[-1] > 0: ind.append(i) @@ -997,6 +1079,7 @@ class ClusterViewer(Gtk.Window): allocation = self.drawing_area.get_allocation() self.drawing_area.queue_draw_area(allocation.x, allocation.y, allocation.width, allocation.height) + return False def swap_buffers(self): if self.back_buffer: @@ -1007,7 +1090,7 @@ class ClusterViewer(Gtk.Window): bitmap = wx.lib.wxcairo.BitmapFromImageSurface(back_buffer) dc = wx.PaintDC(self) dc.DrawBitmap(bitmap, 0, 0) - + def __evt_draw_cb(self, da, ctx): if self.back_buffer: print("Draw called.", ctx) @@ -1022,6 +1105,7 @@ if __name__ == "__main__": import wx MgO = bulk('MgO', crystalstructure='rocksalt', a=4.21, cubic=True) + MgO = MgO.repeat((10,10,10)) #view(MgO) #app = wx.App(False)