gtk-stream 0.9__tar.gz → 0.11__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. {gtk_stream-0.9 → gtk_stream-0.11}/PKG-INFO +1 -1
  2. {gtk_stream-0.9 → gtk_stream-0.11}/gtk_stream/_version.py +2 -2
  3. gtk_stream-0.11/gtk_stream/application.py +140 -0
  4. {gtk_stream-0.9 → gtk_stream-0.11}/gtk_stream/documents/__init__.py +1 -0
  5. {gtk_stream-0.9 → gtk_stream-0.11}/gtk_stream/documents/classes/Button.py +4 -3
  6. {gtk_stream-0.9 → gtk_stream-0.11}/gtk_stream/documents/classes/Document.py +7 -1
  7. {gtk_stream-0.9 → gtk_stream-0.11}/gtk_stream/documents/classes/Dropdown.py +7 -3
  8. {gtk_stream-0.9 → gtk_stream-0.11}/gtk_stream/documents/classes/Entry.py +4 -2
  9. gtk_stream-0.11/gtk_stream/documents/classes/Scale.py +30 -0
  10. {gtk_stream-0.9 → gtk_stream-0.11}/gtk_stream/documents/classes/Switch.py +4 -4
  11. {gtk_stream-0.9 → gtk_stream-0.11}/gtk_stream/parser.py +40 -75
  12. {gtk_stream-0.9 → gtk_stream-0.11}/gtk_stream/properties.py +18 -1
  13. {gtk_stream-0.9 → gtk_stream-0.11}/gtk_stream.egg-info/PKG-INFO +1 -1
  14. {gtk_stream-0.9 → gtk_stream-0.11}/gtk_stream.egg-info/SOURCES.txt +1 -0
  15. gtk_stream-0.9/gtk_stream/application.py +0 -101
  16. {gtk_stream-0.9 → gtk_stream-0.11}/README.md +0 -0
  17. {gtk_stream-0.9 → gtk_stream-0.11}/gtk-stream +0 -0
  18. {gtk_stream-0.9 → gtk_stream-0.11}/gtk_stream/__init__.py +0 -0
  19. {gtk_stream-0.9 → gtk_stream-0.11}/gtk_stream/command_line.py +0 -0
  20. {gtk_stream-0.9 → gtk_stream-0.11}/gtk_stream/common.py +0 -0
  21. {gtk_stream-0.9 → gtk_stream-0.11}/gtk_stream/documents/classes/Box.py +0 -0
  22. {gtk_stream-0.9 → gtk_stream-0.11}/gtk_stream/documents/classes/FlowBox.py +0 -0
  23. {gtk_stream-0.9 → gtk_stream-0.11}/gtk_stream/documents/classes/Frame.py +0 -0
  24. {gtk_stream-0.9 → gtk_stream-0.11}/gtk_stream/documents/classes/Grid.py +0 -0
  25. {gtk_stream-0.9 → gtk_stream-0.11}/gtk_stream/documents/classes/Label.py +0 -0
  26. {gtk_stream-0.9 → gtk_stream-0.11}/gtk_stream/documents/classes/Paned.py +0 -0
  27. {gtk_stream-0.9 → gtk_stream-0.11}/gtk_stream/documents/classes/Picture.py +0 -0
  28. {gtk_stream-0.9 → gtk_stream-0.11}/gtk_stream/documents/classes/ProgressBar.py +0 -0
  29. {gtk_stream-0.9 → gtk_stream-0.11}/gtk_stream/documents/classes/ScrolledWindow.py +0 -0
  30. {gtk_stream-0.9 → gtk_stream-0.11}/gtk_stream/documents/classes/Separator.py +0 -0
  31. {gtk_stream-0.9 → gtk_stream-0.11}/gtk_stream/documents/classes/Stack.py +0 -0
  32. {gtk_stream-0.9 → gtk_stream-0.11}/gtk_stream/documents/classes/__init__.py +0 -0
  33. {gtk_stream-0.9 → gtk_stream-0.11}/gtk_stream.egg-info/dependency_links.txt +0 -0
  34. {gtk_stream-0.9 → gtk_stream-0.11}/gtk_stream.egg-info/entry_points.txt +0 -0
  35. {gtk_stream-0.9 → gtk_stream-0.11}/gtk_stream.egg-info/requires.txt +0 -0
  36. {gtk_stream-0.9 → gtk_stream-0.11}/gtk_stream.egg-info/top_level.txt +0 -0
  37. {gtk_stream-0.9 → gtk_stream-0.11}/pyproject.toml +0 -0
  38. {gtk_stream-0.9 → gtk_stream-0.11}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: gtk-stream
