//CommandBox.java /* CommandBox does triple duty: it is the Command Box: the area where the user enters commands and receives feedback, the Subroutine Editor, and the Batch Loader/Saver. (The alternate modes are indicated to the user by changing the labels at the top of the screen and on the button.) In Command Entry mode, the user may either type a new command and press enter, or they may use the arrow keys to select a previous command for re-execution. Some platforms seem to have trouble trapping the Enter key in the handleEvent() loop, so there is an 'Enter' button as well. In addition to typing commands into the Command Box or Subroutine Editor, the user may use the Turtle Control Panel Buttons, which will simulate commands via the CommandBox's outString() method. */ package logo.ui; import logo.lang.Interpreter; import logo.lang.LogoSub; import java.awt.TextArea; import java.awt.TextField; import java.awt.Event; import java.awt.Panel; import java.awt.BorderLayout; import java.awt.Button; import java.awt.Label; import java.awt.FontMetrics; import java.awt.Font; public class CommandBox extends Panel { TextArea ta; Interpreter i; Button Enter; Label label; String buffer; LogoSub currentSub; //holds the subroutine that is being edited public CommandBox(Interpreter interp) { currentSub=null; setLayout(new BorderLayout()); setInterpreter(interp); ta = new TextArea(); Enter = new Button(""); resetButton(); label = new Label("",Label.CENTER); label.setFont(new Font("TimesRoman",Font.BOLD,14)); resetLabel(); add("North",label); add("South",Enter); add("Center",ta); requestFocus(); } public void setInterpreter(Interpreter interp) { i=interp; } public void edit(LogoSub s) { currentSub=s; buffer=ta.getText(); //hold the CommandBox buffer until we're finished ta.setText(currentSub.getValue()); if ( currentSub.getName().equals(i.rLOGO_BATCH) ) { setLabel("rLogo Batch Input"); } else if ( currentSub.getName().equals(i.rLOGO_DUMP) ) { setLabel("rLogo Batch Dump"); ta.setEditable(false); } else setLabel("to "+currentSub.getName()); setButton("Finished"); } public void setButton(String s) { Enter.setLabel(s); } public void resetButton() { Enter.setLabel("Enter"); } public void setLabel(String l) { label.setText(l); } public void resetLabel() { label.setText("rLogo Command Box"); } public void wrapString(String s) { clearIncompleteCommand(); ta.appendText( wrap(s) ); gotoBottom(); } public void outString(String s) { clearIncompleteCommand(); ta.appendText( s+"\n" ); gotoBottom(); } public void replaceLastLine(String s) { //replaces the last line with a new string clearIncompleteCommand(); String text=ta.getText(); int start=text.lastIndexOf("\n",text.length()-2)+1; //finds the 2nd to last 'newline' if (start<0) start=0; ta.replaceText(s+"\n",start,text.length()); } public void clearIncompleteCommand() { //corrects a subtle quirk when a user begins to type //a command, but then decides to press a button on the //TurtleControlPanel before finishing. String text=ta.getText(); if ( !text.endsWith("\n") ) { int lastLine=text.lastIndexOf("\n")+1; ta.replaceText(text.substring(0,lastLine),0,text.length()); } } /* String thisLine() { return ta.getText(); }*/ public boolean handleEvent(Event e) { boolean result = false; if ( currentSub==null ) { if ( (e.id==Event.KEY_PRESS && e.key=='\n') || e.id==1001) { processNextCommand(); result = true; } } else { if ( e.id==1001) { //finished editing subroutine... if ( currentSub.getName().equals(i.rLOGO_BATCH) ) { i.load(ta.getText()); //process this program immediately... } else if ( currentSub.getName().equals(i.rLOGO_DUMP) ){ ta.setEditable(true); //turn editor back on } else { currentSub.setValue(ta.getText()); } currentSub=null; resetLabel(); resetButton(); ta.setText(buffer); gotoBottom(); result = true; } } //return result; if (result==true) return true; else return super.handleEvent(e); } void gotoBottom() { //positions cursor at the end of the CommandBox ta.select(ta.getText().length(),ta.getText().length()); } void processNextCommand() { i.resetMode(); int start=ta.getSelectionStart()-1; String text=ta.getText(); while (start>0 && text.charAt(start)!='\n') start--; if (start<0) start=0; if (text.charAt(start)=='\n') start++; String command = text.substring(start); if ( !command.startsWith(">") ) { //ignore lines starting with ">" (rLogo output) int stop=command.indexOf("\n"); if (stop>=0) command = command.substring(0,stop); else stop=0; command.trim(); if ( command.length()>0 ) { //if the user arrowed up to repeat a command, be sure to append it to the end: if ( !text.endsWith(command) ) ta.appendText(command+"\n"); //otherwise, just append the newline that was trapped: else ta.appendText("\n"); gotoBottom(); if ( command.trim().toLowerCase().equals("break") ) { i.stop(); } else i.queue(command); } } else gotoBottom(); } public String wrap(String rawText) { int maxLength; int maxSize = (int)(ta.size().width * .8); //it would be nice to be able to access the vertical scrollbar, //get its length, and subtract it here. Instead, I approximate. FontMetrics fm = getFontMetrics(ta.getFont()); String result = new String(); while (rawText.length()>0) { for (maxLength=1; maxLength "+rawText.substring(0,maxLength)+"\n" ); if (rawText.length()>maxLength) { rawText=rawText.substring(maxLength+1); } else { rawText=""; } maxLength=1; } } if ( maxLength>=rawText.length() ) { maxLength=rawText.length(); } else { while (maxLength>0 && rawText.charAt(maxLength)!=' ') { maxLength--; } maxLength++; } result=result.concat( "> "+rawText.substring(0,maxLength)+"\n" ); rawText=rawText.substring(maxLength); } return result; } }