def get_params_metadata(self): return [ Bunch.Bunch(name='usecrop', type=self._bool, valid=set([True, False]), default=True, description="Use center crop of image for speed"), ## Bunch.Bunch(name='hensa_lo', type=float, default=35.0, ## description="Low subtraction factor"), ## Bunch.Bunch(name='hensa_hi', type=float, default=90.0, ## description="High subtraction factor"), ]
def select_child_cb(self, layout, event, widget): ex = event.x ey = event.y x, y, width, height = widget.get_allocation() dx, dy = ex - x, ey - y self.selected_child = Bunch.Bunch(widget=widget, cr=self.setup_cr(self.bin_window), dx=x, dy=y, wd=width, ht=height) return False
def process_common_params(widget, inparams): params = Bunch.Bunch(name=None, height=-1, width=-1, xpos=-1, ypos=-1, spacing=None, wexp=None, hexp=None) params.update(inparams) if params.name: widgetDict[params.name] = widget wexp, hexp = params.wexp, params.hexp # User is specifying the size of the widget if isinstance(widget, Widgets.WidgetBase): if params.spacing is not None: widget.set_spacing(params.spacing) # directive to size widget if (params.width >= 0) or (params.height >= 0): if params.width < 0: width = widget.get_size()[0] if wexp is None: wexp = 8 else: width = params.width if wexp is None: wexp = 1 | 4 if params.height < 0: height = widget.get_size()[1] if hexp is None: hexp = 8 else: height = params.height if hexp is None: hexp = 1 | 4 widget.resize(width, height) # specify expansion policy of widget if (wexp is not None) or (hexp is not None): if wexp is None: wexp = 0 if hexp is None: hexp = 0 widget.cfg_expand(wexp, hexp) # User wants to place window somewhere if params.xpos >= 0: widget.move(params.xpos, params.ypos)
def add_channel_cb(self, viewer, channel): settings = channel.settings settings.getSetting('cuts').add_callback('set', self.change_range_cb, channel.fitsimage, self.colorbar) chname = channel.name info = Bunch.Bunch(chname=chname, channel=channel) self.channel[chname] = info fi = channel.fitsimage rgbmap = fi.get_rgbmap() rgbmap.add_callback('changed', self.rgbmap_cb, channel)
def __init__(self, factory, duration=0.0): super(Timer, self).__init__() self.tfact = factory self.duration = duration # For storing aritrary data with timers self.data = Bunch.Bunch() self.timer = HeapTimer(self.tfact.timer_heap, 0, self._expired_cb) for name in ('expired', 'canceled'): self.enable_callback(name)
def add_channel(self, viewer, chinfo): chname = chinfo.name info = Bunch.Bunch(chname=chname) sw = self._create_header_window(info) self.nb.addTab(sw, chname) index = self.nb.indexOf(sw) info.setvals(nbindex=index) self.channel[chname] = info fitsimage = chinfo.fitsimage fitsimage.set_callback('image-set', self.new_image_cb, info)
def add_channel(self, viewer, channel): if not self.gui_up: return sw, winfo = self._create_info_window() chname = channel.name self.nb.add_widget(sw, title=chname) index = self.nb.index_of(sw) # noqa info = Bunch.Bunch(widget=sw, winfo=winfo, mode_w=None, chinfo=channel) channel.extdata._info_info = info winfo.channel.set_text(chname) winfo.cut_low.add_callback('activated', self.cut_levels, channel, info) winfo.cut_high.add_callback('activated', self.cut_levels, channel, info) winfo.cut_levels.add_callback('activated', self.cut_levels, channel, info) winfo.auto_levels.add_callback('activated', self.auto_levels, channel, info) winfo.cut_new.add_callback('activated', self.set_autocuts_cb, channel, info) winfo.zoom_new.add_callback('activated', self.set_autozoom_cb, channel, info) winfo.center_new.add_callback('activated', self.set_autocenter_cb, channel, info) winfo.follow_new.add_callback('activated', self.set_follow_cb, channel, info) winfo.raise_new.add_callback('activated', self.set_raise_cb, channel, info) fitsimage = channel.fitsimage fitssettings = fitsimage.get_settings() for name in ['cuts']: fitssettings.get_setting(name).add_callback( 'set', self.cutset_cb, channel) for name in ['scale']: fitssettings.get_setting(name).add_callback( 'set', self.zoomset_cb, channel) fitssettings.get_setting('autocuts').add_callback( 'set', self.autocuts_cb, channel) fitssettings.get_setting('autozoom').add_callback( 'set', self.autozoom_cb, channel) fitssettings.get_setting('autocenter').add_callback( 'set', self.autocenter_cb, channel) fitssettings.get_setting('switchnew').add_callback( 'set', self.follow_cb, channel) fitssettings.get_setting('raisenew').add_callback( 'set', self.raise_cb, channel) self.set_info(info, fitsimage)
def register_viewer(vclass): """Register a channel viewer. Parameters ---------- vclass : :py:class The class of the viewer. """ global viewer_db viewer_db[vclass.vname] = Bunch.Bunch(name=vclass.vname, vclass=vclass, priority=0)
def _parse_params(self, url): params = {} regex = r'^.*?\%\((\w+)\)([sfd])(.*)$' match = re.match(regex, url) while match: key, typ, sfx = match.groups() idx = ['s', 'd', 'f'].index(typ) cvt = (str, int, float)[idx] params[key] = Bunch.Bunch(name=key, convert=cvt) match = re.match(regex, sfx) return params
def info_xy(self, data_x, data_y, settings): # Get the value under the data coordinates try: value = self.get_data_xy(int(data_x), int(data_y)) except Exception as e: value = None info = Bunch.Bunch(itype='base', data_x=data_x, data_y=data_y, x=data_x, y=data_y, value=value) return info
def get_scaled_cutout(self, x1, y1, x2, y2, scale_x, scale_y, method='basic', logger=None): if method == 'basic': return self.get_scaled_cutout_basic(x1, y1, x2, y2, scale_x, scale_y) data = self._get_data() newdata, (scale_x, scale_y) = trcalc.get_scaled_cutout_basic( data, x1, y1, x2, y2, scale_x, scale_y, interpolation=method) res = Bunch.Bunch(data=newdata, scale_x=scale_x, scale_y=scale_y) return res
def add_channel(self, viewer, chinfo): chname = chinfo.name info = Bunch.Bunch(chname=chname) widget = self._create_header_window(info) self.nb.append_page(widget, gtk.Label(chname)) index = self.nb.page_num(widget) info.setvals(nbindex=index) self.channel[chname] = info fitsimage = chinfo.fitsimage fitsimage.set_callback('image-set', self.new_image_cb, info)
def start_resize_cb(self, widget, event, subwin): ex, ey = event.x_root, event.y_root x, y = self.get_widget_position(subwin.frame) subwin.x, subwin.y = x, y self.selected_child = Bunch.Bunch(subwin=subwin, action='resize', x_origin=x, y_origin=y, dx=ex, dy=ey) return True
def insert_thumbnail(self, imgwin, thumbkey, thumbname, chname, name, path, metadata): pixmap = QtGui.QPixmap.fromImage(imgwin) imglbl = MyLabel() imglbl.setPixmap(pixmap) imglbl.thumbs_cb = lambda: self.fv.switch_name(chname, name, path=path) text = self.query_thumb(thumbkey, name, metadata) imglbl.setToolTip(text) widget = QtGui.QWidget() #vbox = QtGui.QGridLayout() vbox = QtGui.QVBoxLayout() vbox.setContentsMargins(0, 0, 0, 0) vbox.setSpacing(0) widget.setLayout(vbox) namelbl = QtGui.QLabel(thumbname) namelbl.setAlignment(QtCore.Qt.AlignLeft) namelbl.setAlignment(QtCore.Qt.AlignHCenter) ## vbox.addWidget(namelbl, 0, 0) ## vbox.addWidget(imglbl, 1, 0) vbox.addWidget(namelbl, stretch=0) vbox.addWidget(imglbl, stretch=0) widget.setSizePolicy( QtGui.QSizePolicy(QtGui.QSizePolicy.Fixed, QtGui.QSizePolicy.Fixed)) #widget.show() bnch = Bunch.Bunch(widget=widget, image=imgwin, layout=vbox, imglbl=imglbl, name=name, chname=chname, path=path, pixmap=pixmap) self.thumbDict[thumbkey] = bnch self.thumbList.append(thumbkey) self.w.thumbs.addWidget(widget, self.thumbRowCount, self.thumbColCount) self.thumbColCount = (self.thumbColCount + 1) % self.thumbNumCols if self.thumbColCount == 0: self.thumbRowCount += 1 #self.w.thumbs.show() # force scroll to bottom of thumbs ## rect = self.w.thumbs_w.geometry() ## x1, y1, x2, y2 = rect.getCoords() ## self.w.thumbs_scroll.ensureVisible(x1, y1) #self.w.thumbs_scroll.show() self.logger.debug("added thumb for %s" % (thumbname))
def _get_thumb_image(self, channel, info, image): # Get any previously stored thumb information in the image info thumb_extra = info.setdefault('thumb_extras', Bunch.Bunch()) # Choice [A]: is there a thumb image attached to the image info? if 'rgbimg' in thumb_extra: # yes return thumb_extra.rgbimg thumbpath = self.get_thumbpath(info.path) # Choice [B]: is the full image available to make a thumbnail? if image is None: try: image = channel.get_loaded_image(info.name) except KeyError: pass if image is not None: try: thmb_image = self._regen_thumb_image(image, None) thumb_extra.rgbimg = thmb_image thumb_extra.time_update = time.time() return thmb_image except Exception as e: self.logger.warning("Error generating thumbnail: %s" % (str(e))) thmb_image = RGBImage.RGBImage() thmb_image.set(name=info.name, placeholder=False) # Choice [C]: is there a cached thumbnail image on disk we can use? if (thumbpath is not None) and os.path.exists(thumbpath): try: # try to load the thumbnail image thmb_image.load_file(thumbpath) thmb_image = self._regen_thumb_image(thmb_image, None) thumb_extra.rgbimg = thmb_image return thmb_image except Exception as e: self.logger.warning("Error loading thumbnail: %s" % (str(e))) # Choice [D]: load a placeholder image tmp_path = os.path.join(icondir, 'fits.png') thmb_image.load_file(tmp_path) thmb_image.set(path=None, placeholder=True) return thmb_image
def info_xy(self, data_x, data_y, settings): ct = self.get('ct', None) # Get the value under the data coordinates try: # We report the value across the pixel, even though the coords # change halfway across the pixel x, y = int(data_x + 0.5), int(data_y + 0.5) value = self.get_data_xy(x, y) # Mapping from bytescaled values back to original values value = iis.wcs_pix_transform(ct, value) except Exception as e: self.logger.error("Exception getting value at %d,%d: %s" % (x, y, str(e))) value = None # Calculate WCS RA, if available try: # Subtract offsets of data in framebuffer and add offsets of # rect beginning in source data_x = data_x - (ct.dx - 1) + (ct.sx - 1) data_y = data_y - (ct.dy - 1) + (ct.sy - 1) #ra_deg, dec_deg = wcs_coord_transform(ct, data_x, data_y) #ra_txt, dec_txt = self.wcs.deg2fmt(ra_deg, dec_deg, 'str') ra_txt = 'BAD WCS' dec_txt = 'BAD WCS' except Exception as e: self.logger.warning("Bad coordinate conversion: %s" % (str(e))) ra_txt = 'BAD WCS' dec_txt = 'BAD WCS' # Note: FITS coordinates are 1-based, whereas numpy FITS arrays # are 0-based ra_lbl, dec_lbl = unichr(945), unichr(948) fits_x, fits_y = data_x + 1, data_y + 1 info = Bunch.Bunch(itype='astro', data_x=data_x, data_y=data_y, fits_x=fits_x, fits_y=fits_y, x=fits_x, y=fits_y, ra_txt=ra_txt, dec_txt=dec_txt, ra_lbl=ra_lbl, dec_lbl=dec_lbl, value=value) return info
def add_channel(self, viewer, channel): fitsimage = channel.fitsimage panimage = self._create_pan_image(fitsimage) chname = channel.name iw = Viewers.GingaViewerWidget(panimage) iw.resize(self._wd, self._ht) self.nb.add_widget(iw) index = self.nb.index_of(iw) paninfo = Bunch.Bunch(panimage=panimage, widget=iw, pancompass=None, panrect=None) channel.extdata._pan_info = paninfo # Extract RGBMap object from main image and attach it to this # pan image rgbmap = fitsimage.get_rgbmap() panimage.set_rgbmap(rgbmap) rgbmap.add_callback('changed', self.rgbmap_cb, panimage) fitsimage.copy_attributes(panimage, ['cutlevels']) fitssettings = fitsimage.get_settings() pansettings = panimage.get_settings() xfrmsettings = ['flip_x', 'flip_y', 'swap_xy'] if self.settings.get('rotate_pan_image', False): xfrmsettings.append('rot_deg') fitssettings.shareSettings(pansettings, xfrmsettings) for key in xfrmsettings: pansettings.getSetting(key).add_callback('set', self.settings_cb, fitsimage, channel, paninfo, 0) fitssettings.shareSettings(pansettings, ['cuts']) pansettings.getSetting('cuts').add_callback('set', self.settings_cb, fitsimage, channel, paninfo, 1) zoomsettings = [ 'zoom_algorithm', 'zoom_rate', 'scale_x_base', 'scale_y_base' ] fitssettings.shareSettings(pansettings, zoomsettings) for key in zoomsettings: pansettings.getSetting(key).add_callback('set', self.zoom_ext_cb, fitsimage, channel, paninfo) fitsimage.add_callback('redraw', self.redraw_cb, channel, paninfo) self.logger.debug("channel '%s' added." % (channel.name))
def insert_thumbnail(self, imgwin, thumbkey, thumbname, chname, name, path, thumbpath, metadata, image_future): self.logger.debug("inserting thumb %s" % (thumbname)) # make a context menu menu = self._mk_context_menu(thumbkey, chname, name, path, image_future) thumbw = Widgets.Image(native_image=imgwin, menu=menu, style='clickable') thumbw.resize(self.thumb_width, self.thumb_width) # set the load callback thumbw.add_callback('activated', lambda w: self.load_file(thumbkey, chname, name, path, image_future)) # make a tool tip text = self.query_thumb(thumbkey, name, metadata) thumbw.set_tooltip(text) vbox = Widgets.VBox() vbox.set_margins(0, 0, 0, 0) vbox.set_spacing(0) namelbl = Widgets.Label(text=thumbname, halign='left') vbox.add_widget(namelbl, stretch=0) vbox.add_widget(thumbw, stretch=0) # special hack for Qt widgets vbox.cfg_expand(0, 0) bnch = Bunch.Bunch(widget=vbox, image=thumbw, name=name, imname=name, namelbl=namelbl, chname=chname, path=path, thumbpath=thumbpath, image_future=image_future) with self.thmblock: self.thumb_dict[thumbkey] = bnch self.thumb_list.append(thumbkey) sort_order = self.settings.get('sort_order', None) if sort_order: self.thumb_list.sort() self.reorder_thumbs() return self.w.thumbs.add_widget(vbox, self.thumb_row_count, self.thumb_col_count) self.thumb_col_count = (self.thumb_col_count + 1) % self.thumb_num_cols if self.thumb_col_count == 0: self.thumb_row_count += 1 self._auto_scroll() self.logger.debug("added thumb for %s" % (name))
def _validate_target(name, ra, dec, equinox, logger): logger.debug('validate name={}, ra={}, dec={}, equinox={}'.format( name, ra, dec, equinox)) ra, ra_valid = validate_ra(ra) dec, dec_valid = validate_dec(dec) name, name_valid = validate_name(name) equinox = float(equinox) valid = False if False in [ra_valid, dec_valid, name_valid] else True return Bunch.Bunch(name=name, ra=ra, dec=dec, equinox=equinox, valid=valid)
def highlight_cursor(self, obj): if self.curstar: bnch = self.curstar if bnch.obj == obj: # <-- we are already highlighting this object return True # delete the highlight ring of the former cursor object self.unhighlight_object(bnch.obj, 'cursor') self.highlight_object(obj, 'cursor', self.color_cursor) self.curstar = Bunch.Bunch(obj=obj) self.canvas.redraw()
def set_card(self, key, value, comment=None): try: bnch = super(Header, self).__getitem__(key) bnch.value = value if not (comment is None): bnch.comment = comment except KeyError: if comment is None: comment = '' bnch = Bunch.Bunch(key=key, value=value, comment=comment) self.keyorder.append(key) super(Header, self).__setitem__(key, bnch) return bnch
def __init__(self, duration=0.0): """Create a timer set to expire after `duration` sec. """ super(Timer, self).__init__() self.duration = duration # For storing aritrary data with timers self.data = Bunch.Bunch() self._timer = None for name in ('expired', 'canceled'): self.enable_callback(name)
def __init__(self, logger, ev_quit): Widgets.Application.__init__(self, logger=logger) GwMain.GwMain.__init__(self, logger=logger, ev_quit=ev_quit, app=self) self.w = Bunch.Bunch() self.layout_file = None # For now... self.controller = self # dictionary of plugins self.plugins = {} self.plugin_lst = [] self._plugin_sort_method = self.get_plugin_menuname
def __init__(self, factory): super(Timer, self).__init__() self.tfact = factory # For storing aritrary data with timers self.data = Bunch.Bunch() self.deadline = 0.0 self.interval = 0.0 self.lock = threading.RLock() for name in ('expired', 'cancelled'): self.enable_callback(name)
def __init__(self, fv, fitsimage): super(LocalPlugin, self).__init__() self.fv = fv self.logger = fv.logger self.fitsimage = fitsimage # find our channel info if self.fitsimage is not None: self.chname = self.fv.get_channelName(self.fitsimage) self.chinfo = self.fv.get_channelInfo(self.chname) # Holds GUI widgets self.w = Bunch.Bunch()
def calc_fwhm_gaussian(self, arr1d, medv=None, gauss_fn=None): """FWHM calculation on a 1D array by using least square fitting of a gaussian function on the data. arr1d is a 1D array cut in either X or Y direction on the object. """ if gauss_fn is None: gauss_fn = self.gaussian N = len(arr1d) X = np.array(list(range(N))) Y = arr1d # Fitting works more reliably if we do the following # a. subtract sky background if medv is None: medv = get_median(Y) Y = Y - medv maxv = Y.max() # b. clamp to 0..max (of the sky subtracted field) Y = Y.clip(0, maxv) # Fit a gaussian p0 = [0, N - 1, maxv] # Inital guess # Distance to the target function errfunc = lambda p, x, y: gauss_fn(x, p) - y # noqa # Least square fit to the gaussian with self.lock: # NOTE: without this mutex, optimize.leastsq causes a fatal error # sometimes--it appears not to be thread safe. # The error is: # "SystemError: null argument to internal routine" # "Fatal Python error: GC object already tracked" p1, success = optimize.leastsq(errfunc, p0[:], args=(X, Y)) if not success: raise IQCalcError("FWHM gaussian fitting failed") mu, sdev, maxv = p1 self.logger.debug("mu=%f sdev=%f maxv=%f" % (mu, sdev, maxv)) # Now that we have the sdev from fitting, we can calculate FWHM fwhm = 2.0 * np.sqrt(2.0 * np.log(2.0)) * sdev # some routines choke on numpy values and need "pure" Python floats # e.g. when marshalling through a remote procedure interface fwhm = float(fwhm) mu = float(mu) sdev = float(sdev) maxv = float(maxv) res = Bunch.Bunch(fwhm=fwhm, mu=mu, sdev=sdev, maxv=maxv, fit_fn=gauss_fn, fit_args=[mu, sdev, maxv]) return res
def add_channel(self, viewer, chinfo): panimage = self._create_pan_image() chname = chinfo.name iw = panimage.get_widget() # wrap widget iw = Widgets.wrap(iw) self.nb.add_widget(iw) index = self.nb.index_of(iw) paninfo = Bunch.Bunch(panimage=panimage, widget=iw, pancompass=None, panrect=None, nbindex=index) self.channel[chname] = paninfo # Extract RGBMap object from main image and attach it to this # pan image fitsimage = chinfo.fitsimage rgbmap = fitsimage.get_rgbmap() panimage.set_rgbmap(rgbmap, redraw=False) rgbmap.add_callback('changed', self.rgbmap_cb, panimage) fitsimage.copy_attributes(panimage, ['cutlevels']) fitsimage.add_callback('image-set', self.new_image_cb, chinfo, paninfo) fitsimage.add_callback('redraw', self.panset, chinfo, paninfo) fitssettings = fitsimage.get_settings() pansettings = panimage.get_settings() zoomsettings = [ 'zoom_algorithm', 'zoom_rate', 'scale_x_base', 'scale_y_base' ] fitssettings.shareSettings(pansettings, zoomsettings) for key in zoomsettings: pansettings.getSetting(key).add_callback('set', self.zoom_cb, fitsimage, chinfo, paninfo) xfrmsettings = ['flip_x', 'flip_y', 'swap_xy', 'rot_deg'] fitssettings.shareSettings(pansettings, xfrmsettings) for key in xfrmsettings: pansettings.getSetting(key).add_callback('set', self.redraw_cb, fitsimage, chinfo, paninfo, 0) fitssettings.shareSettings(pansettings, ['cuts']) pansettings.getSetting('cuts').add_callback('set', self.redraw_cb, fitsimage, chinfo, paninfo, 1) self.logger.debug("channel %s added." % (chinfo.name))
def load_plugin(self, pluginName, moduleName, className, wsName, tabName): widget = QtGui.QWidget() # Record plugin info canonicalName = pluginName.lower() bnch = Bunch.Bunch(caseless=True, name=canonicalName, officialname=pluginName, modulename=moduleName, classname=className, wsname=wsName, tabname=tabName, widget=widget) self.plugins[pluginName] = bnch try: module = self.mm.loadModule(moduleName) # Look up the module and class module = self.mm.getModule(moduleName) klass = getattr(module, className) # instantiate the class pluginObj = klass(self.model, self, self.controller, self.logger) # Save a reference to the plugin object so we can use it # later self.plugins[pluginName].setvals(obj=pluginObj) # Build the plugin GUI pluginObj.build_gui(widget) # Add the widget to a workspace and save the tab name in # case we need to delete the widget later on. dsTabName = self.ds.add_page(wsName, widget, 2, tabName) self.plugins[pluginName].setvals(wsTabName=dsTabName) # Start the plugin pluginObj.start() except Exception, e: errstr = "Plugin '%s' failed to initialize: %s" % ( className, str(e)) self.logger.error(errstr) try: (type, value, tb) = sys.exc_info() tb_str = "\n".join(traceback.format_tb(tb)) self.logger.error("Traceback:\n%s" % (tb_str)) except Exception, e: tb_str = "Traceback information unavailable." self.logger.error(tb_str)
def start_resize_cb(self, widget, event, subwin): self.update_subwin_size(subwin) x_root, y_root = event.x_root, event.y_root x, y = widget.translate_coordinates(self, event.x, event.y) rect = subwin.frame.get_allocation() x1, y1, wd, ht = rect.x, rect.y, rect.width, rect.height x2, y2 = x1 + wd, y1 + ht subwin.x, subwin.y = x1, y1 subwin.width, subwin.height = wd, ht updates = set([]) if abs(x - x2) < self.delta_px: # right side if abs(y - y2) < self.delta_px: # lower right corner origin = 'lr' updates = set(['w', 'h']) elif abs(y - y1) < self.delta_px: origin = 'ur' updates = set(['w', 'h', 'y']) else: origin = 'r' updates = set(['w']) elif abs(x - x1) < self.delta_px: # left side if abs(y - y2) < self.delta_px: # lower left corner origin = 'll' updates = set(['w', 'h', 'x']) elif abs(y - y1) < self.delta_px: origin = 'ul' updates = set(['w', 'h', 'x', 'y']) else: origin = 'l' updates = set(['w', 'x']) elif abs(y - y2) < self.delta_px: # bottom origin = 'b' updates = set(['h']) else: origin = 't' updates = set(['h', 'y']) self.selected_child = Bunch.Bunch(subwin=subwin, action='resize', x_origin=x1, y_origin=y1, wd=wd, ht=ht, x_root=x_root, y_root=y_root, origin=origin, updates=updates) return True
def insert_thumbnail(self, imgwin, thumbkey, thumbname, chname, name, path, thumbpath, metadata, image_loader): imgwin.set_property("has-tooltip", True) imgwin.connect("query-tooltip", self._mktt(thumbkey, name, metadata)) vbox = gtk.VBox(spacing=0) vbox.pack_start(gtk.Label(thumbname), expand=False, fill=False, padding=0) evbox = gtk.EventBox() evbox.add(imgwin) evbox.connect( "button-press-event", lambda w, e: self.load_file( thumbkey, chname, name, path, image_loader)) vbox.pack_start(evbox, expand=False, fill=False) vbox.show_all() bnch = Bunch.Bunch(widget=vbox, evbox=evbox, imname=name, thumbname=thumbname, chname=chname, path=path, thumbpath=thumbpath) with self.thmblock: if self.thumbColCount == 0: hbox = gtk.HBox(homogeneous=True, spacing=self.thumbSep) self.w.thumbs.pack_start(hbox) self.thumbRowList.append(hbox) else: hbox = self.thumbRowList[-1] hbox.pack_start(bnch.widget) self.thumbColCount = (self.thumbColCount + 1) % self.thumbNumCols self.w.thumbs.show_all() self.thumbDict[thumbkey] = bnch self.thumbList.append(thumbkey) # force scroll to bottom of thumbs, if checkbox is set scrollp = self.w.auto_scroll.get_active() if scrollp: adj_w = self.w.thumbs_scroll.get_vadjustment() max = adj_w.get_upper() adj_w.set_value(max) self.logger.debug("added thumb for %s" % (thumbname))