GCC Code Coverage Report
Directory: src/ Exec Total Coverage
File: src/gui/windowmenu.cpp Lines: 1 220 0.5 %
Date: 2017-11-29 Branches: 2 332 0.6 %

Line Branch Exec Source
1
/*
2
 *  The ManaPlus Client
3
 *  Copyright (C) 2004-2009  The Mana World Development Team
4
 *  Copyright (C) 2009-2010  The Mana Developers
5
 *  Copyright (C) 2011-2017  The ManaPlus Developers
6
 *
7
 *  This file is part of The ManaPlus Client.
8
 *
9
 *  This program is free software; you can redistribute it and/or modify
10
 *  it under the terms of the GNU General Public License as published by
11
 *  the Free Software Foundation; either version 2 of the License, or
12
 *  any later version.
13
 *
14
 *  This program is distributed in the hope that it will be useful,
15
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
16
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17
 *  GNU General Public License for more details.
18
 *
19
 *  You should have received a copy of the GNU General Public License
20
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
21
 */
22
23
#include "gui/windowmenu.h"
24
25
#include "configuration.h"
26
27
#include "input/inputmanager.h"
28
29
#include "gui/buttoninfo.h"
30
#include "gui/buttontext.h"
31
#include "gui/popupmanager.h"
32
#include "gui/skin.h"
33
34
#include "gui/popups/popupmenu.h"
35
#include "gui/popups/textpopup.h"
36
37
#include "gui/windows/skilldialog.h"
38
39
#include "gui/widgets/button.h"
40
41
#include "utils/dtor.h"
42
#include "utils/foreach.h"
43
#include "utils/gettext.h"
44
45
#include "debug.h"
46
47
WindowMenu *windowMenu = nullptr;
48
49
WindowMenu::WindowMenu(const Widget2 *const widget) :
50
    Container(widget),
51
    ConfigListener(),
52
    ActionListener(),
53
    SelectionListener(),
54
    MouseListener(),
55
    mSkin(theme != nullptr ? theme->load("windowmenu.xml", "") : nullptr),
56
    mPadding(mSkin != nullptr ? mSkin->getPadding() : 1),
57
    mSpacing(mSkin != nullptr ? mSkin->getOption("spacing", 3) : 3),
58
    mButtons(),
59
    mButtonTexts(),
60
    mButtonNames(),
61
    mHaveMouse(false),
62
    mAutoHide(1),
63
    mSmallWindow(mainGraphics->getWidth() < 600)
64
{
65
    int x = mPadding;
66
    int h = 0;
67
68
    setFocusable(false);
69
    // TRANSLATORS: short button name for who is online window.
70
    addButton(N_("ONL"),
71
        // TRANSLATORS: long button name for who is online window.
72
        _("Who is online"), x, h, InputAction::WINDOW_ONLINE);
73
    // TRANSLATORS: short button name for help window.
74
    addButton(N_("HLP"),
75
        // TRANSLATORS: long button name for help window.
76
        _("Help"), x, h, InputAction::WINDOW_HELP);
77
    // TRANSLATORS: short button name for quests window.
78
    addButton(N_("QE"),
79
        // TRANSLATORS: long button name for quests window.
80
        _("Quests"), x, h, InputAction::WINDOW_QUESTS);
81
    // TRANSLATORS: short button name for kill stats window.
82
    addButton(N_("KS"),
83
        // TRANSLATORS: long button name for kill stats window.
84
        _("Kill stats"), x, h, InputAction::WINDOW_KILLS);
85
    addButton(":-)",
86
        // TRANSLATORS: long button name for emotes window.
87
        _("Smilies"), x, h, InputAction::WINDOW_EMOTE_SHORTCUT);
88
    // TRANSLATORS: short button name for chat window.
89
    addButton(N_("CH"),
90
        // TRANSLATORS: longt button name for chat window.
91
        _("Chat"), x, h, InputAction::WINDOW_CHAT,
92
#ifdef ANDROID
93
        Visible_true);
94
#else  // ANDROID
95
        Visible_false);
96
#endif  // ANDROID
97
98
    // TRANSLATORS: short button name for status window.
99
    addButton(N_("STA"),
100
        // TRANSLATORS: long button name for status window.
101
        _("Status"), x, h, InputAction::WINDOW_STATUS);
102
    // TRANSLATORS: short button name for equipment window.
103
    addButton(N_("EQU"),
104
        // TRANSLATORS: long button name for equipment window.
105
        _("Equipment"), x, h, InputAction::WINDOW_EQUIPMENT);
106
    // TRANSLATORS: short button name for inventory window.
107
    addButton(N_("INV"),
108
        // TRANSLATORS: long button name for inventory window.
109
        _("Inventory"), x, h, InputAction::WINDOW_INVENTORY);
