GCC Code Coverage Report
Directory: src/ Exec Total Coverage
File: src/gui/widgets/pincode.cpp Lines: 1 97 1.0 %
Date: 2021-03-17 Branches: 2 80 2.5 %

Line Branch Exec Source
1
/*
2
 *  The ManaPlus Client
3
 *  Copyright (C) 2011-2019  The ManaPlus Developers
4
 *  Copyright (C) 2019-2021  Andrei Karas
5
 *
6
 *  This file is part of The ManaPlus Client.
7
 *
8
 *  This program is free software; you can redistribute it and/or modify
9
 *  it under the terms of the GNU General Public License as published by
10
 *  the Free Software Foundation; either version 2 of the License, or
11
 *  any later version.
12
 *
13
 *  This program is distributed in the hope that it will be useful,
14
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
15
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16
 *  GNU General Public License for more details.
17
 *
18
 *  You should have received a copy of the GNU General Public License
19
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
20
 */
21
22
#include "gui/widgets/pincode.h"
23
24
#include "gui/gui.h"
25
#include "gui/skin.h"
26
27
#include "gui/widgets/button.h"
28
#include "gui/widgets/textfield.h"
29
30
#include "utils/gettext.h"
31
#include "utils/stringutils.h"
32
33
#include "debug.h"
34
35
Skin *Pincode::mSkin = nullptr;
36
int Pincode::mInstances = 0;
37
38
Pincode::Pincode(const Widget2 *const widget,
39
                 TextField *const textField) :
40
    Container(widget),
41
    ActionListener(),
42
    WidgetListener(),
43
    mButtons(),
44
    mText(),
45
    mTextField(textField),
46
    mPadding(0),
47
    mSpacing(2),
48
    mButtonWidth(0),
49
    mButtonHeight(0)
50
{
51
    mAllowLogic = false;
52
    setOpaque(Opaque_false);
53
54
    if (mInstances == 0)
55
    {
56
        if (theme != nullptr)
57
        {
58
            mSkin = theme->load("pin.xml",
59
                "",
60
                true,
61
                Theme::getThemePath());
62
        }
63
    }
64
    mInstances ++;
65
66
    if (mSkin != nullptr)
67
    {
68
        mPadding = mSkin->getPadding();
69
        mSpacing = mSkin->getOption("spacing", 2);
70
    }
71
    setSelectable(false);
72
73
    addButtons();
74
    adjustSize();
75
}
76
77
Pincode::~Pincode()
78
{
79
    if (mWindow != nullptr)
80
        mWindow->removeWidgetListener(this);
81
82
    if (gui != nullptr)
83
        gui->removeDragged(this);
84
85
    mInstances --;
86
    if (mInstances == 0)
87
    {
88
        if (theme != nullptr)
89
            theme->unload(mSkin);
90
    }
91
}
92
93
void Pincode::addButtons()
94
{
95
    int buttonWidth = 0;
96
    int buttonHeight = 0;
97
    for (int f = 0; f < 10; f ++)
98
    {
99
        const std::string str = toString(f);
100
        mButtons[f] = new Button(this,
101
            str,
102
            str,
103
            BUTTON_PIN_SKIN,
104
            this);
105
        mButtons[f]->adjustSize();
106
        const Rect &rect = mButtons[f]->getDimension();
107
        if (rect.width > buttonWidth)
108
            buttonWidth = rect.width;
109
        if (rect.height > buttonHeight)
110
            buttonHeight = rect.height;
111
        add(mButtons[f]);
112
    }
113
    int x = 0;
114
    int y = 0;
115
    const int xSize = buttonWidth + mSpacing;
116
    const int ySize = buttonHeight + mSpacing;
117
    for (int f = 0; f < 10; f ++)
118
    {
119
        mButtons[f]->setPosition(mPadding + x * xSize,
120
            mPadding + y * ySize);
121
        x ++;
122
        if (x > 2)
123
        {
124
            x = 0;
125
            y ++;
126
        }
127
    }
128
    mButtons[10] = new Button(this,
129
        // TRANSLATORS: clear pin code button
130
        _("Clear"),
131
        "clear",
132
        BUTTON_PIN_SKIN,
133
        this);
134
    mButtons[10]->adjustSize();
135
    add(mButtons[10]);
136
    mButtons[10]->setPosition(mPadding + xSize,
137
        mPadding + 3 * ySize);
138
139
    mButtonWidth = buttonWidth;
140
    mButtonHeight = buttonHeight;
141
}
142
143
void Pincode::adjustSize()
144
{
145
    const int pad2 = mPadding * 2;
146
    setSize(pad2 + 3 * mButtonWidth + 2 * mSpacing,
147
        pad2 + 4 * mButtonHeight + 3 * mSpacing);
148
}
149
150
void Pincode::finalCleanup()
151
{
152
    mSkin = nullptr;
153
}
154
155
void Pincode::action(const ActionEvent &event)
156
{
157
    if (event.getId() == "clear")
158
    {
159
        mText.clear();
160
        mTextField->setText(mText);
161
        mTextField->signalEvent();
162
        return;
163
    }
164
    if (mText.size() >= 4)
165
        return;
166
    const Widget *const eventSrc = event.getSource();
167
    for (int f = 0; f < 10; f ++)
168
    {
169
        if (mButtons[f] == eventSrc)
170
        {
171
            const std::string str = toString(f);
172
            mText.append(str);
173
            mTextField->setText(mText);
174
            mTextField->signalEvent();
175
            return;
176
        }
177
    }
178
}
179
180
void Pincode::shuffle(uint32_t seed) const
181
{
182
    int tab[10];
183
    const uint32_t multiplier = 0x3498;
184
    const uint32_t baseSeed = 0x881234;
185
    int k = 2;
186
187
    for (size_t f = 0; f < 10; f ++)
188
        tab[f] = CAST_S32(f);
189
    for (size_t f = 1; f < 10; f ++)
190
    {
191
        seed = baseSeed + seed * multiplier;
192
        const size_t pos = seed % k;
193
        if (f != pos)
194
        {
195
            const int tmp = tab[f];
196
            tab[f] = tab[pos];
197
            tab[pos] = tmp;
198
        }
199
        k = k + 1;
200
    }
201
    for (size_t f = 0; f < 10; f ++)
202
    {
203
        const std::string str = toString(tab[f]);
204
        mButtons[f]->setCaption(str);
205
    }
206

3
}