kolibrios/programs/games/21days/interface.cpp

345 lines
9.4 KiB
C++
Raw Permalink Normal View History

/******************************************************************
* 21 days: a game for programmers
* Copyright (C) 2014 Maxim Grishin
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301, USA.
*******************************************************************/
#include "sys.h"
#ifndef _KOS32
#include <stdio.h> // printf()
#include <stdarg.h>
#define printf2 printf
#endif
#include <cstring> // strlen
#include <string>
using std::string;
char getAnswer(char a1, char a2) {
while(1) {
if (kbhit()) {
char ch = getch();
#ifdef _KOS32
if (ch == 0)
ch = getch();
#endif
if (ch == a1 || ch == a2)
return ch;
}
}
}
char getAnswer(char a1, char a2, char a3) {
while(1) {
if (kbhit()) {
char ch = getch();
#ifdef _KOS32
if (ch == 0)
ch = getch();
#endif
if (ch == a1 || ch == a2 || ch == a3)
return ch;
}
}
}
char getAnswer(char a1, char a2, char a3, char a4) {
while(1) {
if (kbhit()) {
char ch = getch();
#ifdef _KOS32
if (ch == 0)
ch = getch();
#endif
if (ch == a1 || ch == a2 || ch == a3 || ch == a4)
return ch;
}
}
}
void wait(char a = ENTER_KEY, char b = ENTER_KEY) {
getAnswer(a, b);
}
char getKey() {
#ifdef _KOS32
while(1) {
if (kbhit()) {
char ch = getch();
if (ch == 0)
ch = getch();
return ch;
}
}
#else
return getch();
#endif
}
void blankline(int line, int width) {
printf2("<EFBFBD> ");
consoleGoto(line, width);
printf2("<EFBFBD>\n");
}
void drawHBorder(int line, int left, int right, char l = '<EFBFBD>',
char c = '<EFBFBD>', char r = '<EFBFBD>', char e = '\n') {
consoleGoto(line, left);
printf2("%c", l);
for (int i = 0; i< right - left; i++)
printf2("%c", c);
consoleGoto(line, right);
printf2("%c%c", r, e);
}
void drawStringLine(int line, int left, int right, const char* str,
int pos = -1, char border = '<EFBFBD>', bool shadow = false) {
consoleGoto(line, left);
if (pos == -1)
printf2("%c %s", border, str);
else {
printf2("%c ", border);
consoleGoto(line, pos);
printf2("%s", str);
}
consoleGoto(line, right);
if (shadow)
printf2("%c<>", border);
else
printf2("%c\n", border);
}
void drawModalWindow(const char* content, const char* title, const char* buttons) {
cls();
int winWidth, winHeight;
getWinWH(winWidth, winHeight);
int lines = winHeight/3;
int msgWidth = strlen(content)+2;
if (msgWidth >= winWidth-4)
msgWidth = winWidth-5;
int msgLeft = winWidth/2 - msgWidth/2;
int msgRight = winWidth/2 + msgWidth/2+1;
if (msgWidth%2!=0)
msgRight++;
int titleWidth = 0;
if (title != 0)
titleWidth = strlen(title)+2;
drawHBorder(lines, msgLeft, msgRight,'<EFBFBD>','<EFBFBD>', '<EFBFBD>');
// title
if (title != 0) {
consoleGoto(lines, msgLeft+msgWidth/2-titleWidth/2);
printf2(" %s ", title);
}
lines++;
drawHBorder(lines, msgLeft, msgRight, '<EFBFBD>',' ','<EFBFBD>','<EFBFBD>');
lines++;
//======Splitting content into pieces=========================
int maxTextWidth = msgRight-msgLeft; // 2 borders + 2 spaces
int start = 0;
int len = strlen(content);
for (int i = 0; i < len; i++) {
if (content[i] == '\n') {
string tmp = content;
string t1 = tmp.substr(start, i-start+1);
drawStringLine(lines, msgLeft, msgRight, t1.c_str(), -1, '<EFBFBD>', true);
start = i+1;
lines++;
}
else if (i - start >= maxTextWidth-3) {
string tmp = content;
string t1 = tmp.substr(start, i-start);
t1+="\n";
drawStringLine(lines, msgLeft, msgRight, t1.c_str(), -1, '<EFBFBD>', true);
start = i;
lines++;
}
}
if (start != len) {
string tmp = content;
string t1 = tmp.substr(start, len-start);
drawStringLine(lines, msgLeft, msgRight, t1.c_str(), -1, '<EFBFBD>', true);
lines++;
}
//===============================
drawHBorder(lines, msgLeft, msgRight, '<EFBFBD>',' ','<EFBFBD>','<EFBFBD>');
lines++;
consoleGoto(lines, msgLeft);
printf2("<EFBFBD>");
if (!buttons) {
for (int q = 0; q< msgWidth/2-4;q++)
printf2(" ");
printf2("[Enter]");
for (int i = 0; i< msgWidth/2-2; i++)
printf2(" ");
}
else {
int buttonsLen = strlen(buttons);
for (int i = 0; i < msgWidth/2-buttonsLen/2; i++)
printf2(" ");
printf2("%s", buttons);
}
consoleGoto(lines, msgRight);
printf2("<EFBFBD><EFBFBD>");
lines++;
drawHBorder(lines, msgLeft, msgRight,'<EFBFBD>', '<EFBFBD>', '<EFBFBD>','<EFBFBD>');
lines++;
consoleGoto(lines, msgLeft+1);
for (int i = 0; i< msgWidth+2; i++)
printf2("<EFBFBD>");
printf2(" ");
}
void drawWindow(string content, const char* title, string topline , string bottomline, bool usePagesForLongText = false) {
cls();
int winWidth, winHeight;
getWinWH(winWidth, winHeight);
#if defined(_WIN32) && !defined(_KOS32)
int deltaX = 0;
#else
int deltaX = 1;
#endif
// Total lines
#if defined(_WIN32) && !defined(_KOS32)
int lines = 0;
#else
int lines = 1;
#endif
// Top
drawHBorder(lines, deltaX, winWidth);
lines++;
if (topline != "") {
drawStringLine(lines, deltaX, winWidth, topline.c_str());
lines++;
}
// Title
if (title != 0) {
if (topline != "") {
blankline(lines, winWidth);
lines++;
}
drawStringLine(lines, deltaX, winWidth, title, (int)(winWidth/2.0-strlen(title)/2.0));
lines++;
blankline(lines, winWidth);
lines++;
}
//==========Splitting content into pieces=====================
int maxTextWidth = winWidth-4; // 2 borders + 2 spaces
int start = 0;
unsigned int i = 0;
// Let's split content into pieces if it too long or doesn't fit the screen
while (i < content.length()) {
if (usePagesForLongText && lines > winHeight-3) {
consoleGoto(lines, 0);
blankline(lines, winWidth);
lines++;
drawStringLine(lines, deltaX, winWidth, "<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> [Enter] <20><><EFBFBD> <20><EFBFBD><E0AEA4><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>...");
// Bottom line
drawHBorder(winHeight, deltaX, winWidth,'<EFBFBD>','<EFBFBD>','<EFBFBD>');
wait();
// Print next page
cls();
lines = 0;
// Top line
drawHBorder(lines, deltaX, winWidth);
#if defined(_WIN32) && !defined(_KOS32)
lines = 1;
#else
lines = 2;
#endif
}
// Use <c> tag to place text in the center
if (content[i] == '<') {
// Checking for the <c> tag. <c> tag should be prepended with '\n'
if (i+2 < content.length()) {
if (content[i+1] == 'c' && content[i+2] == '>') {
// Tag found. Looking for the end of a string
int cLineEnd = content.length()-1;
for (unsigned int j = i; j < content.length(); j++)
if (content[j] == '\n') {
cLineEnd = j;
break;
}
int cLineWidth = cLineEnd - i-1;
drawStringLine(lines, deltaX, winWidth,
content.substr(i+3, cLineWidth-2).c_str(), winWidth/2-cLineWidth/2);
i = cLineEnd+1;
start = i;
lines++;
continue;
}
}
}
else if (content[i] == '\n') {
consoleGoto(lines, 0);
string t1 = content.substr(start, i-start+1);
drawStringLine(lines, deltaX, winWidth, t1.c_str());
start = i+1;
lines++;
}
else if ((int)i - start >= maxTextWidth-1) {
consoleGoto(lines, 0);
string t1 = content.substr(start, i-start);
t1+="\n";
drawStringLine(lines, deltaX, winWidth, t1.c_str());
start = i;
lines++;
}
i++;
}
if (start <= (int)content.length()) {
consoleGoto(lines, 0);
string t1 = content.substr(start, content.length()-start);
drawStringLine(lines, deltaX, winWidth, t1.c_str());
lines++;
}
//===============================
for (int i = lines; i< winHeight; i++) {
blankline(lines, winWidth);
lines++;
}
if (!bottomline.empty()) {
///Fix for long bottomline
if ((int)bottomline.length() >= winWidth) {
drawStringLine(winHeight-2, deltaX, winWidth, bottomline.substr(0, winWidth-4).c_str());
drawStringLine(winHeight-1, deltaX, winWidth, bottomline.substr(winWidth-4).c_str());
}
else {
drawStringLine(winHeight-1, deltaX, winWidth, bottomline.c_str());
}
}
// Bottom
drawHBorder(winHeight, deltaX, winWidth,'<EFBFBD>','<EFBFBD>','<EFBFBD>');
}