There was an error:
../win/Qt/qt_main.cpp:767:37: error: attempt to use a deleted function
action->setData(actchar);
^
/usr/include/x86_64-linux-gnu/qt6/QtCore/qvariant.h:199:5: note: 'QVariant<char *, false>' has been explicitly marked deleted here
QVariant(T) = delete;
^
1 error generated.
I'm hoping the fix applied is the correct one for the error.
1466 lines
42 KiB
C++
1466 lines
42 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_main.cpp -- the main window
|
|
|
|
extern "C" {
|
|
#include "hack.h"
|
|
#define CTRL(c) (0x1f & (c)) // substitute for C() from global.h, for ^V hack
|
|
}
|
|
|
|
#include "qt_pre.h"
|
|
#include <QtGui/QtGui>
|
|
#if QT_VERSION >= 0x060000
|
|
#include <QtGui/QShortcut>
|
|
#elif QT_VERSION >= 0x050000
|
|
#include <QtWidgets/QShortcut>
|
|
#endif
|
|
|
|
#if QT_VERSION >= 0x050000
|
|
#include <QtWidgets/QtWidgets>
|
|
#endif
|
|
#include "qt_post.h"
|
|
#include "qt_main.h"
|
|
#include "qt_main.moc"
|
|
#include "qt_bind.h"
|
|
#include "qt_glyph.h"
|
|
#include "qt_inv.h"
|
|
#include "qt_key.h"
|
|
#include "qt_map.h"
|
|
#include "qt_msg.h"
|
|
#include "qt_set.h"
|
|
#include "qt_stat.h"
|
|
#include "qt_str.h"
|
|
|
|
#ifndef KDE
|
|
#include "qt_kde0.moc"
|
|
#endif
|
|
|
|
// temporary
|
|
extern char *qt_tilewidth;
|
|
extern char *qt_tileheight;
|
|
extern int qt_compact_mode;
|
|
// end temporary
|
|
|
|
namespace nethack_qt_ {
|
|
|
|
// temporary
|
|
void centerOnMain( QWidget* w );
|
|
// end temporary
|
|
|
|
/* XPM */
|
|
static const char * nh_icon[] = {
|
|
"40 40 6 1",
|
|
" s None c none",
|
|
". c #ffffff",
|
|
"X c #dadab6",
|
|
"o c #6c91b6",
|
|
"O c #476c6c",
|
|
"+ c #000000",
|
|
" ",
|
|
" ",
|
|
" ",
|
|
" . .X..XX.XX X ",
|
|
" .. .....X.XXXXXX XX ",
|
|
" ... ....X..XX.XXXXX XXX ",
|
|
" .. ..........X.XXXXXXXXXXX XX ",
|
|
" .... ........X..XX.XXXXXXXXX XXXX ",
|
|
" .... ..........X.XXXXXXXXXXX XXXX ",
|
|
" ooOOO..ooooooOooOOoOOOOOOOXX+++OO++ ",
|
|
" ooOOO..ooooooooOoOOOOOOOOOXX+++OO++ ",
|
|
" ....O..ooooooOooOOoOOOOOOOXX+XXXX++ ",
|
|
" ....O..ooooooooOoOOOOOOOOOXX+XXXX++ ",
|
|
" ..OOO..ooooooOooOOoOOOOOOOXX+++XX++ ",
|
|
" ++++..ooooooooOoOOOOOOOOOXX+++ +++ ",
|
|
" +++..ooooooOooOOoOOOOOOOXX+++ + ",
|
|
" ++..ooooooooOoOOOOOOOOOXX+++ ",
|
|
" ..ooooooOooOOoOOOOOOOXX+++ ",
|
|
" ..ooooooooOoOOOOOOOOOXX+++ ",
|
|
" ..ooooooOooOOoOOOOOOOXX+++ ",
|
|
" ..ooooooooOoOOOOOOOOOXX+++ ",
|
|
" ..oooooOooOOoOOOOOOXX+++ ",
|
|
" ..oooooooOoOOOOOOOOXX+++ ",
|
|
" ..ooooOooOOoOOOOOXX+++ ",
|
|
" ..ooooooOoOOOOOOOXX++++ ",
|
|
" ..o..oooOooOOoOOOOXX+XX+++ ",
|
|
" ...o..oooooOoOOOOOXX++XXX++ ",
|
|
" ....OO..ooOooOOoOOXX+++XXXX++ ",
|
|
" ...oo..+..oooOoOOOXX++XXooXXX++ ",
|
|
" ...ooo..++..OooOOoXX+++XXooOXXX+ ",
|
|
" ..oooOOXX+++....XXXX++++XXOOoOOXX+ ",
|
|
" ..oooOOXX+++ ...XXX+++++XXOOooOXX++ ",
|
|
" ..oooOXXX+++ ..XX+++ +XXOOooOXX++ ",
|
|
" .....XXX++++ XXXXXXX++ ",
|
|
" ....XX++++ XXXXXXX+ ",
|
|
" ...XX+++ XXXXX++ ",
|
|
" ",
|
|
" ",
|
|
" ",
|
|
" "};
|
|
/* XPM */
|
|
static const char * nh_icon_small[] = {
|
|
/* width height ncolors chars_per_pixel */
|
|
"16 16 16 1",
|
|
/* colors */
|
|
" c #587070",
|
|
". c #D1D5C9",
|
|
"X c #8B8C84",
|
|
"o c #2A2A28",
|
|
"O c #9AABA9",
|
|
"+ c #6A8FB2",
|
|
"@ c #C4CAC4",
|
|
"# c #B6BEB6",
|
|
"$ c None",
|
|
"% c #54564E",
|
|
"& c #476C6C",
|
|
"* c #ADB2AB",
|
|
"= c #ABABA2",
|
|
"- c #5E8295",
|
|
"; c #8B988F",
|
|
": c #E8EAE7",
|
|
/* pixels */
|
|
"$$$$$$$$$$$$$$$$",
|
|
"$$$.$#::.#==*$$$",
|
|
"$.*:::::....#*=$",
|
|
"$@#:..@#*==#;XX;",
|
|
"$@O:+++- &&; X%X",
|
|
"$#%.+++- &&;% oX",
|
|
"$$o.++-- &&;%%X$",
|
|
"$$$:++-- &&;%%$$",
|
|
"$$$.O++- &&=o $$",
|
|
"$$$=:++- & XoX$$",
|
|
"$$*:@O-- ;%Xo$$",
|
|
"$*:O#$+--;oOOX $",
|
|
"$:+ =o::=oo=-;%X",
|
|
"$::.%o$*;X;##@%$",
|
|
"$$@# ;$$$$$=*;X$",
|
|
"$$$$$$$$$$$$$$$$"
|
|
};
|
|
|
|
#if 0 // RLC
|
|
/* XPM */
|
|
static const char * map_xpm[] = {
|
|
"12 13 4 1",
|
|
". c None",
|
|
" c #000000000000",
|
|
"X c #0000B6DAFFFF",
|
|
"o c #69A69248B6DA",
|
|
" .",
|
|
" XXXXX ooo ",
|
|
" XoooX o ",
|
|
" XoooX o o ",
|
|
" XoooX ooo ",
|
|
" XXoXX o ",
|
|
" oooooXXX ",
|
|
" oo o oooX ",
|
|
" o XooX ",
|
|
" oooo XooX ",
|
|
" o o XXXX ",
|
|
" ",
|
|
". "};
|
|
/* XPM */
|
|
static const char * msg_xpm[] = {
|
|
"12 13 4 1",
|
|
". c None",
|
|
" c #FFFFFFFFFFFF",
|
|
"X c #69A69248B6DA",
|
|
"o c #000000000000",
|
|
" .",
|
|
" XXX XXX X o",
|
|
" o",
|
|
" XXXXX XX o",
|
|
" o",
|
|
" XX XXXXX o",
|
|
" o",
|
|
" XXXXXX o",
|
|
" o",
|
|
" XX XXX XX o",
|
|
" o",
|
|
" o",
|
|
".ooooooooooo"};
|
|
/* XPM */
|
|
static const char * stat_xpm[] = {
|
|
"12 13 5 1",
|
|
" c None",
|
|
". c #FFFF00000000",
|
|
"X c #000000000000",
|
|
"o c #FFFFFFFF0000",
|
|
"O c #69A6FFFF0000",
|
|
" ",
|
|
" ",
|
|
"... ",
|
|
"...X ",
|
|
"...X ... ",
|
|
"oooX oooX",
|
|
"oooXooo oooX",
|
|
"OOOXOOOXOOOX",
|
|
"OOOXOOOXOOOX",
|
|
"OOOXOOOXOOOX",
|
|
"OOOXOOOXOOOX",
|
|
"OOOXOOOXOOOX",
|
|
" XXXXXXXXXXX"};
|
|
#endif
|
|
/* XPM */
|
|
static const char * info_xpm[] = {
|
|
"12 13 4 1",
|
|
" c None",
|
|
". c #00000000FFFF",
|
|
"X c #FFFFFFFFFFFF",
|
|
"o c #000000000000",
|
|
" ... ",
|
|
" ....... ",
|
|
" ...XXX... ",
|
|
" .........o ",
|
|
"...XXXX.... ",
|
|
"....XXX....o",
|
|
"....XXX....o",
|
|
"....XXX....o",
|
|
" ...XXX...oo",
|
|
" ..XXXXX..o ",
|
|
" .......oo ",
|
|
" o...ooo ",
|
|
" ooo "};
|
|
|
|
|
|
/* XPM */
|
|
static const char * again_xpm[] = {
|
|
"12 13 2 1",
|
|
" c None",
|
|
". c #000000000000",
|
|
" .. ",
|
|
" .. ",
|
|
" ..... ",
|
|
" ....... ",
|
|
"... .. .. ",
|
|
".. .. .. ",
|
|
".. ..",
|
|
".. ..",
|
|
".. ..",
|
|
" .. .. ",
|
|
" .......... ",
|
|
" ...... ",
|
|
" "};
|
|
/* XPM */
|
|
static const char * kick_xpm[] = {
|
|
"12 13 3 1",
|
|
" c None",
|
|
". c #000000000000",
|
|
"X c #FFFF6DB60000",
|
|
" ",
|
|
" ",
|
|
" . . . ",
|
|
" ... . . ",
|
|
" ... . ",
|
|
" ... . ",
|
|
" ... ",
|
|
"XXX ... ",
|
|
"XXX. ... ",
|
|
"XXX. ... ",
|
|
"XXX. .. ",
|
|
" ... ",
|
|
" "};
|
|
/* XPM */
|
|
static const char * throw_xpm[] = {
|
|
"12 13 3 1",
|
|
" c None",
|
|
". c #FFFF6DB60000",
|
|
"X c #000000000000",
|
|
" ",
|
|
" ",
|
|
" ",
|
|
" ",
|
|
".... X ",
|
|
"....X X ",
|
|
"....X XXXXXX",
|
|
"....X X ",
|
|
" XXXX X ",
|
|
" ",
|
|
" ",
|
|
" ",
|
|
" "};
|
|
/* XPM */
|
|
static const char * fire_xpm[] = {
|
|
"12 13 5 1",
|
|
" c None",
|
|
". c #B6DA45140000",
|
|
"X c #FFFFB6DA9658",
|
|
"o c #000000000000",
|
|
"O c #FFFF6DB60000",
|
|
" . ",
|
|
" X. ",
|
|
" X . ",
|
|
" X .o ",
|
|
" X . o ",
|
|
" X .o o ",
|
|
"OOOOOOOOoooo",
|
|
" X .o o ",
|
|
" X . o o ",
|
|
" X .o ",
|
|
" X. o ",
|
|
" . o ",
|
|
" o "};
|
|
/* XPM */
|
|
static const char * pickup_xpm[] = {
|
|
"12 13 3 1",
|
|
" c None",
|
|
". c #000000000000",
|
|
"X c #FFFF6DB60000",
|
|
" ",
|
|
" . ",
|
|
" ... ",
|
|
" . . . ",
|
|
" . ",
|
|
" . ",
|
|
" ",
|
|
" XXXXX ",
|
|
" XXXXX. ",
|
|
" XXXXX. ",
|
|
" XXXXX. ",
|
|
" ..... ",
|
|
" "};
|
|
/* XPM */
|
|
static const char * drop_xpm[] = {
|
|
"12 13 3 1",
|
|
" c None",
|
|
". c #FFFF6DB60000",
|
|
"X c #000000000000",
|
|
" ",
|
|
" ..... ",
|
|
" .....X ",
|
|
" .....X ",
|
|
" .....X ",
|
|
" XXXXX ",
|
|
" ",
|
|
" X ",
|
|
" X ",
|
|
" X X X ",
|
|
" XXX ",
|
|
" X ",
|
|
" "};
|
|
/* XPM */
|
|
static const char * eat_xpm[] = {
|
|
"12 13 4 1",
|
|
" c None",
|
|
". c #000000000000",
|
|
"X c #FFFFB6DA9658",
|
|
"o c #FFFF6DB60000",
|
|
" .X. .. ",
|
|
" .X. .. ",
|
|
" .X. .. ",
|
|
" .X. .. ",
|
|
" ... .. ",
|
|
" .. .. ",
|
|
" .. .. ",
|
|
" oo oo ",
|
|
" oo oo ",
|
|
" oo oo ",
|
|
" oo oo ",
|
|
" oo oo ",
|
|
" oo oo "};
|
|
/* XPM */
|
|
static const char * search_xpm[] = {
|
|
"12 13 3 1",
|
|
" c None",
|
|
". c #FFFFFFFF0000",
|
|
"X c #7F0000000000",
|
|
" ",
|
|
" XXXXX ",
|
|
" X ... X ",
|
|
" X.....X ",
|
|
" X.....X ",
|
|
" X ... X ",
|
|
" XXXXX ",
|
|
" X ",
|
|
" X ",
|
|
" X ",
|
|
" X ",
|
|
" X ",
|
|
" "};
|
|
/* XPM */
|
|
static const char * rest_xpm[] = {
|
|
"12 13 2 1",
|
|
" c None",
|
|
". c #000000000000",
|
|
" ..... ",
|
|
" . ",
|
|
" . ",
|
|
" . ....",
|
|
" ..... . ",
|
|
" . ",
|
|
" ....",
|
|
" ",
|
|
" .... ",
|
|
" . ",
|
|
" . ",
|
|
" .... ",
|
|
" "};
|
|
/* XPM */
|
|
static const char * cast_a_xpm[] UNUSED = {
|
|
"12 13 3 1",
|
|
" c None",
|
|
". c #FFFF6DB60000",
|
|
"X c #000000000000",
|
|
" . ",
|
|
" . ",
|
|
" .. ",
|
|
" .. ",
|
|
" .. . ",
|
|
" .. . ",
|
|
" ...... ",
|
|
" .. .. XX ",
|
|
" .. X X ",
|
|
" .. X X ",
|
|
" .. XXXX ",
|
|
" . X X ",
|
|
" . X X "};
|
|
/* XPM */
|
|
static const char * cast_b_xpm[] UNUSED = {
|
|
"12 13 3 1",
|
|
" c None",
|
|
". c #FFFF6DB60000",
|
|
"X c #000000000000",
|
|
" . ",
|
|
" . ",
|
|
" .. ",
|
|
" .. ",
|
|
" .. . ",
|
|
" .. . ",
|
|
" ...... ",
|
|
" .. .. XXX ",
|
|
" .. X X ",
|
|
" .. XXX ",
|
|
" .. X X ",
|
|
" . X X ",
|
|
" . XXX "};
|
|
/* XPM */
|
|
static const char * cast_c_xpm[] UNUSED = {
|
|
"12 13 3 1",
|
|
" c None",
|
|
". c #FFFF6DB60000",
|
|
"X c #000000000000",
|
|
" . ",
|
|
" . ",
|
|
" .. ",
|
|
" .. ",
|
|
" .. . ",
|
|
" .. . ",
|
|
" ...... ",
|
|
" .. .. XX ",
|
|
" .. X X ",
|
|
" .. X ",
|
|
" .. X ",
|
|
" . X X ",
|
|
" . XX "};
|
|
|
|
static QString
|
|
aboutMsg()
|
|
{
|
|
char *p, vbuf[BUFSZ];
|
|
/* nethack's getversionstring() includes a final period
|
|
but we're using it mid-sentence so strip period off */
|
|
if ((p = strrchr(::getversionstring(vbuf, sizeof vbuf), '.')) != 0
|
|
&& *(p + 1) == '\0')
|
|
*p = '\0';
|
|
/* it's also long; break it into two pieces */
|
|
(void) strsubst(vbuf, " - ", "\n- ");
|
|
QString msg = nh_qsprintf(
|
|
// format
|
|
"NetHack-Qt is a version of NetHack built using" // no newline
|
|
#ifdef KDE
|
|
" KDE and" // ditto
|
|
#endif
|
|
" the Qt %d GUI toolkit.\n" // short Qt version
|
|
"\n"
|
|
"This is %s%s and Lua %s.\n" // long nethack version, Qt & Lua versions
|
|
"\n"
|
|
"NetHack's Qt interface originally developed by Warwick Allison.\n"
|
|
"\n"
|
|
#if 0
|
|
"Homepage:\n http://trolls.troll.no/warwick/nethack/\n" //obsolete
|
|
#endif
|
|
#ifdef KDE
|
|
"KDE:\n https://kde.org/\n"
|
|
#endif
|
|
#if 1
|
|
"Qt:\n https://qt.io/\n"
|
|
#else
|
|
"Qt:\n http://www.troll.no/\n" // obsolete
|
|
#endif
|
|
"Lua:\n https://lua.org/\n"
|
|
"NetHack:\n %s\n", // DEVTEAM_URL
|
|
// arguments
|
|
#ifdef QT_VERSION_MAJOR
|
|
QT_VERSION_MAJOR,
|
|
#else
|
|
5, // Qt version macro should exist; if not, assume Qt5
|
|
#endif
|
|
vbuf, // nethack version
|
|
#ifdef QT_VERSION_STR
|
|
" with Qt " QT_VERSION_STR,
|
|
#else
|
|
"",
|
|
#endif
|
|
::get_lua_version(),
|
|
DEVTEAM_URL);
|
|
return msg;
|
|
}
|
|
|
|
class SmallToolButton : public QToolButton {
|
|
public:
|
|
SmallToolButton(const QPixmap &pm, const QString &textLabel,
|
|
const QString &grouptext,
|
|
QObject *receiver, const char *slot,
|
|
QWidget *parent) :
|
|
QToolButton(parent)
|
|
{
|
|
setIcon(QIcon(pm));
|
|
setToolTip(textLabel);
|
|
setStatusTip(grouptext);
|
|
connect(this, SIGNAL(clicked(bool)), receiver, slot);
|
|
}
|
|
|
|
QSize sizeHint() const
|
|
{
|
|
// get just a couple more pixels for the map
|
|
return QToolButton::sizeHint()-QSize(0,2);
|
|
}
|
|
};
|
|
|
|
NetHackQtMainWindow::NetHackQtMainWindow(NetHackQtKeyBuffer& ks) :
|
|
message(0), map(0), status(0), invusage(0),
|
|
hsplitter(0), vsplitter(0),
|
|
keysink(ks), dirkey(0)
|
|
{
|
|
QToolBar* toolbar = new QToolBar(this);
|
|
toolbar->setMovable(false);
|
|
toolbar->setFocusPolicy(Qt::NoFocus);
|
|
addToolBar(toolbar);
|
|
menubar = menuBar();
|
|
|
|
setWindowTitle("NetHack-Qt");
|
|
setWindowIcon(QIcon(QPixmap(qt_compact_mode ? nh_icon_small : nh_icon)));
|
|
|
|
#ifdef MACOS
|
|
/*
|
|
* MacOS Note:
|
|
* The toolbar on MacOS starts with a system menu labeled with the
|
|
* Apple logo and an application menu labeled with the application's
|
|
* name (taken from Info.plist if present, otherwise the base name
|
|
* of the running program). After that, application-specific menus
|
|
* (in our case "game",...,"help") follow. Several menu entry
|
|
* names ("About", "Quit"/"Exit", "Preferences"/"Options"/
|
|
* "Settings"/"Setup"/"Config") get hijacked and placed in the
|
|
* application menu (and renamed in the process) even if the code
|
|
* here tries to put them in another menu.
|
|
* See QtWidgets/doc/qmenubar.html for slightly more information.
|
|
* setMenuRole() can be used to override this behavior.
|
|
*/
|
|
#endif
|
|
|
|
#ifdef CTRL_V_HACK
|
|
// NetHackQtBind::notify() sees all control characters except for ^V
|
|
QShortcut *c_V = new QShortcut(QKeySequence(Qt::CTRL + Qt::Key_V), this);
|
|
connect(c_V, &QShortcut::activated, this, &NetHackQtMainWindow::CtrlV);
|
|
#endif
|
|
|
|
QMenu* game=new QMenu;
|
|
QMenu* apparel=new QMenu;
|
|
QMenu* act1=new QMenu;
|
|
QMenu* act2 = qt_compact_mode ? new QMenu : act1;
|
|
QMenu* magic=new QMenu;
|
|
QMenu* info=new QMenu;
|
|
|
|
QMenu *help;
|
|
#ifdef KDE
|
|
help = kapp->getHelpMenu( true, "" );
|
|
help->addSeparator();
|
|
#else
|
|
help = qt_compact_mode ? info : new QMenu;
|
|
#endif
|
|
|
|
enum { OnDesktop=1, OnHandhelds=2 };
|
|
struct Macro {
|
|
QMenu *menu;
|
|
const char *name;
|
|
int flags; // 1 desktop, 2 handheld, 3 either/both
|
|
int (*funct)(void);
|
|
} item[] = {
|
|
{ game, 0, 3, (int (*)(void)) 0},
|
|
{ game, "Extended-commands", 3, doextcmd },
|
|
{ game, 0, 3, (int (*)(void)) 0},
|
|
{ game, "Version", 3, doversion},
|
|
{ game, "Compilation", 3, doextversion},
|
|
{ game, "History", 3, dohistory},
|
|
{ game, "Redraw", 0, doredraw}, // useless
|
|
{ game,
|
|
#ifdef MACOS
|
|
/* Qt on OSX would rename "Options" to "Preferences..." and
|
|
move it from intended destination to the application menu;
|
|
the ampersand produces &O which makes Alt+O into a keyboard
|
|
shortcut--except those are disabled by default by Qt on OSX */
|
|
"Run-time &" // rely on adjacent string concatenation
|
|
#endif
|
|
"Options", 3, doset},
|
|
{ game, "Explore mode", 3, enter_explore_mode},
|
|
{ game, 0, 3, (int (*)(void)) 0},
|
|
{ game, "Save-and-exit", 3, dosave},
|
|
{ game,
|
|
#ifdef MACOS
|
|
/* need something to prevent matching leading "quit" so that it
|
|
isn't hijacked for the application menu; the ampersand is to
|
|
make &Q be a keyboard shortcut (but see Options above) */
|
|
"\177&"
|
|
#endif
|
|
"Quit-without-saving", 3, done2},
|
|
|
|
{ apparel, "Apparel off", 2, doddoremarm},
|
|
{ apparel, "Remove many", 1, doddoremarm},
|
|
{ apparel, 0, 3, (int (*)(void)) 0},
|
|
{ apparel, "Wield weapon", 3, dowield},
|
|
{ apparel, "Exchange weapons", 3, doswapweapon},
|
|
{ apparel, "Two weapon combat", 3, dotwoweapon},
|
|
{ apparel, "Load quiver", 3, dowieldquiver},
|
|
{ apparel, 0, 3, (int (*)(void)) 0},
|
|
{ apparel, "Wear armor", 3, dowear},
|
|
{ apparel, "Take off armor", 3, dotakeoff},
|
|
{ apparel, 0, 3, (int (*)(void)) 0},
|
|
{ apparel, "Put on accessories", 3, doputon},
|
|
{ apparel, "Remove accessories", 3, doremring},
|
|
|
|
/* { act1, "Again\tCtrl+A", "\001", 2},
|
|
{ act1, 0, 0, 3}, */
|
|
{ act1, "Apply", 3, doapply},
|
|
{ act1, "Chat", 3, dotalk},
|
|
{ act1, "Close door", 3, doclose},
|
|
{ act1, "Down", 3, dodown},
|
|
{ act1, "Drop many", 2, doddrop},
|
|
{ act1, "Drop", 2, dodrop},
|
|
{ act1, "Eat", 2, doeat},
|
|
{ act1, "Engrave", 3, doengrave},
|
|
/* { act1, "Fight\tShift+F", "F", 3}, */
|
|
{ act1, "Fire from quiver", 2, dofire},
|
|
{ act1, "Force", 3, doforce},
|
|
{ act1, "Jump", 3, dojump},
|
|
{ act2, "Kick", 2, dokick},
|
|
{ act2, "Loot", 3, doloot},
|
|
{ act2, "Open door", 3, doopen},
|
|
{ act2, "Pay", 3, dopay},
|
|
// calling this "Get" was confusing to experienced players
|
|
{ act1, "Pick up (was Get)", 3, dopickup},
|
|
{ act2, "Rest", 2, donull},
|
|
{ act2, "Ride", 3, doride},
|
|
{ act2, "Search", 3, dosearch},
|
|
{ act2, "Sit", 3, dosit},
|
|
{ act2, "Throw", 2, dothrow},
|
|
{ act2, "Untrap", 3, dountrap},
|
|
{ act2, "Up", 3, doup},
|
|
{ act2, "Wipe face", 3, dowipe},
|
|
|
|
{ magic, "Quaff potion", 3, dodrink},
|
|
{ magic, "Read scroll/book", 3, doread},
|
|
{ magic, "Zap wand", 3, dozap},
|
|
{ magic, "Zap spell", 3, docast},
|
|
{ magic, "Dip", 3, dodip},
|
|
{ magic, "Rub", 3, dorub},
|
|
{ magic, "Invoke", 3, doinvoke},
|
|
{ magic, 0, 3, (int (*)(void)) 0},
|
|
{ magic, "Offer", 3, dosacrifice},
|
|
{ magic, "Pray", 3, dopray},
|
|
{ magic, 0, 3, (int (*)(void)) 0},
|
|
{ magic, "Teleport", 3, dotelecmd},
|
|
{ magic, "Monster action", 3, domonability},
|
|
{ magic, "Turn undead", 3, doturn},
|
|
|
|
{ help, "Help", 3, dohelp},
|
|
{ help, 0, 3, (int (*)(void)) 0},
|
|
{ help, "What is here", 3, dolook},
|
|
{ help, "What is there", 3, doquickwhatis},
|
|
{ help, "What is...", 2, dowhatis},
|
|
{ help, 0, 1, (int (*)(void)) 0},
|
|
|
|
{ info, "Inventory", 3, ddoinv},
|
|
{ info, "Attributes (extended status)", 3, doattributes },
|
|
{ info, "Overview", 3, dooverview },
|
|
{ info, "Conduct", 3, doconduct},
|
|
{ info, "Discoveries", 3, dodiscovered},
|
|
{ info, "List/reorder spells", 3, dovspell},
|
|
{ info, "Adjust inventory letters", 3, doorganize },
|
|
{ info, 0, 3, (int (*)(void)) 0},
|
|
{ info, "Name object or creature", 3, docallcmd},
|
|
{ info, "Annotate level", 3, donamelevel },
|
|
{ info, 0, 3, (int (*)(void)) 0},
|
|
{ info, "Skills", 3, enhance_weapon_skill},
|
|
|
|
{ 0, 0, 0, (int (*)(void)) 0 }
|
|
};
|
|
|
|
QAction *actn;
|
|
#ifndef MACOS
|
|
(void) game->addAction("Qt settings...", this, SLOT(doQtSettings(bool)));
|
|
#else
|
|
/* on OSX, put this in the application menu instead of the game menu;
|
|
Qt would change the action name behind our backs; do it explicitly */
|
|
actn = game->addAction("Preferences...", this, SLOT(doQtSettings(bool)));
|
|
actn->setMenuRole(QWidgetAction::PreferencesRole);
|
|
/* we also want a "Quit NetHack" entry in the application menu;
|
|
when "_Quit-without-saving" was called "Quit" it got intercepted
|
|
for that, but now this needs to be added separately; we'll use a
|
|
handy menu and let the interception put it in the intended place;
|
|
unlike About, it is not a duplicate; _Quit-without-saving runs
|
|
nethack's #quit command with "really quit?" prompt, this quit--with
|
|
Command+q as shortcut--pops up a dialog to choose between quit or
|
|
cancel-and-resume-playing */
|
|
actn = game->addAction("Quit NetHack-Qt", this, SLOT(doQuit(bool)));
|
|
actn->setMenuRole(QWidgetAction::QuitRole);
|
|
#endif
|
|
|
|
actn = help->addAction("About NetHack-Qt", this, SLOT(doAbout(bool)));
|
|
#ifdef MACOS
|
|
actn->setMenuRole(QWidgetAction::AboutRole);
|
|
/* for OSX, the preceding "About" went into the application menu;
|
|
now add another duplicate one to the Help dropdown menu */
|
|
actn = help->addAction("About NetHack-Qt", this, SLOT(doAbout(bool)));
|
|
actn->setMenuRole(QWidgetAction::NoRole);
|
|
#else
|
|
nhUse(actn);
|
|
#endif
|
|
help->addSeparator();
|
|
|
|
//help->addAction("NetHack Guidebook", this, SLOT(doGuidebook(bool)));
|
|
//help->addSeparator();
|
|
|
|
for (int i = 0; item[i].menu; ++i) {
|
|
if ( item[i].flags & (qt_compact_mode ? 1 : 2) ) {
|
|
if (item[i].name) {
|
|
char actchar[32];
|
|
char menuitem[BUFSZ];
|
|
actchar[0] = actchar[1] = '\0';
|
|
if (item[i].funct) {
|
|
actchar[0] = cmd_from_func(item[i].funct);
|
|
if (actchar[0]
|
|
/* M-c won't work; translation between character
|
|
sets by the QString class can classify such
|
|
characters as erroneous and change them to '?' */
|
|
&& ((actchar[0] & 0x7f) != actchar[0]
|
|
/* the vi movement keys won't work reliably
|
|
because toggling number_pad affects them but
|
|
doesn't redo these menus */
|
|
|| strchr("hjklyubnHJKLYUBN", actchar[0])
|
|
|| strchr("hjklyubn", (actchar[0] | 0x60))))
|
|
actchar[0] = '\0';
|
|
}
|
|
if (actchar[0] && !qt_compact_mode)
|
|
Sprintf(menuitem, "%.50s\t%.9s", item[i].name,
|
|
visctrl(actchar[0]));
|
|
else
|
|
Sprintf(menuitem, "%s", item[i].name);
|
|
|
|
if (item[i].funct && !actchar[0]) {
|
|
actchar[0] = '#';
|
|
(void) cmdname_from_func(item[i].funct,
|
|
&actchar[1], FALSE);
|
|
}
|
|
if (actchar[0]) {
|
|
QString name = menuitem;
|
|
QAction *action = item[i].menu->addAction(name);
|
|
#if QT_VERSION < 0x060000
|
|
action->setData(actchar);
|
|
#else
|
|
action->setData(QString(actchar));
|
|
#endif
|
|
}
|
|
} else {
|
|
item[i].menu->addSeparator();
|
|
}
|
|
}
|
|
}
|
|
|
|
game->setTitle("Game");
|
|
menubar->addMenu(game);
|
|
apparel->setTitle("Gear");
|
|
menubar->addMenu(apparel);
|
|
|
|
if ( qt_compact_mode ) {
|
|
act1->setTitle("A-J");
|
|
menubar->addMenu(act1);
|
|
act2->setTitle("K-Z");
|
|
menubar->addMenu(act2);
|
|
magic->setTitle("Magic");
|
|
menubar->addMenu(magic);
|
|
info->setIcon(QIcon(QPixmap(info_xpm)));
|
|
info->setTitle("Info");
|
|
menubar->addMenu(info);
|
|
//menubar->insertItem(QPixmap(map_xpm), this, SLOT(raiseMap()));
|
|
//menubar->insertItem(QPixmap(msg_xpm), this, SLOT(raiseMessages()));
|
|
//menubar->insertItem(QPixmap(stat_xpm), this, SLOT(raiseStatus()));
|
|
info->addSeparator();
|
|
info->addAction("Map", this, SLOT(raiseMap()));
|
|
info->addAction("Messages", this, SLOT(raiseMessages()));
|
|
info->addAction("Status", this, SLOT(raiseStatus()));
|
|
} else {
|
|
act1->setTitle("Action");
|
|
menubar->addMenu(act1);
|
|
magic->setTitle("Magic");
|
|
menubar->addMenu(magic);
|
|
info->setTitle("Info");
|
|
menubar->addMenu(info);
|
|
menubar->addSeparator();
|
|
#ifndef MACOS
|
|
help->setTitle("Help");
|
|
#else
|
|
// On OSX, an entry in the menubar called "Help" will get an
|
|
// extra action, "Search [______]", inserted as the first entry.
|
|
// We have no control over what it does and don't want it.
|
|
//
|
|
// Using actions() to fetch a list of all entries doesn't find it,
|
|
// so we don't have its widget pointer to pass to removeAction().
|
|
//
|
|
// Altering the name with an invisible character to inhibit
|
|
// string matching is ludicrous but keeps the unwanted action
|
|
// from getting inserted into the "Help" menu behind our back.
|
|
// Underscore works too and is more robust but unless we prepend
|
|
// it to every entry, "_Help" would stand out as strange.
|
|
help->setTitle("\177Help");
|
|
// (Renaming back to "Help" after the fact does reset the menu's
|
|
// name but it also results in the Search action being added.
|
|
// Perhaps a custom context menu that changes its name to "Help"
|
|
// as it is being shown--and possibly changes back afterward--
|
|
// would work but the name mangling hack is much simpler.)
|
|
#endif
|
|
menubar->addMenu(help);
|
|
}
|
|
|
|
// order changed: was Again, Get, Kick, Throw, Fire, Drop, Eat, Rest
|
|
// now Again, PickUp, Drop, Kick, Throw, Fire, Eat, Rest
|
|
QSignalMapper* sm = new QSignalMapper(this);
|
|
#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0)
|
|
connect(sm, SIGNAL(mappedString(const QString&)),
|
|
this, SLOT(doKeys(const QString&)));
|
|
#else
|
|
connect(sm, SIGNAL(mapped(const QString&)),
|
|
this, SLOT(doKeys(const QString&)));
|
|
#endif
|
|
AddToolButton(toolbar, sm, "Again", do_repeat, QPixmap(again_xpm));
|
|
// this used to be called "Get" which is confusing to experienced players
|
|
AddToolButton(toolbar, sm, "Pick up", dopickup, QPixmap(pickup_xpm));
|
|
AddToolButton(toolbar, sm, "Drop", doddrop, QPixmap(drop_xpm));
|
|
AddToolButton(toolbar, sm, "Kick", dokick, QPixmap(kick_xpm));
|
|
AddToolButton(toolbar, sm, "Throw", dothrow, QPixmap(throw_xpm));
|
|
AddToolButton(toolbar, sm, "Fire", dofire, QPixmap(fire_xpm));
|
|
AddToolButton(toolbar, sm, "Eat", doeat, QPixmap(eat_xpm));
|
|
AddToolButton(toolbar, sm, "Search", dosearch, QPixmap(search_xpm));
|
|
AddToolButton(toolbar, sm, "Rest", donull, QPixmap(rest_xpm));
|
|
|
|
connect(game, SIGNAL(triggered(QAction *)),
|
|
this, SLOT(doMenuItem(QAction *)));
|
|
connect(apparel, SIGNAL(triggered(QAction *)),
|
|
this, SLOT(doMenuItem(QAction *)));
|
|
connect(act1, SIGNAL(triggered(QAction *)),
|
|
this, SLOT(doMenuItem(QAction *)));
|
|
if (act2 != act1)
|
|
connect(act2, SIGNAL(triggered(QAction *)),
|
|
this, SLOT(doMenuItem(QAction *)));
|
|
connect(magic, SIGNAL(triggered(QAction *)),
|
|
this, SLOT(doMenuItem(QAction *)));
|
|
connect(info, SIGNAL(triggered(QAction *)),
|
|
this, SLOT(doMenuItem(QAction *)));
|
|
connect(help, SIGNAL(triggered(QAction *)),
|
|
this, SLOT(doMenuItem(QAction *)));
|
|
|
|
#ifdef KDE
|
|
setMenu (menubar);
|
|
#endif
|
|
|
|
#if QT_VERSION < 0x060000
|
|
QSize screensize = QApplication::desktop()->size();
|
|
#else
|
|
QSize screensize = screen()->size();
|
|
#endif
|
|
int x=0,y=0;
|
|
int w=screensize.width()-10; // XXX arbitrary extra space for frame
|
|
int h=screensize.height()-50;
|
|
|
|
int maxwn = 1400;
|
|
int maxhn = 1024;
|
|
if (qt_settings != NULL) {
|
|
auto glyphs = &qt_settings->glyphs();
|
|
if (glyphs != NULL) {
|
|
maxwn = glyphs->width() * COLNO + 10;
|
|
maxhn = glyphs->height() * ROWNO * 6/4;
|
|
}
|
|
}
|
|
|
|
// Be exactly the size we want to be - full map...
|
|
if (w>maxwn) {
|
|
x+=(w-maxwn)/2;
|
|
w=maxwn; // Doesn't need to be any wider
|
|
}
|
|
if (h>maxhn) {
|
|
y+=(h-maxhn)/2;
|
|
h=maxhn; // Doesn't need to be any taller
|
|
}
|
|
|
|
setGeometry(x,y,w,h);
|
|
|
|
if ( qt_compact_mode ) {
|
|
stack = new QStackedWidget(this);
|
|
setCentralWidget(stack);
|
|
} else {
|
|
vsplitter = new QSplitter(Qt::Vertical);
|
|
setCentralWidget(vsplitter);
|
|
hsplitter = new QSplitter(Qt::Horizontal);
|
|
invusage = new NetHackQtInvUsageWindow(hsplitter);
|
|
vsplitter->insertWidget(0, hsplitter);
|
|
hsplitter->insertWidget(1, invusage);
|
|
}
|
|
}
|
|
|
|
#ifdef CTRL_V_HACK
|
|
// called when ^V is typed while the main window has keyboard focus;
|
|
// all other control characters go through NetHackQtBind::notify()
|
|
void NetHackQtMainWindow::CtrlV()
|
|
{
|
|
static const char cV[] = { CTRL('V'), '\0' };
|
|
doKeys(cV);
|
|
}
|
|
#endif
|
|
|
|
// add a toolbar button to invoke command 'name' via function '(*func)()'
|
|
void NetHackQtMainWindow::AddToolButton(QToolBar *toolbar, QSignalMapper *sm,
|
|
const char *name, int (*func)(void),
|
|
QPixmap xpm)
|
|
{
|
|
char actchar[2];
|
|
uchar key;
|
|
|
|
key = (uchar) cmd_from_func(func);
|
|
|
|
// if key is valid, add a button for it; otherwise omit the command
|
|
// (won't work as intended if a different command is bound to same key)
|
|
if (key) {
|
|
QToolButton *tb = new SmallToolButton(xpm, QString(name), "Action",
|
|
sm, SLOT(map()), toolbar);
|
|
actchar[0] = '\0';
|
|
sm->setMapping(tb, strkitten(actchar, (char) key));
|
|
toolbar->addWidget(tb);
|
|
}
|
|
}
|
|
|
|
void NetHackQtMainWindow::zoomMap()
|
|
{
|
|
qt_settings->toggleGlyphSize();
|
|
}
|
|
|
|
void NetHackQtMainWindow::raiseMap()
|
|
{
|
|
if ( stack->currentWidget() == map->Widget() ) {
|
|
zoomMap();
|
|
} else {
|
|
stack->setCurrentWidget(map->Widget());
|
|
}
|
|
}
|
|
|
|
void NetHackQtMainWindow::raiseMessages()
|
|
{
|
|
stack->setCurrentWidget(message->Widget());
|
|
}
|
|
|
|
void NetHackQtMainWindow::raiseStatus()
|
|
{
|
|
stack->setCurrentWidget(status->Widget());
|
|
}
|
|
|
|
#if 0 // RLC this isn't used
|
|
class NetHackMimeSourceFactory : public Q3MimeSourceFactory {
|
|
public:
|
|
const QMimeSource* data(const QString& abs_name) const
|
|
{
|
|
const QMimeSource* r = 0;
|
|
if ( (NetHackMimeSourceFactory *) this
|
|
== Q3MimeSourceFactory::defaultFactory() )
|
|
r = Q3MimeSourceFactory::data(abs_name);
|
|
else
|
|
r = Q3MimeSourceFactory::defaultFactory()->data(abs_name);
|
|
if ( !r ) {
|
|
int sl = abs_name.length();
|
|
do {
|
|
sl = abs_name.lastIndexOf('/',sl-1);
|
|
QString name = sl>=0 ? abs_name.mid(sl+1) : abs_name;
|
|
int dot = name.lastIndexOf('.');
|
|
if ( dot >= 0 )
|
|
name = name.left(dot);
|
|
if ( name == "map" )
|
|
r = new Q3ImageDrag(QImage(map_xpm));
|
|
else if ( name == "msg" )
|
|
r = new Q3ImageDrag(QImage(msg_xpm));
|
|
else if ( name == "stat" )
|
|
r = new Q3ImageDrag(QImage(stat_xpm));
|
|
} while (!r && sl>0);
|
|
}
|
|
return r;
|
|
}
|
|
};
|
|
#endif
|
|
|
|
/* used by doMenuItem() and for the toolbar buttons */
|
|
bool NetHackQtMainWindow::ok_for_command()
|
|
{
|
|
/*
|
|
* If the core expects text to be entered (perhaps typing in a wish,
|
|
* assigning a name to something, or answering a y/n prompt), or a
|
|
* map position or a direction is being picked, don't accept commands
|
|
* from the toolbar.
|
|
*
|
|
* FIXME: it would be much better to gray-out inapplicable entries
|
|
* when popping up a command menu instead of needing this.
|
|
*/
|
|
if (::gp.program_state.input_state != commandInp) {
|
|
NetHackQtBind::qt_nhbell();
|
|
// possibly call doKeys("\033"); here?
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
void NetHackQtMainWindow::doMenuItem(QAction *action)
|
|
{
|
|
if (!ok_for_command())
|
|
return;
|
|
/* this converts meta characters to '?'; menu processing has been
|
|
changed to send multi-character "#abc" instead (already needed
|
|
for commands that didn't have either a regular keystroke or a
|
|
meta shortcut); it must send just enough to disambiguate from
|
|
other extended command names, otherwise the remainder would be
|
|
left in the queue for subsequent handling as additional commands */
|
|
doKeys(action->data().toString());
|
|
}
|
|
|
|
void NetHackQtMainWindow::doQtSettings(bool)
|
|
{
|
|
centerOnMain(qt_settings);
|
|
qt_settings->show();
|
|
}
|
|
|
|
void NetHackQtMainWindow::doAbout(bool)
|
|
{
|
|
QMessageBox::about(this, "About NetHack-Qt", aboutMsg());
|
|
}
|
|
|
|
// on OSX, "quit nethack" has been selected in the application menu or
|
|
// "Command+Q" has been typed -- user is asking to quit the application;
|
|
// unlike with the window's Close button, user has a chance to back out
|
|
void NetHackQtMainWindow::doQuit(bool)
|
|
{
|
|
// there is a separate Quit-without-saving menu entry in the game menu
|
|
// that leads to nethack's "Really quit?" prompt; OSX players can use
|
|
// either one, other implementations only have that other one (plus
|
|
// nethack's #quit command itself) but this routine is unconditional
|
|
// in case someone wants to change that
|
|
#ifdef MACOS
|
|
QString info = nh_qsprintf("This will end your NetHack session.%s",
|
|
!gp.program_state.something_worth_saving ? ""
|
|
: "\n(Cancel quitting and use the Save command"
|
|
"\nto save your current game.)");
|
|
/* this is similar to closeEvent but the details are different;
|
|
first choice (Cancel) is the default action for most arbitrary keys;
|
|
the second choice (Quit) is the action for <return> or <space>;
|
|
<escape> leaves the popup waiting for some other response;
|
|
the &<char> settings for Alt+<char> shortcuts don't work on OSX */
|
|
int act = QMessageBox::information(this, "NetHack", info,
|
|
"&Cancel and return to game",
|
|
"&Quit without saving",
|
|
0, 1);
|
|
switch (act) {
|
|
case 0:
|
|
// cancel
|
|
break; // return to game
|
|
case 1:
|
|
// quit -- bypass the prompting preformed by done2()
|
|
gp.program_state.stopprint++;
|
|
::done(QUIT);
|
|
/*NOTREACHED*/
|
|
break;
|
|
}
|
|
#endif
|
|
return;
|
|
}
|
|
|
|
#if 0 // RLC this isn't used
|
|
void NetHackQtMainWindow::doGuidebook(bool)
|
|
{
|
|
QDialog dlg(this);
|
|
new QVBoxLayout(&dlg);
|
|
Q3TextBrowser browser(&dlg);
|
|
NetHackMimeSourceFactory ms;
|
|
browser.setMimeSourceFactory(&ms);
|
|
browser.setSource(QDir::currentPath()+"/Guidebook.html");
|
|
if ( qt_compact_mode )
|
|
dlg.showMaximized();
|
|
dlg.exec();
|
|
}
|
|
#endif
|
|
|
|
void NetHackQtMainWindow::doKeys(const char *cmds)
|
|
{
|
|
keysink.Put(cmds);
|
|
qApp->exit();
|
|
}
|
|
|
|
void NetHackQtMainWindow::doKeys(const QString& k)
|
|
{
|
|
/* [this should probably be using toLocal8Bit();
|
|
toAscii() is not offered as an alternative...] */
|
|
doKeys(k.toLatin1().constData());
|
|
}
|
|
|
|
// queue up the command name for a function, as if user had typed it
|
|
void NetHackQtMainWindow::FuncAsCommand(int (*func)(void))
|
|
{
|
|
char cmdbuf[32];
|
|
Strcpy(cmdbuf, "#");
|
|
(void) cmdname_from_func(func, &cmdbuf[1], FALSE);
|
|
doKeys(cmdbuf);
|
|
}
|
|
|
|
void NetHackQtMainWindow::AddMessageWindow(NetHackQtMessageWindow* window)
|
|
{
|
|
message=window;
|
|
if (!qt_compact_mode)
|
|
hsplitter->insertWidget(0, message->Widget());
|
|
ShowIfReady();
|
|
}
|
|
|
|
NetHackQtMessageWindow * NetHackQtMainWindow::GetMessageWindow()
|
|
{
|
|
return message;
|
|
}
|
|
|
|
void NetHackQtMainWindow::AddMapWindow(NetHackQtMapWindow2* window)
|
|
{
|
|
|
|
map=window;
|
|
if (!qt_compact_mode)
|
|
vsplitter->insertWidget(1, map->Widget());
|
|
ShowIfReady();
|
|
connect(map,SIGNAL(resized()),this,SLOT(layout()));
|
|
}
|
|
|
|
void NetHackQtMainWindow::AddStatusWindow(NetHackQtStatusWindow* window)
|
|
{
|
|
status=window;
|
|
if (!qt_compact_mode)
|
|
hsplitter->insertWidget(2, status->Widget());
|
|
ShowIfReady();
|
|
}
|
|
|
|
void NetHackQtMainWindow::RemoveWindow(NetHackQtWindow* window)
|
|
{
|
|
if (window==status) {
|
|
status=0;
|
|
ShowIfReady();
|
|
} else if (window==map) {
|
|
map=0;
|
|
ShowIfReady();
|
|
} else if (window==message) {
|
|
message=0;
|
|
ShowIfReady();
|
|
}
|
|
}
|
|
|
|
void NetHackQtMainWindow::updateInventory()
|
|
{
|
|
if (invusage) {
|
|
invusage->repaint();
|
|
}
|
|
}
|
|
|
|
void NetHackQtMainWindow::fadeHighlighting(bool before_key)
|
|
{
|
|
if (before_key) {
|
|
// status highlighting fades at start of turn
|
|
if (status)
|
|
status->fadeHighlighting();
|
|
} else {
|
|
// message highlighting fades after user has given input
|
|
if (message && message->hilit_mesgs())
|
|
message->unhighlight_mesgs();
|
|
}
|
|
}
|
|
|
|
void NetHackQtMainWindow::layout()
|
|
{
|
|
#if 0
|
|
if ( qt_compact_mode )
|
|
return;
|
|
if (message && map && status) {
|
|
QSize maxs=map->Widget()->maximumSize();
|
|
int maph=std::min(height()*2/3,maxs.height());
|
|
|
|
QWidget* c = centralWidget();
|
|
int h=c->height();
|
|
int toph=h-maph;
|
|
int iuw=3*qt_settings->glyphs().width();
|
|
int topw=(c->width()-iuw)/2;
|
|
|
|
message->Widget()->setGeometry(0,0,topw,toph);
|
|
invusage->setGeometry(topw,0,iuw,toph);
|
|
status->Widget()->setGeometry(topw+iuw,0,topw,toph);
|
|
map->Widget()->setGeometry(std::max(0,(c->width()-maxs.width())/2),
|
|
toph,c->width(),maph);
|
|
}
|
|
#endif
|
|
|
|
if (qt_settings && !qt_compact_mode
|
|
&& map && message && status && invusage) {
|
|
// For the initial PaperDoll sizing, message window
|
|
// and/or status window might still be empty;
|
|
// widen them before changing PaperDoll to use saved settings.
|
|
QList<int> splittersizes = hsplitter->sizes();
|
|
#define MIN_WIN_WIDTH 400
|
|
if (splittersizes[0] < MIN_WIN_WIDTH
|
|
|| splittersizes[2] < MIN_WIN_WIDTH) {
|
|
if (splittersizes[0] < MIN_WIN_WIDTH)
|
|
splittersizes[0] = MIN_WIN_WIDTH;
|
|
#ifndef ENHANCED_PAPERDOLL
|
|
if (splittersizes[1] < 6) // TILEWMIN
|
|
splittersizes[1] = 16; // 16x16
|
|
#endif
|
|
if (splittersizes[2] < MIN_WIN_WIDTH)
|
|
splittersizes[2] = MIN_WIN_WIDTH;
|
|
hsplitter->setSizes(splittersizes);
|
|
}
|
|
#ifdef ENHANCED_PAPERDOLL
|
|
// call resizePaperDoll() indirectly...
|
|
qt_settings->resizeDoll();
|
|
#endif
|
|
// reset widths
|
|
int w = width(); /* of main window */
|
|
int d = invusage->width();
|
|
splittersizes[2] = w / 2 - (d * 1 / 4); // status
|
|
splittersizes[1] = d; // invusage
|
|
splittersizes[0] = w / 2 - (d * 3 / 4); // messages
|
|
hsplitter->setSizes(splittersizes);
|
|
}
|
|
}
|
|
|
|
#ifdef DYNAMIC_STATUSLINES
|
|
// called when 'statuslines' changes from 2 to 3 or vice versa; simpler to
|
|
// destroy and recreate the status window than to adjust existing fields
|
|
NetHackQtWindow *NetHackQtMainWindow::redoStatus()
|
|
{
|
|
NetHackQtStatusWindow *oldstatus = this->status;
|
|
if (!oldstatus)
|
|
return NULL; // not ready yet?
|
|
this->status = new NetHackQtStatusWindow;
|
|
|
|
if (!qt_compact_mode)
|
|
hsplitter->replaceWidget(2, this->status->Widget());
|
|
|
|
delete oldstatus;
|
|
ShowIfReady();
|
|
|
|
return (NetHackQtWindow *) this->status;
|
|
}
|
|
#endif
|
|
|
|
void NetHackQtMainWindow::resizePaperDoll(bool showdoll)
|
|
{
|
|
#ifdef ENHANCED_PAPERDOLL
|
|
// this is absurd...
|
|
NetHackQtInvUsageWindow *w = static_cast <NetHackQtMainWindow *>
|
|
(NetHackQtBind::mainWidget())->invusage;
|
|
QList<int> hsplittersizes = hsplitter->sizes(),
|
|
vsplittersizes = vsplitter->sizes();
|
|
w->resize(w->sizeHint());
|
|
|
|
int oldwidth = hsplittersizes[1],
|
|
newwidth = w->width();
|
|
if (newwidth != oldwidth) {
|
|
if (oldwidth > newwidth)
|
|
hsplittersizes[0] += (oldwidth - newwidth);
|
|
else
|
|
hsplittersizes[2] += (newwidth - oldwidth);
|
|
hsplittersizes[1] = newwidth;
|
|
hsplitter->setSizes(hsplittersizes);
|
|
}
|
|
|
|
// Height limit is 48+2 pixels per doll cell plus 1 pixel margin at top;
|
|
// values greater than 44+2 need taller window which pushes the map down
|
|
// (when font size 'Large' is used for messages and status; threshold
|
|
// may vary by 1 or 2 for other sizes).
|
|
// FIXME: this doesn't shrink the window back if size is reduced from 45+
|
|
int oldheight = vsplittersizes[0],
|
|
newheight = w->height();
|
|
if (newheight > oldheight && oldheight > 0 && vsplittersizes[1] > 0) {
|
|
vsplittersizes[0] = newheight;
|
|
vsplitter->setSizes(vsplittersizes);
|
|
}
|
|
|
|
if (showdoll) {
|
|
if (w->isHidden())
|
|
w->show();
|
|
else
|
|
w->repaint();
|
|
} else {
|
|
if (w->isVisible())
|
|
w->hide();
|
|
}
|
|
#else
|
|
nhUse(showdoll);
|
|
#endif /* ENHANCED_PAPERDOLL */
|
|
}
|
|
|
|
void NetHackQtMainWindow::resizeEvent(QResizeEvent*)
|
|
{
|
|
layout();
|
|
#ifdef KDE
|
|
updateRects();
|
|
#endif
|
|
}
|
|
|
|
void NetHackQtMainWindow::keyReleaseEvent(QKeyEvent* event)
|
|
{
|
|
if ( dirkey ) {
|
|
doKeys(QString(QChar(dirkey)));
|
|
if ( !event->isAutoRepeat() )
|
|
dirkey = 0;
|
|
}
|
|
}
|
|
|
|
void NetHackQtMainWindow::keyPressEvent(QKeyEvent* event)
|
|
{
|
|
// Global key controls
|
|
|
|
// For desktop, arrow keys scroll map, since we don't want players
|
|
// to think that's the way to move. For handhelds, the normal way is to
|
|
// click-to-travel, so we allow the cursor keys for fine movements.
|
|
|
|
// 321
|
|
// 4 0
|
|
// 567
|
|
|
|
if ( event->isAutoRepeat() &&
|
|
event->key() >= Qt::Key_Left && event->key() <= Qt::Key_Down )
|
|
return;
|
|
|
|
const char* d = gc.Cmd.dirchars;
|
|
switch (event->key()) {
|
|
case Qt::Key_Up:
|
|
if ( dirkey == d[0] )
|
|
dirkey = d[1];
|
|
else if ( dirkey == d[4] )
|
|
dirkey = d[3];
|
|
else
|
|
dirkey = d[2];
|
|
break;
|
|
case Qt::Key_Down:
|
|
if ( dirkey == d[0] )
|
|
dirkey = d[7];
|
|
else if ( dirkey == d[4] )
|
|
dirkey = d[5];
|
|
else
|
|
dirkey = d[6];
|
|
break;
|
|
case Qt::Key_Left:
|
|
if ( dirkey == d[2] )
|
|
dirkey = d[1];
|
|
else if ( dirkey == d[6] )
|
|
dirkey = d[7];
|
|
else
|
|
dirkey = d[0];
|
|
break;
|
|
case Qt::Key_Right:
|
|
if ( dirkey == d[2] )
|
|
dirkey = d[3];
|
|
else if ( dirkey == d[6] )
|
|
dirkey = d[5];
|
|
else
|
|
dirkey = d[4];
|
|
break;
|
|
case Qt::Key_PageUp:
|
|
dirkey = 0;
|
|
if (message) message->Scroll(0,-1);
|
|
break;
|
|
case Qt::Key_PageDown:
|
|
dirkey = 0;
|
|
if (message) message->Scroll(0,+1);
|
|
break;
|
|
case Qt::Key_Space:
|
|
//if (flags.rest_on_space) {
|
|
event->ignore(); // punt to NetHackQtBind::notify()
|
|
return;
|
|
//}
|
|
case Qt::Key_Enter:
|
|
if ( map )
|
|
map->clickCursor();
|
|
break;
|
|
default:
|
|
dirkey = 0;
|
|
event->ignore();
|
|
break;
|
|
}
|
|
}
|
|
|
|
// game window's Close button has been activated
|
|
void NetHackQtMainWindow::closeEvent(QCloseEvent *e UNUSED)
|
|
{
|
|
int ok = 0;
|
|
if ( gp.program_state.something_worth_saving ) {
|
|
/* this used to offer "Save" and "Cancel"
|
|
but cancel (ignoring the close attempt) won't work
|
|
if user has clicked on the window's Close button */
|
|
int act = QMessageBox::information(this, "NetHack",
|
|
"This will end your NetHack session.",
|
|
"&Save and exit", "&Quit without saving", 0, 1);
|
|
switch (act) {
|
|
case 0:
|
|
// save portion of save-and-exit
|
|
ok = dosave0();
|
|
break;
|
|
case 1:
|
|
// quit -- bypass the prompting preformed by done2()
|
|
ok = 1;
|
|
gp.program_state.stopprint++;
|
|
::done(QUIT);
|
|
/*NOTREACHED*/
|
|
break;
|
|
}
|
|
} else {
|
|
/* nothing worth saving; just close/quit */
|
|
ok = 1;
|
|
}
|
|
/* if !ok, we should try to continue, but we don't... */
|
|
nhUse(ok);
|
|
u.uhp = -1;
|
|
NetHackQtBind::qt_exit_nhwindows(0);
|
|
nh_terminate(EXIT_SUCCESS);
|
|
}
|
|
|
|
void NetHackQtMainWindow::ShowIfReady()
|
|
{
|
|
if (message && map && status) {
|
|
QWidget* hp = qt_compact_mode ? static_cast<QWidget *>(stack)
|
|
: static_cast<QWidget *>(hsplitter);
|
|
QWidget* vp = qt_compact_mode ? static_cast<QWidget *>(stack)
|
|
: static_cast<QWidget *>(vsplitter);
|
|
message->Widget()->setParent(hp);
|
|
map->Widget()->setParent(vp);
|
|
status->Widget()->setParent(hp);
|
|
if ( qt_compact_mode ) {
|
|
message->setMap(map);
|
|
stack->addWidget(map->Widget());
|
|
stack->addWidget(message->Widget());
|
|
stack->addWidget(status->Widget());
|
|
raiseMap();
|
|
} else {
|
|
layout();
|
|
}
|
|
showMaximized();
|
|
} else if (isVisible()) {
|
|
hide();
|
|
}
|
|
}
|
|
|
|
} // namespace nethack_qt_
|