# HG changeset patch
# User Dan Smith <dsmith(a)danplanet.com>
# Date 1362347281 28800
# Node ID c12728b5626151c5bcd74fb9bcb0aa91e2ba51c2
# Parent 665acce0c527014a33f919d5759220f4c96b59cc
[RFC] Add bitwise browser when developer options are enabled
This version allows editing of most of the arbitrary data. Note that
since the only semantic interpretation of a given value at this layer
is its format and size, much damage can be caused to the underlying
image if care is not exercised :)
Also, changes are not automatically sync'd back to the other tabs
(i.e. memories), so you have to hit "go" again on that tab to re-load
the latest data.
diff -r 665acce0c527 -r c12728b56261 chirp/bitwise.py
--- a/chirp/bitwise.py Sun Mar 03 11:38:21 2013 -0800
+++ b/chirp/bitwise.py Sun Mar 03 13:48:01 2013 -0800
@@ -188,7 +188,7 @@
def __str__(self):
if isinstance(self.__items[0], charDataElement):
- return "".join([x.get_value() for x in self.__items])
+ return repr("".join([x.get_value() for x in self.__items]))[1:-1]
else:
return str(self.__items)
@@ -248,6 +248,12 @@
def __iter__(self):
return iter(self.__items)
+ def items(self):
+ index = 0
+ for item in self.__items:
+ yield (str(index), item)
+ index += 1
+
def size(self):
size = 0
for i in self.__items:
@@ -612,6 +618,13 @@
raise ValueError("Struct size mismatch during set_raw()")
self._data[self._offset] = buffer
+ def __iter__(self):
+ for item in self._generators.values():
+ yield item
+
+ def items(self):
+ return self._generators.items()
+
class Processor:
_types = {
diff -r 665acce0c527 -r c12728b56261 chirpui/editorset.py
--- a/chirpui/editorset.py Sun Mar 03 11:38:21 2013 -0800
+++ b/chirpui/editorset.py Sun Mar 03 13:48:01 2013 -0800
@@ -19,7 +19,7 @@
from chirp import chirp_common, directory, generic_csv, generic_xml
from chirpui import memedit, dstaredit, bankedit, common, importdialog
-from chirpui import inputdialog, reporting, settingsedit
+from chirpui import inputdialog, reporting, settingsedit, radiobrowser, config
class EditorSet(gtk.VBox):
__gsignals__ = {
@@ -65,6 +65,7 @@
"bank_names" : None,
"bank_members" : None,
"settings" : None,
+ "browser" : None,
}
if isinstance(self.radio, chirp_common.IcomDstarSupport):
@@ -88,6 +89,11 @@
if rf.has_settings:
self.editors["settings"] = settingsedit.SettingsEditor(self.rthread)
+ conf = config.get()
+ if (hasattr(self.rthread.radio, '_memobj') and
+ conf.get_bool("developer", "state")):
+ self.editors["browser"] = radiobrowser.RadioBrowser(self.rthread)
+
lab = gtk.Label(_("Memories"))
self.tabs.append_page(self.editors["memedit"].root, lab)
self.editors["memedit"].root.show()
@@ -115,6 +121,10 @@
self.tabs.append_page(self.editors["settings"].root, lab)
self.editors["settings"].root.show()
+ if self.editors["browser"]:
+ lab = gtk.Label(_("Browser"))
+ self.tabs.append_page(self.editors["browser"].root, lab)
+
self.pack_start(self.tabs)
self.tabs.show()
diff -r 665acce0c527 -r c12728b56261 chirpui/radiobrowser.py
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/chirpui/radiobrowser.py Sun Mar 03 13:48:01 2013 -0800
@@ -0,0 +1,295 @@
+import gtk
+import gobject
+import pango
+import re
+import os
+
+from chirp import bitwise
+from chirpui import common
+
+def do_insert_line_with_tags(b, line):
+ def i(text, *tags):
+ b.insert_with_tags_by_name(b.get_end_iter(), text, *tags)
+
+ def ident(name):
+ if "unknown" in name:
+ i(name, 'grey', 'bold')
+ else:
+ i(name, 'bold')
+
+ def nonzero(value):
+ i(value, 'red', 'bold')
+
+ def foo(value):
+ i(value, 'blue', 'bold')
+
+ m = re.match("^( *)([A-z0-9_]+: )(0x[A-F0-9]+) \((.*)\)$", line)
+ if m:
+ i(m.group(1))
+ ident(m.group(2))
+ if m.group(3) == '0x00':
+ i(m.group(3))
+ else:
+ nonzero(m.group(3))
+ i(' (')
+ for char in m.group(4):
+ if char == '1':
+ nonzero(char)
+ else:
+ i(char)
+ i(')')
+ return
+
+ m = re.match("^( *)([A-z0-9_]+: )(.*)$", line)
+ if m:
+ i(m.group(1))
+ ident(m.group(2))
+ i(m.group(3))
+ return
+
+ m = re.match("^(.*} )([A-z0-9_]+)( \()([0-9]+)( bytes at )(0x[A-F0-9]+)",
+ line)
+ if m:
+ i(m.group(1))
+ ident(m.group(2))
+ i(m.group(3))
+ foo(m.group(4))
+ i(m.group(5))
+ foo(m.group(6))
+ i(")")
+ return
+
+ i(line)
+
+def do_insert_with_tags(buf, text):
+ buf.set_text('')
+ lines = text.split(os.linesep)
+ for line in lines:
+ do_insert_line_with_tags(buf, line)
+ buf.insert_with_tags_by_name(buf.get_end_iter(), os.linesep)
+
+def classname(obj):
+ return str(obj.__class__).split('.')[-1]
+
+def bitwise_type(classname):
+ return classname.split("DataElement")[0]
+
+class FixedEntry(gtk.Entry):
+ def __init__(self, *args, **kwargs):
+ super(FixedEntry, self).__init__(*args, **kwargs)
+ fontdesc = pango.FontDescription("Courier 10")
+ self.modify_font(fontdesc)
+
+class BitwiseEditor(gtk.HBox):
+ def __init__(self, element):
+ super(BitwiseEditor, self).__init__(False, 3)
+ self._element = element
+ self._build_ui()
+
+class IntegerEditor(BitwiseEditor):
+ def _changed(self, entry, base):
+ if not self._update:
+ return
+ value = entry.get_text()
+ if value.startswith("0x"):
+ value = value[2:]
+ self._element.set_value(int(value, base))
+ self._update_entries(skip=entry)
+
+ def _update_entries(self, skip=None):
+ self._update = False
+ for ent, format_spec in self._entries:
+ if ent != skip:
+ ent.set_text(format_spec.format(int(self._element)))
+ self._update = True
+
+ def _build_ui(self):
+ self._entries = []
+ self._update = True
+
+ hexdigits = ((self._element.size() / 4) +
+ (self._element.size() % 4 and 1 or 0))
+ formats = [('Hex', 16, '0x{:0%iX}' % hexdigits),
+ ('Dec', 10, '{:d}'),
+ ('Bin', 2, '{:0%ib}' % self._element.size())]
+ for name, base, format_spec in formats:
+ lab = gtk.Label(name)
+ self.pack_start(lab, 0, 0, 0)
+ lab.show()
+ int(self._element)
+ ent = FixedEntry()
+ self._entries.append((ent, format_spec))
+ ent.connect('changed', self._changed, base)
+ self.pack_start(ent, 0, 0, 0)
+ ent.show()
+ self._update_entries()
+
+class BCDArrayEditor(BitwiseEditor):
+ def _changed(self, entry, hexent):
+ self._element.set_value(int(entry.get_text()))
+ self._format_hexent(hexent)
+
+ def _format_hexent(self, hexent):
+ value = ""
+ for i in self._element:
+ a, b = i.get_value()
+ value += "%i%i" % (a, b)
+ hexent.set_text(value)
+
+ def _build_ui(self):
+ lab = gtk.Label("Dec")
+ lab.show()
+ self.pack_start(lab, 0, 0, 0)
+ ent = FixedEntry()
+ ent.set_text(str(int(self._element)))
+ ent.show()
+ self.pack_start(ent, 1, 1, 1)
+
+ lab = gtk.Label("Hex")
+ lab.show()
+ self.pack_start(lab, 0, 0, 0)
+
+ hexent = FixedEntry()
+ hexent.show()
+ self.pack_start(hexent, 1, 1, 1)
+ hexent.set_editable(False)
+
+ ent.connect('changed', self._changed, hexent)
+ self._format_hexent(hexent)
+
+class CharArrayEditor(BitwiseEditor):
+ def _changed(self, entry):
+ self._element.set_value(entry.get_text().ljust(len(self._element)))
+
+ def _build_ui(self):
+ ent = FixedEntry(len(self._element))
+ ent.set_text(str(self._element))
+ ent.connect('changed', self._changed)
+ ent.show()
+ self.pack_start(ent, 1, 1, 1)
+
+class OtherEditor(BitwiseEditor):
+ def _build_ui(self):
+ name = classname(self._element)
+ name = bitwise_type(name)
+ if isinstance(self._element, bitwise.arrayDataElement):
+ name += " %s[%i]" % (
+ bitwise_type(classname(self._element[0])),
+ len(self._element))
+
+ l = gtk.Label(name)
+ l.show()
+ self.pack_start(l, 1, 1, 1)
+
+class RadioBrowser(common.Editor):
+ def _build_ui(self):
+ self._display = gtk.Table(20, 2)
+
+ self._store = gtk.TreeStore(gobject.TYPE_STRING, gobject.TYPE_PYOBJECT)
+ self._tree = gtk.TreeView(self._store)
+
+ rend = gtk.CellRendererText()
+ tvc = gtk.TreeViewColumn('Element', rend, text=0)
+ self._tree.append_column(tvc)
+ self._tree.connect('button_press_event', self._tree_click)
+ self._tree.set_size_request(200, -1)
+
+ self.root = gtk.HBox(False, 3)
+ sw = gtk.ScrolledWindow()
+ sw.add(self._tree)
+ sw.show()
+ self.root.pack_start(sw, 0, 0, 0)
+ sw = gtk.ScrolledWindow()
+ sw.add_with_viewport(self._display)
+ sw.show()
+ self.root.pack_start(sw, 1, 1, 1)
+ self._tree.show()
+ self._display.show()
+ self.root.show()
+
+ def _fill(self, name, obj, parent=None):
+ iter = self._store.append(parent, (name, obj))
+
+ if isinstance(obj, bitwise.structDataElement):
+ for name, item in obj.items():
+ if isinstance(item, bitwise.structDataElement):
+ self._fill(name, item, iter)
+ elif isinstance(item, bitwise.arrayDataElement):
+ self._fill("%s[%i]" % (name, len(item)), item, iter)
+ elif isinstance(obj, bitwise.arrayDataElement):
+ i = 0
+ for item in obj:
+ self._fill("%s[%i]" % (name, i), item, iter)
+ i += 1
+
+ def _tree_click(self, view, event):
+ if event.button != 1:
+ return
+
+ index = [0]
+
+ def pack(widget, pos):
+ self._display.attach(widget, pos, pos + 1, index[0], index[0] + 1,
+ xoptions=gtk.FILL, yoptions=0)
+
+ def next_row():
+ index[0] += 1
+
+ def abandon(child):
+ self._display.remove(child)
+
+ pathinfo = view.get_path_at_pos(int(event.x), int(event.y))
+ path = pathinfo[0]
+ iter = self._store.get_iter(path)
+ name, obj = self._store.get(iter, 0, 1)
+
+ self._display.foreach(abandon)
+
+ for name, item in obj.items():
+ if item.size() % 8 == 0:
+ name = '<b>%s</b> <small>(%s %i bytes)</small>' % (
+ name, bitwise_type(classname(item)), item.size() / 8)
+ else:
+ name = '<b>%s</b> <small>(%s %i bits)</small>' % (
+ name, bitwise_type(classname(item)), item.size())
+ l = gtk.Label(name + " ")
+ l.set_use_markup(True)
+ l.show()
+ pack(l, 0)
+
+ if (isinstance(item, bitwise.intDataElement) or
+ isinstance(item, bitwise.bcdDataElement)):
+ e = IntegerEditor(item)
+ elif (isinstance(item, bitwise.arrayDataElement) and
+ isinstance(item[0], bitwise.bcdDataElement)):
+ e = BCDArrayEditor(item)
+ elif (isinstance(item, bitwise.arrayDataElement) and
+ isinstance(item[0], bitwise.charDataElement)):
+ e = CharArrayEditor(item)
+ else:
+ e = OtherEditor(item)
+ e.show()
+ pack(e, 1)
+ next_row()
+
+
+ def __init__(self, rthread):
+ super(RadioBrowser, self).__init__()
+ self._radio = rthread.radio
+ self._build_ui()
+ self._fill('root', self._radio._memobj)
+
+if __name__ == "__main__":
+ from chirp import *
+ from chirp import directory
+ import sys
+
+ r = directory.get_radio_by_image(sys.argv[1])
+ class Foo:
+ radio = r
+ w = gtk.Window()
+ b = RadioBrowser(Foo)
+ w.set_default_size(1024, 768)
+ w.add(b.root)
+ w.show()
+ gtk.main()