Browse Source

Added proof-of-concept GUI

It's by no means wonderful internally, but to a large extent it works.
The list functionality is still untested, since I won't be able to have
two PDB Sinks connected to my computer at once until tomorrow.  But for
now, a neat little GUI.
Clara Hobbs 7 years ago
parent
commit
2dcd7d301a
4 changed files with 639 additions and 0 deletions
  1. 2
    0
      .gitignore
  2. 388
    0
      data/pd-buddy-gtk.ui
  3. 76
    0
      data/select-list-row.ui
  4. 173
    0
      pd-buddy-gtk.py

+ 2
- 0
.gitignore View File

58
 # PyBuilder
58
 # PyBuilder
59
 target/
59
 target/
60
 
60
 
61
+# Glade temporary files
62
+*.ui~

+ 388
- 0
data/pd-buddy-gtk.ui View File

1
+<?xml version="1.0" encoding="UTF-8"?>
2
+<!-- Generated with glade 3.20.0 -->
3
+<interface>
4
+  <requires lib="gtk+" version="3.20"/>
5
+  <object class="GtkImage" id="back-image">
6
+    <property name="visible">True</property>
7
+    <property name="can_focus">False</property>
8
+    <property name="icon_name">go-previous-symbolic</property>
9
+  </object>
10
+  <object class="GtkAdjustment" id="current-adjustment">
11
+    <property name="upper">5</property>
12
+    <property name="step_increment">1</property>
13
+    <property name="page_increment">10</property>
14
+  </object>
15
+  <object class="GtkApplicationWindow" id="pdb-window">
16
+    <property name="can_focus">False</property>
17
+    <property name="show_menubar">False</property>
18
+    <signal name="delete-event" handler="on_pdb_window_delete_event" swapped="no"/>
19
+    <signal name="realize" handler="on_pdb_window_realize" swapped="no"/>
20
+    <child>
21
+      <object class="GtkStack" id="stack">
22
+        <property name="visible">True</property>
23
+        <property name="can_focus">False</property>
24
+        <property name="transition_type">slide-left-right</property>
25
+        <child>
26
+          <object class="GtkScrolledWindow" id="select">
27
+            <property name="visible">True</property>
28
+            <property name="can_focus">True</property>
29
+            <property name="hscrollbar_policy">never</property>
30
+            <property name="min_content_height">300</property>
31
+            <property name="propagate_natural_width">True</property>
32
+            <child>
33
+              <object class="GtkViewport">
34
+                <property name="visible">True</property>
35
+                <property name="can_focus">False</property>
36
+                <child>
37
+                  <object class="GtkBox">
38
+                    <property name="visible">True</property>
39
+                    <property name="can_focus">False</property>
40
+                    <property name="orientation">vertical</property>
41
+                    <child>
42
+                      <object class="GtkStack" id="select-stack">
43
+                        <property name="visible">True</property>
44
+                        <property name="can_focus">False</property>
45
+                        <property name="vexpand">True</property>
46
+                        <child>
47
+                          <object class="GtkBox" id="select-none">
48
+                            <property name="visible">True</property>
49
+                            <property name="can_focus">False</property>
50
+                            <property name="halign">center</property>
51
+                            <property name="valign">center</property>
52
+                            <property name="margin_bottom">22</property>
53
+                            <property name="orientation">vertical</property>
54
+                            <child>
55
+                              <object class="GtkLabel" id="select-none-header">
56
+                                <property name="visible">True</property>
57
+                                <property name="can_focus">False</property>
58
+                                <property name="margin_bottom">12</property>
59
+                                <property name="label" translatable="yes">No devices found</property>
60
+                                <attributes>
61
+                                  <attribute name="weight" value="bold"/>
62
+                                  <attribute name="scale" value="2"/>
63
+                                </attributes>
64
+                                <style>
65
+                                  <class name="dim-label"/>
66
+                                </style>
67
+                              </object>
68
+                              <packing>
69
+                                <property name="expand">False</property>
70
+                                <property name="fill">True</property>
71
+                                <property name="position">0</property>
72
+                              </packing>
73
+                            </child>
74
+                            <child>
75
+                              <object class="GtkLabel" id="select-none-text">
76
+                                <property name="visible">True</property>
77
+                                <property name="can_focus">False</property>
78
+                                <property name="label" translatable="yes">All connected PD Buddy devices will appear here</property>
79
+                                <style>
80
+                                  <class name="dim-label"/>
81
+                                </style>
82
+                              </object>
83
+                              <packing>
84
+                                <property name="expand">False</property>
85
+                                <property name="fill">True</property>
86
+                                <property name="position">1</property>
87
+                              </packing>
88
+                            </child>
89
+                          </object>
90
+                          <packing>
91
+                            <property name="name">page1</property>
92
+                            <property name="title" translatable="yes">page1</property>
93
+                          </packing>
94
+                        </child>
95
+                        <child>
96
+                          <object class="GtkFrame" id="select-frame">
97
+                            <property name="visible">True</property>
98
+                            <property name="can_focus">False</property>
99
+                            <property name="halign">center</property>
100
+                            <property name="valign">start</property>
101
+                            <property name="margin_left">50</property>
102
+                            <property name="margin_right">50</property>
103
+                            <property name="margin_top">22</property>
104
+                            <property name="margin_bottom">22</property>
105
+                            <property name="hexpand">False</property>
106
+                            <property name="label_xalign">0</property>
107
+                            <property name="shadow_type">in</property>
108
+                            <child>
109
+                              <object class="GtkAlignment">
110
+                                <property name="visible">True</property>
111
+                                <property name="can_focus">False</property>
112
+                                <child>
113
+                                  <object class="GtkListBox" id="select-list">
114
+                                    <property name="width_request">442</property>
115
+                                    <property name="visible">True</property>
116
+                                    <property name="can_focus">False</property>
117
+                                    <property name="selection_mode">none</property>
118
+                                    <signal name="row-activated" handler="on_select_list_row_activated" swapped="no"/>
119
+                                  </object>
120
+                                </child>
121
+                              </object>
122
+                            </child>
123
+                            <child type="label_item">
124
+                              <placeholder/>
125
+                            </child>
126
+                          </object>
127
+                          <packing>
128
+                            <property name="name">page0</property>
129
+                            <property name="title" translatable="yes">page0</property>
130
+                            <property name="position">1</property>
131
+                          </packing>
132
+                        </child>
133
+                      </object>
134
+                      <packing>
135
+                        <property name="expand">False</property>
136
+                        <property name="fill">True</property>
137
+                        <property name="position">0</property>
138
+                      </packing>
139
+                    </child>
140
+                  </object>
141
+                </child>
142
+              </object>
143
+            </child>
144
+          </object>
145
+          <packing>
146
+            <property name="name">page0</property>
147
+            <property name="title" translatable="yes">page0</property>
148
+          </packing>
149
+        </child>
150
+        <child>
151
+          <object class="GtkScrolledWindow" id="sink">
152
+            <property name="visible">True</property>
153
+            <property name="can_focus">True</property>
154
+            <property name="hscrollbar_policy">never</property>
155
+            <property name="min_content_height">300</property>
156
+            <property name="propagate_natural_width">True</property>
157
+            <child>
158
+              <object class="GtkViewport">
159
+                <property name="visible">True</property>
160
+                <property name="can_focus">False</property>
161
+                <child>
162
+                  <object class="GtkBox">
163
+                    <property name="visible">True</property>
164
+                    <property name="can_focus">False</property>
165
+                    <property name="orientation">vertical</property>
166
+                    <child>
167
+                      <object class="GtkFrame">
168
+                        <property name="visible">True</property>
169
+                        <property name="can_focus">False</property>
170
+                        <property name="halign">center</property>
171
+                        <property name="margin_left">50</property>
172
+                        <property name="margin_right">50</property>
173
+                        <property name="margin_top">30</property>
174
+                        <property name="margin_bottom">22</property>
175
+                        <property name="hexpand">False</property>
176
+                        <property name="label_xalign">0</property>
177
+                        <property name="shadow_type">none</property>
178
+                        <child>
179
+                          <object class="GtkAlignment">
180
+                            <property name="visible">True</property>
181
+                            <property name="can_focus">False</property>
182
+                            <child>
183
+                              <object class="GtkGrid">
184
+                                <property name="visible">True</property>
185
+                                <property name="can_focus">False</property>
186
+                                <property name="row_spacing">6</property>
187
+                                <property name="column_spacing">12</property>
188
+                                <child>
189
+                                  <object class="GtkLabel">
190
+                                    <property name="visible">True</property>
191
+                                    <property name="can_focus">False</property>
192
+                                    <property name="label" translatable="yes">Voltage</property>
193
+                                    <property name="justify">right</property>
194
+                                    <style>
195
+                                      <class name="dim-label"/>
196
+                                    </style>
197
+                                  </object>
198
+                                  <packing>
199
+                                    <property name="left_attach">0</property>
200
+                                    <property name="top_attach">0</property>
201
+                                  </packing>
202
+                                </child>
203
+                                <child>
204
+                                  <object class="GtkLabel">
205
+                                    <property name="visible">True</property>
206
+                                    <property name="can_focus">False</property>
207
+                                    <property name="label" translatable="yes">Current</property>
208
+                                    <property name="justify">right</property>
209
+                                    <style>
210
+                                      <class name="dim-label"/>
211
+                                    </style>
212
+                                  </object>
213
+                                  <packing>
214
+                                    <property name="left_attach">0</property>
215
+                                    <property name="top_attach">1</property>
216
+                                  </packing>
217
+                                </child>
218
+                                <child>
219
+                                  <object class="GtkSpinButton" id="current-spinbutton">
220
+                                    <property name="visible">True</property>
221
+                                    <property name="can_focus">True</property>
222
+                                    <property name="input_purpose">number</property>
223
+                                    <property name="adjustment">current-adjustment</property>
224
+                                    <property name="digits">2</property>
225
+                                    <property name="numeric">True</property>
226
+                                    <signal name="value-changed" handler="on_current_spinbutton_changed" swapped="no"/>
227
+                                  </object>
228
+                                  <packing>
229
+                                    <property name="left_attach">1</property>
230
+                                    <property name="top_attach">1</property>
231
+                                  </packing>
232
+                                </child>
233
+                                <child>
234
+                                  <object class="GtkLabel">
235
+                                    <property name="visible">True</property>
236
+                                    <property name="can_focus">False</property>
237
+                                    <property name="label" translatable="yes">A</property>
238
+                                  </object>
239
+                                  <packing>
240
+                                    <property name="left_attach">2</property>
241
+                                    <property name="top_attach">1</property>
242
+                                  </packing>
243
+                                </child>
244
+                                <child>
245
+                                  <object class="GtkLabel">
246
+                                    <property name="visible">True</property>
247
+                                    <property name="can_focus">False</property>
248
+                                    <property name="label" translatable="yes">V</property>
249
+                                  </object>
250
+                                  <packing>
251
+                                    <property name="left_attach">2</property>
252
+                                    <property name="top_attach">0</property>
253
+                                  </packing>
254
+                                </child>
255
+                                <child>
256
+                                  <object class="GtkComboBoxText" id="voltage-combobox">
257
+                                    <property name="visible">True</property>
258
+                                    <property name="can_focus">False</property>
259
+                                    <items>
260
+                                      <item id="voltage-five" translatable="yes">5</item>
261
+                                      <item id="voltage-nine" translatable="yes">9</item>
262
+                                      <item id="voltage-fifteen" translatable="yes">15</item>
263
+                                      <item id="voltage-twenty" translatable="yes">20</item>
264
+                                    </items>
265
+                                    <signal name="changed" handler="on_voltage_combobox_changed" swapped="no"/>
266
+                                  </object>
267
+                                  <packing>
268
+                                    <property name="left_attach">1</property>
269
+                                    <property name="top_attach">0</property>
270
+                                  </packing>
271
+                                </child>
272
+                              </object>
273
+                            </child>
274
+                          </object>
275
+                        </child>
276
+                        <child type="label_item">
277
+                          <placeholder/>
278
+                        </child>
279
+                      </object>
280
+                      <packing>
281
+                        <property name="expand">False</property>
282
+                        <property name="fill">True</property>
283
+                        <property name="position">0</property>
284
+                      </packing>
285
+                    </child>
286
+                  </object>
287
+                </child>
288
+              </object>
289
+            </child>
290
+          </object>
291
+          <packing>
292
+            <property name="name">page1</property>
293
+            <property name="title" translatable="yes">page1</property>
294
+            <property name="position">1</property>
295
+          </packing>
296
+        </child>
297
+      </object>
298
+    </child>
299
+    <child type="titlebar">
300
+      <object class="GtkStack" id="header-stack">
301
+        <property name="visible">True</property>
302
+        <property name="can_focus">False</property>
303
+        <child>
304
+          <object class="GtkHeaderBar" id="header-select">
305
+            <property name="visible">True</property>
306
+            <property name="can_focus">False</property>
307
+            <property name="title">Select Device</property>
308
+            <property name="show_close_button">True</property>
309
+            <child>
310
+              <object class="GtkLabel" id="dummy">
311
+                <property name="visible">True</property>
312
+                <property name="can_focus">False</property>
313
+              </object>
314
+              <packing>
315
+                <property name="pack_type">end</property>
316
+              </packing>
317
+            </child>
318
+          </object>
319
+          <packing>
320
+            <property name="name">page0</property>
321
+            <property name="title" translatable="yes">page0</property>
322
+          </packing>
323
+        </child>
324
+        <child>
325
+          <object class="GtkHeaderBar" id="header-sink">
326
+            <property name="visible">True</property>
327
+            <property name="can_focus">False</property>
328
+            <property name="title">PD Buddy Sink</property>
329
+            <property name="show_close_button">True</property>
330
+            <child>
331
+              <object class="GtkButton" id="header-sink-back">
332
+                <property name="visible">True</property>
333
+                <property name="can_focus">True</property>
334
+                <property name="receives_default">True</property>
335
+                <property name="image">back-image</property>
336
+                <signal name="clicked" handler="on_header_sink_back_clicked" swapped="no"/>
337
+                <accelerator key="Left" signal="clicked" modifiers="GDK_MOD1_MASK"/>
338
+              </object>
339
+            </child>
340
+            <child>
341
+              <object class="GtkRevealer" id="header-sink-save-revealer">
342
+                <property name="visible">True</property>
343
+                <property name="can_focus">False</property>
344
+                <property name="transition_type">crossfade</property>
345
+                <child>
346
+                  <object class="GtkButtonBox">
347
+                    <property name="visible">True</property>
348
+                    <property name="can_focus">False</property>
349
+                    <property name="orientation">vertical</property>
350
+                    <property name="layout_style">start</property>
351
+                    <child>
352
+                      <object class="GtkButton" id="header-sink-save">
353
+                        <property name="label">gtk-save</property>
354
+                        <property name="visible">True</property>
355
+                        <property name="can_focus">True</property>
356
+                        <property name="receives_default">True</property>
357
+                        <property name="use_stock">True</property>
358
+                        <signal name="clicked" handler="on_header_sink_save_clicked" swapped="no"/>
359
+                        <accelerator key="s" signal="clicked" modifiers="GDK_CONTROL_MASK"/>
360
+                        <style>
361
+                          <class name="suggested-action"/>
362
+                        </style>
363
+                      </object>
364
+                      <packing>
365
+                        <property name="expand">True</property>
366
+                        <property name="fill">True</property>
367
+                        <property name="position">0</property>
368
+                      </packing>
369
+                    </child>
370
+                  </object>
371
+                </child>
372
+              </object>
373
+              <packing>
374
+                <property name="pack_type">end</property>
375
+                <property name="position">1</property>
376
+              </packing>
377
+            </child>
378
+          </object>
379
+          <packing>
380
+            <property name="name">page1</property>
381
+            <property name="title" translatable="yes">page1</property>
382
+            <property name="position">1</property>
383
+          </packing>
384
+        </child>
385
+      </object>
386
+    </child>
387
+  </object>
388
+</interface>

