abouttreesummaryrefslogcommitdiff
path: root/srcs/juloo.keyboard2/CustomLayoutEditDialog.java
blob: d63cf40efa7d59b7f75fa91e7a6c7094ebc24f89 (plain)
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
139
140
141
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;
    }

    /** A mutable Rect object that is used during onDraw. */
    Rect _clip_bounds = new Rect();

    @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());
      canvas.getClipBounds(_clip_bounds);
      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();
    }
  }
}