/* 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::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::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) { ScrollEventType 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) { ScrollEventType event = SCROLL_ESCAPE; return scroll_movement_event(event); } GUI_status MsgScrollNewUI::scroll_movement_event(ScrollEventType 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