From 03789d7d513f5e5ae5f268cb67ab8c91d372d031 Mon Sep 17 00:00:00 2001 From: Kelvin Sherlock Date: Mon, 27 Jul 2020 22:00:39 -0400 Subject: [PATCH] split up components --- base.py | 261 ++++++++++++++++++ control.py | 317 ++++++++++++++++++++++ menu.py | 200 ++++++++++++++ rect.py | 27 +- rezpy.py | 776 +---------------------------------------------------- window.py | 146 ++++++++++ 6 files changed, 954 insertions(+), 773 deletions(-) create mode 100644 base.py create mode 100644 control.py create mode 100644 menu.py create mode 100644 window.py diff --git a/base.py b/base.py new file mode 100644 index 0000000..e82e6f5 --- /dev/null +++ b/base.py @@ -0,0 +1,261 @@ +import struct +from bisect import bisect_left +from rect import * + +# helper functions +def str_to_bytes(text): + if isinstance(text, str): return text.encode("macroman") + if isinstance(text, bytes): return text + if isinstance(text, bytearray): return bytes(text) + raise TypeError("Bad text type: {}".format(type(text))) + + +def make_string(text, rType=None): + if not rType: rType = rPString + if type(text) == rType: return text + if type(text) in (str, bytes, bytearray): return rType(text) + raise TypeError("Bad text type: {}".format(type(text))) + + +#define KeyEquiv array[1]{ char; char; _mybase_ word; _mybase_ word; } + +# ( "Ss", 0x..., 0x.... ) + +class rObject: + rName = None + rType = None + + _rmap = {} + _resources = {} + + # also a define=proeprty to trigger export in equ file? + def __init__(self, id=None, attr=None): + rType = self.rType + self.id = id + self.attr = attr + + self._check_id(rType, id) + + def _check_id(self, rType, rID): + + if rType in self._resources: + xx = self._resources[rType] + else: + xx = [] + self._resources[rType] = xx + xx.append(self) + + if type(rID) == int: + if rType in self._rmap: + xx = self._rmap[rType] + else: + xx = set() + self._rmap[rType] = xx + + if rID in xx: + raise ValueError("{} (${:04x}) ${:08x} already defined".format(self.rName, rType, rID)) + + + def get_id(self): + rID = self.id + rType = self.rType + if type(rID) == int: return rID + + + if rType in self._rmap: + xx = self._rmap[rType] + else: + xx = set() + self._rmap[rType] = xx + + used = list(xx) + used.sort() + + + rr = range(1,0x07FEFFFF) + if type(rID) == range: + rr = rID + + ix = bisect_left(used, rr.start) + + for rID in rr: + if ix >= len(used) or used[ix] > rID : + self.id = rID + xx.add(self.id) + return self.id + ix += 1 + raise Exception("Unable to allocate id for resource") + + # # just append + # if len(xx) == 0: + # self.id = 1 + # xx.add(self.id) + # return self.id + + # rID = used[-1] + 1 + # self.id = rID + # xx.add(self.id) + # return self.id + + @staticmethod + def dump(): + for rType,rList in rObject._resources.items(): + for r in rList: + print("${:04x} {} - ${:08x}".format(rType, r.rName, r.get_id())) + + + @staticmethod + def dumphex(): + for rType,rList in rObject._resources.items(): + for r in rList: + bb = bytes(r) + print("{}(${:08x}) {{".format(r.rName, r.get_id())) + print("\t$\"" + bb.hex() + "\"") + print("}\n") + + @staticmethod + def dumprez(): + for rType,rList in rObject._resources.items(): + for r in rList: + content = r._rez_string() + + print("{}(${:08x}) {{".format(r.rName, r.get_id())) + print(content) + print("}\n") + + + +class rTextObject(rObject): + def __init__(self, text, *, id=None, attr=None): + super().__init__(id=id, attr=attr) + # text is a string or bytes. + # bytes is assumed to be macroman + self.text = text + self._text = str_to_bytes(text) + + def __bytes__(self): + return self._text + + def _rez_string(self): + # todo - should extended chars be macroman? + return '\t"' + self._text.decode("ascii") + '"' + + +class rText(rTextObject): + rName = "rText" + rType = 0x8016 + +class rTextBlock(rTextObject): + rName = "rTextBlock" + rType = 0x8011 + +class rTextForLETextBox2(rTextObject): + rName = "rTextForLETextBox2" + rType = 0x800b + +class rAlertString(rTextObject): + rName = "rAlertString" + rType = 0x8015 + +class rErrorString(rTextObject): + rName = "rErrorString" + rType = 0x8020 + +class rComment(rTextObject): + rName = "rComment" + rType = 0x802a + +class rPString(rTextObject): + rName = "rPString" + rType = 0x8006 + + def __bytes__(self): + bb = super().__bytes__() + return struct.pack("= 32 and x < 0x7e: return '"' + chr(x) + '"' + return "\\x{:02x}".format(x) + +class rMenuBar(rObject): + rName = "rMenuBar" + rType = 0x8008 + + def __init__(self, *children, id=None, attr=None): + super().__init__(id, attr) + self.children = children[:] + for x in children: + if not isinstance(x, rMenu): + raise TypeError("bad type: {}".format(type(x))) + + def __bytes__(self): + bb = struct.pack("= 1: + self.itemChar = bb[0] + self.altItemChar = bb[0] # upper to lower? + if len(bb) >= 2: + self.altItemChar = bb[1] + if len(bb) > 2: + raise ValueError("keys too long: {}".format(keys)) + + + def __bytes__(self): + itemID = self.itemID + if itemID == None: itemID = self.get_id() + bb = struct.pack("= len(used) or used[ix] > rID : - self.id = rID - xx.add(self.id) - return self.id - ix += 1 - raise Exception("Unable to allocate id for resource") - - # # just append - # if len(xx) == 0: - # self.id = 1 - # xx.add(self.id) - # return self.id - - # rID = used[-1] + 1 - # self.id = rID - # xx.add(self.id) - # return self.id - - @staticmethod - def dump(): - for rType,rList in rObject._resources.items(): - for r in rList: - print("${:04x} {} - ${:08x}".format(rType, r.rName, r.get_id())) - - - @staticmethod - def dumphex(): - for rType,rList in rObject._resources.items(): - for r in rList: - bb = bytes(r) - print("{}(${:08x}) {{".format(r.rName, r.get_id())) - print("\t$\"" + bb.hex() + "\"") - print("}\n") - - @staticmethod - def dumprez(): - for rType,rList in rObject._resources.items(): - for r in rList: - content = r._rez_string() - - print("{}(${:08x}) {{".format(r.rName, r.get_id())) - print(content) - print("}\n") - - - -class rTextObject(rObject): - def __init__(self, text, *, id=None, attr=None): - super().__init__(id=id, attr=attr) - # text is a string or bytes. - # bytes is assumed to be macroman - self.text = text - self._text = str_to_bytes(text) - - def __bytes__(self): - return self._text - - def _rez_string(self): - # todo - should extended chars be macroman? - return '"' + self._text.decode("ascii") + '"' - - -class rText(rTextObject): - rName = "rText" - rType = 0x8016 - -class rTextBlock(rTextObject): - rName = "rTextBlock" - rType = 0x8011 - -class rTextForLETextBox2(rTextObject): - rName = "rTextForLETextBox2" - rType = 0x800b - -class rAlertString(rTextObject): - rName = "rAlertString" - rType = 0x8015 - -class rErrorString(rTextObject): - rName = "rErrorString" - rType = 0x8020 - -class rComment(rTextObject): - rName = "rComment" - rType = 0x802a - -class rPString(rTextObject): - rName = "rPString" - rType = 0x8006 - - def __bytes__(self): - bb = super().__bytes__() - return struct.pack("= 1: - self.itemChar = bb[0] - self.altItemChar = bb[0] # upper to lower? - if len(bb) >= 2: - self.altItemChar = bb[1] - if len(bb) > 2: - raise ValueError("keys too long: {}".format(keys)) - - - def __bytes__(self): - itemID = self.itemID - if itemID == None: itemID = self.get_id() - bb = struct.pack("= 32 and x < 0x7e: return '"' + chr(x) + '"' - return "\\x{:02x}".format(x) - -# /*-------------------------------------------------------*/ -# /* Control List Descriptors -# /*-------------------------------------------------------*/ -# #define singlePtr $0000 -# #define singleHandle $0001 -# #define singleResource $0002 -# #define ptrToPtr $0003 -# #define ptrToHandle $0004 -# #define ptrToResource $0005 -# #define handleToPtr $0006 -# #define handleToHandle $0007 -# #define handleToResource $0008 -# #define ResourceToResource $0009 -# -# /*-------------------------------------------------------*/ -# /* Common Flag equates. -# /*-------------------------------------------------------*/ -# #define ctlInvis $0080 -# #define ctlVisible $0000 -# #Define CtlInactive $FF00# -# -# -# /*-------------------------------------------------------*/ -# /* Common MoreFlags equates. -# /*-------------------------------------------------------*/ -# #define FctlTarget $8000 -# #define FctlCanBeTarget $4000 -# #define FctlWantsEvents $2000 -# #define FCtlWantEvents $2000 /* spelling variant */ -# #define FctlProcNotPtr $1000 -# #define FctlTellAboutSize $0800 -# #define FctlIsMultiPart $0400 - -class rControlTemplate(rObject): - rName = "rControlTemplate" - rType = 0x8004 - -class rSimpleButton(rControlTemplate): - rName = "rControlTemplate" - rType = 0x8004 - # /*-------------------------------------------------------*/ - # /* Flag equates for simple buttons. - # /*-------------------------------------------------------*/ - # #Define NormalButton $0000 - # #Define DefaultButton $0001 - # #Define SquareButton $0002 - # #Define SquareShadowButton $0003 - def __init__(self, rect, title, *, - id=None, attr=None, - flags = 0x0000, moreFlags = 0x0000, - refCon = 0x00000000, controlID=None, - **kwargs): - super().__init__(id, attr) - - if kwargs.get("invisible"): flags |= 0x0080 - if kwargs.get("inactive"): flags |= 0xff00 - if kwargs.get("default"): flags |= 0x0001 - if kwargs.get("square"): flags |= 0x0002 - - if kwargs.get("keys"): - moreFlags |= 0x2000 # fCtlWantEvents - moreFlags |= 0x1000 # fCtlProcNotPtr - - # if color: - # moreFlags |= 0x08 # color table is resource id - if title: - moreFlags |= 0x02 # title is resource id - - self.title = make_string(title) - - self.flags = flags - self.moreFlags = moreFlags - self.rect = rect - self.refCon = refCon - self.controlID = controlID - - - def __bytes__(self): - # pcount, id:4, rect, procref:4, flags, moreFlags, refcon, title, color table, keys - - controlID = self.controlID - if controlID == None: controlID = self.get_id() - bb = struct.pack("