# This is a widget that handles a go game # It needs a goban object, and handles it from beginning to end import os import gtk import goban class GoGame(gtk.HBox): """ This class draws a board and some information about the game (turn, captures, etc). It also handles moves and other operations on the goban. """ img_res = None def __init__(self, goban, network_mode=False, our_color=None): super(GoGame, self).__init__() self.goban = goban if GoGame.img_res is None: GoGame.img_res = _build_img_res() self.init_widgets() def init_widgets(self): # All of this is to create the info box along the right side of the board info_box = gtk.VBox() info_rows = [] for i in range(3): info_rows.append(gtk.HBox()) to_move_label = gtk.Label('To Move:') black_cap_label = gtk.Label('Black Captures:') white_cap_label = gtk.Label('White Captures:') self.to_move_value = gtk.Label('None') self.black_cap_value = gtk.Label('0') self.white_cap_value = gtk.Label('0') info_rows[0].pack_start(to_move_label, expand=False, padding=5) info_rows[1].pack_start(black_cap_label, expand=False, padding=5) info_rows[2].pack_start(white_cap_label, expand=False, padding=5) info_rows[0].pack_end(self.to_move_value, expand=False, padding=5) info_rows[1].pack_end(self.black_cap_value, expand=False, padding=5) info_rows[2].pack_end(self.white_cap_value, expand=False, padding=5) for row in info_rows: info_box.pack_start(row, expand=False) self.pass_button = gtk.Button('Pass') self.resign_button = gtk.Button('Resign') self.pass_button.connect('clicked', self.on_pass) self.resign_button.connect('clicked', self.on_resign) info_box.pack_start(self.pass_button, expand=False, padding=10) info_box.pack_start(self.resign_button, expand=False, padding=10) self.board_area = gtk.DrawingArea() self.board_area.set_size_request(800, 800) self.board_area.set_events(gtk.gdk.POINTER_MOTION_MASK | gtk.gdk.POINTER_MOTION_HINT_MASK | gtk.gdk.BUTTON_PRESS_MASK | gtk.gdk.BUTTON_RELEASE_MASK) self.board_area.connect('expose-event', self.draw_board) self.board_area.connect('motion-notify-event', self.do_hover) self.board_area.connect('button-press-event', self.do_play) self.pack_start(self.board_area) self.pack_end(info_box, expand=False) def do_hover(self, widget, event): x = event.x y = event.y width, height = widget.size_request() size = min(width, height) board_size = self.goban.board_size inc = size / board_size row = int(y / inc) col = int(x / inc) if max(row,col) < board_size: if self.goban._real_pos((row,col)) != self.goban.hover: self.goban.set_hover((row,col)) else: self.goban.clear_hover() def do_play(self, widget, event): print 'GoGame:do_play(): stub' # fixme: create a backbuffer pixmap and draw to *that* when we need to update # the board, then just use *this* to print that to the DrawingArea... def draw_board(self, widget, event): gc = widget.get_style().fg_gc[gtk.STATE_NORMAL] drawable = widget.window # pixmap = gtk.gdk.Pixmap(window, width, height, depth=-1) width, height = widget.size_request() size = min(width, height) board_size = self.goban.board_size inc = size / board_size for i in range(len(self.goban.board)): # Get the right image and scale it base_img = GoGame.img_res[self.goban.draw_code(i)] img = base_img.scale_simple(inc, inc, gtk.gdk.INTERP_BILINEAR) row = i / board_size col = i % board_size drawable.draw_pixbuf(gc, img, 0, 0, inc * col, inc * row, inc, inc) def on_pass(self, widget): print 'GoGame.on_pass(): stub' def on_resign(self, widget): print 'GoGame.on_resign(): stub' # pixmap.draw_pixbuf(None, pixbuf, 0, 0, x, y, -1, -1, gtk.gdk.RGB_DITHER_NONE, 0, 0) def _magnitude(vector): x,y = vector return math.sqrt(x*x + y*y) def _build_img_res(): ret = {} triangle = _load_png('go_t.png') circle = _load_png('go_c.png') ret['w'] = _load_png('go_w.png') ret['wT'] = _load_png('go_w.png') ret['wH'] = _load_png('go_w.png', 128) width = ret['wT'].get_width() height = ret['wT'].get_height() triangle.composite(ret['wT'], 0, 0, width, height, 0, 0, 1, 1, gtk.gdk.INTERP_NEAREST, 255) ret['b'] = _load_png('go_b.png') ret['bT'] = _load_png('go_b.png') ret['bH'] = _load_png('go_b.png', 128) width = ret['bT'].get_width() height = ret['bT'].get_height() triangle.composite(ret['bT'], 0, 0, width, height, 0, 0, 1, 1, gtk.gdk.INTERP_NEAREST, 255) for d in ('u', 'd', 'l', 'r', 'm', 'dl', 'dr', 'ul', 'ur', 'h'): ret[d] = _load_png('go_' + d + '.png') ret[d + 'C'] = _load_png('go_' + d + '.png') width = ret[d + 'C'].get_width() height = ret[d + 'C'].get_height() circle.composite(ret[d + 'C'], 0, 0, width, height, 0, 0, 1, 1, gtk.gdk.INTERP_NEAREST, 255) return ret def _load_png(name, alpha=None): """ Load image and return image object""" fullname = os.path.join('ui/res/', name) image = gtk.gdk.pixbuf_new_from_file(fullname) if alpha is not None: image = _set_alpha(image, alpha) return image _trans_png = None def _set_alpha(image, alpha): """ change_opacity - changes the opacity of pixbuf by combining the pixbuf with a pixbuf derived from a transparent .png arguments: alpha - returns: a pixbuf with the transperancy """ global _trans_png if _trans_png is None: _trans_png = _load_png('transparent.png') width = image.get_width() height = image.get_height() _trans_png = _trans_png.scale_simple(width,height,gtk.gdk.INTERP_NEAREST) image.composite(_trans_png, 0, 0, width, height, 0, 0, 1, 1, gtk.gdk.INTERP_NEAREST, alpha)