mirror of
https://github.com/scummvm/scummvm.git
synced 2026-06-20 05:45:29 +00:00
550 lines
12 KiB
C++
550 lines
12 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 "bagel/boflib/app.h"
|
|
#include "bagel/boflib/gfx/text.h"
|
|
#include "bagel/boflib/gui/list_box.h"
|
|
|
|
#include "bagel/boflib/std_keys.h"
|
|
|
|
namespace Bagel {
|
|
|
|
#define TEXT_ITEM_HEIGHT 24
|
|
|
|
#define COLOR_USE_DEFAULT 0xFFFFFFFF
|
|
|
|
|
|
CBofListBox::CBofListBox() {
|
|
_cTextColor = CTEXT_COLOR;
|
|
_cHighColor = CTEXT_COLOR;
|
|
_nTextSize = 10;
|
|
_nTextWeight = TEXT_NORMAL;
|
|
_nNumItems = 0;
|
|
_n1stVisible = 0;
|
|
_nPageSize = 0;
|
|
_pWork = nullptr;
|
|
_nItemHeight = TEXT_ITEM_HEIGHT;
|
|
_nState = LISTBOX_NORMAL;
|
|
_nTextFont = FONT_DEFAULT;
|
|
|
|
// Initialized the selected item
|
|
CBofListBox::clearSelection();
|
|
}
|
|
|
|
|
|
CBofListBox::~CBofListBox() {
|
|
// Kill the temporary work area
|
|
delete _pWork;
|
|
_pWork = nullptr;
|
|
|
|
deleteAll(false);
|
|
}
|
|
|
|
void CBofListBox::clearSelection() {
|
|
_nSelectedItem = -1;
|
|
}
|
|
|
|
void CBofListBox::insertBefore(int nIndex, const CBofString &cString, bool bRepaint) {
|
|
assert(isValidObject(this));
|
|
|
|
ListBoxItem lbi;
|
|
lbi._pTextStr = new CBofString(cString);
|
|
lbi._nTextLineColor = COLOR_USE_DEFAULT;
|
|
|
|
_cTextItems.insertBefore(nIndex, lbi);
|
|
|
|
// One more item
|
|
_nNumItems++;
|
|
|
|
clearSelection();
|
|
|
|
if (bRepaint && isCreated() && isVisible()) {
|
|
repaintAll();
|
|
}
|
|
}
|
|
|
|
|
|
void CBofListBox::insertAfter(int nIndex, const CBofString &cString, bool bRepaint) {
|
|
assert(isValidObject(this));
|
|
|
|
ListBoxItem lbi;
|
|
lbi._pTextStr = new CBofString(cString);
|
|
lbi._nTextLineColor = COLOR_USE_DEFAULT;
|
|
|
|
_cTextItems.insertAfter(nIndex, lbi);
|
|
|
|
// One more item
|
|
_nNumItems++;
|
|
|
|
if (bRepaint && isCreated() && isVisible()) {
|
|
repaintAll();
|
|
}
|
|
}
|
|
|
|
|
|
void CBofListBox::addToHead(const CBofString &cString, bool bRepaint) {
|
|
assert(isValidObject(this));
|
|
|
|
ListBoxItem lbi;
|
|
lbi._pTextStr = new CBofString(cString);
|
|
lbi._nTextLineColor = COLOR_USE_DEFAULT;
|
|
|
|
_cTextItems.addToHead(lbi);
|
|
|
|
// One more item
|
|
_nNumItems++;
|
|
|
|
clearSelection();
|
|
|
|
if (bRepaint && isCreated() && isVisible()) {
|
|
repaintAll();
|
|
}
|
|
}
|
|
|
|
|
|
void CBofListBox::addToTail(const CBofString &cString, bool bRepaint) {
|
|
assert(isValidObject(this));
|
|
|
|
ListBoxItem lbi;
|
|
lbi._pTextStr = new CBofString(cString);
|
|
lbi._nTextLineColor = COLOR_USE_DEFAULT;
|
|
|
|
_cTextItems.addToTail(lbi);
|
|
|
|
// One more item
|
|
_nNumItems++;
|
|
|
|
clearSelection();
|
|
|
|
if (bRepaint && isCreated() && isVisible()) {
|
|
repaintAll();
|
|
}
|
|
}
|
|
|
|
|
|
ErrorCode CBofListBox::delItem(int nIndex, bool bRepaint) {
|
|
assert(isValidObject(this));
|
|
assert(nIndex >= 0 && nIndex < _nNumItems);
|
|
|
|
_cTextItems.remove(nIndex);
|
|
|
|
// One less item
|
|
_nNumItems--;
|
|
|
|
if (_n1stVisible >= _nNumItems) {
|
|
_n1stVisible = _nNumItems - 1;
|
|
if (_n1stVisible < 0)
|
|
_n1stVisible = 0;
|
|
}
|
|
|
|
clearSelection();
|
|
|
|
|
|
if (bRepaint && isCreated() && isVisible()) {
|
|
repaintAll();
|
|
}
|
|
|
|
return _errCode;
|
|
}
|
|
|
|
ErrorCode CBofListBox::deleteAll(bool bRepaint) {
|
|
assert(isValidObject(this));
|
|
|
|
// Switch item to be pointer to cbofstring instead of the item itself
|
|
int nCount = _cTextItems.getCount();
|
|
|
|
for (int i = 0; i < nCount; i++) {
|
|
ListBoxItem lbi = _cTextItems.getNodeItem(i);
|
|
delete lbi._pTextStr;
|
|
}
|
|
|
|
_cTextItems.removeAll();
|
|
_nNumItems = 0;
|
|
_n1stVisible = 0;
|
|
|
|
clearSelection();
|
|
|
|
if (bRepaint && isCreated() && isVisible()) {
|
|
repaintAll();
|
|
}
|
|
|
|
return _errCode;
|
|
}
|
|
|
|
|
|
void CBofListBox::onLButtonDown(uint32 /*nFlags*/, CBofPoint *pPoint, void *) {
|
|
assert(isValidObject(this));
|
|
assert(pPoint != nullptr);
|
|
|
|
int nIndex = (pPoint->y / _nItemHeight) + _n1stVisible;
|
|
if (nIndex < _nNumItems) {
|
|
|
|
_nSelectedItem = nIndex; // Set the selected item
|
|
_nState = LISTBOX_SELECT;
|
|
|
|
if (_parent != nullptr) {
|
|
_parent->setPrevMouseDown(*pPoint);
|
|
_parent->onBofListBox(this, nIndex);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void CBofListBox::onLButtonDblClk(uint32 /*nFlags*/, CBofPoint *pPoint) {
|
|
assert(isValidObject(this));
|
|
assert(pPoint != nullptr);
|
|
|
|
int nIndex = (pPoint->y / _nItemHeight) + _n1stVisible;
|
|
|
|
if (nIndex < _nNumItems) {
|
|
_nSelectedItem = nIndex; // Set the selected item
|
|
_nState = LISTBOX_USENOW;
|
|
|
|
if (_parent != nullptr) {
|
|
_parent->setPrevMouseDown(*pPoint);
|
|
_parent->onBofListBox(this, nIndex);
|
|
}
|
|
}
|
|
|
|
setFocus();
|
|
}
|
|
|
|
|
|
void CBofListBox::onKeyHit(uint32 lKey, uint32 lRepCount) {
|
|
assert(isValidObject(this));
|
|
|
|
switch (lKey) {
|
|
case BKEY_HOME:
|
|
scrollTo(0);
|
|
break;
|
|
|
|
case BKEY_END:
|
|
scrollTo(_nNumItems);
|
|
break;
|
|
|
|
case BKEY_UP:
|
|
lineUp();
|
|
break;
|
|
|
|
case BKEY_DOWN:
|
|
lineDown();
|
|
break;
|
|
|
|
case BKEY_PAGEUP:
|
|
pageUp();
|
|
break;
|
|
|
|
case BKEY_PAGEDOWN:
|
|
pageDown();
|
|
break;
|
|
|
|
default:
|
|
// Call the previous windows onkeyhit
|
|
CBofWindow *pParent = getParent();
|
|
if (pParent && pParent != this) {
|
|
pParent->onKeyHit(lKey, lRepCount);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
ErrorCode CBofListBox::scrollUp(const int nLines) {
|
|
assert(isValidObject(this));
|
|
|
|
// If all the items fit on a single page, make this operation a no-op.
|
|
if (_nNumItems <= _nPageSize) {
|
|
return scrollTo(_n1stVisible);
|
|
}
|
|
|
|
int nNewLine = _n1stVisible - nLines;
|
|
|
|
if (nNewLine < 0) {
|
|
nNewLine = 0;
|
|
|
|
} else if (nNewLine > (_nNumItems - _nPageSize)) {
|
|
// If the line requested to be the top of the page
|
|
// would cause fewer than _nPageSize lines to be displayed,
|
|
// snap nNewLine to be equal to the top of the last full page.
|
|
nNewLine = (_nNumItems - _nPageSize);
|
|
}
|
|
|
|
return scrollTo(nNewLine);
|
|
}
|
|
|
|
ErrorCode CBofListBox::scrollTo(const int nLine) {
|
|
assert(isValidObject(this));
|
|
assert(nLine >= 0 && nLine <= _nNumItems);
|
|
|
|
// Only update the screen if the list actually moved
|
|
if (_n1stVisible != nLine) {
|
|
_n1stVisible = nLine;
|
|
|
|
if (nLine >= _nNumItems) {
|
|
assert(_nNumItems > 0);
|
|
_n1stVisible--;
|
|
}
|
|
|
|
// Show the text box
|
|
repaintAll();
|
|
}
|
|
|
|
return _errCode;
|
|
}
|
|
|
|
|
|
void CBofListBox::onPaint(CBofRect * /*pRect*/) {
|
|
assert(isValidObject(this));
|
|
|
|
_nPageSize = height() / _nItemHeight;
|
|
|
|
if (_pBackdrop == nullptr) {
|
|
saveBackground();
|
|
}
|
|
|
|
repaintAll();
|
|
}
|
|
|
|
|
|
void CBofListBox::killBackground() {
|
|
assert(isValidObject(this));
|
|
|
|
delete _pBackdrop;
|
|
_pBackdrop = nullptr;
|
|
}
|
|
|
|
|
|
ErrorCode CBofListBox::saveBackground() {
|
|
assert(isValidObject(this));
|
|
|
|
killBackground();
|
|
_pBackdrop = new CBofBitmap(width(), height(), CBofApp::getApp()->getPalette());
|
|
|
|
if ((_parent != nullptr) && (_parent->getBackdrop() != nullptr)) {
|
|
CBofRect cRect = _pBackdrop->getRect();
|
|
_parent->getBackdrop()->paint(_pBackdrop, &cRect, &_cWindowRect);
|
|
} else {
|
|
_pBackdrop->captureScreen(this, &_cRect);
|
|
}
|
|
|
|
return _errCode;
|
|
}
|
|
|
|
ErrorCode CBofListBox::createWorkArea() {
|
|
assert(isValidObject(this));
|
|
|
|
if (_pBackdrop == nullptr) {
|
|
saveBackground();
|
|
}
|
|
|
|
if (_pWork == nullptr) {
|
|
assert(_pBackdrop != nullptr);
|
|
_pWork = new CBofBitmap(width(), height(), _pBackdrop->getPalette());
|
|
}
|
|
|
|
return _errCode;
|
|
}
|
|
|
|
|
|
ErrorCode CBofListBox::repaintAll() {
|
|
assert(isValidObject(this));
|
|
|
|
if (!errorOccurred()) {
|
|
assert(isCreated());
|
|
|
|
int nCurFont = getFont();
|
|
setFont(_nTextFont);
|
|
|
|
createWorkArea();
|
|
|
|
if (_pWork != nullptr) {
|
|
_pWork->lock();
|
|
|
|
int nIndexedColor = _pWork->getPalette()->getNearestIndex(_cTextColor);
|
|
|
|
// prepare the background
|
|
//
|
|
assert(_pBackdrop != nullptr);
|
|
_pBackdrop->paint(_pWork);
|
|
|
|
for (int i = 0; i < _nPageSize; i++) {
|
|
CBofRect cRect;
|
|
cRect.setRect(0, i * _nItemHeight, width() - 1, (i + 1) * _nItemHeight - 1);
|
|
|
|
if (i + _n1stVisible < _nNumItems) {
|
|
// If this item is currently selected and we have a high color
|
|
if ((i + _n1stVisible == _nSelectedItem) && (_cHighColor != _cTextColor)) {
|
|
// display text highlighted
|
|
paintText(_pWork,
|
|
&cRect,
|
|
*(_cTextItems.getNodeItem(i + _n1stVisible)._pTextStr),
|
|
_nTextSize,
|
|
_nTextWeight,
|
|
_cHighColor,
|
|
JUSTIFY_LEFT,
|
|
FORMAT_TOP_LEFT | FORMAT_SINGLE_LINE,
|
|
getFont());
|
|
} else {
|
|
// Display text
|
|
// Allow list items of different colors.
|
|
RGBCOLOR rgbTextColor = _cTextColor;
|
|
if (_cTextItems.getNodeItem(i + _n1stVisible)._nTextLineColor != COLOR_USE_DEFAULT) {
|
|
rgbTextColor = _cTextItems.getNodeItem(i + _n1stVisible)._nTextLineColor;
|
|
}
|
|
|
|
paintText(_pWork,
|
|
&cRect,
|
|
*(_cTextItems.getNodeItem(i + _n1stVisible)._pTextStr),
|
|
_nTextSize,
|
|
_nTextWeight,
|
|
rgbTextColor,
|
|
JUSTIFY_LEFT,
|
|
FORMAT_TOP_LEFT | FORMAT_SINGLE_LINE,
|
|
getFont());
|
|
}
|
|
|
|
CBofPoint bl(cRect.bottomLeft()), br(cRect.bottomRight());
|
|
_pWork->line(&bl, &br, (byte)nIndexedColor);
|
|
}
|
|
}
|
|
|
|
// Show final image on screen
|
|
_pWork->paint(this);
|
|
|
|
_pWork->unlock();
|
|
}
|
|
|
|
// Reset the font
|
|
setFont(nCurFont);
|
|
}
|
|
|
|
return _errCode;
|
|
}
|
|
|
|
|
|
ErrorCode CBofListBox::repaintItem(int nIndex) {
|
|
assert(isValidObject(this));
|
|
|
|
if (!errorOccurred()) {
|
|
assert(nIndex >= 0 && nIndex < _nNumItems);
|
|
int nCurFont = getFont();
|
|
setFont(_nTextFont); // Set the proper font
|
|
|
|
// If this item is visible, then repaint it.
|
|
if (nIndex >= _n1stVisible && nIndex <= _n1stVisible + _nPageSize) {
|
|
int i = nIndex - _n1stVisible;
|
|
|
|
createWorkArea();
|
|
int nIndexedColor = _pWork->getPalette()->getNearestIndex(_cTextColor);
|
|
|
|
_pWork->lock();
|
|
|
|
// Calculate area for this text item
|
|
CBofRect cRect;
|
|
cRect.setRect(0, i * _nItemHeight, width() - 1, (i + 1) * _nItemHeight - 1);
|
|
|
|
// Prepare the background
|
|
assert(_pBackdrop != nullptr);
|
|
_pBackdrop->paint(_pWork, &cRect, &cRect);
|
|
|
|
// If this item is currently selected and we have a high color
|
|
if ((nIndex == _nSelectedItem) && (_cHighColor != _cTextColor)) {
|
|
// Display text highlighted
|
|
paintText(_pWork,
|
|
&cRect,
|
|
*(_cTextItems.getNodeItem(nIndex)._pTextStr),
|
|
_nTextSize,
|
|
_nTextWeight,
|
|
_cHighColor,
|
|
JUSTIFY_LEFT,
|
|
FORMAT_TOP_LEFT | FORMAT_SINGLE_LINE,
|
|
getFont());
|
|
|
|
} else {
|
|
// Display text
|
|
// Allow list items of different colors.
|
|
RGBCOLOR rgbTextColor = _cTextColor;
|
|
if (_cTextItems.getNodeItem(i + _n1stVisible)._nTextLineColor != COLOR_USE_DEFAULT) {
|
|
rgbTextColor = _cTextItems.getNodeItem(i + _n1stVisible)._nTextLineColor;
|
|
}
|
|
paintText(_pWork,
|
|
&cRect,
|
|
*(_cTextItems.getNodeItem(nIndex)._pTextStr),
|
|
_nTextSize,
|
|
_nTextWeight,
|
|
rgbTextColor,
|
|
JUSTIFY_LEFT,
|
|
FORMAT_TOP_LEFT | FORMAT_SINGLE_LINE,
|
|
getFont());
|
|
}
|
|
CBofPoint bl(cRect.bottomLeft()), br(cRect.bottomRight());
|
|
_pWork->line(&bl, &br, (byte)nIndexedColor);
|
|
|
|
// Show final image on screen
|
|
_pWork->paint(this, &cRect, &cRect);
|
|
|
|
_pWork->unlock();
|
|
}
|
|
|
|
// Reset the font
|
|
setFont(nCurFont);
|
|
}
|
|
|
|
return _errCode;
|
|
}
|
|
|
|
|
|
void CBofListBox::setSelectedItem(int nItem, bool bRepaint) {
|
|
assert(isValidObject(this));
|
|
|
|
// Set highlighted item
|
|
_nSelectedItem = nItem;
|
|
|
|
if (bRepaint) {
|
|
repaintAll();
|
|
}
|
|
}
|
|
|
|
|
|
CBofString CBofListBox::getText(int nIndex) {
|
|
return *(_cTextItems.getNodeItem(nIndex)._pTextStr);
|
|
}
|
|
|
|
|
|
void CBofListBox::setText(int nIndex, const CBofString &cStr) {
|
|
|
|
ListBoxItem lbi = _cTextItems.getNodeItem(nIndex);
|
|
*lbi._pTextStr = cStr;
|
|
|
|
_cTextItems.setNodeItem(nIndex, lbi);
|
|
}
|
|
|
|
|
|
void CBofListBox::setTextLineColor(int nIndex, RGBCOLOR rgbColor) {
|
|
|
|
ListBoxItem lbi = _cTextItems.getNodeItem(nIndex);
|
|
lbi._nTextLineColor = rgbColor;
|
|
|
|
_cTextItems.setNodeItem(nIndex, lbi);
|
|
}
|
|
|
|
} // namespace Bagel
|