示例#1
0
    def __init__(self, manager, window=None, **kwargs):
        super().__init__(**kwargs)

        self.manager = manager

        if window:
            self._window = window
        else:
            self._window = manager.screen.root.create_window(
                x=0,
                y=0,
                width=self.width,
                height=self.height,
                depth=self.manager.screen.root_depth,
                border_width=0,
                window_class=Xlib.X.InputOutput,
                visual=Xlib.X.CopyFromParent,
            )

        refresh_hz = int(os.environ.get('KIVYWM_REFRESH_HZ', 60))
        self.refresh_rate = 1 / refresh_hz if refresh_hz > 0 else 0
        self.canvas = RenderContext(use_parent_projection=True,
                                    use_parent_modelview=True,
                                    use_parent_frag_modelview=True)

        with self.canvas:
            self.rect = Rectangle(size=self.size)
 def __init__(self, **kwargs):
     self.this_op = None
     self.units_per_meter = 16.0
     self.gravity = 9.8
     self.fps = 60.0
     self.vertex_format = [
         (b'vPosition', 3, 'float'),
         (b'vSize', 1, 'float'),
         (b'vRotation', 1, 'float'),
         (b'vVelocity', 3, 'float'),
     ]
     self.ROTATION_I = 4  # must match index of vRotation above
     self.VELOCITY_I = 5  # must match index of vVelocity above
     self.vertex_depth = 0
     for element in self.vertex_format:
         self.vertex_depth += element[1]
     self.star_list = []
     self.canvas = RenderContext(use_parent_projection=True)
     self.canvas.shader.source = 'pointshader3d.glsl'
     glEnable(0x8642)  #GL_VERTEX_PROGRAM_POINT_SIZE
     glEnable(0x8861)  #GL_POINT_SPRITE
     self.mesh = None
     super(PointRenderer, self).__init__(**kwargs)
     self.canvas["camera_eyespace_z"] = self.width / 2.0
     self.canvas["max_particle_size"] = self.width
     self.draw_mesh_points(60)
     #Clock.schedule_interval(self.test_mesh_remove, 1./60.)
     Clock.schedule_interval(self.test_mesh_move, 1. / self.fps)
示例#3
0
    def create_window(self):
        '''Will create the main window and configure it.

        .. warning::
            This method is called automatically at runtime. If you call it, it
            will recreate a RenderContext and Canvas. This mean you'll have a
            new graphics tree, and the old one will be unusable.

            This method exist to permit the creation of a new OpenGL context
            AFTER closing the first one. (Like using runTouchApp() and
            stopTouchApp()).

            This method have been only tested in unittest environment, and will
            be not suitable for Applications.

            Again, don't use this method unless you know exactly what you are
            doing !
        '''
        from kivy.core.gl import init_gl
        init_gl()

        # create the render context and canvas
        from kivy.graphics import RenderContext, Canvas
        self.render_context = RenderContext()
        self.canvas = Canvas()
        self.render_context.add(self.canvas)
示例#4
0
    def __init__(self, **kwargs):
        # change the default canvas to RenderContext, we can change the shader
        self.canvas = RenderContext()
        self.canvas.shader.fs = hsv_kinect

        # add kinect depth provider, and start the thread
        self.kinect = KinectDepth()
        self.kinect.start()

        # parent init
        super(KinectViewer, self).__init__(**kwargs)

        # allocate texture for pushing depth
        self.texture = Texture.create(size=(640, 480),
                                      colorfmt='luminance',
                                      bufferfmt='ushort')
        self.texture.flip_vertical()

        # create default canvas element
        with self.canvas:
            Color(1, 1, 1)
            Rectangle(size=Window.size, texture=self.texture)

        # add a little clock to update our glsl
        Clock.schedule_interval(self.update_transformation, 0)
    def add_screen(self, screen):
        self.screen_in.pos = self.screen_out.pos
        self.screen_in.size = self.screen_out.size
        self.manager.real_remove_widget(self.screen_out)

        self.fbo_in = self.make_screen_fbo(self.screen_in)
        self.fbo_out = self.make_screen_fbo(self.screen_out)
        self.manager.canvas.add(self.fbo_in)
        self.manager.canvas.add(self.fbo_out)

        self.canvas = Canvas()
        self.c_front = RenderContext()
        self.c_front.shader.source = resource_find('front.glsl')
        self.c_back = RenderContext()
        self.c_back.shader.source = resource_find('back.glsl')
        self.c_backshadow = RenderContext()
        self.c_backshadow.shader.source = resource_find('backshadow.glsl')
        self.canvas.add(self.c_front)
        self.canvas.add(self.c_back)
        self.canvas.add(self.c_backshadow)

        with self.canvas.before:
            Color(1, 1, 1)
            Rectangle(
                size=self.fbo_in.size,
                texture=self.fbo_in.texture)
            Callback(self._enter_3d)
        self._build_mesh(self.fbo_in.size)
        with self.canvas.after:
            Callback(self._leave_3d)

        self.manager.canvas.add(self.canvas)
示例#6
0
    def __init__(self, **kwargs):
        # Make sure opengl context exists
        EventLoop.ensure_window()

        self.canvas = RenderContext(use_parent_projection=True,
                                    use_parent_modelview=True)

        with self.canvas:
            self.fbo = Fbo(size=self.size)

        with self.fbo.before:
            PushMatrix()
        with self.fbo:
            ClearColor(0, 0, 0, 0)
            ClearBuffers()
            self._background_color = Color(*self.background_color)
            self.fbo_rectangle = Rectangle(size=self.size)
        with self.fbo.after:
            PopMatrix()

        super(EffectWidget, self).__init__(**kwargs)

        Clock.schedule_interval(self._update_glsl, 0)

        fbind = self.fbind
        fbo_setup = self.refresh_fbo_setup
        fbind('size', fbo_setup)
        fbind('effects', fbo_setup)
        fbind('background_color', self._refresh_background_color)

        self.refresh_fbo_setup()
        self._refresh_background_color()  # In case thi was changed in kwargs
示例#7
0
    def __init__(self, **kwargs):
        # Make sure opengl context exists
        EventLoop.ensure_window()

        self.canvas = RenderContext(use_parent_projection=True,
                                    use_parent_modelview=True)

        with self.canvas:
            self.fbo = Fbo(size=self.size)

        with self.fbo.before:
            PushMatrix()
            self.fbo_translation = Translate(-self.x, -self.y, 0)
        with self.fbo:
            ClearColor(1, 1, 1, 1)
            Color(*self.background_color)
            ClearBuffers()
            self.fbo_rectangle = Rectangle(size=self.size)
        with self.fbo.after:
            PopMatrix()

        super(EffectWidget, self).__init__(**kwargs)

        Clock.schedule_interval(self._update_glsl, 0)

        self.bind(pos=self._update_translation,
                  size=self.refresh_fbo_setup,
                  effects=self.refresh_fbo_setup)

        self.refresh_fbo_setup()
示例#8
0
    def __init__(self, *args, **kwargs):
        self.render_context = RenderContext()
        super().__init__(**kwargs)
        self.configurable_properties = {}

        self.render_context['modelview_mat'] = Matrix().identity()
        self.render_context['projection_mat'] = Matrix().identity()
        self.render_context['window_size'] = [
            float(Window.width), float(Window.height)
        ]
        self.canvas.before.add(self.render_context)

        self.update_event = None

        self.shader_substitutions = defaultdict(list)
        self.fmt = []
        self.n_data_sources = 0
        self.vertices_per_datum = 1
        self.format_has_changed = True

        prop = self.property('fps')
        prop.dispatch(self)
        with self.canvas:
            StencilPush()
            Color(0, 1, 1, mode='hsv')
            self.stencil = Rectangle(pos=(10, 10), size=(self.size))
            StencilUse()
            self.stencil_color = Color(*self.background_color)
            Rectangle(pos=(-100, -100), size=(10000, 1000000))
            self.render_context = RenderContext()
            StencilPop()
        self.addControlBar()
示例#9
0
class KinectViewer(Widget):

    depth_range = NumericProperty(7.7)

    shader = StringProperty("rgb")

    index = NumericProperty(0)

    def __init__(self, **kwargs):
        # change the default canvas to RenderContext, we can change the shader
        self.canvas = RenderContext()
        self.canvas.shader.fs = hsv_kinect

        # add kinect depth provider, and start the thread
        self.kinect = KinectDepth()
        self.kinect.start()

        # parent init
        super(KinectViewer, self).__init__(**kwargs)

        # allocate texture for pushing depth
        self.texture = Texture.create(size=(640, 480),
                                      colorfmt='luminance',
                                      bufferfmt='ushort')
        self.texture.flip_vertical()

        # create default canvas element
        with self.canvas:
            Color(1, 1, 1)
            Rectangle(size=Window.size, texture=self.texture)

        # add a little clock to update our glsl
        Clock.schedule_interval(self.update_transformation, 0)

    def on_index(self, instance, value):
        self.kinect.index = value

    def on_shader(self, instance, value):
        if value == 'rgb':
            self.canvas.shader.fs = rgb_kinect
        elif value == 'hsv':
            self.canvas.shader.fs = hsv_kinect
        elif value == 'points':
            self.canvas.shader.fs = points_kinect

    def update_transformation(self, *largs):
        # update projection mat and uvsize
        self.canvas['projection_mat'] = Window.render_context['projection_mat']
        self.canvas['depth_range'] = self.depth_range
        self.canvas['size'] = list(map(float, self.size))
        try:
            value = self.kinect.pop()
        except:
            return
        f = value[0].astype('ushort') * 32
        self.texture.blit_buffer(f.tostring(),
                                 colorfmt='luminance',
                                 bufferfmt='ushort')
        self.canvas.ask_update()
示例#10
0
class PointRenderer(Widget):
    def __init__(self, **kwargs):
        self.canvas = RenderContext(use_parent_projection=True)
        self.canvas.shader.source = 'pointshader.glsl'
        glEnable(0x8642)  #GL_VERTEX_PROGRAM_POINT_SIZE
        glEnable(0x8861)  #GL_POINT_SPRITE
        self.mesh = None
        super(PointRenderer, self).__init__(**kwargs)
        self.draw_mesh_points(60)
        Clock.schedule_interval(self.test_mesh_remove, 1. / 60.)

    def test_mesh_remove(self, dt):

        r = random()
        if r > .5:
            self.canvas.remove(self.mesh)
            self.mesh = None
        self.draw_mesh_points(60)

    def draw_mesh_points(self, number):
        star_list = []
        w, h = self.size
        sa = star_list.append
        for number in range(number):
            rand_x = random() * w
            rand_y = random() * h
            size = 29.0
            rotation = random() * 360.0
            sa((rand_x, rand_y, size, rotation))
        self.draw_mesh(star_list)

    def draw_mesh(self, star_list):
        star_tex = Image('star1.png').texture
        vertex_format = [
            (b'vPosition', 2, 'float'),
            (b'vSize', 1, 'float'),
            (b'vRotation', 1, 'float'),
        ]
        indices = []
        ia = indices.append
        for star_number in range(len(star_list)):
            ia(star_number)
        vertices = []
        e = vertices.extend
        for star in star_list:
            e([star[0], star[1], star[2], star[3]])
        if self.mesh == None:
            with self.canvas:
                PushMatrix()
                self.mesh = Mesh(indices=indices,
                                 vertices=vertices,
                                 fmt=vertex_format,
                                 mode='points',
                                 texture=star_tex)
                PopMatrix()
        else:
            self.mesh.indices = indices
            self.mesh.vertices = vertices
示例#11
0
 def __init__(self, **kwargs):
     self.canvas = RenderContext(use_parent_projection=True)
     self.canvas.shader.source = 'pointshader.glsl'
     glEnable(0x8642)  #GL_VERTEX_PROGRAM_POINT_SIZE
     glEnable(0x8861)  #GL_POINT_SPRITE
     self.mesh = None
     super(PointRenderer, self).__init__(**kwargs)
     self.draw_mesh_points(60)
     Clock.schedule_interval(self.test_mesh_remove, 1. / 60.)
示例#12
0
class KinectViewer(Widget):

    depth_range = NumericProperty(7.7)

    shader = StringProperty("rgb")

    index = NumericProperty(0)

    def __init__(self, **kwargs):
        # change the default canvas to RenderContext, we can change the shader
        self.canvas = RenderContext()
        self.canvas.shader.fs = hsv_kinect

        # add kinect depth provider, and start the thread
        self.kinect = KinectDepth()
        self.kinect.start()

        # parent init
        super(KinectViewer, self).__init__(**kwargs)

        # allocate texture for pushing depth
        self.texture = Texture.create(
            size=(640, 480), colorfmt='luminance', bufferfmt='ushort')
        self.texture.flip_vertical()

        # create default canvas element
        with self.canvas:
            Color(1, 1, 1)
            Rectangle(size=Window.size, texture=self.texture)

        # add a little clock to update our glsl
        Clock.schedule_interval(self.update_transformation, 0)

    def on_index(self, instance, value):
        self.kinect.index = value

    def on_shader(self, instance, value):
        if value == 'rgb':
            self.canvas.shader.fs = rgb_kinect
        elif value == 'hsv':
            self.canvas.shader.fs = hsv_kinect
        elif value == 'points':
            self.canvas.shader.fs = points_kinect

    def update_transformation(self, *largs):
        # update projection mat and uvsize
        self.canvas['projection_mat'] = Window.render_context['projection_mat']
        self.canvas['depth_range'] = self.depth_range
        self.canvas['size'] = map(float, self.size)
        try:
            value = self.kinect.pop()
        except:
            return
        f = value[0].astype('ushort') * 32
        self.texture.blit_buffer(
            f.tostring(), colorfmt='luminance', bufferfmt='ushort')
        self.canvas.ask_update()
示例#13
0
 def __init__(self, args, width, height, x=0, y=0, scale=2):
     self.gloo = gloo
     self._app = app
     self.ortho = util.transforms.ortho
     self.program = RenderContext()
     self.program1 = RenderContext()
     raise Exception("Not yet implemented... under work")
     app.Canvas.__init__(self)
     ArtSciTerm.__init__(args, self)
示例#14
0
def test_widget_empty_draw(kivy_benchmark, n):
    from kivy.graphics import RenderContext
    from kivy.uix.widget import Widget
    ctx = RenderContext()
    root = Widget()
    for x in range(n):
        root.add_widget(Widget())
    ctx.add(root.canvas)

    kivy_benchmark(ctx.draw)
示例#15
0
class bench_widget_draw:
    '''Widget: empty drawing (10000 Widget + 1 root)'''
    def __init__(self):
        self.ctx = RenderContext()
        self.root = root = Widget()
        for x in range(10000):
            root.add_widget(Widget())
        self.ctx.add(self.root.canvas)

    def run(self):
        self.ctx.draw()
示例#16
0
    def create_window(self, *largs):
        '''Will create the main window and configure it.

        .. warning::
            This method is called automatically at runtime. If you call it, it
            will recreate a RenderContext and Canvas. This means you'll have a
            new graphics tree, and the old one will be unusable.

            This method exist to permit the creation of a new OpenGL context
            AFTER closing the first one. (Like using runTouchApp() and
            stopTouchApp()).

            This method has only been tested in a unittest environment and
            is not suitable for Applications.

            Again, don't use this method unless you know exactly what you are
            doing!
        '''
        # just to be sure, if the trigger is set, and if this method is
        # manually called, unset the trigger
        Clock.unschedule(self.create_window)

        # ensure the window creation will not be called twice
        if platform in ('android', 'ios'):
            self._unbind_create_window()

        if not self.initialized:
            from kivy.core.gl import init_gl
            init_gl()

            # create the render context and canvas, only the first time.
            from kivy.graphics import RenderContext, Canvas
            self.render_context = RenderContext()
            self.canvas = Canvas()
            self.render_context.add(self.canvas)

        else:
            # if we get initialized more than once, then reload opengl state
            # after the second time.
            # XXX check how it's working on embed platform.
            if platform == 'linux' or Window.__class__.__name__ == 'WindowSDL':
                # on linux, it's safe for just sending a resize.
                self.dispatch('on_resize', *self.system_size)

            else:
                # on other platform, window are recreated, we need to reload.
                from kivy.graphics.context import get_context
                get_context().reload()
                Clock.schedule_once(lambda x: self.canvas.ask_update(), 0)
                self.dispatch('on_resize', *self.system_size)

        # ensure the gl viewport is correct
        self.update_viewport()
示例#17
0
文件: benchmark.py 项目: 5y/kivy
class bench_widget_draw:
    '''Widget: empty drawing (10000 Widget + 1 root)'''

    def __init__(self):
        self.ctx = RenderContext()
        self.root = root = Widget()
        for x in range(10000):
            root.add_widget(Widget())
        self.ctx.add(self.root.canvas)

    def run(self):
        self.ctx.draw()
    def __init__(self, **kwargs):
        super(PageCurl, self).__init__(**kwargs)
        self.c_front = RenderContext()
        self.c_front.shader.source = resource_find('front.glsl')
        self.c_back = RenderContext()
        self.c_back.shader.source = resource_find('back.glsl')
        self.c_backshadow = RenderContext()
        self.c_backshadow.shader.source = resource_find('backshadow.glsl')

        self.canvas.add(self.c_front)
        self.canvas.add(self.c_back)
        self.canvas.add(self.c_backshadow)

        self.texture = CoreImage(self.source).texture
        Clock.schedule_interval(self.update_glsl, 1 / 60.)
示例#19
0
    def __init__(self, **kwargs):
        # Make sure opengl context exists
        EventLoop.ensure_window()
        self.mask_effect = kwargs.get("mask_effect", None)
        self.motion_effect = kwargs.get("motion_effect", None)
        self.fbo_canvas = kwargs.get("motion_effect", None)

        self.canvas = RenderContext(use_parent_projection=True,
                                    use_parent_modelview=True,
                                    with_depthbuffer=True)

        self.size = C_SIZE
        with self.canvas:
            #self._viewport = Rectangle(size=(800,600), pos=self.pos)
            self.fbo = Fbo(size=C_SIZE,
                           with_depthbuffer=True,
                           compute_normal_mat=True,
                           clear_color=(0.3, 0.3, 0.7, 1))

        with self.fbo.before:
            #Rectangle(size=(800, 600))
            PushMatrix()
            self.fbo_translation = Translate(-self.x, -self.y, 0)
            BindTexture(texture=self.fbo_canvas.texture, index=1)
            BindTexture(texture=self.mask_effect.texture, index=4)
            BindTexture(texture=self.motion_effect.texture, index=5)

        with self.fbo:
            Color(0, 0, 0)
            BindTexture(texture=self.fbo_canvas.texture, index=1)
            BindTexture(texture=self.mask_effect.texture, index=4)
            BindTexture(texture=self.motion_effect.texture, index=5)
            self.fbo_rectangle = Rectangle(size=C_SIZE)
            self._instructions = InstructionGroup()

        with self.fbo.after:
            PopMatrix()
            self.cbs = Callback(self.reset_gl_context)

        super(EffectWidget, self).__init__(**kwargs)
        self.size = C_SIZE

        Clock.schedule_interval(self.update_glsl, 0)

        self._instructions.add(Callback(self.setup_gl_context))

        self.refresh_fbo_setup()
        Clock.schedule_interval(self.update_fbos, 0)
示例#20
0
文件: main.py 项目: bloureiro/kary
class SlideShaderContainer(FloatLayout):
    # (internal) This class is used to animate Slide instance.

    alpha = NumericProperty(0.0)
    fbo = ObjectProperty(None)
    fbo_texture = ObjectProperty(None, allownone=True)
    vs = StringProperty(vs_default)
    fs = StringProperty(fs_default)

    def __init__(self, **kwargs):
        self.fbo = Fbo(size=self.size)
        self.fbo_texture = self.fbo
        self.canvas = RenderContext()
        self.canvas.shader.vs = self.vs
        self.canvas.shader.fs = self.fs
        self.canvas.add(self.fbo)
        Clock.schedule_interval(self.update_shader, 0)
        super(SlideShaderContainer, self).__init__(**kwargs)

    def _add_widget(self, widget):
        canvas = self.canvas
        self.canvas = self.fbo
        super(SlideShaderContainer, self).add_widget(widget)
        self.canvas = canvas

    def _remove_widget(self, widget):
        canvas = self.canvas
        self.canvas = self.fbo
        super(SlideShaderContainer, self).remove_widget(widget)
        self.canvas = canvas

    def on_size(self, instance, value):
        if value[0] < 1 or value[1] < 1:
            return
        self.fbo.size = value
        self.fbo_texture = self.fbo.texture

    def on_vs(self, instance, value):
        self.canvas.shader.vs = value

    def on_fs(self, instance, value):
        self.canvas.shader.fs = value

    def update_shader(self, dt):
        self.canvas["projection_mat"] = Window.render_context["projection_mat"]
        self.canvas["modelview_mat"] = Window.render_context["modelview_mat"]
        self.canvas["alpha"] = float(self.alpha)
        self.canvas["size"] = map(float, self.size)
示例#21
0
 def __init__(self, **kwargs):
     self.canvas = RenderContext(use_parent_projection=True)
     self.canvas.shader.source = self.shader_source
     self.mesh = None
     super(PointRenderer, self).__init__(**kwargs) 
     self.generate_mesh_points(600)
     Clock.schedule_interval(self.test_mesh_remove, 1.0)
示例#22
0
    def add_screen(self, screen):
        self.screen_in.pos = self.screen_out.pos
        self.screen_in.size = self.screen_out.size
        self.manager.real_remove_widget(self.screen_out)

        self.fbo_in = self.make_screen_fbo(self.screen_in)
        self.fbo_out = self.make_screen_fbo(self.screen_out)
        self.manager.canvas.add(self.fbo_in)
        self.manager.canvas.add(self.fbo_out)

        screen_rotation = Config.getfloat('graphics', 'rotation')
        pos = (0, 1)
        if screen_rotation == 90:
            pos = (0, 0)
        elif screen_rotation == 180:
            pos = (-1, 0)
        elif screen_rotation == 270:
            pos = (-1, 1)

        self.render_ctx = RenderContext(fs=self.fs, vs=self.vs)
        with self.render_ctx:
            BindTexture(texture=self.fbo_out.texture, index=1)
            BindTexture(texture=self.fbo_in.texture, index=2)
            Rotate(screen_rotation, 0, 0, 1)
            Rectangle(size=(1, -1), pos=pos)
        self.render_ctx['projection_mat'] = Matrix().\
            view_clip(0, 1, 0, 1, 0, 1, 0)
        self.render_ctx['tex_out'] = 1
        self.render_ctx['tex_in'] = 2
        self.manager.canvas.add(self.render_ctx)
示例#23
0
 def __init__(self, **kwargs):
     super(ShaderEditor, self).__init__(**kwargs)
     self._contexts = InstructionGroup()
     self.test_canvas = RenderContext()
     s = self.test_canvas.shader
     self.trigger_compile = Clock.create_trigger(self.compile_shaders, -1)
     self.bind(fs=self.trigger_compile, vs=self.trigger_compile)
示例#24
0
    def __init__(self, **kwargs):
        # Make sure opengl context exists
        EventLoop.ensure_window()

        self.canvas = RenderContext(use_parent_projection=True,
                                    use_parent_modelview=True)

        with self.canvas:
            self.fbo = Fbo(size=self.size)

        with self.fbo.before:
            PushMatrix()
            self.fbo_translation = Translate(-self.x, -self.y, 0)
        with self.fbo:
            Color(*self.background_color)
            self.fbo_rectangle = Rectangle(size=self.size)
        with self.fbo.after:
            PopMatrix()

        super(EffectWidget, self).__init__(**kwargs)

        Clock.schedule_interval(self._update_glsl, 0)

        self.bind(pos=self._update_translation,
                  size=self.refresh_fbo_setup,
                  effects=self.refresh_fbo_setup)

        self.refresh_fbo_setup()
