Browse Source

Merge branch 'src-cap-dialog'

The new Source Capabilities dialog is done, so it's time to merge it
into master.  Before now it would've been a mistake to merge it since it
would've caused a regression in functionality.
Clara Hobbs 6 years ago
parent
commit
da395ece93
2 changed files with 342 additions and 22 deletions
  1. 201
    0
      data/src-cap-dialog.ui
  2. 141
    22
      pd-buddy-gtk.py

+ 201
- 0
data/src-cap-dialog.ui View File

@@ -0,0 +1,201 @@
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="GtkDialog" id="src-cap-dialog">
6
+    <property name="can_focus">False</property>
7
+    <property name="title" translatable="yes">Source Capabilities</property>
8
+    <property name="modal">True</property>
9
+    <property name="type_hint">dialog</property>
10
+    <child internal-child="vbox">
11
+      <object class="GtkBox">
12
+        <property name="can_focus">False</property>
13
+        <property name="orientation">vertical</property>
14
+        <child internal-child="action_area">
15
+          <object class="GtkButtonBox">
16
+            <property name="can_focus">False</property>
17
+            <property name="layout_style">end</property>
18
+            <child>
19
+              <placeholder/>
20
+            </child>
21
+            <child>
22
+              <placeholder/>
23
+            </child>
24
+          </object>
25
+          <packing>
26
+            <property name="expand">False</property>
27
+            <property name="fill">False</property>
28
+            <property name="position">0</property>
29
+          </packing>
30
+        </child>
31
+        <child>
32
+          <object class="GtkScrolledWindow">
33
+            <property name="visible">True</property>
34
+            <property name="can_focus">True</property>
35
+            <property name="hscrollbar_policy">never</property>
36
+            <property name="min_content_height">250</property>
37
+            <property name="propagate_natural_width">True</property>
38
+            <child>
39
+              <object class="GtkViewport">
40
+                <property name="visible">True</property>
41
+                <property name="can_focus">False</property>
42
+                <child>
43
+                  <object class="GtkBox">
44
+                    <property name="visible">True</property>
45
+                    <property name="can_focus">False</property>
46
+                    <property name="valign">start</property>
47
+                    <property name="margin_left">50</property>
48
+                    <property name="margin_right">50</property>
49
+                    <property name="margin_top">22</property>
50
+                    <property name="margin_bottom">22</property>
51
+                    <property name="orientation">vertical</property>
52
+                    <property name="spacing">18</property>
53
+                    <child>
54
+                      <object class="GtkGrid">
55
+                        <property name="visible">True</property>
56
+                        <property name="can_focus">False</property>
57
+                        <property name="halign">center</property>
58
+                        <property name="row_spacing">6</property>
59
+                        <property name="column_spacing">12</property>
60
+                        <child>
61
+                          <object class="GtkLabel" id="power-header">
62
+                            <property name="visible">True</property>
63
+                            <property name="can_focus">False</property>
64
+                            <property name="halign">end</property>
65
+                            <property name="valign">start</property>
66
+                            <property name="label" translatable="yes">PD Power</property>
67
+                            <style>
68
+                              <class name="dim-label"/>
69
+                            </style>
70
+                          </object>
71
+                          <packing>
72
+                            <property name="left_attach">0</property>
73
+                            <property name="top_attach">0</property>
74
+                          </packing>
75
+                        </child>
76
+                        <child>
77
+                          <object class="GtkLabel" id="info-header">
78
+                            <property name="visible">True</property>
79
+                            <property name="can_focus">False</property>
80
+                            <property name="halign">end</property>
81
+                            <property name="valign">start</property>
82
+                            <property name="label" translatable="yes">Information</property>
83
+                            <style>
84
+                              <class name="dim-label"/>
85
+                            </style>
86
+                          </object>
87
+                          <packing>
88
+                            <property name="left_attach">0</property>
89
+                            <property name="top_attach">1</property>
90
+                          </packing>
91
+                        </child>
92
+                        <child>
93
+                          <object class="GtkLabel" id="info-label">
94
+                            <property name="visible">True</property>
95
+                            <property name="can_focus">False</property>
96
+                            <property name="halign">start</property>
97
+                            <property name="valign">start</property>
98
+                            <property name="label" translatable="yes">label</property>
99
+                          </object>
100
+                          <packing>
101
+                            <property name="left_attach">1</property>
102
+                            <property name="top_attach">1</property>
103
+                          </packing>
104
+                        </child>
105
+                        <child>
106
+                          <object class="GtkBox">
107
+                            <property name="visible">True</property>
108
+                            <property name="can_focus">False</property>
109
+                            <property name="halign">start</property>
110
+                            <property name="valign">start</property>
111
+                            <property name="spacing">6</property>
112
+                            <child>
113
+                              <object class="GtkLabel" id="power-label">
114
+                                <property name="visible">True</property>
115
+                                <property name="can_focus">False</property>
116
+                                <property name="halign">start</property>
117
+                                <property name="valign">start</property>
118
+                                <property name="label" translatable="yes">label</property>
119
+                              </object>
120
+                              <packing>
121
+                                <property name="expand">False</property>
122
+                                <property name="fill">True</property>
123
+                                <property name="position">0</property>
124
+                              </packing>
125
+                            </child>
126
+                            <child>
127
+                              <object class="GtkImage" id="source-cap-warning">
128
+                                <property name="can_focus">False</property>
129
+                                <property name="tooltip_text" translatable="yes">Source violates the USB PD Power Rules</property>
130
+                                <property name="halign">start</property>
131
+                                <property name="icon_name">dialog-warning-symbolic</property>
132
+                              </object>
133
+                              <packing>
134
+                                <property name="expand">False</property>
135
+                                <property name="fill">True</property>
136
+                                <property name="position">1</property>
137
+                              </packing>
138
+                            </child>
139
+                          </object>
140
+                          <packing>
141
+                            <property name="left_attach">1</property>
142
+                            <property name="top_attach">0</property>
143
+                          </packing>
144
+                        </child>
145
+                      </object>
146
+                      <packing>
147
+                        <property name="expand">False</property>
148
+                        <property name="fill">True</property>
149
+                        <property name="position">0</property>
150
+                      </packing>
151
+                    </child>
152
+                    <child>
153
+                      <object class="GtkFrame">
154
+                        <property name="visible">True</property>
155
+                        <property name="can_focus">False</property>
156
+                        <property name="halign">center</property>
157
+                        <property name="label_xalign">0</property>
158
+                        <property name="shadow_type">in</property>
159
+                        <child>
160
+                          <object class="GtkAlignment">
161
+                            <property name="visible">True</property>
162
+                            <property name="can_focus">False</property>
163
+                            <child>
164
+                              <object class="GtkListBox" id="src-cap-list">
165
+                                <property name="width_request">300</property>
166
+                                <property name="visible">True</property>
167
+                                <property name="can_focus">False</property>
168
+                                <property name="selection_mode">none</property>
169
+                                <property name="activate_on_single_click">False</property>
170
+                              </object>
171
+                            </child>
172
+                          </object>
173
+                        </child>
174
+                        <child type="label_item">
175
+                          <placeholder/>
176
+                        </child>
177
+                      </object>
178
+                      <packing>
179
+                        <property name="expand">False</property>
180
+                        <property name="fill">False</property>
181
+                        <property name="position">1</property>
182
+                      </packing>
183
+                    </child>
184
+                  </object>
185
+                </child>
186
+              </object>
187
+            </child>
188
+          </object>
189
+          <packing>
190
+            <property name="expand">True</property>
191
+            <property name="fill">True</property>
192
+            <property name="position">1</property>
193
+          </packing>
194
+        </child>
195
+      </object>
196
+    </child>
197
+    <child>
198
+      <placeholder/>
199
+    </child>
200
+  </object>
201
+</interface>

