Ejemplo n.º 1
0
    def capture_image(self, x, y, width, height, window):
        pb = pixbuf.new(colorspace.RGB, True, 8, width, height)
        # mask the pixbuf if we have more than one screen
        root_width, root_height = window.get_width(), window.get_height()
        pb2 = pixbuf.new(colorspace.RGB, True, 8, root_width, root_height)
        pb2 = gdk.pixbuf_get_from_window(window, 0, 0, root_width, root_height)
        pb2 = self.mask_pixbuf(pb2, root_width, root_height)
        pb2.copy_area(x, y, width, height, pb, 0, 0)

        if not pb:
            print('Invalid Pixbuf')
            exit(EXIT_INVALID_PIXBUF)
        if self.use_clipboard:
            self.save_clipboard(pb)
        else:
            self.save_file(pb, width, height)

        # call_exec returns immediately if self.command is None
        self.call_exec(width, height)

        # daemonize here so we don't mess with the CWD on subprocess
        if self.use_clipboard:
            daemonize()
        else:
            # exit here instead of inside save_file
            self.on_exit(width, height)
Ejemplo n.º 2
0
    def load_sample_image(self, fname):
        """Загрузка изображения с образцом чернил в определитель цвета."""

        tmppbuf = Pixbuf.new_from_file(fname)

        self.pixbufCX = tmppbuf.get_width()
        self.pixbufCY = tmppbuf.get_height()

        # создаём новый, строго заданного формата, мало ли что там загрузилось
        self.pixbuf = Pixbuf.new(GdkPixbuf.Colorspace.RGB, False, 8, self.pixbufCX, self.pixbufCY)

        # на случай наличия альфа-канала в исходном изображении
        self.pixbuf.fill(0xffffffff)

        tmppbuf.composite(self.pixbuf,
            0, 0, self.pixbufCX, self.pixbufCY,
            0, 0, 1.0, 1.0,
            GdkPixbuf.InterpType.TILES, 255);

        self.pixbufPixels = self.pixbuf.get_pixels()
        self.pixbufChannels = self.pixbuf.get_n_channels()
        self.pixbufRowStride = self.pixbuf.get_rowstride()

        #self.swImgView.set_max_content_width(self.pixbufCX)
        #self.swImgView.set_max_content_height(self.pixbufCY)

        self.imgView.set_from_pixbuf(self.pixbuf)

        self.swImgView.get_hadjustment().set_value(0)
        self.swImgView.get_vadjustment().set_value(0)

        #
        self.lstoreSamples.clear()
        self.update_sample_count()
        self.compute_average_color()
Ejemplo n.º 3
0
    def gen_preview(text, size=9, opacity=1) -> Pixbuf:
        pix = Pixbuf.new(Colorspace.RGB, True, 8, 60, 80)
        surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, pix.get_width(),
                                     pix.get_height())
        context = cairo.Context(surface)

        # Gdk.cairo_set_source_pixbuf(context, pix, 0, 0)
        # context.paint()  # paint the pixbuf
        # context.select_font_face('sans-serif')
        context.set_font_size(size)

        # Document background
        grad = cairo.LinearGradient(0, 0, 0, pix.get_height())
        grad.add_color_stop_rgb(0, 0.95, 0.95, 0.95)
        grad.add_color_stop_rgb(pix.get_height(), 0.93, 0.93, 0.93)
        context.set_source(grad)
        context.paint_with_alpha(opacity)

        # Document Outline
        grad = cairo.LinearGradient(0, 0, 0, pix.get_height())
        grad.add_color_stop_rgba(0, 1, 1, 1, opacity)
        grad.add_color_stop_rgba(pix.get_height(), 0.94, 0.94, 0.94, opacity)
        context.rectangle(1, 1, pix.get_width() - 2, pix.get_height() - 2)
        context.set_source(grad)
        context.stroke()

        # Border
        context.rectangle(0, 0, pix.get_width(), pix.get_height())
        context.set_source_rgba(0.9, 0.9, 0.9, opacity)
        context.stroke()

        # add the text
        for num, line in enumerate(text.split('\n'), 1):
            context.set_source_rgba(0.2, 0.2, 0.24, opacity)

            # Fix to remove \r if it exists
            if line.startswith('\r'):
                line = line[1:]

            if num == 1:
                context.select_font_face('sans-serif', cairo.FONT_SLANT_NORMAL,
                                         cairo.FONT_WEIGHT_BOLD)
            else:
                context.select_font_face('monospace', cairo.FONT_SLANT_NORMAL,
                                         cairo.FONT_WEIGHT_NORMAL)

            context.move_to(4, 4 + size * num)
            context.show_text(line)

        # get the resulting pixbuf
        surface = context.get_target()
        return Gdk.pixbuf_get_from_surface(surface, 0, 0, surface.get_width(),
                                           surface.get_height())
