Hi Scott, I ran into another issue. If you exercise SCTextView:open 'enthusiastically' graphics go belly-up. I ran into the problem in the nextsteppish file browser below (loosely based on Dan's help browser code). (The motivation behind this is to get a Swing based framework that will allow remote development for embedded or distant copies of SC. I also have a SwingDocument stub started that I will post when it is a little further along.) Arrow keys work on the list views that show directory contents, right and left arrows move down/up a level. You can also type letters to jump down in the list. If you drill down to a help directory (I went to BinaryOps) and hold the arrow key down, it will flash through help files for a while and then just die. At that point you have to reboot SC3 to get graphics to resume. Cheers, RJK var win, lists, listviews; var scrollView, compView, listSizerView; var textView, textSizerView; var screenBounds, bounds, textViewBounds; var makeView; var lViewWidth = 150; screenBounds = Window.screenBounds; bounds = Rect(128, 264, 1040, 564); bounds = bounds.center_(screenBounds.center); bounds = bounds.sect(screenBounds.insetBy(15)); win = Window("File browser", bounds).front; listSizerView = UserView(win, Rect(5, 0, lViewWidth * 2, 529)).resize_(4); scrollView = ScrollView.new(win, Rect(5, 0, lViewWidth * 2, 529)).hasBorder_(true).resize_(4); compView = CompositeView.new(scrollView, Rect(0, 0, lViewWidth * 2, scrollView.bounds.height - 25)); listSizerView.drawFunc = { compView.bounds = compView.bounds.height_(scrollView.bounds.height - 25) }; // textView displays a help file "inline" textViewBounds = Rect(scrollView.bounds.width, 0, /*620*/bounds.width-scrollView.bounds.width, /*554*/ bounds.height-35); textSizerView = UserView(win, textViewBounds).resize_(5); ~tv = textView = TextView(win, textViewBounds) .hasVerticalScroller_(true) .hasHorizontalScroller_(false) .autohidesScrollers_(false) .canFocus_(true); textSizerView.drawFunc_({ | view | var b = view.bounds; textView.bounds= Rect(b.left, b.top, b.width max: 500, b.height max: 100) }); // SCListView makeView = {| index, items | var view, oldvalue, docstr, ext, file; view = ListView( compView, Rect( 5 + (index * lViewWidth), 4, lViewWidth - 10, /* 504 */ scrollView.bounds.height - 25 )) .items_(items ? []) .value_(0) // Swing does not set value on creation .resize_(4) .action_({| view| var newView, newItems; var path; path = view.items[view.value].copy; (index).reverseDo { | i | path = listviews[i].items[ listviews[i].value] ++ path }; listviews[index+1..].do { | v | v.remove }; listviews = listviews[..index]; if (path.last == $/) { newItems = (path ++ "/*").pathMatch.sort.collect(_.asRelativePath(path) ); if (newItems.size > 0) { newView = makeView.value(index + 1, newItems); listviews = listviews[..index].add(newView); compView.bounds = compView.bounds.width_(max(425, listviews.size * lViewWidth) ); textView.string_(""); scrollView.visibleOrigin_(Point(listviews.last.bounds.left - lViewWidth, 0)); }; } { ext = path.splitext[1]; if ( ( ext == "htm" ) || ( ext == "html" ) ) { textView.open(path); } { file = File(path, "r"); if(file.isOpen){ docstr = ext.switch( "rtf", {file.readAllStringRTF}, "sc", {file.readAllString}, "scd", {file.readAllString}, "txt", {file.readAllString}, "ily", {file.readAllString}, "ly", {file.readAllString}, "doc", {file.readAllString}, "", {file.readAllString} ); file.close; textView.font = Font("Helvetica", 10); if(docstr.notNil) { textView.string = docstr } { textView.string = "" }; } } }; compView.refresh; }); view.keyDownAction_({ var search = ""; { | view, char, modifiers, unicode| if (unicode != 16rF703) { textView.string = "" }; if (char.isAlpha) { var index; search = search ++ char.toUpper; index = items.detectIndex({|item| item.asString.toUpper >= search }); if (index.notNil) { view.value = index}; view } { search = ""; case /*up arrow */ {unicode == 16rF700} { view.value = view.value - 1; if (view.item.last != $/) { view.doAction }; view } /*down arrow*/ {unicode == 16rF701} { view.value = view.value + 1; if (view.item.last != $/) { view.doAction }; view } /* left arrow*/ {unicode == 16rF702} { listviews.clipAt(index - 1).focus; if (listviews.size > 1) { listviews.pop.remove }; scrollView.visibleOrigin_(Point(listviews.last.bounds.left - lViewWidth, 0)); view } /*right arrow*/ {unicode == 16rF703 } { view.doAction; // drill down listviews.last.focus; scrollView.visibleOrigin_(Point(listviews.last.bounds.left - lViewWidth, 0)); view } {true} {nil} // bubble if it's an invalid key ; }; } }.value); view.mouseDownAction_({ |lv| if (lv.value == oldvalue) { lv.doAction }; oldvalue = lv.value; }); // if( view.respondsTo( \allowsDeselection ), { // view.allowsDeselection_( true ).value_( nil ); // }); view }; listviews = [ makeView.value(0, "/*".pathMatch.sort) ]; win.front |