diff --git a/version/app.py b/version/app.py index 464ea96..8d9e76a 100644 --- a/version/app.py +++ b/version/app.py @@ -324,14 +324,8 @@ def _web_metadata_picker(self, gallery, title_url_list, queue, parent=None): def get_metadata(self, gal=None): metadata_spinner = misc.Spinner(self) - def move_md_spinner(): - metadata_spinner.update_move(QPoint(self.pos().x() + self.width() - 65, - self.pos().y() + self.toolbar.height() + 55)) metadata_spinner.set_text("Metadata") metadata_spinner.set_size(55) - metadata_spinner.move(QPoint(self.pos().x() + self.width() - 65, - self.pos().y() + self.toolbar.height() + 55)) - self.move_listener.connect(move_md_spinner) thread = QThread(self) thread.setObjectName('App.get_metadata') fetch_instance = fetch.Fetch() @@ -456,7 +450,7 @@ def manga_display(self): def init_spinners(self): # fetching spinner - self.data_fetch_spinner = misc.Spinner(self) + self.data_fetch_spinner = misc.Spinner(self, "center") self.data_fetch_spinner.set_size(60) self.manga_list_view.gallery_model.ADD_MORE.connect(self.data_fetch_spinner.show) @@ -599,14 +593,9 @@ def init_toolbar(self): # debug specfic code if app_constants.DEBUG: def debug_func(): - import time - x = 0 - for g in app_constants.GALLERY_DATA: - x += 1 - if x > 70: - time.sleep(1) - print(g.title.encode(errors="ignore")) - print(g.id) + s = misc.Spinner(self) + s.set_text("this is a really long text") + s.show() debug_btn = QToolButton() debug_btn.setText("DEBUG BUTTON") @@ -1052,11 +1041,16 @@ def populate_n_close(): def finished(): app_constants.SCANNING_FOR_GALLERIES = False + new_gall_spinner = misc.Spinner(self) + new_gall_spinner.set_text("Gallery Scan") + new_gall_spinner.show() + thread = QThread(self) self.scan_inst = ScanDir() self.scan_inst.moveToThread(thread) self.scan_inst.final_paths_and_galleries.connect(show_new_galleries) self.scan_inst.finished.connect(finished) + self.scan_inst.finished.connect(new_gall_spinner.before_hide) thread.started.connect(self.scan_inst.scan_dirs) #self.scan_inst.scan_dirs() thread.finished.connect(thread.deleteLater) @@ -1065,6 +1059,8 @@ def finished(): app_constants.SCANNING_FOR_GALLERIES = False self.notification_bar.add_text('An error occured while attempting to scan for new galleries. Check happypanda.log.') log.exception('An error occured while attempting to scan for new galleries.') app_constants.SCANNING_FOR_GALLERIES = False + else: + self.notification_bar.add_text("Please specify directory in settings to scan for new galleries!") def dragEnterEvent(self, event): if event.mimeData().hasUrls(): @@ -1171,7 +1167,6 @@ def check(self): self.db_activity_checker.connect(db_activity.check) db_activity.moveToThread(app_constants.GENERAL_THREAD) db_activity.FINISHED.connect(db_spinner.close) - db_spinner.set_size(50) db_spinner.set_text('DB Activity') db_spinner.show() self.db_activity_checker.emit() diff --git a/version/gallery.py b/version/gallery.py index a6d42f5..45a572c 100644 --- a/version/gallery.py +++ b/version/gallery.py @@ -536,33 +536,7 @@ def canFetchMore(self, index): def fetchMore(self, index): self.db_emitter.fetch_more() -class CustomDelegate(QStyledItemDelegate): - def __init__(self, parent=None): - super().__init__(parent) - - def text_layout(self, text, width, font, font_metrics, alignment=Qt.AlignCenter): - "Lays out wrapped text" - text_option = QTextOption(alignment) - text_option.setUseDesignMetrics(True) - text_option.setWrapMode(QTextOption.WordWrap) - layout = QTextLayout(text, font) - layout.setTextOption(text_option) - leading = font_metrics.leading() - height = 0 - layout.setCacheEnabled(True) - layout.beginLayout() - while True: - line = layout.createLine() - if not line.isValid(): - break - line.setLineWidth(width) - height += leading - line.setPosition(QPointF(0, height)) - height += line.height() - layout.endLayout() - return layout - -class ListDelegate(CustomDelegate): +class ListDelegate(QStyledItemDelegate): "A custom delegate for the model/view framework" def __init__(self, parent): @@ -641,7 +615,7 @@ def paint(self, painter, option, index): # descr descr_y = artist_y + artist_layout.boundingRect().height() descr_x = title_x + (painter.fontMetrics().width(txt_list[6])*1.1) - descr_layout = self.text_layout(c_gallery.info, title_width, painter.font(), painter.fontMetrics(), Qt.AlignLeft) + descr_layout = misc.text_layout(c_gallery.info, title_width, painter.font(), painter.fontMetrics(), Qt.AlignLeft) descr_layout.draw(painter, QPointF(descr_x, descr_y)) # tags @@ -654,7 +628,7 @@ def paint(self, painter, option, index): painter.drawText(descr_x, tags_y, ns_text) tag_x = descr_x + painter.fontMetrics().width(ns_text) * 1.2 tags_txt = self.tags_text(c_gallery.tags[ns]) - tags_layout = self.text_layout(tags_txt, w-(tag_x*1.1 - x), painter.font(), painter.fontMetrics(), Qt.AlignLeft) + tags_layout = misc.text_layout(tags_txt, w-(tag_x*1.1 - x), painter.font(), painter.fontMetrics(), Qt.AlignLeft) tags_layout.draw(painter, QPointF(tag_x, tags_y-tags_h*0.7)) tags_y += tags_layout.boundingRect().height() @@ -691,17 +665,17 @@ def sizeHint(self, option, index): w = option.rect.width()-(self.pic_width+self._pic_margin*2+ self.parent_font_m.width("Added: {}".format(g.date_added.strftime('%d %b %Y')))) w = abs(w) - h = self.text_layout(g.info, w, self.parent_font, self.parent_font_m, Qt.AlignLeft).boundingRect().height() + h = misc.text_layout(g.info, w, self.parent_font, self.parent_font_m, Qt.AlignLeft).boundingRect().height() for ns in g.tags: tags = g.tags[ns] txt = self.tags_text(tags) - txt_layout = self.text_layout(txt, w, self.parent_font, self.parent_font_m, Qt.AlignLeft) + txt_layout = misc.text_layout(txt, w, self.parent_font, self.parent_font_m, Qt.AlignLeft) h += txt_layout.boundingRect().height() h2 = 0 - title_layout = self.text_layout(g.title, w, self.title_font, self.title_font_m) + title_layout = misc.text_layout(g.title, w, self.title_font, self.title_font_m) h2 += title_layout.boundingRect().height() + self.title_font_m.height() - artist_layout = self.text_layout(g.artist, w, self.artist_font, self.artist_font_m) + artist_layout = misc.text_layout(g.artist, w, self.artist_font, self.artist_font_m) h2 += artist_layout.boundingRect().height() + self.artist_font_m.height() h2 += self.parent_font_m.height()*len(self.gallery_info(g)) print("h:", h, "h2", h2) @@ -715,7 +689,7 @@ def sizeHint(self, option, index): return QSize(self.dynamic_width, dynamic_height) -class GridDelegate(CustomDelegate): +class GridDelegate(QStyledItemDelegate): "A custom delegate for the model/view framework" POPUP = pyqtSignal() @@ -944,8 +918,8 @@ def draw_text_label(lbl_h): if option.state & QStyle.State_MouseOver or\ option.state & QStyle.State_Selected: - title_layout = self.text_layout(title, w, self.title_font, self.title_font_m) - artist_layout = self.text_layout(artist, w, self.artist_font, self.artist_font_m) + title_layout = misc.text_layout(title, w, self.title_font, self.title_font_m) + artist_layout = misc.text_layout(artist, w, self.artist_font, self.artist_font_m) t_h = title_layout.boundingRect().height() a_h = artist_layout.boundingRect().height() diff --git a/version/gallerydb.py b/version/gallerydb.py index ec8b2e2..0547edb 100644 --- a/version/gallerydb.py +++ b/version/gallerydb.py @@ -1351,6 +1351,7 @@ def __init__(self): self.exed = 0 self._cache_id = 0 # used by custom delegate to cache profile + self._grid_visible = False self.dead_link = False self.state = 0 diff --git a/version/main.py b/version/main.py index be4e1f3..e2391b7 100644 --- a/version/main.py +++ b/version/main.py @@ -155,7 +155,7 @@ def start_main_window(conn): # while not done: # try: # if threading.active_count() > 5000: - # thread_list = [] + # thread_list = [] # done = True # else: # thread_list.append( diff --git a/version/misc.py b/version/misc.py index a8c03a5..babedf2 100644 --- a/version/misc.py +++ b/version/misc.py @@ -22,7 +22,7 @@ from PyQt5.QtGui import (QTextCursor, QIcon, QMouseEvent, QFont, QPixmapCache, QPalette, QPainter, QBrush, QColor, QPen, QPixmap, QMovie, QPaintEvent, QFontMetrics, - QPolygonF, QRegion, QCursor) + QPolygonF, QRegion, QCursor, QTextOption, QTextLayout) from PyQt5.QtWidgets import (QWidget, QProgressBar, QLabel, QVBoxLayout, QHBoxLayout, QDialog, QGridLayout, QLineEdit, @@ -57,6 +57,28 @@ log_e = log.error log_c = log.critical +def text_layout(text, width, font, font_metrics, alignment=Qt.AlignCenter): + "Lays out wrapped text" + text_option = QTextOption(alignment) + text_option.setUseDesignMetrics(True) + text_option.setWrapMode(QTextOption.WordWrap) + layout = QTextLayout(text, font) + layout.setTextOption(text_option) + leading = font_metrics.leading() + height = 0 + layout.setCacheEnabled(True) + layout.beginLayout() + while True: + line = layout.createLine() + if not line.isValid(): + break + line.setLineWidth(width) + height += leading + line.setPosition(QPointF(0, height)) + height += line.height() + layout.endLayout() + return layout + def centerWidget(widget, parent_widget=None): if parent_widget: r = parent_widget.rect() @@ -781,17 +803,21 @@ class Spinner(TransparentWidget): activated = pyqtSignal() deactivated = pyqtSignal() about_to_show, about_to_hide = range(2) + _OFFSET_X_TOPRIGHT = [0] - def __init__(self, parent): - super().__init__(parent, flags=Qt.Window|Qt.FramelessWindowHint) + def __init__(self, parent, position='topright'): + "Position can be: 'center', 'topright' or QPoint" + super().__init__(parent, flags=Qt.Window|Qt.FramelessWindowHint, move_listener=False) self.setAttribute(Qt.WA_ShowWithoutActivating) self.fps = 21 self.border = 2 self.line_width = 5 self.arc_length = 100 self.seconds_per_spin = 1 + self.text_layout = None self.text = '' + self._text_margin = 5 self._timer = QTimer(self) self._timer.timeout.connect(self._on_timer_timeout) @@ -800,6 +826,11 @@ def __init__(self, parent): # unnecessary repaints self._start_angle = 0 + self._offset_x_topright = self._OFFSET_X_TOPRIGHT[0] + self.margin = 10 + self._position = position + self._min_size = 0 + self.state_timer = QTimer() self.current_state = self.about_to_show self.state_timer.timeout.connect(super().hide) @@ -811,18 +842,43 @@ def __init__(self, parent): self.fade_animation.setStartValue(0.0) self.fade_animation.setEndValue(1.0) self.setWindowOpacity(0.0) + self._update_layout() self.set_size(50) - parent.move_listener.connect(lambda: self.update_move(QPoint(parent.pos().x() + parent.width() // 2, parent.pos().y() + parent.height() // 2))) + self._set_position(position) + + def _update_layout(self): + self.text_layout = text_layout(self.text, self.width()-self._text_margin, self.font(), self.fontMetrics()) + self.setFixedHeight(self._min_size+self.text_layout.boundingRect().height()) def set_size(self, w): self.setFixedWidth(w) - self.setFixedHeight(w+self.fontMetrics().height()) + self._min_size = w + self._update_layout() self.update() def set_text(self, txt): self.text = txt + self._update_layout() self.update() + def _set_position(self, new_pos): + "'center', 'topright' or QPoint" + p = self.parent_widget + + # topleft + if new_pos == "topright": + def topright(): + return QPoint(p.pos().x() + p.width() - 65 - self._offset_x_topright, p.pos().y() + p.toolbar.height() + 55) + self.move(topright()) + p.move_listener.connect(lambda: self.update_move(topright())) + + elif new_pos == "center": + p.move_listener.connect(lambda: self.update_move(QPoint(p.pos().x() + p.width() // 2, + p.pos().y() + p.height() // 2))) + + elif isinstance(new_pos, QPoint): + p.move_listener.connect(lambda: self.update_move(new_pos)) + def paintEvent(self, event): # call the base paint event: super().paintEvent(event) @@ -846,10 +902,6 @@ def paintEvent(self, event): pen.setWidth(self.line_width) painter.setPen(pen) - if self.text: - text_elided = self.fontMetrics().elidedText(self.text, Qt.ElideRight, self.width()-5) - txt_rect = painter.boundingRect(txt_rect, text_elided) - border = self.border + int(math.ceil(self.line_width / 2.0)) r = QRectF((txt_rect.height())/2, (txt_rect.height()/2), self.width()-txt_rect.height(), self.width()-txt_rect.height()) @@ -860,8 +912,8 @@ def paintEvent(self, event): # draw text if there is if self.text: - painter.drawText(QRectF(5, self.height()-txt_rect.height()-2.5, txt_rect.width(), txt_rect.height()), - text_elided) + txt_rect = self.text_layout.boundingRect() + self.text_layout.draw(painter, QPointF(self._text_margin, self.height()-txt_rect.height()-self._text_margin/2)) r = None @@ -870,6 +922,8 @@ def paintEvent(self, event): painter = None def showEvent(self, event): + if self._position == "topright": + self._OFFSET_X_TOPRIGHT[0] += + self.width() + self.margin if not self._timer.isActive(): self.fade_animation.start() self.current_state = self.about_to_show @@ -887,6 +941,8 @@ def before_hide(self): if self.current_state == self.about_to_hide: return self.current_state = self.about_to_hide + if self._position == "topright": + self._OFFSET_X_TOPRIGHT[0] -= self.width() + self.margin self.state_timer.start(5000) def closeEvent(self, event):