Ejemplo n.º 4
0
    def crop_borders(self):
        if not isinstance(self._buffer, Pixbuf) or self.path is None:
            return self

        bbox = self._compute_borders_crop_bbox()

        # Crop is possible if computed bbox is included in pixbuf
        if bbox[2] - bbox[0] < self.width or bbox[3] - bbox[1] < self.height:
            pixbuf = Pixbuf.new(Colorspace.RGB, self._buffer.get_has_alpha(), 8, bbox[2] - bbox[0], bbox[3] - bbox[1])
            self._buffer.copy_area(bbox[0], bbox[1], bbox[2] - bbox[0], bbox[3] - bbox[1], pixbuf, 0, 0)

            return Imagebuf(self.path, pixbuf, pixbuf.get_width(), pixbuf.get_height())

        return self
Ejemplo n.º 5
0
    def _create_thumbnail(self, source_file, thumbnail_filename):
        # Cannot access source; create neither thumbnail nor fail file
        if not os.access(source_file, os.R_OK):
            return False

        try:
            image = Pixbuf.new_from_file_at_scale(source_file, self.thumb_size,
                                                  self.thumb_size, True)
            dest_path = self._get_thumbnail_path(thumbnail_filename)
            success = True
        except GError:
            image = Pixbuf.new(GdkPixbuf.Colorspace.RGB, False, 8, 1, 1)
            dest_path = self._get_fail_path(thumbnail_filename)
            success = False

        width = 0
        height = 0
        try:
            with Image.open(source_file) as img:
                width = img.size[0]
                height = img.size[1]
        except IOError:
            pass

        options = {
            "tEXt::" + self.KEY_URI: str(self._get_source_uri(source_file)),
            "tEXt::" + self.KEY_MTIME:
            str(self._get_source_mtime(source_file)),
            "tEXt::" + self.KEY_SIZE: str(os.path.getsize(source_file))
        }

        if width > 0 and height > 0:
            options["tEXt::" + self.KEY_WIDTH] = str(width)
            options["tEXt::" + self.KEY_HEIGHT] = str(height)

        # First create temporary file and then move it. This avoids problems
        # with concurrent access of the thumbnail cache, since "move" is an
        # atomic operation
        handle, tmp_filename = tempfile.mkstemp(dir=self.base_dir)
        os.close(handle)
        os.chmod(tmp_filename, 0o600)
        image.savev(tmp_filename, "png", list(options.keys()),
                    list(options.values()))
        os.replace(tmp_filename, dest_path)

        return success
Ejemplo n.º 6
0
    def __init__(self, data, size, palette):
        if not data:
            # dummy image
            self.pixbuf = Pixbuf.new(Colorspace.RGB, False, 8,
                                     size[0] * 8 * 2, size[1] * 8 * 2)
            self.pixbuf.fill(0xAAAAAAFF)
            return

        # slice into blocks
        blocks = cut(data, BLOCK)
        # slice block content
        blocks = [cut(b, ROW) for b in blocks]
        # rearrange into blockrows (y/x coordinates)
        blocks = cut(blocks, size[0])

        bytestring = []
        # for each block row
        for y in range(0, size[1]):
            # for each final row
            for i in range(0, int(BLOCK / ROW)):
                # for each block column
                for x in range(0, size[0]):
                    r = blocks[y][x][i]
                    # extract pixels from rows
                    for j in range(4):
                        bytestring.append(r[j] & 0x0F)  # first  (....AAAA)
                        bytestring.append(r[j] >> 4)    # second (BBBB....)

        # apply palette
        result = []
        for i in bytestring:
            result += palette.colors[i]

        # get result in binary format
        result = b''+bytearray(result)

        # create image
        self.pixbuf = Pixbuf.new_from_data(
            result, 0, False, 8,
            8 * size[0], 8 * size[1], 8 * size[0] * 3, None, None)
        self.pixbuf = self.pixbuf.scale_simple(
            8 * size[0] * 2, 8 * size[1] * 2, InterpType.NEAREST)
Ejemplo n.º 7
0
    def color_sample_add(self, x, y):
        colorv = self.cursorSampler(x, y)

        if colorv is None:
            return

        itr = self.color_sample_find_itr(colorv)

        if (itr is None) and (self.lstoreSamples.iter_n_children() < self.MAX_COLOR_SAMPLES):
            pbuf = Pixbuf.new(GdkPixbuf.Colorspace.RGB, False, 8, self.samplePixbufSize, self.samplePixbufSize)
            pbuf.fill(int(colorv))

            itr = self.lstoreSamples.append((colorv,
                'R=%d, G=%d, B=%d (%s)' % (*colorv.get_values(), colorv.hexv),
                pbuf))

            self.ivSamples.select_path(self.lstoreSamples.get_path(itr))

            self.update_sample_count()
            self.compute_average_color()
