# HG changeset patch # User Dan Smith dsmith@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()