GCC Code Coverage Report
Directory: src/ Exec Total Coverage
File: src/gui/widgets/itemshortcutcontainer.cpp Lines: 1 306 0.3 %
Date: 2018-07-14 Branches: 0 292 0.0 %

Line Branch Exec Source
1
/*
2
 *  The ManaPlus Client
3
 *  Copyright (C) 2007-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/widgets/itemshortcutcontainer.h"
24
25
#include "dragdrop.h"
26
#include "settings.h"
27
#include "spellmanager.h"
28
29
#include "being/playerinfo.h"
30
31
#include "input/inputmanager.h"
32
33
#include "gui/skin.h"
34
#include "gui/viewport.h"
35
36
#include "gui/fonts/font.h"
37
38
#include "gui/shortcut/itemshortcut.h"
39
#include "gui/shortcut/spellshortcut.h"
40
41
#include "gui/popups/itempopup.h"
42
#include "gui/popups/popupmenu.h"
43
#include "gui/popups/skillpopup.h"
44
#include "gui/popups/spellpopup.h"
45
46
#include "gui/windows/inventorywindow.h"
47
#include "gui/windows/skilldialog.h"
48
49
#include "input/inputactionoperators.h"
50
51
#include "const/resources/skill.h"
52
53
#include "utils/stringutils.h"
54
55
#include "debug.h"
56
57
ItemShortcutContainer::ItemShortcutContainer(Widget2 *const widget,
58
                                             const unsigned number) :
59
    ShortcutContainer(widget),
60
    mEquipedColor(getThemeColor(ThemeColorId::ITEM_EQUIPPED, 255U)),
61
    mEquipedColor2(getThemeColor(ThemeColorId::ITEM_EQUIPPED_OUTLINE, 255U)),
62
    mUnEquipedColor(getThemeColor(ThemeColorId::ITEM_NOT_EQUIPPED, 255U)),
63
    mUnEquipedColor2(getThemeColor(ThemeColorId::ITEM_NOT_EQUIPPED_OUTLINE,
64
        255U)),
65
    mNumber(number),
66
    mKeyOffsetX(2),
67
    mKeyOffsetY(2),
68
    mItemClicked(false)
69
{
70
    mMaxItems = ItemShortcut::getItemCount();
71
}
72
73
ItemShortcutContainer::~ItemShortcutContainer()
74
{
75
}
76
77
void ItemShortcutContainer::setSkin(const Widget2 *const widget,
78
                                    Skin *const skin)
79
{
80
    ShortcutContainer::setSkin(widget, skin);
81
    mEquipedColor = getThemeColor(ThemeColorId::ITEM_EQUIPPED, 255U);
82
    mEquipedColor2 = getThemeColor(ThemeColorId::ITEM_EQUIPPED_OUTLINE, 255U);
83
    mUnEquipedColor = getThemeColor(ThemeColorId::ITEM_NOT_EQUIPPED, 255U);
84
    mUnEquipedColor2 = getThemeColor(ThemeColorId::ITEM_NOT_EQUIPPED_OUTLINE,
85
        255U);
86
    mForegroundColor = getThemeColor(ThemeColorId::TEXT, 255U);
87
    mForegroundColor2 = getThemeColor(ThemeColorId::TEXT_OUTLINE, 255U);
88
    if (mSkin != nullptr)
89
    {
90
        mKeyOffsetX = mSkin->getOption("keyOffsetX", 2);
91
        mKeyOffsetY = mSkin->getOption("keyOffsetY", 2);
92
    }
93
}
94
95
void ItemShortcutContainer::draw(Graphics *const graphics)
96
{
97
    BLOCK_START("ItemShortcutContainer::draw")
98
    const ItemShortcut *const selShortcut = itemShortcut[mNumber];
99
    if (selShortcut == nullptr)
100
    {
101
        BLOCK_END("ItemShortcutContainer::draw")
102
        return;
103
    }
104
105
    if (settings.guiAlpha != mAlpha)
106
    {
107
        if (mBackgroundImg != nullptr)
108
            mBackgroundImg->setAlpha(mAlpha);
109
        mAlpha = settings.guiAlpha;
110
    }
111
112
    Font *const font = getFont();
113
    drawBackground(graphics);
114
115
    const Inventory *const inv = PlayerInfo::getInventory();
116
    if (inv == nullptr)
117
    {
118
        BLOCK_END("ItemShortcutContainer::draw")
119
        return;
120
    }
121
122
    // +++ for future usage need reorder drawing images before text or back
123
    for (unsigned i = 0; i < mMaxItems; i++)
124
    {
125
        const int itemX = (i % mGridWidth) * mBoxWidth;
126
        const int itemY = (i / mGridWidth) * mBoxHeight;
127
128
        // Draw item keyboard shortcut.
129
        const std::string key = inputManager.getKeyValueString(
130
            InputAction::SHORTCUT_1 + i);
131
        font->drawString(graphics,
132
            mForegroundColor,
133
            mForegroundColor,
134
            key,
135
            itemX + mKeyOffsetX,
136
            itemY + mKeyOffsetY);
137
138
        const int itemId = selShortcut->getItem(i);
139
        const ItemColor itemColor = selShortcut->getItemColor(i);
140
141
        if (itemId < 0)
142
            continue;
143
144
        // this is item
145
        if (itemId < SPELL_MIN_ID)
146
        {
147
            const Item *const item = inv->findItem(itemId, itemColor);
148
            if (item != nullptr)
149
            {
150
                // Draw item icon.
151
                Image *const image = item->getImage();
152
                if (image != nullptr)
153
                {
154
                    std::string caption;
155
                    if (item->getQuantity() > 1)
156
                        caption = toString(item->getQuantity());
157
                    else if (item->isEquipped() == Equipped_true)
158
                        caption = "Eq.";
159
160
                    image->setAlpha(1.0F);
161
                    graphics->drawImage(image,
162
                        itemX + mImageOffsetX,
163
                        itemY + mImageOffsetY);
164
                    if (item->isEquipped() == Equipped_true)
165
                    {
166
                        font->drawString(graphics,
167
                            mEquipedColor,
168
                            mEquipedColor2,
169
                            caption,
170
                            itemX + (mBoxWidth - font->getWidth(caption)) / 2,
171
                            itemY + mBoxHeight - 14);
172
                    }
173
                    else
174
                    {
175
                        font->drawString(graphics,
176
                            mUnEquipedColor,
177
                            mUnEquipedColor2,
178
                            caption,
179
                            itemX + (mBoxWidth - font->getWidth(caption)) / 2,
180
                            itemY + mBoxHeight - 14);
181
                    }
182
                }
183
            }
184
        }
185
        else if (itemId < SKILL_MIN_ID && (spellManager != nullptr))
186
        {   // this is magic shortcut
187
            const TextCommand *const spell = spellManager
188
                ->getSpellByItem(itemId);
189
            if (spell != nullptr)
190
            {
191
                if (!spell->isEmpty())
192
                {
193
                    Image *const image = spell->getImage();
194
195
                    if (image != nullptr)
196
                    {
197
                        image->setAlpha(1.0F);
198
                        graphics->drawImage(image,
199
                            itemX + mImageOffsetX,
200
                            itemY + mImageOffsetY);
201
                    }
202
                }
203
204
                font->drawString(graphics,
205
                    mForegroundColor,
206
                    mForegroundColor,
207
                    spell->getSymbol(),
208
                    itemX + mTextOffsetX,
209
                    itemY + mTextOffsetY);
210
            }
211
        }
212
        else if (skillDialog != nullptr)
213
        {
214
            const SkillInfo *const skill = skillDialog->getSkill(
215
                itemId - SKILL_MIN_ID);
216
            if (skill != nullptr)
217
            {
218
                Image *const image = skill->data->icon;
219
220
                if (image != nullptr)
221
                {
222
                    image->setAlpha(1.0F);
223
                    graphics->drawImage(image,
224
                        itemX + mImageOffsetX,
225
                        itemY + mImageOffsetY);
226
                }
227
                if (!skill->data->haveIcon)
228
                {
229
                    font->drawString(graphics,
230
                        mForegroundColor,
231
                        mForegroundColor,
232
                        skill->data->shortName,
233
                        itemX + mTextOffsetX,
234
                        itemY + mTextOffsetY);
235
                }
236
            }
237
        }
238
    }
239
    BLOCK_END("ItemShortcutContainer::draw")
240
}
241
242
void ItemShortcutContainer::safeDraw(Graphics *const graphics)
243
{
244
    BLOCK_START("ItemShortcutContainer::draw")
245
    const ItemShortcut *const selShortcut = itemShortcut[mNumber];
246
    if (selShortcut == nullptr)
247
    {
248
        BLOCK_END("ItemShortcutContainer::draw")
249
        return;
250
    }
251
252
    if (settings.guiAlpha != mAlpha)
253
    {
254
        if (mBackgroundImg != nullptr)
255
            mBackgroundImg->setAlpha(mAlpha);
256
        mAlpha = settings.guiAlpha;
257
    }
258
259
    Font *const font = getFont();
260
    safeDrawBackground(graphics);
261
262
    const Inventory *const inv = PlayerInfo::getInventory();
263
    if (inv == nullptr)
264
    {
265
        BLOCK_END("ItemShortcutContainer::draw")
266
        return;
267
    }
268
269
    // +++ for future usage need reorder drawing images before text or back
270
    for (unsigned i = 0; i < mMaxItems; i++)
271
    {
272
        const int itemX = (i % mGridWidth) * mBoxWidth;
273
        const int itemY = (i / mGridWidth) * mBoxHeight;
274
275
        // Draw item keyboard shortcut.
276
        const std::string key = inputManager.getKeyValueString(
277
            InputAction::SHORTCUT_1 + i);
278
        font->drawString(graphics,
279
            mForegroundColor,
280
            mForegroundColor,
281
            key,
282
            itemX + mKeyOffsetX,
283
            itemY + mKeyOffsetY);
284
285
        const int itemId = selShortcut->getItem(i);
286
        const ItemColor itemColor = selShortcut->getItemColor(i);
287
288
        if (itemId < 0)
289
            continue;
290
291
        // this is item
292
        if (itemId < SPELL_MIN_ID)
293
        {
294
            const Item *const item = inv->findItem(itemId, itemColor);
295
            if (item != nullptr)
296
            {
297
                // Draw item icon.
298
                Image *const image = item->getImage();
299
                if (image != nullptr)
300
                {
301
                    std::string caption;
302
                    if (item->getQuantity() > 1)
303
                        caption = toString(item->getQuantity());
304
                    else if (item->isEquipped() == Equipped_true)
305
                        caption = "Eq.";
306
307
                    image->setAlpha(1.0F);
308
                    graphics->drawImage(image,
309
                        itemX + mImageOffsetX,
310
                        itemY + mImageOffsetY);
311
                    if (item->isEquipped() == Equipped_true)
312
                    {
313
                        font->drawString(graphics,
314
                            mEquipedColor,
315
                            mEquipedColor2,
316
                            caption,
317
                            itemX + (mBoxWidth - font->getWidth(caption)) / 2,
318
                            itemY + mBoxHeight - 14);
319
                    }
320
                    else
321
                    {
322
                        font->drawString(graphics,
323
                            mUnEquipedColor,
324
                            mUnEquipedColor2,
325
                            caption,
326
                            itemX + (mBoxWidth - font->getWidth(caption)) / 2,
327
                            itemY + mBoxHeight - 14);
328
                    }
329
                }
330
            }
331
        }
332
        else if (itemId < SKILL_MIN_ID && (spellManager != nullptr))
333
        {   // this is magic shortcut
334
            const TextCommand *const spell = spellManager
335
                ->getSpellByItem(itemId);
336
            if (spell != nullptr)
337
            {
338
                if (!spell->isEmpty())
339
                {
340
                    Image *const image = spell->getImage();
341
342
                    if (image != nullptr)
343
                    {
344
                        image->setAlpha(1.0F);
345
                        graphics->drawImage(image,
346
                            itemX + mImageOffsetX,
347
                            itemY + mImageOffsetY);
348
                    }
349
                }
350
351
                font->drawString(graphics,
352
                    mForegroundColor,
353
                    mForegroundColor,
354
                    spell->getSymbol(),
355
                    itemX + mTextOffsetX,
356
                    itemY + mTextOffsetY);
357
            }
358
        }
359
        else if (skillDialog != nullptr)
360
        {
361
            const SkillInfo *const skill = skillDialog->getSkill(
362
                itemId - SKILL_MIN_ID);
363
            if (skill != nullptr)
364
            {
365
                Image *const image = skill->data->icon;
366
367
                if (image != nullptr)
368
                {
369
                    image->setAlpha(1.0F);
370
                    graphics->drawImage(image,
371
                        itemX + mImageOffsetX,
372
                        itemY + mImageOffsetY);
373
                }
374
                if (!skill->data->haveIcon)
375
                {
376
                    font->drawString(graphics,
377
                        mForegroundColor,
378
                        mForegroundColor,
379
                        skill->data->shortName,
380
                        itemX + mTextOffsetX,
381
                        itemY + mTextOffsetY);
382
                }
383
            }
384
        }
385
    }
386
    BLOCK_END("ItemShortcutContainer::draw")
387
}
388
389
void ItemShortcutContainer::mouseDragged(MouseEvent &event)
390
{
391
    if (mNumber == SHORTCUT_AUTO_TAB)
392
        return;
393
    ItemShortcut *const selShortcut = itemShortcut[mNumber];
394
    if (selShortcut == nullptr)
395
        return;
396
397
    if (event.getButton() == MouseButton::LEFT)
398
    {
399
        if (dragDrop.isEmpty() && mItemClicked)
400
        {
401
            mItemClicked = false;
402
403
            const int index = getIndexFromGrid(event.getX(), event.getY());
404
            if (index == -1)
405
                return;
406
407
            const int itemId = selShortcut->getItem(index);
408
            const ItemColor itemColor = selShortcut->getItemColor(index);
409
410
            if (itemId < 0)
411
                return;
412
413
            event.consume();
414
            if (itemId < SPELL_MIN_ID)
415
            {   // items
416
                if (PlayerInfo::getInventory() == nullptr)
417
                    return;
418
419
                const Item *const item = PlayerInfo::getInventory()->findItem(
420
                    itemId, itemColor);
421
422
                if (item != nullptr)
423
                {
424
                    selShortcut->removeItem(index);
425
                    dragDrop.dragItem(item, DragDropSource::Shortcuts, index);
426
                }
427
                else
428
                {
429
                    dragDrop.clear();
430
                }
431
            }
432
            else if (itemId < SKILL_MIN_ID)
433
            {   // spells/commands
434
                if (spellManager == nullptr)
435
                {
436
                    dragDrop.clear();
437
                    return;
438
                }
439
440
                const TextCommand *const spell = spellManager->getSpellByItem(
441
                    itemId);
442
                if (spell != nullptr)
443
                {
444
                    selShortcut->removeItem(index);
445
                    dragDrop.dragCommand(spell,
446
                        DragDropSource::Shortcuts, index);
447
                    dragDrop.setItem(itemId);
448
                }
449
                else
450
                {
451
                    dragDrop.clear();
452
                }
453
            }
454
            else
455
            {   // skills
456
                if (skillDialog == nullptr)
457
                {
458
                    dragDrop.clear();
459
                    return;
460
                }
461
                const SkillInfo *const skill
462
                    = skillDialog->getSkillByItem(itemId);
463
                if (skill != nullptr)
464
                {
465
                    const std::string itemData = selShortcut->getItemData(
466
                        index);
467
                    selShortcut->removeItem(index);
468
                    dragDrop.dragSkill(skill,
469
                        DragDropSource::Shortcuts,
470
                        index);
471
                    dragDrop.setItem(itemId);
472
                    dragDrop.setItemColor(itemColor);
473
                    dragDrop.setItemData(itemData);
474
                }
475
                else
476
                {
477
                    dragDrop.clear();
478
                }
479
            }
480
        }
481
    }
482
}
483
484
void ItemShortcutContainer::mousePressed(MouseEvent &event)
485
{
486
    ItemShortcut *const selShortcut = itemShortcut[mNumber];
487
    if (selShortcut == nullptr)
488
        return;
489
490
    const int index = getIndexFromGrid(event.getX(), event.getY());
491
492
    if (index == -1)
493
        return;
494
495
    if (event.getButton() == MouseButton::LEFT)
496
    {
497
        event.consume();
498
        // Stores the selected item if theirs one.
499
        if (selShortcut->isItemSelected() && (inventoryWindow != nullptr) &&
500
            (inventoryWindow->isWindowVisible()
501
            || selShortcut->getSelectedItem() >= SPELL_MIN_ID))
502
        {
503
            selShortcut->setItem(index);
504
            selShortcut->setItemSelected(-1);
505
            if (spellShortcut != nullptr)
506
                spellShortcut->setItemSelected(-1);
507
            inventoryWindow->unselectItem();
508
        }
509
        else if (selShortcut->getItem(index) != 0)
510
        {
511
            mItemClicked = true;
512
        }
513
    }
514
    else if (event.getButton() == MouseButton::RIGHT)
515
    {
516
        event.consume();
517
        if (popupMenu != nullptr &&
518
            viewport != nullptr)
519
        {
520
            popupMenu->showItemPopup(viewport->mMouseX,
521
                viewport->mMouseY,
522
                selShortcut->getItem(index),
523
                selShortcut->getItemColor(index));
524
        }
525
    }
526
}
527
528
void ItemShortcutContainer::mouseReleased(MouseEvent &event)
529
{
530
    ItemShortcut *const selShortcut = itemShortcut[mNumber];
531
    if (selShortcut == nullptr)
532
        return;
533
534
    if (event.getButton() == MouseButton::LEFT)
535
    {
536
        if (selShortcut->isItemSelected())
537
            selShortcut->setItemSelected(-1);
538
539
        const int index = getIndexFromGrid(event.getX(), event.getY());
540
        if (index == -1)
541
            return;
542
543
        if (dragDrop.isEmpty())
544
        {
545
            if ((selShortcut->getItem(index) != 0) && mItemClicked)
546
                selShortcut->useItem(index);
547
        }
548
        else
549
        {
550
            if (dragDrop.getSource() == DragDropSource::Shortcuts)
551
            {
552
                const int oldIndex = dragDrop.getTag();
553
                selShortcut->setItem(oldIndex, dragDrop.getItem(),
554
                    dragDrop.getItemColor());
555
                selShortcut->swap(oldIndex, index);
556
            }
557
            else
558
            {
559
                selShortcut->setItemData(index,
560
                    dragDrop.getItemData());
561
                selShortcut->setItem(index, dragDrop.getItem(),
562
                    dragDrop.getItemColor());
563
            }
564
            dragDrop.clear();
565
            dragDrop.deselect();
566
        }
567
568
        mItemClicked = false;
569
    }
570
}
571
572
void ItemShortcutContainer::mouseMoved(MouseEvent &event)
573
{
574
    const ItemShortcut *const selShortcut = itemShortcut[mNumber];
575
    if (selShortcut == nullptr)
576
        return;
577
578
    const int index = getIndexFromGrid(event.getX(), event.getY());
579
580
    if (index == -1)
581
        return;
582
583
    const int itemId = selShortcut->getItem(index);
584
    const ItemColor itemColor = selShortcut->getItemColor(index);
585
586
    if (itemId < 0)
587
        return;
588
589
    if (itemId < SPELL_MIN_ID)
590
    {
591
        skillPopup->setVisible(Visible_false);
592
        spellPopup->setVisible(Visible_false);
593
594
        Inventory *const inv = PlayerInfo::getInventory();
595
        if (inv == nullptr)
596
            return;
597
598
        const Item *const item = inv->findItem(itemId, itemColor);
599
        if ((item != nullptr) && (viewport != nullptr))
600
        {
601
            itemPopup->setItem(item, false);
602
            itemPopup->position(viewport->mMouseX, viewport->mMouseY);
603
        }
604
        else
605
        {
606
            itemPopup->setVisible(Visible_false);
607
        }
608
    }
609
    else if (itemId < SKILL_MIN_ID && (spellManager != nullptr))
610
    {
611
        skillPopup->setVisible(Visible_false);
612
        itemPopup->setVisible(Visible_false);
613
        const TextCommand *const spell = spellManager->getSpellByItem(itemId);
614
        if ((spell != nullptr) && (viewport != nullptr))
615
        {
616
            spellPopup->setItem(spell);
617
            spellPopup->view(viewport->mMouseX,
618
                viewport->mMouseY);
619
        }
620
        else
621
        {
622
            spellPopup->setVisible(Visible_false);
623
        }
624
    }
625
    else if (skillDialog != nullptr)
626
    {
627
        itemPopup->setVisible(Visible_false);
628
        spellPopup->setVisible(Visible_false);
629
        const SkillInfo *const skill = skillDialog->getSkillByItem(itemId);
630
        if (skill == nullptr)
631
            return;
632
633
        const std::string data = selShortcut->getItemData(index);
634
        CastTypeT castType = CastType::Default;
635
        int offsetX = 0;
636
        int offsetY = 0;
637
        if (!data.empty())
638
        {
639
            STD_VECTOR<int> vect;
640
            splitToIntVector(vect, data, ' ');
641
            const size_t sz = vect.size();
642
            if (sz > 0)
643
                castType = static_cast<CastTypeT>(vect[0]);
644
            if (sz > 2)
645
            {
646
                offsetX = vect[1];
647
                offsetY = vect[2];
648
            }
649
        }
650
        skillPopup->show(skill,
651
            toInt(itemColor, int),
652
            castType,
653
            offsetX,
654
            offsetY);
655
        skillPopup->position(viewport->mMouseX,
656
            viewport->mMouseY);
657
    }
658
}
659
660
// Hide ItemTooltip
661
void ItemShortcutContainer::mouseExited(MouseEvent &event A_UNUSED)
662
{
663
    if (itemPopup != nullptr)
664
        itemPopup->setVisible(Visible_false);
665
    if (spellPopup != nullptr)
666
        spellPopup->setVisible(Visible_false);
667
    if (skillPopup != nullptr)
668
        skillPopup->setVisible(Visible_false);
669
}
670
671
void ItemShortcutContainer::widgetHidden(const Event &event A_UNUSED)
672
{
673
    if (itemPopup != nullptr)
674
        itemPopup->setVisible(Visible_false);
675
    if (spellPopup != nullptr)
676
        spellPopup->setVisible(Visible_false);
677
2
}