GCC Code Coverage Report
Directory: src/ Exec Total Coverage
File: src/gui/windowmenu.cpp Lines: 1 272 0.4 %
Date: 2018-07-14 Branches: 2 360 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-2018  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
#include "settings.h"
27
28
#include "input/inputmanager.h"
29
30
#include "gui/buttoninfo.h"
31
#include "gui/buttontext.h"
32
#include "gui/popupmanager.h"
33
#include "gui/skin.h"
34
35
#include "gui/popups/popupmenu.h"
36
#include "gui/popups/textpopup.h"
37
38
#include "gui/windows/skilldialog.h"
39
40
#include "gui/widgets/button.h"
41
42
#include "utils/dtor.h"
43
#include "utils/foreach.h"
44
#include "utils/gettext.h"
45
46
#include "resources/imageset.h"
47
48
#include "debug.h"
49
50
WindowMenu *windowMenu = nullptr;
51
52
WindowMenu::WindowMenu(const Widget2 *const widget) :
53
    Container(widget),
54
    ConfigListener(),
55
    ActionListener(),
56
    SelectionListener(),
57
    MouseListener(),
58
    mSkin(theme != nullptr ? theme->load("windowmenu.xml", "",
59
        true, Theme::getThemePath()) : nullptr),
60
    mImageSet(nullptr),
61
    mPadding(mSkin != nullptr ? mSkin->getPadding() : 1),
62
    mSpacing(mSkin != nullptr ? mSkin->getOption("spacing", 3) : 3),
63
    mButtons(),
64
    mButtonTexts(),
65
    mButtonNames(),
66
    mHaveMouse(false),
67
    mAutoHide(1),
68
    mSmallWindow(mainGraphics->getWidth() < 600)
69
{
70
    int x = mPadding;
71
    int h = 0;
72
73
    setFocusable(false);
74
75
    if (settings.showButtonIcons)
76
    {
77
        mImageSet = Theme::getImageSetFromTheme("buttonsicons.png",
78
            mSkin->getOption("imageWidth", 20),
79
            mSkin->getOption("imageHeight", 20));
80
    }
81
82
    // TRANSLATORS: short button name for who is online window.
83
    addButton(N_("ONL"),
84
        13,
85
        // TRANSLATORS: long button name for who is online window.
86
        _("Who is online"), x, h, InputAction::WINDOW_ONLINE,
87
        Visible_true);
88
    // TRANSLATORS: short button name for help window.
89
    addButton(N_("HLP"),
90
        0,
91
        // TRANSLATORS: long button name for help window.
92
        _("Help"), x, h, InputAction::WINDOW_HELP,
93
        Visible_true);
94
    // TRANSLATORS: short button name for quests window.
95
    addButton(N_("QE"),
96
        12,
97
        // TRANSLATORS: long button name for quests window.
98
        _("Quests"), x, h, InputAction::WINDOW_QUESTS,
99
        Visible_true);
100
    // TRANSLATORS: short button name for kill stats window.
101
    addButton(N_("KS"),
102
        16,
103
        // TRANSLATORS: long button name for kill stats window.
104
        _("Kill stats"), x, h, InputAction::WINDOW_KILLS,
105
        Visible_true);
106
    addButton(":-)",
107
        6,
108
        // TRANSLATORS: long button name for emotes window.
109
        _("Smilies"), x, h, InputAction::WINDOW_EMOTE_SHORTCUT,
110
        Visible_true);
111
    // TRANSLATORS: short button name for chat window.
112
    addButton(N_("CH"),
113
        20,
114
        // TRANSLATORS: longt button name for chat window.
115
        _("Chat"), x, h, InputAction::WINDOW_CHAT,
116
#ifdef ANDROID
117
        Visible_true);
118
#else  // ANDROID
119
        Visible_false);
120
#endif  // ANDROID
121
122
    // TRANSLATORS: short button name for status window.
123
    addButton(N_("STA"),
124
        17,
125
        // TRANSLATORS: long button name for status window.
126
        _("Status"), x, h, InputAction::WINDOW_STATUS,
127
        Visible_true);
