package ch.unifr.pai.twice.widgets.client;
/*
* Copyright 2013 Oliver Schmid
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import java.util.HashMap;
import java.util.Map;
import ch.unifr.pai.twice.comm.serverPush.client.RemoteWidget;
import ch.unifr.pai.twice.utils.device.client.UUID;
import com.google.gwt.canvas.client.Canvas;
import com.google.gwt.canvas.dom.client.Context2d;
import com.google.gwt.canvas.dom.client.Context2d.TextAlign;
import com.google.gwt.canvas.dom.client.Context2d.TextBaseline;
import com.google.gwt.dom.client.Element;
import com.google.gwt.dom.client.Node;
import com.google.gwt.dom.client.Style.BorderStyle;
import com.google.gwt.dom.client.Style.Display;
import com.google.gwt.dom.client.Style.Unit;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.logical.shared.ValueChangeEvent;
import com.google.gwt.event.logical.shared.ValueChangeHandler;
import com.google.gwt.event.shared.HandlerRegistration;
import com.google.gwt.user.client.Event;
import com.google.gwt.user.client.Event.NativePreviewEvent;
import com.google.gwt.user.client.Event.NativePreviewHandler;
import com.google.gwt.user.client.Timer;
import com.google.gwt.user.client.ui.AbsolutePanel;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.FlowPanel;
import com.google.gwt.user.client.ui.HTML;
import com.google.gwt.user.client.ui.HasValue;
import com.google.gwt.user.client.ui.TextBox;
public class MultiFocusTextBox extends Composite implements HasValue<String>{
private final Map<String, Cursor> cursors = new HashMap<String, Cursor>();
FlowPanel p = new FlowPanel();
private String value;
AbsolutePanel multiFocus = new AbsolutePanel();
private final int cursorSpeed = 700;
String[] colors = new String[]{"red", "blue"};
Cursor blueCursor = new Cursor("blue", UUID.createNew());
Cursor redCursor = new Cursor("red", UUID.createNew());
private final Context2d context;
private TextBox textBox = new TextBox();
private final Canvas c;
private Timer blinkTimer;
private boolean cursorsVisible;
public MultiFocusTextBox() {
blinkTimer = new Timer(){
@Override
public void run() {
for(Cursor c : cursors.values()){
c.setVisible(cursorsVisible);
}
cursorsVisible = !cursorsVisible;
}
};
blinkTimer.scheduleRepeating(cursorSpeed);
p.getElement().getStyle().setDisplay(Display.INLINE_BLOCK);
c = Canvas.createIfSupported();
c.getElement().getStyle().setBorderWidth(0, Unit.PX);
c.getElement().getStyle().setProperty("outline", "none");
c.addClickHandler(new ClickHandler() {
@Override
public void onClick(ClickEvent event) {
//TODO if it is a new device, create a new cursor with the
repositionCursor(null, event.getRelativeX(c.getCanvasElement()), event.getRelativeY(c.getCanvasElement()));
}
});
multiFocus.insert(c, 0, 0, 0);
initWidget(multiFocus);
getElement().getStyle().setBorderStyle(BorderStyle.SOLID);
getElement().getStyle().setBorderWidth(1, Unit.PX);
c.getElement().getStyle().setMargin(5, Unit.PX);
context = c.getContext2d();
context.setTextAlign(TextAlign.LEFT);
context.setTextBaseline(TextBaseline.TOP);
context.setFont("13px sans-serif;");
// TODO Auto-generated constructor stub
// multiFocus.setVisible(false);
multiFocus.setWidth("161px");
multiFocus.setHeight("28px");
}
private void repositionCursor(String deviceId, int x, int y){
blueCursor.setPosition(findChar(x));
}
private int findChar(int x){
StringBuilder b = new StringBuilder();
for(char c : value.toCharArray()){
b.append(c);
double textWidth = context.measureText(b.toString()).getWidth();
if(x<textWidth){
double charWidth = context.measureText(String.valueOf(c)).getWidth();
if(textWidth-(charWidth/2.0)>x)
return Math.max(b.length()-1, 0);
else
return b.length();
}
}
return b.length();
}
private void registerCursor(String uuid, Cursor c){
cursors.put(uuid, c);
}
private void unregisterCursor(String uuid){
cursors.remove(uuid);
}
protected class Cursor extends HTML{
int x;
int y;
final String uuid;
int position;
HandlerRegistration reg;
private Cursor(String color, String uuid){
this.uuid = uuid;
getElement().getStyle().setBackgroundColor(color);
setWidth("1px");
setHeight("18px");
}
private void hide(){
multiFocus.remove(this);
unregisterCursor(uuid);
if(reg!=null){
reg.removeHandler();
reg = null;
}
}
private void show(){
registerCursor(uuid, this);
multiFocus.add(this);
multiFocus.setWidgetPosition(this, x+5, y+5);
reg = Event.addNativePreviewHandler(new NativePreviewHandler() {
@Override
public void onPreviewNativeEvent(NativePreviewEvent event) {
if(event.getTypeInt() == Event.ONMOUSEUP && !c.getElement().isOrHasChild(Element.as(event.getNativeEvent().getEventTarget()))){
//TODO enable after testing
// hide();
}
}
});
}
public void setPosition(int position){
hide();
this.position = position;
this.x = (int)Math.max(0, context.measureText(position<value.length() ? value.substring(0, position) : value).getWidth());
show();
}
public int getPosition(){
return position;
}
}
@Override
public HandlerRegistration addValueChangeHandler(
ValueChangeHandler<String> handler) {
return addHandler(handler, ValueChangeEvent.getType());
}
@Override
public String getValue() {
return value;
}
protected Cursor getOrCreateCursor(String uuid){
Cursor c = cursors.get(uuid);
if(c==null){
c = new Cursor("blue", uuid);
registerCursor(uuid, c);
}
return c;
}
protected Map<String, Cursor> getCursors(){
return cursors;
}
private void processInput(String uuid, int pos, char c){
if(pos<=value.length()){
setValue(value.substring(0, pos)+c+((pos==value.length())? "" : value.substring(pos)));
}
for(Cursor cursor : cursors.values()){
if(pos<=cursor.getPosition()){
cursor.setPosition(cursor.getPosition()+1);
}
}
}
@Override
public void setValue(String value) {
this.value = value;
textBox.setValue(value);
context.clearRect(0, 0, c.getOffsetWidth(), c.getOffsetHeight());
context.fillText(value, 0, 0);
}
@Override
public void setValue(String value, boolean fireEvents) {
setValue(value);
//TODO
}
}