示例#25
0
    def __init__(self, **kwargs):
        # Make sure opengl context exists
        EventLoop.ensure_window()

        self.canvas = RenderContext(use_parent_projection=True,
                                    use_parent_modelview=True)

        with self.canvas:
            self.fbo = Fbo(size=self.size)

        with self.fbo.before:
            PushMatrix()
        with self.fbo:
            ClearColor(0, 0, 0, 0)
            ClearBuffers()
            self._background_color = Color(*self.background_color)
            self.fbo_rectangle = Rectangle(size=self.size)
        with self.fbo.after:
            PopMatrix()

        super(EffectWidget, self).__init__(**kwargs)

        Clock.schedule_interval(self._update_glsl, 0)

        self.bind(size=self.refresh_fbo_setup,
                  effects=self.refresh_fbo_setup,
                  background_color=self._refresh_background_color)

        self.refresh_fbo_setup()
        self._refresh_background_color()  # In case thi was changed in kwargs
示例#26
0
    def __init__(self, **kwargs):
        # Instead of using canvas, we will use a RenderContext,
        # and change the default shader used.
        self.canvas = RenderContext(use_parent_projection=True)

        # We create a framebuffer at the size of the window
        # FIXME: this should be created at the size of the widget
        with self.canvas:
            self.fbo = Fbo(size=Window.size, use_parent_projection=True)

        # Set the fbo background to black.
        with self.fbo:
            Color(0, 0, 0)
            Rectangle(size=Window.size)

        # call the constructor of parent
        # if they are any graphics object, they will be added on our new canvas
        super(ShaderWidget, self).__init__(**kwargs)

        # We'll update our glsl variables in a clock
        Clock.schedule_interval(self.update_glsl, 0)

        # Don't forget to set the texture property to the texture
        # of framebuffer
        self.texture = self.fbo.texture
示例#27
0
    def create_window(self):
        '''Will create the main window and configure it.

        .. warning::
            This method is called automatically at runtime. If you call it, it
            will recreate a RenderContext and Canvas. This mean you'll have a
            new graphics tree, and the old one will be unusable.

            This method exist to permit the creation of a new OpenGL context
            AFTER closing the first one. (Like using runTouchApp() and
            stopTouchApp()).

            This method have been only tested in unittest environment, and will
            be not suitable for Applications.

            Again, don't use this method unless you know exactly what you are
            doing !
        '''
        from kivy.core.gl import init_gl
        init_gl()

        # create the render context and canvas
        from kivy.graphics import RenderContext, Canvas
        self.render_context = RenderContext()
        self.canvas = Canvas()
        self.render_context.add(self.canvas)
示例#28
0
    def __init__(self, **kwargs):
        self.canvas = RenderContext()
        # setting shader.fs to new source code automatically compiles it.
        self.canvas.shader.fs = fs_multitexture
        with self.canvas:
            Color(1, 1, 1)

            # here, we are binding a custom texture at index 1
            # this will be used as texture1 in shader.
            # The filenames are misleading: they do not correspond to the
            # index here or in the shader.
            BindTexture(source='mtexture2.png', index=1)

            # create a rectangle with texture (will be at index 0)
            Rectangle(size=(150, 150), source='mtexture1.png', pos=(500, 200))

        # set the texture1 to use texture index 1
        self.canvas['texture1'] = 1

        # call the constructor of parent
        # if they are any graphics objects, they will be added on our new
        # canvas
        super(MultitextureWidget, self).__init__(**kwargs)

        # We'll update our glsl variables in a clock
        Clock.schedule_interval(self.update_glsl, 0)
示例#29
0
    def add_screen(self, screen):
        self.screen_in.pos = self.screen_out.pos
        self.screen_in.size = self.screen_out.size
        self.manager.real_remove_widget(self.screen_out)
        self.manager.canvas.add(self.screen_out.canvas)

        def remove_screen_out(instr):
            Clock.schedule_once(self._remove_out_canvas, -1)
            self.render_ctx.remove(instr)

        self.fbo_in = self.make_screen_fbo(self.screen_in)
        self.fbo_out = self.make_screen_fbo(self.screen_out)
        self.manager.canvas.add(self.fbo_in)
        self.manager.canvas.add(self.fbo_out)

        self.render_ctx = RenderContext(fs=self.fs, vs=self.vs,
                                        use_parent_modelview=True,
                                        use_parent_projection=True)
        with self.render_ctx:
            BindTexture(texture=self.fbo_out.texture, index=1)
            BindTexture(texture=self.fbo_in.texture, index=2)
            x, y = self.screen_in.pos
            w, h = self.fbo_in.texture.size
            Rectangle(size=(w, h), pos=(x, y),
                      tex_coords=self.fbo_in.texture.tex_coords)
            Callback(remove_screen_out)
        self.render_ctx['tex_out'] = 1
        self.render_ctx['tex_in'] = 2
        self.manager.canvas.add(self.render_ctx)
示例#30
0
    def __init__(self, **kwargs):

        EventLoop.ensure_window()
        self.canvas = RenderContext(use_parent_projection=True,
                                    use_parent_modelview=True)
        #print shader_header
        self.shader_header = shader_header + open(
            'glsl_headers/shader_header.frag', 'r').read()
        self.shader_source = open('glsl/blank.frag', 'r').read()
        self.shader_footer = open('glsl_headers/shader_footer.frag',
                                  'r').read()
        self.definition_template = open('glsl_headers/definition.frag',
                                        'r').read()

        self.canvas['iChannelResolution'] = self.iChannelResolution

        super(ShaderWidget, self).__init__(**kwargs)
        self.bind(iChannel0_source=self.update_definitions,
                  iChannel1_source=self.update_definitions,
                  iChannel2_source=self.update_definitions,
                  iChannel3_source=self.update_definitions,
                  ichannels_definition=self.update_definitions)

        self.c_event = None
        self.new_name = None
        self.cshader = self.canvas.shader
        self.init_definitions()
        self.init_shader()
示例#31
0
    def __init__(self, **kwargs):

        self.register_event_type('on_load')

        self.canvas = RenderContext(fs=self.FS_CONVERT_YUV)
        self.canvas['tex_y'] = 1
        self.canvas['tex_u'] = 2
        self.canvas['tex_v'] = 3

        super(YuvVideo, self).__init__(**kwargs)

        if self.colorfmt == OUT_COLOR_FORMAT[0]:
            self.fs = self.FS_CONVERT_RGB
        elif self.format != YUV_CHROMA_FORMAT[0]:
            self.fs = self.FS_CONVERT_YUV
        else:
            self.fs = self.FS_CONVERT_MONO
示例#32
0
    def __init__(self,
                 smpl_faces_path=None,
                 keypoints_spec=None,
                 obj_mesh_path=None):

        if smpl_faces_path is not None:
            self._smpl_faces = np.load(smpl_faces_path)

        if keypoints_spec is not None:
            self.keypoints_spec = keypoints_spec.copy()
            self.keypoints_spec.sort(key=lambda kpnt: kpnt["smpl_indx"])
            # Extract the parent indices from the keypoints dictionary
            self.parents = [
                next(
                    (indx for (indx, kpnt) in enumerate(self.keypoints_spec)
                     if kpnt["name"] == p_kpnt["parent"]),
                    -1,
                ) for p_kpnt in self.keypoints_spec
            ]

        if obj_mesh_path is not None:
            self._monkey_scene = ObjFile(obj_mesh_path)

        # Make a canvas and add simple view
        self.canvas = RenderContext(compute_normal_mat=True)

        shader_path = os.path.join(os.path.abspath(os.path.dirname(__file__)),
                                   "simple.glsl")
        self._init_shader(shader_path)
        super().__init__()

        self._create_mesh_fn = {
            "monkey": self._create_monkey_mesh,
            "monkey_no_norms": self._create_monkey_mesh_no_norms,
            "random": self._create_rand_mesh,
            "smpl_mesh": self._create_smpl_mesh,
            "smpl_kpnts": self._create_smpl_kpnts,
            "error_vectors": self._create_error_vectors,
        }

        self._curr_mode = "triangles"
        self.curr_obj = None
        self._nframes = 0
        self.reset_scene()
        self._store_quat = None
        self._dx_acc, self._dy_acc = 0, 0
示例#33
0
    def __init__(self, code, **kwargs):
        Fbo.__init__(self, **kwargs)
        self.canvas = RenderContext()

        shader = self.canvas.shader
        shader.fs = header + code
        if not shader.success:
            print '! Shader compilation failed (GLSL)'
            assert False
示例#34
0
 def __init__(self, **kwargs):
     self.canvas = RenderContext(use_parent_projection=True)
     self.canvas.shader.source = 'pointshader.glsl'
     glEnable(0x8642) #GL_VERTEX_PROGRAM_POINT_SIZE
     glEnable(0x8861) #GL_POINT_SPRITE
     self.mesh = None
     super(PointRenderer, self).__init__(**kwargs) 
     self.draw_mesh_points(60)
     Clock.schedule_interval(self.test_mesh_remove, 1./60.)
示例#35
0
文件: main.py 项目: bloureiro/kary
 def __init__(self, **kwargs):
     self.fbo = Fbo(size=self.size)
     self.fbo_texture = self.fbo
     self.canvas = RenderContext()
     self.canvas.shader.vs = self.vs
     self.canvas.shader.fs = self.fs
     self.canvas.add(self.fbo)
     Clock.schedule_interval(self.update_shader, 0)
     super(SlideShaderContainer, self).__init__(**kwargs)
示例#36
0
    def create_window(self, *largs):
        """Will create the main window and configure it.

        .. warning::
            This method is called automatically at runtime. If you call it, it
            will recreate a RenderContext and Canvas. This means you'll have a
            new graphics tree, and the old one will be unusable.

            This method exist to permit the creation of a new OpenGL context
            AFTER closing the first one. (Like using runTouchApp() and
            stopTouchApp()).

            This method has only been tested in a unittest environment and
            is not suitable for Applications.

            Again, don't use this method unless you know exactly what you are
            doing!
        """
        # just to be sure, if the trigger is set, and if this method is
        # manually called, unset the trigger
        Clock.unschedule(self.create_window)

        # ensure the window creation will not be called twice
        if platform in ("android", "ios"):
            self._unbind_create_window()

        if not self.initialized:
            from kivy.core.gl import init_gl

            init_gl()

            # create the render context and canvas, only the first time.
            from kivy.graphics import RenderContext, Canvas

            self.render_context = RenderContext()
            self.canvas = Canvas()
            self.render_context.add(self.canvas)

        else:
            # if we get initialized more than once, then reload opengl state
            # after the second time.
            # XXX check how it's working on embed platform.
            if platform == "linux" or Window.__class__.__name__ == "WindowSDL":
                # on linux, it's safe for just sending a resize.
                self.dispatch("on_resize", *self.system_size)

            else:
                # on other platform, window are recreated, we need to reload.
                from kivy.graphics.context import get_context

                get_context().reload()
                Clock.schedule_once(lambda x: self.canvas.ask_update(), 0)
                self.dispatch("on_resize", *self.system_size)

        # ensure the gl viewport is correct
        self.update_viewport()
示例#37
0
 def __init__(self, **kwargs):
     self.cols = self.rows = 2
     self.canvas = RenderContext(fs=FS,
                                 vs=VS,
                                 use_parent_projection=True,
                                 use_parent_modelview=True)
     super(ProjectionMappingGrid, self).__init__(**kwargs)
     self.build_mapping()
     self.init_fbo()
     self.bind(size=self.rebuild_fbo)
示例#38
0
    def __init__(self, client, **kwargs):
        self.canvas = RenderContext(use_parent_projection=True)
        self.client = client

        super(Section, self).__init__(**kwargs)
        
        self.canvas.shader.fs = open(resource_find('shaders/section_fragment.glsl')).read()
        self.canvas.shader.vs = open(resource_find('shaders/section_vertex.glsl')).read()
        
        self.recalc()
示例#39
0
    def __init__(self, **kwargs):
        # Instead of using Canvas, we will use a RenderContext,
        # and change the default shader used.
        self.canvas = RenderContext()

        # call the constructor of parent
        # if they are any graphics object, they will be added on our new canvas
        super(ShaderWidget, self).__init__(**kwargs)

        # We'll update our glsl variables in a clock
        Clock.schedule_interval(self.update_glsl, 1 / 60.)
示例#40
0
    def create_drawings(self):
        from kivy.graphics import Line, RenderContext

        self._grc = RenderContext(
                use_parent_modelview=True,
                use_parent_projection=True)
        with self._grc:
            self._gcolor = Color(*self.color)
            self._gline = Line(points=[], cap='none', width=self._line_width, joint='round')

        return [self._grc]
示例#41
0
    def create_drawings(self):
        # from kivy.graphics import Line, RenderContext, Color, Point
        #from kivy.graphics import RenderContext, Color, Point

        self._grc = RenderContext(use_parent_modelview=True,
                                  use_parent_projection=True)
        with self._grc:
            self._gcolor = Color(*self.color)
            self._gline = Point(pointsize=self._pointsize)

        return [self._grc]
示例#42
0
    def create_canvas(self):
        self.canvas = Canvas()
        self.c_front = RenderContext()
        self.c_front.shader.source = join(curdir, 'front.glsl')
        self.c_back = RenderContext()
        self.c_back.shader.source = join(curdir, 'back.glsl')
        self.c_backshadow = RenderContext()
        self.c_backshadow.shader.source = join(curdir, 'backshadow.glsl')
        self.canvas.add(self.c_front)
        self.canvas.add(self.c_back)
        self.canvas.add(self.c_backshadow)

        with self.canvas.before:
            Color(1, 1, 1)
            Rectangle(
                size=self.fbo_in.size,
                texture=self.fbo_in.texture)
            Callback(self._enter_3d)
        self._build_mesh(self.fbo_in.size)
        with self.canvas.after:
            Callback(self._leave_3d)
示例#43
0
    def create_drawings(self):
        from kivy.graphics import RenderContext

        self._grc = RenderContext(
            use_parent_modelview=True,
            use_parent_projection=True)

        with self._grc:
            self._gcolor = Color(*self.color)
            self._ellipses = [Ellipse() for i in xrange(len(self.points))]

        return [self._grc]
示例#44
0
    def add_screen(self, screen):
        self.screen_in.pos = self.screen_out.pos
        self.screen_in.size = self.screen_out.size
        self.manager.real_remove_widget(self.screen_out)

        print '-----------'
        print 'add_screen', screen, screen.canvas
        print 'screen_in', self.screen_in, self.screen_in.parent
        print 'screen_out', self.screen_out, self.screen_out.parent
        print '-----------'
        self.fbo_in = self.make_screen_fbo(self.screen_in, mode='in')
        self.fbo_out = self.make_screen_fbo(self.screen_out, mode='out')
        self.manager.canvas.add(self.fbo_in)
        self.manager.canvas.add(self.fbo_out)

        self.canvas = Canvas()
        self.c_front = RenderContext()
        self.c_front.shader.source = join(curdir, 'front.glsl')
        self.c_back = RenderContext()
        self.c_back.shader.source = join(curdir, 'back.glsl')
        self.c_backshadow = RenderContext()
        self.c_backshadow.shader.source = join(curdir, 'backshadow.glsl')
        self.canvas.add(self.c_front)
        self.canvas.add(self.c_back)
        self.canvas.add(self.c_backshadow)

        with self.canvas.before:
            Color(1, 1, 1)
            Rectangle(
                size=self.fbo_in.size,
                texture=self.fbo_in.texture)
            Callback(self._enter_3d)
        self._build_mesh(self.fbo_in.size)
        with self.canvas.after:
            Callback(self._leave_3d)

        self.manager.canvas.add(self.canvas)
        self.on_progress(0)
示例#45
0
    def __init__(self, **kwargs):

        self.register_event_type('on_load')

        self.canvas = RenderContext(fs=self.FS_CONVERT_YUV)
        self.canvas['tex_y'] = 1
        self.canvas['tex_u'] = 2
        self.canvas['tex_v'] = 3

        super(YuvVideo, self).__init__(**kwargs)

        if self.colorfmt == OUT_COLOR_FORMAT[0]:
            self.fs = self.FS_CONVERT_RGB
        elif self.format != YUV_CHROMA_FORMAT[0]:
            self.fs = self.FS_CONVERT_YUV
        else:
            self.fs = self.FS_CONVERT_MONO
示例#46
0
    def __init__(self, **kwargs):
        self.canvas = RenderContext()

        super(AndroidCameraPreview, self).__init__(**kwargs)
        self.bind(resolution=self._resolution_changed)
        self.bind(camera_id=self._camera_id_changed)
        self.bind(play=self._play_changed)


        # This is needed for the default vertex shader.
        self.canvas['projection_mat'] = Window.render_context['projection_mat']


        with self.canvas:   
            Callback(self._draw_callback)
            BindTexture(texture=self._secondary_texture, index=1)
        self.canvas['secondary_texture'] = 1
        self._init_texture(self.resolution)
示例#47
0
    def __init__(self, **kwargs):
        # Make sure opengl context exists
        EventLoop.ensure_window()
        self.mask_effect = kwargs.get("mask_effect", None)
        self.motion_effect = kwargs.get("motion_effect", None)

        self.canvas = RenderContext(use_parent_projection=True,
                                    use_parent_modelview=True)

        self.size = C_SIZE
        with self.canvas:
            #self._viewport = Rectangle(size=(800,600), pos=self.pos)
            self.fbo = Fbo(size=C_SIZE, with_depthbuffer=True,  compute_normal_mat=True,
                           clear_color=(0.3, 0.3, 0.7, 1))

        with self.fbo.before:
            #Rectangle(size=(800, 600))
            PushMatrix()
            self.fbo_translation = Translate(-self.x, -self.y, 0)
            BindTexture(texture=self.mask_effect.texture, index=4)
            BindTexture(texture=self.motion_effect.texture, index=5)

        with self.fbo:
            Color(0, 0, 0)
            BindTexture(texture=self.mask_effect.texture, index=4)
            BindTexture(texture=self.motion_effect.texture, index=5)
            self.fbo_rectangle = Rectangle(size=C_SIZE)
            self._instructions = InstructionGroup()

        with self.fbo.after:
            PopMatrix()
            self.cbs = Callback(self.reset_gl_context)


        super(EffectWidget, self).__init__(**kwargs)
        self.size = C_SIZE

        Clock.schedule_interval(self.update_glsl, 0)

        self._instructions.add(Callback(self.setup_gl_context))

        self.refresh_fbo_setup()
        Clock.schedule_interval(self.update_fbos, 0)
示例#48
0
    def __init__(self, **kwargs):
        # change the default canvas to RenderContext, we can change the shader
        self.canvas = RenderContext()
        self.canvas.shader.fs = hsv_kinect

        # add kinect depth provider, and start the thread
        self.kinect = KinectDepth()
        self.kinect.start()

        # parent init
        super(KinectViewer, self).__init__(**kwargs)

        # allocate texture for pushing depth
        self.texture = Texture.create(
            size=(640, 480), colorfmt='luminance', bufferfmt='ushort')
        self.texture.flip_vertical()

        # create default canvas element
        with self.canvas:
            Color(1, 1, 1)
            Rectangle(size=Window.size, texture=self.texture)

        # add a little clock to update our glsl
        Clock.schedule_interval(self.update_transformation, 0)
示例#49
0
class AndroidCameraPreview(Image):
    """
    Android camera preview widget. Extends Image with a custom shader that 
    displays textures of target GL_TEXTURE_EXTERNAL_OES. Note, this requires 
    Android API 11 because of it's use of SurfaceTexture.
    """
    play = BooleanProperty(False)
    resolution = ListProperty([720, 720])
    camera_id = NumericProperty(-1)


    _camera = None
    _previewCallback = None
    _previewTexture = None

    _previewSurface = None
    _secondary_texture = None


    def __init__(self, **kwargs):
        self.canvas = RenderContext()

        super(AndroidCameraPreview, self).__init__(**kwargs)
        self.bind(resolution=self._resolution_changed)
        self.bind(camera_id=self._camera_id_changed)
        self.bind(play=self._play_changed)


        # This is needed for the default vertex shader.
        self.canvas['projection_mat'] = Window.render_context['projection_mat']


        with self.canvas:   
            Callback(self._draw_callback)
            BindTexture(texture=self._secondary_texture, index=1)
        self.canvas['secondary_texture'] = 1
        self._init_texture(self.resolution)

    def start(self, play=True):
        self._init_camera(self.camera_id)
        self.play = play

    def stop(self):
        self._release_camera()

    def _init_texture(self, resolution):
        width, height = resolution
        # Image looks at self.texture to determine layout, so we create 
        # texture but don't actually display it.
        self.texture = Texture.create(size=(height, width))
        self.texture_size = self.texture.size
        if IsAndroid:
            self._secondary_texture = Texture(width=height, height=width, target=GL_TEXTURE_EXTERNAL_OES, colorfmt='rgba')
            self._secondary_texture.bind()
            self._previewTexture = SurfaceTexture(int(self._secondary_texture.id))

    def _init_camera(self, camera_id):
        Logger.info('Init camera %d' % camera_id)
        if self._camera and self.camera_id == camera_id:
            return
        self._release_camera()
        if IsAndroid:
            self._camera = Camera.open(camera_id)
            parameters = self._camera.getParameters()            

            #print parameters.flatten()
            if parameters is None:
                Logger.warning('Can''t read parameters')
                return

            supportedSizes = parameters.getSupportedVideoSizes()
            if supportedSizes is None:
                supportedSizes = parameters.getSupportedPreviewSizes()
            
            sizes = []
            if supportedSizes is not None:
                  iterator = supportedSizes.iterator()
                  while iterator.hasNext():
                      cameraSize = iterator.next()
                      sizes.append((cameraSize.width, cameraSize.height))

            pickedSize = self._pick_optimal_size(sizes)

            # Update texture according to picked size
            self.resolution = list(pickedSize)

            parameters.setPreviewSize(*pickedSize)
            self._camera.setParameters(parameters)
            self._camera.setPreviewTexture(self._previewTexture)

    def get_camera(self):
        return self._camera

    def _resolution_changed(self, instance, value):
        Logger.info('Resolution changed to ' + str(value))
        self._init_texture(value)

    def _camera_id_changed(self, instance, value):
        Logger.info('Changed camera %d' % value)
        if not IsAndroid:
            return

        # Transform orientation based on selected camera
        if self.camera_id == 0:
            sampleVec = ('1.0-tex_coord0.y','1.0-tex_coord0.x')
        elif self.camera_id == 1:
            sampleVec = ('tex_coord0.y','1.0-tex_coord0.x')
        else:
            raise Exception('Invalid camera id')

        self.canvas.shader.fs = '''

            #extension GL_OES_EGL_image_external : require
            #ifdef GL_ES
                precision highp float;
            #endif

            /* Outputs from the vertex shader */
            varying vec4 frag_color;
            varying vec2 tex_coord0;

            /* uniform texture samplers */
            uniform sampler2D texture0;
            uniform samplerExternalOES texture1;

            void main()
            {
                // Flip & Mirror coordinates to rotate source texture by 90 degress
                gl_FragColor = texture2D(texture1, vec2(%s,%s));
            }
        ''' % (sampleVec[0], sampleVec[1])

    def _play_changed(self, instance, value):
        Logger.info('camera %d _play_changed %d' % (self.camera_id, value))
        if not IsAndroid:
            return

        if value:
            if not self._camera:
                self._init_camera(self.camera_id)        
            self._camera.startPreview()
            Clock.schedule_interval(self._update_canvas, 1.0/30)
        else:
            if self._camera:
                Clock.unschedule(self._update_canvas)
                self._camera.stopPreview()

    def _release_camera(self):
        self.play = False
        if self._camera:
            self._camera.release()
            self._camera = None

    def _pick_optimal_size(self, sizes):        
        # Now just returns the one guaranteed support size
        return sizes[0]

    def _draw_callback(self, instr):
        if self._previewTexture:
            self._previewTexture.updateTexImage()

    def _update_canvas(self, dt):
        self.canvas.ask_update()
