diff --git a/sc/Document.sc b/sc/Document.sc new file mode 100644 index 0000000..8e3d7b1 --- /dev/null +++ b/sc/Document.sc @@ -0,0 +1,587 @@ +// Since SC v3.2 dev, Document is an ABSTRACT class. Can't be instantiated directly. +// Subclasses provide the editor-specific implementation, e.g. CocoaDocument for the standard Mac interface. +// Subclasses also (in their SC code files) add a "implementationClass" method to Document to tell it to use them. + +Document { + + classvar current; + classvar initAction; + + classvar <>autoRun = true; + + classvar <>implementationClass; + + //don't change the order of these vars: + var keyDownAction, <>keyUpAction, <>mouseUpAction; + var <>toFrontAction, <>endFrontAction, <>onClose, <>mouseDownAction; + + var = 0 } + } { start = start - 1 }; + while { + str[end] !== Char.nl and: { end < max } + } { end = end + 1 }; + ^str.copyRange(start + 1, end); + } + +//actions: + + didBecomeKey { + this.class.current = this; + this.saveCurrentEnvironment; + toFrontAction.value(this); + } + + didResignKey { + endFrontAction.value(this); + this.restoreCurrentEnvironment; + } + + mouseUp{ | x, y, modifiers, buttonNumber, clickCount, clickPos | + mouseUpAction.value(this, x, y, modifiers, buttonNumber, clickCount) + } + + keyDown { | character, modifiers, unicode, keycode | + this.class.globalKeyDownAction.value(this,character, modifiers, unicode, keycode); + keyDownAction.value(this,character, modifiers, unicode, keycode); + } + + keyUp { | character, modifiers, unicode, keycode | + this.class.globalKeyUpAction.value(this,character, modifiers, unicode, keycode); + keyUpAction.value(this,character, modifiers, unicode, keycode); + } + + == { | doc | + ^if(this.path.isNil or: { doc.path.isNil }) { doc === this } { + this.path == doc.path + } + } + + hash { + ^(this.path ? this).hash + } + + *defaultUsesAutoInOutdent_ {|bool| + Document.implementationClass.prDefaultUsesAutoInOutdent_(bool) + } + + usesAutoInOutdent_ {|bool| + this.prUsesAutoInOutdent_(bool) + } + + *prDefaultUsesAutoInOutdent_{|bool| + this.subclassResponsibility(thisMethod); + } + + *prPostColor_{ |color| + this.subclassResponsibility(thisMethod); + } + + prUsesAutoInOutdent_{|bool| + ^this.subclassResponsibility(thisMethod); + } + + +// private implementation + + prIsEditable_{ | editable=true | + ^this.subclassResponsibility(thisMethod) + } + prSetTitle { | argName | + ^this.subclassResponsibility(thisMethod) + } + prGetTitle { + ^this.subclassResponsibility(thisMethod) + } + prGetFileName { + ^this.subclassResponsibility(thisMethod) + } + prSetFileName { | apath | + ^this.subclassResponsibility(thisMethod) + } + prGetBounds { | argBounds | + ^this.subclassResponsibility(thisMethod) + } + + prSetBounds { | argBounds | + ^this.subclassResponsibility(thisMethod) + } + + text { + ^this.subclassResponsibility(thisMethod) + } + selectedText { + ^this.subclassResponsibility(thisMethod) + } + selectUnderlinedText { | clickPos | + ^this.subclassResponsibility(thisMethod) + } + + linkAtClickPos { | clickPos | + ^this.subclassResponsibility(thisMethod) + } + + rangeText { | rangestart=0, rangesize=1 | + ^this.subclassResponsibility(thisMethod) + } + + prclose { + ^this.subclassResponsibility(thisMethod) + } + + closed { + onClose.value(this); // call user function + this.restoreCurrentEnvironment; + allDocuments.remove(this); + dataptr = nil; + } + + prinsertText { | dataPtr, txt | + ^this.subclassResponsibility(thisMethod) + } + insertTextRange { | string, rangestart, rangesize | + ^this.subclassResponsibility(thisMethod) + } + + prAdd { + allDocuments = allDocuments.add(this); + this.editable = true; + if (autoRun) { + if (this.rangeText(0,7) == "/*RUN*/") + { + this.text.interpret; + } + }; + current = this; + initAction.value(this); + + } + + //this is called after recompiling the lib + *prnumberOfOpen { + ^this.subclassResponsibility(thisMethod) + } + *numberOfOpen { + thisProcess.platform.when(\_NumberOfOpenTextWindows) { + ^this.prnumberOfOpen + } { ^allDocuments.size }; + ^0 + } + + *newFromIndex { | idx | + ^super.new.initByIndex(idx) + } + initByIndex { | idx | + //allDocuments = allDocuments.add(this); + var doc; + doc = this.prinitByIndex(idx); + if(doc.isNil,{^nil}); + this.prAdd; + } + prinitByIndex { | idx | + ^this.subclassResponsibility(thisMethod) + } + + //this is called from the menu: open, new + *prGetLast { + ^Document.implementationClass.prBasicNew.initLast + } + + initLast { + ^this.subclassResponsibility(thisMethod) + } + + prGetLastIndex { + ^this.subclassResponsibility(thisMethod) + } + + // private open + initFromPath { | path, selectionStart, selectionLength | + var stpath; + // path = apath; + stpath = this.class.standardizePath(path); + this.propen(stpath, selectionStart, selectionLength); + if(dataptr.isNil,{ + this.class.allDocuments.do{ |d| + if(d.path == stpath.absolutePath){ + ^d + } + }; + ^nil + }); + this.background_(Color.white); + ^this.prAdd; + } + propen { | path, selectionStart=0, selectionLength=0 | + ^this.subclassResponsibility(thisMethod) + } + + // private newTextWindow + initByString{ | argTitle, str, makeListener | + + this.prinitByString(argTitle, str, makeListener); + this.background_(Color.white); + if(dataptr.isNil,{^nil}); + this.prAdd; + this.title = argTitle; + + } + prinitByString { | title, str, makeListener | + ^this.subclassResponsibility(thisMethod) + } + + // other private + // if -1 whole doc + + prSetBackgroundColor { | color | + ^this.subclassResponsibility(thisMethod) + } + prGetBackgroundColor { | color | + ^this.subclassResponsibility(thisMethod) + } + prSetSelectedBackgroundColor { | color | + ^this.subclassResponsibility(thisMethod); + } + prGetSelectedBackgroundColor { | color | + ^this.subclassResponsibility(thisMethod); + } + selectedRangeLocation { + ^this.subclassResponsibility(thisMethod) + } + selectedRangeSize { + ^this.subclassResponsibility(thisMethod) + } + + prSelectLine { | line | + ^this.subclassResponsibility(thisMethod) + } + + *prGetIndexOfListener { + if (this.implementationClass.isNil) { + ^nil + }; + + if (this.implementationClass.respondsTo(\prGetIndexOfListener)) { + ^this.implementationClass.prGetIndexOfListener + } { + ^nil + } + } + + //---not yet implemented + // ~/Documents + // /Volumes + // Music/Patches + + //*reviewUnsavedDocumentsWithAlertTitle + //*saveAllDocuments + //*recentDocumentPaths + //save + //saveAs + //print + // + //hasPath was loaded + + +// Environment handling Document with its own envir must set and restore currentEnvironment on entry and exit. +// Requires alteration of *open, *new, closed, didBecomeKey, and didResignKey + + envir_ { | ev | + envir = ev; + if (this.class.current == this) { + if(envir.isNil) { + this.restoreCurrentEnvironment + } { + if (savedEnvir.isNil) { + this.saveCurrentEnvironment + } + } + } + } + + restoreCurrentEnvironment { + if (savedEnvir.notNil) { + currentEnvironment = savedEnvir; + savedEnvir = nil; + } + } + + saveCurrentEnvironment { + if (envir.notNil) { + savedEnvir = currentEnvironment; + currentEnvironment = envir; + } + } + + *prBasicNew { + ^super.new + } +}