110
    // TRANSLATORS: short button name for cart window.
111
    addButton(N_("CA"),
112
        // TRANSLATORS: long button name for cart window.
113
        _("Cart"), x, h, InputAction::WINDOW_CART);
114
    // TRANSLATORS: short button name for map window.
115
    addButton(N_("MAP"),
116
        // TRANSLATORS: long button name for map window.
117
        _("Map"), x, h, InputAction::WINDOW_MINIMAP,
118
        Visible_false);
119
120
    if (skillDialog->hasSkills())
121
    {
122
        // TRANSLATORS: short button name for skills window.
123
        addButton(N_("SKI"),
124
            // TRANSLATORS: long button name for skills window.
125
            _("Skills"), x, h, InputAction::WINDOW_SKILL);
126
    }
127
128
    // TRANSLATORS: short button name for social window.
129
    addButton(N_("SOC"),
130
        // TRANSLATORS: long button name for social window.
131
        _("Social"), x, h, InputAction::WINDOW_SOCIAL);
132
    // TRANSLATORS: short button name for shortcuts window.
133
    addButton(N_("SH"),
134
        // TRANSLATORS: long button name for shortcuts window.
135
        _("Shortcuts"), x, h, InputAction::WINDOW_SHORTCUT);
136
    // TRANSLATORS: short button name for spells window.
137
    addButton(N_("SP"),
138
        // TRANSLATORS: long button name for spells window.
139
        _("Spells"), x, h, InputAction::WINDOW_SPELLS);
140
    // TRANSLATORS: short button name for drops window.
141
    addButton(N_("DR"),
142
        // TRANSLATORS: long button name for drops window.
143
        _("Drop"), x, h, InputAction::WINDOW_DROP,
144
        Visible_false);
145
    // TRANSLATORS: short button name for did you know window.
146
    addButton(N_("YK"),
147
        // TRANSLATORS: long button name for did you know window.
148
        _("Did you know"), x, h, InputAction::WINDOW_DIDYOUKNOW,
149
        Visible_false);
150
    // TRANSLATORS: short button name for shop window.
151
    addButton(N_("SHP"),
152
        // TRANSLATORS: long button name for shop window.
153
        _("Shop"), x, h, InputAction::WINDOW_SHOP,
154
        Visible_false);
155
    // TRANSLATORS: short button name for outfits window.
156
    addButton(N_("OU"),
157
        // TRANSLATORS: long button name for outfits window.
158
        _("Outfits"), x, h, InputAction::WINDOW_OUTFIT,
159
        Visible_false);
160
    // TRANSLATORS: short button name for updates window.
161
    addButton(N_("UP"),
162
        // TRANSLATORS: long button name for updates window.
163
        _("Updates"), x, h, InputAction::WINDOW_UPDATER,
164
        Visible_false);
165
    // TRANSLATORS: short button name for bank window.
166
    addButton(N_("BA"),
167
        // TRANSLATORS: long button name for bank window.
168
        _("Bank"), x, h, InputAction::WINDOW_BANK,
169
        Visible_true);
170
    // TRANSLATORS: short button name for mail window.
171
    addButton(N_("MA"),
172
        // TRANSLATORS: long button name for mail window.
173
        _("Mail"), x, h, InputAction::WINDOW_MAIL,
174
        Visible_true);
175
    // TRANSLATORS: short button name for server info window.
176
    addButton(N_("SI"),
177
        // TRANSLATORS: long button name for server info window.
178
        _("Server info"), x, h, InputAction::WINDOW_SERVER_INFO,
179
        Visible_true);
180
    // TRANSLATORS: short button name for debug window.
181
    addButton(N_("DBG"),
182
        // TRANSLATORS: long button name for debug window.
183
        _("Debug"), x, h, InputAction::WINDOW_DEBUG,
184
#ifdef ANDROID
185
        Visible_true);
186
#else  // ANDROID
187
        Visible_false);
188
#endif  // ANDROID
189
190
    // TRANSLATORS: short button name for windows list menu.
191
    addButton(N_("WIN"),
192
        // TRANSLATORS: long button name for windows list menu.
193
        _("Windows"), x, h, InputAction::SHOW_WINDOWS,
194
        Visible_false);
195
    // TRANSLATORS: short button name for setup window.
196
    addButton(N_("SET"),
197
        // TRANSLATORS: long button name for setup window.
198
        _("Setup"), x, h, InputAction::WINDOW_SETUP);
199
200
    x += mPadding - mSpacing;
201
    if (mainGraphics != nullptr)
202
        setDimension(Rect(mainGraphics->mWidth - x, 0, x, h));
203
204
    loadButtons();