3
- Version: 0.9
3
+ Version: 0.11
4
4
  Summary: A simple stream-oriented GUI protocol
5
5
  Author-email: Marc Coiffier <marc.coiffier@univ-grenoble-alpes.fr>
6
6
  Project-URL: Homepage, https://coiffier.net/projects/gtk-stream/
@@ -12,5 +12,5 @@ __version__: str
12
12
  __version_tuple__: VERSION_TUPLE
13
13
  version_tuple: VERSION_TUPLE
14
14
 
15
- __version__ = version = '0.9'
16
- __version_tuple__ = version_tuple = (0, 9)
15
+ __version__ = version = '0.11'
16
+ __version_tuple__ = version_tuple = (0, 11)
@@ -0,0 +1,140 @@
1
+ # Gtk-Stream : A stream-based GUI protocol
2
+ # Copyright (C) 2024 Marc Coiffier
3
+ #
4
+ # This program is free software: you can redistribute it and/or modify
5
+ # it under the terms of the GNU General Public License as published by
6
+ # the Free Software Foundation, either version 3 of the License, or
7
+ # (at your option) any later version.
8
+ #
9
+ # This program is distributed in the hope that it will be useful,
10
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
+ # GNU General Public License for more details.
13
+ #
14
+ # You should have received a copy of the GNU General Public License
15
+ # along with this program. If not, see <https://www.gnu.org/licenses/>.
16
+
17
+ import sys
18
+ from . import Gtk, GLib, Gdk
19
+ from .common import printEvent
20
+ from .properties import parse_property, get_prop_type, set_parse_prop
21
+
22
+ class _Object:
23
+ pass
24
+
25
+ def app_message(name, store = None):
26
+ """A decorator for methods that are both called from the pilot
27
+ application and need access to the gtk main thread"""
28
+ def app_message_f(f):
29
+ def ret(self, *args, **kwargs):
30
+ def cb():
31
+ f(self, *args, **kwargs)
32
+ self.run_when_idle(cb)
33
+ ret.__tag_name__ = name
34
+ ret.__store__ = store
35
+ return ret
36
+ return app_message_f
37
+
38
+ def single_store():
39
+ store = _Object()
40
+ def setChild(child):
41
+ store.child = child
42
+ return (lambda: store.child, setChild, None)
43
+ def multiple_store():
44
+ children = []
45
+ return (lambda: children, children.append, None)
46
+ def style_store():
47
+ style = []
48
+ return (lambda: " ".join(style),None, style.append)
49
+
50
+ class GtkStreamApp(Gtk.Application):
51
+ def __init__(self, logger, name = None, **kwargs):
52
+ super().__init__(**kwargs)
53
+ self.logger = logger
54
+ if name != None:
55
+ GLib.set_application_name(name)
56
+ self.namedWidgets = { }
57
+ self.namedWindows = { }
58
+
59
+ # The first messages from the pilot may arrive before the
60
+ # application is ready to process them.
61
+ #
62
+ # If that happens, store the actions until they can be taken
63
+ # (when the "startup" signal is called)
64
+ callback_queue = []
65
+ def run_when_idle_before_startup(cb):
66
+ callback_queue.append(cb)
67
+ self.run_when_idle = run_when_idle_before_startup
68
+
69
+ def on_startup(_):
70
+ for cb in callback_queue:
71
+ GLib.idle_add(cb)
72
+ self.run_when_idle = GLib.idle_add
73
+ self.connect('startup', on_startup)
74
+
75
+ def nameWidget(self, id, w):
76
+ if id is not None:
77
+ self.namedWidgets[id] = w
78
+
79
+ @app_message('file-dialog')
80
+ def openFileDialog(self, id, parent):
81
+ dialog = Gtk.FileDialog()
82
+ dialog.props.modal = True
83
+ def on_choose(_, b):
84
+ try:
85
+ file = dialog.open_finish(b)
86
+ print(f"{id}:selected:{file.get_path()}")
87
+ sys.stdout.flush()
88
+ except GLib.GError as e:
89
+ print(f"{id}:none-selected")
90
+ sys.stdout.flush()
91
+
92
+ dialog.open(parent = self.namedWindows[parent], callback = on_choose)
93
+
94
+ @app_message('window', single_store)
95
+ def newWindow(self, document, id, **attrs):
96
+ win = Gtk.Window(application=self)
97
+ for (attr_name, attr_val) in attrs.items():
98
+ set_parse_prop(self, win, attr_name, attr_val)
99
+ self.namedWindows[id] = win
100
+ win.set_child(document.render())
101
+ win.connect('close-request', printEvent(self.logger, 'close-request', id))
102
+ win.present()
103
+
104
+ @app_message('style', style_store)
105
+ def addStyle(self, style):
106
+ provider = Gtk.CssProvider()
107
+ provider.load_from_data(style)
108
+ Gtk.StyleContext.add_provider_for_display(Gdk.Display.get_default(), provider, Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION)
109
+
110
+ @app_message('add-icon-path')
111
+ def addIconPath(self, path):
112
+ theme = Gtk.IconTheme.get_for_display(Gdk.Display.get_default())
113
+ theme.add_search_path(path)
114
+
115
+ @app_message('close-window')
116
+ def closeWindow(self, id):
117
+ self.namedWindows[id].close()
118
+
119
+ @app_message('remove')
120
+ def removeWidget(self, id):
121
+ w = self.namedWidgets[id]
122
+ w.get_parent().remove(w)
123
+
124
+ @app_message('insert', multiple_store)
125
+ def insertWidgets(self, documents, into):
126
+ for doc in documents:
127
+ self.insertWidget(doc, into)
128
+
129
+ def insertWidget(self, document, into):
130
+ if into in self.namedWidgets:
131
+ w = self.namedWidgets[into]
132
+ w.insert_child(document)
133
+ else:
134
+ raise Exception(f"Error: unknown widget id '{into}'")
135
+
136
+ @app_message('set-prop')
137
+ def setProp(self, id, name, value):
138
+ w = self.namedWidgets[id]
139
+ w.set_property(name, parse_property(get_prop_type(w.__class__, name), value)(self))
140
+
@@ -6,6 +6,7 @@ from .classes.ProgressBar import ProgressBar
6
6
  from .classes.Separator import Separator