+ 141
- 22
pd-buddy-gtk.py View File

@@ -17,7 +17,7 @@ def comms_error_dialog(parent, e):
17 17
     dialog.destroy()
18 18
 
19 19
 
20
-class ListRowModel(GObject.GObject):
20
+class SelectListRowModel(GObject.GObject):
21 21
 
22 22
     def __init__(self, serport):
23 23
         GObject.GObject.__init__(self)
@@ -49,7 +49,7 @@ class SelectListStore(Gio.ListStore):
49 49
         # Add any new ports
50 50
         for port in serports:
51 51
             if port is not None:
52
-                self.append(ListRowModel(port))
52
+                self.append(SelectListRowModel(port))
53 53
 
54 54
 
55 55
 def list_box_update_header_func(row, before, data):
@@ -114,7 +114,6 @@ class SelectListRow(Gtk.ListBoxRow):
114 114
 
115 115
     def __init__(self, model):
116 116
         Gtk.EventBox.__init__(self)
117
-
118 117
         self.model = model
119 118
 
120 119
         self._builder = Gtk.Builder()
@@ -142,6 +141,97 @@ class SelectListRow(Gtk.ListBoxRow):
142 141
             return
143 142
 
144 143
 
144
+class PDOListRowModel(GObject.GObject):
145
+
146
+    def __init__(self, pdo):
147
+        GObject.GObject.__init__(self)
148
+        self.pdo = pdo
149
+
150
+
151
+class PDOListStore(Gio.ListStore):
152
+
153
+    def update_items(self, pdo_list):
154
+        # Clear the list
155
+        self.remove_all()
156
+
157
+        # Add everything from the new list
158
+        for pdo in pdo_list:
159
+            self.append(PDOListRowModel(pdo))
160
+
161
+
162
+class PDOListRow(Gtk.ListBoxRow):
163
+    oc_tooltips = [
164
+        "I<sub>Peak</sub> = I<sub>OC</sub> (default)",
165
+        """Overload Capabilities:
166
+1. I<sub>Peak</sub> = 150% I<sub>OC</sub> for 1 ms @ 5% duty cycle (I<sub>Low</sub> = 97% I<sub>OC</sub> for 19 ms)
167
+2. I<sub>Peak</sub> = 125% I<sub>OC</sub> for 2 ms @ 10% duty cycle (I<sub>Low</sub> = 97% I<sub>OC</sub> for 18 ms)
168
+3. I<sub>Peak</sub> = 110% I<sub>OC</sub> for 10 ms @ 50% duty cycle (I<sub>Low</sub> = 90% I<sub>OC</sub> for 10 ms)""",
169
+        """Overload Capabilities:
170
+1. I<sub>Peak</sub> = 200% I<sub>OC</sub> for 1 ms @ 5% duty cycle (I<sub>Low</sub> = 95% I<sub>OC</sub> for 19 ms)
171
+2. I<sub>Peak</sub> = 150% I<sub>OC</sub> for 2 ms @ 10% duty cycle (I<sub>Low</sub> = 94% I<sub>OC</sub> for 18 ms)
172
+3. I<sub>Peak</sub> = 125% I<sub>OC</sub> for 10 ms @ 50% duty cycle (I<sub>Low</sub> = 75% I<sub>OC</sub> for 10 ms)""",
173
+        """Overload Capabilities:
174
+1. I<sub>Peak</sub> = 200% I<sub>OC</sub> for 1 ms @ 5% duty cycle (I<sub>Low</sub> = 95% I<sub>OC</sub> for 19 ms)
175
+2. I<sub>Peak</sub> = 175% I<sub>OC</sub> for 2 ms @ 10% duty cycle (I<sub>Low</sub> = 92% I<sub>OC</sub> for 18 ms)
176
+3. I<sub>Peak</sub> = 150% I<sub>OC</sub> for 10 ms @ 50% duty cycle (I<sub>Low</sub> = 50% I<sub>OC</sub> for 10 ms)"""
177
+    ]
178
+
179
+    def __init__(self, model):
180
+        Gtk.ListBoxRow.__init__(self)
181
+        self.model = model
182
+
183
+        self.set_activatable(False)
184
+        self.set_selectable(False)
185
+        self.set_can_focus(False)
186
+
187
+        # Make the widgets and populate them with info from the model
188
+        # Main box
189
+        box = Gtk.Box(Gtk.Orientation.HORIZONTAL, 12)
190
+        box.set_homogeneous(True)
191
+        box.set_margin_left(12)
192
+        box.set_margin_right(12)
193
+        box.set_margin_top(6)
194
+        box.set_margin_bottom(6)
195
+
196
+        # Type label
197
+        type_label = Gtk.Label(model.pdo.pdo_type.capitalize())
198
+        type_label.set_halign(Gtk.Align.START)
199
+        box.pack_start(type_label, True, True, 0)
200
+
201
+        # Voltage label
202
+        if model.pdo.pdo_type != "unknown":
203
+            voltage_label = Gtk.Label("{:g} V".format(model.pdo.v / 1000.0))
204
+            voltage_label.set_halign(Gtk.Align.END)
205
+            box.pack_start(voltage_label, True, True, 0)
206
+
207
+        # Right box
208
+        right_box = Gtk.Box(Gtk.Orientation.HORIZONTAL, 6)
209
+        right_box.set_halign(Gtk.Align.END)
210
+        if model.pdo.pdo_type != "unknown":
211
+            # Current label
212
+            current_label = Gtk.Label("{:g} A".format(model.pdo.i / 1000.0))
213
+            current_label.set_halign(Gtk.Align.END)
214
+            right_box.pack_end(current_label, True, False, 0)
215
+
216
+            # Over-current image(?)
217
+            if model.pdo.peak_i > 0:
218
+                oc_image = Gtk.Image.new_from_icon_name(
219
+                        "dialog-information-symbolic", Gtk.IconSize.BUTTON)
220
+                oc_image.set_tooltip_markup(
221
+                        PDOListRow.oc_tooltips[model.pdo.peak_i])
222
+                right_box.pack_end(oc_image, True, False, 0)
223
+        else:
224
+            # PDO value
225
+            text_label = Gtk.Label()
226
+            text_label.set_markup("<tt>{}</tt>".format(model.pdo))
227
+            right_box.pack_end(text_label, True, False, 0)
228
+
229
+        box.pack_end(right_box, True, True, 0)
230
+
231
+        self.add(box)
232
+        self.show_all()
233
+
234
+
145 235
 class Handler:
