--- pythonwimp/wimp.py 2005/02/27 13:53:48 73 +++ pythonwimp/wimp.py 2005/05/15 12:08:06 74 @@ -60,6 +60,7 @@ import string import sys import types +import rufl task_handle = 0 task_name = 'Application' @@ -75,7 +76,7 @@ def task(name, dir, task, messages = (), debug = 0, profile = 0, mask = None): "Initialise the task with the wimp and load the messages file" global task_name, directory, b, wimp_version, task_handle, territory, m, task_module, _trace - + hourglass_on() task_name = name directory = dir @@ -113,10 +114,10 @@ print _depth * ' ', event + ':', arg return _trace sys.settrace(_trace) - + # buffer for various stuff b = swi.block(64) - + # initialise with wimp # place the message list in the buffer b[0] = 0x502 # Message_HelpRequest @@ -158,12 +159,12 @@ except: if debug > 1: sys.settrace(None) - + type, value, traceb = sys.exc_info() swi.swi(0x400df, 'sis', ' Internal error - must exit (' + str(type) + ': ' + str(value) + ')', 1, task_name) - + if debug: traceback.print_exc() trace = traceback.extract_tb(traceb) @@ -175,26 +176,26 @@ swi.swi(0x42589, '') except: pass - + if sys.stderr.tell() > 0: sys.stderr.close() os.system('Filer_Run ' + directory + '.^.Output') else: sys.stderr.close() - + # Wimp_CloseDown swi.swi(0x400dd, 'ii', task_handle, 0x4b534154) hourglass_off() - + def _go(): "Run the program" task_module.init() hourglass_off() while 1: handle(poll(poll_mask)) - - + + def quit(): "Trigger quitting" for f in fonts.values(): @@ -488,6 +489,17 @@ (screen_width + width) / 2, (screen_height + height) / 2, bb[5], bb[6], behind) + def open_full_size(self, behind = None): + bb = swi.block(20) + bb[0] = self.handle + swi.swi('Wimp_GetWindowState', '.b', bb) + bb[3] = 10000 + bb[2] = -10000 + if behind: + bb[7] = behind + swi.swi('Wimp_OpenWindow', '.b', bb) + self.is_open = 1 + def open_as_menu(self): "Open the window as a menu centred on the pointer" bb = swi.block(20) @@ -508,13 +520,13 @@ # Wimp_CloseWindow swi.swi(0x400c6, '.b', bb) self.is_open = 0 - + def entering(self): "Pointer entering window" - + def leaving(self): "Pointer leaving window" - + def click(self, icon, buttons, x, y, sx, sy): "Mouse click in window" self.contents.reverse() @@ -526,7 +538,7 @@ return 1 self.contents.reverse() return 0 - + def help(self, icon): "Return interactive help message" if m.has_key('help.' + self.name + '.' + str(icon)): @@ -534,12 +546,12 @@ elif m.has_key('help.' + self.name): return m['help.' + self.name] return None - + def key(self, icon, key): "Handle key presses" # Wimp_ProcessKey swi.swi(0x400dc, 'i', key) - + def icon_text(self, icon, text = None): "Read or write an icon's text contents" if icon >= self.icons: @@ -566,7 +578,7 @@ swi.swi(0x400d3, '.b', bb) if bb[0] == self.handle and bb[1] == icon: self.put_caret(icon) - + def icon_crement(self, icon, min, max, step = 1): "Increment or decrement a numerical icon" number = self.icon_text(icon) @@ -583,7 +595,7 @@ else: number = number + step self.icon_text(0, str(number)) - + def icon_set(self, icon, state = None): "Return the state or set the state of an icon" if icon >= self.icons: @@ -602,7 +614,7 @@ # Wimp_SetIconState bb[2] = bb[3] = bb[6] swi.swi(0x400cd, '.b', bb) - + def put_caret(self, icon = -1, x = 0, y = 0, height = 0x2000000): "Place the caret in the window" if icon == -1: @@ -626,19 +638,19 @@ def icon_ungrey(self, icon): "Ungrey an icon" self.icon_grey(icon, 0) - + def add_content(self, content): "Add a content class to the window" self.contents.append(content) - + def remove_content(self, content): "Remove a content class from the window" self.contents.remove(content) - + def refresh(self, x0, y0, x1, y1): "Force a redraw of an area of the window" swi.swi('Wimp_ForceRedraw', 'iiiii', self.handle, x0, -y1, x1, -y0) - + def update(self, x0, y0, x1, y1): "Update an area of the window" bb = swi.block(20) @@ -661,7 +673,7 @@ # Wimp_GetRectangle more = swi.swi(0x400ca, '.b;i', bb) self.redraw_stop() - + def title(self, title = None): "Change or return the window title" if title is None: @@ -690,7 +702,7 @@ bb[3] = -y0 # Wimp_SetExtent swi.swi(0x400d7, 'ib', self.handle, bb) - + def origin(self): "Return the window origin position on the screen" bb = swi.block(20) @@ -699,7 +711,7 @@ self.ox = b[1] - b[5] self.oy = b[4] - b[6] return self.ox, self.oy - + def icon_box(self, icon): "Return the bbox of an icon relative to the window" bb = swi.block(20) @@ -707,7 +719,7 @@ bb[1] = icon swi.swi('Wimp_GetIconState', '.b', bb) return bb[2], -bb[5], bb[4], -bb[3] - + def icon_drag(self, icon): "Start to drag the specified icon" self.origin() @@ -721,7 +733,7 @@ class iconbar_icon(window): - + def __init__(self, sprite, handler, indirected = 0): "Create an iconbar icon with the specified sprite" bb = swi.block(20) @@ -745,22 +757,22 @@ self.name = 'iconbar' self.handler = handler windows[-2] = self - + def click(self, icon, buttons, x, y, sx, sy): "Handle a click on the iconbar" self.handler(buttons, sx) - + def change(self, sprite): self.icon_text(self.icon, sprite) class info_window(window): "Info box window including email/web buttons" - + def __init__(self): "Load the window template" window.__init__(self, 'info') - + def click(self, icon, buttons, x, y, sx, sy): "Handle mouse clicks" try: @@ -780,13 +792,13 @@ class save_window(window): "Standard RISC OS save window" - + def __init__(self, handler, type): "Load the window template" window.__init__(self, 'save') self.handler = handler self.type = type - + def click(self, icon, buttons = 0, x = 0, y = 0, sx = 0, sy = 0): "Handle mouse clicks" if icon == 0 and buttons > 15: @@ -854,13 +866,13 @@ class menu: "Wimp menu class" - + def __init__(self, name, items): "Load menu" self.blocks = [] self.menu_block = self._load(items) self.name = name - + def menu(self, x, y): "Display menu and return the selection" global current_menu @@ -897,20 +909,20 @@ "Create a wimp menu structure (recursively)" menu_block = swi.block(7 + 6 * (len(items) - 1)) self.blocks.append(menu_block) - + title_block = swi.block(len(lookup(items[0])) / 4 + 1) self.blocks.append(title_block) title_block.padstring(lookup(items[0]), '\0') menu_block[0] = title_block.start - + menu_block[1] = menu_block[2] = -1 menu_block[3] = 0x00070207 menu_block[4] = 300 menu_block[5] = 44 menu_block[6] = 0 - + offset = 7 - + for item in items[1:]: if isinstance(item, types.StringType): text = item @@ -921,6 +933,10 @@ submenu = item[1].handle else: submenu = self._load(item[1]).start + grey = False + if text[0] == '-': + grey = True + text = text[1:] item_block = swi.block(len(lookup(text)) / 4 + 1) self.blocks.append(item_block) @@ -928,49 +944,57 @@ menu_block[offset] = (0x100 * (offset == 7)) menu_block[offset + 1] = submenu menu_block[offset + 2] = 0x07000111 + if grey: + menu_block[offset + 2] |= 1 << 22 menu_block[offset + 3] = item_block.start menu_block[offset + 4] = menu_block[offset + 5] = -1 - + offset = offset + 6 - + menu_block[offset - 6] = menu_block[offset - 6] | 0x80 - + return menu_block class content: "Base window content class" - + def __init__(self, w, x0, y0, x1, y1): "Initialise a window content" self.window = w self.pos = [x0, y0, x1, y1] - + def redraw(self, ox, oy): "Redraw content" pass - + def click(self, buttons, x, y): "Handle clicks in the content" return 0 - + def refresh(self): "Force redraw of the content" - self.window.refresh(self.pos[0] - 4, self.pos[1] - 4, self.pos[2] + 4, self.pos[3] + 4) - + self.window.refresh(self.pos[0] - 4, self.pos[1] - 4, + self.pos[2] + 4, self.pos[3] + 4) + def update(self): "Update the content" - self.window.update(self.pos[0] - 4, self.pos[1] - 4, self.pos[2] + 4, self.pos[3] + 4) + self.window.update(self.pos[0] - 4, self.pos[1] - 4, + self.pos[2] + 4, self.pos[3] + 4) class rectangle(content): "Example window content" - def __init__(self, w, x0, y0, x1, y1, fill = None, border = None): + def __init__(self, w, x0, y0, x1, y1, fill = None, border = None, + text = None, font = None, text_colour = 0x000000): content.__init__(self, w, x0, y0, x1, y1) self.fill = fill self.border = border - + self.text = text + self.font = font + self.text_colour = text_colour + def redraw(self, ox, oy): if not self.fill is None: # ColourTrans_SetGCOL @@ -987,33 +1011,92 @@ swi.swi(0x45, '5ii', ox + self.pos[2], oy - self.pos[1]) swi.swi(0x45, '5ii', ox + self.pos[0], oy - self.pos[1]) swi.swi(0x45, '5ii', ox + self.pos[0], oy - self.pos[3]) + if not self.text is None and not self.font is None: + self.font.colour(0xdddddd, self.text_colour) + self.font.paint(self.text, 400 * (ox + self.pos[0]), + 400 * (oy - (self.pos[1] + self.pos[3] * 3) / 4)) def click(self, buttons, x, y): - self.window.remove_content(self) - self.refresh() - return 1 + #self.window.remove_content(self) + #self.refresh() + return 0 + + +class paragraph(content): + "A paragraph of text" + def __init__(self, w, x0, y0, x1, font_family, font_style, font_size, + text, text_colour = 0x000000, fill = None, padding = 10): + self.font_family = font_family + self.font_style = font_style + self.font_size = font_size + self.line_height = int(font_size * 0.2) + self.text = [] + self.text_colour = text_colour + self.fill = fill + self.padding = padding + text = text.encode('utf8') + width = x1 - x0 - padding - padding + while text: + (c, x) = rufl.split(font_family, font_style, font_size, text, + width) + s = text[:c] + space = s.rfind(' ') + if c != len(text) and space != -1: + c = space + s = text[:c + 1] + text = text[c + 1:] + self.text.append(s) + y1 = y0 + len(self.text) * self.line_height + padding + padding + content.__init__(self, w, x0, y0, x1, y1) + self.y1 = y1 -def font(name, size_x, size_y): + def redraw(self, ox, oy): + if not self.fill is None: + swi.swi('ColourTrans_SetGCOL', 'i..i0', self.fill << 8, 1 << 8) + swi.swi('OS_Plot', '4ii', ox + self.pos[0], oy - self.pos[3]) + swi.swi('OS_Plot', 'iii', 96 + 5, ox + self.pos[2], + oy - self.pos[1]) + swi.swi('ColourTrans_SetFontColours', 'iiii', 0, + 0xffffff << 8, self.text_colour << 8, 14) + y = oy - self.pos[1] - self.padding - self.line_height * 0.75 + for line in self.text: + rufl.paint(self.font_family, self.font_style, self.font_size, + line, ox + self.pos[0] + self.padding, y, rufl.blend) + y -= self.line_height + + +def font(name, size_x, size_y, no_encoding = False): f = (name, size_x, size_y) if fonts.has_key(f): font = fonts[f] font.use = font.use + 1 return font else: - fonts[f] = _font(name, size_x, size_y) + fonts[f] = _font(name, size_x, size_y, no_encoding) return fonts[f] class _font: - def __init__(self, name, size_x, size_y): + def __init__(self, name, size_x, size_y, no_encoding): self.name = name self.size_x = size_x self.size_y = size_y self.use = 1 - # Font_FindFont - self.handle = swi.swi(0x40081, '.sii00;i', self.name, self.size_x, self.size_y) - + if no_encoding: + self.handle = swi.swi('XFont_FindFont', '.sii00;i', + self.name, self.size_x, self.size_y) + self.utf8 = False + else: + try: + self.handle = swi.swi('XFont_FindFont', '.sii00;i', + self.name + '\EUTF8', self.size_x, self.size_y) + self.utf8 = True + except swi.error: + self.handle = swi.swi('XFont_FindFont', '.sii00;i', + self.name + '\ELatin1', self.size_x, self.size_y) + self.utf8 = False + def lose(self): self.use = self.use - 1 if self.use == 0: @@ -1022,7 +1105,10 @@ def paint(self, string, x, y, spacex = 0, spacey = 0, offx = 0, offy = 0, x0 = 0, y0 = 0, x1 = 0, y1 = 0): - # Font_Paint + if self.utf8: + s = string.encode('utf8') + else: + s = string.encode('latin1', 'replace') if x0: bb = swi.block(20) bb[0] = spacex @@ -1033,13 +1119,13 @@ bb[5] = int(y0) bb[6] = int(x1) bb[7] = int(y1) - swi.swi(0x40086, 'isiiib', self.handle, string, 0x322, x, y, bb) - else: - swi.swi(0x40086, 'isiii', self.handle, string, 0x300, x, y) + swi.swi('Font_Paint', 'isiiib', self.handle, s, 0x322, x, y, bb) + else: + swi.swi('Font_Paint', 'isiii', self.handle, s, 0x300, x, y) def charbbox(self, char): return swi.swi('Font_CharBBox', 'ii0;.iiii', self.handle, ord(char)) - + def colour(self, back, fore): # ColourTrans_SetFontColours swi.swi(0x4074f, 'iiii', self.handle, back << 8, fore << 8, 14) @@ -1049,30 +1135,49 @@ return (0, 0, 0, 0) if string[-1] == ' ': string = string + ' ' + if self.utf8: + s = string.encode('utf8') + else: + s = string.encode('latin1', 'replace') bb = swi.block(20) bb[0] = bb[1] = bb[2] = bb[3] = 0 bb[4] = -1 # Font_ScanString - swi.swi(0x400a1, 'isiiib', self.handle, string, 0x40320, 0x7fffffff, 0x7fffffff, bb) + swi.swi(0x400a1, 'isiiib', self.handle, s, 0x40320, 0x7fffffff, + 0x7fffffff, bb) return bb[5], bb[6], bb[7], bb[8] def caretpos(self, string, x, y): - bb = swi.block(len(string) / 4 + 10) - bb.padstring(string, chr(0)) + if self.utf8: + s = string.encode('utf8') + else: + s = string.encode('latin1', 'replace') + bb = swi.block(len(s) / 4 + 10) + bb.padstring(s, chr(0)) # Font_ScanString - pos, cx, cy = swi.swi(0x400a1, 'ibiii;.i.ii', self.handle, bb, 0x20300, x, y) + pos, cx, cy = swi.swi(0x400a1, 'ibiii;.i.ii', self.handle, bb, + 0x20300, x, y) return pos - bb.start, cx, cy - + def caretxy(self, string, pos): + if self.utf8: + s = string.encode('utf8') + else: + s = string.encode('latin1', 'replace') # Font_ScanString - return swi.swi(0x400a1, 'isiii..i;...ii', self.handle, string, 0x20380, 0x7fffffff, 0x7fffffff, pos) - + return swi.swi(0x400a1, 'isiii..i;...ii', self.handle, s, + 0x20380, 0x7fffffff, 0x7fffffff, pos) + def fontbox(self): return swi.swi('Font_ReadInfo', 'i;.iiii', self.handle) - + def split(self, string, x, y): - bb = swi.block(len(string) / 4 + 10) - bb.padstring(string, chr(0)) + if self.utf8: + s = string.encode('utf8') + else: + s = string.encode('latin1', 'replace') + bb = swi.block(len(s) / 4 + 10) + bb.padstring(s, chr(0)) # Font_ScanString pos = swi.swi(0x400a1, 'ibiii;.i', self.handle, bb, 0x300, x, y) return pos - bb.start @@ -1105,7 +1210,7 @@ self.views.remove(view) for content in self.contents: content.remove_view(view) - + def rescaled(self, view): for content in self.contents: content.remove_view(view) @@ -1125,10 +1230,10 @@ view.gx1 * 400 / scale - content.pos[0], view.gy1 * 400 / scale - content.pos[1]] content.redraw(view, view.ox, view.oy, scale) - + def redraw_stop(self, view, scale): pass - + def redraw_margin(self, view): set_colour(0x777777) plot(4, view.ox + view.gx0, view.oy) @@ -1144,12 +1249,12 @@ for content in self.contents: if content.pos[0] <= x <= content.pos[2] and content.pos[1] <= y <= content.pos[3]: content.click(view, buttons, x - content.pos[0], y - content.pos[1]) - + def refresh(self, x0, y0, x1, y1): for view in self.views: view.update(int(view.scale * x0 / 400 - 4), int(view.scale * y0 / 400 - 4), int(view.scale * x1 / 400 + 4), int(view.scale * y1 / 400 + 4)) - + def add_font(self, name, size_x, size_y): f = (name, size_x, size_y) if self.fonts.has_key(f): @@ -1168,7 +1273,7 @@ class document_view(window): - + def __init__(self, document, id, scale): window.__init__(self, id) self.document = document @@ -1182,7 +1287,7 @@ def redraw(self): self.document.redraw(self, self.scale) - + def redraw_stop(self): self.document.redraw_stop(self, self.scale) @@ -1210,7 +1315,7 @@ class document_content: - + def __init__(self, document, x0, y0, x1, y1): self.pos = [x0, y0, x1, y1] self.colour = 0x0000ff @@ -1222,7 +1327,7 @@ def remove_view(self, view): pass - + def redraw(self, view, x, y, scale): set_colour(self.colour) plot(4, x + self.scaled_pos[0], y - self.scaled_pos[1]) @@ -1233,7 +1338,7 @@ plot(21, x + self.scaled_pos[2], y - self.scaled_pos[3]) plot(4, x + self.scaled_pos[2], y - self.scaled_pos[1]) plot(21, x + self.scaled_pos[0], y - self.scaled_pos[3]) - + def click(self, view, buttons, x, y): self.colour = 0xffffff - self.colour self.document.refresh(self.pos[0], self.pos[1], self.pos[2], self.pos[3])