7
7
 
8
8
  from .classes.Button import Button, LinkButton
9
+ from .classes.Scale import Scale
9
10
  from .classes.Dropdown import Dropdown, Item
10
11
  from .classes.Switch import Switch
11
12
  from .classes.Entry import Entry
@@ -15,7 +15,6 @@
15
15
  # along with this program. If not, see <https://www.gnu.org/licenses/>.
16
16
 
17
17
  from ... import Gtk
18
- from ...common import printEvent
19
18
  from .. import Document
20
19
 
21
20
  class Button(Document):
@@ -24,7 +23,7 @@ class Button(Document):
24
23
  super().__init__(app, id = id, **kwargs)
25
24
  def render_raw(self):
26
25
  button = Gtk.Button()
27
- button.connect('clicked', printEvent(self.app.logger, 'clicked', self.id))
26
+ self.connect_event(button, 'clicked', 'clicked')
28
27
  return button
29
28
  def insert_child(self, w, d):
30
29
  w.set_child(d.render())
@@ -35,7 +34,9 @@ class LinkButton(Button):
35
34
  super().__init__(app, id=id, **kwargs)
36
35
  def render_raw(self):
37
36
  button = Gtk.LinkButton()
38
- button.connect('activate-link', printEvent(self.app.logger, 'clicked', self.id, True))
37
+ self.connect_event(
38
+ button, 'activate-link', 'clicked',
39
+ retval = True)
39
40
  return button
