@@ -679,6 +679,9 @@ def _wrap_notebook_pages(self):
679679 nb = self .wTree .get_object ("notebook1" )
680680 if nb is None :
681681 return
682+ # Removing/reinserting pages drifts the selection, so remember the
683+ # startup page and restore it after wrapping.
684+ current = nb .get_current_page ()
682685 self ._prefs_index = - 1
683686 for i in range (nb .get_n_pages ()):
684687 page = nb .get_nth_page (i )
@@ -697,8 +700,49 @@ def _wrap_notebook_pages(self):
697700 viewport = scroller .get_child ()
698701 if isinstance (viewport , Gtk .Viewport ):
699702 viewport .set_shadow_type (Gtk .ShadowType .NONE )
703+ self ._enable_drag_scroll (scroller )
700704 scroller .show_all ()
701705 nb .insert_page (scroller , label , i )
706+ if current >= 0 :
707+ nb .set_current_page (current )
708+
709+ def _enable_drag_scroll (self , scroller ):
710+ # Touchy is a touchscreen UI, so let the user drag the content to
711+ # scroll it (finger or mouse), not just the wheel/scrollbar. A drag
712+ # gesture pans the adjustments once movement passes a small
713+ # threshold; shorter presses fall through so buttons still click.
714+ try :
715+ gesture = Gtk .GestureDrag .new (scroller )
716+ except Exception :
717+ return
718+ gesture .set_propagation_phase (Gtk .PropagationPhase .BUBBLE )
719+ if not hasattr (self , "_drag_gestures" ):
720+ self ._drag_gestures = []
721+ self ._drag_gestures .append (gesture )
722+ start = {}
723+
724+ def on_begin (g , x , y ):
725+ va = scroller .get_vadjustment ()
726+ ha = scroller .get_hadjustment ()
727+ start ["v" ] = va .get_value () if va is not None else 0
728+ start ["h" ] = ha .get_value () if ha is not None else 0
729+ start ["active" ] = False
730+
731+ def on_update (g , off_x , off_y ):
732+ if not start .get ("active" ):
733+ if abs (off_x ) < 8 and abs (off_y ) < 8 :
734+ return
735+ start ["active" ] = True
736+ g .set_state (Gtk .EventSequenceState .CLAIMED )
737+ va = scroller .get_vadjustment ()
738+ ha = scroller .get_hadjustment ()
739+ if va is not None :
740+ va .set_value (start ["v" ] - off_y )
741+ if ha is not None :
742+ ha .set_value (start ["h" ] - off_x )
743+
744+ gesture .connect ("drag-begin" , on_begin )
745+ gesture .connect ("drag-update" , on_update )
702746
703747 def _constrain_to_monitor (self ):
704748 # Wrap the content in a scroller so the window can be bounded to the
@@ -764,10 +808,16 @@ def _fit_to_monitor(self, win, event, scroller, child):
764808 if monitor is None :
765809 monitor = display .get_monitor (0 )
766810 area = monitor .get_workarea ()
767- scroller .set_min_content_width (area .width )
811+ # Bound the scroller (and thus the window) to the work area so
812+ # oversized content scrolls instead of growing off-screen, but
813+ # leave the minimum at 0 so the user can still resize smaller.
768814 scroller .set_max_content_width (area .width )
769- scroller .set_min_content_height (area .height )
770815 scroller .set_max_content_height (area .height )
816+ # Open at the content size, capped to the screen; this avoids an
817+ # off-screen window without forcing a screen-sized minimum.
818+ nat = child .get_preferred_size ()[1 ]
819+ win .resize (min (nat .width , area .width ),
820+ min (nat .height , area .height ))
771821 GLib .idle_add (self ._offer_fit , child , area )
772822 except Exception :
773823 pass
0 commit comments