示例#50
0
文件: benchmark.py 项目: 5y/kivy
 def __init__(self):
     self.ctx = RenderContext()
     self.root = root = Widget()
     for x in range(10000):
         root.add_widget(Widget())
     self.ctx.add(self.root.canvas)
示例#51
0
class EffectWidget(RelativeLayout):
    '''
    Widget with the ability to apply a series of graphical effects to
    its children. See module documentation for full information on
    setting effects and creating your own.
    '''

    background_color = ListProperty((0, 0, 0, 1))
    '''This defines the background color to be used for the fbo in the
    EffectWidget.

    :attr:`background_color` is a :class:`ListProperty` defaults to
    (0, 0, 0, 1)
    '''

    texture = ObjectProperty(None)
    '''The output texture of our final :class:`~kivy.graphics.Fbo` after
    all effects have been applied.

    texture is an :class:`~kivy.properties.ObjectProperty` and defaults
    to None.
    '''

    effects = ListProperty([])
    '''List of all the effects to be applied. These should all be
    instances of :class:`EffectBase`.

    effects is a :class:`ListProperty` and defaults to [].
    '''

    fbo_list = ListProperty([])
    '''(internal) list of all the fbos that are being used to apply
    the effects.

    fbo_list is a :class:`ListProperty` and defaults to [].
    '''

    _bound_effects = ListProperty([])
    '''(internal) list of effect classes that have been given an fbo to
    manage. This is necessary so that the fbo can be removed it the
    effect is no longer in use.

    _bound_effects is a :class:`ListProperty` and defaults to [].
    '''

    def __init__(self, **kwargs):
        # Make sure opengl context exists
        EventLoop.ensure_window()

        self.canvas = RenderContext(use_parent_projection=True,
                                    use_parent_modelview=True)

        with self.canvas:
            self.fbo = Fbo(size=self.size)

        with self.fbo.before:
            PushMatrix()
        with self.fbo:
            ClearColor(0, 0, 0, 0)
            ClearBuffers()
            self._background_color = Color(*self.background_color)
            self.fbo_rectangle = Rectangle(size=self.size)
        with self.fbo.after:
            PopMatrix()

        super(EffectWidget, self).__init__(**kwargs)

        Clock.schedule_interval(self._update_glsl, 0)

        self.bind(size=self.refresh_fbo_setup,
                  effects=self.refresh_fbo_setup,
                  background_color=self._refresh_background_color)

        self.refresh_fbo_setup()
        self._refresh_background_color()  # In case thi was changed in kwargs

    def _refresh_background_color(self, *args):
        self._background_color.rgba = self.background_color

    def _update_glsl(self, *largs):
        '''(internal) Passes new time and resolution uniform
        variables to the shader.
        '''
        time = Clock.get_boottime()
        resolution = [float(size) for size in self.size]
        self.canvas['time'] = time
        self.canvas['resolution'] = resolution
        for fbo in self.fbo_list:
            fbo['time'] = time
            fbo['resolution'] = resolution

    def refresh_fbo_setup(self, *args):
        '''(internal) Creates and assigns one :class:`~kivy.graphics.Fbo`
        per effect, and makes sure all sizes etc. are correct and
        consistent.
        '''
        # Add/remove fbos until there is one per effect
        while len(self.fbo_list) < len(self.effects):
            with self.canvas:
                new_fbo = EffectFbo(size=self.size)
            with new_fbo:
                ClearColor(0, 0, 0, 0)
                ClearBuffers()
                Color(1, 1, 1, 1)
                new_fbo.texture_rectangle = Rectangle(size=self.size)

                new_fbo.texture_rectangle.size = self.size
            self.fbo_list.append(new_fbo)
        while len(self.fbo_list) > len(self.effects):
            old_fbo = self.fbo_list.pop()
            self.canvas.remove(old_fbo)

        # Remove fbos from unused effects
        for effect in self._bound_effects:
            if effect not in self.effects:
                effect.fbo = None
        self._bound_effects = self.effects

        # Do resizing etc.
        self.fbo.size = self.size
        self.fbo_rectangle.size = self.size
        for i in range(len(self.fbo_list)):
            self.fbo_list[i].size = self.size
            self.fbo_list[i].texture_rectangle.size = self.size

        # If there are no effects, just draw our main fbo
        if len(self.fbo_list) == 0:
            self.texture = self.fbo.texture
            return

        for i in range(1, len(self.fbo_list)):
            fbo = self.fbo_list[i]
            fbo.texture_rectangle.texture = self.fbo_list[i - 1].texture

        # Build effect shaders
        for effect, fbo in zip(self.effects, self.fbo_list):
            effect.fbo = fbo

        self.fbo_list[0].texture_rectangle.texture = self.fbo.texture
        self.texture = self.fbo_list[-1].texture

    def add_widget(self, widget):
        # Add the widget to our Fbo instead of the normal canvas
        c = self.canvas
        self.canvas = self.fbo
        super(EffectWidget, self).add_widget(widget)
        self.canvas = c

    def remove_widget(self, widget):
        # Remove the widget from our Fbo instead of the normal canvas
        c = self.canvas
        self.canvas = self.fbo
        super(EffectWidget, self).remove_widget(widget)
        self.canvas = c

    def clear_widgets(self, children=None):
        # Clear widgets from our Fbo instead of the normal canvas
        c = self.canvas
        self.canvas = self.fbo
        super(EffectWidget, self).clear_widgets(children)
        self.canvas = c
示例#52
0
class WindowBase(EventDispatcher):
    '''WindowBase is an abstract window widget for any window implementation.

    :Parameters:
        `borderless`: str, one of ('0', '1')
            Set the window border state. Check the
            :mod:`~kivy.config` documentation for a
            more detailed explanation on the values.
        `fullscreen`: str, one of ('0', '1', 'auto', 'fake')
            Make the window fullscreen. Check the
            :mod:`~kivy.config` documentation for a
            more detailed explanation on the values.
        `width`: int
            Width of the window.
        `height`: int
            Height of the window.

    :Events:
        `on_motion`: etype, motionevent
            Fired when a new :class:`~kivy.input.motionevent.MotionEvent` is
            dispatched
        `on_touch_down`:
            Fired when a new touch event is initiated.
        `on_touch_move`:
            Fired when an existing touch event changes location.
        `on_touch_up`:
            Fired when an existing touch event is terminated.
        `on_draw`:
            Fired when the :class:`Window` is being drawn.
        `on_flip`:
            Fired when the :class:`Window` GL surface is being flipped.
        `on_rotate`: rotation
            Fired when the :class:`Window` is being rotated.
        `on_close`:
            Fired when the :class:`Window` is closed.
        `on_request_close`:
            Fired when the event loop wants to close the window, or if the
            escape key is pressed and `exit_on_escape` is `True`. If a function
            bound to this event returns `True`, the window will not be closed.
            If the the event is triggered because of the keyboard escape key,
            the keyword argument `source` is dispatched along with a value of
            `keyboard` to the bound functions.

            .. versionadded:: 1.9.0

        `on_keyboard`: key, scancode, codepoint, modifier
            Fired when the keyboard is used for input.

            .. versionchanged:: 1.3.0
                The *unicode* parameter has been deprecated in favor of
                codepoint, and will be removed completely in future versions.

        `on_key_down`: key, scancode, codepoint
            Fired when a key pressed.

            .. versionchanged:: 1.3.0
                The *unicode* parameter has been deprecated in favor of
                codepoint, and will be removed completely in future versions.

        `on_key_up`: key, scancode, codepoint
            Fired when a key is released.

            .. versionchanged:: 1.3.0
                The *unicode* parameter has be deprecated in favor of
                codepoint, and will be removed completely in future versions.

        `on_dropfile`: str
            Fired when a file is dropped on the application.

    '''

    __instance = None
    __initialized = False
    _fake_fullscreen = False

    # private properties
    _size = ListProperty([0, 0])
    _modifiers = ListProperty([])
    _rotation = NumericProperty(0)
    _clearcolor = ObjectProperty([0, 0, 0, 1])

    children = ListProperty([])
    '''List of the children of this window.

    :attr:`children` is a :class:`~kivy.properties.ListProperty` instance and
    defaults to an empty list.

    Use :meth:`add_widget` and :meth:`remove_widget` to manipulate the list of
    children. Don't manipulate the list directly unless you know what you are
    doing.
    '''

    parent = ObjectProperty(None, allownone=True)
    '''Parent of this window.

    :attr:`parent` is a :class:`~kivy.properties.ObjectProperty` instance and
    defaults to None. When created, the parent is set to the window itself.
    You must take care of it if you are doing a recursive check.
    '''

    icon = StringProperty()

    def _get_modifiers(self):
        return self._modifiers

    modifiers = AliasProperty(_get_modifiers, None)
    '''List of keyboard modifiers currently active.
    '''

    def _get_size(self):
        r = self._rotation
        w, h = self._size
        if self.softinput_mode == 'resize':
            h -= self.keyboard_height
        if r in (0, 180):
            return w, h
        return h, w

    def _set_size(self, size):
        if self._size != size:
            r = self._rotation
            if r in (0, 180):
                self._size = size
            else:
                self._size = size[1], size[0]

            self.dispatch('on_resize', *size)
            return True
        else:
            return False
    size = AliasProperty(_get_size, _set_size, bind=('_size', ))
    '''Get the rotated size of the window. If :attr:`rotation` is set, then the
    size will change to reflect the rotation.
    '''

    def _get_clearcolor(self):
        return self._clearcolor

    def _set_clearcolor(self, value):
        if value is not None:
            if type(value) not in (list, tuple):
                raise Exception('Clearcolor must be a list or tuple')
            if len(value) != 4:
                raise Exception('Clearcolor must contain 4 values')
        self._clearcolor = value

    clearcolor = AliasProperty(_get_clearcolor, _set_clearcolor,
                               bind=('_clearcolor', ))
    '''Color used to clear the window.

    ::

        from kivy.core.window import Window

        # red background color
        Window.clearcolor = (1, 0, 0, 1)

        # don't clear background at all
        Window.clearcolor = None

    .. versionchanged:: 1.7.2
        The clearcolor default value is now: (0, 0, 0, 1).

    '''

    # make some property read-only
    def _get_width(self):
        r = self._rotation
        if r == 0 or r == 180:
            return self._size[0]
        return self._size[1]

    width = AliasProperty(_get_width, None, bind=('_rotation', '_size'))
    '''Rotated window width.

    :attr:`width` is a read-only :class:`~kivy.properties.AliasProperty`.
    '''

    def _get_height(self):
        '''Rotated window height'''
        r = self._rotation
        kb = self.keyboard_height if self.softinput_mode == 'resize' else 0
        if r == 0 or r == 180:
            return self._size[1] - kb
        return self._size[0] - kb

    height = AliasProperty(_get_height, None, bind=('_rotation', '_size'))
    '''Rotated window height.

    :attr:`height` is a read-only :class:`~kivy.properties.AliasProperty`.
    '''

    def _get_center(self):
        return self.width / 2., self.height / 2.

    center = AliasProperty(_get_center, None, bind=('width', 'height'))
    '''Center of the rotated window.

    :attr:`center` is a :class:`~kivy.properties.AliasProperty`.
    '''

    def _get_rotation(self):
        return self._rotation

    def _set_rotation(self, x):
        x = int(x % 360)
        if x == self._rotation:
            return
        if x not in (0, 90, 180, 270):
            raise ValueError('can rotate only 0, 90, 180, 270 degrees')
        self._rotation = x
        if self.initialized is False:
            return
        self.dispatch('on_resize', *self.size)
        self.dispatch('on_rotate', x)

    rotation = AliasProperty(_get_rotation, _set_rotation,
                             bind=('_rotation', ))
    '''Get/set the window content rotation. Can be one of 0, 90, 180, 270
    degrees.
    '''

    softinput_mode = OptionProperty('', options=('', 'pan', 'scale', 'resize'))
    '''This specifies the behavior of window contents on display of soft
    keyboard on mobile platform. Can be one of '', 'pan', 'scale', 'resize'.

    When '' The main window is left as it is allowing the user to use
    :attr:`keyboard_height` to manage the window contents the way they want.

    when 'pan' The main window pans moving the bottom part of the window to be
    always on top of the keyboard.

    when 'resize' The window is resized and the contents scaled to fit the
    remaining space.

    ..versionadded::1.9.0

    :attr:`softinput_mode` is a :class:`OptionProperty` defaults to None.

    '''

    _keyboard_changed = BooleanProperty(False)

    def _upd_kbd_height(self, *kargs):
        self._keyboard_changed = not self._keyboard_changed

    def _get_ios_kheight(self):
        return 0

    def _get_android_kheight(self):
        global android
        if not android:
            import android
        return android.get_keyboard_height()

    def _get_kheight(self):
        if platform == 'android':
            return self._get_android_kheight()
        if platform == 'ios':
            return self._get_ios_kheight()
        return 0

    keyboard_height = AliasProperty(_get_kheight, None,
                                    bind=('_keyboard_changed',))
    '''Rerturns the height of the softkeyboard/IME on mobile platforms.
    Will return 0 if not on mobile platform or if IME is not active.

    ..versionadded:: 1.9.0

    :attr:`keyboard_height` is a read-only :class:`AliasProperty` defaults to 0.
    '''

    def _set_system_size(self, size):
        self._size = size

    def _get_system_size(self):
        if self.softinput_mode == 'resize':
            return self._size[0], self._size[1] - self.keyboard_height
        return self._size

    system_size = AliasProperty(
        _get_system_size,
        _set_system_size,
        bind=('_size', ))
    '''Real size of the window ignoring rotation.
    '''

    borderless = BooleanProperty(False)
    '''When set to True, this property removes the window border/decoration.

    .. versionadded:: 1.9.0

    :attr:`borderless` is a :class:`BooleanProperty`, defaults to False.
    '''

    fullscreen = OptionProperty(False, options=(True, False, 'auto', 'fake'))
    '''This property sets the fullscreen mode of the window. Available options
    are: True, False, 'auto', 'fake'. Check the :mod:`~kivy.config`
    documentation for a more detailed explanation on the values.

    .. versionadded:: 1.2.0

    .. note::
        The 'fake' option has been deprecated, use the :attr:`borderless`
        property instead.
    '''

    mouse_pos = ObjectProperty([0, 0])
    '''2d position of the mouse within the window.

    .. versionadded:: 1.2.0
    '''

    @property
    def __self__(self):
        return self

    top = NumericProperty(None, allownone=True)
    left = NumericProperty(None, allownone=True)
    position = OptionProperty('auto', options=['auto', 'custom'])
    render_context = ObjectProperty(None)
    canvas = ObjectProperty(None)
    title = StringProperty('Kivy')

    __events__ = ('on_draw', 'on_flip', 'on_rotate', 'on_resize', 'on_close',
                  'on_motion', 'on_touch_down', 'on_touch_move', 'on_touch_up',
                  'on_mouse_down', 'on_mouse_move', 'on_mouse_up',
                  'on_keyboard', 'on_key_down', 'on_key_up', 'on_dropfile',
                  'on_request_close', 'on_joy_axis', 'on_joy_hat',
                  'on_joy_ball', 'on_joy_button_down', "on_joy_button_up")

    def __new__(cls, **kwargs):
        if cls.__instance is None:
            cls.__instance = EventDispatcher.__new__(cls)
        return cls.__instance

    def __init__(self, **kwargs):

        kwargs.setdefault('force', False)

        # don't init window 2 times,
        # except if force is specified
        if WindowBase.__instance is not None and not kwargs.get('force'):
            return

        self.initialized = False
        self._is_desktop = Config.getboolean('kivy', 'desktop')

        # create a trigger for update/create the window when one of window
        # property changes
        self.trigger_create_window = Clock.create_trigger(
            self.create_window, -1)

        # Create a trigger for updating the keyboard height
        self.trigger_keyboard_height = Clock.create_trigger(
            self._upd_kbd_height, .5)

        # set the default window parameter according to the configuration
        if 'borderless' not in kwargs:
            kwargs['borderless'] = Config.getboolean('graphics', 'borderless')
        if 'fullscreen' not in kwargs:
            fullscreen = Config.get('graphics', 'fullscreen')
            if fullscreen not in ('auto', 'fake'):
                fullscreen = fullscreen.lower() in ('true', '1', 'yes', 'yup')
            kwargs['fullscreen'] = fullscreen
        if 'width' not in kwargs:
            kwargs['width'] = Config.getint('graphics', 'width')
        if 'height' not in kwargs:
            kwargs['height'] = Config.getint('graphics', 'height')
        if 'rotation' not in kwargs:
            kwargs['rotation'] = Config.getint('graphics', 'rotation')
        if 'position' not in kwargs:
            kwargs['position'] = Config.getdefault('graphics', 'position',
                                                   'auto')
        if 'top' in kwargs:
            kwargs['position'] = 'custom'
            kwargs['top'] = kwargs['top']
        else:
            kwargs['top'] = Config.getint('graphics', 'top')
        if 'left' in kwargs:
            kwargs['position'] = 'custom'
            kwargs['left'] = kwargs['left']
        else:
            kwargs['left'] = Config.getint('graphics', 'left')
        kwargs['_size'] = (kwargs.pop('width'), kwargs.pop('height'))

        super(WindowBase, self).__init__(**kwargs)

        # bind all the properties that need to recreate the window
        self._bind_create_window()
        self.bind(size=self.trigger_keyboard_height,
                  rotation=self.trigger_keyboard_height)

        self.bind(softinput_mode=lambda *dt: self.update_viewport(),
                  keyboard_height=lambda *dt: self.update_viewport())

        # init privates
        self._system_keyboard = Keyboard(window=self)
        self._keyboards = {'system': self._system_keyboard}
        self._vkeyboard_cls = None

        self.children = []
        self.parent = self

        # before creating the window
        import kivy.core.gl  # NOQA

        # configure the window
        self.create_window()

        # attach modules + listener event
        EventLoop.set_window(self)
        Modules.register_window(self)
        EventLoop.add_event_listener(self)

        # manage keyboard(s)
        self.configure_keyboards()

        # assign the default context of the widget creation
        if not hasattr(self, '_context'):
            self._context = get_current_context()

        # mark as initialized
        self.initialized = True

    def _bind_create_window(self):
        for prop in (
                'fullscreen', 'borderless', 'position', 'top',
                'left', '_size', 'system_size'):
            self.bind(**{prop: self.trigger_create_window})

    def _unbind_create_window(self):
        for prop in (
                'fullscreen', 'borderless', 'position', 'top',
                'left', '_size', 'system_size'):
            self.unbind(**{prop: self.trigger_create_window})

    def toggle_fullscreen(self):
        '''Toggle between fullscreen and windowed mode.

        .. deprecated:: 1.9.0
            Use :attr:`fullscreen` instead.
        '''
        pass

    def maximize(self):
        '''Maximizes the window. This method should be used on desktop
        platforms only.

        .. versionadded:: 1.9.0

        .. note::
            This feature works with the SDL2 window provider only.

        .. warning::
            This code is still experimental, and its API may be subject to
            change in a future version.
        '''
        Logger.warning('Window: maximize() is not implemented in the current '
                        'window provider.')

    def minimize(self):
        '''Minimizes the window. This method should be used on desktop
        platforms only.

        .. versionadded:: 1.9.0

        .. note::
            This feature works with the SDL2 window provider only.

        .. warning::
            This code is still experimental, and its API may be subject to
            change in a future version.
        '''
        Logger.warning('Window: minimize() is not implemented in the current '
                        'window provider.')

    def restore(self):
        '''Restores the size and position of a maximized or minimized window.
        This method should be used on desktop platforms only.

        .. versionadded:: 1.9.0

        .. note::
            This feature works with the SDL2 window provider only.

        .. warning::
            This code is still experimental, and its API may be subject to
            change in a future version.
        '''
        Logger.warning('Window: restore() is not implemented in the current '
                        'window provider.')

    def hide(self):
        '''Hides the window. This method should be used on desktop
        platforms only.

        .. versionadded:: 1.9.0

        .. note::
            This feature works with the SDL2 window provider only.

        .. warning::
            This code is still experimental, and its API may be subject to
            change in a future version.
        '''
        Logger.warning('Window: hide() is not implemented in the current '
                        'window provider.')

    def show(self):
        '''Shows the window. This method should be used on desktop
        platforms only.

        .. versionadded:: 1.9.0

        .. note::
            This feature works with the SDL2 window provider only.

        .. warning::
            This code is still experimental, and its API may be subject to
            change in a future version.
        '''
        Logger.warning('Window: show() is not implemented in the current '
                        'window provider.')

    def close(self):
        '''Close the window'''
        pass

    def create_window(self, *largs):
        '''Will create the main window and configure it.

        .. warning::
            This method is called automatically at runtime. If you call it, it
            will recreate a RenderContext and Canvas. This means you'll have a
            new graphics tree, and the old one will be unusable.

            This method exist to permit the creation of a new OpenGL context
            AFTER closing the first one. (Like using runTouchApp() and
            stopTouchApp()).

            This method has only been tested in a unittest environment and
            is not suitable for Applications.

            Again, don't use this method unless you know exactly what you are
            doing!
        '''
        # just to be sure, if the trigger is set, and if this method is
        # manually called, unset the trigger
        Clock.unschedule(self.create_window)

        # ensure the window creation will not be called twice
        if platform in ('android', 'ios'):
            self._unbind_create_window()

        if not self.initialized:
            from kivy.core.gl import init_gl
            init_gl()

            # create the render context and canvas, only the first time.
            from kivy.graphics import RenderContext, Canvas
            self.render_context = RenderContext()
            self.canvas = Canvas()
            self.render_context.add(self.canvas)

        else:
            # if we get initialized more than once, then reload opengl state
            # after the second time.
            # XXX check how it's working on embed platform.
            if platform == 'linux' or Window.__class__.__name__ == 'WindowSDL':
                # on linux, it's safe for just sending a resize.
                self.dispatch('on_resize', *self.system_size)

            else:
                # on other platform, window are recreated, we need to reload.
                from kivy.graphics.context import get_context
                get_context().reload()
                Clock.schedule_once(lambda x: self.canvas.ask_update(), 0)
                self.dispatch('on_resize', *self.system_size)

        # ensure the gl viewport is correct
        self.update_viewport()

    def on_flip(self):
        '''Flip between buffers (event)'''
        self.flip()

    def flip(self):
        '''Flip between buffers'''
        pass

    def _update_childsize(self, instance, value):
        self.update_childsize([instance])

    def add_widget(self, widget):
        '''Add a widget to a window'''
        widget.parent = self
        self.children.insert(0, widget)
        self.canvas.add(widget.canvas)
        self.update_childsize([widget])
        widget.bind(
            pos_hint=self._update_childsize,
            size_hint=self._update_childsize,
            size=self._update_childsize,
            pos=self._update_childsize)

    def remove_widget(self, widget):
        '''Remove a widget from a window
        '''
        if not widget in self.children:
            return
        self.children.remove(widget)
        self.canvas.remove(widget.canvas)
        widget.parent = None
        widget.unbind(
            pos_hint=self._update_childsize,
            size_hint=self._update_childsize,
            size=self._update_childsize,
            pos=self._update_childsize)

    def clear(self):
        '''Clear the window with the background color'''
        # XXX FIXME use late binding
        from kivy.graphics.opengl import glClearColor, glClear, \
            GL_COLOR_BUFFER_BIT, GL_DEPTH_BUFFER_BIT, GL_STENCIL_BUFFER_BIT
        cc = self._clearcolor
        if cc is not None:
            glClearColor(*cc)
            glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT |
                    GL_STENCIL_BUFFER_BIT)

    def set_title(self, title):
        '''Set the window title.

        .. versionadded:: 1.0.5
        '''
        self.title = title

    def set_icon(self, filename):
        '''Set the icon of the window.

        .. versionadded:: 1.0.5
        '''
        self.icon = filename

    def to_widget(self, x, y, initial=True, relative=False):
        return (x, y)

    def to_window(self, x, y, initial=True, relative=False):
        return (x, y)

    def get_root_window(self):
        return self

    def get_parent_window(self):
        return self

    def get_parent_layout(self):
        return None

    def on_draw(self):
        self.clear()
        self.render_context.draw()

    def on_motion(self, etype, me):
        '''Event called when a Motion Event is received.

        :Parameters:
            `etype`: str
                One of 'begin', 'update', 'end'
            `me`: :class:`~kivy.input.motionevent.MotionEvent`
                The Motion Event currently dispatched.
        '''
        if me.is_touch:
            w, h = self.system_size
            me.scale_for_screen(w, h, rotation=self._rotation,
                                smode=self.softinput_mode,
                                kheight=self.keyboard_height)
            if etype == 'begin':
                self.dispatch('on_touch_down', me)
            elif etype == 'update':
                self.dispatch('on_touch_move', me)
            elif etype == 'end':
                self.dispatch('on_touch_up', me)
                FocusBehavior._handle_post_on_touch_up(me)

    def on_touch_down(self, touch):
        '''Event called when a touch down event is initiated.

        .. versionchanged:: 1.9.0
            The touch `pos` is now transformed to window coordinates before
            this method is called. Before, the touch `pos` coordinate would be
            `(0, 0)` when this method was called.
        '''
        for w in self.children[:]:
            if w.dispatch('on_touch_down', touch):
                return True

    def on_touch_move(self, touch):
        '''Event called when a touch event moves (changes location).

        .. versionchanged:: 1.9.0
            The touch `pos` is now transformed to window coordinates before
            this method is called. Before, the touch `pos` coordinate would be
            `(0, 0)` when this method was called.
        '''
        for w in self.children[:]:
            if w.dispatch('on_touch_move', touch):
                return True

    def on_touch_up(self, touch):
        '''Event called when a touch event is released (terminated).

        .. versionchanged:: 1.9.0
            The touch `pos` is now transformed to window coordinates before
            this method is called. Before, the touch `pos` coordinate would be
            `(0, 0)` when this method was called.
        '''
        for w in self.children[:]:
            if w.dispatch('on_touch_up', touch):
                return True

    def on_resize(self, width, height):
        '''Event called when the window is resized.'''
        self.update_viewport()

    def update_viewport(self):
        from kivy.graphics.opengl import glViewport
        from kivy.graphics.transformation import Matrix
        from math import radians

        w, h = self.system_size

        smode = self.softinput_mode
        kheight = self.keyboard_height

        w2, h2 = w / 2., h / 2.
        r = radians(self.rotation)

        x, y = 0, 0
        _h = h
        if smode:
            y = kheight
        if smode == 'scale':
            _h -= kheight

        # prepare the viewport
        glViewport(x, y, w, _h)

        # do projection matrix
        projection_mat = Matrix()
        projection_mat.view_clip(0.0, w, 0.0, h, -1.0, 1.0, 0)
        self.render_context['projection_mat'] = projection_mat

        # do modelview matrix
        modelview_mat = Matrix().translate(w2, h2, 0)
        modelview_mat = modelview_mat.multiply(Matrix().rotate(r, 0, 0, 1))

        w, h = self.size
        w2, h2 = w / 2., h / 2.
        modelview_mat = modelview_mat.multiply(Matrix().translate(-w2, -h2, 0))
        self.render_context['modelview_mat'] = modelview_mat

        # redraw canvas
        self.canvas.ask_update()

        # and update childs
        self.update_childsize()

    def update_childsize(self, childs=None):
        width, height = self.size
        if childs is None:
            childs = self.children
        for w in childs:
            shw, shh = w.size_hint
            if shw and shh:
                w.size = shw * width, shh * height
            elif shw:
                w.width = shw * width
            elif shh:
                w.height = shh * height
            for key, value in w.pos_hint.items():
                if key == 'x':
                    w.x = value * width
                elif key == 'right':
                    w.right = value * width
                elif key == 'y':
                    w.y = value * height
                elif key == 'top':
                    w.top = value * height
                elif key == 'center_x':
                    w.center_x = value * width
                elif key == 'center_y':
                    w.center_y = value * height

    def screenshot(self, name='screenshot{:04d}.png'):
        '''Save the actual displayed image in a file
        '''
        i = 0
        path = None
        if name != 'screenshot{:04d}.png':
            _ext = name.split('.')[-1]
            name = ''.join((name[:-(len(_ext) + 1)], '{:04d}.', _ext))
        while True:
            i += 1
            path = join(getcwd(), name.format(i))
            if not exists(path):
                break
        return path

    def on_rotate(self, rotation):
        '''Event called when the screen has been rotated.
        '''
        pass

    def on_close(self, *largs):
        '''Event called when the window is closed'''
        Modules.unregister_window(self)
        EventLoop.remove_event_listener(self)

    def on_request_close(self, *largs, **kwargs):
        '''Event called before we close the window. If a bound function returns
        `True`, the window will not be closed. If the the event is triggered
        because of the keyboard escape key, the keyword argument `source` is
        dispatched along with a value of `keyboard` to the bound functions.

        .. warning::
            When the bound function returns True the window will not be closed,
            so use with care because the user would not be able to close the
            program, even if the red X is clicked.
        '''
        pass

    def on_mouse_down(self, x, y, button, modifiers):
        '''Event called when the mouse is used (pressed/released)'''
        pass

    def on_mouse_move(self, x, y, modifiers):
        '''Event called when the mouse is moved with buttons pressed'''
        pass

    def on_mouse_up(self, x, y, button, modifiers):
        '''Event called when the mouse is moved with buttons pressed'''
        pass

    def on_joy_axis(self, stickid, axisid, value):
        '''Event called when a joystick has a stick or other axis moved

        .. versionadded:: 1.9.0'''
        pass

    def on_joy_hat(self, stickid, hatid, value):
        '''Event called when a joystick has a hat/dpad moved

        .. versionadded:: 1.9.0'''
        pass

    def on_joy_ball(self, stickid, ballid, value):
        '''Event called when a joystick has a ball moved

        .. versionadded:: 1.9.0'''
        pass

    def on_joy_button_down(self, stickid, buttonid):
        '''Event called when a joystick has a button pressed

        .. versionadded:: 1.9.0'''
        pass

    def on_joy_button_up(self, stickid, buttonid):
        '''Event called when a joystick has a button released

        .. versionadded:: 1.9.0'''
        pass

    def on_keyboard(self, key, scancode=None, codepoint=None,
                    modifier=None, **kwargs):
        '''Event called when keyboard is used.

        .. warning::
            Some providers may omit `scancode`, `codepoint` and/or `modifier`!
        '''
        if 'unicode' in kwargs:
            Logger.warning("The use of the unicode parameter is deprecated, "
                           "and will be removed in future versions. Use "
                           "codepoint instead, which has identical "
                           "semantics.")

        # Quit if user presses ESC or the typical OSX shortcuts CMD+q or CMD+w
        # TODO If just CMD+w is pressed, only the window should be closed.
        is_osx = platform == 'darwin'
        if WindowBase.on_keyboard.exit_on_escape:
            if key == 27 or all([is_osx, key in [113, 119], modifier == 1024]):
                if not self.dispatch('on_request_close', source='keyboard'):
                    stopTouchApp()
                    self.close()
                    return True
    if Config:
        on_keyboard.exit_on_escape = Config.getboolean('kivy', 'exit_on_escape')

        def __exit(section, name, value):
            WindowBase.__dict__['on_keyboard'].exit_on_escape = \
                Config.getboolean('kivy', 'exit_on_escape')

        Config.add_callback(__exit, 'kivy', 'exit_on_escape')

    def on_key_down(self, key, scancode=None, codepoint=None,
                    modifier=None, **kwargs):
        '''Event called when a key is down (same arguments as on_keyboard)'''
        if 'unicode' in kwargs:
            Logger.warning("The use of the unicode parameter is deprecated, "
                           "and will be removed in future versions. Use "
                           "codepoint instead, which has identical "
                           "semantics.")

    def on_key_up(self, key, scancode=None, codepoint=None,
                  modifier=None, **kwargs):
        '''Event called when a key is released (same arguments as on_keyboard)
        '''
        if 'unicode' in kwargs:
            Logger.warning("The use of the unicode parameter is deprecated, "
                           "and will be removed in future versions. Use "
                           "codepoint instead, which has identical "
                           "semantics.")

    def on_dropfile(self, filename):
        '''Event called when a file is dropped on the application.

        .. warning::

            This event currently works with sdl2 window provider, on pygame
            window provider and MacOSX with a patched version of pygame.
            This event is left in place for further evolution
            (ios, android etc.)

        .. versionadded:: 1.2.0
        '''
        pass

    @reify
    def dpi(self):
        '''Return the DPI of the screen. If the implementation doesn't support
        any DPI lookup, it will just return 96.

        .. warning::

            This value is not cross-platform. Use
            :attr:`kivy.base.EventLoop.dpi` instead.
        '''
        return 96.

    def configure_keyboards(self):
        # Configure how to provide keyboards (virtual or not)

        # register system keyboard to listening keys from window
        sk = self._system_keyboard
        self.bind(
            on_key_down=sk._on_window_key_down,
            on_key_up=sk._on_window_key_up)

        # use the device's real keyboard
        self.use_syskeyboard = True

        # use the device's real keyboard
        self.allow_vkeyboard = False

        # one single vkeyboard shared between all widgets
        self.single_vkeyboard = True

        # the single vkeyboard is always sitting at the same position
        self.docked_vkeyboard = False

        # now read the configuration
        mode = Config.get('kivy', 'keyboard_mode')
        if mode not in ('', 'system', 'dock', 'multi', 'systemanddock',
                        'systemandmulti'):
            Logger.critical('Window: unknown keyboard mode %r' % mode)

        # adapt mode according to the configuration
        if mode == 'system':
            self.use_syskeyboard = True
            self.allow_vkeyboard = False
            self.single_vkeyboard = True
            self.docked_vkeyboard = False
        elif mode == 'dock':
            self.use_syskeyboard = False
            self.allow_vkeyboard = True
            self.single_vkeyboard = True
            self.docked_vkeyboard = True
        elif mode == 'multi':
            self.use_syskeyboard = False
            self.allow_vkeyboard = True
            self.single_vkeyboard = False
            self.docked_vkeyboard = False
        elif mode == 'systemanddock':
            self.use_syskeyboard = True
            self.allow_vkeyboard = True
            self.single_vkeyboard = True
            self.docked_vkeyboard = True
        elif mode == 'systemandmulti':
            self.use_syskeyboard = True
            self.allow_vkeyboard = True
            self.single_vkeyboard = False
            self.docked_vkeyboard = False

        Logger.info(
            'Window: virtual keyboard %sallowed, %s, %s' % (
                '' if self.allow_vkeyboard else 'not ',
                'single mode' if self.single_vkeyboard else 'multiuser mode',
                'docked' if self.docked_vkeyboard else 'not docked'))

    def set_vkeyboard_class(self, cls):
        '''.. versionadded:: 1.0.8

        Set the VKeyboard class to use. If set to None, it will use the
        :class:`kivy.uix.vkeyboard.VKeyboard`.
        '''
        self._vkeyboard_cls = cls

    def release_all_keyboards(self):
        '''.. versionadded:: 1.0.8

        This will ensure that no virtual keyboard / system keyboard is
        requested. All instances will be closed.
        '''
        for key in list(self._keyboards.keys())[:]:
            keyboard = self._keyboards[key]
            if keyboard:
                keyboard.release()

    def request_keyboard(self, callback, target, input_type='text'):
        '''.. versionadded:: 1.0.4

        Internal widget method to request the keyboard. This method is rarely
        required by the end-user as it is handled automatically by the
        :class:`~kivy.uix.textinput.TextInput`. We expose it in case you want
        to handle the keyboard manually for unique input scenarios.

        A widget can request the keyboard, indicating a callback to call
        when the keyboard is released (or taken by another widget).

        :Parameters:
            `callback`: func
                Callback that will be called when the keyboard is
                closed. This can be because somebody else requested the
                keyboard or the user closed it.
            `target`: Widget
                Attach the keyboard to the specified `target`. This should be
                the widget that requested the keyboard. Ensure you have a
                different target attached to each keyboard if you're working in
                a multi user mode.

                .. versionadded:: 1.0.8

            `input_type`: string
                Choose the type of soft keyboard to request. Can be one of
                'text', 'number', 'url', 'mail', 'datetime', 'tel', 'address'.

                .. note::

                    `input_type` is currently only honored on mobile devices.

                .. versionadded:: 1.8.0

        :Return:
            An instance of :class:`Keyboard` containing the callback, target,
            and if the configuration allows it, a
            :class:`~kivy.uix.vkeyboard.VKeyboard` instance attached as a
            *.widget* property.

        .. note::

            The behavior of this function is heavily influenced by the current
            `keyboard_mode`. Please see the Config's
            :ref:`configuration tokens <configuration-tokens>` section for
            more information.

        '''

        # release any previous keyboard attached.
        self.release_keyboard(target)

        # if we can use virtual vkeyboard, activate it.
        if self.allow_vkeyboard:
            keyboard = None

            # late import
            global VKeyboard
            if VKeyboard is None and self._vkeyboard_cls is None:
                from kivy.uix.vkeyboard import VKeyboard
                self._vkeyboard_cls = VKeyboard

            # if the keyboard doesn't exist, create it.
            key = 'single' if self.single_vkeyboard else target
            if key not in self._keyboards:
                vkeyboard = self._vkeyboard_cls()
                keyboard = Keyboard(widget=vkeyboard, window=self)
                vkeyboard.bind(
                    on_key_down=keyboard._on_vkeyboard_key_down,
                    on_key_up=keyboard._on_vkeyboard_key_up)
                self._keyboards[key] = keyboard
            else:
                keyboard = self._keyboards[key]

            # configure vkeyboard
            keyboard.target = keyboard.widget.target = target
            keyboard.callback = keyboard.widget.callback = callback

            # add to the window
            self.add_widget(keyboard.widget)

            # only after add, do dock mode
            keyboard.widget.docked = self.docked_vkeyboard
            keyboard.widget.setup_mode()

        else:
            # system keyboard, just register the callback.
            keyboard = self._system_keyboard
            keyboard.callback = callback
            keyboard.target = target

        # use system (hardware) keyboard according to flag
        if self.allow_vkeyboard and self.use_syskeyboard:
            self.unbind(
                on_key_down=keyboard._on_window_key_down,
                on_key_up=keyboard._on_window_key_up)
            self.bind(
                on_key_down=keyboard._on_window_key_down,
                on_key_up=keyboard._on_window_key_up)

        return keyboard

    def release_keyboard(self, target=None):
        '''.. versionadded:: 1.0.4

        Internal method for the widget to release the real-keyboard. Check
        :meth:`request_keyboard` to understand how it works.
        '''
        if self.allow_vkeyboard:
            key = 'single' if self.single_vkeyboard else target
            if key not in self._keyboards:
                return
            keyboard = self._keyboards[key]
            callback = keyboard.callback
            if callback:
                keyboard.callback = None
                callback()
            keyboard.target = None
            self.remove_widget(keyboard.widget)
            if key != 'single' and key in self._keyboards:
                del self._keyboards[key]
        elif self._system_keyboard.callback:
            # this way will prevent possible recursion.
            callback = self._system_keyboard.callback
            self._system_keyboard.callback = None
            callback()
            return True
示例#53
0
class WindowBase(EventDispatcher):
    '''WindowBase is a abstract window widget, for any window implementation.

    :Parameters:
        `fullscreen`: str, one of ('0', '1', 'auto', 'fake')
            Make window as fullscreen, check config documentation for more
            explaination about the values.
        `width`: int
            Width of window
        `height`: int
            Height of window

    :Events:
        `on_motion`: etype, motionevent
            Fired when a new :class:`~kivy.input.motionevent.MotionEvent` is
            dispatched
        `on_touch_down`:
            Fired when a new touch appear
        `on_touch_move`:
            Fired when an existing touch is moved
        `on_touch_up`:
            Fired when an existing touch disapear
        `on_draw`:
            Fired when the :class:`Window` is beeing drawed
        `on_flip`:
            Fired when the :class:`Window` GL surface is beeing flipped
        `on_rotate`: rotation
            Fired when the :class:`Window` is beeing rotated
        `on_close`:
            Fired when the :class:`Window` is closed
        `on_keyboard`: key, scancode, codepoint, modifier
            Fired when the keyboard is in action
            .. versionchanged:: 1.3.0

            The *unicode* parameter has be deprecated in favor of
            codepoint, and will be removed completely in future versions
        `on_key_down`: key, scancode, codepoint
            Fired when a key is down
            .. versionchanged:: 1.3.0

            The *unicode* parameter has be deprecated in favor of
            codepoint, and will be removed completely in future versions
        `on_key_up`: key, scancode, codepoint
            Fired when a key is up
            .. versionchanged:: 1.3.0

            The *unicode* parameter has be deprecated in favor of
            codepoint, and will be removed completely in future versions
        `on_dropfile`: str
            Fired when a file is dropped on the application
    '''

    __instance = None
    __initialized = False

    # private properties
    _size = ListProperty([0, 0])
    _modifiers = ListProperty([])
    _rotation = NumericProperty(0)
    _clearcolor = ObjectProperty([0, 0, 0, 1])

    children = ListProperty([])
    '''List of children of this window.

    :data:`children` is a :class:`~kivy.properties.ListProperty` instance,
    default to an empty list.

    Use :func:`add_widget` and :func:`remove_widget` for manipulate children
    list. Don't manipulate children list directly until you know what you are
    doing.
    '''

    parent = ObjectProperty(None, allownone=True)
    '''Parent of this window

    :data:`parent` is a :class:`~kivy.properties.ObjectProperty` instance,
    default to None. When created, the parent is set to the window itself.
    You must take care of it if you are doing recursive check.
    '''

    icon = StringProperty()

    def _get_modifiers(self):
        return self._modifiers

    modifiers = AliasProperty(_get_modifiers, None)
    '''List of keyboard modifiers currently in action
    '''

    def _get_size(self):
        r = self._rotation
        w, h = self._size
        if r in (0, 180):
            return w, h
        return h, w

    def _set_size(self, size):
        if self._size != size:
            r = self._rotation
            if r in (0, 180):
                self._size = size
            else:
                self._size = size[1], size[0]

            self.dispatch('on_resize', *size)
            return True
        else:
            return False
    size = AliasProperty(_get_size, _set_size, bind=('_size', ))
    '''Get the rotated size of the window. If :data:`rotation` is set, then the
    size will change to reflect the rotation.
    '''

    def _get_clearcolor(self):
        return self._clearcolor

    def _set_clearcolor(self, value):
        if value is not None:
            if type(value) not in (list, tuple):
                raise Exception('Clearcolor must be a list or tuple')
            if len(value) != 4:
                raise Exception('Clearcolor must contain 4 values')
        self._clearcolor = value

    clearcolor = AliasProperty(_get_clearcolor, _set_clearcolor,
            bind=('_clearcolor', ))
    '''Color used to clear window.

  ::
        from kivy.core.window import Window

        # red background color
        Window.clearcolor = (1, 0, 0, 1)

        # don't clear background at all
        Window.clearcolor = None

    .. versionchanged:: 1.7.2

        Clear color default value is now: (0, 0, 0, 1).

    '''

    # make some property read-only
    def _get_width(self):
        r = self._rotation
        if r == 0 or r == 180:
            return self._size[0]
        return self._size[1]

    width = AliasProperty(_get_width, None, bind=('_rotation', '_size'))
    '''Rotated window width.

    :data:`width` is a :class:`~kivy.properties.AliasProperty`.
    '''

    def _get_height(self):
        '''Rotated window height'''
        r = self._rotation
        if r == 0 or r == 180:
            return self._size[1]
        return self._size[0]

    height = AliasProperty(_get_height, None, bind=('_rotation', '_size'))
    '''Rotated window height.

    :data:`height` is a :class:`~kivy.properties.AliasProperty`.
    '''

    def _get_center(self):
        return self.width / 2., self.height / 2.

    center = AliasProperty(_get_center, None, bind=('width', 'height'))
    '''Center of the rotated window.

    :data:`center` is a :class:`~kivy.properties.AliasProperty`.
    '''

    def _get_rotation(self):
        return self._rotation

    def _set_rotation(self, x):
        x = int(x % 360)
        if x == self._rotation:
            return
        if x not in (0, 90, 180, 270):
            raise ValueError('can rotate only 0, 90, 180, 270 degrees')
        self._rotation = x
        if self.initialized is False:
            return
        self.dispatch('on_resize', *self.size)
        self.dispatch('on_rotate', x)

    rotation = AliasProperty(_get_rotation, _set_rotation, bind=('_rotation', ))
    '''Get/set the window content rotation. Can be one of 0, 90, 180, 270
    degrees.
    '''

    def _set_system_size(self, size):
        self._size = size

    def _get_system_size(self):
        return self._size

    system_size = AliasProperty(
            _get_system_size,
            _set_system_size,
            bind=('_size', ))
    '''Real size of the window, without taking care of the rotation.
    '''

    fullscreen = OptionProperty(False, options=(True, False, 'auto', 'fake'))
    '''If true, the window will be put in fullscreen mode, "auto". That's mean
    the screen size will not change, and use the current one to set the app
    fullscreen

    .. versionadded:: 1.2.0
    '''

    mouse_pos = ObjectProperty([0, 0])
    '''2d position of the mouse within the window.

    .. versionadded:: 1.2.0
    '''

    top = NumericProperty(None, allownone=True)
    left = NumericProperty(None, allownone=True)
    position = OptionProperty('auto', options=['auto', 'custom'])
    render_context = ObjectProperty(None)
    canvas = ObjectProperty(None)
    title = StringProperty('Kivy')

    __events__ = ('on_draw', 'on_flip', 'on_rotate', 'on_resize', 'on_close',
            'on_motion', 'on_touch_down', 'on_touch_move', 'on_touch_up',
            'on_mouse_down', 'on_mouse_move', 'on_mouse_up', 'on_keyboard',
            'on_key_down', 'on_key_up', 'on_dropfile')

    def __new__(cls, **kwargs):
        if cls.__instance is None:
            cls.__instance = EventDispatcher.__new__(cls)
        return cls.__instance

    def __init__(self, **kwargs):

        kwargs.setdefault('force', False)

        # don't init window 2 times,
        # except if force is specified
        if WindowBase.__instance is not None and not kwargs.get('force'):
            return
        self.initialized = False

        # create a trigger for update/create the window when one of window
        # property changes
        self.trigger_create_window = Clock.create_trigger(
                self.create_window, -1)

        # set the default window parameter according to the configuration
        if 'fullscreen' not in kwargs:
            fullscreen = Config.get('graphics', 'fullscreen')
            if fullscreen not in ('auto', 'fake'):
                fullscreen = fullscreen.lower() in ('true', '1', 'yes', 'yup')
            kwargs['fullscreen'] = fullscreen
        if 'width' not in kwargs:
            kwargs['width'] = Config.getint('graphics', 'width')
        if 'height' not in kwargs:
            kwargs['height'] = Config.getint('graphics', 'height')
        if 'rotation' not in kwargs:
            kwargs['rotation'] = Config.getint('graphics', 'rotation')
        if 'position' not in kwargs:
            kwargs['position'] = Config.getdefault('graphics', 'position', 'auto')
        if 'top' in kwargs:
            kwargs['position'] = 'custom'
            kwargs['top'] = kwargs['top']
        else:
            kwargs['top'] = Config.getint('graphics', 'top')
        if 'left' in kwargs:
            kwargs['position'] = 'custom'
            kwargs['left'] = kwargs['left']
        else:
            kwargs['left'] = Config.getint('graphics', 'left')
        kwargs['_size'] = (kwargs.pop('width'), kwargs.pop('height'))

        super(WindowBase, self).__init__(**kwargs)

        # bind all the properties that need to recreate the window
        for prop in (
                'fullscreen', 'position', 'top',
                'left', '_size', 'system_size'):
            self.bind(**{prop: self.trigger_create_window})

        # init privates
        self._system_keyboard = Keyboard(window=self)
        self._keyboards = {'system': self._system_keyboard}
        self._vkeyboard_cls = None

        self.children = []
        self.parent = self

        # before creating the window
        import kivy.core.gl

        # configure the window
        self.create_window()

        # attach modules + listener event
        EventLoop.set_window(self)
        Modules.register_window(self)
        EventLoop.add_event_listener(self)

        # manage keyboard(s)
        self.configure_keyboards()

        # mark as initialized
        self.initialized = True

    def toggle_fullscreen(self):
        '''Toggle fullscreen on window'''
        pass

    def close(self):
        '''Close the window'''
        pass

    def create_window(self, *largs):
        '''Will create the main window and configure it.

        .. warning::
            This method is called automatically at runtime. If you call it, it
            will recreate a RenderContext and Canvas. This mean you'll have a
            new graphics tree, and the old one will be unusable.

            This method exist to permit the creation of a new OpenGL context
            AFTER closing the first one. (Like using runTouchApp() and
            stopTouchApp()).

            This method have been only tested in unittest environment, and will
            be not suitable for Applications.

            Again, don't use this method unless you know exactly what you are
            doing !
        '''
        # just to be sure, if the trigger is set, and if this method is manually
        # called, unset the trigger
        Clock.unschedule(self.create_window)

        if not self.initialized:
            from kivy.core.gl import init_gl
            init_gl()

            # create the render context and canvas, only the first time.
            from kivy.graphics import RenderContext, Canvas
            self.render_context = RenderContext()
            self.canvas = Canvas()
            self.render_context.add(self.canvas)

        else:
            # if we get initialized more than once, then reload opengl state
            # after the second time.
            # XXX check how it's working on embed platform.
            if platform() == 'linux':
                # on linux, it's safe for just sending a resize.
                self.dispatch('on_resize', *self.system_size)

            else:
                # on other platform, window are recreated, we need to reload.
                from kivy.graphics.context import get_context
                get_context().reload()
                Clock.schedule_once(lambda x: self.canvas.ask_update(), 0)
                self.dispatch('on_resize', *self.system_size)

        # ensure the gl viewport is correct
        self.update_viewport()

    def on_flip(self):
        '''Flip between buffers (event)'''
        self.flip()

    def flip(self):
        '''Flip between buffers'''
        pass

    def _update_childsize(self, instance, value):
        self.update_childsize([instance])

    def add_widget(self, widget):
        '''Add a widget on window'''
        widget.parent = self
        self.children.insert(0, widget)
        self.canvas.add(widget.canvas)
        self.update_childsize([widget])
        widget.bind(
            pos_hint=self._update_childsize,
            size_hint=self._update_childsize,
            size=self._update_childsize,
            pos=self._update_childsize)

    def remove_widget(self, widget):
        '''Remove a widget from window
        '''
        if not widget in self.children:
            return
        self.children.remove(widget)
        self.canvas.remove(widget.canvas)
        widget.parent = None
        widget.unbind(
            pos_hint=self._update_childsize,
            size_hint=self._update_childsize,
            size=self._update_childsize,
            pos=self._update_childsize)

    def clear(self):
        '''Clear the window with background color'''
        # XXX FIXME use late binding
        from kivy.graphics.opengl import glClearColor, glClear, \
            GL_COLOR_BUFFER_BIT, GL_DEPTH_BUFFER_BIT
        cc = self._clearcolor
        if cc is not None:
            glClearColor(*cc)
            glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)

    def set_title(self, title):
        '''Set the window title.

        .. versionadded:: 1.0.5
        '''
        self.title = title

    def set_icon(self, filename):
        '''Set the icon of the window

        .. versionadded:: 1.0.5
        '''
        self.icon = filename

    def to_widget(self, x, y, initial=True, relative=False):
        return (x, y)

    def to_window(self, x, y, initial=True, relative=False):
        return (x, y)

    def get_root_window(self):
        return self

    def get_parent_window(self):
        return self

    def get_parent_layout(self):
        return None

    def on_draw(self):
        self.clear()
        self.render_context.draw()

    def on_motion(self, etype, me):
        '''Event called when a Motion Event is received.

        :Parameters:
            `etype`: str
                One of 'begin', 'update', 'end'
            `me`: :class:`~kivy.input.motionevent.MotionEvent`
                Motion Event currently dispatched
        '''
        if me.is_touch:
            if etype == 'begin':
                self.dispatch('on_touch_down', me)
            elif etype == 'update':
                self.dispatch('on_touch_move', me)
            elif etype == 'end':
                self.dispatch('on_touch_up', me)

    def on_touch_down(self, touch):
        '''Event called when a touch is down
        '''
        w, h = self.system_size
        touch.scale_for_screen(w, h, rotation=self._rotation)
        for w in self.children[:]:
            if w.dispatch('on_touch_down', touch):
                return True

    def on_touch_move(self, touch):
        '''Event called when a touch move
        '''
        w, h = self.system_size
        touch.scale_for_screen(w, h, rotation=self._rotation)
        for w in self.children[:]:
            if w.dispatch('on_touch_move', touch):
                return True

    def on_touch_up(self, touch):
        '''Event called when a touch up
        '''
        w, h = self.system_size
        touch.scale_for_screen(w, h, rotation=self._rotation)
        for w in self.children[:]:
            if w.dispatch('on_touch_up', touch):
                return True

    def on_resize(self, width, height):
        '''Event called when the window is resized'''
        self.update_viewport()

    def update_viewport(self):
        from kivy.graphics.opengl import glViewport
        from kivy.graphics.transformation import Matrix
        from math import radians

        w, h = self.system_size
        w2, h2 = w / 2., h / 2.
        r = radians(self.rotation)

        # prepare the viewport
        glViewport(0, 0, w, h)

        # do projection matrix
        projection_mat = Matrix()
        projection_mat.view_clip(0.0, w, 0.0, h, -1.0, 1.0, 0)
        self.render_context['projection_mat'] = projection_mat

        # do modelview matrix
        modelview_mat = Matrix().translate(w2, h2, 0)
        modelview_mat = modelview_mat.multiply(Matrix().rotate(r, 0, 0, 1))

        w, h = self.size
        w2, h2 = w / 2., h / 2.
        modelview_mat = modelview_mat.multiply(Matrix().translate(-w2, -h2, 0))
        self.render_context['modelview_mat'] = modelview_mat

        # redraw canvas
        self.canvas.ask_update()

        # and update childs
        self.update_childsize()

    def update_childsize(self, childs=None):
        width, height = self.size
        if childs is None:
            childs = self.children
        for w in childs:
            shw, shh = w.size_hint
            if shw and shh:
                w.size = shw * width, shh * height
            elif shw:
                w.width = shw * width
            elif shh:
                w.height = shh * height
            for key, value in w.pos_hint.items():
                if key == 'x':
                    w.x = value * width
                elif key == 'right':
                    w.right = value * width
                elif key == 'y':
                    w.y = value * height
                elif key == 'top':
                    w.top = value * height
                elif key == 'center_x':
                    w.center_x = value * width
                elif key == 'center_y':
                    w.center_y = value * height

    def screenshot(self, name='screenshot%(counter)04d.png'):
        '''Save the actual displayed image in a file
        '''
        i = 0
        path = None
        while True:
            i += 1
            path = join(getcwd(), name % {'counter': i})
            if not exists(path):
                break
        return path

    def on_rotate(self, rotation):
        '''Event called when the screen have been rotated
        '''
        pass

    def on_close(self, *largs):
        '''Event called when the window is closed'''
        Modules.unregister_window(self)
        EventLoop.remove_event_listener(self)

    def on_mouse_down(self, x, y, button, modifiers):
        '''Event called when mouse is in action (press/release)'''
        pass

    def on_mouse_move(self, x, y, modifiers):
        '''Event called when mouse is moving, with buttons pressed'''
        pass

    def on_mouse_up(self, x, y, button, modifiers):
        '''Event called when mouse is moving, with buttons pressed'''
        pass

    def on_keyboard(self, key,
        scancode=None, codepoint=None, modifier=None, **kwargs):
        '''Event called when keyboard is in action

        .. warning::
            Some providers may omit `scancode`, `codepoint` and/or `modifier`!
        '''
        if 'unicode' in kwargs:
            Logger.warning("The use of the unicode parameter is deprecated, "
                "and will be removed in future versions. Use codepoint "
                "instead, which has identical semantics.")

    def on_key_down(self, key,
        scancode=None, codepoint=None, modifier=None, **kwargs):
        '''Event called when a key is down (same arguments as on_keyboard)'''
        if 'unicode' in kwargs:
            Logger.warning("The use of the unicode parameter is deprecated, "
                "and will be removed in future versions. Use codepoint "
                "instead, which has identical semantics.")

    def on_key_up(self, key,
        scancode=None, codepoint=None, modifier=None, **kwargs):
        '''Event called when a key is up (same arguments as on_keyboard)'''
        if 'unicode' in kwargs:
            Logger.warning("The use of the unicode parameter is deprecated, "
                "and will be removed in future versions. Use codepoint "
                "instead, which has identical semantics.")

    def on_dropfile(self, filename):
        '''Event called when a file is dropped on the application.

        .. warning::

            This event is actually used only on MacOSX with a patched version of
            pygame. But this will be a place for a further evolution (ios,
            android etc.)

        .. versionadded:: 1.2.0
        '''
        pass

    @reify
    def dpi(self):
        '''Return the DPI of the screen. If the implementation doesn't support
        any DPI lookup, it will just return 96.

        .. warning::

            This value is not cross-platform. Use
            :data:`kivy.base.EventLoop.dpi` instead.
        '''
        return 96.

    def configure_keyboards(self):
        # Configure how to provide keyboards (virtual or not)

        # register system keyboard to listening keys from window
        sk = self._system_keyboard
        self.bind(
            on_key_down=sk._on_window_key_down,
            on_key_up=sk._on_window_key_up)

        # use the device's real keyboard
        self.allow_vkeyboard = False

        # one single vkeyboard shared between all widgets
        self.single_vkeyboard = True

        # the single vkeyboard is always sitting at the same position
        self.docked_vkeyboard = False

        # now read the configuration
        mode = Config.get('kivy', 'keyboard_mode')
        if mode not in ('', 'system', 'dock', 'multi'):
            Logger.critical('Window: unknown keyboard mode %r' % mode)

        # adapt mode according to the configuration
        if mode == 'system':
            self.allow_vkeyboard = False
            self.single_vkeyboard = True
            self.docked_vkeyboard = False
        elif mode == 'dock':
            self.allow_vkeyboard = True
            self.single_vkeyboard = True
            self.docked_vkeyboard = True
        elif mode == 'multi':
            self.allow_vkeyboard = True
            self.single_vkeyboard = False
            self.docked_vkeyboard = False

        Logger.info('Window: virtual keyboard %sallowed, %s, %s' %
                ('' if self.allow_vkeyboard else 'not ',
                'single mode' if self.single_vkeyboard else 'multiuser mode',
                'docked' if self.docked_vkeyboard else 'not docked'))

    def set_vkeyboard_class(self, cls):
        '''.. versionadded:: 1.0.8

        Set the VKeyboard class to use. If None set, it will use the
        :class:`kivy.uix.vkeyboard.VKeyboard`.
        '''
        self._vkeyboard_cls = cls

    def release_all_keyboards(self):
        '''.. versionadded:: 1.0.8

        This will ensure that no virtual keyboard / system keyboard are actually
        requested. All will be closed.
        '''
        for key in list(self._keyboards.keys())[:]:
            keyboard = self._keyboards[key]
            if keyboard:
                keyboard.release()

    def request_keyboard(self, callback, target):
        '''.. versionadded:: 1.0.4

        Internal method for widget, to request the keyboard. This method is
        not intented to be used by end-user, however, if you want to use the
        real-keyboard (not virtual keyboard), you don't want to share it with
        another widget.

        A widget can request the keyboard, indicating a callback to call
        when the keyboard will be released (or taken by another widget).

        :Parameters:
            `callback`: func
                Callback that will be called when the keyboard is closed. It can
                be because somebody else requested the keyboard, or if the user
                itself closed it.
            `target`: Widget
                Attach the keyboard to the specified target. Ensure you have a
                target attached if you're using the keyboard in a multi users
                mode.

        :Return:
            An instance of :class:`Keyboard`, containing the callback, target,
            and if configuration allowed it, a VKeyboard instance.

        .. versionchanged:: 1.0.8
            `target` have been added, and must be the widget source that request
            the keyboard. If set, the widget must have one method named
            `on_keyboard_text`, that will be called from the vkeyboard.

        '''

        # release any previous keyboard attached.
        self.release_keyboard(target)

        # if we can use virtual vkeyboard, activate it.
        if self.allow_vkeyboard:
            keyboard = None

            # late import
            global VKeyboard
            if VKeyboard is None and self._vkeyboard_cls is None:
                from kivy.uix.vkeyboard import VKeyboard
                self._vkeyboard_cls = VKeyboard

            # if the keyboard doesn't exist, create it.
            key = 'single' if self.single_vkeyboard else target
            if key not in self._keyboards:
                vkeyboard = self._vkeyboard_cls()
                keyboard = Keyboard(widget=vkeyboard, window=self)
                vkeyboard.bind(
                    on_key_down=keyboard._on_vkeyboard_key_down,
                    on_key_up=keyboard._on_vkeyboard_key_up)
                self._keyboards[key] = keyboard
            else:
                keyboard = self._keyboards[key]

            # configure vkeyboard
            keyboard.target = keyboard.widget.target = target
            keyboard.callback = keyboard.widget.callback = callback

            # add to the window
            self.add_widget(keyboard.widget)

            # only after add, do dock mode
            keyboard.widget.docked = self.docked_vkeyboard
            keyboard.widget.setup_mode()

            # return it.
            return keyboard

        else:
            # system keyboard, just register the callback.
            self._system_keyboard.callback = callback
            self._system_keyboard.target = target
            return self._system_keyboard

    def release_keyboard(self, target=None):
        '''.. versionadded:: 1.0.4

        Internal method for widget, to release the real-keyboard. Check
        :func:`request_keyboard` to understand how it works.
        '''
        if self.allow_vkeyboard:
            key = 'single' if self.single_vkeyboard else target
            if key not in self._keyboards:
                return
            keyboard = self._keyboards[key]
            callback = keyboard.callback
            if callback:
                keyboard.callback = None
                callback()
            keyboard.target = None
            self.remove_widget(keyboard.widget)
            if key != 'single' and key in self._keyboards:
                del self._keyboards[key]
        elif self._system_keyboard.callback:
            # this way will prevent possible recursion.
            callback = self._system_keyboard.callback
            self._system_keyboard.callback = None
            callback()
            return True
示例#54
0
class YuvVideo(Video):

    FS_CONVERT_RGB = '''$HEADER$
    uniform sampler2D tex_y;
    uniform sampler2D tex_u;
    uniform sampler2D tex_v;

    void main(void) {
        float r, g, b;

        r = texture2D(tex_y, tex_coord0).r;
        g = texture2D(tex_y, tex_coord0).g;
        b = texture2D(tex_y, tex_coord0).b;

        gl_FragColor = vec4(r, g, b, 1.0);
    }
    '''

    FS_CONVERT_YUV = '''$HEADER$
    uniform sampler2D tex_y;
    uniform sampler2D tex_u;
    uniform sampler2D tex_v;

    void main(void) {
        float r, g, b, y, u, v;

        y = texture2D(tex_y, tex_coord0).s;
        u = texture2D(tex_u, tex_coord0).s;
        v = texture2D(tex_v, tex_coord0).s;

        y = 1.1643 * (y - 0.0625);
        u = u - 0.5;
        v = v - 0.5;

        r = y + 1.5958  * v;
        g = y - 0.39173 * u - 0.81290 * v;
        b = y + 2.017   * u;

        gl_FragColor = vec4(r, g, b, 1.0);
    }
    '''

    FS_CONVERT_MONO = '''$HEADER$
    uniform sampler2D tex_y;
    uniform sampler2D tex_u;
    uniform sampler2D tex_v;

    void main(void) {
        float y;

        y = texture2D(tex_y, tex_coord0).s;
        y = 1.1643 * (y - 0.0625);

        gl_FragColor = vec4(y, y, y, 1.0);
    }
    '''

    fs       = StringProperty(None)
    textures = ListProperty([None, None, None])

    format   = OptionProperty(YUV_CHROMA_FORMAT[1], options=YUV_CHROMA_FORMAT)
    colorfmt = OptionProperty(OUT_COLOR_FORMAT[1], options=OUT_COLOR_FORMAT)
    yuv_size = ListProperty([0, 0])
    yuv_fps  = NumericProperty(30.)

    def __init__(self, **kwargs):

        self.register_event_type('on_load')

        self.canvas = RenderContext(fs=self.FS_CONVERT_YUV)
        self.canvas['tex_y'] = 1
        self.canvas['tex_u'] = 2
        self.canvas['tex_v'] = 3

        super(YuvVideo, self).__init__(**kwargs)

        if self.colorfmt == OUT_COLOR_FORMAT[0]:
            self.fs = self.FS_CONVERT_RGB
        elif self.format != YUV_CHROMA_FORMAT[0]:
            self.fs = self.FS_CONVERT_YUV
        else:
            self.fs = self.FS_CONVERT_MONO

    def seek(self, percent):
        if self.eos == True:
            self.eos = False
        super(YuvVideo, self).seek(percent)

    def on_load(self, *largs):
        pass

    def on_fs(self, instance, value):
        shader = self.canvas.shader
        old_value = shader.fs
        shader.fs = value
        if not shader.success:
            shader.fs = old_value
            raise Exception('failed')

    def on_size(self, instance, value):
        window = self.get_parent_window()
        if window:
            self.canvas['projection_mat'] = window.render_context['projection_mat']

    def on_state(self, instance, value):
        if not self._video:
            return
        if value == 'stop':
            self._video.stop()
        else:
            super(YuvVideo, self).on_state(instance, value)

    def _do_video_load(self, *largs):
        if self._video:
            self._video.stop()
        if not self.source:
            self._video   = None
            self.textures = [None, None, None]
            self.texture  = None
        else:
            filename = self.source
            if filename.split(':')[0] not in (
                    'http', 'https', 'file', 'udp', 'rtp', 'rtsp'):
                filename = resource_find(filename)
            self._video = VideoYuv(filename=filename,
                                   format=self.format,
                                   colorfmt=self.colorfmt,
                                   size=self.yuv_size,
                                   fps=self.yuv_fps)
            self._video.volume = self.volume
            self._video.bind(on_load=self._on_video_load,
                             on_frame=self._on_video_frame,
                             on_eos=self._on_eos)
            if self.state == 'play' or self.play:
                self._video.play()
            self.duration = 1.
            self.position = 0.

    def _on_video_load(self, *largs):
        self._on_video_frame()
        self.dispatch('on_load')

    def _on_video_frame(self, *largs):
        self.duration = self._video.duration
        self.position = self._video.position
        self.textures = self._video.texture
        self.texture  = self._video.texture[0]
        self.canvas.ask_update()

    def _on_eos(self, *largs):
        self.duration = self._video.duration
        self.position = self._video.position
        self.state = 'pause'
        self.eos = True
class PageCurl(Widget):
    source = StringProperty()
    time = NumericProperty(1.)

    cy_x = NumericProperty(520.)
    cy_y = NumericProperty(-50)
    cy_dir = NumericProperty(1.18)
    cy_radius = NumericProperty(150.)

    def __init__(self, **kwargs):
        super(PageCurl, self).__init__(**kwargs)
        self.c_front = RenderContext()
        self.c_front.shader.source = resource_find('front.glsl')
        self.c_back = RenderContext()
        self.c_back.shader.source = resource_find('back.glsl')
        self.c_backshadow = RenderContext()
        self.c_backshadow.shader.source = resource_find('backshadow.glsl')

        self.canvas.add(self.c_front)
        self.canvas.add(self.c_back)
        self.canvas.add(self.c_backshadow)

        self.texture = CoreImage(self.source).texture
        Clock.schedule_interval(self.update_glsl, 1 / 60.)

    def on_size(self, instance, size):
        with self.canvas.before:
            Callback(self._enter_3d)
        self.build_mesh()
        with self.canvas.after:
            Callback(self._leave_3d)

    def update_glsl(self, *largs):
        proj = Matrix().view_clip(0, self.width, 0, self.height, -1000, 1000, 0)
        self.c_front['projection_mat'] = proj
        self.c_front['cylinder_position'] = map(float, (self.cy_x, self.cy_y))
        self.c_front['cylinder_direction'] = (cos(self.cy_dir), sin(self.cy_dir))
        self.c_front['cylinder_radius'] = float(self.cy_radius)

        for key in ('projection_mat', 'cylinder_position', 'cylinder_radius',
                'cylinder_direction'):
            self.c_back[key] = self.c_front[key]
            self.c_backshadow[key] = self.c_front[key]

        self.c_front['texture1'] = 1
        self.c_backshadow['texture1'] = 1
        self.c_back['texture1'] = 1

    def _enter_3d(self, *args):
        glEnable(GL_DEPTH_TEST)
        glEnable(GL_CULL_FACE)

    def _leave_3d(self, *args):
        glDisable(GL_DEPTH_TEST)
        glDisable(GL_CULL_FACE)

    def build_mesh(self):
        m = 20
        width = self.width
        height = self.height
        step_width = width / (width / m)
        step_height = height / (height / m)
        vertices = []
        indices = []
        indices_back = []
        fw = float(width)
        fh = float(height)

        # create all the vertices
        for y in xrange(0, self.height + step_height, step_height):
            for x in xrange(0, self.width + step_width, step_width):
                vertices += [x, y, 0, x / fw, 1. - y / fh]

        # trace a triangles mesh
        mx = 1 + self.width / step_width
        my = 1 + self.height / step_height

        texture = self.texture
        mode = 'triangles'
        if DEBUG:
            texture = None
            mode = 'points'
        self.vertex_format = [
            ('vPosition', 3, 'float'),
            ('vTexCoords0', 2, 'float')]

        for x in xrange(mx - 1):
            for y in xrange(my - 1):
                i = y * mx + x
                indices += [i, i + 1, i + 1 + mx,
                            i, i + 1 + mx, i + mx]
                indices_back += [i, i + 1 + mx, i + 1,
                            i, i + mx, i + 1 + mx]

        self.g_mesh = Mesh(vertices=vertices, indices=indices,
                mode=mode, texture=texture, fmt=self.vertex_format)
        self.g_mesh_back = Mesh(vertices=vertices, indices=indices_back,
                mode=mode, texture=texture, fmt=self.vertex_format)
        self.o_vertices = vertices

        self.c_front.add(BindTexture(source='frontshadow.png', index=1))
        self.c_front.add(self.g_mesh)
        self.c_backshadow.add(Rectangle(size=self.size))
        self.c_back.add(BindTexture(source='backshadow.png', index=1))
        self.c_back.add(self.g_mesh_back)

    def on_time(self, instance, t):
        t = self.time
        d = 0.8
        if t < d:
            dt = t / d
            self.cy_dir = funcLinear(AnimationTransition.out_circ(dt), 0, 1.55)
        else:
            self.cy_dir = 1.55

        self.cy_x = funcLinear(t, self.width, -self.width / 2.0)
示例#56
0
class EffectWidget(FloatLayout):

    fs = StringProperty(None)

    # Texture of the final Fbo
    texture = ObjectProperty(None)

    # Rectangle clearing Fbo
    fbo_rectangle = ObjectProperty(None)

    # List of effect strings
    effects = ListProperty([])

    # One extra Fbo for each effect
    fbo_list = ListProperty([])

    effect_mask = None
    motion_effect = None

    def __init__(self, **kwargs):
        # Make sure opengl context exists
        EventLoop.ensure_window()
        self.mask_effect = kwargs.get("mask_effect", None)
        self.motion_effect = kwargs.get("motion_effect", None)

        self.canvas = RenderContext(use_parent_projection=True,
                                    use_parent_modelview=True)

        self.size = C_SIZE
        with self.canvas:
            #self._viewport = Rectangle(size=(800,600), pos=self.pos)
            self.fbo = Fbo(size=C_SIZE, with_depthbuffer=True,  compute_normal_mat=True,
                           clear_color=(0.3, 0.3, 0.7, 1))

        with self.fbo.before:
            #Rectangle(size=(800, 600))
            PushMatrix()
            self.fbo_translation = Translate(-self.x, -self.y, 0)
            BindTexture(texture=self.mask_effect.texture, index=4)
            BindTexture(texture=self.motion_effect.texture, index=5)

        with self.fbo:
            Color(0, 0, 0)
            BindTexture(texture=self.mask_effect.texture, index=4)
            BindTexture(texture=self.motion_effect.texture, index=5)
            self.fbo_rectangle = Rectangle(size=C_SIZE)
            self._instructions = InstructionGroup()

        with self.fbo.after:
            PopMatrix()
            self.cbs = Callback(self.reset_gl_context)


        super(EffectWidget, self).__init__(**kwargs)
        self.size = C_SIZE

        Clock.schedule_interval(self.update_glsl, 0)

        self._instructions.add(Callback(self.setup_gl_context))

        self.refresh_fbo_setup()
        Clock.schedule_interval(self.update_fbos, 0)

    def on_pos(self, *args):
        self.fbo_translation.x = -self.x
        self.fbo_translation.y = -self.y

    def on_size(self, instance, value):
        self.fbo.size = C_SIZE
        self.fbo_rectangle.size = C_SIZE
        self.refresh_fbo_setup()

        #self._viewport.texture = self.fbo.texture
        #self._viewport.size = value


    def setup_gl_context(self, *args):
        glEnable(GL_DEPTH_TEST)
        self.fbo.clear_buffer()

        #for fbo in self.fbo_list:
        #    fbo.clear_buffer()

    def reset_gl_context(self, *args):
        glDisable(GL_DEPTH_TEST)

    def update_glsl(self, *largs):
        time = Clock.get_boottime()
        resolution = [float(size) for size in C_SIZE]
        self.canvas['time'] = time
        self.canvas['resolution'] = resolution
        self.canvas['texture4'] = 4
        self.canvas['texture5'] = 5
        for fbo in self.fbo_list:
            fbo['time'] = time
            fbo['resolution'] = resolution
            fbo['texture4'] = 4
            fbo['texture5'] = 5


    def on_effects(self, *args):
        self.refresh_fbo_setup()

    def update_fbos(self, *args):
        for fbo in self.fbo_list:
            fbo.ask_update()

    def refresh_fbo_setup(self, *args):
        # Add/remove fbos until there is one per effect
        while len(self.fbo_list) < len(self.effects):
            with self.canvas:
                new_fbo = EffectFbo(size=C_SIZE)
            with new_fbo:
                Color(1, 1, 1, 1)
                new_fbo.texture_rectangle = Rectangle(
                    size=C_SIZE)

                new_fbo.texture_rectangle.size = C_SIZE
            self.fbo_list.append(new_fbo)
        while len(self.fbo_list) > len(self.effects):
            old_fbo = self.fbo_list.pop()
            self.canvas.remove(old_fbo)

        # Do resizing etc.
        self.fbo.size = C_SIZE
        self.fbo_rectangle.size = C_SIZE
        for i in range(len(self.fbo_list)):
            self.fbo_list[i].size = C_SIZE
            self.fbo_list[i].texture_rectangle.size = C_SIZE

        # If there are no effects, just draw our main fbo
        if len(self.fbo_list) == 0:
            self.texture = self.fbo.texture
            return

        for i in range(1, len(self.fbo_list)):
            fbo = self.fbo_list[i]
            fbo.texture_rectangle.texture = self.fbo_list[i - 1].texture

        for effect, fbo in zip(self.effects, self.fbo_list):
            fbo.set_fs(shader_header + shader_uniforms + effect +
                       shader_footer_effect)

        self.fbo_list[0].texture_rectangle.texture = self.fbo.texture
        self.texture = self.fbo_list[-1].texture

    def on_fs(self, instance, value):
        # set the fragment shader to our source code
        shader = self.canvas.shader
        old_value = shader.fs
        shader.fs = value
        if not shader.success:
            shader.fs = old_value
            raise Exception('failed')

    def add_widget(self, widget):
        # Add the widget to our Fbo instead of the normal canvas
        c = self.canvas
        self.canvas = self.fbo
        super(EffectWidget, self).add_widget(widget)
        #self._instructions.add(widget.canvas)
        self.canvas = c

    def remove_widget(self, widget):
        # Remove the widget from our Fbo instead of the normal canvas
        c = self.canvas
        self.canvas = self.fbo
        super(EffectWidget, self).remove_widget(widget)
        self.canvas = c

    def clear_widgets(self, children=None):
        # Clear widgets from our Fbo instead of the normal canvas
        c = self.canvas
        self.canvas = self.fbo
        super(EffectWidget, self).clear_widgets(children)
        self.canvas = c
示例#57
0
class WindowBase(EventDispatcher):
    '''WindowBase is a abstract window widget, for any window implementation.

    :Parameters:
        `fullscreen`: str, one of ('0', '1', 'auto', 'fake')
            Make window as fullscreen, check config documentation for more
            explaination about the values.
        `width`: int
            Width of window
        `height`: int
            Height of window

    :Events:
        `on_motion`: etype, motionevent
            Fired when a new :class:`~kivy.input.motionevent.MotionEvent` is
            dispatched
        `on_touch_down`:
            Fired when a new touch appear
        `on_touch_move`:
            Fired when an existing touch is moved
        `on_touch_up`:
            Fired when an existing touch disapear
        `on_draw`:
            Fired when the :class:`Window` is beeing drawed
        `on_flip`:
            Fired when the :class:`Window` GL surface is beeing flipped
        `on_rotate`: rotation
            Fired when the :class:`Window` is beeing rotated
        `on_close`:
            Fired when the :class:`Window` is closed
        `on_keyboard`: key, scancode, unicode, modifier
            Fired when the keyboard is in action
        `on_key_down`: key, scancode, unicode
            Fired when a key is down
        `on_key_up`: key, scancode, unicode
            Fired when a key is up
    '''

    __instance = None
    __initialized = False

    def __new__(cls, **kwargs):
        if cls.__instance is None:
            cls.__instance = EventDispatcher.__new__(cls)
        return cls.__instance

    def __init__(self, **kwargs):

        kwargs.setdefault('force', False)
        kwargs.setdefault('config', None)

        # don't init window 2 times,
        # except if force is specified
        if self.__initialized and not kwargs.get('force'):
            return

        # event subsystem
        self.register_event_type('on_draw')
        self.register_event_type('on_flip')
        self.register_event_type('on_rotate')
        self.register_event_type('on_resize')
        self.register_event_type('on_close')
        self.register_event_type('on_motion')
        self.register_event_type('on_touch_down')
        self.register_event_type('on_touch_move')
        self.register_event_type('on_touch_up')
        self.register_event_type('on_mouse_down')
        self.register_event_type('on_mouse_move')
        self.register_event_type('on_mouse_up')
        self.register_event_type('on_keyboard')
        self.register_event_type('on_key_down')
        self.register_event_type('on_key_up')

        super(WindowBase, self).__init__()

        # init privates
        self._system_keyboard = Keyboard(window=self)
        self._keyboards = {'system': self._system_keyboard}
        self._modifiers = []
        self._size = (0, 0)
        self._rotation = 0
        self._clearcolor = [0, 0, 0, 0]
        self._vkeyboard_cls = None

        self.children = []
        self.parent = self

        # add view
        if 'view' in kwargs:
            self.add_widget(kwargs.get('view'))

        # get window params, user options before config option
        params = {}

        if 'fullscreen' in kwargs:
            params['fullscreen'] = kwargs.get('fullscreen')
        else:
            params['fullscreen'] = Config.get('graphics', 'fullscreen')
            if params['fullscreen'] not in ('auto', 'fake'):
                params['fullscreen'] = params['fullscreen'].lower() in \
                    ('true', '1', 'yes', 'yup')

        if 'width' in kwargs:
            params['width'] = kwargs.get('width')
        else:
            params['width'] = Config.getint('graphics', 'width')

        if 'height' in kwargs:
            params['height'] = kwargs.get('height')
        else:
            params['height'] = Config.getint('graphics', 'height')

        if 'rotation' in kwargs:
            params['rotation'] = kwargs.get('rotation')
        else:
            params['rotation'] = Config.getint('graphics', 'rotation')

        params['position'] = Config.get(
            'graphics', 'position', 'auto')
        if 'top' in kwargs:
            params['position'] = 'custom'
            params['top'] = kwargs.get('top')
        else:
            params['top'] = Config.getint('graphics', 'top')

        if 'left' in kwargs:
            params['position'] = 'custom'
            params['left'] = kwargs.get('left')
        else:
            params['left'] = Config.getint('graphics', 'left')

        # before creating the window
        import kivy.core.gl

        # configure the window
        self.params = params
        self.create_window()

        # attach modules + listener event
        Modules.register_window(self)
        EventLoop.set_window(self)
        EventLoop.add_event_listener(self)

        # manage keyboard(s)
        self.configure_keyboards()

        # mark as initialized
        self.__initialized = True

    def toggle_fullscreen(self):
        '''Toggle fullscreen on window'''
        pass

    def close(self):
        '''Close the window'''
        pass

    def create_window(self):
        '''Will create the main window and configure it.

        .. warning::
            This method is called automatically at runtime. If you call it, it
            will recreate a RenderContext and Canvas. This mean you'll have a
            new graphics tree, and the old one will be unusable.

            This method exist to permit the creation of a new OpenGL context
            AFTER closing the first one. (Like using runTouchApp() and
            stopTouchApp()).

            This method have been only tested in unittest environment, and will
            be not suitable for Applications.

            Again, don't use this method unless you know exactly what you are
            doing !
        '''
        from kivy.core.gl import init_gl
        init_gl()

        # create the render context and canvas
        from kivy.graphics import RenderContext, Canvas
        self.render_context = RenderContext()
        self.canvas = Canvas()
        self.render_context.add(self.canvas)

    def on_flip(self):
        '''Flip between buffers (event)'''
        self.flip()

    def flip(self):
        '''Flip between buffers'''
        pass

    def _get_modifiers(self):
        return self._modifiers
    modifiers = property(_get_modifiers)

    def _get_size(self):
        r = self._rotation
        w, h = self._size
        if r == 0 or r == 180:
            return w, h
        return h, w

    def _set_size(self, size):
        if super(WindowBase, self)._set_size(size):
            Logger.debug('Window: Resize window to %s' % str(self.size))
            self.dispatch('on_resize', *size)
            return True
        return False

    size = property(_get_size, _set_size,
        doc='''Rotated size of the window''')

    def _get_clearcolor(self):
        return self._clearcolor

    def _set_clearcolor(self, value):
        if value is not None:
            if type(value) not in (list, tuple):
                raise Exception('Clearcolor must be a list or tuple')
            if len(value) != 4:
                raise Exception('Clearcolor must contain 4 values')
        self._clearcolor = value

    clearcolor = property(_get_clearcolor, _set_clearcolor,
        doc='''
        Color used to clear window::

            from kivy.core.window import Window

            # red background color
            Window.clearcolor = (1, 0, 0, 1)

            # don't clear background at all
            Window.clearcolor = None
        ''')

    # make some property read-only
    @property
    def width(self):
        '''Rotated window width'''
        r = self._rotation
        if r == 0 or r == 180:
            return self._size[0]
        return self._size[1]

    @property
    def height(self):
        '''Rotated window height'''
        r = self._rotation
        if r == 0 or r == 180:
            return self._size[1]
        return self._size[0]

    @property
    def center(self):
        '''Rotated window center'''
        return self.width / 2., self.height / 2.

    def _update_childsize(self, instance, value):
        self.update_childsize([instance])

    def add_widget(self, widget):
        '''Add a widget on window'''
        widget.parent = self
        self.children.insert(0, widget)
        self.canvas.add(widget.canvas)
        self.update_childsize([widget])
        widget.bind(
            pos_hint=self._update_childsize,
            size_hint=self._update_childsize,
            size=self._update_childsize,
            pos=self._update_childsize)

    def remove_widget(self, widget):
        '''Remove a widget from window
        '''
        if not widget in self.children:
            return
        self.children.remove(widget)
        self.canvas.remove(widget.canvas)
        widget.parent = None
        widget.unbind(
            pos_hint=self._update_childsize,
            size_hint=self._update_childsize,
            size=self._update_childsize,
            pos=self._update_childsize)

    def clear(self):
        '''Clear the window with background color'''
        # XXX FIXME use late binding
        from kivy.graphics.opengl import glClearColor, glClear, \
            GL_COLOR_BUFFER_BIT, GL_DEPTH_BUFFER_BIT
        cc = self._clearcolor
        if cc is not None:
            glClearColor(*cc)
            glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)

    def set_title(self, title):
        '''Set the window title.

        .. versionadded:: 1.0.5
        '''
        pass

    def set_icon(self, filename):
        '''Set the icon of the window

        .. versionadded:: 1.0.5
        '''
        pass

    def to_widget(self, x, y, initial=True, relative=False):
        return (x, y)

    def to_window(self, x, y, initial=True, relative=False):
        return (x, y)

    def get_root_window(self):
        return self

    def get_parent_window(self):
        return self

    def get_parent_layout(self):
        return None

    def on_draw(self):
        self.clear()
        self.render_context.draw()

    def on_motion(self, etype, me):
        '''Event called when a Motion Event is received.

        :Parameters:
            `etype`: str
                One of 'begin', 'update', 'end'
            `me`: :class:`~kivy.input.motionevent.MotionEvent`
                Motion Event currently dispatched
        '''
        if me.is_touch:
            if etype == 'begin':
                self.dispatch('on_touch_down', me)
            elif etype == 'update':
                self.dispatch('on_touch_move', me)
            elif etype == 'end':
                self.dispatch('on_touch_up', me)

    def on_touch_down(self, touch):
        '''Event called when a touch is down
        '''
        w, h = self.system_size
        touch.scale_for_screen(w, h, rotation=self._rotation)
        for w in self.children[:]:
            if w.dispatch('on_touch_down', touch):
                return True

    def on_touch_move(self, touch):
        '''Event called when a touch move
        '''
        w, h = self.system_size
        touch.scale_for_screen(w, h, rotation=self._rotation)
        for w in self.children[:]:
            if w.dispatch('on_touch_move', touch):
                return True

    def on_touch_up(self, touch):
        '''Event called when a touch up
        '''
        w, h = self.system_size
        touch.scale_for_screen(w, h, rotation=self._rotation)
        for w in self.children[:]:
            if w.dispatch('on_touch_up', touch):
                return True

    def on_resize(self, width, height):
        '''Event called when the window is resized'''
        self.update_viewport()

    def update_viewport(self):
        from kivy.graphics.opengl import glViewport
        from kivy.graphics.transformation import Matrix
        from math import radians

        w, h = self.system_size
        w2, h2 = w / 2., h / 2.
        r = radians(self.rotation)

        # prepare the viewport
        glViewport(0, 0, w, h)

        # do projection matrix
        projection_mat = Matrix()
        projection_mat.view_clip(0.0, w, 0.0, h, -1.0, 1.0, 0)
        self.render_context['projection_mat'] = projection_mat

        # do modelview matrix
        modelview_mat = Matrix().translate(w2, h2, 0)
        modelview_mat = modelview_mat.multiply(Matrix().rotate(r, 0, 0, 1))

        w, h = self.size
        w2, h2 = w / 2., h / 2.
        modelview_mat = modelview_mat.multiply(Matrix().translate(-w2, -h2, 0))
        self.render_context['modelview_mat'] = modelview_mat

        # redraw canvas
        self.canvas.ask_update()

        # and update childs
        self.update_childsize()

    def update_childsize(self, childs=None):
        width, height = self.size
        if childs is None:
            childs = self.children
        for w in childs:
            shw, shh = w.size_hint
            if shw and shh:
                w.size = shw * width, shh * height
            elif shw:
                w.width = shw * width
            elif shh:
                w.height = shh * height
            for key, value in w.pos_hint.iteritems():
                if key == 'x':
                    w.x = value * width
                elif key == 'right':
                    w.right = value * width
                elif key == 'y':
                    w.y = value * height
                elif key == 'top':
                    w.top = value * height
                elif key == 'center_x':
                    w.center_x = value * width
                elif key == 'center_y':
                    w.center_y = value * height

    def _get_rotation(self):
        return self._rotation

    def _set_rotation(self, x):
        x = int(x % 360)
        if x == self._rotation:
            return
        if x not in (0, 90, 180, 270):
            raise ValueError('can rotate only 0,90,180,270 degrees')
        self._rotation = x
        self.dispatch('on_resize', *self.size)
        self.dispatch('on_rotate', x)

    rotation = property(_get_rotation, _set_rotation,
            'Get/set the window content rotation. Can be one of '
            '0, 90, 180, 270 degrees.')

    @property
    def system_size(self):
        '''Real size of the window, without taking care of the rotation
        '''
        return self._size

    def screenshot(self, name='screenshot%(counter)04d.jpg'):
        '''Save the actual displayed image in a file
        '''
        i = 0
        path = None
        while True:
            i += 1
            path = join(getcwd(), name % {'counter': i})
            if not exists(path):
                break
        return path

    def on_rotate(self, rotation):
        '''Event called when the screen have been rotated
        '''
        pass

    def on_close(self, *largs):
        '''Event called when the window is closed'''
        Modules.unregister_window(self)
        EventLoop.remove_event_listener(self)

    def on_mouse_down(self, x, y, button, modifiers):
        '''Event called when mouse is in action (press/release)'''
        pass

    def on_mouse_move(self, x, y, modifiers):
        '''Event called when mouse is moving, with buttons pressed'''
        pass

    def on_mouse_up(self, x, y, button, modifiers):
        '''Event called when mouse is moving, with buttons pressed'''
        pass

    def on_keyboard(self, key, scancode=None, unicode=None, modifier=None):
        '''Event called when keyboard is in action

        .. warning::
            Some providers may omit `scancode`, `unicode` and/or `modifier`!
        '''
        pass

    def on_key_down(self, key, scancode=None, unicode=None, modifier=None):
        '''Event called when a key is down (same arguments as on_keyboard)'''
        pass

    def on_key_up(self, key, scancode=None, unicode=None, modifier=None):
        '''Event called when a key is up (same arguments as on_keyboard)'''
        pass

    def configure_keyboards(self):
        # Configure how to provide keyboards (virtual or not)

        # register system keyboard to listening keys from window
        sk = self._system_keyboard
        self.bind(
            on_key_down=sk._on_window_key_down,
            on_key_up=sk._on_window_key_up)

        # use the device's real keyboard
        self.allow_vkeyboard = False

        # one single vkeyboard shared between all widgets
        self.single_vkeyboard = True

        # the single vkeyboard is always sitting at the same position
        self.docked_vkeyboard = False

        # now read the configuration
        mode = Config.get('kivy', 'keyboard_mode')
        if mode not in ('', 'system', 'dock', 'multi'):
            Logger.critical('Window: unknown keyboard mode %r' % mode)

        # adapt mode according to the configuration
        if mode == 'system':
            self.allow_vkeyboard = False
            self.single_vkeyboard = True
            self.docked_vkeyboard = False
        elif mode == 'dock':
            self.allow_vkeyboard = True
            self.single_vkeyboard = True
            self.docked_vkeyboard = True
        elif mode == 'multi':
            self.allow_vkeyboard = True
            self.single_vkeyboard = False
            self.docked_vkeyboard = False

        Logger.info('Window: virtual keyboard %sallowed, %s, %s' %
                ('' if self.allow_vkeyboard else 'not ',
                'single mode' if self.single_vkeyboard else 'multiuser mode',
                'docked' if self.docked_vkeyboard else 'not docked'))

    def set_vkeyboard_class(self, cls):
        '''.. versionadded:: 1.0.8

        Set the VKeyboard class to use. If None set, it will use the
        :class:`kivy.uix.vkeyboard.VKeyboard`.
        '''
        self._vkeyboard_cls = cls

    def release_all_keyboards(self):
        '''.. versionadded:: 1.0.8

        This will ensure that no virtual keyboard / system keyboard are actually
        requested. All will be closed.
        '''
        for key in self._keyboards.keys()[:]:
            keyboard = self._keyboards[key]
            if keyboard:
                keyboard.release()

    def request_keyboard(self, callback, target):
        '''.. versionadded:: 1.0.4

        Internal method for widget, to request the keyboard. This method is
        not intented to be used by end-user, however, if you want to use the
        real-keyboard (not virtual keyboard), you don't want to share it with
        another widget.

        A widget can request the keyboard, indicating a callback to call
        when the keyboard will be released (or taken by another widget).

        :Parameters:
            `callback`: func
                Callback that will be called when the keyboard is closed. It can
                be because somebody else requested the keyboard, or if the user
                itself closed it.
            `target`: Widget
                Attach the keyboard to the specified target. Ensure you have a
                target attached if you're using the keyboard in a multi users
                mode.

        :Return:
            An instance of :class:`Keyboard`, containing the callback, target,
            and if configuration allowed it, a VKeyboard instance.

        .. versionchanged:: 1.0.8

            `target` have been added, and must be the widget source that request
            the keyboard. If set, the widget must have one method named
            `on_keyboard_text`, that will be called from the vkeyboard.

        '''

        # release any previous keyboard attached.
        self.release_keyboard(target)

        # if we can use virtual vkeyboard, activate it.
        if self.allow_vkeyboard:
            keyboard = None

            # late import
            global VKeyboard
            if VKeyboard is None and self._vkeyboard_cls is None:
                from kivy.uix.vkeyboard import VKeyboard
                self._vkeyboard_cls = VKeyboard

            # if the keyboard doesn't exist, create it.
            key = 'single' if self.single_vkeyboard else target
            if key not in self._keyboards:
                vkeyboard = self._vkeyboard_cls()
                keyboard = Keyboard(widget=vkeyboard, window=self)
                vkeyboard.bind(
                    on_key_down=keyboard._on_vkeyboard_key_down,
                    on_key_up=keyboard._on_vkeyboard_key_up)
                self._keyboards[key] = keyboard
            else:
                keyboard = self._keyboards[key]

            # configure vkeyboard
            keyboard.target = keyboard.widget.target = target
            keyboard.callback = keyboard.widget.callback = callback

            # add to the window
            self.add_widget(keyboard.widget)

            # only after add, do dock mode
            keyboard.widget.docked = self.docked_vkeyboard
            keyboard.widget.setup_mode()

            # return it.
            return keyboard

        else:
            # system keyboard, just register the callback.
            self._system_keyboard.callback = callback
            self._system_keyboard.target = target
            return self._system_keyboard

    def release_keyboard(self, target=None):
        '''.. versionadded:: 1.0.4

        Internal method for widget, to release the real-keyboard. Check
        :func:`request_keyboard` to understand how it works.
        '''
        if self.allow_vkeyboard:
            key = 'single' if self.single_vkeyboard else target
            if key not in self._keyboards:
                return
            keyboard = self._keyboards[key]
            callback = keyboard.callback
            if callback:
                keyboard.callback = None
                callback()
            keyboard.target = None
            self.remove_widget(keyboard.widget)
            if key != 'single' and key in self._keyboards:
                del self._keyboards[key]
        elif self._system_keyboard.callback:
            # this way will prevent possible recursion.
            callback = self._system_keyboard.callback
            self._system_keyboard.callback = None
            callback()
            return True