128
    // TRANSLATORS: short button name for equipment window.
129
    addButton(N_("EQU"),
130
        7,
131
        // TRANSLATORS: long button name for equipment window.
132
        _("Equipment"), x, h, InputAction::WINDOW_EQUIPMENT,
133
        Visible_true);
134
    // TRANSLATORS: short button name for inventory window.
135
    addButton(N_("INV"),
136
        9,
137
        // TRANSLATORS: long button name for inventory window.
138
        _("Inventory"), x, h, InputAction::WINDOW_INVENTORY,
139
        Visible_true);
140
    // TRANSLATORS: short button name for cart window.
141
    addButton(N_("CA"),
142
        11,
143
        // TRANSLATORS: long button name for cart window.
144
        _("Cart"), x, h, InputAction::WINDOW_CART,
145
        Visible_true);
146
    // TRANSLATORS: short button name for map window.
147
    addButton(N_("MAP"),
148
        19,
149
        // TRANSLATORS: long button name for map window.
150
        _("Map"), x, h, InputAction::WINDOW_MINIMAP,
151
        Visible_false);
152
153
    if (skillDialog->hasSkills())
154
    {
155
        // TRANSLATORS: short button name for skills window.
156
        addButton(N_("SKI"),
157
            5,
158
            // TRANSLATORS: long button name for skills window.
159
            _("Skills"), x, h, InputAction::WINDOW_SKILL,
160
        Visible_true);
161
    }
162
163
    // TRANSLATORS: short button name for social window.
164
    addButton(N_("SOC"),
165
        1,
166
        // TRANSLATORS: long button name for social window.
167
        _("Social"), x, h, InputAction::WINDOW_SOCIAL,
168
        Visible_true);
169
    // TRANSLATORS: short button name for shortcuts window.
170
    addButton(N_("SH"),
171
        14,
172
        // TRANSLATORS: long button name for shortcuts window.
173
        _("Shortcuts"), x, h, InputAction::WINDOW_SHORTCUT,
174
        Visible_true);
175
    // TRANSLATORS: short button name for spells window.
176
    addButton(N_("SP"),
177
        15,
178
        // TRANSLATORS: long button name for spells window.
179
        _("Spells"), x, h, InputAction::WINDOW_SPELLS,
180
        Visible_true);
181
    // TRANSLATORS: short button name for drops window.
182
    addButton(N_("DR"),
183
        26,
184
        // TRANSLATORS: long button name for drops window.
185
        _("Drop"), x, h, InputAction::WINDOW_DROP,
186
        Visible_false);
187
    // TRANSLATORS: short button name for did you know window.
188
    addButton(N_("YK"),
189
        24,
190
        // TRANSLATORS: long button name for did you know window.
191
        _("Did you know"), x, h, InputAction::WINDOW_DIDYOUKNOW,
192
        Visible_false);
193
    // TRANSLATORS: short button name for shop window.
194
    addButton(N_("SHP"),
195
        18,
196
        // TRANSLATORS: long button name for shop window.
197
        _("Shop"), x, h, InputAction::WINDOW_SHOP,
198
        Visible_false);
199
    // TRANSLATORS: short button name for outfits window.
200
    addButton(N_("OU"),
201
        21,
202
        // TRANSLATORS: long button name for outfits window.
203
        _("Outfits"), x, h, InputAction::WINDOW_OUTFIT,
204
        Visible_false);
205
    // TRANSLATORS: short button name for updates window.
206
    addButton(N_("UP"),
207
        25,
208
        // TRANSLATORS: long button name for updates window.
209
        _("Updates"), x, h, InputAction::WINDOW_UPDATER,
210
        Visible_false);
211
    // TRANSLATORS: short button name for bank window.
212
    addButton(N_("BA"),
213
        2,
214
        // TRANSLATORS: long button name for bank window.
215
        _("Bank"), x, h, InputAction::WINDOW_BANK,
216
        Visible_true);
217
    // TRANSLATORS: short button name for mail window.
