diff --git a/jgui/events/events.py b/jgui/events/events.py index 2ae3572..4473752 100644 --- a/jgui/events/events.py +++ b/jgui/events/events.py @@ -28,10 +28,14 @@ class EventSource(object): self.events[event].remove(callback) class WindowEventSource(EventSource): - types = ['mouse-enter', 'mouse-leave', - 'resize', 'move', - 'key-repeat', 'key-down', 'key-up', - 'mouse-right', 'mouse-right-up', - 'mouse-left', 'mouse-left-up', - 'mouse-middle', 'mouse-middle-up', - 'scroll-up', 'scroll-down', 'drag'] + mouse_events = ['mouse-enter', 'mouse-leave', 'drag', 'mouse-move', 'hover'] + mouse_wheel_events = ['scroll-up', 'scroll-down'] + mouse_button_down_events = ['mouse-right', 'mouse-left', 'mouse-middle'] + mouse_button_drag_events = ['mouse-right-drag', 'mouse-left-drag', 'mouse-middle-drag'] + mouse_button_up_events = ['mouse-right-up', 'mouse-left-up', + 'mouse-middle-up'] + mouse_button_events = mouse_button_down_events + mouse_button_up_events + mouse_button_drag_events + window_events = ['resize', 'move', 'focus'] + key_events = ['key-down', 'key-up', 'key-repeat'] + types = mouse_events + mouse_wheel_events + mouse_button_events +\ + window_events + key_events diff --git a/jgui/surface/structures.py b/jgui/surface/structures.py index 1636dbc..caeba65 100644 --- a/jgui/surface/structures.py +++ b/jgui/surface/structures.py @@ -50,6 +50,12 @@ class Position(StructureBase): other = Position.from_value(other) return Position(self.x-other.x, self.y-other.y) + def __eq__(self, other): + return self.x == other.x and self.y == other.y + + def __ne__(self, other): + return not(self == other) + @classmethod def from_value(cls, value): if not value: @@ -75,6 +81,12 @@ class Size(StructureBase): other = Size.from_value(other) return Size(self.width-other.width, self.height-other.height) + def __eq__(self, other): + return self.width == other.width and self.height == other.height + + def __ne__(self, other): + return not(self == other) + @classmethod def from_value(cls, value): if not value: diff --git a/jgui/surface/surface.py b/jgui/surface/surface.py index a2a2268..a2b6df9 100644 --- a/jgui/surface/surface.py +++ b/jgui/surface/surface.py @@ -12,7 +12,7 @@ class Surface(object): else: self.context = context self.root_window = Window('root', Position(0,0), self.size, self.context) - self.root_window.add_child(Window('child', Position(0,0), [500,200], self.context)) + self.root_window.add_child(Window('child', Position(0,0), [500,200], self.context, draggable=True)) self.windows = [self.root_window] def setTopZero(self, context): @@ -21,6 +21,12 @@ class Surface(object): 1, 0, 0) context.transform(matrix) + def inject_mouse_position(self, pos): + self.root_window.inject_mouse_position(pos) + + def inject_mouse_down(self, button): + self.root_window.inject_mouse_down(button) + def draw(self): #self.setTopZero(ctx) self.context.identity_matrix() @@ -86,19 +92,20 @@ class WindowSurface(object): context.stroke() def render(self): - self.draw_rounded_rect([0,0], [self.size.width, self.size.height], outline_width=self.size.width/50) + self.draw_rounded_rect([0,0], [self.size.width, self.size.height], outline_width=self.size.width/70) def draw(self): - self.context.save() - self.process_inputs() - self.render() - for child in self.children: - child.draw() - self.context.restore() + if self.visible: + self.context.save() + self.process_inputs() + self.render() + for child in self.children: + child.draw() + self.context.restore() class Window(WindowEventSource, WindowSurface): - def __init__(self, name, position=None, size=None, context=None): + def __init__(self, name, position=None, size=None, context=None, draggable=False): super(Window, self).__init__() self.context = context self.name = name @@ -106,50 +113,110 @@ class Window(WindowEventSource, WindowSurface): self.children = [] self.parent = None self.mouse_pos = Position(-1, -1) + self.mouse_diff = Position(0, 0) self.mouse_in = False self.mouse_hover = False self.mouse_down = False self.old_mouse_down = False + self.mouse_inputs = dict.fromkeys(self.mouse_button_down_events, False) + self.focused = False + self.visible = True + self.draggable = draggable - def injectMouseDown(self, button): - self.mouse_down = True + if self.draggable: + self.accept('mouse-left-drag', self.drag) + self.accept('mouse-left', self.click) + self.accept('mouse-left-up', self.click_up) - def injectMouseUp(self, button): - self.mouse_down = False + def drag(self, obj, mouse_pos): + obj.position = mouse_pos - self.mouse_diff - def injectMousePosition(self, pos): - self.mouse_pos = Position.from_value(pos) + def click(self, obj, mouse_pos): + self.mouse_diff = mouse_pos - self.position + + def click_up(self, obj, mouse_pos): + self.mouse_diff = Position(0, 0) + + def show(self): + self.visible = True + + def hide(self): + self.visible = False + + def inject_mouse_down(self, button): + if self.mouse_inside(): + print button, self.name + self.mouse_inputs[button] = True + self.mouse_down = True + self.grab_focus() + self.dispatch(button, self, self.mouse_pos) + else: + self.release_focus() for child in self.children: - child.injectMousePosition(pos) + child.inject_mouse_down(button) - def has_mouse_focus(self): + def inject_mouse_up(self, button): + if self.mouse_inside() and self.mouse_inputs[button]: + print button+'-up', self.name + self.mouse_down = False + self.mouse_inputs[button] = False + self.dispatch('{}-up'.format(button), self, self.mouse_pos) + for child in self.children: + child.inject_mouse_up(button) + + def inject_mouse_position(self, pos): + mouse_pos = Position.from_value(pos) + diff = mouse_pos - self.mouse_pos + if diff != Position(0,0): + self.dispatch('mouse-move', self, self.mouse_pos, mouse_pos) + if self.focused and self.mouse_down: + for button, down in self.mouse_inputs.items(): + if down: + self.dispatch('{}-drag'.format(button), self, self.mouse_pos) + self.mouse_pos = mouse_pos + for child in self.children: + child.inject_mouse_position(pos) + + def grab_focus(self): + self.focused = True + + def release_focus(self): + if self.focused: + print 'released', self.name + self.focused = False + self.mouse_down = False + #clear events that may have been triggered + #eg. User clicks on one window, holds, and + #then releases on another + for key in self.mouse_inputs: + self.mouse_inputs[key] = False + + + def mouse_inside(self): res = self.rectangle.intersects_with(self.mouse_pos) for child in self.children: - res &= not child.has_mouse_focus() + res &= not child.mouse_inside() + return res + + def mouse_held(self): + res = self.mouse_down + for child in self.children: + res |= child.mouse_down return res def process_inputs(self): - mouse_focus = self.has_mouse_focus() - if mouse_focus: - if not self.mouse_in: - print 'mouse-enter' - self.dispatch('mouse-enter', self) - self.mouse_in = True - else: - if self.mouse_in: - print 'mouse-leave' - self.dispatch('mouse-leave', self) - self.mouse_in = False - - if self.mouse_in and self.mouse_down and not self.old_mouse_down: - print 'mousedown' - self.dispatch('mouse-left', self, self.mouse_pos) - self.old_mouse_down = True - elif self.mouse_in and not self.mouse_down and self.old_mouse_down: - print 'mouseup' - self.dispatch('mouse-left-up', self, self.mouse_pos) - self.old_mouse_down = False - + mouse_focus = self.mouse_inside() + if not self.mouse_held(): + if mouse_focus: + if not self.mouse_in: + print 'mouse-enter', self.name + self.dispatch('mouse-enter', self) + self.mouse_in = True + else: + if self.mouse_in: + print 'mouse-leave', self.name + self.dispatch('mouse-leave', self) + self.mouse_in = False def add_child(self, child_window): if child_window not in self.children: