画面の中に、ミニ画面があって、リターンで画面の切り替え。

#!/usr/bin/env ruby

require 'sdl'
require 'cairo'


class Sprite
  attr_accessor :x, :y, :alive, :enabled, :idx, :info
  attr_writer :draw, :matrix

  def initialize
    @x, @y = 0, 0
    @alive = true
    @enabled = true
    @idx = 0
    @info = {}
    @matrix = Cairo::Matrix.identity
  end

  def renew(cr)
    return if !@enabled
    cr.matrix = @matrix * Cairo::Matrix.translate(@x, @y)
    @draw[cr]
  end
end

class Phase
  attr_accessor :handles, :task

  def initialize(w, h, info=nil)
    @image = Cairo::ImageSurface.new(w, h)
    @info = info
    @sprites = []
    @handles = {}
  end

  def addSprite
    @sprites << Sprite.new
    yield(@sprites.last)
    @sprites.last
  end

  def renew(drawFlag=true)
    @task[] if @task
    if drawFlag
      cr = Cairo::Context.new(@image)
      @sprites.reject!{|obj| !obj.alive}
      @sprites.each {|obj| obj.renew(cr)}
      @image
    else
      nil
    end
  end

  def layerSort
    @sprites.sort!{|a, b| a.idx <=> b.idx}
  end
end

SDL.init(SDL::INIT_VIDEO)
SDL::WM.set_caption("Change Screen","")
w, h = 350,230
screen = SDL::Screen.open(w, h, 32, 0)
phases = []
handles = {}
balls = []
font_size = 20
r = 7
[Cairo::Color::BLACK, Cairo::Color::GRAY].each do |color|
  phases << Phase.new(w, h)
  phases.last.addSprite do |obj|
    obj.draw = proc do |cr|
      cr.set_source_color(color)
      cr.rectangle(0, 0, w, h)
      cr.fill
    end
  end
  phases.last.addSprite do |obj|
    obj.x, obj.y = 30, h - 35
    obj.draw = proc do |cr|
      cr.set_source_color(Cairo::Color::WHITE)
      cr.font_size = font_size
      cr.move_to(0, font_size)
      cr.show_text("Chang Screen : Return Key")
    end
  end
  balls << phases.last.addSprite do |obj|
    obj.x, obj.y = w / 2, h / 2
    obj.info[:rx] = Range.new(r, w - r)
    obj.info[:ry] = Range.new(r, h - r)
    obj.info[:dx] = rand(5) + 2
    obj.info[:dx] *=  -1 if rand(9) < 5
    obj.info[:dy] = rand(5) + 2
    obj.info[:dy] *=  -1 if rand(9) < 5
    obj.draw = proc do |cr|
      cr.set_source_color(Cairo::Color::RED)
      cr.circle(0, 0, r)
      cr.fill
    end
  end
  idx = balls.size - 1
  phases.last.task = proc do
    if !balls[idx].info[:rx].include?(balls[idx].x + balls[idx].info[:dx])
      balls[idx].info[:dx] *=  -1
    end
    if !balls[idx].info[:ry].include?(balls[idx].y + balls[idx].info[:dy])
      balls[idx].info[:dy] *=  -1
    end
    balls[idx].x += balls[idx].info[:dx]
    balls[idx].y += balls[idx].info[:dy]
  end
end
idx = 0
handles[SDL::Event::KeyDown] = proc do|e|
  case e.sym
  when SDL::Key::RETURN
    idx = 1 - idx
  when SDL::Key::ESCAPE
    exit
  end
end
handles[SDL::Event::Quit] = proc{exit}
loop do
  while e = SDL::Event.poll
    if handle = handles[e.class]
      handle[e]
    end
  end
  big = phases[idx].renew
  small = phases[1 - idx].renew
  cr = Cairo::Context.new(big)
  cr.matrix = Cairo::Matrix.scale(0.3, 0.3) * Cairo::Matrix.translate(230, 15)
  cr.set_source(small)
  cr.paint(0.7)
  surface = SDL::Surface.new_from(big.data, w, h, 32, big.stride, 0, 0, 0, 0)
  screen.put(surface,0,0)
  screen.flip
  SDL.delay(20)
end