import os import sys import math import pygame from pygame.locals import * import sgc from sgc.locals import * import socket import goban import gtpsocket import networkthread class GUI: def __init__(self, goban, settings): # Basic screen init pygame.init() # screen = pygame.display.set_mode((1000, 800)) self.screen = sgc.surface.Screen((1000,800)) pygame.display.set_caption('pyGo') # SGC font color sgc.Font.col = (10,10,10) # Create the background object, make it blank # background = pygame.Surface(screen.get_size()) # background = background.convert() # background.fill((250, 250, 250)) # Build the dict of image objects self.img_res = _build_img_res() self.goban = goban self.settings = settings # Network-related settings self.net_thread = None self.socket = None self.network_mode = False self.our_color = None self.board_size = 800 self.board_inc = self.board_size / 19 self.screen.fill((250, 250, 250)) self.join_btn = sgc.widgets.Button(label="Join Game", pos=(850,400)) self.join_btn.activate = self.join_game self.join_btn.add() self.wait_btn = sgc.widgets.Button(label="Listen", pos=(850,475)) self.wait_btn.activate = self.wait_for_game self.wait_btn.add() self.pass_btn = sgc.widgets.Button(label="Pass", pos=(850,550)) self.pass_btn.activate = goban.pass_move self.pass_btn.add() self.resign_btn = sgc.widgets.Button(label="Resign", pos=(850,625)) self.resign_btn.activate = goban.resign self.resign_btn.add() self.quit_btn = sgc.widgets.Button(label="Quit", pos=(850,700)) self.quit_btn.activate = sys.exit self.quit_btn.add() wait_label = sgc.widgets.Label(text='Waiting for a connection') self.wait_dialog = sgc.widgets.Dialog(title="Please wait...", widget=wait_label) self.wait_dialog.rect.center = self.screen.rect.center # Generate a spurious event once a second, just to # force an update pygame.time.set_timer(USEREVENT, 1000) def do_event(self): event = pygame.event.wait() sgc.widgets.event(event) if event.type == QUIT: return if self.network_mode: # This set of events should only be called if we can currently play if self.goban.to_move == self.our_color: print 'Processing an event while it is our turn: {}'.format(event) # Hover a transparent stone over our # cursor position, assuming play is legal if event.type == MOUSEMOTION: with self.net_thread.goban_lock: self.do_hover(event) if event.type == MOUSEBUTTONDOWN: x, y = event.pos row = y / self.board_inc col = x / self.board_inc if x <= self.board_size: if event.button == 1: with self.net_thread.send_lock: col_letter = chr(col + 96) self.socket.send(col_letter + str(row)) self.goban.play_move((row, col)) # Local play mode else: # Hover a transparent stone over our # cursor position, assuming play is legal if event.type == MOUSEMOTION: self.do_hover(event) # Place a stone on left-click if event.type == MOUSEBUTTONDOWN: x, y = event.pos row = y / self.board_inc col = x / self.board_inc if x < self.board_size and y < self.board_size: if event.button == 1: self.goban.play_move((row, col)) # if event.type == USEREVENT: # goban.elapsed_time += 1 # Cleanup removed windows # for widget in dialogs: # if not widget.active(): # dialogs.remove(widget) def update(self): board = self.goban.draw_board(self.board_size, self.img_res) self.screen.blit(board, (0,0)) text = self.goban.draw_info() self.screen.blit(text, (815, 25)) sgc.widgets.update(0) pygame.display.flip() # fixme: this uses localhost as a stub def join_game(self): try: sock = socket.create_connection(("127.0.0.1", 6859)) except socket.error as exception: print 'Error: Socket creation failed: {}'.format(exception.args) else: self.socket = gtpsocket.GTPSocket(sock) self.net_thread = networkthread.NetworkThread(self.goban, sock) self.net_thread.start() self.network_mode = True self.our_color = goban.Goban.BLACK # fixme: this uses localhost as a stub def wait_for_game(self): self.wait_dialog.add() self.update() try: sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.bind(("127.0.0.1", 6859)) sock.listen(1) conn, addr = sock.accept() sock.close() except socket.error as exception: print 'Error: Socket creation failed: {}'.format(exception.args) else: self.socket = gtpsocket.GTPSocket(conn) self.net_thread = networkthread.NetworkThread(self.goban, conn) self.net_thread.start() self.network_mode = True self.our_color = goban.Goban.WHITE finally: self.wait_dialog.remove() self.update() def do_hover(self, event): x, y = event.pos row = y / self.board_inc col = x / self.board_inc if _magnitude(event.rel) < 3: if x < self.board_size and y < self.board_size: self.goban.set_hover((row,col)) else: self.goban.clear_hover() elif self.goban.hover != self.goban._real_pos((row,col)): self.goban.clear_hover() def _magnitude(vector): x,y = vector return math.sqrt(x*x + y*y) def _load_png(name, alpha=None): """ Load image and return image object""" fullname = os.path.join('res', name) try: image = pygame.image.load(fullname) if image.get_alpha() is None: image = image.convert() else: image = image.convert_alpha() if alpha is not None: image.set_alpha(alpha) except pygame.error, message: print 'Cannot load image:', fullname raise SystemExit, message return image def _build_img_res(): ret = {} triangle = _load_png('go_t.png') ret['w'] = _load_png('go_w.png') ret['wT'] = _load_png('go_w.png') ret['wT'].blit(triangle, (0,0)) ret['wH'] = _load_png('go_w.png', 128) ret['b'] = _load_png('go_b.png') ret['bT'] = _load_png('go_b.png') ret['bT'].blit(triangle, (0,0)) ret['bH'] = _load_png('go_b.png', 128) circle = _load_png('go_c.png') 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') ret[d + 'C'].blit(circle, (0,0)) return ret