33-------------------
44
55"""
6+ import sys
67import os
78import weakref
89import logging
@@ -43,6 +44,7 @@ def __init__(self, pixmap, parent=None):
4344 self .setCacheMode (QGraphicsItem .ItemCoordinateCache )
4445 self ._pixmap = pixmap
4546 self ._pixmapSize = QSizeF ()
47+ self ._keepAspect = True
4648 self .setSizePolicy (QSizePolicy .Fixed , QSizePolicy .Fixed )
4749
4850 def setPixmap (self , pixmap ):
@@ -53,30 +55,29 @@ def setPixmap(self, pixmap):
5355 def pixmap (self ):
5456 return QPixmap (self ._pixmap )
5557
56- def setPixmapSize (self , size ):
57- if self ._pixmapSize != size :
58- self ._pixmapSize = QSizeF (size )
59- self .updateGeometry ()
60-
61- def pixmapSize (self ):
62- if self ._pixmapSize .isValid ():
63- return QSizeF (self ._pixmapSize )
64- else :
65- return QSizeF (self ._pixmap .size ())
66-
6758 def sizeHint (self , which , constraint = QSizeF ()):
6859 if which == Qt .PreferredSize :
69- return self .pixmapSize ( )
60+ return QSizeF ( self ._pixmap . size () )
7061 else :
7162 return QGraphicsWidget .sizeHint (self , which , constraint )
7263
64+ def setKeepAspectRatio (self , keep ):
65+ if self ._keepAspect != keep :
66+ self ._keepAspect = bool (keep )
67+ self .update ()
68+
69+ def keepAspectRatio (self ):
70+ return self ._keepAspect
71+
7372 def paint (self , painter , option , widget = 0 ):
7473 if self ._pixmap .isNull ():
7574 return
7675
7776 rect = self .contentsRect ()
78-
79- pixsize = self .pixmapSize ()
77+ pixsize = QSizeF (self ._pixmap .size ())
78+ aspectmode = (Qt .KeepAspectRatio if self ._keepAspect
79+ else Qt .IgnoreAspectRatio )
80+ pixsize .scale (rect .size (), aspectmode )
8081 pixrect = QRectF (QPointF (0 , 0 ), pixsize )
8182 pixrect .moveCenter (rect .center ())
8283
@@ -132,13 +133,13 @@ def __init__(self, pixmap, title="", parent=None):
132133
133134 layout .addItem (self .pixmapWidget )
134135 layout .addItem (self .labelWidget )
135-
136+ layout . addStretch ()
136137 layout .setAlignment (self .pixmapWidget , Qt .AlignCenter )
137138 layout .setAlignment (self .labelWidget , Qt .AlignHCenter | Qt .AlignBottom )
139+
138140 self .setLayout (layout )
139141
140- self .setSizePolicy (QSizePolicy .MinimumExpanding ,
141- QSizePolicy .MinimumExpanding )
142+ self .setSizePolicy (QSizePolicy .Minimum , QSizePolicy .Minimum )
142143
143144 self .setFlag (QGraphicsItem .ItemIsSelectable , True )
144145 self .setTitle (title )
@@ -178,18 +179,14 @@ def paint(self, painter, option, widget=0):
178179 painter .save ()
179180 painter .setPen (QPen (QColor (125 , 162 , 206 , 192 )))
180181 painter .setBrush (QBrush (QColor (217 , 232 , 252 , 192 )))
181- painter .drawRoundedRect (QRectF ( contents . topLeft (),
182- self .geometry ().size ()), 3 , 3 )
182+ painter .drawRoundedRect (
183+ QRectF ( contents . topLeft (), self .geometry ().size ()), 3 , 3 )
183184 painter .restore ()
184185
185186 def _updatePixmapSize (self ):
186- pixmap = self .pixmap ()
187- if not pixmap .isNull () and self ._size .isValid ():
188- pixsize = QSizeF (self .pixmap ().size ())
189- pixsize .scale (self ._size , Qt .KeepAspectRatio )
190- else :
191- pixsize = QSizeF ()
192- self .pixmapWidget .setPixmapSize (pixsize )
187+ pixsize = QSizeF (self ._size )
188+ self .pixmapWidget .setMinimumSize (pixsize )
189+ self .pixmapWidget .setMaximumSize (pixsize )
193190
194191
195192class ThumbnailWidget (QGraphicsWidget ):
@@ -206,6 +203,16 @@ def setGeometry(self, geom):
206203 super (ThumbnailWidget , self ).setGeometry (geom )
207204 self .reflow (self .size ().width ())
208205
206+ def event (self , event ):
207+ if event .type () == QEvent .LayoutRequest :
208+ sh = self .effectiveSizeHint (Qt .PreferredSize )
209+ self .resize (sh )
210+ self .layout ().activate ()
211+ event .accept ()
212+ return True
213+ else :
214+ return super ().event (event )
215+
209216 def reflow (self , width ):
210217 if not self .layout ():
211218 return
@@ -231,6 +238,8 @@ def reflow(self, width):
231238 for i , item in enumerate (items ):
232239 layout .addItem (item , i // ncol , i % ncol )
233240
241+ layout .invalidate ()
242+
234243 def items (self ):
235244 layout = self .layout ()
236245 if layout :
@@ -330,14 +339,27 @@ class OWImageViewer(widget.OWWidget):
330339 imageAttr = settings .ContextSetting (0 )
331340 titleAttr = settings .ContextSetting (0 )
332341
333- zoom = settings .Setting (25 )
342+ imageSize = settings .Setting (100 )
334343 autoCommit = settings .Setting (False )
335344
336345 buttons_area_orientation = Qt .Vertical
337346 graph_name = "scene"
338347
339348 def __init__ (self ):
340349 super ().__init__ ()
350+ self .data = None
351+ self .allAttrs = []
352+ self .stringAttrs = []
353+
354+ self .thumbnailWidget = None
355+ self .sceneLayout = None
356+ self .selectedIndices = []
357+
358+ #: List of _ImageItems
359+ self .items = []
360+
361+ self ._errcount = 0
362+ self ._successcount = 0
341363
342364 self .info = gui .widgetLabel (
343365 gui .vBox (self .controlArea , "Info" ),
@@ -363,9 +385,9 @@ def __init__(self):
363385 )
364386
365387 gui .hSlider (
366- self .controlArea , self , "zoom " ,
367- box = "Zoom " , minValue = 1 , maxValue = 100 , step = 1 ,
368- callback = self .updateZoom ,
388+ self .controlArea , self , "imageSize " ,
389+ box = "Image Size " , minValue = 32 , maxValue = 1024 , step = 16 ,
390+ callback = self .updateSize ,
369391 createLabel = False
370392 )
371393 gui .rubber (self .controlArea )
@@ -388,16 +410,6 @@ def __init__(self):
388410 )
389411 self .resize (800 , 600 )
390412
391- self .thumbnailWidget = None
392- self .sceneLayout = None
393- self .selectedIndices = []
394-
395- #: List of _ImageItems
396- self .items = []
397-
398- self ._errcount = 0
399- self ._successcount = 0
400-
401413 self .loader = ImageLoader (self )
402414
403415 def setData (self , data ):
@@ -452,7 +464,7 @@ def setupScene(self):
452464 if numpy .isfinite (inst [attr ])]
453465 widget = ThumbnailWidget ()
454466 layout = widget .layout ()
455-
467+ size = QSizeF ( self . imageSize , self . imageSize )
456468 self .scene .addItem (widget )
457469
458470 for i , inst in enumerate (instances ):
@@ -462,7 +474,7 @@ def setupScene(self):
462474 thumbnail = GraphicsThumbnailWidget (
463475 QPixmap (), title = title , parent = widget
464476 )
465-
477+ thumbnail . setThumbnailSize ( size )
466478 thumbnail .setToolTip (url .toString ())
467479 thumbnail .instance = inst
468480 layout .addItem (thumbnail , i / 5 , i % 5 )
@@ -486,8 +498,6 @@ def set_pixmap(future, thumb=thumbnail):
486498 pixmap = QPixmap .fromImage (future .result ())
487499
488500 thumb .setPixmap (pixmap )
489- if not pixmap .isNull ():
490- thumb .setThumbnailSize (self .pixmapSize (pixmap ))
491501
492502 self ._updateStatus (future )
493503
@@ -503,11 +513,7 @@ def set_pixmap(future, thumb=thumbnail):
503513 self .sceneLayout = layout
504514
505515 if self .sceneLayout :
506- width = (self .sceneView .width () -
507- self .sceneView .verticalScrollBar ().width ())
508- self .thumbnailWidget .reflow (width )
509- self .thumbnailWidget .setPreferredWidth (width )
510- self .sceneLayout .activate ()
516+ self ._updateGeometryConstraints ()
511517
512518 def urlFromValue (self , value ):
513519 variable = value .variable
@@ -530,14 +536,6 @@ def urlFromValue(self, value):
530536 url .setScheme ("file" )
531537 return url
532538
533- def pixmapSize (self , pixmap ):
534- """
535- Return the preferred pixmap size based on the current `zoom` value.
536- """
537- scale = 2 * self .zoom / 100.0
538- size = QSizeF (pixmap .size ()) * scale
539- return size .expandedTo (QSizeF (16 , 16 ))
540-
541539 def _cancelAllFutures (self ):
542540 for item in self .items :
543541 if item .future is not None :
@@ -560,19 +558,12 @@ def clearScene(self):
560558 def thumbnailItems (self ):
561559 return [item .widget for item in self .items ]
562560
563- def updateZoom (self ):
561+ def updateSize (self ):
562+ size = QSizeF (self .imageSize , self .imageSize )
564563 for item in self .thumbnailItems ():
565- item .setThumbnailSize (self .pixmapSize (item .pixmap ()))
566-
567- if self .thumbnailWidget :
568- width = (self .sceneView .width () -
569- self .sceneView .verticalScrollBar ().width ())
564+ item .setThumbnailSize (size )
570565
571- self .thumbnailWidget .reflow (width )
572- self .thumbnailWidget .setPreferredWidth (width )
573-
574- if self .sceneLayout :
575- self .sceneLayout .activate ()
566+ self ._updateGeometryConstraints ()
576567
577568 def updateTitles (self ):
578569 titleAttr = self .allAttrs [self .titleAttr ]
@@ -632,24 +623,32 @@ def _updateStatus(self, future):
632623 def _updateSceneRect (self ):
633624 self .scene .setSceneRect (self .scene .itemsBoundingRect ())
634625
626+ def _updateGeometryConstraints (self ):
627+ # Update the thumbnail grid widget's width constraint (derived from
628+ # the viewport's width
629+ if self .thumbnailWidget is not None :
630+ width = (self .sceneView .width () -
631+ self .sceneView .verticalScrollBar ().width ())
632+ width = width - 2
633+ self .thumbnailWidget .reflow (width )
634+ self .thumbnailWidget .setPreferredWidth (width )
635+ self .thumbnailWidget .layout ().activate ()
636+
635637 def onDeleteWidget (self ):
636638 self ._cancelAllFutures ()
639+ self .clear ()
637640
638641 def eventFilter (self , receiver , event ):
639642 if receiver is self .sceneView and event .type () == QEvent .Resize \
640643 and self .thumbnailWidget :
641- width = (self .sceneView .width () -
642- self .sceneView .verticalScrollBar ().width ())
643-
644- self .thumbnailWidget .reflow (width )
645- self .thumbnailWidget .setPreferredWidth (width )
644+ self ._updateGeometryConstraints ()
646645
647646 return super (OWImageViewer , self ).eventFilter (receiver , event )
648647
649648
650649class ImageLoader (QObject ):
651650 #: A weakref to a QNetworkAccessManager used for image retrieval.
652- #: (we can only have only one QNetworkDiskCache opened on the same
651+ #: (we can only have one QNetworkDiskCache opened on the same
653652 #: directory)
654653 _NETMANAGER_REF = None
655654
@@ -740,17 +739,24 @@ def on_reply_ready(reply, future):
740739 return future
741740
742741
743- def main ():
742+ def main (argv = sys . argv ):
744743 import sip
745744
746- app = QApplication ([])
745+ app = QApplication (argv )
746+ argv = app .arguments ()
747747 w = OWImageViewer ()
748748 w .show ()
749749 w .raise_ ()
750- data = Orange .data .Table ('zoo-with-images' )
750+
751+ if len (argv ) > 1 :
752+ data = Orange .data .Table (argv [1 ])
753+ else :
754+ data = Orange .data .Table ('zoo-with-images' )
755+
751756 w .setData (data )
752757 rval = app .exec_ ()
753758 w .saveSettings ()
759+ w .onDeleteWidget ()
754760 sip .delete (w )
755761 app .processEvents ()
756762 return rval
0 commit comments