Ejemplo n.º 8
0
def create_doubled_pixbuf(frompixbuf):
    # создаём "сдвоенную" иконку из обычной

    cx = frompixbuf.get_width()
    cy = frompixbuf.get_height()

    pixbuf = Pixbuf.new(Colorspace.RGB, True, 8, cx, cy)
    pixbuf.fill(0xff00ff00)

    scale = 0.75
    ncx = int(round(cx * scale))
    ncy = int(round(cy * scale))

    frompixbuf.composite(pixbuf, 0, 0, ncx, ncy, 0, 0, scale, scale,
                         InterpType.HYPER, 255)

    cx -= ncx
    cy -= ncy
    frompixbuf.composite(pixbuf, cx, cy, ncx, ncy, cx, cy, scale, scale,
                         InterpType.HYPER, 255)

    return pixbuf
Ejemplo n.º 9
0
## Add a row without own image (easy)
treestore.append(None, [None, "data without own image"])

## Add a row with a stock icon (also easy)
iconpixbuf = Gtk.IconTheme.get_default().load_icon("./images", 16, 0)
treestore.append(None, [iconpixbuf, "data with a stock icon"])

## Add a row with an image from disk (still easy, uncomment if you have a suitable image file)
#loadedpixbuf = Pixbuf.new_from_file_at_size("../../img/logo.png", 125, 125)
#treestore.append(None, [loadedpixbuf, "data with a custom image from disk"])

## Add a row with a flat-painted image (easy, but not always useful...)
from gi.repository import GLib, Gtk, Gdk, GObject

filledpixbuf = Pixbuf.new(Colorspace.RGB, True, 8, 16,
                          16)  ## In fact, it is RGBA
filledpixbuf.fill(0xff9922ff)
treestore.append(None, [filledpixbuf, "data with a custom color filled image"])

## Add a row with a custom-drawn image (cannot do)
import cairo  # one "cairo" is not ...
#from gi.repository import cairo     # ... the other "cairo" (which does not even contain ImageSurface)
drawnpixbuf = filledpixbuf.copy()
img = cairo.ImageSurface(cairo.FORMAT_ARGB32, 50, 50)
cc = cairo.Context(img)
cc.set_source_rgb(.8, .0, .0)  # Cairo uses floats from 0 to 1 for RGB values
cc.rectangle(5, 5, 5, 30)
cc.fill()
cc.set_source_rgb(.5, .9, .2)
cc.move_to(5, 5)  ## (not visible, but this is a minor problem)
cc.line_to(100, 100)
Ejemplo n.º 10
0
def create_blank_pixbuf(size=16):
    pix = Pixbuf.new(Colorspace.RGB, True, 8, size, size)
    pix.fill(0x0)
    return pix
