/*******************************************************************************
* Copyright (c) 2007, 2008 Gregory Jordan
*
* This file is part of PhyloWidget.
*
* PhyloWidget is free software: you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation, either version 2 of the License, or (at your option) any later
* version.
*
* PhyloWidget 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. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* PhyloWidget. If not, see <http://www.gnu.org/licenses/>.
*/
package org.andrewberman.ui;
import java.awt.AlphaComposite;
import java.awt.BasicStroke;
import java.awt.Composite;
import java.awt.Cursor;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.RenderingHints;
import java.awt.event.FocusEvent;
import java.awt.event.KeyEvent;
import java.awt.event.MouseEvent;
import java.awt.geom.Rectangle2D;
import org.andrewberman.ui.ifaces.Malleable;
import org.andrewberman.ui.menu.MenuStyle;
import processing.core.PApplet;
import processing.core.PFont;
import processing.core.PGraphicsJava2D;
/**
* The <code>TextField</code> class is a Processing-based implementation of a
* simple one-line text field.
* <p>
* The x- and y- coordinates of this text field represent the upper-left hand
* corner of the bounding box; if you wish to position the object using some
* other reference point, use one of the convenience methods with the name
* <code>layoutByXXXX</code>.
* <p>
* As with most of the other UI objects in this package, the
* <code>TextField</code> relies heavily on Java2D calls for all of its
* drawing. As such, it switches drawing strategies depending on the type of
* <code>PGraphics</code> object being used by the current
* <code>PApplet</code>:
* <ul>
* <li> If the canvas is a <code>PGraphicsJava2D</code> instance, then:
* <ul>
* <li>Draw directly onto the canvas' internal Graphics2D object.</li>
* </ul>
* </li>
* <li> If the canvas is anything else (P3D or OpenGL), then:
* <ul>
* <li>Draw onto an off-screen PGraphicsJava2D buffer, and use the
* <code>image()</code> function to copy the off-screen buff onto the canvas.</li>
* </ul>
* </li>
* </ul>
* <p>
* If you want your TextField to maintain all the current matrix transformations
* associated with the "canvas" <code>PGraphics</code> object, then set the
* <code>useCameraCoordinates</code> value to <code>true</code>. Otherwise,
* the TextField will be positioned and drawn in screen coordinates (i.e. the
* top-left corner equals [0,0]).
*
* @author Greg
*/
public class TextField extends AbstractUIObject implements Malleable
{
static final int LEFT = -1;
static final int RIGHT = 1;
static final int SELECT = 0;
static final int MOVE = 1;
static final int CARET_JUMP = 1; // Default the CARET_JUMP to 5
// characters.
static final int DRAG_BORDER_FACTOR = 10;
static final int MOUSE_DRAG_DELAY = 1;
static final float TEXT_BORDER_MULT = .1f;
static final int metaMask = UIUtils.getMetaMask();
static final int OFFSET = 10;
PApplet p;
UIContext c;
PGraphicsJava2D pg;
TextFieldStyle style;
PFont pFont;
Font font;
float fontSize;
Blinker blinker;
StringClipboard clip;
Rectangle2D.Float clipRect, buffRect;
RenderingHints oldRH;
float offsetX, offsetY, ascent, descent;
float x, y, width, height, pad;
float mouseDragPos;
int mouseDragCounter;
int caret, anchorPos, selAnchor;
int viewLo, viewHi, selLo, selHi;
boolean anchorRight;
boolean mouseDragging, shiftPressed;
protected boolean hidden;
public StringBuffer text = new StringBuffer();
/**
* If set to true, then this textfield will draw itself in "camera"
* coordinates, i.e. it won't reset the camera before it draws itself.
*/
public boolean useCameraCoordinates = true;
/**
* If set to true, then this text field will always have its text anchored
* to the left. If you're constantly resizing the text field to fit the text
* and don't want it looking funky, set this to true.
*/
public boolean alwaysAnchorLeft = false;
public TextField(PApplet p)
{
c = UIPlatform.getInstance().getAppContext(p);
StringClipboard.lazyLoad();
Blinker.lazyLoad();
this.p = p;
style = new TextFieldStyle();
style.set("font",c.getPFont());
style.set("f.fontSize", 12);
pFont = style.getFont("font");
font = pFont.getFont();
blinker = Blinker.instance;
clipRect = new Rectangle2D.Float(0, 0, 0, 0);
buffRect = new Rectangle2D.Float(0, 0, 0, 0);
clip = StringClipboard.instance;
width = 50;
x = 0;
y = 0;
if (UIUtils.isJava2D(p))
{
/*
* If the canvas is Java2D, we can draw directly to it.
*/
pg = (PGraphicsJava2D) p.g;
layout();
} else
{
// We need to create our own graphics here.
pg = createBuffer(OFFSET, OFFSET);
layout();
}
c.event().add(this);
}
PGraphicsJava2D createBuffer(int w, int h)
{
PGraphicsJava2D asdf = (PGraphicsJava2D) p.createGraphics(w, h, PApplet.JAVA2D);
return asdf;
}
protected void reset()
{
anchorRight = false;
selLo = selHi = 0;
anchorPos = 0;
caret = 0;
mouseDragging = false;
shiftPressed = false;
}
protected void layout()
{
/*
* Size me up.
*/
ascent = UIUtils.getTextAscent(pg, pFont, fontSize, true);
descent = UIUtils.getTextDescent(pg, pFont, fontSize, true);
float textHeight = ascent + descent;
pad = textHeight * TEXT_BORDER_MULT;
height = textHeight;
offsetY = ascent;
if (!UIUtils.isJava2D(p))
{
float fullHeight = height + pad * 2 + OFFSET * 2;
float fullWidth = width + pad * 2 + OFFSET * 2;
if (pg.width < fullWidth || pg.height < fullHeight)
pg = createBuffer((int) fullWidth, (int) fullHeight);
hint();
}
}
public void draw()
{
if (hidden)
return;
calculateViewport();
// hint();
p.pushMatrix();
resetMatrix();
Composite origComp = pg.g2.getComposite();
pg.g2.setComposite(AlphaComposite.getInstance(
AlphaComposite.SRC_OVER, alpha));
if (!UIUtils.isJava2D(p))
{
pg.beginDraw();
pg.background(255, 0);
pg.translate(-x, -y);
pg.translate(OFFSET, OFFSET);
doTheDrawing();
pg.setModified(true);
// pg.modified = true;
pg.endDraw();
drawToCanvas();
} else
{
// resetMatrix();
synchronized (text)
{
doTheDrawing();
}
}
p.popMatrix();
pg.g2.setComposite(origComp);
}
public void hide()
{
hidden = true;
UIUtils.releaseCursor(this, p);
}
public void show()
{
hidden = false;
}
public float alpha = 1f;
protected void drawToCanvas()
{
int w = (int) (width + OFFSET * 2);
int h = (int) (height + OFFSET * 2);
// canvas.pushMatrix();
// resetMatrix();
p.image(pg, (int) (x - OFFSET), (int) (y - OFFSET), w, h, 0, 0, w, h);
// canvas.popMatrix();
}
protected void resetMatrix()
{
if (useCameraCoordinates)
return;
if (UIUtils.isJava2D(p))
p.resetMatrix();
else
{
p.camera();
// canvas.translate(-canvas.width/2,-canvas.height/2);
}
}
public void dispose()
{
if (c != null && c.event() != null)
{
c.event().remove(this);
}
blinker.stop();
blinker = null;
}
protected void doTheDrawing()
{
Color bgFill = style.getC("c.backgroundFill");
Color stroke = style.getC("c.foreground");
/*
* Draw the padded outer region of the textarea.
*/
clipRect.setRect(x, y, width + 2 * pad, height + 2 * pad);
pg.g2.setPaint(Color.white);
pg.g2.fill(clipRect);
pg.g2.setPaint(stroke);
pg.g2.setStroke(new BasicStroke(style.getF("f.strokeWeight")));
pg.g2.draw(clipRect);
/*
* Draw the actual text.
*/
clipRect.setRect(x + pad, y + pad, width, height);
pg.g2.setClip(clipRect);
pg.g2.setFont(pFont.getFont().deriveFont(fontSize));
pg.g2.setPaint(stroke);
// synchronized (this)
// {
pg.g2.drawString(substring(viewLo, viewHi), x + pad + offsetX, y + pad + offsetY);
// }
/*
* Draw the selection box.
*/
if (selHi - selLo > 0)
{
int lo = Math.max(viewLo, selLo);
int hi = Math.min(viewHi, selHi);
float loX = getPosForIndex(lo);
float selWidth = getWidth(lo, hi);
clipRect.setRect(x + loX + pad, y + pad, selWidth, height);
pg.g2.setPaint(style.getC("c.highlight"));
pg.g2.fill(clipRect);
pg.g2.setClip(clipRect);
pg.g2.setPaint(stroke.inverse());
// synchronized (this)
// {
pg.g2.drawString(substring(lo, hi), x + pad + loX, y + pad + offsetY);
// }
}
/*
* Draw the caret.
*/
if (blinker.isOn && c.focus().isFocused(this) && selHi - selLo == 0)
{
// System.out.println("Heyoo");
pg.g2.setStroke(new BasicStroke(1));
pg.g2.setPaint(stroke);
int caretX = (int) (x + pad + getPosForIndex(caret));
if (caret == text.length() && caret != 0)
caretX--;
pg.g2.drawLine(caretX, (int) (y + pad + height / 10), caretX, (int) (y + pad + height - height / 10));
}
pg.g2.setClip(null);
/*
* Handle the edge-of-box mouse dragging gesture.
*/
handleDragScroll();
}
private synchronized String substring(int lo, int hi)
{
if (hi > text.length())
hi = text.length();
if (lo < 0)
lo = 0;
if (hi - lo == 0)
return "";
return text.substring(lo,hi);
}
protected void handleDragScroll()
{
if (!mouseDragging)
return;
mouseDragCounter--;
if (mouseDragCounter <= 0)
{
mouseDragCounter = MOUSE_DRAG_DELAY;
if (mouseDragPos < x + (width / DRAG_BORDER_FACTOR / 2.0))
{
this.selectChar(-1);
mouseDragCounter += MOUSE_DRAG_DELAY;
}
if (mouseDragPos > x + width - (width / DRAG_BORDER_FACTOR / 2.0))
{
this.selectChar(1);
mouseDragCounter += MOUSE_DRAG_DELAY;
}
}
}
protected void hint()
{
oldRH = pg.g2.getRenderingHints();
pg.g2.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON);
pg.g2.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_OFF);
pg.g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_OFF);
}
protected void unhint()
{
pg.g2.setRenderingHints(oldRH);
}
protected void calculateViewport()
{
if (anchorRight)
{
viewHi = anchorPos;
int i = viewHi;
float textWidth = 0;
while (textWidth <= width && i > 0)
{
textWidth = getWidth(i - 1, viewHi);
i--;
}
viewLo = i;
offsetX = width - textWidth;
} else
{
viewLo = anchorPos;
int i = viewLo;
float textWidth = 0;
while (textWidth <= width && i < text.length())
{
textWidth = getWidth(viewLo, i + 1);
i++;
}
viewHi = i;
offsetX = 0;
}
}
float lastWidth = 0;
protected float getWidth(int lo, int hi)
{
if (lo > hi) // Switch lo and hi if they're reversed.
{
lo = Math.min(lo, hi);
hi = Math.max(lo, hi);
}
synchronized (text)
{
try
{
FontMetrics fm = UIUtils.getMetrics(pg, pFont.getFont(), fontSize);
float f = (float) fm.getStringBounds(text.substring(lo, hi), pg.g2).getWidth();
// System.out.println(Math.round(f)+" "+text.substring(lo,hi));
lastWidth = f;
return f;
} catch (Exception e)
{
return lastWidth;
}
}
}
protected float getPosForIndex(int index)
{
return offsetX + getWidth(viewLo, index);
}
public float getX()
{
return x;
}
public float getY()
{
return y;
}
public void setPosition(float x, float y)
{
setPositionByCorner(x, y);
}
public void setPositionByCorner(float x, float y)
{
this.x = x;
this.y = y;
}
public void setPositionByBaseline(float x, float y)
{
this.x = x - pad;
this.y = y - ascent - pad;
}
public void setTextSize(float textSize)
{
this.fontSize = textSize;
layout();
}
public void setWidth(float width)
{
this.width = width;
layout();
}
protected void selectAll()
{
selAnchor = 0;
selectChar(text.length());
}
protected void selectWord(int n)
{
nextWord(SELECT, n);
}
protected void selectToEnd(int dir)
{
if (dir == LEFT)
selectChar(0 - caret);
else if (dir == RIGHT)
selectChar(text.length() - caret);
}
protected void moveToEnd(int dir)
{
if (dir == LEFT)
moveChar(0 - caret);
else if (dir == RIGHT)
moveChar(text.length() - caret);
}
protected void moveWord(int n)
{
nextWord(MOVE, n);
}
protected void nextWord(int type, int n)
{
nextWord(type, n, true);
}
protected void nextWord(int type, int dir, boolean skipSpace)
{
int pad = 0;
if (skipSpace)
pad = 1;
String s = "";
if (dir == RIGHT)
{
s = text.substring(caret, text.length());
String[] words = s.split("\\w\\W", 2);
String firstWord = words[0];
if (type == SELECT)
selectChar(firstWord.length() + pad);
else
moveChar(firstWord.length() + pad);
} else if (dir == LEFT)
{
s = text.reverse().substring(text.length() - caret, text.length());
text.reverse(); // Reverse the stringbuffer back to normal!
String[] words = s.split("\\W\\w", 2);
String firstWord = words[0];
if (type == SELECT)
selectChar(-1 * (firstWord.length() + 1));
else
moveChar(-1 * (firstWord.length() + 1));
}
}
// Lowest-level method for selection moving.
protected void selectChar(int dist)
{
selLo = Math.min(caret + dist, selAnchor);
selHi = Math.max(caret + dist, selAnchor);
if (selLo < 0)
selLo = 0;
if (selHi > text.length())
selHi = text.length();
// System.out.println("Lo: "+selLo+" Hi:"+selHi);
moveCaretTo(caret + dist);
}
// Lowest-level method for caret moving.
protected void moveChar(int dist)
{
if (caret + dist > text.length())
dist = text.length() - caret;
if (caret + dist < 0)
dist = 0 - caret;
moveCaretTo(caret + dist);
clearSelection();
}
protected void moveCaretTo(int index)
{
caret = index;
if (caret > text.length())
caret = text.length();
else if (caret < 0)
caret = 0;
if (getWidth(0, text.length()) <= width)
{
anchorRight = false;
anchorPos = 0;
} else if (viewLo + 1 > caret)
{
anchorPos = caret - CARET_JUMP;
anchorRight = false;
} else if (viewHi - 1 < caret)
{
anchorPos = caret + CARET_JUMP;
anchorRight = true;
}
/*
* A quick hack to allow the alwaysAnchorLeft override to work.
*/
if (alwaysAnchorLeft)
{
anchorRight = false;
anchorPos = 0;
}
if (anchorPos > text.length())
anchorPos = text.length();
else if (anchorPos < 0)
anchorPos = 0;
blinker.reset();
fireEvent(UIEvent.TEXT_CARET);
}
protected void insertCharAt(char c, int pos)
{
insert(String.valueOf(c), pos);
fireEvent(UIEvent.TEXT_VALUE);
}
protected void insert(String s, int pos)
{
text.insert(pos, s);
moveChar(s.length());
// textChanged();
fireEvent(UIEvent.TEXT_VALUE);
}
protected void backspaceAt(int pos)
{
// Remove the char that exists before index pos.
if (pos <= 0)
return;
// text.deleteCharAt(pos - 1);
deleteAt(pos - 1);
moveCaretTo(pos - 1);
fireEvent(UIEvent.TEXT_VALUE);
}
protected void deleteAt(int pos)
{
// Remove the char that exists at index pos.
if (pos < 0 || pos >= text.length())
return;
text.deleteCharAt(pos);
moveChar(0);
fireEvent(UIEvent.TEXT_VALUE);
}
protected void deleteRange(int lo, int hi)
{
for (int i = hi; i >= lo; i--)
{
deleteAt(i);
}
}
protected void deleteSelection()
{
// text.delete(selLo, selHi);
deleteRange(selLo, selHi);
// selHi = selAnchor = caret = selLo; // Need to resolve selection
// // deletion before calling
// // moveCaretTo.
moveCaretTo(selLo);
clearSelection();
fireEvent(UIEvent.TEXT_VALUE);
}
protected void clearSelection()
{
selHi = selLo = caret;
selAnchor = caret;
fireEvent(UIEvent.TEXT_SELECTION);
}
protected void cut()
{
// String s = text.substring(selLo, selHi);
String s = getText(selLo, selHi);
clip.toClipboard(s);
deleteSelection();
}
protected void copy()
{
clip.toClipboard(text.substring(selLo, selHi));
}
protected void paste()
{
if (selHi - selLo > 0)
{
deleteSelection();
}
String s = clip.fromClipboard();
insert(s, caret);
}
public void replaceText(String replacement)
{
selectAll();
deleteSelection();
insert(replacement, 0);
}
public String getText(int lo, int hi)
{
return text.substring(lo, hi);
}
public String getText()
{
// return text.toString();
return getText(0, text.length());
}
synchronized protected void printState()
{
System.err.println("Text: " + text.toString());
System.err.println("Text length: " + text.length());
System.err.println("Anchor: " + (anchorRight ? "Right" : "Left") + " Position: " + anchorPos);
System.err.println("View Low: " + viewLo + " View High: " + viewHi);
System.err.println("Caret Position: " + caret);
System.err.println("Selection: " + text.substring(selLo, selHi));
System.err.println("");
}
public void keyEvent(KeyEvent e)
{
if (hidden)
return;
if (!c.focus().isFocused(this))
{
return;
}
// System.out.println(getText());
// System.out.println(e);
int code = e.getKeyCode();
boolean meta = ((e.getModifiersEx() & metaMask) != 0);
boolean alt = ((e.getModifiersEx() & KeyEvent.ALT_DOWN_MASK) == KeyEvent.ALT_DOWN_MASK);
boolean shift = ((e.getModifiersEx() & KeyEvent.SHIFT_DOWN_MASK) == KeyEvent.SHIFT_DOWN_MASK);
shiftPressed = shift;
/*
* Do some stuff to appease the OSX junkies.
*/
boolean wordJump = meta;
if (PApplet.platform == PApplet.MACOSX)
wordJump = alt;
boolean endJump = false;
if (PApplet.platform == PApplet.MACOSX)
endJump = meta;
if (e.getID() == KeyEvent.KEY_PRESSED)
{
int dir = 0;
switch (code)
{
case (37): // Left
dir = LEFT;
break;
case (39): // Right
dir = RIGHT;
break;
case (8): // Backspace
if (selHi - selLo > 0)
deleteSelection();
else
backspaceAt(caret);
break;
case (127): // Delete
if (selHi - selLo > 0)
deleteSelection();
else
deleteAt(caret);
break;
case (36): // Home
if (shift)
selectChar(-caret);
else
moveChar(-caret);
break;
case (35): // End
if (shift)
selectChar(text.length() - caret);
else
moveChar(text.length() - caret);
break;
case (16): // Shift
case (17): // Control
case (18): // Alt
case (9): // Tab
// Do nothing.
break;
case (88): // X
if (meta)
cut();
break;
case (67): // C
if (meta)
copy();
break;
case (86): // V
if (meta)
paste();
break;
case (65): // A
if (meta)
selectAll();
break;
}
if (dir != 0)
{
if (shift && wordJump)
selectWord(dir);
else if (wordJump)
moveWord(dir);
else if (shift && endJump)
selectToEnd(dir);
else if (endJump)
moveToEnd(dir);
else if (shift)
selectChar(dir);
else
moveChar(dir);
}
if (!Character.isISOControl(e.getKeyChar()))
{
e.consume();
}
} else if (e.getID() == KeyEvent.KEY_TYPED)
{
char c = e.getKeyChar();
/*
* Java tries to let us insert all sorts of garbage characters, such
* as backspace, delete, and Control-F (wtf?). Use this method to
* check that the current character is something actually worth
* displaying.
*/
if (!Character.isISOControl(c))
{
if (selHi - selLo != 0)
deleteSelection();
insertCharAt(c, caret);
/*
* Consume the event so the ToolManager doesn't dispatch the
* event to any tools.
*/
// e.consume();
}
}
}
protected boolean withinOuterRect(Point pt)
{
buffRect.setRect(x, y, width + 2 * pad, height + 2 * pad);
return buffRect.contains(pt);
}
public boolean containsPoint(Point pt)
{
return withinOuterRect(pt);
}
protected boolean withinInnerRect(Point pt)
{
buffRect.setRect(x + pad, y + pad, width, height);
return buffRect.contains(pt);
}
public void mouseEvent(MouseEvent e, Point screen, Point model)
{
if (hidden)
return;
Point p1;
if (useCameraCoordinates)
p1 = model;
else
p1 = screen;
Point pt = new Point(p1.x, p1.y);
if (e.getID() != MouseEvent.MOUSE_DRAGGED)
{
mouseDragging = false;
if (c.focus().isFocused(this) && c.focus().isModal())
{
c.focus().removeFromFocus(this);
c.focus().setFocus(this);
}
}
if (e.getID() == MouseEvent.MOUSE_MOVED || e.getID() == MouseEvent.MOUSE_RELEASED
|| e.getID() == MouseEvent.MOUSE_ENTERED || e.getID() == MouseEvent.MOUSE_EXITED)
{
if (withinInnerRect(pt) || mouseDragging)
{
UIUtils.setCursor(this, p, Cursor.TEXT_CURSOR);
} else
{
UIUtils.releaseCursor(this, p);
}
return;
}
if (e.isPopupTrigger())
return;
// printState();
if (withinOuterRect(pt) || mouseDragging) // contained within
// text+padding area.
{
if (withinInnerRect(pt) || mouseDragging) // contained within text
// area.
{
c.focus().setFocus(this);
// Find the correct insertion point.
int insertionIndex = viewLo;
float ult = x + getPosForIndex(viewLo);
float penult = ult;
for (int i = viewLo; i <= viewHi; i++)
{
float pos = x + getPosForIndex(i); // get the left edge of
// the "i"th character.
insertionIndex = i;
penult = ult;
ult = pos;
if (pos > pt.x)
{
break; // If the left edge is past our point, bail out.
}
}
float middle = (ult + penult) / 2;
if (pt.x < middle)
insertionIndex--;
int diff = insertionIndex - caret;
if (e.getID() == MouseEvent.MOUSE_DRAGGED)
{
mouseDragging = true;
c.focus().setModalFocus(this);
mouseDragPos = pt.x;
// if (insertionIndex <= viewLo || insertionIndex >= viewHi)
if (insertionIndex > 1 && insertionIndex < text.length() - 1)
handleDragScroll();
selectChar(diff);
} else if (e.getID() == MouseEvent.MOUSE_PRESSED)
{
switch (e.getClickCount())
{
case (1): // Single click: move to insertion point.
if (shiftPressed)
selectChar(diff);
else
moveChar(diff);
break;
case (2): // Double click: select surrounding word.
moveChar(diff);
nextWord(MOVE, RIGHT, false);
nextWord(SELECT, LEFT, false);
break;
case (3): // Triple click: select all.
selectAll();
break;
}
}
}
} else if (e.getID() == MouseEvent.MOUSE_PRESSED)
{
// Point is not contained within this box, so unset focus.
if (c.focus().removeFromFocus(this))
clearSelection();
}
}
public void focusEvent(FocusEvent e)
{
if (e.getID() == FocusEvent.FOCUS_LOST)
{
}
}
public void setX(float f)
{
x = f;
}
public void setY(float f)
{
y = f;
}
public float getBaselineY()
{
return y + pad + ascent;
}
public float getHeight()
{
return height + 2 * pad;
}
public float getWidth()
{
return width + 2 * pad;
}
public float getFontSize()
{
return fontSize;
}
public void setHeight(float h)
{
// TODO
}
public void setSize(float w, float h)
{
// TODO
}
public StringBuffer getTextModel()
{
return text;
}
class TextFieldStyle extends MenuStyle
{
public TextFieldStyle()
{
super();
set("c.highlight", new Color(40, 40, 255));
set("c.backgroundFill", new Color(255, 255, 255));
}
}
}