Source code for

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# pylint:disable=unused-wildcard-import,wildcard-import,attribute-defined-outside-init
"""Graphics tab for the TKinter GUI."""

from tkinter import *  # noqa: F403
from tkinter import messagebox
from tkinter.ttk import *  # noqa: F403

from core import colors, graphics, paths
from core.lnp import lnp

from . import binding, controls, tkhelpers
from .layout import GridLayouter
from .tab import Tab

[docs]class GraphicsTab(Tab): """Graphics tab for the TKinter GUI.""" # pylint: disable=too-many-instance-attributes
[docs] def create_variables(self): = Variable() self.colors = Variable() self.tilesets = Variable()
[docs] def read_data(self): self.read_graphics() self.read_colors() self.read_tilesets()
[docs] def create_controls(self): Style().configure('SubNotebook.TNotebook', tabposition='n') n = Notebook(self, style='SubNotebook.TNotebook') n.pack(fill=BOTH, expand=Y, pady=(4, 2)) # Tab: Change Graphics change_graphics_tab = Frame(self, pad=(4, 2)) change_graphics_tab.pack(fill=BOTH, expand=Y) n.add(change_graphics_tab, text="Choose") self._create_cg_group(change_graphics_tab).pack(fill=BOTH, expand=Y) self._create_display_group(change_graphics_tab).pack(fill=X, expand=N) self._create_advanced_group(change_graphics_tab).pack(fill=X, expand=N) # Tab: Customization customize_tab = Frame(self, pad=(4, 2)) customize_tab.pack(fill=BOTH, expand=Y) n.add(customize_tab, text="Customize") self._create_tilesets_group(customize_tab).pack(fill=BOTH, expand=Y) self._create_cs_group(customize_tab).pack(fill=BOTH, expand=N)
def _create_cg_group(self, parent, show_title=True): title = 'Change Graphics' if show_title else None change_graphics = controls.create_control_group(parent, title, True) change_graphics.rowconfigure(0, weight=1) grid = GridLayouter(2) listframe = Frame(change_graphics) grid.add(listframe, 2) _, self.graphicpacks = controls.create_file_list( listframe, None,, height=8) self.graphicpacks.bind( '<<ListboxSelect>>', lambda e: self.select_graphics()) controls.listbox_dyn_tooltip( self.graphicpacks, lambda i: self.packs[i], graphics.get_tooltip) for seq in ("<Double-1>", "<Return>"): self.graphicpacks.bind(seq, lambda e: self.install_graphics()) grid.add(controls.create_trigger_button( change_graphics, 'Install Graphics', 'Install selected graphics pack', self.install_graphics)) grid.add(controls.create_trigger_button( change_graphics, 'Update Savegames', 'Install current graphics pack in all savegames', self.update_savegames)) grid.add(controls.create_trigger_button( change_graphics, 'Refresh', 'Refresh list of graphics packs', self.read_graphics)) grid.add(controls.create_trigger_button( change_graphics, 'Open Folder', 'Add your own graphics packs here!', graphics.open_graphics)) return change_graphics def _create_advanced_group(self, parent, show_title=True): title = 'Advanced' if show_title else None advanced = controls.create_control_group(parent, title, True) grid = GridLayouter(2) if 'legacy' not in lnp.df_info.variations: grid.add(controls.create_option_button( advanced, 'Print Mode', 'Changes how Dwarf Fortress draws to the screen. "2D" allows ' 'Truetype fonts, "standard" enables advanced graphics tools. ' 'Certain modifications may use other values.', 'printmode'), 2) grid.add(controls.create_option_button( advanced, 'TrueType Fonts', 'Toggles whether to use TrueType fonts or tileset for text. ' 'Only works with Print Mode set to 2D.', 'truetype'), 2) grid.add(controls.create_trigger_button( advanced, 'Simplify Graphic Folders', 'Deletes unnecessary files from graphics packs ' '(saves space, useful for re-packaging)', self.simplify_graphics)) return advanced def _create_tilesets_group(self, parent, show_title=True): title = 'Change Tilesets' if show_title else None customize = controls.create_control_group(parent, title, True) _, self.fonts = controls.create_file_list( customize, 'FONT', self.tilesets) for seq in ("<Double-1>", "<Return>"): self.fonts.bind(seq, lambda e: self.install_tilesets(1)) if lnp.settings.version_has_option('GRAPHICS_FONT'): _, self.graphicsfonts = controls.create_file_list( customize, 'GRAPHICS_FONT', self.tilesets) for seq in ("<Double-1>", "<Return>"): self.graphicsfonts.bind(seq, lambda e: self.install_tilesets(2)) buttons = controls.create_control_group(customize, None, True) buttons.pack(fill=X) grid = GridLayouter(2) grid.add(controls.create_trigger_button( buttons, 'Install Tilesets', 'Install selected tilesets', self.install_tilesets), 2) grid.add(controls.create_trigger_button( buttons, 'Refresh', 'Refresh list of tilesets', self.read_tilesets)) grid.add(controls.create_trigger_button( buttons, 'Open Folder', 'Add your own tilesets here!', graphics.open_tilesets)) return customize def _create_cs_group(self, parent, show_title=True): title = "Color schemes" if show_title else None colorframe, self.color_entry, self.color_files = \ controls.create_list_with_entry( parent, title, self.colors, [("Save", "Save current color scheme", self.save_colors), ("Load", "Load color scheme", self.load_colors), ("Delete", "Delete color scheme", self.delete_colors), ("Refresh", "Refresh list", self.read_colors)], entry_default="Save current color scheme as...") self.color_files.bind( "<<ListboxSelect>>", lambda e: self.select_colors()) for seq in ("<Double-1>", "<Return>"): self.color_files.bind(seq, lambda e: self.load_colors()) self.color_preview = Canvas( colorframe, width=128, height=32, highlightthickness=0, takefocus=False) self.color_preview.grid(column=0, row=0, columnspan=2, pady=(0, 4)) return colorframe @staticmethod def _create_display_group(parent, show_title=True): title = 'Display Options' if show_title else None display = controls.create_control_group(parent, title, True) grid = GridLayouter(2) grid.add(controls.create_option_button( display, 'Liquid Depth', 'Displays the depth of liquids with numbers 1-7', 'liquidDepth')) grid.add(controls.create_option_button( display, 'Varied Ground', 'If ground tiles use a variety of punctuation, or only periods', 'variedGround')) grid.add(controls.create_option_button( display, 'Hide Engravings', 'Make all engravings look the same', 'engravingsObscured')) grid.add(controls.create_option_button( display, 'Show Improvement', 'Show the quality of improvement in name of items', 'improvementQuality')) return display
[docs] def read_graphics(self): """Reads list of graphics packs.""" packs = self.packs = [p[0] for p in graphics.read_graphics()][graphics.get_title(p) for p in packs]))) current = graphics.current_pack() default_bg = Style().lookup('TListbox', 'fill') for i, p in enumerate(packs): if p == current: self.graphicpacks.itemconfig(i, bg='pale green') else: self.graphicpacks.itemconfig(i, bg=default_bg) self.select_graphics()
[docs] def install_graphics(self): """Installs a graphics pack.""" if len(self.graphicpacks.curselection()) != 0: if not tkhelpers.check_vanilla_raws(): return gfx_dir = self.packs[int(self.graphicpacks.curselection()[0])] result = None if messagebox.askokcancel( message='Your graphics, settings and raws will be changed.' '\n\nAny manually installed mods will be removed in the ' 'process.\n\nAre you sure you want to continue?', title='Are you sure?'): result = graphics.install_graphics(gfx_dir) if result is False: messagebox.showerror( title='Error occurred', message='Something went wrong: ' 'the graphics folder may be missing important files. ' 'Graphics may not be installed correctly.\n' 'See the output log for error details.') elif result == 0: messagebox.showerror( title='Not updatable', message='The graphics raws could' ' not be updated due to missing graphics files, or ' 'your installed mods are incompatible with this ' 'graphics pack.') elif result: if len(graphics.savegames_to_update()) != 0: if messagebox.askyesno( 'Update Savegames?', 'Graphics and settings installed!\n' 'Would you like to update your savegames to ' 'properly use the new graphics?'): self.update_savegames() else: messagebox.showinfo( 'Graphics installed', 'Graphics and settings installed!') else: messagebox.showerror( title='Error occurred', message='Nothing was installed.\n' 'Folder does not exist or does not have required files ' 'or folders:\n' + str(gfx_dir)) if result: self.graphicpacks.selection_clear( self.graphicpacks.curselection()) binding.update() self.read_data()
[docs] @staticmethod def update_savegames(): """Updates saved games with new raws.""" count, skipped = graphics.update_savegames() if count + skipped == 0: messagebox.showinfo( title='Update skipped', message="No savegames to update.") else: msg = "{} savegames updated!\n\n".format(count) if skipped: msg += "{} savegames were skipped (would have broken raws)"\ .format(skipped) messagebox.showinfo('Update complete', msg)
[docs] def simplify_graphics(self): """Removes unnecessary files from graphics packs.""" if not tkhelpers.check_vanilla_raws(): return self.read_graphics() for pack in result = graphics.simplify_pack(pack) if result is None: messagebox.showinfo( title='Error occurred', message='No files in: ' + str(pack)) elif result is False: messagebox.showerror( title='Error occurred', message='Error simplifying graphics folder. ' 'It may not have the required files.\n' + str(pack) + '\n' 'See the output log for error details.') elif result != 0: messagebox.showinfo( title='Success', message='Deleted {0} unnecessary file(s) in: {1}'.format( result, pack)) messagebox.showinfo(title='Success', message='All graphics {} ' 'are simplified!'.format(
[docs] def read_colors(self): """Reads list of color schemes.""" files = colors.read_colors() self.colors.set(files) current = colors.get_installed_file() default_bg = Style().lookup('TListbox', 'fill') for i, f in enumerate(files): if f == current: self.color_files.itemconfig(i, bg='pale green') else: self.color_files.itemconfig(i, bg=default_bg) self.select_colors()
[docs] def load_colors(self): """Replaces color scheme with the selected file.""" items = self.color_files.curselection() if len(items) > 0: self.color_files.selection_clear(items) colors.load_colors(self.color_files.get(items[0])) self.read_colors() self.color_entry.delete(0, END)
[docs] def save_colors(self): """Saves color scheme to a file.""" v = self.color_entry.get() if v and not getattr(self.color_entry, 'default_showing', False): if (not colors.color_exists(v) or messagebox.askyesno( message='Overwrite {0}?'.format(v), icon='question', title='Overwrite file?')): self.color_entry.delete(0, END) colors.save_colors(v) self.read_colors()
[docs] def delete_colors(self): """Deletes the selected color scheme.""" if len(self.color_files.curselection()) != 0: filename = self.color_files.get(self.color_files.curselection()[0]) if messagebox.askyesno( 'Delete file?', 'Are you sure you want to delete {0}?'.format(filename)): colors.delete_colors(filename) self.read_colors()
[docs] def select_graphics(self): """Event handler for selecting a graphics pack.""" colorscheme = None if len(self.graphicpacks.curselection()) != 0: pack = self.packs[int(self.graphicpacks.curselection()[0])] if lnp.df_info.version >= '0.31.04': colorscheme = paths.get('graphics', pack, 'data', 'init', 'colors.txt') else: colorscheme = paths.get('graphics', pack, 'data', 'init', 'init.txt') self.paint_color_preview(colorscheme)
[docs] def select_colors(self): """Event handler for selecting a colorscheme.""" colorscheme = None if len(self.color_files.curselection()) != 0: colorscheme = self.color_files.get( self.color_files.curselection()[0]) self.paint_color_preview(colorscheme)
[docs] def paint_color_preview(self, colorscheme): """ Draws a preview of a color scheme. If no scheme is specified, draws the currently installed color scheme. Args: colorscheme: Listbox containing the list of color schemes. """ colorlist = colors.get_colors(colorscheme) self.color_preview.delete(ALL) if not colorlist: self.color_preview.create_text( 0, 0, text="Error reading colorscheme", anchor=NW) else: for i, c in enumerate(colorlist): row = i // 8 col = i % 8 self.color_preview.create_rectangle( col * 16, row * 16, (col + 1) * 16, (row + 1) * 16, fill="#%02x%02x%02x" % tuple(int(v % 256) for v in c), width=0)
[docs] def read_tilesets(self): """Reads list of graphics packs.""" files = graphics.read_tilesets() self.tilesets.set(files) current = graphics.current_tilesets() default_bg = Style().lookup('TListbox', 'fill') for i, f in enumerate(files): if f == current[0]: self.fonts.itemconfig(i, bg='pale green') else: self.fonts.itemconfig(i, bg=default_bg) if lnp.settings.version_has_option('GRAPHICS_FONT'): if f == current[1]: self.graphicsfonts.itemconfig(i, bg='pale green') else: self.graphicsfonts.itemconfig(i, bg=default_bg)
[docs] def install_tilesets(self, mode=3): """ Installs selected tilesets. Args: mode: If ``mode & 1``, installs FONT. If ``mode & 2``, installs GRAPHICS_FONT. """ font = None graphicsfont = None if len(self.fonts.curselection()) != 0 and (mode & 1): font = self.fonts.get(self.fonts.curselection()[0]) self.fonts.selection_clear(self.fonts.curselection()) if len(self.graphicsfonts.curselection()) != 0 and (mode & 2): graphicsfont = self.graphicsfonts.get( self.graphicsfonts.curselection()[0]) self.graphicsfonts.selection_clear( self.graphicsfonts.curselection()) graphics.install_tilesets(font, graphicsfont) binding.update() self.read_data()