import os import zmq import logbook import urwid from network.client import Discoverer log = logbook.Logger(__name__) def button_width(btn): return len(btn.label) + 4 def focusable(widget): return urwid.AttrMap(widget, None, focus_map='reversed') class Browser(Discoverer): SERVER_KIND = 'robots' def __init__(self, avail_walker, added_walker, ctx=None): super(Browser, self).__init__(self.SERVER_KIND) if ctx is None: ctx = zmq.Context.instance() self.ctx = ctx self.targets = {} self.added = [] self.avail_walker = avail_walker self.added_walker = added_walker def make_server_widget(self, target, info): return urwid.AttrMap( urwid.Text(info['name']), 'bright', ) def make_bot_widget(self, key, server_info, name): button = urwid.Button('Add') def on_button_pressed(_): self.added.append((key, server_info, name)) self.update_added() urwid.connect_signal(button, 'click', on_button_pressed) return focusable(urwid.Columns([ urwid.Text(' ' * 4 + name), (button_width(button), button), ])) def make_added_widget(self, key, server_info, name): button = urwid.Button('Remove') widget = focusable(urwid.Columns([ urwid.Text(server_info['name'] + ' / ' + name), (button_width(button), button), ])) def on_button_pressed(_): self.added.remove((key, server_info, name)) self.update_added() urwid.connect_signal(button, 'click', on_button_pressed) return widget def on_services_changed(self): current_targets = set() for service in self.services.values(): if service is None: continue target = service['target'] current_targets.add(target) if target in self.targets: continue sock = self.ctx.socket(zmq.REQ) sock.connect(target) sock.send_json({'action': 'list'}) response = sock.recv_json() if response['status'] == 200: self.targets[target] = { 'name': str(service['name']), 'bots': response['bots'], } for target in list(self.targets.keys()): if target not in current_targets: del self.targets[target] self.update_avail() def update_avail(self): things = [] for target, info in sorted( self.targets.items(), key=lambda item: item[1]['name'], ): things.append(self.make_server_widget(target, info)) for name in sorted(info['bots']): key = (target, name) things.append(self.make_bot_widget(key, info, name)) things.append(urwid.Text('')) self.avail_walker[:] = things def update_added(self): things = [] for key, server_info, name in self.added: things.append(self.make_added_widget(key, server_info, name)) self.added_walker[:] = things def make_ui(avail_walker, added_walker): start_game = urwid.Button('Start Game') def on_start_game(_): raise urwid.ExitMainLoop() urwid.connect_signal(start_game, 'click', on_start_game) main = urwid.Columns([ urwid.Frame( urwid.LineBox(urwid.ListBox(avail_walker)), header=urwid.Text('Available bots:'), ), urwid.Frame( urwid.Pile([ urwid.LineBox(urwid.ListBox(added_walker)), ('pack', urwid.Padding( focusable(start_game), align='right', width=button_width(start_game), )), ]), header=urwid.Text('Bots in game:'), ), ]) stdout = urwid.Text('') def update_stdout(data): content = stdout.text + data.decode('utf-8') lines = content.split('\n') stdout.set_text('\n'.join(lines[-5:])) frame = urwid.Frame(main, footer=urwid.LineBox(stdout)) return frame, update_stdout def choose_bots(): avail_walker = urwid.SimpleFocusListWalker([]) added_walker = urwid.SimpleFocusListWalker([]) frame, update_stdout = make_ui(avail_walker, added_walker) mainloop = urwid.MainLoop( frame, palette=[('reversed', 'standout', '')], event_loop=urwid.GLibEventLoop(), ) pipe = mainloop.watch_pipe(update_stdout) handler = logbook.StreamHandler(os.fdopen(pipe, 'w')) with handler.applicationbound(): browser = Browser(avail_walker, added_walker) mainloop.run() return [key for key, _, _ in browser.added] def main(): bots = choose_bots() print(bots) if __name__ == '__main__': main()