1 ////////////////////////////////////////////////////////////////////////////////
2 //    Scorched3D (c) 2000-2011
3 //
4 //    This file is part of Scorched3D.
5 //
6 //    Scorched3D is free software; you can redistribute it and/or modify
7 //    it under the terms of the GNU General Public License as published by
8 //    the Free Software Foundation; either version 2 of the License, or
9 //    (at your option) any later version.
10 //
11 //    Scorched3D is distributed in the hope that it will be useful,
12 //    but WITHOUT ANY WARRANTY; without even the implied warranty of
13 //    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 //    GNU General Public License for more details.
15 //
16 //    You should have received a copy of the GNU General Public License along
17 //    with this program; if not, write to the Free Software Foundation, Inc.,
18 //    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 ////////////////////////////////////////////////////////////////////////////////
20 
21 #include <console/ConsoleImpl.h>
22 #include <common/Keyboard.h>
23 #include <common/Defines.h>
24 #include <common/Logger.h>
25 #include <GLEXT/GLState.h>
26 #include <GLEXT/GLViewPort.h>
27 #include <GLW/GLWFont.h>
28 #include <GLW/GLWToolTip.h>
29 #include <limits.h>
30 
ConsoleImpl()31 ConsoleImpl::ConsoleImpl() :
32 	GameStateI("Console"),
33 	height_(0.0f), opening_(false),
34 	lines_(1000), historyPosition_(-1), font_(0),
35 	showCursor_(true)
36 {
37 	Logger::addLogger(this);
38 }
39 
~ConsoleImpl()40 ConsoleImpl::~ConsoleImpl()
41 {
42 
43 }
44 
init()45 void ConsoleImpl::init()
46 {
47 	methods_.init();
48 }
49 
logMessage(LoggerInfo & info)50 void ConsoleImpl::logMessage(LoggerInfo &info)
51 {
52 	addLine(false, info.getMessage());
53 }
54 
keyboardCheck(const unsigned state,float frameTime,char * buffer,unsigned int keyState,KeyboardHistory::HistoryElement * history,int hisCount,bool & skipRest)55 void ConsoleImpl::keyboardCheck(const unsigned state, float frameTime,
56 							   char *buffer, unsigned int keyState,
57 							   KeyboardHistory::HistoryElement *history, int hisCount,
58 							   bool &skipRest)
59 {
60 	// Use the history to ensure that no keystrokes are missed
61 	// regardless of the framerate.
62 	KEYBOARDKEY("CONSOLE", consoleKey);
63 	for (int i=0; i<hisCount; i++)
64 	{
65 		unsigned int dik = history[i].sdlKey;
66 		if (consoleKey->keyMatch(dik))
67 		{
68 			resetPositions();
69 			if (currentLine_.empty()) opening_ = !opening_;
70 			else currentLine_ = "";
71 			skipRest = true;
72 		}
73 	}
74 
75 	if (height_ > 0.0f)
76 	{
77 		// Use the history to ensure that no keystrokes are missed
78 		// regardless of the framerate.
79 		if (!skipRest)
80 		for (int i=0; i<hisCount; i++)
81 		{
82 			char unicodeKey = history[i].representedUnicode;
83 			unsigned int dik = history[i].sdlKey;
84 
85 			if (unicodeKey >= ' ')
86 			{
87 				resetPositions();
88 				if (unicodeKey < 127) currentLine_ += (char) unicodeKey;
89 			}
90 			else
91 			{
92 				switch (dik)
93 				{
94 				case SDLK_ESCAPE:
95 					resetPositions();
96 					if (currentLine_.empty()) opening_ = false;
97 					else currentLine_ = "";
98 					break;
99 				case SDLK_TAB:
100 					resetPositions();
101 					{
102 						std::vector<ConsoleRule *> matches;
103 						std::string result =
104 							rules_.matchRule(currentLine_.c_str(), matches);
105 						if (result.length() > 0) currentLine_ = result;
106 
107 						addLine(false, "-------------------");
108 						std::vector<ConsoleRule *>::iterator itor;
109 						for (itor = matches.begin();
110 							itor != matches.end();
111 							++itor)
112 						{
113 							std::string text = (*itor)->toString();
114 							addLine(false, text.c_str());
115 						}
116 					}
117 					break;
118 				case SDLK_BACKSPACE:
119 				case SDLK_DELETE:
120 					resetPositions();
121 					currentLine_ = currentLine_.substr(0, currentLine_.length() - 1);
122 					break;
123 				case SDLK_RETURN:
124 					if (!currentLine_.empty())
125 					{
126 						resetPositions();
127 						addLine(true, currentLine_.c_str());
128 						history_.push_front(currentLine_.c_str());
129 						currentLine_.erase();
130 					}
131 					break;
132 				case SDLK_UP:
133 					historyPosition_++;
134 					if (historyPosition_ >= int(history_.size()))
135 						historyPosition_ = int(history_.size()) - 1;
136 					if (historyPosition_ >= 0)
137 						currentLine_ = history_[historyPosition_];
138 					break;
139 				case SDLK_DOWN:
140 					historyPosition_--;
141 					if (historyPosition_ <= 0)
142 						historyPosition_ = (history_.empty()?-1:0);
143 					if (historyPosition_ >= 0)
144 						currentLine_ = history_[historyPosition_];
145 					break;
146 				case SDLK_PAGEUP:
147 					lines_.scroll(-5);
148 					break;
149 				case SDLK_PAGEDOWN:
150 					lines_.scroll(+5);
151 					break;
152 				case SDLK_HOME:
153 					lines_.scroll(INT_MIN);
154 					break;
155 				case SDLK_END:
156 					lines_.scroll(INT_MAX);
157 					break;
158 				}
159 			}
160 		}
161 		skipRest = true;
162 	}
163 	else
164 	{
165 		std::list<KeyboardKey *> &keys = Keyboard::instance()->getCommandKeys();
166 		std::list<KeyboardKey *>::iterator keyItor = keys.begin();
167 		std::list<KeyboardKey *>::iterator keyEndItor = keys.end();
168 		for (; keyItor != keyEndItor; ++keyItor)
169 		{
170 			KeyboardKey *key = (*keyItor);
171 			if (key->keyDown(buffer, keyState, false))
172 			{
173 				resetPositions();
174 				addLine(true, key->getName());
175 			}
176 		}
177 	}
178 }
179 
resetPositions()180 void ConsoleImpl::resetPositions()
181 {
182 	historyPosition_ = -1;
183 	lines_.resetScroll();
184 }
185 
simulate(const unsigned state,float frameTime)186 void ConsoleImpl::simulate(const unsigned state, float frameTime)
187 {
188 	const GLfloat dropSpeed = 1200.0f;
189 	if (opening_)
190 	{
191 		height_ += frameTime * dropSpeed;
192 	}
193 	else
194 	{
195 		height_ -= frameTime * dropSpeed;
196 		if (height_ < 0.0f) height_ = 0.0f;
197 	}
198 
199 	static float ctime = 0;
200 	ctime += frameTime;
201 	if (ctime > 0.5f)
202 	{
203 		ctime = 0.0f;
204 		showCursor_ = !showCursor_;
205 	}
206 }
207 
draw(const unsigned state)208 void ConsoleImpl::draw(const unsigned state)
209 {
210 	if (height_ <= 0.0f) return;
211 
212 	GLState currentState(GLState::DEPTH_OFF | GLState::TEXTURE_OFF | GLState::BLEND_ON);
213 
214 	GLfloat width = (GLfloat) GLViewPort::getWidth();
215 	GLfloat top = (GLfloat) GLViewPort::getHeight();
216 
217 	drawBackdrop(width, top);
218 	drawText(width, top);
219 }
220 
drawBackdrop(float width,float top)221 void ConsoleImpl::drawBackdrop(float width, float top)
222 {
223 	if (height_ > top * .85f) height_ = top * .85f;
224 
225 	GLWToolTip::instance()->clearToolTip(
226 		0.0f, top - height_ + 10.0f,
227 		width, height_);
228 
229 	glColor4f(0.0f, 0.0f, 0.0f, 0.9f);
230 	glBegin(GL_QUADS);
231 		glVertex2f(0.0f, top - height_ + 10.0f);
232 		glVertex2f(width, top - height_ + 10.0f);
233 		glVertex2f(width, top);
234 		glVertex2f(0.0f, top);
235 
236 		glVertex2f(10.0f, top - height_);
237 		glVertex2f(width - 10.0f, top - height_);
238 		glVertex2f(width, top - height_ + 10.0f);
239 		glVertex2f(0.0f, top - height_ + 10.0f);
240 	glEnd();
241 
242 	glColor4f(0.1f, 0.1f, 0.1f, 1.0f);
243 	glBegin(GL_LINE_STRIP);
244 		glVertex2f(0.0f, top - height_ + 10.0f);
245 		glVertex2f(10.0f, top - height_);
246 		glVertex2f(width - 10.0f, top - height_);
247 		glVertex2f(width, top - height_ + 10.0f);
248 	glEnd();
249 }
250 
drawText(float width,float top)251 void ConsoleImpl::drawText(float width, float top)
252 {
253 	static Vector color(1.0f, 1.0f, 1.0f);
254 	if (!font_) font_ = GLWFont::instance()->getCourierFont();
255 	font_->draw(color, 14,
256 		10.0f, top - (height_ - 14.0f), 0.0f,
257 		S3D::formatStringBuffer("> %s%c",
258 		currentLine_.c_str(),
259 		(showCursor_?'_':' ')));
260 
261 	lines_.drawLines(font_, top - (height_ - 14.0f), top, width);
262 }
263 
addLine(bool parse,const std::string & text)264 void ConsoleImpl::addLine(bool parse, const std::string &text)
265 {
266 	lines_.addLine(text, parse);
267 	if (parse)
268 	{
269 		rules_.addLine(this, text.c_str());
270 	}
271 }
272 
help()273 void ConsoleImpl::help()
274 {
275 	std::vector<std::string>::iterator itor;
276 	std::vector<std::string> result;
277 	rules_.dump(result);
278 
279 	for (itor = result.begin();
280 		itor != result.end();
281 		++itor)
282 	{
283 		addLine(false, *itor);
284 	}
285 }
286