def _create_image(self):
     grp = Group()
     for word in self.words:
         if len(grp.sprites()) == 0:
             word.scale(self.ratio+0.2)
             pm_w = word.rect.width
             pm_h = word.rect.height
             pm_x, pm_y = place_primary(pm_w, pm_h)
             word.rect.x, word.rect.y = pm_x, pm_y
             arch_x = pm_x + pm_w/2
             arch_y = pm_y + pm_h/2
         else:
             word.scale(self.ratio)
             for x, y in archimedean_spiral(False):
                 if self.debug:
                     rs = Surface((5, 5))
                     rs.fill((0, 0, 255))
                     rs.set_alpha(100)
                     self.sf.blit(rs, (x + arch_x, y + arch_y))
                 word.set_position(x + arch_x, y + arch_y)
                 x_out = CANVAS_WIDTH - CANVAS_PADDING < word.rect.x + word.rect.width or word.rect.x < CANVAS_PADDING
                 y_out = CANVAS_HEIGHT - CANVAS_PADDING < word.rect.y + word.rect.height or word.rect.y < CANVAS_PADDING
                 out_of_bound = x_out or y_out
                 if spritecollideany(word, grp, collide_mask) is None and not out_of_bound:
                     if self.debug:
                         rs = Surface((5, 5))
                         rs.fill((0, 255, 0))
                         rs.set_alpha(100)
                         self.sf.blit(rs, (x + arch_x, y + arch_y))
                     break
         self.sf.blit(word.image, word.rect)
         grp.add(word)
Exemple #2
0
class Status_bar:
    def __init__(self, x, y):
        self.x = x
        self.y = y
        self.surface = Surface((360, 60))
        self.surface.fill((65, 56, 231))
        self.surface.set_colorkey((65, 56, 231))
        self.surface.set_alpha(200)
        self.image = load("images/status_bar/status_bar.png")
        self.hp_image = load('images/status_bar/hp.png')
        self.friend_image = load('images/tanks/player_up_1.png')
        self.friend_image.set_colorkey((255, 255, 255))
        self.enemy_image = load('images/tanks/enemy_up_1.png')
        self.enemy_image.set_colorkey((255, 255, 255))
        self.font = font.Font('fonts/ComicTalecopy.ttf', 32)

    def show(self, hp, friends, enemies, lvl, scr, scr_w):
        self.surface.blit(self.image, (0, 0))
        self.surface.blit(self.hp_image, (10, 10))
        self.surface.blit(self.font.render('X' + str(hp), 1, (255, 255, 255)),
                          (55, 15))

        self.surface.blit(self.friend_image, (110, 10))
        self.surface.blit(
            self.font.render('X' + str(friends - 1), 1, (255, 255, 255)),
            (155, 15))

        self.surface.blit(self.enemy_image, (210, 10))
        self.surface.blit(
            self.font.render('X' + str(enemies), 1, (255, 255, 255)),
            (255, 15))

        scr.blit(self.surface, (0, 0))
        scr.blit(self.font.render('Stage ' + str(lvl), 1, (255, 255, 255)),
                 (1366 - self.font.size('stage' + str(lvl))[0] - 20, 10))
    def draw(self):
        """
        Method called each frame to (re)draw the objects and UI
        :return:
        """
        if not self.overlay_drawn:
            overlay = Surface((self.scaled_width, LEVEL_HEIGHT))
            overlay.set_alpha(128)
            overlay.fill((0, 0, 0))
            self.overlay_drawn = True
            self.screen.blit(overlay, (0, 0))

        o_max_width = max([option.get_rect().width for option in self.menu_options])
        width = o_max_width + MENU_PADDING[0] * 2
        height = self.menu_options[0].get_rect().height + MENU_PADDING[1] * 2
        x = self.scaled_width / 2 - width / 2
        y = LEVEL_HEIGHT / 2 - (height * len(self.menu_options)) / 2
        counter = 0
        for option in self.menu_options:
            if counter == self.menu_option:
                used_color = MENU_COLORS[1]
            else:
                used_color = MENU_COLORS[0]
            draw.rect(self.screen, used_color, (x, y + counter * height, width, height), 0)
            option_x = x + MENU_PADDING[0] + (o_max_width - option.get_rect().width) / 2
            self.screen.blit(option, (option_x, y + height * counter + MENU_PADDING[1]))
            counter += 1
Exemple #4
0
	def load_transparent_image(self):
		image = Surface((32, 32))
		image.fill(DEFAULT_COLORKEY)
		image.set_colorkey(DEFAULT_COLORKEY)
		image.blit(self.image, (0, 0))
		image.set_alpha(120)
		self.transparent_image = image