40
41
  def insert_child(self, w, d):
41
42
  w.set_child(d.render())
@@ -15,15 +15,21 @@
15
15
  # along with this program. If not, see <https://www.gnu.org/licenses/>.
16
16
 
17
17
  from ...properties import parse_property, get_prop_type
18
+ from ...common import printEvent
18
19
 
19
20
  class Document:
20
21
  __g_class__ = None
21
22
  def __init__(self, app, id = None, **attrs):
22
23
  self.id = id
23
24
  self.app = app
24
- self.props = { attr: parse_property(get_prop_type(self.__g_class__, attr), val) for (attr, val) in attrs.items() }
25
+ self.props = {
26
+ attr: parse_property(get_prop_type(self.__g_class__, attr), val)
27
+ for (attr, val) in attrs.items()
28
+ }
25
29
  self.children = []
26
30
 
31
+ def connect_event(self, w, event, name, **printEvent_kwargs):
32
+ w.connect(event, printEvent(self.app.logger, name, self.id, **printEvent_kwargs))
27
33
  def add_child(self, child):
28
34
  self.children.append(child)
29
35
 
@@ -16,7 +16,6 @@
16
16
 
17
17
  from ... import Gtk, Gio, GObject
18
18
  from .. import Document
19
- from ...common import printEvent
20
19
 
21
20
  class Item(Document):
22
21
  def __init__(self, app, value, **kwargs):
@@ -57,9 +56,14 @@ class Dropdown(Document):
57
56
  factory.connect("setup", on_list_setup)
58
57
  factory.connect("bind", on_list_bind)
59
58
 
60
- ret = Gtk.DropDown(model=model, expression=Gtk.PropertyExpression.new(_ItemObject, None, 'item_value'), factory=factory)
59
+ ret = Gtk.DropDown(
60
+ model=model,
61
+ expression=Gtk.PropertyExpression.new(_ItemObject, None, 'item_value'),
62
+ factory=factory)
61
63
 
62
- ret.connect('notify::selected-item', printEvent(self.app.logger, 'selected', self.id, get_data = lambda w,_: w.get_selected_item().value))
64
+ self.connect_event(
65
+ ret, 'notify::selected-item', 'selected',
66
+ get_data = lambda w,_: w.get_selected_item().value)
63
67
  return ret
64
68
  def insert_child(self, w, d):
65
69
  pass
@@ -15,7 +15,6 @@
15
15
  # along with this program. If not, see <https://www.gnu.org/licenses/>.
16
16
 
17
17
  from ... import Gtk
18
- from ...common import printEvent
19
18
  from .. import Document
20
19
 
21
20
  class Entry(Document):
@@ -24,5 +23,8 @@ class Entry(Document):
24
23
  super().__init__(app, id = id, **kwargs)
25
24
  def render_raw(self):
26
25
  entry = Gtk.Entry()
27
- entry.connect('changed', printEvent(self.app.logger, 'changed', self.id, get_data = lambda _: entry.get_text()))
26
+ self.connect_event(
27
+ entry, 'changed', 'changed',
28
+ get_data = lambda _: entry.get_text()
29
+ )
28
30
  return entry
