1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
|
package juloo.keyboard2;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Rect;
import android.os.Handler;
import android.text.InputType;
import android.text.Layout;
import android.widget.EditText;
public class CustomLayoutEditDialog
{
/** Dialog for specifying a custom layout. [initial_text] is the layout
description when modifying a layout. */
public static void show(Context ctx, String initial_text,
boolean allow_remove, final Callback callback)
{
final LayoutEntryEditText input = new LayoutEntryEditText(ctx);
input.setText(initial_text);
AlertDialog.Builder dialog = new AlertDialog.Builder(ctx)
.setView(input)
.setTitle(R.string.pref_custom_layout_title)
.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener(){
public void onClick(DialogInterface _dialog, int _which)
{
callback.select(input.getText().toString());
}
})
.setNegativeButton(android.R.string.cancel, null);
// Might be true when modifying an existing layout
if (allow_remove)
dialog.setNeutralButton(R.string.pref_layouts_remove_custom, new DialogInterface.OnClickListener(){
public void onClick(DialogInterface _dialog, int _which)
{
callback.select(null);
}
});
input.set_on_text_change(new LayoutEntryEditText.OnChangeListener()
{
public void on_change()
{
String error = callback.validate(input.getText().toString());
input.setError(error);
}
});
dialog.show();
}
public interface Callback
{
/** The entered text when the user clicks "OK", [null] when the user
cancels editing. */
public void select(String text);
/** Return a human readable error string if the [text] contains an error.
Return [null] otherwise. The error string will be displayed atop the
input box. This method is called everytime the text changes. */
public String validate(String text);
}
/** An editable text view that shows line numbers. */
static class LayoutEntryEditText extends EditText
{
/** Used to draw line numbers. */
Paint _ln_paint;
OnChangeListener _on_change_listener = null;
/** Delay validation to when user stops typing for a second. */
Handler _on_change_throttler;
Runnable _on_change_delayed = new Runnable()
{
public void run()
{
OnChangeListener l = LayoutEntryEditText.this._on_change_listener;
if (l != null)
l.on_change();
}
};
public LayoutEntryEditText(Context ctx)
{
super(ctx);
_ln_paint = new Paint(getPaint());
_ln_paint.setTextSize(_ln_paint.getTextSize() * 0.8f);
setHorizontallyScrolling(true);
setInputType(InputType.TYPE_CLASS_TEXT
| InputType.TYPE_TEXT_FLAG_MULTI_LINE);
_on_change_throttler = new Handler(ctx.getMainLooper());
}
public void set_on_text_change(OnChangeListener l)
{
_on_change_listener = l;
}
@Override
protected void onDraw(Canvas canvas)
{
float digit_width = _ln_paint.measureText("0");
int line_count = getLineCount();
// Extra '+ 1' serves as padding.
setPadding((int)(((int)Math.log10(line_count) + 1 + 1) * digit_width), 0, 0, 0);
super.onDraw(canvas);
_ln_paint.setColor(getPaint().getColor());
Rect clip_bounds = canvas.getClipBounds();
Layout layout = getLayout();
int offset = clip_bounds.left + (int)(digit_width / 2.f);
int line = layout.getLineForVertical(clip_bounds.top);
int skipped = line;
while (line < line_count)
{
int baseline = getLineBounds(line, null);
canvas.drawText(String.valueOf(line), offset, baseline, _ln_paint);
line++;
if (baseline >= clip_bounds.bottom)
break;
}
}
@Override
protected void onTextChanged(CharSequence text, int _start, int _lengthBefore, int _lengthAfter)
{
if (_on_change_throttler != null)
{
_on_change_throttler.removeCallbacks(_on_change_delayed);
_on_change_throttler.postDelayed(_on_change_delayed, 1000);
}
}
public static interface OnChangeListener
{
public void on_change();
}
}
}
|