@@ -667,6 +667,9 @@ def _wrap_notebook_pages(self):
667667 nb = self .wTree .get_object ("notebook1" )
668668 if nb is None :
669669 return
670+ # Removing/reinserting pages drifts the selection, so remember the
671+ # startup page and restore it after wrapping.
672+ current = nb .get_current_page ()
670673 self ._prefs_index = - 1
671674 for i in range (nb .get_n_pages ()):
672675 page = nb .get_nth_page (i )
@@ -685,8 +688,49 @@ def _wrap_notebook_pages(self):
685688 viewport = scroller .get_child ()
686689 if isinstance (viewport , Gtk .Viewport ):
687690 viewport .set_shadow_type (Gtk .ShadowType .NONE )
691+ self ._enable_drag_scroll (scroller )
688692 scroller .show_all ()
689693 nb .insert_page (scroller , label , i )
694+ if current >= 0 :
695+ nb .set_current_page (current )
696+
697+ def _enable_drag_scroll (self , scroller ):
698+ # Touchy is a touchscreen UI, so let the user drag the content to
699+ # scroll it (finger or mouse), not just the wheel/scrollbar. A drag
700+ # gesture pans the adjustments once movement passes a small
701+ # threshold; shorter presses fall through so buttons still click.
702+ try :
703+ gesture = Gtk .GestureDrag .new (scroller )
704+ except Exception :
705+ return
706+ gesture .set_propagation_phase (Gtk .PropagationPhase .BUBBLE )
707+ if not hasattr (self , "_drag_gestures" ):
708+ self ._drag_gestures = []
709+ self ._drag_gestures .append (gesture )
710+ start = {}
711+
712+ def on_begin (g , x , y ):
713+ va = scroller .get_vadjustment ()
714+ ha = scroller .get_hadjustment ()
715+ start ["v" ] = va .get_value () if va is not None else 0
716+ start ["h" ] = ha .get_value () if ha is not None else 0
717+ start ["active" ] = False
718+
719+ def on_update (g , off_x , off_y ):
720+ if not start .get ("active" ):
721+ if abs (off_x ) < 8 and abs (off_y ) < 8 :
722+ return
723+ start ["active" ] = True
724+ g .set_state (Gtk .EventSequenceState .CLAIMED )
725+ va = scroller .get_vadjustment ()
726+ ha = scroller .get_hadjustment ()
727+ if va is not None :
728+ va .set_value (start ["v" ] - off_y )
729+ if ha is not None :
730+ ha .set_value (start ["h" ] - off_x )
731+
732+ gesture .connect ("drag-begin" , on_begin )
733+ gesture .connect ("drag-update" , on_update )
690734
691735 def _constrain_to_monitor (self ):
692736 # Wrap the content in a scroller so the window can be bounded to the
@@ -752,10 +796,16 @@ def _fit_to_monitor(self, win, event, scroller, child):
752796 if monitor is None :
753797 monitor = display .get_monitor (0 )
754798 area = monitor .get_workarea ()
755- scroller .set_min_content_width (area .width )
799+ # Bound the scroller (and thus the window) to the work area so
800+ # oversized content scrolls instead of growing off-screen, but
801+ # leave the minimum at 0 so the user can still resize smaller.
756802 scroller .set_max_content_width (area .width )
757- scroller .set_min_content_height (area .height )
758803 scroller .set_max_content_height (area .height )
804+ # Open at the content size, capped to the screen; this avoids an
805+ # off-screen window without forcing a screen-sized minimum.
806+ nat = child .get_preferred_size ()[1 ]
807+ win .resize (min (nat .width , area .width ),
808+ min (nat .height , area .height ))
759809 GLib .idle_add (self ._offer_fit , child , area )
760810 except Exception :
761811 pass
0 commit comments