@@ -0,0 +1,30 @@
1
+ # Gtk-Stream : A stream-based GUI protocol
2
+ # Copyright (C) 2024 Marc Coiffier
3
+ #
4
+ # This program is free software: you can redistribute it and/or modify
5
+ # it under the terms of the GNU General Public License as published by
6
+ # the Free Software Foundation, either version 3 of the License, or
7
+ # (at your option) any later version.
8
+ #
9
+ # This program is distributed in the hope that it will be useful,
10
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
+ # GNU General Public License for more details.
13
+ #
14
+ # You should have received a copy of the GNU General Public License
15
+ # along with this program. If not, see <https://www.gnu.org/licenses/>.
16
+
17
+ from ... import Gtk
18
+ from .. import Document
19
+
20
+ class Scale(Document):
21
+ __g_class__ = Gtk.Scale
22
+ def __init__(self, app, id, **kwargs):
23
+ super().__init__(app, id = id, **kwargs)
24
+ def render_raw(self):
25
+ scale = Gtk.Scale()
26
+ self.connect_event(
27
+ scale, 'value-changed', 'changed',
28
+ get_data = lambda _: str(scale.get_value())
29
+ )
30
+ return scale
@@ -15,7 +15,6 @@
15
15
  # along with this program. If not, see <https://www.gnu.org/licenses/>.
16
16
 
17
17
  from ... import Gtk
18
- from ...common import printEvent
19
18
  from .. import Document
20
19
  from ...properties import parse_property
21
20
 
@@ -26,7 +25,8 @@ class Switch(Document):
26
25
  self.managed = parse_property('gboolean', managed)(app)
27
26
  def render_raw(self):
28
27
  ret = Gtk.Switch()
29
- ret.connect('state-set', printEvent(self.app.logger, 'switch', self.id,
30
- retval = self.managed,
31
- get_data = lambda _,state: "on" if state else "off"))
28
+ self.connect_event(
29
+ ret, 'state-set', 'switch',
30
+ retval = self.managed,
31
+ get_data = lambda _,state: "on" if state else "off")
32
32
  return ret
@@ -14,6 +14,7 @@
14
14
  # You should have received a copy of the GNU General Public License
15
15
  # along with this program. If not, see <https://www.gnu.org/licenses/>.
16
16
 
17
+ import functools
17
18
  import threading
18
19
  import signal
19
20
  import sys
@@ -24,9 +25,6 @@ from . import documents as docs
24
25
 
25
26
  from .application import GtkStreamApp
26
27
 
