"position" option - dragging window by mouse
Andrew P.
9 years ago
1036 | 1036 | </object> |
1037 | 1037 | </child> |
1038 | 1038 | <child type="overlay"> |
1039 | <object class="GtkFrame" id="greeter_position_window_frame"> | |
1040 | <property name="width_request">100</property> | |
1041 | <property name="height_request">80</property> | |
1039 | <object class="GtkEventBox" id="greeter_position_window_box"> | |
1042 | 1040 | <property name="visible">True</property> |
1043 | 1041 | <property name="can_focus">False</property> |
1042 | <property name="events">GDK_BUTTON1_MOTION_MASK | GDK_BUTTON_PRESS_MASK | GDK_STRUCTURE_MASK</property> | |
1044 | 1043 | <property name="halign">start</property> |
1045 | 1044 | <property name="valign">start</property> |
1046 | <property name="border_width">2</property> | |
1047 | <property name="label_xalign">0</property> | |
1048 | <property name="shadow_type">in</property> | |
1049 | 1045 | <child> |
1050 | <object class="GtkGrid" id="greeter_position_window_grid"> | |
1046 | <object class="GtkFrame" id="greeter_position_window_frame"> | |
1047 | <property name="width_request">100</property> | |
1048 | <property name="height_request">80</property> | |
1051 | 1049 | <property name="visible">True</property> |
1052 | 1050 | <property name="can_focus">False</property> |
1053 | <property name="column_spacing">30</property> | |
1054 | <property name="row_homogeneous">True</property> | |
1055 | <property name="column_homogeneous">True</property> | |
1051 | <property name="border_width">2</property> | |
1052 | <property name="label_xalign">0</property> | |
1053 | <property name="shadow_type">in</property> | |
1056 | 1054 | <child> |
1057 | <placeholder/> | |
1055 | <object class="GtkGrid" id="greeter_position_window_grid"> | |
1056 | <property name="visible">True</property> | |
1057 | <property name="can_focus">False</property> | |
1058 | <property name="column_spacing">30</property> | |
1059 | <property name="row_homogeneous">True</property> | |
1060 | <property name="column_homogeneous">True</property> | |
1061 | <child> | |
1062 | <placeholder/> | |
1063 | </child> | |
1064 | <child> | |
1065 | <placeholder/> | |
1066 | </child> | |
1067 | <child> | |
1068 | <placeholder/> | |
1069 | </child> | |
1070 | <child> | |
1071 | <placeholder/> | |
1072 | </child> | |
1073 | <child> | |
1074 | <placeholder/> | |
1075 | </child> | |
1076 | <child> | |
1077 | <placeholder/> | |
1078 | </child> | |
1079 | <child> | |
1080 | <placeholder/> | |
1081 | </child> | |
1082 | <child> | |
1083 | <placeholder/> | |
1084 | </child> | |
1085 | <child> | |
1086 | <placeholder/> | |
1087 | </child> | |
1088 | </object> | |
1058 | 1089 | </child> |
1059 | <child> | |
1060 | <placeholder/> | |
1061 | </child> | |
1062 | <child> | |
1063 | <placeholder/> | |
1064 | </child> | |
1065 | <child> | |
1066 | <placeholder/> | |
1067 | </child> | |
1068 | <child> | |
1069 | <placeholder/> | |
1070 | </child> | |
1071 | <child> | |
1072 | <placeholder/> | |
1073 | </child> | |
1074 | <child> | |
1075 | <placeholder/> | |
1076 | </child> | |
1077 | <child> | |
1078 | <placeholder/> | |
1079 | </child> | |
1080 | <child> | |
1090 | <child type="label_item"> | |
1081 | 1091 | <placeholder/> |
1082 | 1092 | </child> |
1083 | 1093 | </object> |
1084 | </child> | |
1085 | <child type="label_item"> | |
1086 | <placeholder/> | |
1087 | 1094 | </child> |
1088 | 1095 | </object> |
1089 | 1096 | </child> |
109 | 109 | 'reader': (OptionEntry.StringPathEntry, None), |
110 | 110 | 'a11y-states': (OptionEntry.AccessibilityStatesEntry, ''), |
111 | 111 | 'allow-debugging': (OptionEntry.BooleanEntry, 'false'), }), |
112 | MonitorsGroup(WidgetsWrapper(self.builder))) | |
112 | MonitorsGroup(self.builder)) | |
113 | 113 | |
114 | 114 | for group in self._groups: |
115 | 115 | group.entry_added.connect(self.on_entry_added) |
656 | 656 | self._tools_menu = Gtk.Menu() |
657 | 657 | self._tools_menu.attach_to_widget(self._tools) |
658 | 658 | |
659 | unused_item = Gtk.CheckMenuItem( | |
660 | C_('option-entry|indicators', 'Show unused items')) | |
659 | unused_item = Gtk.CheckMenuItem(C_('option-entry|indicators', 'Show unused items')) | |
661 | 660 | unused_item.connect('toggled', self._tools_show_unused_toggled) |
662 | 661 | self._tools_menu.append(unused_item) |
663 | 662 | |
664 | header_item = Gtk.MenuItem( | |
665 | C_('option-entry|indicators', 'Predefined templates:')) | |
663 | header_item = Gtk.MenuItem(C_('option-entry|indicators', 'Predefined templates:')) | |
666 | 664 | header_item.props.sensitive = False |
667 | 665 | self._tools_menu.append(Gtk.SeparatorMenuItem()) |
668 | 666 | self._tools_menu.append(header_item) |
677 | 675 | |
678 | 676 | for title, value in templates: |
679 | 677 | item = Gtk.MenuItem(title) |
680 | item.connect( | |
681 | 'activate', self._on_tools_template_clicked, value) | |
678 | item.connect('activate', self._on_tools_template_clicked, value) | |
682 | 679 | self._tools_menu.append(item) |
683 | 680 | |
684 | 681 | self._tools_menu.show_all() |
16 | 16 | |
17 | 17 | from itertools import product |
18 | 18 | |
19 | from gi.repository import Gtk | |
19 | from gi.repository import ( | |
20 | Gdk, | |
21 | Gtk) | |
20 | 22 | |
21 | 23 | from lightdm_gtk_greeter_settings.helpers import WidgetsWrapper |
22 | 24 | from lightdm_gtk_greeter_settings.OptionEntry import BaseEntry |
52 | 54 | |
53 | 55 | @value.setter |
54 | 56 | def value(self, s): |
55 | value, _, anchor = s.partition(',') | |
56 | ||
57 | percents = value and value[-1] == '%' | |
58 | if percents: | |
59 | value = value[:-1] | |
60 | ||
61 | try: | |
62 | p = int(value) | |
63 | except ValueError: | |
64 | p = 0 | |
65 | ||
66 | negative = (p < 0) or (p == 0 and value and value[0] == '-') | |
67 | ||
68 | if not anchor or anchor not in ('start', 'center', 'end'): | |
69 | if negative: | |
70 | anchor = 'end' | |
71 | else: | |
72 | anchor = 'start' | |
57 | if isinstance(s, tuple): | |
58 | p, percents, negative, anchor = s | |
59 | else: | |
60 | value, __, anchor = s.partition(',') | |
61 | ||
62 | percents = value and value[-1] == '%' | |
63 | if percents: | |
64 | value = value[:-1] | |
65 | ||
66 | try: | |
67 | p = int(value) | |
68 | except ValueError: | |
69 | p = 0 | |
70 | ||
71 | negative = (p < 0) or (p == 0 and value and value[0] == '-') | |
72 | ||
73 | if not anchor or anchor not in ('start', 'center', 'end'): | |
74 | if negative: | |
75 | anchor = 'end' | |
76 | else: | |
77 | anchor = 'start' | |
78 | ||
73 | 79 | self._anchor = anchor |
74 | ||
75 | 80 | self._percents.props.active = percents |
76 | 81 | self._adjustment.props.upper = 100 if self._percents.props.active else 10000 |
77 | 82 | self._mirror.props.active = negative |
86 | 91 | def anchor(self, value): |
87 | 92 | self._anchor = value |
88 | 93 | |
94 | @property | |
95 | def negative(self): | |
96 | return self._mirror.props.active | |
97 | ||
98 | @negative.setter | |
99 | def negative(self, value): | |
100 | self._mirror.props.active = value | |
101 | ||
89 | 102 | def get_value_for_screen(self, screen: int): |
90 | 103 | p = int(self._adjustment.props.value) |
91 | 104 | |
97 | 110 | return int(p) |
98 | 111 | |
99 | 112 | def _on_percents_toggled(self, toggle): |
100 | self._adjustment.props.upper = 100 if toggle.props.active \ | |
101 | else 10000 | |
113 | self._adjustment.props.upper = 100 if toggle.props.active else 10000 | |
102 | 114 | self._on_changed(self) |
103 | 115 | |
104 | 116 | def _on_mirror_toggled(self, toggle): |
107 | 119 | def _on_value_changed(self, widget): |
108 | 120 | self._on_changed(self) |
109 | 121 | |
110 | ASSUMED_WINDOW_SIZE = 430, 240 | |
122 | AssumedWindowSize = 430, 240 | |
111 | 123 | |
112 | 124 | def __init__(self, widgets): |
113 | 125 | super().__init__(widgets) |
118 | 130 | |
119 | 131 | self._screen_frame = widgets['screen_frame'] |
120 | 132 | self._screen_overlay = widgets['screen_overlay'] |
121 | self._window_frame = widgets['window_frame'] | |
122 | self._grid = widgets['window_grid'] | |
133 | window_box = widgets['window_box'] | |
134 | grid = widgets['window_grid'] | |
135 | ||
136 | self._motion = False | |
137 | ||
138 | window_box.connect('motion-notify-event', self._on_window_motion) | |
139 | window_box.connect('button-press-event', self._on_window_button_press) | |
140 | window_box.connect('button-release-event', self._on_window_button_release) | |
123 | 141 | |
124 | 142 | # Creating points grid |
125 | 143 | anchors_align = (Gtk.Align.START, Gtk.Align.CENTER, Gtk.Align.END) |
133 | 151 | if w != anchors[0][-1]: |
134 | 152 | w.props.group = anchors[0][-1] |
135 | 153 | w.connect('toggled', self._on_anchor_toggled, x_anchor, y_anchor) |
136 | self._grid.attach(w, left, top, 1, 1) | |
154 | grid.attach(w, left, top, 1, 1) | |
137 | 155 | self._anchors[x_anchor, y_anchor] = w |
138 | 156 | |
139 | self._grid.show_all() | |
157 | grid.show_all() | |
140 | 158 | |
141 | 159 | self._x = PositionEntry.Dimension(WidgetsWrapper(widgets, 'x'), self._on_dimension_changed) |
142 | 160 | self._y = PositionEntry.Dimension(WidgetsWrapper(widgets, 'y'), self._on_dimension_changed) |
143 | 161 | |
144 | 162 | self._on_gdk_screen_changed() |
145 | 163 | |
146 | self._screen_overlay.connect( | |
147 | 'get-child-position', self._on_screen_overlay_get_child_position) | |
164 | self._screen_overlay.connect('get-child-position', | |
165 | self._on_screen_overlay_get_child_position) | |
148 | 166 | self._screen_overlay.connect('screen-changed', self._on_gdk_screen_changed) |
149 | 167 | |
150 | 168 | def _get_value(self): |
191 | 209 | |
192 | 210 | scale = screen.width / self._screen_size[0] |
193 | 211 | |
194 | width = int(self.ASSUMED_WINDOW_SIZE[0] * scale) | |
195 | height = int(self.ASSUMED_WINDOW_SIZE[1] * scale) | |
212 | width = int(self.AssumedWindowSize[0] * scale) | |
213 | height = int(self.AssumedWindowSize[1] * scale) | |
196 | 214 | |
197 | 215 | # Set desired size |
198 | 216 | child.set_size_request(width, height) |
224 | 242 | geometry = screen.get_monitor_geometry(screen.get_primary_monitor()) |
225 | 243 | self._screen_size = geometry.width, geometry.height |
226 | 244 | self._screen_frame.props.ratio = geometry.width / geometry.height |
245 | ||
246 | def _on_window_motion(self, widget, event): | |
247 | if not event.state & Gdk.ModifierType.BUTTON1_MASK: | |
248 | return False | |
249 | ||
250 | screen = self._screen_overlay.get_allocation() | |
251 | x, y = widget.translate_coordinates(self._screen_overlay, event.x, event.y) | |
252 | ||
253 | for d, p in ((self._x, int(100 * x / screen.width)), | |
254 | (self._y, int(100 * y / screen.height))): | |
255 | if p < 0: | |
256 | p = 0 | |
257 | elif p > 100: | |
258 | p = 100 | |
259 | if d.negative: | |
260 | d.value = p - 100, True, True, d.anchor | |
261 | else: | |
262 | d.value = p, True, False, d.anchor | |
263 | ||
264 | self._motion = True | |
265 | self._last_window_allocation = None | |
266 | self._screen_overlay.queue_resize() | |
267 | return True | |
268 | ||
269 | def _on_window_button_press(self, widget, event): | |
270 | if event.button == 1: | |
271 | self._motion = False | |
272 | ||
273 | def _on_window_button_release(self, widget, event): | |
274 | if self._motion and event.button == 1: | |
275 | self._motion = False | |
276 | self._emit_changed() |
57 | 57 | __all__ = [ |
58 | 58 | 'bool2string', |
59 | 59 | 'C_', |
60 | 'clamp', | |
60 | 61 | 'check_path_accessibility', |
61 | 62 | 'DefaultValueDict', |
62 | 63 | 'file_is_readable_by_greeter', |
197 | 198 | return None |
198 | 199 | |
199 | 200 | |
201 | def clamp(v, a, b): | |
202 | if v < a: | |
203 | return a | |
204 | if v > b: | |
205 | return b | |
206 | return v | |
207 | ||
208 | ||
200 | 209 | class DefaultValueDict(defaultdict): |
201 | 210 | |
202 | 211 | def __init__(self, *items, default=None, factory=None, source=None): |