Initial commit
This commit is contained in:
272
gui/widgets/richtext.cpp
Normal file
272
gui/widgets/richtext.cpp
Normal file
@@ -0,0 +1,272 @@
|
||||
/* 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 "common/system.h"
|
||||
#include "common/unicode-bidi.h"
|
||||
|
||||
#include "graphics/macgui/mactext.h"
|
||||
|
||||
#include "gui/gui-manager.h"
|
||||
|
||||
#include "gui/ThemeEngine.h"
|
||||
#include "gui/ThemeEval.h"
|
||||
|
||||
#include "gui/widgets/richtext.h"
|
||||
#include "gui/widgets/scrollbar.h"
|
||||
|
||||
namespace GUI {
|
||||
|
||||
const Graphics::TTFMap ttfFamily[] = {
|
||||
{"NotoSans-Regular.ttf", Graphics::kMacFontRegular},
|
||||
{"NotoSans-Bold.ttf", Graphics::kMacFontBold},
|
||||
{"NotoSerif-Italic.ttf", Graphics::kMacFontItalic},
|
||||
{"NotoSerif-Bold-Italic.ttf", Graphics::kMacFontBold | Graphics::kMacFontItalic},
|
||||
{nullptr, 0}
|
||||
};
|
||||
|
||||
RichTextWidget::RichTextWidget(GuiObject *boss, int x, int y, int w, int h, bool scale, const Common::U32String &text, const Common::U32String &tooltip)
|
||||
: Widget(boss, x, y, w, h, scale, tooltip), CommandSender(nullptr) {
|
||||
|
||||
_text = text;
|
||||
|
||||
init();
|
||||
}
|
||||
|
||||
RichTextWidget::RichTextWidget(GuiObject *boss, int x, int y, int w, int h, const Common::U32String &text, const Common::U32String &tooltip)
|
||||
: RichTextWidget(boss, x, y, w, h, false, text, tooltip) {
|
||||
}
|
||||
|
||||
RichTextWidget::RichTextWidget(GuiObject *boss, const Common::String &name, const Common::U32String &text, const Common::U32String &tooltip)
|
||||
: Widget(boss, name, tooltip), CommandSender(nullptr) {
|
||||
|
||||
_text = text;
|
||||
|
||||
init();
|
||||
}
|
||||
|
||||
void RichTextWidget::init() {
|
||||
setFlags(WIDGET_ENABLED | WIDGET_CLEARBG | WIDGET_TRACK_MOUSE | WIDGET_DYN_TOOLTIP);
|
||||
|
||||
_type = kRichTextWidget;
|
||||
|
||||
_verticalScroll = new ScrollBarWidget(this, _w - 16, 0, 16, _h);
|
||||
_verticalScroll->setTarget(this);
|
||||
_scrolledX = 0;
|
||||
_scrolledY = 0;
|
||||
|
||||
_innerMargin = g_gui.xmlEval()->getVar("Globals.RichTextWidget.InnerMargin", 0);
|
||||
_scrollbarWidth = g_gui.xmlEval()->getVar("Globals.Scrollbar.Width", 0);
|
||||
|
||||
_textWidth = MAX(1, _w - _scrollbarWidth - 2 * _innerMargin);
|
||||
_textHeight = MAX(1, _h - 2 * _innerMargin);
|
||||
|
||||
_limitH = 140;
|
||||
}
|
||||
|
||||
|
||||
RichTextWidget::~RichTextWidget() {
|
||||
delete _txtWnd;
|
||||
|
||||
if (_surface)
|
||||
_surface->free();
|
||||
|
||||
delete _surface;
|
||||
}
|
||||
|
||||
void RichTextWidget::handleMouseWheel(int x, int y, int direction) {
|
||||
_verticalScroll->handleMouseWheel(x, y, direction);
|
||||
}
|
||||
|
||||
void RichTextWidget::handleMouseDown(int x, int y, int button, int clickCount) {
|
||||
_mouseDownY = _mouseDownStartY = y;
|
||||
}
|
||||
|
||||
void RichTextWidget::handleMouseUp(int x, int y, int button, int clickCount) {
|
||||
// Allow some tiny finger slipping
|
||||
if (ABS(_mouseDownY - _mouseDownStartY) > 5) {
|
||||
_mouseDownY = _mouseDownStartY = 0;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
_mouseDownY = _mouseDownStartY = 0;
|
||||
|
||||
Common::String link = _txtWnd->getMouseLink(x - _innerMargin + _scrolledX, y - _innerMargin + _scrolledY).encode();
|
||||
|
||||
if (link.hasPrefixIgnoreCase("http"))
|
||||
g_system->openUrl(link);
|
||||
}
|
||||
|
||||
void RichTextWidget::handleMouseMoved(int x, int y, int button) {
|
||||
if (_mouseDownStartY == 0 || _mouseDownY == y)
|
||||
return;
|
||||
|
||||
int h = _txtWnd->getTextHeight();
|
||||
int prevScrolledY = _scrolledY;
|
||||
|
||||
_scrolledY = CLIP(_scrolledY - (y - _mouseDownY), 0, h);
|
||||
|
||||
_mouseDownY = y;
|
||||
|
||||
if (_scrolledY == prevScrolledY)
|
||||
return;
|
||||
|
||||
recalc();
|
||||
_verticalScroll->recalc();
|
||||
markAsDirty();
|
||||
}
|
||||
|
||||
void RichTextWidget::handleTooltipUpdate(int x, int y) {
|
||||
_tooltip = _txtWnd->getMouseLink(x - _innerMargin + _scrolledX, y - _innerMargin + _scrolledY);
|
||||
}
|
||||
|
||||
void RichTextWidget::handleCommand(CommandSender *sender, uint32 cmd, uint32 data) {
|
||||
Widget::handleCommand(sender, cmd, data);
|
||||
switch (cmd) {
|
||||
case kSetPositionCmd:
|
||||
_scrolledY = _verticalScroll->_currentPos;
|
||||
reflowLayout();
|
||||
g_gui.scheduleTopDialogRedraw();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void RichTextWidget::recalc() {
|
||||
_innerMargin = g_gui.xmlEval()->getVar("Globals.RichTextWidget.InnerMargin", 0);
|
||||
_scrollbarWidth = g_gui.xmlEval()->getVar("Globals.Scrollbar.Width", 0);
|
||||
_textWidth = MAX(1, _w - _scrollbarWidth - 2 * _innerMargin);
|
||||
_textHeight = MAX(1, _h - 2 * _innerMargin);
|
||||
_limitH = _textHeight;
|
||||
|
||||
// Workaround: Currently Graphics::MacText::setMaxWidth does not work well.
|
||||
// There is a known limitation that the size is skipped when the text contains table,
|
||||
// and there is also an issue with the font.
|
||||
// So for now we recreate the widget.
|
||||
// if (_txtWnd) {
|
||||
// _txtWnd->setMaxWidth(_textWidth);
|
||||
// if (_surface->w != _textWidth || _surface->h != _textHeight)
|
||||
// _surface->create(_textWidth, _textHeight, g_gui.getWM()->_pixelformat);
|
||||
// } else {
|
||||
// createWidget();
|
||||
// }
|
||||
if (!_surface || _surface->w != _textWidth) {
|
||||
delete _txtWnd;
|
||||
createWidget();
|
||||
} else if (_surface->h != _textHeight)
|
||||
_surface->create(_textWidth, _textHeight, g_gui.getWM()->_pixelformat);
|
||||
|
||||
int h = _txtWnd->getTextHeight();
|
||||
|
||||
if (h <= _limitH) _scrolledY = 0;
|
||||
if (_scrolledY > h - _limitH) _scrolledY = MAX(0, h - _limitH);
|
||||
|
||||
_verticalScroll->_numEntries = h;
|
||||
_verticalScroll->_currentPos = _scrolledY;
|
||||
_verticalScroll->_entriesPerPage = _limitH;
|
||||
_verticalScroll->_singleStep = _h / 4;
|
||||
_verticalScroll->setPos(_w - _scrollbarWidth, 0);
|
||||
_verticalScroll->setSize(_scrollbarWidth, _h - 1);
|
||||
}
|
||||
|
||||
void RichTextWidget::createWidget() {
|
||||
Graphics::MacWindowManager *wm = g_gui.getWM();
|
||||
|
||||
uint32 bg = wm->_pixelformat.ARGBToColor(0, 0xff, 0xff, 0xff); // transparent
|
||||
TextColorData *normal = g_gui.theme()->getTextColorData(kTextColorNormal);
|
||||
uint32 fg = wm->_pixelformat.RGBToColor(normal->r, normal->g, normal->b);
|
||||
|
||||
const int fontHeight = g_gui.xmlEval()->getVar("Globals.Font.Height", 25);
|
||||
|
||||
int newId;
|
||||
if (ConfMan.hasKey("gui_language") && !ConfMan.get("gui_language").empty())
|
||||
// MacFONTs do not contain diacritic marks or non-English characters, so we have to use TTF instead
|
||||
newId = wm->_fontMan->registerTTFFont(ttfFamily);
|
||||
else
|
||||
newId = Graphics::kMacFontNewYork;
|
||||
Graphics::MacFont macFont(newId, fontHeight, Graphics::kMacFontRegular);
|
||||
|
||||
_txtWnd = new Graphics::MacText(Common::U32String(), wm, &macFont, fg, bg, _textWidth, Graphics::kTextAlignLeft);
|
||||
|
||||
if (!_imageArchive.empty())
|
||||
_txtWnd->setImageArchive(_imageArchive);
|
||||
|
||||
_txtWnd->setMarkdownText(_text);
|
||||
|
||||
if (_surface)
|
||||
_surface->create(_textWidth, _textHeight, g_gui.getWM()->_pixelformat);
|
||||
else
|
||||
_surface = new Graphics::ManagedSurface(_textWidth, _textHeight, wm->_pixelformat);
|
||||
}
|
||||
|
||||
void RichTextWidget::reflowLayout() {
|
||||
Widget::reflowLayout();
|
||||
|
||||
recalc();
|
||||
|
||||
_verticalScroll->setVisible(_verticalScroll->_numEntries > _limitH); //show when there is something to scroll
|
||||
_verticalScroll->recalc();
|
||||
}
|
||||
|
||||
void RichTextWidget::drawWidget() {
|
||||
if (!_txtWnd)
|
||||
recalc();
|
||||
|
||||
g_gui.theme()->drawWidgetBackground(Common::Rect(_x, _y, _x + _w, _y + _h), ThemeEngine::kWidgetBackgroundPlain);
|
||||
|
||||
_surface->clear(g_gui.getWM()->_pixelformat.ARGBToColor(0, 0xff, 0xff, 0xff)); // transparent
|
||||
|
||||
_txtWnd->draw(_surface, 0, _scrolledY, _textWidth, _textHeight, 0, 0);
|
||||
|
||||
g_gui.theme()->drawManagedSurface(Common::Point(_x + _innerMargin, _y + _innerMargin), *_surface, Graphics::ALPHA_FULL);
|
||||
}
|
||||
|
||||
void RichTextWidget::draw() {
|
||||
Widget::draw();
|
||||
|
||||
if (_verticalScroll->isVisible()) {
|
||||
_verticalScroll->draw();
|
||||
}
|
||||
}
|
||||
|
||||
void RichTextWidget::markAsDirty() {
|
||||
Widget::markAsDirty();
|
||||
|
||||
if (_verticalScroll->isVisible()) {
|
||||
_verticalScroll->markAsDirty();
|
||||
}
|
||||
}
|
||||
|
||||
bool RichTextWidget::containsWidget(Widget *w) const {
|
||||
if (w == _verticalScroll || _verticalScroll->containsWidget(w))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
Widget *RichTextWidget::findWidget(int x, int y) {
|
||||
if (_verticalScroll->isVisible() && x >= _w - _scrollbarWidth)
|
||||
return _verticalScroll;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
} // End of namespace GUI
|
||||
Reference in New Issue
Block a user