205
206
    addMouseListener(this);
207
    setVisible(Visible_true);
208
209
    config.addListener("autohideButtons", this);
210
    mAutoHide = config.getIntValue("autohideButtons");
211
}
212
213
WindowMenu::~WindowMenu()
214
{
215
    config.removeListener("autohideButtons", this);
216
    CHECKLISTENERS
217
218
    for (std::map <std::string, ButtonInfo*>::iterator
219
         it = mButtonNames.begin(),
220
         it_fend = mButtonNames.end(); it != it_fend; ++it)
221
    {
222
        delete (*it).second;
223
    }
224
    mButtonNames.clear();
225
    FOR_EACH (STD_VECTOR <Button*>::iterator, it, mButtons)
226
    {
227
        Button *const btn = *it;
228
        if (btn == nullptr)
229
            continue;
230
        if (btn->mVisible == Visible_false)
231
            delete btn;
232
    }
233
    delete_all(mButtonTexts);
234
    mButtonTexts.clear();
235
    if (mSkin != nullptr)
236
    {
237
        if (theme != nullptr)
238
            theme->unload(mSkin);
239
        mSkin = nullptr;
240
    }
241
}
242
243
void WindowMenu::action(const ActionEvent &event)
244
{
245
    const std::string &eventId = event.getId();
246
    const std::map <std::string, ButtonInfo*>::iterator
247
        it = mButtonNames.find(eventId);
248
    if (it == mButtonNames.end())
249
        return;
250
251
    const ButtonInfo *const info = (*it).second;
252
    if (info == nullptr)
253
        return;
254
255
    inputManager.executeAction(info->key);
256
}
257
258
void WindowMenu::addButton(const char *const text,
259
                           const std::string &description,
260
                           int &restrict x,
261
                           int &restrict h,
262
                           const InputActionT key,
263
                           const Visible visible)
264
{
265
    Button *const btn = new Button(this, gettext(text), text, this);
266
    btn->setPosition(x, mPadding);
267
    btn->setDescription(description);
268
    btn->setTag(CAST_S32(key));
269
    add(btn);
270
    btn->setFocusable(false);
271
    x += btn->getWidth() + mSpacing;
272
    h = btn->getHeight() + 2 * mPadding;
273
    mButtons.push_back(btn);
274
    mButtonNames[text] = new ButtonInfo(btn, key, visible);
275
    if (key != InputAction::SHOW_WINDOWS)
276
        mButtonTexts.push_back(new ButtonText(description, key));
277
}
278
279
void WindowMenu::mousePressed(MouseEvent &event)
280
{
281
    if (popupManager == nullptr)
282
        return;
283
284
    if (event.getButton() == MouseButton::RIGHT)
285
    {
286
        if (mSmallWindow)
287
            return;
288
289
        event.consume();
290
        Button *const btn = dynamic_cast<Button*>(event.getSource());
291
        if (btn == nullptr)
292
            return;
293
        if (popupMenu != nullptr)
294
        {
295
            popupMenu->showPopup(getX() + event.getX(),
296
                getY() + event.getY(), btn);
297
        }
298
    }
299
}
300
301
void WindowMenu::mouseMoved(MouseEvent &event)
302
{
303
    mHaveMouse = true;
304
305
    if (textPopup == nullptr)
306
        return;
307
308
    if (event.getSource() == this)
309
    {
310
        textPopup->hide();
311
        return;
312
    }
313
314
    const Button *const btn = dynamic_cast<const Button *>(
315
        event.getSource());
316
317
    if (btn == nullptr)
318
    {
319
        textPopup->hide();
320
        return;
321
    }
322
323
    const int x = event.getX();
324
    const int y = event.getY();
325
    const InputActionT key = static_cast<InputActionT>(btn->getTag());
326
    const Rect &rect = mDimension;
327
    if (key != InputAction::NO_VALUE)
328
    {
329
        textPopup->show(x + rect.x, y + rect.y, btn->getDescription(),
330
            // TRANSLATORS: short key name
331
            strprintf(_("Key: %s"), inputManager.getKeyValueString(
332
            key).c_str()));
333
    }
334
    else
335
    {
336
        textPopup->show(x + rect.x, y + rect.y, btn->getDescription());
337
    }
338
}
339
340
void WindowMenu::mouseExited(MouseEvent& event A_UNUSED)
341
{
342
    mHaveMouse = false;
343
    if (textPopup == nullptr)
344
        return;
345
346
    textPopup->hide();
347
}
348
349
void WindowMenu::showButton(const std::string &name,
350
                            const Visible visible)
