def mouseReleaseEvent(self, event): if not self.rubberBand.size().isEmpty(): rect = QRect(self.rubberBand.pos(), self.rubberBand.size()) rect.moveLeft(rect.left() - (self.width() - self.pixmap().width()) / 2.0) rect.moveTop(rect.top() - (self.height() - self.pixmap().height()) / 2.0) self.currentSelection = rect self.copySelectionMenu.popup(QCursor.pos()) else: self.copyMenu.popup(QCursor.pos()) self.rubberBand.hide()
def __init__(self, url): QWidget.__init__(self, None, Qt.ToolTip) self.url = url self.font = QFont(QApplication.font(self)) self.font.setPointSize(8) desktop = QApplication.desktop().availableGeometry(self) cursor = QCursor.pos() rect = QRect(cursor + QPoint(-10, 10), QSize(240,180 + QFontMetrics(self.font).height())) if rect.left() < desktop.left(): rect.moveLeft(desktop.left()) if rect.right() > desktop.right(): rect.moveRight(cursor.x() - 10) if rect.bottom() > desktop.bottom(): rect.moveBottom(cursor.y() - 10) self.setGeometry(rect) self.pixmap = None self.progress = 0 self.title = unicode(self.url) self.webView = QWebView() self.webView.page().mainFrame().setScrollBarPolicy(Qt.Horizontal, Qt.ScrollBarAlwaysOff) self.webView.page().mainFrame().setScrollBarPolicy(Qt.Vertical, Qt.ScrollBarAlwaysOff) self.webView.resize(1024,768) self.webView.load(QUrl(url)) self.timer = QTimer(self) self.connect(self.timer, SIGNAL("timeout()"), self.refresh) self.timer.start(3000) self.connect(self.webView, SIGNAL("loadFinished(bool)"), self.refresh) self.connect(self.webView, SIGNAL("loadProgress(int)"), self.updateProgress) self.connect(self.webView, SIGNAL("urlChanged(const QUrl&)"), self.newUrl) self.connect(self.webView, SIGNAL("titleChanged(const QString&)"), self.newTitle)
def paint(self, painter, option, index): """ Draws the widget Arguments: painter -- a QPainter option -- a QStyleOptionView index -- a QModelIndex """ # Retrieve the data model = index.model() record = model.data(index) text = record.toString() zoteroItem = zoteroCache[unicode(text)] l = zoteroItem.full_format().split(u"\n") if zoteroItem.fulltext == None: pixmap = self.noPdfPixmap else: pixmap = self.pdfPixmap # Choose the colors self.palette = self.qnotero.ui.listWidgetResults.palette() if option.state & QStyle.State_MouseOver: background = self.palette.Highlight foreground = self.palette.HighlightedText _note = zoteroItem.get_note() if _note != None: self.qnotero.showNoteHint() else: self.qnotero.hideNoteHint() elif option.state & QStyle.State_Selected: background = self.palette.Dark foreground = self.palette.WindowText else: background = self.palette.Base foreground = self.palette.WindowText # Draw the frame _rect = option.rect.adjusted(self._margin, self._margin, \ -2*self._margin, -self._margin) pen = painter.pen() pen.setColor(self.palette.color(background)) painter.setPen(pen) painter.setBrush(self.palette.brush(background)) painter.drawRoundedRect(_rect, self.roundness, self.roundness) font = painter.font pen = painter.pen() pen.setColor(self.palette.color(foreground)) painter.setPen(pen) # Draw icon _rect = QRect(option.rect) _rect.moveBottom(_rect.bottom() + 0.5 * self.dy) _rect.moveLeft(_rect.left() + 0.5 * self.dy) _rect.setHeight(self.pixmapSize) _rect.setWidth(self.pixmapSize) painter.drawPixmap(_rect, pixmap) # Draw the text _rect = option.rect.adjusted(self.pixmapSize+self.dy, 0.5*self.dy, \ -self.dy, 0) f = [self.tagFont, self.italicFont, self.regularFont, \ self.boldFont] l.reverse() while len(l) > 0: s = l.pop() if len(f) > 0: painter.setFont(f.pop()) painter.drawText(_rect, Qt.AlignLeft, s) _rect = _rect.adjusted(0, self.dy, 0, 0)
class PlottingThread(QThread): def __init__(self, parent): QThread.__init__(self) self.result = None self.parent = parent self._stopped = False self.mutex = QMutex() self.filePrefix = None self.fileFormat = None self.wallColoring = None self.cellColoring = None self.pointColoring = None self.extraDrawing = [] self.pointSize = None self.pointLineColor = None self.pointLineThickness = None self.ellipsisDraw = None self.overSampling = None self.wallThickness = None self.bgColor = None self.loading = False self._crop = QRect(0,0,1,1) self._pix = None self._end_image_plot = False self._loading_arguments = {} self.retryObject = None def end_step(self): return len(self.result)+1 def stop(self, value = True): self.mutex.lock() self._stopped = value self.mutex.unlock() def stopped(self): self.mutex.lock() val = self._stopped self.mutex.unlock() return val def nextImage(self): QCoreApplication.postEvent(self.parent, NextImageEvent()) def abort(self, reason, **others): e = AbortPlottingEvent(reason) if others: e.others = others QCoreApplication.postEvent(self.parent, e) def finished(self): if self.loading: QCoreApplication.postEvent(self.parent, FinishLoadingEvent()) self.loading = False else: QCoreApplication.postEvent(self.parent, FinishPlottingEvent()) def image_ready(self): QCoreApplication.postEvent(self.parent, ImageReadyPlottingEvent()) def update_nb_images(self, nb): QCoreApplication.postEvent(self.parent, UpdateNbImageEvent(nb)) @property def crop_left(self): return self._crop.left() @crop_left.setter def crop_left(self, value): self._crop.moveLeft(int(value)) @property def crop_top(self): return self._crop.top() @crop_top.setter def crop_top(self, value): self._crop.moveTop(int(value)) @property def crop_width(self): return self._crop.width() @crop_width.setter def crop_width(self, value): self._crop.setWidth(int(value)) @property def crop_height(self): return self._crop.height() @crop_height.setter def crop_height(self, value): self._crop.setHeight(int(value)) def reset_crop(self): self._crop = QRect(QPoint(0,0), self.img_size) @property def crop(self): return QRect(self._crop) @crop.deleter def crop(self): self.reset_crop() @property def end_image_plot(self): ''' If true, plot the growth data on the end image rather than the start image of the growth calculation. ''' return self._end_image_plot @end_image_plot.setter def end_image_plot(self, value): self._end_image_plot = bool(value) @property def pix(self): '''Thread-safe image storage.''' self.mutex.lock() pix = self._pix self.mutex.unlock() return pix @pix.setter def pix(self, value): self.mutex.lock() self._pix = value self.mutex.unlock() def render_valid(self): if self.result is None: log_debug("result is None") return False if self.parent is None: log_debug("parent is None") return False if self.ellipsisDraw is None: log_debug("ellipsisDraw is None") return False if self.cellColoring is None: log_debug("cellColoring is None") return False if self.wallColoring is None: log_debug("wallColoring is None") return False if self.pointColoring is None: log_debug("pointColoring is None") return False if self.pointSize is None: log_debug("pointSize is None") return False if self.pointLineThickness is None: log_debug("pointSize is None") return False if self.pointLineColor is None: log_debug("pointSize is None") return False if self.wallThickness is None: log_debug("wallThickness is None") return False if self.overSampling is None: log_debug("overSampling is None") return False if self.bgColor is None: log_debug("bgColor is None") return False return True def valid(self): if self.filePrefix is None: log_debug("filePrefix is None") return False if not self.filePrefix: log_debug("filePrefix is Empty") return False if self.fileFormat is None: log_debug("fileFormat is None") return False return self.render_valid() def drawImage(self, imageid): cache = image_cache.cache cellColoring = self.cellColoring wallColoring = self.wallColoring pointColoring = self.pointColoring ellipsisDraw = self.ellipsisDraw overSampling = self.overSampling extraDrawing = self.extraDrawing bgColor = self.bgColor.rgb() result = self.result if self.result_type == "Data": data = result img_name = result.images_name[imageid] else: data = result.data img_name = result.images[imageid] #scale = data.images_scale[img_name] min_scale = data.minScale() img = cache.image(data.image_path(img_name)) img_data = data[img_name] size = self._crop.size() pix = QImage(size*overSampling, QImage.Format_ARGB32) pix.fill(bgColor) painter = QPainter() if not painter.begin(pix): self.abort("Cannot create painter on QImage") return None, None, None painter.setRenderHints(QPainter.SmoothPixmapTransform, True) painter.setRenderHints(QPainter.Antialiasing, True) if overSampling > 1: painter.scale(overSampling, overSampling) painter.translate(-self._crop.topLeft()) painter.save() painter.translate(self.translate) log_debug("Translating: %gx%g" % (self.translate.x(), self.translate.y()) ) painter.scale(1/min_scale, 1/min_scale) painter.save() matrix = img_data.matrix() painter.setWorldTransform(matrix, True) painter.drawImage(QPoint(0,0), img) painter.restore() #pt_matrix = QTransform() #pt_matrix.scale(1/min_scale, 1/min_scale) #painter.setTransform(pt_matrix, True) cellColoring.startImage(painter, imageid) wallColoring.startImage(painter, imageid) for ed in extraDrawing: ed.startImage(painter, imageid) if self.result_type == "Growth": cells = result.cells[imageid] walls = result.walls[imageid] else: cells = img_data.cells walls = set() for cid in img_data.cells: pts = [ pt for pt in data.cells[cid] if pt in img_data ] if len(pts) > 1: for i in range(len(pts)): walls.add(data.wallId(pts[i-1], pts[i])) # Now, draw the cells and the ellipsis for cid in cells: painter.setPen(Qt.NoPen) color = cellColoring(imageid, cid) painter.setBrush(color) pts = data.cellAtTime(cid, img_data.index) if pts: pts.append(pts[0]) ppts = [] for p1,p2 in zip(pts[:-1], pts[1:]): ppts.append(img_data[p1]) ppts.extend(img_data.walls[p1,p2]) ppts.append(ppts[0]) poly = QPolygonF(ppts) painter.drawPolygon(poly) # And draw the walls wallThickness = self.wallThickness*min_scale for wid in walls: color = wallColoring(imageid, wid) if color.alpha() > 0: pen = QPen(color) pen.setWidthF(wallThickness) painter.setPen(pen) pts = [img_data[wid[0]]] + img_data.walls[wid[0], wid[1]] + [img_data[wid[1]]] #painter.drawLine(img_data[wid[0]], img_data[wid[1]]) painter.drawPolyline(*pts) # Then, draw the points pointSize = self.pointSize*min_scale pointLineColor = self.pointLineColor pointLineThickness = self.pointLineThickness*min_scale log_debug("pointSize = %g" % pointSize) for pid in img_data: color = pointColoring(imageid, pid) if color.alpha() > 0: pen = QPen(pointLineColor) pen.setWidthF(pointLineThickness) brush = QBrush(color) painter.setPen(pen) painter.setBrush(brush) pos = img_data[pid] rect = QRectF(pos.x()-pointSize, pos.y()-pointSize, 2*pointSize, 2*pointSize) painter.drawEllipse(rect) if ellipsisDraw.plot: for cid in cells: pts = data.cellAtTime(cid, img_data.index) if pts: pts.append(pts[0]) ppts = [] for p1,p2 in zip(pts[:-1], pts[1:]): ppts.append(img_data[p1]) ppts.extend(img_data.walls[p1,p2]) ppts.append(ppts[0]) #poly = QPolygonF(ppts) #painter.drawPolygon(poly) ellipsisDraw(painter, imageid, cid, ppts, min_scale) # At last, draw the extra data for ed in extraDrawing: ed(painter, imageid) tr = painter.worldTransform() painter.restore() pic_w = wallColoring.finalizeImage(painter, imageid, tr, self.crop) pic_c = cellColoring.finalizeImage(painter, imageid, tr, self.crop) for ed in extraDrawing: ed.finalizeImage(painter, imageid, tr, self.crop) painter.end() return pix, pic_w, pic_c def start(self): if self.isRunning(): assert not self.rendering_all, "Cannot run twice the rendering of all images with the same object." return if parameters.instance.use_thread: log_debug("Starting rendering thread.") QThread.start(self) return False else: self.run() return True def render_all(self): self.rendering_all = True return self.start() def render_single(self, img_id, retry=False): if retry: while self.isRunning(): self.wait(10000) elif self.isRunning(): return self.rendering_all = False self.current_image = img_id return self.start() def load(self, filename): self.loading = True self.result = filename return self.start() def run(self): if self.loading: self.run_loader() elif self.rendering_all: self.run_full() else: self.run_single() def run_single(self): img = self.current_image self.cellColoring.init() self.wallColoring.init() self.pointColoring.init() log_debug("Rendering image %d" % img) self.pix, self.pic_w, self.pic_c = self.drawImage(img) if self.pic_w is not None: log_debug("Has wall image") if self.pic_c is not None: log_debug("Has cell image") if self.pix is not None: log_debug("Pix correctly rendered") log_debug("Rendered image %d = %s" % (img, self.pix)) self.image_ready() def reload(self): if self.retryObject is None: return self._loading_arguments.update(self.retryObject.method_args) self.load(self.retryObject.filename) def run_loader(self): filename = self.result try: self.retryObject = None # First, prepare the data by getting the images and computing how big they # should be f = open(filename) first_line = f.readline() f.close() if first_line.startswith("TRKR_VERSION"): result = Result(None) result.load(self.result, **self._loading_arguments) result_type = "Growth" else: result = TrackingData() result.load(self.result, **self._loading_arguments) result_type = "Data" self.result = result self.result_type = result_type if result_type == "Data": data = result images = data.images_name if data.cells: self.has_cells = True self.has_walls = True else: self.has_cells = False self.has_walls = False self.has_points = bool(data.cell_points) else: data = result.data images = result.images self.has_cells = False self.has_walls = False self.has_points = False self.images = images cache = image_cache.cache self.update_nb_images(len(result)) bbox = QRectF() ms = data.minScale() for i in range(len(result)): img_name = images[i] img_data = data[img_name] img = cache.image(data.image_path(img_name)) matrix = QTransform() matrix = img_data.matrix() sc = QTransform() sc.scale(1.0/ms, 1.0/ms) matrix *= sc r = QRectF(img.rect()) rbox = matrix.map(QPolygonF(r)).boundingRect() bbox |= rbox log_debug("Image '%s':\n\tSize = %gx%g\n\tTransformed = %gx%g %+g %+g\n\tGlobal bbox = %gx%g %+g %+g\n" % (img_name, r.width(), r.height(), rbox.width(), rbox.height(), rbox.left(), rbox.top(), bbox.width(), bbox.height(), bbox.left(), bbox.top())) log_debug("Matrix:\n%g\t%g\t%g\n%g\t%g\t%g\n" % (matrix.m11(), matrix.m12(), matrix.dx(), matrix.m21(), matrix.m22(), matrix.dy())) if result_type == "Growth": if result.cells[i]: self.has_cells = True if result.walls[i]: self.has_walls = True self.has_points = bool(result.data.cell_points) self.nextImage() translate = bbox.topLeft() translate *= -1 self.translate = translate size = bbox.size().toSize() self.img_size = size self._crop = QRect(QPoint(0,0), size) self.finished() self._loading_arguments = {} # All done, we don't need that anymore except RetryTrackingDataException as ex: ex.filename = filename self.retryObject = ex self.finished() return except Exception as ex: _, _, exceptionTraceback = sys.exc_info() self.abort(ex, traceback=exceptionTraceback) raise def run_full(self): if not self.valid(): self.abort("Object was not correctly initialized") return self.stop(False) painter = None try: result = self.result self.update_nb_images(len(result)) # if self.result_type == "Data": # data = result # images = result.images_name # else: # data = result.data # images = result.images # cache = image_cache.cache cellColoring = self.cellColoring wallColoring = self.wallColoring pointColoring = self.pointColoring file_format = self.fileFormat file_pattern = "%s%%0%dd.%s" % (self.filePrefix, len(str(len(result))), file_format) wall_file_pattern = "%s%%0%dd_wall.%s" % (self.filePrefix, len(str(len(result))), file_format) cell_file_pattern = "%s%%0%dd_cell.%s" % (self.filePrefix, len(str(len(result))), file_format) cellColoring.init() wallColoring.init() pointColoring.init() self.nextImage() for i in range(len(result)): if self.stopped(): self.abort("User interruption") return pix, pic_w, pic_c = self.drawImage(i) pix.save(file_pattern % (i+1), file_format) if pic_w is not None: self.saveExtra(pic_w, wall_file_pattern % (i+1), file_format) if pic_c is not None: self.saveExtra(pic_c, cell_file_pattern % (i+1), file_format) self.nextImage() self.finished() except Exception as ex: if painter is not None: painter.end() _, _, exceptionTraceback = sys.exc_info() self.abort(ex, traceback=exceptionTraceback) raise def saveExtra(self, picture, file_name, file_format): rect = picture.boundingRect() pix = QImage(rect.size(), QImage.Format_ARGB32) pix.fill(QColor(0, 0, 0, 0).rgba()) paint = QPainter() paint.begin(pix) paint.drawPicture(rect.topLeft()*-1, picture) paint.end() pix.save(file_name, file_format)
def paint(self, painter, option, index): """ Draws the widget Arguments: painter -- a QPainter option -- a QStyleOptionView index -- a QModelIndex """ # Retrieve the data model = index.model() record = model.data(index) text = record.toString() zoteroItem = zoteroCache[unicode(text)] l = zoteroItem.full_format().split("\n") if zoteroItem.fulltext == None: pixmap = self.noPdfPixmap else: pixmap = self.pdfPixmap # Choose the colors self.palette = self.qnotero.ui.listWidgetResults.palette() if option.state & QStyle.State_MouseOver: background = self.palette.Highlight foreground = self.palette.HighlightedText _note = zoteroItem.get_note() if _note != None: self.qnotero.showNoteHint() else: self.qnotero.hideNoteHint() elif option.state & QStyle.State_Selected: background = self.palette.Dark foreground = self.palette.WindowText else: background = self.palette.Base foreground = self.palette.WindowText # Draw the frame _rect = option.rect.adjusted(self._margin, self._margin, \ -2*self._margin, -self._margin) pen = painter.pen() pen.setColor(self.palette.color(background)) painter.setPen(pen) painter.setBrush(self.palette.brush(background)) painter.drawRoundedRect(_rect, self.roundness, self.roundness) font = painter.font pen = painter.pen() pen.setColor(self.palette.color(foreground)) painter.setPen(pen) # Draw icon _rect = QRect(option.rect) _rect.moveBottom(_rect.bottom() + 0.5*self.dy) _rect.moveLeft(_rect.left() + 0.5*self.dy) _rect.setHeight(self.pixmapSize) _rect.setWidth(self.pixmapSize) painter.drawPixmap(_rect, pixmap) # Draw the text _rect = option.rect.adjusted(self.pixmapSize+self.dy, 0.5*self.dy, \ -self.dy, 0) f = [self.tagFont, self.italicFont, self.regularFont, \ self.boldFont] l.reverse() while len(l) > 0: s = l.pop() if len(f) > 0: painter.setFont(f.pop()) painter.drawText(_rect, Qt.AlignLeft, s) _rect = _rect.adjusted(0, self.dy, 0, 0)
class AbstractScrollTela(TelaConsole): def __init__(self, altura, parent=None): super().__init__(parent=parent) self._rectTela = QRect(0,0,0,altura) self._mostrarHorizontal = False self._mostrarVertical = False self._scrollHorizontal = ScrollBarConsole(3,0,orientacao=ScrollBarConsole.HORIZONTAL,parent=self) self._scrollVertical = ScrollBarConsole(self._rectTela.height(),0,orientacao=ScrollBarConsole.VERTICAL,parent=self) self._scrollHorizontal.valorScrollModificado.connect(self._moverHorizontal) self._scrollVertical.valorScrollModificado.connect(self._moverVertical) self._scrollBarFocus = ScrollBarConsole(3,0,parent=self) self._scrollBarFocus.installEventFilter(self) def eventFilter(self, obj, event): if obj == self._scrollBarFocus and event.type() != EventoTecladoConsole.TabType: self._scrollVertical.customEvent(event) self._scrollHorizontal.customEvent(event) return True else: return False def acceptFocus(self): return True def focusNextChild(self): if self._scrollBarFocus.hasFocus(): return False if self.hasFocus(): if not (self._mostrarVertical or self._mostrarHorizontal): return False self._scrollBarFocus.setFocus() else: if not self.acceptFocus(): return False self.setFocus() return True def focusPrevChild(self): if self.hasFocus(): return False if self._scrollBarFocus.hasFocus(): if self.acceptFocus(): self.setFocus() else: return False else: self._scrollBarFocus.setFocus() return True def indexChildActive(self): if self._scrollBarFocus.hasFocus(): return 0 return -1 def getRectTela(self): return self._rectTela def _moverVertical(self, valor): self._scrollVertical.setValorAtual(valor) self._rectTela.moveTop(valor) def _moverHorizontal(self, valor): self._scrollHorizontal.setValorAtual(valor) self._rectTela.moveLeft(valor) def deixarVisivelVertical(self, valor): top = self.getRectTela().top() height = self.getRectTela().height() - self._numLinhasFixas() - 1 bottom = top + height if valor < top: self._moverVertical(valor) elif valor > bottom: self._moverVertical(valor - height) def deixarVisivelHorizontal(self, valor): left = self.getRectTela().left() width = self.getRectTela().width()-1 right = left + width if valor < left: self._moverHorizontal(valor) elif valor > right: self._moverHorizontal(valor - width) def scrollContentsBy(self, dx, dy): self._rectTela.translate(dx,dy) def getDesenhoTela(self): raise NotImplemented("Metodo abstrato") def _adicionarScrollBar(self, tela): if self._mostrarVertical: tela = self._adicionarScrollVertical(tela) if self._mostrarHorizontal: tela = self._adicionarScrollHorizontal(tela) return tela def _adicionarScrollVertical(self, texto): scroll = '' for i in self._scrollVertical.desenhoTelaConsole(self._rectTela.width()).split('\n'): scroll += "{0}|\n".format(i) scroll = "-|\n{0}-|".format(scroll).split('\n') s = '' texto = texto.split('\n') for i in range(len(texto)): s += "{0:{1}}{2}\n".format(texto[i], self._rectTela.width()+2, scroll[i]) if s.endswith('\n'): s = s[:len(s)-1] return s def _adicionarScrollHorizontal(self, texto): texto += '\n|{0}|{1}\n'.format(self._scrollHorizontal.desenhoTelaConsole(self._rectTela.width()), 'X|' if self._mostrarVertical else '') texto += '|{0:-<{1}}|{2}'.format('', self._rectTela.width(), '-|' if self._mostrarVertical else '') return texto def _ajustarScroll(self, tela): linhas = tela.split('\n') numColunas = max(map(len, linhas)) numLinhasFixas = self._numLinhasFixas() numLinhas = len(linhas) + numLinhasFixas self._mostrarVertical = numLinhas > self._rectTela.height() self._mostrarHorizontal = numColunas > self._rectTela.width() self._scrollHorizontal.setAteValor(max(0, numColunas-self._rectTela.width())) self._scrollVertical.setAteValor(max(0, numLinhas-self._rectTela.height())) def _adicionarLinhasFixas(self, tela): """Esse método deve ser sobrescrito pela classe filha para adicionar as linhas fixas na tela""" return tela def _numLinhasFixas(self): return self._adicionarLinhasFixas('').count('\n') def _linhasVisiveis(self, tela): linhas = tela.split('\n') numLinhasFixas = self._numLinhasFixas() numLinhas = len(linhas) + numLinhasFixas if numLinhas < self._rectTela.height(): tela = self._adicionarLinhasFixas(tela) tela += '\n'*(self._rectTela.height()-numLinhas) else: top = self.getRectTela().top() bottom = self.getRectTela().bottom()+1 return self._adicionarLinhasFixas('\n'.join(linhas[top:bottom - numLinhasFixas])) return tela def _colunasVisiveis(self, tela): linhas = tela.split('\n') numColunas = max(map(len, linhas))+1 if numColunas > self._rectTela.width(): tela = '\n'.join([linha[self._rectTela.left():self._rectTela.right()+1] for linha in linhas]) return tela def _ajustarTela(self, tela): tela = self._linhasVisiveis(tela) tela = self._colunasVisiveis(tela) return tela def desenhoTela(self, tam): tela = self.getDesenhoTela() self._ajustarScroll(tela) if self._mostrarVertical: tam -= 2 if tam-2 != self._rectTela.width(): self._rectTela.setWidth(tam-2) self._scrollHorizontal.setTamanho(tam-2) self._ajustarScroll(tela) tela = self._ajustarTela(tela) tela = self._colocarBorda(tela, tam) return self._adicionarScrollBar(tela)
class PlottingThread(QThread): def __init__(self, parent): QThread.__init__(self) self.result = None self.parent = parent self._stopped = False self.mutex = QMutex() self.filePrefix = None self.fileFormat = None self.wallColoring = None self.cellColoring = None self.pointColoring = None self.extraDrawing = [] self.pointSize = None self.pointLineColor = None self.pointLineThickness = None self.ellipsisDraw = None self.overSampling = None self.wallThickness = None self.bgColor = None self.loading = False self._crop = QRect(0, 0, 1, 1) self._pix = None self._end_image_plot = False self._loading_arguments = {} self.retryObject = None def end_step(self): return len(self.result) + 1 def stop(self, value=True): self.mutex.lock() self._stopped = value self.mutex.unlock() def stopped(self): self.mutex.lock() val = self._stopped self.mutex.unlock() return val def nextImage(self): QCoreApplication.postEvent(self.parent, NextImageEvent()) def abort(self, reason, **others): e = AbortPlottingEvent(reason) if others: e.others = others QCoreApplication.postEvent(self.parent, e) def finished(self): if self.loading: QCoreApplication.postEvent(self.parent, FinishLoadingEvent()) self.loading = False else: QCoreApplication.postEvent(self.parent, FinishPlottingEvent()) def image_ready(self): QCoreApplication.postEvent(self.parent, ImageReadyPlottingEvent()) def update_nb_images(self, nb): QCoreApplication.postEvent(self.parent, UpdateNbImageEvent(nb)) @property def crop_left(self): return self._crop.left() @crop_left.setter def crop_left(self, value): self._crop.moveLeft(int(value)) @property def crop_top(self): return self._crop.top() @crop_top.setter def crop_top(self, value): self._crop.moveTop(int(value)) @property def crop_width(self): return self._crop.width() @crop_width.setter def crop_width(self, value): self._crop.setWidth(int(value)) @property def crop_height(self): return self._crop.height() @crop_height.setter def crop_height(self, value): self._crop.setHeight(int(value)) def reset_crop(self): self._crop = QRect(QPoint(0, 0), self.img_size) @property def crop(self): return QRect(self._crop) @crop.deleter def crop(self): self.reset_crop() @property def end_image_plot(self): ''' If true, plot the growth data on the end image rather than the start image of the growth calculation. ''' return self._end_image_plot @end_image_plot.setter def end_image_plot(self, value): self._end_image_plot = bool(value) @property def pix(self): '''Thread-safe image storage.''' self.mutex.lock() pix = self._pix self.mutex.unlock() return pix @pix.setter def pix(self, value): self.mutex.lock() self._pix = value self.mutex.unlock() def render_valid(self): if self.result is None: log_debug("result is None") return False if self.parent is None: log_debug("parent is None") return False if self.ellipsisDraw is None: log_debug("ellipsisDraw is None") return False if self.cellColoring is None: log_debug("cellColoring is None") return False if self.wallColoring is None: log_debug("wallColoring is None") return False if self.pointColoring is None: log_debug("pointColoring is None") return False if self.pointSize is None: log_debug("pointSize is None") return False if self.pointLineThickness is None: log_debug("pointSize is None") return False if self.pointLineColor is None: log_debug("pointSize is None") return False if self.wallThickness is None: log_debug("wallThickness is None") return False if self.overSampling is None: log_debug("overSampling is None") return False if self.bgColor is None: log_debug("bgColor is None") return False return True def valid(self): if self.filePrefix is None: log_debug("filePrefix is None") return False if not self.filePrefix: log_debug("filePrefix is Empty") return False if self.fileFormat is None: log_debug("fileFormat is None") return False return self.render_valid() def drawImage(self, imageid): cache = image_cache.cache cellColoring = self.cellColoring wallColoring = self.wallColoring pointColoring = self.pointColoring ellipsisDraw = self.ellipsisDraw overSampling = self.overSampling extraDrawing = self.extraDrawing bgColor = self.bgColor.rgb() result = self.result if self.result_type == "Data": data = result img_name = result.images_name[imageid] else: data = result.data img_name = result.images[imageid] #scale = data.images_scale[img_name] min_scale = data.minScale() img = cache.image(data.image_path(img_name)) img_data = data[img_name] size = self._crop.size() pix = QImage(size * overSampling, QImage.Format_ARGB32) pix.fill(bgColor) painter = QPainter() if not painter.begin(pix): self.abort("Cannot create painter on QImage") return None, None, None painter.setRenderHints(QPainter.SmoothPixmapTransform, True) painter.setRenderHints(QPainter.Antialiasing, True) if overSampling > 1: painter.scale(overSampling, overSampling) painter.translate(-self._crop.topLeft()) painter.save() painter.translate(self.translate) log_debug("Translating: %gx%g" % (self.translate.x(), self.translate.y())) painter.scale(1 / min_scale, 1 / min_scale) painter.save() matrix = img_data.matrix() painter.setWorldTransform(matrix, True) painter.drawImage(QPoint(0, 0), img) painter.restore() #pt_matrix = QTransform() #pt_matrix.scale(1/min_scale, 1/min_scale) #painter.setTransform(pt_matrix, True) cellColoring.startImage(painter, imageid) wallColoring.startImage(painter, imageid) for ed in extraDrawing: ed.startImage(painter, imageid) if self.result_type == "Growth": cells = result.cells[imageid] walls = result.walls[imageid] else: cells = img_data.cells walls = set() for cid in img_data.cells: pts = [pt for pt in data.cells[cid] if pt in img_data] if len(pts) > 1: for i in range(len(pts)): walls.add(data.wallId(pts[i - 1], pts[i])) # Now, draw the cells and the ellipsis for cid in cells: painter.setPen(Qt.NoPen) color = cellColoring(imageid, cid) painter.setBrush(color) pts = data.cellAtTime(cid, img_data.index) if pts: pts.append(pts[0]) ppts = [] for p1, p2 in zip(pts[:-1], pts[1:]): ppts.append(img_data[p1]) ppts.extend(img_data.walls[p1, p2]) ppts.append(ppts[0]) poly = QPolygonF(ppts) painter.drawPolygon(poly) # And draw the walls wallThickness = self.wallThickness * min_scale for wid in walls: color = wallColoring(imageid, wid) if color.alpha() > 0: pen = QPen(color) pen.setWidthF(wallThickness) painter.setPen(pen) pts = [img_data[wid[0]] ] + img_data.walls[wid[0], wid[1]] + [img_data[wid[1]]] #painter.drawLine(img_data[wid[0]], img_data[wid[1]]) painter.drawPolyline(*pts) # Then, draw the points pointSize = self.pointSize * min_scale pointLineColor = self.pointLineColor pointLineThickness = self.pointLineThickness * min_scale log_debug("pointSize = %g" % pointSize) for pid in img_data: color = pointColoring(imageid, pid) if color.alpha() > 0: pen = QPen(pointLineColor) pen.setWidthF(pointLineThickness) brush = QBrush(color) painter.setPen(pen) painter.setBrush(brush) pos = img_data[pid] rect = QRectF(pos.x() - pointSize, pos.y() - pointSize, 2 * pointSize, 2 * pointSize) painter.drawEllipse(rect) if ellipsisDraw.plot: for cid in cells: pts = data.cellAtTime(cid, img_data.index) if pts: pts.append(pts[0]) ppts = [] for p1, p2 in zip(pts[:-1], pts[1:]): ppts.append(img_data[p1]) ppts.extend(img_data.walls[p1, p2]) ppts.append(ppts[0]) #poly = QPolygonF(ppts) #painter.drawPolygon(poly) ellipsisDraw(painter, imageid, cid, ppts, min_scale) # At last, draw the extra data for ed in extraDrawing: ed(painter, imageid) tr = painter.worldTransform() painter.restore() pic_w = wallColoring.finalizeImage(painter, imageid, tr, self.crop) pic_c = cellColoring.finalizeImage(painter, imageid, tr, self.crop) for ed in extraDrawing: ed.finalizeImage(painter, imageid, tr, self.crop) painter.end() return pix, pic_w, pic_c def start(self): if self.isRunning(): assert not self.rendering_all, "Cannot run twice the rendering of all images with the same object." return if parameters.instance.use_thread: log_debug("Starting rendering thread.") QThread.start(self) return False else: self.run() return True def render_all(self): self.rendering_all = True return self.start() def render_single(self, img_id, retry=False): if retry: while self.isRunning(): self.wait(10000) elif self.isRunning(): return self.rendering_all = False self.current_image = img_id return self.start() def load(self, filename): self.loading = True self.result = filename return self.start() def run(self): if self.loading: self.run_loader() elif self.rendering_all: self.run_full() else: self.run_single() def run_single(self): img = self.current_image self.cellColoring.init() self.wallColoring.init() self.pointColoring.init() log_debug("Rendering image %d" % img) self.pix, self.pic_w, self.pic_c = self.drawImage(img) if self.pic_w is not None: log_debug("Has wall image") if self.pic_c is not None: log_debug("Has cell image") if self.pix is not None: log_debug("Pix correctly rendered") log_debug("Rendered image %d = %s" % (img, self.pix)) self.image_ready() def reload(self): if self.retryObject is None: return self._loading_arguments.update(self.retryObject.method_args) self.load(self.retryObject.filename) def run_loader(self): filename = self.result try: self.retryObject = None # First, prepare the data by getting the images and computing how big they # should be f = open(filename) first_line = f.readline() f.close() if first_line.startswith("TRKR_VERSION"): result = Result(None) result.load(self.result, **self._loading_arguments) result_type = "Growth" else: result = TrackingData() result.load(self.result, **self._loading_arguments) result_type = "Data" self.result = result self.result_type = result_type if result_type == "Data": data = result images = data.images_name if data.cells: self.has_cells = True self.has_walls = True else: self.has_cells = False self.has_walls = False self.has_points = bool(data.cell_points) else: data = result.data images = result.images self.has_cells = False self.has_walls = False self.has_points = False self.images = images cache = image_cache.cache self.update_nb_images(len(result)) bbox = QRectF() ms = data.minScale() for i in range(len(result)): img_name = images[i] img_data = data[img_name] img = cache.image(data.image_path(img_name)) matrix = QTransform() matrix = img_data.matrix() sc = QTransform() sc.scale(1.0 / ms, 1.0 / ms) matrix *= sc r = QRectF(img.rect()) rbox = matrix.map(QPolygonF(r)).boundingRect() bbox |= rbox log_debug( "Image '%s':\n\tSize = %gx%g\n\tTransformed = %gx%g %+g %+g\n\tGlobal bbox = %gx%g %+g %+g\n" % (img_name, r.width(), r.height(), rbox.width(), rbox.height(), rbox.left(), rbox.top(), bbox.width(), bbox.height(), bbox.left(), bbox.top())) log_debug("Matrix:\n%g\t%g\t%g\n%g\t%g\t%g\n" % (matrix.m11(), matrix.m12(), matrix.dx(), matrix.m21(), matrix.m22(), matrix.dy())) if result_type == "Growth": if result.cells[i]: self.has_cells = True if result.walls[i]: self.has_walls = True self.has_points = bool(result.data.cell_points) self.nextImage() translate = bbox.topLeft() translate *= -1 self.translate = translate size = bbox.size().toSize() self.img_size = size self._crop = QRect(QPoint(0, 0), size) self.finished() self._loading_arguments = { } # All done, we don't need that anymore except RetryTrackingDataException as ex: ex.filename = filename self.retryObject = ex self.finished() return except Exception as ex: _, _, exceptionTraceback = sys.exc_info() self.abort(ex, traceback=exceptionTraceback) raise def run_full(self): if not self.valid(): self.abort("Object was not correctly initialized") return self.stop(False) painter = None try: result = self.result self.update_nb_images(len(result)) # if self.result_type == "Data": # data = result # images = result.images_name # else: # data = result.data # images = result.images # cache = image_cache.cache cellColoring = self.cellColoring wallColoring = self.wallColoring pointColoring = self.pointColoring file_format = self.fileFormat file_pattern = "%s%%0%dd.%s" % (self.filePrefix, len(str(len(result))), file_format) wall_file_pattern = "%s%%0%dd_wall.%s" % ( self.filePrefix, len(str(len(result))), file_format) cell_file_pattern = "%s%%0%dd_cell.%s" % ( self.filePrefix, len(str(len(result))), file_format) cellColoring.init() wallColoring.init() pointColoring.init() self.nextImage() for i in range(len(result)): if self.stopped(): self.abort("User interruption") return pix, pic_w, pic_c = self.drawImage(i) pix.save(file_pattern % (i + 1), file_format) if pic_w is not None: self.saveExtra(pic_w, wall_file_pattern % (i + 1), file_format) if pic_c is not None: self.saveExtra(pic_c, cell_file_pattern % (i + 1), file_format) self.nextImage() self.finished() except Exception as ex: if painter is not None: painter.end() _, _, exceptionTraceback = sys.exc_info() self.abort(ex, traceback=exceptionTraceback) raise def saveExtra(self, picture, file_name, file_format): rect = picture.boundingRect() pix = QImage(rect.size(), QImage.Format_ARGB32) pix.fill(QColor(0, 0, 0, 0).rgba()) paint = QPainter() paint.begin(pix) paint.drawPicture(rect.topLeft() * -1, picture) paint.end() pix.save(file_name, file_format)