218
    addButton(N_("MA"),
219
        10,
220
        // TRANSLATORS: long button name for mail window.
221
        _("Mail"), x, h, InputAction::WINDOW_MAIL,
222
        Visible_true);
223
    // TRANSLATORS: short button name for clan window.
224
    addButton(N_("CL"),
225
        4,
226
        // TRANSLATORS: long button name for clan window.
227
        _("Clan"), x, h, InputAction::WINDOW_CLAN,
228
        Visible_true);
229
    // TRANSLATORS: short button name for server info window.
230
    addButton(N_("SI"),
231
        8,
232
        // TRANSLATORS: long button name for server info window.
233
        _("Server info"), x, h, InputAction::WINDOW_SERVER_INFO,
234
        Visible_true);
235
    // TRANSLATORS: short button name for debug window.
236
    addButton(N_("DBG"),
237
        22,
238
        // TRANSLATORS: long button name for debug window.
239
        _("Debug"), x, h, InputAction::WINDOW_DEBUG,
240
#ifdef ANDROID
241
        Visible_true);
242
#else  // ANDROID
243
        Visible_false);
244
#endif  // ANDROID
245
246
    // TRANSLATORS: short button name for windows list menu.
247
    addButton(N_("WIN"),
248
        23,
249
        // TRANSLATORS: long button name for windows list menu.
250
        _("Windows"), x, h, InputAction::SHOW_WINDOWS,
251
        Visible_false);
252
    // TRANSLATORS: short button name for setup window.
253
    addButton(N_("SET"),
254
        3,
255
        // TRANSLATORS: long button name for setup window.
256
        _("Setup"), x, h, InputAction::WINDOW_SETUP,
257
        Visible_true);
258
259
    x += mPadding - mSpacing;
260
    if (mainGraphics != nullptr)
261
        setDimension(Rect(mainGraphics->mWidth - x, 0, x, h));
262
263
    loadButtons();
264
265
    addMouseListener(this);
266
    setVisible(Visible_true);
267
268
    config.addListener("autohideButtons", this);
269
    mAutoHide = config.getIntValue("autohideButtons");
270
}
271
272
WindowMenu::~WindowMenu()
273
{
274
    config.removeListener("autohideButtons", this);
275
    CHECKLISTENERS
276
277
    for (std::map <std::string, ButtonInfo*>::iterator
278
         it = mButtonNames.begin(),
279
         it_fend = mButtonNames.end(); it != it_fend; ++it)
280
    {
281
        delete (*it).second;
282
    }
283
    mButtonNames.clear();
284
    FOR_EACH (STD_VECTOR <Button*>::iterator, it, mButtons)
285
    {
286
        Button *const btn = *it;
287
        if (btn == nullptr)
288
            continue;
289
        if (btn->mVisible == Visible_false)
290
            delete btn;
291
    }
292
    delete_all(mButtonTexts);
293
    mButtonTexts.clear();
294
    if (mImageSet != nullptr)
295
    {
296
        mImageSet->decRef();
297
        mImageSet = nullptr;
298
    }
299
    if (mSkin != nullptr)
300
    {
301
        if (theme != nullptr)
302
            theme->unload(mSkin);
303
        mSkin = nullptr;
304
    }
305
}
306
307
void WindowMenu::action(const ActionEvent &event)
308
{
309
    const std::string &eventId = event.getId();
310
    const std::map <std::string, ButtonInfo*>::iterator
311
        it = mButtonNames.find(eventId);
312
    if (it == mButtonNames.end())
313
        return;
314
315
    const ButtonInfo *const info = (*it).second;
316
    if (info == nullptr)
317
        return;
318
319
    inputManager.executeAction(info->key);
320
}
321
322
void WindowMenu::addButton(const char *const text,
323
                           const int iconNumber,
324
                           const std::string &description,
325
                           int &restrict x,
326
                           int &restrict h,
327
                           const InputActionT key,
328
                           const Visible visible)
