1067 lines
32 KiB
C++
1067 lines
32 KiB
C++
// Copyright (c) Warwick Allison, 1999.
|
|
// Qt4 conversion copyright (c) Ray Chason, 2012-2014.
|
|
// NetHack may be freely redistributed. See license for details.
|
|
|
|
// qt_map.cpp -- the map window
|
|
|
|
extern "C" {
|
|
#include "hack.h"
|
|
|
|
extern glyph_map glyphmap[MAX_GLYPH]; /* from tile.c */
|
|
}
|
|
|
|
#include "qt_pre.h"
|
|
#include <QtGui/QtGui>
|
|
#if QT_VERSION >= 0x050000
|
|
#include <QtWidgets/QtWidgets>
|
|
#endif
|
|
#include "qt_post.h"
|
|
#include "qt_map.h"
|
|
#include "qt_map.moc"
|
|
#include "qt_click.h"
|
|
#include "qt_glyph.h"
|
|
#include "qt_set.h"
|
|
#include "qt_str.h"
|
|
|
|
// pet- and pile-mark xpm arrays moved out of qt_xpms.h so that we don't
|
|
// include it here anymore; including that header in two files resulted in
|
|
// two copies of all the static xpm data and all the rest is for qt_stat.cpp
|
|
//
|
|
/* XPM */
|
|
static const char *pet_mark_xpm[] = {
|
|
/* width height ncolors chars_per_pixel */
|
|
"8 7 2 1",
|
|
/* colors */
|
|
". c None",
|
|
" c #FF0000",
|
|
/* pixels */
|
|
"........",
|
|
".. . .",
|
|
". ",
|
|
". ",
|
|
".. .",
|
|
"... ..",
|
|
".... ..."
|
|
};
|
|
/* XPM */
|
|
static const char *pet_mark_small_xpm[] = {
|
|
/* width height ncolors chars_per_pixel */
|
|
"5 5 2 1",
|
|
/* colors */
|
|
". c None",
|
|
"X c #FF0000",
|
|
/* pixels */
|
|
".X.X.",
|
|
"XXXXX",
|
|
".XXX.",
|
|
"..X.."
|
|
};
|
|
/* XPM */
|
|
static const char *pile_mark_xpm[] = {
|
|
/* width height ncolors chars_per_pixel */
|
|
"5 5 2 1",
|
|
/* colors */
|
|
". c None",
|
|
"X c #00FF00",
|
|
/* pixels */
|
|
"..X..",
|
|
"..X..",
|
|
"XXXXX",
|
|
"..X..",
|
|
"..X.."
|
|
};
|
|
|
|
// temporary
|
|
extern int qt_compact_mode;
|
|
// end temporary
|
|
|
|
namespace nethack_qt_ {
|
|
|
|
|
|
NetHackQtMapViewport::NetHackQtMapViewport(NetHackQtClickBuffer& click_sink) :
|
|
QWidget(NULL),
|
|
rogue_font(NULL),
|
|
clicksink(click_sink),
|
|
change(10)
|
|
{
|
|
pet_annotation = QPixmap(qt_compact_mode ? pet_mark_small_xpm
|
|
: pet_mark_xpm);
|
|
pile_annotation = QPixmap(pile_mark_xpm);
|
|
|
|
Clear(); // initializes glyph[][], glyphttychar, glyphcolor, glyphflags
|
|
cursor.setX(0);
|
|
cursor.setY(0);
|
|
}
|
|
|
|
NetHackQtMapViewport::~NetHackQtMapViewport(void)
|
|
{
|
|
delete rogue_font; //rogue_font = NULL;
|
|
}
|
|
|
|
// pick a font to use for text map; rogue level is always displayed as text
|
|
void NetHackQtMapViewport::SetupTextmapFont(QPainter &painter)
|
|
{
|
|
QString fontfamily = iflags.wc_font_map ? iflags.wc_font_map
|
|
: "Monospace";
|
|
int maybebold = QFont::Normal;
|
|
if (fontfamily.right(5).toLower() == "-bold") {
|
|
fontfamily.truncate(fontfamily.length() - 5);
|
|
maybebold = QFont::Bold;
|
|
}
|
|
// Find font...
|
|
int pts = 5;
|
|
while (pts < 32) {
|
|
QFont f(fontfamily, pts, maybebold);
|
|
painter.setFont(QFont(fontfamily, pts));
|
|
QFontMetrics fm = painter.fontMetrics();
|
|
if (fm.QFM_WIDTH("M") > qt_settings->glyphs().width())
|
|
break;
|
|
if (fm.height() > qt_settings->glyphs().height())
|
|
break;
|
|
pts++;
|
|
}
|
|
rogue_font = new QFont(fontfamily, pts - 1);
|
|
}
|
|
|
|
void NetHackQtMapViewport::paintEvent(QPaintEvent* event)
|
|
{
|
|
NetHackQtGlyphs &glyphs = qt_settings->glyphs();
|
|
int gW = glyphs.width(),
|
|
gH = glyphs.height();
|
|
QRect area = event->rect();
|
|
QRect garea;
|
|
garea.setCoords(std::max(0, area.left() / gW),
|
|
std::max(0, area.top() / gH),
|
|
std::min(COLNO - 1, area.right() / gW),
|
|
std::min(ROWNO - 1, area.bottom() / gH));
|
|
|
|
QPainter painter;
|
|
painter.begin(this);
|
|
|
|
unsigned special, tileidx;
|
|
uint32 color;
|
|
uint32 framecolor;
|
|
|
|
if (Is_rogue_level(&u.uz) || iflags.wc_ascii_map) {
|
|
// You enter a VERY primitive world!
|
|
|
|
painter.setClipRect( event->rect() ); // (normally we don't clip)
|
|
painter.fillRect( event->rect(), Qt::black );
|
|
|
|
if (!rogue_font)
|
|
SetupTextmapFont(painter);
|
|
painter.setFont(*rogue_font);
|
|
|
|
for (int j = garea.top(); j <= garea.bottom(); j++) {
|
|
for (int i = garea.left(); i <= garea.right(); i++) {
|
|
char32_t ch = Glyphttychar(i, j);
|
|
|
|
special = Glyphflags(i, j);
|
|
if (SYMHANDLING(H_IBM)) {
|
|
ch = cp437(ch);
|
|
}
|
|
color = Glyphcolor(i, j);
|
|
painter.setPen(NetHackQtBind::nhcolor_to_pen(color));
|
|
if (!DrawWalls(painter, i * gW, j * gH, gW, gH, ch)) {
|
|
ushort utf16[3];
|
|
if (ch < 0x10000) {
|
|
utf16[0] = static_cast<ushort>(ch);
|
|
utf16[1] = 0;
|
|
} else {
|
|
utf16[0] = static_cast<ushort>((ch >> 10) + 0xD7C0);
|
|
utf16[1] = static_cast<ushort>((ch & 0x3FF) + 0xDC00);
|
|
utf16[2] = 0;
|
|
}
|
|
painter.drawText(i * gW, j * gH, gW, gH, Qt::AlignCenter,
|
|
QString::fromUtf16(utf16));
|
|
}
|
|
if ((special & MG_PET) != 0 && ::iflags.hilite_pet) {
|
|
painter.drawPixmap(QPoint(i * gW, j * gH),
|
|
pet_annotation);
|
|
} else if ((special & MG_OBJPILE) != 0
|
|
&& ::iflags.hilite_pile) {
|
|
painter.drawPixmap(QPoint(i * gW, j * gH),
|
|
pile_annotation);
|
|
}
|
|
framecolor = GlyphFramecolor(i, j);
|
|
if (framecolor != NO_COLOR) {
|
|
painter.setPen(NetHackQtBind::nhcolor_to_pen(framecolor));
|
|
painter.drawRect(i * qt_settings->glyphs().width(),
|
|
j * qt_settings->glyphs().height(),
|
|
qt_settings->glyphs().width() - 1,
|
|
qt_settings->glyphs().height() - 1);
|
|
}
|
|
}
|
|
}
|
|
|
|
painter.setFont(font());
|
|
} else { // tiles
|
|
for (int j = garea.top(); j <= garea.bottom(); j++) {
|
|
for (int i = garea.left(); i <= garea.right(); i++) {
|
|
unsigned short g = Glyph(i, j);
|
|
|
|
special = Glyphflags(i, j);
|
|
tileidx = Glyphtileidx(i, j);
|
|
glyphs.drawCell(painter, g, tileidx, i, j);
|
|
|
|
if ((special & MG_PET) != 0 && ::iflags.hilite_pet) {
|
|
painter.drawPixmap(QPoint(i * gW, j * gH),
|
|
pet_annotation);
|
|
} else if ((special & MG_OBJPILE) != 0
|
|
&& ::iflags.hilite_pile) {
|
|
painter.drawPixmap(QPoint(i * gW, j * gH),
|
|
pile_annotation);
|
|
}
|
|
framecolor = GlyphFramecolor(i, j);
|
|
if (framecolor != NO_COLOR) {
|
|
painter.setPen(NetHackQtBind::nhcolor_to_pen(framecolor));
|
|
painter.drawRect(i * qt_settings->glyphs().width(),
|
|
j * qt_settings->glyphs().height(),
|
|
qt_settings->glyphs().width() - 1,
|
|
qt_settings->glyphs().height() - 1);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (garea.contains(cursor)) {
|
|
if (Is_rogue_level(&u.uz)) {
|
|
painter.setPen( Qt::white );
|
|
} else {
|
|
int hp = !Upolyd ? u.uhp : u.mh,
|
|
hpmax = !Upolyd ? u.uhpmax : u.mhmax,
|
|
hp100 = hpmax ? (hp * 100 / hpmax) : 100;
|
|
|
|
// this uses a different color scheme from hitpoint bar but has
|
|
// the same cutoff thresholds (except for lack of separate 100%)
|
|
if (hp100 < 10 || hp < 5)
|
|
painter.setPen(Qt::magenta);
|
|
else if (hp100 < 25 || hp < 10 )
|
|
painter.setPen(Qt::red);
|
|
else if (hp100 < 50)
|
|
painter.setPen(QColor(0xff, 0xbf, 0x00)); // orange
|
|
else if (hp100 < 75)
|
|
painter.setPen(Qt::yellow);
|
|
else
|
|
painter.setPen(Qt::white);
|
|
}
|
|
|
|
painter.drawRect(cursor.x() * gW, cursor.y() * gH, gW - 1, gH - 1);
|
|
}
|
|
|
|
#if 0
|
|
if (area.intersects(messages_rect)) {
|
|
painter.setPen(Qt::black);
|
|
painter.drawText(viewport.contentsX() + 1, viewport.contentsY() + 1,
|
|
viewport.width(), 0,
|
|
(Qt::TextWordWrap | Qt::AlignTop
|
|
| Qt::AlignLeft | Qt::TextDontClip), messages);
|
|
painter.setPen(Qt::white);
|
|
painter.drawText(viewport.contentsX(), viewport.contentsY(),
|
|
viewport.width(), 0,
|
|
(Qt::TextWordWrap | Qt::AlignTop
|
|
| Qt::AlignLeft | Qt::TextDontClip), messages);
|
|
}
|
|
#endif
|
|
|
|
painter.end();
|
|
}
|
|
|
|
bool NetHackQtMapViewport::DrawWalls(QPainter& painter, int x, int y,
|
|
int w, int h, unsigned short ch)
|
|
{
|
|
enum wallbits {
|
|
w_left = 0x01,
|
|
w_right = 0x02,
|
|
w_up = 0x04,
|
|
w_down = 0x08,
|
|
w_sq_top = 0x10,
|
|
w_sq_bottom = 0x20,
|
|
w_sq_left = 0x40,
|
|
w_sq_right = 0x80
|
|
};
|
|
unsigned linewidth;
|
|
unsigned walls;
|
|
int x1, y1, x2, y2, x3, y3;
|
|
|
|
linewidth = ((w < h) ? w : h) / 8;
|
|
if (linewidth == 0)
|
|
linewidth = 1;
|
|
|
|
// Single walls
|
|
walls = 0;
|
|
switch (ch) {
|
|
case 0x2500: // box drawings light horizontal
|
|
walls = w_left | w_right;
|
|
break;
|
|
case 0x2502: // box drawings light vertical
|
|
walls = w_up | w_down;
|
|
break;
|
|
case 0x250C: // box drawings light down and right
|
|
walls = w_down | w_right;
|
|
break;
|
|
case 0x2510: // box drawings light down and left
|
|
walls = w_down | w_left;
|
|
break;
|
|
case 0x2514: // box drawings light up and right
|
|
walls = w_up | w_right;
|
|
break;
|
|
case 0x2518: // box drawings light up and left
|
|
walls = w_up | w_left;
|
|
break;
|
|
case 0x251C: // box drawings light vertical and right
|
|
walls = w_up | w_down | w_right;
|
|
break;
|
|
case 0x2524: // box drawings light vertical and left
|
|
walls = w_up | w_down | w_left;
|
|
break;
|
|
case 0x252C: // box drawings light down and horizontal
|
|
walls = w_down | w_left | w_right;
|
|
break;
|
|
case 0x2534: // box drawings light up and horizontal
|
|
walls = w_up | w_left | w_right;
|
|
break;
|
|
case 0x253C: // box drawings light vertical and horizontal
|
|
walls = w_up | w_down | w_left | w_right;
|
|
break;
|
|
}
|
|
|
|
if (walls != 0) {
|
|
x1 = x + w / 2;
|
|
switch (walls & (w_up | w_down)) {
|
|
case w_up:
|
|
painter.drawLine(x1, y, x1, y + h / 2);
|
|
break;
|
|
case w_down:
|
|
painter.drawLine(x1, y + h / 2, x1, y + h - 1);
|
|
break;
|
|
case w_up | w_down:
|
|
painter.drawLine(x1, y, x1, y + h - 1);
|
|
break;
|
|
}
|
|
|
|
y1 = y + h / 2;
|
|
switch (walls & (w_left | w_right)) {
|
|
case w_left:
|
|
painter.drawLine(x, y1, x + w / 2, y1);
|
|
break;
|
|
case w_right:
|
|
painter.drawLine(x + w / 2, y1, x + w - 1, y1);
|
|
break;
|
|
case w_left | w_right:
|
|
painter.drawLine(x, y1, x + w - 1, y1);
|
|
break;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
// Double walls
|
|
walls = 0;
|
|
switch (ch) {
|
|
case 0x2550: // box drawings double horizontal
|
|
walls = w_left | w_right | w_sq_top | w_sq_bottom;
|
|
break;
|
|
case 0x2551: // box drawings double vertical
|
|
walls = w_up | w_down | w_sq_left | w_sq_right;
|
|
break;
|
|
case 0x2554: // box drawings double down and right
|
|
walls = w_down | w_right | w_sq_top | w_sq_left;
|
|
break;
|
|
case 0x2557: // box drawings double down and left
|
|
walls = w_down | w_left | w_sq_top | w_sq_right;
|
|
break;
|
|
case 0x255A: // box drawings double up and right
|
|
walls = w_up | w_right | w_sq_bottom | w_sq_left;
|
|
break;
|
|
case 0x255D: // box drawings double up and left
|
|
walls = w_up | w_left | w_sq_bottom | w_sq_right;
|
|
break;
|
|
case 0x2560: // box drawings double vertical and right
|
|
walls = w_up | w_down | w_right | w_sq_left;
|
|
break;
|
|
case 0x2563: // box drawings double vertical and left
|
|
walls = w_up | w_down | w_left | w_sq_right;
|
|
break;
|
|
case 0x2566: // box drawings double down and horizontal
|
|
walls = w_down | w_left | w_right | w_sq_top;
|
|
break;
|
|
case 0x2569: // box drawings double up and horizontal
|
|
walls = w_up | w_left | w_right | w_sq_bottom;
|
|
break;
|
|
case 0x256C: // box drawings double vertical and horizontal
|
|
walls = w_up | w_down | w_left | w_right;
|
|
break;
|
|
}
|
|
|
|
if (walls != 0) {
|
|
x1 = x + w / 2 - linewidth;
|
|
x2 = x + w / 2 + linewidth;
|
|
x3 = x + w - 1;
|
|
y1 = y + h / 2 - linewidth;
|
|
y2 = y + h / 2 + linewidth;
|
|
y3 = y + h - 1;
|
|
if (walls & w_up) {
|
|
painter.drawLine(x1, y, x1, y1);
|
|
painter.drawLine(x2, y, x2, y1);
|
|
}
|
|
if (walls & w_down) {
|
|
painter.drawLine(x1, y2, x1, y3);
|
|
painter.drawLine(x2, y2, x2, y3);
|
|
}
|
|
if (walls & w_left) {
|
|
painter.drawLine(x, y1, x1, y1);
|
|
painter.drawLine(x, y2, x1, y2);
|
|
}
|
|
if (walls & w_right) {
|
|
painter.drawLine(x2, y1, x3, y1);
|
|
painter.drawLine(x2, y2, x3, y2);
|
|
}
|
|
if (walls & w_sq_top) {
|
|
painter.drawLine(x1, y1, x2, y1);
|
|
}
|
|
if (walls & w_sq_bottom) {
|
|
painter.drawLine(x1, y2, x2, y2);
|
|
}
|
|
if (walls & w_sq_left) {
|
|
painter.drawLine(x1, y1, x1, y2);
|
|
}
|
|
if (walls & w_sq_right) {
|
|
painter.drawLine(x2, y1, x2, y2);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
// Solid blocks
|
|
if (0x2591 <= ch && ch <= 0x2593) {
|
|
unsigned shade = ch - 0x2590;
|
|
QColor rgb(painter.pen().color());
|
|
QColor rgb2(rgb.red() * shade / 4,
|
|
rgb.green() * shade / 4,
|
|
rgb.blue() * shade / 4);
|
|
painter.fillRect(x, y, w, h, rgb2);
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
void NetHackQtMapViewport::mousePressEvent(QMouseEvent* event)
|
|
{
|
|
clicksink.Put(event->pos().x() / qt_settings->glyphs().width(),
|
|
event->pos().y() / qt_settings->glyphs().height(),
|
|
(event->button() == Qt::LeftButton) ? CLICK_1 : CLICK_2);
|
|
qApp->exit();
|
|
}
|
|
|
|
void NetHackQtMapViewport::updateTiles()
|
|
{
|
|
change.clear();
|
|
change.add(0, 0, COLNO, ROWNO);
|
|
delete rogue_font; rogue_font = NULL;
|
|
}
|
|
|
|
QSize NetHackQtMapViewport::sizeHint() const
|
|
{
|
|
return QSize(qt_settings->glyphs().width() * COLNO,
|
|
qt_settings->glyphs().height() * ROWNO);
|
|
}
|
|
|
|
QSize NetHackQtMapViewport::minimumSizeHint() const
|
|
{
|
|
return sizeHint();
|
|
}
|
|
|
|
void NetHackQtMapViewport::clickCursor()
|
|
{
|
|
clicksink.Put(cursor.x(), cursor.y(), CLICK_1);
|
|
qApp->exit();
|
|
}
|
|
|
|
// [re-]init map display to unexplored with no changed cells
|
|
void NetHackQtMapViewport::Clear()
|
|
{
|
|
for (int j = 0; j < ROWNO; ++j) {
|
|
//
|
|
// FIXME: map column 0 should be suppressed from being displayed
|
|
//
|
|
Glyph(0, j) = GLYPH_NOTHING;
|
|
Glyphttychar(0, j) = ' ';
|
|
Glyphcolor(0, j) = NO_COLOR;
|
|
GlyphFramecolor(0, j) = NO_COLOR;
|
|
Glyphflags(0, j) = 0U;
|
|
Glyphtileidx(0, j) = ::glyphmap[GLYPH_NOTHING].tileidx;
|
|
|
|
for (int i = 1; i < COLNO; ++i) {
|
|
Glyph(i, j) = GLYPH_UNEXPLORED;
|
|
Glyphttychar(i, j) = ' ';
|
|
Glyphcolor(i, j) = NO_COLOR;
|
|
GlyphFramecolor(i, j) = NO_COLOR;
|
|
Glyphflags(i, j) = 0U;
|
|
Glyphtileidx(i, j) = ::glyphmap[GLYPH_UNEXPLORED].tileidx;
|
|
}
|
|
}
|
|
|
|
change.clear();
|
|
change.add(0, 0, COLNO, ROWNO);
|
|
}
|
|
|
|
void NetHackQtMapViewport::Display(bool block)
|
|
{
|
|
int gW = qt_settings->glyphs().width(),
|
|
gH = qt_settings->glyphs().height();
|
|
|
|
for (int i = 0; i < change.clusters(); i++) {
|
|
const QRect& chg = change[i];
|
|
repaint(chg.x() * gW, chg.y() * gH,
|
|
chg.width() * gW, chg.height() * gH);
|
|
}
|
|
change.clear();
|
|
|
|
if (block) {
|
|
yn_function("Press a key when done viewing", NULL, '\0', TRUE);
|
|
}
|
|
}
|
|
|
|
void NetHackQtMapViewport::CursorTo(int x,int y)
|
|
{
|
|
Changed(cursor.x(), cursor.y());
|
|
cursor.setX(x);
|
|
cursor.setY(y);
|
|
Changed(cursor.x(), cursor.y());
|
|
}
|
|
|
|
void NetHackQtMapViewport::PrintGlyph(int x, int y,
|
|
const glyph_info *glyphinfo,
|
|
const glyph_info *bkglyphinfo)
|
|
{
|
|
Glyph(x, y) = (unsigned short) glyphinfo->glyph;
|
|
Glyphttychar(x, y) = (char32_t) glyphinfo->ttychar;
|
|
Glyphcolor(x, y) = (uint32) glyphinfo->gm.sym.color;
|
|
GlyphFramecolor(x, y) = (uint32) bkglyphinfo->framecolor;
|
|
#ifdef ENHANCED_SYMBOLS
|
|
if (SYMHANDLING(H_UTF8) && glyphinfo->gm.u && glyphinfo->gm.u->utf8str) {
|
|
Glyphttychar(x, y) = glyphinfo->gm.u->utf32ch;
|
|
}
|
|
#endif
|
|
if (glyphinfo->gm.customcolor != 0) {
|
|
uint32 nhcolor = COLORVAL(glyphinfo->gm.customcolor);
|
|
if (glyphinfo->gm.customcolor == nhcolor) {
|
|
/* 24-bit color */
|
|
Glyphcolor(x, y) = COLORVAL(glyphinfo->gm.customcolor) | 0x80000000;
|
|
} else {
|
|
/* NH_BASIC_COLOR */
|
|
Glyphcolor(x, y) = COLORVAL(glyphinfo->gm.customcolor);
|
|
}
|
|
}
|
|
Glyphflags(x, y) = glyphinfo->gm.glyphflags;
|
|
Glyphtileidx(x, y) = (unsigned short) glyphinfo->gm.tileidx;
|
|
Changed(x, y);
|
|
}
|
|
|
|
void NetHackQtMapViewport::Changed(int x, int y)
|
|
{
|
|
change.add(x, y);
|
|
}
|
|
|
|
NetHackQtMapWindow2::NetHackQtMapWindow2(NetHackQtClickBuffer& click_sink) :
|
|
QScrollArea(NULL),
|
|
m_viewport(new NetHackQtMapViewport(click_sink))
|
|
{
|
|
QPalette palette;
|
|
palette.setColor(backgroundRole(), Qt::black);
|
|
setPalette(palette);
|
|
|
|
setWidget(m_viewport);
|
|
|
|
connect(qt_settings, SIGNAL(tilesChanged()), this, SLOT(updateTiles()));
|
|
updateTiles();
|
|
}
|
|
|
|
void NetHackQtMapWindow2::updateTiles()
|
|
{
|
|
NetHackQtGlyphs& glyphs = qt_settings->glyphs();
|
|
int gW = glyphs.width();
|
|
int gH = glyphs.height();
|
|
// Be exactly the size we want to be - full map...
|
|
m_viewport->resize(COLNO * gW, ROWNO * gH);
|
|
|
|
verticalScrollBar()->setSingleStep(gH);
|
|
verticalScrollBar()->setPageStep(gH);
|
|
horizontalScrollBar()->setSingleStep(gW);
|
|
horizontalScrollBar()->setPageStep(gW);
|
|
|
|
m_viewport->updateTiles();
|
|
Display(false);
|
|
|
|
emit resized();
|
|
}
|
|
|
|
void NetHackQtMapWindow2::clearMessages()
|
|
{
|
|
messages = "";
|
|
update(messages_rect);
|
|
messages_rect = QRect();
|
|
}
|
|
|
|
void NetHackQtMapWindow2::putMessage(int attr UNUSED, const QString& text)
|
|
{
|
|
if (!messages.isEmpty())
|
|
messages += "\n";
|
|
messages += QString(text).replace(QChar(0x200B), "");
|
|
#if 0
|
|
QFontMetrics fm = fontMetrics();
|
|
messages_rect = fm.boundingRect(viewport.contentsX(), viewport.contentsY(),
|
|
viewport.width(), 0,
|
|
(Qt::TextWordWrap | Qt::AlignTop
|
|
| Qt::AlignLeft | Qt::TextDontClip),
|
|
messages);
|
|
update(messages_rect);
|
|
#endif
|
|
}
|
|
|
|
void NetHackQtMapWindow2::clickCursor()
|
|
{
|
|
m_viewport->clickCursor();
|
|
}
|
|
|
|
QWidget *NetHackQtMapWindow2::Widget()
|
|
{
|
|
return this;
|
|
}
|
|
|
|
void NetHackQtMapWindow2::Clear()
|
|
{
|
|
m_viewport->Clear();
|
|
}
|
|
|
|
void NetHackQtMapWindow2::Display(bool block)
|
|
{
|
|
m_viewport->Display(block);
|
|
}
|
|
|
|
void NetHackQtMapWindow2::CursorTo(int x,int y)
|
|
{
|
|
m_viewport->CursorTo(x, y);
|
|
}
|
|
|
|
void NetHackQtMapWindow2::PutStr(int attr UNUSED, const QString& text UNUSED)
|
|
{
|
|
puts("unexpected PutStr in MapWindow");
|
|
}
|
|
|
|
void NetHackQtMapWindow2::ClipAround(int x,int y)
|
|
{
|
|
// Convert to pixel of center of tile
|
|
x=x*qt_settings->glyphs().width()+qt_settings->glyphs().width()/2;
|
|
y=y*qt_settings->glyphs().height()+qt_settings->glyphs().height()/2;
|
|
|
|
// Then ensure that pixel is visible
|
|
ensureVisible(x,y,width()*0.45,height()*0.45);
|
|
}
|
|
|
|
void NetHackQtMapWindow2::PrintGlyph(int x,int y,
|
|
const glyph_info *glyphinfo,
|
|
const glyph_info *bkglyphinfo)
|
|
{
|
|
m_viewport->PrintGlyph(x, y, glyphinfo, bkglyphinfo);
|
|
}
|
|
|
|
#if 0 //RLC
|
|
// XXX Hmmm... crash after saving bones file if Map window is
|
|
// XXX deleted. Strange bug somewhere.
|
|
bool NetHackQtMapWindow::Destroy() { return false; }
|
|
|
|
NetHackQtMapWindow::NetHackQtMapWindow(NetHackQtClickBuffer& click_sink) :
|
|
clicksink(click_sink),
|
|
change(10),
|
|
rogue_font(0)
|
|
{
|
|
viewport.addChild(this);
|
|
|
|
QPalette palette;
|
|
palette.setColor(backgroundRole(), Qt::black);
|
|
setPalette(palette);
|
|
palette.setColor(viewport.backgroundRole(), Qt::black);
|
|
viewport.setPalette(palette);
|
|
|
|
pet_annotation = QPixmap(qt_compact_mode ? pet_mark_small_xpm
|
|
: pet_mark_xpm);
|
|
pile_annotation = QPixmap(pile_mark_xpm);
|
|
|
|
cursor.setX(0);
|
|
cursor.setY(0);
|
|
Clear();
|
|
|
|
connect(qt_settings,SIGNAL(tilesChanged()),this,SLOT(updateTiles()));
|
|
connect(&viewport, SIGNAL(contentsMoving(int,int)), this,
|
|
SLOT(moveMessages(int,int)));
|
|
|
|
updateTiles();
|
|
//setFocusPolicy(Qt::StrongFocus);
|
|
}
|
|
|
|
void NetHackQtMapWindow::moveMessages(int x, int y)
|
|
{
|
|
QRect u = messages_rect;
|
|
messages_rect.moveTopLeft(QPoint(x,y));
|
|
u |= messages_rect;
|
|
update(u);
|
|
}
|
|
|
|
void NetHackQtMapWindow::clearMessages()
|
|
{
|
|
messages = "";
|
|
update(messages_rect);
|
|
messages_rect = QRect();
|
|
}
|
|
|
|
void NetHackQtMapWindow::putMessage(int attr, const QString& text)
|
|
{
|
|
if ( !messages.isEmpty() )
|
|
messages += "\n";
|
|
messages += QString(text).replace(QChar(0x200B), "");
|
|
QFontMetrics fm = fontMetrics();
|
|
messages_rect = fm.boundingRect(viewport.contentsX(), viewport.contentsY(),
|
|
viewport.width(), 0,
|
|
(Qt::TextWordWrap | Qt::AlignTop
|
|
| Qt::AlignLeft | Qt::TextDontClip),
|
|
messages);
|
|
update(messages_rect);
|
|
}
|
|
|
|
void NetHackQtMapWindow::updateTiles()
|
|
{
|
|
NetHackQtGlyphs& glyphs = qt_settings->glyphs();
|
|
int gw = glyphs.width();
|
|
int gh = glyphs.height();
|
|
// Be exactly the size we want to be - full map...
|
|
resize(COLNO*gw,ROWNO*gh);
|
|
|
|
viewport.verticalScrollBar()->setSingleStep(gh);
|
|
viewport.verticalScrollBar()->setPageStep(gh);
|
|
viewport.horizontalScrollBar()->setSingleStep(gw);
|
|
viewport.horizontalScrollBar()->setPageStep(gw);
|
|
/*
|
|
viewport.setMaximumSize(
|
|
gw*COLNO + viewport.verticalScrollBar()->width(),
|
|
gh*ROWNO + viewport.horizontalScrollBar()->height()
|
|
);
|
|
*/
|
|
viewport.updateScrollBars();
|
|
|
|
change.clear();
|
|
change.add(0,0,COLNO,ROWNO);
|
|
delete rogue_font; rogue_font = 0;
|
|
Display(false);
|
|
|
|
emit resized();
|
|
}
|
|
|
|
NetHackQtMapWindow::~NetHackQtMapWindow()
|
|
{
|
|
// Remove from viewport porthole, since that is a destructible member.
|
|
viewport.removeChild(this);
|
|
setParent(0,0);
|
|
}
|
|
|
|
QWidget* NetHackQtMapWindow::Widget()
|
|
{
|
|
return &viewport;
|
|
}
|
|
|
|
void NetHackQtMapWindow::Scroll(int dx, int dy)
|
|
{
|
|
if (viewport.horizontalScrollBar()->isVisible()) {
|
|
while (dx<0) { viewport.horizontalScrollBar()->triggerAction(QAbstractSlider::SliderPageStepSub); dx++; }
|
|
while (dx>0) { viewport.horizontalScrollBar()->triggerAction(QAbstractSlider::SliderPageStepAdd); dx--; }
|
|
}
|
|
if (viewport.verticalScrollBar()->isVisible()) {
|
|
while (dy<0) { viewport.verticalScrollBar()->triggerAction(QAbstractSlider::SliderPageStepSub); dy++; }
|
|
while (dy>0) { viewport.verticalScrollBar()->triggerAction(QAbstractSlider::SliderPageStepAdd); dy--; }
|
|
}
|
|
}
|
|
|
|
void NetHackQtMapWindow::Clear()
|
|
{
|
|
for (int j = 0; j < ROWNO; ++j) {
|
|
Glyph(0, j) = GLYPH_NOTHING;
|
|
Glyphcolor(0, j) = NO_COLOR;
|
|
GlyphFramecolor(0, j) = NO_COLOR;
|
|
Glyphttychar(0, j) = ' ';
|
|
Glyphflags(0, j) = 0;
|
|
Glyphtileidx(0, j) = ::glyphmap[GLYPH_NOTHING].tileidx;
|
|
|
|
for (int i = 1; i < COLNO; ++i) {
|
|
Glyph(i, j) = GLYPH_UNEXPLORED;
|
|
Glyphcolor(i, j) = NO_COLOR;
|
|
GlyphFramecolor(i, j) = NO_COLOR;
|
|
Glyphttychar(i, j) = ' ';
|
|
Glyphflags(i, j) = 0;
|
|
Glyphtileidx(i, j) = ::glyphmap[GLYPH_UNEXPLORED].tileidx;
|
|
}
|
|
}
|
|
|
|
change.clear();
|
|
change.add(0,0,COLNO,ROWNO);
|
|
}
|
|
|
|
void NetHackQtMapWindow::clickCursor()
|
|
{
|
|
clicksink.Put(cursor.x(),cursor.y(),CLICK_1);
|
|
qApp->exit();
|
|
}
|
|
|
|
void NetHackQtMapWindow::mousePressEvent(QMouseEvent* event)
|
|
{
|
|
clicksink.Put(
|
|
event->pos().x()/qt_settings->glyphs().width(),
|
|
event->pos().y()/qt_settings->glyphs().height(),
|
|
event->button()==Qt::LeftButton ? CLICK_1 : CLICK_2
|
|
);
|
|
qApp->exit();
|
|
}
|
|
|
|
void NetHackQtMapWindow::paintEvent(QPaintEvent* event)
|
|
{
|
|
QRect area=event->rect();
|
|
QRect garea;
|
|
garea.setCoords(
|
|
std::max(0,area.left()/qt_settings->glyphs().width()),
|
|
std::max(0,area.top()/qt_settings->glyphs().height()),
|
|
std::min(COLNO-1,area.right()/qt_settings->glyphs().width()),
|
|
std::min(ROWNO-1,area.bottom()/qt_settings->glyphs().height())
|
|
);
|
|
|
|
QPainter painter;
|
|
|
|
painter.begin(this);
|
|
|
|
if (is_rogue_level(&u.uz) || iflags.wc_ascii_map) {
|
|
// You enter a VERY primitive world!
|
|
|
|
painter.setClipRect( event->rect() ); // (normally we don't clip)
|
|
painter.fillRect( event->rect(), Qt::black );
|
|
|
|
if ( !rogue_font ) {
|
|
// Find font...
|
|
int pts = 5;
|
|
QString fontfamily = iflags.wc_font_map
|
|
? iflags.wc_font_map : "Courier";
|
|
bool bold = false;
|
|
if ( fontfamily.right(5).toLower() == "-bold" ) {
|
|
fontfamily.truncate(fontfamily.length()-5);
|
|
bold = true;
|
|
}
|
|
while ( pts < 32 ) {
|
|
QFont f(fontfamily, pts, bold ? QFont::Bold : QFont::Normal);
|
|
painter.setFont(QFont(fontfamily, pts));
|
|
QFontMetrics fm = painter.fontMetrics();
|
|
if ( fm.width("M") > qt_settings->glyphs().width() )
|
|
break;
|
|
if ( fm.height() > qt_settings->glyphs().height() )
|
|
break;
|
|
pts++;
|
|
}
|
|
rogue_font = new QFont(fontfamily,pts-1);
|
|
}
|
|
painter.setFont(*rogue_font);
|
|
|
|
for (int j=garea.top(); j<=garea.bottom(); j++) {
|
|
for (int i=garea.left(); i<=garea.right(); i++) {
|
|
unsigned short g=Glyph(i,j);
|
|
uint32 color = Glyphcolor(i,j);
|
|
uint32 framecolor = GlyphFramecolor(i,j);
|
|
char32_t ch = Glyphttychar(i,j);
|
|
unsigned special = Glyphflags(i,j);
|
|
|
|
if (framecolor != NO_COLOR) {
|
|
painter.fillRect(i*qt_settings->glyphs().width(),
|
|
j*qt_settings->glyphs().height(),
|
|
qt_settings->glyphs().width()-1,
|
|
qt_settings->glyphs().height()-1,
|
|
nhcolor_to_pen(framecolor).color());
|
|
}
|
|
painter.setPen( Qt::green );
|
|
painter.setPen( nhcolor_to_pen(color) );
|
|
painter.drawText(
|
|
i*qt_settings->glyphs().width(),
|
|
j*qt_settings->glyphs().height(),
|
|
qt_settings->glyphs().width(),
|
|
qt_settings->glyphs().height(),
|
|
Qt::AlignCenter,
|
|
QString(QChar(ch)).left(1)
|
|
);
|
|
if ((special & MG_PET) != 0 && ::iflags.hilite_pet) {
|
|
painter.drawPixmap(QPoint(i*qt_settings->glyphs().width(),
|
|
j*qt_settings->glyphs().height()),
|
|
pet_annotation);
|
|
} else if ((special & MG_OBJPILE) != 0
|
|
&& ::iflags.hilite_pile) {
|
|
painter.drawPixmap(QPoint(i*qt_settings->glyphs().width(),
|
|
j*qt_settings->glyphs().height()),
|
|
pile_annotation);
|
|
}
|
|
if (framecolor != NO_COLOR) {
|
|
painter.setPen( nhcolor_to_pen(framecolor) );
|
|
painter.drawRect(i*qt_settings->glyphs().width(),
|
|
j*qt_settings->glyphs().height(),
|
|
qt_settings->glyphs().width()-1,
|
|
qt_settings->glyphs().height()-1);
|
|
}
|
|
}
|
|
}
|
|
|
|
painter.setFont(font());
|
|
} else {
|
|
for (int j=garea.top(); j<=garea.bottom(); j++) {
|
|
for (int i=garea.left(); i<=garea.right(); i++) {
|
|
unsigned short g=Glyph(i,j);
|
|
unsigned special = Glyphflags(i,j);
|
|
unsigned short tileidx = Glyphtileidx(i,j);
|
|
uint32 framecolor = GlyphFramecolor(i,j);
|
|
|
|
qt_settings->glyphs().drawCell(painter, g, tileidx, i, j);
|
|
if ((special & MG_PET) != 0 && ::iflags.hilite_pet) {
|
|
painter.drawPixmap(QPoint(i*qt_settings->glyphs().width(),
|
|
j*qt_settings->glyphs().height()),
|
|
pet_annotation);
|
|
} else if ((special & MG_OBJPILE) != 0
|
|
&& ::iflags.hilite_pile) {
|
|
painter.drawPixmap(QPoint(i*qt_settings->glyphs().width(),
|
|
j*qt_settings->glyphs().height()),
|
|
pile_annotation);
|
|
}
|
|
if (framecolor != NO_COLOR) {
|
|
painter.setPen( nhcolor_to_pen(framecolor) );
|
|
painter.drawRect(i*qt_settings->glyphs().width(),
|
|
j*qt_settings->glyphs().height(),
|
|
qt_settings->glyphs().width()-1,
|
|
qt_settings->glyphs().height()-1);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (garea.contains(cursor)) {
|
|
if (Is_rogue_level(&u.uz)) {
|
|
painter.setPen( Qt::white );
|
|
} else {
|
|
int hp100;
|
|
if (Upolyd) {
|
|
hp100=u.mhmax ? u.mh*100/u.mhmax : 100;
|
|
} else {
|
|
hp100=u.uhpmax ? u.uhp*100/u.uhpmax : 100;
|
|
}
|
|
|
|
if (hp100 > 75)
|
|
painter.setPen(Qt::white);
|
|
else if (hp100 > 50)
|
|
painter.setPen(Qt::yellow);
|
|
else if (hp100 > 25)
|
|
painter.setPen(QColor(0xff, 0xbf, 0x00)); // orange
|
|
else if (hp100 > 10)
|
|
painter.setPen(Qt::red);
|
|
else
|
|
painter.setPen(Qt::magenta);
|
|
}
|
|
|
|
painter.drawRect(cursor.x() * qt_settings->glyphs().width(),
|
|
cursor.y() * qt_settings->glyphs().height(),
|
|
qt_settings->glyphs().width() - 1,
|
|
qt_settings->glyphs().height() - 1);
|
|
}
|
|
|
|
if (area.intersects(messages_rect)) {
|
|
painter.setPen(Qt::black);
|
|
painter.drawText(viewport.contentsX() + 1, viewport.contentsY() + 1,
|
|
viewport.width(), 0,
|
|
(Qt::TextWordWrap | Qt::AlignTop
|
|
| Qt::AlignLeft | Qt::TextDontClip), messages);
|
|
painter.setPen(Qt::white);
|
|
painter.drawText(viewport.contentsX(), viewport.contentsY(),
|
|
viewport.width(), 0,
|
|
(Qt::TextWordWrap | Qt::AlignTop
|
|
| Qt::AlignLeft | Qt::TextDontClip), messages);
|
|
}
|
|
|
|
painter.end();
|
|
}
|
|
|
|
void NetHackQtMapWindow::Display(bool block)
|
|
{
|
|
for (int i=0; i<change.clusters(); i++) {
|
|
const QRect& ch=change[i];
|
|
repaint(
|
|
ch.x()*qt_settings->glyphs().width(),
|
|
ch.y()*qt_settings->glyphs().height(),
|
|
ch.width()*qt_settings->glyphs().width(),
|
|
ch.height()*qt_settings->glyphs().height()
|
|
);
|
|
}
|
|
|
|
change.clear();
|
|
|
|
if (block) {
|
|
yn_function("Press a key when done viewing",0,'\0');
|
|
}
|
|
}
|
|
|
|
void NetHackQtMapWindow::CursorTo(int x,int y)
|
|
{
|
|
Changed(cursor.x(),cursor.y());
|
|
cursor.setX(x);
|
|
cursor.setY(y);
|
|
Changed(cursor.x(),cursor.y());
|
|
}
|
|
|
|
void NetHackQtMapWindow::PutStr(int attr, const QString& text)
|
|
{
|
|
puts("unexpected PutStr in MapWindow");
|
|
}
|
|
|
|
void NetHackQtMapWindow::ClipAround(int x,int y)
|
|
{
|
|
// Convert to pixel of center of tile
|
|
x=x*qt_settings->glyphs().width()+qt_settings->glyphs().width()/2;
|
|
y=y*qt_settings->glyphs().height()+qt_settings->glyphs().height()/2;
|
|
|
|
// Then ensure that pixel is visible
|
|
viewport.center(x,y,0.45,0.45);
|
|
}
|
|
|
|
void NetHackQtMapWindow::PrintGlyph(int x,int y, const glyph_info *glyphinfo)
|
|
{
|
|
Glyph(x,y)=glyphinfo->glyph;
|
|
Glyphttychar(x,y)=glyphinfo->ttychar;
|
|
Glyphcolor(x,y)=glyphinfo->color;
|
|
GlyphFramecolor(x,y)=bkglyphinfo->framecolor;
|
|
#ifdef ENHANCED_SYMBOLS
|
|
if (SYMHANDLING(H_UTF8)
|
|
&& glyphinfo->gm.u
|
|
&& glyphinfo->gm.u->utf8str) {
|
|
Glyphttychar(x, y) = glyphinfo->gm.u->utf32ch;
|
|
if (glyphinfo->gm.u->ucolor != 0) {
|
|
Glyphcolor(x, y) = glyphinfo->gm.u->ucolor | 0x80000000;
|
|
}
|
|
}
|
|
#endif
|
|
Glyphflags(x,y)=glyphinfo->glyphflags;
|
|
Glyphtileidx(x,y)=glyphinfo->tileidx;
|
|
Changed(x,y);
|
|
}
|
|
|
|
//void NetHackQtMapWindow::PrintGlyphCompose(int x,int y,int glyph1, int glyph2)
|
|
//{
|
|
// TODO: composed graphics
|
|
//}
|
|
|
|
void NetHackQtMapWindow::Changed(int x, int y)
|
|
{
|
|
change.add(x,y);
|
|
}
|
|
#endif /* 0 //RLC */
|
|
|
|
} // namespace nethack_qt_
|