File: TextControls.h

package info (click to toggle)
vcmi 0.99%2Bdfsg%2Bgit20190113.f06c8a87-2
  • links: PTS, VCS
  • area: contrib
  • in suites: bullseye
  • size: 11,136 kB
  • sloc: cpp: 142,615; sh: 315; objc: 248; makefile: 32; ansic: 28; python: 13
file content (199 lines) | stat: -rw-r--r-- 6,670 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
/*
 * TextControls.h, part of VCMI engine
 *
 * Authors: listed in file AUTHORS in main folder
 *
 * License: GNU General Public License v2.0 or later
 * Full text of license available in license.txt file, in main folder
 *
 */
#pragma once

#include "../gui/CIntObject.h"
#include "../gui/SDL_Extensions.h"
#include "../../lib/FunctionList.h"

class CSlider;

/// Base class for all text-related widgets.
/// Controls text blitting-related options
class CTextContainer : public virtual CIntObject
{
protected:
	/// returns size of border, for left- or right-aligned text
	virtual Point getBorderSize() = 0;
	/// do actual blitting of line. Text "what" will be placed at "where" and aligned according to alignment
	void blitLine(SDL_Surface * to, Rect where, std::string what);

	CTextContainer(EAlignment alignment, EFonts font, SDL_Color color);

public:
	EAlignment alignment;
	EFonts font;
	SDL_Color color; // default font color. Can be overridden by placing "{}" into the string
};

/// Label which shows text
class CLabel : public CTextContainer
{
protected:
	Point getBorderSize() override;
	virtual std::string visibleText();

	std::shared_ptr<CPicture> background;
public:

	std::string text;
	bool autoRedraw;  //whether control will redraw itself on setTxt

	std::string getText();
	virtual void setAutoRedraw(bool option);
	virtual void setText(const std::string &Txt);
	virtual void setColor(const SDL_Color & Color);
	size_t getWidth();

	CLabel(int x=0, int y=0, EFonts Font = FONT_SMALL, EAlignment Align = TOPLEFT,
	       const SDL_Color &Color = Colors::WHITE, const std::string &Text =  "");
	void showAll(SDL_Surface * to) override; //shows statusbar (with current text)
};

/// Small helper class to manage group of similar labels
class CLabelGroup : public CIntObject
{
	std::vector<std::shared_ptr<CLabel>> labels;
	EFonts font;
	EAlignment align;
	SDL_Color color;
public:
	CLabelGroup(EFonts Font = FONT_SMALL, EAlignment Align = TOPLEFT, const SDL_Color &Color = Colors::WHITE);
	void add(int x=0, int y=0, const std::string &text =  "");
	size_t currentSize() const;
};

/// Multi-line label that can display multiple lines of text
/// If text is too big to fit into requested area remaining part will not be visible
class CMultiLineLabel : public CLabel
{
	// text to blit, split into lines that are no longer than widget width
	std::vector<std::string> lines;

	// area of text that actually will be printed, default is widget size
	Rect visibleSize;

	void splitText(const std::string &Txt);
	Rect getTextLocation();
public:
	// total size of text, x = longest line of text, y = total height of lines
	Point textSize;

	CMultiLineLabel(Rect position, EFonts Font = FONT_SMALL, EAlignment Align = TOPLEFT, const SDL_Color &Color = Colors::WHITE, const std::string &Text =  "");

	void setText(const std::string &Txt) override;
	void showAll(SDL_Surface * to) override;

	void setVisibleSize(Rect visibleSize);
	// scrolls text visible in widget. Positive value will move text up
	void scrollTextTo(int distance);
	void scrollTextBy(int distance);
};

/// a multi-line label that tries to fit text with given available width and height;
/// if not possible, it creates a slider for scrolling text
class CTextBox : public CIntObject
{
	int sliderStyle;
public:
	std::shared_ptr<CMultiLineLabel> label;
	std::shared_ptr<CSlider> slider;

	CTextBox(std::string Text, const Rect & rect, int SliderStyle, EFonts Font = FONT_SMALL, EAlignment Align = TOPLEFT, const SDL_Color & Color = Colors::WHITE);

	void resize(Point newSize);
	void setText(const std::string & Txt);
	void sliderMoved(int to);
};

/// Status bar which is shown at the bottom of the in-game screens
class CGStatusBar : public CLabel, public std::enable_shared_from_this<CGStatusBar>
{
	bool textLock; //Used for blocking changes to the text
	void init();

	std::shared_ptr<CGStatusBar> oldStatusBar;

	CGStatusBar(std::shared_ptr<CPicture> background_, EFonts Font = FONT_SMALL, EAlignment Align = CENTER, const SDL_Color & Color = Colors::WHITE);
	CGStatusBar(int x, int y, std::string name, int maxw = -1);
protected:
	Point getBorderSize() override;

public:
	template<typename ...Args>
	static std::shared_ptr<CGStatusBar> create(Args... args)
	{
		std::shared_ptr<CGStatusBar> ret{new CGStatusBar{args...}};
		ret->init();
		return ret;
	}
	void clear();//clears statusbar and refreshes
	void setText(const std::string & Text) override; //prints text and refreshes statusbar

	void show(SDL_Surface * to) override; //shows statusbar (with current text)

	~CGStatusBar();

	void lock(bool shouldLock); //If true, current text cannot be changed until lock(false) is called
};

/// UIElement which can get input focus
class CFocusable : public virtual CIntObject
{
protected:
	virtual void focusGot(){};
	virtual void focusLost(){};
public:
	bool focus; //only one focusable control can have focus at one moment

	void giveFocus(); //captures focus
	void moveFocus(); //moves focus to next active control (may be used for tab switching)

	static std::list<CFocusable*> focusables; //all existing objs
	static CFocusable *inputWithFocus; //who has focus now
	CFocusable();
	~CFocusable();
};

/// Text input box where players can enter text
class CTextInput : public CLabel, public CFocusable
{
	std::string newText;
protected:
	std::string visibleText() override;

	void focusGot() override;
	void focusLost() override;

#ifdef VCMI_ANDROID
	void notifyAndroidTextInputChanged(std::string & text);
#endif
public:
	CFunctionList<void(const std::string &)> cb;
	CFunctionList<void(std::string &, const std::string &)> filters;
	void setText(const std::string &nText, bool callCb = false);

	CTextInput(const Rect &Pos, EFonts font, const CFunctionList<void(const std::string &)> &CB);
	CTextInput(const Rect &Pos, const Point &bgOffset, const std::string &bgName, const CFunctionList<void(const std::string &)> &CB);
	CTextInput(const Rect &Pos, SDL_Surface *srf = nullptr);

	void clickLeft(tribool down, bool previousState) override;
	void keyPressed(const SDL_KeyboardEvent & key) override;
	bool captureThisEvent(const SDL_KeyboardEvent & key) override;

	void textInputed(const SDL_TextInputEvent & event) override;
	void textEdited(const SDL_TextEditingEvent & event) override;

	//Filter that will block all characters not allowed in filenames
	static void filenameFilter(std::string &text, const std::string & oldText);
	//Filter that will allow only input of numbers in range min-max (min-max are allowed)
	//min-max should be set via something like std::bind
	static void numberFilter(std::string &text, const std::string & oldText, int minValue, int maxValue);
};