+ 76
- 0
data/select-list-row.ui View File

1
+<?xml version="1.0" encoding="UTF-8"?>
2
+<!-- Generated with glade 3.20.0 -->
3
+<interface>
4
+  <requires lib="gtk+" version="3.20"/>
5
+  <object class="GtkImage" id="identify-image">
6
+    <property name="visible">True</property>
7
+    <property name="can_focus">False</property>
8
+    <property name="icon_name">dialog-information-symbolic</property>
9
+    <child internal-child="accessible">
10
+      <object class="AtkObject" id="identify-image-atkobject">
11
+        <property name="AtkObject::accessible-name" translatable="yes">Identify</property>
12
+      </object>
13
+    </child>
14
+  </object>
15
+  <object class="GtkGrid" id="grid">
16
+    <property name="visible">True</property>
17
+    <property name="can_focus">False</property>
18
+    <property name="valign">center</property>
19
+    <property name="margin_right">6</property>
20
+    <property name="margin_top">6</property>
21
+    <property name="margin_bottom">6</property>
22
+    <property name="column_spacing">16</property>
23
+    <child>
24
+      <object class="GtkLabel" id="name">
25
+        <property name="visible">True</property>
26
+        <property name="can_focus">False</property>
27
+        <property name="halign">start</property>
28
+        <property name="margin_left">12</property>
29
+        <property name="hexpand">True</property>
30
+        <property name="label" translatable="yes">name</property>
31
+        <style>
32
+          <class name="title"/>
33
+        </style>
34
+      </object>
35
+      <packing>
36
+        <property name="left_attach">0</property>
37
+        <property name="top_attach">0</property>
38
+      </packing>
39
+    </child>
40
+    <child>
41
+      <object class="GtkLabel" id="device">
42
+        <property name="visible">True</property>
43
+        <property name="can_focus">False</property>
44
+        <property name="halign">start</property>
45
+        <property name="margin_left">12</property>
46
+        <property name="hexpand">True</property>
47
+        <property name="label" translatable="yes">device</property>
48
+        <attributes>
49
+          <attribute name="scale" value="0.90000000000000002"/>
50
+        </attributes>
51
+        <style>
52
+          <class name="dim-label"/>
53
+        </style>
54
+      </object>
55
+      <packing>
56
+        <property name="left_attach">0</property>
57
+        <property name="top_attach">1</property>
58
+      </packing>
59
+    </child>
60
+    <child>
61
+      <object class="GtkButton" id="identify">
62
+        <property name="visible">True</property>
63
+        <property name="can_focus">True</property>
64
+        <property name="receives_default">True</property>
65
+        <property name="tooltip_text" translatable="yes">Identify device</property>
66
+        <property name="image">identify-image</property>
67
+        <signal name="clicked" handler="on_identify_clicked" swapped="no"/>
68
+      </object>
69
+      <packing>
70
+        <property name="left_attach">1</property>
71
+        <property name="top_attach">0</property>
72
+        <property name="height">2</property>
73
+      </packing>
74
+    </child>
75
+  </object>
76
+</interface>

