# This file is part of MyPaint. # Copyright (C) 2007 by Martin Renold # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY. See the COPYING file for more details. import gtk, os import brush class Application: # singleton def __init__(self, share, confpath, loadimage): self.confpath = confpath datapaths = [share] self.datapath = None for p in datapaths: if os.path.isdir(os.path.join(p, 'brushes')): self.datapath = p break if not self.datapath: print 'Default brush collection not found! Searched:' print ' '.join(datapaths) raise SystemExit self.user_brushpath = os.path.join(self.confpath, 'brushes') self.stock_brushpath = os.path.join(self.datapath, 'brushes') if not os.path.isdir(self.confpath): os.mkdir(self.confpath) print 'Created', self.confpath if not os.path.isdir(self.user_brushpath): os.mkdir(self.user_brushpath) self.init_brushes() self.window_names = 'drawWindow brushSettingsWindow brushSelectionWindow colorSelectionWindow'.split() for name in self.window_names: module = __import__(name.lower()) window = self.__dict__[name] = module.Window(self) self.load_window_position(name, window) gtk.accel_map_load(os.path.join(self.confpath, 'accelmap.conf')) if loadimage: self.drawWindow.open_file(loadimage) def init_brushes(self): self.brush = brush.Brush(self) self.brushes = [] self.selected_brush = None self.brush_selected_callbacks = [self.brush_selected_cb] self.contexts = [] for i in range(10): c = brush.Brush(self) c.name = 'context%02d' % i self.contexts.append(c) self.selected_context = None # find all brush names to load deleted = [] filename = os.path.join(self.user_brushpath, 'deleted.conf') if os.path.exists(filename): for line in open(filename): deleted.append(line.strip()) def listbrushes(path): return [filename[:-4] for filename in os.listdir(path) if filename.endswith('.myb')] stock_names = listbrushes(self.stock_brushpath) user_names = listbrushes(self.user_brushpath) stock_names = [name for name in stock_names if name not in deleted and name not in user_names] loadnames_unsorted = user_names + stock_names loadnames_sorted = [] # sort them for path in [self.user_brushpath, self.stock_brushpath]: filename = os.path.join(path, 'order.conf') if not os.path.exists(filename): continue for line in open(filename): name = line.strip() if name in loadnames_sorted: continue if name not in loadnames_unsorted: continue loadnames_unsorted.remove(name) loadnames_sorted.append(name) if len(loadnames_unsorted) > 3: # many new brushes, do not disturb user's order loadnames = loadnames_sorted + loadnames_unsorted else: loadnames = loadnames_unsorted + loadnames_sorted for name in loadnames: # load brushes from disk b = brush.Brush(self) b.load(name) if name.startswith('context'): i = int(name[-2:]) assert i >= 0 and i < 10 # 10 for now... self.contexts[i] = b else: self.brushes.append(b) if self.brushes: self.select_brush(self.brushes[0]) self.brush.set_color_hsv((0, 0, 0)) def save_brushorder(self): f = open(os.path.join(self.user_brushpath, 'order.conf'), 'w') f.write('# this file saves brushorder\n') f.write('# the first one (upper left) will be selected at startup\n') for b in self.brushes: f.write(b.name + '\n') f.close() def brush_selected_cb(self, brush): "actually set the new brush" assert brush is not self.brush # self.brush never gets exchanged if brush in self.brushes: self.selected_brush = brush else: #print 'Warning, you have selected a brush not in the list.' # TODO: maybe find out parent and set this as selected_brush self.selected_brush = None if brush is not None: self.brush.copy_settings_from(brush) def select_brush(self, brush): for callback in self.brush_selected_callbacks: callback(brush) def hide_window_cb(self, window, event): # used by some of the windows window.hide() return True def quit(self): gtk.accel_map_save(os.path.join(self.confpath, 'accelmap.conf')) d = gtk.Dialog("Really quit?", None, gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT, (gtk.STOCK_YES, gtk.RESPONSE_ACCEPT, gtk.STOCK_NO, gtk.RESPONSE_REJECT)) if d.run() == gtk.RESPONSE_ACCEPT: self.save_window_positions() gtk.main_quit() return False d.destroy() return True def save_window_positions(self): f = open(os.path.join(self.confpath, 'windowpos.conf'), 'w') f.write('# name visible x y width height\n') for name in self.window_names: window = self.__dict__[name] x, y = window.get_position() w, h = window.get_size() visible = window.get_property('visible') f.write('%s %s %d %d %d %d\n' % (name, visible, x, y, w, h)) def load_window_position(self, name, window): try: for line in open(os.path.join(self.confpath, 'windowpos.conf')): if line.startswith(name): parts = line.split() visible = parts[1] == 'True' x, y, w, h = [int(i) for i in parts[2:2+4]] window.parse_geometry('%dx%d+%d+%d' % (w, h, x, y)) if visible or name == 'drawWindow': window.show_all() return except IOError: pass if name == 'brushSelectionWindow': window.parse_geometry('300x500') # default visibility setting if name in 'drawWindow brushSelectionWindow colorSelectionWindow'.split(): window.show_all()