JGUI/jgui/surface/surface.py
2014-01-29 15:51:36 -07:00

259 lines
8.9 KiB
Python

import cairo
import math
from .structures import Size, Position, Rectangle
from ..events.events import WindowEventSource
class Surface(object):
def __init__(self, size=None, context=None):
self.size = Size.from_value(size)
if context is None:
self.csurface = cairo.ImageSurface(cairo.FORMAT_ARGB32, self.size.width, self.size.height)
self.context = cairo.Context(self.csurface)
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, draggable=True))
self.windows = [self.root_window]
def setTopZero(self, context):
context.identity_matrix()
matrix = cairo.Matrix(1, 0, 0,
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()
self.context.set_operator(cairo.OPERATOR_CLEAR)
self.context.rectangle(0.0, 0.0, self.size.width, self.size.height)
self.context.fill()
self.context.set_operator(cairo.OPERATOR_OVER)
for window in self.windows:
window.draw()
class WindowSurface(object):
def __init__(self):
super(WindowSurface, self).__init__()
#self.mouse_pos
def draw_circle(self, position, size, color=(1,1,1), outline_width=1.0, outline_color=(0,0,0), start_angle=0.0, end_angle=360.0):
context = self.context
position = Position.from_value(position)
size = Size.from_value(size)
width = size.width
height = size.height
x,y = (self.position.x+position.x+width/2,
self.position.y+position.y+height/2)
context.set_line_width(outline_width)
context.save()
context.translate(x, y)
context.scale(width/2.0-outline_width/2.0, height/2.0-outline_width/2.0)
context.arc(0, 0, 1, start_angle, end_angle * math.pi/180.0)
context.restore()
context.set_source_rgba(*color)
context.fill_preserve()
context.set_source_rgba(*outline_color)
context.stroke()
def draw_rounded_rect(self, position, size, color=(1,1,1), outline_width=1, outline_color=(0,0,0), corner_radius=10):
position = Position.from_value(position)
size = Size.from_value(size)
context = self.context
radius = corner_radius
degrees = math.pi / 180.0
x = position.x + self.position.x
y = position.y + self.position.y
width = size.width
height = size.height
context.new_sub_path()
context.arc(x + width - radius - outline_width/2.0, y + radius + outline_width/2.0, radius, -90 * degrees, 0 * degrees)
context.arc(x + width - radius - outline_width/2.0, y + height - radius - outline_width/2.0, radius, 0 * degrees, 90 * degrees)
context.arc(x + radius + outline_width/2.0, y + height - radius - outline_width/2.0, radius, 90 * degrees, 180 * degrees)
context.arc(x + radius + outline_width/2.0, y + radius + outline_width/2.0, radius, 180 * degrees, 270 * degrees)
context.close_path()
context.set_source_rgb(*color)
context.fill_preserve()
context.set_source_rgba(*outline_color)
context.set_line_width(outline_width)
context.stroke()
def render(self):
self.draw_rounded_rect([0,0], [self.size.width, self.size.height], outline_width=self.size.width/70)
def draw(self):
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, draggable=False):
super(Window, self).__init__()
self.context = context
self.name = name
self.rectangle = Rectangle(position, size)
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
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 drag(self, obj, mouse_pos):
obj.position = mouse_pos - self.mouse_diff
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.inject_mouse_down(button)
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.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.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:
child_window.parent = self
child_window.position = child_window.position + self.position
self.children.append(child_window)
def remove_child(self, child_window):
try:
self.children.remove(child_window)
child_window.parent = None
except ValueError:
pass
@property
def position(self):
return self.rectangle.position
@position.setter
def position(self, position):
diff = position - self.rectangle.position
if diff.x != 0 or diff.y != 0:
self.dispatch('move', self, position)
for child in self.children:
child.position = child.position + diff
self.rectangle.position = position
@property
def size(self):
return self.rectangle.size
@size.setter
def size(self, size):
diff = size - self.rectangle.size
if diff.height != 0 or diff.width != 0:
self.dispatch('resize', self, size)
for child in self.children:
child.size = child.size + diff
self.rectangle.size = size