351
{
352
    const ButtonInfo *const info = mButtonNames[name];
353
    if ((info == nullptr) || (info->button == nullptr))
354
        return;
355
356
    info->button->setVisible(visible);
357
    updateButtons();
358
    saveButtons();
359
}
360
361
void WindowMenu::updateButtons()
362
{
363
    int x = mPadding;
364
    int h = 0;
365
    FOR_EACH (STD_VECTOR <Button*>::const_iterator, it, mButtons)
366
        safeRemove(*it);
367
    const int pad2 = 2 * mPadding;
368
    FOR_EACH (STD_VECTOR <Button*>::iterator, it, mButtons)
369
    {
370
        Button *const btn = *it;
371
        if (btn == nullptr)
372
            continue;
373
        if (btn->mVisible == Visible_true)
374
        {
375
            btn->setPosition(x, mPadding);
376
            add(btn);
377
            x += btn->getWidth() + mSpacing;
378
            h = btn->getHeight() + pad2;
379
        }
380
    }
381
    x += mPadding - mSpacing;
382
    if (mainGraphics != nullptr)
383
        setDimension(Rect(mainGraphics->mWidth - x, 0, x, h));
384
}
385
386
void WindowMenu::loadButtons()
387
{
388
    if (!mSmallWindow)
389
    {
390
        if (config.getValue("windowmenu0", "").empty())
391
        {
392
            for (std::map <std::string, ButtonInfo*>::iterator
393
                 it = mButtonNames.begin(),
394
                 it_fend = mButtonNames.end(); it != it_fend; ++it)
395
            {
396
                const ButtonInfo *const info = (*it).second;
397
                if (info == nullptr ||
398
                    info->button == nullptr ||
399
                    info->visible == Visible_true)
400
                {
401
                    continue;
402
                }
403
                info->button->setVisible(Visible_false);
404
            }
405
            updateButtons();
406
            return;
407
        }
408
409
        for (int f = 0; f < 30; f ++)
410
        {
411
            const std::string str = config.getValue(
412
                "windowmenu" + toString(f), "");
413
            if (str.empty() || str == "SET")
414
                continue;
415
            const ButtonInfo *const info = mButtonNames[str];
416
            if ((info == nullptr) || (info->button == nullptr))
417
                continue;
418
            info->button->setVisible(Visible_false);
419
        }
420
    }
421
    else
422
    {
423
        for (std::map <std::string, ButtonInfo*>::iterator
424
             it = mButtonNames.begin(),
425
             it_fend = mButtonNames.end(); it != it_fend; ++it)
426
        {
427
            const ButtonInfo *const info = (*it).second;
428
            if ((info == nullptr) || (info->button == nullptr))
429
                continue;
430
            Button *const button = info->button;
431
            const std::string &str = button->getActionEventId();
432
            button->setVisible(fromBool(
433
                str == "SET" || str == "WIN", Visible));
434
        }
435
    }
436
    updateButtons();
437
}
438
439
void WindowMenu::saveButtons() const
440
{
441
    int i = 0;
442
    FOR_EACH (STD_VECTOR <Button*>::const_iterator, it, mButtons)
443
    {
444
        const Button *const btn = *it;
445
        if ((btn != nullptr) && btn->mVisible == Visible_false)
446
        {
447
            config.setValue("windowmenu" + toString(i),
448
                btn->getActionEventId());
449
            i ++;
450
        }
451
    }
452
    for (int f = i; f < 30; f ++)
453
        config.deleteKey("windowmenu" + toString(f));
454
}
455
456
void WindowMenu::drawChildren(Graphics *const graphics)
457
{
458
    if (mHaveMouse ||
459
        mAutoHide == 0 ||
460
        (mAutoHide == 1 &&
461
        mainGraphics != nullptr &&
462
        (mSmallWindow || mainGraphics->mWidth > 800)))
463
    {
464
        Container::drawChildren(graphics);
465
    }
466
}
467
468
void WindowMenu::safeDrawChildren(Graphics *const graphics)
469
{
470
    if (mHaveMouse ||
471
        mAutoHide == 0 ||
472
        (mAutoHide == 1 &&
473
        mainGraphics != nullptr &&
474
        (mSmallWindow || mainGraphics->mWidth > 800)))
475
    {
476
        Container::safeDrawChildren(graphics);
477
    }
478
}
479
480
void WindowMenu::optionChanged(const std::string &name)
481
{
482
    if (name == "autohideButtons")
483
        mAutoHide = config.getIntValue("autohideButtons");
484

6
}
485
486
#ifdef USE_PROFILER
487
void WindowMenu::logicChildren()
488
{
489
    BLOCK_START("WindowMenu::logicChildren")
490
    BasicContainer::logicChildren();
491
    BLOCK_END("WindowMenu::logicChildren")
492
}
493
#endif  // USE_PROFILER