scummvm/engines/ultima/nuvie/gui/widgets/msg_scroll_new_ui.cpp
2020-09-08 18:56:17 -07:00

301 lines
8.4 KiB
C++

/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* 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 "ultima/shared/std/string.h"
#include "ultima/nuvie/core/nuvie_defs.h"
#include "ultima/nuvie/conf/configuration.h"
#include "ultima/nuvie/misc/u6_misc.h"
#include "ultima/nuvie/fonts/font_manager.h"
#include "ultima/nuvie/fonts/font.h"
#include "ultima/nuvie/screen/game_palette.h"
#include "ultima/nuvie/gui/gui.h"
#include "ultima/nuvie/gui/widgets/msg_scroll.h"
#include "ultima/nuvie/portraits/portrait.h"
#include "ultima/nuvie/core/player.h"
#include "ultima/nuvie/fonts/conv_font.h"
#include "ultima/nuvie/gui/widgets/msg_scroll_new_ui.h"
#include "ultima/nuvie/actors/actor_manager.h"
#include "ultima/nuvie/core/timed_event.h"
namespace Ultima {
namespace Nuvie {
// MsgScrollNewUI Class
MsgScrollNewUI::MsgScrollNewUI(Configuration *cfg, Screen *s) {
drop_target = false; //we don't participate in drag and drop.
font_normal = Game::get_game()->get_font_manager()->get_conv_font();
font_garg = Game::get_game()->get_font_manager()->get_conv_garg_font();
init(cfg, font_normal);
Std::string new_scroll_cfg = config_get_game_key(config) + "/newscroll";
cfg->value(new_scroll_cfg + "/solid_bg", solid_bg, false);
int c;
if (Game::get_game()->get_game_type() == NUVIE_GAME_U6) {
bg_color = 218;
border_color = 220;
} else if (Game::get_game()->get_game_type() == NUVIE_GAME_SE) {
bg_color = 216;
border_color = 219;
} else { // MD
bg_color = 136;
border_color = 133;
}
cfg->value(new_scroll_cfg + "/bg_color", c, bg_color);
bg_color = clamp_max(c, 255);
cfg->value(new_scroll_cfg + "/border_color", c, border_color);
border_color = clamp_max(c, 255);
cfg->value(new_scroll_cfg + "/width", c, 18);
scroll_width = c;
cfg->value(new_scroll_cfg + "/height", c, 19);
scroll_height = clamp_max(c, scrollback_height);
uint16 x_off = Game::get_game()->get_game_x_offset();
uint16 y_off = Game::get_game()->get_game_y_offset();
// need to accept clicks on whole game area
GUI_Widget::Init(NULL, x_off, y_off, Game::get_game()->get_game_width(), Game::get_game()->get_game_height());
cursor_wait = 0;
timer = NULL;
position = 0;
}
MsgScrollNewUI::~MsgScrollNewUI() {
}
bool MsgScrollNewUI::can_fit_token_on_msgline(MsgLine *msg_line, MsgText *token) {
if (msg_line->get_display_width() + token->getDisplayWidth() > scroll_width * 7 - 8) {
return false; //token doesn't fit on the current line.
}
return true;
}
void MsgScrollNewUI::display_string(Std::string s, Font *f, bool include_on_map_window) {
if (s.empty())
return;
bool has_trailing_whitespace = (!trailing_whitespace.empty());
s = trailing_whitespace + s;
trailing_whitespace.clear();
Std::string::reverse_iterator iter;
uint16 i;
for (i = 0, iter = s.rbegin(); iter != s.rend(); iter++, i++) {
char c = *iter;
if (c != '\t' && c != '\n')
break;
}
if (i > 0) {
trailing_whitespace = s.substr(s.length() - i, i);
s = s.substr(0, s.length() - i);
}
if (!s.empty()) {
if (position > 0 && position == msg_buf.size()) {
if (!has_trailing_whitespace)
position--;
else {
position += count_empty_lines(s) - 1;
}
}
timer = new TimedCallback(this, NULL, 2000);
MsgScroll::display_string(s, f, include_on_map_window);
}
}
uint16 MsgScrollNewUI::count_empty_lines(Std::string s) {
Std::string::iterator iter;
uint16 count = 0;
for (iter = s.begin(); iter != s.end(); iter++) {
char c = *iter;
if (c != ' ' && c != '\t' && c != '\n')
break;
if (c == '\n')
count++;
}
return count;
}
void MsgScrollNewUI::set_font(uint8 font_type) {
if (font_type == NUVIE_FONT_NORMAL) {
font = font_normal;
} else {
if (font_garg) {
font = font_garg;
}
}
}
bool MsgScrollNewUI::is_garg_font() {
return (font == font_garg);
}
uint16 MsgScrollNewUI::callback(uint16 msg, CallBack *caller, void *data) {
if (msg == CB_TIMED && (timer == NULL || timer == caller)) {
timer = NULL;
if (input_mode) {
new TimedCallback(this, NULL, 100);
} else {
//roll up the message scroll so it's out of the way.
if (position < msg_buf.size()) {
if ((uint16)(position + 1) < msg_buf.size()
|| msg_buf.back()->total_length > 0) { //don't advance if on second last line and the last line is empty.
position++;
new TimedCallback(this, NULL, 50);
}
}
}
}
return 1;
}
void MsgScrollNewUI::Display(bool full_redraw) {
MsgText *token;
uint16 y = area.top + 4;
uint16 total_length = 0;
Std::list<MsgLine *>::iterator iter;
iter = msg_buf.begin();
for (uint16 i = 0; i < position && iter != msg_buf.end(); i++)
iter++;
for (uint16 i = 0; i < scroll_height && iter != msg_buf.end(); i++, iter++) {
MsgLine *msg_line = *iter;
Std::list<MsgText *>::iterator iter1;
iter1 = msg_line->text.begin();
//if not last record or if last record is not an empty line.
if (i + position < ((int)msg_buf.size() - 1) || (iter1 != msg_line->text.end() && ((*iter)->total_length != 0))) {
if (bg_color != 255) {
if (solid_bg)
screen->fill(bg_color, area.left, y + (i == 0 ? -4 : 4), scroll_width * 7 + 8, (i == 0 ? 18 : 10));
else
screen->stipple_8bit(bg_color, area.left, y + (i == 0 ? -4 : 4), scroll_width * 7 + 8, (i == 0 ? 18 : 10));
}
if (border_color != 255) {
screen->fill(border_color, area.left, y + (i == 0 ? -4 : 4), 1, (i == 0 ? 18 : 10));
screen->fill(border_color, area.left + scroll_width * 7 + 7, y + (i == 0 ? -4 : 4), 1, (i == 0 ? 18 : 10));
}
for (total_length = 0; iter1 != msg_line->text.end() ; iter1++) {
token = *iter1;
total_length += token->font->drawString(screen, token->s.c_str(), area.left + 4 + 4 + total_length, y + 4, 0, 0); //FIX for hardcoded font height
}
y += 10;
}
}
if (input_char != 0)
font->drawChar(screen, get_char_from_input_char(), total_length + 8, y - 6);
if (border_color != 255 && y != area.top + 4) {
screen->fill(border_color, area.left, y + 4, scroll_width * 7 + 8, 1); //draw bottom border
}
/* Debug
char buf[10];
snprintf(buf, 10, "%d", position);
font_normal->drawString(screen, buf, 160, 10);
snprintf(buf, 10, "%d", (int)msg_buf.size());
font_normal->drawString(screen, buf, 160, 20);
*/
screen->update(area.left, area.top, scroll_width * 7 + 8, scroll_height * 10 + 8);
}
GUI_status MsgScrollNewUI::KeyDown(const Common::KeyState &key) {
MsgScrollEventType event = SCROLL_ESCAPE;
/*
switch(key.keycode)
{
case Common::KEYCODE_PAGEDOWN: if(input_mode) event = SCROLL_DOWN; break;
case Common::KEYCODE_PAGEUP: if(input_mode) event = SCROLL_UP; break;
default : break;
}
*/
if (scroll_movement_event(event) == GUI_YUM)
return GUI_YUM;
return MsgScroll::KeyDown(key);
}
GUI_status MsgScrollNewUI::MouseDown(int x, int y, Shared::MouseButton button) {
MsgScrollEventType event = SCROLL_ESCAPE;
return scroll_movement_event(event);
}
GUI_status MsgScrollNewUI::scroll_movement_event(MsgScrollEventType event) {
switch (event) {
case SCROLL_UP :
if (position > 0) {
timer = new TimedCallback(this, NULL, 2000);
position--;
grab_focus();
}
return GUI_YUM;
case SCROLL_DOWN :
timer = new TimedCallback(this, NULL, 2000);
if (position < msg_buf.size())
position++;
return (GUI_YUM);
default :
release_focus();
new TimedCallback(this, NULL, 50);
break;
}
return GUI_PASS;
}
MsgLine *MsgScrollNewUI::add_new_line() {
MsgLine *line = MsgScroll::add_new_line();
if (position + scroll_height < (uint16)msg_buf.size()) {
position++;
} else if (position + scroll_height > scrollback_height) {
position--;
}
return line;
}
} // End of namespace Nuvie
} // End of namespace Ultima