+ 173
- 0
pd-buddy-gtk.py View File

1
+#!/usr/bin/env python3
2
+
3
+import sys
4
+
5
+import serial
6
+import serial.tools.list_ports
7
+import gi
8
+gi.require_version('Gtk', '3.0')
9
+from gi.repository import Gtk
10
+
11
+
12
+def pdb_send_message(sp, message):
13
+        # Open the serial port
14
+        # FIXME handle exceptions
15
+        sp = serial.Serial(sp.device, baudrate=115200, timeout=0.01)
16
+
17
+        sp.write(bytes(message, 'utf-8') + b'\r\n')
18
+        sp.flush()
19
+        answer = sp.readlines()
20
+
21
+        sp.close()
22
+
23
+        # Remove the echoed command and prompt
24
+        answer = answer[1:-1]
25
+        return answer
26
+
27
+class SelectListRow(Gtk.ListBoxRow):
28
+
29
+    def __init__(self, serial_port):
30
+        Gtk.EventBox.__init__(self)
31
+
32
+        self.serial_port = serial_port
33
+
34
+        self._builder = Gtk.Builder()
35
+        self._builder.add_from_file("data/select-list-row.ui")
36
+        self._builder.connect_signals(self)
37
+
38
+        name = self._builder.get_object("name")
39
+        name.set_text(serial_port.description)
40
+
41
+        device = self._builder.get_object("device")
42
+        device.set_text(serial_port.device)
43
+
44
+        self.add(self._builder.get_object("grid"))
45
+        self.show_all()
46
+
47
+    def on_identify_clicked(self, button):
48
+        pdb_send_message(self.serial_port, 'identify')
49
+
50
+
51
+class Handler:
52
+
53
+    def __init__(self, builder):
54
+        self.builder = builder
55
+
56
+    def on_pdb_window_realize(self, *args):
57
+        # Get the list
58
+        sl = self.builder.get_object("select-list")
59
+        ss = self.builder.get_object("select-stack")
60
+        sf = self.builder.get_object("select-frame")
61
+
62
+        # Search for the serial ports
63
+        for serport in serial.tools.list_ports.grep("1209:0001"):
64
+            # Show the list if we have a serial port
65
+            ss.set_visible_child(sf)
66
+            sl.insert(SelectListRow(serport), -1)
67
+
68
+    def on_pdb_window_delete_event(self, *args):
69
+        Gtk.main_quit(*args)
70
+
71
+    def on_select_list_row_activated(self, box, row):
72
+        # Get voltage and current widgets
73
+        voltage = self.builder.get_object("voltage-combobox")
74
+        current = self.builder.get_object("current-spinbutton")
75
+
76
+        self.serial_port = row.serial_port
77
+
78
+        pdb_send_message(self.serial_port, 'load')
79
+        lines = pdb_send_message(self.serial_port, 'get_tmpcfg')
80
+
81
+        # Get information
82
+        for line in lines:
83
+            if line.startswith(b'v:'):
84
+                v = line.split()[1]
85
+                if v == b'5.00':
86
+                    voltage.set_active_id('voltage-five')
87
+                elif v == b'9.00':
88
+                    voltage.set_active_id('voltage-nine')
89
+                elif v == b'15.00':
90
+                    voltage.set_active_id('voltage-fifteen')
91
+                if v == b'20.00':
92
+                    voltage.set_active_id('voltage-twenty')
93
+            elif line.startswith(b'i:'):
94
+                i = float(line.split()[1])
95
+                current.set_value(i)
96
+
97
+        # Hide the Save button
98
+        rev = self.builder.get_object("header-sink-save-revealer")
99
+        rev.set_reveal_child(False)
100
+
101
+        # Show the Sink page
102
+        hst = self.builder.get_object("header-stack")
103
+        hsink = self.builder.get_object("header-sink")
104
+        hsink.set_subtitle(row.serial_port.device)
105
+        hst.set_visible_child(hsink)
106
+
107
+        st = self.builder.get_object("stack")
108
+        sink = self.builder.get_object("sink")
109
+        st.set_visible_child(sink)
110
+
111
+    def on_header_sink_back_clicked(self, data):
112
+        # Show the Select page
113
+        hst = self.builder.get_object("header-stack")
114
+        hselect = self.builder.get_object("header-select")
115
+        hst.set_visible_child(hselect)
116
+
117
+        st = self.builder.get_object("stack")
118
+        select = self.builder.get_object("select")
119
+        st.set_visible_child(select)
120
+
121
+    def on_header_sink_save_clicked(self, button):
122
+        combo = self.builder.get_object("voltage-combobox")
123
+        spin = self.builder.get_object("current-spinbutton")
124
+        print("{} V".format(combo.get_active_text()))
125
+        print("{} A".format(spin.get_value()))
126
+        rev = self.builder.get_object("header-sink-save-revealer")
127
+        rev.set_reveal_child(False)
128
+
129
+        pdb_send_message(self.serial_port, 'write')
130
+
131
+    def on_voltage_combobox_changed(self, combo):
132
+        rev = self.builder.get_object("header-sink-save-revealer")
133
+        rev.set_reveal_child(True)
134
+
135
+        pdb_send_message(self.serial_port,
136
+                         'set_v {}'.format(int(combo.get_active_text())*1000))
137
+
138
+    def on_current_spinbutton_changed(self, spin):
139
+        rev = self.builder.get_object("header-sink-save-revealer")
140
+        rev.set_reveal_child(True)
141
+
142
+        pdb_send_message(self.serial_port,
143
+                         'set_i {}'.format(int(spin.get_value()*1000)))
144
+
145
+class Application(Gtk.Application):
146
+
147
+    def __init__(self, *args, **kwargs):
148
+        super().__init__(*args, application_id="com.clayhobbs.pd-buddy-gtk",
149
+                         **kwargs)
150
+        self.window = None
151
+
152
+    def do_startup(self):
153
+        Gtk.Application.do_startup(self)
154
+
155
+        self.builder = Gtk.Builder()
156
+        self.builder.add_from_file("data/pd-buddy-gtk.ui")
157
+        self.builder.connect_signals(Handler(self.builder))
158
+
159
+    def do_activate(self):
160
+        # We only allow a single window and raise any existing ones
161
+        if not self.window:
162
+            # Windows are associated with the application
163
+            # when the last one is closed the application shuts down
164
+            self.window = self.builder.get_object("pdb-window")
165
+            self.add_window(self.window)
166
+            self.window.set_wmclass("PD Buddy Configuration",
167
+                                    "PD Buddy Configuration")
168
+
169
+        self.window.present()
170
+
171
+if __name__ == "__main__":
172
+    app = Application()
173
+    app.run(sys.argv)

Loading…
Cancel
Save