27
- class _Object:
28
- pass
29
-
30
28
  WIDGET_DOCUMENTS = {
31
29
  'progress-bar' : docs.ProgressBar,
32
30
  'label' : docs.Label,
@@ -49,7 +47,9 @@ WIDGET_DOCUMENTS = {
49
47
  'stack' : docs.Stack,
50
48
  'flow-box' : docs.FlowBox,
51
49
  'flow-box-prepend': docs.FlowBoxPrepend,
52
- 'entry' : docs.Entry
50
+ 'entry' : docs.Entry,
51
+ 'scale' : docs.Scale
52
+
53
53
  }
54
54
 
55
55
  class GtkStreamXMLHandler(sax.ContentHandler):
@@ -109,83 +109,48 @@ class GtkStreamXMLHandler(sax.ContentHandler):
109
109
  self.quit_application()
110
110
  signal.signal(signal.SIGINT, on_sigint)
111
111
 
112
+ # Get all messages directly from the application
113
+ # class. This allows defining new messages without
114
+ # touching the parser
115
+ self.messages = {
116
+ f.__tag_name__: self.startMessage(functools.partial(f,self.app), f.__store__)
117
+ for f in GtkStreamApp.__dict__.values()
118
+ if hasattr(f, '__tag_name__')
119
+ }
120
+ self.logger.debug("Messages: %s", self.messages)
121
+
112
122
  self.transition_enter = self.transE_message
113
123
  self.transition_leave = self.transL_tag('application', self.transE_final, self.transL_final)
114
124
  case _:
115
125
  raise Exception("Error: expected 'application' tag")
116
- def transE_message(self, name, attrs):
117
- leave_parent = self.transition_leave
118
- match name:
119
- case 'style':
120
- style = _Object()
121
- style.chars = []
122
- def onchars(s):
123
- style.chars.append(s)
124
- def leave():
125
- self.transition_chars = self.ignore_chars
126
- self.app.addStyle(" ".join(style.chars))
127
- self.transition_chars = onchars
128
- self.transition_enter = self.transE_final
129
- self.transition_leave = self.transL_tag('style', self.transE_message, leave_parent, leave)
130
-
131
- case 'window':
132
- if 'id' in attrs:
133
- store = _Object()
134
- def leave():
135
- self.app.newWindow(store.child, **attrs)
136
- def setChild(c):
137
- store.child = c
138
- self.transition_enter = self.transE_addChild(setChild)
139
- self.transition_leave = self.transL_tag('window', self.transE_message, leave_parent, leave)
140
- else:
141
- raise Exception("Error: expected attribute 'id' in 'window' tag")
142
-
143
- case 'file-dialog':
144
- id = attrs.get('id')
145
- parent = attrs.get('parent')
146
- if id != None and parent != None:
147
- self.app.openFileDialog(id, parent)
148
- self.transition_enter = self.transE_final
149
- self.transition_leave = self.transL_tag('file-dialog', self.transE_message, leave_parent)
150
- else:
151
- raise Exception("Error: expected 'id' and 'parent' attributes on 'file-chooser'")
152
-
153
- case 'close-window':
154
- if 'id' in attrs:
155
- def leave():
156
- self.app.closeWindow(attrs['id'])
157
- self.transition_enter = self.transE_final
158
- self.transition_leave = self.transL_tag('close-window', self.transE_message, leave_parent, leave)
159
- else:
160
- raise Exception("Error: expected 'id' attribute in 'close-window' tag")
161
126
 
162
- case 'set-prop':
163
- self.app.setProp(**attrs)
127
+ def startMessage(self, f, child = None):
128
+ if child != None:
129
+ def ret(name,attrs):
130
+ getC, setC, setChars = child()
131
+ old_chars = self.transition_chars
132
+ def leave():
133
+ if setChars != None:
134
+ self.transition_chars = old_chars
135
+ f(getC(),**attrs)
136
+ if setChars != None:
137
+ self.transition_chars = setChars
138
+ self.transition_enter = self.transE_addChild(setC)
139
+ self.transition_leave = self.transL_tag(name, self.transE_message, self.transition_leave, leave)
140
+ else:
141
+ def ret(name, attrs):
142
+ def leave():
143
+ f(**attrs)
164
144
  self.transition_enter = self.transE_final
165
- self.transition_leave = self.transL_tag('set-prop', self.transE_message, leave_parent)
166
-
167
- case 'insert':
168
- if 'into' in attrs:
169
- children = []
170
- def leave():
171
- for child in children:
172
- self.app.insertWidget(attrs['into'], child)
173
- self.transition_enter = self.transE_addChild(lambda child: children.append(child))
174
- self.transition_leave = self.transL_tag('insert', self.transE_message, leave_parent, leave)
175
- else:
176
- raise Exception("Expected 'to' attribute of 'append' message")
177
-
178
- case 'remove':
179
- if 'id' in attrs:
180
- def leave():
181
- self.app.removeWidget(attrs['id'])
182
- self.transition_enter = self.transE_final
183
- self.transition_leave = self.transL_tag('remove', self.transE_message, leave_parent, leave)
184
- else:
185
- raise Exception("Expected 'id' attribute of 'remove' message")
145
+ self.transition_leave = self.transL_tag(name, self.transE_message, self.transition_leave, leave)
146
+ return ret
186
147
 
187
- case _:
188
- raise Exception(f"Error: unknown message '{name}'")
148
+ def transE_message(self, name, attrs):
149
+ start = self.messages.get(name)
150
+ if start != None:
151
+ start(name,attrs)
152
+ else:
153
+ raise Exception(f"Error: unknown message '{name}'")
189
154
 
190
155
  def transE_addChild(self, addChild):
191
156
  def ret(name, attrs):
@@ -197,7 +162,7 @@ class GtkStreamXMLHandler(sax.ContentHandler):
197
162
  self.transition_enter = self.transE_addChild(lambda child: doc.add_child(child))
198
163
  self.transition_leave = self.transL_tag(name, self.transE_addChild(addChild), leave_parent)
199
164
  else:
200
- raise Exception(f"Error: Unknown widget {name}")
165
+ raise Exception(f"Error: Unknown widget type '{name}'")
201
166
  return ret
202
167
 
203
168
  def characters(self, s):
@@ -36,6 +36,17 @@ def _parse_searchMode_property(val):
36
36
  return _const(Gtk.StringFilterMatchMode.SUBSTRING)
37
37
  case _:
38
38
  return _const(Gtk.StringFilterMatchMode.PREFIX)
39
+ def _parse_adjustment_property(val):
40
+ adj = Gtk.Adjustment()
41
+ start, end, *rest = val.split(':')
42
+ adj.set_lower(int(start))
43
+ adj.set_upper(int(end))
44
+ if len(rest) > 0:
45
+ default = rest[0]
46
+ else:
47
+ default = start
48
+ adj.set_value(int(default))
49
+ return _const(adj)
39
50
  def _parse_css_classes_property(val):
40
51
  return _const(val.split())
41
52
  def _parse_widget_property(val):
@@ -50,6 +61,7 @@ _PARSE_TYPE_PROPERTY = {
50
61
  'gboolean' : _parse_boolean_property,
51
62
  'GtkStringFilterMatchMode' : _parse_searchMode_property,
52
63
  'GtkWidget' : _parse_widget_property,
64
+ 'GtkAdjustment' : _parse_adjustment_property,
53
65
  'gchararray' : _const,
54
66
  }
55
67
 
@@ -57,4 +69,9 @@ def parse_property(prop_type, val):
57
69
  # print(f"Parsing property '{val}' of type '{prop_type}'", file=sys.stderr)
58
70
  return _PARSE_TYPE_PROPERTY[prop_type](val)
59
71
  def get_prop_type(klass, prop):
60
- return klass.find_property(prop).value_type.name
72
+ try:
73
+ return klass.find_property(prop).value_type.name
74
+ except AttributeError:
75
+ raise Exception(f"Unknown GTK property '{prop}' of class '{klass}'")
76
+ def set_parse_prop(app, w, prop_name, val):
77
+ w.set_property(prop_name, parse_property(get_prop_type(w.__class__, prop_name), val)(app))
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: gtk-stream
3
- Version: 0.9
3
+ Version: 0.11
4
4
  Summary: A simple stream-oriented GUI protocol
5
5
  Author-email: Marc Coiffier <marc.coiffier@univ-grenoble-alpes.fr>
6
6
  Project-URL: Homepage, https://coiffier.net/projects/gtk-stream/
@@ -27,6 +27,7 @@ gtk_stream/documents/classes/Label.py
27
27
  gtk_stream/documents/classes/Paned.py
28
28
  gtk_stream/documents/classes/Picture.py
29
29
  gtk_stream/documents/classes/ProgressBar.py
30
+ gtk_stream/documents/classes/Scale.py
30
31
  gtk_stream/documents/classes/ScrolledWindow.py
31
32
  gtk_stream/documents/classes/Separator.py
32
33
  gtk_stream/documents/classes/Stack.py
@@ -1,101 +0,0 @@
1
- # Gtk-Stream : A stream-based GUI protocol
2
- # Copyright (C) 2024 Marc Coiffier
3
- #
4
- # This program is free software: you can redistribute it and/or modify
5
- # it under the terms of the GNU General Public License as published by
6
- # the Free Software Foundation, either version 3 of the License, or
7
- # (at your option) any later version.
8
- #
9
- # This program is distributed in the hope that it will be useful,
10
- # but WITHOUT ANY WARRANTY; without even the implied warranty of
11
- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
- # GNU General Public License for more details.
13
- #
14
- # You should have received a copy of the GNU General Public License
15
- # along with this program. If not, see <https://www.gnu.org/licenses/>.
16
-
17
- import sys
18
- from . import Gtk, GLib, Gdk
19
- from .common import printEvent
20
- from .properties import parse_property, get_prop_type
21
-
22
- class GtkStreamApp(Gtk.Application):
23
- def __init__(self, logger, name = None, **kwargs):
24
- super().__init__(**kwargs)
25
- self.logger = logger
26
- if name != None:
27
- GLib.set_application_name(name)
28
- self.namedWidgets = { }
29
- self.namedWindows = { }
30
-
31
- self.callback_queue = []
32
-
33
- def run_when_idle_before_startup(cb):
34
- self.callback_queue.append(cb)
35
- self.run_when_idle = run_when_idle_before_startup
36
-
37
- def on_startup(_):
38
- for cb in self.callback_queue:
39
- GLib.idle_add(cb)
40
- self.run_when_idle = GLib.idle_add
41
- self.connect('startup', on_startup)
42
-
43
- def nameWidget(self, id, w):
44
- if id is not None:
45
- self.namedWidgets[id] = w
46
-
47
- def openFileDialog(self, id, parent):
48
- def cb():
49
- dialog = Gtk.FileDialog()
50
- dialog.props.modal = True
51
- def on_choose(_, b):
52
- try:
53
- file = dialog.open_finish(b)
54
- print(f"{id}:selected:{file.get_path()}")
55
- sys.stdout.flush()
56
- except GLib.GError as e:
57
- print(f"{id}:none-selected")
58
- sys.stdout.flush()
59
-
60
- dialog.open(parent = self.namedWindows[parent], callback = on_choose)
61
- self.run_when_idle(cb)
62
- def newWindow(self, document, id, title = "Window", width = None, height = None):
63
- def cb():
64
- win = Gtk.Window(application=self)
65
- win.set_title(title)
66
- if width != None and height != None:
67
- win.set_default_size(int(width), int(height))
68
- self.namedWindows[id] = win
69
- win.set_child(document.render())
70
- win.connect('close-request', printEvent(self.logger, 'close-request', id))
71
- win.present()
72
- return False
73
- self.run_when_idle(cb)
74
- def addStyle(self, style):
75
- def cb():
76
- provider = Gtk.CssProvider()
77
- provider.load_from_data(style)
78
- Gtk.StyleContext.add_provider_for_display(Gdk.Display.get_default(), provider, Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION)
79
- self.run_when_idle(cb)
80
- def closeWindow(self, id):
81
- def cb():
82
- self.namedWindows[id].close()
83
- self.run_when_idle(cb)
84
- def removeWidget(self, id):
85
- def cb():
86
- w = self.namedWidgets[id]
87
- w.get_parent().remove(w)
88
- self.run_when_idle(cb)
89
- def insertWidget(self, to, document):
90
- def cb():
91
- if to in self.namedWidgets:
92
- w = self.namedWidgets[to]
93
- w.insert_child(document)
94
- else:
95
- raise Exception(f"Error: unknown widget id '{to}'")
96
- self.run_when_idle(cb)
97
- def setProp(self, id, name, value):
98
- def cb():
99
- w = self.namedWidgets[id]
100
- w.set_property(name, parse_property(get_prop_type(w.__class__, name), value)(self))
101
- self.run_when_idle(cb)
File without changes
File without changes
File without changes
File without changes
File without changes