Exemple #5
0
class Cell():
  def __init__(self, x, y, width, height, block_image):
    self.x = x
    self.y = y
    self.activated = False
    self.small_block_image = scale_image(block_image, (20, 20))
    self.image = Surface((width, height))
    self.image.fill((139,69,19))
    self.image.set_alpha(60)
  def update(self, event, cells):
    if event.type == MOUSEBUTTONDOWN:
      if event.button == 1:
        if event.pos[0] in range(self.x, self.x + self.image.get_width()) and event.pos[1] in range(self.y, self.y + self.image.get_height()):
          button_press_sound.play()
          self.activated = True
          for cell in cells:
            if cell != self:
              cell.activated = False
  def draw(self, window):
    window.blit(self.image, (self.x, self.y))
    if self.activated:
      draw_rect(window, (0, 0, 0), (self.x, self.y, self.image.get_width(), self.image.get_height()), 2)
    else:
      draw_rect(window, (150, 150, 150), (self.x, self.y, self.image.get_width(), self.image.get_height()), 2)
    window.blit(self.small_block_image, ((self.x + self.image.get_width() // 2) - self.small_block_image.get_width() // 2, (self.y + self.image.get_height() // 2) - self.small_block_image.get_height() // 2))
    def finish_game(self):
        """
        Function triggered on the game end, passed to the Level
        :return:
        """
        self.game_finished = True
        self.end_labels = []
        player1score = self.levels[0].player.score
        player2score = self.levels[1].player.score
        if player1score > player2score:
            self.end_labels.append(Assets.menu_font.render("Player 1 wins!", 1, (255, 255, 255)))
        elif player1score < player2score:
            self.end_labels.append(Assets.menu_font.render("Player 2 wins!", 1, (255, 255, 255)))
        else:
            self.end_labels.append(Assets.menu_font.render("Draw!", 1, (255, 255, 255)))
        self.end_labels.append(Assets.font.render("Player 1 score: " + str(player1score), 1,
                                                  (255, 255, 255)))
        self.end_labels.append(Assets.font.render("Player 2 score: " + str(player2score), 1,
                                                  (255, 255, 255)))
        self.end_labels.append(Assets.font.render("Press enter to return to menu", 1,
                                                  (255, 255, 255)))

        overlay = Surface((LEVEL_WIDTH * 2, LEVEL_HEIGHT))
        overlay.set_alpha(128)
        overlay.fill((0, 0, 0))
        self.screen.blit(overlay, (0, 0))

        y = LEVEL_HEIGHT / 2 - sum([label.get_rect().height / 2 for label in self.end_labels])
        offset = 0
        for label in self.end_labels:
            self.screen.blit(label, (LEVEL_WIDTH - label.get_rect().width / 2, y + offset))
            offset = offset + label.get_rect().height
Exemple #7
0
 def mouse_over_effect(self, stage_node_x, stage_node_y):
     mouse_over = Surface((30, 30), SRCALPHA, 32)
     mouse_over.set_alpha(100)
     mouse_over.fill(Color('Green'))
     self.surface.blit(mouse_over, (stage_node_x, stage_node_y))
     rect_hover = Rect(stage_node_x, stage_node_y, 30, 30)
     draw.rect(self.surface, Color('Tomato'), rect_hover, 2)
Exemple #8
0
def blit_alpha(target, source, location, opacity):
        x,y = location
        temp = Surface((source.get_width(), source.get_height())).convert()
        temp.blit(target, (-x, -y))
        temp.blit(source, (0, 0))
        temp.set_alpha(opacity)        
        target.blit(temp, location)
Exemple #9
0
 def __init__(self, x, y):
     sprite.Sprite.__init__(self)
     self.xvel = 0
     self.yvel = 0
     self.startX = x
     self.startY = y
     self.x = self.startX
     self.y = self.startY
     img = image.load(resources.MAPFILE)
     size = img.get_size()
     new_size = (
         int(size[0] * resources.MAPFILE_SCALE),
         int(size[1] * resources.MAPFILE_SCALE),
     )
     self.image = transform.scale(img, new_size)
     self.image.set_alpha(128)
     self.rect = self.image.get_rect()
     self.moveTo(self.x, self.y)
     fg = Surface((self.rect.width, self.rect.height))
     fg.set_alpha(128)
     # fg.fill(Color(0, 255, 0))
     points = []
     seapoints = []
     for sea in SEAS:
         seapoints += BgMap.by_points(sea)
     for land in LANDS:
         points += BgMap.by_points(land, seapoints)
     for p in points:
         rect = Rect(p[0] * MOVE_SPEED, p[1] * MOVE_SPEED, 32, 32)
         draw.rect(fg, Color(255, 255, 0), rect)
     self.image.blit(fg, (0, 0))
Exemple #10
0
class Nest(Entity):
	"""
	Encapsulates a colony of ants
	"""
	def __init__(self, world, id, size, location, ant_count):
		self.id = id
		self.size = size
		self.world = world
		self.ant_count = ant_count
		super(Nest, self).__init__(world, location, size, None)
		self.spawn_ants()
		self.mark_home()
		self.set_image()

	def set_image(self):
		w, h = self.size
		w *= self.world.cell_size
		h *= self.world.cell_size
		self.image = Surface((w,h))
		self.image.fill(YELLOW)
		self.image.set_alpha(196)

	def mark_home(self):
		"""
		Converts the cell at its location to its nest
		"""
		width, height = self.size
		# width /= self.world.settings["cell_size"]
		# height /= self.world.settings["cell_size"]
		x, y = self.location
		for i in range(width):
			for j in range(height):
				self.world[(x+i,y+j)].make_home(self.id)

	def spawn_ants(self):
		"""
		Creates instances of ants and adds them into the world
		"""
		for ant in self.ant_count:
			for i in range(self.ant_count[ant]):
				self.add_new_ant(ant)

	def add_new_ant(self, ant_type):
		x, y = self.location
		width, height = self.size
		direction = randint(1,8)
		location = x+randint(0,width/self.world.settings["cell_size"]), y+randint(0,height/self.world.settings["cell_size"])
		new_ant = ant_type(self.world, self.world.images["ant"], direction, location, self)
		self.world.add_ant(new_ant)

	def add_new_ant_randomly(self):
		num = randint(1,100)
		if num<90:
			ant = WorkerAnt
		elif num<98:
			ant = SoldierAnt
		else:
			ant = QueenAnt
		self.add_new_ant(ant)
Exemple #11
0
class Controls:
    def __init__(self, scr_w, scr_h, list):
        self.surface = Surface((scr_w, scr_h))
        self.font = font.Font(None, 32)
        self.list = list
        self.surface.set_alpha(150)

    def show(self):
        for x in range(0, len(self.list)):
            self.surface.blit(
                self.font.render(self.list[x], 1, (255, 255, 255)),
                (100, x * 30 + 20))
 def set_alpha(self):
     if self.alpha != 255:
         self.alpha += 10
     if self.alpha != 255:
         surf = Surface(self.rect.size)
         surf.fill(self.anticolor)
         surf.set_colorkey(self.anticolor)
         surf.blit(self.text, (0, 0))
         surf.set_alpha(self.alpha)
         return surf
     else:
         return self.text
 def get_surface(self):
     surface = Surface(self.size)
     if self.colorkey:
         surface.fill(self.colorkey)
     if 0 < self.alpha < 255:
         surface.set_alpha(self.alpha, RLEACCEL)
     self.blit_templates(surface)
     ##        self.blit_corners(surface)
     ##        self.blit_sides(surface)
     surface.set_colorkey(self.colorkey, RLEACCEL)
     surface.set_clip(self.clip)
     return surface.convert()
Exemple #14
0
class Pointer:
    def __init__(self):
        self.pointer = Surface((16, 8))
        self.pointer.fill(palete['claro'])
        self.alpha = 255
        self.alpha_vel = -10

    def run(self):
        self.pointer.set_alpha(self.alpha)
        self.alpha += self.alpha_vel
        if self.alpha <= 0 or self.alpha >= 255:
            self.alpha_vel *= -1
Exemple #15
0
 def set_alpha(self):
     if self.alpha != 255:
         self.alpha += 10
     if self.alpha != 255:
         surf = Surface(self.rect.size)
         surf.fill(self.anticolor)
         surf.set_colorkey(self.anticolor)
         surf.blit(self.text, (0, 0))
         surf.set_alpha(self.alpha)
         return surf
     else:
         return self.text
Exemple #16
0
class Platform(sprite.Sprite):
    def __init__(self, x, y, filename):
        super().__init__()
        self.dmg = False
        if filename is not None:
            if filename not in tiles_textures:
                tiles_textures[filename] = \
                    pygame.transform.scale(image.load(filename).convert_alpha(), (64, 64))
            self.image = tiles_textures[filename]
        else:
            self.image = Surface((PLAT_W, PLAT_H))
            self.image.set_alpha(0)
        self.rect = Rect(x, y, PLAT_W * 2, PLAT_H * 2)
        self.hitbox = pygame.Rect(x + PLAT_W // 2, y + PLAT_H // 2, PLAT_W,
                                  PLAT_H)
class button():
    def __init__(self, x, y, width, length, text, color, pic=None):
        self.img = Surface((width, length))
        self.cover = Surface((width, length))
        self.cover.fill((0, 0, 0))
        self.color = color
        self.img.fill((color))
        self.x, self.y = x, y
        font1 = font.Font(font.get_default_font(), int(width * 0.09))
        self.txt = font1.render(str(text), True, (255, 255, 255))
        if pic:
            pic = transform.scale(
                pic,
                (width, length),
            )
        self.icon = pic

    def draw_button(self, screen, posx, posy):
        self.ishover(posx, posy)
        screen.blit(self.img, (self.x, self.y))
        screen.blit(self.cover, (self.x, self.y))
        screen.blit(
            self.txt,
            (self.x +
             (self.img.get_size()[0] / 2 - self.txt.get_width() / 2), self.y +
             (self.img.get_size()[1] / 2 - self.txt.get_height() / 2)))
        if (self.icon):
            screen.blit(
                self.icon,
                (self.x +
                 (self.img.get_size()[0] / 2 - self.icon.get_width() / 2),
                 self.y +
                 (self.img.get_size()[1] / 2 - self.icon.get_height() / 2)))

    def ishover(self, posx, posy):
        if (posx >= self.x and posx <= self.x + self.img.get_size()[0]
                and posy >= self.y
                and posy <= self.y + self.img.get_size()[1]):
            self.cover.set_alpha(100)
        else:
            self.cover.set_alpha(0)

    def isclicked(self, posx, posy):
        if (posx >= self.x and posx <= self.x + self.img.get_size()[0]
                and posy >= self.y
                and posy <= self.y + self.img.get_size()[1]):
            return True
        return False
Exemple #18
0
class StatusBar:
    def __init__(self):
        self.x = 10
        self.y = W_HEIGHT - 40
        self.w = W_WIDTH - 20
        self.h = 30
        self.color = GRAY
        self.s = Surface((self.w, self.h))
        
    def draw(self, screen, health):
        # draw.rect(screen, self.color, (self.x, self.y,self.w, self.h))
        if health <= 0:
            self.color = RED
        self.s.set_alpha(100)
        self.s.fill(self.color)
        screen.blit(self.s, (10, W_HEIGHT - 40))
Exemple #19
0
	def generate_fire_sprite(self):
		if self.upgrade_levels[0] >= 3:
			self.set_fire_ring(None)
			return
		fire_width = self.fire_width
		fire_effect_image = Surface((92, 92))
		fire_effect_image.fill(DEFAULT_COLORKEY)
		fire_effect_image.set_colorkey(DEFAULT_COLORKEY)
		pygame.draw.line(fire_effect_image, self.fire_color, (46, 30), (46, 0), fire_width)
		pygame.draw.line(fire_effect_image, self.fire_color, (30, 46), (0, 46), fire_width)
		pygame.draw.line(fire_effect_image, self.fire_color, (62, 46), (92, 46), fire_width)
		pygame.draw.line(fire_effect_image, self.fire_color, (46, 62), (46, 92), fire_width)
		fire_effect_image.set_alpha(225)
		self.fire_sprite = pygame.sprite.Sprite()		
		self.fire_sprite.image = fire_effect_image
		self.fire_sprite.rect = Rect(self.rect.left - 30, self.rect.top - 30, 92, 92)
		self.fire_sprite.mask = pygame.mask.from_surface(self.fire_sprite.image)
Exemple #20
0
    def go(self, display):

        super().go(display)

        shade = Surface(
            (self._w, self._h * self._cooldown_left // self._cooldown_timer))
        shade.set_alpha(63)
        shade.fill(constants.BLACK)
        y_pos = self._y + (self._h *
                           (self._cooldown_timer - self._cooldown_left) //
                           self._cooldown_timer)
        display.blit(shade, (self._x, y_pos))

        pygame.draw.rect(display, constants.BLACK,
                         Rect(self._x, self._y, self._w, self._h), 2)

        self._cooldown_left = max(0, self._cooldown_left - 1)
Exemple #21
0
class LightColumn(GameObject):
    '''
    This class exists to let the player know where exactly he's aiming.
    '''
    SIZE = Rect(0, 0, 32, config.SCREEN_HEIGHT - 32 * 3)

    def __init__(self):
        super().__init__()
        self.image = Surface(self.__class__.SIZE.size, config.BLIT_FLAGS)
        self.position = [-300.0, -300.0]
        self.rect = Rect(self.position, self.__class__.SIZE.size)
        self.state = 1

        self.image.fill(color.WHITE)
        self.image.set_alpha(128)
        del self.acceleration, self.velocity

    actions = {1: None}
Exemple #22
0
class LightColumn(GameObject):
    '''
    This class exists to let the player know where exactly he's aiming.
    '''
    SIZE = Rect(0, 0, 32, config.SCREEN_HEIGHT - 32 * 3)
    
    def __init__(self):
        super().__init__()
        self.image    = Surface(self.__class__.SIZE.size, config.BLIT_FLAGS)
        self.position = [-300.0, -300.0]
        self.rect     = Rect(self.position, self.__class__.SIZE.size)
        self.state    = 1
        
        self.image.fill(color.WHITE)
        self.image.set_alpha(128)
        del self.acceleration, self.velocity
        
    actions = {1 : None}
Exemple #23
0
    def get_image(self,
                  x: int,
                  y: int,
                  width: int,
                  height: int,
                  alpha: bool = False) -> Surface:
        """
        Extracts sprite of given point (x, y) (left, top) and width and height.

        Alpha boolean keyword argument for converting the sprite in alpha or non-alpha.
        """
        image = Surface((width, height))
        image.blit(self.spritesheet, (0, 0), (x, y, width, height))
        image.set_colorkey((0, 0, 0))
        image.set_alpha(255)

        if alpha:
            return image.convert_alpha()
        return image.convert()
Exemple #24
0
class VisionSurface:
    def __init__(self, tile_size, color, coords, surface):
        surface_size = ((Settings.VISION_DISTANCE * 2 + 1) * tile_size[0],
                        (Settings.VISION_DISTANCE * 2 + 1) * tile_size[1])
        self.parent_surface = surface
        self.surface = Surface(surface_size)
        self.surface.set_alpha(20)
        self.x, self.y = coords
        self.tile_size = tile_size
        self.color = color

    def draw(self):
        self.surface.fill(self.color)
        self.parent_surface.blit(self.surface, (self.x * self.tile_size[0],
                                                self.y * self.tile_size[1]))

    def move(self, dx=0, dy=0):
        self.x += dx
        self.y += dy
Exemple #25
0
 def render(self, surf: Surface):
     player_pos = LEVEL.get(self.player)
     enemy_pos = LEVEL.get(self.enemy)
     if global_vars.intro_part > 1:
         psurf = Surface(surf.get_size()).convert_alpha()
         psurf.fill((0, 0, 0, 0))
         if self.show_enemy and self.enemy == self.player:
             pygame.draw.circle(
                 psurf,
                 PLAYER_COLOR if global_vars.blink_on else ENEMY_COLOR,
                 enemy_pos.render, 10)
         else:
             if self.show_enemy and enemy_pos is not None:
                 pygame.draw.circle(psurf, ENEMY_COLOR, enemy_pos.render,
                                    10)
             if player_pos is not None:
                 pygame.draw.circle(psurf, PLAYER_COLOR, player_pos.render,
                                    10)
         psurf.set_alpha(CHARACTER_OPACITY)
         surf.blit(psurf, (0, 0))
Exemple #26
0
 def __init__(self, config, *args, **kwargs):
     super(Game, self).__init__(config, *args, **kwargs)
     self.background = Surface(config.RESOLUTION)
     self.rendering = sprite.LayeredDirty()
     self.player = sprite.GroupSingle()
     self.creeps = sprite.Group()
     image = Surface((20, 20)).convert(self.display)
     image.fill((255, 255, 255))
     mob.Player(image, 0, config, self.rendering, self.player, self.rendering)
     self.rendering.change_layer(self.player.sprite, 1)
     self.camera = FollowCam(Vector(0, 0), self.player.sprite, config,
                             max_dist=100, max_speed=(60))
     offset = self.camera.get_offset()
     image = Surface((20, 20)).convert(self.display)
     image.fill((0, 128, 0))
     m_image = Surface((100, 100)).convert(self.display)
     m_image.set_alpha(64)
     m_image.fill((128, 64, 192))
     for x in xrange(config.INITIAL_SPAWN):
         mob.Creep(image, m_image, self.player.sprite, offset, config, self.rendering, self.creeps, self.rendering)
Exemple #27
0
    def contruct_menu_background(self, size):
        changes = 5
        
        bg = Surface(size) # Surface with horizontal lines
        bg2 = Surface(size, pg.SRCALPHA, 32) # Surfave with vertical lines


        red, green, blue = (100, 100, 100)
        for y in range(HEIGHT):
            red, green, blue = transform_color((red, green, blue), changes, max_=200, min_=30)
            pg.draw.line(bg, (red, green, blue), (0, y), (WIDTH-1, y))

        red, green, blue = (10, 10, 10)
        for x in range(0, WIDTH):
            red, green, blue = transform_color((red, green, blue), changes, max_=55)
            pg.draw.line(bg2, pg.Color(red, green, blue, 100), (x, 0), (x, HEIGHT))


        bg2.set_alpha(255/2)  # 50% vertical lines, 50% horizontal lines
        bg.blit(bg2, (0,0))

        return bg
    def finish_game(self):
        """
        Function triggered on the game end, passed to the Level
        :return:
        """
        self.game_finished = True
        self.end_labels = (
            Assets.menu_font.render("Congratulations!", 1, (255, 255, 255)),
            Assets.font.render("Your final score: " + str(self.level.player.score), 1,
                               (255, 255, 255)),
            Assets.font.render("Press enter to return to menu", 1, (255, 255, 255))
        )

        overlay = Surface((LEVEL_WIDTH, LEVEL_HEIGHT))
        overlay.set_alpha(128)
        overlay.fill((0, 0, 0))
        self.screen.blit(overlay, (0, 0))

        y = LEVEL_HEIGHT / 2 - sum([label.get_rect().height / 2 for label in self.end_labels])
        offset = 0
        for label in self.end_labels:
            self.screen.blit(label, (LEVEL_WIDTH / 2 - label.get_rect().width / 2, y + offset))
            offset = offset + label.get_rect().height
Exemple #29
0
class World:
	def __init__(self):
		self.screen = None
		self.player = None
		self.camera = Camera()
		self.initialize_tiles()
		self.flash_counter = [0, 0]
		self.flash_image = Surface((WIN_WIDTH, WIN_HEIGHT))

	def initialize_screen(self, screen_manager, game_screen):
		""" l.initialize_screen( ScreenManager, GameScreen ) -> None

		Associate this level with the given screen_manager and game_screen.
		"""
		self.screen_manager = screen_manager
		self.screen = game_screen.screen_image

	def initialize_tiles(self):	#TEMP
		self.tiles = []
		for y in xrange(WORLD_HEIGHT):
			self.tiles.append([])
			for x in xrange(WORLD_WIDTH): 
				t = Tile(x, y, MEADOW_GRASS)	
				self.tiles[y].append(t)
		for y in range(WORLD_HEIGHT*3/8, WORLD_HEIGHT*3/8 + WORLD_HEIGHT/4):
			for x in range(WORLD_WIDTH*3/8, WORLD_WIDTH*3/8 + WORLD_WIDTH/4):
				self.tiles[y][x] = Tile(x, y, FOREST_GRASS)
		for y in range(WORLD_HEIGHT*5/8, WORLD_HEIGHT*6/8):
			for x in range(WORLD_WIDTH*3/8, WORLD_WIDTH*3/8 + WORLD_WIDTH/4):
				self.tiles[y][x] = Tile(x, y, BUG_GRASS)
		for y in range(0, WORLD_HEIGHT):
			for x in range(WORLD_WIDTH*7/8, WORLD_WIDTH):
				self.tiles[y][x] = Tile(x, y, CHARRED_GRASS)
		for y in range(19, 21):
			for x in range(38, 40):
				self.tiles[y][x] = Tile(x, y, DARK_GRASS)
		self.tiles[WORLD_HEIGHT/2][WORLD_WIDTH/2].set_entity(TileEntity(HEALING_TOTEM))
		self.tiles[20][WORLD_WIDTH*15/16].set_entity(TileEntity(SVON))

	def update(self, up, down, left, right):
		player = self.player
		self.camera.update(player)
		player.update()
		self.draw_tiles()
		self.screen.blit(player.world_image, self.camera.apply(player))
		self.flash_update()

	def begin_flash(self, color, duration):
		self.flash_counter = [duration, duration]
		self.flash_image.fill(color)
		
	def draw_tiles(self):
		for row in self.tiles:
			for t in row:
				if t: self.screen.blit(t.image, self.camera.apply(t))

	def flash_update(self):
		if self.flash_counter[0] <= 0: return
		half = self.flash_counter[1]/2
		if half <= 0: return
		current = self.flash_counter[0]
		if current > half: alpha = int(255.0 - ((current - half)/float(half))*255.0)
		else: alpha = int(((current)/float(half))*255.0)
		self.flash_image.set_alpha(alpha)
		self.screen.blit(self.flash_image, (0, 0))
		self.flash_counter[0] -= 1

	def add_player(self, player, x, y):
		self.player = player
		player.rect.left, player.rect.top = x*TILE_SIZE, y*TILE_SIZE

	def add_tile(self, tile, x, y):
		self.tiles[y][x] = tile

	def tile_at(self, x, y):
		width, height = len(self.tiles[0]), len(self.tiles)
		if x < 0 or x > width: return None
		if y < 0 or y > height: return None
		return self.tiles[y][x]
Exemple #30
0
def Game_loop():
    size = DISPLAY_WIDTH / 16.0
    posx = (DISPLAY_WIDTH - (size // 2) * 17) * 27 // 100
    posy = 0
    court = generate_court(size=size, start_posx=posx, start_posy=posy)
    snake = [(8, 18, 9), (8, 16, 8), (8, 14, 7)]
    prey = 0

    button_group = Group()
    left_button = Text(text=u'<',
                       x=5,
                       y=50,
                       size=22,
                       font_file='a_Albionic.ttf',
                       color=(250, 250, 250),
                       surface=screen)
    right_button = Text(text=u'>',
                        x=85,
                        y=50,
                        size=22,
                        font_file='a_Albionic.ttf',
                        color=(250, 250, 250),
                        surface=screen)
    button_group.add(left_button, right_button)
    menu_button = Hexagon_Button(lable=u'меню',
                                 posx=87,
                                 posy=2,
                                 font_size=3,
                                 font_file='a_Albionic.ttf',
                                 color=(35, 125, 30),
                                 text_color=(210, 205, 10),
                                 border_color=(210, 205, 10))

    wasted = Text(text=u'Потрачено!',
                  x=6,
                  y=35,
                  size=7,
                  font_file='a_Albionic.ttf',
                  color=(250, 150, 120),
                  surface=screen)
    win = Text(text=u'Победа!',
               x=20,
               y=35,
               size=14,
               font_file='a_Albionic.ttf',
               color=(250, 150, 120),
               surface=screen)
    points_label = Text(text=u'Очки: 0',
                        x=2,
                        y=2,
                        size=3,
                        font_file='a_Albionic.ttf',
                        color=(85, 170, 10),
                        surface=screen)

    fps = Text(text=u'',
               x=5,
               y=2,
               size=2,
               font_file='a_Albionic.ttf',
               color=(85, 170, 10),
               surface=screen)

    apple_eat_sound = mixer.Sound('sounds/Apple_eat.ogg')
    apple_eat_sound.set_volume(1.0)

    finally_background = Surface((DISPLAY_WIDTH, DISPLAY_HEIGHT))
    vector = 1
    alpha = 0
    id = 8
    x = 14
    y = 7
    dt = 0
    clock = Clock()
    done = False
    while not done:
        mp = mouse.get_pos()
        for event in get():
            if event.type == QUIT:
                done = True
                continue
            if event.type == KEYDOWN:
                if vector > 0:
                    if event.key == K_LEFT:
                        vector -= 1
                    if event.key == K_RIGHT:
                        vector += 1
            if event.type == MOUSEBUTTONDOWN:
                if vector > 0:
                    if left_button.rect.collidepoint(mp):
                        vector -= 1
                    elif right_button.rect.collidepoint(mp):
                        vector += 1
                if menu_button.rect.collidepoint(mp):
                    done = True
                    continue
            if vector < 1 and vector > -1:
                vector = 6
            elif vector > 6:
                vector = 1

        if not prey:
            prey = choice(tuple(court))
            while prey.id_and_pos in snake:
                prey = choice(tuple(court))

        if dt > 400:
            dt = 0
            if vector == 1:
                x -= 2
                y -= 1
            elif vector == 2:
                x -= 1
                if x % 2 != 0:
                    y -= 1
                id += 1
            elif vector == 3:
                x += 1
                if x % 2 == 0:
                    y += 1
                id += 1
            elif vector == 4:
                x += 2
                y += 1
            elif vector == 5:
                x += 1
                if x % 2 == 0:
                    y += 1
                id -= 1
            elif vector == 6:
                x -= 1
                if x % 2 != 0:
                    y -= 1
                id -= 1

            next_step = (id, x, y)
            if next_step not in snake:
                if prey.id_and_pos != next_step:
                    snake.append(next_step)
                    snake.pop(0)
                else:
                    snake.append(next_step)
                    apple_eat_sound.play(0)
                    points_label.set_text(text=u'Очки: %s' %
                                          str(len(snake) - 3))
                    prey = 0
                    #if len(snake) > 13:
                    #    vector = -1
                    #delay(10)
            else:
                vector = -1
            if id < 0 or id > 16 or y < 0 or y > 9:
                vector = -1

        screen.fill((20, 20, 40))
        court.update(screen, snake, prey)

        if vector == -1:
            if alpha < 200:
                alpha += 3
                finally_background.set_alpha(alpha)
            screen.blit(finally_background, (0, 0))
            #if len(snake) < 12:
            #    wasted.draw()
            #else:
            #    win.draw()
            wasted.set_text(text=u'Уничтожено %s жертв!' % str(len(snake) - 3))
            wasted.draw()

        fps.set_text(u'FPS: %s' % clock.get_fps())
        fps.draw()

        button_group.draw(screen)
        menu_button.draw(screen, mp)
        points_label.draw()

        window.blit(screen, (0, 0))
        flip()
        clock.tick(40)
        dt += clock.get_tick()
Exemple #31
0
class Pheromone(AlphaGradient):
    """Pheromone control Ant movement.

    Pheromone are placed by Ants on cells during their movement through the environment.
    Pheromone are sigmoid functions whom intensity is between [0,1]. Pheromone provide an
    interface for decreasing and increasing their intensity.

    Args:
        rect (:obj:`Rect`): The position of the Pheromone on the display.
        surface (:obj:`Surface`): The surface to draw the Pheromone on.
        steepness (:obj:`float`, optional): The steepness of the sigmoid function.
        rel_tol (:obj:`float`, optional): Relative tolerance to 1.

    Attributes:
        intensity (:obj:`float`): Current intensity of the Pheromone.
        rect (:obj:`Rect`): The position of the Pheromone on the display.
        surface (:obj:`Surface`): The surface to draw the Pheromone on.
    """

    MIN_INTENSITY = GAMMA
    MAX_INTENSITY = GAMMA

    def __init__(self, background, width, height, gamma=GAMMA, q=Q, rho=RHO):
        self.intensity = GAMMA

        self.background = background

        dwidth, dheight = 0.8 * width, 0.8 * height

        self.surface = Surface((dwidth, dheight))
        self.rect = self.surface.get_rect(
            width=dwidth,
            height=dheight,
            centerx=width / 2,
            centery=height / 2,
        )

        self._q = q
        self._gamma = gamma
        self._rho = rho

        self._xmin = __class__.MIN_INTENSITY
        self._xmax = __class__.MAX_INTENSITY
        self._ymin = 0
        self._ymax = 255

    def draw(self):
        """Draw Pheromone on surface."""
        self.surface.fill(PHEROMONE_COLOR)

        self._xmin = __class__.MIN_INTENSITY
        self._xmax = __class__.MAX_INTENSITY

        self.surface.set_alpha(int(self.get_alpha(self.intensity)))

        self.background.blit(self.surface, self.rect)

    def update(self, length):
        """Increases the Pheromone intensity by a certain amount.

        Args:
            amount (:obj:`float`): Increase Pheromone intensity by this amount
        """
        self.intensity = (1 - RHO) * self.intensity + 1 / length

        if self.intensity > __class__.MAX_INTENSITY:
            __class__.MAX_INTENSITY = self.intensity

        if self.intensity < __class__.MIN_INTENSITY:
            __class__.MIN_INTENSITY = self.intensity

    def decoy(self):
        self.intensity = (1 - RHO) * self.intensity

    def __str__(self):
        return '{} {}i'.format(__class__.__name__, self.intensity)

    def __repr__(self):
        return '<{}(gamma={}, q={}, rho={}) at {}>'.format(
            __class__.__name__, self._gamma, self._q, self._rho, hex(id(self)))
Exemple #32
0
class Glyph(object):
    """
    Main glyph class
    image-- the image that text is set to
    rect-- rect for blitting image to viewing surface
    spacing-- line spacing
    links-- dict of (link, [rects]) pairs
    """


    ##################################################################
    # class methods
    def __init__(self, rect, bkg=BLACK, color=WHITE, font=FONT, spacing=0,
                 ncols=1, col_space=20): # FUTURE COLS ADD
        """
        Initialize a glyph object

        rect-- rect object for positioning glyph image on viewing surface
        **kwargs-- dictionary of (env_id, value) pairs
          required kwargs are:
          bkg-- background color
          color-- font color
          font-- font
        """
        # initialize
        self.image = Surface(rect.size)
        self.image.fill(bkg)
        self.image.set_alpha(255)
        self._bkg = bkg
        self.rect = rect
        self.spacing = spacing
        self.links = defaultdict(list)
        # FUTURE ###
        self.editors = {}
        ############
        # FUTURE COLS ###
        self.col_w = ((rect.w + col_space) / ncols) - col_space
        self.col_space = col_space
        self.col_n = 1
        self.ncols = ncols
        #################
        self._dest = Rect(0, 0, 0, 0) # rect to blit a txt line to image surface
        # list of (env_id, value) pairs for environments;
        # _envs is used as a stack data structure
        self._envs = [('bkg', bkg),
                      ('color', color),
                      ('font', font),
                      ('link', None)] # link id string

        self.buff = deque() # rendered text buffer


    ##################################################################
    # helper methods
    def __read_env(self, _txt_):
        # interprets and returns an environment.  environments set text
        # characteristics such as color or links.
        # accepts the _txt_ iterable at an environment starting point
        # return (environment type, environment) tuple (e.g (font, Font object))

        # re to get env arguments (arguments may be paths and contain \ or /)
        r = re.compile('(\w+)(\s+((\"|\').*?(\"|\')|.*?))?;')
        charbuffer = ''
        # _txt_ is a generator, so iterating consumes the contents for the
        # references to _txt_ in the _interpret function
        for i, char in _txt_:
            charbuffer += char
            s = r.search(charbuffer) # search for environment name arguments
            if s: # if search successful
                groups = s.groups() # get environment
                env, args = groups[0], groups[2]
                if env in Macros: return Macros[env]
                # new environment types must be added here

                elif env == 'bkg':
                    # return new backgroun color
                    return ('bkg', tuple([int(e) for e in args.split(',')]))

                elif env == 'color':
                    # return new font color
                    return ('color', tuple([int(e) for e in args.split(',')]))

                elif env == 'font':
                    # return new font
                    path, size = args.split(',') # the font location and size
                    return ('font', Font(os.path.realpath(path), int(size)))

                elif env == 'link':
                    # return new link
                    return ('link', args.strip())

                # FUTURE ###
                elif env == 'editor':
                    #editor is considered an environment because it must be
                    #linked.  any text in an editor environment is input to
                    #that editor, and any nested environments are ignored.
                    name, w = args.split(',')
                    #extract editor kw args
                    kw = dict(self._envs)
                    del kw['link']
                    kw['spacing'] = self.spacing
                    h = kw['font'].get_linesize()
                    editor = Editor(Rect(0, 0, int(w), h), **kw)
                    self.editors[name] = editor 
                    # treat as link env, get_collision will sort 
                    return ('link', name)
                ############

                else:
                    raise ValueError(env + ' is an unrecognized environment')


    # the space func could take a size and return a surface or rect...
    # really only need to shift tokens.  surfs do that without requiring tokens
    # to have rects
    def __read_func(self, _txt_):
        # interprets and returns a function.  functions are special surfaces or
        # objects.
        # accepts the _txt_ iterable at function starting point
        # returns (function type, function results) tuple
        #   (eg. (space, Surface obejct))
        r = re.compile('(\w+){(.*?)}')
        i, char = _txt_.next()

        if char in SPECIALS: return 'special', char
        if char in WHITESPACE: return 'whitespace', WHITESPACE[char]

        charbuff = char
        for i, char in _txt_:
            charbuff += char
            s = r.search(charbuff)
            if s:
                func, args = s.groups()
                if func in Macros: return func, Macros[func]

                if func == 'space': return func, Surface((int(args), 1))
                #"if charbuff = 'img'"?
                if func == 'img': return func, pygame.image.load(args).convert()


    ##################################################################
    # private methods
    def _interpret(self, txt):
        # iterprets glyph markup language
        # accepts string literal
        # returns a list of (env, charbuff) pairs,
        #   where env is a dictionary of environment types keyed to values and
        #   charbuff a list of text strings and the surfaces created from
        #   functions
        editors, envs = self.editors, self._envs
        read_env, read_func = self.__read_env, self.__read_func
        iswhitespace = _iswhitespace

        txt = txt.strip()
        # FUTURE ###
        # preamble, txt = read_preamble(txt)
        # if preamble: envs = preamble
        # ##########

        # initialize charbuff, renderbuff, interpreted text, and previous char
        charbuff, interpreted_txt, prevchar = [], [], ''
        _txt_ = enumerate(txt)
        for i, char in _txt_:
            if iswhitespace(char) and iswhitespace(prevchar):
                if char == '\n': charbuff[-1] = char
                continue

            if char == '/': # a function:
                func, char = read_func(_txt_)
                charbuff.append(char)
                prevchar = char

            elif char == '{': # a new environment has started
                # using dict(envs) allows new environments to overwrite default
                # environments, which are in the beginning of the list
                interpreted_txt.append((dict(envs), charbuff))
                charbuff = []
                envs.append(read_env(_txt_))

            elif char == '}': # an environment has ended
                # FUTURE ###
                link = dict(envs)['link']
                if link in editors:
                    editor = editors[link]
                    # this is a hack to feed char to editor using input method
                    for char in charbuff:
                        mod = 0
                        if char.isupper(): mod = 3
                        event = Event(KEYDOWN, key=None, mod=mod,
                                      unicode=char.encode('utf8'))
                        editor.input(event)
                    interpreted_txt.append((dict(envs), [editor.image]))
                else: interpreted_txt.append((dict(envs), charbuff))
                #interpreted_txt.append((dict(envs), charbuff)) # FUTURE DEL
                ############
                charbuff = []
                envs.pop()

            else: # a normal, string, character
                charbuff.append(char)
                prevchar = char
        if charbuff: interpreted_txt.append((dict(envs), charbuff))
        return interpreted_txt


    def _tokenize(self, interpreted_txt):
        # tokenizes text
        # accepts (envs, charbuff)
        # returns a list of tokens
        iswhitespace, token_builder = _iswhitespace, _token_builder

        charbuff, _interpreted_txt, tokenized_txt = [], [], []
        for (envs, chars) in interpreted_txt:
            for char in chars:
                if iswhitespace(char):
                    if charbuff:
                        _interpreted_txt.append((envs, charbuff))
                        charbuff = []

                    if _interpreted_txt:
                        yield token_builder(_interpreted_txt)
                        _interpreted_txt = []

                    yield token_builder([(envs, [char])])

                else: charbuff.append(char)

            if charbuff:
                _interpreted_txt.append((envs, charbuff))
                charbuff = []
        if _interpreted_txt: yield token_builder(_interpreted_txt)


    def _wrap(self, tokenized_txt, justify):
        # wrap interpreted text to page width
        # accepts a list of Token objects tuples
        # returns a list of Line objects, each wrapped to self.rect
        Line = _Line
        # FUTURE COLS ###
        rect_w = self.col_w
        #rect_w = self.rect.w # FUTURE COLS DEL
        #################

        # linesize tracks the current size of the rendered line because moving
        # between environments will mean that there will be multiple surfaces
        # that need to be glued together
        line = [] # initialize line, and linesize
        for token in tokenized_txt:
            token_w = token.get_width()
            if token_w > rect_w:
                raise ValueError("The token '"+token.str+"' is "
                                 +str((token_w - rect_w))
                                 +" pixels too wide to fit in the rect passed.")

            # the token fits, process it and check if the line still fits inside
            # rect area, if not, append line without token, reinitialize line
            # with token
            line.append(token)
            if unicode(token) == '\n':
                # don't justify a line that would not wrap
                if justify == 'justified': _justify = 'left'
                else: _justify = justify

                yield Line(line, rect_w, _justify)
                line = [] # reset line

            elif sum(token.get_width() for token in line) > rect_w:
                token = line.pop()
                # remove single trailing whitespace
                if line[-1].iswhitespace: line = line[:-1]

                yield Line(line, rect_w, justify)
                line = [] # reinitialize _line, line, linesize, and num objects
                # do not append whitespace as the first token of the new line
                if not token.iswhitespace: line.append(token)

        if line:
            # don't justify a line that would not wrap
            if justify == 'justified': _justify = 'left'
            else: _justify = justify

            yield Line(line, rect_w, _justify)


    ##################################################################
    # public methods
    def input(self, txt, justify=None, update=True):
        """
        interprets, renders, wraps, and justifies input text

        txt -- raw text written with glyph markup
        justify -- a justify command; default is left justified
          left: left justified
          right: right justified
          justified: justified (both sides even)
          center: center justified

        returns nothing
        """
        buff, interpret, tokenize, wrap = (self.buff, self._interpret,
                                           self._tokenize, self._wrap)
        interpreted_txt = interpret(txt)
        tokens = tokenize(interpreted_txt)
        lines = wrap(tokens, justify)
        buff.extend(lines)
        if update: self.update()


    def overwrite(self, txt, **kw):
        self.clear()
        self.input(txt, **kw)


    def update(self):
        """
        updates the surface with the text input to the buffer by the input
        method, then deletes buffer

        accepts nothing

        returns nothing
        """
        buff, dest = self.buff, self._dest
        spacing = self.spacing
        image, rect = self.image, self.rect
        editors, links = self.editors, self.links
        # FUTURE COLS ###
        ncols, col_n = self.ncols, self.col_n
        col_w, col_space = self.col_w, self.col_space
        #################

        while buff:
            line = buff.popleft()
            line_h = line.get_height()
            if dest.y + line_h > rect.h:
                buff.appendleft(line)
                # FUTURE COLS ###
                if col_n < ncols:
                    dest.move_ip(col_w+col_space, -dest.y)
                    col_n += 1
                else:
                    stderr.write(WARN_BUFF)
                    return 0
                # break # FUTURE COLS DEL
                #################
            else:
                image.blit(line, dest)

                for link in line.links:
                    for _rect in line.links[link]:
                        # move rect to token's pos on image and append to links
                        _rect.move_ip(dest.topleft) # FUTURE ADD
                        # FUTURE DEL
                        #links[link].append(_rect.move(dest.topleft))
                        links[link].append(_rect)
                        # FUTURE ###
                        if link in editors: editors[link].rect = _rect
                        ############

                dest.y += line_h + spacing

        # FUTURE ###
        for editor in editors.values(): image.blit(editor.image, editor.rect)
        ############
        # FUTURE COLS ###
        self.col_n = col_n
        #################
        return 1


    def clear(self, *a):
        """
        draws background over surface_dest using self.rect and resets self._dest

        surface_dest-- the destination surface that self.image has been drawn to
        background-- the background to draw over the areas that self.image was
        drawn to on surface_dest

        returns nothing
        """
        # reset glyph
        self._dest = Rect(0, 0, 0, 0)
        self.links = defaultdict(list)
        self.col_n = 1
        self.buff = deque()
        rect = self.rect
        self.image = Surface(rect.size)
        self.image.fill(self._bkg)
        # if provided, clear a surface at glyph rect
        if a:
            surface_dest, background = a
            surface_dest.blit(background, rect, rect)


    def get_collisions(self, mpos):
        """
        get collisions between a point and the linked text on the glyph surface

        mpos-- the point to check against the linked text

        if a link collides with mpos
          returns the link collinding with mpos
        if no link collides with mpos
          returns None
        """
        editors, links, rect = self.editors, self.links, self.rect
        for link in links:
            for _rect in links[link]:
                if _rect.move(rect.topleft).collidepoint(mpos): return link
dir_path = os.path.dirname(os.path.realpath(__file__))

pygame.init()

screen = pygame.display.set_mode((0, 0), pygame.FULLSCREEN)
bg = pygame.image.load(dir_path +
                       '/windowtests/textured_background.jpg').convert()

pygame.display.set_caption('Magic Mirror')

clock_fps = pygame.time.Clock()

while True:

    for event in pygame.event.get():
        if event.type == pygame.KEYDOWN:
            if event.key == ord("q"):
                pygame.quit()

    screen.blit(bg, (0, 0))

    clock_surface = Surface((300, 300))
    clock_surface.set_alpha(100)

    clock_surface.blit(sine_wave_clock.updateAndRender(), (0, 0))
    screen.blit(clock_surface, (20, 50))

    pygame.display.update()

    clock_fps.tick(30)
class MiniMap(object):
   def __init__(self, mapInfo):
      fp = open(mapInfo)
      
      jData = json.load(fp)
      
      fp.close()
      
      self.drawSize = 3
      self.downScale = 2
      self.__blinkCount = 0
      self.__showPlayer = True
      self.__blinkSpeed = 0.003
      self.__alpha = 200
      
      self.__colors = {
         "poi" : (255, 255, 255), "grassland" : (38,200,80),
         "forest" : (0,60,5), "plains" : (150,150,90),
         "mountain" : (117,26,12), "water" : (0,30,100),
         "desert" : (255,255,102), "snow" : (190,190,255)
      }

      self.poiLocs = []

      self.size = [x / self.downScale for x in jData["size"]]

      
      self.__map = Surface([x * self.drawSize for x in self.size])
      self.canvas = Surface([x * self.drawSize for x in self.size])
      
      self.canvas.set_alpha(self.__alpha)
      for x in range(self.size[0]):
         jRows = []
         for i in range(self.downScale):
            jRows.append(jData["tiles"][x * self.downScale + i])
            
         for y in range(self.size[1]):
            # draw each pixel
            tTypes = []
            for jr in jRows:
               for j in range(self.downScale):
                  tTypes.append(jr[y * self.downScale + j])
                  
            color = [0,0,0]
            cCount = 0
            poiFound = False
            
            for t in tTypes:
               if t not in locations.keys():
                  cCount += 1
                  for rgb in range(3):
                     color[rgb] += self.__colors[t][rgb]
               elif not poiFound:
                  if t != "MasterSword":
                     self.poiLocs.append((x,y))
                     poiFound = True
            
            for rgb in range(3):
               color[rgb] /= cCount
               
            area = Rect((x * self.drawSize, y * self.drawSize),
                        (self.drawSize, self.drawSize))
            draw.rect(self.__map, color, area)
            
      
      

   def draw(self, canvas, playerLocation, windowSize=(640,480)):
      
      self.canvas.blit(self.__map, (0,0))
      
      
      if self.__showPlayer:
         
         for poi in self.poiLocs:
            
            area = Rect((poi[0] * self.drawSize, poi[1] * self.drawSize),
                        (self.drawSize, self.drawSize))
            draw.rect(self.canvas, (0,0,0), area)
            
         area = Rect((int(playerLocation[0] / self.downScale) * self.drawSize,
                      int(playerLocation[1] / self.downScale) * self.drawSize),
                     (self.drawSize, self.drawSize))
         draw.rect(self.canvas, (255,0,0), area)
            
      
      canvas.blit(self.canvas, (windowSize[0] - (self.size[0] * self.drawSize),
                                windowSize[1] - (self.size[1] * self.drawSize)))
      
   
   def update(self, ticks):
      self.__blinkCount += self.__blinkSpeed * ticks
      
      if self.__blinkCount > 1:
         self.__blinkCount -= 1
         self.__showPlayer = not self.__showPlayer
def gasgraph_loop(limit_mass):
    done = False
    data = {}
    text_mass = 'Mass: N/A'
    text_radius = 'Radius: N/A'
    text_density = 'Density: N/A'
    invalid = True

    fondo = display.set_mode((ANCHO, ALTO), SCALED)
    fondo.fill(COLOR_BOX)

    numbers = WidgetGroup()
    for i in [i for i in range(len(radius_keys[:4]))]:
        n = Number(radius_imgs[i], x=i * 28 + 30, y=3)
        numbers.add(n)
        exes.append(n.rect.centerx)

    for i in [i + 4 for i in range(len(radius_keys[4:14]))]:
        n = Number(radius_imgs[i], x=i * 27 + 26, y=3)
        numbers.add(n)
        exes.append(n.rect.centerx)

    for i in [i + 14 for i in range(len(radius_keys[14:]))]:
        n = Number(radius_imgs[i], x=i * 22 + 90, y=3)
        numbers.add(n)
        exes.append(n.rect.centerx)

    for i in [i for i in range(len(mass_keys))]:
        n = Number(mass_imgs[i], right=30, centery=i * 20 + 21)
        numbers.add(n)
        yes.append(n.rect.centery)

    x = exes[radius_keys.index(1.02)]
    y = yes[mass_keys.index(2)]

    rect_super = Rect(31, y, x - 3, (img_rect.h / 2) - 60)
    rect_puffy = Rect(x + 28, 16, (img_rect.w / 2) + 100, y - 16)
    rect_giant = Rect(31, 16, x - 3, y - 16)

    lim_y = find_and_interpolate(limit_mass, mass_keys, yes)
    lim_rect = Rect(31, lim_y, img_rect.w, img_rect.h - lim_y + img_rect.y)
    lim_img = Surface(lim_rect.size)
    lim_img.set_alpha(150)

    lineas = WidgetGroup()
    linea_h = Linea(img_rect, img_rect.x, img_rect.centery, img_rect.w, 1,
                    lineas)
    linea_v = Linea(img_rect, img_rect.centerx, img_rect.y, 1, img_rect.h,
                    lineas)
    punto = Punto(img_rect, img_rect.centerx, img_rect.centery, lineas)

    move_x, move_y = True, True
    while not done:
        for e in event.get(
            [KEYDOWN, KEYUP, QUIT, MOUSEBUTTONDOWN, MOUSEMOTION]):
            if (e.type == KEYDOWN and e.key == K_ESCAPE) or e.type == QUIT:
                quit()
                exit()

            elif e.type == MOUSEMOTION:
                px, py = e.pos

                if move_y:
                    linea_h.move_y(py)
                    punto.move_y(py)
                if move_x:
                    linea_v.move_x(px)
                    punto.move_x(px)

                dx, dy = punto.rect.center
                valid = [
                    rect_puffy.collidepoint(dx, dy),
                    rect_giant.collidepoint(dx, dy),
                    rect_super.collidepoint(dx, dy)
                ]
                off_limit = lim_rect.collidepoint(dx, dy)

                if img_rect.collidepoint(px,
                                         py) and any(valid) and not off_limit:
                    invalid = False
                    mass = round(
                        find_and_interpolate(linea_h.rect.y + 1, yes,
                                             mass_keys), 5)
                    radius = round(
                        find_and_interpolate(linea_v.rect.x, exes,
                                             radius_keys), 3)
                    clase = 'Puffy Giant' if valid[0] else ''
                    clase = 'Gas Giant' if valid[1] else clase
                    clase = 'Super Jupiter' if valid[2] else clase
                    data.update({
                        'mass': mass,
                        'radius': radius,
                        'clase': clase,
                        'albedo': 42.25
                    })

                    d = round(density(mass, radius), 5)
                    text_mass = 'Mass: {}'.format(mass)
                    text_radius = 'Radius: {}'.format(radius)
                    text_density = 'Density: {}'.format(d)

                else:
                    invalid = True
                    text_mass = 'Mass: N/A'
                    text_radius = 'Radius: N/A'
                    text_density = 'Density: N/A'

            elif e.type == MOUSEBUTTONDOWN:
                if e.button == 1:
                    done = True

            elif e.type == KEYDOWN and not invalid:
                if e.key == K_SPACE:
                    done = True

                elif e.key == K_LSHIFT:
                    move_x = False

                elif e.key == K_LCTRL:
                    move_y = False

            elif e.type == KEYUP:
                if e.key == K_LSHIFT:
                    move_x = True

                elif e.key == K_LCTRL:
                    move_y = True

        render_mass = fuente2.render(text_mass, True, COLOR_TEXTO, COLOR_BOX)
        render_radius = fuente2.render(text_radius, True, COLOR_TEXTO,
                                       COLOR_BOX)
        render_density = fuente.render(text_density, True, COLOR_TEXTO,
                                       COLOR_BOX)

        fondo.fill(COLOR_BOX)
        fondo.blit(render_mass, (3, ALTO - 20))
        fondo.blit(render_radius, (150, ALTO - 20))
        fondo.blit(render_density, (300, ALTO - 20))

        fondo.blit(img, img_rect)
        fondo.blit(lim_img, lim_rect)
        numbers.draw(fondo)
        lineas.update()
        lineas.draw(fondo)
        display.update()

    display.quit()
    return data
Exemple #36
0
class Nest(Entity):
    """
	Encapsulates a colony of ants
	"""
    def __init__(self, world, id, size, location, ant_count):
        self.id = id
        self.size = size
        self.world = world
        self.ant_count = ant_count
        super(Nest, self).__init__(world, location, size, None)
        self.spawn_ants()
        self.mark_home()
        self.set_image()

    def set_image(self):
        w, h = self.size
        w *= self.world.cell_size
        h *= self.world.cell_size
        self.image = Surface((w, h))
        self.image.fill(YELLOW)
        self.image.set_alpha(196)

    def mark_home(self):
        """
		Converts the cell at its location to its nest
		"""
        width, height = self.size
        # width /= self.world.settings["cell_size"]
        # height /= self.world.settings["cell_size"]
        x, y = self.location
        for i in range(width):
            for j in range(height):
                self.world[(x + i, y + j)].make_home(self.id)

    def spawn_ants(self):
        """
		Creates instances of ants and adds them into the world
		"""
        for ant in self.ant_count:
            for i in range(self.ant_count[ant]):
                self.add_new_ant(ant)

    def add_new_ant(self, ant_type):
        x, y = self.location
        width, height = self.size
        direction = randint(1, 8)
        location = x + randint(
            0, width / self.world.settings["cell_size"]), y + randint(
                0, height / self.world.settings["cell_size"])
        new_ant = ant_type(self.world, self.world.images["ant"], direction,
                           location, self)
        self.world.add_ant(new_ant)

    def add_new_ant_randomly(self):
        num = randint(1, 100)
        if num < 90:
            ant = WorkerAnt
        elif num < 98:
            ant = SoldierAnt
        else:
            ant = QueenAnt
        self.add_new_ant(ant)
Exemple #37
0
class GameMenu:
    
    # Menu item details, perhaps consider putting this in a configuration
    # file in future
    
    menu_items = [
        MenuItem('Start game', 'start', 'command'),
        MenuItem('Instructions', 'instructions', 'textpage'),
        MenuItem('Customize character', 'character', 'subcommand'),
        MenuItem('Game controls', 'controls', 'subcommand'),
        MenuItem('View high scores', 'highscore', 'subcommand'),
        MenuItem('Credits', 'credits', 'textpage'),
        MenuItem('Quit', 'quit', 'command')
    ]
    
    # Dictionary of text pages for menu entries 
    # Note currently no word wrapping - needs \n to be added in advance
    menu_pages = {
        'instructions':"INSTRUCTIONS\n\nFollow the direction at the top centre\nof the screen.\n\nMove the character using a joystick (Picade)\n or cursor keys (keyboard).\nPress top button or SPACE to duck\nPress RIGHT SHIFT to view the map\n\nAvoid the obstacles that appear on later levels\n",
        'credits':"CREDITS\n\nCreate by Stewart Watkiss\nMade available under GPL v3 License\nSee: www.penguintutor.com/compassgame"
    }
    
    
    menu_spacing = 50 # distance between menu items
    top_spacing = 20  # distance between top of menu and start of menu
    left_spacing = 20 # distance between left and text for page text / command text
    menu_font_size = 45   # size of font for menu items
    menu_font_page = 32   # size of font for text page display
    status = STATUS_MENU         # Track whether to display menu or in menu etc.


    # Requires width and height - these can be the same as the screen or smaller if need to constrain menu
    # Offset and border determine distance from origin of screen and any fixed area to avoid respectively
    def __init__(self, game_controls, width, height, offset=(0,0), border=100):
        self.game_controls = game_controls
        self.width = width              # width of screen
        self.height = height            # height of screen
        self.offset = offset            # tuple x,y for offset from start of screen
        self.border = border            # single value same for x and y
        # Start position of the menu area and size
        self.start_pos = (self.offset[0]+self.border, self.offset[1]+self.border)
        self.size = (self.width-2*self.start_pos[0], self.height-2*self.start_pos[1])
        
        # Create a menu surface - this involves using pygame surface feature (rather than through pygame zero)
        # Allows for more advanced features such as alpha adjustment (partial transparency)
        self.menu_surface = Surface(self.size)
        # 75% opacity
        self.menu_surface.set_alpha(192)
        
        # Position of rect is 0,0 relative to the surface, not the screen
        self.menu_box = Rect((0,0),self.size)
        # Uses pygame rect so we can add it to own surface
        self.menu_rect = pygame.draw.rect(self.menu_surface , (200,200,200), self.menu_box)
        self.menu_pos = 0       # Tracks which menu item is selected

        
        # Timer restrict keyboard movements to prevent multiple presses
        self.menu_timer = Timer(0.12)
        
        # Finish setting up MenuItems
        # At the moment this doesn't provide much extra functionality, but by 
        # placing it into the MenuItem object then makes it easier if we load 
        # MenuItems from a configuration file in future
        for i in range (0,len(self.menu_items)):
            if self.menu_items[i].getCommand() in self.menu_pages:
                self.menu_items[i].setPage(self.menu_pages[self.menu_items[i].getCommand()])
                
        
    # Update menu based on keyboard direction
    # If return is 'menu' then still in menu, so don't update anything else
    # If return is 'quit' then quit the application
    # Any other return is next instruction 
    def update(self, keyboard):
        # set status_selected if menu status changed (through mouse click or press)
        selected_command_type = ""
        selected_command = ""
        # check if status is clicked - which means mouse was pressed on a valid entry
        if (self.status == STATUS_CLICKED):
            selected_command_type = self.menu_items[self.menu_pos].getMenuType()
            selected_command = self.menu_items[self.menu_pos].getCommand()
            self.status = STATUS_MENU
        # check if we are in menu timer in which case return until expired
        elif (self.menu_timer.getTimeRemaining() > 0): 
            return 'menu'
        elif (self.game_controls.isPressed(keyboard,'up') and self.menu_pos>0):
            if (self.status == STATUS_MENU):
                self.menu_pos -= 1
                self.menu_timer.startCountDown()
        elif (self.game_controls.isPressed(keyboard,'down') and self.menu_pos<len(self.menu_items)-1):
            if (self.status == STATUS_MENU):
                self.menu_pos += 1
                self.menu_timer.startCountDown()
        elif (self.game_controls.isOrPressed(keyboard,['jump','duck'])):
            if (self.status == STATUS_MENU):
                selected_command_type =  self.menu_items[self.menu_pos].getMenuType()
                selected_command = self.menu_items[self.menu_pos].getCommand()
            # If click was on text page then return to main menu
            elif (self.status == STATUS_PAGE):
                selected_command_type = 'menu'
                self.status = STATUS_MENU
                self.menu_timer.startCountDown()
        elif (self.game_controls.isPressed(keyboard,'escape')):
            selected_command_type = 'command'
            selected_command = 'quit'
            
        # If a menu object was clicked / chosen then handle
        if (selected_command_type == 'command'):
            # Reset menu to start position
            self.reset()
            return selected_command
        elif (selected_command_type == 'textpage'):
            self.status = STATUS_PAGE
            self.menu_timer.startCountDown()
            return 'menu'
        elif (selected_command_type == 'subcommand'):
            return selected_command
        else:
            return 'menu'

    
    def show(self, screen):
        # Create a rectangle across the area - provides transparancy
        screen.blit(self.menu_surface,self.start_pos)
        # draw directly onto the screen draw surface (transparency doesn't apply)
        if (self.status == STATUS_MENU):
            self.showMenu(screen)
        elif (self.status == STATUS_PAGE):
            self.showPage(screen)
        
        
        
    def showMenu(self, screen):
        for menu_num in range (0,len(self.menu_items)):
            if (menu_num == self.menu_pos):
                background_color = (255,255,255)
            else:
                background_color = None
            screen.draw.text(self.menu_items[menu_num].getText(), fontsize=self.menu_font_size, midtop=(self.width/2,self.offset[1]+self.border+(self.menu_spacing*menu_num)+self.top_spacing), color=(0,0,0), background=background_color)
            
            
    # Shows a page of text
    def showPage(self, screen):
        page_text = self.menu_items[self.menu_pos].getPage()
        screen.draw.text(page_text, fontsize=self.menu_font_page, topleft=(self.offset[0]+self.border+self.left_spacing,self.offset[1]+self.border+self.top_spacing), color=(0,0,0))
        
           

    def mouse_move(self, pos):
        if (self.status == STATUS_MENU): 
            return_val = self.get_mouse_menu_pos(pos)
            if return_val != -1:
                self.menu_pos = return_val


    def mouse_click(self, pos):
        if (self.status == STATUS_MENU): 
            return_val = self.get_mouse_menu_pos(pos)
            if return_val != -1:
                self.menu_pos = return_val
                self.status = STATUS_CLICKED
        # If click from text page then return to menu
        elif (self.status == STATUS_PAGE):
            self.status = STATUS_MENU
    
    def reset(self):
        self.menu_pos = 0
        self.status = STATUS_MENU
    
    
    # Checks if mouse is over menu and if so returns menu position
    # Otherwise returns -1
    def get_mouse_menu_pos (self, pos):
        if (pos[0] > self.start_pos[0] and pos[1] > self.start_pos[1] + self.top_spacing and pos[0] < self.start_pos[0] + self.size[0] and pos[1] < self.start_pos[1] + self.size[1]):
            start_y = self.start_pos[1] + self.top_spacing
            for this_menu_pos in range(0,len(self.menu_items)):
                if (pos[1] - start_y >= this_menu_pos * self.menu_spacing and pos[1] - start_y <= (this_menu_pos * self.menu_spacing)+self.menu_spacing):
                    return this_menu_pos
        # If not returned then not over menu
        return -1
Exemple #38
0
class CustomControls:
    
    
    menu_spacing = 35 # distance between menu items
    top_spacing = 20  # distance between top of menu and start of menu
    left_spacing = 20 # distance between left and text for page text / command text
    menu_font_size = 32   # size of font for menu items
    status = STATUS_MENU         # Track whether to display menu or in menu etc.


    # Requires width and height - these can be the same as the screen or smaller if need to constrain menu
    # Offset and border determine distance from origin of screen and any fixed area to avoid respectively
    def __init__(self, game_controls, width=800, height=600, offset=(0,0), border=100):
        self.game_controls = game_controls
        self.width = width              # width of screen
        self.height = height            # height of screen
        self.offset = offset            # tuple x,y for offset from start of screen
        self.border = border            # single value same for x and y
        # Start position of the menu area and size
        self.start_pos = (self.offset[0]+self.border, self.offset[1]+self.border)
        self.size = (self.width-2*self.start_pos[0], self.height-2*self.start_pos[1])
        
        # Create a menu surface - this involves using pygame surface feature (rather than through pygame zero)
        # Allows for more advanced features such as alpha adjustment (partial transparency)
        self.menu_surface = Surface(self.size)
        # 75% opacity
        self.menu_surface.set_alpha(192)
        
        # Position of rect is 0,0 relative to the surface, not the screen
        self.menu_box = Rect((0,0),self.size)
        # Uses pygame rect so we can add it to own surface
        self.menu_rect = pygame.draw.rect(self.menu_surface , (200,200,200), self.menu_box)
        self.menu_pos = 0       # Tracks which menu item is selected

        
        # Timer restrict keyboard movements to prevent multiple presses
        self.menu_timer = Timer(0.12)
        
        self.updateMenuItems()
        
        
        
    # Updates the menu items - run this whenever the menu changes
    def updateMenuItems(self):
        
        self.menu_items = []
        # Store keys in an array to fix order and make easier to identify selected key
        for this_key in self.game_controls.getKeys():
            self.menu_items.append(MenuItem(this_key+" ("+str(self.game_controls.getKeyString(this_key))+")", this_key, 'control'))
                
        # Dummy entry - blank line
        self.menu_items.append(MenuItem("","","controls"))
        # Last Menu item is to save and return
        self.menu_items.append(MenuItem("Save settings", 'save', 'menu'))


        
    # Update menu based on keyboard direction
    # If return is 'controls' then still in custon controls, so don't update anything else
    # If return is 'menu' then return to main game menu
    def update(self, keyboard):
        # Handle erquest for new key
        if (self.status == STATUS_CUSTOM_KEY and self.menu_timer.getTimeRemaining() <= 0):
            keycode = self.checkKey(keyboard)
            if (keycode != None):
                self.game_controls.setKey(self.selected_key, keycode)
                self.menu_timer.startCountDown()
                self.status = STATUS_MENU
            self.updateMenuItems()
            return 'controls'
        # check if status is clicked - which means mouse was pressed on a valid entry
        if (self.status == STATUS_CLICKED):
            self.selected_key = self.menu_items[self.menu_pos].getCommand()
            self.reset()
            self.status = STATUS_CUSTOM_KEY
        # check if we are in menu timer in which case return until expired
        elif (self.menu_timer.getTimeRemaining() > 0): 
            return 'controls'
        elif (self.game_controls.isPressed(keyboard,'up') and self.menu_pos>0):
            if (self.status == STATUS_MENU):
                self.menu_pos -= 1
                self.menu_timer.startCountDown()
        elif (self.game_controls.isPressed(keyboard,'down') and self.menu_pos<len(self.menu_items)-1):
            if (self.status == STATUS_MENU):
                self.menu_pos += 1
                self.menu_timer.startCountDown()
        elif (self.game_controls.isOrPressed(keyboard,['jump','duck'])):
            if (self.status == STATUS_MENU):
                self.selected_key = self.menu_items[self.menu_pos].getCommand()
                self.reset()
                # special case where selected_key is the save option
                if (self.selected_key == 'save'):
                    # Save the controls
                    self.game_controls.saveControls()
                    return 'menu'
                # Another special case - blank entry used as a spacer
                # Ignore and continue with custom controls menu
                elif (self.selected_key == ''):
                    self.menu_timer.startCountDown()
                    return 'controls'
                self.status = STATUS_CUSTOM_KEY
        elif (self.game_controls.isPressed(keyboard,'escape')):
            return 'menu'
        return 'controls'            

    # Checks pygame event queue for last key pressed
    def checkKey(self, keyboard):
        # Check all keycodes to see if any are high
        for this_code in keycodes:
            if (keyboard[this_code]):
                    return this_code
        return None


    
    def draw(self, screen):
        # Create a rectangle across the area - provides transparancy
        screen.blit(self.menu_surface,self.start_pos)
        # draw directly onto the screen draw surface (transparency doesn't apply)
        if (self.status == STATUS_MENU):
            self.drawMenu(screen)
        elif (self.status == STATUS_CUSTOM_KEY):
            self.drawCustom(screen)
        
        
    def drawCustom(self, screen):
        screen.draw.text("Press custom key for "+self.selected_key, fontsize=self.menu_font_size, midtop=(self.width/2,self.offset[1]+self.border+(self.menu_spacing)+self.top_spacing), color=(0,0,0))
        
        
    def drawMenu(self, screen):
        for menu_num in range (0,len(self.menu_items)):
            if (menu_num == self.menu_pos):
                background_color = (255,255,255)
            else:
                background_color = None
            screen.draw.text(self.menu_items[menu_num].getText(), fontsize=self.menu_font_size, midtop=(self.width/2,self.offset[1]+self.border+(self.menu_spacing*menu_num)+self.top_spacing), color=(0,0,0), background=background_color)
           

    def mouse_move(self, pos):
        if (self.status == STATUS_MENU): 
            return_val = self.get_mouse_menu_pos(pos)
            if return_val != -1:
                self.menu_pos = return_val


    def mouse_click(self, pos):
        if (self.status == STATUS_MENU): 
            return_val = self.get_mouse_menu_pos(pos)
            if return_val != -1:
                self.menu_pos = return_val
                self.status = STATUS_CLICKED
        # If click from text page then return to menu
        elif (self.status == STATUS_PAGE):
            self.status = STATUS_MENU
    
    def select(self):
        self.menu_timer.startCountDown()
        
    
    def reset(self):
        self.menu_timer.startCountDown()
        self.menu_pos = 0
        self.status = STATUS_MENU
    
    
    # Checks if mouse is over menu and if so returns menu position
    # Otherwise returns -1
    def get_mouse_menu_pos (self, pos):
        if (pos[0] > self.start_pos[0] and pos[1] > self.start_pos[1] + self.top_spacing and pos[0] < self.start_pos[0] + self.size[0] and pos[1] < self.start_pos[1] + self.size[1]):
            start_y = self.start_pos[1] + self.top_spacing
            for this_menu_pos in range(0,len(self.menu_items)):
                if (pos[1] - start_y >= this_menu_pos * self.menu_spacing and pos[1] - start_y <= (this_menu_pos * self.menu_spacing)+self.menu_spacing):
                    return this_menu_pos
        # If not returned then not over menu
        return -1
Exemple #39
0
class BaseWidget(BaseObject, sprite.Sprite):
    """BaseWidget () -> BaseWidget

    A basic widget class for user interface elements.

    The BaseWidget is the most basic widget class, from which any other
    widget class should be inherited. It provides the most basic
    attributes and methods, every widget needs.

    The widget is a visible (or non-vissible) element on the display,
    which allows the user to interact with it (active or passive) in a
    specific way. It has several methods and attributes to allow
    developers to control this interaction and supports accessibility
    through the ocempgui.access module.

    The widget can be placed on the display by accessing the various
    attributes of its 'rect' attribute directly. It exposes the following
    pygame.Rect attributes:
    
        top, left, bottom, right,
        topleft, bottomleft, topright, bottomright,
        midtop, midleft, midbottom, midright,
        center, centerx, centery,
        size, width, height

    Except the last three ones, 'size', 'width' and 'height' any of those
    can be assigned similarily to the pygame.Rect:

    widget.top = 10
    widget.center = (10, 10)
    ...

    Note: This will only work for toplevel widgets as widgets are placed
    relative to their parent. Thus the 'top' attribute value of a
    widget, which is packed into another one, refers to its parents
    coordinates. So if it is placed four pixels to the left on its
    parent, its 'top' value will be 4, while the parent might be placed
    at e.g. 100, 100.
    You can get the absolute coordinates, the widget is placed on the
    display, by using the rect_to_client() method.
    
    To get the actual dimensions of the widget, it provides the
    read-only 'width', 'height' and 'size' attributes.

    if (widget.width > 50) or (widget.height > 50):
        ...
    if widget.size == (50, 50):
        ...

    To force a specific minimum size to occupy by the widget, the
    'minsize' attribute or the respective set_minimum_size() method can
    be used. The occupied area of the widget will not be smaller than
    the size, but can grow bigger.

    widget.minsize = 100, 50
    widget.set_minimum_size (10, 33)

    The counterpart of 'minsize' is the 'maxsize' attribute, which
    defines the maximum size, the widget can grow to. It will never
    exceed that size.

    widget.maxsize = 200, 200
    wdget.set_maximum_size (100, 22)

    The 'image' and 'rect' attributes are used and needed by the
    pygame.sprite system. 'image' refers to the visible surface of the
    widget, which will be blitted on the display. 'rect' is a copy of
    the pygame.Rect object indicating the occupied area of the
    widget. The rect denotes the relative position of the widget on its
    parent (as explained above).

    The 'index' attribute and set_index() method set the navigation
    index position for the widget. It is highly recommended to set this
    value in order to provide a better accessibility (e.g. for keyboard
    navigation). The attribute can be used in ocempgui.access.IIndexable
    implementations for example.

    widget.index = 3
    widget.set_index (0)

    Widgets support a 'style' attribute and create_style() method, which
    enable them to use different look than default one without the need
    to override their draw() method. The 'style' attribute of a widget
    usually defaults to a None value and can be set using the
    create_style() method. This causes the widget internals to setup the
    specific style for the widget and can be accessed through the
    'style' attribute later on. A detailled documentation of the style
    can be found in the Style class.

    if not widget.style:
        widget.create_style () # Setup the style internals first.
    widget.style['font']['size'] = 18
    widget.create_style ()['font']['name'] = Arial

    Widgets can be in different states, which cause the widgets to have
    a certain behaviour and/or look. Dependant on the widget, the
    actions it supports and actions, which have taken place, the state
    of the widget can change. The actual state of the widget can be
    looked up via the 'state' attribute and is one of the STATE_TYPES
    constants.

    if widget.state == STATE_INSENSITIVE:
        print 'The widget is currently insensitive and does not react.'

    Any widget supports layered drawing through the 'depth' attribute.
    The higher the depth is, the higher the layer on the z-axis will be,
    on which the widget will be drawn. Widgets might use the flag to set
    themselves on top or bottom of the display.

    # The widget will be placed upon all widgets with a depth lower than 4.
    widget.depth = 4
    widget.set_depth (4)
    
    Widgets should set the 'dirty' attribute to True, whenever an update
    of the widget surface is necessary, which includes redrawing the
    widget (resp. calling draw_bg() and draw()). In user code, 'dirty'
    usually does not need to be modified manually, but for own widget
    implementations it is necessary (e.g. if a Label text changed).
    If the 'parent' attribute of the widget is set, the parent will be
    notified automatically, that it has to update portions of its
    surface.

    # Force redrawing the widget on the next update cycle of the render
    # group.
    widget.dirty = True

    Widgets support a focus mode, which denotes that the widget has the
    current input and action focus. Setting the focus can be done via
    the 'focus' attribute or the set_focus() method.

    widget.focus = True
    widget.set_focus (True)

    'sensitive' is an attribute, which can block the widget's reaction
    upon events temporarily. It also influences the look of the widget
    by using other style values (see STATE_INSENSITIVE in the Style
    class).

    widget.sensitive = False
    widget.set_sensitive (False)

    Each widget supports transparency, which also includes all children
    which are drawn on it. By setting the 'opacity' attribute you can
    adjust the degree of transparency of the widget. The allowed values
    are ranged between 0 for fully transparent and 255 for fully opaque.

    widget.opacity = 100
    widget.set_opacity (25)

    Widgets allow parent-child relationships via the 'parent' attribute.
    Parental relationships are useful for container classes, which can
    contain widgets and need to be informed, when the widget is
    destroyed, for example. Take a look the Bin and Container classes
    for details about possible implementations.
    Do NOT modify the 'parent' attribute value, if you do not know, what
    might happen.

    Widgets support locking themselves self temporarily using the lock()
    method. This is extremely useful to avoid multiple update/draw
    calls, when certain operations take place on it. To unlock the
    widget, the unlock() method should be called, which causes it to
    update itself instantly.

    widget.lock ()            # Acquire lock.
    widget.focus = False      # Normally update() would be called here.
    widget.sensitive = False  # Normally update() would be called here.
    widget.unlock ()          # Release lock and call update().

    When using the lock() method in your own code, you have to ensure,
    that you unlock() the widget as soon as you do not need the lock
    anymore. The state of the lock on a widget can be queried using the
    'locked' attribute:

    if widget.locked:
        print 'The widget is currently locked'

    Widgets can consist of other widgets. To guarantee that all of them
    will be added to the same event management system, set the same
    state, etc., the 'controls' attribute exists. It is a collection to
    and from which widgets can be attached or detached. Several methods
    make use of this attribute by iterating over the attached widgets
    and invoking their methods to put them into the same state, etc. as
    the main widget.

    widget.controls.append (sub_widget)
    for sub in widget.controls:
        ...

    Default action (invoked by activate()):
    None, will raise an NotImplementedError

    Mnemonic action (invoked by activate_mnemonic()):
    None

    Signals:
    SIG_FOCUSED   - Invoked, when the widget received the focus
                    (widget.focus=True).
    SIG_ENTER     - Invoked, when the input device enters the widget.
    SIG_LEAVE     - Invoked, when the input device leaves the wigdet.
    SIG_DESTROYED - Invoked, when the widget is destroyed.

    Attributes:
    minsize   - Guaranteed size of the widget.
    maxsize   - Counterpart to size and denotes the maximum size the widget.
                is allowed to occupy. Defaults to None usually.
    image     - The visible surface of the widget.
    index     - Navigation index of the widget.
    style     - The style to use for drawing the widget.
    state     - The current state of the widget.
    depth     - The z-axis layer depth of the widget.
    dirty     - Indicates, that the widget needs to be updated.
    focus     - Indicates, that the widget has the current input focus.
    sensitive - Indicates, if the user can interact with the widget.
    parent    - Slot for the creation of parent-child relationships.
    controls  - Collection of attached controls for complex widgets.
    tooltip   - The tool tip text to display for the widget.
    opacity   - The degree of transparency to apply (0-255, 0 for fully
                transparent, 255 for fully opaque).
    indexable - The ocempgui.access.IIndexable implementation to use for
                the 'index' attribute support.
    entered   - Indicates, that an input device is currently over the widget
                (e.g. the mouse cursor).
    locked    - Indicates, whether the widget is locked.
    rect      - The area occupied by the widget.
    x, y, ... - The widget allows to reposition itself through the various
    width, ...  attributes offered by its rect attribute.
    size       
    """
    def __init__(self):
        BaseObject.__init__(self)
        sprite.Sprite.__init__(self)

        # Guaranteed sizes for the widget, see also the minsize/maxsize
        # attributes and set_*_size () methods.
        self._minwidth = 0
        self._minheight = 0
        self._maxwidth = 0
        self._maxheight = 0

        self._indexable = None

        self._image = None
        self._rect = Rect(0, 0, 0, 0)
        self._oldrect = Rect(0, 0, 0, 0)

        self._opacity = 255
        self._style = None
        self._index = 0
        self._state = STATE_NORMAL
        self._focus = False
        self._entered = False
        self._sensitive = True

        self._controls = []
        self._depth = 0
        self._dirty = True
        self._lock = 0

        self._bg = None

        self.parent = None

        # Accessibility.
        self._tooltip = None

        # Signals, the widget listens to by default
        self._signals[SIG_FOCUSED] = []
        self._signals[SIG_ENTER] = []
        self._signals[SIG_LEAVE] = []
        self._signals[SIG_DESTROYED] = []

    def _get_rect_attr(self, attr):
        """W._get_rect_attr (...) -> var

        Gets the wanted attribute value from the underlying rect.
        """
        return getattr(self._rect, attr)

    def _set_rect_attr(self, attr, value):
        """W._set_rect_attr (...) -> None

        Sets a specific attribute value on the underlying rect.

        Raises an AttributeError if the attr argument is the width,
        height or size.
        """
        if attr in ("width", "height", "size"):
            # The width and height are protected!
            raise AttributeError("%s attribute is read-only" % attr)

        # TODO: This is just a hack around wrong positioning in
        # containers.
        self._oldrect = self.rect
        setattr(self._rect, attr, value)
        if (self.parent != None):
            if not isinstance(self.parent, BaseWidget):
                self.update()
            else:
                self._oldrect = self.rect

    def initclass(cls):
        """B.initclass () -> None

        Class method to expose the attributes of the own self.rect attribute.

        The method usually is called in the __init__.py script of the
        module.
        """
        attributes = dir(Rect)
        for attr in attributes:
            if not attr.startswith ("__") and \
                   not callable (getattr (Rect, attr)):

                def get_attr(self, attr=attr):
                    return cls._get_rect_attr(self, attr)

                def set_attr(self, value, attr=attr):
                    return cls._set_rect_attr(self, attr, value)

                prop = property(get_attr, set_attr)
                setattr(cls, attr, prop)

    initclass = classmethod(initclass)

    def _get_rect(self):
        """W._get_rect () -> pygame.Rect

        Gets a copy of the widget's rect.
        """
        return Rect(self._rect)

    # DEPRECATED
    def set_position(self, x, y):
        """W.set_position (...) -> None

        DEPRECATED - use the 'topleft' attribute instead
        """
        print "*** Warning: set_position() is deprecated, use the topleft"
        print "             attribute instead."
        self._set_rect_attr("topleft", (x, y))

    def rect_to_client(self, rect=None):
        """W.rect_to_client (...) -> pygame.Rect

        Returns the absolute coordinates a rect is located at.

        In contrast to the widget.rect attribute, which denotes the
        relative position and size of the widget on its parent, this
        method returns the absolute position and occupied size on the
        screen for a passed rect.

        Usually this method will be called by children of the callee and
        the callee itself to detrmine their absolute positions on the
        screen.
        """
        if self.parent and isinstance(self.parent, BaseWidget):
            re = self.rect
            if rect != None:
                re.x += rect.x
                re.y += rect.y
                re.width = rect.width
                re.height = rect.height
            return self.parent.rect_to_client(re)

        elif rect != None:
            rect.x = self.x + rect.x
            rect.y = self.y + rect.y
            return rect
        return self.rect

    def set_minimum_size(self, width, height):
        """W.set_minimum_size (...) -> None

        Sets the minimum size to occupy for the widget.

        Minimum size means that the widget can exceed the size by any
        time, but its width and height will never be smaller than these
        values.

        Raises a TypeError, if the passed arguments are not integers.
        Raises a ValueError, if the passed arguments are not positive.
        """
        if (type(width) != int) or (type(height) != int):
            raise TypeError("width and height must be positive integers")
        if (width < 0) or (height < 0):
            raise ValueError("width and height must be positive integers")
        self._minwidth = width
        self._minheight = height
        self.dirty = True

    # DEPRECATED
    def set_size(self, width, height):
        """W.set_size (...) -> None

        DEPREACATED - use set_minimum_size () instead.
        """
        print "*** Warning: set_size() is deprecated, use set_minimum_size()."
        self.set_minimum_size(width, height)

    def set_maximum_size(self, width, height):
        """W.set_maximum_size (...) -> None

        Sets the maximum size the widget is allowed to occupy.

        This is the counterpart to the set_minimum_size() method.
        """
        if (type(width) != int) or (type(height) != int):
            raise TypeError("width and height must be positive integers")
        if (width < 0) or (height < 0):
            raise ValueError("width and height must be positive integers")
        self._maxwidth = width
        self._maxheight = height
        self.dirty = True

    def check_sizes(self, width, height):
        """W.check_sizes (...) -> int, int

        Checks the passed width and height for allowed values.

        Checks, whether the passed width an height match the upper and
        lower size ranges of the widget and returns corrected values, if
        they exceed those. Else the same values are returned.
        """
        minwidth, minheight = self.minsize
        maxwidth, maxheight = self.maxsize

        if (minwidth != 0) and (width < minwidth):
            width = minwidth
        elif (maxwidth != 0) and (width > maxwidth):
            width = maxwidth

        if (minheight != 0) and (height < minheight):
            height = minheight
        elif (maxheight != 0) and (height > maxheight):
            height = maxheight

        return width, height

    def set_index(self, index):
        """W.set_index (...) -> None
        
        Sets the tab index of the widget.

        Sets the index position of the widget to the given value. It can
        be used by ocempgui.access.IIndexable implementations to allow
        easy navigation access and activation for the widgets.

        Raises a TypeError, if the passed argument is not a positive
        integer.
        """
        if (type(index) != int) or (index < 0):
            raise TypeError("index must be a positive integer")
        self._index = index

    def set_depth(self, depth):
        """W.set_depth (...) -> None

        Sets the z-axis layer depth for the widget.

        Sets the z-axis layer depth for the widget. This will need a
        renderer, which makes use of layers such as the Renderer
        class. By default, the higher the depth value, the higher the
        drawing layer of the widget is. That means, that a widget with a
        depth of 1 is placed upon widgets with a depth of 0.

        Raises a TypeError, if the passed argument is not an integer.
        """
        if type(depth) != int:
            raise TypeError("depth must be an integer")

        self.lock()

        old = self._depth
        self._depth = depth

        if isinstance(self.parent, BaseWidget):
            try:
                self.parent.update_layer(old, self)
            except:
                pass
        for c in self._controls:
            c.set_depth(depth)
        self.unlock()

    def set_dirty(self, dirty, update=True):
        """W.set_dirty (...) -> None

        Marks the widget as dirty.

        Marks the widget as dirty, so that it will be updated and
        redrawn.
        """
        self._dirty = dirty
        if dirty and update:
            self.update()

    def set_event_manager(self, manager):
        """W.set_event_manager (...) -> None

        Sets the event manager of the widget and its controls.

        Adds the widget to an event manager and causes its controls to
        be added to the same, too.
        """
        BaseObject.set_event_manager(self, manager)
        for control in self.controls:
            control.set_event_manager(manager)

    def set_indexable(self, indexable):
        """W.set_indexable (...) -> None

        Sets the IIndexable for the widget.

        The widget will invoke the add_index() method for itself on the
        IIndexable.
        """
        if indexable and not isinstance(indexable, IIndexable):
            raise TypeError("indexable must inherit from IIndexable")
        if self._indexable == indexable:
            return

        if self._indexable != None:
            self._indexable.remove_index(self)

        self._indexable = indexable
        if indexable != None:
            indexable.add_index(self)

        for ctrl in self.controls:
            ctrl.set_indexable(indexable)

    # DEPRECATED
    def get_style(self):
        """W.get_style () -> WidgetStyle

        DEPRECATED - use the create_style() method instead
        """
        print "*** Warning: get_style() is deprecated, use the create_style()"
        print "             method instead."
        return self.create_style()

    def create_style(self):
        """W.create_style () -> WidgetStyle
        
        Creates the instance-specific style for the widget.

        Gets the style associated with the widget. If the widget had no
        style before, a new one will be created for it, based on the
        class name of the widget. The style will be copied internally
        and associated with the widget, so that modifications on it will
        be instance specific.
        
        More information about how a style looks like and how to modify
        them can be found in the Style class documentation.
        """
        if not self._style:
            # Create a new style from the base style class.
            self._style = base.GlobalStyle.copy_style(self.__class__)
            self._style.set_value_changed(lambda: self.set_dirty(True))
        return self._style

    def set_style(self, style):
        """W.set_style (...) -> None

        Sets the style of the widget.

        Sets the style of the widget to the passed style dictionary.
        This method currently does not perform any checks, whether the
        passed dictionary matches the criteria of the Style class.

        Raises a TypeError, if the passed argument is not a WidgetStyle
        object.
        """
        if not isinstance(style, WidgetStyle):
            raise TypeError("style must be a WidgetStyle")
        self._style = style
        if not self._style.get_value_changed():
            self._style.set_value_changed(lambda: self.set_dirty(True))
        self.dirty = True

    def set_focus(self, focus=True):
        """W.set_focus (...) -> bool

        Sets the input and action focus of the widget.
        
        Sets the input and action focus of the widget and returns True
        upon success or False, if the focus could not be set.
        """
        if not self.sensitive:
            return False
        if focus:
            if not self._focus:
                self._focus = True
                self.emit(SIG_FOCUSED, self)
                self.dirty = True
                self.run_signal_handlers(SIG_FOCUSED)
        else:
            if self._focus:
                self._focus = False
                self.dirty = True
        return True

    def set_entered(self, entered):
        """W.set_entered (...) -> None

        Sets the widget into an entered mode.
        """
        if entered:
            if not self._entered:
                self._entered = True
                self.state = STATE_ENTERED
                self.emit(SIG_ENTER, self)
                self.run_signal_handlers(SIG_ENTER)
        elif self._entered:
            self._entered = False
            self.state = STATE_NORMAL
            self.run_signal_handlers(SIG_LEAVE)

    def set_sensitive(self, sensitive=True):
        """W.set_sensitive (...) -> None

        Sets the sensitivity of the widget.

        In a sensitive state (the default), widgets can react upon user
        interaction while they will not do so in an insensitive
        state.
        
        To support the visibility of this, the widget style should
        support the STATE_INSENSITIVE flag, while inheriting widgets
        should check for the sensitivity to enable or disable the event
        mechanisms.
        """
        if sensitive != self._sensitive:
            if sensitive:
                self._sensitive = True
                self.state = STATE_NORMAL
            else:
                self._sensitive = False
                self.state = STATE_INSENSITIVE
        for control in self.controls:
            control.set_sensitive(sensitive)

    def set_state(self, state):
        """W.set_state (...) -> None

        Sets the state of the widget.

        Sets the state of the widget. The state of the widget is mainly
        used for the visible or non-visible appearance of the widget,
        so that the user can determine the state of the widget
        easier.
        Usually this method should not be invoked by user code.

        Raises a ValueError, if the passed argument is not a value of
        the STATE_TYPES tuple.
        """
        if state not in STATE_TYPES:
            raise ValueError("state must be a value from STATE_TYPES")
        if self._state != state:
            self._state = state
            self.dirty = True

    def set_opacity(self, opacity):
        """W.set_opacity (...) -> None

        Sets the opacity of the widget.
        """
        if type(opacity) != int:
            raise TypeError("opacity must be an integer")
        dirty = self._opacity != opacity
        self._opacity = opacity
        self.update()

    # DEPRECATED
    def set_event_area(self, area):
        """W.set_event_area (...) -> None

        DEPRECATED - this is no longer used.
        """
        print "*** Warning: set_event_area() is no longer used!"

    def lock(self):
        """W.lock () -> None

        Acquires a lock on the Widget to suspend its updating methods.
        """
        self._lock += 1

    def unlock(self):
        """W.unlock () -> None

        Releases a previously set lock on the Widget and updates it
        instantly.
        """
        if self._lock > 0:
            self._lock -= 1
        if self._lock == 0:
            self.update()

    def set_tooltip(self, tooltip):
        """W.set_tooltip (...) -> None

        Sets the tooltip information for the widget.

        Raises a TypeError, if the passed argument is not a string or
        unicode.
        """
        if type(tooltip) not in (str, unicode):
            raise TypeError("text must be a string or unicode")
        self._tooltip = tooltip

    def activate(self):
        """W.activate () -> None

        Activates the widget.

        Activates the widget, which means, that the default action of
        the widget will be invoked.

        This method should be implemented by inherited widgets.
        """
        raise NotImplementedError

    def activate_mnemonic(self, mnemonic):
        """W.activate_mnemonic (...) -> bool

        Activates the widget through the set mnemonic.

        Activates the widget through the set mnemonic for it and returns
        True upon successful activation or False, if the widget was not
        activated.

        The BaseWidget.activate_mnemonic () method always returns False
        by default, so that this method should be implemented by
        inherited widgets, if they need explicit mnemonic support.
        """
        return False

    def draw_bg(self):
        """W.draw_bg () -> Surface

        Draws the widget background surface and returns it.

        Creates the visible background surface of the widget and returns
        it to the caller.
        
        This method has to be implemented by inherited widgets.
        """
        raise NotImplementedError

    def draw(self):
        """W.draw () -> None

        Draws the widget surface.

        Creates the visible surface of the widget and updates its
        internals.
        """
        # Original surface.
        self._bg = self.draw_bg()
        try:
            self._bg = self._bg.convert()
        except PygameError:
            pass

        rect = self._bg.get_rect()

        # Current surface for blits.
        self._image = Surface((rect.width, rect.height))
        self._image.blit(self._bg, (0, 0))
        topleft = self._rect.topleft
        self._rect = rect
        self._rect.topleft = topleft
        self._oldrect = self.rect

    def notify(self, event):
        """W.notify (...) -> None

        Notifies the widget about an event.

        Note: Widgets, which are not visible (not shown) or are in a
        specific state (e.g. STATE_INSENSITIVE), usually do not receive
        any events. But dependant on the widget, this behaviour can be
        different, thus checking the visibility depends on the widget
        and implementation.
        """
        if not self.sensitive:
            return

        if (event.signal == SIG_FOCUSED) and (event.data != self):
            self.focus = False
        elif (event.signal == SIG_ENTER) and (event.data != self):
            self.entered = False

    def update(self, **kwargs):
        """W.update (...) -> None

        Updates the widget.

        Updates the widget and causes its parent to update itself on
        demand.
        """
        if self.locked:
            return

        oldrect = Rect(self._oldrect)
        resize = kwargs.get("resize", False)

        if not self.dirty:
            children = kwargs.get("children", {})
            blit = self.image.blit
            items = children.items()

            # Clean up the dirty areas on the widget.
            for child, rect in items:
                blit(self._bg, rect, rect)
            # Blit the changes.
            for child, rect in items:
                blit(child.image, child.rect)

            self._image.set_alpha(self.opacity)
            # If a parent's available, reassign the child rects, so that
            # they point to the absolute position on the widget and build
            # one matching them all for an update.
            if self.parent:
                vals = children.values()
                rect = oldrect
                if len(vals) != 0:
                    rect = vals[0]
                    x = self.x
                    y = self.y
                    for r in vals:
                        r.x += x
                        r.y += y
                    rect.unionall(vals[1:])
                self.parent.update(children={self: rect}, resize=resize)
            self._lock = max(self._lock - 1, 0)
            return

        # Acquire lock to prevent recursion on drawing.
        self._lock += 1

        # Draw the widget.
        self.draw()
        self._image.set_alpha(self.opacity)
        if self.parent != None:
            resize = oldrect != self._rect
            self.parent.update(children={self: oldrect}, resize=resize)

        # Release previously set lock.
        self._lock = max(self._lock - 1, 0)
        self.dirty = False

    def destroy(self):
        """W.destroy () -> None

        Destroys the widget and removes it from its event system.

        Causes the widget to destroy itself as well as its controls and
        removes all from the connected event manager and sprite groups
        using the sprite.kill() method.
        """
        if isinstance(self.parent, BaseWidget):
            raise AttributeError("widget still has a parent relationship")
        self.run_signal_handlers(SIG_DESTROYED)
        self.emit(SIG_DESTROYED, self)

        # Clear the associated controls.
        _pop = self._controls.pop
        while len(self._controls) > 0:
            control = _pop()
            control.parent = None
            control.destroy()
            del control
        del self._controls

        if self._indexable != None:
            index = self._indexable
            self._indexable = None
            index.remove_index(self)
        if self._manager != None:
            self._manager.remove_object(self)

        BaseObject.destroy(self)  # Clear BaseObject internals.
        self.kill()  # Clear Sprite
        #del self.parent
        del self._indexable
        del self._bg
        del self._style
        del self._image
        del self._rect
        del self._oldrect
        del self

    # DEPRECATED
    position = property(lambda self: self.topleft,
                        lambda self, (x, y): self.set_position(x, y),
                        doc="The position of the topleft corner.")
    eventarea = property(lambda self: self.rect_to_client(),
                         lambda self, var: self.set_event_area(var),
                         doc="The area, which gets the events.")

    minsize = property(lambda self: (self._minwidth, self._minheight),
                       lambda self, (w, h): self.set_minimum_size(w, h),
                       doc="The guaranteed size of the widget.")
    maxsize = property(lambda self: (self._maxwidth, self._maxheight),
                       lambda self, (w, h): self.set_maximum_size(w, h),
                       doc="The maximum size to occupy by the widget.")
    image = property(lambda self: self._image,
                     doc="The visible surface of the widget.")
    rect = property(lambda self: self._get_rect(),
                    doc="The area occupied by the widget.")
    index = property(lambda self: self._index,
                     lambda self, var: self.set_index(var),
                     doc="The tab index position of the widget.")
    style = property(lambda self: self._style,
                     lambda self, var: self.set_style(var),
                     doc="The style of the widget.")
    state = property(lambda self: self._state,
                     lambda self, var: self.set_state(var),
                     doc="The current state of the widget.")
    focus = property(lambda self: self._focus,
                     lambda self, var: self.set_focus(var),
                     doc="The focus of the widget.")
    sensitive = property(lambda self: self._sensitive,
                         lambda self, var: self.set_sensitive(var),
                         doc="The sensitivity of the widget.")
    dirty = property(lambda self: self._dirty,
                     lambda self, var: self.set_dirty(var),
                     doc="""Indicates, whether the widget need to be
                      redrawn.""")
    controls = property(lambda self: self._controls,
                        doc="Widgets associated with the widget.")
    depth = property(lambda self: self._depth,
                     lambda self, var: self.set_depth(var),
                     doc="The z-axis layer depth of the widget.")
    tooltip = property(lambda self: self._tooltip,
                       lambda self, var: self.set_tooltip(var),
                       doc="The tool tip text to display for the widget.")
    locked = property(lambda self: self._lock > 0,
                      doc="Indicates, whether the widget is locked.")
    indexable = property(lambda self: self._indexable,
                         lambda self, var: self.set_indexable(var),
                         doc="The IIndexable, the widget is attached to.")
    entered = property(lambda self: self._entered,
                       lambda self, var: self.set_entered(var),
                       doc="Indicates, whether the widget is entered.")
    opacity = property(lambda self: self._opacity,
                       lambda self, var: self.set_opacity(var),
                       doc="The opacity of the widget.")
Exemple #40
0
def generateDefaultImage(size):
    i = Surface(size)
    i.fill((0, 128, 128))
    i.set_alpha(128)
    return i
class BaseWidget (BaseObject, sprite.Sprite):
    """BaseWidget () -> BaseWidget

    A basic widget class for user interface elements.

    The BaseWidget is the most basic widget class, from which any other
    widget class should be inherited. It provides the most basic
    attributes and methods, every widget needs.

    The widget is a visible (or non-vissible) element on the display,
    which allows the user to interact with it (active or passive) in a
    specific way. It has several methods and attributes to allow
    developers to control this interaction and supports accessibility
    through the ocempgui.access module.

    The widget can be placed on the display by accessing the various
    attributes of its 'rect' attribute directly. It exposes the following
    pygame.Rect attributes:
    
        top, left, bottom, right,
        topleft, bottomleft, topright, bottomright,
        midtop, midleft, midbottom, midright,
        center, centerx, centery,
        size, width, height

    Except the last three ones, 'size', 'width' and 'height' any of those
    can be assigned similarily to the pygame.Rect:

    widget.top = 10
    widget.center = (10, 10)
    ...

    Note: This will only work for toplevel widgets as widgets are placed
    relative to their parent. Thus the 'top' attribute value of a
    widget, which is packed into another one, refers to its parents
    coordinates. So if it is placed four pixels to the left on its
    parent, its 'top' value will be 4, while the parent might be placed
    at e.g. 100, 100.
    You can get the absolute coordinates, the widget is placed on the
    display, by using the rect_to_client() method.
    
    To get the actual dimensions of the widget, it provides the
    read-only 'width', 'height' and 'size' attributes.

    if (widget.width > 50) or (widget.height > 50):
        ...
    if widget.size == (50, 50):
        ...

    To force a specific minimum size to occupy by the widget, the
    'minsize' attribute or the respective set_minimum_size() method can
    be used. The occupied area of the widget will not be smaller than
    the size, but can grow bigger.

    widget.minsize = 100, 50
    widget.set_minimum_size (10, 33)

    The counterpart of 'minsize' is the 'maxsize' attribute, which
    defines the maximum size, the widget can grow to. It will never
    exceed that size.

    widget.maxsize = 200, 200
    wdget.set_maximum_size (100, 22)

    The 'image' and 'rect' attributes are used and needed by the
    pygame.sprite system. 'image' refers to the visible surface of the
    widget, which will be blitted on the display. 'rect' is a copy of
    the pygame.Rect object indicating the occupied area of the
    widget. The rect denotes the relative position of the widget on its
    parent (as explained above).

    The 'index' attribute and set_index() method set the navigation
    index position for the widget. It is highly recommended to set this
    value in order to provide a better accessibility (e.g. for keyboard
    navigation). The attribute can be used in ocempgui.access.IIndexable
    implementations for example.

    widget.index = 3
    widget.set_index (0)

    Widgets support a 'style' attribute and create_style() method, which
    enable them to use different look than default one without the need
    to override their draw() method. The 'style' attribute of a widget
    usually defaults to a None value and can be set using the
    create_style() method. This causes the widget internals to setup the
    specific style for the widget and can be accessed through the
    'style' attribute later on. A detailled documentation of the style
    can be found in the Style class.

    if not widget.style:
        widget.create_style () # Setup the style internals first.
    widget.style['font']['size'] = 18
    widget.create_style ()['font']['name'] = Arial

    Widgets can be in different states, which cause the widgets to have
    a certain behaviour and/or look. Dependant on the widget, the
    actions it supports and actions, which have taken place, the state
    of the widget can change. The actual state of the widget can be
    looked up via the 'state' attribute and is one of the STATE_TYPES
    constants.

    if widget.state == STATE_INSENSITIVE:
        print 'The widget is currently insensitive and does not react.'

    Any widget supports layered drawing through the 'depth' attribute.
    The higher the depth is, the higher the layer on the z-axis will be,
    on which the widget will be drawn. Widgets might use the flag to set
    themselves on top or bottom of the display.

    # The widget will be placed upon all widgets with a depth lower than 4.
    widget.depth = 4
    widget.set_depth (4)
    
    Widgets should set the 'dirty' attribute to True, whenever an update
    of the widget surface is necessary, which includes redrawing the
    widget (resp. calling draw_bg() and draw()). In user code, 'dirty'
    usually does not need to be modified manually, but for own widget
    implementations it is necessary (e.g. if a Label text changed).
    If the 'parent' attribute of the widget is set, the parent will be
    notified automatically, that it has to update portions of its
    surface.

    # Force redrawing the widget on the next update cycle of the render
    # group.
    widget.dirty = True

    Widgets support a focus mode, which denotes that the widget has the
    current input and action focus. Setting the focus can be done via
    the 'focus' attribute or the set_focus() method.

    widget.focus = True
    widget.set_focus (True)

    'sensitive' is an attribute, which can block the widget's reaction
    upon events temporarily. It also influences the look of the widget
    by using other style values (see STATE_INSENSITIVE in the Style
    class).

    widget.sensitive = False
    widget.set_sensitive (False)

    Each widget supports transparency, which also includes all children
    which are drawn on it. By setting the 'opacity' attribute you can
    adjust the degree of transparency of the widget. The allowed values
    are ranged between 0 for fully transparent and 255 for fully opaque.

    widget.opacity = 100
    widget.set_opacity (25)

    Widgets allow parent-child relationships via the 'parent' attribute.
    Parental relationships are useful for container classes, which can
    contain widgets and need to be informed, when the widget is
    destroyed, for example. Take a look the Bin and Container classes
    for details about possible implementations.
    Do NOT modify the 'parent' attribute value, if you do not know, what
    might happen.

    Widgets support locking themselves self temporarily using the lock()
    method. This is extremely useful to avoid multiple update/draw
    calls, when certain operations take place on it. To unlock the
    widget, the unlock() method should be called, which causes it to
    update itself instantly.

    widget.lock ()            # Acquire lock.
    widget.focus = False      # Normally update() would be called here.
    widget.sensitive = False  # Normally update() would be called here.
    widget.unlock ()          # Release lock and call update().

    When using the lock() method in your own code, you have to ensure,
    that you unlock() the widget as soon as you do not need the lock
    anymore. The state of the lock on a widget can be queried using the
    'locked' attribute:

    if widget.locked:
        print 'The widget is currently locked'

    Widgets can consist of other widgets. To guarantee that all of them
    will be added to the same event management system, set the same
    state, etc., the 'controls' attribute exists. It is a collection to
    and from which widgets can be attached or detached. Several methods
    make use of this attribute by iterating over the attached widgets
    and invoking their methods to put them into the same state, etc. as
    the main widget.

    widget.controls.append (sub_widget)
    for sub in widget.controls:
        ...

    Default action (invoked by activate()):
    None, will raise an NotImplementedError

    Mnemonic action (invoked by activate_mnemonic()):
    None

    Signals:
    SIG_FOCUSED   - Invoked, when the widget received the focus
                    (widget.focus=True).
    SIG_ENTER     - Invoked, when the input device enters the widget.
    SIG_LEAVE     - Invoked, when the input device leaves the wigdet.
    SIG_DESTROYED - Invoked, when the widget is destroyed.

    Attributes:
    minsize   - Guaranteed size of the widget.
    maxsize   - Counterpart to size and denotes the maximum size the widget.
                is allowed to occupy. Defaults to None usually.
    image     - The visible surface of the widget.
    index     - Navigation index of the widget.
    style     - The style to use for drawing the widget.
    state     - The current state of the widget.
    depth     - The z-axis layer depth of the widget.
    dirty     - Indicates, that the widget needs to be updated.
    focus     - Indicates, that the widget has the current input focus.
    sensitive - Indicates, if the user can interact with the widget.
    parent    - Slot for the creation of parent-child relationships.
    controls  - Collection of attached controls for complex widgets.
    tooltip   - The tool tip text to display for the widget.
    opacity   - The degree of transparency to apply (0-255, 0 for fully
                transparent, 255 for fully opaque).
    indexable - The ocempgui.access.IIndexable implementation to use for
                the 'index' attribute support.
    entered   - Indicates, that an input device is currently over the widget
                (e.g. the mouse cursor).
    locked    - Indicates, whether the widget is locked.
    rect      - The area occupied by the widget.
    x, y, ... - The widget allows to reposition itself through the various
    width, ...  attributes offered by its rect attribute.
    size       
    """
    def __init__ (self):
        BaseObject.__init__ (self)
        sprite.Sprite.__init__ (self)

        # Guaranteed sizes for the widget, see also the minsize/maxsize
        # attributes and set_*_size () methods.
        self._minwidth = 0
        self._minheight = 0
        self._maxwidth = 0
        self._maxheight = 0

        self._indexable = None
        
        self._image = None
        self._rect = Rect (0, 0, 0, 0)
        self._oldrect = Rect (0, 0, 0, 0)

        self._opacity = 255
        self._style = None
        self._index = 0
        self._state = STATE_NORMAL
        self._focus = False
        self._entered = False
        self._sensitive = True

        self._controls = []
        self._depth = 0
        self._dirty = True
        self._lock = 0

        self._bg = None

        self.parent = None
        
        # Accessibility.
        self._tooltip = None
        
        # Signals, the widget listens to by default
        self._signals[SIG_FOCUSED] = []
        self._signals[SIG_ENTER] = []
        self._signals[SIG_LEAVE] = []
        self._signals[SIG_DESTROYED] = []

    def _get_rect_attr (self, attr):
        """W._get_rect_attr (...) -> var

        Gets the wanted attribute value from the underlying rect.
        """
        return getattr (self._rect, attr)

    def _set_rect_attr (self, attr, value):
        """W._set_rect_attr (...) -> None

        Sets a specific attribute value on the underlying rect.

        Raises an AttributeError if the attr argument is the width,
        height or size.
        """
        if attr in ("width", "height", "size"):
            # The width and height are protected!
            raise AttributeError ("%s attribute is read-only" % attr)

        # TODO: This is just a hack around wrong positioning in
        # containers.
        self._oldrect = self.rect
        setattr (self._rect, attr, value)
        if (self.parent != None):
            if not isinstance (self.parent, BaseWidget):
                self.update ()
            else:
                self._oldrect = self.rect

    def initclass (cls):
        """B.initclass () -> None

        Class method to expose the attributes of the own self.rect attribute.

        The method usually is called in the __init__.py script of the
        module.
        """
        attributes = dir (Rect)
        for attr in attributes:
            if not attr.startswith ("__") and \
                   not callable (getattr (Rect, attr)):
                def get_attr (self, attr=attr):
                    return cls._get_rect_attr (self, attr)
                def set_attr (self, value, attr=attr):
                    return cls._set_rect_attr (self, attr, value)
                prop = property (get_attr, set_attr)
                setattr (cls, attr, prop)
    initclass = classmethod (initclass)
    
    def _get_rect (self):
        """W._get_rect () -> pygame.Rect

        Gets a copy of the widget's rect.
        """
        return Rect (self._rect)

    # DEPRECATED
    def set_position (self, x, y):
        """W.set_position (...) -> None

        DEPRECATED - use the 'topleft' attribute instead
        """
        print "*** Warning: set_position() is deprecated, use the topleft"
        print "             attribute instead."
        self._set_rect_attr ("topleft", (x, y))

    def rect_to_client (self, rect=None):
        """W.rect_to_client (...) -> pygame.Rect

        Returns the absolute coordinates a rect is located at.

        In contrast to the widget.rect attribute, which denotes the
        relative position and size of the widget on its parent, this
        method returns the absolute position and occupied size on the
        screen for a passed rect.

        Usually this method will be called by children of the callee and
        the callee itself to detrmine their absolute positions on the
        screen.
        """
        if self.parent and isinstance (self.parent, BaseWidget):
            re = self.rect
            if rect != None:
                re.x += rect.x
                re.y += rect.y
                re.width = rect.width
                re.height = rect.height
            return self.parent.rect_to_client (re)
        
        elif rect != None:
            rect.x = self.x + rect.x
            rect.y = self.y + rect.y
            return rect
        return self.rect
    
    def set_minimum_size (self, width, height):
        """W.set_minimum_size (...) -> None

        Sets the minimum size to occupy for the widget.

        Minimum size means that the widget can exceed the size by any
        time, but its width and height will never be smaller than these
        values.

        Raises a TypeError, if the passed arguments are not integers.
        Raises a ValueError, if the passed arguments are not positive.
        """
        if (type (width) != int) or (type (height) != int):
            raise TypeError ("width and height must be positive integers")
        if (width < 0) or (height < 0):
            raise ValueError ("width and height must be positive integers")
        self._minwidth = width
        self._minheight = height
        self.dirty = True

    # DEPRECATED
    def set_size (self, width, height):
        """W.set_size (...) -> None

        DEPREACATED - use set_minimum_size () instead.
        """
        print "*** Warning: set_size() is deprecated, use set_minimum_size()."
        self.set_minimum_size (width, height)

    def set_maximum_size (self, width, height):
        """W.set_maximum_size (...) -> None

        Sets the maximum size the widget is allowed to occupy.

        This is the counterpart to the set_minimum_size() method.
        """
        if (type (width) != int) or (type (height) != int):
            raise TypeError ("width and height must be positive integers")
        if (width < 0) or (height < 0):
            raise ValueError ("width and height must be positive integers")
        self._maxwidth = width
        self._maxheight = height
        self.dirty = True

    def check_sizes (self, width, height):
        """W.check_sizes (...) -> int, int

        Checks the passed width and height for allowed values.

        Checks, whether the passed width an height match the upper and
        lower size ranges of the widget and returns corrected values, if
        they exceed those. Else the same values are returned.
        """
        minwidth, minheight = self.minsize
        maxwidth, maxheight = self.maxsize

        if (minwidth != 0) and (width < minwidth):
            width = minwidth
        elif (maxwidth != 0) and (width > maxwidth):
            width = maxwidth
        
        if (minheight != 0) and (height < minheight):
            height = minheight
        elif (maxheight != 0) and (height > maxheight):
            height = maxheight

        return width, height

    def set_index (self, index):
        """W.set_index (...) -> None
        
        Sets the tab index of the widget.

        Sets the index position of the widget to the given value. It can
        be used by ocempgui.access.IIndexable implementations to allow
        easy navigation access and activation for the widgets.

        Raises a TypeError, if the passed argument is not a positive
        integer.
        """
        if (type (index) != int) or (index < 0):
            raise TypeError ("index must be a positive integer")
        self._index = index

    def set_depth (self, depth):
        """W.set_depth (...) -> None

        Sets the z-axis layer depth for the widget.

        Sets the z-axis layer depth for the widget. This will need a
        renderer, which makes use of layers such as the Renderer
        class. By default, the higher the depth value, the higher the
        drawing layer of the widget is. That means, that a widget with a
        depth of 1 is placed upon widgets with a depth of 0.

        Raises a TypeError, if the passed argument is not an integer.
        """
        if type (depth) != int:
            raise TypeError ("depth must be an integer")

        self.lock ()

        old = self._depth
        self._depth = depth

        if isinstance (self.parent, BaseWidget):
            try:
                self.parent.update_layer (old, self)
            except: pass
        for c in self._controls:
            c.set_depth (depth)
        self.unlock ()

    def set_dirty (self, dirty, update=True):
        """W.set_dirty (...) -> None

        Marks the widget as dirty.

        Marks the widget as dirty, so that it will be updated and
        redrawn.
        """
        self._dirty = dirty
        if dirty and update:
            self.update ()

    def set_event_manager (self, manager):
        """W.set_event_manager (...) -> None

        Sets the event manager of the widget and its controls.

        Adds the widget to an event manager and causes its controls to
        be added to the same, too.
        """
        BaseObject.set_event_manager (self, manager)
        for control in self.controls:
            control.set_event_manager (manager)

    def set_indexable (self, indexable):
        """W.set_indexable (...) -> None

        Sets the IIndexable for the widget.

        The widget will invoke the add_index() method for itself on the
        IIndexable.
        """
        if indexable and not isinstance (indexable, IIndexable):
            raise TypeError ("indexable must inherit from IIndexable")
        if self._indexable == indexable:
            return

        if self._indexable != None:
            self._indexable.remove_index (self)

        self._indexable = indexable
        if indexable != None:
            indexable.add_index (self)

        for ctrl in self.controls:
            ctrl.set_indexable (indexable)

    # DEPRECATED
    def get_style (self):
        """W.get_style () -> WidgetStyle

        DEPRECATED - use the create_style() method instead
        """
        print "*** Warning: get_style() is deprecated, use the create_style()"
        print "             method instead."
        return self.create_style ()
    
    def create_style (self):
        """W.create_style () -> WidgetStyle
        
        Creates the instance-specific style for the widget.

        Gets the style associated with the widget. If the widget had no
        style before, a new one will be created for it, based on the
        class name of the widget. The style will be copied internally
        and associated with the widget, so that modifications on it will
        be instance specific.
        
        More information about how a style looks like and how to modify
        them can be found in the Style class documentation.
        """
        if not self._style:
            # Create a new style from the base style class.
            self._style = base.GlobalStyle.copy_style (self.__class__)
            self._style.set_value_changed (lambda: self.set_dirty (True))
        return self._style

    def set_style (self, style):
        """W.set_style (...) -> None

        Sets the style of the widget.

        Sets the style of the widget to the passed style dictionary.
        This method currently does not perform any checks, whether the
        passed dictionary matches the criteria of the Style class.

        Raises a TypeError, if the passed argument is not a WidgetStyle
        object.
        """
        if not isinstance (style, WidgetStyle):
            raise TypeError ("style must be a WidgetStyle")
        self._style = style
        if not self._style.get_value_changed ():
            self._style.set_value_changed (lambda: self.set_dirty (True))
        self.dirty = True
    
    def set_focus (self, focus=True):
        """W.set_focus (...) -> bool

        Sets the input and action focus of the widget.
        
        Sets the input and action focus of the widget and returns True
        upon success or False, if the focus could not be set.
        """
        if not self.sensitive:
            return False
        if focus:
            if not self._focus:
                self._focus = True
                self.emit (SIG_FOCUSED, self)
                self.dirty = True
                self.run_signal_handlers (SIG_FOCUSED)
        else:
            if self._focus:
                self._focus = False
                self.dirty = True
        return True

    def set_entered (self, entered):
        """W.set_entered (...) -> None

        Sets the widget into an entered mode.
        """
        if entered:
            if not self._entered:
                self._entered = True
                self.state = STATE_ENTERED
                self.emit (SIG_ENTER, self)
                self.run_signal_handlers (SIG_ENTER)
        elif self._entered:
            self._entered = False
            self.state = STATE_NORMAL
            self.run_signal_handlers (SIG_LEAVE)

    def set_sensitive (self, sensitive=True):
        """W.set_sensitive (...) -> None

        Sets the sensitivity of the widget.

        In a sensitive state (the default), widgets can react upon user
        interaction while they will not do so in an insensitive
        state.
        
        To support the visibility of this, the widget style should
        support the STATE_INSENSITIVE flag, while inheriting widgets
        should check for the sensitivity to enable or disable the event
        mechanisms.
        """
        if sensitive != self._sensitive:
            if sensitive:
                self._sensitive = True
                self.state = STATE_NORMAL
            else:
                self._sensitive = False
                self.state = STATE_INSENSITIVE
        for control in self.controls:
            control.set_sensitive (sensitive)

    def set_state (self, state):
        """W.set_state (...) -> None

        Sets the state of the widget.

        Sets the state of the widget. The state of the widget is mainly
        used for the visible or non-visible appearance of the widget,
        so that the user can determine the state of the widget
        easier.
        Usually this method should not be invoked by user code.

        Raises a ValueError, if the passed argument is not a value of
        the STATE_TYPES tuple.
        """
        if state not in STATE_TYPES:
            raise ValueError ("state must be a value from STATE_TYPES")
        if self._state != state:
            self._state = state
            self.dirty = True

    def set_opacity (self, opacity):
        """W.set_opacity (...) -> None

        Sets the opacity of the widget.
        """
        if type (opacity) != int:
            raise TypeError ("opacity must be an integer")
        dirty = self._opacity != opacity
        self._opacity = opacity
        self.update ()
        
    # DEPRECATED
    def set_event_area (self, area):
        """W.set_event_area (...) -> None

        DEPRECATED - this is no longer used.
        """
        print "*** Warning: set_event_area() is no longer used!"

    def lock (self):
        """W.lock () -> None

        Acquires a lock on the Widget to suspend its updating methods.
        """
        self._lock += 1
    
    def unlock (self):
        """W.unlock () -> None

        Releases a previously set lock on the Widget and updates it
        instantly.
        """
        if self._lock > 0:
            self._lock -= 1
        if self._lock == 0:
            self.update ()

    def set_tooltip (self, tooltip):
        """W.set_tooltip (...) -> None

        Sets the tooltip information for the widget.

        Raises a TypeError, if the passed argument is not a string or
        unicode.
        """
        if type (tooltip) not in (str, unicode):
            raise TypeError ("text must be a string or unicode")
        self._tooltip = tooltip
    
    def activate (self):
        """W.activate () -> None

        Activates the widget.

        Activates the widget, which means, that the default action of
        the widget will be invoked.

        This method should be implemented by inherited widgets.
        """
        raise NotImplementedError

    def activate_mnemonic (self, mnemonic):
        """W.activate_mnemonic (...) -> bool

        Activates the widget through the set mnemonic.

        Activates the widget through the set mnemonic for it and returns
        True upon successful activation or False, if the widget was not
        activated.

        The BaseWidget.activate_mnemonic () method always returns False
        by default, so that this method should be implemented by
        inherited widgets, if they need explicit mnemonic support.
        """
        return False

    def draw_bg (self):
        """W.draw_bg () -> Surface

        Draws the widget background surface and returns it.

        Creates the visible background surface of the widget and returns
        it to the caller.
        
        This method has to be implemented by inherited widgets.
        """
        raise NotImplementedError

    def draw (self):
        """W.draw () -> None

        Draws the widget surface.

        Creates the visible surface of the widget and updates its
        internals.
        """
        # Original surface.
        self._bg = self.draw_bg ()
        try:
            self._bg = self._bg.convert ()
        except PygameError: pass
        
        rect = self._bg.get_rect ()

        # Current surface for blits.
        self._image = Surface ((rect.width, rect.height))
        self._image.blit (self._bg, (0, 0))
        topleft = self._rect.topleft
        self._rect = rect
        self._rect.topleft = topleft
        self._oldrect = self.rect

    def notify (self, event):
        """W.notify (...) -> None

        Notifies the widget about an event.

        Note: Widgets, which are not visible (not shown) or are in a
        specific state (e.g. STATE_INSENSITIVE), usually do not receive
        any events. But dependant on the widget, this behaviour can be
        different, thus checking the visibility depends on the widget
        and implementation.
        """
        if not self.sensitive:
            return
        
        if (event.signal == SIG_FOCUSED) and (event.data != self):
            self.focus = False
        elif (event.signal == SIG_ENTER) and (event.data != self):
            self.entered = False

    def update (self, **kwargs):
        """W.update (...) -> None

        Updates the widget.

        Updates the widget and causes its parent to update itself on
        demand.
        """
        if self.locked:
            return

        oldrect = Rect (self._oldrect)
        resize = kwargs.get ("resize", False)

        if not self.dirty:
            children = kwargs.get ("children", {})
            blit = self.image.blit
            items = children.items ()

            # Clean up the dirty areas on the widget.
            for child, rect in items:
                blit (self._bg, rect, rect)
            # Blit the changes.
            for child, rect in items:
                blit (child.image, child.rect)

            self._image.set_alpha (self.opacity)
            # If a parent's available, reassign the child rects, so that
            # they point to the absolute position on the widget and build
            # one matching them all for an update.
            if self.parent:
                vals = children.values ()
                rect = oldrect
                if len (vals) != 0:
                    rect = vals[0]
                    x = self.x
                    y = self.y
                    for r in vals:
                        r.x += x
                        r.y += y
                    rect.unionall (vals[1:])
                self.parent.update (children={ self : rect }, resize=resize)
            self._lock = max (self._lock - 1, 0)
            return

        # Acquire lock to prevent recursion on drawing.
        self._lock += 1

        # Draw the widget.
        self.draw ()
        self._image.set_alpha (self.opacity)
        if self.parent != None:
            resize = oldrect != self._rect
            self.parent.update (children={ self : oldrect }, resize=resize)

        # Release previously set lock.
        self._lock = max (self._lock - 1, 0)
        self.dirty = False

    def destroy (self):
        """W.destroy () -> None

        Destroys the widget and removes it from its event system.

        Causes the widget to destroy itself as well as its controls and
        removes all from the connected event manager and sprite groups
        using the sprite.kill() method.
        """
        if isinstance (self.parent, BaseWidget):
            raise AttributeError ("widget still has a parent relationship")
        self.run_signal_handlers (SIG_DESTROYED)
        self.emit (SIG_DESTROYED, self)

        # Clear the associated controls.
        _pop = self._controls.pop
        while len (self._controls) > 0:
            control = _pop ()
            control.parent = None
            control.destroy ()
            del control
        del self._controls

        if self._indexable != None:
            index = self._indexable
            self._indexable = None
            index.remove_index (self)
        if self._manager != None:
            self._manager.remove_object (self)
        
        BaseObject.destroy (self) # Clear BaseObject internals.
        self.kill ()              # Clear Sprite
        #del self.parent
        del self._indexable
        del self._bg
        del self._style
        del self._image
        del self._rect
        del self._oldrect
        del self


    # DEPRECATED
    position = property (lambda self: self.topleft,
                         lambda self, (x, y): self.set_position (x, y),
                         doc = "The position of the topleft corner.")
    eventarea = property (lambda self: self.rect_to_client (),
                          lambda self, var: self.set_event_area (var),
                          doc = "The area, which gets the events.")

    minsize = property (lambda self: (self._minwidth, self._minheight),
                     lambda self, (w, h): self.set_minimum_size (w, h),
                     doc = "The guaranteed size of the widget.")
    maxsize = property (lambda self: (self._maxwidth, self._maxheight),
                        lambda self, (w, h): self.set_maximum_size (w, h),
                        doc = "The maximum size to occupy by the widget.")
    image = property (lambda self: self._image,
                      doc = "The visible surface of the widget.")
    rect = property (lambda self: self._get_rect (),
                     doc = "The area occupied by the widget.")
    index = property (lambda self: self._index,
                      lambda self, var: self.set_index (var),
                      doc = "The tab index position of the widget.")
    style = property (lambda self: self._style,
                      lambda self, var: self.set_style (var),
                      doc = "The style of the widget.")
    state = property (lambda self: self._state,
                      lambda self, var: self.set_state (var),
                      doc = "The current state of the widget.")
    focus = property (lambda self: self._focus,
                      lambda self, var: self.set_focus (var),
                      doc = "The focus of the widget.")
    sensitive = property (lambda self: self._sensitive,
                          lambda self, var: self.set_sensitive (var),
                          doc = "The sensitivity of the widget.")
    dirty = property (lambda self: self._dirty,
                      lambda self, var: self.set_dirty (var),
                      doc = """Indicates, whether the widget need to be
                      redrawn.""")
    controls = property (lambda self: self._controls,
                         doc = "Widgets associated with the widget.")
    depth = property (lambda self: self._depth,
                      lambda self, var: self.set_depth (var),
                      doc = "The z-axis layer depth of the widget.")
    tooltip = property (lambda self: self._tooltip,
                        lambda self, var: self.set_tooltip (var),
                        doc = "The tool tip text to display for the widget.")
    locked = property (lambda self: self._lock > 0,
                       doc = "Indicates, whether the widget is locked.")
    indexable = property (lambda self: self._indexable,
                          lambda self, var: self.set_indexable (var),
                          doc = "The IIndexable, the widget is attached to.")
    entered = property (lambda self: self._entered,
                        lambda self, var: self.set_entered (var),
                        doc = "Indicates, whether the widget is entered.")
    opacity = property (lambda self: self._opacity,
                        lambda self, var: self.set_opacity (var),
                        doc = "The opacity of the widget.")
Exemple #42
0
class Nutrient(AlphaGradient):
    """Nutrient is collected by Ants.

    Ants search for Nutrients. Each Ant can collect one Nutrient unit.
    Nutrient provide an interface for collection Nutrient units.

    Args:
        amount (:obj:`int`): The amount of nutrient units.
        rect (:obj:`Rect`): The position of the Nutrient on the display.
        surface (:obj:`Surface`): The surface to draw the Nutrient on.

    Attributes:
        rect (:obj:`Rect`): The position of the Nutrient on the display.
        surface (:obj:`Surface`): The surface to draw the Nutrient on.
    """
    def __init__(self, amount, background, width, height):
        self.background = background

        width, height = width/2, height/2

        self.surface = Surface((width, height))
        self.rect = self.surface.get_rect(
            width=width,
            height=height,
            centerx=width,
            centery=height
        )

        self._amount = int(abs(amount))

        # Mixin attributes
        self._xmin = 0
        self._xmax = amount
        self._ymin = 0
        self._ymax = 255

    @property
    def nutrient_unit(self):
        """:obj:`int`: Get a Nutrient unit."""
        if not self.empty():
            self._amount -= 1
            return 1

        raise NutrientEmptyError()

    def draw(self):
        """Draw Nutrient on surface."""
        self.surface.fill(NUTRIENT_COLOR)
        self.surface.set_alpha(int(self.get_alpha(self._amount)))
        self.background.blit(self.surface, self.rect)

    def empty(self):
        """Is Nutrient empty?

        Returns:
            :obj:`bool`: Is Nutirent amount zero.
        """
        return self._amount == 0

    def __str__(self):
        return '{} {}u'.format(__class__.__name__, self._amount)

    def __repr__(self):
        return '<{}(amount={}) at {}>'.format(__class__.__name__, self._amount, hex(id(self)))
Exemple #43
0
class Renderer(object):
    """ General object for a renderer.

    Store and manage cameras and has a method to render rects.
    """

    def __init__(self, level, screen_size):

        self.tiledmap = level.tiledmap
        self.screen_size = screen_size

        self.tw = self.tiledmap.tilewidth
        self.th = self.tiledmap.tileheight
        self.map_size = level.map_size
        self.level = level

        # list of cameras
        self.current_camera = None
        self.current_camera_index = 0
        self.camera_list = []

        # fade in out things
        self.fade_opacity = 0
        self.fading = 0
        self.fade_start_time = None
        self.fade_color = BLACK
        self.generate_fade_image(self.display_size)
        self.fading_speed = 0.003
        self.FADE_IN = 1
        self.FADE_OUT = -1

    def add_camera(self, camera):
        """ Adds a camera to this renderer.

        You can change the used camera while in game using next_camera().

        """

        if isinstance(camera, Camera):
            # the size of the screen diplayed to the player in tiles
            camera.screen_size_in_tiles = self.screen_size_in_tiles
            # the tile size in pixels
            tw = self.level.tiledmap.tilewidth
            th = self.level.tiledmap.tileheight
            mw = self.level.tiledmap.width
            mh = self.level.tiledmap.height

            camera.tile_size = (tw, th)
            # size of the whole map in tiles
            camera.map_size_in_tiles = (mw, mh)

            # size of the map in 'screens'
            mt = camera.map_size_in_tiles
            st = self.screen_size_in_tiles
            camera.map_size_in_screens = (mt[0] / st[0], mt[1] / st[1])

            self.camera_list.append(camera)

            if not self.current_camera:
                self.current_camera = camera
                self.current_camera_index = 0

            x = camera.sprite.rect.x
            y = camera.sprite.rect.y
            ts = (tw, th)
            # TODO move all this inside each camera with _after_init or 
            # any similar name
            if isinstance(camera, ScrollCamera):
                st = self.screen_size_in_tiles
                
                # The player should be in a rect that is considered the center
                # of the camera
                x = camera.sprite.rect.x
                y = camera.sprite.rect.y
                
                camera.camera_rect = Rect(x, y, st[0] * ts[0], st[1] * ts[1])
                camera.outview_rect = camera.camera_rect.inflate(camera.margins[0] * -1, camera.margins[1] * -1)
                # used when recentering the player in the camera
                camera.inview_rect = camera.camera_rect.inflate( camera.s_rect_size[0] - st[0] * ts[0], camera.s_rect_size[1] - st[1] * ts[1])
            if isinstance(camera, FreeCamera):
                camera.camera_rect = Rect(x, y, st[0] * ts[0], st[1] * ts[1])
        else:
            raise RendererError("Error! \'{0}\' is not a camera object!".format(camera))

    def next_camera(self):
        """ Switch to the next camera in the list. """
        try:
            self.current_camera = self.camera_list[self.current_camera_index + 1]
            self.current_camera_index += 1

        except LookupError:
            self.current_camera = self.camera_list[0]
            self.current_camera_index = 0

    def draw_rects(self, surface, rects, offset, size=1, color=WHITE):
        """ Draw all the pygame rects in a iterable.

        Used to draw the collision rects for debugging.
        """

        for rect in rects:
            pygame.draw.rect(surface, color, rect.move(offset[0] * -1 , offset[1] * -1), size)

    def generate_fade_image(self, display_size):
        """ Generate the image used for fade in/out. """
        self.display_size = display_size
        self.fade_image = Surface(self.display_size)
        self.fade_image.fill(self.fade_color)
        self.fade_image.set_alpha(0)

    def update_fading(self):
        """ Does the math to update the fade in/out alpha value. """

        # functions to calculate the opacity of the fade image
        def fun1(time):
            time = time / 1000.
            return 1 - exp(time*( - self.fading_speed))
        def fun2(time):
            time = time / 1000.
            return exp(time*(- self.fading_speed))

        # in the first update there is no fade_start_time
        if not self.fade_start_time:
            self.fade_start_time = time.get_ticks()
        t = time.get_ticks() - self.fade_start_time

        if self.fading == self.FADE_IN:
            # make it zero when it's almost zero
            if self.fade_opacity > 0.003:
                self.fade_opacity = fun2(t)
            else:
                self.fading = 0
                self.fade_opacity = 0

        elif self.fading == self.FADE_OUT:
            # make it one when it's almost one
            if self.fade_opacity < 0.997:
                self.fade_opacity = fun1(t)
            else:
                self.fading = 0
                self.fade_opacity = 1
        
        # calculate the alpha value and set it in the fade_image
        a = ceil(255 * self.fade_opacity)
        if a > 255: a = 255
        self.fade_image.set_alpha(a)

    def fade(self, value, fade_speed=3):
        """ Execute fade in/out.

        Use the constants FADE_IN FADE_OUT to specificate the type of 
        fade, the speed with fade_speed (a positive non-zero float value).
        """

        self.fading_speed = fade_speed
        self.fading = value
        self.fade_start_time = time.get_ticks()

    def toggle_fade(self):
        if self.fade_opacity == 1:
            self.fade(self.FADE_IN, 4)
        elif self.fade_opacity == 0:
            self.fade(self.FADE_OUT, 4)

    def dprint(self,text):
        """ If self.debugging is True it will print all the debugging 
        lines. """
        if self.debugging:
            print text
Exemple #44
0
class Main(Sprite):
    """
    Main glyph class
    image-- the image that text is set to
    rect-- rect for blitting image to viewing surface
    spacing-- line spacing
    links-- dict of (link, [rects]) pairs
    """


    ##################################################################
    # class methods
    def __init__(self, rect, **kwargs):
        """
        Initialize a glyph object

        rect-- rect object for positioning glyph image on viewing surface
        **kwargs-- dictionary of (env_id, value) pairs
          required kwargs are:
          bkg-- background color
          color-- font color
          font-- font
        """
        self.image = Surface(rect.size)#dodal ALPHA
        self.image.fill(kwargs['bkg'])
        self.image.set_alpha(255)


        self._bkg = kwargs['bkg']
        self.rect = rect
        self.spacing = kwargs['spacing']
        self.links = defaultdict(list)
        self._dest = Rect(0, 0, 0, 0) # rect for blitting a text line to image surface
        # list of (env_id, value) pairs for environments;
        # _envs is used as a stack data structure
        self._envs = [('bkg', kwargs['bkg']),
                      ('color', kwargs['color']),
                      ('font', kwargs['font']),
                      ('link', None)] # link id string
        #print self._envs
        self._buff = deque() # rendered text buffer


    ##################################################################
    # helper methods
    def __read_env(self, _txt_):
        # helper function to interpret
        # accepts the _txt_ iterable at an environment starting point
        # return (environment type, environment) tuple (e.g (font, Font object))

        # re to get env arguments (arguments may be paths and contain \ or /)
        r = re.compile('(\w+)(?:\s+([\w\s\.,=\\\\/]+))?\s*;')
        charbuffer = ''
        # _txt_ is a generator, so iterating consumes the contents for the
        # references to _txt_ in the _interpret function
        for i, char in _txt_:
            charbuffer += char
            s = r.search(charbuffer) # search for environment name arguments
            if s: # if search successful
                env = s.groups() # get environment
                if env[0] in Macros: return Macros[env[0]]
                # new environment types must be added here

                elif env[0] == 'bkg':
                    # return new backgroun color
                    return ('bkg', tuple([int(e) for e in env[1].split(',')]))

                elif env[0] == 'color':
                    # return new font color
                    return ('color', tuple([int(e) for e in env[1].split(',')]))

                elif env[0] == 'font':
                    # return new font
                    path, size = env[1].split(',') # the font location and size
                    return ('font', Font(os.path.realpath(path), int(size)))

                elif env[0] == 'link':
                    # return new link
                    return ('link', env[1].strip())
                elif env[0] == 'id': #moje
                    return('id', env[1].strip())

                else:
                    raise ValueError(env[0] + ' is an unrecognized environment')


    # the space func could take a size and return a surface or rect...
    # really only need to shift tokens.  surfs do that without requiring tokens
    # to have rects
    def __read_func(self, _txt_):
        # helper function to interpret
        # accepts the _txt_ iterable at function starting point
        # returns (function type, function results) tuple
        #   (eg. (space, Surface obejct))
        r = re.compile('(\w+){(.*?)}')
        i, char = _txt_.next()

        if char in SPECIALS: return char
        if char in WHITESPACE: return WHITESPACE[char]

        charbuff = char
        for i, char in _txt_:
            charbuff += char
            s = r.search(charbuff)
            if s:
                func, args = s.groups()
                if func in Macros: return Macros[func]

                if func == 'space': return Surface((int(args), 1))

                if charbuff == 'img': return image.load(args).convert()


    ##################################################################
    # private methods
    def _interpret(self, txt):
        # iterprets glyph markup language
        # accepts string literal
        # returns a list of (env, charbuff) pairs,
        #   where env is a dictionary of environment types keyed to values and
        #   charbuff a list of text strings and the surfaces created from functions
        envs = self._envs
        read_env, read_func = self.__read_env, self.__read_func
        iswhitespace = _iswhitespace

        # initialize charbuff, renderbuff, interpreted text, and previous character
        charbuff, interpreted_txt, prevchar = [], [], ''
        txt = txt.strip()
        _txt_ = enumerate(txt)
        for i, char in _txt_:
            if iswhitespace(char) and iswhitespace(prevchar):
                if char == '\n': charbuff[-1] = char
                continue

            if char == '/': # a function:
                char = read_func(_txt_)
                charbuff.append(char)
                prevchar = char

            elif char == '{': # a new environment has started
                # using dict(envs) allows new environments to overwrite default
                # environments, which are in the beginning of the list
                interpreted_txt.append((dict(envs), charbuff))
                charbuff = []
                envs.append(read_env(_txt_))

            elif char == '}': # an environment has ended
                interpreted_txt.append((dict(envs), charbuff))
                charbuff = []
                envs.pop()

            else: # a normal, string, character
                charbuff.append(char)
                prevchar = char
        if charbuff: interpreted_txt.append((dict(envs), charbuff))
        return interpreted_txt


    def _tokenize(self, interpreted_txt):
        # tokenizes text
        # accepts (envs, charbuff)
        # returns a list of tokens
        iswhitespace, token_builder = _iswhitespace, _token_builder

        charbuff, _interpreted_txt, tokenized_txt = [], [], []
        for (envs, chars) in interpreted_txt:
            for char in chars:
                if iswhitespace(char):
                    if charbuff:
                        _interpreted_txt.append((envs, charbuff))
                        charbuff = []

                    if _interpreted_txt:
                        yield token_builder(_interpreted_txt)
                        _interpreted_txt = []

                    yield token_builder([(envs, [char])])

                else: charbuff.append(char)

            if charbuff:
                _interpreted_txt.append((envs, charbuff))
                charbuff = []
        if _interpreted_txt: yield token_builder(_interpreted_txt)


    def _wrap(self, tokenized_txt, justify):
        # wrap interpreted text to page width
        # accepts a list of Token objects tuples
        # returns a list of Line objects, each wrapped to self.rect
        Line = _Line
        rect_w = self.rect.w

        # linesize tracks the current size of the rendered line because moving
        # between environments will mean that there will be multiple surfaces
        # that need to be glued together
        line = [] # initialize line, and linesize
        tokens = []
        for token in tokenized_txt:
            token_w = token.get_width()
            if token_w > rect_w:
                raise ValueError("The token '"+token.str+"' is "
                                 +str((token_w - rect_w))
                                 +" pixels too wide to fit in the rect passed.")

            # the token fits, process it and check if the line still fits inside
            # rect area, if not, append line without token, reinitialize line
            # with token
            txt = str(token)
            # print txt
            line.append(token)
            tokens.append(txt)

            
            

            if unicode(token) == '\n':
                # don't justify a line that would not wrap
                if justify == 'justified': _justify = 'left'
                else: _justify = justify

                yield Line(line, rect_w, _justify)
                line = [] # reset line

            elif sum(token.get_width() for token in line) > rect_w:
                token = line.pop()
                # remove single trailing whitespace
                if line[-1].iswhitespace: line = line[:-1]

                yield Line(line, rect_w, justify)
                line = [] # reinitialize _line, line, linesize, and number of objects
                # do not append whitespace as the first token of the new line
                if not token.iswhitespace: line.append(token)
        self.tokens = tokens

        if line:
            # don't justify a line that would not wrap
            if justify == 'justified': _justify = 'left'
            else: _justify = justify

            yield Line(line, rect_w, _justify)




    ##################################################################
    # public methods
    def input(self, txt, justify = None):
        """
        interprets, renders, wraps, and justifies input text

        txt -- raw text written with glyph markup
        justify -- a justify command; default is left justified
          left: left justified
          right: right justified
          justified: justified (both sides even)
          center: center justified

        returns nothing
        """
        buff, interpret, tokenize, wrap = self._buff, self._interpret, self._tokenize, self._wrap
        interpreted_txt = interpret(txt)
        tokens = tokenize(interpreted_txt)
        lines = wrap(tokens, justify)
        buff.extend(lines)




    def update(self):
        """
        updates the surface with the text input to the buffer by the input method, then deletes buffer

        accepts nothing

        returns nothing
        """
        buff, dest, image, links, rect, spacing = self._buff, self._dest, self.image, self.links, self.rect, self.spacing
        while buff:
            line = buff.popleft()
            line_h = line.get_height()
            if dest.y + line_h > rect.h:
                buff.append(line)
                break
            else:
                image.blit(line, dest)

                for link in line.links:
                    for _rect in line.links[link]:
                        # move rect to token's position in line and append to links
                        links[link].append(_rect.move(dest.topleft))


                dest.y += line_h + spacing


    def clear(self, surface_dest, background):
        """
        draws background over surface_dest using self.rect and resets self._dest

        surface_dest-- the destination surface that self.image has been drawn to
        background-- the background to draw over the areas that self.image was drawn to on surface_dest

        returns nothing
        """
        rect = self.rect
        self.image = Surface(rect.size)
        self.image.fill(self._bkg)
        self._dest = Rect(0, 0, 0, 0)
        self.links = defaultdict(list)
        surface_dest.blit(background, rect, rect)



    def get_collisions(self, mpos):
        """
        get collisions between a point and the linked text on the glyph surface

        mpos-- the point to check against the linked text

        if a link collides with mpos
          returns the link collinding with mpos
        if no link collides with mpos
          returns None
        """
        links, rect = self.links, self.rect
        for link in links:
            #print link
            for _rect in links[link]:


                if _rect.move(rect.topleft).collidepoint(mpos): return link
Exemple #45
0
def render_tooltips():
    """Render the tooltip for the object under the mouse."""
    obj = object_under_mouse()
    if obj:
        if obj.__class__.__name__ == "ClientMonster":
            hp_bar = True
        else:
            hp_bar = False

        bar_len = 100

        if CS.u.fov_map.in_fov(obj.x, obj.y):
            text = "You see: " + obj.name
        else:
            text = "You remember seeing: " + obj.name

        text_img = CS.font.render(text, True, CLR["white"])
        text_rect = text_img.get_rect()

        if hp_bar and text_rect.w < bar_len:
            surf_w = bar_len
        else:
            surf_w = text_rect.w

        surf_w += cfg.PADDING * 2 + cfg.BORDER_W * 2

        surf_h = text_rect.h + cfg.PADDING * 2 + cfg.BORDER_W * 2
        if hp_bar:
            surf_h += CS.font_h

        # pylint: disable=E1121
        tooltip_surf = Surface((surf_w, surf_h)).convert()
        # pylint: enable=E1121
        tooltip_surf.fill(CLR["black"])

        text_rect.centerx = surf_w / 2
        text_rect.top = cfg.BORDER_W + cfg.PADDING
        tooltip_surf.blit(text_img, text_rect)

        if hp_bar:
            render_bar(
                tooltip_surf,
                cfg.BORDER_W + cfg.PADDING,
                cfg.BORDER_W + cfg.PADDING + text_rect.h,
                bar_len,
                obj.hp,
                obj.max_hp,
                CS.hp_bar_color,
                CS.hp_bar_bg_color,
            )
            hp_img = CS.font.render(str(obj.hp) + " / " + str(obj.max_hp), True, CLR["white"])
            hp_rect = hp_img.get_rect()
            hp_rect.centerx = cfg.BORDER_W + cfg.PADDING + bar_len / 2
            hp_rect.top = cfg.BORDER_W + cfg.PADDING + text_rect.h
            tooltip_surf.blit(hp_img, hp_rect)

        rect = tooltip_surf.get_rect()
        x, rect.bottom = pygame.mouse.get_pos()

        # The lower left corner of the tooltip is next to the mouse, unless
        # doing so would print the tooltip off the right side of the screen.
        if x + rect.w > CS.screen_rect.w:
            rect.right = x
        else:
            rect.left = x

        add_surface_border(tooltip_surf)
        tooltip_surf.set_colorkey(CLR["floor_blue"])
        tooltip_surf.set_alpha(cfg.TOOLTIP_ALPHA)
        CS.screen.blit(tooltip_surf, rect)
Exemple #46
0
class Glyph(object):
    """
    Main glyph class
    image-- the image that text is set to
    rect-- rect for blitting image to viewing surface
    spacing-- line spacing
    links-- dict of (link, [rects]) pairs
    """

    ##################################################################
    # class methods
    def __init__(self, rect, bkg=BLACK, color=WHITE, font=FONT, spacing=0, ncols=1, col_space=20):  # FUTURE COLS ADD
        """
        Initialize a glyph object

        rect-- rect object for positioning glyph image on viewing surface
        **kwargs-- dictionary of (env_id, value) pairs
          required kwargs are:
          bkg-- background color
          color-- font color
          font-- font
        """
        # initialize
        self.image = Surface(rect.size)
        self.image.fill(bkg)
        self.image.set_alpha(255)
        self._bkg = bkg
        self.rect = rect
        self.spacing = spacing
        self.links = defaultdict(list)
        # FUTURE ###
        self.editors = {}
        ############
        # FUTURE COLS ###
        self.col_w = ((rect.w + col_space) / ncols) - col_space
        self.col_space = col_space
        self.col_n = 1
        self.ncols = ncols
        #################
        self._dest = Rect(0, 0, 0, 0)  # rect to blit a txt line to image surface
        # list of (env_id, value) pairs for environments;
        # _envs is used as a stack data structure
        self._envs = [("bkg", bkg), ("color", color), ("font", font), ("link", None)]  # link id string

        self.buff = deque()  # rendered text buffer

    ##################################################################
    # helper methods
    def __read_env(self, _txt_):
        # interprets and returns an environment.  environments set text
        # characteristics such as color or links.
        # accepts the _txt_ iterable at an environment starting point
        # return (environment type, environment) tuple (e.g (font, Font object))

        # re to get env arguments (arguments may be paths and contain \ or /)
        r = re.compile("(\w+)(\s+((\"|').*?(\"|')|.*?))?;")
        charbuffer = ""
        # _txt_ is a generator, so iterating consumes the contents for the
        # references to _txt_ in the _interpret function
        for i, char in _txt_:
            charbuffer += char
            s = r.search(charbuffer)  # search for environment name arguments
            if s:  # if search successful
                groups = s.groups()  # get environment
                env, args = groups[0], groups[2]
                if env in Macros:
                    return Macros[env]
                # new environment types must be added here

                elif env == "bkg":
                    # return new backgroun color
                    return ("bkg", tuple([int(e) for e in args.split(",")]))

                elif env == "color":
                    # return new font color
                    return ("color", tuple([int(e) for e in args.split(",")]))

                elif env == "font":
                    # return new font
                    path, size = args.split(",")  # the font location and size
                    return ("font", Font(os.path.realpath(path), int(size)))

                elif env == "link":
                    # return new link
                    return ("link", args.strip())

                # FUTURE ###
                elif env == "editor":
                    # editor is considered an environment because it must be
                    # linked.  any text in an editor environment is input to
                    # that editor, and any nested environments are ignored.
                    name, w = args.split(",")
                    # extract editor kw args
                    kw = dict(self._envs)
                    del kw["link"]
                    kw["spacing"] = self.spacing
                    h = kw["font"].get_linesize()
                    editor = Editor(Rect(0, 0, int(w), h), **kw)
                    self.editors[name] = editor
                    # treat as link env, get_collision will sort
                    return ("link", name)
                ############

                else:
                    raise ValueError(env + " is an unrecognized environment")

    # the space func could take a size and return a surface or rect...
    # really only need to shift tokens.  surfs do that without requiring tokens
    # to have rects
    def __read_func(self, _txt_):
        # interprets and returns a function.  functions are special surfaces or
        # objects.
        # accepts the _txt_ iterable at function starting point
        # returns (function type, function results) tuple
        #   (eg. (space, Surface obejct))
        r = re.compile("(\w+){(.*?)}")
        i, char = _txt_.next()

        if char in SPECIALS:
            return "special", char
        if char in WHITESPACE:
            return "whitespace", WHITESPACE[char]

        charbuff = char
        for i, char in _txt_:
            charbuff += char
            s = r.search(charbuff)
            if s:
                func, args = s.groups()
                if func in Macros:
                    return func, Macros[func]

                if func == "space":
                    return func, Surface((int(args), 1))
                # "if charbuff = 'img'"?
                if func == "img":
                    return func, pygame.image.load(args).convert()

    ##################################################################
    # private methods
    def _interpret(self, txt):
        # iterprets glyph markup language
        # accepts string literal
        # returns a list of (env, charbuff) pairs,
        #   where env is a dictionary of environment types keyed to values and
        #   charbuff a list of text strings and the surfaces created from
        #   functions
        editors, envs = self.editors, self._envs
        read_env, read_func = self.__read_env, self.__read_func
        iswhitespace = _iswhitespace

        txt = txt.strip()
        # FUTURE ###
        # preamble, txt = read_preamble(txt)
        # if preamble: envs = preamble
        # ##########

        # initialize charbuff, renderbuff, interpreted text, and previous char
        charbuff, interpreted_txt, prevchar = [], [], ""
        _txt_ = enumerate(txt)
        for i, char in _txt_:
            if iswhitespace(char) and iswhitespace(prevchar):
                if char == "\n":
                    charbuff[-1] = char
                continue

            if char == "/":  # a function:
                func, char = read_func(_txt_)
                charbuff.append(char)
                prevchar = char

            elif char == "{":  # a new environment has started
                # using dict(envs) allows new environments to overwrite default
                # environments, which are in the beginning of the list
                interpreted_txt.append((dict(envs), charbuff))
                charbuff = []
                envs.append(read_env(_txt_))

            elif char == "}":  # an environment has ended
                # FUTURE ###
                link = dict(envs)["link"]
                if link in editors:
                    editor = editors[link]
                    # this is a hack to feed char to editor using input method
                    for char in charbuff:
                        mod = 0
                        if char.isupper():
                            mod = 3
                        event = Event(KEYDOWN, key=None, mod=mod, unicode=char.encode("utf8"))
                        editor.input(event)
                    interpreted_txt.append((dict(envs), [editor.image]))
                else:
                    interpreted_txt.append((dict(envs), charbuff))
                # interpreted_txt.append((dict(envs), charbuff)) # FUTURE DEL
                ############
                charbuff = []
                envs.pop()

            else:  # a normal, string, character
                charbuff.append(char)
                prevchar = char
        if charbuff:
            interpreted_txt.append((dict(envs), charbuff))
        return interpreted_txt

    def _tokenize(self, interpreted_txt):
        # tokenizes text
        # accepts (envs, charbuff)
        # returns a list of tokens
        iswhitespace, token_builder = _iswhitespace, _token_builder

        charbuff, _interpreted_txt, tokenized_txt = [], [], []
        for (envs, chars) in interpreted_txt:
            for char in chars:
                if iswhitespace(char):
                    if charbuff:
                        _interpreted_txt.append((envs, charbuff))
                        charbuff = []

                    if _interpreted_txt:
                        yield token_builder(_interpreted_txt)
                        _interpreted_txt = []

                    yield token_builder([(envs, [char])])

                else:
                    charbuff.append(char)

            if charbuff:
                _interpreted_txt.append((envs, charbuff))
                charbuff = []
        if _interpreted_txt:
            yield token_builder(_interpreted_txt)

    def _wrap(self, tokenized_txt, justify):
        # wrap interpreted text to page width
        # accepts a list of Token objects tuples
        # returns a list of Line objects, each wrapped to self.rect
        Line = _Line
        # FUTURE COLS ###
        rect_w = self.col_w
        # rect_w = self.rect.w # FUTURE COLS DEL
        #################

        # linesize tracks the current size of the rendered line because moving
        # between environments will mean that there will be multiple surfaces
        # that need to be glued together
        line = []  # initialize line, and linesize
        for token in tokenized_txt:
            token_w = token.get_width()
            if token_w > rect_w:
                raise ValueError(
                    "The token '"
                    + token.str
                    + "' is "
                    + str((token_w - rect_w))
                    + " pixels too wide to fit in the rect passed."
                )

            # the token fits, process it and check if the line still fits inside
            # rect area, if not, append line without token, reinitialize line
            # with token
            line.append(token)
            if unicode(token) == "\n":
                # don't justify a line that would not wrap
                if justify == "justified":
                    _justify = "left"
                else:
                    _justify = justify

                yield Line(line, rect_w, _justify)
                line = []  # reset line

            elif sum(token.get_width() for token in line) > rect_w:
                token = line.pop()
                # remove single trailing whitespace
                if line[-1].iswhitespace:
                    line = line[:-1]

                yield Line(line, rect_w, justify)
                line = []  # reinitialize _line, line, linesize, and num objects
                # do not append whitespace as the first token of the new line
                if not token.iswhitespace:
                    line.append(token)

        if line:
            # don't justify a line that would not wrap
            if justify == "justified":
                _justify = "left"
            else:
                _justify = justify

            yield Line(line, rect_w, _justify)

    ##################################################################
    # public methods
    def input(self, txt, justify=None, update=True):
        """
        interprets, renders, wraps, and justifies input text

        txt -- raw text written with glyph markup
        justify -- a justify command; default is left justified
          left: left justified
          right: right justified
          justified: justified (both sides even)
          center: center justified

        returns nothing
        """
        buff, interpret, tokenize, wrap = (self.buff, self._interpret, self._tokenize, self._wrap)
        interpreted_txt = interpret(txt)
        tokens = tokenize(interpreted_txt)
        lines = wrap(tokens, justify)
        buff.extend(lines)
        if update:
            self.update()

    def overwrite(self, txt, **kw):
        self.clear()
        self.input(txt, **kw)

    def update(self):
        """
        updates the surface with the text input to the buffer by the input
        method, then deletes buffer

        accepts nothing

        returns nothing
        """
        buff, dest = self.buff, self._dest
        spacing = self.spacing
        image, rect = self.image, self.rect
        editors, links = self.editors, self.links
        # FUTURE COLS ###
        ncols, col_n = self.ncols, self.col_n
        col_w, col_space = self.col_w, self.col_space
        #################

        while buff:
            line = buff.popleft()
            line_h = line.get_height()
            if dest.y + line_h > rect.h:
                buff.appendleft(line)
                # FUTURE COLS ###
                if col_n < ncols:
                    dest.move_ip(col_w + col_space, -dest.y)
                    col_n += 1
                else:
                    stderr.write(WARN_BUFF)
                    return 0
                # break # FUTURE COLS DEL
                #################
            else:
                image.blit(line, dest)

                for link in line.links:
                    for _rect in line.links[link]:
                        # move rect to token's pos on image and append to links
                        _rect.move_ip(dest.topleft)  # FUTURE ADD
                        # FUTURE DEL
                        # links[link].append(_rect.move(dest.topleft))
                        links[link].append(_rect)
                        # FUTURE ###
                        if link in editors:
                            editors[link].rect = _rect
                        ############

                dest.y += line_h + spacing

        # FUTURE ###
        for editor in editors.values():
            image.blit(editor.image, editor.rect)
        ############
        # FUTURE COLS ###
        self.col_n = col_n
        #################
        return 1

    def clear(self, *a):
        """
        draws background over surface_dest using self.rect and resets self._dest

        surface_dest-- the destination surface that self.image has been drawn to
        background-- the background to draw over the areas that self.image was
        drawn to on surface_dest

        returns nothing
        """
        # reset glyph
        self._dest = Rect(0, 0, 0, 0)
        self.links = defaultdict(list)
        self.col_n = 1
        self.buff = deque()
        rect = self.rect
        self.image = Surface(rect.size)
        self.image.fill(self._bkg)
        # if provided, clear a surface at glyph rect
        if a:
            surface_dest, background = a
            surface_dest.blit(background, rect, rect)

    def get_collisions(self, mpos):
        """
        get collisions between a point and the linked text on the glyph surface

        mpos-- the point to check against the linked text

        if a link collides with mpos
          returns the link collinding with mpos
        if no link collides with mpos
          returns None
        """
        editors, links, rect = self.editors, self.links, self.rect
        for link in links:
            for _rect in links[link]:
                if _rect.move(rect.topleft).collidepoint(mpos):
                    return link
Exemple #47
0
def dwarfgraph_loop(limit_mass=None):
    fondo = display.set_mode((ANCHO, ALTO), SCALED)
    fondo.fill(COLOR_BOX)

    fuente2 = font.SysFont('Verdana', 13, bold=True)

    render = fuente2.render('Mass', True, COLOR_TEXTO, COLOR_BOX)
    render = transform.rotate(render, -90)
    render_rect = render.get_rect(right=ANCHO - 53, centery=ALTO / 2)
    fondo.blit(render, render_rect)

    render = fuente2.render('Radius', True, COLOR_TEXTO, COLOR_BOX)
    render_rect = render.get_rect(x=3, y=3)
    fondo.blit(render, render_rect)

    text_mass = 'Mass: N/A'
    text_radius = 'Radius: N/A'
    text_density = 'Density: N/A'

    done = False
    data = {}

    lineas = WidgetGroup()
    linea_h = Linea(bg_rect, bg_rect.x, bg_rect.centery, bg_rect.w, 1, lineas)
    linea_v = Linea(bg_rect, bg_rect.centerx, bg_rect.y, 1, bg_rect.h, lineas)
    punto = Punto(bg_rect, bg_rect.centerx, bg_rect.centery, lineas)

    lim_img, lim_rect = None, None
    if limit_mass is not None:
        lim_y = find_and_interpolate(limit_mass, mass_keys, yes)
        lim_rect = Rect(54, lim_y + 26, bg_rect.w,
                        bg_rect.h - lim_y - 26 + bg_rect.y)
        lim_img = Surface(lim_rect.size)
        lim_img.set_alpha(150)

    move_x, move_y = True, True
    while not done:
        for e in event.get(
            [KEYDOWN, QUIT, MOUSEMOTION, MOUSEBUTTONDOWN, KEYUP]):
            if (e.type == KEYDOWN and e.key == K_ESCAPE) or e.type == QUIT:
                quit()
                exit()

            elif e.type == MOUSEMOTION:
                x, y = e.pos

                if move_y:
                    linea_h.move_y(y)
                    punto.move_y(y)

                if move_x:
                    linea_v.move_x(x)
                    punto.move_x(x)

                dx, dy = punto.rect.center
                if bg_rect.collidepoint(dx, dy):
                    mass = round(
                        find_and_interpolate(linea_h.rect.y - 26, yes,
                                             mass_keys), 5)
                    radius = round(
                        find_and_interpolate(linea_v.rect.x, exes,
                                             radius_keys), 3)

                    data.update({
                        'mass': mass,
                        'radius': radius,
                        'clase': 'Dwarf Planet',
                        'albedo': 40
                    })
                    d = density(mass, radius)
                    text_mass = 'Mass: {}'.format(mass)
                    text_radius = 'Radius: {}'.format(radius)
                    text_density = 'Density: {}'.format(d)
                    color = bg.get_at((dx - 54, dy - 24))
                    composition = {}
                    s, i, r = 0, 0, 0
                    if tuple(color) == (63, 223, 0, 255):
                        i = 100
                    elif tuple(color) == (31, 255, 0,
                                          255):  # 10% silicates, 90% water ice
                        i = round(roll(60, 90), 2)
                        s = round(100 - i, 2)
                    elif tuple(color) == (95, 191, 0,
                                          255):  # 60% silicates, 40% water ice
                        s = round(roll(50, 60), 2)
                        i = round(100 - s, 2)
                    elif tuple(color) == (127, 159, 0,
                                          255):  # 90% silicates, 10% water ice
                        s = round(roll(60, 90), 2)
                        i = round(100 - s, 2)
                    elif tuple(color) == (159, 127, 0,
                                          255):  # 90% silicates, 10% iron
                        s = round(roll(60, 90), 2)
                        r = round(100 - s, 2)
                    elif tuple(color) == (191, 95, 0,
                                          255):  # 60% silicates, 40% iron
                        s = round(roll(50, 60), 2)
                        r = round(100 - s, 2)
                    elif tuple(color) == (223, 63, 0,
                                          255):  # 10% silicates, 90% iron
                        r = round(roll(60, 90), 2)
                        s = round(100 - r, 2)
                    elif tuple(color) == (255, 31, 0, 255):
                        r = 100

                    if s:
                        composition['silicates'] = s
                    if i:
                        composition['water ice'] = i
                    if r:
                        composition['iron'] = r

                    data['composition'] = composition
                else:
                    text_mass = 'Mass: N/A'
                    text_radius = 'Radius: N/A'
                    text_density = 'Density: N/A'

            elif e.type == MOUSEBUTTONDOWN:
                if e.button == 1:
                    done = True

            elif e.type == KEYDOWN:
                if e.key == K_SPACE:
                    done = True

                elif e.key == K_LSHIFT:
                    move_x = False

                elif e.key == K_LCTRL:
                    move_y = False

            elif e.type == KEYUP:
                if e.key == K_LSHIFT:
                    move_x = True

                elif e.key == K_LCTRL:
                    move_y = True

        render_mass = fuente.render(text_mass, True, COLOR_TEXTO, COLOR_BOX)
        render_radius = fuente.render(text_radius, True, COLOR_TEXTO,
                                      COLOR_BOX)
        render_density = fuente.render(text_density, True, COLOR_TEXTO,
                                       COLOR_BOX)

        fondo.fill(COLOR_BOX)
        fondo.blit(render_mass, (3, ALTO - 20))
        fondo.blit(render_radius, (150, ALTO - 20))
        fondo.blit(render_density, (300, ALTO - 20))
        fondo.blit(bg, bg_rect)
        if limit_mass is not None:
            fondo.blit(lim_img, lim_rect)
        numbers.draw(fondo)
        lineas.update()
        lineas.draw(fondo)
        display.update()

    display.quit()
    return data