1
/*
2
 *  Support for non-overlapping floating text
3
 *  Copyright (C) 2008  Douglas Boffey <DougABoffey@netscape.net>
4
 *
5
 *  This file is part of The Mana World.
6
 *
7
 *  This program is free software; you can redistribute it and/or modify
8
 *  it under the terms of the GNU General Public License as published by
9
 *  the Free Software Foundation; either version 2 of the License, or
10
 *  any later version.
11
 *
12
 *  This program is distributed in the hope that it will be useful,
13
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
14
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15
 *  GNU General Public License for more details.
16
 *
17
 *  You should have received a copy of the GNU General Public License
18
 *  along with this program; if not, write to the Free Software
19
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20
 */
21
22
#include "textmanager.h"
23
24
#include <cstring>
25
26
#include "text.h"
27
28
TextManager *textManager = 0;
29
30
TextManager::TextManager()
31
{
32
}
33
34
void TextManager::addText(Text *text)
35
{
36
    place(text, 0, text->mX, text->mY, text->mHeight);
37
    mTextList.push_back(text);
38
}
39
40
void TextManager::moveText(Text *text, int x, int y)
41
{
42
    text->mX = x;
43
    text->mY = y;
44
    place(text, text, text->mX, text->mY, text->mHeight);
45
}
46
47
void TextManager::removeText(const Text *text)
48
{
49
    for (TextList::iterator ptr = mTextList.begin(),
50
             pEnd = mTextList.end(); ptr != pEnd; ++ptr)
51
    {
52
        if (*ptr == text)
53
        {
54
            mTextList.erase(ptr);
55
            return;
56
        }
57
    }
58
}
59
60
TextManager::~TextManager()
61
{
62
}
63
64
void TextManager::draw(gcn::Graphics *graphics, int xOff, int yOff)
65
{
66
    for (TextList::iterator bPtr = mTextList.begin(), ePtr = mTextList.end();
67
         bPtr != ePtr; ++bPtr)
68
    {
69
        (*bPtr)->draw(graphics, xOff, yOff);
70
    }
71
}
72
73
void TextManager::place(const Text *textObj, const Text *omit,
74
                        int &x, int &y, int h)
75
{
76
    int xLeft = textObj->mX;
77
    int xRight = xLeft + textObj->mWidth - 1;
78
    const int TEST = 100; // Number of lines to test for text
79
    bool occupied[TEST]; // is some other text obscuring this line?
80
    std::memset(&occupied, 0, sizeof(occupied)); // set all to false
81
    int wantedTop = (TEST - h) / 2; // Entry in occupied at top of text
82
    int occupiedTop = y - wantedTop; // Line in map representing to of occupied
83
84
    for (TextList::const_iterator ptr = mTextList.begin(),
85
             pEnd = mTextList.end(); ptr != pEnd; ++ptr)
86
    {
87
        if (*ptr != omit &&
88
            (*ptr)->mX <= xRight &&
89
            (*ptr)->mX + (*ptr)->mWidth > xLeft)
90
        {
91
            int from = (*ptr)->mY - occupiedTop;
92
            int to = from + (*ptr)->mHeight - 1;
93
            if (to < 0 || from >= TEST) // out of range considered
94
                continue;
95
            if (from < 0)
96
                from = 0;
97
            if (to >= TEST)
98
                to = TEST - 1;
99
            for (int i = from; i <= to; ++i)
100
                occupied[i] = true;
101
        }
102
    }
103
    bool ok = true;
104
    for (int i = wantedTop; i < wantedTop + h; ++i)
105
    {
106
        ok = ok && !occupied[i];
107
    }
108
109
    if (ok)
110
        return;
111
112
    // Have to move it up or down, so find nearest spaces either side
113
    int consec = 0;
114
    int upSlot = -1; // means not found
115
    for (int seek = wantedTop + h - 2; seek >= 0; --seek)
116
    {
117
        if (occupied[seek])
118
        {
119
            consec = 0;
120
        }
121
        else
122
        {
123
            if (++consec == h)
124
            {
125
                upSlot = seek;
126
                break;
127
            }
128
        }
129
    }
130
    int downSlot = -1;
131
    consec = 0;
132
    for (int seek = wantedTop + 1; seek < TEST; ++seek)
133
    {
134
        if (occupied[seek])
135
        {
136
            consec = 0;
137
        }
138
        else
139
        {
140
            if (++consec == h)
141
            {
142
                downSlot = seek - h + 1;
143
                break;
144
            }
145
        }
146
    }
147
    if (upSlot == -1 && downSlot == -1) // no good solution, so leave as is
148
    {
149
        return;
150
    }
151
    if (upSlot == -1) // must go down
152
    {
153
        y += downSlot - wantedTop;
154
        return;
155
    }
156
    if (downSlot == -1) // must go up
157
    {
158
        y -= wantedTop - upSlot;
159
        return;
160
    }
161
    if (wantedTop - upSlot > downSlot - wantedTop) // down is better
162
    {
163
        y += downSlot - wantedTop;
164
    }
165
    else
166
    {
167
        y -= wantedTop - upSlot;
168
    }
169
}