use of com.codename1.rad.ui.UI in project CodenameOne by codenameone.
the class CSSEngine method createBorder.
/**
* Returns a border for a specific side of the component
*
* @param styleAttributes The style attributes element containing the border directives
* @param ui The component we want to set the border on
* @param location One of Component.TOP/BOTTOM/LEFT/RIGHT
* @return
*/
Border createBorder(CSSElement styleAttributes, Component ui, int location, int styles, int type) {
int borderStyle = styleAttributes.getAttrVal(BORDER_OUTLINE_PROPERTIES[type][STYLE] + location);
if ((borderStyle == -1) || (borderStyle == BORDER_STYLE_NONE)) {
return null;
}
int borderColor = styleAttributes.getAttrVal(BORDER_OUTLINE_PROPERTIES[type][COLOR] + location);
int borderWidth = styleAttributes.getAttrLengthVal(BORDER_OUTLINE_PROPERTIES[type][WIDTH] + location, ui, 0);
if (borderWidth == -1) {
// Default value
borderWidth = CSSElement.BORDER_DEFAULT_WIDTH;
}
if (type == OUTLINE) {
// all
location = -1;
}
if ((styles & STYLE_SELECTED) != 0) {
incPadding(ui.getSelectedStyle(), location, borderWidth);
}
if ((styles & STYLE_UNSELECTED) != 0) {
incPadding(ui.getUnselectedStyle(), location, borderWidth);
}
if ((styles & STYLE_PRESSED) != 0) {
incPadding(((HTMLLink) ui).getPressedStyle(), location, borderWidth);
}
Border border = null;
if ((borderColor == -1) && (borderStyle >= BORDER_STYLE_GROOVE)) {
borderColor = DEFAULT_3D_BORDER_COLOR;
}
switch(borderStyle) {
case BORDER_STYLE_SOLID:
if (borderColor == -1) {
border = Border.createLineBorder(borderWidth);
} else {
border = Border.createLineBorder(borderWidth, borderColor);
}
break;
case BORDER_STYLE_DOUBLE:
if (borderColor == -1) {
border = Border.createDoubleBorder(borderWidth);
} else {
border = Border.createDoubleBorder(borderWidth, borderColor);
}
break;
case BORDER_STYLE_GROOVE:
border = Border.createGrooveBorder(borderWidth, borderColor);
break;
case BORDER_STYLE_RIDGE:
border = Border.createRidgeBorder(borderWidth, borderColor);
break;
case BORDER_STYLE_INSET:
border = Border.createInsetBorder(borderWidth, borderColor);
break;
case BORDER_STYLE_OUTSET:
border = Border.createOutsetBorder(borderWidth, borderColor);
break;
case BORDER_STYLE_DOTTED:
if (borderColor == -1) {
border = Border.createDottedBorder(borderWidth);
} else {
border = Border.createDottedBorder(borderWidth, borderColor);
}
break;
case BORDER_STYLE_DASHED:
if (borderColor == -1) {
border = Border.createDashedBorder(borderWidth);
} else {
border = Border.createDashedBorder(borderWidth, borderColor);
}
break;
}
return border;
}
use of com.codename1.rad.ui.UI in project CodenameOne by codenameone.
the class CSSEngine method setWrapText.
/**
* Replaces an unwrapped text with a wrapped version, while copying the style of the original text.
*
* @param label The current label that contains the unwrapped text
* @param words A vector containing one word of the text (without white spaces) in each element
* @param element The text element
*/
private void setWrapText(Label label, Vector words, HTMLElement element, HTMLComponent htmlC) {
Style selectedStyle = label.getSelectedStyle();
Style unselectedStyle = label.getUnselectedStyle();
Vector ui = new Vector();
label.setText((String) words.elementAt(0) + ' ');
HTMLLink link = null;
if (label instanceof HTMLLink) {
link = (HTMLLink) label;
}
ui.addElement(label);
for (int i = 1; i < words.size(); i++) {
Label word = null;
if (link != null) {
word = new HTMLLink((String) words.elementAt(i) + ' ', link.link, htmlC, link, link.linkVisited);
} else {
word = new Label((String) words.elementAt(i) + ' ');
}
word.setSelectedStyle(selectedStyle);
word.setUnselectedStyle(unselectedStyle);
label.getParent().addComponent(word);
ui.addElement(word);
}
element.setAssociatedComponents(ui);
label.getParent().revalidate();
}
use of com.codename1.rad.ui.UI in project CodenameOne by codenameone.
the class CSSEngine method setWrapRecursive.
/**
* Sets this element and all children to have wrapped text.
* In cases where text is already wrapped no change will be made.
* This will work only in FIXED_WIDTH mode (Checked before called)
* Technically all this logic can be found in HTMLComponent.showText, but since we don't want to get into
* the context of this element (i.e. what was the indentation, alignment etc.), we use this algorithm.
*
* @param element The element to apply text wrapping on
* @param htmlC The HTMLComponent
*/
private void setWrapRecursive(HTMLElement element, HTMLComponent htmlC) {
if (element.isTextElement()) {
String text = element.getText();
final Vector ui = element.getUi();
if ((text != null) && (ui != null) && (ui.size() == 1)) {
// If it's already wrapped, no need to process
final Vector words = htmlC.getWords(text, Component.LEFT, false);
final Label label = (Label) ui.elementAt(0);
setWrapText(label, words, element, htmlC);
}
}
for (int i = 0; i < element.getNumChildren(); i++) {
setWrapRecursive((HTMLElement) element.getChildAt(i), htmlC);
}
}
use of com.codename1.rad.ui.UI in project CodenameOne by codenameone.
the class ResetableTextWatcher method showTextEditorAgain.
/**
* Shows the native text field again after it has been hidden in async edit mode.
*/
private void showTextEditorAgain() {
if (!mIsEditing || !isTextEditorHidden()) {
return;
}
textEditorHidden = false;
final TextArea ta = mEditText.mTextArea;
// changed since the native aread was hidden.
synchronized (this) {
inputBuffer = new ArrayList<TextChange>();
}
// We are probably not on the EDT. We need to be on the EDT to
// safely get text from the textarea for synchronization.
Display.getInstance().callSerially(new Runnable() {
public void run() {
// and the editing text area hasn't changed since we issued this call.
if (mIsEditing && mEditText != null && mEditText.mTextArea == ta) {
final String text = ta.getText();
final int cursorPos = ta.getCursorPosition();
// Now that we have our text from the CN1 text area, we need to be on the
// Android UI thread in order to set the text of the native text editor.
impl.getActivity().runOnUiThread(new Runnable() {
public void run() {
// and the editing text area hasn't changed since we issued this call.
if (mIsEditing && mEditText != null && mEditText.mTextArea == ta) {
// so that we don't find it in an inconsistent state.
synchronized (InPlaceEditView.this) {
// Let's record the cursor positions of the native
// text editor in case we need to use them after synchronizing
// with the CN1 textarea.
int start = cursorPos;
int end = cursorPos;
/*
if (!inputBuffer.isEmpty()) {
// If the input buffer isn't empty, then our start
// and end positions will be "wonky"
start = end = inputBuffer.get(0).atPos;
// If the first change was a delete, then the atPos
// will point to the beginning of the deleted section
// so we need to adjust the end point to be *after*
// the deleted section to begin.
if (inputBuffer.get(0).deleteLength > 0) {
end = start = end + inputBuffer.get(0).deleteLength;
}
}
*/
StringBuilder buf = new StringBuilder();
buf.append(text);
// Loop through any pending changes in the input buffer
// (I.e. key strokes that have occurred since we initiated
// this async callback hell!!)
List<TextChange> tinput = inputBuffer;
if (tinput != null) {
for (TextChange change : tinput) {
// end.
if (change.textToAppend != null) {
if (end >= 0 && end <= buf.length()) {
buf.insert(end, change.textToAppend);
end += change.textToAppend.length();
start = end;
} else {
buf.append(change.textToAppend);
end = buf.length();
start = end;
}
} else // The change is "deleted" text.
if (change.deleteLength > 0) {
if (end >= change.deleteLength && end <= buf.length()) {
buf.delete(end - change.deleteLength, end);
end -= change.deleteLength;
start = end;
} else if (end > 0 && end < change.deleteLength) {
buf.delete(0, end);
end = 0;
start = end;
}
}
}
}
// Important: Clear the input buffer so that the TextWatcher
// knows to stop filling it up. We only need the inputBuffer
// to keep input between the original showTextEditorAgain() call
// and here.
inputBuffer = null;
mEditText.setText(buf.toString());
if (start < 0 || start > mEditText.getText().length()) {
start = mEditText.getText().length();
}
if (end < 0 || end > mEditText.getText().length()) {
end = mEditText.getText().length();
}
// Update the caret in the edit text field so we can continue.
mEditText.setSelection(start, end);
}
}
}
});
}
}
});
reLayoutEdit(true);
repaintTextEditor(true);
}
use of com.codename1.rad.ui.UI in project CodenameOne by codenameone.
the class ResetableTextWatcher method startEditing.
/**
* Start editing the given text-area
* This method is executed on the UI thread, so UI manipulation is safe here.
* @param activity Current running activity
* @param textArea The TextAreaData instance that wraps the CN1 TextArea that our internal EditText needs to overlap. We use
* a TextAreaData so that the text area properties can be accessed off the EDT safely.
* @param codenameOneInputType One of the input type constants in com.codename1.ui.TextArea
* @param initialText The text that appears in the Codename One text are before the call to startEditing
* @param isEditedFieldSwitch if true, then special case for async edit mode - the native editing is already active, no need to show
* native field, just change the connected field
*/
private synchronized void startEditing(Activity activity, TextAreaData textArea, String initialText, int codenameOneInputType, final boolean isEditedFieldSwitch) {
int txty = lastTextAreaY = textArea.getAbsoluteY() + textArea.getScrollY();
int txtx = lastTextAreaX = textArea.getAbsoluteX() + textArea.getScrollX();
lastTextAreaWidth = textArea.getWidth();
lastTextAreaHeight = textArea.getHeight();
int paddingTop = 0;
int paddingLeft = textArea.paddingLeft;
int paddingRight = textArea.paddingRight;
int paddingBottom = textArea.paddingBottom;
// An ugly hack to smooth over an apparent race condition where
// the lightweight textarea is not repainted after the native text field
// becomes visible - resulting in the hint still appearing while typing.
// https://github.com/codenameone/CodenameOne/issues/2629
// We just blindly repaint the textfield every 50ms for half a second
// to make sure it gets a repaint properly.
final TextArea fTextArea = textArea.textArea;
new Thread(new Runnable() {
public void run() {
for (int i = 0; i < 10; i++) {
com.codename1.io.Util.sleep(50);
com.codename1.ui.CN.callSerially(new Runnable() {
public void run() {
fTextArea.repaint();
}
});
}
}
}).start();
if (textArea.isTextField) {
switch(textArea.getVerticalAlignment()) {
case Component.BOTTOM:
paddingTop = textArea.getHeight() - textArea.paddingBottom - textArea.fontHeight;
break;
case Component.CENTER:
paddingTop = textArea.getHeight() / 2 - textArea.fontHeight / 2;
break;
default:
paddingTop = textArea.paddingTop;
break;
}
} else {
paddingTop = textArea.paddingTop;
}
int id = activity.getResources().getIdentifier("cn1Style", "attr", activity.getApplicationInfo().packageName);
if (!isEditedFieldSwitch) {
mEditText = new EditView(activity, textArea.textArea, this, id);
defaultInputType = mEditText.getInputType();
defaultIMEOptions = mEditText.getImeOptions();
} else {
mEditText.switchToTextArea(textArea.textArea);
}
if (textArea.getClientProperty("blockCopyPaste") != null || Display.getInstance().getProperty("blockCopyPaste", "false").equals("true")) {
// The code below is taken from this stackoverflow answer: http://stackoverflow.com/a/22756538/756809
if (android.os.Build.VERSION.SDK_INT < 11) {
mEditText.setOnCreateContextMenuListener(new OnCreateContextMenuListener() {
@Override
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {
menu.clear();
}
});
} else {
mEditText.setCustomSelectionActionModeCallback(new ActionMode.Callback() {
public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
return false;
}
public void onDestroyActionMode(ActionMode mode) {
}
public boolean onCreateActionMode(ActionMode mode, Menu menu) {
return false;
}
public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
return false;
}
});
}
} else if (isEditedFieldSwitch) {
// reset copy-paste protection
if (android.os.Build.VERSION.SDK_INT < 11) {
mEditText.setOnCreateContextMenuListener(null);
} else {
mEditText.setCustomSelectionActionModeCallback(null);
}
}
if (!isEditedFieldSwitch) {
mEditText.addTextChangedListener(mEditText.mTextWatcher);
}
mEditText.setBackgroundDrawable(null);
mEditText.setFocusableInTouchMode(true);
mEditLayoutParams = new FrameLayout.LayoutParams(0, 0);
// Set the appropriate gravity so that the left and top margins will be
// taken into account
mEditLayoutParams.gravity = Gravity.LEFT | Gravity.TOP;
mEditLayoutParams.setMargins(txtx, txty, 0, 0);
mEditLayoutParams.width = textArea.getWidth();
mEditLayoutParams.height = textArea.getHeight();
mEditText.setLayoutParams(mEditLayoutParams);
if (textArea.isRTL()) {
mEditText.setGravity(Gravity.RIGHT | Gravity.TOP);
} else {
mEditText.setGravity(Gravity.LEFT | Gravity.TOP);
}
mEditText.setPadding(paddingLeft, paddingTop, paddingRight, paddingBottom);
Component nextDown = textArea.nextDown;
boolean imeOptionTaken = true;
int ime = EditorInfo.IME_FLAG_NO_EXTRACT_UI;
if (textArea.isSingleLineTextArea() || textArea.getDoneListener() != null) {
if (textArea.getClientProperty("searchField") != null) {
mEditText.setImeOptions(ime | EditorInfo.IME_ACTION_SEARCH);
} else {
if (textArea.getClientProperty("sendButton") != null) {
mEditText.setImeOptions(ime | EditorInfo.IME_ACTION_SEND);
} else {
if (textArea.getClientProperty("goButton") != null) {
mEditText.setImeOptions(ime | EditorInfo.IME_ACTION_GO);
} else {
if (textArea.getDoneListener() != null) {
mEditText.setImeOptions(ime | EditorInfo.IME_ACTION_DONE);
} else if (nextDown != null) {
mEditText.setImeOptions(ime | EditorInfo.IME_ACTION_NEXT);
} else {
mEditText.setImeOptions(ime | EditorInfo.IME_ACTION_DONE);
imeOptionTaken = false;
}
}
}
}
}
mEditText.setSingleLine(textArea.isSingleLineTextArea());
mEditText.setAdapter((ArrayAdapter<String>) null);
mEditText.setText(initialText);
if (!textArea.isSingleLineTextArea() && textArea.textArea.isGrowByContent() && textArea.textArea.getGrowLimit() > -1) {
defaultMaxLines = mEditText.getMaxLines();
mEditText.setMaxLines(textArea.textArea.getGrowLimit());
}
if (textArea.nativeHintBool && textArea.getHint() != null) {
mEditText.setHint(textArea.getHint());
}
if (!isEditedFieldSwitch) {
addView(mEditText, mEditLayoutParams);
}
invalidate();
setVisibility(VISIBLE);
bringToFront();
mEditText.requestFocus();
Object nativeFont = textArea.nativeFont;
if (nativeFont == null) {
nativeFont = impl.getDefaultFont();
}
Paint p = (Paint) ((AndroidImplementation.NativeFont) nativeFont).font;
mEditText.setTypeface(p.getTypeface());
mEditText.setTextScaleX(p.getTextScaleX());
mEditText.setTextSize(TypedValue.COMPLEX_UNIT_PX, p.getTextSize());
int fgColor = textArea.fgColor;
mEditText.setTextColor(Color.rgb(fgColor >> 16, (fgColor & 0x00ff00) >> 8, (fgColor & 0x0000ff)));
boolean password = false;
if ((codenameOneInputType & TextArea.PASSWORD) == TextArea.PASSWORD) {
codenameOneInputType = codenameOneInputType ^ TextArea.PASSWORD;
password = true;
}
if (textArea.isSingleLineTextArea()) {
mEditText.setInputType(getAndroidInputType(codenameOneInputType));
// if not ime was explicity requested and this is a single line textfield of type ANY add the emoji keyboard.
if (!imeOptionTaken && codenameOneInputType == TextArea.ANY) {
mEditText.setInputType(getAndroidInputType(codenameOneInputType) | InputType.TYPE_TEXT_VARIATION_SHORT_MESSAGE);
}
if (Display.getInstance().getProperty("andAddComma", "false").equals("true") && (codenameOneInputType & TextArea.DECIMAL) == TextArea.DECIMAL) {
defaultKeyListener = mEditText.getKeyListener();
mEditText.setKeyListener(DigitsKeyListener.getInstance("0123456789.,"));
}
} else {
if (textArea.getDoneListener() != null) {
mEditText.setHorizontallyScrolling(false);
mEditText.setMaxLines(Integer.MAX_VALUE);
mEditText.setInputType(InputType.TYPE_TEXT_FLAG_MULTI_LINE);
mEditText.setMaxWidth(textArea.getWidth());
mEditText.setMaxHeight(textArea.getHeight());
mEditText.setHorizontalScrollBarEnabled(false);
mEditText.getLayoutParams().width = textArea.getWidth();
mEditText.getLayoutParams().height = textArea.getHeight();
} else {
mEditText.setInputType(getAndroidInputType(codenameOneInputType, true));
}
}
if (password) {
int type = mInputTypeMap.get(codenameOneInputType, InputType.TYPE_CLASS_TEXT);
if ((type & InputType.TYPE_TEXT_FLAG_CAP_SENTENCES) == InputType.TYPE_TEXT_FLAG_CAP_SENTENCES) {
type = type ^ InputType.TYPE_TEXT_FLAG_CAP_SENTENCES;
}
// turn off suggestions for passwords
mEditText.setInputType(type | InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD | InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS);
mEditText.setTransformationMethod(new MyPasswordTransformationMethod());
}
int maxLength = textArea.maxSize;
InputFilter[] FilterArray = new InputFilter[1];
FilterArray[0] = new InputFilter.LengthFilter(maxLength);
mEditText.setFilters(FilterArray);
mEditText.setSelection(mEditText.getText().length());
showVirtualKeyboard(true);
if (Boolean.FALSE.equals(textArea.getClientProperty("android.cursorVisible"))) {
// This provides an imperfect workaround for this issue:
// https://github.com/codenameone/CodenameOne/issues/2317
// Blinking cursor causes text to disappear on some versions of android
// Can't seem to find how to detect whether device is affected, so
// just providing a client property to disable the blinking cursor
// on a particular text field.
mEditText.setCursorVisible(false);
}
/*
// Leaving this hack here for posterity. It seems that this manually
// blinking cursor causes the paste menu to disappear
// https://github.com/codenameone/CodenameOne/issues/2147
// Removing the hack below, fixes this issue. And in the test device
// I'm using the blinking of text doesn't seem to occur, so perhaps
// it was fixed via other means. Test device:
// Name: Samsung Galaxy S3 (T-Mobile)
// OS: 4.3
// Manufacturer: Samsung
// Model: 4.3
// Chipset: armeabi-v7a 1512MHz
// Memory: 16000000000
// Heap: 256000000
// Display: 720 x 1280
//
// UPDATE Feb. 13, 2018:
// This issue seems to be still present in some devices, but it isn't clear even
// how to detect it.
// Issue reported and reproduced here https://github.com/codenameone/CodenameOne/issues/2317
// Issue has been observed in a Virtual Box installation with 5.1.1, but
// cannot be reproduced in a Nexus 5 running 5.1.1.
//
if (Build.VERSION.SDK_INT < 21) {
// HACK!!! On Android 4.4, it seems that the natural blinking cursor
// causes text to disappear when it blinks. Manually blinking the
// cursor seems to work around this issue, so that's what we do here.
// This issue is described here: http://stackoverflow.com/questions/41305052/textfields-content-disappears-during-typing?noredirect=1#comment69977316_41305052
mEditText.setCursorVisible(false);
final boolean[] cursorVisible = new boolean[]{false};
if (cursorTimer != null) {
cursorTimer.cancel();
}
cursorTimer = new Timer();
cursorTimerTask = new TimerTask() {
public void run() {
AndroidNativeUtil.getActivity().runOnUiThread(new Runnable() {
public void run() {
EditView v = mEditText;
if (v != null) {
cursorVisible[0] = !cursorVisible[0];
v.setCursorVisible(cursorVisible[0]);
}
}
});
}
};
cursorTimer.schedule(cursorTimerTask, 100, 500);
}
*/
}
Aggregations