This class is meant as an emulation of SCTextView. last mod: 31-dec-09 sciss
Also refer to JSCView for different behaviour affecting all widgets
different behaviour | |
string_ | effective even when the view is made non-editable (in CocoaGUI, string_ doesn't work in this case) |
enterInterpretsSelection | uses Ctrl+Return instead |
extended functionality | |
caret_ | sets the cursor position |
select | changes the selection range |
selectAll | select whole document |
caretColor_ | colour of the cursor (useful for dark backgrounds) |
openURL | allows loading of remote files via HTTP |
action_ | action function is called whenever text is entered, removed or caret moved |
known issues / todo | |
textBounds_ | not available |
usesTabToFocusNextView_ | not yet available |
mouseDownAction | not called with extra "pos" argument |
string_ | doesn't clear previously used style, there should be a way to clear it |
text transmission | due to the trickery of the SuperCollider unicode support (a unicode character can be reflected by more than one Char in a SuperCollider String), there occurs a discrepency between the character count (and hence cursor position) of the server (Swing) and the client (SuperCollider). You'll get "discrepancy" warning messages, indicating that the text representation on the client (SuperCollider) might be wrong |
Note: please use the abstraction layer TextView if possible!
A text view can display a large body of text, either plain or with attributes (such as in HTML). It can also be used to edit multiline text.
( var win; win = JSCWindow.new; t = JSCTextView( win, win.view.bounds.insetBy( 4, 4 )) .resize_( 5 ) .hasVerticalScroller_( true ) .autohidesScrollers_( true ) .focus( true ); win.front; )
The content can be programmatically set from a plain string, using the string_
method:
t.string = "Schoko";
There is a general approach to changing and styling the text: Global methods such as string_
and font_
apply to the whole text, and they are accompanied by methods of the type set<PropertyName>
which along with the new property value take two additional parameters, the cursor start position and the amount of characters to change. For setString
it means that text is inserted when the amount of characters is zero, or replaced if it is greater than zero. Examples:
t.setString( "lade", 7, 0 ); // insert given string at position 7 t.setString( "Klang", 0, 6 ); // at position 0 replace 6 characters with the given string
The other properties are font
, stringColor
, leftIndent
, rightIndent
, spaceAbove
, spaceBelow
, lineSpacing
, and align
. Here are font
and stringColor
:
t.font = JSCFont( "Times", 14 ); t.setFont( JSCFont( "Times-Bold", 20 ), 0, 5 ); t.stringColor = Color.blue; t.setStringColor( Color.red, 5, 4 ); t.background = Color.yellow; // the global background colour t.background = Color.white; t.caretColor = Color.green; // cursor colour (SwingOSC only) t.caretColor = Color.black;
The indentation of paragraphs is controlled through the properties leftIndent
, rightIndent
, spaceAbove
, and spaceBelow
, where each value is specified in pixels:
t.string = "".catList(({{ "riverrun, past Eve and Adams".scramble } ! 8 ++ "\n" } ! 3).flatten ); t.leftIndent = 30; // all paragraphs t.rightIndent = 30; t.setLeftIndent( 60, 550, 1 ); // just the last paragraph t.setRightIndent( 0, 550, 1 ); // just the last paragraph t.spaceAbove = 15; t.spaceBelow = 15;
Paragraph line spacing and alignment:
t.setLineSpacing( 1.0, 0, 1 ); // first paragraph: +100% (double-spacing) t.setLineSpacing( -0.5, 225, 1 ); // second paragraph: -50% (half-spacing) t.lineSpacing = 0.0; // all normal (+- 0 %) t.align = \right; t.setAlign( \center, 0, 1 ); // just the first paragraph t.setAlign( \justified, 225, 1 ); // just the second paragraph t.setAlign( \left, 550, 1 ); // just the third paragraph
First, let's start with a basic text:>
t.string = "\talpha\n\t\tbeta\n\t\t\tgamma\n\t\t\t\tdelta"; t.leftIndent = 0; t.align = \left; // (reset previously made indentation)
Now let's customize the tabs:
// either just positions in pixels t.tabs = [ 30, 60, 90, 120 ]; t.tabs = Array.geom( 5, 20, 1.5 ).integrate; // ...or combos of positions with alignment t.tabs = [[ 30, \center ], [ 60, \center ], [ 90, \center ], [ 120, \center ]]; t.tabs = [[ 30, \right ], [ 60, \right ], [ 90, \right ], [ 120, \right ]]; t.string = "\t1.0\n\t2.3456\n\t-133.3" t.tabs = [[ 40, \decimal ]];
When the text view is a display-only element and you don't want the content to be editable, you can call
t.editable = false; // disable editing t.editable = true; // enable editing
When using the view as an editor, you may want to be notified about the editing process. To do so, register an action function:
t.action = { arg view, state ... params; ([ state ] ++ params).postcs };
The following states and state-parameters are defined:
\insert, <(Integer) pos>, <(Integer) length>, <(String) insertedText>
\remove, <(Integer) pos>, <(Integer) length>
\caret, <(Integer) pos1>, <(Integer) pos2>
\caret
means the cursor was moved or the selection changed. with no text selected (cursor displayed) pos1
equals pos2
, otherwise pos1
and pos2
correspond to the selected range (pos1
may be both greater or less than pos2
).
While the whole text (without styling) can be queried with the string
method, selectedString
returns the currently selected text (possibly empty). The cursor position where the selections begins is returned by selectionStart
and the number of characters in the selection by selectionSize
. The following example uses these methods to provide a styling button:
( t.bounds = t.bounds.insetAll( 0, 30, 0, 0 ); x = JSCButton( t.parent, Rect( 4, 4, 60, 22 )) .enabled_( false ) .canFocus_( false ) .states_([[ "Style" ]]) .action_({ t.setStringColor( Color.rand, t.selectionStart, t.selectionSize )}); t.action = { arg view, what, pos1, pos2; if( what == \caret, { x.enabled = pos1 != pos2 })}; )
JSCTextView
by default allows you to execute the selected text (or the current line if no selection has been made) in the SuperCollider interpreter, by pressing Ctrl+Return
. For example, try to focus the view and press Ctrl+Return
here:
t.string = "JSCTextView.superclasses"; t.selectAll;
To disable this keystroke feature:
t.enterInterpretsSelection_( false );
There are two methods, open
and openURL
to open local and remote text files. These can be plain text or HTML formatted files.
t.open( Document.current.path ); // load this help document t.openURL( "http://en.wikipedia.org/wiki/SuperCollider" ); // a web document
As you can see with the Wikipedia page, the support for modern HTML is limited. E.g. see this bug report: bugs.sun.com/bugdatabase/view_bug.do?bug_id=4296022. Also note that the display becomes better when the view is made non-editable (see next section).
When viewing HTML documents, you may wish to be notified about hyperlink mouse-overs and activations. A precondition is that the view is read-only, that is non-editable:
t.editable = false;
Three action fields are provided, linkAction
(executed when the user clicks on a link), linkEnteredAction
(executed when the user moves the mouse over a link), and linkExitedAction
(executed when the user move the mouse away from a link). The arguments passed into the functions registered here are view
(the instance of the JSCTextView
), the url
and the description
. For special links like "javascript:..."
the url
is empty. Examples:
t.linkAction = { arg view, url, description; [ "activated", url, description ].postln }; t.linkEnteredAction = { arg view, url, description; [ "entered", url, description ].postln }; t.linkExitedAction = { arg view, url, description; [ "exited", url, description ].postln }; // a simple link-action to follow links t.linkAction = { arg view, url; view.openURL( url )};
By default, the view does not have scrollbars. These can be enabled using the hasHorizontalScroller_
and hasVerticalScroller_
methods:
( var win; win = JSCWindow.new; t = JSCTextView( win, win.view.bounds.insetBy( 4, 4 )) .resize_( 5 ) .string_( UGen.allSubclasses.collect( _.name ).asCompileString ); win.front; ) // now display the vertical scrollbars t.hasVerticalScroller = true; // now display the horizontal scrollbars // ...note that since lineWrap is on, there is // ...nothing to scroll here... t.hasHorizontalScroller = true; // therefore, when we enable automatic hiding // ...of unused scrollbars, the horizontal bar // ...will disappear again t.autohidesScrollers = true;