GCC Code Coverage Report
Directory: src/ Exec Total Coverage
File: src/textmanager.cpp Lines: 55 77 71.4 %
Date: 2017-11-29 Branches: 33 56 58.9 %

Line Branch Exec Source
1
/*
2
 *  The ManaPlus Client
3
 *  Copyright (C) 2008  Douglas Boffey <[email protected]>
4
 *  Copyright (C) 2011-2017  The ManaPlus Developers
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 "textmanager.h"
23
24
#include "text.h"
25
26
#include "utils/foreach.h"
27
28
#include <cstring>
29
30
#include "debug.h"
31
32
TextManager *textManager = nullptr;
33
34
12
TextManager::TextManager() :
35
24
    mTextList()
36
{
37
12
}
38
39
18
void TextManager::addText(Text *const text)
40
{
41
18
    if (text == nullptr)
42
        return;
43
18
    place(text, nullptr, text->mX, text->mY, text->mHeight);
44
18
    mTextList.push_back(text);
45
}
46
47
void TextManager::moveText(Text *const text,
48
                           const int x, const int y) const
49
{
50
    if (text == nullptr)
51
        return;
52
    text->mX = x;
53
    text->mY = y;
54
    place(text, text, text->mX, text->mY, text->mHeight);
55
}
56
57
18
void TextManager::removeText(const Text *const text)
58
{
59
54
    FOR_EACH (TextList::iterator, ptr, mTextList)
60
    {
61
21
        if (*ptr == text)
62
        {
63
36
            mTextList.erase(ptr);
64
18
            return;
65
        }
66
    }
67
}
68
69
24
TextManager::~TextManager()
70
{
71
12
}
72
73
void TextManager::draw(Graphics *const graphics,
74
                       const int xOff, const int yOff)
75
{
76
    BLOCK_START("TextManager::draw")
77
    FOR_EACH (TextList::const_iterator, bPtr, mTextList)
78
        (*bPtr)->draw(graphics, xOff, yOff);
79
    BLOCK_END("TextManager::draw")
80
}
81
82
18
void TextManager::place(const Text *const textObj,
83
                        const Text *const omit,
84
                        const int &x A_UNUSED,
85
                        int &y,
86
                        const int h) const
87
{
88
18
    if (textObj == nullptr)
89
18
        return;
90
18
    const int xLeft = textObj->mX;
91
18
    const int xRight1 = xLeft + textObj->mWidth;
92
18
    const int TEST = 50;  // Number of lines to test for text
93
18
    const int nBeings = 30;
94
    bool occupied[TEST];  // is some other text obscuring this line?
95
18
    std::memset(&occupied, 0, sizeof(occupied));  // set all to false
96
18
    const int wantedTop = (TEST - h) / 2;   // Entry in occupied at top of text
97
18
    const int occupiedTop = y - wantedTop;  // Line in map representing
98
                                            // to of occupied
99
18
    int cnt = 0;
100
101
44
    for (TextList::const_iterator ptr = mTextList.begin(),
102
36
         pfEnd = mTextList.end();
103

26
         ptr != pfEnd && cnt < nBeings;
104
         ++ptr, cnt ++)
105
    {
106
8
        const Text *const text = *ptr;
107
108

16
        if (text != omit && text->mX + 1 <= xRight1
109
8
            && text->mX + text->mWidth > xLeft)
110
        {
111
8
            int from = text->mY - occupiedTop;
112
8
            int to = from + text->mHeight - 1;
113
8
            if (to < 0 || from >= TEST)  // out of range considered
114
                continue;
115
8
            if (from < 0)
116
                from = 0;
117
8
            if (to >= TEST)
118
                to = TEST - 1;
119
160
            for (int i = from; i <= to; ++i)
120
152
                occupied[i] = true;
121
        }
122
    }
123
18
    bool ok = true;
124
18
    const int sz = wantedTop + h;
125
492
    for (int i = wantedTop; i < sz; i ++)
126
    {
127
234
        if (occupied[i])
128
        {
129
            ok = false;
130
            break;
131
        }
132
    }
133
134
18
    if (ok)
135
        return;
136
137
    // Have to move it up or down, so find nearest spaces either side
138
6
    int consec = 0;
139
6
    int upSlot = -1;  // means not found
140
6
    const int sz2 = wantedTop + h - 2;
141
204
    for (int seek = sz2; seek >= 0; --seek)
142
    {
143
198
        if (occupied[seek])
144
        {
145
            consec = 0;
146
        }
147
        else
148
        {
149
90
            if (++consec == h)
150
            {
151
                upSlot = seek;
152
                break;
153
            }
154
        }
155
    }
156
6
    int downSlot = -1;
157
6
    consec = 0;
158
210
    for (int seek = wantedTop + 1; seek < TEST; ++seek)
159
    {
160
204
        if (occupied[seek])
161
        {
162
            consec = 0;
163
        }
164
        else
165
        {
166
96
            if (++consec == h)
167
            {
168
                downSlot = seek - h + 1;
169
                break;
170
            }
171
        }
172
    }
173
6
    if (upSlot == -1 && downSlot == -1)  // no good solution, so leave as is
174
    {
175
        return;
176
    }
177
    if (upSlot == -1)  // must go down
178
    {
179
        y += downSlot - wantedTop;
180
        return;
181
    }
182
    if (downSlot == -1)  // must go up
183
    {
184
        y -= wantedTop - upSlot;
185
        return;
186
    }
187
    if (wantedTop - upSlot > downSlot - wantedTop)  // down is better
188
    {
189
        y += downSlot - wantedTop;
190
    }
191
    else
192
    {
193
        y -= wantedTop - upSlot;
194
    }
195
}