示例#58
0
class PageCurlTransition(TransitionBase):

    cy_x = NumericProperty(520.)
    cy_y = NumericProperty(-50)
    cy_dir = NumericProperty(1.18)
    cy_radius = NumericProperty(150.)

    def __init__(self, **kwargs):
        super(PageCurlTransition, self).__init__(**kwargs)
        self.fbo_in = None
        self.fbo_out = None

    def make_screen_fbo(self, screen, mode=None):
        assert(mode is not None)
        attr = 'fbo_'  + mode
        fbo = getattr(self, attr)

        w, h = screen.size
        w = (w - w % TILE) + TILE
        h = (h - h % TILE) + TILE
        size = w, h

        if not fbo:
            fbo = Fbo(size=size)
            setattr(self, attr, fbo)

        fbo.clear()
        with fbo:
            ClearColor(0, 0, 0, 1)
            ClearBuffers()

        fbo.add(screen.canvas)
        fbo.draw()
        return fbo

    def add_screen(self, screen):
        self.screen_in.pos = self.screen_out.pos
        self.screen_in.size = self.screen_out.size
        self.manager.real_remove_widget(self.screen_out)

        print '-----------'
        print 'add_screen', screen, screen.canvas
        print 'screen_in', self.screen_in, self.screen_in.parent
        print 'screen_out', self.screen_out, self.screen_out.parent
        print '-----------'
        self.fbo_in = self.make_screen_fbo(self.screen_in, mode='in')
        self.fbo_out = self.make_screen_fbo(self.screen_out, mode='out')
        self.manager.canvas.add(self.fbo_in)
        self.manager.canvas.add(self.fbo_out)

        self.canvas = Canvas()
        self.c_front = RenderContext()
        self.c_front.shader.source = join(curdir, 'front.glsl')
        self.c_back = RenderContext()
        self.c_back.shader.source = join(curdir, 'back.glsl')
        self.c_backshadow = RenderContext()
        self.c_backshadow.shader.source = join(curdir, 'backshadow.glsl')
        self.canvas.add(self.c_front)
        self.canvas.add(self.c_back)
        self.canvas.add(self.c_backshadow)

        with self.canvas.before:
            Color(1, 1, 1)
            Rectangle(
                size=self.fbo_in.size,
                texture=self.fbo_in.texture)
            Callback(self._enter_3d)
        self._build_mesh(self.fbo_in.size)
        with self.canvas.after:
            Callback(self._leave_3d)

        self.manager.canvas.add(self.canvas)
        self.on_progress(0)

    def remove_screen(self, screen):
        self.manager.canvas.remove(self.fbo_in)
        self.manager.canvas.remove(self.fbo_out)
        self.manager.canvas.remove(self.canvas)
        self.manager.real_add_widget(self.screen_in)

    def on_progress(self, t):
        d = 0.8
        if t < d:
            dt = t / d
            self.cy_dir = funcLinear(AnimationTransition.out_circ(dt), 0, 1.55)
        else:
            self.cy_dir = 1.5
        self.cy_x = funcLinear(t, self.screen_in.width, -self.screen_in.width / 2.0)
        self.update_glsl()

    def update_glsl(self, *largs):
        size = self.manager.size
        proj = Matrix().view_clip(0, size[0], 0, size[1], -1000, 1000, 0)
        self.c_front['projection_mat'] = proj
        self.c_front['cylinder_position'] = map(float, (self.cy_x, self.cy_y))
        self.c_front['cylinder_direction'] = (cos(self.cy_dir), sin(self.cy_dir))
        self.c_front['cylinder_radius'] = float(self.cy_radius)
        self.c_front['texture1'] = 1

        for key in ('projection_mat', 'cylinder_position', 'cylinder_radius',
                'cylinder_direction', 'texture1'):
            self.c_back[key] = self.c_front[key]
            self.c_backshadow[key] = self.c_front[key]

    def _enter_3d(self, *args):
        glEnable(GL_DEPTH_TEST)
        glEnable(GL_CULL_FACE)

    def _leave_3d(self, *args):
        glDisable(GL_DEPTH_TEST)
        glDisable(GL_CULL_FACE)

    def _build_mesh(self, size):
        m = TILE
        width, height = map(int, size)
        step_width = int(width / (width / m))
        step_height = int(height / (height / m))
        vertices = []
        indices = []
        indices_back = []
        fw = float(width)
        fh = float(height)

        # create all the vertices
        for y in xrange(0, height + step_height, step_height):
            for x in xrange(0, width + step_width, step_width):
                vertices += [x, y, 0, x / fw, y / fh]

        # trace a triangles mesh
        mx = 1 + width / step_width
        my = 1 + height / step_height

        self.vertex_format = [
            ('vPosition', 3, 'float'),
            ('vTexCoords0', 2, 'float')]

        mode = 'line_loop' if DEBUG else 'triangles'
        for x in xrange(mx - 1):
            for y in xrange(my - 1):
                i = y * mx + x
                indices += [i, i + 1, i + 1 + mx,
                            i, i + 1 + mx, i + mx]
                indices_back += [i, i + 1 + mx, i + 1,
                            i, i + mx, i + 1 + mx]

        fbo_out_texture = None if DEBUG else self.fbo_out.texture
        self.g_mesh = Mesh(vertices=vertices, indices=indices,
                mode=mode, texture=fbo_out_texture, fmt=self.vertex_format)
        self.g_mesh_back = Mesh(vertices=vertices, indices=indices_back,
                mode=mode, texture=fbo_out_texture, fmt=self.vertex_format)
        self.o_vertices = vertices
        print 'vertices', len(vertices)
        print 'indices', len(indices)
        print 'indices_back', len(indices_back)

        self.c_front.add(BindTexture(source=join(curdir, 'frontshadow.png'), index=1))
        self.c_front.add(self.g_mesh)
        self.c_backshadow.add(Rectangle(size=size))
        self.c_back.add(BindTexture(source=join(curdir, 'backshadow.png'), index=1))
        self.c_back.add(self.g_mesh_back)
示例#59
0
文件: __init__.py 项目: arasbm/kivy
class WindowBase(EventDispatcher):
    '''WindowBase is a abstract window widget, for any window implementation.

    .. warning::

        The parameters are not working in normal case. Because at import, Kivy
        create a default OpenGL window, to add the ability to use OpenGL
        directives, texture creation.. before creating Window.
        If you don't like this behavior, you can include before the very first
        import of Kivy ::

            import os
            os.environ['KIVY_SHADOW'] = '0'

        This will forbid Kivy to create the default window !


    :Parameters:
        `fullscreen`: bool
            Make window as fullscreen
        `width`: int
            Width of window
        `height`: int
            Height of window

    :Events:
        `on_motion`: etype, motionevent
            Fired when a new :class:`~kivy.input.motionevent.MotionEvent` is
            dispatched
        `on_touch_down`:
            Fired when a new touch appear
        `on_touch_move`:
            Fired when an existing touch is moved
        `on_touch_down`:
            Fired when an existing touch disapear
        `on_draw`:
            Fired when the :class:`Window` is beeing drawed
        `on_flip`:
            Fired when the :class:`Window` GL surface is beeing flipped
        `on_rotate`: rotation
            Fired when the :class:`Window` is beeing rotated
        `on_close`:
            Fired when the :class:`Window` is closed
        `on_keyboard`: key, scancode, unicode
            Fired when the keyboard is in action
        `on_key_down`: key, scancode, unicode
            Fired when a key is down
        `on_key_up`: key, scancode, unicode
            Fired when a key is up
    '''

    __instance = None
    __initialized = False

    def __new__(cls, **kwargs):
        if cls.__instance is None:
            cls.__instance = EventDispatcher.__new__(cls)
        return cls.__instance

    def __init__(self, **kwargs):

        kwargs.setdefault('force', False)
        kwargs.setdefault('config', None)

        # don't init window 2 times,
        # except if force is specified
        if self.__initialized and not kwargs.get('force'):
            return

        super(WindowBase, self).__init__()

        # init privates
        self._modifiers = []
        self._size = (0, 0)
        self._rotation = 0
        self._clearcolor = [0, 0, 0, 0]

        # event subsystem
        self.register_event_type('on_draw')
        self.register_event_type('on_flip')
        self.register_event_type('on_rotate')
        self.register_event_type('on_resize')
        self.register_event_type('on_close')
        self.register_event_type('on_motion')
        self.register_event_type('on_touch_down')
        self.register_event_type('on_touch_move')
        self.register_event_type('on_touch_up')
        self.register_event_type('on_mouse_down')
        self.register_event_type('on_mouse_move')
        self.register_event_type('on_mouse_up')
        self.register_event_type('on_keyboard')
        self.register_event_type('on_key_down')
        self.register_event_type('on_key_up')

        self.children = []
        self.parent = self
        #self.visible = True

        # add view
        if 'view' in kwargs:
            self.add_widget(kwargs.get('view'))

        # get window params, user options before config option
        params = {}

        if 'fullscreen' in kwargs:
            params['fullscreen'] = kwargs.get('fullscreen')
        else:
            params['fullscreen'] = Config.get('graphics', 'fullscreen')
            if params['fullscreen'] not in ('auto', 'fake'):
                params['fullscreen'] = params['fullscreen'].lower() in \
                    ('true', '1', 'yes', 'yup')

        if 'width' in kwargs:
            params['width'] = kwargs.get('width')
        else:
            params['width'] = Config.getint('graphics', 'width')

        if 'height' in kwargs:
            params['height'] = kwargs.get('height')
        else:
            params['height'] = Config.getint('graphics', 'height')

        if 'rotation' in kwargs:
            params['rotation'] = kwargs.get('rotation')
        else:
            params['rotation'] = Config.getint('graphics', 'rotation')

        params['position'] = Config.get(
            'graphics', 'position', 'auto')
        if 'top' in kwargs:
            params['position'] = 'custom'
            params['top'] = kwargs.get('top')
        else:
            params['top'] = Config.getint('graphics', 'top')

        if 'left' in kwargs:
            params['position'] = 'custom'
            params['left'] = kwargs.get('left')
        else:
            params['left'] = Config.getint('graphics', 'left')

        # before creating the window
        import kivy.core.gl

        # configure the window
        self.params = params
        self.create_window()

        # attach modules + listener event
        Modules.register_window(self)
        EventLoop.set_window(self)
        EventLoop.add_event_listener(self)

        # mark as initialized
        self.__initialized = True

    def toggle_fullscreen(self):
        '''Toggle fullscreen on window'''
        pass

    def close(self):
        '''Close the window'''
        pass

    def create_window(self):
        '''Will create the main window and configure it.

        .. warning::
            This method is called automatically at runtime. If you call it, it
            will recreate a RenderContext and Canvas. This mean you'll have a
            new graphics tree, and the old one will be unusable.

            This method exist to permit the creation of a new OpenGL context
            AFTER closing the first one. (Like using runTouchApp() and
            stopTouchApp()).

            This method have been only tested in unittest environment, and will
            be not suitable for Applications.

            Again, don't use this method unless you know exactly what you are
            doing !
        '''
        from kivy.core.gl import init_gl
        init_gl()

        # create the render context and canvas
        from kivy.graphics import RenderContext, Canvas
        self.render_context = RenderContext()
        self.canvas = Canvas()
        self.render_context.add(self.canvas)

    def on_flip(self):
        '''Flip between buffers (event)'''
        self.flip()

    def flip(self):
        '''Flip between buffers'''
        pass

    def _get_modifiers(self):
        return self._modifiers
    modifiers = property(_get_modifiers)

    def _get_size(self):
        r = self._rotation
        w, h = self._size
        if r == 0 or r == 180:
            return w, h
        return h, w

    def _set_size(self, size):
        if super(WindowBase, self)._set_size(size):
            Logger.debug('Window: Resize window to %s' % str(self.size))
            self.dispatch('on_resize', *size)
            return True
        return False

    size = property(_get_size, _set_size,
        doc='''Rotated size of the window''')

    def _get_clearcolor(self):
        return self._clearcolor

    def _set_clearcolor(self, value):
        if value is not None:
            if type(value) not in (list, tuple):
                raise Exception('Clearcolor must be a list or tuple')
            if len(value) != 4:
                raise Exception('Clearcolor must contain 4 values')
        self._clearcolor = value

    clearcolor = property(_get_clearcolor, _set_clearcolor,
        doc='''Color used to clear window::

            from kivy.core.window import Window

            # red background color
            Window.clearcolor = (1, 0, 0, 1)

            # don't clear background at all
            Window.clearcolor = None

        ''')

    # make some property read-only
    @property
    def width(self):
        '''Rotated window width'''
        r = self._rotation
        if r == 0 or r == 180:
            return self._size[0]
        return self._size[1]

    @property
    def height(self):
        '''Rotated window height'''
        r = self._rotation
        if r == 0 or r == 180:
            return self._size[1]
        return self._size[0]

    @property
    def center(self):
        '''Rotated window center'''
        return self.width / 2., self.height / 2.

    def add_widget(self, widget):
        '''Add a widget on window'''
        self.children.append(widget)
        widget.parent = self
        self.canvas.add(widget.canvas)
        self.update_childsize([widget])

    def remove_widget(self, widget):
        '''Remove a widget from window
        '''
        if not widget in self.children:
            return
        self.children.remove(widget)
        self.canvas.remove(widget.canvas)
        widget.parent = None

    def clear(self):
        '''Clear the window with background color'''
        # XXX FIXME use late binding
        from kivy.graphics.opengl import glClearColor, glClear, \
            GL_COLOR_BUFFER_BIT, GL_DEPTH_BUFFER_BIT
        cc = self._clearcolor
        if cc is not None:
            glClearColor(*cc)
            glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)

    def to_widget(self, x, y, initial=True, relative=False):
        return (x, y)

    def to_window(self, x, y, initial=True, relative=False):
        return (x, y)

    def get_root_window(self):
        return self

    def get_parent_window(self):
        return self

    def get_parent_layout(self):
        return None

    def on_draw(self):
        self.clear()
        self.render_context.draw()

    def on_motion(self, etype, me):
        '''Event called when a Motion Event is received.

        :Parameters:
            `etype`: str
                One of 'begin', 'update', 'end'
            `me`: :class:`~kivy.input.motionevent.MotionEvent`
                Motion Event currently dispatched
        '''
        if me.is_touch:
            if etype == 'begin':
                self.dispatch('on_touch_down', me)
            elif etype == 'update':
                self.dispatch('on_touch_move', me)
            elif etype == 'end':
                self.dispatch('on_touch_up', me)

    def on_touch_down(self, touch):
        '''Event called when a touch is down
        '''
        w, h = self.system_size
        touch.scale_for_screen(w, h, rotation=self._rotation)
        for w in self.children[:]:
            if w.dispatch('on_touch_down', touch):
                return True

    def on_touch_move(self, touch):
        '''Event called when a touch move
        '''
        w, h = self.system_size
        touch.scale_for_screen(w, h, rotation=self._rotation)
        for w in self.children[:]:
            if w.dispatch('on_touch_move', touch):
                return True

    def on_touch_up(self, touch):
        '''Event called when a touch up
        '''
        w, h = self.system_size
        touch.scale_for_screen(w, h, rotation=self._rotation)
        for w in self.children[:]:
            if w.dispatch('on_touch_up', touch):
                return True

    def on_resize(self, width, height):
        '''Event called when the window is resized'''
        self.update_viewport()

    def update_viewport(self):
        from kivy.graphics.opengl import glViewport
        from kivy.graphics.transformation import Matrix

        width, height = self.system_size
        w2 = width / 2.
        h2 = height / 2.

        # prepare the viewport
        glViewport(0, 0, width, height)
        projection_mat = Matrix()
        projection_mat.view_clip(0.0, width, 0.0, height, -1.0, 1.0, 0)
        self.render_context['projection_mat'] = projection_mat

        # use the rotated size.
        # XXX FIXME fix rotation
        '''
        width, height = self.size
        w2 = width / 2.
        h2 = height / 2.
        glTranslatef(-w2, -h2, -500)

        # set the model view
        glMatrixMode(GL_MODELVIEW)
        glLoadIdentity()
        glTranslatef(w2, h2, 0)
        glRotatef(self._rotation, 0, 0, 1)
        glTranslatef(-w2, -h2, 0)
        '''

        self.update_childsize()

    def update_childsize(self, childs=None):
        width, height = self.system_size
        if childs is None:
            childs = self.children
        for w in childs:
            shw, shh = w.size_hint
            if shw and shh:
                w.size = shw * width, shh * height
            elif shw:
                w.width = shw * width
            elif shh:
                w.height = shh * height
            for key, value in w.pos_hint.iteritems():
                if key == 'x':
                    w.x = value * width
                elif key == 'right':
                    w.right = value * width
                elif key == 'y':
                    w.y = value * height
                elif key == 'top':
                    w.top = value * height

    def _get_rotation(self):
        return self._rotation

    def _set_rotation(self, x):
        x = int(x % 360)
        if x == self._rotation:
            return
        if x not in (0, 90, 180, 270):
            raise ValueError('can rotate only 0,90,180,270 degrees')
        self._rotation = x
        self.dispatch('on_resize', *self.size)
        self.dispatch('on_rotate', x)

    rotation = property(_get_rotation, _set_rotation,
            'Get/set the window content rotation. Can be one of '
            '0, 90, 180, 270 degrees.')

    @property
    def system_size(self):
        '''Real size of the window, without taking care of the rotation
        '''
        return self._size

    def screenshot(self, name='screenshot%(counter)04d.jpg'):
        '''Save the actual displayed image in a file
        '''
        from os.path import join, exists
        from os import getcwd
        i = 0
        path = None
        while True:
            i += 1
            path = join(getcwd(), name % {'counter': i})
            if not exists(path):
                break
        return path

    def on_rotate(self, rotation):
        '''Event called when the screen have been rotated
        '''
        pass

    def on_close(self, *largs):
        '''Event called when the window is closed'''
        Modules.unregister_window(self)
        EventLoop.remove_event_listener(self)

    def on_mouse_down(self, x, y, button, modifiers):
        '''Event called when mouse is in action (press/release)'''
        pass

    def on_mouse_move(self, x, y, modifiers):
        '''Event called when mouse is moving, with buttons pressed'''
        pass

    def on_mouse_up(self, x, y, button, modifiers):
        '''Event called when mouse is moving, with buttons pressed'''
        pass

    def on_keyboard(self, key, scancode=None, unicode=None):
        '''Event called when keyboard is in action

        .. warning::
            Some providers can skip `scancode` or `unicode` !!
        '''
        pass

    def on_key_down(self, key, scancode=None, unicode=None):
        '''Event called when a key is down (same arguments as on_keyboard)'''
        pass

    def on_key_up(self, key, scancode=None, unicode=None):
        '''Event called when a key is up (same arguments as on_keyboard)'''
        pass