Ejemplo n.º 11
0
    def __init__(self):
        #
        self.emacs = which('emacs')
        self.emacsProcess = None

        self.cfg = Config()

        self.cursorSamplers = (('rbtnCursorPixel', self.get_pixbuf_pixel_color),
                ('rbtnCursorBoxIntenseColor', self.get_pixbuf_intense_color))

        self.cfg.maxPixelSamplerMode = len(self.cursorSamplers) - 1
        self.cfg.load()

        resldr = get_resource_loader()
        uibldr = get_gtk_builder(resldr, 'inktools.ui')

        Gtk.Settings.get_default().set_property('gtk-application-prefer-dark-theme',
            self.DARK_THEME)

        self.sampleFillColor = self.SAMPLE_FILL_DARK if self.DARK_THEME else self.SAMPLE_FILL_LIGHT

        self.db = None
        self.rndchooser = None
        self.stats = None

        # для выбора в случайном выбираторе
        self.includetags = set()
        self.excludetags = set()

        __LOGO = 'inktools.svg'
        #
        # очень важное окно
        #
        self.aboutDialog = uibldr.get_object('aboutDialog')

        logoSize = WIDGET_BASE_HEIGHT * 10
        self.aboutDialog.set_logo(resldr.load_pixbuf(__LOGO, logoSize, logoSize))
        self.aboutDialog.set_program_name(TITLE)
        self.aboutDialog.set_version(TITLE_VERSION)
        self.aboutDialog.set_copyright(COPYRIGHT)
        self.aboutDialog.set_website(URL)
        self.aboutDialog.set_website_label(URL)

        #
        # основное окно
        #
        self.window = uibldr.get_object('inkavailwnd')
        icon = resldr.load_pixbuf_icon_size(__LOGO, Gtk.IconSize.DIALOG, 'computer')
        self.window.set_icon(icon)

        self.headerbar = uibldr.get_object('headerbar')

        self.headerbar.set_title(TITLE_VERSION)

        #
        self.pages, self.pageStatistics, self.pageChooser, self.pageSampler = get_ui_widgets(uibldr,
            'pages', 'pageStatistics', 'pageChooser', 'pageSampler')

        _, self.samplePixbufSize, _ = Gtk.IconSize.lookup(Gtk.IconSize.MENU)

        #
        # страница статистики
        #
        self.nocoloricon = resldr.load_pixbuf_icon_size(
            'nocolor-dark.svg' if self.DARK_THEME else 'nocolor.svg',
            Gtk.IconSize.MENU,
            'dialog-question-symbolic')

        self.totalstatlstore, self.totalstatview = get_ui_widgets(uibldr,
            'totalstatlstore', 'totalstatview')

        self.detailstats = TreeViewShell.new_from_uibuilder(uibldr, 'detailstatsview')
        detailstatswnd = uibldr.get_object('detailstatswnd')

        # костылинг
        detailstatswnd.set_min_content_height(WIDGET_BASE_HEIGHT * 24)

        self.openorgfiledlg = uibldr.get_object('openorgfiledlg')

        #
        # главное меню
        #

        # грязный хакЪ из-за ошибки в Glade 3.22.2, криво генерирующей элементы меню со значками
        # пока это всё оторву - пущай будет человеческое меню, а не гномье
        #mnuFile = uibldr.get_object('mnuFile')
        #img = Gtk.Image.new_from_icon_name('open-menu-symbolic', Gtk.IconSize.MENU)
        #mnuFile.add(img)

        self.mnuFileOpenRecent = uibldr.get_object('mnuFileOpenRecent')

        #
        # страница случайного выбора чернил
        #
        self.randominkname, self.randominktags, self.randominkdesc,\
        self.randominkavail, self.randominkstatus,\
        self.randominkcolorimg, self.randominkcolordesc, self.randominkmaincolor,\
        self.randominkusagecnt = get_ui_widgets(uibldr,
            'randominkname', 'randominktags', 'randominkdesc',
            'randominkavail', 'randominkstatus', 'randominkcolorimg',
            'randominkcolordesc', 'randominkmaincolor', 'randominkusagecnt')
        self.randominkdescbuf = self.randominkdesc.get_buffer()

        uibldr.get_object('randominkusagesw').set_size_request(-1, WIDGET_BASE_HEIGHT * 6)

        self.randominkusageview = TreeViewShell.new_from_uibuilder(uibldr, 'randominkusagetv')
        self.randominkusageview.sortColumn = 0

        self.includetagstxt, self.excludetagstxt, self.tagchooserdlg = get_ui_widgets(uibldr,
            'includetagstxt', 'excludetagstxt', 'tagchooserdlg')

        self.randominkColorPixbuf = Pixbuf.new(GdkPixbuf.Colorspace.RGB,
            False, 8, self.samplePixbufSize, self.samplePixbufSize)

        self.tagchecklistbox = CheckListBox(selectionbuttons=True)
        # костыль
        # потому что set_min_content_width с какого-то хрена не работает
        self.tagchecklistbox.scwindow.set_size_request(WIDGET_BASE_WIDTH * 80, WIDGET_BASE_HEIGHT * 10)
        #self.tagchecklistbox.scwindow.set_min_content_width(WIDGET_BASE_WIDTH * 90)
        #self.tagchecklistbox.scwindow.set_min_content_height(WIDGET_BASE_HEIGHT * 16)

        taglistvbox = self.tagchooserdlg.get_content_area()
        taglistvbox.pack_start(self.tagchecklistbox, True, True, 0)

        self.chosenInk = None

        #
        # страница подбора среднего цвета
        #
        self.btnImageFile = uibldr.get_object('btnImageFile')
        self.btnImageFile.set_current_folder(self.cfg.imageSampleDirectory)

        self.swImgView, self.imgView, self.ebImgView,\
        self.labCursorRGBX, self.imgLens, self.imgCursorColor = get_ui_widgets(uibldr,
            'swImgView', 'imgView', 'ebImgView',
            'labCursorRGBX', 'imgLens', 'imgCursorColor')

        self.pixbuf = None
        self.pixbufPixels = None
        self.pixbufChannels = 0
        self.pixbufRowStride = 0
        self.pixbufCX = 0
        self.pixbufCY = 0

        self.imgViewOX = 0
        self.imgViewOY = 0

        #
        # курсор цветовыбиралки
        #
        self.pixbufCursorImgView = resldr.load_pixbuf('cursor.png', None, None)
        self.cursorImgViewOX = 7
        self.cursorImgViewOY = 7

        # будут присвоены потом, когда ebImgView заимеет Gdk.Window
        self.cursorOutOfImgView = None
        self.cursorImgView = None

        self.ebImgView.add_events(Gdk.EventMask.BUTTON_PRESS_MASK\
            | Gdk.EventMask.POINTER_MOTION_MASK\
            | Gdk.EventMask.LEAVE_NOTIFY_MASK)

        self.lensPixbuf = Pixbuf.new(GdkPixbuf.Colorspace.RGB, False, 8, self.LENS_CX, self.LENS_CY)
        self.lensPixbuf.fill(self.sampleFillColor)
        self.imgLens.set_from_pixbuf(self.lensPixbuf)

        #
        swSamples, self.ivSamples, self.lstoreSamples, self.labNSamples,\
        self.btnSampleRemove = get_ui_widgets(uibldr,
            'swSamples', 'ivSamples', 'lstoreSamples', 'labNSamples',
            'btnSampleRemove')
        self.itrSelectedSample = None

        self.cursorSampler = self.get_pixbuf_pixel_color

        for ix, (rbtnn, sampler) in enumerate(self.cursorSamplers):
            #
            rbtn = uibldr.get_object(rbtnn)
            if ix == self.cfg.pixelSamplerMode:
                rbtn.set_active(True)

            rbtn.connect('toggled', self.rbtnCursorSamplerMode_toggled, ix)

        self.cursorSampler = self.cursorSamplers[self.cfg.pixelSamplerMode][-1]

        self.swImgView.set_min_content_width(WIDGET_BASE_WIDTH * 48)

        swSamples.set_min_content_height(WIDGET_BASE_HEIGHT * 6)
        swSamples.set_size_request(WIDGET_BASE_WIDTH * 24, -1)

        #
        self.cursorColorPixbuf = Pixbuf.new(GdkPixbuf.Colorspace.RGB, False, 8, self.samplePixbufSize, self.samplePixbufSize)
        self.cursorColorPixbuf.fill(self.sampleFillColor)

        self.imgCursorColor.set_from_pixbuf(self.nocoloricon)

        #
        self.averageColorPixbuf = Pixbuf.new(GdkPixbuf.Colorspace.RGB, False, 8, self.samplePixbufSize, self.samplePixbufSize)
        self.averageColorPixbuf.fill(self.sampleFillColor)

        self.imgAverageColor, self.labAverageRGBX, self.btnCopy = get_ui_widgets(uibldr,
            'imgAverageColor','labAverageRGBX','btnCopy')

        self.imgAverageColor.set_from_pixbuf(self.averageColorPixbuf)

        self.clipboard = Gtk.Clipboard.get(Gdk.SELECTION_CLIPBOARD)

        #
        self.window.show_all()
        self.load_window_state()
        self.update_recent_files_menu()

        uibldr.connect_signals(self)

        self.load_db()