329
{
330
    Button *btn = nullptr;
331
    if (settings.showButtonIcons &&
332
        mImageSet)
333
    {
334
        Image *const image = mImageSet->get(iconNumber);
335
        if (image != nullptr)
336
        {
337
/*
338
            btn = new Button(this,
339
                "buttonsicons.png",
340
                20,
341
                20,
342
                text,
343
                BUTTON_SKIN,
344
                this);
345
*/
346
            btn = new Button(this,
347
                std::string(),
348
                text,
349
                BUTTON_SKIN,
350
                this);
351
            btn->setImage(image);
352
            btn->adjustSize();
353
        }
354
    }
355
    if (btn == nullptr)
356
    {
357
        btn = new Button(this,
358
            gettext(text),
359
            text,
360
            BUTTON_SKIN,
361
            this);
362
    }
363
    btn->setPosition(x, mPadding);
364
    btn->setDescription(description);
365
    btn->setTag(CAST_S32(key));
366
    add(btn);
367
    btn->setFocusable(false);
368
    x += btn->getWidth() + mSpacing;
369
    h = btn->getHeight() + 2 * mPadding;
370
    mButtons.push_back(btn);
371
    mButtonNames[text] = new ButtonInfo(btn, key, visible);
372
    if (key != InputAction::SHOW_WINDOWS)
373
        mButtonTexts.push_back(new ButtonText(description, key));
374
}
375
376
void WindowMenu::mousePressed(MouseEvent &event)
377
{
378
    if (popupManager == nullptr)
379
        return;
380
381
    if (event.getButton() == MouseButton::RIGHT)
382
    {
383
        if (mSmallWindow)
384
            return;
385
386
        event.consume();
387
        Button *const btn = dynamic_cast<Button*>(event.getSource());
388
        if (btn == nullptr)
389
            return;
390
        if (popupMenu != nullptr)
391
        {
392
            popupMenu->showPopup(getX() + event.getX(),
393
                getY() + event.getY(), btn);
394
        }
395
    }
396
}
397
398
void WindowMenu::mouseMoved(MouseEvent &event)
399
{
400
    mHaveMouse = true;
401
402
    if (textPopup == nullptr)
403
        return;
404
405
    if (event.getSource() == this)
406
    {
407
        textPopup->hide();
408
        return;
409
    }
410
411
    const Button *const btn = dynamic_cast<const Button *>(
412
        event.getSource());
413
414
    if (btn == nullptr)
415
    {
416
        textPopup->hide();
417
        return;
418
    }
419
420
    const int x = event.getX();
421
    const int y = event.getY();
422
    const InputActionT key = static_cast<InputActionT>(btn->getTag());
423
    const Rect &rect = mDimension;
424
    if (key != InputAction::NO_VALUE)
425
    {
426
        textPopup->show(x + rect.x, y + rect.y, btn->getDescription(),
427
            // TRANSLATORS: short key name
428
            strprintf(_("Key: %s"), inputManager.getKeyValueString(
429
            key).c_str()));
430
    }
431
    else
432
    {
433
        textPopup->show(x + rect.x, y + rect.y, btn->getDescription());
434
    }
435
}
436
437
void WindowMenu::mouseExited(MouseEvent& event A_UNUSED)
438
{
439
    mHaveMouse = false;
440
    if (textPopup == nullptr)
441
        return;
442
443
    textPopup->hide();
444
}
445
446
void WindowMenu::showButton(const std::string &name,
447
                            const Visible visible)