示例#60
0
文件: __init__.py 项目: jchome/kivy
class WindowBase(EventDispatcher):
    """WindowBase is an abstract window widget for any window implementation.

    :Parameters:
        `fullscreen`: str, one of ('0', '1', 'auto', 'fake')
            Make the window fullscreen. Check the
            :mod:`~kivy.config` documentation for a
            more detailed explanation on the values.
        `width`: int
            Width of the window.
        `height`: int
            Height of the window.

    :Events:
        `on_motion`: etype, motionevent
            Fired when a new :class:`~kivy.input.motionevent.MotionEvent` is
            dispatched
        `on_touch_down`:
            Fired when a new touch event is initiated.
        `on_touch_move`:
            Fired when an existing touch event changes location.
        `on_touch_up`:
            Fired when an existing touch event is terminated.
        `on_draw`:
            Fired when the :class:`Window` is being drawn.
        `on_flip`:
            Fired when the :class:`Window` GL surface is being flipped.
        `on_rotate`: rotation
            Fired when the :class:`Window` is being rotated.
        `on_close`:
            Fired when the :class:`Window` is closed.
        `on_request_close`:
            Fired when the event loop wants to close the window, or if the
            escape key is pressed and `exit_on_escape` is `True`. If a function
            bound to this event returns `True`, the window will not be closed.
            If the the event is triggered because of the keyboard escape key,
            the keyword argument `source` is dispatched along with a value of
            `keyboard` to the bound functions.
        `on_keyboard`: key, scancode, codepoint, modifier
            Fired when the keyboard is used for input.

            .. versionchanged:: 1.3.0
                The *unicode* parameter has been deprecated in favor of
                codepoint, and will be removed completely in future versions.

        `on_key_down`: key, scancode, codepoint
            Fired when a key pressed.

            .. versionchanged:: 1.3.0
                The *unicode* parameter has been deprecated in favor of
                codepoint, and will be removed completely in future versions.

        `on_key_up`: key, scancode, codepoint
            Fired when a key is released.

            .. versionchanged:: 1.3.0
                The *unicode* parameter has be deprecated in favor of
                codepoint, and will be removed completely in future versions.

        `on_dropfile`: str
            Fired when a file is dropped on the application.

        .. versionchanged:: 1.8.1
            `on_request_close` has been added.
    """

    __instance = None
    __initialized = False

    # private properties
    _size = ListProperty([0, 0])
    _modifiers = ListProperty([])
    _rotation = NumericProperty(0)
    _clearcolor = ObjectProperty([0, 0, 0, 1])

    children = ListProperty([])
    """List of the children of this window.

    :attr:`children` is a :class:`~kivy.properties.ListProperty` instance and
    defaults to an empty list.

    Use :meth:`add_widget` and :meth:`remove_widget` to manipulate the list of
    children. Don't manipulate the list directly unless you know what you are
    doing.
    """

    parent = ObjectProperty(None, allownone=True)
    """Parent of this window.

    :attr:`parent` is a :class:`~kivy.properties.ObjectProperty` instance and
    defaults to None. When created, the parent is set to the window itself.
    You must take care of it if you are doing a recursive check.
    """

    icon = StringProperty()

    def _get_modifiers(self):
        return self._modifiers

    modifiers = AliasProperty(_get_modifiers, None)
    """List of keyboard modifiers currently active.
    """

    def _get_size(self):
        r = self._rotation
        w, h = self._size
        if self.softinput_mode == "resize":
            h -= self.keyboard_height
        if r in (0, 180):
            return w, h
        return h, w

    def _set_size(self, size):
        if self._size != size:
            r = self._rotation
            if r in (0, 180):
                self._size = size
            else:
                self._size = size[1], size[0]

            self.dispatch("on_resize", *size)
            return True
        else:
            return False

    size = AliasProperty(_get_size, _set_size, bind=("_size",))
    """Get the rotated size of the window. If :attr:`rotation` is set, then the
    size will change to reflect the rotation.
    """

    def _get_clearcolor(self):
        return self._clearcolor

    def _set_clearcolor(self, value):
        if value is not None:
            if type(value) not in (list, tuple):
                raise Exception("Clearcolor must be a list or tuple")
            if len(value) != 4:
                raise Exception("Clearcolor must contain 4 values")
        self._clearcolor = value

    clearcolor = AliasProperty(_get_clearcolor, _set_clearcolor, bind=("_clearcolor",))
    """Color used to clear the window.

    ::

        from kivy.core.window import Window

        # red background color
        Window.clearcolor = (1, 0, 0, 1)

        # don't clear background at all
        Window.clearcolor = None

    .. versionchanged:: 1.7.2
        The clearcolor default value is now: (0, 0, 0, 1).

    """

    # make some property read-only
    def _get_width(self):
        r = self._rotation
        if r == 0 or r == 180:
            return self._size[0]
        return self._size[1]

    width = AliasProperty(_get_width, None, bind=("_rotation", "_size"))
    """Rotated window width.

    :attr:`width` is a read-only :class:`~kivy.properties.AliasProperty`.
    """

    def _get_height(self):
        """Rotated window height"""
        r = self._rotation
        if r == 0 or r == 180:
            return self._size[1]
        return self._size[0]

    height = AliasProperty(_get_height, None, bind=("_rotation", "_size"))
    """Rotated window height.

    :attr:`height` is a read-only :class:`~kivy.properties.AliasProperty`.
    """

    def _get_center(self):
        return self.width / 2.0, self.height / 2.0

    center = AliasProperty(_get_center, None, bind=("width", "height"))
    """Center of the rotated window.

    :attr:`center` is a :class:`~kivy.properties.AliasProperty`.
    """

    def _get_rotation(self):
        return self._rotation

    def _set_rotation(self, x):
        x = int(x % 360)
        if x == self._rotation:
            return
        if x not in (0, 90, 180, 270):
            raise ValueError("can rotate only 0, 90, 180, 270 degrees")
        self._rotation = x
        if self.initialized is False:
            return
        self.dispatch("on_resize", *self.size)
        self.dispatch("on_rotate", x)

    rotation = AliasProperty(_get_rotation, _set_rotation, bind=("_rotation",))
    """Get/set the window content rotation. Can be one of 0, 90, 180, 270
    degrees.
    """

    softinput_mode = OptionProperty("", options=("", "pan", "scale", "resize"))
    """This specifies the behavior of window contents on display of soft
    keyboard on mobile platform. Can be one of '', 'pan', 'scale', 'resize'.
    
    When '' The main window is left as it is allowing the user to use
    :attr:`keyboard_height` to manage the window contents the way they want.
    
    when 'pan' The main window pans moving the bottom part of the window to be
    always on top of the keyboard.
    
    when 'resize' The window is resized and the contents scaled to fit the
    remaining space.
    
    ..versionadded::1.8.1

    :attr:`softinput_mode` is a :class:`OptionProperty` defaults to None.

    """

    _keyboard_changed = BooleanProperty(False)

    def _upd_kbd_height(self, *kargs):
        self._keyboard_changed = not self._keyboard_changed

    def _get_ios_kheight(self):
        return 0

    def _get_android_kheight(self):
        global android
        if not android:
            import android
        return android.get_keyboard_height()

    def _get_kheight(self):
        if platform == "android":
            return self._get_android_kheight()
        if platform == "ios":
            return self._get_ios_kheight()
        return 0

    keyboard_height = AliasProperty(_get_kheight, None, bind=("_keyboard_changed",))
    """Rerturns the height of the softkeyboard/IME on mobile platforms.
    Will return 0 if not on mobile platform or if IME is not active.

    ..versionadded:: 1.8.1

    :attr:`keyboard_height` is a read-only :class:`AliasProperty` defaults to 0.
    """

    def _set_system_size(self, size):
        self._size = size

    def _get_system_size(self):
        if self.softinput_mode == "resize":
            return self._size[0], self._size[1] - self.keyboard_height
        return self._size

    system_size = AliasProperty(_get_system_size, _set_system_size, bind=("_size",))
    """Real size of the window ignoring rotation.
    """

    fullscreen = OptionProperty(False, options=(True, False, "auto", "fake"))
    """This property sets the fullscreen mode of the window. Available options
    are: True, False, 'auto', 'fake'. Check the :mod:`~kivy.config`
    documentation for a more detailed explanation on the values.

    .. versionadded:: 1.2.0
    """

    mouse_pos = ObjectProperty([0, 0])
    """2d position of the mouse within the window.

    .. versionadded:: 1.2.0
    """

    top = NumericProperty(None, allownone=True)
    left = NumericProperty(None, allownone=True)
    position = OptionProperty("auto", options=["auto", "custom"])
    render_context = ObjectProperty(None)
    canvas = ObjectProperty(None)
    title = StringProperty("Kivy")

    __events__ = (
        "on_draw",
        "on_flip",
        "on_rotate",
        "on_resize",
        "on_close",
        "on_motion",
        "on_touch_down",
        "on_touch_move",
        "on_touch_up",
        "on_mouse_down",
        "on_mouse_move",
        "on_mouse_up",
        "on_keyboard",
        "on_key_down",
        "on_key_up",
        "on_dropfile",
        "on_request_close",
    )

    def __new__(cls, **kwargs):
        if cls.__instance is None:
            cls.__instance = EventDispatcher.__new__(cls)
        return cls.__instance

    def __init__(self, **kwargs):

        kwargs.setdefault("force", False)

        # don't init window 2 times,
        # except if force is specified
        if WindowBase.__instance is not None and not kwargs.get("force"):
            return
        self.initialized = False

        # create a trigger for update/create the window when one of window
        # property changes
        self.trigger_create_window = Clock.create_trigger(self.create_window, -1)

        # Create a trigger for updating the keyboard height
        self.trigger_keyboard_height = Clock.create_trigger(self._upd_kbd_height, 0.5)

        # set the default window parameter according to the configuration
        if "fullscreen" not in kwargs:
            fullscreen = Config.get("graphics", "fullscreen")
            if fullscreen not in ("auto", "fake"):
                fullscreen = fullscreen.lower() in ("true", "1", "yes", "yup")
            kwargs["fullscreen"] = fullscreen
        if "width" not in kwargs:
            kwargs["width"] = Config.getint("graphics", "width")
        if "height" not in kwargs:
            kwargs["height"] = Config.getint("graphics", "height")
        if "rotation" not in kwargs:
            kwargs["rotation"] = Config.getint("graphics", "rotation")
        if "position" not in kwargs:
            kwargs["position"] = Config.getdefault("graphics", "position", "auto")
        if "top" in kwargs:
            kwargs["position"] = "custom"
            kwargs["top"] = kwargs["top"]
        else:
            kwargs["top"] = Config.getint("graphics", "top")
        if "left" in kwargs:
            kwargs["position"] = "custom"
            kwargs["left"] = kwargs["left"]
        else:
            kwargs["left"] = Config.getint("graphics", "left")
        kwargs["_size"] = (kwargs.pop("width"), kwargs.pop("height"))

        super(WindowBase, self).__init__(**kwargs)

        # bind all the properties that need to recreate the window
        for prop in ("fullscreen", "position", "top", "left", "_size", "system_size"):
            self.bind(**{prop: self.trigger_create_window})

        self.bind(size=self.trigger_keyboard_height, rotation=self.trigger_keyboard_height)

        self.bind(softinput_mode=lambda *dt: self.update_viewport(), keyboard_height=lambda *dt: self.update_viewport())

        # init privates
        self._system_keyboard = Keyboard(window=self)
        self._keyboards = {"system": self._system_keyboard}
        self._vkeyboard_cls = None

        self.children = []
        self.parent = self

        # before creating the window
        import kivy.core.gl  # NOQA

        # configure the window
        self.create_window()

        # attach modules + listener event
        EventLoop.set_window(self)
        Modules.register_window(self)
        EventLoop.add_event_listener(self)

        # manage keyboard(s)
        self.configure_keyboards()

        # assign the default context of the widget creation
        if not hasattr(self, "_context"):
            self._context = get_current_context()

        # mark as initialized
        self.initialized = True

    def toggle_fullscreen(self):
        """Toggle fullscreen on window"""
        pass

    def close(self):
        """Close the window"""
        pass

    def create_window(self, *largs):
        """Will create the main window and configure it.

        .. warning::
            This method is called automatically at runtime. If you call it, it
            will recreate a RenderContext and Canvas. This means you'll have a
            new graphics tree, and the old one will be unusable.

            This method exist to permit the creation of a new OpenGL context
            AFTER closing the first one. (Like using runTouchApp() and
            stopTouchApp()).

            This method has only been tested in a unittest environment and
            is not suitable for Applications.

            Again, don't use this method unless you know exactly what you are
            doing!
        """
        # just to be sure, if the trigger is set, and if this method is
        # manually called, unset the trigger
        Clock.unschedule(self.create_window)

        if not self.initialized:
            from kivy.core.gl import init_gl

            init_gl()

            # create the render context and canvas, only the first time.
            from kivy.graphics import RenderContext, Canvas

            self.render_context = RenderContext()
            self.canvas = Canvas()
            self.render_context.add(self.canvas)

        else:
            # if we get initialized more than once, then reload opengl state
            # after the second time.
            # XXX check how it's working on embed platform.
            if platform == "linux":
                # on linux, it's safe for just sending a resize.
                self.dispatch("on_resize", *self.system_size)

            else:
                # on other platform, window are recreated, we need to reload.
                from kivy.graphics.context import get_context

                get_context().reload()
                Clock.schedule_once(lambda x: self.canvas.ask_update(), 0)
                self.dispatch("on_resize", *self.system_size)

        # ensure the gl viewport is correct
        self.update_viewport()

    def on_flip(self):
        """Flip between buffers (event)"""
        self.flip()

    def flip(self):
        """Flip between buffers"""
        pass

    def _update_childsize(self, instance, value):
        self.update_childsize([instance])

    def add_widget(self, widget):
        """Add a widget to a window"""
        widget.parent = self
        self.children.insert(0, widget)
        self.canvas.add(widget.canvas)
        self.update_childsize([widget])
        widget.bind(
            pos_hint=self._update_childsize,
            size_hint=self._update_childsize,
            size=self._update_childsize,
            pos=self._update_childsize,
        )

    def remove_widget(self, widget):
        """Remove a widget from a window
        """
        if not widget in self.children:
            return
        self.children.remove(widget)
        self.canvas.remove(widget.canvas)
        widget.parent = None
        widget.unbind(
            pos_hint=self._update_childsize,
            size_hint=self._update_childsize,
            size=self._update_childsize,
            pos=self._update_childsize,
        )

    def clear(self):
        """Clear the window with the background color"""
        # XXX FIXME use late binding
        from kivy.graphics.opengl import (
            glClearColor,
            glClear,
            GL_COLOR_BUFFER_BIT,
            GL_DEPTH_BUFFER_BIT,
            GL_STENCIL_BUFFER_BIT,
        )

        cc = self._clearcolor
        if cc is not None:
            glClearColor(*cc)
            glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT)

    def set_title(self, title):
        """Set the window title.

        .. versionadded:: 1.0.5
        """
        self.title = title

    def set_icon(self, filename):
        """Set the icon of the window.

        .. versionadded:: 1.0.5
        """
        self.icon = filename

    def to_widget(self, x, y, initial=True, relative=False):
        return (x, y)

    def to_window(self, x, y, initial=True, relative=False):
        return (x, y)

    def get_root_window(self):
        return self

    def get_parent_window(self):
        return self

    def get_parent_layout(self):
        return None

    def on_draw(self):
        self.clear()
        self.render_context.draw()

    def on_motion(self, etype, me):
        """Event called when a Motion Event is received.

        :Parameters:
            `etype`: str
                One of 'begin', 'update', 'end'
            `me`: :class:`~kivy.input.motionevent.MotionEvent`
                The Motion Event currently dispatched.
        """
        if me.is_touch:
            w, h = self.system_size
            me.scale_for_screen(w, h, rotation=self._rotation, smode=self.softinput_mode, kheight=self.keyboard_height)
            if etype == "begin":
                self.dispatch("on_touch_down", me)
            elif etype == "update":
                self.dispatch("on_touch_move", me)
            elif etype == "end":
                self.dispatch("on_touch_up", me)

    def on_touch_down(self, touch):
        """Event called when a touch down event is initiated.

        .. versionchanged:: 1.8.1
            The touch `pos` is now transformed to window coordinates before
            this method is called. Before, the touch `pos` coordinate would be
            `(0, 0)` when this method was called.
        """
        for w in self.children[:]:
            if w.dispatch("on_touch_down", touch):
                return True

    def on_touch_move(self, touch):
        """Event called when a touch event moves (changes location).

        .. versionchanged:: 1.8.1
            The touch `pos` is now transformed to window coordinates before
            this method is called. Before, the touch `pos` coordinate would be
            `(0, 0)` when this method was called.
        """
        for w in self.children[:]:
            if w.dispatch("on_touch_move", touch):
                return True

    def on_touch_up(self, touch):
        """Event called when a touch event is released (terminated).

        .. versionchanged:: 1.8.1
            The touch `pos` is now transformed to window coordinates before
            this method is called. Before, the touch `pos` coordinate would be
            `(0, 0)` when this method was called.
        """
        for w in self.children[:]:
            if w.dispatch("on_touch_up", touch):
                return True

    def on_resize(self, width, height):
        """Event called when the window is resized."""
        self.update_viewport()

    def update_viewport(self):
        from kivy.graphics.opengl import glViewport
        from kivy.graphics.transformation import Matrix
        from math import radians

        w, h = self.system_size

        smode = self.softinput_mode
        kheight = self.keyboard_height

        w2, h2 = w / 2.0, h / 2.0
        r = radians(self.rotation)

        x, y = 0, 0
        _h = h
        if smode:
            y = kheight
        if smode == "scale":
            _h -= kheight

        # prepare the viewport
        glViewport(x, y, w, _h)

        # do projection matrix
        projection_mat = Matrix()
        projection_mat.view_clip(0.0, w, 0.0, h, -1.0, 1.0, 0)
        self.render_context["projection_mat"] = projection_mat

        # do modelview matrix
        modelview_mat = Matrix().translate(w2, h2, 0)
        modelview_mat = modelview_mat.multiply(Matrix().rotate(r, 0, 0, 1))

        w, h = self.size
        w2, h2 = w / 2.0, h / 2.0
        modelview_mat = modelview_mat.multiply(Matrix().translate(-w2, -h2, 0))
        self.render_context["modelview_mat"] = modelview_mat

        # redraw canvas
        self.canvas.ask_update()

        # and update childs
        self.update_childsize()

    def update_childsize(self, childs=None):
        width, height = self.size
        if childs is None:
            childs = self.children
        for w in childs:
            shw, shh = w.size_hint
            if shw and shh:
                w.size = shw * width, shh * height
            elif shw:
                w.width = shw * width
            elif shh:
                w.height = shh * height
            for key, value in w.pos_hint.items():
                if key == "x":
                    w.x = value * width
                elif key == "right":
                    w.right = value * width
                elif key == "y":
                    w.y = value * height
                elif key == "top":
                    w.top = value * height
                elif key == "center_x":
                    w.center_x = value * width
                elif key == "center_y":
                    w.center_y = value * height

    def screenshot(self, name="screenshot{:04d}.png"):
        """Save the actual displayed image in a file
        """
        i = 0
        path = None
        if name != "screenshot{:04d}.png":
            _ext = name.split(".")[-1]
            name = "".join((name[: -(len(_ext) + 1)], "{:04d}.", _ext))
        while True:
            i += 1
            path = join(getcwd(), name.format(i))
            if not exists(path):
                break
        return path

    def on_rotate(self, rotation):
        """Event called when the screen has been rotated.
        """
        pass

    def on_close(self, *largs):
        """Event called when the window is closed"""
        Modules.unregister_window(self)
        EventLoop.remove_event_listener(self)

    def on_request_close(self, *largs, **kwargs):
        """Event called before we close the window. If a bound function returns
        `True`, the window will not be closed. If the the event is triggered
        because of the keyboard escape key, the keyword argument `source` is
        dispatched along with a value of `keyboard` to the bound functions.

        .. warning::
            When the bound function returns True the window will not be closed,
            so use with care because the user would not be able to close the
            program, even if the red X is clicked.
        """
        pass

    def on_mouse_down(self, x, y, button, modifiers):
        """Event called when the mouse is used (pressed/released)"""
        pass

    def on_mouse_move(self, x, y, modifiers):
        """Event called when the mouse is moved with buttons pressed"""
        pass

    def on_mouse_up(self, x, y, button, modifiers):
        """Event called when the mouse is moved with buttons pressed"""
        pass

    def on_keyboard(self, key, scancode=None, codepoint=None, modifier=None, **kwargs):
        """Event called when keyboard is used.

        .. warning::
            Some providers may omit `scancode`, `codepoint` and/or `modifier`!
        """
        if "unicode" in kwargs:
            Logger.warning(
                "The use of the unicode parameter is deprecated, "
                "and will be removed in future versions. Use "
                "codepoint instead, which has identical "
                "semantics."
            )

        # Quit if user presses ESC or the typical OSX shortcuts CMD+q or CMD+w
        # TODO If just CMD+w is pressed, only the window should be closed.
        is_osx = platform == "darwin"
        if self.on_keyboard.exit_on_escape:
            if key == 27 or all([is_osx, key in [113, 119], modifier == 1024]):
                if not self.dispatch("on_request_close", source="keyboard"):
                    stopTouchApp()
                    self.close()
                    return True

    if Config:
        on_keyboard.exit_on_escape = Config.getboolean("kivy", "exit_on_escape")

        def __exit(section, name, value):
            WindowBase.__dict__["on_keyboard"].exit_on_escape = Config.getboolean("kivy", "exit_on_escape")

        Config.add_callback(__exit, "kivy", "exit_on_escape")

    def on_key_down(self, key, scancode=None, codepoint=None, modifier=None, **kwargs):
        """Event called when a key is down (same arguments as on_keyboard)"""
        if "unicode" in kwargs:
            Logger.warning(
                "The use of the unicode parameter is deprecated, "
                "and will be removed in future versions. Use "
                "codepoint instead, which has identical "
                "semantics."
            )

    def on_key_up(self, key, scancode=None, codepoint=None, modifier=None, **kwargs):
        """Event called when a key is released (same arguments as on_keyboard)
        """
        if "unicode" in kwargs:
            Logger.warning(
                "The use of the unicode parameter is deprecated, "
                "and will be removed in future versions. Use "
                "codepoint instead, which has identical "
                "semantics."
            )

    def on_dropfile(self, filename):
        """Event called when a file is dropped on the application.

        .. warning::

            This event is currently used only on MacOSX with a patched version
            of pygame, but is left in place for further evolution (ios,
            android etc.)

        .. versionadded:: 1.2.0
        """
        pass

    @reify
    def dpi(self):
        """Return the DPI of the screen. If the implementation doesn't support
        any DPI lookup, it will just return 96.

        .. warning::

            This value is not cross-platform. Use
            :attr:`kivy.base.EventLoop.dpi` instead.
        """
        return 96.0

    def configure_keyboards(self):
        # Configure how to provide keyboards (virtual or not)

        # register system keyboard to listening keys from window
        sk = self._system_keyboard
        self.bind(on_key_down=sk._on_window_key_down, on_key_up=sk._on_window_key_up)

        # use the device's real keyboard
        self.use_syskeyboard = True

        # use the device's real keyboard
        self.allow_vkeyboard = False

        # one single vkeyboard shared between all widgets
        self.single_vkeyboard = True

        # the single vkeyboard is always sitting at the same position
        self.docked_vkeyboard = False

        # now read the configuration
        mode = Config.get("kivy", "keyboard_mode")
        if mode not in ("", "system", "dock", "multi", "systemanddock", "systemandmulti"):
            Logger.critical("Window: unknown keyboard mode %r" % mode)

        # adapt mode according to the configuration
        if mode == "system":
            self.use_syskeyboard = True
            self.allow_vkeyboard = False
            self.single_vkeyboard = True
            self.docked_vkeyboard = False
        elif mode == "dock":
            self.use_syskeyboard = False
            self.allow_vkeyboard = True
            self.single_vkeyboard = True
            self.docked_vkeyboard = True
        elif mode == "multi":
            self.use_syskeyboard = False
            self.allow_vkeyboard = True
            self.single_vkeyboard = False
            self.docked_vkeyboard = False
        elif mode == "systemanddock":
            self.use_syskeyboard = True
            self.allow_vkeyboard = True
            self.single_vkeyboard = True
            self.docked_vkeyboard = True
        elif mode == "systemandmulti":
            self.use_syskeyboard = True
            self.allow_vkeyboard = True
            self.single_vkeyboard = False
            self.docked_vkeyboard = False

        Logger.info(
            "Window: virtual keyboard %sallowed, %s, %s"
            % (
                "" if self.allow_vkeyboard else "not ",
                "single mode" if self.single_vkeyboard else "multiuser mode",
                "docked" if self.docked_vkeyboard else "not docked",
            )
        )

    def set_vkeyboard_class(self, cls):
        """.. versionadded:: 1.0.8

        Set the VKeyboard class to use. If set to None, it will use the
        :class:`kivy.uix.vkeyboard.VKeyboard`.
        """
        self._vkeyboard_cls = cls

    def release_all_keyboards(self):
        """.. versionadded:: 1.0.8

        This will ensure that no virtual keyboard / system keyboard is
        requested. All instances will be closed.
        """
        for key in list(self._keyboards.keys())[:]:
            keyboard = self._keyboards[key]
            if keyboard:
                keyboard.release()

    def request_keyboard(self, callback, target, input_type="text"):
        """.. versionadded:: 1.0.4

        Internal widget method to request the keyboard. This method is rarely
        required by the end-user as it is handled automatically by the
        :class:`~kivy.uix.textinput.TextInput`. We expose it in case you want
        to handle the keyboard manually for unique input scenarios.

        A widget can request the keyboard, indicating a callback to call
        when the keyboard is released (or taken by another widget).

        :Parameters:
            `callback`: func
                Callback that will be called when the keyboard is
                closed. This can be because somebody else requested the
                keyboard or the user closed it.
            `target`: Widget
                Attach the keyboard to the specified `target`. This should be
                the widget that requested the keyboard. Ensure you have a
                different target attached to each keyboard if you're working in
                a multi user mode.

                .. versionadded:: 1.0.8

            `input_type`: string
                Choose the type of soft keyboard to request. Can be one of
                'text', 'number', 'url', 'mail', 'datetime', 'tel', 'address'.

                .. note::

                    `input_type` is currently only honored on mobile devices.

                .. versionadded:: 1.8.0

        :Return:
            An instance of :class:`Keyboard` containing the callback, target,
            and if the configuration allows it, a
            :class:`~kivy.uix.vkeyboard.VKeyboard` instance attached as a
            *.widget* property.

        """

        # release any previous keyboard attached.
        self.release_keyboard(target)

        # if we can use virtual vkeyboard, activate it.
        if self.allow_vkeyboard:
            keyboard = None

            # late import
            global VKeyboard
            if VKeyboard is None and self._vkeyboard_cls is None:
                from kivy.uix.vkeyboard import VKeyboard

                self._vkeyboard_cls = VKeyboard

            # if the keyboard doesn't exist, create it.
            key = "single" if self.single_vkeyboard else target
            if key not in self._keyboards:
                vkeyboard = self._vkeyboard_cls()
                keyboard = Keyboard(widget=vkeyboard, window=self)
                vkeyboard.bind(on_key_down=keyboard._on_vkeyboard_key_down, on_key_up=keyboard._on_vkeyboard_key_up)
                self._keyboards[key] = keyboard
            else:
                keyboard = self._keyboards[key]

            # configure vkeyboard
            keyboard.target = keyboard.widget.target = target
            keyboard.callback = keyboard.widget.callback = callback

            # add to the window
            self.add_widget(keyboard.widget)

            # only after add, do dock mode
            keyboard.widget.docked = self.docked_vkeyboard
            keyboard.widget.setup_mode()

        else:
            # system keyboard, just register the callback.
            keyboard = self._system_keyboard
            keyboard.callback = callback
            keyboard.target = target

        # use system (hardware) keyboard according to flag
        if self.allow_vkeyboard and self.use_syskeyboard:
            self.unbind(on_key_down=keyboard._on_window_key_down, on_key_up=keyboard._on_window_key_up)
            self.bind(on_key_down=keyboard._on_window_key_down, on_key_up=keyboard._on_window_key_up)

        return keyboard

    def release_keyboard(self, target=None):
        """.. versionadded:: 1.0.4

        Internal method for the widget to release the real-keyboard. Check
        :meth:`request_keyboard` to understand how it works.
        """
        if self.allow_vkeyboard:
            key = "single" if self.single_vkeyboard else target
            if key not in self._keyboards:
                return
            keyboard = self._keyboards[key]
            callback = keyboard.callback
            if callback:
                keyboard.callback = None
                callback()
            keyboard.target = None
            self.remove_widget(keyboard.widget)
            if key != "single" and key in self._keyboards:
                del self._keyboards[key]
        elif self._system_keyboard.callback:
            # this way will prevent possible recursion.
            callback = self._system_keyboard.callback
            self._system_keyboard.callback = None
            callback()
            return True