# A minimal text editor using MLTE. Based on wed.py. # # To be done: # - Functionality: find, etc. from Menu import DrawMenuBar from FrameWork import * from Carbon import Win from Carbon import Ctl from Carbon import Qd from Carbon import Res from Carbon import Scrap import os from Carbon import MacTextEditor from Carbon import Mlte UNDOLABELS = [ # Indexed by MLTECanUndo() value "Typing", "Cut", "Paste", "Clear", "Font Change", "Color Change", "Size Change", "Style Change", "Align Left", "Align Center", "Align Right", "Drop", "Move"] class MlteWindow(Window): def open(self, path, name, data): self.path = path self.name = name r = windowbounds(400, 400) w = Win.NewWindow(r, name, 1, 0, -1, 1, 0) self.wid = w flags = MacTextEditor.kTXNDrawGrowIconMask|MacTextEditor.kTXNWantHScrollBarMask| \ MacTextEditor.kTXNWantVScrollBarMask self.ted, self.frameid = Mlte.TXNNewObject(None, w, None, flags, MacTextEditor.kTXNTextEditStyleFrameType, MacTextEditor.kTXNTextFile, MacTextEditor.kTXNMacOSEncoding) self.ted.TXNSetData(MacTextEditor.kTXNTextData, data, 0, 0x7fffffff) self.changed = 0 self.do_postopen() self.do_activate(1, None) def do_idle(self, event): self.ted.TXNIdle() self.ted.TXNAdjustCursor(None) def do_activate(self, onoff, evt): if onoff: ## self.ted.TXNActivate(self.frameid, 0) self.ted.TXNFocus(1) self.parent.active = self else: self.ted.TXNFocus(0) self.parent.active = None self.parent.updatemenubar() def do_update(self, wid, event): self.ted.TXNDraw(None) def do_postresize(self, width, height, window): self.ted.TXNResizeFrame(width, height, self.frameid) def do_contentclick(self, local, modifiers, evt): self.ted.TXNClick(evt) self.parent.updatemenubar() def do_char(self, ch, event): self.ted.TXNKeyDown(event) self.parent.updatemenubar() def close(self): if self.changed: save = EasyDialogs.AskYesNoCancel('Save window "%s" before closing?'%self.name, 1) if save > 0: self.menu_save() elif save < 0: return if self.parent.active == self: self.parent.active = None self.ted.TXNDeleteObject() del self.ted ## del self.tedtexthandle self.do_postclose() def menu_save(self): if not self.path: self.menu_save_as() return # Will call us recursively dhandle = self.ted.TXNGetData(0, 0x7fffffff) data = dhandle.data fp = open(self.path, 'wb') # NOTE: wb, because data has CR for end-of-line fp.write(data) if data[-1] <> '\r': fp.write('\r') fp.close() self.changed = 0 def menu_save_as(self): path = EasyDialogs.AskFileForSave(message='Save as:') if not path: return self.path = path self.name = os.path.split(self.path)[-1] self.wid.SetWTitle(self.name) self.menu_save() def menu_cut(self): ## self.ted.WESelView() self.ted.TXNCut() ### Mlte.ConvertToPublicScrap() ## Scrap.ZeroScrap() ## self.ted.WECut() ## self.updatescrollbars() self.parent.updatemenubar() self.changed = 1 def menu_copy(self): ## Scrap.ZeroScrap() self.ted.TXNCopy() ### Mlte.ConvertToPublicScrap() ## self.updatescrollbars() self.parent.updatemenubar() def menu_paste(self): ### Mlte.ConvertFromPublicScrap() self.ted.TXNPaste() ## self.updatescrollbars() self.parent.updatemenubar() self.changed = 1 def menu_clear(self): ## self.ted.WESelView() self.ted.TXNClear() ## self.updatescrollbars() self.parent.updatemenubar() self.changed = 1 def menu_undo(self): self.ted.TXNUndo() ## self.updatescrollbars() self.parent.updatemenubar() def menu_redo(self): self.ted.TXNRedo() ## self.updatescrollbars() self.parent.updatemenubar() def have_selection(self): start, stop = self.ted.TXNGetSelection() return start < stop def can_paste(self): return Mlte.TXNIsScrapPastable() def can_undo(self): can, which = self.ted.TXNCanUndo() if not can: return None if which >= len(UNDOLABELS): # Unspecified undo return "Undo" which = UNDOLABELS[which] return "Undo "+which def can_redo(self): can, which = self.ted.TXNCanRedo() if not can: return None if which >= len(UNDOLABELS): # Unspecified undo return "Redo" which = UNDOLABELS[which] return "Redo "+which class Mlted(Application): def __init__(self): Application.__init__(self) self.num = 0 self.active = None self.updatemenubar() def makeusermenus(self): self.filemenu = m = Menu(self.menubar, "File") self.newitem = MenuItem(m, "New window", "N", self.open) self.openitem = MenuItem(m, "Open...", "O", self.openfile) self.closeitem = MenuItem(m, "Close", "W", self.closewin) m.addseparator() self.saveitem = MenuItem(m, "Save", "S", self.save) self.saveasitem = MenuItem(m, "Save as...", "", self.saveas) m.addseparator() self.quititem = MenuItem(m, "Quit", "Q", self.quit) self.editmenu = m = Menu(self.menubar, "Edit") self.undoitem = MenuItem(m, "Undo", "Z", self.undo) self.redoitem = MenuItem(m, "Redo", None, self.redo) m.addseparator() self.cutitem = MenuItem(m, "Cut", "X", self.cut) self.copyitem = MenuItem(m, "Copy", "C", self.copy) self.pasteitem = MenuItem(m, "Paste", "V", self.paste) self.clearitem = MenuItem(m, "Clear", "", self.clear) # Groups of items enabled together: self.windowgroup = [self.closeitem, self.saveitem, self.saveasitem, self.editmenu] self.focusgroup = [self.cutitem, self.copyitem, self.clearitem] self.windowgroup_on = -1 self.focusgroup_on = -1 self.pastegroup_on = -1 self.undo_label = "never" self.redo_label = "never" def updatemenubar(self): changed = 0 on = (self.active <> None) if on <> self.windowgroup_on: for m in self.windowgroup: m.enable(on) self.windowgroup_on = on changed = 1 if on: # only if we have an edit menu on = self.active.have_selection() if on <> self.focusgroup_on: for m in self.focusgroup: m.enable(on) self.focusgroup_on = on changed = 1 on = self.active.can_paste() if on <> self.pastegroup_on: self.pasteitem.enable(on) self.pastegroup_on = on changed = 1 on = self.active.can_undo() if on <> self.undo_label: if on: self.undoitem.enable(1) self.undoitem.settext(on) self.undo_label = on else: self.undoitem.settext("Nothing to undo") self.undoitem.enable(0) changed = 1 on = self.active.can_redo() if on <> self.redo_label: if on: self.redoitem.enable(1) self.redoitem.settext(on) self.redo_label = on else: self.redoitem.settext("Nothing to redo") self.redoitem.enable(0) changed = 1 if changed: DrawMenuBar() # # Apple menu # def do_about(self, id, item, window, event): EasyDialogs.Message("A simple single-font text editor based on MacTextEditor") # # File menu # def open(self, *args): self._open(0) def openfile(self, *args): self._open(1) def _open(self, askfile): if askfile: path = EasyDialogs.AskFileForOpen(typeList=('TEXT',)) if not path: return name = os.path.split(path)[-1] try: fp = open(path, 'rb') # NOTE binary, we need cr as end-of-line data = fp.read() fp.close() except IOError as arg: EasyDialogs.Message("IOERROR: %r" % (arg,)) return else: path = None name = "Untitled %d"%self.num data = '' w = MlteWindow(self) w.open(path, name, data) self.num = self.num + 1 def closewin(self, *args): if self.active: self.active.close() else: EasyDialogs.Message("No active window?") def save(self, *args): if self.active: self.active.menu_save() else: EasyDialogs.Message("No active window?") def saveas(self, *args): if self.active: self.active.menu_save_as() else: EasyDialogs.Message("No active window?") def quit(self, *args): for w in self._windows.values(): w.close() if self._windows: return self._quit() # # Edit menu # def undo(self, *args): if self.active: self.active.menu_undo() else: EasyDialogs.Message("No active window?") def redo(self, *args): if self.active: self.active.menu_redo() else: EasyDialogs.Message("No active window?") def cut(self, *args): if self.active: self.active.menu_cut() else: EasyDialogs.Message("No active window?") def copy(self, *args): if self.active: self.active.menu_copy() else: EasyDialogs.Message("No active window?") def paste(self, *args): if self.active: self.active.menu_paste() else: EasyDialogs.Message("No active window?") def clear(self, *args): if self.active: self.active.menu_clear() else: EasyDialogs.Message("No active window?") # # Other stuff # def idle(self, event): if self.active: self.active.do_idle(event) else: Qd.SetCursor(Qd.GetQDGlobalsArrow()) def main(): Mlte.TXNInitTextension(0) try: App = Mlted() App.mainloop() finally: Mlte.TXNTerminateTextension() if __name__ == '__main__': main()