448
{
449
    const ButtonInfo *const info = mButtonNames[name];
450
    if ((info == nullptr) || (info->button == nullptr))
451
        return;
452
453
    info->button->setVisible(visible);
454
    updateButtons();
455
    saveButtons();
456
}
457
458
void WindowMenu::updateButtons()
459
{
460
    int x = mPadding;
461
    int h = 0;
462
    FOR_EACH (STD_VECTOR <Button*>::const_iterator, it, mButtons)
463
        safeRemove(*it);
464
    const int pad2 = 2 * mPadding;
465
    FOR_EACH (STD_VECTOR <Button*>::iterator, it, mButtons)
466
    {
467
        Button *const btn = *it;
468
        if (btn == nullptr)
469
            continue;
470
        if (btn->mVisible == Visible_true)
471
        {
472
            btn->setPosition(x, mPadding);
473
            add(btn);
474
            x += btn->getWidth() + mSpacing;
475
            h = btn->getHeight() + pad2;
476
        }
477
    }
478
    x += mPadding - mSpacing;
479
    if (mainGraphics != nullptr)
480
        setDimension(Rect(mainGraphics->mWidth - x, 0, x, h));
481
}
482
483
void WindowMenu::loadButtons()
484
{
485
    if (!mSmallWindow)
486
    {
487
        if (config.getValue("windowmenu0", "").empty())
488
        {
489
            for (std::map <std::string, ButtonInfo*>::iterator
490
                 it = mButtonNames.begin(),
491
                 it_fend = mButtonNames.end(); it != it_fend; ++it)
492
            {
493
                const ButtonInfo *const info = (*it).second;
494
                if (info == nullptr ||
495
                    info->button == nullptr ||
496
                    info->visible == Visible_true)
497
                {
498
                    continue;
499
                }
500
                info->button->setVisible(Visible_false);
501
            }
502
            updateButtons();
503
            return;
504
        }
505
506
        for (int f = 0; f < 30; f ++)
507
        {
508
            const std::string str = config.getValue(
509
                "windowmenu" + toString(f), "");
510
            if (str.empty() || str == "SET")
511
                continue;
512
            const ButtonInfo *const info = mButtonNames[str];
513
            if ((info == nullptr) || (info->button == nullptr))
514
                continue;
515
            info->button->setVisible(Visible_false);
516
        }
517
    }
518
    else
519
    {
520
        for (std::map <std::string, ButtonInfo*>::iterator
521
             it = mButtonNames.begin(),
522
             it_fend = mButtonNames.end(); it != it_fend; ++it)
523
        {
524
            const ButtonInfo *const info = (*it).second;
525
            if ((info == nullptr) || (info->button == nullptr))
526
                continue;
527
            Button *const button = info->button;
528
            const std::string &str = button->getActionEventId();
529
            button->setVisible(fromBool(
530
                str == "SET" || str == "WIN", Visible));
531
        }
532
    }
533
    updateButtons();
534
}
535
536
void WindowMenu::saveButtons() const
537
{
538
    int i = 0;
539
    FOR_EACH (STD_VECTOR <Button*>::const_iterator, it, mButtons)
540
    {
541
        const Button *const btn = *it;
542
        if ((btn != nullptr) && btn->mVisible == Visible_false)
543
        {
544
            config.setValue("windowmenu" + toString(i),
545
                btn->getActionEventId());
546
            i ++;
547
        }
548
    }
549
    for (int f = i; f < 30; f ++)
550
        config.deleteKey("windowmenu" + toString(f));
551
}
552
553
void WindowMenu::drawChildren(Graphics *const graphics)
554
{
555
    if (mHaveMouse ||
556
        mAutoHide == 0 ||
557
        (mAutoHide == 1 &&
558
        mainGraphics != nullptr &&
559
        (mSmallWindow || mainGraphics->mWidth > 800)))
560
    {
561
        Container::drawChildren(graphics);
562
    }
563
}
564
565
void WindowMenu::safeDrawChildren(Graphics *const graphics)
566
{
567
    if (mHaveMouse ||
568
        mAutoHide == 0 ||
569
        (mAutoHide == 1 &&
570
        mainGraphics != nullptr &&
571
        (mSmallWindow || mainGraphics->mWidth > 800)))
572
    {
573
        Container::safeDrawChildren(graphics);
574
    }
575
}
576
577
void WindowMenu::optionChanged(const std::string &name)
578
{
579
    if (name == "autohideButtons")
580
        mAutoHide = config.getIntValue("autohideButtons");
581

3
}
582
583
#ifdef USE_PROFILER
584
void WindowMenu::logicChildren()
585
{
586
    BLOCK_START("WindowMenu::logicChildren")
587
    BasicContainer::logicChildren();
588
    BLOCK_END("WindowMenu::logicChildren")
589
}
590
#endif  // USE_PROFILER