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

« back to all changes in this revision

Viewing changes to src/gui/ContextMenu.cxx

  • Committer: Bazaar Package Importer
  • Author(s): Stephen Kitt
  • Date: 2010-07-12 23:49:36 UTC
  • mfrom: (1.1.4 upstream)
  • Revision ID: james.westby@ubuntu.com-20100712234936-juawrr3etzhr2qpv
Tags: 3.1.2-1
* New maintainer (closes: #532039).
* New upstream version (closes: #461121):
  - includes launcher (closes: #396058).
* Fix the reference to the X Window System in the description (closes:
  #411815).
* Move to main, DFSG-free ROMs are available (see README.Debian).
* Enhance the package description.
* Drop the libslang2-dev dependency (closes: #560274).
* Remove the Encoding entry from stella.desktop.
* Avoid ignoring errors when cleaning.
* Add ${misc:Depends} to the package dependencies.
* Provide a doc-base file to install the documentation using doc-base.
* Switch to debhelper 7 with a simplified rules file.
* Use autotools-dev to provide updated configuration files.
* Update to Standards-Version 3.9.0:
  - Move to menu section Applications/Emulators.
  - Move the homepage declaration.
* Re-write the manpage.

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-2010 by Bradford W. Mott, Stephen Anthony
 
12
// and the Stella Team
 
13
//
 
14
// See the file "License.txt" for information on usage and redistribution of
 
15
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
 
16
//
 
17
// $Id: ContextMenu.cxx 2001 2010-04-10 21:37:23Z stephena $
 
18
//
 
19
//   Based on code from ScummVM - Scumm Interpreter
 
20
//   Copyright (C) 2002-2004 The ScummVM project
 
21
//============================================================================
 
22
 
 
23
#include "OSystem.hxx"
 
24
#include "FrameBuffer.hxx"
 
25
#include "Dialog.hxx"
 
26
#include "DialogContainer.hxx"
 
27
#include "ContextMenu.hxx"
 
28
 
 
29
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 
30
ContextMenu::ContextMenu(GuiObject* boss, const GUI::Font& font,
 
31
                         const StringMap& items, int cmd)
 
32
  : Dialog(&boss->instance(), &boss->parent(), 0, 0, 16, 16),
 
33
    CommandSender(boss),
 
34
    _rowHeight(font.getLineHeight()),
 
35
    _firstEntry(0),
 
36
    _numEntries(0),
 
37
    _selectedOffset(0),
 
38
    _selectedItem(-1),
 
39
    _showScroll(false),
 
40
    _font(&font),
 
41
    _cmd(cmd),
 
42
    _xorig(0),
 
43
    _yorig(0)
 
44
{
 
45
  addItems(items);
 
46
}
 
47
 
 
48
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 
49
ContextMenu::~ContextMenu()
 
50
{
 
51
  _entries.clear();
 
52
}
 
53
 
 
54
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 
55
void ContextMenu::addItems(const StringMap& items)
 
56
{
 
57
  _entries.clear();
 
58
  _entries = items;
 
59
 
 
60
  // Resize to largest string
 
61
  int maxwidth = 0;
 
62
  for(unsigned int i = 0; i < _entries.size(); ++i)
 
63
  {
 
64
    int length = _font->getStringWidth(_entries[i].first);
 
65
    if(length > maxwidth)
 
66
      maxwidth = length;
 
67
  }
 
68
 
 
69
  _x = _y = 0;
 
70
  _w = maxwidth + 10;
 
71
  _h = 1;  // recalculate this in ::recalc()
 
72
}
 
73
 
 
74
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 
75
void ContextMenu::show(uInt32 x, uInt32 y, int item)
 
76
{
 
77
  _xorig = x;
 
78
  _yorig = y;
 
79
 
 
80
  recalc(instance().frameBuffer().imageRect());
 
81
  parent().addDialog(this);
 
82
  setSelected(item);
 
83
}
 
84
 
 
85
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 
86
void ContextMenu::center()
 
87
{
 
88
  // Make sure the menu is exactly where it should be, in case the image
 
89
  // offset has changed
 
90
  const GUI::Rect& image = instance().frameBuffer().imageRect();
 
91
  recalc(image);
 
92
  uInt32 x = image.x() + _xorig;
 
93
  uInt32 y = image.y() + _yorig;
 
94
  uInt32 tx = image.x() + image.width();
 
95
  uInt32 ty = image.y() + image.height();
 
96
  if(x + _w > tx) x -= (x + _w - tx);
 
97
  if(y + _h > ty) y -= (y + _h - ty);
 
98
 
 
99
  surface().setPos(x, y);
 
100
}
 
101
 
 
102
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 
103
void ContextMenu::recalc(const GUI::Rect& image)
 
104
{
 
105
  // Now is the time to adjust the height
 
106
  // If it's higher than the screen, we need to scroll through
 
107
  int maxentries = (image.height() - 4) / _rowHeight;
 
108
  if((int)_entries.size() > maxentries)
 
109
  {
 
110
    // We show two less than the max, so we have room for two scroll buttons
 
111
    _numEntries = maxentries - 2;
 
112
    _h = maxentries * _rowHeight + 4;
 
113
    _showScroll = true;
 
114
  }
 
115
  else
 
116
  {
 
117
    _numEntries = _entries.size();
 
118
    _h = _entries.size() * _rowHeight + 4;
 
119
    _showScroll = false;
 
120
  }
 
121
}
 
122
 
 
123
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 
124
void ContextMenu::setSelected(int item)
 
125
{
 
126
  if(item >= 0 && item < (int)_entries.size())
 
127
    _selectedItem = item;
 
128
  else
 
129
    _selectedItem = -1;
 
130
}
 
131
 
 
132
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 
133
void ContextMenu::setSelected(const string& tag, const string& defaultTag)
 
134
{
 
135
  for(unsigned int item = 0; item < _entries.size(); ++item)
 
136
  {
 
137
    if(BSPF_strcasecmp(_entries[item].second.c_str(), tag.c_str()) == 0)
 
138
    {
 
139
      setSelected(item);
 
140
      return;
 
141
    }
 
142
  }
 
143
 
 
144
  // If we get this far, the value wasn't found; use the default value
 
145
  for(unsigned int item = 0; item < _entries.size(); ++item)
 
146
  {
 
147
    if(BSPF_strcasecmp(_entries[item].second.c_str(), defaultTag.c_str()) == 0)
 
148
    {
 
149
      setSelected(item);
 
150
      return;
 
151
    }
 
152
  }
 
153
}
 
154
 
 
155
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 
156
void ContextMenu::setSelectedMax()
 
157
{
 
158
  setSelected(_entries.size() - 1);
 
159
}
 
160
 
 
161
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 
162
void ContextMenu::clearSelection()
 
163
{
 
164
  _selectedItem = -1;
 
165
}
 
166
 
 
167
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 
168
int ContextMenu::getSelected() const
 
169
{
 
170
  return _selectedItem;
 
171
}
 
172
 
 
173
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 
174
const string& ContextMenu::getSelectedName() const
 
175
{
 
176
  return (_selectedItem >= 0) ? _entries[_selectedItem].first : EmptyString;
 
177
}
 
178
 
 
179
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 
180
const string& ContextMenu::getSelectedTag() const
 
181
{
 
182
  return (_selectedItem >= 0) ? _entries[_selectedItem].second : EmptyString;
 
183
}
 
184
 
 
185
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 
186
void ContextMenu::handleMouseDown(int x, int y, int button, int clickCount)
 
187
{
 
188
  // Only do a selection when the left button is in the dialog
 
189
  if(button == 1)
 
190
  {
 
191
    x += getAbsX(); y += getAbsY();
 
192
    if(x >= _x && x <= _x+_w && y >= _y && y <= _y+_h)
 
193
      sendSelection();
 
194
    else
 
195
      close();
 
196
  }
 
197
}
 
198
 
 
199
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 
200
void ContextMenu::handleMouseMoved(int x, int y, int button)
 
201
{
 
202
  // Compute over which item the mouse is...
 
203
  int item = findItem(x, y);
 
204
  if(item == -1)
 
205
    return;
 
206
 
 
207
  // ...and update the selection accordingly
 
208
  drawCurrentSelection(item);
 
209
}
 
210
 
 
211
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 
212
void ContextMenu::handleKeyDown(int ascii, int keycode, int modifiers)
 
213
{
 
214
  handleEvent(instance().eventHandler().eventForKey(keycode, kMenuMode));
 
215
}
 
216
 
 
217
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 
218
void ContextMenu::handleJoyDown(int stick, int button)
 
219
{
 
220
  handleEvent(instance().eventHandler().eventForJoyButton(stick, button, kMenuMode));
 
221
}
 
222
 
 
223
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 
224
void ContextMenu::handleJoyAxis(int stick, int axis, int value)
 
225
{
 
226
  if(value != 0)  // we don't care about 'axis up' events
 
227
    handleEvent(instance().eventHandler().eventForJoyAxis(stick, axis, value, kMenuMode));
 
228
}
 
229
 
 
230
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 
231
bool ContextMenu::handleJoyHat(int stick, int hat, int value)
 
232
{
 
233
  handleEvent(instance().eventHandler().eventForJoyHat(stick, hat, value, kMenuMode));
 
234
  return true;
 
235
}
 
236
 
 
237
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 
238
void ContextMenu::handleEvent(Event::Type e)
 
239
{
 
240
  switch(e)
 
241
  {
 
242
    case Event::UISelect:
 
243
      sendSelection();
 
244
      break;
 
245
    case Event::UIUp:
 
246
    case Event::UILeft:
 
247
      moveUp();
 
248
      break;
 
249
    case Event::UIDown:
 
250
    case Event::UIRight:
 
251
      moveDown();
 
252
      break;
 
253
    case Event::UICancel:
 
254
      close();
 
255
      break;
 
256
    default:
 
257
      break;
 
258
  }
 
259
}
 
260
 
 
261
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 
262
int ContextMenu::findItem(int x, int y) const
 
263
{
 
264
  if(x >= 0 && x < _w && y >= 0 && y < _h)
 
265
    return (y - 4) / _rowHeight;
 
266
 
 
267
  return -1;
 
268
}
 
269
 
 
270
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 
271
void ContextMenu::drawCurrentSelection(int item)
 
272
{
 
273
  // Change selection
 
274
  _selectedOffset = item;
 
275
  setDirty();
 
276
}
 
277
 
 
278
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 
279
void ContextMenu::sendSelection()
 
280
{
 
281
  // Select the correct item when scrolling; we have to take into account
 
282
  // that the viewable items are no longer 1-to-1 with the entries
 
283
  int item = _firstEntry + _selectedOffset;
 
284
 
 
285
  if(_showScroll)
 
286
  {
 
287
    if(_selectedOffset == 0)  // scroll up
 
288
      return scrollUp();
 
289
    else if(_selectedOffset == _numEntries+1) // scroll down
 
290
      return scrollDown();
 
291
    else
 
292
      item--;
 
293
  }
 
294
 
 
295
  // We remove the dialog when the user has selected an item
 
296
  // Make sure the dialog is removed before sending any commands,
 
297
  // since one consequence of sending a command may be to add another
 
298
  // dialog/menu
 
299
  close();
 
300
 
 
301
  // Send any command associated with the selection
 
302
  _selectedItem = item;
 
303
  sendCommand(_cmd ? _cmd : kCMenuItemSelectedCmd, _selectedItem, -1);
 
304
}
 
305
 
 
306
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 
307
void ContextMenu::moveUp()
 
308
{
 
309
  if(_showScroll)
 
310
  {
 
311
    // Reaching the top of the list means we have to scroll up, but keep the
 
312
    // current item offset
 
313
    // Otherwise, the offset should decrease by 1
 
314
    if(_selectedOffset == 1)
 
315
      scrollUp();
 
316
    else if(_selectedOffset > 1)
 
317
      drawCurrentSelection(_selectedOffset-1);
 
318
  }
 
319
  else
 
320
  {
 
321
    if(_selectedOffset > 0)
 
322
      drawCurrentSelection(_selectedOffset-1);
 
323
  }
 
324
}
 
325
 
 
326
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 
327
void ContextMenu::moveDown()
 
328
{
 
329
  if(_showScroll)
 
330
  {
 
331
    // Reaching the bottom of the list means we have to scroll down, but keep the
 
332
    // current item offset
 
333
    // Otherwise, the offset should increase by 1
 
334
    if(_selectedOffset == _numEntries)
 
335
      scrollDown();
 
336
    else if(_selectedOffset < (int)_entries.size())
 
337
      drawCurrentSelection(_selectedOffset+1);    
 
338
  }
 
339
  else
 
340
  {
 
341
    if(_selectedOffset < (int)_entries.size() - 1)
 
342
      drawCurrentSelection(_selectedOffset+1);
 
343
  }
 
344
}
 
345
 
 
346
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 
347
void ContextMenu::scrollUp()
 
348
{
 
349
  if(_firstEntry > 0)
 
350
  {
 
351
    _firstEntry--;
 
352
    setDirty();
 
353
  }
 
354
}
 
355
 
 
356
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 
357
void ContextMenu::scrollDown()
 
358
{
 
359
  if(_firstEntry + _numEntries < (int)_entries.size())
 
360
  {
 
361
    _firstEntry++;
 
362
    setDirty();
 
363
  }
 
364
}
 
365
 
 
366
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 
367
void ContextMenu::drawDialog()
 
368
{
 
369
  static uInt32 up_arrow[8] = {
 
370
    0x00011000,
 
371
    0x00011000,
 
372
    0x00111100,
 
373
    0x00111100,
 
374
    0x01111110,
 
375
    0x01111110,
 
376
    0x11111111,
 
377
    0x11111111
 
378
  };
 
379
  static uInt32 down_arrow[8] = {
 
380
    0x11111111,
 
381
    0x11111111,
 
382
    0x01111110,
 
383
    0x01111110,
 
384
    0x00111100,
 
385
    0x00111100,
 
386
    0x00011000,
 
387
    0x00011000
 
388
  };
 
389
 
 
390
  // Normally we add widgets and let Dialog::draw() take care of this
 
391
  // logic.  But for some reason, this Dialog was written differently
 
392
  // by the ScummVM guys, so I'm not going to mess with it.
 
393
  FBSurface& s = surface();
 
394
 
 
395
  if(_dirty)
 
396
  {
 
397
    // Draw menu border and background
 
398
    s.fillRect(_x+1, _y+1, _w-2, _h-2, kWidColor);
 
399
    s.box(_x, _y, _w, _h, kColor, kShadowColor);
 
400
 
 
401
    // Draw the entries, taking scroll buttons into account
 
402
    int x = _x + 2, y = _y + 2, w = _w - 4;
 
403
 
 
404
    // Show top scroll area
 
405
    int offset = _selectedOffset;
 
406
    if(_showScroll)
 
407
    {
 
408
      s.hLine(x, y+_rowHeight-1, w+2, kShadowColor);
 
409
      s.drawBitmap(up_arrow, ((_w-_x)>>1)-4, (_rowHeight>>1)+y-4, kScrollColor, 8);
 
410
      y += _rowHeight;
 
411
      offset--;
 
412
    }
 
413
 
 
414
    for(int i = _firstEntry, current = 0; i < _firstEntry + _numEntries; ++i, ++current)
 
415
    {
 
416
      bool hilite = offset == current;
 
417
      if(hilite) s.fillRect(x, y, w, _rowHeight, kTextColorHi);
 
418
      s.drawString(_font, _entries[i].first, x + 1, y + 2, w,
 
419
                   !hilite ? kTextColor : kWidColor);
 
420
      y += _rowHeight;
 
421
    }
 
422
 
 
423
    // Show bottom scroll area
 
424
    if(_showScroll)
 
425
    {
 
426
      s.hLine(x, y, w+2, kShadowColor);
 
427
      s.drawBitmap(down_arrow, ((_w-_x)>>1)-4, (_rowHeight>>1)+y-4, kScrollColor, 8);
 
428
    }
 
429
 
 
430
    s.addDirtyRect(_x, _y, _w, _h);
 
431
    _dirty = false;
 
432
  }
 
433
 
 
434
  // Commit surface changes to screen
 
435
  s.update();
 
436
}