146 236
 
147 237
     def __init__(self, builder):
@@ -339,26 +429,56 @@ class Handler:
339 429
         if row != sc_row:
340 430
             # If it's not the source-cap-row, leave
341 431
             return
432
+
342 433
         # Get the source capabilities
343 434
         with pdbuddy.Sink(self.serial_port) as pdbs:
344 435
             caps = pdbs.get_source_cap()
345
-            s = ""
346
-            for i, cap in enumerate(caps):
347
-                s += "PDO {}: {}".format(i+1, cap)
348
-                if i < len(caps) - 1:
349
-                    s += "\n"
350
-            if not s:
351
-                s = "No Source_Capabilities"
352
-            flags = Gtk.DialogFlags.DESTROY_WITH_PARENT;
353
-            window = self.builder.get_object("pdb-window")
354
-            dialog = Gtk.MessageDialog(window,
355
-                             flags,
356
-                             Gtk.MessageType.INFO,
357
-                             Gtk.ButtonsType.CLOSE,
358
-                             None)
359
-            dialog.set_markup("<span font_family='monospace'>{}</span>".format(s))
360
-            dialog.run()
361
-            dialog.destroy()
436
+
437
+        # Create the dialog
438
+        window = self.builder.get_object("pdb-window")
439
+        dialog_builder = Gtk.Builder.new_from_file("data/src-cap-dialog.ui")
440
+        dialog = dialog_builder.get_object("src-cap-dialog")
441
+        dialog.set_transient_for(window)
442
+
443
+        # Populate PD Power
444
+        d_power = dialog_builder.get_object("power-label")
445
+        d_power.set_text("{:g} W".format(pdbuddy.calculate_pdp(caps)))
446
+        # Warning icon
447
+        cap_warning = dialog_builder.get_object("source-cap-warning")
448
+        cap_warning.set_visible(not pdbuddy.follows_power_rules(caps))
449
+
450
+        # Populate Information
451
+        d_info_header = dialog_builder.get_object("info-header")
452
+        d_info = dialog_builder.get_object("info-label")
453
+        # Make the string to display
454
+        info_str = ""
455
+        if caps[0].dual_role_pwr:
456
+            info_str += "Dual-Role Power\n"
457
+        if caps[0].usb_suspend:
458
+            info_str += "USB Suspend Supported\n"
459
+        if caps[0].unconstrained_pwr:
460
+            info_str += "Unconstrained Power\n"
461
+        if caps[0].usb_comms:
462
+            info_str += "USB Communications Capable\n"
463
+        if caps[0].dual_role_data:
464
+            info_str += "Dual-Role Data\n"
465
+        info_str = info_str[:-1]
466
+        # Set the text and label visibility
467
+        d_info.set_text(info_str)
468
+        d_info_header.set_visible(info_str)
469
+        d_info.set_visible(info_str)
470
+
471
+        # PDO list
472
+        d_list = dialog_builder.get_object("src-cap-list")
473
+        d_list.set_header_func(list_box_update_header_func, None)
474
+
475
+        model = PDOListStore()
476
+        d_list.bind_model(model, PDOListRow)
477
+        model.update_items(caps)
478
+
479
+        # Show the dialog
480
+        dialog.run()
481
+        dialog.destroy()
362 482
 
363 483
 
364 484
 class Application(Gtk.Application):
@@ -371,8 +491,7 @@ class Application(Gtk.Application):
371 491
     def do_startup(self):
372 492
         Gtk.Application.do_startup(self)
373 493
 
374
-        self.builder = Gtk.Builder()
375
-        self.builder.add_from_file("data/pd-buddy-gtk.ui")
494
+        self.builder = Gtk.Builder.new_from_file("data/pd-buddy-gtk.ui")
376 495
         self.builder.connect_signals(Handler(self.builder))
377 496
 
378 497
     def do_activate(self):

Loading…
Cancel
Save