Ejemplo n.º 12
0
    def load_db(self):
        self.totalstatview.set_model(None)
        self.totalstatlstore.clear()

        self.detailstats.view.set_model(None)
        self.detailstats.store.clear()

        expand = []

        def __bool_s(b, clr=None):
            st = '√' if clr is None else '<span color="%s"><b>√</b></span>' % clr
            return st if b else ''

        CTODO = '#fd0'
        CNODO = '#c00'
        CDONE = '#0f0'

        try:
            self.db = load_ink_db(self.cfg.databaseFileName)
            self.stats = get_ink_stats(self.db)
            self.rndchooser = None

            # статистика
            if self.stats:
                dfname = os.path.split(self.cfg.databaseFileName)[-1]

                #
                # общая статистика
                #
                totals = self.stats.get_total_result_table()

                for row in totals:
                    self.totalstatlstore.append(row)

                #
                # детали
                #
                for tagstat in self.stats.tagStats:
                    itr = self.detailstats.store.append(None,
                            (None, tagstat.title, '', '', '', '', None, None))

                    expand.append(self.detailstats.store.get_path(itr))

                    _items = tagstat.stats.items()

                    # мелкий костылинг: сортироваться должны только списки,
                    # полученные обработкой директив TAGSTATS

                    if tagstat.issortable:
                        # порядок сортировки: название метки, наличие
                        # на кой чорт питонщики сделали key вместо cmp?
                        # в случае cmp не пришлось бы тратить память на
                        # значение временного ключа сортировки
                        # и фрагментировать кучу
                        def __group_key_f(r):
                            return '%5d%s' % (r[1].available,
                                              self.stats.get_tag_display_name(r[0]).lower())

                        _items = sorted(_items, key=__group_key_f, reverse=True)

                    for tag, nfo in _items:
                        row = (None, self.stats.get_tag_display_name(tag),
                            *nfo.counter_strs(), None,
                            None)

                        subitr = self.detailstats.store.append(itr, row)

                        # конкретные марки чернил сортируем уже по названию в алфавитном порядке
                        for ink in sorted(nfo.inks, key=lambda i: i.text.lower()):
                            if ink.color:
                                pbuf = Pixbuf.new(GdkPixbuf.Colorspace.RGB, False, 8, self.samplePixbufSize, self.samplePixbufSize)
                                pbuf.fill(int(ColorValue.get_rgb32_value(ink.color)))
                            else:
                                pbuf = self.nocoloricon

                            # 'название', 'отсортированный список человекочитаемых меток', 'описание', 'наличие'
                            _inkname, _inktags, _inkdesc, _inkavail = self.stats.get_ink_description(ink)

                            hint = ['<b>%s</b>' % markup_escape_text(_inkname)]

                            if ink.color:
                                hint.append('Цвет: <span color="#%.6x">██</span> %s' % (ink.color,
                                    markup_escape_text(ColorValue.new_from_rgb24(ink.color).get_description())))

                            if _inkdesc:
                                hint.append(markup_escape_text(_inkdesc))

                            if _inkavail:
                                hint.append('В наличии: %s' % markup_escape_text(_inkavail))

                            if ink.done == False:
                                hint.append('Запланирована покупка этих чернил')

                            if ink.missing:
                                hint.append('Отсутствуют данные: %s' % self.stats.get_ink_missing_data_str(ink))

                            bunwanted = ink.done is None
                            self.detailstats.store.append(subitr,
                                    (ink,
                                    ink.text,
                                    # avail
                                    __bool_s(ink.avail, CDONE),
                                    # unavail
                                    __bool_s(not ink.avail, None if bunwanted else CTODO),
                                    # wanted
                                    __bool_s(ink.done == False, CTODO), # прямое сравнение, т.к. иначе None будет воспринято тоже как False
                                    # unwanted
                                    __bool_s(bunwanted, CNODO),
                                    pbuf,
                                    '\n\n'.join(hint)))

                self.rndchooser = RandomInkChooser(self.stats, None, None)

            else:
                dfname = ''

            #
            # метки
            #
            self.tagchecklistbox.clear_items()

            def __add_tag(tagname):
                tagdisp = tagname if tagname not in self.stats.tagNames else self.stats.tagNames[tagname]
                self.tagchecklistbox.add_item(False, tagdisp, tagname)

            # в первую очередь используем только метки, учитываемые в статистике
            ntags = 0

            for tsinfo in self.stats.tagStats:
                for tagname in sorted(tsinfo.tags):
                    __add_tag(tagname)
                    ntags += 1

            # ...а вот если там меток не было - берём весь список меток
            if not ntags:
                for tagname in sorted(self.stats.tags):
                    __add_tag(tagname)

            self.includetags.clear() # пустое множество - выбирать все
            self.excludetags.clear() # пустое множество - не исключать ничего

            self.includetagstxt.set_text(self.INCLUDE_ANY)
            self.excludetagstxt.set_text(self.EXCLUDE_NOTHING)

            #

            self.openorgfiledlg.select_filename(self.cfg.databaseFileName)
            self.headerbar.set_subtitle(dfname)

            self.cfg.add_recent_file(self.cfg.databaseFileName)
            self.update_recent_files_menu()

        finally:
            self.detailstats.view.set_model(self.detailstats.store)

            for path in expand:
                self.detailstats.view.expand_row(path, False)

            self.totalstatview.set_model(self.totalstatlstore)

        self.choose_random_ink()
