Files
scummvm-cursorfix/engines/ultima/nuvie/views/scroll_widget_gump.cpp
2026-02-02 04:50:13 +01:00

308 lines
8.2 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#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/views/scroll_widget_gump.h"
#include "ultima/nuvie/actors/actor_manager.h"
#include "ultima/nuvie/core/timed_event.h"
#include "ultima/nuvie/keybinding/keys.h"
namespace Ultima {
namespace Nuvie {
// ScrollWidgetGump Class
ScrollWidgetGump::ScrollWidgetGump(const Configuration *cfg, Screen *s) :
arrow_up_rect(SCROLLWIDGETGUMP_W - 8 - 1, 4 + 1,
SCROLLWIDGETGUMP_W - 8 - 1 + 7, 4 + 1 + 5),
arrow_down_rect(SCROLLWIDGETGUMP_W - 8 - 1, SCROLLWIDGETGUMP_H - 8 + 3,
SCROLLWIDGETGUMP_W - 8 - 1 + 7, SCROLLWIDGETGUMP_H - 8 + 3 + 5) {
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);
font_color = 0; // black
font_highlight = FONT_COLOR_U6_HIGHLIGHT;
scroll_width = 40;
scroll_height = 10;
show_up_arrow = false;
show_down_arrow = false;
GUI_Widget::Init(nullptr, 0, 0, SCROLLWIDGETGUMP_W, SCROLLWIDGETGUMP_H);
add_new_line(); //MsgScroll requires a line to start.
position = 0;
// ignore_page_breaks = true;
}
ScrollWidgetGump::~ScrollWidgetGump() {
// ignore_page_breaks = false;
}
void ScrollWidgetGump::set_font(uint8 font_type) {
if (font_type == NUVIE_FONT_NORMAL) {
font = font_normal;
} else {
font = font_garg;
}
}
bool ScrollWidgetGump::is_garg_font() {
return (font == font_garg);
}
bool ScrollWidgetGump::can_fit_token_on_msgline(MsgLine *msg_line, MsgText *token) {
if (msg_line->get_display_width() + token->getDisplayWidth() > SCROLLWIDGETGUMP_W - 8 - 8) {
return false; //token doesn't fit on the current line.
}
return true;
}
bool ScrollWidgetGump::parse_token(MsgText *token) {
if (token->s[0] == '*') // We don't want page breaks in the scroll widget.
return true;
return MsgScroll::parse_token(token);
}
void ScrollWidgetGump::display_string(const Std::string &s) {
MsgScroll::display_string(s);
update_arrows();
}
void ScrollWidgetGump::Display(bool full_redraw) {
MsgText *token;
uint16 y = area.top + 4;
Std::list<MsgLine *>::iterator iter;
if (show_up_arrow) {
font_normal->drawChar(screen, FONT_UP_ARROW_CHAR, area.left + SCROLLWIDGETGUMP_W - 8, area.top + 4);
}
if (show_down_arrow) {
font_normal->drawChar(screen, FONT_DOWN_ARROW_CHAR, area.left + SCROLLWIDGETGUMP_W - 8, area.top + SCROLLWIDGETGUMP_H - 8);
}
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))) {
//screen->fill(26, area.left, y + (i==0?-4:4), scroll_width * 7 + 8, (i==0?18:10));
for (uint16 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, font_color, font_highlight); //FIX for hardcoded font height
}
y += 10;
}
}
screen->update(area.left, area.top, area.width(), area.height());
}
GUI_status ScrollWidgetGump::KeyDown(const Common::KeyState &key) {
ScrollEventType event = SCROLL_ESCAPE;
KeyBinder *keybinder = Game::get_game()->get_keybinder();
ActionType a = keybinder->get_ActionType(key);
switch (keybinder->GetActionKeyType(a)) {
case MSGSCROLL_DOWN_KEY:
event = SCROLL_PAGE_DOWN;
break;
case SOUTH_KEY:
event = SCROLL_DOWN;
break;
case MSGSCROLL_UP_KEY:
event = SCROLL_PAGE_UP;
break;
case NORTH_KEY:
event = SCROLL_UP;
break;
case HOME_KEY:
event = SCROLL_TO_BEGINNING;
break;
case END_KEY:
event = SCROLL_TO_END;
break;
default :
break;
}
if (scroll_movement_event(event) == GUI_YUM)
return GUI_YUM;
return MsgScroll::KeyDown(key);
}
GUI_status ScrollWidgetGump::MouseWheel(sint32 x, sint32 y) {
ScrollEventType event = SCROLL_ESCAPE;
if (y > 0)
event = SCROLL_UP;
if (y < 0)
event = SCROLL_DOWN;
return scroll_movement_event(event);
}
GUI_status ScrollWidgetGump::MouseDown(int x, int y, Events::MouseButton button) {
ScrollEventType event = SCROLL_ESCAPE;
switch (button) {
case Events::BUTTON_LEFT : {
x -= area.left;
y -= area.top;
if (HitRect(x, y, arrow_up_rect))
event = SCROLL_UP;
else if (HitRect(x, y, arrow_down_rect))
event = SCROLL_DOWN;
// FIXME - uncomment when we get a checkmark
// else if(show_down_arrow || show_up_arrow) // don't close if scrollable
// return GUI_YUM;
break;
}
default :
break;
}
return scroll_movement_event(event);
}
GUI_status ScrollWidgetGump::scroll_movement_event(ScrollEventType event) {
switch (event) {
case SCROLL_UP :
if (position > 0) {
//timer = new TimedCallback(this, nullptr, 2000);
position--;
update_arrows();
//grab_focus();
}
return GUI_YUM;
case SCROLL_DOWN :
//timer = new TimedCallback(this, nullptr, 2000);
if (page_break && position + scroll_height >= (int)msg_buf.size()) {
if (position + scroll_height == (int)msg_buf.size()) // break was just off the page so advance text
position++;
process_page_break();
update_arrows();
} else if (position + scroll_height < (int)msg_buf.size()) {
position++;
update_arrows();
}
return GUI_YUM;
case SCROLL_PAGE_UP:
if (position > 0) {
position = position > scroll_height ? position - scroll_height : 0;
update_arrows();
}
return GUI_YUM;
case SCROLL_PAGE_DOWN:
if (position + scroll_height < (int)msg_buf.size() || page_break) {
if (position + scroll_height >= (int)msg_buf.size())
position = (int)msg_buf.size();
else {
position += scroll_height;
update_arrows();
return GUI_YUM;
}
if (page_break) { // we didn't have enough text showing to fill out the current page.
position = msg_buf.size();
process_page_break();
}
update_arrows();
}
return GUI_YUM;
case SCROLL_TO_BEGINNING :
if (position > 0) {
position = 0;
update_arrows();
}
return GUI_YUM;
case SCROLL_TO_END :
if (position + scroll_height < (int)msg_buf.size() || page_break) {
while (position + scroll_height < (int)msg_buf.size() || page_break) {
if (page_break)
process_page_break();
else // added else just in case noting is added to the buffer
position++;
}
update_arrows();
}
return GUI_YUM;
default :
//release_focus();
//new TimedCallback(this, nullptr, 50);
break;
}
return GUI_PASS;
}
void ScrollWidgetGump::update_arrows() {
if (position == 0) {
show_up_arrow = false;
} else {
show_up_arrow = true;
}
if (position + scroll_height < (int)msg_buf.size() || page_break) {
show_down_arrow = true;
} else {
show_down_arrow = false;
}
}
} // End of namespace Nuvie
} // End of namespace Ultima