~ubuntu-branches/debian/squeeze/stella/squeeze

« back to all changes in this revision

Viewing changes to src/gui/EditableWidget.cxx

  • Committer: Bazaar Package Importer
  • Author(s): Mario Iseli
  • Date: 2006-04-08 18:38:25 UTC
  • mfrom: (1.1.2 upstream) (2.1.1 etch)
  • Revision ID: james.westby@ubuntu.com-20060408183825-vu1jk57rk929derx
* New Maintainer (Closes: #361345)
* New upstream release (Closes: #349725)
* Build-Depend now on libslang2-dev (Closes: #325577)
* Complete rebuild of debian/, upgraded to policy-standards
  3.6.2 and compat-level 5.
* Removed stellarc since stella only reads ~/.stellarc and even
  works without a first config.
* New debian/watch file.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
//============================================================================
 
2
//
 
3
//   SSSS    tt          lll  lll       
 
4
//  SS  SS   tt           ll   ll        
 
5
//  SS     tttttt  eeee   ll   ll   aaaa 
 
6
//   SSSS    tt   ee  ee  ll   ll      aa
 
7
//      SS   tt   eeeeee  ll   ll   aaaaa  --  "An Atari 2600 VCS Emulator"
 
8
//  SS  SS   tt   ee      ll   ll  aa  aa
 
9
//   SSSS     ttt  eeeee llll llll  aaaaa
 
10
//
 
11
// Copyright (c) 1995-2005 by Bradford W. Mott and the Stella team
 
12
//
 
13
// See the file "license" for information on usage and redistribution of
 
14
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
 
15
//
 
16
// $Id: EditableWidget.cxx,v 1.17 2006/03/25 00:34:17 stephena Exp $
 
17
//
 
18
//   Based on code from ScummVM - Scumm Interpreter
 
19
//   Copyright (C) 2002-2004 The ScummVM project
 
20
//============================================================================
 
21
 
 
22
#include "EditableWidget.hxx"
 
23
 
 
24
 
 
25
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 
26
EditableWidget::EditableWidget(GuiObject* boss, const GUI::Font& font,
 
27
                               int x, int y, int w, int h)
 
28
  : Widget(boss, font, x, y, w, h),
 
29
    CommandSender(boss),
 
30
    _editable(true)
 
31
{
 
32
  _caretVisible = false;
 
33
  _caretTime = 0;
 
34
  _caretPos = 0;        // FIXME
 
35
 
 
36
  _caretInverse = false;
 
37
 
 
38
  _editScrollOffset = 0;
 
39
}
 
40
 
 
41
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 
42
EditableWidget::~EditableWidget()
 
43
{
 
44
}
 
45
 
 
46
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 
47
void EditableWidget::setEditString(const string& str)
 
48
{
 
49
  // TODO: We probably should filter the input string here,
 
50
  // e.g. using tryInsertChar.
 
51
  _editString = str;
 
52
  _caretPos = _editString.size();
 
53
 
 
54
  _editScrollOffset = (_font->getStringWidth(_editString) - (getEditRect().width()));
 
55
  if (_editScrollOffset < 0)
 
56
    _editScrollOffset = 0;
 
57
 
 
58
  // Make sure the new string is seen onscreen
 
59
  setDirty(); draw();
 
60
}
 
61
 
 
62
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 
63
bool EditableWidget::tryInsertChar(char c, int pos)
 
64
{
 
65
  if (isprint(c))
 
66
  {
 
67
    _editString.insert(pos, 1, c);
 
68
    return true;
 
69
  }
 
70
  return false;
 
71
}
 
72
 
 
73
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 
74
bool EditableWidget::handleKeyDown(int ascii, int keycode, int modifiers)
 
75
{
 
76
  if(!_editable)
 
77
    return true;
 
78
 
 
79
  // Ignore all alt-mod keys
 
80
  if(instance()->eventHandler().kbdAlt(modifiers))
 
81
    return true;
 
82
 
 
83
  bool handled = true;
 
84
  bool dirty = false;
 
85
 
 
86
  switch (ascii)
 
87
  {
 
88
    case '\n':  // enter/return
 
89
    case '\r':
 
90
      // confirm edit and exit editmode
 
91
      endEditMode();
 
92
      sendCommand(kEditAcceptCmd, 0, _id);
 
93
      dirty = true;
 
94
      break;
 
95
 
 
96
    case 27:    // escape
 
97
      abortEditMode();
 
98
      sendCommand(kEditCancelCmd, 0, _id);
 
99
      dirty = true;
 
100
      break;
 
101
 
 
102
    case 8:     // backspace
 
103
      dirty = killChar(-1);
 
104
      break;
 
105
 
 
106
    case 127:   // delete
 
107
      dirty = killChar(+1);
 
108
      break;
 
109
 
 
110
    case 256 + 20:  // left arrow
 
111
                if (_caretPos > 0)
 
112
          dirty = setCaretPos(_caretPos - 1);
 
113
        break;
 
114
 
 
115
    case 256 + 19:  // right arrow
 
116
      if (_caretPos < (int)_editString.size())
 
117
        dirty = setCaretPos(_caretPos + 1);
 
118
      break;
 
119
 
 
120
    case 256 + 22:  // home
 
121
      dirty = setCaretPos(0);
 
122
      break;
 
123
 
 
124
    case 256 + 23:  // end
 
125
      dirty = setCaretPos(_editString.size());
 
126
      break;
 
127
 
 
128
    default:
 
129
      if (instance()->eventHandler().kbdControl(modifiers))
 
130
      {
 
131
        dirty = specialKeys(keycode);
 
132
      }
 
133
      else if (tryInsertChar((char)ascii, _caretPos))
 
134
      {
 
135
        _caretPos++;
 
136
        sendCommand(kEditChangedCmd, ascii, _id);
 
137
        dirty = true;
 
138
      }
 
139
      else
 
140
        handled = false;
 
141
  }
 
142
 
 
143
  if (dirty)
 
144
  {
 
145
    setDirty(); draw();
 
146
  }
 
147
 
 
148
  return handled;
 
149
}
 
150
 
 
151
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 
152
int EditableWidget::getCaretOffset() const
 
153
{
 
154
  int caretpos = 0;
 
155
  for (int i = 0; i < _caretPos; i++)
 
156
    caretpos += _font->getCharWidth(_editString[i]);
 
157
 
 
158
  caretpos -= _editScrollOffset;
 
159
 
 
160
  return caretpos;
 
161
}
 
162
 
 
163
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 
164
void EditableWidget::drawCaret()
 
165
{
 
166
//cerr << "EditableWidget::drawCaret()\n";
 
167
  // Only draw if item is visible
 
168
  if (!_editable || !isVisible() || !_boss->isVisible() || !_hasFocus)
 
169
    return;
 
170
 
 
171
  GUI::Rect editRect = getEditRect();
 
172
 
 
173
  int color = kTextColorHi;
 
174
  int x = editRect.left;
 
175
  int y = editRect.top;
 
176
 
 
177
  x += getCaretOffset();
 
178
 
 
179
  x += _x;
 
180
  y += _y;
 
181
 
 
182
  FrameBuffer& fb = _boss->instance()->frameBuffer();
 
183
  fb.vLine(x, y+2, y + editRect.height() - 2, color);
 
184
}
 
185
 
 
186
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 
187
bool EditableWidget::setCaretPos(int newPos)
 
188
{
 
189
  assert(newPos >= 0 && newPos <= (int)_editString.size());
 
190
  _caretPos = newPos;
 
191
 
 
192
  return adjustOffset();
 
193
}
 
194
 
 
195
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 
196
bool EditableWidget::adjustOffset()
 
197
{
 
198
  // check if the caret is still within the textbox; if it isn't,
 
199
  // adjust _editScrollOffset
 
200
 
 
201
  // For some reason (differences in ScummVM event handling??),
 
202
  // this method should always return true.
 
203
 
 
204
  int caretpos = getCaretOffset();
 
205
  const int editWidth = getEditRect().width();
 
206
 
 
207
  if (caretpos < 0)
 
208
  {
 
209
    // scroll left
 
210
    _editScrollOffset += caretpos;
 
211
  }
 
212
  else if (caretpos >= editWidth)
 
213
  {
 
214
    // scroll right
 
215
    _editScrollOffset -= (editWidth - caretpos);
 
216
  }
 
217
  else if (_editScrollOffset > 0)
 
218
  {
 
219
    const int strWidth = _font->getStringWidth(_editString);
 
220
    if (strWidth - _editScrollOffset < editWidth)
 
221
    {
 
222
      // scroll right
 
223
      _editScrollOffset = (strWidth - editWidth);
 
224
      if (_editScrollOffset < 0)
 
225
        _editScrollOffset = 0;
 
226
    }
 
227
  }
 
228
 
 
229
  return true;
 
230
}
 
231
 
 
232
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 
233
bool EditableWidget::specialKeys(int keycode)
 
234
{
 
235
  bool handled = true;
 
236
 
 
237
  switch (keycode)
 
238
  {
 
239
    case 'a':
 
240
      setCaretPos(0);
 
241
      break;
 
242
 
 
243
    case 'e':
 
244
      setCaretPos(_editString.size());
 
245
      break;
 
246
 
 
247
    case 'd':
 
248
      handled = killChar(+1);
 
249
      break;
 
250
 
 
251
    case 'k':
 
252
      handled = killLine(+1);
 
253
      break;
 
254
 
 
255
    case 'u':
 
256
      handled = killLine(-1);
 
257
      break;
 
258
 
 
259
    case 'w':
 
260
      handled = killLastWord();
 
261
      break;
 
262
 
 
263
    default:
 
264
      handled = false;
 
265
  }
 
266
 
 
267
  return handled;
 
268
}
 
269
 
 
270
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 
271
bool EditableWidget::killChar(int direction)
 
272
{
 
273
  bool handled = false;
 
274
 
 
275
  if(direction == -1)      // Delete previous character (backspace)
 
276
  {
 
277
    if(_caretPos > 0)
 
278
    {
 
279
      _caretPos--;
 
280
      _editString.erase(_caretPos, 1);
 
281
      handled = true;
 
282
    }
 
283
  }
 
284
  else if(direction == 1)  // Delete next character (delete)
 
285
  {
 
286
    _editString.erase(_caretPos, 1);
 
287
    handled = true;
 
288
  }
 
289
 
 
290
  return handled;
 
291
}
 
292
 
 
293
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 
294
bool EditableWidget::killLine(int direction)
 
295
{
 
296
  bool handled = false;
 
297
 
 
298
  if(direction == -1)  // erase from current position to beginning of line
 
299
  {
 
300
    int count = _caretPos;
 
301
    if(count > 0)
 
302
    {
 
303
      for (int i = 0; i < count; i++)
 
304
        killChar(-1);
 
305
 
 
306
      handled = true;
 
307
    }
 
308
  }
 
309
  else if(direction == 1)  // erase from current position to end of line
 
310
  {
 
311
    int count = _editString.size() - _caretPos;
 
312
    if(count > 0)
 
313
    {
 
314
      for (int i = 0; i < count; i++)
 
315
        killChar(+1);
 
316
 
 
317
      handled = true;
 
318
    }
 
319
  }
 
320
 
 
321
  return handled;
 
322
}
 
323
 
 
324
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 
325
bool EditableWidget::killLastWord()
 
326
{
 
327
  bool handled = false;
 
328
  int count = 0, currentPos = _caretPos;
 
329
  bool space = true;
 
330
  while (currentPos > 0)
 
331
  {
 
332
    if (_editString[currentPos - 1] == ' ')
 
333
    {
 
334
      if (!space)
 
335
        break;
 
336
    }
 
337
    else
 
338
      space = false;
 
339
 
 
340
    currentPos--;
 
341
    count++;
 
342
  }
 
343
 
 
344
  if(count > 0)
 
345
  {
 
346
    for (int i = 0; i < count; i++)
 
347
      killChar(-1);
 
348
 
 
349
    handled = true;
 
350
  }
 
351
 
 
352
  return handled;
 
353
}