2121
2222from PySide6 .QtSvg import QSvgRenderer
2323from PySide6 .QtCore import QByteArray , Qt , QRunnable , Signal , QThreadPool , Slot , QTimer , QThread , QStringListModel , QObject
24- from PySide6 .QtGui import QPainter , QImage
24+ from PySide6 .QtGui import QPainter , QImage , QPen
2525
2626from collections import OrderedDict
2727from functools import lru_cache
@@ -360,14 +360,41 @@ def __init__(self, parent=None):
360360 self .setDefaultDropAction (Qt .DropAction .MoveAction )
361361 self .setSelectionMode (QListView .SelectionMode .ExtendedSelection )
362362 self .hovered_item = None
363+ self .scroll_timer = QTimer (self )
364+ self .scroll_timer .timeout .connect (self ._auto_scroll )
365+ self .scroll_direction = 0
366+ self .scroll_speed = 0
367+
368+ def _auto_scroll (self ):
369+ sb = self .verticalScrollBar ()
370+ sb .setValue (sb .value () + self .scroll_direction * self .scroll_speed )
363371
364372 def dragEnterEvent (self , event ):
373+ super ().dragEnterEvent (event )
365374 if event .source () == self :
366375 event .accept ()
367- else :
368- super ().dragEnterEvent (event )
369376
370377 def dragMoveEvent (self , event ):
378+ super ().dragMoveEvent (event )
379+
380+ outer_margin = 60
381+ inner_margin = 20
382+ y = event .pos ().y ()
383+ height = self .viewport ().height ()
384+
385+ if y < outer_margin :
386+ self .scroll_direction = - 1
387+ self .scroll_speed = 75 if y < inner_margin else 25
388+ if not self .scroll_timer .isActive ():
389+ self .scroll_timer .start (50 )
390+ elif y > height - outer_margin :
391+ self .scroll_direction = 1
392+ self .scroll_speed = 75 if y > height - inner_margin else 25
393+ if not self .scroll_timer .isActive ():
394+ self .scroll_timer .start (50 )
395+ else :
396+ self .scroll_timer .stop ()
397+
371398 if event .source () == self :
372399 target_item = self .itemAt (event .pos ())
373400 if target_item != self .hovered_item :
@@ -391,16 +418,16 @@ def dragMoveEvent(self, event):
391418 event .accept ()
392419 return
393420 event .ignore ()
394- else :
395- super ().dragMoveEvent (event )
396421
397422 def dragLeaveEvent (self , event ):
423+ self .scroll_timer .stop ()
398424 if self .hovered_item :
399425 self ._restore_icon (self .hovered_item )
400426 self .hovered_item = None
401427 super ().dragLeaveEvent (event )
402428
403429 def dropEvent (self , event ):
430+ self .scroll_timer .stop ()
404431 if self .hovered_item :
405432 self ._restore_icon (self .hovered_item )
406433 self .hovered_item = None
@@ -435,6 +462,54 @@ def _restore_icon(self, item):
435462 item .setIcon (self .original_icon )
436463 self .original_icon = None
437464
465+ class PieProgressBar (QWidget ):
466+ def __init__ (self , parent = None ):
467+ super ().__init__ (parent )
468+ self .setFixedSize (24 , 24 )
469+ self ._value = 0
470+ self ._maximum = 1
471+
472+ def setValue (self , value ):
473+ self ._value = value
474+ self .update ()
475+
476+ def setMaximum (self , maximum ):
477+ self ._maximum = maximum
478+ self .update ()
479+
480+ def paintEvent (self , event ):
481+ painter = QPainter (self )
482+ painter .setRenderHint (QPainter .RenderHint .Antialiasing )
483+
484+ rect = self .rect ().adjusted (2 , 2 , - 2 , - 2 )
485+
486+ # Draw background circle
487+ bg_color = QApplication .palette ().alternateBase ().color ()
488+ painter .setPen (Qt .PenStyle .NoPen )
489+ painter .setBrush (bg_color )
490+ painter .drawEllipse (rect )
491+
492+ # Draw pie
493+ if self ._maximum > 0 :
494+ fg_color = QApplication .palette ().highlight ().color ()
495+ painter .setBrush (fg_color )
496+
497+ start_angle = 90 * 16
498+ progress = self ._value / self ._maximum
499+ span_angle = int (- progress * 360 * 16 )
500+
501+ painter .drawPie (rect , start_angle , span_angle )
502+
503+ # Draw a subtle outline
504+ outline_pen = QPen (QApplication .palette ().text ().color (), 1 )
505+ c = outline_pen .color ()
506+ c .setAlpha (64 )
507+ outline_pen .setColor (c )
508+ painter .setPen (outline_pen )
509+ painter .setBrush (Qt .BrushStyle .NoBrush )
510+ painter .drawEllipse (rect )
511+
512+
438513class ClickSelectLineEdit (QLineEdit ):
439514 escPressed = Signal ()
440515
@@ -481,7 +556,6 @@ def __init__(self):
481556 self .gdrive_pool .setMaxThreadCount (10 )
482557 self .gdrive_tasks_total = 0
483558 self .gdrive_tasks_completed = 0
484- self .gdrive_progress_dialog : QProgressDialog | None = None
485559
486560 self .gcache : DriveCache | None = None
487561 self .init_ui ()
@@ -569,6 +643,9 @@ def init_ui(self):
569643 top_bar .addWidget (self .up_btn )
570644 top_bar .addWidget (self .address_bar )
571645
646+ self .gdrive_progress_widget = PieProgressBar ()
647+ top_bar .addWidget (self .gdrive_progress_widget )
648+
572649 self .folder_menu_btn = QPushButton ()
573650 self .folder_menu_btn .setIcon (get_icon (OutlineIcon .DOTS ))
574651 self .folder_menu_btn .setToolTip ("Folder actions" )
@@ -1073,20 +1150,10 @@ def queue_gdrive_action(self, action: GDriveAction):
10731150
10741151 def _update_gdrive_progress (self ):
10751152 if self .gdrive_tasks_total > self .gdrive_tasks_completed :
1076- if not self .gdrive_progress_dialog :
1077- self .gdrive_progress_dialog = QProgressDialog ("Processing operations..." , "Cancel" , 0 , self .gdrive_tasks_total , self )
1078- self .gdrive_progress_dialog .setWindowTitle ("GDrive Operations" )
1079- self .gdrive_progress_dialog .setWindowModality (Qt .WindowModality .NonModal )
1080- self .gdrive_progress_dialog .setCancelButton (None )
1081- self .gdrive_progress_dialog .setMinimumDuration (0 )
1082- self .gdrive_progress_dialog .show ()
1083-
1084- self .gdrive_progress_dialog .setMaximum (self .gdrive_tasks_total )
1085- self .gdrive_progress_dialog .setValue (self .gdrive_tasks_completed )
1153+ self .gdrive_progress_widget .setMaximum (self .gdrive_tasks_total )
1154+ self .gdrive_progress_widget .setValue (self .gdrive_tasks_completed )
1155+ self .gdrive_progress_widget .setToolTip (f"Processing... ({ self .gdrive_tasks_completed } /{ self .gdrive_tasks_total } )" )
10861156 else :
1087- if self .gdrive_progress_dialog :
1088- self .gdrive_progress_dialog .close ()
1089- self .gdrive_progress_dialog = None
10901157 self .gdrive_tasks_total = 0
10911158 self .gdrive_tasks_completed = 0
10921159
0 commit comments