def __init__(self, palabra_window, properties): PalabraDialog.__init__(self, palabra_window, u"Appearance") self.palabra_window = palabra_window hbox = gtk.HBox() hbox.set_spacing(18) hbox.pack_start(self.create_content(properties)) mode = constants.VIEW_MODE_PREVIEW_SOLUTION self.preview = GridPreview(mode=mode, cell_size=None) self.preview.set_size_request(200, 200) hbox.pack_start(self.preview, False, False, 0) self.pack(hbox) g = Grid(3, 3) g.set_block(0, 2, True) g.set_void(2, 0, True) g.set_char(0, 0, "A") g.assign_numbers() self.preview.display(g) self.on_update() self.add_button(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL) self.add_button(gtk.STOCK_APPLY, gtk.RESPONSE_OK)
def __init__(self, parent, size=None): super(GridEditor, self).__init__(parent, u"Grid editor", horizontal=True) self.size = size if size else (15, 15) table = gtk.Table(2, 2, False) radio = gtk.RadioButton(None, u"Tile from: ") radio.connect("toggled", self.on_option_toggle, "tile") self.tile_starts = [(p, q) for q in xrange(2) for p in xrange(2)] self.tile_combo = gtk.combo_box_new_text() self.tile_combo.append_text(u"") for x, y in self.tile_starts: content = str(''.join(["(", str(x + 1), ",", str(y + 1), ")" ])) self.tile_combo.append_text(content) self.tile_combo.connect("changed", self.on_tile_changed) table.attach(radio, 0, 1, 0, 1) table.attach(self.tile_combo, 1, 2, 0, 1) radio = gtk.RadioButton(radio, u"Fill with: ") radio.connect("toggled", self.on_option_toggle, "fill") self.fill_combo = create_combo([u"", u"Block"], f_change=self.on_fill_changed) table.attach(radio, 0, 1, 1, 2) table.attach(self.fill_combo, 1, 2, 1, 2) self.preview = GridPreview() self.preview.set_size_request(384, 384) alignment = gtk.Alignment() alignment.add(table) vbox2 = gtk.VBox(False, 6) vbox2.pack_start(create_label(u"<b>Options</b>"), False, False, 0) vbox2.pack_start(alignment, False, False, 0) self.pack(vbox2, False) self.pack(self.preview, False) self.add_button(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL) self.ok_button = self.add_button(gtk.STOCK_OK, gtk.RESPONSE_OK) self.ok_button.set_sensitive(False) self._select_option("tile") self.display_pattern(None)
def __init__(self, palabra_window): flags = gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT buttons = (gtk.STOCK_CANCEL, gtk.RESPONSE_REJECT, gtk.STOCK_OK, gtk.RESPONSE_ACCEPT) super(NewWindow, self).__init__("New puzzle", palabra_window, flags, buttons) self.showing_pattern = False self.preview = GridPreview() self.preview.set_size_request(300, 400) hbox = gtk.HBox(False, 0) hbox.set_border_width(12) hbox.set_spacing(18) options_vbox = gtk.VBox(False, 0) hbox.pack_start(options_vbox, True, True, 0) hbox.pack_start(self.preview, True, True, 0) self.vbox.pack_start(hbox, True, True, 0) self.size_component = SizeComponent( title=u"<b>Dimensions</b>" , callback=self.load_empty_grid) options_vbox.pack_start(self.size_component, False, False, 0) label = gtk.Label() label.set_alignment(0, 0) label.set_markup(u"<b>Grids</b>") options_vbox.pack_start(label, False, False, 6) # display_string grid self.store = gtk.ListStore(str, gobject.TYPE_PYOBJECT) self.tree = gtk.TreeView(self.store) self.tree.set_headers_visible(False) self.tree.get_selection().connect("changed", self.on_pattern_changed) cell = gtk.CellRendererText() column = gtk.TreeViewColumn("") column.pack_start(cell, True) column.set_attributes(cell, text=0) self.tree.append_column(column) window = gtk.ScrolledWindow(None, None) window.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC) window.add(self.tree) self.clear_button = gtk.Button("Clear grid") self.clear_button.connect("clicked", self.clear_pattern) self.files = [] for f in constants.STANDARD_PATTERN_FILES + preferences.prefs["pattern_files"]: self.files.append(get_real_filename(f)) self.patterns = [] for f, meta, data in palabra_window.patterns: if f is not None: self.patterns.append((f, meta, [p.grid for p in data])) file_combo = gtk.combo_box_new_text() file_combo.append_text("All files") file_combo.set_active(0) for path, metadata, data in self.patterns: filename = path[path.rfind(os.sep) + 1:] caption = metadata["title"] if "title" in metadata else filename file_combo.append_text(caption) file_combo.connect("changed", self.on_file_changed) patterns_vbox = gtk.VBox(False, 0) files_hbox = gtk.HBox(False, 0) files_hbox.pack_start(gtk.Label(u"Show grids from: "), False, False, 0) align = gtk.Alignment(0, 0.5, 0, 0) align.add(file_combo) files_hbox.pack_start(align, False, False, 0) self.find_button = gtk.Button(u"Find grids") self.find_button.connect("clicked", self.on_find_patterns) files_hbox.pack_start(self.find_button, False, False, 0) patterns_vbox.pack_start(files_hbox, False, False, 6) patterns_vbox.pack_start(window, True, True, 0) buttons_hbox = gtk.HBox(False, 6) generate_button = gtk.Button(u"Construct grid") generate_button.connect("clicked", self.construct_pattern) buttons_hbox.pack_start(generate_button, False, False, 0) align = gtk.Alignment(0, 0, 1, 0) align.add(self.clear_button) buttons_hbox.pack_start(align, False, False, 0) patterns_vbox.pack_start(buttons_hbox, False, False, 6) align = gtk.Alignment(0, 0, 1, 1) align.set_padding(0, 0, 12, 0) align.add(patterns_vbox) options_vbox.pack_start(align, True, True, 0) self.clear_button.set_sensitive(False) self._load_pattern_list(self.files)
class NewWindow(gtk.Dialog): def __init__(self, palabra_window): flags = gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT buttons = (gtk.STOCK_CANCEL, gtk.RESPONSE_REJECT, gtk.STOCK_OK, gtk.RESPONSE_ACCEPT) super(NewWindow, self).__init__("New puzzle", palabra_window, flags, buttons) self.showing_pattern = False self.preview = GridPreview() self.preview.set_size_request(300, 400) hbox = gtk.HBox(False, 0) hbox.set_border_width(12) hbox.set_spacing(18) options_vbox = gtk.VBox(False, 0) hbox.pack_start(options_vbox, True, True, 0) hbox.pack_start(self.preview, True, True, 0) self.vbox.pack_start(hbox, True, True, 0) self.size_component = SizeComponent( title=u"<b>Dimensions</b>" , callback=self.load_empty_grid) options_vbox.pack_start(self.size_component, False, False, 0) label = gtk.Label() label.set_alignment(0, 0) label.set_markup(u"<b>Grids</b>") options_vbox.pack_start(label, False, False, 6) # display_string grid self.store = gtk.ListStore(str, gobject.TYPE_PYOBJECT) self.tree = gtk.TreeView(self.store) self.tree.set_headers_visible(False) self.tree.get_selection().connect("changed", self.on_pattern_changed) cell = gtk.CellRendererText() column = gtk.TreeViewColumn("") column.pack_start(cell, True) column.set_attributes(cell, text=0) self.tree.append_column(column) window = gtk.ScrolledWindow(None, None) window.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC) window.add(self.tree) self.clear_button = gtk.Button("Clear grid") self.clear_button.connect("clicked", self.clear_pattern) self.files = [] for f in constants.STANDARD_PATTERN_FILES + preferences.prefs["pattern_files"]: self.files.append(get_real_filename(f)) self.patterns = [] for f, meta, data in palabra_window.patterns: if f is not None: self.patterns.append((f, meta, [p.grid for p in data])) file_combo = gtk.combo_box_new_text() file_combo.append_text("All files") file_combo.set_active(0) for path, metadata, data in self.patterns: filename = path[path.rfind(os.sep) + 1:] caption = metadata["title"] if "title" in metadata else filename file_combo.append_text(caption) file_combo.connect("changed", self.on_file_changed) patterns_vbox = gtk.VBox(False, 0) files_hbox = gtk.HBox(False, 0) files_hbox.pack_start(gtk.Label(u"Show grids from: "), False, False, 0) align = gtk.Alignment(0, 0.5, 0, 0) align.add(file_combo) files_hbox.pack_start(align, False, False, 0) self.find_button = gtk.Button(u"Find grids") self.find_button.connect("clicked", self.on_find_patterns) files_hbox.pack_start(self.find_button, False, False, 0) patterns_vbox.pack_start(files_hbox, False, False, 6) patterns_vbox.pack_start(window, True, True, 0) buttons_hbox = gtk.HBox(False, 6) generate_button = gtk.Button(u"Construct grid") generate_button.connect("clicked", self.construct_pattern) buttons_hbox.pack_start(generate_button, False, False, 0) align = gtk.Alignment(0, 0, 1, 0) align.add(self.clear_button) buttons_hbox.pack_start(align, False, False, 0) patterns_vbox.pack_start(buttons_hbox, False, False, 6) align = gtk.Alignment(0, 0, 1, 1) align.set_padding(0, 0, 12, 0) align.add(patterns_vbox) options_vbox.pack_start(align, True, True, 0) self.clear_button.set_sensitive(False) self._load_pattern_list(self.files) def on_file_changed(self, combo): index = combo.get_active() files = self.files if index == 0 else self.files[index - 1:index] if files: self._load_pattern_list(files) def _load_pattern_list(self, files): data = [d for (f, _, d) in self.patterns if f in files] grids = reduce(operator.add, data) if data else [] stats = [(g.count_words(), g.count_blocks(), g) for g in grids] stats.sort() self.grids = [grid for (_, _, grid) in stats] self.load_empty_grid(*self.size_component.get_size()) def on_pattern_changed(self, selection): store, it = selection.get_selected() if it is not None: self.show_grid(store.get_value(it, 1)) def show_grid(self, grid, showing_pattern=True): self.showing_pattern = showing_pattern self.grid = grid self.preview.display(self.grid) self.clear_button.set_sensitive(showing_pattern) def clear_pattern(self, button=None): """Display an empty grid without the currently selected pattern.""" self.show_grid(Grid(*self.grid.size), False) self.tree.get_selection().unselect_all() def construct_pattern(self, button): """Open the pattern editor to construct a pattern.""" editor = GridEditor(self, size=self.grid.size) editor.show_all() if editor.run() == gtk.RESPONSE_OK: self.show_grid(editor.grid) self.tree.get_selection().unselect_all() editor.destroy() def on_find_patterns(self, button): d = FindPatternDialog(self) d.show_all() if d.run() == gtk.RESPONSE_OK: buff = d.text.get_buffer() text = buff.get_text(*buff.get_bounds()) words = [w for w in text.split() if w != ''] if words: w, h = self.grid.size c = self.generate_criteria(list(set(words))) self.clear_pattern() self.display_patterns(w, h, criteria=c) d.destroy() def load_empty_grid(self, width, height): """Load an empty grid with the specified dimensions and load patterns.""" self.grid = Grid(width, height) self.preview.display(self.grid) self.display_patterns(width, height, criteria=None) def generate_criteria(self, words): """Determine search criteria per word length.""" counts = {} for word in words: l = len(word) if l in counts: counts[l] += 1 else: counts[l] = 1 return {"counts": counts, "words": words} def _check_grid(self, grid, criteria): """Return a grid or None when the grid meets all the search criteria.""" if "counts" in criteria: counts = grid.determine_word_counts() for k, v in criteria["counts"].items(): if k not in counts or counts[k] < v: return None if "words" in criteria: return attempt_fill(grid, criteria["words"]) return grid def display_patterns(self, width, height, criteria=None): gs = [] for grid in self.grids: if grid.size != (width, height): continue if not criteria: gs.append(grid) continue g = self._check_grid(grid, criteria) if g is not None and g.has_chars(): gs.append(g) self.store.clear() self.find_button.set_sensitive(len(gs) > 0) for g in gs: blocks = g.count_blocks() words = g.count_words() s = ''.join([str(words), " words, ", str(blocks), " blocks"]) self.store.append([s, g]) def get_configuration(self): configuration = {} configuration["type"] = "crossword" if self.grid is not None: configuration["grid"] = copy.deepcopy(self.grid) return configuration
class GridEditor(PalabraDialog): def __init__(self, parent, size=None): super(GridEditor, self).__init__(parent, u"Grid editor", horizontal=True) self.size = size if size else (15, 15) table = gtk.Table(2, 2, False) radio = gtk.RadioButton(None, u"Tile from: ") radio.connect("toggled", self.on_option_toggle, "tile") self.tile_starts = [(p, q) for q in xrange(2) for p in xrange(2)] self.tile_combo = gtk.combo_box_new_text() self.tile_combo.append_text(u"") for x, y in self.tile_starts: content = str(''.join(["(", str(x + 1), ",", str(y + 1), ")" ])) self.tile_combo.append_text(content) self.tile_combo.connect("changed", self.on_tile_changed) table.attach(radio, 0, 1, 0, 1) table.attach(self.tile_combo, 1, 2, 0, 1) radio = gtk.RadioButton(radio, u"Fill with: ") radio.connect("toggled", self.on_option_toggle, "fill") self.fill_combo = create_combo([u"", u"Block"], f_change=self.on_fill_changed) table.attach(radio, 0, 1, 1, 2) table.attach(self.fill_combo, 1, 2, 1, 2) self.preview = GridPreview() self.preview.set_size_request(384, 384) alignment = gtk.Alignment() alignment.add(table) vbox2 = gtk.VBox(False, 6) vbox2.pack_start(create_label(u"<b>Options</b>"), False, False, 0) vbox2.pack_start(alignment, False, False, 0) self.pack(vbox2, False) self.pack(self.preview, False) self.add_button(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL) self.ok_button = self.add_button(gtk.STOCK_OK, gtk.RESPONSE_OK) self.ok_button.set_sensitive(False) self._select_option("tile") self.display_pattern(None) def on_option_toggle(self, widget, option): if widget.get_active() == 1: self._select_option(option) def _select_option(self, option): if option == "tile": self.fill_combo.set_active(0) elif option == "fill": self.tile_combo.set_active(0) self.tile_combo.set_sensitive(option == "tile") self.fill_combo.set_sensitive(option == "fill") def display_pattern(self, pattern=None): """ Display a pattern in the preview. If pattern=None then an empty Grid is displayed. """ self.ok_button.set_sensitive(pattern is not None) self.grid = Grid(*self.size) if pattern: apply_pattern(self.grid, pattern) self.preview.display(self.grid) def on_tile_changed(self, combo): """Create and display a tiled pattern in the preview.""" index = combo.get_active() if index == 0: self.display_pattern(None) return width, height = self.grid.size pattern = tile_from_cell(width, height, *self.tile_starts[index - 1]) self.display_pattern(pattern) def on_fill_changed(self, combo): """Fill the entire grid with the specified content.""" index = combo.get_active() if index == 0: self.display_pattern(None) return content = {1: "block", 2: "void"}[index] width, height = self.grid.size self.display_pattern(fill_with_content(width, height, content))
def __init__(self, palabra_window): gtk.Dialog.__init__(self, u"Pattern file manager" , palabra_window, gtk.DIALOG_MODAL) self.palabra_window = palabra_window self.set_size_request(640, 512) self.preview = GridPreview() self.preview.set_size_request(200, 256) self.patterns = {} # display_string filename id_of_grid self.store = gtk.TreeStore(str, str, str) self.reset_pattern_list() self.tree = gtk.TreeView(self.store) self.tree.set_headers_visible(False) self.tree.get_selection().set_mode(gtk.SELECTION_MULTIPLE) self.tree.get_selection().connect("changed", self.on_selection_changed) cell = gtk.CellRendererText() column = gtk.TreeViewColumn() column.pack_start(cell, True) column.set_attributes(cell, text=0) self.tree.append_column(column) right_vbox = gtk.VBox(False, 6) label = gtk.Label() label.set_markup(u"<b>Options for pattern files</b>") align = gtk.Alignment(0, 0.5) align.add(label) right_vbox.pack_start(align, False, False, 0) add_button = gtk.Button(stock=gtk.STOCK_ADD) add_button.connect("clicked", lambda button: self.add_file()) align = add_button.get_children()[0] hbox = align.get_children()[0] image, label = hbox.get_children() label.set_text(u"Add pattern file"); right_vbox.pack_start(add_button, False, False, 0) self.remove_button = gtk.Button(stock=gtk.STOCK_REMOVE) self.remove_button.connect("clicked", lambda button: self.remove_file()) self.remove_button.set_sensitive(False) align = self.remove_button.get_children()[0] hbox = align.get_children()[0] image, label = hbox.get_children() label.set_text(u"Remove pattern file(s)"); right_vbox.pack_start(self.remove_button, False, False, 0) label = gtk.Label() label.set_markup(u"<b>Options for patterns</b>") align = gtk.Alignment(0, 0.5) align.add(label) right_vbox.pack_start(align, False, False, 0) self.copy_pattern_button = gtk.Button(u"Copy pattern(s) to file...") self.copy_pattern_button.set_sensitive(False) self.copy_pattern_button.connect("clicked", self.on_copy_patterns) right_vbox.pack_start(self.copy_pattern_button, False, False, 0) self.move_pattern_button = gtk.Button(u"Move pattern(s) to file...") self.move_pattern_button.set_sensitive(False) self.move_pattern_button.connect("clicked", self.on_move_patterns) right_vbox.pack_start(self.move_pattern_button, False, False, 0) self.add_pattern_button = gtk.Button(stock=gtk.STOCK_ADD); try: grid = self.palabra_window.puzzle_manager.current_puzzle.grid except AttributeError: # TODO self.add_pattern_button.set_sensitive(False) self.add_pattern_button.connect("clicked", self.on_add_pattern) align = self.add_pattern_button.get_children()[0] hbox = align.get_children()[0] image, label = hbox.get_children() label.set_text(u"Add current pattern to file..."); right_vbox.pack_start(self.add_pattern_button, False, False, 0) self.remove_pattern_button = gtk.Button(stock=gtk.STOCK_REMOVE); self.remove_pattern_button.set_sensitive(False) self.remove_pattern_button.connect("clicked", self.on_remove_patterns) align = self.remove_pattern_button.get_children()[0] hbox = align.get_children()[0] image, label = hbox.get_children() label.set_text(u"Remove pattern(s)"); right_vbox.pack_start(self.remove_pattern_button, False, False, 0) scrolled_window = gtk.ScrolledWindow(None, None) scrolled_window.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC) scrolled_window.add_with_viewport(self.tree) vbox1 = gtk.VBox(False, 12) label = gtk.Label() label.set_markup(u"<b>Pattern files</b>") align = gtk.Alignment(0, 0.5) align.add(label) vbox1.pack_start(align, False, False, 0) vbox1.pack_start(scrolled_window, True, True, 0) vbox1.pack_start(self.preview, False, False, 0) self.info = gtk.TextView() self.info.set_buffer(gtk.TextBuffer()) self.info.set_editable(False) scrolled_window = gtk.ScrolledWindow(None, None) scrolled_window.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC) scrolled_window.add_with_viewport(self.info) vbox2 = gtk.VBox(False, 12) vbox2.pack_start(right_vbox, False, False, 0) label = gtk.Label() label.set_markup(u"<b>Information</b>") align = gtk.Alignment(0, 0.5) align.add(label) vbox2.pack_start(align, False, False, 0) vbox2.pack_start(scrolled_window, True, True, 0) options_hbox = gtk.HBox(True, 12) options_hbox.pack_start(vbox1, True, True, 0) options_hbox.pack_start(vbox2, True, True, 0) hbox = gtk.HBox(False, 0) hbox.set_border_width(12) hbox.set_spacing(18) hbox.pack_start(options_hbox, True, True, 0) self.vbox.pack_start(hbox, True, True, 0) self.add_button(gtk.STOCK_OK, gtk.RESPONSE_OK)
class PatternFileEditor(gtk.Dialog): def __init__(self, palabra_window): gtk.Dialog.__init__(self, u"Pattern file manager" , palabra_window, gtk.DIALOG_MODAL) self.palabra_window = palabra_window self.set_size_request(640, 512) self.preview = GridPreview() self.preview.set_size_request(200, 256) self.patterns = {} # display_string filename id_of_grid self.store = gtk.TreeStore(str, str, str) self.reset_pattern_list() self.tree = gtk.TreeView(self.store) self.tree.set_headers_visible(False) self.tree.get_selection().set_mode(gtk.SELECTION_MULTIPLE) self.tree.get_selection().connect("changed", self.on_selection_changed) cell = gtk.CellRendererText() column = gtk.TreeViewColumn() column.pack_start(cell, True) column.set_attributes(cell, text=0) self.tree.append_column(column) right_vbox = gtk.VBox(False, 6) label = gtk.Label() label.set_markup(u"<b>Options for pattern files</b>") align = gtk.Alignment(0, 0.5) align.add(label) right_vbox.pack_start(align, False, False, 0) add_button = gtk.Button(stock=gtk.STOCK_ADD) add_button.connect("clicked", lambda button: self.add_file()) align = add_button.get_children()[0] hbox = align.get_children()[0] image, label = hbox.get_children() label.set_text(u"Add pattern file"); right_vbox.pack_start(add_button, False, False, 0) self.remove_button = gtk.Button(stock=gtk.STOCK_REMOVE) self.remove_button.connect("clicked", lambda button: self.remove_file()) self.remove_button.set_sensitive(False) align = self.remove_button.get_children()[0] hbox = align.get_children()[0] image, label = hbox.get_children() label.set_text(u"Remove pattern file(s)"); right_vbox.pack_start(self.remove_button, False, False, 0) label = gtk.Label() label.set_markup(u"<b>Options for patterns</b>") align = gtk.Alignment(0, 0.5) align.add(label) right_vbox.pack_start(align, False, False, 0) self.copy_pattern_button = gtk.Button(u"Copy pattern(s) to file...") self.copy_pattern_button.set_sensitive(False) self.copy_pattern_button.connect("clicked", self.on_copy_patterns) right_vbox.pack_start(self.copy_pattern_button, False, False, 0) self.move_pattern_button = gtk.Button(u"Move pattern(s) to file...") self.move_pattern_button.set_sensitive(False) self.move_pattern_button.connect("clicked", self.on_move_patterns) right_vbox.pack_start(self.move_pattern_button, False, False, 0) self.add_pattern_button = gtk.Button(stock=gtk.STOCK_ADD); try: grid = self.palabra_window.puzzle_manager.current_puzzle.grid except AttributeError: # TODO self.add_pattern_button.set_sensitive(False) self.add_pattern_button.connect("clicked", self.on_add_pattern) align = self.add_pattern_button.get_children()[0] hbox = align.get_children()[0] image, label = hbox.get_children() label.set_text(u"Add current pattern to file..."); right_vbox.pack_start(self.add_pattern_button, False, False, 0) self.remove_pattern_button = gtk.Button(stock=gtk.STOCK_REMOVE); self.remove_pattern_button.set_sensitive(False) self.remove_pattern_button.connect("clicked", self.on_remove_patterns) align = self.remove_pattern_button.get_children()[0] hbox = align.get_children()[0] image, label = hbox.get_children() label.set_text(u"Remove pattern(s)"); right_vbox.pack_start(self.remove_pattern_button, False, False, 0) scrolled_window = gtk.ScrolledWindow(None, None) scrolled_window.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC) scrolled_window.add_with_viewport(self.tree) vbox1 = gtk.VBox(False, 12) label = gtk.Label() label.set_markup(u"<b>Pattern files</b>") align = gtk.Alignment(0, 0.5) align.add(label) vbox1.pack_start(align, False, False, 0) vbox1.pack_start(scrolled_window, True, True, 0) vbox1.pack_start(self.preview, False, False, 0) self.info = gtk.TextView() self.info.set_buffer(gtk.TextBuffer()) self.info.set_editable(False) scrolled_window = gtk.ScrolledWindow(None, None) scrolled_window.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC) scrolled_window.add_with_viewport(self.info) vbox2 = gtk.VBox(False, 12) vbox2.pack_start(right_vbox, False, False, 0) label = gtk.Label() label.set_markup(u"<b>Information</b>") align = gtk.Alignment(0, 0.5) align.add(label) vbox2.pack_start(align, False, False, 0) vbox2.pack_start(scrolled_window, True, True, 0) options_hbox = gtk.HBox(True, 12) options_hbox.pack_start(vbox1, True, True, 0) options_hbox.pack_start(vbox2, True, True, 0) hbox = gtk.HBox(False, 0) hbox.set_border_width(12) hbox.set_spacing(18) hbox.pack_start(options_hbox, True, True, 0) self.vbox.pack_start(hbox, True, True, 0) self.add_button(gtk.STOCK_OK, gtk.RESPONSE_OK) def reset_pattern_list(self): self.store.clear() for f in preferences.prefs["pattern_files"]: try: g, meta, data = read_pattern_file(f) self.patterns[f] = {"metadata": meta, "data": data} except ParserError: # TODO pass for item in self.patterns.items(): self._append_file(*item) def _append_file(self, path, patterns): meta = patterns["metadata"] data = patterns["data"] s = meta["title"] if "title" in meta else path parent = self.store.append(None, [s, path, "0"]) for id, grid in data.items(): blocks = str(grid.count_blocks()) words = str(grid.count_words()) s = "".join([words, " words, ", blocks, " blocks"]) self.store.append(parent, [s, path, id]) def add_file(self): dialog = gtk.FileChooserDialog(u"Add pattern file" , self , gtk.FILE_CHOOSER_ACTION_OPEN , (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL , gtk.STOCK_OPEN, gtk.RESPONSE_OK)) filter = gtk.FileFilter() filter.set_name(u"Palabra pattern files (*.xml)") filter.add_pattern("*.xml") dialog.add_filter(filter) dialog.show_all() response = dialog.run() path = dialog.get_filename() dialog.destroy() if response == gtk.RESPONSE_OK: for g, pattern in self.patterns.items(): if g == path: mdialog = gtk.MessageDialog(None, gtk.DIALOG_MODAL , gtk.MESSAGE_INFO, gtk.BUTTONS_NONE, u"This file is already in the list.") mdialog.add_button(gtk.STOCK_CLOSE, gtk.RESPONSE_CLOSE) mdialog.set_title("Duplicate file") mdialog.run() mdialog.destroy() break else: try: g, meta, data = read_pattern_file(path) preferences.prefs["pattern_files"].append(path) self.patterns[path] = {"metadata": meta, "data": data} self._append_file(path, self.patterns[path]) self.tree.columns_autosize() except ParserError: # TODO pass def remove_file(self): image = gtk.Image() image.set_from_stock(gtk.STOCK_DIALOG_WARNING, gtk.ICON_SIZE_DIALOG) dialog = gtk.Dialog(u"Remove pattern files" , self , gtk.DIALOG_DESTROY_WITH_PARENT | gtk.DIALOG_MODAL , (gtk.STOCK_NO, gtk.RESPONSE_NO , gtk.STOCK_YES, gtk.RESPONSE_YES)) dialog.set_default_response(gtk.RESPONSE_CLOSE) dialog.set_title(u"Remove pattern files") label = gtk.Label(u"Are you sure you want to remove the selected pattern file(s)?") hbox = gtk.HBox(False, 0) hbox.pack_start(image, False, False, 0) hbox.pack_start(label, True, False, 10) dialog.vbox.pack_start(hbox, False, False, 10) dialog.set_resizable(False) dialog.set_modal(True) dialog.show_all() response = dialog.run() dialog.destroy() if response == gtk.RESPONSE_YES: while True: store, paths = self.tree.get_selection().get_selected_rows() if not paths: break it = store.get_iter(paths.pop()) filename = store.get_value(it, 1) store.remove(it) preferences.prefs["pattern_files"].remove(filename) try: del self.patterns[filename] self.tree.columns_autosize() except KeyError: pass def on_selection_changed(self, selection): grid = None store, paths = selection.get_selected_rows() self.copy_pattern_button.set_sensitive(False) self.move_pattern_button.set_sensitive(False) self.remove_pattern_button.set_sensitive(False) self.remove_button.set_sensitive(False) self.info.get_buffer().set_text("") self.preview.clear() if not paths: return if all([self.is_file(store, p) for p in paths]): self.remove_button.set_sensitive(True) if len(paths) == 1: if not self.is_file(store, paths[0]): it = store.get_iter(paths[0]) filepath = store.get_value(it, 1) id = store.get_value(it, 2) grid = self.patterns[filepath]["data"][id] self.preview.display(grid) only_patterns = not any([self.is_file(store, p) for p in paths]) self.copy_pattern_button.set_sensitive(only_patterns) self.move_pattern_button.set_sensitive(only_patterns) self.remove_pattern_button.set_sensitive(only_patterns) files = list(set([self.get_file(store, p) for p in paths])) self.info.get_buffer().set_text("") if len(files) == 1: for g, pattern in self.patterns.items(): if g == files[0]: if grid: stats = grid.determine_status() info = "".join(["Blocks: ", str(stats["block_count"]) , " (%.2f" % stats["block_percentage"], "%)\n" , "Letters: ", str(stats["char_count"]), "\n" , "Words: ", str(stats["word_count"]), "\n" , "Voids: ", str(stats["void_count"]), "\n"]) else: total = str(len(self.patterns[g]["data"].keys())) info = "".join(["Location: ", g, "\n" , "Number of patterns: ", total, "\n"]) self.info.get_buffer().set_text(info) break def append_to_file(self, path, patterns): """Append all patterns to the specified file.""" try: g, meta, data = read_pattern_file(path) except ParserError: # TODO return try: max_id = int(max(data.keys())) + 1 except ValueError: # max() arg is an empty sequence max_id = 1 for f, keys in patterns.items(): for k in keys: data[str(max_id)] = self.patterns[f]["data"][k] max_id += 1 write_pattern_file(g, meta, data) @staticmethod def remove_from_files(patterns): """Remove the patterns from their respective files.""" for f, keys in patterns.items(): try: g, meta, data = read_pattern_file(f) ndata = {} for k, v in data.items(): if k not in keys: ndata[k] = v write_pattern_file(g, meta, ndata) except ParserError: # TODO pass def on_copy_patterns(self, button): """Copy the currently selected patterns to a specified file.""" patterns = self._gather_selected_patterns() path = self._get_pattern_file() if not path: return self.append_to_file(path, patterns) def on_move_patterns(self, button): """Move the currently selected patterns to a specified file.""" patterns = self._gather_selected_patterns() path = self._get_pattern_file() if not path: return self.append_to_file(path, patterns) self.remove_from_files(patterns) def on_add_pattern(self, button): """Add the pattern of the current puzzle to a specified file.""" path = self._get_pattern_file() if not path: return # TODO ugly try: grid = self.palabra_window.puzzle_manager.current_puzzle.grid except AttributeError: # TODO return try: g, meta, data = read_pattern_file(path) except ParserError: # TODO return max_id = int(max(data.keys())) + 1 data[str(max_id)] = grid write_pattern_file(g, meta, data) def on_remove_patterns(self, button): """Remove the currently selected patterns from their respective files.""" image = gtk.Image() image.set_from_stock(gtk.STOCK_DIALOG_WARNING, gtk.ICON_SIZE_DIALOG) dialog = gtk.Dialog(u"Remove patterns" , self , gtk.DIALOG_DESTROY_WITH_PARENT | gtk.DIALOG_MODAL , (gtk.STOCK_NO, gtk.RESPONSE_NO , gtk.STOCK_YES, gtk.RESPONSE_YES)) dialog.set_default_response(gtk.RESPONSE_CLOSE) dialog.set_title(u"Remove patterns") label = gtk.Label(u"Are you sure you want to remove the selected pattern(s)?") hbox = gtk.HBox(False, 0) hbox.pack_start(image, False, False, 0) hbox.pack_start(label, True, False, 10) dialog.vbox.pack_start(hbox, False, False, 10) dialog.set_resizable(False) dialog.set_modal(True) dialog.show_all() response = dialog.run() dialog.destroy() if response == gtk.RESPONSE_YES: patterns = self._gather_selected_patterns() self.remove_from_files(patterns) while True: store, paths = self.tree.get_selection().get_selected_rows() if not paths: break it = store.get_iter(paths.pop()) filename = store.get_value(it, 1) store.remove(it) # currently disabled, don't automatically remove file without patterns if False: for row in self.store: if not self.is_file_with_patterns(self.store, row.path): filename = row[1] it = store.get_iter(row.path) self.store.remove(it) preferences.prefs["pattern_files"].remove(filename) try: del self.patterns[filename] except KeyError: pass self.tree.columns_autosize() def _get_pattern_file(self): """Request a filepath from the user.""" dialog = gtk.FileChooserDialog(u"Select a pattern file" , self , gtk.FILE_CHOOSER_ACTION_OPEN , (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL , gtk.STOCK_OPEN, gtk.RESPONSE_OK)) filter = gtk.FileFilter() filter.set_name(u"Palabra pattern files (*.xml)") filter.add_pattern("*.xml") dialog.add_filter(filter) dialog.show_all() path = None response = dialog.run() if response == gtk.RESPONSE_OK: path = dialog.get_filename() dialog.destroy() return path def _gather_selected_patterns(self): """Gather the currently selected patterns and the files they belong to.""" patterns = {} store, paths = self.tree.get_selection().get_selected_rows() for path in paths: it = store.get_iter(path) parent = store.iter_parent(it) id = store.get_value(it, 2) try: patterns[store.get_value(parent, 1)].append(id) except KeyError: patterns[store.get_value(parent, 1)] = [id] return patterns def get_file(self, store, path): return store.get_value(store.get_iter(path), 1) def is_file(self, store, path): return store.iter_parent(store.get_iter(path)) is None def is_file_with_patterns(self, store, path): return self.is_file(store, path) and store.iter_has_child(store.get_iter(path))
class AppearanceDialog(PalabraDialog): def __init__(self, palabra_window, properties): PalabraDialog.__init__(self, palabra_window, u"Appearance") self.palabra_window = palabra_window hbox = gtk.HBox() hbox.set_spacing(18) hbox.pack_start(self.create_content(properties)) mode = constants.VIEW_MODE_PREVIEW_SOLUTION self.preview = GridPreview(mode=mode, cell_size=None) self.preview.set_size_request(200, 200) hbox.pack_start(self.preview, False, False, 0) self.pack(hbox) g = Grid(3, 3) g.set_block(0, 2, True) g.set_void(2, 0, True) g.set_char(0, 0, "A") g.assign_numbers() self.preview.display(g) self.on_update() self.add_button(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL) self.add_button(gtk.STOCK_APPLY, gtk.RESPONSE_OK) def create_content(self, properties): main = gtk.VBox() main.set_spacing(6) table = gtk.Table(10, 3) table.set_col_spacings(6) table.set_row_spacings(6) main.pack_start(table) def create_label(label): align = gtk.Alignment(0, 0.5) align.set_padding(0, 0, 12, 0) align.add(gtk.Label(label)) return align def create_width_spinner(current): adj = gtk.Adjustment(current, 1, constants.MAX_LINE_WIDTH, 1, 0, 0) button = gtk.SpinButton(adj, 0.0, 0) return button def create_row(table, y, label, c1, c2=None): table.attach(label, 0, 1, y, y + 1, gtk.FILL, gtk.FILL) table.attach(c1, 1, 2, y, y + 1, 0, 0) if c2 is not None: table.attach(c2, 2, 3, y, y + 1, 0, 0) table.attach(create_label(u"Color"), 1, 2, 0, 1, gtk.FILL, gtk.FILL) table.attach(create_label(u"Width (px)"), 2, 3, 0, 1, gtk.FILL, gtk.FILL) def create_line_controls(title, key_color, key_width): label = create_label(title) button = create_color_button(properties[key_color], self.on_update) spinner = create_width_spinner(properties[key_width]) return label, button, spinner # borders and lines widgets = create_line_controls(u"Border:", ("border", "color"), ("border", "width")) self.border_color_button = widgets[1] self.border_width_spinner = widgets[2] create_row(table, 1, *widgets) widgets = create_line_controls(u"Line:", ("line", "color"), ("line", "width")) self.line_color_button = widgets[1] self.line_width_spinner = widgets[2] create_row(table, 2, *widgets) def cap_line_width_at(bound): s = self.line_width_spinner adj = s.get_adjustment() adj.set_upper(bound) if s.get_value_as_int() > bound: s.set_value(bound) def on_border_width_update(widget): cap_line_width_at(widget.get_value_as_int()) self.on_update() self.border_width_spinner.connect("value-changed", on_border_width_update) self.line_width_spinner.connect("value_changed", self.on_update) cap_line_width_at(properties["border", "width"]) table.attach(create_label(u"Color"), 1, 2, 3, 4, gtk.FILL, gtk.FILL) table.attach(create_label(u"Size (%)"), 2, 3, 3, 4, gtk.FILL, gtk.FILL) def create_font_controls(title, key_color, key_size): label = create_label(title) button = create_color_button(properties[key_color], self.on_update) adj = gtk.Adjustment(properties[key_size][0], 10, 100, 1, 0, 0) spinner = gtk.SpinButton(adj) spinner.connect("value-changed", self.on_update) return label, button, spinner # letters and numbers widgets = create_font_controls(u"Letter:", ("char", "color"), ("char", "size")) self.char_color_button = widgets[1] self.char_size_spinner = widgets[2] create_row(table, 4, *widgets) widgets = create_font_controls(u"Number:", ("number", "color"), ("number", "size")) self.number_color_button = widgets[1] self.number_size_spinner = widgets[2] create_row(table, 5, *widgets) # cells table.attach(create_label(u"Color"), 1, 2, 6, 7, gtk.FILL, gtk.FILL) table.attach(create_label(u"Size (px)"), 2, 3, 6, 7, gtk.FILL, gtk.FILL) label = create_label(u"Cell:") self.cell_color_button = create_color_button(properties["cell", "color"], self.on_update) adj = gtk.Adjustment(properties["cell", "size"], 32, 128, 1, 0, 0) self.cell_size_spinner = gtk.SpinButton(adj, 0.0, 0) self.cell_size_spinner.connect("value-changed", self.on_update) create_row(table, 7, label, self.cell_color_button, self.cell_size_spinner) # blocks table.attach(create_label(u"Color"), 1, 2, 8, 9, gtk.FILL, gtk.FILL) table.attach(create_label(u"Margin (%)"), 2, 3, 8, 9, gtk.FILL, gtk.FILL) current = properties["block", "margin"] label = create_label(u"Block:") self.block_color_button = create_color_button(properties["block", "color"], self.on_update) adj = gtk.Adjustment(current, 0, 49, 1, 0, 0) self.block_margin_spinner = gtk.SpinButton(adj, 0.0, 0) self.block_margin_spinner.connect("value-changed", self.on_update) create_row(table, 9, label, self.block_color_button, self.block_margin_spinner) return main def on_update(self, widget=None): for k, v in self.gather_appearance().items(): self.preview.view.properties[k] = v self.preview.refresh(force=True) def gather_appearance(self): a = {} a["block", "margin"] = self.block_margin_spinner.get_value_as_int() a["border", "width"] = self.border_width_spinner.get_value_as_int() a["cell", "size"] = self.cell_size_spinner.get_value_as_int() a["line", "width"] = self.line_width_spinner.get_value_as_int() a["cell", "color"] = color_tuple(self.cell_color_button) a["line", "color"] = color_tuple(self.line_color_button) a["border", "color"] = color_tuple(self.border_color_button) a["block", "color"] = color_tuple(self.block_color_button) a["char", "color"] = color_tuple(self.char_color_button) a["number", "color"] = color_tuple(self.number_color_button) p = self.char_size_spinner.get_value_as_int() key = ("cell", "size") a["char", "size"] = (p, _relative_to(key, p / 100.0, d=a)) p = self.number_size_spinner.get_value_as_int() a["number", "size"] = (p, _relative_to(key, p / 100.0, d=a)) return a
def __init__(self, palabra_window, properties): super(CellPropertiesDialog, self).__init__(palabra_window, u"Cell properties") self.palabra_window = palabra_window self.properties = properties x, y = properties["cell"] c1 = (u"Background color", ("cell", "color")) c2 = (u"Block color", ("block", "color")) c3 = (u"Letter color", ("char", "color")) c4 = (u"Number color", ("number", "color")) self.colors = [c1, c2, c3, c4] self.grid = Grid(1, 1) self.grid.data[0][0].update(properties["grid"].data[y][x]) table = gtk.Table(3, 3, False) table.set_col_spacings(6) table.set_row_spacings(6) def create_row(table, title, value, x, y): table.attach(create_label(title), x, x + 1, y, y + 1, gtk.FILL, gtk.FILL) table.attach(create_label(value, align=(0, 0)), x + 1, x + 2, y, y + 1) def create_color_row(table, title, b_align, r_align, x, y): table.attach(create_label(title), x, x + 1, y, y + 1, gtk.FILL, gtk.FILL) table.attach(b_align, x + 1, x + 2, y, y + 1) table.attach(r_align, x + 2, x + 3, y, y + 1) on_color_set = lambda button, key: self._on_update(key, color_tuple(button)) for i, (title, key) in enumerate(self.colors): attr = "_".join(list(key) + ["button"]) setattr(self, attr, create_color_button(properties[key])) getattr(self, attr).connect("color-set", on_color_set, key) attr2 = "_".join(list(key) + ["reset", "button"]) setattr(self, attr2, gtk.Button(u"Reset")) getattr(self, attr2).connect("clicked", self.on_color_reset, key) b_align = gtk.Alignment(0, 0.5) b_align.add(getattr(self, attr)) r_align = gtk.Alignment(0, 0.5) r_align.add(getattr(self, attr2)) create_color_row(table, title, b_align, r_align, 0, i) table.attach(create_label(u"Other options"), 0, 1, 4, 5, gtk.FILL, gtk.FILL) on_circle = lambda b: self._on_update("circle", b.get_active()) self.circle_button = create_check_button(u"Display circle", active=properties["circle"], f_toggle=on_circle) table.attach(self.circle_button, 1, 3, 4, 5) main = gtk.VBox() main.set_spacing(6) main.pack_start(create_label(u"<b>Properties</b>"), False, False, 0) main.pack_start(table, False, False, 0) content = gtk.HBox() content.set_border_width(6) content.set_spacing(6) content.pack_start(main) self.previews = [] prevs = gtk.VBox() p1 = (constants.VIEW_MODE_PREVIEW_CELL, "Puzzle") p2 = (constants.VIEW_MODE_PREVIEW_SOLUTION, "Solution") for m, h in [p1, p2]: p = GridPreview(mode=m, header=h, cell_size=96) p.set_size_request(164, 164) align = gtk.Alignment() align.add(p) self.previews.append(p) p.display(self.grid) for k in DEFAULTS_CELL: p.view.properties[k] = properties[k] p.refresh() prevs.pack_start(align, False, False, 0) content.pack_start(prevs, False, False, 0) self.pack(content) self.add_button(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL) self.add_button(gtk.STOCK_APPLY, gtk.RESPONSE_OK)