1 /* ScummVM - Graphic Adventure Engine
3 * ScummVM is the legal property of its developers, whose names
4 * are too numerous to list here. Please refer to the COPYRIGHT
5 * file distributed with this source distribution.
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
25 #include "backends/keymapper/remap-dialog.h"
27 #ifdef ENABLE_KEYMAPPER
29 #include "gui/GuiManager.h"
30 #include "gui/PopUpWidget.h"
31 #include "gui/ScrollBarWidget.h"
32 #include "gui/ThemeEval.h"
41 RemapDialog::RemapDialog()
42 : Dialog("KeyMapper"), _keymapTable(0), _activeRemapAction(0), _topAction(0), _remapTimeout(0) {
44 _keymapper
= g_system
->getEventManager()->getKeymapper();
47 _kmPopUpDesc
= new GUI::StaticTextWidget(this, "KeyMapper.PopupDesc", "Keymap:");
48 _kmPopUp
= new GUI::PopUpWidget(this, "KeyMapper.Popup");
50 _scrollBar
= new GUI::ScrollBarWidget(this, 0, 0, 0, 0);
52 new GUI::ButtonWidget(this, "KeyMapper.Close", "Close", kCloseCmd
);
55 RemapDialog::~RemapDialog() {
59 void RemapDialog::open() {
61 const Stack
<Keymapper::MapRecord
> &activeKeymaps
= _keymapper
->getActiveStack();
63 if (!(activeKeymaps
.size() > 0)) {
64 _kmPopUp
->appendEntry(activeKeymaps
.top().keymap
->getName() + " (Active)");
68 Keymapper::Domain
*_globalKeymaps
= &_keymapper
->getGlobalDomain();
69 Keymapper::Domain
*_gameKeymaps
= 0;
73 if (_globalKeymaps
->empty())
76 keymapCount
+= _globalKeymaps
->size();
78 if (ConfMan
.getActiveDomain() != 0) {
79 _gameKeymaps
= &_keymapper
->getGameDomain();
81 if (_gameKeymaps
->empty())
84 keymapCount
+= _gameKeymaps
->size();
87 debug(3, "keymaps: %d", keymapCount
);
89 _keymapTable
= (Keymap
**)malloc(sizeof(Keymap
*) * keymapCount
);
91 Keymapper::Domain::iterator it
;
96 _kmPopUp
->appendEntry("");
97 for (it
= _globalKeymaps
->begin(); it
!= _globalKeymaps
->end(); it
++) {
98 _kmPopUp
->appendEntry(it
->_value
->getName() + " (Global)", idx
);
99 _keymapTable
[idx
++] = it
->_value
;
106 _kmPopUp
->appendEntry("");
107 for (it
= _gameKeymaps
->begin(); it
!= _gameKeymaps
->end(); it
++) {
108 _kmPopUp
->appendEntry(it
->_value
->getName() + " (Game)", idx
);
109 _keymapTable
[idx
++] = it
->_value
;
117 _kmPopUp
->setSelected(0);
121 void RemapDialog::close() {
122 _kmPopUp
->clearEntries();
128 ConfMan
.flushToDisk();
133 void RemapDialog::reflowLayout() {
134 Dialog::reflowLayout();
136 int buttonHeight
= g_gui
.xmlEval()->getVar("Globals.Button.Height", 0);
137 int scrollbarWidth
= g_gui
.xmlEval()->getVar("Globals.Scrollbar.Width", 0);
141 int spacing
= g_gui
.xmlEval()->getVar("Globals.KeyMapper.Spacing");
142 int labelWidth
= g_gui
.xmlEval()->getVar("Globals.KeyMapper.LabelWidth");
143 int buttonWidth
= g_gui
.xmlEval()->getVar("Globals.KeyMapper.ButtonWidth");
144 int colWidth
= labelWidth
+ buttonWidth
+ spacing
;
146 g_gui
.xmlEval()->getWidgetData((const String
&)String("KeyMapper.KeymapArea"), areaX
, areaY
, areaW
, areaH
);
148 _colCount
= (areaW
- scrollbarWidth
) / colWidth
;
149 _rowCount
= (areaH
+ spacing
) / (buttonHeight
+ spacing
);
150 if (_colCount
<= 0 || _rowCount
<= 0)
151 error("Remap dialog too small to display any keymaps");
153 _scrollBar
->resize(areaX
+ areaW
- scrollbarWidth
, areaY
, scrollbarWidth
, areaH
);
154 _scrollBar
->_entriesPerPage
= _rowCount
;
155 _scrollBar
->_numEntries
= 1;
156 _scrollBar
->recalc();
158 uint textYOff
= (buttonHeight
- kLineHeight
) / 2;
159 uint oldSize
= _keymapWidgets
.size();
160 uint newSize
= _rowCount
* _colCount
;
162 _keymapWidgets
.reserve(newSize
);
164 for (uint i
= 0; i
< newSize
; i
++) {
167 if (i
>= _keymapWidgets
.size()) {
169 new GUI::StaticTextWidget(this, 0, 0, 0, 0, "", Graphics::kTextAlignRight
);
171 new GUI::ButtonWidget(this, 0, 0, 0, 0, "", kRemapCmd
+ i
);
172 _keymapWidgets
.push_back(widg
);
174 widg
= _keymapWidgets
[i
];
177 uint x
= areaX
+ (i
% _colCount
) * colWidth
;
178 uint y
= areaY
+ (i
/ _colCount
) * (buttonHeight
+ spacing
);
180 widg
.actionText
->resize(x
, y
+ textYOff
, labelWidth
, kLineHeight
);
181 widg
.keyButton
->resize(x
+ labelWidth
, y
, buttonWidth
, buttonHeight
);
183 while (oldSize
> newSize
) {
184 ActionWidgets widg
= _keymapWidgets
.remove_at(--oldSize
);
186 removeWidget(widg
.actionText
);
187 delete widg
.actionText
;
189 removeWidget(widg
.keyButton
);
190 delete widg
.keyButton
;
194 void RemapDialog::handleCommand(GUI::CommandSender
*sender
, uint32 cmd
, uint32 data
) {
195 debug(0, "Command!");
197 if (cmd
>= kRemapCmd
&& cmd
< kRemapCmd
+ _keymapWidgets
.size()) {
198 startRemapping(cmd
- kRemapCmd
);
199 } else if (cmd
== GUI::kPopUpItemSelectedCmd
) {
201 } else if (cmd
== GUI::kSetPositionCmd
) {
203 } else if (cmd
== kCloseCmd
) {
206 GUI::Dialog::handleCommand(sender
, cmd
, data
);
210 void RemapDialog::startRemapping(uint i
) {
211 if (_topAction
+ i
>= _currentActions
.size())
214 _remapTimeout
= getMillis() + kRemapTimeoutDelay
;
215 _activeRemapAction
= _currentActions
[_topAction
+ i
].action
;
216 _keymapWidgets
[i
].keyButton
->setLabel("...");
217 _keymapWidgets
[i
].keyButton
->draw();
218 _keymapper
->setEnabled(false);
222 void RemapDialog::stopRemapping() {
227 _activeRemapAction
= 0;
229 _keymapper
->setEnabled(true);
232 void RemapDialog::handleKeyDown(Common::KeyState state
) {
233 if (_activeRemapAction
)
236 GUI::Dialog::handleKeyDown(state
);
239 void RemapDialog::handleKeyUp(Common::KeyState state
) {
240 if (_activeRemapAction
) {
241 const HardwareKey
*hwkey
= _keymapper
->findHardwareKey(state
);
243 debug(0, "Key: %d, %d (%c), %x", state
.keycode
, state
.ascii
, (state
.ascii
? state
.ascii
: ' '), state
.flags
);
246 _activeRemapAction
->mapKey(hwkey
);
247 _activeRemapAction
->getParent()->saveMappings();
252 GUI::Dialog::handleKeyUp(state
);
256 void RemapDialog::handleMouseDown(int x
, int y
, int button
, int clickCount
) {
257 if (_activeRemapAction
)
260 Dialog::handleMouseDown(x
, y
, button
, clickCount
);
263 void RemapDialog::handleTickle() {
264 if (_activeRemapAction
&& getMillis() > _remapTimeout
)
266 Dialog::handleTickle();
269 void RemapDialog::loadKeymap() {
270 _currentActions
.clear();
271 const Stack
<Keymapper::MapRecord
> &activeKeymaps
= _keymapper
->getActiveStack();
273 if (!activeKeymaps
.empty() && _kmPopUp
->getSelected() == 0) {
274 // load active keymaps
276 List
<const HardwareKey
*> freeKeys(_keymapper
->getHardwareKeys());
278 // add most active keymap's keys
279 Keymapper::MapRecord top
= activeKeymaps
.top();
280 List
<Action
*>::iterator actIt
;
282 for (actIt
= top
.keymap
->getActions().begin(); actIt
!= top
.keymap
->getActions().end(); ++actIt
) {
283 Action
*act
= *actIt
;
284 ActionInfo info
= {act
, false, act
->description
};
286 _currentActions
.push_back(info
);
288 if (act
->getMappedKey())
289 freeKeys
.remove(act
->getMappedKey());
292 // loop through remaining finding mappings for unmapped keys
294 for (int i
= activeKeymaps
.size() - 2; i
>= 0; --i
) {
295 Keymapper::MapRecord mr
= activeKeymaps
[i
];
296 List
<const HardwareKey
*>::iterator keyIt
= freeKeys
.begin();
298 while (keyIt
!= freeKeys
.end()) {
299 Action
*act
= mr
.keymap
->getMappedAction((*keyIt
)->key
);
302 ActionInfo info
= {act
, true, act
->description
+ " (" + mr
.keymap
->getName() + ")"};
303 _currentActions
.push_back(info
);
304 freeKeys
.erase(keyIt
++);
310 if (mr
.inherit
== false || freeKeys
.empty())
315 } else if (_kmPopUp
->getSelected() != -1) {
316 Keymap
*km
= _keymapTable
[_kmPopUp
->getSelectedTag()];
318 List
<Action
*>::iterator it
;
320 for (it
= km
->getActions().begin(); it
!= km
->getActions().end(); it
++) {
321 ActionInfo info
= {*it
, false, (*it
)->description
};
323 _currentActions
.push_back(info
);
327 // refresh scroll bar
328 _scrollBar
->_currentPos
= 0;
329 _scrollBar
->_numEntries
= (_currentActions
.size() + _colCount
- 1) / _colCount
;
330 _scrollBar
->recalc();
337 void RemapDialog::refreshKeymap() {
338 int newTopAction
= _scrollBar
->_currentPos
* _colCount
;
340 if (newTopAction
== _topAction
)
343 _topAction
= newTopAction
;
345 //_container->draw();
348 uint actionI
= _topAction
;
350 for (uint widgetI
= 0; widgetI
< _keymapWidgets
.size(); widgetI
++) {
351 ActionWidgets
& widg
= _keymapWidgets
[widgetI
];
353 if (actionI
< _currentActions
.size()) {
354 ActionInfo
& info
= _currentActions
[actionI
];
356 widg
.actionText
->setLabel(info
.description
+ ": ");
357 widg
.actionText
->setEnabled(!info
.inherited
);
359 const HardwareKey
*mappedKey
= info
.action
->getMappedKey();
362 widg
.keyButton
->setLabel(mappedKey
->description
);
364 widg
.keyButton
->setLabel("-");
366 widg
.actionText
->setVisible(true);
367 widg
.keyButton
->setVisible(true);
371 widg
.actionText
->setVisible(false);
372 widg
.keyButton
->setVisible(false);
374 //widg.actionText->draw();
375 //widg.keyButton->draw();
377 // need to redraw entire Dialog so that invisible
383 } // end of namespace Common
385 #endif // #ifdef ENABLE_KEYMAPPER