/*********************************************************************************
* TotalCross Software Development Kit *
* Copyright (C) 2000-2012 SuperWaba Ltda. *
* All Rights Reserved *
* *
* This library and virtual machine is distributed in the hope that it will *
* be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. *
* *
* This file is covered by the GNU LESSER GENERAL PUBLIC LICENSE VERSION 3.0 *
* A copy of this license is located in file license.txt at the root of this *
* SDK or can be downloaded here: *
* http://www.gnu.org/licenses/lgpl-3.0.txt *
* *
*********************************************************************************/
package totalcross.ui.dialog;
import totalcross.sys.*;
import totalcross.ui.*;
import totalcross.ui.event.*;
import totalcross.ui.font.*;
import totalcross.ui.gfx.*;
/** This class pops up a Window with a Label, an Edit and some buttons. Good
to input some text from the user.
Here is an example (taken from examples/apps/GuiBuilder):
<pre>
// on some event...
if (renameDialog == null)
renameDialog = new InputBox("Project Rename","Please enter the new name which will be used for the project:","");
renameDialog.setValue(projectName);
renameDialog.popup();
// when window closes...
if (renameDialog.getPressedButtonIndex() == 0) // ok?
{
projectName = renameDialog.getValue();
}
</pre>
*/
public class InputBox extends Window
{
private Label msg;
private PushButtonGroup btns;
private Edit ed;
private int selected = -1;
private String originalText;
private String[] buttonCaptions;
private int labelAlign = CENTER;
private int gap, insideGap;
/** Set to true to automatically open the keyboard once the InputBox is open.
* @since TotalCross 1.53
*/
public static boolean openKeyboardOnPopup;
/**
* Set at the object creation. if true, all the buttons will have the same width, based on the width of the largest
* one.<br>
* Default value is false.
*
* @since TotalCross 1.27
*/
private boolean allSameWidth;
/** Defines the y position on screen where this window opens. Can be changed to TOP or BOTTOM. Defaults to CENTER.
* @see #CENTER
* @see #TOP
* @see #BOTTOM
*/
public int yPosition = CENTER; // guich@tc110_7
/** If you set the buttonCaptions array in the construction, you can also set this
* public field to an int array of the keys that maps to each of the buttons.
* For example, if you set the buttons to {"Ok","Cancel"}, you can map the enter key
* for the Ok button and the escape key for the Cancel button by assigning:
* <pre>
* buttonKeys = new int[]{SpecialKeys.ENTER,SpecialKeys.ESCAPE};
* </pre>
* Note that if you use the default Ok/Cancel buttons, this mapping is already done.
* @since TotalCross 1.27
*/
public int[] buttonKeys; // guich@tc126_40
/** Creates a new InputBox with the given window Title,
* the given label Text, the given Default value for the Edit,
* and two buttons "Ok" and "Cancel".
* The text used in a Label can be multi-line. If the text is too big, it will be splitted.
*/
public InputBox(String title, String text, String defaultValue)
{
this(title, text, defaultValue, new String[]{"Ok","Cancel"},false,4,6);
buttonKeys = new int[]{SpecialKeys.ENTER,SpecialKeys.ESCAPE};
}
/** Creates a new InputBox with the given window Title,
* the given label Text, the given Default value for the Edit
* and with the given buttons.
* The text used in a Label can be multi-line. If the text is too big, it will be splitted.
*/
public InputBox(String title, String text, String defaultValue, String[] buttonCaptions)
{
this(title,text,defaultValue,buttonCaptions,false,4,6);
}
/** Creates a new InputBox with the given window Title,
* the given label Text, the given Default value for the Edit
* and with the given buttons.
* The text used in a Label can be multi-line. If the text is too big, it will be splitted.
*/
public InputBox(String title, String text, String defaultValue, String[] buttonCaptions, boolean allSameWidth, int gap, int insideGap)
{
super(title,ROUND_BORDER);
this.buttonCaptions = buttonCaptions;
this.gap = gap;
this.insideGap = insideGap;
this.allSameWidth = allSameWidth;
fadeOtherWindows = Settings.fadeOtherWindows;
transitionEffect = Settings.enableWindowTransitionEffects ? TRANSITION_OPEN : TRANSITION_NONE;
uiAdjustmentsBasedOnFontHeightIsSupported = false;
this.originalText = text;
ed = new Edit("@@@@@@@@@@");
if (defaultValue != null) ed.setText(defaultValue);
}
protected void onPopup()
{
removeAll();
String text = originalText;
if (text.indexOf('\n') < 0 && fm.stringWidth(text) > Settings.screenWidth-6) // guich@tc100: automatically split the text if its too big to fit screen
text = Convert.insertLineBreak(Settings.screenWidth-6, fm, text.replace('\n',' '));
msg = new Label(text,labelAlign);
msg.setFont(font);
ed.setFont(font);
btns = new PushButtonGroup(buttonCaptions,false,-1,gap,insideGap,1,allSameWidth || uiAndroid,PushButtonGroup.BUTTON);
btns.setFont(font);
int wb = btns.getPreferredWidth();
if (wb > Settings.screenWidth-10) // guich@tc123_38: buttons too large? place them in a single column
{
btns = new PushButtonGroup(buttonCaptions,false,-1,gap,insideGap,buttonCaptions.length,true,PushButtonGroup.BUTTON);
btns.setFont(font);
wb = btns.getPreferredWidth();
}
int androidGap = uiAndroid ? fmH/3 : 0;
if (androidGap > 0 && (androidGap&1) == 1) androidGap++;
int hb = btns.getPreferredHeight() + androidGap;
int wm = Math.min(msg.getPreferredWidth()+(uiAndroid?fmH:1),Settings.screenWidth-6);
int hm = msg.getPreferredHeight();
if (uiAndroid)
hb += fmH/2;
int we = ed.getPreferredWidth();
int he = ed.getPreferredHeight();
FontMetrics fm2 = titleFont.fm; // guich@220_28
int captionH = fm2.height+10 + titleGap;
int h = captionH + hb + hm + he;
int w = Math.max(Math.max(Math.max(wb,wm),we),fm2.stringWidth(title!=null?title:""))+6; // guich@200b4_29
w = Math.min(w,Settings.screenWidth); // guich@200b4_28: dont let the window be greater than the screen size
setRect(CENTER,yPosition,w,h);
add(msg);
add(btns);
add(ed);
msg.setRect(4,TOP,wm,hm);
ed.setRect(LEFT+4,AFTER+2,FILL-4,he);
if (uiAndroid)
btns.setRect(buttonCaptions.length > 1 ? LEFT+3 : CENTER,AFTER+3,buttonCaptions.length > 1 ? FILL-3 : Math.max(w/3,wb),FILL-3);
else
btns.setRect(CENTER,AFTER+2,wb,hb);
setBackForeColors(UIColors.inputboxBack, UIColors.inputboxFore);
msg.setBackForeColors(backColor, foreColor); // guich@tc115_9: moved to here
if (btns != null) btns.setBackForeColors(UIColors.inputboxAction,Color.getBetterContrast(UIColors.inputboxAction, foreColor, backColor)); // guich@tc123_53
}
/** Sets the alignment for the text. Must be CENTER (default), LEFT or RIGHT */
public void setTextAlignment(int align)
{
labelAlign = align;
}
public void reposition()
{
onPopup();
}
protected void postPopup()
{
ed.requestFocus();
if (openKeyboardOnPopup)
ed.popupKCC();
if (Settings.keyboardFocusTraversable) // guich@570_39: use this instead of pen less
isHighlighting = false; // allow a direct click to dismiss this dialog
}
protected void postUnpop()
{
if (Settings.keyboardFocusTraversable) // guich@573_1: put back the highlighting state
isHighlighting = true;
if (selected != -1)
postPressedEvent(); // guich@580_27
}
/** handle scroll buttons and normal buttons */
public void onEvent(Event e)
{
switch (e.type)
{
case KeyEvent.KEY_PRESS:
case KeyEvent.SPECIAL_KEY_PRESS:
if (buttonKeys != null)
{
int k = ((KeyEvent)e).key;
for (int i = buttonKeys.length; --i >= 0;)
if (buttonKeys[i] == k)
{
btns.setSelectedIndex(i);
close();
break;
}
}
break;
case ControlEvent.PRESSED:
if (e.target == btns && btns.getSelectedIndex() != -1)
close();
break;
}
}
private void close()
{
selected = btns.getSelectedIndex();
btns.requestFocus(); // remove focus from the edit
btns.setSelectedIndex(-1);
unpop();
}
/** Returns the pressed button index, starting from 0 */
public int getPressedButtonIndex()
{
return selected;
}
/** Returns the value entered */
public String getValue()
{
return ed.getText();
}
/** Sets the default value on the Edit field */
public void setValue(String value)
{
ed.setText(value);
}
/** Returns the Edit so you can set its properties. */
public Edit getEdit() // guich@310_23
{
return ed;
}
/** Sets the Edit to the given one. */
public void setEdit(Edit ed)
{
this.ed = ed;
}
}