def create_database(self): dialog = Gtk.FileChooserDialog( _("Create New Pgn Database"), mainwindow(), Gtk.FileChooserAction.SAVE, (Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL, Gtk.STOCK_NEW, Gtk.ResponseType.ACCEPT)) dialog.set_current_folder(os.path.expanduser("~")) dialog.set_current_name("new.pgn") response = dialog.run() if response == Gtk.ResponseType.ACCEPT: new_pgn = dialog.get_filename() if not new_pgn.endswith(".pgn"): new_pgn = "%s.pgn" % new_pgn if not os.path.isfile(new_pgn): # create new file with open(new_pgn, "w"): pass self.open_chessfile(new_pgn) else: d = Gtk.MessageDialog(mainwindow(), type=Gtk.MessageType.ERROR, buttons=Gtk.ButtonsType.OK) d.set_markup(_("<big><b>File '%s' already exists.</b></big>") % new_pgn) d.run() d.hide() print("%s allready exist." % new_pgn) dialog.destroy()
def on_selection_changed(self, selection): model, iter = selection.get_selected() if iter is None: self.gamemodel.boards = [Board(FEN_EMPTY)] del self.gamemodel.moves[:] self.boardview.shown = 0 self.boardview.redrawCanvas() return path = self.persp.gamelist.get_model().get_path(iter) rec, ply = self.persp.gamelist.get_record(path) if rec is None: return try: self.persp.chessfile.loadToModel(rec, -1, self.gamemodel) except LoadingError as err: dialogue = Gtk.MessageDialog(mainwindow(), type=Gtk.MessageType.WARNING, buttons=Gtk.ButtonsType.OK, message_format=err.args[0]) if len(err.args) > 1: dialogue.format_secondary_text(err.args[1]) dialogue.connect("response", lambda dialogue, a: dialogue.hide()) dialogue.show() self.boardview.lastMove = None self.boardview._shown = self.gamemodel.lowply self.boardview.redrawCanvas() self.boardview.shown = ply if ply > 0 else self.persp.gamelist.ply
def on_save_as_clicked(self, widget): dialog = Gtk.FileChooserDialog( _("Save as"), mainwindow(), Gtk.FileChooserAction.SAVE, (Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL, Gtk.STOCK_SAVE, Gtk.ResponseType.ACCEPT)) dialog.set_current_folder(os.path.expanduser("~")) response = dialog.run() if response == Gtk.ResponseType.ACCEPT: filename = dialog.get_filename() else: filename = None dialog.destroy() if filename is None: return self.progress_dialog.set_title(_("Save as")) def save_as(cancel_event): with open(filename, "w") as to_file: self.process_records(self.save_records, cancel_event, to_file) GLib.idle_add(self.progress_dialog.hide) cancel_event = threading.Event() loop = asyncio.get_event_loop() loop.run_in_executor(None, save_as, cancel_event) response = self.progress_dialog.run() if response == Gtk.ResponseType.CANCEL: cancel_event.set() self.progress_dialog.hide()
def on_pick_date(button, date_entry): # Parse the existing date date = date_entry.get_text() year, month, day = parseDateTag(date) # Prepare the date of the picker calendar = Gtk.Calendar() curyear, curmonth, curday = calendar.get_date() year = curyear if year is None else year month = curmonth if month is None else month - 1 day = curday if day is None else day calendar.select_month(month, year) calendar.select_day(day) # Show the dialog dialog = Gtk.Dialog(_("Pick a date"), mainwindow(), Gtk.DialogFlags.MODAL | Gtk.DialogFlags.DESTROY_WITH_PARENT, (Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL, Gtk.STOCK_OK, Gtk.ResponseType.ACCEPT)) sw = Gtk.ScrolledWindow() sw.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC) sw.add(calendar) dialog.get_content_area().pack_start(sw, True, True, 0) dialog.resize(300, 200) dialog.show_all() response = dialog.run() dialog.destroy() if response == Gtk.ResponseType.ACCEPT: year, month, day = calendar.get_date() date_entry.set_text("%04d.%02d.%02d" % (year, month + 1, day))
def load_from_xml(self): if os.path.isfile(self.dockLocation): try: self.dock.loadFromXML(self.dockLocation, self.docks) except Exception as e: # We don't send error message when error caused by no more existing SwitcherPanel if e.args[0] != "SwitcherPanel" and "unittest" not in sys.modules.keys(): stringio = StringIO() traceback.print_exc(file=stringio) error = stringio.getvalue() log.error("Dock loading error: %s\n%s" % (e, error)) msg_dia = Gtk.MessageDialog(mainwindow(), type=Gtk.MessageType.ERROR, buttons=Gtk.ButtonsType.CLOSE) msg_dia.set_markup(_( "<b><big>PyChess was unable to load your panel settings</big></b>")) msg_dia.format_secondary_text(_( "Your panel settings have been reset. If this problem repeats, \ you should report it to the developers")) msg_dia.run() msg_dia.hide() os.remove(self.dockLocation) for title, panel, menu_item in self.docks.values(): title.unparent() panel.unparent()
def on_import_clicked(self, widget): dialog = Gtk.FileChooserDialog( _("Open chess file"), mainwindow(), Gtk.FileChooserAction.OPEN, (Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL, Gtk.STOCK_OPEN, Gtk.ResponseType.OK)) dialog.set_select_multiple(True) filter_text = Gtk.FileFilter() filter_text.set_name(".pgn") filter_text.add_pattern("*.pgn") filter_text.add_mime_type("application/x-chess-pgn") dialog.add_filter(filter_text) filter_text = Gtk.FileFilter() filter_text.set_name(".zip") filter_text.add_pattern("*.zip") filter_text.add_mime_type("application/zip") dialog.add_filter(filter_text) response = dialog.run() if response == Gtk.ResponseType.OK: filenames = dialog.get_filenames() else: filenames = None dialog.destroy() if filenames is not None: self.do_import(filenames) response = self.progress_dialog.run() if response == Gtk.ResponseType.CANCEL: self.importer.do_cancel() self.progress_dialog.hide()
def on_save_as_clicked(self, widget): dialog = Gtk.FileChooserDialog( _("Save as"), mainwindow(), Gtk.FileChooserAction.SAVE, (Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL, Gtk.STOCK_SAVE, Gtk.ResponseType.ACCEPT)) dialog.set_current_folder(os.path.expanduser("~")) response = dialog.run() if response == Gtk.ResponseType.ACCEPT: filename = dialog.get_filename() else: filename = None dialog.destroy() if filename is not None: with open(filename, "w") as to_file: records, plys = self.chessfile.get_records(FIRST_PAGE) self.save_records(records, to_file) while True: records, plys = self.chessfile.get_records(NEXT_PAGE) if records: self.save_records(records, to_file) else: break
def get_save_dialog(export=False): savedialog = Gtk.FileChooserDialog( "", mainwindow(), Gtk.FileChooserAction.SAVE, (Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL, Gtk.STOCK_SAVE, Gtk.ResponseType.ACCEPT)) savedialog.set_current_folder(os.path.expanduser("~")) # Add widgets to the savedialog savecombo = Gtk.ComboBox() savecombo.set_name("savecombo") crt = Gtk.CellRendererText() savecombo.pack_start(crt, True) savecombo.add_attribute(crt, 'text', 0) crt = Gtk.CellRendererText() savecombo.pack_start(crt, False) savecombo.add_attribute(crt, 'text', 1) if export: savecombo.set_model(exportformats) else: savecombo.set_model(saveformats) savecombo.set_active(1) # pgn savedialog.set_extra_widget(savecombo) return savedialog, savecombo
def get_open_dialog(): opendialog = Gtk.FileChooserDialog( _("Open chess file"), mainwindow(), Gtk.FileChooserAction.OPEN, (Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL, Gtk.STOCK_OPEN, Gtk.ResponseType.OK)) opendialog.set_show_hidden(True) opendialog.set_select_multiple(True) # All chess files filter all_filter = Gtk.FileFilter() all_filter.set_name(_("All Chess Files")) opendialog.add_filter(all_filter) opendialog.set_filter(all_filter) # Specific filters and save formats for ending, saver in enddir.items(): label = saver.__label__ endstr = "(%s)" % ending f = Gtk.FileFilter() f.set_name(label + " " + endstr) if hasattr(saver, "load"): f.add_pattern("*." + ending) all_filter.add_pattern("*." + ending) opendialog.add_filter(f) return opendialog
def __init__(self): self.window = Gtk.Window(Gtk.WindowType.TOPLEVEL, title=_("Ask for permissions")) self.window.set_transient_for(mainwindow()) vbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL) gtk_version = (Gtk.get_major_version(), Gtk.get_minor_version()) if gtk_version >= (3, 12): vbox.props.margin_start = 9 vbox.props.margin_end = 9 else: vbox.props.margin_left = 9 vbox.props.margin_right = 9 vbox.props.margin_bottom = 9 self.window.add(vbox) uistuff.keepWindowSize("externalsdialog", self.window, (320, 240), uistuff.POSITION_CENTER) label = Gtk.Label(_("Some of PyChess features needs your permission to download external programs")) vbox.pack_start(label, True, True, 0) box = Gtk.Box() check_button = Gtk.CheckButton(_("database querying needs scoutfish")) check_button.set_active(conf.get("download_scoutfish", False)) check_button.connect("toggled", lambda w: conf.set("download_scoutfish", w.get_active())) box.add(check_button) link = "https://github.com/pychess/scoutfish" link_button = Gtk.LinkButton(link, link) box.add(link_button) vbox.pack_start(box, False, False, 0) box = Gtk.Box() check_button = Gtk.CheckButton(_("database opening tree needs chess_db")) check_button.set_active(conf.get("download_chess_db", False)) check_button.connect("toggled", lambda w: conf.set("download_chess_db", w.get_active())) box.add(check_button) link = "https://github.com/pychess/chess_db" link_button = Gtk.LinkButton(link, link) box.add(link_button) vbox.pack_start(box, False, False, 0) box = Gtk.Box() check_button = Gtk.CheckButton(_("ICC lag compensation needs timestamp")) check_button.set_active(conf.get("download_timestamp", False)) check_button.connect("toggled", lambda w: conf.set("download_timestamp", w.get_active())) box.add(check_button) link = "https://www.chessclub.com/user/resources/icc/timestamp" link_button = Gtk.LinkButton(link, link) box.add(link_button) vbox.pack_start(box, False, False, 0) check_button = Gtk.CheckButton(_("Don't show this dialog on startup.")) check_button.set_active(conf.get("dont_show_externals_at_startup", False)) check_button.connect("toggled", lambda w: conf.set("dont_show_externals_at_startup", w.get_active())) vbox.pack_start(check_button, True, True, 0) buttonbox = Gtk.ButtonBox() close_button = Gtk.Button.new_from_stock(Gtk.STOCK_OK) close_button.connect("clicked", self.on_close_clicked) self.window.connect("delete_event", lambda w, a: self.window.destroy()) buttonbox.add(close_button) vbox.pack_start(buttonbox, False, False, 0)
def run(): global dialog dialog.widgets["fics_logon"].set_transient_for(mainwindow()) if dialog.lounge: dialog.lounge.present() else: dialog.present()
def paste(gamemodel): dialog = Gtk.MessageDialog(mainwindow(), type=Gtk.MessageType.QUESTION, buttons=Gtk.ButtonsType.YES_NO) if gamemodel.status in UNDOABLE_STATES: text = _("The current game is over. First, please verify the properties of the game.") else: text = _("The current game is not terminated. Its export may have a limited interest.") text += "\n\n" + _("Should %s publicly publish your game as PGN on chesspastebin.com ?") % NAME dialog.set_markup(text) response = dialog.run() dialog.destroy() if response != Gtk.ResponseType.YES: return output = StringIO() text = pgn.save(output, gamemodel) values = {'apikey': APIKEY, 'pgn': text, "name": "PyChess", 'sandbox': 'false'} data = urlencode(values).encode('utf-8') req = Request(URL, data) try: response = urlopen(req, timeout=10) except URLError as err: if hasattr(err, 'reason'): print('We failed to reach the server.') print('Reason: ', err.reason) elif hasattr(err, 'code'): print('The server couldn\'t fulfill the request.') print('Error code: ', err.code) else: ID = response.read() link = "http://www.chesspastebin.com/?p=%s" % int(ID) clipboard = Gtk.Clipboard.get(Gdk.SELECTION_CLIPBOARD) clipboard.set_text(link, -1) # print(text) # print(clipboard.wait_for_text()) msg_dialog = Gtk.MessageDialog(mainwindow(), type=Gtk.MessageType.INFO, buttons=Gtk.ButtonsType.OK) msg = _( "Game shared at ") + '<a href="%s">chesspastebin.com</a>' % link msg_dialog.set_markup(msg) msg_dialog.format_secondary_text(_("(Link is available on clipboard.)")) msg_dialog.connect("response", lambda msg_dialog, a: msg_dialog.hide()) msg_dialog.show()
def engineDead(self, engine, gmwidg): gmwidg.bringToFront() dialog = Gtk.MessageDialog(mainwindow(), type=Gtk.MessageType.ERROR, buttons=Gtk.ButtonsType.OK) dialog.set_markup(_("<big><b>Engine, %s, has died</b></big>") % repr(engine)) dialog.format_secondary_text(_( "PyChess has lost connection to the engine, probably because it has died.\n\n \ You can try to start a new game with the engine, or try to play against another one.")) dialog.connect("response", lambda dialog, r: dialog.hide()) dialog.show_all()
def notify(new_version): msg_dialog = Gtk.MessageDialog(mainwindow(), type=Gtk.MessageType.INFO, buttons=Gtk.ButtonsType.OK) msg = _("<b>New version %s is available!</b>" % new_version) msg_dialog.set_markup(msg) msg_dialog.format_secondary_markup('<a href="%s">%s</a>' % (LINK, LINK)) msg_dialog.connect("response", lambda msg_dialog, a: msg_dialog.hide()) msg_dialog.show()
def __init__(self): self.widgets = uistuff.GladeWidgets("tipoftheday.glade") self.widgets["window1"].set_transient_for(mainwindow()) uistuff.keepWindowSize("tipoftheday", self.widgets["window1"], (320, 240), uistuff.POSITION_CENTER) self.widgets["checkbutton1"].set_active(conf.get("show_tip_at_startup")) self.widgets["checkbutton1"].connect("toggled", lambda w: conf.set("show_tip_at_startup", w.get_active())) self.widgets["close_button"].connect("clicked", lambda w: self.widgets["window1"].emit("delete-event", None)) self.widgets["window1"].connect("delete_event", lambda w, a: self.widgets["window1"].destroy()) self.widgets["back_button"].connect("clicked", lambda w: self.set_currentIndex(self.currentIndex - 1)) self.widgets["forward_button"].connect("clicked", lambda w: self.set_currentIndex(self.currentIndex + 1)) self.currentIndex = 0
def __init__(self, widgets): # Init 'auto save" checkbutton def checkCallBack(_): """ :Description: Sets the various option based on user interaction with the checkboxes in the gui """ checkbox = widgets["autoSave"] widgets["autosave_grid"].set_property("sensitive", checkbox.get_active()) conf.notify_add("autoSave", checkCallBack) uistuff.keep(widgets["autoSave"], "autoSave", first_value=True) checkCallBack(_) default_path = os.path.expanduser("~") self.auto_save_path = conf.get("autoSavePath", default_path) conf.set("autoSavePath", self.auto_save_path) auto_save_chooser_dialog = Gtk.FileChooserDialog( _("Select auto save path"), mainwindow(), Gtk.FileChooserAction.SELECT_FOLDER, (Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL, Gtk.STOCK_OPEN, Gtk.ResponseType.OK)) auto_save_chooser_button = Gtk.FileChooserButton.new_with_dialog( auto_save_chooser_dialog) auto_save_chooser_button.set_current_folder(self.auto_save_path) widgets["savePathChooserDock"].add(auto_save_chooser_button) auto_save_chooser_button.show() def selectAutoSave(_): """ :Description: Sets the auto save path for stored games if it has changed since last time :signal: Activated on receiving the 'current-folder-changed' signal """ new_directory = auto_save_chooser_dialog.get_filename() if new_directory != self.auto_save_path: conf.set("autoSavePath", new_directory) auto_save_chooser_button.connect("current-folder-changed", selectAutoSave) conf.set("autoSaveFormat", conf.get("autoSaveFormat", "pychess")) uistuff.keep(widgets["autoSaveFormat"], "autoSaveFormat") uistuff.keep(widgets["saveEmt"], "saveEmt") uistuff.keep(widgets["saveEval"], "saveEval") uistuff.keep(widgets["saveRatingChange"], "saveRatingChange") uistuff.keep(widgets["indentPgn"], "indentPgn") uistuff.keep(widgets["saveOwnGames"], "saveOwnGames", first_value=True)
def _validate(gamemodel): try: fenstr = cls.get_fen() cls.setupmodel.variant(setup=fenstr) return True except (AssertionError, LoadingError, SyntaxError) as e: d = Gtk.MessageDialog(mainwindow(), type=Gtk.MessageType.WARNING, buttons=Gtk.ButtonsType.OK, message_format=e.args[0]) if len(e.args) > 1: d.format_secondary_text(e.args[1]) d.connect("response", lambda d, a: d.hide()) d.show() return False
def panel_about(self, button): store, iter = self.tv.get_selection().get_selected() assert iter # The button should only be clickable when we have a selection path = store.get_path(iter) panel = store[path][3] d = Gtk.MessageDialog(mainwindow(), type=Gtk.MessageType.INFO, buttons=Gtk.ButtonsType.CLOSE) d.set_markup("<big><b>%s</b></big>" % panel.__title__) text = panel.__about__ if hasattr( panel, '__about__') else _('Undescribed panel') d.format_secondary_text(text) d.run() d.hide()
def engine_default_options(button): if self.cur_engine is not None and not self.selection: engine = discoverer.getEngineByName(self.cur_engine) options = engine.get("options") if options: dialog = Gtk.MessageDialog(mainwindow(), type=Gtk.MessageType.QUESTION, buttons=Gtk.ButtonsType.YES_NO) dialog.set_markup(_("Do you really want to restore the default options of the engine ?")) response = dialog.run() dialog.destroy() if response == Gtk.ResponseType.YES: for option in options: if "default" in option: option["value"] = option["default"] self.update_options()
def _validate(gamemodel): try: text, loadType = _get_text() chessfile = loadType.load(StringIO(text)) chessfile.loadToModel(chessfile.games[0], -1, model=gamemodel) gamemodel.status = WAITING_TO_START return True except LoadingError as e: d = Gtk.MessageDialog(mainwindow(), type=Gtk.MessageType.WARNING, buttons=Gtk.ButtonsType.OK, message_format=e.args[0]) d.format_secondary_text(e.args[1]) d.connect("response", lambda d, a: d.hide()) d.show() return False
def create_book(self, new_bin=None): if new_bin is None: dialog = Gtk.FileChooserDialog( _("Create New Polyglot Opening Book"), mainwindow(), Gtk.FileChooserAction.SAVE, (Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL, Gtk.STOCK_NEW, Gtk.ResponseType.ACCEPT)) dialog.set_current_folder(os.path.expanduser("~")) dialog.set_current_name("new_book.bin") response = dialog.run() if response == Gtk.ResponseType.ACCEPT: new_bin = dialog.get_filename() if not new_bin.endswith(".bin"): new_bin = "%s.bin" % new_bin dialog.destroy() if new_bin is None: return self.progress_dialog.set_title(_("Create Polyglot Book")) def creating_book(cancel_event): positions = {} self.process_records(self.feed_book, cancel_event, positions) if cancel_event.is_set(): return with open(new_bin, "wb") as to_file: GLib.idle_add(self.progressbar.set_text, _("Save")) for key, moves in sorted(positions.items(), key=lambda item: item[0]): # print(key, moves) for move in moves: to_file.write(pack(">QHHI", key, move, moves[move], 0)) GLib.idle_add(self.emit, "bookfile_created") GLib.idle_add(self.progress_dialog.hide) cancel_event = threading.Event() loop = asyncio.get_event_loop() loop.run_in_executor(None, creating_book, cancel_event) response = self.progress_dialog.run() if response == Gtk.ResponseType.CANCEL: cancel_event.set() self.progress_dialog.hide()
def cancel_event(widget, with_confirmation, *args): # Confirm if the changes need to be saved modified = discoverer.hasChanged() if modified and with_confirmation: dialog = Gtk.MessageDialog(mainwindow(), type=Gtk.MessageType.QUESTION, buttons=Gtk.ButtonsType.YES_NO) dialog.set_markup(_("You have unsaved changes. Do you want to save before leaving?")) response = dialog.run() dialog.destroy() # if response == Gtk.ResponseType.CANCEL: # return False if response == Gtk.ResponseType.NO: discoverer.restore() if response == Gtk.ResponseType.YES: discoverer.save() # Close the window widgets["manage_engines_dialog"].hide() return True
def __init__(self, image, child): GObject.GObject.__init__(self) self.add(image) self.subwindow = Gtk.Window() self.subwindow.set_transient_for(mainwindow()) self.subwindow.set_decorated(False) self.subwindow.set_resizable(False) self.subwindow.set_type_hint(Gdk.WindowTypeHint.DIALOG) self.subwindow.add(child) self.subwindow.connect_after("draw", self.__sub_onExpose) self.subwindow.connect("button_press_event", self.__sub_onPress) # self.subwindow.connect("motion_notify_event", self.__sub_onMotion) # self.subwindow.connect("leave_notify_event", self.__sub_onMotion) # self.subwindow.connect("delete-event", self.__sub_onDelete) self.subwindow.connect("focus-out-event", self.__sub_onFocusOut) child.show_all() self.setOpen(False) self.connect("button_press_event", self.__onPress)
def onHelperConnectionError(self, connection, error): if self.helperconn is not None: dialog = Gtk.MessageDialog(mainwindow(), type=Gtk.MessageType.QUESTION, buttons=Gtk.ButtonsType.YES_NO) dialog.set_markup(_("Guest logins disabled by FICS server")) text = "PyChess can maintain users status and games list only if it changes\n\ 'open', 'gin' and 'availinfo' user variables.\n\ Do you enable to set these variables on?" dialog.format_secondary_text(text) response = dialog.run() dialog.destroy() self.helperconn.cancel() self.helperconn.close() self.helperconn = None set_user_vars = response == Gtk.ResponseType.YES @asyncio.coroutine def coro(): yield from self.main_connected_event.wait() self.connection.start_helper_manager(set_user_vars) asyncio.async(coro())
def onAssessReceived(self, glm, assess): if self.assess_sent: self.assess_sent = False dialog = Gtk.MessageDialog(mainwindow(), type=Gtk.MessageType.INFO, buttons=Gtk.ButtonsType.OK) dialog.set_title(_("Assess")) dialog.set_markup(_("Effect on ratings by the possible outcomes")) grid = Gtk.Grid() grid.set_column_homogeneous(True) grid.set_row_spacing(12) grid.set_row_spacing(12) name0 = Gtk.Label() name0.set_markup("<b>%s</b>" % assess["names"][0]) name1 = Gtk.Label() name1.set_markup("<b>%s</b>" % assess["names"][1]) grid.attach(Gtk.Label(""), 0, 0, 1, 1) grid.attach(name0, 1, 0, 1, 1) grid.attach(name1, 2, 0, 1, 1) grid.attach(Gtk.Label(assess["type"]), 0, 1, 1, 1) grid.attach(Gtk.Label(assess["oldRD"][0]), 1, 1, 1, 1) grid.attach(Gtk.Label(assess["oldRD"][1]), 2, 1, 1, 1) grid.attach(Gtk.Label(_("Win:")), 0, 2, 1, 1) grid.attach(Gtk.Label(assess["win"][0]), 1, 2, 1, 1) grid.attach(Gtk.Label(assess["win"][1]), 2, 2, 1, 1) grid.attach(Gtk.Label(_("Draw:")), 0, 3, 1, 1) grid.attach(Gtk.Label(assess["draw"][0]), 1, 3, 1, 1) grid.attach(Gtk.Label(assess["draw"][1]), 2, 3, 1, 1) grid.attach(Gtk.Label(_("Loss:")), 0, 4, 1, 1) grid.attach(Gtk.Label(assess["loss"][0]), 1, 4, 1, 1) grid.attach(Gtk.Label(assess["loss"][1]), 2, 4, 1, 1) grid.attach(Gtk.Label(_("New RD:")), 0, 5, 1, 1) grid.attach(Gtk.Label(assess["newRD"][0]), 1, 5, 1, 1) grid.attach(Gtk.Label(assess["newRD"][1]), 2, 5, 1, 1) grid.show_all() dialog.get_message_area().add(grid) dialog.run() dialog.destroy()
def __init__(self, widgets): self.widgets = widgets # Options on by default for key in ("opening_check", "endgame_check", "online_egtb_check", "inv_analyzer_check"): uistuff.keep(widgets[key], key, first_value=False) uistuff.keep(widgets["analyzer_check"], "analyzer_check", first_value=True) # Opening book default_path = os.path.join(addDataPrefix("pychess_book.bin")) path = conf.get("opening_file_entry", default_path) conf.set("opening_file_entry", path) book_chooser_dialog = Gtk.FileChooserDialog( _("Select book file"), mainwindow(), Gtk.FileChooserAction.OPEN, (Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL, Gtk.STOCK_OPEN, Gtk.ResponseType.OK)) book_chooser_button = Gtk.FileChooserButton.new_with_dialog( book_chooser_dialog) filter = Gtk.FileFilter() filter.set_name(_("Opening books")) filter.add_pattern("*.bin") book_chooser_dialog.add_filter(filter) book_chooser_button.set_filename(path) self.widgets["bookChooserDock"].add(book_chooser_button) book_chooser_button.show() def select_new_book(button): new_book = book_chooser_dialog.get_filename() if new_book: conf.set("opening_file_entry", new_book) else: # restore the original book_chooser_dialog.set_filename(path) book_chooser_button.connect("file-set", select_new_book) def on_opening_check_toggled(check): self.widgets["opening_hbox"].set_sensitive(check.get_active()) self.widgets["opening_check"].connect_after("toggled", on_opening_check_toggled) # Endgame default_path = os.path.join(getDataPrefix()) egtb_path = conf.get("egtb_path", default_path) conf.set("egtb_path", egtb_path) egtb_chooser_dialog = Gtk.FileChooserDialog( _("Select Gaviota TB path"), mainwindow(), Gtk.FileChooserAction.SELECT_FOLDER, (Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL, Gtk.STOCK_OPEN, Gtk.ResponseType.OK)) egtb_chooser_button = Gtk.FileChooserButton.new_with_dialog( egtb_chooser_dialog) egtb_chooser_button.set_current_folder(egtb_path) self.widgets["egtbChooserDock"].add(egtb_chooser_button) egtb_chooser_button.show() def select_egtb(button): new_directory = egtb_chooser_dialog.get_filename() if new_directory != egtb_path: conf.set("egtb_path", new_directory) egtb_chooser_button.connect("current-folder-changed", select_egtb) def on_endgame_check_toggled(check): self.widgets["endgame_hbox"].set_sensitive(check.get_active()) self.widgets["endgame_check"].connect_after("toggled", on_endgame_check_toggled) # Analyzing engines from pychess.widgets import newGameDialog data = [(item[0], item[1]) for item in newGameDialog.analyzerItems] uistuff.createCombo(widgets["ana_combobox"], data, name="ana_combobox") uistuff.createCombo(widgets["inv_ana_combobox"], data, name="inv_ana_combobox") def update_analyzers_store(discoverer): data = [(item[0], item[1]) for item in newGameDialog.analyzerItems] uistuff.updateCombo(widgets["ana_combobox"], data) uistuff.updateCombo(widgets["inv_ana_combobox"], data) discoverer.connect_after("all_engines_discovered", update_analyzers_store) update_analyzers_store(discoverer) # Save, load and make analyze combos active engine = discoverer.getEngineByName(discoverer.getEngineLearn()) if engine is None: engine = discoverer.getEngineN(-1) default = engine.get("md5") conf.set("ana_combobox", conf.get("ana_combobox", default)) conf.set("inv_ana_combobox", conf.get("inv_ana_combobox", default)) def on_analyzer_check_toggled(check): self.widgets["analyzers_vbox"].set_sensitive(check.get_active()) from pychess.widgets.gamewidget import widgets perspective = perspective_manager.get_perspective("games") if len(perspective.gamewidgets) != 0: if check.get_active(): for gmwidg in perspective.gamewidgets: asyncio. async ( gmwidg.gamemodel.restart_analyzer(HINT)) if not widgets["hint_mode"].get_active(): gmwidg.gamemodel.pause_analyzer(HINT) else: for gmwidg in perspective.gamewidgets: gmwidg.gamemodel.remove_analyzer(HINT) self.widgets["analyzers_vbox"].set_sensitive( widgets["analyzer_check"].get_active()) self.widgets["analyzer_check"].connect_after( "toggled", on_analyzer_check_toggled) def on_invanalyzer_check_toggled(check): self.widgets["inv_analyzers_vbox"].set_sensitive( check.get_active()) perspective = perspective_manager.get_perspective("games") if len(perspective.gamewidgets) != 0: if check.get_active(): for gmwidg in perspective.gamewidgets: asyncio. async (gmwidg.gamemodel.restart_analyzer(SPY)) if not widgets["spy_mode"].get_active(): gmwidg.gamemodel.pause_analyzer(SPY) else: for gmwidg in perspective.gamewidgets: gmwidg.gamemodel.remove_analyzer(SPY) self.widgets["inv_analyzers_vbox"].set_sensitive( widgets["inv_analyzer_check"].get_active()) self.widgets["inv_analyzer_check"].connect_after( "toggled", on_invanalyzer_check_toggled) # Give widgets to keeper uistuff.keep( self.widgets["ana_combobox"], "ana_combobox", anal_combo_get_value, lambda combobox, value: anal_combo_set_value( combobox, value, "hint_mode", "analyzer_check", HINT)) uistuff.keep( self.widgets["inv_ana_combobox"], "inv_ana_combobox", anal_combo_get_value, lambda combobox, value: anal_combo_set_value( combobox, value, "spy_mode", "inv_analyzer_check", SPY)) uistuff.keep(self.widgets["max_analysis_spin"], "max_analysis_spin", first_value=3) uistuff.keep(self.widgets["infinite_analysis"], "infinite_analysis", first_value=False)
def add(button): self.add = True response = engine_chooser_dialog.run() if response == Gtk.ResponseType.OK: new_engine = engine_chooser_dialog.get_filename() binname = os.path.split(new_engine)[1] ext = os.path.splitext(new_engine)[1] # Verify if the engine already exists under the same name if new_engine != "": for eng in discoverer.getEngines(): if eng["command"] == new_engine: msg_dia = Gtk.MessageDialog( mainwindow(), type=Gtk.MessageType.ERROR, buttons=Gtk.ButtonsType.OK) msg_dia.set_markup( _("<big><b>Unable to add %s</b></big>" % new_engine)) msg_dia.format_secondary_text( _("The engine is already installed under the same name" )) msg_dia.run() msg_dia.hide() new_engine = "" break # Detect the host application if new_engine != "": vm_name = None vm_args = None vmpath = "" # Scripting for vm in VM_LIST: if ext == vm.ext: vm_name = vm.name vm_args = vm.args break # Wine for Windows application under Linux if vm_name is None and new_engine.lower().endswith( ".exe") and sys.platform != "win32": vm_name = "wine" # Check that the interpreter is available if vm_name is not None: vmpath = shutil.which(vm_name, mode=os.R_OK | os.X_OK) if vmpath is None: msg_dia = Gtk.MessageDialog( mainwindow(), type=Gtk.MessageType.ERROR, buttons=Gtk.ButtonsType.OK) msg_dia.set_markup( _("<big><b>Unable to add %s</b></big>" % new_engine)) msg_dia.format_secondary_text( vm_name + _(" is not installed")) msg_dia.run() msg_dia.hide() new_engine = "" # Next checks if new_engine: vm_ext_list = [vm.ext for vm in VM_LIST] if ext not in vm_ext_list and not os.access( new_engine, os.X_OK): msg_dia = Gtk.MessageDialog(mainwindow(), type=Gtk.MessageType.ERROR, buttons=Gtk.ButtonsType.OK) msg_dia.set_markup( _("<big><b>%s is not marked executable in the filesystem</b></big>" % new_engine)) msg_dia.format_secondary_text( _("Try chmod a+x %s" % new_engine)) msg_dia.run() msg_dia.hide() self.add = False engine_chooser_dialog.hide() return try: engine_command = [] if vmpath: engine_command.append(vmpath) if vm_args is not None: engine_command += vm_args engine_command.append(new_engine) # Search the engines based on the most expectable protocol refeng = discoverer.getReferencedEngine(binname) if refeng is not None and refeng[ "protocol"] == "xboard": checkers = [is_cecp, is_uci] else: checkers = [is_uci, is_cecp] uci = False for checker in checkers: check_ok = checker(engine_command) if check_ok: uci = checker is is_uci break if not check_ok: # restore the original engine = discoverer.getEngineByName( self.cur_engine) engine_chooser_dialog.set_filename( engine["command"]) msg_dia = Gtk.MessageDialog( mainwindow(), type=Gtk.MessageType.ERROR, buttons=Gtk.ButtonsType.OK) msg_dia.set_markup( _("<big><b>Unable to add %s</b></big>" % new_engine)) msg_dia.format_secondary_text( _("There is something wrong with this executable" )) msg_dia.run() msg_dia.hide() engine_chooser_dialog.hide() self.add = False engine_chooser_dialog.hide() return self.widgets["engine_command_entry"].set_text( new_engine) self.widgets["engine_protocol_combo"].set_active( 0 if uci else 1) self.widgets["engine_args_entry"].set_text("") # active = self.widgets["engine_protocol_combo"].get_active() protocol = "uci" if uci else "xboard" # print(binname, new_engine, protocol, vm_name, vm_args) discoverer.addEngine(binname, new_engine, protocol, vm_name, vm_args) self.cur_engine = binname self.add = False discoverer.discover() except Exception: msg_dia = Gtk.MessageDialog(mainwindow(), type=Gtk.MessageType.ERROR, buttons=Gtk.ButtonsType.OK) msg_dia.set_markup( _("<big><b>Unable to add %s</b></big>" % new_engine)) msg_dia.format_secondary_text( _("There is something wrong with this executable")) msg_dia.run() msg_dia.hide() self.add = False engine_chooser_dialog.hide() return else: # restore the original engine = discoverer.getEngineByName(self.cur_engine) engine_chooser_dialog.set_filename(engine["command"]) engine_chooser_dialog.hide()
def _init(cls): cls.widgets = uistuff.GladeWidgets("newInOut.glade") cls.widgets["newgamedialog"].set_transient_for(mainwindow()) uistuff.createCombo(cls.widgets["whitePlayerCombobox"], name="whitePlayerCombobox") uistuff.createCombo(cls.widgets["blackPlayerCombobox"], name="blackPlayerCombobox") cls.widgets["playersIcon"].set_from_pixbuf(big_people) cls.widgets["timeIcon"].set_from_pixbuf(big_time) def on_playerCombobox_changed(widget, skill_hbox): skill_hbox.props.visible = widget.get_active() > 0 cls.widgets["whitePlayerCombobox"].connect("changed", on_playerCombobox_changed, cls.widgets["skillHbox1"]) cls.widgets["blackPlayerCombobox"].connect("changed", on_playerCombobox_changed, cls.widgets["skillHbox2"]) cls.widgets["whitePlayerCombobox"].set_active(0) cls.widgets["blackPlayerCombobox"].set_active(1) def on_skill_changed(scale, image): image.set_from_pixbuf(skillToIcon[int(scale.get_value())]) cls.widgets["skillSlider1"].connect("value-changed", on_skill_changed, cls.widgets["skillIcon1"]) cls.widgets["skillSlider2"].connect("value-changed", on_skill_changed, cls.widgets["skillIcon2"]) cls.widgets["skillSlider1"].set_value(3) cls.widgets["skillSlider2"].set_value(3) cls.__initTimeRadio(_("Blitz"), "ngblitz", cls.widgets["blitzRadio"], cls.widgets["configImageBlitz"], 5, 0, 0) cls.__initTimeRadio(_("Rapid"), "ngrapid", cls.widgets["rapidRadio"], cls.widgets["configImageRapid"], 15, 5, 0) cls.__initTimeRadio(_("Normal"), "ngnormal", cls.widgets["normalRadio"], cls.widgets["configImageNormal"], 40, 15, 0) cls.__initTimeRadio(_("Classical"), "ngclassical", cls.widgets["classicalRadio"], cls.widgets["configImageClassical"], 3, 0, 40) cls.__initVariantRadio("ngvariant1", cls.widgets["playVariant1Radio"], cls.widgets["configImageVariant1"], FISCHERRANDOMCHESS) cls.__initVariantRadio("ngvariant2", cls.widgets["playVariant2Radio"], cls.widgets["configImageVariant2"], LOSERSCHESS) def updateCombos(*args): if cls.widgets["playNormalRadio"].get_active(): variant = NORMALCHESS elif cls.widgets["playVariant1Radio"].get_active(): variant = conf.get("ngvariant1", FISCHERRANDOMCHESS) else: variant = conf.get("ngvariant2", LOSERSCHESS) variant1 = conf.get("ngvariant1", FISCHERRANDOMCHESS) cls.widgets["playVariant1Radio"].set_tooltip_text( variants[variant1].__desc__) variant2 = conf.get("ngvariant2", LOSERSCHESS) cls.widgets["playVariant2Radio"].set_tooltip_text( variants[variant2].__desc__) data = [(item[0], item[1]) for item in playerItems[variant]] uistuff.updateCombo(cls.widgets["blackPlayerCombobox"], data) uistuff.updateCombo(cls.widgets["whitePlayerCombobox"], data) discoverer.connect_after("all_engines_discovered", updateCombos) updateCombos(discoverer) conf.notify_add("ngvariant1", updateCombos) conf.notify_add("ngvariant2", updateCombos) cls.widgets["playNormalRadio"].connect("toggled", updateCombos) cls.widgets["playNormalRadio"].set_tooltip_text( variants[NORMALCHESS].__desc__) cls.widgets["playVariant1Radio"].connect("toggled", updateCombos) variant1 = conf.get("ngvariant1", FISCHERRANDOMCHESS) cls.widgets["playVariant1Radio"].set_tooltip_text( variants[variant1].__desc__) cls.widgets["playVariant2Radio"].connect("toggled", updateCombos) variant2 = conf.get("ngvariant2", LOSERSCHESS) cls.widgets["playVariant2Radio"].set_tooltip_text( variants[variant2].__desc__) # The "variant" has to come before players, because the engine positions # in the user comboboxes can be different in different variants for key in ("whitePlayerCombobox", "blackPlayerCombobox", "skillSlider1", "skillSlider2", "notimeRadio", "blitzRadio", "rapidRadio", "normalRadio", "classicalRadio", "playNormalRadio", "playVariant1Radio", "playVariant2Radio"): uistuff.keep(cls.widgets[key], key) # We don't want the dialog to deallocate when closed. Rather we hide # it on respond cls.widgets["newgamedialog"].connect("delete_event", lambda *a: True)
def __init__(self): self.widgets = uistuff.GladeWidgets("analyze_game.glade") self.widgets["analyze_game"].set_transient_for(mainwindow()) self.stop_event = asyncio.Event() uistuff.keep(self.widgets["fromCurrent"], "fromCurrent") uistuff.keep(self.widgets["shouldBlack"], "shouldBlack") uistuff.keep(self.widgets["shouldWhite"], "shouldWhite") uistuff.keep(self.widgets["threatPV"], "threatPV") uistuff.keep(self.widgets["showEval"], "showEval") uistuff.keep(self.widgets["showBlunder"], "showBlunder") uistuff.keep(self.widgets["max_analysis_spin"], "max_analysis_spin") uistuff.keep( self.widgets["variation_threshold_spin"], "variation_threshold_spin" ) # Analyzing engines uistuff.createCombo(self.widgets["ana_combobox"], name="ana_combobox") from pychess.widgets import newGameDialog def update_analyzers_store(discoverer): data = [(item[0], item[1]) for item in newGameDialog.analyzerItems] uistuff.updateCombo(self.widgets["ana_combobox"], data) discoverer.connect_after("all_engines_discovered", update_analyzers_store) update_analyzers_store(discoverer) uistuff.keep( self.widgets["ana_combobox"], "ana_combobox", anal_combo_get_value, lambda combobox, value: anal_combo_set_value( combobox, value, "hint_mode", HINT ), ) def hide_window(button, *args): self.widgets["analyze_game"].destroy() def abort(): self.analyzer.pause() if self.threat_PV: self.inv_analyzer.pause() self.stop_event.set() self.widgets["analyze_game"].destroy() def run_analyze(button, *args): @asyncio.coroutine def coro(): persp = perspective_manager.get_perspective("games") gmwidg = persp.cur_gmwidg() gamemodel = gmwidg.gamemodel old_check_value = conf.get("analyzer_check") conf.set("analyzer_check", True) if HINT not in gamemodel.spectators: try: yield from asyncio.wait_for(gamemodel.start_analyzer(HINT), 5.0) except asyncio.TimeoutError: log.error("Got timeout error while starting hint analyzer") return except Exception: log.error("Unknown error while starting hint analyzer") return self.analyzer = gamemodel.spectators[HINT] gmwidg.menuitems["hint_mode"].active = True self.threat_PV = conf.get("ThreatPV") if self.threat_PV: old_inv_check_value = conf.get("inv_analyzer_check") conf.set("inv_analyzer_check", True) if SPY not in gamemodel.spectators: try: yield from asyncio.wait_for( gamemodel.start_analyzer(SPY), 5.0 ) except asyncio.TimeoutError: log.error("Got timeout error while starting spy analyzer") return except Exception: log.error("Unknown error while starting spy analyzer") return inv_analyzer = gamemodel.spectators[SPY] gmwidg.menuitems["spy_mode"].active = True title = _("Game analyzing in progress...") text = _("Do you want to abort it?") content = InfoBar.get_message_content( title, text, Gtk.STOCK_DIALOG_QUESTION ) def response_cb(infobar, response, message): conf.set("analyzer_check", old_check_value) if self.threat_PV: conf.set("inv_analyzer_check", old_inv_check_value) message.dismiss() abort() message = InfoBarMessage(Gtk.MessageType.QUESTION, content, response_cb) message.add_button( InfoBarMessageButton(_("Abort"), Gtk.ResponseType.CANCEL) ) gmwidg.replaceMessages(message) @asyncio.coroutine def analyse_moves(): should_black = conf.get("shouldBlack") should_white = conf.get("shouldWhite") from_current = conf.get("fromCurrent") start_ply = gmwidg.board.view.shown if from_current else 0 move_time = int(conf.get("max_analysis_spin")) threshold = int(conf.get("variation_threshold_spin")) for board in gamemodel.boards[start_ply:]: if self.stop_event.is_set(): break gmwidg.board.view.setShownBoard(board) self.analyzer.setBoard(board) if self.threat_PV: inv_analyzer.setBoard(board) yield from asyncio.sleep(move_time + 0.1) ply = board.ply - gamemodel.lowply color = (ply - 1) % 2 if ( ply - 1 in gamemodel.scores and ply in gamemodel.scores and ( (color == BLACK and should_black) or (color == WHITE and should_white) ) ): oldmoves, oldscore, olddepth = gamemodel.scores[ply - 1] oldscore = oldscore * -1 if color == BLACK else oldscore score_str = prettyPrintScore(oldscore, olddepth) moves, score, depth = gamemodel.scores[ply] score = score * -1 if color == WHITE else score diff = score - oldscore if ( (diff > threshold and color == BLACK) or (diff < -1 * threshold and color == WHITE) ) and ( gamemodel.moves[ply - 1] != parseAny(gamemodel.boards[ply - 1], oldmoves[0]) ): if self.threat_PV: try: if ply - 1 in gamemodel.spy_scores: oldmoves0, oldscore0, olddepth0 = gamemodel.spy_scores[ ply - 1 ] score_str0 = prettyPrintScore( oldscore0, olddepth0 ) pv0 = listToMoves( gamemodel.boards[ply - 1], ["--"] + oldmoves0, validate=True, ) if len(pv0) > 2: gamemodel.add_variation( gamemodel.boards[ply - 1], pv0, comment="Threatening", score=score_str0, emit=False, ) except ParsingError as e: # ParsingErrors may happen when parsing "old" lines from # analyzing engines, which haven't yet noticed their new tasks log.debug( "__parseLine: Ignored (%s) from analyzer: ParsingError%s" % (" ".join(oldmoves), e) ) try: pv = listToMoves( gamemodel.boards[ply - 1], oldmoves, validate=True, ) gamemodel.add_variation( gamemodel.boards[ply - 1], pv, comment="Better is", score=score_str, emit=False, ) except ParsingError as e: # ParsingErrors may happen when parsing "old" lines from # analyzing engines, which haven't yet noticed their new tasks log.debug( "__parseLine: Ignored (%s) from analyzer: ParsingError%s" % (" ".join(oldmoves), e) ) self.widgets["analyze_game"].hide() self.widgets["analyze_ok_button"].set_sensitive(True) conf.set("analyzer_check", old_check_value) if self.threat_PV: conf.set("inv_analyzer_check", old_inv_check_value) message.dismiss() gamemodel.emit("analysis_finished") create_task(analyse_moves()) hide_window(None) return True create_task(coro()) self.widgets["analyze_game"].connect("delete-event", hide_window) self.widgets["analyze_cancel_button"].connect("clicked", hide_window) self.widgets["analyze_ok_button"].connect("clicked", run_analyze)
def parseLine(self, proc): while True: line = yield from wait_signal(proc, 'line') if not line: break else: line = line[1] if line[0:1] == "#": # Debug line which we shall ignore as specified in CECPv2 specs continue # log.debug("__parseLine: line=\"%s\"" % line.strip(), extra={"task":self.defname}) parts = whitespaces.split(line.strip()) if parts[0] == "pong": self.lastpong = int(parts[1]) continue # Illegal Move if parts[0].lower().find("illegal") >= 0: log.warning( "__parseLine: illegal move: line=\"%s\", board=%s" % (line.strip(), self.board), extra={"task": self.defname}) if parts[-2] == "sd" and parts[-1].isdigit(): print("depth", parts[-1], file=self.engine) continue # A Move (Perhaps) if self.board: if parts[0] == "move": movestr = parts[1] # Old Variation elif d_plus_dot_expr.match(parts[0]) and parts[1] == "...": movestr = parts[2] else: movestr = False if movestr: self.waitingForMove = False self.readyForMoveNowCommand = False if self.engineIsInNotPlaying: # If engine was set in pause just before the engine sent its # move, we ignore it. However the engine has to know that we # ignored it, and thus we step it one back log.info( "__parseLine: Discarding engine's move: %s" % movestr, extra={"task": self.defname}) print("undo", file=self.engine) continue else: try: move = parseAny(self.board, movestr) except ParsingError: self.invalid_move = movestr log.info( "__parseLine: ParsingError engine move: %s %s" % (movestr, self.board), extra={"task": self.defname}) self.end( WHITEWON if self.board.color == BLACK else BLACKWON, WON_ADJUDICATION) continue if validate(self.board, move): self.board = None self.queue.put_nowait(move) continue else: self.invalid_move = movestr log.info( "__parseLine: can't validate engine move: %s %s" % (movestr, self.board), extra={"task": self.defname}) self.end( WHITEWON if self.board.color == BLACK else BLACKWON, WON_ADJUDICATION) continue # Analyzing if self.engineIsInNotPlaying: if parts[:4] == ["0", "0", "0", "0"]: # Crafty doesn't analyze until it is out of book print("book off", file=self.engine) continue match = anare.match(line) if match: depth, score, time, nodes, moves = match.groups() if "mat" in score.lower() or "#" in moves: # Will look either like -Mat 3 or Mat3 scoreval = MATE_VALUE if score.startswith('-'): scoreval = -scoreval else: scoreval = int(score) nps = str( int(int(nodes) / (int(time) / 100))) if int(time) > 0 else "" mvstrs = movere.findall(moves) if mvstrs: self.emit("analyze", [(self.board.ply, mvstrs, scoreval, depth.strip(), nps)]) continue # Offers draw if parts[0:2] == ["offer", "draw"]: self.emit("accept", Offer(DRAW_OFFER)) continue # Resigns if parts[0] == "resign" or \ (parts[0] == "tellics" and parts[1] == "resign"): # buggy crafty # Previously: if "resign" in parts, # however, this is too generic, since "hint", "bk", # "feature option=.." and possibly other, future CECPv2 # commands can validly contain the word "resign" without this # being an intentional resign offer. self.emit("offer", Offer(RESIGNATION)) continue # if parts[0].lower() == "error": # continue # Tell User Error if parts[0] == "tellusererror": # We don't want to see our stop analyzer hack as an error message if "8/8/8/8/8/8/8/8" in "".join(parts[1:]): continue # Create a non-modal non-blocking message dialog with the error: dlg = Gtk.MessageDialog(mainwindow(), flags=0, type=Gtk.MessageType.WARNING, buttons=Gtk.ButtonsType.CLOSE, message_format=None) # Use the engine name if already known, otherwise the defname: displayname = self.name if not displayname: displayname = self.defname # Compose the dialog text: dlg.set_markup( GObject.markup_escape_text( _("The engine %s reports an error:") % displayname) + "\n\n" + GObject.markup_escape_text(" ".join(parts[1:]))) # handle response signal so the "Close" button works: dlg.connect("response", lambda dlg, x: dlg.destroy()) dlg.show_all() continue # Tell Somebody if parts[0][:4] == "tell" and \ parts[0][4:] in ("others", "all", "ics", "icsnoalias"): log.info("Ignoring tell %s: %s" % (parts[0][4:], " ".join(parts[1:]))) continue if "feature" in parts: # Some engines send features after done=1, so we will iterate after done=1 too done1 = False # We skip parts before 'feature', as some engines give us lines like # White (1) : feature setboard=1 analyze...e="GNU Chess 5.07" done=1 parts = parts[parts.index("feature"):] for i, pair in enumerate(parts[1:]): # As "parts" is split with no thoughs on quotes or double quotes # we need to do some extra handling. if pair.find("=") < 0: continue key, value = pair.split("=", 1) if key not in self.features: continue if value.startswith('"') and value.endswith('"'): value = value[1:-1] # If our pair was unfinished, like myname="GNU, we search the # rest of the pairs for a quotating mark. elif value[0] == '"': rest = value[1:] + " " + " ".join(parts[2 + i:]) j = rest.find('"') if j == -1: log.warning( "Missing endquotation in %s feature", extra={"task": self.defname}) value = rest else: value = rest[:j] elif value.isdigit(): value = int(value) if key in self.supported_features: print("accepted %s" % key, file=self.engine) else: print("rejected %s" % key, file=self.engine) if key == "done": if value == 1: done1 = True continue elif value == 0: log.info("Adds %d seconds timeout" % TIME_OUT_SECOND, extra={"task": self.defname}) # This'll buy you some more time self.queue.put_nowait("not ready") break if key == "smp" and value == 1: self.options["cores"] = { "name": "cores", "type": "spin", "default": 1, "min": 1, "max": 64 } elif key == "memory" and value == 1: self.options["memory"] = { "name": "memory", "type": "spin", "default": 32, "min": 1, "max": 4096 } elif key == "option" and key != "done": option = self.__parse_option(value) self.options[option["name"]] = option else: self.features[key] = value if key == "myname" and not self.name: self.setName(value) if done1: # Start a new game before using the engine: # (CECPv2 engines) print("new", file=self.engine) # We are now ready for play: self.emit("readyForOptions") self.emit("readyForMoves") self.queue.put_nowait("ready") # A hack to get better names in protover 1. # Unfortunately it wont work for now, as we don't read any lines from # protover 1 engines. When should we stop? if self.protover == 1: if self.defname[0] in ''.join(parts): basis = self.defname[0] name = ' '.join( itertools.dropwhile(lambda part: basis not in part, parts)) self.features['myname'] = name if not self.name: self.setName(name)
def init_layout(self): perspective_widget = Gtk.Box(orientation=Gtk.Orientation.VERTICAL) perspective_manager.set_perspective_widget("database", perspective_widget) self.notebooks = {"gamelist": new_notebook()} self.main_notebook = self.notebooks["gamelist"] for panel in self.sidePanels: self.notebooks[panel.__name__] = new_notebook(panel.__name__) self.spinner = Gtk.Spinner() self.spinner.set_size_request(50, 50) self.progressbar0 = Gtk.ProgressBar(show_text=True) self.progressbar1 = Gtk.ProgressBar(show_text=True) self.progress_dialog = Gtk.Dialog( "", mainwindow(), 0, (Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL)) self.progress_dialog.set_deletable(False) self.progress_dialog.get_content_area().pack_start( self.spinner, True, True, 0) self.progress_dialog.get_content_area().pack_start( self.progressbar0, True, True, 0) self.progress_dialog.get_content_area().pack_start( self.progressbar1, True, True, 0) self.progress_dialog.get_content_area().show_all() # Initing headbook align = createAlignment(4, 4, 0, 4) align.set_property("yscale", 0) self.headbook = Gtk.Notebook() self.headbook.set_name("headbook") self.headbook.set_scrollable(True) align.add(self.headbook) perspective_widget.pack_start(align, False, True, 0) self.headbook.connect_after("switch-page", self.on_switch_page) # The dock self.dock = PyDockTop("database", self) align = Gtk.Alignment() align.show() align.add(self.dock) self.dock.show() perspective_widget.pack_start(align, True, True, 0) self.docks["gamelist"] = (Gtk.Label(label="gamelist"), self.notebooks["gamelist"], None) for panel in self.sidePanels: self.docks[panel.__name__][1] = self.notebooks[panel.__name__] self.load_from_xml() # Default layout of side panels if not os.path.isfile(self.dockLocation): leaf = self.dock.dock(self.docks["gamelist"][1], CENTER, self.docks["gamelist"][0], "gamelist") leaf.setDockable(False) leaf = leaf.dock(self.docks["OpeningTreePanel"][1], EAST, self.docks["OpeningTreePanel"][0], "OpeningTreePanel") leaf = leaf.dock(self.docks["FilterPanel"][1], CENTER, self.docks["FilterPanel"][0], "FilterPanel") leaf.dock(self.docks["PreviewPanel"][1], SOUTH, self.docks["PreviewPanel"][0], "PreviewPanel") def unrealize(dock): dock.saveToXML(self.dockLocation) dock._del() self.dock.connect("unrealize", unrealize) self.dock.show_all() perspective_widget.show_all() perspective_manager.set_perspective_menuitems("database", self.menuitems) perspective_manager.set_perspective_toolbuttons( "database", [self.import_button, self.save_as_button])
def __init__(self, widgets): self.widgets = widgets self.dialog = self.widgets["manage_engines_dialog"] self.cur_engine = None self.default_workdir = getEngineDataPrefix() uistuff.keepWindowSize("engineswindow", self.dialog, defaultSize=(1, 500)) # Put engines into tree store allstore = Gtk.ListStore(Pixbuf, str) self.tv = self.widgets["engines_treeview"] self.tv.set_model(allstore) self.tv.append_column( Gtk.TreeViewColumn("Flag", Gtk.CellRendererPixbuf(), pixbuf=0)) name_renderer = Gtk.CellRendererText() name_renderer.set_property("editable", False) self.tv.append_column(Gtk.TreeViewColumn("Name", name_renderer, text=1)) def name_edited(renderer, path, new_name): if self.cur_engine is not None: old_name = self.cur_engine if new_name and new_name != old_name: names = [ engine["name"] for engine in discoverer.getEngines() ] if new_name not in names: engine = discoverer.getEngineByName(self.cur_engine) engine["name"] = new_name discoverer.save() self.cur_engine = new_name update_store() # Notify playerCombos in NewGameTasker discoverer.emit("all_engines_discovered") name_renderer.connect("edited", name_edited) # Add cell renderer to protocol combo column protocol_combo = self.widgets["engine_protocol_combo"] protocol_combo.set_name("engine_protocol_combo") cell = Gtk.CellRendererText() protocol_combo.pack_start(cell, True) protocol_combo.add_attribute(cell, "text", 0) # Add columns and cell renderers to options treeview self.options_store = Gtk.ListStore(str, GObject.TYPE_PYOBJECT) optv = self.widgets["options_treeview"] optv.set_model(self.options_store) optv.append_column( Gtk.TreeViewColumn("Option", Gtk.CellRendererText(), text=0)) optv.append_column( Gtk.TreeViewColumn("Data", KeyValueCellRenderer(self.options_store), data=1)) def update_options(*args): if self.cur_engine is not None: engines = discoverer.getEngines() names = [engine["name"] for engine in engines] # After deleting an engine we will select first if self.cur_engine not in names: self.cur_engine = engines[0]["name"] engine = discoverer.getEngineByName(self.cur_engine) options = engine.get("options") self.options_store.clear() if options: options.sort(key=lambda obj: obj['name'].lower() if 'name' in obj else '') for option in options: key = option["name"] val = option if option["type"] != "button": val["default"] = option.get("default") val["value"] = option.get("value", val["default"]) self.options_store.append([key, val]) def update_store(*args): newGameDialog.createPlayerUIGlobals(discoverer) engine_names = [row[1] for row in allstore] new_items = [] # don't add the very first (Human) player to engine store for item in newGameDialog.allEngineItems: if item[1] not in engine_names: new_items.append(item) ts_iter = None for item in new_items: ts_iter = allstore.append(item) if ts_iter is not None: text_select = self.tv.get_selection() text_select.select_iter(ts_iter) update_options() update_store() def do_update_store(*args): GLib.idle_add(update_store) discoverer.connect_after("engine_discovered", do_update_store) ################################################################ # remove button ################################################################ def remove(button): if self.cur_engine is not None: self.widgets['remove_engine_button'].set_sensitive(False) # engine = discoverer.getEngineByName(self.cur_engine) discoverer.removeEngine(self.cur_engine) discoverer.save() selection = self.tv.get_selection() result = selection.get_selected() if result is not None: model, ts_iter = result model.remove(ts_iter) # Notify playerCombos in NewGameTasker discoverer.emit("all_engines_discovered") self.widgets["remove_engine_button"].connect("clicked", remove) ################################################################ # add button ################################################################ engine_chooser_dialog = Gtk.FileChooserDialog( _("Select engine"), mainwindow(), Gtk.FileChooserAction.OPEN, (Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL, Gtk.STOCK_OPEN, Gtk.ResponseType.OK)) filter = Gtk.FileFilter() filter.set_name(_("Executable files")) filter.add_mime_type("application/x-executable") filter.add_mime_type("application/x-sharedlib") filter.add_mime_type("application/x-ms-dos-executable") filter.add_mime_type("application/x-msdownload") filter.add_pattern("*.exe") for vm in VM_LIST: filter.add_pattern("*%s" % vm.ext) engine_chooser_dialog.add_filter(filter) self.add = False def add(button): self.add = True response = engine_chooser_dialog.run() if response == Gtk.ResponseType.OK: new_engine = engine_chooser_dialog.get_filename() vm_name = None vm_args = None vmpath = "" if new_engine.lower().endswith( ".exe") and sys.platform != "win32": vm_name = "wine" vmpath = shutil.which(vm_name, mode=os.R_OK | os.X_OK) if vmpath is None: msg_dia = Gtk.MessageDialog(mainwindow(), type=Gtk.MessageType.ERROR, buttons=Gtk.ButtonsType.OK) msg_dia.set_markup( _("<big><b>Unable to add %s</b></big>" % new_engine)) msg_dia.format_secondary_text(_("wine not installed")) msg_dia.run() msg_dia.hide() new_engine = "" for vm in VM_LIST: ext = os.path.splitext(new_engine)[1] if ext == vm.ext: vm_name = vm.name vm_args = vm.args vmpath = shutil.which(vm_name, mode=os.R_OK | os.X_OK) if vmpath is None: msg_dia = Gtk.MessageDialog( mainwindow(), type=Gtk.MessageType.ERROR, buttons=Gtk.ButtonsType.OK) msg_dia.set_markup( _("<big><b>Unable to add %s</b></big>" % new_engine)) msg_dia.format_secondary_text( vm_name + _(" is not installed")) msg_dia.run() msg_dia.hide() new_engine = "" break if new_engine: vm_ext_list = [vm.ext for vm in VM_LIST] if ext not in vm_ext_list and not os.access( new_engine, os.X_OK): msg_dia = Gtk.MessageDialog(mainwindow(), type=Gtk.MessageType.ERROR, buttons=Gtk.ButtonsType.OK) msg_dia.set_markup( _("<big><b>%s is not marked executable in the filesystem</b></big>" % new_engine)) msg_dia.format_secondary_text( _("Try chmod a+x %s" % new_engine)) msg_dia.run() msg_dia.hide() self.add = False engine_chooser_dialog.hide() return try: engine_command = [] if vmpath: engine_command.append(vmpath) if vm_args is not None: engine_command.append(vm_args) engine_command.append(new_engine) # Some engines support CECP and UCI, but main variant engines are CECP, # so we better to start with CECP this case variant_engines = ("fmax", "sjaakii", "sjeng") if any((True for eng in variant_engines if eng in new_engine.lower())): checkers = [is_cecp, is_uci] else: checkers = [is_uci, is_cecp] uci = False for checker in checkers: check_ok = checker(engine_command) if check_ok: uci = checker is is_uci break else: continue if not check_ok: # restore the original engine = discoverer.getEngineByName( self.cur_engine) engine_chooser_dialog.set_filename( engine["command"]) msg_dia = Gtk.MessageDialog( mainwindow(), type=Gtk.MessageType.ERROR, buttons=Gtk.ButtonsType.OK) msg_dia.set_markup( _("<big><b>Unable to add %s</b></big>" % new_engine)) msg_dia.format_secondary_text( _("There is something wrong with this executable" )) msg_dia.run() msg_dia.hide() engine_chooser_dialog.hide() self.add = False engine_chooser_dialog.hide() return binname = os.path.split(new_engine)[1] for eng in discoverer.getEngines(): if eng["name"] == binname: binname = eng["name"] + "(1)" break self.widgets["engine_command_entry"].set_text( new_engine) self.widgets["engine_protocol_combo"].set_active( 0 if uci else 1) self.widgets["engine_args_entry"].set_text("") # active = self.widgets["engine_protocol_combo"].get_active() protocol = "uci" if uci else "xboard" if vm_args is not None: vm_args = vm_args.split(",") # print(binname, new_engine, protocol, vm_name, vm_args) discoverer.addEngine(binname, new_engine, protocol, vm_name, vm_args, "unknown") self.cur_engine = binname self.add = False discoverer.discover() except Exception: msg_dia = Gtk.MessageDialog(mainwindow(), type=Gtk.MessageType.ERROR, buttons=Gtk.ButtonsType.OK) msg_dia.set_markup( _("<big><b>Unable to add %s</b></big>" % new_engine)) msg_dia.format_secondary_text( _("There is something wrong with this executable")) msg_dia.run() msg_dia.hide() self.add = False engine_chooser_dialog.hide() return else: # restore the original engine = discoverer.getEngineByName(self.cur_engine) engine_chooser_dialog.set_filename(engine["command"]) engine_chooser_dialog.hide() self.widgets["add_engine_button"].connect("clicked", add) ################################################################ # vm args ################################################################ def vm_args_changed(widget): if self.cur_engine is not None: new_args = self.widgets["vm_args_entry"].get_text().strip() engine = discoverer.getEngineByName(self.cur_engine) old_args = engine.get("vm_args") if new_args != old_args: engine["vm_args"] = new_args.split() discoverer.save() self.widgets["vm_args_entry"].connect("changed", vm_args_changed) ################################################################ # engine args ################################################################ def args_changed(widget): if self.cur_engine is not None: new_args = self.widgets["engine_args_entry"].get_text().strip() engine = discoverer.getEngineByName(self.cur_engine) old_args = engine.get("args") if new_args != old_args: engine["args"] = new_args.split() discoverer.save() self.widgets["engine_args_entry"].connect("changed", args_changed) ################################################################ # engine working directory ################################################################ dir_chooser_dialog = Gtk.FileChooserDialog( _("Select working directory"), mainwindow(), Gtk.FileChooserAction.SELECT_FOLDER, (Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL, Gtk.STOCK_OPEN, Gtk.ResponseType.OK)) dir_chooser_button = Gtk.FileChooserButton.new_with_dialog( dir_chooser_dialog) self.widgets["dirChooserDock"].add(dir_chooser_button) dir_chooser_button.show() def select_dir(button): new_directory = dir_chooser_dialog.get_filename() engine = discoverer.getEngineByName(self.cur_engine) old_directory = engine.get("workingDirectory") if new_directory != old_directory and new_directory != self.default_workdir: engine["workingDirectory"] = new_directory discoverer.save() dir_chooser_button.connect("current-folder-changed", select_dir) ################################################################ # engine protocol ################################################################ def protocol_changed(widget): if self.cur_engine is not None and not self.add and not self.selection: active = self.widgets["engine_protocol_combo"].get_active() new_protocol = "uci" if active == 0 else "xboard" engine = discoverer.getEngineByName(self.cur_engine) old_protocol = engine["protocol"] if new_protocol != old_protocol: command = engine.get("command") engine_command = [] vm_command = engine.get("vm_command") if vm_command is not None: engine_command.append(vm_command) vm_args = engine.get("vm_args") if vm_args is not None: engine_command.append(", ".join(vm_args)) engine_command.append(command) # is the new protocol supported by the engine? if new_protocol == "uci": check_ok = is_uci(engine_command) else: check_ok = is_cecp(engine_command) if check_ok: # discover engine options for new protocol engine["protocol"] = new_protocol engine["recheck"] = True discoverer.discover() else: # restore the original protocol widgets["engine_protocol_combo"].set_active( 0 if old_protocol == "uci" else 1) self.widgets["engine_protocol_combo"].connect("changed", protocol_changed) ################################################################ # engine country ################################################################ def country_changed(widget): if self.cur_engine is not None and not self.selection: engine = discoverer.getEngineByName(self.cur_engine) old_country = discoverer.getCountry(engine) new_country = ISO3166_LIST[widget.get_active()].iso2 if old_country != new_country: engine["country"] = new_country discoverer.save() # Refresh the flag in the tree view path = addDataPrefix("flags/%s.png" % new_country) if not os.path.isfile(path): path = addDataPrefix("flags/unknown.png") item = self.tv.get_selection().get_selected() if item is not None: model, ts_iter = item model[ts_iter][0] = get_pixbuf(path) # Notify playerCombos in NewGameTasker discoverer.emit("all_engines_discovered") self.widgets["engine_country_combo"].connect("changed", country_changed) def country_keypressed(widget, event): idx = 0 for iso in ISO3166_LIST: if (idx != 0) and ( (ord(iso.country[0].lower()) == event.keyval) or (ord(iso.country[0].upper()) == event.keyval)): widget.set_active(idx) break idx += 1 self.widgets["engine_country_combo"].connect("key-press-event", country_keypressed) ################################################################ # engine tree ################################################################ self.selection = False def selection_changed(treeselection): store, tv_iter = self.tv.get_selection().get_selected() if tv_iter: self.selection = True path = store.get_path(tv_iter) indices = path.get_indices() row = indices[0] name = store[row][1] self.cur_engine = name engine = discoverer.getEngineByName(name) self.widgets['copy_engine_button'].set_sensitive(True) if "PyChess.py" in engine["command"]: self.widgets['remove_engine_button'].set_sensitive(False) else: self.widgets['remove_engine_button'].set_sensitive(True) self.widgets["engine_command_entry"].set_text( engine["command"]) engine_chooser_dialog.set_filename(engine["command"]) args = [] if engine.get("args") is None else engine.get("args") self.widgets["engine_args_entry"].set_text(' '.join(args)) vm = engine.get("vm_command") self.widgets["vm_command_entry"].set_text( vm if vm is not None else "") args = [] if engine.get("vm_args") is None else engine.get( "vm_args") self.widgets["vm_args_entry"].set_text(' '.join(args)) directory = engine.get("workingDirectory") dir_choice = directory if directory is not None else self.default_workdir dir_chooser_dialog.set_current_folder(dir_choice) self.widgets["engine_protocol_combo"].set_active( 0 if engine["protocol"] == "uci" else 1) self.widgets["engine_country_combo"].set_active(0) country = discoverer.getCountry(engine) idx = 0 for iso in ISO3166_LIST: if iso.iso2 == country: self.widgets["engine_country_combo"].set_active(idx) break idx += 1 update_options() self.selection = False tree_selection = self.tv.get_selection() tree_selection.connect('changed', selection_changed) tree_selection.select_path((0, )) selection_changed(tree_selection) ################################################################ # restore the default options of the engine ################################################################ def engine_default_options(button): if self.cur_engine is not None and not self.selection: engine = discoverer.getEngineByName(self.cur_engine) options = engine.get("options") if options: dialog = Gtk.MessageDialog(mainwindow(), type=Gtk.MessageType.QUESTION, buttons=Gtk.ButtonsType.YES_NO) dialog.set_markup( _("Do you really want to restore the default options of the engine ?" )) response = dialog.run() dialog.destroy() if response == Gtk.ResponseType.YES: for option in options: if "default" in option: option["value"] = option["default"] discoverer.save() update_options() self.widgets["engine_default_options_button"].connect( "clicked", engine_default_options)
def on_remote_game_activate(self, widget): url = getUserTextDialog(mainwindow(), _('Load a remote game'), _('Paste the link to download:')) create_task(get_internet_game(url))
def init_layout(self): perspective_widget = Gtk.Box(orientation=Gtk.Orientation.VERTICAL) perspective_manager.set_perspective_widget("database", perspective_widget) self.switcher_panel = SwitcherPanel(self) self.notebooks["gamelist"] = new_notebook() self.notebooks["opening_tree"] = new_notebook() self.notebooks["filter"] = new_notebook() self.notebooks["preview"] = new_notebook() self.spinner = Gtk.Spinner() self.spinner.set_size_request(50, 50) self.progressbar0 = Gtk.ProgressBar(show_text=True) self.progressbar1 = Gtk.ProgressBar(show_text=True) self.progress_dialog = Gtk.Dialog( "", mainwindow(), 0, (Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL)) self.progress_dialog.get_content_area().pack_start( self.spinner, True, True, 0) self.progress_dialog.get_content_area().pack_start( self.progressbar0, True, True, 0) self.progress_dialog.get_content_area().pack_start( self.progressbar1, True, True, 0) self.progress_dialog.get_content_area().show_all() self.dock = PyDockTop("database", self) align = Gtk.Alignment() align.show() align.add(self.dock) self.dock.show() perspective_widget.pack_start(align, True, True, 0) dockLocation = addUserConfigPrefix("pydock-database.xml") docks = { "gamelist": (Gtk.Label(label="gamelist"), self.notebooks["gamelist"]), "switcher": (dock_panel_tab(_("Databases"), "", addDataPrefix("glade/panel_database.svg")), self.switcher_panel.alignment), "openingtree": (dock_panel_tab(_("Openings"), "", addDataPrefix("glade/panel_book.svg")), self.notebooks["opening_tree"]), "filter": (dock_panel_tab(_("Filters"), "", addDataPrefix("glade/panel_filter.svg")), self.notebooks["filter"]), "preview": (dock_panel_tab(_("Preview"), "", addDataPrefix("glade/panel_games.svg")), self.notebooks["preview"]), } if os.path.isfile(dockLocation): try: self.dock.loadFromXML(dockLocation, docks) except Exception as e: stringio = StringIO() traceback.print_exc(file=stringio) error = stringio.getvalue() log.error("Dock loading error: %s\n%s" % (e, error)) msg_dia = Gtk.MessageDialog(mainwindow(), type=Gtk.MessageType.ERROR, buttons=Gtk.ButtonsType.CLOSE) msg_dia.set_markup( _("<b><big>PyChess was unable to load your panel settings</big></b>" )) msg_dia.format_secondary_text( _("Your panel settings have been reset. If this problem repeats, \ you should report it to the developers")) msg_dia.run() msg_dia.hide() os.remove(dockLocation) for title, panel in docks.values(): title.unparent() panel.unparent() if not os.path.isfile(dockLocation): leaf = self.dock.dock(docks["gamelist"][1], CENTER, docks["gamelist"][0], "gamelist") leaf.setDockable(False) leaf.dock(docks["switcher"][1], NORTH, docks["switcher"][0], "switcher") leaf = leaf.dock(docks["openingtree"][1], EAST, docks["openingtree"][0], "openingtree") leaf = leaf.dock(docks["filter"][1], CENTER, docks["filter"][0], "filter") leaf.dock(docks["preview"][1], SOUTH, docks["preview"][0], "preview") def unrealize(dock): dock.saveToXML(dockLocation) dock._del() self.dock.connect("unrealize", unrealize) self.dock.show_all() perspective_widget.show_all() perspective_manager.set_perspective_toolbuttons( "database", [self.import_button, self.save_as_button, self.close_button]) self.switcher_panel.connect("chessfile_switched", self.on_chessfile_switched)
def add(button): self.add = True response = engine_chooser_dialog.run() if response == Gtk.ResponseType.OK: new_engine = engine_chooser_dialog.get_filename() vm_name = None vm_args = None vmpath = "" if new_engine.lower().endswith( ".exe") and sys.platform != "win32": vm_name = "wine" vmpath = shutil.which(vm_name, mode=os.R_OK | os.X_OK) if vmpath is None: msg_dia = Gtk.MessageDialog(mainwindow(), type=Gtk.MessageType.ERROR, buttons=Gtk.ButtonsType.OK) msg_dia.set_markup( _("<big><b>Unable to add %s</b></big>" % new_engine)) msg_dia.format_secondary_text(_("wine not installed")) msg_dia.run() msg_dia.hide() new_engine = "" for vm in VM_LIST: ext = os.path.splitext(new_engine)[1] if ext == vm.ext: vm_name = vm.name vm_args = vm.args vmpath = shutil.which(vm_name, mode=os.R_OK | os.X_OK) if vmpath is None: msg_dia = Gtk.MessageDialog( mainwindow(), type=Gtk.MessageType.ERROR, buttons=Gtk.ButtonsType.OK) msg_dia.set_markup( _("<big><b>Unable to add %s</b></big>" % new_engine)) msg_dia.format_secondary_text( vm_name + _(" is not installed")) msg_dia.run() msg_dia.hide() new_engine = "" break if new_engine: vm_ext_list = [vm.ext for vm in VM_LIST] if ext not in vm_ext_list and not os.access( new_engine, os.X_OK): msg_dia = Gtk.MessageDialog(mainwindow(), type=Gtk.MessageType.ERROR, buttons=Gtk.ButtonsType.OK) msg_dia.set_markup( _("<big><b>%s is not marked executable in the filesystem</b></big>" % new_engine)) msg_dia.format_secondary_text( _("Try chmod a+x %s" % new_engine)) msg_dia.run() msg_dia.hide() self.add = False engine_chooser_dialog.hide() return try: engine_command = [] if vmpath: engine_command.append(vmpath) if vm_args is not None: engine_command.append(vm_args) engine_command.append(new_engine) # Some engines support CECP and UCI, but main variant engines are CECP, # so we better to start with CECP this case variant_engines = ("fmax", "sjaakii", "sjeng") if any((True for eng in variant_engines if eng in new_engine.lower())): checkers = [is_cecp, is_uci] else: checkers = [is_uci, is_cecp] uci = False for checker in checkers: check_ok = checker(engine_command) if check_ok: uci = checker is is_uci break else: continue if not check_ok: # restore the original engine = discoverer.getEngineByName( self.cur_engine) engine_chooser_dialog.set_filename( engine["command"]) msg_dia = Gtk.MessageDialog( mainwindow(), type=Gtk.MessageType.ERROR, buttons=Gtk.ButtonsType.OK) msg_dia.set_markup( _("<big><b>Unable to add %s</b></big>" % new_engine)) msg_dia.format_secondary_text( _("There is something wrong with this executable" )) msg_dia.run() msg_dia.hide() engine_chooser_dialog.hide() self.add = False engine_chooser_dialog.hide() return binname = os.path.split(new_engine)[1] for eng in discoverer.getEngines(): if eng["name"] == binname: binname = eng["name"] + "(1)" break self.widgets["engine_command_entry"].set_text( new_engine) self.widgets["engine_protocol_combo"].set_active( 0 if uci else 1) self.widgets["engine_args_entry"].set_text("") # active = self.widgets["engine_protocol_combo"].get_active() protocol = "uci" if uci else "xboard" if vm_args is not None: vm_args = vm_args.split(",") # print(binname, new_engine, protocol, vm_name, vm_args) discoverer.addEngine(binname, new_engine, protocol, vm_name, vm_args, "unknown") self.cur_engine = binname self.add = False discoverer.discover() except Exception: msg_dia = Gtk.MessageDialog(mainwindow(), type=Gtk.MessageType.ERROR, buttons=Gtk.ButtonsType.OK) msg_dia.set_markup( _("<big><b>Unable to add %s</b></big>" % new_engine)) msg_dia.format_secondary_text( _("There is something wrong with this executable")) msg_dia.run() msg_dia.hide() self.add = False engine_chooser_dialog.hide() return else: # restore the original engine = discoverer.getEngineByName(self.cur_engine) engine_chooser_dialog.set_filename(engine["command"]) engine_chooser_dialog.hide()
def generalStart(self, gamemodel, player0tup, player1tup, loaddata=None): """ The player tuples are: (The type af player in a System.const value, A callable creating the player, A list of arguments for the callable, A preliminary name for the player) If loaddata is specified, it should be a tuple of: (A text uri or fileobj, A Savers.something module with a load function capable of loading it, An int of the game in file you want to load, The position from where to start the game) """ log.debug("Games.generalStart: %s\n %s\n %s" % (gamemodel, player0tup, player1tup)) gmwidg = gamewidget.GameWidget(gamemodel, self) self.gamewidgets.add(gmwidg) self.gmwidg_cids[gmwidg] = gmwidg.connect("game_close_clicked", self.closeGame) # worker.publish((gmwidg,gamemodel)) self.attachGameWidget(gmwidg) game_nanny.nurseGame(gmwidg, gamemodel) log.debug("Games.generalStart: -> emit gmwidg_created: %s" % (gmwidg)) self.emit("gmwidg_created", gmwidg) log.debug("Games.generalStart: <- emit gmwidg_created: %s" % (gmwidg)) # Initing players def xxxset_name(none, player, key, alt): player.setName(conf.get(key, alt)) players = [] for i, playertup in enumerate((player0tup, player1tup)): type, func, args, prename = playertup if type != LOCAL: if type == ARTIFICIAL: player = yield from func(*args) else: player = func(*args) players.append(player) # if type == ARTIFICIAL: # def readyformoves (player, color): # gmwidg.setTabText(gmwidg.display_text)) # players[i].connect("readyForMoves", readyformoves, i) else: # Until PyChess has a proper profiles system, as discussed on the # issue tracker, we need to give human players special treatment player = func(gmwidg, *args) players.append(player) assert len(players) == 2 if player0tup[0] == ARTIFICIAL and player1tup[0] == ARTIFICIAL: def emit_action(board, action, player, param, gmwidg): if gmwidg.isInFront(): gamemodel.curplayer.emit("offer", Offer(action, param=param)) self.board_cids[gmwidg.board] = gmwidg.board.connect( "action", emit_action, gmwidg) log.debug("Games.generalStart: -> gamemodel.setPlayers(): %s" % (gamemodel)) gamemodel.setPlayers(players) log.debug("Games.generalStart: <- gamemodel.setPlayers(): %s" % (gamemodel)) # Forward information from the engines for playertup, tagname in ((player0tup, "WhiteElo"), (player1tup, "BlackElo")): if playertup[0] == ARTIFICIAL: elo = playertup[2][0].get("elo") if elo: gamemodel.tags[tagname] = elo # Starting if loaddata: try: uri, loader, gameno, position = loaddata gamemodel.loadAndStart(uri, loader, gameno, position) if position != gamemodel.ply and position != -1: gmwidg.board.view.shown = position except LoadingError as e: d = Gtk.MessageDialog(mainwindow(), type=Gtk.MessageType.WARNING, buttons=Gtk.ButtonsType.OK) d.set_markup(_("<big><b>Error loading game</big></b>")) d.format_secondary_text(", ".join(str(a) for a in e.args)) d.show() d.destroy() else: if gamemodel.variant.need_initial_board: for player in gamemodel.players: player.setOptionInitialBoard(gamemodel) log.debug("Games..generalStart: -> gamemodel.start(): %s" % (gamemodel)) gamemodel.emit("game_loaded", "") gamemodel.start() log.debug("Games.generalStart: <- gamemodel.start(): %s" % (gamemodel)) log.debug("Games.generalStart: returning gmwidg=%s\n gamemodel=%s" % (gmwidg, gamemodel))
def closeGame(self, gmwidg): log.debug("Games.closeGame") response = None if not gmwidg.gamemodel.isChanged(): response = Gtk.ResponseType.OK else: markup = "<b><big>" + _( "Save the current game before you close it?") + "</big></b>" if conf.get("autoSave"): x = self.saveGamePGN(gmwidg.gamemodel) if x: response = Gtk.ResponseType.OK else: markup = "<b><big>" + _( "Unable to save to configured file. \ Save the current game before you close it?" ) + "</big></b>" if response is None: d = Gtk.MessageDialog(mainwindow(), type=Gtk.MessageType.WARNING) d.add_button(_("Close _without Saving"), Gtk.ResponseType.OK) d.add_button(Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL) if gmwidg.gamemodel.uri: d.add_button(Gtk.STOCK_SAVE, Gtk.ResponseType.YES) else: d.add_button(Gtk.STOCK_SAVE_AS, Gtk.ResponseType.YES) gmwidg.bringToFront() d.set_markup(markup) d.format_secondary_text( _("It is not possible later to continue the game,\nif you don't save it." )) response = d.run() d.destroy() if response == Gtk.ResponseType.YES: # Test if cancel was pressed in the save-file-dialog if self.saveGame(gmwidg.gamemodel) != Gtk.ResponseType.ACCEPT: response = Gtk.ResponseType.CANCEL if response not in (Gtk.ResponseType.DELETE_EVENT, Gtk.ResponseType.CANCEL): if gmwidg.gamemodel.status in UNFINISHED_STATES: gmwidg.gamemodel.end(ABORTED, ABORTED_AGREEMENT) gmwidg.disconnect(self.gmwidg_cids[gmwidg]) del self.gmwidg_cids[gmwidg] for cid in self.notify_cids[gmwidg]: conf.notify_remove(cid) del self.notify_cids[gmwidg] if gmwidg.board in self.board_cids: gmwidg.board.disconnect(self.board_cids[gmwidg.board]) del self.board_cids[gmwidg.board] self.delGameWidget(gmwidg) self.gamewidgets.remove(gmwidg) gmwidg.gamemodel.terminate() db_persp = perspective_manager.get_perspective("database") if len(self.gamewidgets) == 0: for widget in MENU_ITEMS: if widget in ("copy_pgn", "copy_fen" ) and db_persp.preview_panel is not None: continue gamewidget.getWidgets()[widget].set_property( 'sensitive', False) return response
def on_drag_received(self, widget, context, x, y, selection, target_type, timestamp): if target_type == TARGET_TYPE_URI_LIST: NOTPROC, PARTIAL, FULL = range(3) status = NOTPROC uris = selection.get_uris() for uri in uris: fn, fext = os.path.splitext(uri.lower()) b = False # Chess position if fext == '.fen': b = newGameDialog.loadFileAndRun(uri) # Shortcut elif fext in ['.url', '.desktop']: # Preconf if fext == '.url': sectname = 'InternetShortcut' typeok = True elif fext == '.desktop': sectname = 'Desktop Entry' typeok = False else: assert (False) # Read the shortcut filename = splitUri(uri)[1] with open(filename, 'r') as file: content = file.read() lines = content.replace("\r", '').split("\n") # Extract the link section = False link = '' for item in lines: # Header if item.startswith('['): if section: break section = item.startswith('[%s]' % sectname) if not section: continue # Item if item.startswith('URL='): link = item[4:] if item.startswith('Type=Link') and fext == '.desktop': typeok = True # Load the link if typeok and link != '': pgn = get_internet_game_as_pgn(link) b = newGameDialog.loadPgnAndRun(pgn) # Database else: perspective = perspective_manager.get_perspective( "database") perspective.open_chessfile(uri) b = True # Update the global status if b: if status == NOTPROC: status = FULL else: if status != NOTPROC: status = PARTIAL # Feedback about the load msg = '' if status == NOTPROC: msg = _( 'All the links failed to fetch a relevant chess content.') msgtype = Gtk.MessageType.ERROR elif status == PARTIAL: msg = _('Some links were invalid.') msgtype = Gtk.MessageType.WARNING if msg != '': dlg = Gtk.MessageDialog(mainwindow(), type=msgtype, buttons=Gtk.ButtonsType.OK, message_format=msg) dlg.run() dlg.destroy()
def __init__(self, widgets): self.widgets = widgets self.dialog = self.widgets["manage_engines_dialog"] self.cur_engine = None self.default_workdir = getEngineDataPrefix() uistuff.keepWindowSize("engineswindow", self.dialog) # Put engines into tree store self.allstore = Gtk.ListStore(Pixbuf, str) self.tv = self.widgets["engines_treeview"] self.tv.set_model(self.allstore) self.tv.append_column( Gtk.TreeViewColumn("Flag", Gtk.CellRendererPixbuf(), pixbuf=0)) name_renderer = Gtk.CellRendererText() name_renderer.set_property("editable", False) self.tv.append_column(Gtk.TreeViewColumn("Name", name_renderer, text=1)) # Add cell renderer to protocol combo column protocol_combo = self.widgets["engine_protocol_combo"] protocol_combo.set_name("engine_protocol_combo") cell = Gtk.CellRendererText() protocol_combo.pack_start(cell, True) protocol_combo.add_attribute(cell, "text", 0) # Add columns and cell renderers to options treeview self.options_store = Gtk.ListStore(str, str, GObject.TYPE_PYOBJECT) optv = self.widgets["options_treeview"] optv.set_model(self.options_store) optv.append_column( Gtk.TreeViewColumn(" ", Gtk.CellRendererText(), text=0)) optv.append_column( Gtk.TreeViewColumn(_("Option"), Gtk.CellRendererText(), text=1)) optv.append_column( Gtk.TreeViewColumn(_("Value"), KeyValueCellRenderer(self.options_store), data=2)) self.update_store() def do_update_store(self, *args): GLib.idle_add(engine_dialog.update_store) discoverer.connect_after("engine_discovered", do_update_store) ################################################################ # remove button ################################################################ def remove(button): if self.cur_engine is not None: self.widgets['remove_engine_button'].set_sensitive(False) discoverer.removeEngine(self.cur_engine) selection = self.tv.get_selection() result = selection.get_selected() if result is not None: model, ts_iter = result model.remove(ts_iter) if model.iter_n_children() == 0: clearView() # Notify playerCombos in NewGameTasker discoverer.emit("all_engines_discovered") self.widgets["remove_engine_button"].connect("clicked", remove) ################################################################ # add button ################################################################ engine_chooser_dialog = Gtk.FileChooserDialog( _("Select engine"), mainwindow(), Gtk.FileChooserAction.OPEN, (Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL, Gtk.STOCK_OPEN, Gtk.ResponseType.OK)) filter = Gtk.FileFilter() filter.set_name(_("Executable files")) filter.add_mime_type("application/x-executable") filter.add_mime_type("application/x-sharedlib") filter.add_mime_type("application/x-ms-dos-executable") filter.add_mime_type("application/x-msdownload") filter.add_pattern("*.exe") for vm in VM_LIST: filter.add_pattern("*%s" % vm.ext) engine_chooser_dialog.add_filter(filter) self.add = False def add(button): self.add = True response = engine_chooser_dialog.run() if response == Gtk.ResponseType.OK: new_engine = engine_chooser_dialog.get_filename() binname = os.path.split(new_engine)[1] ext = os.path.splitext(new_engine)[1] # Verify if the engine already exists under the same name if new_engine != "": for eng in discoverer.getEngines(): if eng["command"] == new_engine: msg_dia = Gtk.MessageDialog( mainwindow(), type=Gtk.MessageType.ERROR, buttons=Gtk.ButtonsType.OK) msg_dia.set_markup( _("<big><b>Unable to add %s</b></big>" % new_engine)) msg_dia.format_secondary_text( _("The engine is already installed under the same name" )) msg_dia.run() msg_dia.hide() new_engine = "" break # Detect the host application if new_engine != "": vm_name = None vm_args = None vmpath = "" # Scripting for vm in VM_LIST: if ext == vm.ext: vm_name = vm.name vm_args = vm.args break # Wine for Windows application under Linux if vm_name is None and new_engine.lower().endswith( ".exe") and sys.platform != "win32": vm_name = "wine" # Check that the interpreter is available if vm_name is not None: vmpath = shutil.which(vm_name, mode=os.R_OK | os.X_OK) if vmpath is None: msg_dia = Gtk.MessageDialog( mainwindow(), type=Gtk.MessageType.ERROR, buttons=Gtk.ButtonsType.OK) msg_dia.set_markup( _("<big><b>Unable to add %s</b></big>" % new_engine)) msg_dia.format_secondary_text( vm_name + _(" is not installed")) msg_dia.run() msg_dia.hide() new_engine = "" # Next checks if new_engine: vm_ext_list = [vm.ext for vm in VM_LIST] if ext not in vm_ext_list and not os.access( new_engine, os.X_OK): msg_dia = Gtk.MessageDialog(mainwindow(), type=Gtk.MessageType.ERROR, buttons=Gtk.ButtonsType.OK) msg_dia.set_markup( _("<big><b>%s is not marked executable in the filesystem</b></big>" % new_engine)) msg_dia.format_secondary_text( _("Try chmod a+x %s" % new_engine)) msg_dia.run() msg_dia.hide() self.add = False engine_chooser_dialog.hide() return try: engine_command = [] if vmpath: engine_command.append(vmpath) if vm_args is not None: engine_command += vm_args engine_command.append(new_engine) # Search the engines based on the most expectable protocol refeng = discoverer.getReferencedEngine(binname) if refeng is not None and refeng[ "protocol"] == "xboard": checkers = [is_cecp, is_uci] else: checkers = [is_uci, is_cecp] uci = False for checker in checkers: check_ok = checker(engine_command) if check_ok: uci = checker is is_uci break if not check_ok: # restore the original engine = discoverer.getEngineByName( self.cur_engine) engine_chooser_dialog.set_filename( engine["command"]) msg_dia = Gtk.MessageDialog( mainwindow(), type=Gtk.MessageType.ERROR, buttons=Gtk.ButtonsType.OK) msg_dia.set_markup( _("<big><b>Unable to add %s</b></big>" % new_engine)) msg_dia.format_secondary_text( _("There is something wrong with this executable" )) msg_dia.run() msg_dia.hide() engine_chooser_dialog.hide() self.add = False engine_chooser_dialog.hide() return self.widgets["engine_command_entry"].set_text( new_engine) self.widgets["engine_protocol_combo"].set_active( 0 if uci else 1) self.widgets["engine_args_entry"].set_text("") # active = self.widgets["engine_protocol_combo"].get_active() protocol = "uci" if uci else "xboard" # print(binname, new_engine, protocol, vm_name, vm_args) discoverer.addEngine(binname, new_engine, protocol, vm_name, vm_args) self.cur_engine = binname self.add = False discoverer.discover() except Exception: msg_dia = Gtk.MessageDialog(mainwindow(), type=Gtk.MessageType.ERROR, buttons=Gtk.ButtonsType.OK) msg_dia.set_markup( _("<big><b>Unable to add %s</b></big>" % new_engine)) msg_dia.format_secondary_text( _("There is something wrong with this executable")) msg_dia.run() msg_dia.hide() self.add = False engine_chooser_dialog.hide() return else: # restore the original engine = discoverer.getEngineByName(self.cur_engine) engine_chooser_dialog.set_filename(engine["command"]) engine_chooser_dialog.hide() self.widgets["add_engine_button"].connect("clicked", add) ################################################################ # add in mass button ################################################################ def addInMass(button): # Ask the user to select a folder folder_dlg = Gtk.FileChooserDialog( _("Choose a folder"), None, Gtk.FileChooserAction.SELECT_FOLDER, (Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL, Gtk.STOCK_OPEN, Gtk.ResponseType.OK)) answer = folder_dlg.run() path = folder_dlg.get_filename() folder_dlg.destroy() # Search for the engines if answer != Gtk.ResponseType.OK: return False possibleFiles = listEnginesFromPath(path) # Remove the existing engines from the list def isNewEngine(path): sfn = os.path.basename(path) for engine in discoverer.getEngines(): if sfn in engine.get( "command"): # The short name must be unique return False return True possibleFiles = [fn for fn in possibleFiles if isNewEngine(fn)] if len(possibleFiles) == 0: return False # Prepare the result in a dialog mass_dialog = self.widgets["engine_list_dialog"] self.widgets["mass_path_label"].set_text(path) mass_list = self.widgets["mass_list_treeview"] if len(mass_list.get_columns()) == 0: # Not initialized yet mass_store = Gtk.ListStore(bool, str) mass_list.set_model(mass_store) def checkbox_renderer_cb(cell, path, model): model[path][0] = not model[path][0] return checkbox_renderer = Gtk.CellRendererToggle() checkbox_renderer.set_property("activatable", True) checkbox_renderer.connect("toggled", checkbox_renderer_cb, mass_store) mass_list.append_column( Gtk.TreeViewColumn(_("Import"), checkbox_renderer, active=0)) mass_list.append_column( Gtk.TreeViewColumn(_("File name"), Gtk.CellRendererText(), text=1)) else: mass_store = mass_list.get_model() mass_store.clear() for fn in possibleFiles: mass_store.append([False, fn[len(path):]]) # Show the dialog answer = mass_dialog.run() mass_dialog.hide() if answer != Gtk.ResponseType.OK.real: return False # Add the new engines self.add = True found = False for entry in mass_store: if entry[0]: newengine = discoverer.getReferencedEngine(path + entry[1]) if newengine is not None: discoverer.addEngineFromReference(newengine) found = True self.add = False if found: discoverer.discover() return True self.widgets["mass_engine_button"].connect("clicked", addInMass) ################################################################ def clearView(): self.selection = True self.cur_engine = None self.widgets["vm_command_entry"].set_text("") self.widgets["vm_args_entry"].set_text("") self.widgets["engine_command_entry"].set_text("") self.widgets["engine_args_entry"].set_text("") self.widgets["engine_protocol_combo"].set_active(0) self.widgets["engine_country_combo"].set_active(0) self.widgets["engine_comment_entry"].set_text("") self.widgets["engine_level_scale"].set_value(ENGINE_DEFAULT_LEVEL) self.options_store.clear() self.selection = False ################################################################ # vm args ################################################################ def vm_args_changed(widget): if self.cur_engine is not None and not self.selection: new_args = self.widgets["vm_args_entry"].get_text().strip() engine = discoverer.getEngineByName(self.cur_engine) old_args = engine.get("vm_args") if new_args != old_args: engine["vm_args"] = new_args.split() self.widgets["vm_args_entry"].connect("changed", vm_args_changed) ################################################################ # engine args ################################################################ def args_changed(widget): if self.cur_engine is not None and not self.selection: new_args = self.widgets["engine_args_entry"].get_text().strip() engine = discoverer.getEngineByName(self.cur_engine) old_args = engine.get("args") if new_args != old_args: engine["args"] = new_args.split() self.widgets["engine_args_entry"].connect("changed", args_changed) ################################################################ # engine working directory ################################################################ dir_chooser_dialog = Gtk.FileChooserDialog( _("Select working directory"), mainwindow(), Gtk.FileChooserAction.SELECT_FOLDER, (Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL, Gtk.STOCK_OPEN, Gtk.ResponseType.OK)) dir_chooser_button = Gtk.FileChooserButton.new_with_dialog( dir_chooser_dialog) self.widgets["dirChooserDock"].add(dir_chooser_button) dir_chooser_button.show() def select_dir(button): new_directory = dir_chooser_dialog.get_filename() engine = discoverer.getEngineByName(self.cur_engine) old_directory = engine.get("workingDirectory") if new_directory != old_directory and new_directory != self.default_workdir: engine["workingDirectory"] = new_directory dir_chooser_button.connect("current-folder-changed", select_dir) ################################################################ # engine protocol ################################################################ def protocol_changed(widget): if self.cur_engine is not None and not self.add and not self.selection: active = self.widgets["engine_protocol_combo"].get_active() new_protocol = "uci" if active == 0 else "xboard" engine = discoverer.getEngineByName(self.cur_engine) old_protocol = engine["protocol"] if new_protocol != old_protocol: command = engine.get("command") engine_command = [] vm_command = engine.get("vm_command") if vm_command is not None: engine_command.append(vm_command) vm_args = engine.get("vm_args") if vm_args is not None: engine_command.append(", ".join(vm_args)) engine_command.append(command) # is the new protocol supported by the engine? if new_protocol == "uci": check_ok = is_uci(engine_command) else: check_ok = is_cecp(engine_command) if check_ok: # discover engine options for new protocol engine["protocol"] = new_protocol engine["recheck"] = True discoverer.discover() else: # restore the original protocol widgets["engine_protocol_combo"].set_active( 0 if old_protocol == "uci" else 1) self.widgets["engine_protocol_combo"].connect("changed", protocol_changed) ################################################################ # engine country ################################################################ def country_changed(widget): if self.cur_engine is not None and not self.selection: engine = discoverer.getEngineByName(self.cur_engine) old_country = discoverer.getCountry(engine) new_country = ISO3166_LIST[widget.get_active()].iso2 if old_country != new_country: engine["country"] = new_country # Refresh the flag in the tree view path = addDataPrefix("flags/%s.png" % new_country) if not os.path.isfile(path): path = addDataPrefix("flags/unknown.png") item = self.tv.get_selection().get_selected() if item is not None: model, ts_iter = item model[ts_iter][0] = get_pixbuf(path) # Notify playerCombos in NewGameTasker discoverer.emit("all_engines_discovered") self.widgets["engine_country_combo"].connect("changed", country_changed) def country_keypressed(widget, event): idx = 0 for iso in ISO3166_LIST: if (idx != 0) and ( (ord(iso.country[0].lower()) == event.keyval) or (ord(iso.country[0].upper()) == event.keyval)): widget.set_active(idx) break idx += 1 self.widgets["engine_country_combo"].connect("key-press-event", country_keypressed) ################################################################ # comment changed ################################################################ def comment_changed(widget): if self.cur_engine is not None and not self.selection: new_comment = self.widgets["engine_comment_entry"].get_text( ).strip() engine = discoverer.getEngineByName(self.cur_engine) old_comment = engine.get("comment") if new_comment != old_comment: engine["comment"] = new_comment self.widgets["engine_comment_entry"].connect("changed", comment_changed) ################################################################ # level changed ################################################################ def level_changed(widget): if self.cur_engine is not None and not self.selection: new_level = widget.get_value() engine = discoverer.getEngineByName(self.cur_engine) old_level = engine.get("level") if new_level != old_level: engine["level"] = int(new_level) self.widgets["engine_level_scale"].connect("value-changed", level_changed) ################################################################ # engine tree ################################################################ self.selection = False def selection_changed(treeselection): store, tv_iter = self.tv.get_selection().get_selected() if tv_iter: self.selection = True path = store.get_path(tv_iter) indices = path.get_indices() row = indices[0] name = store[row][1] self.cur_engine = name engine = discoverer.getEngineByName(name) if "PyChess.py" in engine["command"]: self.widgets['remove_engine_button'].set_sensitive(False) else: self.widgets['remove_engine_button'].set_sensitive(True) self.widgets["engine_command_entry"].set_text( engine["command"]) engine_chooser_dialog.set_filename(engine["command"]) args = [] if engine.get("args") is None else engine.get("args") self.widgets["engine_args_entry"].set_text(' '.join(args)) vm = engine.get("vm_command") self.widgets["vm_command_entry"].set_text( vm if vm is not None else "") args = [] if engine.get("vm_args") is None else engine.get( "vm_args") self.widgets["vm_args_entry"].set_text(' '.join(args)) directory = engine.get("workingDirectory") dir_choice = directory if directory is not None else self.default_workdir dir_chooser_dialog.set_current_folder(dir_choice) self.widgets["engine_protocol_combo"].set_active( 0 if engine["protocol"] == "uci" else 1) self.widgets["engine_country_combo"].set_active(0) country = discoverer.getCountry(engine) idx = 0 for iso in ISO3166_LIST: if iso.iso2 == country: self.widgets["engine_country_combo"].set_active(idx) break idx += 1 comment = engine.get("comment") self.widgets["engine_comment_entry"].set_text( comment if comment is not None else "") level = engine.get("level") try: level = int(level) except Exception: level = ENGINE_DEFAULT_LEVEL self.widgets["engine_level_scale"].set_value(level) self.update_options() self.selection = False tree_selection = self.tv.get_selection() tree_selection.connect('changed', selection_changed) tree_selection.select_path((0, )) selection_changed(tree_selection) ################################################################ # restore the default options of the engine ################################################################ def engine_default_options(button): if self.cur_engine is not None and not self.selection: engine = discoverer.getEngineByName(self.cur_engine) options = engine.get("options") if options: dialog = Gtk.MessageDialog(mainwindow(), type=Gtk.MessageType.QUESTION, buttons=Gtk.ButtonsType.YES_NO) dialog.set_markup( _("Do you really want to restore the default options of the engine ?" )) response = dialog.run() dialog.destroy() if response == Gtk.ResponseType.YES: for option in options: if "default" in option: option["value"] = option["default"] self.update_options() self.widgets["engine_default_options_button"].connect( "clicked", engine_default_options)
def saveGameAs(self, game, position=None, export=False): savedialog, savecombo = get_save_dialog(export) # Keep running the dialog until the user has canceled it or made an error # free operation title = _("Save Game") if not export else _("Export position") savedialog.set_title(title) while True: savedialog.set_current_name( "%s %s %s" % (game.players[0], _("vs."), game.players[1])) res = savedialog.run() if res != Gtk.ResponseType.ACCEPT: break uri = savedialog.get_filename() ending = os.path.splitext(uri)[1] if ending.startswith("."): ending = ending[1:] append = False index = savecombo.get_active() if index == 0: if ending not in enddir: d = Gtk.MessageDialog(mainwindow(), type=Gtk.MessageType.ERROR, buttons=Gtk.ButtonsType.OK) folder, file = os.path.split(uri) d.set_markup(_("<big><b>Unknown file type '%s'</b></big>") % ending) d.format_secondary_text(_( "Was unable to save '%(uri)s' as PyChess doesn't know the format '%(ending)s'.") % {'uri': uri, 'ending': ending}) d.run() d.destroy() continue else: saver = enddir[ending] else: format = exportformats[index] if export else saveformats[index] saver = format[2] if ending not in enddir or not saver == enddir[ending]: uri += ".%s" % saver.__ending__ if os.path.isfile(uri) and not os.access(uri, os.W_OK): d = Gtk.MessageDialog(mainwindow(), type=Gtk.MessageType.ERROR, buttons=Gtk.ButtonsType.OK) d.set_markup(_("<big><b>Unable to save file '%s'</b></big>") % uri) d.format_secondary_text(_( "You don't have the necessary rights to save the file.\n\ Please ensure that you have given the right path and try again.")) d.run() d.destroy() continue if os.path.isfile(uri): d = Gtk.MessageDialog(mainwindow(), type=Gtk.MessageType.QUESTION) d.add_buttons(Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL, _("_Replace"), Gtk.ResponseType.ACCEPT) if saver.__append__: d.add_buttons(Gtk.STOCK_ADD, 1) d.set_title(_("File exists")) folder, file = os.path.split(uri) d.set_markup(_( "<big><b>A file named '%s' already exists. Would you like to replace it?</b></big>") % file) d.format_secondary_text(_( "The file already exists in '%s'. If you replace it, its content will be overwritten.") % folder) replaceRes = d.run() d.destroy() if replaceRes == 1: append = True elif replaceRes == Gtk.ResponseType.CANCEL: continue else: print(repr(uri)) try: game.save(uri, saver, append, position) except IOError as e: d = Gtk.MessageDialog(mainwindow(), type=Gtk.MessageType.ERROR) d.add_buttons(Gtk.STOCK_OK, Gtk.ResponseType.OK) d.set_title(_("Could not save the file")) d.set_markup(_( "<big><b>PyChess was not able to save the game</b></big>")) d.format_secondary_text(_("The error was: %s") % ", ".join( str(a) for a in e.args)) d.run() d.destroy() continue break savedialog.destroy() return res
def _init(cls): cls.white = get_pixbuf("glade/white.png") cls.black = get_pixbuf("glade/black.png") cls.widgets = uistuff.GladeWidgets("newInOut.glade") cls.widgets["newgamedialog"].set_transient_for(mainwindow()) def on_exchange_players(widget, button_event): white = cls.widgets["whitePlayerCombobox"].get_active() black = cls.widgets["blackPlayerCombobox"].get_active() whiteLevel = cls.widgets["skillSlider1"].get_value() blackLevel = cls.widgets["skillSlider2"].get_value() cls.widgets["whitePlayerCombobox"].set_active(black) cls.widgets["blackPlayerCombobox"].set_active(white) cls.widgets["skillSlider1"].set_value(blackLevel) cls.widgets["skillSlider2"].set_value(whiteLevel) cls.widgets["whitePlayerButton"].set_image( Gtk.Image.new_from_pixbuf(cls.white)) cls.widgets["whitePlayerButton"].connect("button-press-event", on_exchange_players) cls.widgets["blackPlayerButton"].set_image( Gtk.Image.new_from_pixbuf(cls.black)) cls.widgets["blackPlayerButton"].connect("button-press-event", on_exchange_players) uistuff.createCombo(cls.widgets["whitePlayerCombobox"], name="whitePlayerCombobox") uistuff.createCombo(cls.widgets["blackPlayerCombobox"], name="blackPlayerCombobox") cls.widgets["playersIcon"].set_from_pixbuf(big_people) cls.widgets["timeIcon"].set_from_pixbuf(big_time) def on_playerCombobox_changed(widget, skill_hbox, skill_level): position = widget.get_active() skill_hbox.props.visible = position > 0 if position > 0: tree_iter = widget.get_active_iter() if tree_iter is not None: engine_name = widget.get_model()[tree_iter][1] engine = discoverer.getEngineByName(engine_name) if engine: pref_level = engine.get("level") if pref_level: skill_level.set_value(pref_level) cls.widgets["whitePlayerCombobox"].connect("changed", on_playerCombobox_changed, cls.widgets["skillHbox1"], cls.widgets["skillSlider1"]) cls.widgets["blackPlayerCombobox"].connect("changed", on_playerCombobox_changed, cls.widgets["skillHbox2"], cls.widgets["skillSlider2"]) cls.widgets["whitePlayerCombobox"].set_active(0) cls.widgets["blackPlayerCombobox"].set_active(1) def on_skill_changed(scale, image): image.set_from_pixbuf(skillToIcon[int(scale.get_value())]) cls.widgets["skillSlider1"].connect("value-changed", on_skill_changed, cls.widgets["skillIcon1"]) cls.widgets["skillSlider2"].connect("value-changed", on_skill_changed, cls.widgets["skillIcon2"]) cls.widgets["skillSlider1"].set_value(3) cls.widgets["skillSlider2"].set_value(3) cls.__initTimeRadio("ngblitz", cls.widgets["blitzRadio"], cls.widgets["configImageBlitz"], 5, 0, 0) cls.__initTimeRadio("ngrapid", cls.widgets["rapidRadio"], cls.widgets["configImageRapid"], 15, 5, 0) cls.__initTimeRadio("ngnormal", cls.widgets["normalRadio"], cls.widgets["configImageNormal"], 45, 15, 0) cls.__initTimeRadio("ngclassical", cls.widgets["classicalRadio"], cls.widgets["configImageClassical"], 3, 0, 40) cls.__initVariantRadio("ngvariant1", cls.widgets["playVariant1Radio"], cls.widgets["configImageVariant1"]) cls.__initVariantRadio("ngvariant2", cls.widgets["playVariant2Radio"], cls.widgets["configImageVariant2"]) def updateCombos(*args): if cls.widgets["playNormalRadio"].get_active(): variant = NORMALCHESS elif cls.widgets["playVariant1Radio"].get_active(): variant = conf.get("ngvariant1") else: variant = conf.get("ngvariant2") variant1 = conf.get("ngvariant1") cls.widgets["playVariant1Radio"].set_tooltip_text( variants[variant1].__desc__) variant2 = conf.get("ngvariant2") cls.widgets["playVariant2Radio"].set_tooltip_text( variants[variant2].__desc__) data = [(item[0], item[1]) for item in playerItems[variant]] uistuff.updateCombo(cls.widgets["blackPlayerCombobox"], data) uistuff.updateCombo(cls.widgets["whitePlayerCombobox"], data) discoverer.connect_after("all_engines_discovered", updateCombos) updateCombos(discoverer) conf.notify_add("ngvariant1", updateCombos) conf.notify_add("ngvariant2", updateCombos) cls.widgets["playNormalRadio"].connect("toggled", updateCombos) cls.widgets["playNormalRadio"].set_tooltip_text( variants[NORMALCHESS].__desc__) cls.widgets["playVariant1Radio"].connect("toggled", updateCombos) variant1 = conf.get("ngvariant1") cls.widgets["playVariant1Radio"].set_tooltip_text( variants[variant1].__desc__) cls.widgets["playVariant2Radio"].connect("toggled", updateCombos) variant2 = conf.get("ngvariant2") cls.widgets["playVariant2Radio"].set_tooltip_text( variants[variant2].__desc__) # The "variant" has to come before players, because the engine positions # in the user comboboxes can be different in different variants for key in ("whitePlayerCombobox", "blackPlayerCombobox", "skillSlider1", "skillSlider2", "notimeRadio", "blitzRadio", "rapidRadio", "normalRadio", "classicalRadio", "playNormalRadio", "playVariant1Radio", "playVariant2Radio"): uistuff.keep(cls.widgets[key], key) # We don't want the dialog to deallocate when closed. Rather we hide # it on respond cls.widgets["newgamedialog"].connect("delete_event", lambda *a: True)
def generalStart(self, gamemodel, player0tup, player1tup, loaddata=None): """ The player tuples are: (The type af player in a System.const value, A callable creating the player, A list of arguments for the callable, A preliminary name for the player) If loaddata is specified, it should be a tuple of: (A text uri or fileobj, A Savers.something module with a load function capable of loading it, An int of the game in file you want to load, The position from where to start the game) """ log.debug("Games.generalStart: %s\n %s\n %s" % (gamemodel, player0tup, player1tup)) gmwidg = gamewidget.GameWidget(gamemodel, self) self.gamewidgets.add(gmwidg) self.gmwidg_cids[gmwidg] = gmwidg.connect("game_close_clicked", self.closeGame) # worker.publish((gmwidg,gamemodel)) self.attachGameWidget(gmwidg) game_nanny.nurseGame(gmwidg, gamemodel) log.debug("Games.generalStart: -> emit gmwidg_created: %s" % (gmwidg)) self.emit("gmwidg_created", gmwidg) log.debug("Games.generalStart: <- emit gmwidg_created: %s" % (gmwidg)) # Initing players def xxxset_name(none, player, key, alt): player.setName(conf.get(key, alt)) players = [] for i, playertup in enumerate((player0tup, player1tup)): type, func, args, prename = playertup if type != LOCAL: if type == ARTIFICIAL: player = yield from func(*args) else: player = func(*args) players.append(player) # if type == ARTIFICIAL: # def readyformoves (player, color): # gmwidg.setTabText(gmwidg.display_text)) # players[i].connect("readyForMoves", readyformoves, i) else: # Until PyChess has a proper profiles system, as discussed on the # issue tracker, we need to give human players special treatment player = func(gmwidg, *args) players.append(player) assert len(players) == 2 if player0tup[0] == ARTIFICIAL and player1tup[0] == ARTIFICIAL: def emit_action(board, action, player, param, gmwidg): if gmwidg.isInFront(): gamemodel.curplayer.emit("offer", Offer(action, param=param)) self.board_cids[gmwidg.board] = gmwidg.board.connect("action", emit_action, gmwidg) log.debug("Games.generalStart: -> gamemodel.setPlayers(): %s" % (gamemodel)) gamemodel.setPlayers(players) log.debug("Games.generalStart: <- gamemodel.setPlayers(): %s" % (gamemodel)) # Forward information from the engines for playertup, tagname in ((player0tup, "WhiteElo"), (player1tup, "BlackElo")): if playertup[0] == ARTIFICIAL: elo = playertup[2][0].get("elo") if elo: gamemodel.tags[tagname] = elo # Starting if loaddata: try: uri, loader, gameno, position = loaddata gamemodel.loadAndStart(uri, loader, gameno, position) if position != gamemodel.ply and position != -1: gmwidg.board.view.shown = position except LoadingError as e: d = Gtk.MessageDialog(mainwindow(), type=Gtk.MessageType.WARNING, buttons=Gtk.ButtonsType.OK) d.set_markup(_("<big><b>Error loading game</big></b>")) d.format_secondary_text(", ".join(str(a) for a in e.args)) d.show() d.destroy() else: if gamemodel.variant.need_initial_board: for player in gamemodel.players: player.setOptionInitialBoard(gamemodel) log.debug("Games..generalStart: -> gamemodel.start(): %s" % (gamemodel)) gamemodel.start() log.debug("Games.generalStart: <- gamemodel.start(): %s" % (gamemodel)) log.debug("Games.generalStart: returning gmwidg=%s\n gamemodel=%s" % (gmwidg, gamemodel))
def __init__(self, persp): GObject.GObject.__init__(self) self.persp = persp self.filtered = False self.widgets = uistuff.GladeWidgets("PyChess.glade") # Build variant combo model variant_store = Gtk.ListStore(str, int) for name, variant in sorted(name2variant.items()): variant_store.append((name, variant.variant)) self.widgets["variant"].set_model(variant_store) renderer_text = Gtk.CellRendererText() self.widgets["variant"].pack_start(renderer_text, True) self.widgets["variant"].add_attribute(renderer_text, "text", 0) # Add piece widgets to dialog *_dock containers on material tab self.dialog = self.widgets["filter_dialog"] self.dialog.set_transient_for(mainwindow()) for piece in "qrbnp": dock = "w%s_dock" % piece self.widgets[dock].add(PieceWidget(Piece(WHITE, chr2Sign[piece]))) self.widgets[dock].get_child().show() dock = "b%s_dock" % piece self.widgets[dock].add(PieceWidget(Piece(BLACK, chr2Sign[piece]))) self.widgets[dock].get_child().show() dock = "moved_%s_dock" % piece self.widgets[dock].add(PieceWidget(Piece(BLACK, chr2Sign[piece]))) self.widgets[dock].get_child().show() dock = "captured_%s_dock" % piece self.widgets[dock].add(PieceWidget(Piece(BLACK, chr2Sign[piece]))) self.widgets[dock].get_child().show() piece = "k" dock = "moved_%s_dock" % piece self.widgets[dock].add(PieceWidget(Piece(BLACK, chr2Sign[piece]))) self.widgets[dock].get_child().show() # We will store our filtering queries in a ListStore # column 0: query as text # column 1: query dict # column 2: filter type (NONE, TAG_FILTER or MATERIAL_FILTER or PATTERN_FILTER) # column 3: row type (RULE, SEQUENCE, STREAK) self.treestore = Gtk.TreeStore(str, object, int, int) self.set_model(self.treestore) self.set_headers_visible(True) self.set_grid_lines(Gtk.TreeViewGridLines.HORIZONTAL) column = Gtk.TreeViewColumn("filter", Gtk.CellRendererText(), text=0) column.set_min_width(80) self.append_column(column) self.columns_autosize() sw = Gtk.ScrolledWindow() sw.set_shadow_type(Gtk.ShadowType.ETCHED_IN) sw.add(self) self.box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL) self.box.pack_start(sw, True, True, 0) # Add buttons toolbar = Gtk.Toolbar() editButton = Gtk.ToolButton(Gtk.STOCK_EDIT) editButton.set_tooltip_text(_("Edit selected filter")) editButton.connect("clicked", self.on_edit_clicked) toolbar.insert(editButton, -1) delButton = Gtk.ToolButton(Gtk.STOCK_REMOVE) delButton.set_tooltip_text(_("Remove selected filter")) delButton.connect("clicked", self.on_del_clicked) toolbar.insert(delButton, -1) addButton = Gtk.ToolButton(Gtk.STOCK_ADD) addButton.set_tooltip_text(_("Add new filter")) addButton.connect("clicked", self.on_add_clicked) toolbar.insert(addButton, -1) addSeqButton = Gtk.ToolButton() addSeqButton.set_label(_("Seq")) addSeqButton.set_is_important(True) addSeqButton.set_tooltip_text( _("Create new squence where listed conditions may be satisfied at different times in a game" )) addSeqButton.connect("clicked", self.on_add_sequence_clicked) toolbar.insert(addSeqButton, -1) addStreakButton = Gtk.ToolButton() addStreakButton.set_label(_("Str")) addStreakButton.set_is_important(True) addStreakButton.set_tooltip_text( _("Create new streak sequence where listed conditions have to be satisfied in consecutive (half)moves" )) addStreakButton.connect("clicked", self.on_add_streak_clicked) toolbar.insert(addStreakButton, -1) self.filterButton = Gtk.ToggleToolButton(Gtk.STOCK_FIND) self.filterButton.set_tooltip_text( _("Filter game list by various conditions")) self.filterButton.connect("clicked", self.on_filter_clicked) toolbar.insert(self.filterButton, -1) tool_box = Gtk.Box() tool_box.pack_start(toolbar, False, False, 0) self.box.pack_start(tool_box, False, False, 0) self.box.show_all()
def init_layout(self): perspective_widget = Gtk.Box(orientation=Gtk.Orientation.VERTICAL) perspective_manager.set_perspective_widget("games", perspective_widget) self.notebooks = {"board": cleanNotebook("board"), "buttons": cleanNotebook("buttons"), "messageArea": cleanNotebook("messageArea")} for panel in sidePanels: self.notebooks[panel.__name__] = cleanNotebook(panel.__name__) # Initing headbook align = gamewidget.createAlignment(4, 4, 0, 4) align.set_property("yscale", 0) headbook = Gtk.Notebook() headbook.set_name("headbook") headbook.set_scrollable(True) align.add(headbook) perspective_widget.pack_start(align, False, True, 0) self.show_tabs(not conf.get("hideTabs", False)) # Initing center centerVBox = Gtk.VBox() # The dock self.dock = PyDockTop("main", self) self.dockAlign = gamewidget.createAlignment(4, 4, 0, 4) self.dockAlign.add(self.dock) centerVBox.pack_start(self.dockAlign, True, True, 0) self.dockAlign.show() self.dock.show() self.docks = {"board": (Gtk.Label(label="Board"), self.notebooks["board"])} for panel in sidePanels: box = dock_panel_tab(panel.__title__, panel.__desc__, panel.__icon__) self.docks[panel.__name__] = (box, self.notebooks[panel.__name__]) if os.path.isfile(dockLocation): try: self.dock.loadFromXML(dockLocation, self.docks) except Exception as e: stringio = StringIO() traceback.print_exc(file=stringio) error = stringio.getvalue() log.error("Dock loading error: %s\n%s" % (e, error)) msg_dia = Gtk.MessageDialog(mainwindow(), type=Gtk.MessageType.ERROR, buttons=Gtk.ButtonsType.CLOSE) msg_dia.set_markup(_( "<b><big>PyChess was unable to load your panel settings</big></b>")) msg_dia.format_secondary_text(_( "Your panel settings have been reset. If this problem repeats, \ you should report it to the developers")) msg_dia.run() msg_dia.hide() os.remove(dockLocation) for title, panel in self.docks.values(): title.unparent() panel.unparent() if not os.path.isfile(dockLocation): leaf = self.dock.dock(self.docks["board"][1], CENTER, Gtk.Label(label=self.docks["board"][0]), "board") self.docks["board"][1].show_all() leaf.setDockable(False) # S epanel = leaf.dock(self.docks["bookPanel"][1], SOUTH, self.docks["bookPanel"][0], "bookPanel") epanel.default_item_height = 45 epanel = epanel.dock(self.docks["engineOutputPanel"][1], CENTER, self.docks["engineOutputPanel"][0], "engineOutputPanel") # NE leaf = leaf.dock(self.docks["annotationPanel"][1], EAST, self.docks["annotationPanel"][0], "annotationPanel") leaf = leaf.dock(self.docks["historyPanel"][1], CENTER, self.docks["historyPanel"][0], "historyPanel") leaf = leaf.dock(self.docks["scorePanel"][1], CENTER, self.docks["scorePanel"][0], "scorePanel") # SE leaf = leaf.dock(self.docks["chatPanel"][1], SOUTH, self.docks["chatPanel"][0], "chatPanel") leaf = leaf.dock(self.docks["commentPanel"][1], CENTER, self.docks["commentPanel"][0], "commentPanel") def unrealize(dock, notebooks): # unhide the panel before saving so its configuration is saved correctly self.notebooks["board"].get_parent().get_parent().zoomDown() dock.saveToXML(dockLocation) dock._del() self.dock.connect("unrealize", unrealize, self.notebooks) hbox = Gtk.HBox() # Buttons self.notebooks["buttons"].set_border_width(4) hbox.pack_start(self.notebooks["buttons"], False, True, 0) # The message area # TODO: If you try to fix this first read issue #958 and 1018 align = gamewidget.createAlignment(0, 0, 0, 0) # sw = Gtk.ScrolledWindow() # port = Gtk.Viewport() # port.add(self.notebooks["messageArea"]) # sw.add(port) # align.add(sw) align.add(self.notebooks["messageArea"]) hbox.pack_start(align, True, True, 0) def ma_switch_page(notebook, gpointer, page_num): notebook.props.visible = notebook.get_nth_page(page_num).\ get_child().props.visible self.notebooks["messageArea"].connect("switch-page", ma_switch_page) centerVBox.pack_start(hbox, False, True, 0) perspective_widget.pack_start(centerVBox, True, True, 0) centerVBox.show_all() perspective_widget.show_all() conf.notify_add("hideTabs", self.tabsCallback) # Connecting headbook to other notebooks def hb_switch_page(notebook, gpointer, page_num): for notebook in self.notebooks.values(): notebook.set_current_page(page_num) gmwidg = self.key2gmwidg[self.getheadbook().get_nth_page(page_num)] if isinstance(gmwidg.gamemodel, ICGameModel): primary = "primary " + str(gmwidg.gamemodel.ficsgame.gameno) gmwidg.gamemodel.connection.client.run_command(primary) headbook.connect("switch-page", hb_switch_page) if hasattr(headbook, "set_tab_reorderable"): def page_reordered(widget, child, new_num, headbook): old_num = self.notebooks["board"].page_num(self.key2gmwidg[child].boardvbox) if old_num == -1: log.error('Games and labels are out of sync!') else: for notebook in self.notebooks.values(): notebook.reorder_child( notebook.get_nth_page(old_num), new_num) headbook.connect("page-reordered", page_reordered, headbook)
def closeGame(self, gmwidg): log.debug("Games.closeGame") response = None if not gmwidg.gamemodel.isChanged(): response = Gtk.ResponseType.OK else: markup = "<b><big>" + _("Save the current game before you close it?") + "</big></b>" if conf.get("autoSave"): x = self.saveGamePGN(gmwidg.gamemodel) if x: response = Gtk.ResponseType.OK else: markup = "<b><big>" + _("Unable to save to configured file. \ Save the current game before you close it?") + "</big></b>" if response is None: d = Gtk.MessageDialog(mainwindow(), type=Gtk.MessageType.WARNING) d.add_button(_("Close _without Saving"), Gtk.ResponseType.OK) d.add_button(Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL) if gmwidg.gamemodel.uri: d.add_button(Gtk.STOCK_SAVE, Gtk.ResponseType.YES) else: d.add_button(Gtk.STOCK_SAVE_AS, Gtk.ResponseType.YES) gmwidg.bringToFront() d.set_markup(markup) d.format_secondary_text(_( "It is not possible later to continue the game,\nif you don't save it.")) response = d.run() d.destroy() if response == Gtk.ResponseType.YES: # Test if cancel was pressed in the save-file-dialog if self.saveGame(gmwidg.gamemodel) != Gtk.ResponseType.ACCEPT: response = Gtk.ResponseType.CANCEL if response not in (Gtk.ResponseType.DELETE_EVENT, Gtk.ResponseType.CANCEL): if gmwidg.gamemodel.status in UNFINISHED_STATES: gmwidg.gamemodel.end(ABORTED, ABORTED_AGREEMENT) gmwidg.disconnect(self.gmwidg_cids[gmwidg]) del self.gmwidg_cids[gmwidg] for cid in self.notify_cids[gmwidg]: conf.notify_remove(cid) del self.notify_cids[gmwidg] if gmwidg.board in self.board_cids: gmwidg.board.disconnect(self.board_cids[gmwidg.board]) del self.board_cids[gmwidg.board] self.delGameWidget(gmwidg) self.gamewidgets.remove(gmwidg) gmwidg.gamemodel.terminate() db_persp = perspective_manager.get_perspective("database") if len(self.gamewidgets) == 0: for widget in MENU_ITEMS: if widget in ("copy_pgn", "copy_fen") and db_persp.preview_panel is not None: continue gamewidget.getWidgets()[widget].set_property('sensitive', False) return response
def __init__(self, lounge): self.lounge = lounge self.widgets = lounge.widgets self.connection = lounge.connection self.widgets["editSeekDialog"].set_transient_for(mainwindow()) self.widgets["challengeDialog"].set_transient_for(mainwindow()) self.finger = None conf.set("numberOfFingers", 0) self.connection.fm.connect("fingeringFinished", self.onFinger) self.connection.fm.finger(self.connection.getUsername()) self.widgets["untimedCheck"].connect("toggled", self.onUntimedCheckToggled) self.widgets["minutesSpin"].connect("value-changed", self.onTimeSpinChanged) self.widgets["gainSpin"].connect("value-changed", self.onTimeSpinChanged) self.onTimeSpinChanged(self.widgets["minutesSpin"]) self.widgets["nocolorRadio"].connect("toggled", self.onColorRadioChanged) self.widgets["whitecolorRadio"].connect("toggled", self.onColorRadioChanged) self.widgets["blackcolorRadio"].connect("toggled", self.onColorRadioChanged) self.onColorRadioChanged(self.widgets["nocolorRadio"]) self.widgets["noVariantRadio"].connect("toggled", self.onVariantRadioChanged) self.widgets["variantRadio"].connect("toggled", self.onVariantRadioChanged) variantcombo = self.widgets["variantCombo"] variantcombo.set_name("variantcombo") variantComboGetter, variantComboSetter = self.__initVariantCombo( variantcombo) self.seekEditorWidgetGettersSetters["variantCombo"] = ( variantComboGetter, variantComboSetter) self.widgets["variantCombo"].connect("changed", self.onVariantComboChanged) self.widgets["editSeekDialog"].connect("delete_event", lambda *a: True) # self.widgets["challengeDialog"].connect("delete_event", lambda *a: True) self.widgets["strengthCheck"].connect("toggled", self.onStrengthCheckToggled) self.onStrengthCheckToggled(self.widgets["strengthCheck"]) self.widgets["ratingCenterSlider"].connect( "value-changed", self.onRatingCenterSliderChanged) self.onRatingCenterSliderChanged(self.widgets["ratingCenterSlider"]) self.widgets["toleranceSlider"].connect("value-changed", self.onToleranceSliderChanged) self.onToleranceSliderChanged(self.widgets["toleranceSlider"]) self.widgets["toleranceButton"].connect("clicked", self.onToleranceButtonClicked) self.widgets["toleranceButton"].connect("activate-link", lambda link_button: True) def intGetter(widget): return int(widget.get_value()) self.seekEditorWidgetGettersSetters["minutesSpin"] = (intGetter, None) self.seekEditorWidgetGettersSetters["gainSpin"] = (intGetter, None) self.seekEditorWidgetGettersSetters["ratingCenterSlider"] = \ (intGetter, None) self.seekEditorWidgetGettersSetters["toleranceSlider"] = \ (intGetter, None) def toleranceHBoxGetter(widget): return self.widgets["toleranceHBox"].get_property("visible") def toleranceHBoxSetter(widget, visible): assert isinstance(visible, bool) if visible: self.widgets["toleranceHBox"].show() else: self.widgets["toleranceHBox"].hide() self.seekEditorWidgetGettersSetters["toleranceHBox"] = ( toleranceHBoxGetter, toleranceHBoxSetter) self.chainbox = ChainVBox() self.widgets["chainAlignment"].add(self.chainbox) def chainboxGetter(widget): return self.chainbox.active def chainboxSetter(widget, is_active): self.chainbox.active = is_active self.seekEditorWidgetGettersSetters["chainAlignment"] = ( chainboxGetter, chainboxSetter) self.challengee = None self.in_challenge_mode = False self.seeknumber = 1 self.widgets["seekButton"].connect("clicked", self.onSeekButtonClicked) self.widgets["seekAllButton"].connect("clicked", self.onSeekAllButtonClicked) self.widgets["challengeButton"].connect("clicked", self.onChallengeButtonClicked) self.widgets["challengeDialog"].connect("delete-event", self.onChallengeDialogResponse) self.widgets["challengeDialog"].connect("response", self.onChallengeDialogResponse) self.widgets["editSeekDialog"].connect("response", self.onEditSeekDialogResponse) for widget in ("seek1Radio", "seek2Radio", "seek3Radio", "challenge1Radio", "challenge2Radio", "challenge3Radio"): uistuff.keep(self.widgets[widget], widget) self.lastdifference = 0 self.loading_seek_editor = False self.savedSeekRadioTexts = [GAME_TYPES["blitz"].display_text] * 3 for i in range(1, 4): self.__loadSeekEditor(i) self.__writeSavedSeeks(i) self.widgets["seek%sRadioConfigButton" % i].connect( "clicked", self.onSeekRadioConfigButtonClicked, i) self.widgets["challenge%sRadioConfigButton" % i].connect( "clicked", self.onChallengeRadioConfigButtonClicked, i) if not self.connection.isRegistred(): self.chainbox.active = False self.widgets["chainAlignment"].set_sensitive(False) self.widgets["chainAlignment"].set_tooltip_text( _("The chain button is disabled because you are logged in as a guest. Guests \ can't establish ratings, and the chain button's state has no effect when \ there is no rating to which to tie \"Opponent Strength\" to"))
def _init(cls): cls.white = get_pixbuf("glade/white.png") cls.black = get_pixbuf("glade/black.png") cls.widgets = uistuff.GladeWidgets("newInOut.glade") cls.widgets["newgamedialog"].set_transient_for(mainwindow()) def on_exchange_players(widget, button_event): white = cls.widgets["whitePlayerCombobox"].get_active() black = cls.widgets["blackPlayerCombobox"].get_active() whiteLevel = cls.widgets["skillSlider1"].get_value() blackLevel = cls.widgets["skillSlider2"].get_value() cls.widgets["whitePlayerCombobox"].set_active(black) cls.widgets["blackPlayerCombobox"].set_active(white) cls.widgets["skillSlider1"].set_value(blackLevel) cls.widgets["skillSlider2"].set_value(whiteLevel) cls.widgets["whitePlayerButton"].set_image(Gtk.Image.new_from_pixbuf(cls.white)) cls.widgets["whitePlayerButton"].connect("button-press-event", on_exchange_players) cls.widgets["blackPlayerButton"].set_image(Gtk.Image.new_from_pixbuf(cls.black)) cls.widgets["blackPlayerButton"].connect("button-press-event", on_exchange_players) uistuff.createCombo(cls.widgets["whitePlayerCombobox"], name="whitePlayerCombobox") uistuff.createCombo(cls.widgets["blackPlayerCombobox"], name="blackPlayerCombobox") cls.widgets["playersIcon"].set_from_pixbuf(big_people) cls.widgets["timeIcon"].set_from_pixbuf(big_time) def on_playerCombobox_changed(widget, skill_hbox, skill_level): position = widget.get_active() skill_hbox.props.visible = position > 0 if position > 0: tree_iter = widget.get_active_iter() if tree_iter is not None: engine_name = widget.get_model()[tree_iter][1] engine = discoverer.getEngineByName(engine_name) if engine: pref_level = engine.get("level") if pref_level: skill_level.set_value(pref_level) cls.widgets["whitePlayerCombobox"].connect("changed", on_playerCombobox_changed, cls.widgets["skillHbox1"], cls.widgets["skillSlider1"]) cls.widgets["blackPlayerCombobox"].connect("changed", on_playerCombobox_changed, cls.widgets["skillHbox2"], cls.widgets["skillSlider2"]) cls.widgets["whitePlayerCombobox"].set_active(0) cls.widgets["blackPlayerCombobox"].set_active(1) def on_skill_changed(scale, image): image.set_from_pixbuf(skillToIcon[int(scale.get_value())]) cls.widgets["skillSlider1"].connect("value-changed", on_skill_changed, cls.widgets["skillIcon1"]) cls.widgets["skillSlider2"].connect("value-changed", on_skill_changed, cls.widgets["skillIcon2"]) cls.widgets["skillSlider1"].set_value(3) cls.widgets["skillSlider2"].set_value(3) cls.__initTimeRadio("ngblitz", cls.widgets["blitzRadio"], cls.widgets["configImageBlitz"], 5, 0, 0) cls.__initTimeRadio("ngrapid", cls.widgets["rapidRadio"], cls.widgets["configImageRapid"], 15, 5, 0) cls.__initTimeRadio("ngnormal", cls.widgets["normalRadio"], cls.widgets["configImageNormal"], 45, 15, 0) cls.__initTimeRadio("ngclassical", cls.widgets["classicalRadio"], cls.widgets["configImageClassical"], 3, 0, 40) cls.__initVariantRadio("ngvariant1", cls.widgets["playVariant1Radio"], cls.widgets["configImageVariant1"]) cls.__initVariantRadio("ngvariant2", cls.widgets["playVariant2Radio"], cls.widgets["configImageVariant2"]) def updateCombos(*args): if cls.widgets["playNormalRadio"].get_active(): variant = NORMALCHESS elif cls.widgets["playVariant1Radio"].get_active(): variant = conf.get("ngvariant1") else: variant = conf.get("ngvariant2") variant1 = conf.get("ngvariant1") cls.widgets["playVariant1Radio"].set_tooltip_text(variants[variant1].__desc__) variant2 = conf.get("ngvariant2") cls.widgets["playVariant2Radio"].set_tooltip_text(variants[variant2].__desc__) data = [(item[0], item[1]) for item in playerItems[variant]] uistuff.updateCombo(cls.widgets["blackPlayerCombobox"], data) uistuff.updateCombo(cls.widgets["whitePlayerCombobox"], data) discoverer.connect_after("all_engines_discovered", updateCombos) updateCombos(discoverer) conf.notify_add("ngvariant1", updateCombos) conf.notify_add("ngvariant2", updateCombos) cls.widgets["playNormalRadio"].connect("toggled", updateCombos) cls.widgets["playNormalRadio"].set_tooltip_text(variants[NORMALCHESS].__desc__) cls.widgets["playVariant1Radio"].connect("toggled", updateCombos) variant1 = conf.get("ngvariant1") cls.widgets["playVariant1Radio"].set_tooltip_text(variants[variant1].__desc__) cls.widgets["playVariant2Radio"].connect("toggled", updateCombos) variant2 = conf.get("ngvariant2") cls.widgets["playVariant2Radio"].set_tooltip_text(variants[variant2].__desc__) # The "variant" has to come before players, because the engine positions # in the user comboboxes can be different in different variants for key in ("whitePlayerCombobox", "blackPlayerCombobox", "skillSlider1", "skillSlider2", "notimeRadio", "blitzRadio", "rapidRadio", "normalRadio", "classicalRadio", "playNormalRadio", "playVariant1Radio", "playVariant2Radio"): uistuff.keep(cls.widgets[key], key) # We don't want the dialog to deallocate when closed. Rather we hide # it on respond cls.widgets["newgamedialog"].connect("delete_event", lambda *a: True)
def onResponse(dialog, response): if response == COPY: clipboard = Gtk.Clipboard.get(Gdk.SELECTION_CLIPBOARD) clipboard.set_text(cls.get_fen(), -1) # print("put clipboard:", clipboard.wait_for_text()) return elif response == CLEAR: cls.board_control.emit("action", "SETUP", None, True) cls.ini_widgets(True) # print("clear") return elif response == PASTE: clipboard = Gtk.Clipboard.get(Gdk.SELECTION_CLIPBOARD) text = clipboard.wait_for_text() # print("got clipboard:", text) if text is None or len(text.split()) < 2: return try: lboard = cls.setupmodel.variant(setup=text).board cls.ini_widgets(lboard.asFen()) cls.board_control.emit("action", "SETUP", None, text) except SyntaxError as e: d = Gtk.MessageDialog(mainwindow(), type=Gtk.MessageType.WARNING, buttons=Gtk.ButtonsType.OK, message_format=e.args[0]) if len(e.args) > 1: d.format_secondary_text(e.args[1]) d.connect("response", lambda d, a: d.hide()) d.show() return elif response == INITIAL: lboard = cls.setupmodel.variant(setup=FEN_START).board cls.ini_widgets(lboard.asFen()) cls.board_control.emit("action", "SETUP", None, FEN_START) return elif response != Gtk.ResponseType.OK: cls.widgets["newgamedialog"].hide() cls.widgets["newgamedialog"].disconnect(handlerId) return if hasattr(cls, "board_control"): cls.board_control.emit("action", "CLOSE", None, None) # Find variant if cls.widgets["playNormalRadio"].get_active(): variant_index = NORMALCHESS elif cls.widgets["playVariant1Radio"].get_active(): variant_index = conf.get("ngvariant1") else: variant_index = conf.get("ngvariant2") variant = variants[variant_index] # Find time if cls.widgets["notimeRadio"].get_active(): secs = 0 incr = 0 moves = 0 elif cls.widgets["blitzRadio"].get_active(): secs = cls.ngblitz_min.get_value_as_int() * 60 incr = cls.ngblitz_gain.get_value_as_int() moves = 0 elif cls.widgets["rapidRadio"].get_active(): secs = cls.ngrapid_min.get_value_as_int() * 60 incr = cls.ngrapid_gain.get_value_as_int() moves = 0 elif cls.widgets["normalRadio"].get_active(): secs = cls.ngnormal_min.get_value_as_int() * 60 incr = cls.ngnormal_gain.get_value_as_int() moves = 0 elif cls.widgets["classicalRadio"].get_active(): secs = cls.ngclassical_min.get_value_as_int() * 60 incr = 0 moves = cls.ngclassical_moves.get_value_as_int() # Find players player0combo = cls.widgets["whitePlayerCombobox"] player0 = player0combo.get_active() tree_iter = player0combo.get_active_iter() if tree_iter is not None: model = player0combo.get_model() name0 = model[tree_iter][1] diffi0 = int(cls.widgets["skillSlider1"].get_value()) player1combo = cls.widgets["blackPlayerCombobox"] player1 = player1combo.get_active() tree_iter = player1combo.get_active_iter() if tree_iter is not None: model = player1combo.get_model() name1 = model[tree_iter][1] diffi1 = int(cls.widgets["skillSlider2"].get_value()) # Prepare players playertups = [] for i, playerno, name, diffi, color in ((0, player0, name0, diffi0, WHITE), (1, player1, name1, diffi1, BLACK)): if playerno > 0: engine = discoverer.getEngineByName(name) playertups.append( (ARTIFICIAL, discoverer.initPlayerEngine, [engine, color, diffi, variant, secs, incr, moves], name)) else: if not playertups or playertups[0][0] != LOCAL: name = conf.get("firstName") else: name = conf.get("secondName") playertups.append((LOCAL, Human, (color, name), name)) # Set forcePonderOff initPlayerEngine param True in engine-engine games if playertups[0][0] == ARTIFICIAL and playertups[1][ 0] == ARTIFICIAL: playertups[0][2].append(True) playertups[1][2].append(True) timemodel = TimeModel(secs, incr, moves=moves) gamemodel = GameModel(timemodel, variant) if not validate(gamemodel): return else: cls.widgets["newgamedialog"].hide() cls.widgets["newgamedialog"].disconnect(handlerId) callback(gamemodel, playertups[0], playertups[1])
def __init__(self): self.widgets = uistuff.GladeWidgets("tipoftheday.glade") self.widgets["window1"].set_transient_for(mainwindow()) uistuff.keepWindowSize("tipoftheday", self.widgets["window1"], (320, 240), uistuff.POSITION_CENTER) self.widgets["checkbutton1"].set_active(conf.get("show_tip_at_startup")) self.widgets["checkbutton1"].connect("toggled", lambda w: conf.set("show_tip_at_startup", w.get_active())) self.widgets["close_button"].connect("clicked", lambda w: self.widgets["window1"].emit("delete-event", None)) self.widgets["window1"].connect("delete_event", lambda w, a: self.widgets["window1"].destroy()) self.widgets["back_button"].connect("clicked", lambda w: self.set_currentIndex(self.tips_curindex - 1)) self.widgets["forward_button"].connect("clicked", lambda w: self.set_currentIndex(self.tips_curindex + 1)) self.tips_fixed = 2 self.tips = [ # PyChess facts -- The first tips_fixed messages are always displayed first _("PyChess is an open-source chess application that can be enhanced by any chess enthusiasts: bug reports, source code, documentation, translations, feature requests, user assistance... Let's get in touch at <b>http://www.pychess.org</b>"), _("PyChess supports a wide range of chess engines, variants, Internet servers and lessons. It is a perfect desktop application to increase your chess skills very conveniently."), _("The releases of PyChess hold the name of historical world chess champions. Do you know the name of the current world chess champion?"), _("Do you know that you can help to translate PyChess into your language, <b>Help</b> > <b>Translate PyChess</b>."), _("A game is made of an opening, a middle-game and an end-game. PyChess is able to train you thanks to its opening book, its supported chess engines and its training module."), # Chess facts _("Do you know that it is possible to finish a chess game in just 2 turns?"), _("Do you know that a knight is better placed in the center of the board?"), _("Do you know that moving the queen at the very beginning of a game does not offer any particular advantage?"), _("Do you know that having two-colored bishops working together is very powerful?"), _("Do you know that the rooks are generally engaged late in game?"), _("Do you know that the king can move across two cells under certain conditions? This is called ""castling""."), _("Do you know that the number of possible chess games exceeds the number of atoms in the Universe?"), # General UI _("You can start a new game by <b>Game</b> > <b>New Game</b>, then choose the <b>Players</b>, <b>Time Control</b> and <b>Chess Variants</b>."), _("You can choose from 20 different difficulties to play against the computer. It will mainly affect the available time to think."), _("The level 20 gives a full autonomy to the chess engine in managing its own time during the game."), _("To save a game <b>Game</b> > <b>Save Game As</b>, give the filename and choose where you want to be saved. At the bottom choose extension type of the file, and <b>Save</b>."), _("Calling the flag is the termination of the current game when the time of your opponent is over. If the clock is with you, click on the menu item <b>Actions</b> > <b>Call Flag</b> to claim the victory."), _("Press <b>Ctrl+Z</b> to ask your opponent to rollback the last played move. Against a computer or for an unrated game, undoing is generally automatically accepted."), _("To play on <b>Fullscreen mode</b>, just press the key <b>F11</b>. Press it again to exit this mode."), _("Many sounds are emitted by PyChess while you are playing if you activate them in the preferences: <b>Settings</b> > <b>Preferences</b> > <b>Sound tab</b> > <b>Use sounds in PyChess</b>."), _("Do you know that a game is generally finished after 20 to 40 moves per player? The estimated duration of a game is displayed when you configure a new game."), _("The standard file format to manage chess games is <b>PGN</b>. It stands for ""Portable Game Notation"". Do not get confused with PNG which is a usual file format to store drawings and pictures."), _("You can share a position by using the exchange format <b>FEN</b>, which stands for ""Forsyth-Edwards Notation"". This format is also adapted for the chess variants."), # Analysis _("You must define a chess engine in the preferences in order to use the local chess analysis. By default, PyChess recommends you to use the free engine named Stockfish which is renown to be the strongest engine in the world."), _("<b>Hint mode</b> analyzes your game to show you the best current move. Enable it with the shortcut <b>Ctrl+H</b> from the menu <b>View</b>."), _("<b>Spy mode</b> analyzes the threats, so the best move that your opponent would play as if it was his turn. Enable it with the shortcut <b>Ctrl+H</b> from the menu <b>View</b>."), _("<b>Ponder</b> is an option available in some chess engines that allows thinking when it is not the turn of the engine. It will then consume more resources on your computer."), _("<b>MultiPV</b> is an option of some chess engines that shows other possible good moves. They are displayed in the panel <b>Hints</b>. The value can be adapted from that panel with a double-click on the displayed figure."), _("You cannot use the local chess analysis mode while you are playing an unterminated game over Internet. Else you would be a cheater."), _("An evaluation of +2.3 is an advantage for White of more than 2 pawns, even if White and Black have the same number of pawns. The position of all the pieces and their mobility are some of the factors that contribute to the score."), _("PyChess includes a chess engine that offers an evaluation for any chess position. Winning against PyChess engine is a coherent way to succeed in chess and improve your skills."), _("The rating is your strength: 1500 is a good average player, 2000 is a national champion and 2800 is the best human chess champion. From the properties of the game in the menu <b>Game</b>, the difference of points gives you your chance to win and the projected evolution of your rating. If your rating is provisional, append a question mark '?' to your level, like ""1399?""."), _("Several rating systems exist to evaluate your skills in chess. The most common one is ELO (from its creator Arpad Elo) established on 1970. Schematically, the concept is to engage +/- 20 points for a game and that you will win or lose proportionally to the difference of ELO points you have with your opponent."), _("Each chess engine has its own evaluation function. It is normal to get different scores for a same position."), # Opening book and EGDB _("The opening book gives you the moves that are considered to be good from a theoretical perspective. You are free to play any other legal move."), _("The <b>Gaviota tables</b> are precalculated positions that tell the final outcome of the current game in terms of win, loss or draw."), _("Do you know that your computer is too small to store a 7-piece endgame database? That's why the Gaviota tablebase is limited to 5 pieces."), _("A tablebase can be connected either to PyChess, or to a compatible chess engine."), _("The <b>DTZ</b> is the ""distance to zero"", so the remaining possible moves to end into a tie as soon as possible."), # Variant chess _("The chess variants consist in changing the start position, the rules of the game, the types of the pieces... The gameplay is totally modified, so you must use dedicated chess engines to play against the computer."), _("In Chess960, the lines of the main pieces are shuffled in a precise order. Therefore, you cannot use the booking book and you should change your tactical habits."), _("When playing crazyhouse chess, the captured pieces change of ownership and can reappear on the board at a later turn."), _("Suicide chess, giveaway chess or antichess are all the same variant: you must give your pieces to your opponent by forcing the captures like at draughts. The outcome of the game can change completely if you make an incorrect move."), _("Playing horde in PyChess consists in destroying a flow of 36 white pawns with a normal set of black pieces."), _("You might be interested in playing ""King of the hill"" if you target to place your king in the middle of the board, instead of protecting it in a corner of the board as usual."), _("A lot of fun is offered by atomic chess that destroys all the surrounding main pieces at each capture move."), _("The experienced chess players can use blind pieces by starting a new variant game."), # Internet chess _("You should sign up online to play on an Internet chess server, so that you can find your games later and see the evolution of your rating. In the preferences, PyChess still have the possibility to save your played games locally."), _("The time compensation is a feature that doesn't waste your clock time because of the latency of your Internet connection. The module can be downloaded from the menu <b>Edit</b> > <b>Externals</b>."), _("You can play against chess engines on an Internet chess server. Use the filter to include or exclude them from the available players."), _("The communication with an Internet chess server is not standardized. Therefore you can only connect to the supported chess servers in PyChess, like freechess.org or chessclub.com"), # Externals _("PyChess uses the external module Scoutfish to evaluate the chess databases. For example, it is possible to extract the games where some pieces are in precise count or positions."), _("Parser/ChessDB is an external module used by PyChess to show the expected outcome for a given position."), _("SQLite is an internal module used to describe the loaded PGN files, so that PyChess can retrieve the games very fast during a search."), _("PyChess generates 3 information files when a PGN file is opened : .sqlite (description), scout (positions), .bin (book and outcomes). These files can be removed manually if necessary."), # Lessons _("PyChess uses offline lessons to learn chess. You will be then never disappointed if you have no Internet connection."), _("To start Learning, click on the <b>Book icon</b> available on the welcome screen. Or choose the category next to that button to start the activity directly."), _("The <b>lectures</b> are commented games to learn step-by-step the strategy and principles of some chess techniques. Just watch and read."), _("Whatever the number of pawns, an <b>end-game</b> starts when the board is made of certain main pieces : 1 rook vs 1 bishop, 1 queen versus 2 rooks, etc... Knowing the moves will help you to not miss the checkmate!"), _("A <b>puzzle</b> is a set of simple positions classified by theme for which you should guess the best moves. It helps you to understand the patterns to drive an accurate attack or defense."), _("A <b>lesson</b> is a complex study that explains the tactics for a given position. It is common to view circles and arrows over the board to focus on the behavior of the pieces, the threats, etc...") ] self.tips_seed = conf.get("tips_seed") if self.tips_seed == 0: # Forbidden value self.tips_seed = 123456789 + randrange(876543210) conf.set("tips_seed", self.tips_seed) self.tips_curindex = conf.get("tips_index") self.shuffleTips()
def __init__(self, widgets): self.widgets = widgets # Font chooser font = conf.get("movetextFont", "FreeSerif Regular 12") font_button = Gtk.FontButton.new_with_font(font) demo_text = "♔a1 ♕f8 ♖h8 ♗g7 ♘g2 Ka1 Qf8 Rh8 Bg7 Ng2" font_button.set_preview_text(demo_text) self.widgets["fontChooserDock"].add(font_button) font_button.show() def select_font(button): conf.set("movetextFont", button.get_font_name()) font_button.connect("font-set", select_font) # Background image path = conf.get("welcome_image", addDataPrefix("glade/clear.png")) conf.set("welcome_image", path) image_chooser_dialog = Gtk.FileChooserDialog( _("Select background image file"), mainwindow(), Gtk.FileChooserAction.OPEN, (Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL, Gtk.STOCK_OPEN, Gtk.ResponseType.OK)) image_chooser_button = Gtk.FileChooserButton.new_with_dialog( image_chooser_dialog) filter = Gtk.FileFilter() filter.set_name(_("Images")) filter.add_pattern("*.bmp") filter.add_pattern("*.jpg") filter.add_pattern("*.png") filter.add_pattern("*.svg") image_chooser_dialog.add_filter(filter) image_chooser_button.set_filename(path) self.widgets["imageChooserDock"].add(image_chooser_button) image_chooser_button.show() def select_new_image(button): new_image = image_chooser_dialog.get_filename() if new_image: conf.set("welcome_image", new_image) from pychess.widgets.TaskerManager import tasker newTheme(tasker, background=new_image) tasker.queue_draw() else: # restore the original image_chooser_dialog.set_filename(path) image_chooser_button.connect("file-set", select_new_image) # Board style uistuff.createCombo(widgets["board_style"], name="board_style") data = [(item[0], item[1]) for item in board_items] uistuff.createCombo(widgets["board_style"], data) uistuff.keep(widgets["board_style"], "board_style", first_value=1) # conf.set("board_style", conf.get("board_style", 1)) # Board frame uistuff.createCombo(widgets["board_frame"], name="board_frame") data = [(item[0], item[1]) for item in [(None, "no frame")] + board_items[1:]] uistuff.createCombo(widgets["board_frame"], data) uistuff.keep(widgets["board_frame"], "board_frame", first_value=1) # conf.set("board_frame", conf.get("board_frame", 1)) # Board Colours style_ctxt = widgets["main_window"].get_style_context() LIGHT = hexcol(style_ctxt.lookup_color("p_light_color")[1]) DARK = hexcol(style_ctxt.lookup_color("p_dark_color")[1]) def onColourSetLight(_): """ :Description: Sets the light squares of the chess board to the value selected in the colour picker """ conf.set('lightcolour', widgets['light_cbtn'].get_color().to_string()) widgets["light_cbtn"].connect_after("color-set", onColourSetLight) def onColourSetDark(_): """ :Description: Sets the dark squares of the chess board to the value selected in the colour picker """ conf.set('darkcolour', widgets['dark_cbtn'].get_color().to_string()) widgets["dark_cbtn"].connect_after("color-set", onColourSetDark) def onResetColourClicked(_): """ :Description: Resets the chess board squares to factory default """ conf.set("lightcolour", LIGHT) conf.set("darkcolour", DARK) widgets["reset_btn"].connect("clicked", onResetColourClicked) # Get the current board colours if set, if not set, set them to default conf.set("lightcolour", conf.get("lightcolour", LIGHT)) conf.set("darkcolour", conf.get("darkcolour", DARK)) # Next 2 lines take a #hex str converts them to a color then to a RGBA representation self.lightcolour = Gdk.RGBA() self.lightcolour.parse(conf.get("lightcolour", LIGHT)) self.darkcolour = Gdk.RGBA() self.darkcolour.parse(conf.get("darkcolour", DARK)) # Set the color swatches in preference to stored values widgets['light_cbtn'].set_rgba(self.lightcolour) widgets['dark_cbtn'].set_rgba(self.darkcolour) # Chess Sets self.themes = self.discoverThemes() store = Gtk.ListStore(GdkPixbuf.Pixbuf, str) for theme in self.themes: pngfile = "%s/%s.png" % (addDataPrefix("pieces"), theme) if isfile(pngfile): pixbuf = get_pixbuf(pngfile) store.append((pixbuf, theme)) else: print( "WARNING: No piece theme preview icons found. Please run \ create_theme_preview.sh !") break self.icon_view = widgets["pieceTheme"] self.icon_view.set_model(store) self.icon_view.set_pixbuf_column(0) self.icon_view.set_text_column(1) def keepSize(crt, _): """ :Description: Hack to fix spacing problem in iconview http://stackoverflow.com/questions/14090094/what-causes-the-different-\ display-behaviour-for-a-gtkiconview-between-different """ crt.handler_block(crt_notify) crt.set_property('width', 40) crt.handler_unblock(crt_notify) crt = self.icon_view.get_cells()[0] crt_notify = crt.connect('notify', keepSize) def _getActive(iconview): model = iconview.get_model() selected = iconview.get_selected_items() if len(selected) == 0: return conf.get("pieceTheme", "Chessicons") indices = selected[0].get_indices() if indices: idx = indices[0] theme = model[idx][1] Pieces.set_piece_theme(theme) return theme def _setActive(iconview, value): try: index = self.themes.index(value) except ValueError: index = 0 iconview.select_path(Gtk.TreePath(index, )) uistuff.keep(widgets["pieceTheme"], "pieceTheme", _getActive, _setActive, "Chessicons")
def onResponse(dialog, response): if response == COPY: clipboard = Gtk.Clipboard.get(Gdk.SELECTION_CLIPBOARD) clipboard.set_text(cls.get_fen(), -1) # print("put clipboard:", clipboard.wait_for_text()) return elif response == CLEAR: cls.board_control.emit("action", "SETUP", None, True) cls.ini_widgets(True) # print("clear") return elif response == PASTE: clipboard = Gtk.Clipboard.get(Gdk.SELECTION_CLIPBOARD) text = clipboard.wait_for_text() # print("got clipboard:", text) if text is None or len(text.split()) < 2: return try: lboard = cls.setupmodel.variant(setup=text).board cls.ini_widgets(lboard.asFen()) cls.board_control.emit("action", "SETUP", None, text) except SyntaxError as e: d = Gtk.MessageDialog(mainwindow(), type=Gtk.MessageType.WARNING, buttons=Gtk.ButtonsType.OK, message_format=e.args[0]) if len(e.args) > 1: d.format_secondary_text(e.args[1]) d.connect("response", lambda d, a: d.hide()) d.show() return elif response == INITIAL: lboard = cls.setupmodel.variant(setup=FEN_START).board cls.ini_widgets(lboard.asFen()) cls.board_control.emit("action", "SETUP", None, FEN_START) return elif response != Gtk.ResponseType.OK: cls.widgets["newgamedialog"].hide() cls.widgets["newgamedialog"].disconnect(handlerId) return if hasattr(cls, "board_control"): cls.board_control.emit("action", "CLOSE", None, None) # Find variant if cls.widgets["playNormalRadio"].get_active(): variant_index = NORMALCHESS elif cls.widgets["playVariant1Radio"].get_active(): variant_index = conf.get("ngvariant1") else: variant_index = conf.get("ngvariant2") variant = variants[variant_index] # Find time if cls.widgets["notimeRadio"].get_active(): secs = 0 incr = 0 moves = 0 elif cls.widgets["blitzRadio"].get_active(): secs = cls.ngblitz_min.get_value_as_int() * 60 incr = cls.ngblitz_gain.get_value_as_int() moves = 0 elif cls.widgets["rapidRadio"].get_active(): secs = cls.ngrapid_min.get_value_as_int() * 60 incr = cls.ngrapid_gain.get_value_as_int() moves = 0 elif cls.widgets["normalRadio"].get_active(): secs = cls.ngnormal_min.get_value_as_int() * 60 incr = cls.ngnormal_gain.get_value_as_int() moves = 0 elif cls.widgets["classicalRadio"].get_active(): secs = cls.ngclassical_min.get_value_as_int() * 60 incr = 0 moves = cls.ngclassical_moves.get_value_as_int() # Find players player0combo = cls.widgets["whitePlayerCombobox"] player0 = player0combo.get_active() tree_iter = player0combo.get_active_iter() if tree_iter is not None: model = player0combo.get_model() name0 = model[tree_iter][1] diffi0 = int(cls.widgets["skillSlider1"].get_value()) player1combo = cls.widgets["blackPlayerCombobox"] player1 = player1combo.get_active() tree_iter = player1combo.get_active_iter() if tree_iter is not None: model = player1combo.get_model() name1 = model[tree_iter][1] diffi1 = int(cls.widgets["skillSlider2"].get_value()) # Prepare players playertups = [] for i, playerno, name, diffi, color in ((0, player0, name0, diffi0, WHITE), (1, player1, name1, diffi1, BLACK)): if playerno > 0: engine = discoverer.getEngineByName(name) playertups.append((ARTIFICIAL, discoverer.initPlayerEngine, [engine, color, diffi, variant, secs, incr, moves], name)) else: if not playertups or playertups[0][0] != LOCAL: name = conf.get("firstName") else: name = conf.get("secondName") playertups.append((LOCAL, Human, (color, name), name)) # Set forcePonderOff initPlayerEngine param True in engine-engine games if playertups[0][0] == ARTIFICIAL and playertups[1][ 0] == ARTIFICIAL: playertups[0][2].append(True) playertups[1][2].append(True) timemodel = TimeModel(secs, incr, moves=moves) gamemodel = GameModel(timemodel, variant) if not validate(gamemodel): return else: cls.widgets["newgamedialog"].hide() cls.widgets["newgamedialog"].disconnect(handlerId) callback(gamemodel, playertups[0], playertups[1])
def __init__(self, widgets): # Init open dialog opendialog = Gtk.FileChooserDialog( _("Open Sound File"), mainwindow(), Gtk.FileChooserAction.OPEN, (Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL, Gtk.STOCK_OPEN, Gtk.ResponseType.ACCEPT)) for dir in self.SOUND_DIRS: if os.path.isdir(dir): opendialog.set_current_folder(dir) break soundfilter = Gtk.FileFilter() soundfilter.set_name(_("Sound files")) soundfilter.add_mime_type("audio/%s" % EXT) soundfilter.add_pattern("*.%s" % EXT) opendialog.add_filter(soundfilter) # Get combo icons icons = ((_("No sound"), "audio-volume-muted", "audio-volume-muted"), (_("Beep"), "stock_bell", "audio-x-generic"), (_("Select sound file..."), "gtk-open", "document-open")) items = [] for level, stock, altstock in icons: image = load_icon(16, stock, altstock) items += [(image, level)] audioIco = load_icon(16, "audio-x-generic") # Set-up combos def callback(combobox, index): if combobox.get_active() == SOUND_SELECT: if opendialog.run() == Gtk.ResponseType.ACCEPT: uri = opendialog.get_uri() model = combobox.get_model() conf.set("sounduri%d" % index, uri) label = unquote(os.path.split(uri)[1]) if len(model) == 3: model.append([audioIco, label]) else: model.set(model.get_iter((3, )), 1, label) combobox.set_active(3) else: combobox.set_active( conf.get("soundcombo%d" % index, SOUND_MUTE)) opendialog.hide() for i in range(COUNT_OF_SOUNDS): combo = widgets["sound%dcombo" % i] uistuff.createCombo(combo, items, name="soundcombo%d" % i) combo.connect("changed", callback, i) label = widgets["soundlabel%d" % i] label.props.mnemonic_widget = combo uri = conf.get("sounduri%d" % i, "") if os.path.isfile(url2pathname(uri[5:])): model = combo.get_model() model.append([audioIco, unquote(os.path.split(uri)[1])]) for i in range(COUNT_OF_SOUNDS): if conf.get("soundcombo%d" % i, SOUND_MUTE) == SOUND_URI and \ not os.path.isfile(url2pathname(conf.get("sounduri%d" % i, "")[5:])): conf.set("soundcombo%d" % i, SOUND_MUTE) uistuff.keep(widgets["sound%dcombo" % i], "soundcombo%d" % i) # Init play button def playCallback(button, index): SoundTab.playAction(index) for i in range(COUNT_OF_SOUNDS): button = widgets["sound%dbutton" % i] button.connect("clicked", playCallback, i) # Init 'use sound" checkbutton def checkCallBack(*args): checkbox = widgets["useSounds"] widgets["sounds_frame"].set_property("sensitive", checkbox.get_active()) conf.notify_add("useSounds", checkCallBack) widgets["useSounds"].set_active(True) uistuff.keep(widgets["useSounds"], "useSounds") checkCallBack() if not self.getPlayer().ready: widgets["useSounds"].set_sensitive(False) widgets["useSounds"].set_active(False) uistuff.keep(widgets["alarm_spin"], "alarm_spin", first_value=15)
def saveGameAs(self, game, position=None, export=False): savedialog, savecombo = get_save_dialog(export) # Keep running the dialog until the user has canceled it or made an error # free operation title = _("Save Game") if not export else _("Export position") savedialog.set_title(title) while True: filename = "%s-%s" % (game.players[0], game.players[1]) savedialog.set_current_name(filename.replace(" ", "_")) res = savedialog.run() if res != Gtk.ResponseType.ACCEPT: break uri = savedialog.get_filename() ending = os.path.splitext(uri)[1] if ending.startswith("."): ending = ending[1:] append = False index = savecombo.get_active() if index == 0: if ending not in enddir: d = Gtk.MessageDialog(mainwindow(), type=Gtk.MessageType.ERROR, buttons=Gtk.ButtonsType.OK) folder, file = os.path.split(uri) d.set_markup( _("<big><b>Unknown file type '%s'</b></big>") % ending) d.format_secondary_text( _("Was unable to save '%(uri)s' as PyChess doesn't know the format '%(ending)s'." ) % { 'uri': uri, 'ending': ending }) d.run() d.destroy() continue else: saver = enddir[ending] else: format = exportformats[index] if export else saveformats[index] saver = format[2] if ending not in enddir or not saver == enddir[ending]: uri += ".%s" % saver.__ending__ if os.path.isfile(uri) and not os.access(uri, os.W_OK): d = Gtk.MessageDialog(mainwindow(), type=Gtk.MessageType.ERROR, buttons=Gtk.ButtonsType.OK) d.set_markup( _("<big><b>Unable to save file '%s'</b></big>") % uri) d.format_secondary_text( _("You don't have the necessary rights to save the file.\n\ Please ensure that you have given the right path and try again.")) d.run() d.destroy() continue if os.path.isfile(uri): d = Gtk.MessageDialog(mainwindow(), type=Gtk.MessageType.QUESTION) d.add_buttons(Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL, _("_Replace"), Gtk.ResponseType.ACCEPT) if saver.__append__: d.add_buttons(Gtk.STOCK_ADD, 1) d.set_title(_("File exists")) folder, file = os.path.split(uri) d.set_markup( _("<big><b>A file named '%s' already exists. Would you like to replace it?</b></big>" ) % file) d.format_secondary_text( _("The file already exists in '%s'. If you replace it, its content will be overwritten." ) % folder) replaceRes = d.run() d.destroy() if replaceRes == 1: append = True elif replaceRes == Gtk.ResponseType.CANCEL: continue else: print(repr(uri)) try: flip = self.cur_gmwidg().board.view.rotation > 0 game.save(uri, saver, append, position, flip) except IOError as e: d = Gtk.MessageDialog(mainwindow(), type=Gtk.MessageType.ERROR) d.add_buttons(Gtk.STOCK_OK, Gtk.ResponseType.OK) d.set_title(_("Could not save the file")) d.set_markup( _("<big><b>PyChess was not able to save the game</b></big>" )) d.format_secondary_text( _("The error was: %s") % ", ".join(str(a) for a in e.args)) d.run() d.destroy() continue break savedialog.destroy() return res
def __init__(self): self.window = Gtk.Window( Gtk.WindowType.TOPLEVEL, title=_("Ask for permissions") ) self.window.set_transient_for(mainwindow()) vbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL) gtk_version = (Gtk.get_major_version(), Gtk.get_minor_version()) if gtk_version >= (3, 12): vbox.props.margin_start = 9 vbox.props.margin_end = 9 else: vbox.props.margin_left = 9 vbox.props.margin_right = 9 vbox.props.margin_bottom = 9 self.window.add(vbox) uistuff.keepWindowSize( "externalsdialog", self.window, (320, 240), uistuff.POSITION_CENTER ) label = Gtk.Label( _( "Some of PyChess features needs your permission to download external programs" ) ) vbox.pack_start(label, True, True, 0) box = Gtk.Box() check_button = Gtk.CheckButton(_("database querying needs scoutfish")) check_button.set_active(conf.get("download_scoutfish")) check_button.connect( "toggled", lambda w: conf.set("download_scoutfish", w.get_active()) ) box.add(check_button) link = "https://github.com/pychess/scoutfish" link_button = Gtk.LinkButton(link, link) box.add(link_button) vbox.pack_start(box, False, False, 0) box = Gtk.Box() check_button = Gtk.CheckButton(_("database opening tree needs chess_db")) check_button.set_active(conf.get("download_chess_db")) check_button.connect( "toggled", lambda w: conf.set("download_chess_db", w.get_active()) ) box.add(check_button) link = "https://github.com/pychess/chess_db" link_button = Gtk.LinkButton(link, link) box.add(link_button) vbox.pack_start(box, False, False, 0) box = Gtk.Box() check_button = Gtk.CheckButton(_("ICC lag compensation needs timestamp")) check_button.set_active(conf.get("download_timestamp")) check_button.connect( "toggled", lambda w: conf.set("download_timestamp", w.get_active()) ) box.add(check_button) link = "http://download.chessclub.com/timestamp/" link_button = Gtk.LinkButton(link, link) box.add(link_button) vbox.pack_start(box, False, False, 0) check_button = Gtk.CheckButton(_("Don't show this dialog on startup.")) check_button.set_active(conf.get("dont_show_externals_at_startup")) check_button.connect( "toggled", lambda w: conf.set("dont_show_externals_at_startup", w.get_active()), ) vbox.pack_start(check_button, True, True, 0) buttonbox = Gtk.ButtonBox() close_button = Gtk.Button.new_from_stock(Gtk.STOCK_OK) close_button.connect("clicked", self.on_close_clicked) self.window.connect("delete_event", lambda w, a: self.window.destroy()) buttonbox.add(close_button) vbox.pack_start(buttonbox, False, False, 0)