window.set_size_request(500, 500)

## Add a row without own image (easy)
treestore.append(None, [None, "data without own image"])

## Add a row with a stock icon (also easy)
iconpixbuf = Gtk.IconTheme.get_default().load_icon("folder", 16, 0)
treestore.append(None, [iconpixbuf, "data with a stock icon"])

## Add a row with an image from disk (still easy, uncomment if you have a suitable image file)
#loadedpixbuf = Pixbuf.new_from_file_at_size("../../img/logo.png", 125, 125) 
#treestore.append(None, [loadedpixbuf, "data with a custom image from disk"])

## Add a row with a flat-painted image (easy, but not always useful...)
from gi.repository import Gtk, Gdk
filledpixbuf = Pixbuf.new(Colorspace.RGB, True, 8, 16, 16)  ## In fact, it is RGBA
filledpixbuf.fill(0xff9922ff) 
treestore.append(None, [filledpixbuf, "data with a custom color filled image"])


px = PixbufLoader.new_with_type('pnm')
#color = b'\xee\xff\x2d'
#px.write(b'P6\n\n1 1\n255\n' + color)
#px.write(color)
iconpnm = b"""P2 24 7 25
0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0
0  3  3  3  3  0  0  7  7  7  7  0  0 11 11 11 11  0  0 15 15 15 15  0
0  3  0  0  0  0  0  7  0  0  0  0  0 11  0  0  0  0  0 15  0  0 15  0
0  3  3  3  0  0  0  7  7  7  0  0  0 11 11 11  0  0  0 15 15 15 15  0
0  3  0  0  0  0  0  7  0  0  0  0  0 11  0  0  0  0  0 15  0  0  0  0
0  3  0  0  0  0  0  7  7  7  7  0  0 11 11 11 11  0  0 15  0  0  0  0
Ejemplo n.º 14
0
    def populateTreeStore(self,
                          treeStore,
                          parent_row=None,
                          reset_path=None):  # {{{
        ## without any parent specified, rows will be added to the very left of the TreeView,
        ## otherwise they will become childs thereof
        if parent_row is None:
            if reset_path is not None:
                basepath = reset_path
            else:
                if self.row_prop(self.tsFiles.get_iter_first(),
                                 'rowtype') == 'updir':
                    basepath = self.row_prop(self.tsFiles.get_iter_first(),
                                             'filepath')
                else:
                    raise AttributeError(
                        'Specify either parent_row, reset_path, or ensure the first row is of "updir" type'
                    )
            w('window1').set_title('PlotCommander: %s' % basepath)

            ## On startup, or when the 'updir' node is selected, we update the whole tree.
            ## Initially, it has to be cleared of all rows.
            ## During this operation, its selection will change, but the plots should not be updated so that it is fast.
            self.lockTreeViewEvents = True
            self.tsFiles.clear(
            )  ## TODO: remember the unpacked rows, and also the selected ones
            self.clearAllPlotIcons(
                self.tsFiles.get_iter_first())  ## TODO: obsolete, rm!
            self.lockTreeViewEvents = False

            ## The first node of cleared treeStore will point to the above directory, enabling one to browse whole filesystem
            plotstyleIcon = Pixbuf.new(Colorspace.RGB, True, 8, 10, 10)
            plotstyleIcon.fill(0xffffffff)
            currentIter = treeStore.append(None, [
                basepath,
                self.rowtype_icon('updir'), '..', plotstyleIcon, None, None,
                'updir'
            ])
            ## ^^ FIXME basepath? or os.path.dirname(basepath) ?
            treeStore.append(currentIter, self.dummy_treestore_row)
        elif parent_row is not None and reset_path is None:
            ## If not resetting the whole tree, get the basepath from the parent row
            basepath = treeStore.get_value(parent_row,
                                           self.treeStoreColumns['filepath'])
        else:
            raise AttributeError()

        ## Prepare the lists of paths, column numbers and spreadsheet numbers to be added
        parentrowtype = self.row_prop(parent_row,
                                      'rowtype') if parent_row else 'dir'
        assert not self.rowtype_is_leaf(parentrowtype)
        if parentrowtype == 'dir':  ## Populate a directory with files/subdirs
            ## Get the directory contents and sort it alphabetically
            filenames = os.listdir(basepath)
            filenames = sorted(filenames,
                               key=sort_alpha_numeric.split_alpha_numeric
                               )  # intelligent alpha/numerical sorting
            fileFilterString = w('enFileFilter').get_text().strip()
            itemFullNames = [
                os.path.join(basepath, filename) for filename in filenames
            ]  # add the full path
            # dirs will be listed first and files below; filter the files  ## FIXME: filter only through the file name, not full path!
            itemFullNames =  [f for f in itemFullNames if     self.is_dir(f)] + \
                    [f for f in itemFullNames if (not self.is_dir(f) and (fileFilterString == '' or re.findall(fileFilterString, f)))]
            itemShowNames = [os.path.split(f)[1] for f in itemFullNames
                             ]  # only file name without path will be shown
            columnNumbers = [None] * len(
                itemFullNames
            )  # obviously files/subdirs are assigned no column number
            spreadNumbers = [None] * len(
                itemFullNames)  # nor they are assigned any spreadsheet number
            rowTypes = [self.row_type_from_fullpath(f) for f in itemFullNames]
        elif parentrowtype == 'csvmulticolumn':
            ## Note: Multicolumn means at least 3 columns (i.e. x-column and two or more y-columns)
            data_array, header, parameters = robust_csv_parser.loadtxt(
                basepath, sizehint=10000)
            columnFilterString = w('enColFilter').get_text().strip()
            columnNumbers, header = zip(*[
                n for n in enumerate(header)
                if re.findall(columnFilterString, n[1])
            ])  ## filter the columns
            #FIXME File "/home/dominecf/p/plotcommander/plotcommander.py", line 303, in populateTreeStore
            #columnNumbers, header = zip(*[n for n in enumerate(header) if re.findall(columnFilterString, n[1])]) ## filter the columns
            #ValueError: not enough values to unpack (expected 2, got 0)
            itemFullNames = [basepath] * len(
                header)  # all columns are from one file
            itemShowNames = header  # column numbers are either in file header, or auto-generated
            spreadNumbers = [None] * len(
                header)  # there are no spreadsheets in CSV files
            rowTypes = ['csvcolumn'] * len(header)
        elif parentrowtype == 'opjfile':
            print("parentrowtype == 'opjfile':", basepath)
            opj = self.origin_parse_or_cache(basepath)

            ## Add "graphs" - which show the selected columns in presentation-ready format
            ## Fixme support for multiple opjlayers also here
            def generate_graph_annotation(graph):
                layerNumber = 0  ## Fixme support for multiple opjlayers:    ["graphs"][1].layers[0].curves[3].xColumnName
                legend_box = self.decode_origin_label(
                    graph.layers[0].legend.text, splitrows=True)
                comment = ""
                for legendline in legend_box:  ## the legend may have format as such: ['\l(1) 50B', '\l(2) 48B', ...], needs to be pre-formatted:
                    newline = re.sub(r'\\l\(\d\)\s', '', legendline)
                    if newline == legendline: comment += newline + ' '
                return comment

            itemShowNames = [
                '%s; name: %s; label: %s' % (self.decode_origin_label(
                    graph.name), self.decode_origin_label(
                        graph.label), generate_graph_annotation(graph))
                for graph in opj['graphs']
            ]
            itemFullNames = [basepath] * len(
                itemShowNames)  # all columns are from one file
            columnNumbers = [None] * len(itemShowNames)
            spreadNumbers = list(range(len(itemShowNames)))
            rowTypes = ['opjgraph'] * len(itemShowNames)

            ## Add "columns" - which enable to access all data in the file, including those not used in "graphs"
            for spread in opj['spreads']:
                print(spread.label, self.decode_origin_label(spread.label))
            itemShowNames = itemShowNames + [
                '%s "%s"' % (self.decode_origin_label(
                    spread.name), self.decode_origin_label(spread.label))
                for spread in opj['spreads']
            ]
            itemFullNames = itemFullNames + [basepath] * len(
                itemShowNames)  # all columns are from one file
            columnNumbers = columnNumbers + [None] * len(itemShowNames)
            spreadNumbers = spreadNumbers + list(range(len(itemShowNames)))
            rowTypes = rowTypes + ['opjspread'] * len(itemShowNames)
        elif parentrowtype == 'opjspread':
            opj = self.origin_parse_or_cache(basepath)
            parent_spreadsheet = self.row_prop(parent_row, 'spreadsheet')
            itemShowNames = [
                self.decode_origin_label(column.name)
                for column in opj['spreads'][parent_spreadsheet].columns
            ]
            itemFullNames = [basepath] * len(
                itemShowNames)  # all columns are from one file
            columnNumbers = list(range(len(itemShowNames)))
            spreadNumbers = [parent_spreadsheet] * len(itemShowNames)
            rowTypes = ['opjcolumn'] * len(itemShowNames)
        elif parentrowtype == 'opjgraph':
            opj = self.origin_parse_or_cache(basepath)
            parent_graph = self.row_prop(
                parent_row, 'spreadsheet'
            )  ## The key 'spreadsheet' is misused here to mean 'graph'
            layerNumber = 0  ## Fixme support for multiple opjlayers:    ["graphs"][1].layers[0].curves[3].xColumnName

            ## Try to extract meaningful legend for each curve, assuming the legend box has the same number of lines
            curves = opj['graphs'][parent_graph].layers[layerNumber].curves
            legend_box = self.decode_origin_label(
                opj['graphs'][parent_graph].layers[layerNumber].legend.text,
                splitrows=True)
            legends = []
            for legendline in legend_box:  ## the legend may have format as such: ['\l(1) 50B', '\l(2) 48B', ...], needs to be pre-formatted:
                newline = re.sub(r'\\l\(\d\)\s', '', legendline)
                if newline != legendline: legends.append(newline)
            legends = legends[:len(curves)] + (
                [''] * (len(curves) - len(legends))
            )  ## trim or extend the legends to match the curves

            itemShowNames, itemFullNames, columnNumbers, spreadNumbers = [], [], [], []
            for curve, legend in zip(curves, legends):
                ## FIXME add support for xColumn different than the first one in Spreadsheet, also here
                #print("curve t xCol yCol:", curve.dataName.self.decode_origin_label('utf-8'),
                #curve.xColumnName.self.decode_origin_label('utf-8'), curve.yColumnName.self.decode_origin_label('utf-8'))
                #print([spread.name for spread in opj['spreads']], (curve.dataName[2:]))

                ## Seek the corresponding spreadsheet and column by their name
                spreadsheet_index = [spread.name for spread in opj['spreads']
                                     ].index(curve.dataName[2:])
                spread = opj['spreads'][spreadsheet_index]
                y_column_index = [column.name for column in spread.columns
                                  ].index(curve.yColumnName)
                x_column_index = [column.name for column in spread.columns
                                  ].index(curve.xColumnName)
                #print(curve.dataName[2:].self.decode_origin_label('utf-8'), spreadsheet_index, curve.yColumnName.self.decode_origin_label('utf-8'), y_column_index)

                itemShowNames.append(
                    '%s -> spread %s: column %s (against  %s)' %
                    (legend, self.decode_origin_label(spread.name),
                     self.decode_origin_label(
                         spread.columns[y_column_index].name),
                     self.decode_origin_label(
                         spread.columns[x_column_index].name)))
                itemFullNames.append(basepath)  # all columns are from one file
                columnNumbers.append(y_column_index)
                spreadNumbers.append(spreadsheet_index)
            rowTypes = ['opjcolumn'] * len(
                itemShowNames)  ## TODO or introduce opjgraphcurve ?
        else:
            warnings.warn(
                'Not prepared yet to show listings of this file: %s' %
                parentrowtype)
            return

        ## Go through all items and populate the node
        for itemFullName, itemShowName, columnNumber, spreadNumber, rowtype in \
                zip(itemFullNames, itemShowNames, columnNumbers, spreadNumbers, rowTypes):
            plotstyleIcon = Pixbuf.new(Colorspace.RGB, True, 8, 10, 10)
            plotstyleIcon.fill(0xffffffff)
            currentIter = treeStore.append(parent_row, [
                itemFullName,
                self.rowtype_icon(rowtype), itemShowName, plotstyleIcon,
                columnNumber, spreadNumber, rowtype
            ])
            if not self.rowtype_is_leaf(
                    rowtype):  ## TODO row---> parentrowtype
                treeStore.append(
                    currentIter, self.dummy_treestore_row
                )  # shows the "unpacking arrow" left of the item