diff --git a/include/tcap.h b/include/tcap.h
index a17833385..ec5e9a336 100644
--- a/include/tcap.h
+++ b/include/tcap.h
@@ -9,6 +9,7 @@
#define TCAP_H
#ifndef MICRO
+/* NLE: We use ANSI_DEFAULT for terminal handling*/
#ifndef RL_GRAPHICS
#define TERMLIB /* include termcap code */
#endif
diff --git a/win/Qt/Info.plist b/win/Qt/Info.plist
deleted file mode 100644
index f2e9195ee..000000000
--- a/win/Qt/Info.plist
+++ /dev/null
@@ -1,20 +0,0 @@
-
-
-
-
- CFBundleGetInfoHTML
- http://www.nethack.org
- CFBundleGetInfoString
- Copyright (C) 1985-2003 Stichting Mathematisch Centrum
- CFBundleIconFile
- nethack.icns
- CFBundleIdentifier
- org.nethack.qt
- CFBundlePackageType
- APPL
- CFBundleShortVersionString
- 3.5.0
- CFBundleSignature
- NHak
-
-
diff --git a/win/Qt/Install.Qt b/win/Qt/Install.Qt
deleted file mode 100644
index 6a3de9c3e..000000000
--- a/win/Qt/Install.Qt
+++ /dev/null
@@ -1,113 +0,0 @@
-Installing NetHack with a Qt or KDE interface
----------------------------------------------
-$NHDT-Date: 1524689332 2018/04/25 20:48:52 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.11 $
-# Copyright (c) 2004 by Warwick Allison
-# NetHack may be freely redistributed. See license for details.
-
-This document describes the installation of NetHack with a Qt interface
-on UNIX/X11 or Mac OS X. This code should also work with Qt/Windows, but
-support for that is not currently official.
-
-You can download Qt from http://www.trolltech.com.
-You need Qt 2.0 or later to use this code.
-
-To use this code on UNIX (not Mac OS X):
-
- 1. follow the directions for the UNIX installation (in ../../sys/unix)
- to create the Makefiles.
-
- 2. ../../include/config.h
-
- define QT_GRAPHICS (search for it). You can comment out
- TTY_GRAPHICS if you want to, or leave it in to support both
- interfaces (in which case be sure you have the right curses
- libraries etc. required for that interface).
-
- 3. ../../src/Makefile
-
- ensure your QTDIR environment variable was set correctly when
- you installed Qt - $QTDIR/include/qwidget.h should exist, for
- example.
-
- ensure CXX and LINK are set to the compiler and linker you need
- for compiling and linking C++ software (e.g., set both to g++).
-
- add $(WINQTSRC), $(WINQTOBJ), and $(WINQTLIB) to WINSRC, WINOBJ,
- and WINLIB respectively, and compile. This will give you an
- executable supporting both Qt and tty windowing.
-
- 4. ../../Makefile (the top-level makefile)
-
- Just change the VARDATND setting to contain the files
- "x11tiles", "rip.xpm", and "nhsplash.xpm":
-
- VARDATND = x11tiles rip.xpm nhsplash.xpm
-
- 5. Follow all the instructions in ../../sys/unix/Install.unx for
- the remainder of the installation process.
-
- 6. Consider adding the lines below to your .nethackrc, as they are
- likely to give the best interface for this window port:
-
- OPTIONS=name:player,number_pad,menustyle:partial,!time,showexp
- OPTIONS=hilite_pet,toptenwin,msghistory:200,windowtype:Qt
-
-If you are using KDE, you may want to also try the KDE version. It just
-uses the KDE menubar and follows other KDE conventions - there is no
-extra functionality. To do so:
-
- 1. Ensure that you have KDE 2.x libraries on your system
- (in 1999 KDE 1.x was the norm)
-
- 2. ../../src/Makefile
-
- Add $(KDECXXFLAGS) to the CXXFLAGS definition, $(KDELFLAGS) to
- the LFLAGS definition and $(WINKDELIB) to WINLIB.
-
- 3. Some additional files here - knh-mini.xpm, knh.xpm, and
- knethack.lnk are useful if you want to install "knethack" in
- the KDE games directory.
-
-If you are using Qtopia, you can compile NetHack for that environment
-with the following additional steps:
-
- 1. First be sure that you can build a simple Qtopia application,
- such as the examples that ship with Qtopia. Do not attempt
- something as challenging to compile as NetHack before you can
- already build a Qtopia application for your target device.
-
- 2. If you are cross-compiling (eg. targetting an ARM-based handheld),
- be sure to follow the steps for cross-compiling in the Makefile.src
- and Makefile.utl files.
-
- 3. To CXXFLAGS in Makefile.src, add:
- -DQWS -I$(QPEDIR)/include -fno-rtti -fno-exceptions
-
- 4. Rather than -lqt in WINQTLIB, have:
- -L$(QPEDIR)/lib -lqpe -lqte
-
- 5. After building, use the "mkipks" program that ships with Qtopia
- to package the result into an ipk file.
-
-To use this code on Mac OS X:
-
- 1. follow the directions for the UNIX installation (in ../../sys/unix)
- to create the Makefiles.
-
- 2. quite a number of changes are required to the Makefiles. They are
- slowly being made 'official', but for now they are all in the patch
- nethack-macosx-qt.patch:
-
- cd ../..
- patch -p0 < win/Qt/nethack-macosx-qt.patch
-
- 3. Follow all the instructions in ../../sys/unix/Install.unx for
- the remainder of the installation process (basically run "make install").
-
- 4. Consider adding the lines below to a file called "NetHack Defaults",
- in your "Library/Preferences" folder, as they are likely to give
- the best interface for this window port:
-
- OPTIONS=name:player,number_pad,menustyle:partial,!time,showexp
- OPTIONS=hilite_pet,toptenwin,msghistory:200,windowtype:Qt
-
diff --git a/win/Qt/Qt-issues.txt b/win/Qt/Qt-issues.txt
new file mode 100644
index 000000000..1de8b9c8c
--- /dev/null
+++ b/win/Qt/Qt-issues.txt
@@ -0,0 +1,68 @@
+Qt-NetHack issues
+-----
+
+Urgent: if the program crashes on OSX, a dialog box asking the user
+whether to [ignore], [report...], or [re-open] will eventually appear
+(it's slow). That should be repressed even if the report choice could
+be directed at nethack.org.
+
+Launching Qt nethack as a synchronous subprocess (ie, no trailing '&')
+from a Terminal window, changing focus back to that terminal after
+NetHack has started, and typing ^C was sending the program into an
+endless loop in qt_nhgetch() with repeated messages to stderr
+(the terminal) complaining that the event loop is already running.
+Triggered by yn_function("Really quit?") in the core. That situation
+has been reduced to a single event loop complaint, so downgraded from
+"Urgent", but the prompt is auto-answered with ESC instead of letting
+the user respond.
+
+On OSX, if the program is run from nethackdir/nethack rather than from
+NetHack.app/Contents/MacOS/nethack (plus having NetHack.app/Contents/
+Info.plist containing pertinent information) then the menu bar at the
+top of the screen won't accept mouse clicks and the application menu
+entry in that menu bar will show as "nethack" (filename) rather than
+"NetHack" (intended application name). The click issue can be worked
+around by giving focus to some other application (which will put up
+its own menu bar) and then back to nethack (thereby reloading nethack's
+menu bar).
+
+Sometimes scrolling a menu leaves the displayed text not matching what
+nethack thinks is displayed, so making a selection by mouse click may
+occasionally pick the wrong item. There's usually a visual clue when
+this happens. As long as it's not a pick-one menu, scrolling up and
+down or back and worth a few times will usually get things back in
+sync, then you can click on the wrong entry to uncheck it and then on
+the right entry to check that. Making a selection by typing its
+letter doesn't suffer from this, but isn't always possible (ie, long
+menu like 'O's where first 52 items have letters but remainder don't).
+
+On OSX, command+Q while a menu (which has its own key event handler)
+is popped up gets ignored. It should at least close the popup like
+ESC and maybe also initiate quitting.
+
+Map column #0, which the core reserves for its own purposes and isn't
+intended to be displayed, is displayed (as blank terrain).
+
+5.0 status conditions haven't been implemented.
+
+3.6 status conditions (Stone, Slime, Strngl, Deaf, Lev, Fly, Ride)
+have been implemented but need icon artwork (one 40x40 tile for each).
+
+Clicking on window close button pops up a confirmation dialog with
+ [ Save and exit ] [__Quit_without_saving__]
+with the second one highlighted. Internally they're specified as
+"&Save" and "&Quit". Typing or picks Quit, but
+typing 'Q' or 'q' picks Save-and-exit because Alt+Q is expected for
+the keyboard shortcut.
+
+The status window can't be resized while hitpointbar is active.
+Toggling it off, resizing as desired, then toggling it back on is a
+viable workaround.
+
+When choosing a saved game to restore ('selectsaved' option), the
+selection dialog does not provide any way to scroll if there are more
+games than will fit on the screen. Access to "New game" and "Quit"
+isn't affected because those both have distinct buttons rather than
+rely on fake save file entries at the end of the list.
+
+-----
diff --git a/win/Qt/knethack.lnk b/win/Qt/knethack.lnk
deleted file mode 100644
index 35e01f920..000000000
--- a/win/Qt/knethack.lnk
+++ /dev/null
@@ -1,18 +0,0 @@
-# KDE Config File
-# Call this file knethack.kdelnk or knethack.desktop
-[KDE Desktop Entry]
-Name=Nethack
-Name[fr]=Nethack
-Name[hu]=Nethack
-Name[no]=Nethack
-Name[sk]=Nethack
-Name[cs]=Nethack
-Name[hr]=Nethack
-Name[pt]=Nethack
-Name[pt_BR]=Nethack
-Icon=knh.xpm
-Exec=knethack -caption "%c" %i %m
-Type=Application
-DocPath=knethack/index.html
-Comment=The classic Unix role-playing game - fight monsters and seek the Amulet of Yendor for your god!
-
diff --git a/win/Qt/knh-mini.xpm b/win/Qt/knh-mini.xpm
deleted file mode 100644
index 05bd70e6f..000000000
--- a/win/Qt/knh-mini.xpm
+++ /dev/null
@@ -1,30 +0,0 @@
-/* XPM */
-static char *noname[] = {
-/* width height ncolors chars_per_pixel */
-"16 16 7 1",
-/* colors */
-" c #000000",
-". c #DCDCDC",
-"X c #008080",
-"o c #A0A0A0",
-"O c None",
-"+ c #FFFFFF",
-"@ c #C3C3C3",
-/* pixels */
-"OOOOOOOOOOOOOOOO",
-"OOO+O+++@@@O@OOO",
-"O+O+++++@@@@@O.O",
-"O+o+XXXXX X @ . ",
-"O+o+XXXX X X@ . ",
-"OO +XXXXX X @ O ",
-"OOO+XXXX X X@ OO",
-"OOO+XXXXX X @ OO",
-"OOO+XXXX X X@ OO",
-"OOOO+XXXX X@ OO",
-"OOOO+XXX X . OO",
-"OOO+O+XXX . . OO",
-"OO+++ +X . ... O",
-"O+++. O+. .... ",
-"OO+. OOOOOO.. O",
-"OOOOOOOOOOOOOOOO"
-};
diff --git a/win/Qt/knh.xpm b/win/Qt/knh.xpm
deleted file mode 100644
index 9c0312796..000000000
--- a/win/Qt/knh.xpm
+++ /dev/null
@@ -1,67 +0,0 @@
-/* XPM */
-static char *noname[] = {
-/* width height ncolors chars_per_pixel */
-"40 40 20 1",
-/* colors */
-" c #000000",
-". c #0000C0",
-"X c #FFC0FF",
-"o c #FFC0C0",
-"O c #DCDCDC",
-"+ c #C0C0FF",
-"@ c #008080",
-"# c #A0A0A0",
-"$ c None",
-"% c #000080",
-"& c #585858",
-"* c #800080",
-"= c #FFFFFF",
-"- c #FFFFC0",
-"; c #00C0C0",
-": c #C0FFFF",
-"> c #C0FFC0",
-", c #C3C3C3",
-"< c #FFDCA8",
-"1 c #0000FF",
-/* pixels */
-"$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$",
-"$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$",
-"$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$",
-"$$$$$$$$=$$$$$$=,==<,=<,$$$$$$,$$$$$$$$$",
-"$$$$$$$$==$$$=====,=<>,<><$$$<>$$$$$$$$$",
-"$$$$$$$$===$====,==>,=<,<,,$,,<$$$$$$$$$",
-"$$$==$$$==========<=<,><,><<><,$$$,<$$$$",
-"$$$====$========,==,,=<>,<,>,<,$<><,$$$$",
-"$$$====$==========<=<,,<<><,<><$,,<>$$$$",
-"$$$$#&&&==$#$#$#@#$&@#&&@&&&&,, && $$",
-"$$$;#@&@==;#;#;#$;@&@$&@&@$>< &@ $$",
-"$$$====&==###1##.##@&@&&$&&<, <>O< $$",
-"$$$====&==$;##;##;@&@$&@&@&>, O<,> $$",
-"$$$==&@&==#1#;##.##@&@&$@$&,< ,< $$",
-"$$$$ ==###1#;##.#@$&&&@&&@-, $ $$",
-"$$$$$ =X;#;###&;#&@#&@$&@$&,< $$ $$$",
-"$$$$$$ ==#$+@+1##@#&@&$@&&&@<> $$$$$$",
-"$$$$$$$$=X;#1#$#@##@@&&&@$&<, $$$$$$",
-"$$$$$$$$==##;#;##1$#@&$@$&&@&>< $$$$$$",
-"$$$$$$$$=X;###1#@##@@&&@$&&O, $$$$$$",
-"$$$$$$$$==#1#;##;#.#@&&$@&@&@<> $$$$$$",
-"$$$$$$$$$==###;#*;#&@#&@&&$&O< $$$$$$$",
-"$$$$$$$$$==;#1,$;#@$@&$@&@<, $$$$$$$",
-"$$$$$$$$$$=X####.##@&&@&& ><, $$$$$$",
-"$$$$$$====@&=O##@#;&@#&&,< <,>< $$$$$",
-"$$$$$===#$== ==$1#&@&O> ,<$#,,> $$$$",
-"$$$$===#;#== ==$#;&@#O, >,#;&<,< $$$$",
-"$$$==$#;*@O< ====Oo,> <,&$#@&O, $$$",
-"$$$==;$#&&<, $===<,< < $$",
-"$$$==##;&O>, $$==,> $$ ,<&$@o, $$",
-"$$$===X=O,< $$$$$$$$$$$$$>OO,Oo> $$$",
-"$$$$====,< $$$$$$$$$$$$$$,<,>,<, $$$$",
-"$$$$$===<> $$$$$$$$$$$$$$$$><,<> $$$$",
-"$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$",
-"$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$",
-"$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$",
-"$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$"
-};
diff --git a/win/Qt/qpe-nethack.control b/win/Qt/qpe-nethack.control
deleted file mode 100644
index c8b73f5f7..000000000
--- a/win/Qt/qpe-nethack.control
+++ /dev/null
@@ -1,9 +0,0 @@
-Files: bin/nethack pics/NetHack.png apps/Games/nethack.desktop games/lib/nethackdir/[a-r]* games/lib/nethackdir/[t-z]* games/lib/nethackdir/save games/lib/nethackdir/s*.* games/lib/nethackdir/[A-Z0-9]*
-Priority: optional
-Section: qpe/games
-Maintainer: Warwick Allison
-Architecture: arm
-Version: 3.5.0-1
-Depends: qpe-base ($QPE_VERSION)
-Description: NetHack - The Dungeon Game
- Graphical version of NetHack for Qtopia
diff --git a/win/Qt/qt_bind.cpp b/win/Qt/qt_bind.cpp
new file mode 100644
index 000000000..feb716a2d
--- /dev/null
+++ b/win/Qt/qt_bind.cpp
@@ -0,0 +1,1331 @@
+// Copyright (c) Warwick Allison, 1999.
+// Qt4 conversion copyright (c) Ray Chason, 2012-2014.
+// NetHack may be freely redistributed. See license for details.
+
+// qt_bind.cpp -- bindings between the Qt 4 interface and the main code
+
+extern "C" {
+#include "hack.h"
+}
+
+#include "qt_pre.h"
+#include
+#include
+#if defined(USER_SOUNDS) && !defined(QT_NO_SOUND)
+#if QT_VERSION < 0x050000
+#include
+#elif QT_VERSION < 0x060000
+#include
+#include
+#else
+/* Qt6 or above */
+#include
+#include
+#endif /* QT_VERSION */
+#endif /* USER_SOUNDS && !QT_NO_SOUND */
+#include "qt_post.h"
+#include "qt_bind.h"
+#include "qt_click.h"
+#ifdef TIMED_DELAY
+#include "qt_delay.h"
+#endif
+#include "qt_xcmd.h"
+#include "qt_key.h"
+#include "qt_map.h"
+#include "qt_menu.h"
+#include "qt_msg.h"
+#include "qt_plsel.h"
+#include "qt_svsel.h"
+#include "qt_set.h"
+#include "qt_stat.h"
+#include "qt_streq.h"
+#include "qt_yndlg.h"
+#include "qt_str.h"
+
+extern "C" {
+#include "dlb.h"
+}
+
+// temporary
+extern int qt_compact_mode;
+// end temporary
+
+namespace nethack_qt_ {
+
+// XXX Should be from Options [or from Qt Settings (aka Preferences)].
+//
+// XXX Hmm. Tricky part is that perhaps some macros should only be active
+// XXX when a key is about to be gotten. For example, the user could
+// XXX define "-" to do "E-yyyyyyyy\r", but would still need "-" for
+// XXX other purposes. Maybe just too bad.
+//
+static struct key_macro_rec {
+ int key;
+ uint state;
+ const char *macro, *numpad_macro;
+} key_macro[]={
+ { Qt::Key_F1, 0U, "100.", "n100." }, // Rest (x100)
+ { Qt::Key_F2, 0U, "20s", "n20s" }, // Search (x20)
+ { Qt::Key_Tab, 0U, "\001", "\001" }, // ^A (Do-again)
+ { 0, 0U, (const char *) 0, (const char *) 0 }
+};
+
+#ifdef IDLECHECKPOINT
+#ifndef IDLECHECKPOINT_WAIT_TIME
+#define IDLECHECKPOINT_WAIT_TIME 10
+#endif
+static void qt_timer_fire(void);
+QTimer *qt_input_timer;
+#endif
+
+static QPen *pen = (QPen *) 0;
+
+NetHackQtBind::NetHackQtBind(int& argc, char** argv) :
+#ifdef KDE
+ KApplication(argc,argv)
+#elif defined(QWS) // not quite the right condition
+ QPEApplication(argc,argv)
+#else
+ QApplication(argc,argv)
+#endif
+{
+ splash = 0;
+ if (iflags.wc_splash_screen)
+ NetHackQtBind::qt_Splash(); // show something while starting up
+
+ // these used to be in MainWindow but we want them before QtSettings
+ // which we want before MainWindow...
+ QCoreApplication::setOrganizationName("The NetHack DevTeam");
+ QCoreApplication::setOrganizationDomain("nethack.org");
+ QCoreApplication::setApplicationName("NetHack-Qt"); // Qt NetHack
+ {
+ char cvers[BUFSZ];
+ QString qvers = QString(::version_string(cvers, sizeof cvers));
+ QCoreApplication::setApplicationVersion(qvers);
+ }
+#ifdef MACOS
+ /* without this, neither control+x nor option+x do anything;
+ with it, control+x is ^X and option+x still does nothing */
+ QCoreApplication::setAttribute(Qt::AA_MacDontSwapCtrlAndMeta);
+#endif
+
+ qt_settings = new NetHackQtSettings(); /*(main->width(),main->height());*/
+
+ main = new NetHackQtMainWindow(keybuffer);
+ connect(qApp, SIGNAL(lastWindowClosed()), qApp, SLOT(quit()));
+ msgs_strings = new QStringList();
+ msgs_initd = false;
+ msgs_saved = false;
+}
+
+// before the game windows have been rendered, display a small, centered
+// window showing a flying red dragon ridden by someone wielding a lance,
+// with caption "Loading..."
+void
+NetHackQtBind::qt_Splash()
+{
+ QPixmap pm("nhsplash.xpm"); // load splash image from a file in HACKDIR
+ if (!pm.isNull()) {
+ splash = new QFrame(NULL, (Qt::FramelessWindowHint
+ | Qt::X11BypassWindowManagerHint
+ | Qt::WindowStaysOnTopHint));
+ QVBoxLayout *vb = new QVBoxLayout(splash);
+ QLabel *lsplash = new QLabel(splash);
+ vb->addWidget(lsplash);
+ lsplash->setAlignment(Qt::AlignCenter);
+ lsplash->setPixmap(pm);
+ lsplash->setFixedSize(pm.size());
+ //lsplash->setMask(pm.mask());
+ QLabel *capt = new QLabel("Loading...", splash);
+ vb->addWidget(capt);
+ capt->setAlignment(Qt::AlignCenter);
+
+#if QT_VERSION < 0x060000
+ QSize screensize = QApplication::desktop()->size();
+#else
+ QSize screensize = splash->screen()->size();
+#endif
+ splash->move((screensize.width() - pm.width()) / 2,
+ (screensize.height() - pm.height()) / 2);
+ //splash->setGeometry(0,0,100,100);
+ if (qt_compact_mode) {
+ splash->showMaximized();
+ } else {
+#if __cplusplus >= 202002L
+ splash->setFrameStyle(static_cast(QFrame::WinPanel)
+ | static_cast(QFrame::Raised));
+#else
+ splash->setFrameStyle(QFrame::WinPanel | QFrame::Raised);
+#endif
+ splash->setLineWidth(10);
+ splash->adjustSize();
+ splash->show();
+ }
+
+ // force content refresh outside event loop
+ splash->repaint();
+ lsplash->repaint();
+ capt->repaint();
+ qApp->processEvents();
+ } else {
+ splash = 0; // caller has already done this...
+ }
+}
+
+void NetHackQtBind::qt_init_nhwindows(int *argc, char **argv)
+{
+ // menu entries use embedded to align fields;
+ // it could be toggled off via 'O', but only when in wizard mode
+ ::iflags.menu_tab_sep = true;
+
+ // force high scores display to be shown in a window, and don't allow
+ // that to be toggled off via 'O' (note: 'nethack -s' won't reach here;
+ // its output goes to stdout so can potentially be redirected into a file)
+ ::iflags.toptenwin = true;
+ ::set_option_mod_status("toptenwin", ::set_in_config);
+
+#ifdef UNIX
+// Userid control
+//
+// Michael Hohmuth ...
+//
+// As the game runs setuid games, it must seteuid(getuid()) before
+// calling XOpenDisplay(), and reset the euid afterwards.
+// Otherwise, it can't read the $HOME/.Xauthority file and whines about
+// not being able to open the X display (if a magic-cookie
+// authorization mechanism is being used).
+
+ uid_t gamesuid=geteuid();
+ seteuid(getuid());
+#endif
+
+ instance=new NetHackQtBind(*argc,argv);
+
+#ifdef UNIX
+ seteuid(gamesuid);
+#endif
+
+#ifdef _WS_WIN_
+ // This nethack engine feature should be moved into windowport API
+ nt_kbhit = NetHackQtBind::qt_kbhit;
+#endif
+
+#ifndef DYNAMIC_STATUSLINES
+ // 'statuslines' option can be set in config file but not via 'O'
+ set_wc2_option_mod_status(WC2_STATUSLINES, set_gameview);
+#endif
+#if defined(SND_LIB_QTSOUND) && !defined(QT_NO_SOUND)
+ /* assign_soundlib() just flags to NetHack which soundlib
+ * should be loaded by activate_chosen_soundlib() shortly.
+ * gc.chosen_soundlib is initialized to soundlib_nosound.
+ */
+ if (gc.chosen_soundlib == (uint32_t) soundlib_nosound) {
+ uint32_t soundlibchoice = (uint32_t) soundlib_qtsound;
+
+ assign_soundlib(soundlibchoice);
+ }
+#endif
+}
+
+int NetHackQtBind::qt_kbhit()
+{
+ return !keybuffer.Empty();
+}
+
+
+static bool have_asked = false;
+
+void NetHackQtBind::qt_player_selection()
+{
+ if ( !have_asked )
+ qt_askname();
+}
+
+void NetHackQtBind::qt_askname()
+{
+ char default_plname[PL_NSIZ];
+ int ch = -1; // -1 => new game
+
+ have_asked = true;
+ str_copy(default_plname, svp.plname, PL_NSIZ);
+
+ // We do it all here (plus qt_plsel.cpp and qt_svsel.cpp),
+ // nothing in player_selection().
+
+#ifdef SELECTSAVED
+ char **saved = 0;
+ if (::iflags.wc2_selectsaved)
+ saved = get_saved_games();
+ if (saved && *saved) {
+ if (splash)
+ splash->hide();
+ NetHackQtSavedGameSelector sgsel((const char **) saved);
+ ch = sgsel.choose();
+ if (ch >= 0)
+ str_copy(svp.plname, saved[ch], SIZE(svp.plname));
+ // caller needs new lock name even if plname[] hasn't changed
+ // because successful get_saved_games() clobbers gs.SAVEF[]
+ ::iflags.renameinprogress = TRUE;
+ }
+ free_saved_games(saved);
+#endif
+
+ switch (ch) {
+ case -1:
+ // New Game
+ if (splash)
+ splash->hide();
+ if (NetHackQtPlayerSelector(keybuffer).Choose()) {
+ // success; handle plname[] verification below prior to returning
+ break;
+ }
+ FALLTHROUGH;
+ /*FALLTHRU*/
+ case -2:
+ // Quit
+ clearlocks();
+ qt_exit_nhwindows(0);
+ nh_terminate(0);
+ /*NOTREACHED*/
+ break;
+ default:
+ // picked a character from the saved games list
+ break;
+ }
+
+ if (!*svp.plname)
+ // in case Choose() returns with plname[] empty
+ Strcpy(svp.plname, default_plname);
+ else if (strcmp(svp.plname, default_plname) != 0)
+ // caller needs to set new lock file name
+ ::iflags.renameinprogress = TRUE;
+ return;
+}
+
+void NetHackQtBind::qt_get_nh_event()
+{
+}
+
+#if defined(QWS)
+// Kludge to access lastWindowClosed() signal.
+class TApp : public QApplication {
+public:
+ TApp(int& c, char**v) : QApplication(c,v) {}
+ void lwc() { emit lastWindowClosed(); }
+};
+#endif
+
+void NetHackQtBind::qt_exit_nhwindows(const char *)
+{
+#ifdef IDLECHECKPOINT
+ if (qt_input_timer) {
+ NetHackQtBind::free_qt_input_timer();
+ }
+#endif
+#if defined(QWS)
+ // Avoids bug in SHARP SL5500
+ ((TApp*)qApp)->lwc();
+ qApp->quit();
+#endif
+
+ delete instance; // ie. qApp
+}
+
+void NetHackQtBind::qt_suspend_nhwindows(const char *)
+{
+}
+
+void NetHackQtBind::qt_resume_nhwindows()
+{
+}
+
+static QVector id_to_window;
+
+winid NetHackQtBind::qt_create_nhwindow(int type)
+{
+ winid id;
+ for (id = 0; id < (winid) id_to_window.size(); id++) {
+ if ( !id_to_window[(int)id] )
+ break;
+ }
+ if ( id == (winid) id_to_window.size() )
+ id_to_window.resize(id+1);
+
+ NetHackQtWindow* window=0;
+
+ switch (type) {
+ case NHW_MAP: {
+ NetHackQtMapWindow2* w=new NetHackQtMapWindow2(clickbuffer);
+ main->AddMapWindow(w);
+ window=w;
+ break;
+ }
+ case NHW_MESSAGE: {
+ NetHackQtMessageWindow* w=new NetHackQtMessageWindow;
+ main->AddMessageWindow(w);
+ window=w;
+ break;
+ }
+ case NHW_STATUS: {
+ NetHackQtStatusWindow* w=new NetHackQtStatusWindow;
+ main->AddStatusWindow(w);
+ window=w;
+ break;
+ }
+ case NHW_MENU:
+ window=new NetHackQtMenuOrTextWindow(mainWidget());
+ break;
+ case NHW_TEXT:
+ window=new NetHackQtTextWindow(mainWidget());
+ break;
+ }
+
+ window->nhid = id;
+
+ // Note: use of isHidden does not work with Qt 2.1
+ if ( splash
+#if QT_VERSION >= 300
+ && !main->isHidden()
+#else
+ && main->isVisible()
+#endif
+ ) {
+ delete splash;
+ splash = 0;
+ }
+
+ id_to_window[(int)id] = window;
+ return id;
+}
+
+void NetHackQtBind::qt_clear_nhwindow(winid wid)
+{
+ NetHackQtWindow* window=id_to_window[(int)wid];
+ if (window)
+ window->Clear();
+}
+
+void NetHackQtBind::qt_display_nhwindow(winid wid, boolean block)
+{
+ NetHackQtWindow* window=id_to_window[(int)wid];
+ if (window)
+ window->Display(block);
+}
+
+void NetHackQtBind::qt_destroy_nhwindow(winid wid)
+{
+ NetHackQtWindow* window=id_to_window[(int)wid];
+ if (window) {
+ main->RemoveWindow(window);
+ if (window->Destroy())
+ delete window;
+ id_to_window[(int) wid] = 0;
+ }
+}
+
+void NetHackQtBind::qt_curs(winid wid, int x, int y)
+{
+ NetHackQtWindow* window=id_to_window[(int)wid];
+ window->CursorTo(x,y);
+}
+
+void NetHackQtBind::qt_putstr(winid wid, int attr, const char *text)
+{
+ NetHackQtWindow* window=id_to_window[(int)wid];
+ window->PutStr(attr,QString::fromLatin1(text));
+}
+
+void NetHackQtBind::qt_putstr(winid wid, int attr, const std::string& text)
+{
+ NetHackQtWindow* window=id_to_window[(int)wid];
+ window->PutStr(attr,QString::fromLatin1(text.c_str(), text.size()));
+}
+
+void NetHackQtBind::qt_putstr(winid wid, int attr, const QString& text)
+{
+ NetHackQtWindow* window=id_to_window[(int)wid];
+ window->PutStr(attr,text);
+}
+
+void NetHackQtBind::qt_display_file(const char *filename, boolean must_exist)
+{
+ NetHackQtTextWindow* window=new NetHackQtTextWindow(mainWidget());
+ bool complain = false;
+
+ {
+ dlb *f;
+ char buf[BUFSZ];
+ char *cr;
+
+ window->Clear();
+ f = dlb_fopen(filename, "r");
+ if (!f) {
+ complain = must_exist;
+ } else {
+ while (dlb_fgets(buf, BUFSZ, f)) {
+ if ((cr = strchr(buf, '\n')) != 0) *cr = 0;
+#ifdef MSDOS
+ if ((cr = strchr(buf, '\r')) != 0) *cr = 0;
+#endif
+ window->PutStr(ATR_NONE, tabexpand(buf));
+ }
+ window->Display(false);
+ (void) dlb_fclose(f);
+ }
+ }
+
+ if (complain) {
+ QString message = nh_qsprintf("File not found: %s\n",filename);
+ QMessageBox::warning(NULL, "File Error", message, QMessageBox::Ignore);
+ }
+}
+
+void NetHackQtBind::qt_start_menu(winid wid, unsigned long mbehavior UNUSED)
+{
+ NetHackQtWindow* window=id_to_window[(int)wid];
+ window->StartMenu(wid == WIN_INVEN);
+}
+
+void NetHackQtBind::qt_add_menu(winid wid, const glyph_info *glyphinfo,
+ const ANY_P * identifier, char ch, char gch, int attr, int clr,
+ const char *str, unsigned itemflags)
+{
+ NetHackQtWindow* window=id_to_window[(int)wid];
+ window->AddMenu(glyphinfo->glyph, identifier, ch, gch, attr, clr,
+ QString::fromLatin1(str),
+ itemflags);
+}
+
+void NetHackQtBind::qt_end_menu(winid wid, const char *prompt)
+{
+ NetHackQtWindow* window=id_to_window[(int)wid];
+ window->EndMenu(prompt);
+}
+
+int NetHackQtBind::qt_select_menu(winid wid, int how, MENU_ITEM_P **menu_list)
+{
+ NetHackQtWindow* window=id_to_window[(int)wid];
+ return window->SelectMenu(how,menu_list);
+}
+
+void NetHackQtBind::qt_update_inventory(int arg UNUSED)
+{
+ if (main)
+ main->updateInventory(); // update the paper doll inventory subset
+
+ /* doesn't work yet
+ if (program_state.something_worth_saving && iflags.perm_invent)
+ repopulate_perminvent();
+ */
+}
+
+win_request_info *NetHackQtBind::qt_ctrl_nhwindow(
+ winid wid,
+ int request,
+ win_request_info *wri)
+{
+ NetHackQtWindow* window UNUSED =id_to_window[(int)wid];
+
+ if (!wri)
+ return (win_request_info *) 0;
+
+ switch(request) {
+ case set_mode:
+ case request_settings:
+ break;
+ case set_menu_promptstyle:
+ /* = wri->fromcore.menu_promptstyle; */
+ break;
+ default:
+ break;
+ }
+ return wri;
+}
+
+void NetHackQtBind::qt_mark_synch()
+{
+}
+
+void NetHackQtBind::qt_wait_synch()
+{
+}
+
+void NetHackQtBind::qt_cliparound(int x, int y)
+{
+ // XXXNH - winid should be a parameter!
+ qt_cliparound_window(WIN_MAP,x,y);
+}
+
+void NetHackQtBind::qt_cliparound_window(winid wid, int x, int y)
+{
+ NetHackQtWindow* window=id_to_window[(int)wid];
+ window->ClipAround(x,y);
+}
+
+void NetHackQtBind::qt_print_glyph(
+ winid wid, coordxy x, coordxy y,
+ const glyph_info *glyphinfo,
+ const glyph_info *bkglyphinfo)
+{
+ /* TODO: bkglyph */
+ NetHackQtWindow *window = id_to_window[(int) wid];
+ window->PrintGlyph(x, y, glyphinfo, bkglyphinfo);
+}
+
+#if 0
+void NetHackQtBind::qt_print_glyph_compose(
+ winid wid, coordxy x, coordxy y, int glyph1, int glyph2)
+{
+ NetHackQtWindow *window = id_to_window[(int) wid];
+ window->PrintGlyphCompose(x, y, glyph1, glyph2);
+}
+#endif /*0*/
+
+//
+// FIXME: sending output to stdout can mean that the player never sees it.
+//
+void NetHackQtBind::qt_raw_print(const char *str)
+{
+ puts(str);
+}
+
+void NetHackQtBind::qt_raw_print_bold(const char *str)
+{
+ qt_raw_print(str);
+}
+
+const QPen NetHackQtBind::nhcolor_to_pen(uint32_t c)
+{
+ if (!pen) {
+ pen = new QPen[17];
+
+ pen[ 0] = QColor(64, 64, 64); // black
+ pen[ 1] = QColor(Qt::red);
+ pen[ 2] = QColor(0, 191, 0); // green
+ pen[ 3] = QColor(127, 127, 0); // brownish
+ pen[ 4] = QColor(Qt::blue);
+ pen[ 5] = QColor(Qt::magenta);
+ pen[ 6] = QColor(Qt::cyan);
+ pen[ 7] = QColor(Qt::gray);
+ // on tty, "light" variations are "bright" instead; here they're paler
+ pen[ 8] = QColor(Qt::white); // no color
+ pen[ 9] = QColor(255, 127, 0); // orange
+ pen[10] = QColor(127, 255, 127); // light green
+ pen[11] = QColor(Qt::yellow);
+ pen[12] = QColor(127, 127, 255); // light blue
+ pen[13] = QColor(255, 127, 255); // light magenta
+ pen[14] = QColor(127, 255, 255); // light cyan
+ pen[15] = QColor(Qt::white);
+ // ? out of range for 0..15
+ pen[16] = QColor(Qt::black);
+ }
+
+#ifdef ENHANCED_SYMBOLS
+ if (c & 0x80000000) {
+ return QColor(
+ (c >> 16) & 0xFF,
+ (c >> 8) & 0xFF,
+ (c >> 0) & 0xFF);
+ } else
+#endif
+ {
+ return pen[c];
+ }
+}
+
+int NetHackQtBind::qt_nhgetch()
+{
+ if (main)
+ main->fadeHighlighting(true);
+
+ // Process events until a key arrives.
+ //
+ while (keybuffer.Empty()) {
+ int exc = qApp->exec();
+ /*
+ * On OSX (possibly elsewhere), this prevents an infinite
+ * loop repeatedly issuing the complaint:
+QCoreApplication::exec: The event loop is already running
+ * to stderr if you synchronously start nethack from a terminal
+ * then switch focus back to that terminal and type ^C.
+ * SIGINT -> done1() -> done2() -> yn_function("Really quit?")
+ * in the core asks for another keystroke.
+ *
+ * However, it still issues one such complaint, and whatever
+ * prompt wanted a response ("Really quit?") is shown in the
+ * message window but is auto-answered with ESC.
+ */
+ if (exc == -1)
+ keybuffer.Put('\033');
+ }
+
+ // after getting a key rather than before
+ if (main)
+ main->fadeHighlighting(false);
+
+ return keybuffer.GetAscii();
+}
+
+#ifdef IDLECHECKPOINT
+void
+NetHackQtBind::free_qt_input_timer(void)
+{
+ if (qt_input_timer) {
+ if (qt_input_timer->isActive())
+ qt_input_timer->stop();
+ if (qt_input_timer)
+ delete qt_input_timer;
+ qt_input_timer = 0;
+ }
+}
+
+static void
+qt_timer_fire(void)
+{
+ if (iflags.idlecheckpoint) {
+ /* no input for 30 seconds, so let's take
+ * advantage and do a game checkpoint,
+ * then resume the wait.
+ */
+#if defined(INSURANCE)
+ save_currentstate();
+#endif /* INSURANCE */
+ }
+ if (qt_input_timer->isActive())
+ qt_input_timer->stop();
+}
+
+//void
+//cancel_qt_input_timer(void)
+//{
+//
+//}
+#endif /* IDLECHECKPOINT */
+
+int NetHackQtBind::qt_nh_poskey(coordxy *x, coordxy *y, int *mod)
+{
+ if (main)
+ main->fadeHighlighting(true);
+
+#ifdef IDLECHECKPOINT
+ if (iflags.idlecheckpoint) {
+ if (!qt_input_timer) {
+ qt_input_timer = new QTimer();
+ qt_input_timer->setSingleShot(true);
+ connect(qt_input_timer, &QTimer::timeout, &qt_timer_fire);
+ }
+ if (!qt_input_timer->isActive())
+ qt_input_timer->start(IDLECHECKPOINT_WAIT_TIME * 1000);
+ }
+#endif
+ // Process events until a key or map-click arrives.
+ //
+ while (keybuffer.Empty() && clickbuffer.Empty()) {
+ int exc = qApp->exec();
+ // [see comment above in qt_nhgetch()]
+ if (exc == -1)
+ keybuffer.Put('\033');
+ }
+
+ // after getting a key or click rather than before
+ if (main)
+ main->fadeHighlighting(false);
+
+ if (!keybuffer.Empty()) {
+#ifdef IDLECHECKPOINT
+ if (qt_input_timer->isActive())
+ qt_input_timer->stop();
+#endif
+ return keybuffer.GetAscii();
+ } else {
+ *x=clickbuffer.NextX();
+ *y=clickbuffer.NextY();
+ *mod=clickbuffer.NextMod();
+ clickbuffer.Get();
+#ifdef IDLECHECKPOINT
+ if (qt_input_timer->isActive())
+ qt_input_timer->stop();
+#endif
+ return 0;
+ }
+}
+
+void NetHackQtBind::qt_nhbell()
+{
+ if (!::flags.silent)
+ QApplication::beep();
+}
+
+int NetHackQtBind::qt_doprev_message()
+{
+ // Don't need it - uses scrollbar
+ // XXX but could make this a shortcut
+ return 0;
+}
+
+// display "--More--" as a prompt and wait for a response from the user
+//
+// Used by qt_display_nhwindow(WIN_MESSAGE, TRUE) where second argument
+// True requests blocking. We need it to support MSGTYPE=stop but the
+// core also uses that in various other situations.
+char NetHackQtBind::qt_more()
+{
+ char ch = '\033';
+
+ // without this gameover hack, quitting via menu or window close
+ // button ends up provoking a complaint from qt_nhgetch() [see the
+ // ^C comment in that routine] when the core triggers --More-- via
+ // done2() -> really_done() -> display_nhwindow(WIN_MESSAGE, TRUE)
+ // (get rid of this if the exec() loop issue gets properly fixed)
+ if (::program_state.gameover)
+ return ch; // bypass --More-- and just continue with program exit
+
+ NetHackQtMessageWindow *mesgwin = main ? main->GetMessageWindow() : NULL;
+
+ // kill any typeahead; for '!popup_dialog' this forces qt_nhgetch()
+ keybuffer.Drain();
+
+ if (mesgwin && !::iflags.wc_popup_dialog && WIN_MESSAGE != WIN_ERR) {
+
+ mesgwin->AddToStr("--More--");
+ bool retry = false;
+ int complain = 0;
+ do {
+ ch = NetHackQtBind::qt_nhgetch();
+ if (::program_state.savefile_completed) {
+ retry = false;
+ break;
+ }
+ switch (ch) {
+ case '\0': // hypothetical
+ ch = '\033';
+ FALLTHROUGH;
+ /*FALLTHRU*/
+ case ' ':
+ case '\n':
+ case '\r':
+ case '\033':
+ retry = false;
+ break;
+ default:
+ if (++complain > 1)
+ NetHackQtBind::qt_nhbell();
+ // typing anything caused the most recent message line
+ // (which happens to our prompt) from having highlighting
+ // be removed; put that back
+ if (mesgwin)
+ mesgwin->RehighlightPrompt();
+ retry = true;
+ break;
+ }
+ } while (retry);
+ // unhighlight the line with the prompt; does not erase the window
+ NetHackQtBind::qt_clear_nhwindow(WIN_MESSAGE);
+
+ } else {
+ // use a popup dialog box; unlike yn_function(), we don't show
+ // the prompt+response in the message window
+ NetHackQtYnDialog dialog(main, "--More--", " \033\n\r", ' ');
+ ch = dialog.Exec();
+ if (ch == '\0') {
+ ch = '\033';
+ }
+ // discard any input that YnDialog() might have left pending
+ keybuffer.Drain();
+ }
+
+ return ch;
+}
+
+char NetHackQtBind::qt_yn_function(const char *question_,
+ const char *choices, char def)
+{
+ QString question(QString::fromLatin1(question_));
+ QString message;
+ char yn_esc_map='\033';
+ int result = -1;
+
+ if (choices) {
+ QString choicebuf;
+ for (const char *p = choices; *p; ++p) {
+ if (*p == '\033') // and anything beyond is hidden
+ break;
+ choicebuf += visctrl(*p);
+ }
+ choicebuf.truncate(QBUFSZ - 1); // no effect if already shorter
+ message = QString("%1 [%2] ").arg(question, choicebuf);
+ if (def)
+ message += QString("(%1) ").arg(QChar(def));
+ // escape maps to 'q' or 'n' or default, in that order
+ yn_esc_map = strchr(choices, 'q') ? 'q'
+ : strchr(choices, 'n') ? 'n'
+ : def;
+ } else {
+ message = question;
+ }
+
+ if (
+ /*
+ * The 'Settings' dialog doesn't present prompting-in-message-window
+ * as a candidate for customization but core supports 'popup_dialog'
+ * option so let player use that instead.
+ */
+#if 0
+ qt_settings->ynInMessages()
+#else
+ !::iflags.wc_popup_dialog
+#endif
+ && WIN_MESSAGE != WIN_ERR) {
+ // Similar to X11 windowport `slow' feature.
+
+ char cbuf[20];
+ cbuf[0] = '\0';
+
+ // add the prompt to the message window
+ NetHackQtBind::qt_putstr(WIN_MESSAGE, ATR_BOLD, message);
+
+ while (result < 0) {
+ cbuf[0] = '\0';
+ char ch=NetHackQtBind::qt_nhgetch();
+ if (ch=='\033') {
+ result=yn_esc_map;
+ Strcpy(cbuf, "ESC");
+ } else if (choices && !strchr(choices,ch)) {
+ if (def && (ch==' ' || ch=='\r' || ch=='\n')) {
+ result=def;
+ Strcpy(cbuf, visctrl(def));
+ } else {
+ NetHackQtBind::qt_nhbell();
+ // typing anything caused the most recent message line
+ // (which happens to our prompt) from having highlighting
+ // be removed; put that back
+ NetHackQtMessageWindow
+ *mesgwin = main ? main->GetMessageWindow() : NULL;
+ if (mesgwin)
+ mesgwin->RehighlightPrompt();
+ // and try again...
+ }
+ } else {
+ result=ch;
+ Strcpy(cbuf, visctrl(ch));
+ }
+ }
+
+ // update the prompt message line to include the response
+ if (cbuf[0]) {
+ if (!strcmp(cbuf, " "))
+ Strcpy(cbuf, "SPC");
+
+ NetHackQtMessageWindow *mesgwin = main->GetMessageWindow();
+ if (mesgwin)
+ mesgwin->AddToStr(cbuf);
+ }
+
+ } else {
+ // use a popup dialog box
+ NetHackQtYnDialog dialog(main, question, choices, def);
+ char ret = dialog.Exec();
+ if (ret == 0) {
+ ret = '\033';
+ }
+ // discard any input that YnDialog() might have left pending
+ keybuffer.Drain();
+
+ // combine the prompt and result
+ char cbuf[40];
+ Strcpy(cbuf, (ret == '\033') ? "ESC"
+ : (ret == ' ') ? "SPC"
+ : visctrl(ret));
+ if (ret == '#' && choices && !strncmp(choices, "yn#", (size_t) 3))
+ Sprintf(eos(cbuf), " %ld", ::yn_number);
+ message += QString(" %1").arg(cbuf);
+
+ // add the prompt with appended response to the message window
+ if (WIN_MESSAGE != WIN_ERR)
+ NetHackQtBind::qt_putstr(WIN_MESSAGE, ATR_BOLD, message);
+
+ result = ret;
+ }
+
+ // unhighlight the prompt; does not erase the multi-line message window
+ if (WIN_MESSAGE != WIN_ERR)
+ NetHackQtBind::qt_clear_nhwindow(WIN_MESSAGE);
+
+ return (char) result;
+}
+
+void NetHackQtBind::qt_getlin(const char *prompt, char *line)
+{
+ NetHackQtStringRequestor requestor(mainWidget(),prompt);
+ if (!requestor.Get(line, BUFSZ, 40)) {
+ Strcpy(line, "\033");
+ // discard any input that Get() might have left pending
+ keybuffer.Drain();
+ }
+
+ // add the prompt with appended response to the message window
+ char buf[BUFSZ + 20], *q; /* +20: plenty of extra room for visctrl() */
+ copynchars(buf, prompt, BUFSZ - 1);
+ q = eos(buf);
+ *q++ = ' '; /* guaranteed to fit; temporary lack of terminator is ok */
+
+ if (line[0] == '\033') {
+ Strcpy(q, "ESC");
+ } else if (line[0] == ' ' && !line[1]) {
+ Strcpy(q, "SPC");
+ } else {
+ /* buf[] has more than enough room to hold one extra visctrl()
+ in case q is at the last viable slot and *p yields "M-^c" */
+ for (char *p = line; *p && q < &buf[BUFSZ - 1]; ++p, q = eos(q))
+ Strcpy(q, visctrl(*p));
+ }
+ if (q > &buf[BUFSZ - 1])
+ q = &buf[BUFSZ - 1];
+ *q = '\0';
+
+ NetHackQtBind::qt_putstr(WIN_MESSAGE, ATR_BOLD, buf);
+ // unhighlight the prompt; does not erase the multi-line message window
+ NetHackQtBind::qt_clear_nhwindow(WIN_MESSAGE);
+}
+
+// User has typed '#' to begin entering an extended command; core calls us.
+int NetHackQtBind::qt_get_ext_cmd()
+{
+ NetHackQtExtCmdRequestor *xcmd;
+ int result;
+ do {
+ xcmd = new NetHackQtExtCmdRequestor(mainWidget());
+ result = xcmd->get();
+ delete xcmd;
+ } while (result == xcmdNoMatch);
+ // refresh message window after extended command dialog is dismissed
+ NetHackQtBind::qt_clear_nhwindow(WIN_MESSAGE);
+ return result;
+}
+
+void NetHackQtBind::qt_number_pad(int)
+{
+ // Ignore.
+}
+
+void NetHackQtBind::qt_delay_output()
+{
+#ifdef TIMED_DELAY
+ NetHackQtDelay delay(50);
+ delay.wait();
+#endif
+}
+
+#ifdef CHANGE_COLOR
+void NetHackQtBind::qt_change_color(int color, long rgb, int reverse UNUSED)
+{
+ int r, g, b;
+
+ r = (rgb >> 16) & 0xFF;
+ g = (rgb >> 8) & 0xFF;
+ b = rgb & 0xFF;
+ if (!pen) {
+ (void) NetHackQtBind::nhcolor_to_pen(0); /* init pen[] */
+ }
+ pen[color % 16] = QColor(r, g, b);
+}
+
+char *
+NetHackQtBind::qt_get_color_string(void)
+{
+ return (char *) 0;
+}
+
+#endif
+
+void NetHackQtBind::qt_outrip(winid wid, int how, time_t when)
+{
+ NetHackQtWindow* window=id_to_window[(int)wid];
+ window->UseRIP(how, when);
+}
+
+void NetHackQtBind::qt_preference_update(const char *optname)
+{
+#ifdef DYNAMIC_STATUSLINES // defined in qt_main.h
+ if (!strcmp(optname, "statuslines")) {
+ // delete and recreate status window
+ // to toggle statuslines from 2 to 3 or vice versa
+ id_to_window[WIN_STATUS] = main->redoStatus();
+ }
+#else
+ nhUse(optname);
+#endif
+}
+
+char *NetHackQtBind::qt_getmsghistory(boolean init)
+{
+ NetHackQtMessageWindow *window = main->GetMessageWindow();
+ if (window)
+ return (char *) window->GetStr((bool) init);
+ return NULL;
+}
+
+void NetHackQtBind::qt_putmsghistory(const char *msg, boolean is_restoring)
+{
+ NetHackQtMessageWindow *window = main->GetMessageWindow();
+ if (!window)
+ return;
+
+ if (is_restoring && !msgs_initd) {
+ /* we're restoring history from the previous session, but new
+ messages have already been issued this session */
+ int i = 0;
+ const char *str;
+
+ while ((str = window->GetStr((bool) (i == 0))) != 0) {
+ msgs_strings->append(str);
+ i++;
+ }
+ msgs_initd = true;
+ msgs_saved = (i > 0);
+ window->ClearMessages();
+ }
+
+ if (msg) {
+ //raw_printf("msg='%s'", msg);
+ window->PutStr(ATR_NONE, QString::fromLatin1(msg));
+#ifdef DUMPLOG_CORE
+ dumplogmsg(msg);
+#endif
+ } else if (msgs_saved) {
+ /* restore strings */
+ for (int i = 0; i < msgs_strings->size(); ++i) {
+ const QString &nxtmsg = msgs_strings->at(i);
+ window->PutStr(ATR_NONE, nxtmsg);
+#ifdef DUMPLOG_CORE
+ dumplogmsg(nxtmsg.toLatin1().constData());
+#endif
+ }
+ delete msgs_strings;
+ msgs_initd = false;
+ }
+}
+
+// event loop callback
+bool NetHackQtBind::notify(QObject *receiver, QEvent *event)
+{
+ // Ignore Alt-key navigation to menubar, it's annoying when you
+ // use Alt-Direction to move around.
+ if (main && receiver == main && event->type() == QEvent::KeyRelease
+ && ((QKeyEvent *) event)->key() == Qt::Key_Alt)
+ return true;
+
+ bool result = QApplication::notify(receiver, event);
+ int evtyp = event->type();
+
+ if (evtyp == QEvent::KeyPress) {
+ QKeyEvent *key_event = (QKeyEvent *) event;
+
+ if (!key_event->isAccepted()) {
+ Qt::KeyboardModifiers mod = key_event->modifiers();
+ const int k = key_event->key();
+ for (int i = 0; key_macro[i].key; i++) {
+ if (key_macro[i].key == k
+ && ((key_macro[i].state & mod) == key_macro[i].state)) {
+ // matched macro; put its expansion into the input buffer
+ keybuffer.Put(!::iflags.num_pad ? key_macro[i].macro
+ : key_macro[i].numpad_macro);
+ key_event->accept();
+ qApp->exit();
+ return true;
+ }
+ }
+ QString key = key_event->text();
+ QChar ch = !key.isEmpty() ? key.at(0) : QChar(0);
+ if (ch > QChar(128))
+ ch = QChar(0);
+ // on OSX, ascii control codes are not sent, force them
+ if (ch == 0 && (mod & Qt::ControlModifier) != 0) {
+ if (k >= Qt::Key_A && k <= Qt::Key_Underscore)
+ ch = (QChar) (k - (Qt::Key_A - 1));
+ }
+ //raw_printf("notify()=%d \"%s\"", k, visctrl(ch.cell()));
+ // if we have a valid character, queue it up
+ if (ch != 0) {
+ bool alt = ((mod & Qt::AltModifier) != 0
+ || (k >= Qt::Key_0 && k <= Qt::Key_9
+ && (mod & Qt::ControlModifier) != 0));
+ keybuffer.Put(k, ch.cell() + (alt ? 128 : 0), (uint) mod);
+ key_event->accept();
+ qApp->exit();
+ result = true;
+ }
+
+#if 0 /* this was a failed attempt to prevent qt_more() from looping
+ * after command+q (on OSX) is used to bring up the quit dialog;
+ * now qt_more() uses an early return if program_state.gameover
+ * is set */
+ } else if (evtyp == QEvent::FocusOut
+ || evtyp == QEvent::ShortcutOverride
+ || evtyp == QEvent::PlatformSurface) {
+ // leave qt_nhgetch()'s event loop if focus switches somewhere else
+ qApp->exit();
+ result = false;
+#endif
+ }
+ }
+ return result;
+}
+
+NetHackQtBind* NetHackQtBind::instance=0;
+NetHackQtKeyBuffer NetHackQtBind::keybuffer;
+NetHackQtClickBuffer NetHackQtBind::clickbuffer;
+NetHackQtMainWindow* NetHackQtBind::main=0;
+QFrame* NetHackQtBind::splash=0;
+QStringList *NetHackQtBind::msgs_strings;
+boolean NetHackQtBind::msgs_saved = false;
+boolean NetHackQtBind::msgs_initd = false;
+#if 0
+static void Qt_positionbar(char *) {}
+#endif
+
+#if defined(SND_LIB_QTSOUND) && !defined(QT_NO_SOUND)
+void NetHackQtBind::qtsound_init_nhsound(void)
+{
+}
+
+void NetHackQtBind::qtsound_exit_nhsound(const char *reason UNUSED)
+{
+}
+
+void NetHackQtBind::qtsound_achievement(schar ach1 UNUSED, schar ach2 UNUSED, int32_t repeat UNUSED)
+{
+}
+
+void NetHackQtBind::qtsound_soundeffect(char *desc UNUSED, int32_t seid UNUSED, int32_t volume UNUSED)
+{
+}
+
+void NetHackQtBind::qtsound_hero_playnotes(int32_t instrument UNUSED, const char *str UNUSED, int32_t volume UNUSED)
+{
+}
+void NetHackQtBind::qtsound_ambience(int32_t ambienceid UNUSED, int32_t ambience_action UNUSED, int32_t proximity UNUSED)
+{
+}
+void NetHackQtBind::qtsound_verbal(char *text UNUSED, int32_t gender UNUSED, int32_t tone UNUSED, int32_t vol UNUSED, int32_t moreinfo UNUSED)
+{
+}
+
+QSoundEffect *effect = NULL;
+
+void NetHackQtBind::qtsound_play_usersound(char *filename, int32_t volume, int32_t idx UNUSED)
+{
+ if (!effect)
+ effect = new QSoundEffect(nethack_qt_::NetHackQtBind::mainWidget());
+ if (effect) {
+ effect->setLoopCount(1);
+ effect->setVolume((1.00f * volume) / 100.0f);
+ effect->setSource(QUrl::fromLocalFile(filename));
+ effect->play();
+ }
+}
+#endif
+
+} // namespace nethack_qt_
+
+struct window_procs Qt_procs = {
+ WPID(Qt),
+ (WC_COLOR | WC_HILITE_PET
+ | WC_ASCII_MAP | WC_TILED_MAP
+ | WC_FONT_MAP | WC_TILE_FILE | WC_TILE_WIDTH | WC_TILE_HEIGHT
+ | WC_POPUP_DIALOG | WC_PLAYER_SELECTION | WC_SPLASH_SCREEN),
+ (WC2_HITPOINTBAR
+#ifdef SELECTSAVED
+ | WC2_SELECTSAVED
+#endif
+#ifdef ENHANCED_SYMBOLS
+ | WC2_U_UTF8STR
+#endif
+ | WC2_EXTRACOLORS
+ | WC2_STATUSLINES),
+ {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, /* color availability */
+ nethack_qt_::NetHackQtBind::qt_init_nhwindows,
+ nethack_qt_::NetHackQtBind::qt_player_selection,
+ nethack_qt_::NetHackQtBind::qt_askname,
+ nethack_qt_::NetHackQtBind::qt_get_nh_event,
+ nethack_qt_::NetHackQtBind::qt_exit_nhwindows,
+ nethack_qt_::NetHackQtBind::qt_suspend_nhwindows,
+ nethack_qt_::NetHackQtBind::qt_resume_nhwindows,
+ nethack_qt_::NetHackQtBind::qt_create_nhwindow,
+ nethack_qt_::NetHackQtBind::qt_clear_nhwindow,
+ nethack_qt_::NetHackQtBind::qt_display_nhwindow,
+ nethack_qt_::NetHackQtBind::qt_destroy_nhwindow,
+ nethack_qt_::NetHackQtBind::qt_curs,
+ nethack_qt_::NetHackQtBind::qt_putstr,
+ genl_putmixed,
+ nethack_qt_::NetHackQtBind::qt_display_file,
+ nethack_qt_::NetHackQtBind::qt_start_menu,
+ nethack_qt_::NetHackQtBind::qt_add_menu,
+ nethack_qt_::NetHackQtBind::qt_end_menu,
+ nethack_qt_::NetHackQtBind::qt_select_menu,
+ genl_message_menu, /* no need for Qt-specific handling */
+ nethack_qt_::NetHackQtBind::qt_mark_synch,
+ nethack_qt_::NetHackQtBind::qt_wait_synch,
+#ifdef CLIPPING
+ nethack_qt_::NetHackQtBind::qt_cliparound,
+#endif
+#ifdef POSITIONBAR
+ nethack_qt_::Qt_positionbar,
+#endif
+ nethack_qt_::NetHackQtBind::qt_print_glyph,
+ //NetHackQtBind::qt_print_glyph_compose,
+ nethack_qt_::NetHackQtBind::qt_raw_print,
+ nethack_qt_::NetHackQtBind::qt_raw_print_bold,
+ nethack_qt_::NetHackQtBind::qt_nhgetch,
+ nethack_qt_::NetHackQtBind::qt_nh_poskey,
+ nethack_qt_::NetHackQtBind::qt_nhbell,
+ nethack_qt_::NetHackQtBind::qt_doprev_message,
+ nethack_qt_::NetHackQtBind::qt_yn_function,
+ nethack_qt_::NetHackQtBind::qt_getlin,
+ nethack_qt_::NetHackQtBind::qt_get_ext_cmd,
+ nethack_qt_::NetHackQtBind::qt_number_pad,
+ nethack_qt_::NetHackQtBind::qt_delay_output,
+#ifdef CHANGE_COLOR
+ nethack_qt_::NetHackQtBind::qt_change_color,
+#ifdef MAC /* old OS 9, not OSX */
+ donull,
+ donull,
+#endif
+ nethack_qt_::NetHackQtBind::qt_get_color_string,
+#endif
+#ifdef GRAPHIC_TOMBSTONE
+ nethack_qt_::NetHackQtBind::qt_outrip,
+#else
+ genl_outrip,
+#endif
+ nethack_qt_::NetHackQtBind::qt_preference_update,
+ nethack_qt_::NetHackQtBind::qt_getmsghistory,
+ nethack_qt_::NetHackQtBind::qt_putmsghistory,
+ genl_status_init,
+ genl_status_finish, genl_status_enablefield,
+#ifdef STATUS_HILITES
+ genl_status_update,
+#else
+ genl_status_update,
+#endif
+ genl_can_suspend_yes,
+ nethack_qt_::NetHackQtBind::qt_update_inventory,
+ nethack_qt_::NetHackQtBind::qt_ctrl_nhwindow,
+};
+
+#if defined(SND_LIB_QTSOUND) && !defined(QT_NO_SOUND)
+struct sound_procs qtsound_procs = {
+ SOUNDID(qtsound),
+ SOUND_TRIGGER_USERSOUNDS,
+ nethack_qt_::NetHackQtBind::qtsound_init_nhsound,
+ nethack_qt_::NetHackQtBind::qtsound_exit_nhsound,
+ nethack_qt_::NetHackQtBind::qtsound_achievement,
+ nethack_qt_::NetHackQtBind::qtsound_soundeffect,
+ nethack_qt_::NetHackQtBind::qtsound_hero_playnotes,
+ nethack_qt_::NetHackQtBind::qtsound_play_usersound,
+ nethack_qt_::NetHackQtBind::qtsound_ambience,
+ nethack_qt_::NetHackQtBind::qtsound_verbal,
+};
+#endif /* SND_LIB_QTSOUND and !QT_NO_SOUND */
+
+//qt_bind.cpp
diff --git a/win/Qt/qt_bind.h b/win/Qt/qt_bind.h
new file mode 100644
index 000000000..17dad758c
--- /dev/null
+++ b/win/Qt/qt_bind.h
@@ -0,0 +1,123 @@
+// Copyright (c) Warwick Allison, 1999.
+// Qt4 conversion copyright (c) Ray Chason, 2012-2014.
+// NetHack may be freely redistributed. See license for details.
+
+// qt_bind.h -- bindings between the Qt 4 interface and the main code
+
+#ifndef QT4BIND_H
+#define QT4BIND_H
+
+#include "qt_main.h"
+
+namespace nethack_qt_ {
+
+class NetHackQtClickBuffer;
+
+#ifdef KDE
+#define NetHackQtBindBase KApplication
+#elif defined(QWS)
+#define NetHackQtBindBase QPEApplication
+#else
+#define NetHackQtBindBase QApplication
+#endif
+
+class NetHackQtBind : NetHackQtBindBase {
+private:
+ // Single-instance preservation...
+ NetHackQtBind(int& argc, char** argv);
+
+ static NetHackQtBind* instance;
+
+ static NetHackQtKeyBuffer keybuffer;
+ static NetHackQtClickBuffer clickbuffer;
+
+ static QFrame* splash;
+ static NetHackQtMainWindow* main;
+
+public:
+ static void qt_Splash();
+
+ /* window interface */
+
+ static void qt_init_nhwindows(int* argc, char** argv);
+ static void qt_player_selection();
+ static void qt_askname();
+ static void qt_get_nh_event();
+ static void qt_exit_nhwindows(const char *);
+ static void qt_suspend_nhwindows(const char *);
+ static void qt_resume_nhwindows();
+ static winid qt_create_nhwindow(int type);
+ static void qt_clear_nhwindow(winid wid);
+ static void qt_display_nhwindow(winid wid, boolean block);
+ static void qt_destroy_nhwindow(winid wid);
+ static void qt_curs(winid wid, int x, int y);
+ static void qt_putstr(winid wid, int attr, const char *text);
+ static void qt_putstr(winid wid, int attr, const std::string& text);
+ static void qt_putstr(winid wid, int attr, const QString& text);
+ static void qt_display_file(const char *filename, boolean must_exist);
+ static void qt_start_menu(winid wid, unsigned long mbehavior);
+ static void qt_add_menu(winid wid, const glyph_info *glyphinfo,
+ const ANY_P * identifier, char ch, char gch, int attr, int clr,
+ const char *str, unsigned int itemflags);
+ static void qt_end_menu(winid wid, const char *prompt);
+ static int qt_select_menu(winid wid, int how, MENU_ITEM_P **menu_list);
+ static void qt_mark_synch();
+ static void qt_wait_synch();
+
+ static void qt_cliparound(int x, int y);
+ static void qt_cliparound_window(winid wid, int x, int y);
+ static void qt_print_glyph(winid wid, coordxy x, coordxy y,
+ const glyph_info *glyphingo,
+ const glyph_info *bkglyphinfo);
+ static void qt_raw_print(const char *str);
+ static void qt_raw_print_bold(const char *str);
+ static const QPen nhcolor_to_pen(uint32_t c);
+ static void qt_change_color(int color, long rgb, int reverse UNUSED);
+ static char *qt_get_color_string(void);
+ static int qt_nhgetch();
+ static int qt_nh_poskey(coordxy *x, coordxy *y, int *mod);
+ static void qt_nhbell();
+ static int qt_doprev_message();
+ static char qt_more();
+ static char qt_yn_function(const char *question,
+ const char *choices, char def);
+ static void qt_getlin(const char *prompt, char *line);
+ static int qt_get_ext_cmd();
+ static void qt_number_pad(int);
+ static void qt_delay_output();
+
+ static void qt_preference_update(const char *optname);
+ static char *qt_getmsghistory(boolean init);
+ static void qt_putmsghistory(const char *msg, boolean is_restoring);
+
+ static void qt_outrip(winid wid, int how, time_t when);
+ static int qt_kbhit();
+ static void qt_update_inventory(int);
+ static win_request_info *qt_ctrl_nhwindow(winid, int, win_request_info *);
+ static QWidget *mainWidget() { return main; }
+#if defined(SND_LIB_QTSOUND) && !defined(QT_NO_SOUND)
+ /* sound interface */
+ static void qtsound_init_nhsound(void);
+ static void qtsound_exit_nhsound(const char *);
+ static void qtsound_achievement(schar, schar, int32_t);
+ static void qtsound_soundeffect(char *, int32_t, int32_t);
+ static void qtsound_hero_playnotes(int32_t instrument, const char *str, int32_t volume);
+ static void qtsound_play_usersound(char *, int32_t, int32_t);
+ static void qtsound_ambience(int32_t, int32_t, int32_t);
+ static void qtsound_verbal(char *text, int32_t gender, int32_t tone, int32_t vol, int32_t moreinfo);
+#endif
+#ifdef IDLECHECKPOINT
+ static void free_qt_input_timer(void);
+#endif
+
+private:
+ virtual bool notify(QObject *receiver, QEvent *event);
+
+ static QStringList *msgs_strings;
+ static boolean msgs_saved;
+ static boolean msgs_initd;
+};
+
+} // namespace nethack_qt_
+
+#endif
diff --git a/win/Qt4/qt4click.cpp b/win/Qt/qt_click.cpp
similarity index 77%
rename from win/Qt4/qt4click.cpp
rename to win/Qt/qt_click.cpp
index 78177a14f..d8f5030b7 100644
--- a/win/Qt4/qt4click.cpp
+++ b/win/Qt/qt_click.cpp
@@ -2,23 +2,18 @@
// Qt4 conversion copyright (c) Ray Chason, 2012-2014.
// NetHack may be freely redistributed. See license for details.
-// qt4click.cpp -- a mouse click buffer
+// qt_click.cpp -- a mouse click buffer
+extern "C" {
#include "hack.h"
-#undef Invisible
-#undef Warning
-#undef index
-#undef msleep
-#undef rindex
-#undef wizard
-#undef yn
-#undef min
-#undef max
+}
+#include "qt_pre.h"
#include
-#include "qt4click.h"
+#include "qt_post.h"
+#include "qt_click.h"
-namespace nethack_qt4 {
+namespace nethack_qt_ {
NetHackQtClickBuffer::NetHackQtClickBuffer() :
in(0), out(0)
@@ -45,4 +40,4 @@ void NetHackQtClickBuffer::Get()
out=(out+1)%maxclick;
}
-} // namespace nethack_qt4
+} // namespace nethack_qt_
diff --git a/win/Qt4/qt4click.h b/win/Qt/qt_click.h
similarity index 85%
rename from win/Qt4/qt4click.h
rename to win/Qt/qt_click.h
index 50fd8b1cc..325f455fd 100644
--- a/win/Qt4/qt4click.h
+++ b/win/Qt/qt_click.h
@@ -2,12 +2,12 @@
// Qt4 conversion copyright (c) Ray Chason, 2012-2014.
// NetHack may be freely redistributed. See license for details.
-// qt4click.h -- a mouse click buffer
+// qt_click.h -- a mouse click buffer
#ifndef QT4CLICK_H
#define QT4CLICK_H
-namespace nethack_qt4 {
+namespace nethack_qt_ {
class NetHackQtClickBuffer {
public:
@@ -32,6 +32,6 @@ class NetHackQtClickBuffer {
int in,out;
};
-} // namespace nethack_qt4
+} // namespace nethack_qt_
#endif
diff --git a/win/Qt/qt_clust.cpp b/win/Qt/qt_clust.cpp
index c5063a6a3..d63d2d7de 100644
--- a/win/Qt/qt_clust.cpp
+++ b/win/Qt/qt_clust.cpp
@@ -1,168 +1,169 @@
-/* NetHack 3.6 qt_clust.cpp $NHDT-Date: 1524684507 2018/04/25 19:28:27 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.8 $ */
+/* SCCS Id: @(#)qt_clust.cpp 3.4 1999/11/19 */
/* Copyright (c) Warwick Allison, 1999. */
/* NetHack may be freely redistributed. See license for details. */
#include "qt_clust.h"
-static
-void include(QRect& r, const QRect& rect)
+static void include(QRect& r, const QRect& rect)
{
- if (rect.left()r.right()) {
- r.setRight(rect.right());
- }
- if (rect.top()r.bottom()) {
- r.setBottom(rect.bottom());
- }
+ if (rect.left() < r.left()) {
+ r.setLeft(rect.left());
+ }
+ if (rect.right() > r.right()) {
+ r.setRight(rect.right());
+ }
+ if (rect.top() < r.top()) {
+ r.setTop(rect.top());
+ }
+ if (rect.bottom() > r.bottom()) {
+ r.setBottom(rect.bottom());
+ }
}
/*
-A Clusterizer groups rectangles (QRects) into non-overlapping rectangles
-by a merging heuristic.
-*/
+ * A Clusterizer groups rectangles (QRects) into non-overlapping
+ * rectangles by a merging heuristic.
+ */
Clusterizer::Clusterizer(int maxclusters) :
- cluster(new QRect[maxclusters]),
- count(0),
- max(maxclusters)
-{ }
+ cluster(new QRect[maxclusters]),
+ count(0),
+ max(maxclusters)
+{
+}
Clusterizer::~Clusterizer()
{
- delete [] cluster;
+ delete [] cluster;
}
void Clusterizer::clear()
{
- count=0;
+ count = 0;
}
void Clusterizer::add(int x, int y)
{
- add(QRect(x,y,1,1));
+ add(QRect(x, y, 1, 1));
}
void Clusterizer::add(int x, int y, int w, int h)
{
- add(QRect(x,y,w,h));
+ add(QRect(x, y, w, h));
}
void Clusterizer::add(const QRect& rect)
{
- QRect biggerrect(rect.x()-1,rect.y()-1,rect.width()+2,rect.height()+2);
-
- //assert(rect.width()>0 && rect.height()>0);
-
- int cursor;
-
- for (cursor=0; cursor=0) {
- include(cluster[cheapest],rect);
- return;
- }
-
- if (count < max) {
- cluster[count++]=rect;
- return;
- }
-
- // Do cheapest of:
- // add to closest cluster
- // do cheapest cluster merge, add to new cluster
-
- lowestcost=9999999;
- cheapest=-1;
- for (cursor=0; cursor=0) {
- include(cluster[cheapestmerge1],cluster[cheapestmerge2]);
- cluster[cheapestmerge2]=cluster[count--];
- } else {
- // if (!cheapest) debugRectangles(rect);
- include(cluster[cheapest],rect);
- }
-
- // NB: clusters do not intersect (or intersection will
- // overwrite). This is a result of the above algorithm,
- // given the assumption that (x,y) are ordered topleft
- // to bottomright.
+ QRect biggerrect(rect.x() - 1, rect.y() - 1,
+ rect.width() + 2, rect.height() + 2);
+
+ //assert(rect.width() > 0 && rect.height() > 0);
+
+ int cursor;
+
+ for (cursor=0; cursor < count; cursor++) {
+ if (cluster[cursor].contains(rect)) {
+ // Wholly contained already.
+ return;
+ }
+ }
+
+ int lowestcost = 9999999;
+ int cheapest = -1;
+ for (cursor = 0; cursor < count; cursor++) {
+ if (cluster[cursor].intersects(biggerrect)) {
+ QRect larger=cluster[cursor];
+ include(larger,rect);
+ int cost = larger.width() * larger.height()
+ - cluster[cursor].width() * cluster[cursor].height();
+
+ if (cost < lowestcost) {
+ bool bad = false;
+ for (int c = 0; c < count && !bad; c++) {
+ bad = cluster[c].intersects(larger) && c != cursor;
+ }
+ if (!bad) {
+ cheapest = cursor;
+ lowestcost = cost;
+ }
+ }
+ }
+ }
+ if (cheapest >= 0) {
+ include(cluster[cheapest], rect);
+ return;
+ }
+
+ if (count < max) {
+ cluster[count++] = rect;
+ return;
+ }
+
+ // Do cheapest of:
+ // add to closest cluster
+ // do cheapest cluster merge, add to new cluster
+
+ lowestcost = 9999999;
+ cheapest = -1;
+ for (cursor = 0; cursor < count; cursor++) {
+ QRect larger = cluster[cursor];
+ include(larger, rect);
+ int cost = larger.width() * larger.height()
+ - cluster[cursor].width() * cluster[cursor].height();
+ if (cost < lowestcost) {
+ bool bad = false;
+ for (int c = 0; c < count && !bad; c++) {
+ bad = cluster[c].intersects(larger) && c != cursor;
+ }
+ if (!bad) {
+ cheapest = cursor;
+ lowestcost = cost;
+ }
+ }
+ }
+
+ // XXX could make an heuristic guess as to whether we
+ // XXX need to bother looking for a cheap merge.
+
+ int cheapestmerge1 = -1;
+ int cheapestmerge2 = -1;
+
+ for (int merge1 = 0; merge1 < count; merge1++) {
+ for (int merge2 = 0; merge2 < count; merge2++) {
+ if (merge1 != merge2) {
+ QRect larger = cluster[merge1];
+ include(larger, cluster[merge2]);
+ int cost = larger.width() * larger.height()
+ - cluster[merge1].width() * cluster[merge1].height()
+ - cluster[merge2].width() * cluster[merge2].height();
+ if (cost < lowestcost) {
+ bool bad = false;
+ for (int c = 0; c < count && !bad; c++) {
+ bad = cluster[c].intersects(larger) && c != cursor;
+ }
+ if (!bad) {
+ cheapestmerge1 = merge1;
+ cheapestmerge2 = merge2;
+ lowestcost = cost;
+ }
+ }
+ }
+ }
+ }
+
+ if (cheapestmerge1 >= 0) {
+ include(cluster[cheapestmerge1], cluster[cheapestmerge2]);
+ cluster[cheapestmerge2] = cluster[count--];
+ } else {
+ // if (!cheapest) debugRectangles(rect);
+ include(cluster[cheapest],rect);
+ }
+
+ // NB: clusters do not intersect (or intersection will
+ // overwrite). This is a result of the above algorithm,
+ // given the assumption that (x,y) are ordered topleft
+ // to bottomright.
}
const QRect& Clusterizer::operator[](int i)
{
- return cluster[i];
+ return cluster[i];
}
diff --git a/win/Qt4/qt4clust.h b/win/Qt/qt_clust.h
similarity index 100%
rename from win/Qt4/qt4clust.h
rename to win/Qt/qt_clust.h
diff --git a/win/Qt4/qt4delay.cpp b/win/Qt/qt_delay.cpp
similarity index 63%
rename from win/Qt4/qt4delay.cpp
rename to win/Qt/qt_delay.cpp
index eadf42a94..0fa3003ce 100644
--- a/win/Qt4/qt4delay.cpp
+++ b/win/Qt/qt_delay.cpp
@@ -2,23 +2,18 @@
// Qt4 conversion copyright (c) Ray Chason, 2012-2014.
// NetHack may be freely redistributed. See license for details.
-// qt4delay.cpp -- implement a delay
+// qt_delay.cpp -- implement a delay
+extern "C" {
#include "hack.h"
-#undef Invisible
-#undef Warning
-#undef index
-#undef msleep
-#undef rindex
-#undef wizard
-#undef yn
-#undef min
-#undef max
+}
+#include "qt_pre.h"
#include
-#include "qt4delay.h"
+#include "qt_post.h"
+#include "qt_delay.h"
-namespace nethack_qt4 {
+namespace nethack_qt_ {
// RLC Can we use QTimer::single_shot for this?
NetHackQtDelay::NetHackQtDelay(int ms) :
@@ -32,11 +27,11 @@ void NetHackQtDelay::wait()
m_loop.exec();
}
-void NetHackQtDelay::timerEvent(QTimerEvent* timer)
+void NetHackQtDelay::timerEvent(QTimerEvent* timer UNUSED)
{
m_loop.exit();
killTimer(m_timer);
m_timer = 0;
}
-} // namespace nethack_qt4
+} // namespace nethack_qt_
diff --git a/win/Qt4/qt4delay.h b/win/Qt/qt_delay.h
similarity index 82%
rename from win/Qt4/qt4delay.h
rename to win/Qt/qt_delay.h
index 2e0085edf..8c918856f 100644
--- a/win/Qt4/qt4delay.h
+++ b/win/Qt/qt_delay.h
@@ -2,12 +2,12 @@
// Qt4 conversion copyright (c) Ray Chason, 2012-2014.
// NetHack may be freely redistributed. See license for details.
-// qt4delay.h -- implement a delay
+// qt_delay.h -- implement a delay
#ifndef QT4DELAY_H
#define QT4DELAY_H
-namespace nethack_qt4 {
+namespace nethack_qt_ {
class NetHackQtDelay : QObject {
private:
@@ -21,6 +21,6 @@ class NetHackQtDelay : QObject {
virtual void timerEvent(QTimerEvent* timer);
};
-} // namespace nethack_qt4
+} // namespace nethack_qt_
#endif
diff --git a/win/Qt/qt_glyph.cpp b/win/Qt/qt_glyph.cpp
new file mode 100644
index 000000000..9aa739fce
--- /dev/null
+++ b/win/Qt/qt_glyph.cpp
@@ -0,0 +1,278 @@
+// Copyright (c) Warwick Allison, 1999.
+// Qt4 conversion copyright (c) Ray Chason, 2012-2014.
+// NetHack may be freely redistributed. See license for details.
+
+// qt_glyph.cpp -- class to manage the glyphs in a tile set
+
+extern "C" {
+#include "hack.h"
+#include "tile2x11.h" /* x11tiles is potential fallback for nhtiles.bmp */
+}
+
+#include "qt_pre.h"
+#include
+#if QT_VERSION >= 0x050000
+#include
+#endif
+#include "qt_post.h"
+#include "qt_glyph.h"
+#include "qt_bind.h"
+#include "qt_set.h"
+#include "qt_inv.h"
+#include "qt_map.h"
+#include "qt_str.h"
+
+extern short glyph2tile[]; // from tile.c
+
+namespace nethack_qt_ {
+
+static int tilefile_tile_W=16;
+static int tilefile_tile_H=16;
+
+// Debian uses a separate PIXMAPDIR
+#ifndef PIXMAPDIR
+# ifdef HACKDIR
+# define PIXMAPDIR HACKDIR
+# else
+# define PIXMAPDIR "."
+# endif
+#endif
+
+NetHackQtGlyphs::NetHackQtGlyphs()
+{
+ boolean tilesok = TRUE, user_tiles = (::iflags.wc_tile_file != NULL);
+ char cbuf[BUFSZ];
+ const char *tile_file = NULL, *tile_list[2];
+
+ this->no_tiles = false;
+ tiles_per_row = TILES_PER_ROW;
+
+ if (user_tiles) {
+ tile_list[0] = ::iflags.wc_tile_file;
+ Snprintf(cbuf, sizeof cbuf, "%s/%s", PIXMAPDIR, tile_list[0]);
+ tile_list[1] = cbuf;
+ } else {
+ tile_list[0] = PIXMAPDIR "/nhtiles.bmp";
+ tile_list[1] = PIXMAPDIR "/x11tiles";
+ }
+
+ if (img.load(tile_list[0]))
+ tile_file = tile_list[0];
+ else if (img.load(tile_list[1]))
+ tile_file = tile_list[1];
+
+ if (!tile_file) {
+ tilesok = FALSE;
+ QString msg = nh_qsprintf("Cannot load '%s'.",
+ user_tiles ? tile_list[0]
+ // mismatched quotes match format
+ : "nhtiles.bmp' or 'x11tiles");
+ QMessageBox::warning(0, "IO Error", msg);
+ } else {
+ if (img.width() % tiles_per_row) {
+ tilesok = FALSE;
+ impossible(
+ "Tile file \"%s\" has %d columns, not multiple of row count (%d)",
+ tile_file, img.width(), tiles_per_row);
+ }
+ }
+
+ if (!tilesok) {
+ this->no_tiles = true;
+ /* tiles wouldn't load so force ascii map */
+ ::iflags.wc_ascii_map = 1;
+ ::iflags.wc_tiled_map = 0;
+ /* tiles wouldn't load so don't allow toggling to tiled map */
+ ::set_wc_option_mod_status(WC_ASCII_MAP | WC_TILED_MAP,
+ ::set_in_config);
+ tiles_per_row = 40; // arbitrary to avoid potential divide-by-0
+ }
+
+ if (iflags.wc_tile_width)
+ tilefile_tile_W = iflags.wc_tile_width;
+ else if (iflags.wc_ascii_map)
+ tilefile_tile_W = 16;
+ else
+ tilefile_tile_W = img.width() / tiles_per_row;
+
+ if (iflags.wc_tile_height)
+ tilefile_tile_H = iflags.wc_tile_height;
+ else
+ tilefile_tile_H = tilefile_tile_W;
+
+ setSize(tilefile_tile_W, tilefile_tile_H);
+}
+
+// display a map tile somewhere other than the map;
+// used for paper doll and also role/race selection
+void
+NetHackQtGlyphs::drawGlyph(
+ QPainter& painter,
+ int glyph, int tileidx,
+ int x, int y,
+ bool reversed)
+{
+ if (!reversed) {
+#if 0
+ int tile = glyph2tile[glyph];
+#else
+ int tile = tileidx;
+#endif
+ int px = (tile % tiles_per_row) * width();
+ int py = tile / tiles_per_row * height();
+
+ painter.drawPixmap(x, y, pm, px, py, width(), height());
+ } else {
+ // for paper doll; mirrored image for left side of two-handed weapon
+ painter.drawPixmap(x, y, reversed_pixmap(glyph, tileidx),
+ 0, 0, width(), height());
+ }
+}
+
+// draw a tile into the paper doll
+void
+NetHackQtGlyphs::drawCell(
+ QPainter& painter,
+ int glyph, int tileidx,
+ int cellx, int celly)
+{
+ drawGlyph(painter, glyph, tileidx, cellx * width(), celly * height(),
+ false);
+}
+
+// draw a tile into the paper doll and then draw a BUC border around it
+void
+NetHackQtGlyphs::drawBorderedCell(
+ QPainter& painter,
+ int glyph, int tileidx,
+ int cellx, int celly,
+ int border, bool reversed)
+{
+ int wd = width(),
+ ht = height(),
+ yoffset = 1, // tiny extra margin at top
+ lox = cellx * (wd + 2),
+ loy = celly * (ht + 2) + yoffset;
+
+ drawGlyph(painter, glyph, tileidx, lox + 1, loy + 1, reversed);
+
+ if (border != NO_BORDER) {
+ // gray would be a better mid-point between red and cyan but it
+ // doesn't show up well enough against the wall tile background
+ painter.setPen((border == BORDER_CURSED) ? Qt::red
+ : (border == BORDER_UNCURSED) ? Qt::yellow
+ : (border == BORDER_BLESSED) ? Qt::cyan
+ : Qt::white); // BORDER_DEFAULT
+ // assuming 32x32, draw 34x34 rectangle from 0..33x0..33, outside glyph
+#if 0 /* Qt 5.11 drawRect(x,y,width,height) seems to have an off by 1 bug;
+ * drawRect(0,0,34,34) is drawing at 0..34x0..34 which is 35x35;
+ * should subtract 1 when adding width and/or height to base coord;
+ * the relevant code in QtCore/QRect.h is correct so this observable
+ * misbehavior is a mystery... */
+ painter.drawRect(lox, loy, wd + 2, ht + 2);
+#else
+ painter.drawLine(lox, loy, lox + wd + 1, loy); // 0,0->33,0
+ painter.drawLine(lox, loy + ht + 1, lox + wd + 1, loy + ht + 1);
+ painter.drawLine(lox, loy, lox, loy + ht + 1); // 0,0->0,33
+ painter.drawLine(lox + wd + 1, loy, lox + wd + 1, loy + ht + 1);
+#endif
+ if (border != BORDER_DEFAULT) {
+ // assuming 32x32, draw rectangle from 1..32x1..32, inside glyph
+#if 0 /* (see above) */
+ painter.drawRect(lox + 1, loy + 1, wd, ht);
+#else
+ painter.drawLine(lox + 1, loy + 1, lox + wd, loy + 1); // 1,1->32,1
+ painter.drawLine(lox + 1, loy + ht, lox + wd, loy + ht);
+ painter.drawLine(lox + 1, loy + 1, lox + 1, loy + ht); // 1,1->1,32
+ painter.drawLine(lox + wd, loy + 1, lox + wd, loy + ht);
+#endif
+ for (int i = lox + 2; i < lox + wd - 1; i += 2) {
+ // assuming 32x32, draw points along <2..31,2> and <2..31,31>
+ painter.drawPoint(i, loy + 2);
+ painter.drawPoint(i + 1, loy + ht - 1);
+ }
+ for (int j = loy + 2; j < loy + ht - 1; j += 2) {
+ // assuming 32x32, draw points along <2,2..31> and <31,2..31>
+ painter.drawPoint(lox + 2, j);
+ painter.drawPoint(lox + wd - 1, j + 1);
+ }
+ }
+ }
+}
+
+// mis-named routine to get the pixmap for a particular glyph
+QPixmap
+NetHackQtGlyphs::glyph(
+ int glyphindx UNUSED,
+ int tileidx)
+{
+#if 0
+ int tile = glyph2tile[glyphindx];
+#else
+ int tile = tileidx;
+#endif
+ int px = (tile % tiles_per_row) * tilefile_tile_W;
+ int py = tile / tiles_per_row * tilefile_tile_H;
+
+ return QPixmap::fromImage(img.copy(px, py,
+ tilefile_tile_W, tilefile_tile_H));
+}
+
+// transpose a glyph's tile horizontally, scaled for use in paper doll
+QPixmap
+NetHackQtGlyphs::reversed_pixmap(
+ int glyphindx, int tileidx)
+{
+ QPixmap pxmp = glyph(glyphindx, tileidx);
+#ifdef ENHANCED_PAPERDOLL
+ qreal wid = (qreal) pxmp.width(),
+ //hgt = (qreal) pxmp.height(),
+ xscale = (qreal) qt_settings->dollWidth / (qreal) tilefile_tile_W,
+ yscale = (qreal) qt_settings->dollHeight / (qreal) tilefile_tile_H;
+ QTransform *mirrormatrix = new QTransform(
+ // negate x coordinates to flip the image across the y-axis
+ -1.0 * xscale, 0.0, 0.0, yscale,
+ // slide flipped image to the right to make things positive again
+ wid * xscale, 0.0
+ );
+ return pxmp.transformed(*mirrormatrix);
+#else
+ return pxmp;
+#endif
+}
+
+void NetHackQtGlyphs::setSize(int w, int h)
+{
+ if (size == QSize(w, h))
+ return;
+ size = QSize(w, h);
+ if (!w || !h)
+ return; // Still not decided
+
+ if (size == pm1.size()) { // not zoomed
+ pm = pm1;
+ return;
+ }
+ if (size == pm2.size()) { // zoomed
+ pm = pm2;
+ return;
+ }
+
+ bool was1 = (size == pm1.size());
+ if (w == tilefile_tile_W && h == tilefile_tile_H) {
+ pm.convertFromImage(img);
+ } else {
+ QApplication::setOverrideCursor(Qt::WaitCursor);
+ QImage scaled = img.scaled(
+ w * img.width() / tilefile_tile_W,
+ h * img.height() / tilefile_tile_H,
+ Qt::IgnoreAspectRatio,
+ Qt::FastTransformation
+ );
+ pm.convertFromImage(scaled, Qt::ThresholdDither | Qt::PreferDither);
+ QApplication::restoreOverrideCursor();
+ }
+ (was1 ? pm2 : pm1) = pm;
+}
+
+} // namespace nethack_qt_
diff --git a/win/Qt/qt_glyph.h b/win/Qt/qt_glyph.h
new file mode 100644
index 000000000..8f5e9c65a
--- /dev/null
+++ b/win/Qt/qt_glyph.h
@@ -0,0 +1,49 @@
+// Copyright (c) Warwick Allison, 1999.
+// Qt4 conversion copyright (c) Ray Chason, 2012-2014.
+// NetHack may be freely redistributed. See license for details.
+
+// qt_glyph.h -- class to manage the glyphs in a tile set
+
+#ifndef QT4GLYPH_H
+#define QT4GLYPH_H
+
+namespace nethack_qt_ {
+
+enum border_code {
+ NO_BORDER, BORDER_DEFAULT,
+ BORDER_CURSED, BORDER_UNCURSED, BORDER_BLESSED
+};
+
+class NetHackQtGlyphs {
+public:
+ bool no_tiles;
+
+ NetHackQtGlyphs();
+
+ int width() const { return size.width(); }
+ int height() const { return size.height(); }
+ void toggleSize();
+ void setSize(int w, int h);
+
+ void drawGlyph(QPainter &, int glyph, int tileidx,
+ int pixelx, int pixely,
+ bool reversed = false);
+ void drawCell(QPainter &, int glyph, int tileidx,
+ int cellx, int celly);
+ void drawBorderedCell(QPainter &, int glyph, int tileidx,
+ int cellx, int celly, int bordercode,
+ bool reversed);
+ QPixmap glyph(int glyphindx, int tileidx);
+ QPixmap reversed_pixmap(int glyphindx, int tileidx);
+
+private:
+ QImage img;
+ QPixmap pm,pm1, pm2;
+ QSize size;
+ int tiles_per_row;
+ //QTransform *mirrormatrix;
+};
+
+} // namespace nethack_qt_
+
+#endif
diff --git a/win/Qt/qt_icon.cpp b/win/Qt/qt_icon.cpp
new file mode 100644
index 000000000..488584f0c
--- /dev/null
+++ b/win/Qt/qt_icon.cpp
@@ -0,0 +1,256 @@
+// Copyright (c) Warwick Allison, 1999.
+// Qt4 conversion copyright (c) Ray Chason, 2012-2014.
+// NetHack may be freely redistributed. See license for details.
+
+// qt_icon.cpp -- a labelled icon for display in the status window
+//
+// TODO?
+// When the label specifies two values separated by a slash (curHP/maxHP,
+// curEn/maxEn, XpLevel/ExpPoints when 'showexp' is On), highlighting
+// for changes is all or nothing based on which field caller passes
+// as the value to use for comparison. curHP and curEn go up and down
+// without any change to the corresponding maximum all the time. Much
+// rarer, but when maxHP and maxEn go up with level gain, the hero
+// could be injured by a passive counterattack or collateral damage
+// from an area effect--or much simpler, the casting cost of a spell
+// that killed a monster and produced the level gain--so the current
+// value could stay the same or even go down at same time max goes up.
+// Likewise, Exp goes up a lot but Xp relatively rarely. (On the very
+// rare occasions where either goes down, they'll both do so.)
+// Highlighting two slash-separated values independently would be
+// worthwhile but with the 'single label using a style sheet for color'
+// approach it isn't going to happen.
+// FIXME:
+// Every LabelledIcon duplicates hl_better, hl_worse, hl_changd.
+//
+
+extern "C" {
+#include "hack.h"
+}
+
+#include "qt_pre.h"
+#include
+#if QT_VERSION >= 0x050000
+#include
+#endif
+#include "qt_post.h"
+#include "qt_icon.h"
+#include "qt_str.h"
+
+namespace nethack_qt_ {
+
+NetHackQtLabelledIcon::NetHackQtLabelledIcon(QWidget *parent, const char *l) :
+ QWidget(parent),
+ label(new QLabel(l,this)),
+ icon(NULL),
+ comp_mode(BiggerIsBetter),
+ prev_value(NoNum),
+ turn_count(-1L)
+{
+ initHighlight();
+}
+
+NetHackQtLabelledIcon::NetHackQtLabelledIcon(QWidget *parent, const char *l,
+ const QPixmap &i) :
+ QWidget(parent),
+ label(new QLabel(l,this)),
+ icon(new QLabel(this)),
+ comp_mode(BiggerIsBetter),
+ prev_value(NoNum),
+ turn_count(-1L)
+{
+ setIcon(i);
+ initHighlight();
+}
+
+// set up the style sheet strings used to specify color for status field
+// labels [done "once", but once for each LabelledIcon that's constructed,
+// so about 30 copies overall with 3.6's status conditions]
+void NetHackQtLabelledIcon::initHighlight()
+{
+ // note: string "green" is much darker than enum Qt::green
+ // QColor("green") => #00ff00
+ // QColor(Qt::green) => #008000
+ // QColor("green").lighter(150) => #00c000 /* hitpoint bar's green */
+ hl_better = "QLabel { background-color : #00c000 ; color : white }";
+ hl_worse = "QLabel { background-color : red ; color : white }";
+ hl_changd = "QLabel { background-color : blue ; color : white }";
+}
+
+void NetHackQtLabelledIcon::setLabel(const QString &t, bool lower)
+{
+ if (!label) {
+ label=new QLabel(this);
+ label->setFont(font());
+ }
+ if (label->text() != t) {
+ label->setText(t);
+ ForceResize();
+ if (comp_mode != NoCompare) {
+ highlight((comp_mode == NeitherIsBetter) ? hl_changd
+ : (comp_mode == (lower ? SmallerIsBetter
+ : BiggerIsBetter)) ? hl_better
+ : hl_worse);
+ } else if (turn_count) {
+ // if we don't want to highlight this status field but it is
+ // currently highlighted (perhaps optional Score recently went
+ // up and has just been toggled off), remove the highlight
+ unhighlight();
+ }
+ }
+}
+
+void NetHackQtLabelledIcon::setLabel(const QString& t, long v, long cv,
+ const QString& tail)
+{
+ QString buf;
+ if (v==NoNum) {
+ buf = "";
+ } else {
+ buf = nh_qsprintf("%ld", v);
+ }
+ setLabel(t + buf + tail, cv < prev_value);
+ prev_value=cv;
+}
+
+void NetHackQtLabelledIcon::setLabel(const QString& t, long v,
+ const QString& tail)
+{
+ setLabel(t,v,v,tail);
+}
+
+void NetHackQtLabelledIcon::setIcon(
+ const QPixmap& i,
+ const QString& tooltip)
+{
+ if (!icon)
+ icon = new QLabel(this);
+ icon->setPixmap(i);
+ if (!tooltip.isNull() && !tooltip.isEmpty())
+ icon->setToolTip(" " + tooltip + " ");
+ ForceResize();
+ icon->resize(i.width(), i.height());
+}
+
+void NetHackQtLabelledIcon::setFont(const QFont& f)
+{
+ QWidget::setFont(f);
+ if (label) label->setFont(f);
+}
+
+// used to highlight status conditions going from Off (blank) to On as "Worse"
+void NetHackQtLabelledIcon::show()
+{
+ // Hunger and Encumbrance are worse when going from not shown
+ // to anything and they're set to SmallerIsBetter, so both
+ // BiggerIsBetter and SmallerIsBetter warrant hl_worse here.
+ // Fly, Lev, and Ride are set NeitherIsBetter so that when
+ // they appear they won't be classified as worse.
+ if (isHidden() && comp_mode != NoCompare)
+ highlight((comp_mode != NeitherIsBetter) ? hl_worse : hl_changd);
+ QWidget::show();
+}
+
+QSize NetHackQtLabelledIcon::sizeHint() const
+{
+ QSize iconsize, textsize;
+
+ if (label && !icon) return label->sizeHint();
+ if (icon && !label) return icon->sizeHint();
+ if (!label && !icon) return QWidget::sizeHint();
+
+ iconsize = icon->sizeHint();
+ textsize = label->sizeHint();
+ return QSize(
+ std::max(iconsize.width(), textsize.width()),
+ iconsize.height() + textsize.height());
+}
+
+QSize NetHackQtLabelledIcon::minimumSizeHint() const
+{
+ QSize iconsize, textsize;
+
+ if (label && !icon) return label->minimumSizeHint();
+ if (icon && !label) return icon->minimumSizeHint();
+ if (!label && !icon) return QWidget::minimumSizeHint();
+
+ iconsize = icon->minimumSizeHint();
+ textsize = label->minimumSizeHint();
+ return QSize(
+ std::max(iconsize.width(), textsize.width()),
+ iconsize.height() + textsize.height());
+}
+
+void NetHackQtLabelledIcon::highlightWhenChanging()
+{
+ turn_count = 0; // turn_count starts negative (as flag to not highlight)
+}
+
+// set comp_mode to one of NoCompare or {Bigger,Smaller,Neither}IsBetter
+void NetHackQtLabelledIcon::setCompareMode(int newmode)
+{
+ comp_mode = newmode;
+}
+
+void NetHackQtLabelledIcon::unhighlight()
+{
+ if (label) { // Surely it is?!
+ label->setStyleSheet("");
+ }
+ if (turn_count > 0)
+ turn_count = 0;
+}
+
+void NetHackQtLabelledIcon::highlight(const QString& hl)
+{
+ if (label) { // Surely it is?!
+ if (turn_count >= 0) {
+ label->setStyleSheet(hl);
+ turn_count = 4;
+ // 4 includes this turn, so dissipates after 3 more keypresses.
+ } else {
+ unhighlight();
+ }
+ }
+}
+
+void NetHackQtLabelledIcon::dissipateHighlight()
+{
+ if (turn_count > 0) {
+ if (!--turn_count)
+ unhighlight();
+ }
+}
+
+// used when label (most status fields) or pixmap (alignment, hunger,
+// encumbrance) changes value
+void NetHackQtLabelledIcon::ForceResize()
+{
+ this->resizeEvent((QResizeEvent *) NULL);
+}
+
+void NetHackQtLabelledIcon::resizeEvent(QResizeEvent*)
+{
+ setAlignments();
+
+ //int labw=label ? label->fontMetrics().width(label->text()) : 0;
+ int labh=label ? label->fontMetrics().height() : 0;
+ int icoh=icon ? icon->height() : 0;
+ int h=icoh+labh;
+ int icoy=(h>height() ? height()-labh-icoh : height()/2-h/2);
+ int laby=icoy+icoh;
+ if (icon) {
+ icon->setGeometry(0,icoy,width(),icoh);
+ }
+ if (label) {
+ label->setGeometry(0,laby,width(),labh);
+ }
+}
+
+void NetHackQtLabelledIcon::setAlignments()
+{
+ if (label) label->setAlignment(Qt::AlignHCenter|Qt::AlignVCenter);
+ if (icon) icon->setAlignment(Qt::AlignHCenter|Qt::AlignVCenter);
+}
+
+} // namespace nethack_qt_
diff --git a/win/Qt/qt_icon.h b/win/Qt/qt_icon.h
new file mode 100644
index 000000000..dddcda7ff
--- /dev/null
+++ b/win/Qt/qt_icon.h
@@ -0,0 +1,64 @@
+// Copyright (c) Warwick Allison, 1999.
+// Qt4 conversion copyright (c) Ray Chason, 2012-2014.
+// NetHack may be freely redistributed. See license for details.
+
+// qt_icon.cpp -- a labelled icon
+
+#ifndef QT4ICON_H
+#define QT4ICON_H
+
+namespace nethack_qt_ {
+
+enum CompareMode {
+ NoCompare = -1, BiggerIsBetter = 0,
+ SmallerIsBetter = 1, NeitherIsBetter = 2
+};
+
+class NetHackQtLabelledIcon : public QWidget {
+public:
+ NetHackQtLabelledIcon(QWidget *parent, const char *label);
+ NetHackQtLabelledIcon(QWidget *parent, const char *label,
+ const QPixmap &icon);
+
+ enum { NoNum = -99999L };
+ void setLabel(const QString &, bool lower=true); // string
+ void setLabel(const QString &, long, const QString &tail=""); // number
+ void setLabel(const QString &, long show_value,
+ long comparative_value, const QString &tail="");
+ void setIcon(const QPixmap &, const QString &tooltip=NULL);
+ virtual void setFont(const QFont &);
+ //QString labelText() { return QString(this->label->text()); }
+
+ void highlightWhenChanging();
+ void setCompareMode(int newmode);
+ void dissipateHighlight();
+ void ForceResize();
+
+ virtual void show();
+ virtual QSize sizeHint() const;
+ virtual QSize minimumSizeHint() const;
+
+ QLabel *label;
+ QLabel *icon;
+
+protected:
+ void resizeEvent(QResizeEvent*);
+
+private:
+ void initHighlight();
+ void setAlignments();
+ void highlight(const QString& highlight);
+ void unhighlight();
+
+ int comp_mode; /* compareMode; default is BiggerIsBetter */
+ long prev_value;
+ long turn_count; /* last time the value changed */
+
+ QString hl_better;
+ QString hl_worse;
+ QString hl_changd;
+};
+
+} // namespace nethack_qt_
+
+#endif
diff --git a/win/Qt/qt_inv.cpp b/win/Qt/qt_inv.cpp
new file mode 100644
index 000000000..76bc06cff
--- /dev/null
+++ b/win/Qt/qt_inv.cpp
@@ -0,0 +1,343 @@
+// Copyright (c) Warwick Allison, 1999.
+// Qt4 conversion copyright (c) Ray Chason, 2012-2014.
+// NetHack may be freely redistributed. See license for details.
+
+// qt_inv.cpp -- inventory subset of equipment in use,
+// displayed in a rectangular grid of object tiles
+//
+// Essentially a "paper doll" style display. [grep fodder]
+//
+// This is at the top center of the main window, between messages and
+// status. Qt settings (non-OSX) or Preferences (OSX) has a checkbox to
+// show it or hide it, plus the tile size to use (independent of map's
+// tile size). Supported tile size is 6..48x6..48 with default of 32x32.
+//
+// TODO?
+// When yn_function() is asking for an inventory letter (not sure whether
+// that is currently discernable...), allow clicking on a cell in the
+// paper doll grid to return the invlet of the item clicked upon.
+//
+
+extern "C" {
+#include "hack.h"
+}
+
+#include "qt_pre.h"
+#include
+#if QT_VERSION >= 0x050000
+#include
+#endif
+#include "qt_post.h"
+#include "qt_inv.h"
+#include "qt_glyph.h"
+#include "qt_main.h"
+#include "qt_set.h"
+
+namespace nethack_qt_ {
+
+static struct obj *
+find_tool(int tooltyp)
+{
+ struct obj *o;
+
+ for (o = gi.invent; o; o = o->nobj) {
+ if ((tooltyp == LEASH && o->otyp == LEASH && o->leashmon)
+ // OIL_LAMP is used for candles, lamps, lantern, candelabrum too
+ || (tooltyp == OIL_LAMP && o->lamplit))
+ break;
+ }
+ return o;
+}
+
+NetHackQtInvUsageWindow::NetHackQtInvUsageWindow(QWidget *parent) :
+ QWidget(parent)
+{
+ setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
+ // needed to enable tool tips
+ setMouseTracking(true);
+
+ /*
+ * TODO:
+ * Add support for clicking on a paperdoll cell and have that
+ * run itemactions(invent.c) for the object shown in the cell.
+ */
+
+ // paperdoll is 6x3 but the indices are column oriented: 0..2x0..5
+ for (int x = 0; x <= 2; ++x)
+ for (int y = 0; y <= 5; ++y)
+ tips[x][y] = NULL;
+}
+
+NetHackQtInvUsageWindow::~NetHackQtInvUsageWindow()
+{
+ for (int x = 0; x <= 2; ++x)
+ for (int y = 0; y <= 5; ++y)
+ if (tips[x][y])
+ free((void *) tips[x][y]), tips[x][y] = NULL;
+}
+
+void NetHackQtInvUsageWindow::drawWorn(
+ QPainter &painter,
+ obj *nhobj,
+ int x, int y, // cell index, not pixels
+ const char *alttip,
+ int flags)
+{
+ short int glyph;
+ glyph_info gi;
+ int border;
+ char tipstr[1 + BUFSZ + 1]; // extra room for leading and trailing space
+ bool rev = (flags == dollReverse),
+ canbe = (flags != dollUnused);
+
+ if (nhobj) {
+ border = BORDER_DEFAULT;
+ // don't expect this to happen but check just in case;
+ // learn_unseen_invent() is normally called when regaining sight
+ // and sets dknown and maybe bknown, then updates perm_invent (do
+ // it regardless of ENHANCED_PAPERDOLL for same effect either way)
+ if (!Blind && (!nhobj->dknown
+ || (Role_if(PM_CLERIC) && !nhobj->bknown)))
+ ::learn_unseen_invent();
+#ifdef ENHANCED_PAPERDOLL
+ // color margin around cell containing item whose BUC state is known
+ if (nhobj->bknown)
+ border = nhobj->cursed ? BORDER_CURSED
+ : !nhobj->blessed ? BORDER_UNCURSED
+ : BORDER_BLESSED;
+
+ // border color is used to indicate BUC state; make tip text match
+ boolean save_implicit_uncursed = ::flags.implicit_uncursed;
+ ::flags.implicit_uncursed = FALSE;
+ // set up a tool tip describing the item that will be displayed here
+ Sprintf(tipstr, " %s ", // extra spaces for enhanced readability
+ // xprname: invlet, space, dash, space, object description
+ xprname(nhobj, (char *) NULL, nhobj->invlet, FALSE, 0L, 0L));
+ ::flags.implicit_uncursed = save_implicit_uncursed;
+
+ // tips are managed with nethack's alloc(); we don't track allocation
+ // amount; allocated buffers get reused when big enough (usual case
+ // since paperdoll updates occur more often than equipment changes)
+ if (tips[x][y] && strlen(tipstr) > strlen(tips[x][y]))
+ free((void *) tips[x][y]), tips[x][y] = NULL;
+
+ if (tips[x][y])
+ Strcpy(tips[x][y], tipstr); // guaranteed to fit
+ else
+ tips[x][y] = dupstr(tipstr);
+#endif
+ glyph = obj_to_glyph(nhobj, rn2_on_display_rng);
+ } else {
+ border = NO_BORDER;
+#ifdef ENHANCED_PAPERDOLL
+ // caller usually passes an alternate tool tip for empty cells
+ size_t altlen = alttip ? 1U + strlen(alttip) + 1U : 0U;
+ if (tips[x][y] && (!alttip || altlen > strlen(tips[x][y])))
+ free((void *) tips[x][y]), tips[x][y] = NULL;
+
+ if (alttip) {
+ Sprintf(tipstr, " %s ", alttip);
+ if (tips[x][y])
+ Strcpy(tips[x][y], tipstr); // guaranteed to fit
+ else
+ tips[x][y] = dupstr(tipstr);
+ }
+#else
+ nhUse(alttip);
+#endif
+ // an empty slot is shown as floor tile unless it's always empty
+ glyph = canbe ? fn_cmap_to_glyph(S_room) : GLYPH_UNEXPLORED;
+ }
+ map_glyphinfo(0, 0, glyph, 0, &gi); /* this skirts the defined
+ * interface unfortunately */
+ qt_settings->glyphs().drawBorderedCell(painter, glyph, gi.gm.tileidx,
+ x, y, border, rev);
+}
+
+// called to update the paper doll inventory subset
+void NetHackQtInvUsageWindow::paintEvent(QPaintEvent*)
+{
+ // Paper doll is a 6 row by 3 column grid of worn and wielded
+ // equipment showing the map tiles that the inventory objects
+ // would be displayed as if they were on the floor.
+ //
+ // 0 1 2 two- dual
+ // [ old ] normal hander wielding legend
+ // 0 [x H b] q H b q H b q H b q quiver H helmet b eyewear
+ // 1 [S " w] w " S W " W w " X w weapon " amulet S shield
+ // 2 [G C G] x C G x C G . C G x alt-weap C cloak G gloves
+ // 3 [= A =] = A = = A = = A = = right rg A suit = left ring
+ // 4 [. U .] L U l L U l L U l L light U shirt l leash
+ // 5 [. F .] . F . . F . . F . . blank F boots . blank
+ // W wielded two-handed weapon
+ // X wielded secondary weapon
+ //
+ // 5.0: use a different layout (also different legend for it, above):
+ // invert so grid is facing player, with right hand on screen left;
+ // show gloves in only one slot;
+ // move alternate weapon to former right hand glove slot;
+ // move blindfold to former alternate weapon slot;
+ // add quiver to former blindfold slot;
+ // show secondary weapon in shield slot when two-weapon is active;
+ // show two-handed primary weapon in both shield and uwep slots;
+ // add lit lamp/lantern/candle/candelabrum on lower left side;
+ // add leash-in-use on lower right side
+ //
+ // Actually indexed by grid[column][row].
+
+#ifdef ENHANCED_PAPERDOLL
+ if (qt_settings->doll_is_shown && ::iflags.wc_ascii_map
+ && qt_settings->glyphs().no_tiles)
+ qt_settings->doll_is_shown = false;
+ if (!qt_settings->doll_is_shown)
+ return;
+ // set glyphs() for the paper doll; might be different size than map's
+ qt_settings->glyphs().setSize(qt_settings->dollWidth,
+ qt_settings->dollHeight);
+
+ /* for drawWorn()'s use of obj->invlet */
+ if (!::flags.invlet_constant)
+ reassign();
+#endif
+
+ QPainter painter;
+ painter.begin(this);
+
+ // String argument is for a tool tip when the object in question is Null.
+ //
+ // left grid column (depicts hero's right side)
+ drawWorn(painter, uquiver, 0, 0, "nothing readied for firing"); // quiver
+ drawWorn(painter, uwep, 0, 1, "no weapon");
+ /* uswapwep slot varies depending upon dual-wielding state;
+ shown in shield slot when actively wielded, so uswapwep slot is empty
+ then and an alternate tool tip is used to explain that emptiness */
+ if (!u.twoweap)
+ drawWorn(painter, uswapwep, 0, 2, "no alternate weapon");
+ else
+ drawWorn(painter, NULL, 0, 2, "secondary weapon is wielded");
+ drawWorn(painter, uright, 0, 3, "no right ring");
+ /* OIL_LAMP matches lit candles, lamps, lantern, and candelabrum
+ (and might also duplicate Sunsword when it is wielded--hence lit--
+ depending upon whether another light source precedes it in invent) */
+ drawWorn(painter, find_tool(OIL_LAMP), 0, 4, "no active light sources");
+ drawWorn(painter, NULL, 0, 5, NULL, dollUnused); // always blank
+
+ // middle grid column; no unused slots
+ drawWorn(painter, uarmh, 1, 0, "no helmet");
+ drawWorn(painter, uamul, 1, 1, "no amulet");
+ drawWorn(painter, uarmc, 1, 2, "no cloak");
+ drawWorn(painter, uarm, 1, 3, "no suit");
+ drawWorn(painter, uarmu, 1, 4, "no shirt");
+ drawWorn(painter, uarmf, 1, 5, "no boots");
+
+ // right grid column (depicts hero's left side)
+ drawWorn(painter, ublindf, 2, 0, "no eyewear"); // bf|towel|lenses
+ /* shield slot varies depending upon weapon usage;
+ no alt tool tip is needed for first two cases because object will
+ never be Null when the corresponding tests pass */
+ if (u.twoweap)
+ drawWorn(painter, uswapwep, 2, 1, NULL); // secondary weapon, in use
+ else if (uwep && bimanual(uwep)) // show two-handed uwep twice
+ drawWorn(painter, uwep, 2, 1, NULL, dollReverse); // uwep on right
+ else
+ drawWorn(painter, uarms, 2, 1, "no shield");
+ drawWorn(painter, uarmg, 2, 2, "no gloves");
+ drawWorn(painter, uleft, 2, 3, "no left ring");
+ /* light source and leash aren't unique and don't have pointers defined */
+ drawWorn(painter, find_tool(LEASH), 2, 4, "no leashes in use");
+ drawWorn(painter, NULL, 2, 5, NULL, dollUnused); // always blank
+
+ painter.end();
+
+#ifdef ENHANCED_PAPERDOLL
+ // reset glyphs() to the ones being used for the map
+ qt_settings->glyphs().setSize(qt_settings->tileWidth,
+ qt_settings->tileHeight);
+#endif
+}
+
+QSize NetHackQtInvUsageWindow::sizeHint(void) const
+{
+ if (qt_settings) {
+ int w = 0, h = 1; // one pixel margin at top
+ // 1+X+1: one pixel border surrounding each tile in the paper doll,
+ // so +1 left and +1 right, also +1 above and +1 below
+#ifdef ENHANCED_PAPERDOLL
+ if (iflags.wc_ascii_map)
+ qt_settings->doll_is_shown = false;
+ if (qt_settings->doll_is_shown) {
+ w += (1 + qt_settings->dollWidth + 1) * 3;
+ h += (1 + qt_settings->dollHeight + 1) * 6;
+ }
+#else
+ if (iflags.wc_tiled_map) {
+ w += (1 + qt_settings->glyphs().width() + 1) * 3;
+ h += (1 + qt_settings->glyphs().height() + 1) * 6;
+ }
+#endif
+ return QSize(w, h);
+ } else {
+ return QWidget::sizeHint();
+ }
+}
+
+// ENHANCED_PAPERDOLL - called when a tool tip is triggered by hovering mouse
+bool NetHackQtInvUsageWindow::tooltip_event(QHelpEvent *tipevent)
+{
+#ifdef ENHANCED_PAPERDOLL
+ if (iflags.wc_ascii_map)
+ qt_settings->doll_is_shown = false;
+ if (!qt_settings->doll_is_shown) {
+ tipevent->ignore();
+ return false;
+ }
+ int wd = qt_settings->dollWidth,
+ ht = qt_settings->dollHeight;
+
+ // inverse of drawBorderedCell();
+ int yoffset = 1, // tiny extra margin at top
+ ex = tipevent->pos().x(),
+ ey = tipevent->pos().y() - yoffset,
+ // KISS: treat 1-pixel margin around cells as part of enclosed cell
+ cellx = ex / (wd + 2),
+ celly = ey / (ht + 2);
+
+ const char *tip = (cellx >= 0 && cellx <= 2 && celly >= 0 && celly <= 5)
+ ? tips[cellx][celly] : NULL;
+ if (tip && *tip) {
+ QToolTip::showText(tipevent->globalPos(), QString(tip));
+ } else {
+ QToolTip::hideText();
+ tipevent->ignore();
+ }
+#else
+ nhUse(tipevent);
+#endif /* ENHANCED_PAPERDOLL */
+ return true;
+}
+
+// ENHANCED_PAPERDOLL - event handler is necessary to support tool tips
+bool NetHackQtInvUsageWindow::event(QEvent *event)
+{
+#ifdef ENHANCED_PAPERDOLL
+ if (event->type() == QEvent::ToolTip) {
+ QHelpEvent *tipevent = static_cast (event);
+ return tooltip_event(tipevent);
+ }
+#endif
+ // with this routine intercepting events, we need to pass along
+ // paint and mouse-press events to have them handled
+ return QWidget::event(event);
+
+}
+
+// ENHANCED_PAPERDOLL - clicking on the PaperDoll runs #seeall ('*')
+void NetHackQtInvUsageWindow::mousePressEvent(QMouseEvent *event UNUSED)
+{
+#ifdef ENHANCED_PAPERDOLL
+ QWidget *main = NetHackQtBind::mainWidget();
+ (static_cast (main))->FuncAsCommand(doprinuse);
+#endif
+}
+
+} // namespace nethack_qt_
diff --git a/win/Qt/qt_inv.h b/win/Qt/qt_inv.h
new file mode 100644
index 000000000..2c1c694e0
--- /dev/null
+++ b/win/Qt/qt_inv.h
@@ -0,0 +1,37 @@
+// Copyright (c) Warwick Allison, 1999.
+// Qt4 conversion copyright (c) Ray Chason, 2012-2014.
+// NetHack may be freely redistributed. See license for details.
+
+// qt_inv.h -- inventory usage window
+// This is at the top center of the main window
+
+#ifndef QT4INV_H
+#define QT4INV_H
+
+namespace nethack_qt_ {
+
+// for calls to drawWorn
+enum drawWornFlag { dollNoFlag = 0, dollUnused = 1, dollReverse = 2 };
+
+class NetHackQtInvUsageWindow : public QWidget {
+public:
+ NetHackQtInvUsageWindow(QWidget* parent);
+ virtual ~NetHackQtInvUsageWindow();
+ virtual void paintEvent(QPaintEvent*);
+ virtual QSize sizeHint(void) const;
+
+protected:
+ virtual bool event(QEvent *event);
+ virtual void mousePressEvent(QMouseEvent *event);
+
+private:
+ void drawWorn(QPainter &painter, obj *nhobj, int x, int y,
+ const char *alttip, int flags = dollNoFlag);
+ bool tooltip_event(QHelpEvent *tipevent);
+
+ char *tips[3][6]; // PAPERDOLL is a grid of 3x6 cells for tiles
+};
+
+} // namespace nethack_qt_
+
+#endif
diff --git a/win/Qt4/qt4kde0.h b/win/Qt/qt_kde0.h
similarity index 91%
rename from win/Qt4/qt4kde0.h
rename to win/Qt/qt_kde0.h
index 27a678c01..8ac1f9595 100644
--- a/win/Qt4/qt4kde0.h
+++ b/win/Qt/qt_kde0.h
@@ -4,7 +4,7 @@
#ifndef QT_DUMMYKDE
#define QT_DUMMYKDE
-namespace nethack_qt4 {
+namespace nethack_qt_ {
class KTopLevelWidget : public QMainWindow {
Q_OBJECT
diff --git a/win/Qt/qt_key.cpp b/win/Qt/qt_key.cpp
new file mode 100644
index 000000000..b598d6b1d
--- /dev/null
+++ b/win/Qt/qt_key.cpp
@@ -0,0 +1,126 @@
+// Copyright (c) Warwick Allison, 1999.
+// Qt4 conversion copyright (c) Ray Chason, 2012-2014.
+// NetHack may be freely redistributed. See license for details.
+
+// qt_key.cpp -- a key buffer
+
+extern "C" {
+#include "hack.h"
+}
+
+#include "qt_pre.h"
+#include
+#include "qt_post.h"
+#include "qt_key.h"
+
+namespace nethack_qt_ {
+
+// convert a Qt key event into a simple ASCII character
+uchar keyValue(QKeyEvent *key_event)
+{
+ // key_event manipulation derived from NetHackQtBind::notify();
+ // used for menus and text windows in qt_menu.cpp, also for
+ // extended commands in xcmd.cpp and popup yn_function in qt_yndlg.cpp
+
+ const int k = key_event->key();
+ Qt::KeyboardModifiers mod = key_event->modifiers();
+ const QString &txt = key_event->text();
+ QChar ch = !txt.isEmpty() ? txt.at(0) : QChar(0);
+
+ if (ch >= QChar(128))
+ ch = QChar(0);
+ // on OSX, ascii control codes are not sent, force them
+ if (ch == 0 && (mod & Qt::ControlModifier) != 0) {
+ if (k >= Qt::Key_A && k <= Qt::Key_Underscore)
+ ch = QChar((k - (Qt::Key_A - 1)));
+ }
+
+ uchar result = (uchar) ch.cell();
+ //raw_printf("kV: k=%d, ch=%u", k, (unsigned) result);
+ return result;
+}
+
+NetHackQtKeyBuffer::NetHackQtKeyBuffer() :
+ in(0), out(0)
+{
+}
+
+bool NetHackQtKeyBuffer::Empty() const
+{
+ return (in == out);
+}
+
+bool NetHackQtKeyBuffer::Full() const
+{
+ return (((in + 1) % maxkey) == out);
+}
+
+void NetHackQtKeyBuffer::Put(int k, int a, uint kbstate)
+{
+ //raw_printf("k:%3d a:'%s' s:0x%08x", k, visctrl((char) a), kbstate);
+ if (Full())
+ return; // Safety
+ key[in] = k;
+ ascii[in] = a;
+ state[in] = (Qt::KeyboardModifiers) kbstate;
+ in = (in + 1) % maxkey;
+}
+
+void NetHackQtKeyBuffer::Put(char a)
+{
+ Put(0, a, 0U);
+}
+
+void NetHackQtKeyBuffer::Put(const char* str)
+{
+ while (*str) Put(*str++);
+}
+
+int NetHackQtKeyBuffer::GetKey()
+{
+ if ( Empty() ) return 0;
+ int r=TopKey();
+ out=(out+1)%maxkey;
+ return r;
+}
+
+int NetHackQtKeyBuffer::GetAscii()
+{
+ if ( Empty() ) return 0; // Safety
+ int r=TopAscii();
+ out=(out+1)%maxkey;
+ return r;
+}
+
+Qt::KeyboardModifiers NetHackQtKeyBuffer::GetState()
+{
+ if ( Empty() ) return Qt::NoModifier;
+ Qt::KeyboardModifiers r=TopState();
+ out=(out+1)%maxkey;
+ return r;
+}
+
+int NetHackQtKeyBuffer::TopKey() const
+{
+ if ( Empty() ) return 0;
+ return key[out];
+}
+
+int NetHackQtKeyBuffer::TopAscii() const
+{
+ if ( Empty() ) return 0;
+ return ascii[out];
+}
+
+Qt::KeyboardModifiers NetHackQtKeyBuffer::TopState() const
+{
+ if ( Empty() ) return Qt::NoModifier;
+ return state[out];
+}
+
+void NetHackQtKeyBuffer::Drain()
+{
+ in = out = 0;
+}
+
+} // namespace nethack_qt_
diff --git a/win/Qt4/qt4key.h b/win/Qt/qt_key.h
similarity index 70%
rename from win/Qt4/qt4key.h
rename to win/Qt/qt_key.h
index 0333269cd..f2e2c2084 100644
--- a/win/Qt4/qt4key.h
+++ b/win/Qt/qt_key.h
@@ -2,12 +2,15 @@
// Qt4 conversion copyright (c) Ray Chason, 2012-2014.
// NetHack may be freely redistributed. See license for details.
-// qt4key.h -- a key buffer
+// qt_key.h -- a key buffer
#ifndef QT4KEY_H
#define QT4KEY_H
-namespace nethack_qt4 {
+namespace nethack_qt_ {
+
+// not part of any class; used in qt_menu.cpp, qt_xcmd.cpp, qt_yndlg.cpp
+extern uchar keyValue(QKeyEvent *key_event);
class NetHackQtKeyBuffer {
public:
@@ -16,7 +19,7 @@ class NetHackQtKeyBuffer {
bool Empty() const;
bool Full() const;
- void Put(int k, int ascii, int state);
+ void Put(int k, int ascii, uint state);
void Put(char a);
void Put(const char* str);
int GetKey();
@@ -27,6 +30,8 @@ class NetHackQtKeyBuffer {
int TopAscii() const;
Qt::KeyboardModifiers TopState() const;
+ void Drain();
+
private:
enum { maxkey=64 };
int key[maxkey];
@@ -35,6 +40,6 @@ class NetHackQtKeyBuffer {
int in,out;
};
-} // namespace nethack_qt4
+} // namespace nethack_qt_
#endif
diff --git a/win/Qt4/qt4line.cpp b/win/Qt/qt_line.cpp
similarity index 71%
rename from win/Qt4/qt4line.cpp
rename to win/Qt/qt_line.cpp
index dd9b18c5f..482122589 100644
--- a/win/Qt4/qt4line.cpp
+++ b/win/Qt/qt_line.cpp
@@ -2,33 +2,28 @@
// Qt4 conversion copyright (c) Ray Chason, 2012-2014.
// NetHack may be freely redistributed. See license for details.
-// qt4line.cpp -- a one line input window
+// qt_line.cpp -- a one line input window
+extern "C" {
#include "hack.h"
-#undef Invisible
-#undef Warning
-#undef index
-#undef msleep
-#undef rindex
-#undef wizard
-#undef yn
-#undef min
-#undef max
+}
+#include "qt_pre.h"
#include
#if QT_VERSION >= 0x050000
#include
#endif
-#include "qt4line.h"
+#include "qt_post.h"
+#include "qt_line.h"
-namespace nethack_qt4 {
+namespace nethack_qt_ {
NetHackQtLineEdit::NetHackQtLineEdit() :
QLineEdit(0)
{
}
-NetHackQtLineEdit::NetHackQtLineEdit(QWidget* parent, const char* name) :
+NetHackQtLineEdit::NetHackQtLineEdit(QWidget* parent, const char* name UNUSED) :
QLineEdit(parent)
{
}
@@ -39,4 +34,4 @@ void NetHackQtLineEdit::fakeEvent(int key, int ascii, Qt::KeyboardModifiers stat
keyPressEvent(&fake);
}
-} // namespace nethack_qt4
+} // namespace nethack_qt_
diff --git a/win/Qt4/qt4line.h b/win/Qt/qt_line.h
similarity index 81%
rename from win/Qt4/qt4line.h
rename to win/Qt/qt_line.h
index bb5067f79..4b3c10cef 100644
--- a/win/Qt4/qt4line.h
+++ b/win/Qt/qt_line.h
@@ -2,12 +2,12 @@
// Qt4 conversion copyright (c) Ray Chason, 2012-2014.
// NetHack may be freely redistributed. See license for details.
-// qt4line.h -- a one line input window
+// qt_line.h -- a one line input window
#ifndef QT4LINE_H
#define QT4LINE_H
-namespace nethack_qt4 {
+namespace nethack_qt_ {
class NetHackQtLineEdit : public QLineEdit {
public:
@@ -17,6 +17,6 @@ class NetHackQtLineEdit : public QLineEdit {
void fakeEvent(int key, int ascii, Qt::KeyboardModifiers state);
};
-} // namespace nethack_qt4
+} // namespace nethack_qt_
#endif
diff --git a/win/Qt/qt_main.cpp b/win/Qt/qt_main.cpp
new file mode 100644
index 000000000..14a4f51f6
--- /dev/null
+++ b/win/Qt/qt_main.cpp
@@ -0,0 +1,1465 @@
+// 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
+#if QT_VERSION >= 0x060000
+#include
+#elif QT_VERSION >= 0x050000
+#include
+#endif
+
+#if QT_VERSION >= 0x050000
+#include
+#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 + 1);
+ maxhn = glyphs->height() * ROWNO * 6/4 + glyphs->height() * 10;
+ }
+ }
+
+ // 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 (::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",
+ !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 or ;
+ leaves the popup waiting for some other response;
+ the & settings for Alt+ 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()
+ 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 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
+ (NetHackQtBind::mainWidget())->invusage;
+ QList 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 ( 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;
+ 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(stack)
+ : static_cast(hsplitter);
+ QWidget* vp = qt_compact_mode ? static_cast(stack)
+ : static_cast(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();
+ }
+ showNormal();
+ } else if (isVisible()) {
+ hide();
+ }
+}
+
+} // namespace nethack_qt_
diff --git a/win/Qt4/qt4main.h b/win/Qt/qt_main.h
similarity index 64%
rename from win/Qt4/qt4main.h
rename to win/Qt/qt_main.h
index a3ec15ac2..3aa5de79c 100644
--- a/win/Qt4/qt4main.h
+++ b/win/Qt/qt_main.h
@@ -2,7 +2,7 @@
// Qt4 conversion copyright (c) Ray Chason, 2012-2014.
// NetHack may be freely redistributed. See license for details.
-// qt4main.h -- the main window
+// qt_main.h -- the main window
#ifndef QT4MAIN_H
#define QT4MAIN_H
@@ -11,10 +11,22 @@
#include
#include
#else
-#include "qt4kde0.h"
+#include "qt_kde0.h"
#endif
-namespace nethack_qt4 {
+// Allow changing 'statuslines:2' to 'statuslines:3' or vice versa
+// while the game is running; deletes and re-creates the status window.
+// [Used in qt_bind.cpp and qt_main.cpp, but not referenced in qt_stat.cpp.]
+#if QT_VERSION >= QT_VERSION_CHECK(5, 9, 0)
+#define DYNAMIC_STATUSLINES
+#endif
+
+// NetHackQtBind::notify() doesn't see ^V on OSX
+#ifdef MACOS
+#define CTRL_V_HACK
+#endif
+
+namespace nethack_qt_ {
class NetHackQtInvUsageWindow;
class NetHackQtKeyBuffer;
@@ -47,13 +59,23 @@ class NetHackQtMainWindow : public KTopLevelWidget {
void RemoveWindow(NetHackQtWindow* window);
void updateInventory();
- void fadeHighlighting();
+ void fadeHighlighting(bool before_key);
+
+ void FuncAsCommand(int (*func)(void));
+ // this is unconditional in case qt_main.h comes before qt_set.h
+ void resizePaperDoll(bool); // ENHANCED_PAPERDOLL
+#ifdef DYNAMIC_STATUSLINES
+ // called when 'statuslines' option has been changed
+ NetHackQtWindow *redoStatus();
+#endif
public slots:
void doMenuItem(QAction *);
void doQtSettings(bool);
void doAbout(bool);
+ void doQuit(bool);
//RLC void doGuidebook(bool);
+ void doKeys(const char *);
void doKeys(const QString&);
protected:
@@ -68,9 +90,15 @@ private slots:
void zoomMap();
void raiseMessages();
void raiseStatus();
+#ifdef CTRL_V_HACK
+ void CtrlV();
+#endif
private:
void ShowIfReady();
+ void AddToolButton(QToolBar *toolbar, QSignalMapper *sm,
+ const char *name, int (*func)(void), QPixmap xpm);
+ static bool ok_for_command();
#ifdef KDE
KMenuBar* menubar;
@@ -90,6 +118,6 @@ private slots:
int dirkey;
};
-} // namespace nethack_qt4
+} // namespace nethack_qt_
#endif
diff --git a/win/Qt/qt_map.cpp b/win/Qt/qt_map.cpp
new file mode 100644
index 000000000..85817dabf
--- /dev/null
+++ b/win/Qt/qt_map.cpp
@@ -0,0 +1,1066 @@
+// 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
+#if QT_VERSION >= 0x050000
+#include
+#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(ch);
+ utf16[1] = 0;
+ } else {
+ utf16[0] = static_cast((ch >> 10) + 0xD7C0);
+ utf16[1] = static_cast((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; iglyphs().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_
diff --git a/win/Qt/qt_map.h b/win/Qt/qt_map.h
new file mode 100644
index 000000000..321db2541
--- /dev/null
+++ b/win/Qt/qt_map.h
@@ -0,0 +1,106 @@
+// Copyright (c) Warwick Allison, 1999.
+// Qt4 conversion copyright (c) Ray Chason, 2012-2014.
+// NetHack may be freely redistributed. See license for details.
+
+// qt_map.h -- the map window
+
+#ifndef QT4MAP_H
+#define QT4MAP_H
+
+#include "qt_win.h"
+#include "qt_clust.h"
+
+namespace nethack_qt_ {
+
+class NetHackQtClickBuffer;
+
+class NetHackQtMapViewport : public QWidget {
+ Q_OBJECT
+public:
+ NetHackQtMapViewport(NetHackQtClickBuffer& click_sink);
+ ~NetHackQtMapViewport(void);
+
+protected:
+ virtual void paintEvent(QPaintEvent* event);
+ bool DrawWalls(QPainter& painter, int x, int y,
+ int w, int h, unsigned short ch);
+ virtual QSize sizeHint() const;
+ virtual QSize minimumSizeHint() const;
+ virtual void mousePressEvent(QMouseEvent* event);
+
+private:
+ QFont *rogue_font;
+ unsigned short glyph[ROWNO][COLNO];
+ unsigned short &Glyph(int x, int y) {
+ return glyph[y][x];
+ }
+ char32_t glyphttychar[ROWNO][COLNO];
+ char32_t &Glyphttychar(int x, int y) {
+ return glyphttychar[y][x];
+ }
+ uint32 glyphcolor[ROWNO][COLNO];
+ uint32 &Glyphcolor(int x, int y) {
+ return glyphcolor[y][x];
+ }
+ uint32 glyphframecolor[ROWNO][COLNO];
+ uint32 &GlyphFramecolor(int x, int y) {
+ return glyphframecolor[y][x];
+ }
+ unsigned int glyphflags[ROWNO][COLNO];
+ unsigned int &Glyphflags(int x, int y) {
+ return glyphflags[y][x];
+ }
+ unsigned short glyphtileidx[ROWNO][COLNO];
+ unsigned short &Glyphtileidx(int x, int y) {
+ return glyphtileidx[y][x];
+ }
+ QPoint cursor;
+ QPixmap pet_annotation;
+ QPixmap pile_annotation;
+ NetHackQtClickBuffer &clicksink;
+ Clusterizer change;
+
+ void clickCursor();
+ void Clear();
+ void Display(bool block);
+ void CursorTo(int x,int y);
+ void PrintGlyph(int x,int y, const glyph_info *glyphinfo, const glyph_info *bkglyphinfo);
+ void Changed(int x, int y);
+ void updateTiles();
+ void SetupTextmapFont(QPainter &painter);
+
+ // NetHackQtMapWindow2 passes through many calls to the viewport
+ friend class NetHackQtMapWindow2;
+};
+
+class NetHackQtMapWindow2 : public QScrollArea, public NetHackQtWindow {
+ Q_OBJECT
+public:
+ NetHackQtMapWindow2(NetHackQtClickBuffer& click_sink);
+ void clearMessages();
+ void putMessage(int attr, const QString& text);
+ void clickCursor();
+ virtual QWidget *Widget();
+
+ virtual void Clear();
+ virtual void Display(bool block);
+ virtual void CursorTo(int x,int y);
+ virtual void PutStr(int attr, const QString& text);
+ virtual void ClipAround(int x,int y);
+ virtual void PrintGlyph(int x,int y, const glyph_info *glyphinfo, const glyph_info *bkglyphinfo);
+
+signals:
+ void resized();
+
+private slots:
+ void updateTiles();
+
+private:
+ NetHackQtMapViewport *m_viewport;
+ QRect messages_rect;
+ QString messages;
+};
+
+} // namespace nethack_qt_
+
+#endif
diff --git a/win/Qt/qt_menu.cpp b/win/Qt/qt_menu.cpp
new file mode 100644
index 000000000..f469597e2
--- /dev/null
+++ b/win/Qt/qt_menu.cpp
@@ -0,0 +1,1318 @@
+// Copyright (c) Warwick Allison, 1999.
+// Qt4 conversion copyright (c) Ray Chason, 2012-2014.
+// NetHack may be freely redistributed. See license for details.
+
+// qt_menu.cpp -- a menu or text-list widget
+
+//
+// TODO:
+// inventory menus reuse the same menu window over and over (in the core);
+// it isn't resizing properly to reflect each new instance's content;
+// [temporary 'fix' allocates at least 15 lines in case a really short
+// subset is displayed before a full inventory; but all inventory menus
+// will be padded to that length when they might otherwise show all the
+// entries with less, and inventories which have more will need to be
+// scrolled to see the excess even if a taller menu would fit on the
+// screen; code now has to distinguish between inventory menu and
+// 'other' menu so that the latter isn't padded too]
+// implement next_page, prev_page, first_page, and last_page to work
+// like they do for X11: scroll menu window as if it were paginated;
+// entering a count that uses more digits than the previous biggest count
+// widens count field but fails to widen the whole menu so a horizontal
+// scrollbar might appear;
+// create and use custom check-box icons to visually distinguish
+// pre-selected entries and numeric subset entries from ordinary select
+// and unselected.
+//
+
+extern "C" {
+#include "hack.h"
+}
+
+#include "qt_pre.h"
+#include
+#if QT_VERSION >= 0x050000
+#include
+#endif
+#include "qt_post.h"
+#include "qt_menu.h"
+#include "qt_menu.moc"
+#include "qt_key.h" // for keyValue()
+#include "qt_glyph.h"
+#include "qt_set.h"
+#include "qt_streq.h"
+#include "qt_str.h"
+
+// temporary
+extern "C" int qt_compact_mode;
+// end temporary
+
+/* for documentation rather than necessity; hack.h -> decl.h declares this */
+extern "C" struct menucoloring *menu_colorings;
+
+namespace nethack_qt_ {
+
+// temporary
+void centerOnMain( QWidget* w );
+// end temporary
+
+QSize NetHackQtTextListBox::sizeHint() const
+{
+ QScrollBar *hscroll = horizontalScrollBar();
+ int hsize = hscroll ? hscroll->height() : 0;
+ return QSize(TotalWidth()+hsize, TotalHeight()+hsize);
+}
+
+int NetHackQtMenuListBox::TotalWidth() const
+{
+ int width = 0;
+
+ for (int col = 0; col < columnCount(); ++col) {
+ width += columnWidth(col);
+ }
+ return width;
+}
+
+int NetHackQtMenuListBox::TotalHeight() const
+{
+ int row, rowheight, height = 0;
+
+ for (row = 0; row < rowCount(); ++row) {
+ height += rowHeight(row);
+ }
+ // 20: arbitrary; should always have at least 1 row so it shouldn't matter
+ rowheight = (row > 0) ? rowHeight(row - 1) : 20;
+
+ //
+ // FIXME:
+ // The core reuses one window for inventory displays and this
+ // part of sizeHint() is working for the initial size but is
+ // ineffective for later resizes.
+ //
+
+ // TEMPORARY:
+ // in case first inventory menu displayed is a short one pad it
+ // with blank lines so later long ones won't be far too short
+ if ((dynamic_cast (parent()))->is_invent) {
+ if (row < 15)
+ height += (15 - row) * rowheight;
+ }
+
+ // include extra height so that there will be a blank gap after the
+ // last entry to show that there is nothing to scroll forward too
+ height += rowheight / 2;
+ return height;
+}
+
+QSize NetHackQtMenuListBox::sizeHint() const
+{
+ QScrollBar *hscroll = horizontalScrollBar(),
+ *vscroll = verticalScrollBar();
+ int hsize = (hscroll && hscroll->isVisible()) ? hscroll->height() : 0,
+ vsize = (vscroll && vscroll->isVisible()) ? vscroll->width() : 0;
+ hsize += MENU_WIDTH_SLOP, vsize += MENU_WIDTH_SLOP;
+ // note: a vertical scrollbar affects widget width, a horizontal one height
+ return QSize(TotalWidth() + vsize, TotalHeight() + hsize);
+}
+
+//
+// FIXME:
+// Inventory displays reuse the same menu window and so far this
+// is not updating the size as intended. The size of the first
+// instance persists.
+//
+
+// resize current menu window and the table (rows of entries) inside it
+void NetHackQtMenuWindow::MenuResize()
+{
+ // when this was just 'adjustSize()', our sizeHints() was not
+ // being called so explicitly indicate the table widget
+ table->adjustSize();
+ this->adjustSize();
+
+ // Temporary? workaround for scrolling becoming wedged if using
+ // all/none/invert removes all counts so we narrow a non-empty
+ // count column to empty. [That can take away the horizontal
+ // scroll bar but should not be affecting the vertical one, yet
+ // is (Qt 5.11.3).] Typing any digit restored normal scrolling
+ // and the only significant thing about that is that it updates
+ // the prompt line which is outside the table of menu items where
+ // scrolling takes place. Oddly, both prompt changes are needed
+ // (possibly the unnecessary space in the first is being optimized
+ // away but the second call to remove it isn't aware of that, or
+ // perhaps the 'fix' only happens when the line gets shorter).
+ prompt.setText(promptstr + " ");
+ prompt.setText(promptstr);
+ // [Later: becoming wedged doesn't just occur after shrinking the
+ // count column and seems to be triggered by table->adjustSize().]
+}
+
+// Table view columns (0..4):
+//
+// [pick-count] [check-box] [object-glyph] [selector-letter] [description]
+//
+// pick-count is normally empty and gets wider as needed.
+//
+NetHackQtMenuWindow::NetHackQtMenuWindow(QWidget *parent) :
+ QDialog(parent),
+ is_invent(false), // reset to True when window is core's WIN_INVEN
+ table(new NetHackQtMenuListBox()),
+ prompt(0),
+ biggestcount(0L), // largest subset amount that user has entered
+ countdigits(0), // number of digits needed by biggestcount
+ counting(false), // user has typed a digit and more might follow
+ searching(false) // user has begun entering a search target string
+{
+ // setFont() was in SelectMenu(), in time to be rendered but too late
+ // when measuring the width and height that will be needed
+ QFont tablefont(qt_settings->normalFixedFont());
+ table->setFont(tablefont);
+
+ QGridLayout *grid = new QGridLayout();
+ table->setColumnCount(5);
+#if __cplusplus >= 202002L
+ table->setFrameStyle(static_cast(QFrame::Panel)
+ | static_cast(QFrame::Sunken));
+#else
+ table->setFrameStyle(QFrame::Panel|QFrame::Sunken);
+#endif
+ table->setLineWidth(2); // note: this is not row spacing
+ table->setShowGrid(false);
+ table->horizontalHeader()->hide();
+ table->verticalHeader()->hide();
+
+ ok=new QPushButton("Ok");
+ connect(ok,SIGNAL(clicked()),this,SLOT(accept()));
+
+ cancel=new QPushButton("Cancel");
+ connect(cancel,SIGNAL(clicked()),this,SLOT(reject()));
+
+ all=new QPushButton("All");
+ connect(all,SIGNAL(clicked()),this,SLOT(All()));
+
+ none=new QPushButton("None");
+ connect(none,SIGNAL(clicked()),this,SLOT(ChooseNone()));
+
+ invert=new QPushButton("Invert");
+ connect(invert,SIGNAL(clicked()),this,SLOT(Invert()));
+
+ search=new QPushButton("Search");
+ connect(search,SIGNAL(clicked()),this,SLOT(Search()));
+
+ QPoint pos(0,ok->height());
+ move(pos);
+ prompt.setParent(this);
+ prompt.move(pos);
+
+ grid->addWidget(ok, 0, 0);
+ grid->addWidget(cancel, 0, 1);
+ grid->addWidget(all, 0, 2);
+ grid->addWidget(none, 0, 3);
+ grid->addWidget(invert, 0, 4);
+ grid->addWidget(search, 0, 5);
+ grid->addWidget(&prompt, 1, 0, 1, 7);
+ grid->addWidget(table, 2, 0, 1, 7);
+ grid->setColumnStretch(6, 1);
+ grid->setRowStretch(2, 1);
+ setFocusPolicy(Qt::StrongFocus);
+ table->setFocusPolicy(Qt::NoFocus);
+ connect(table, SIGNAL(cellClicked(int,int)),
+ this, SLOT(TableCellClicked(int,int)));
+
+ setLayout(grid);
+ setModal(true);
+}
+
+NetHackQtMenuWindow::~NetHackQtMenuWindow()
+{
+}
+
+QWidget* NetHackQtMenuWindow::Widget() { return this; }
+
+//
+// Note: inventory menus reuse the same menu window over and over
+// so StartMenu(), AddMenu(), EndMenu(), and SelectMenu()
+// can't rely on the MenuWindow constructor for initialization.
+//
+
+void NetHackQtMenuWindow::StartMenu(bool using_WIN_INVEN)
+{
+ itemcount = 0;
+ table->setRowCount(itemcount);
+ next_accel = 0;
+ has_glyphs = false;
+ biggestcount = 0L;
+ countdigits = 0;
+ ClearCount(); // reset 'counting' flag and digit string 'countstr'
+ ClearSearch(); // reset 'searching' flag
+
+ is_invent = using_WIN_INVEN;
+}
+
+NetHackQtMenuWindow::MenuItem::MenuItem() :
+ str("")
+{
+}
+
+NetHackQtMenuWindow::MenuItem::~MenuItem()
+{
+}
+
+void NetHackQtMenuWindow::AddMenu(int glyph, const ANY_P *identifier,
+ char ch, char gch, int attr, int clr,
+ const QString& str, unsigned itemflags)
+{
+ bool presel = (itemflags & MENU_ITEMFLAGS_SELECTED) != 0;
+ if (!ch && identifier->a_void!=0) {
+ // Supply a keyboard accelerator. Limited supply.
+ static char accel[]
+ = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
+ if (accel[next_accel]) {
+ ch=accel[next_accel++];
+ }
+ }
+
+ if ((int)itemlist.size() < itemcount+1) {
+ itemlist.resize(itemcount*4+10);
+ }
+ itemlist[itemcount].glyph = glyph;
+ itemlist[itemcount].identifier = *identifier;
+ itemlist[itemcount].ch = ch;
+ itemlist[itemcount].gch = gch;
+ itemlist[itemcount].attr = attr;
+ itemlist[itemcount].color = clr;
+ itemlist[itemcount].str = str;
+ itemlist[itemcount].selected = itemlist[itemcount].preselected = presel;
+ itemlist[itemcount].itemflags = itemflags;
+ itemlist[itemcount].count = -1L;
+ // Display the boulder symbol correctly
+ if (str.left(8) == "boulder\t") {
+ int bracket = str.indexOf('[');
+ if (bracket != -1) {
+ itemlist[itemcount].str = str.left(bracket+1)
+ + QChar(cp437(str.at(bracket+1).unicode()))
+ + str.mid(bracket+2);
+ }
+ }
+ ++itemcount;
+
+ if (glyph != NO_GLYPH)
+ has_glyphs = true;
+}
+
+void NetHackQtMenuWindow::EndMenu(const QString& p)
+{
+ prompt.setText(p);
+ promptstr = p;
+}
+
+int NetHackQtMenuWindow::SelectMenu(int h, MENU_ITEM_P **menu_list)
+{
+ table->setRowCount(itemcount);
+
+ how=h;
+
+ int presel_ct = 0;
+ for (int i = 0; i < itemcount; ++i)
+ if (itemlist[i].preselected)
+ ++presel_ct;
+ bool ok_ok = (how != PICK_ONE || presel_ct == 1);
+ ok->setEnabled(ok_ok); ok->setDefault(ok_ok);
+ cancel->setEnabled(true);
+ all->setEnabled(how == PICK_ANY || (how == PICK_ONE && itemcount == 1));
+ none->setEnabled(how == PICK_ANY || (how == PICK_ONE && presel_ct == 1));
+ invert->setEnabled(how == PICK_ANY || (how == PICK_ONE && itemcount == 1));
+ search->setEnabled(how != PICK_NONE);
+
+ setResult(-1);
+
+ // Set contents of table
+ QFontMetrics fm(table->font());
+ for (int col = 0; col < 5; ++col) {
+ table->setColumnWidth(col, 0);
+ }
+ // default height is way too big; rows end up being double-spaced with it
+ int rowheight = fm.height() * 3 / 5;
+ for (int row = 0; row < itemcount; ++row) {
+ AddRow(row, itemlist[row]);
+ table->setRowHeight(row, rowheight);
+ }
+ PadMenuColumns(::iflags.menu_tab_sep ? true : false);
+
+ MenuResize();
+
+ //old FIXME: size for compact mode
+ //resize(this->width(), parent()->height()*7/8);
+ move(0, 0);
+ centerOnMain(this);
+
+ exec();
+ int result = this->result();
+
+ *menu_list = (MENU_ITEM_P *) 0;
+ if (result > 0 && how != PICK_NONE) {
+ int n = 0;
+ for (int i = 0; i < itemcount; ++i)
+ if (itemlist[i].selected)
+ ++n;
+ if (n) {
+ *menu_list = (MENU_ITEM_P *) alloc(n * sizeof(MENU_ITEM_P));
+ n = 0;
+ for (int i = 0; i < itemcount; ++i) {
+ if (itemlist[i].selected) {
+ (*menu_list)[n].item = itemlist[i].identifier;
+ (*menu_list)[n].count = count(i);
+ ++n;
+ }
+ }
+ }
+ return n;
+ } else {
+ return -1;
+ }
+}
+
+// pad the menu columns so that they all line up
+void NetHackQtMenuWindow::PadMenuColumns(bool split_descr)
+{
+ QFontMetrics fm(table->font());
+ QString col0width_str = "";
+ if (biggestcount > 0L)
+ col0width_str = nh_qsprintf("%*ld", std::max(countdigits, 1),
+ biggestcount);
+ int col0width_int = (int) fm.QFM_WIDTH(col0width_str) + MENU_WIDTH_SLOP;
+ if (col0width_int > table->columnWidth(0))
+ WidenColumn(0, col0width_int);
+
+ // If the description (column 4) is a tab separated list, split
+ // it into fields and figure out how wide each field should be.
+ // Needs to be done at most once for any given menu instantiation.
+ std::vector col_widths(1, 0); // start with 1 element init'd to 0
+ if (split_descr) {
+ for (int row = 0; row < itemcount; ++row) {
+ QTableWidgetItem *twi = table->item(row, 4); // description
+ if (twi == NULL)
+ continue;
+ // if a header/footnote/&c with no sub-fields, don't inflate
+ // the size of col_widths[0]
+ if (!itemlist[row].Selectable()
+ && !itemlist[row].str.contains(QChar('\t')))
+ continue;
+ // determine column widths of sub-fields within description
+ QStringList columns = itemlist[row].str.split("\t");
+ for (int fld = 0; fld < (int) columns.size(); ++fld) {
+ bool lastcol = (fld == (int) columns.size() - 1);
+ int w = fm.QFM_WIDTH(columns[fld] + (lastcol ? "" : " "));
+ if (fld >= (int) col_widths.size()) {
+ col_widths.push_back(w); // add another element
+ } else if (col_widths[fld] < w) {
+ col_widths[fld] = w;
+ }
+ }
+ }
+ } // split_descr
+
+ // Reformat all counts so that they line up right justified and
+ // pad each field within description to fill that field's width.
+ int widest4 = 0;
+ for (int row = 0; row < (int) itemlist.size(); ++row) {
+ // column 0 (subset count); format as right-justified number
+ QTableWidgetItem *cnt = table->item(row, 0);
+ if (cnt != NULL) {
+ QString Amt = "";
+ long amt = count(row); // fetch item(row,0) as a number
+ if (amt > 0L)
+ Amt = nh_qsprintf("%*ld", countdigits, amt);
+ cnt->setText(Amt);
+ }
+
+ // column 4 (item description)
+ QTableWidgetItem *twi = table->item(row, 4);
+ if (twi == NULL)
+ continue;
+ QString text = twi->text();
+ if (split_descr) {
+ QStringList columns = text.split("\t");
+ for (int fld = 0; fld < (int) columns.size() - 1; ++fld) {
+ //columns[fld] += "\t"; /* (used to pad with tabs) */
+ int width = col_widths[fld];
+ while (fm.QFM_WIDTH(columns[fld]) < width)
+ columns[fld] += " "; //"\t";
+ }
+ text = columns.join("");
+ twi->setText(text);
+ }
+ // TODO? if description needs to wrap, increase the height of this row
+ int wid = fm.QFM_WIDTH(text) + MENU_WIDTH_SLOP;
+ if (wid > widest4)
+ widest4 = wid;
+ }
+ if (widest4 > table->columnWidth(4))
+ WidenColumn(4, widest4);
+}
+
+// got a bigger count than previously; might need to widen column 0
+// (or possibly had all counts removed and need to shrink column 0)
+void NetHackQtMenuWindow::UpdateCountColumn(long newcount)
+{
+ if (newcount < 0L) {
+ // this will happen if user clicks on [all],[none],[invert] buttons;
+ // they clear all pending counts while selecting or unselecting
+ biggestcount = 0L;
+ countdigits = 0;
+ table->setColumnWidth(0, 0);
+ WidenColumn(0, MENU_WIDTH_SLOP);
+ } else {
+ biggestcount = std::max(biggestcount, newcount);
+ QString num;
+ num = nh_qsprintf("%*ld", std::max(countdigits, 1), biggestcount);
+ int numlen = (int) num.length();
+ if (numlen % 2)
+ ++numlen;
+ if (numlen <= countdigits)
+ return;
+ countdigits = numlen;
+ // FIXME: neither adjusting the table size (below) nor the
+ // menu widget size (also below) is making the menu widget
+ // bigger after the count column has been expanded
+ }
+
+ PadMenuColumns(false);
+
+ MenuResize();
+ table->repaint();
+}
+
+void NetHackQtMenuWindow::SetTwiAttr(QTableWidgetItem *twi, int color, int attr)
+{
+ if (color != NO_COLOR) {
+ const QPen qp = NetHackQtBind::nhcolor_to_pen(color);
+ twi->setForeground(qp.color());
+ }
+
+ if (attr != ATR_NONE) {
+ QFont itemfont(table->font());
+ switch (attr) {
+ case ATR_BOLD:
+ itemfont.setWeight(QFont::Bold);
+ twi->setFont(itemfont);
+ break;
+ case ATR_ITALIC:
+ itemfont.setItalic(true);
+ twi->setFont(itemfont);
+ break;
+ case ATR_DIM:
+ twi->setFlags(Qt::NoItemFlags);
+ break;
+ case ATR_ULINE:
+ itemfont.setUnderline(true);
+ twi->setFont(itemfont);
+ break;
+ case ATR_INVERSE: {
+ QBrush fg = twi->foreground();
+ QBrush bg = twi->background();
+ if (fg.color() == bg.color()) {
+ // default foreground and background come up the same for
+ // some unknown reason
+ //[pr: both are set to 'Qt::color1' which has same RGB
+ // value as 'Qt::black'; X11 on OSX behaves similarly]
+ if (fg.color() == Qt::color1) {
+ fg = Qt::black;
+ bg = Qt::white;
+ } else {
+ fg = (bg.color() == Qt::white) ? Qt::black : Qt::white;
+ }
+ }
+ twi->setForeground(bg);
+ twi->setBackground(fg);
+ break;
+ }
+ case ATR_BLINK:
+ // not supported
+ break;
+ } /* switch */
+ } /* if attr != ATR_NONE */
+}
+
+void NetHackQtMenuWindow::AddRow(int row, const MenuItem& mi)
+{
+ QFontMetrics fm(table->font());
+ QTableWidgetItem *twi;
+ glyph_info gi;
+
+ if (mi.Selectable() && how != PICK_NONE) {
+ // Count
+ twi = new QTableWidgetItem("");
+ table->setItem(row, 0, twi);
+ twi->setFlags(Qt::ItemIsEnabled);
+#if 0 // active count field now widened as needed rather than preset
+ WidenColumn(0, fm.QFM_WIDTH("999999") + MENU_WIDTH_SLOP);
+#else
+ WidenColumn(0, MENU_WIDTH_SLOP);
+#endif
+
+ // Check box, set if pre-selected
+ QCheckBox *cb = new QCheckBox();
+ cb->setChecked(mi.preselected);
+ cb->setFocusPolicy(Qt::NoFocus);
+ // CheckboxClicked() will call ToggleSelect() for item whose checkbox
+ // gets clicked upon
+ connect(cb, SIGNAL(clicked(bool)), this, SLOT(CheckboxClicked(bool)));
+ table->setCellWidget(row, 1, cb);
+ WidenColumn(1, cb->width());
+ }
+ if (mi.glyph != NO_GLYPH) {
+ // Icon
+ map_glyphinfo(0, 0, mi.glyph, 0, &gi);
+ QPixmap pm(qt_settings->glyphs().glyph(mi.glyph, gi.gm.tileidx));
+ twi = new QTableWidgetItem(QIcon(pm), "");
+ table->setItem(row, 2, twi);
+ twi->setFlags(Qt::ItemIsEnabled);
+ WidenColumn(2, pm.width());
+ }
+
+ QString letter, text(mi.str);
+ if (mi.ch != 0) {
+ // Letter specified
+ letter = QString(mi.ch) + " - ";
+ } else {
+ // Letter is left blank, except for skills display when # and * are
+ // presented (note: they're just displayed, not become selectors)
+ if (text.startsWith(" ")) {
+ // If mi.str starts with " ", it's meant to line up with lines
+ // that have a letter; we don't want that here
+ text = text.mid(4);
+ } else if (text.startsWith(" #") || text.startsWith(" *")) {
+ // Put the * or # in the letter column
+ letter = text.left(4);
+ text = text.mid(4);
+ }
+ }
+ twi = new QTableWidgetItem(letter);
+ table->setItem(row, 3, twi);
+ table->item(row, 3)->setFlags(Qt::ItemIsEnabled);
+ // add extra padding because the measured width comes out too narrow;
+ // for the normal case of "a - ", the trailing space hid the fact that
+ // the column wasn't wide enough for four characters; for the " #"
+ // and " *" cases, the last character was replaced by very tiny "..."
+ int w = (int) fm.QFM_WIDTH(letter);
+ if (w)
+ w += MENU_WIDTH_SLOP / 2;
+ WidenColumn(3, w);
+
+ twi = new QTableWidgetItem(text);
+ table->setItem(row, 4, twi);
+ table->item(row, 4)->setFlags(Qt::ItemIsEnabled);
+ WidenColumn(4, fm.QFM_WIDTH(text));
+
+ SetTwiAttr(twi, mi.color, mi.attr);
+}
+
+void NetHackQtMenuWindow::WidenColumn(int column, int width)
+{
+ // need to add a bit so the whole column displays
+ width += 7;
+ if (table->columnWidth(column) < width) {
+ table->setColumnWidth(column, width);
+ }
+}
+
+void NetHackQtMenuWindow::InputCount(char key)
+{
+ if (key == '\b' || key == '\177' || how == PICK_NONE) {
+ if (counting) {
+ if (countstr.isEmpty())
+ ClearCount();
+ else
+ countstr = countstr.mid(0, countstr.size() - 1);
+ }
+ } else {
+ counting = true;
+ // starting a count (enforced by caller) with '#' is optional;
+ // if used, show visible '0'
+ if (key == '#')
+ key = '0';
+ // if we have non-zero digit and are currently showing visible '0',
+ // replace instead of append; doesn't attempt to handle multiple
+ // leading zeroes--they won't affect the outcome, just look odd
+ else if (key > '0' && countstr == "0")
+ countstr = "";
+ countstr += QChar(key);
+ }
+ if (counting)
+ prompt.setText("Count: " + countstr);
+}
+
+void NetHackQtMenuWindow::ClearCount(void)
+{
+ counting = false;
+ prompt.setText(promptstr);
+ countstr = "";
+}
+
+void NetHackQtMenuWindow::keyPressEvent(QKeyEvent *key_event)
+{
+ uchar key = keyValue(key_event);
+ if (!key)
+ return;
+
+ // only one possible match for key==ch, and if one occurs it takes
+ // precedence over any other match (for instance, some menus might
+ // contain '-' to represent bare hands vs '-' for menu_unselect_page,
+ // or ':' to look into a container vs ':' for menu_search)
+ for (int row = 0; row < itemcount; ++row)
+ if (key == (uchar) itemlist[row].ch) {
+ ToggleSelect(row, false);
+ return;
+ }
+
+ if (key == '\033') {
+ if (counting)
+ ClearCount();
+ else if (searching)
+ ClearSearch();
+ else
+ reject();
+ } else if (key == '\r' || key == '\n' || key == ' ') {
+ accept();
+ } else if ('0' <= key && key <= '9' && !counting) {
+ // check whether digit 'key' matches a group accelerator
+ int hits = 0;
+ for (int row = 0; row < itemcount; ++row)
+ if (key == (uchar) itemlist[row].gch) {
+ ToggleSelect(row, false); // matched so toggle this item
+ ++hits;
+ }
+ if (!hits) // didn't match any group accelerator; start a count
+ InputCount(key);
+ } else if (('0' <= key && key <= '9')
+ || (key == '#' && !counting)
+ || key == '\b' || key == '\177') {
+ InputCount(key);
+ } else if (key == MENU_SELECT_ALL || key == MENU_SELECT_PAGE) {
+ All();
+ } else if (key == MENU_INVERT_ALL || key == MENU_INVERT_PAGE) {
+ Invert();
+ } else if (key == MENU_UNSELECT_ALL || key == MENU_UNSELECT_PAGE) {
+ ChooseNone();
+ } else if (key == MENU_SEARCH) {
+ Search();
+ } else {
+ // multiple matches are possible with gch
+ for (int row = 0; row < itemcount; ++row)
+ if (key == (uchar) itemlist[row].gch)
+ ToggleSelect(row, false);
+ }
+}
+
+void NetHackQtMenuWindow::All()
+{
+ if (how != PICK_ANY && (how != PICK_ONE || itemcount != 1))
+ return;
+
+ if (counting)
+ ClearCount(); // discard any pending count
+ for (int row = 0; row < itemcount; ++row) {
+ itemlist[row].preselected = false; // stale for all rows
+ // skip if not selectable or already selected or fails invert_test()
+ if (!itemlist[row].Selectable()
+ || itemlist[row].selected
+ || !menuitem_invert_test(1, itemlist[row].itemflags, FALSE))
+ continue;
+ itemlist[row].selected = true;
+
+ QTableWidgetItem *count = table->item(row, 0);
+ if (count != NULL) {
+ count->setText("");
+ }
+ QCheckBox *cb = dynamic_cast (table->cellWidget(row, 1));
+ if (cb != NULL) {
+ cb->setChecked(true);
+ }
+ }
+ if (biggestcount > 0L) { // had one or more counts
+ UpdateCountColumn(-1L); // all counts are now gone
+ } else {
+ table->repaint();
+ }
+}
+
+void NetHackQtMenuWindow::ChooseNone()
+{
+ if (how == PICK_NONE)
+ return;
+
+ if (counting)
+ ClearCount(); // discard any pending count
+ for (int row = 0; row < itemcount; ++row) {
+ itemlist[row].preselected = false; // stale for all rows
+ // skip if not selectable or already unselected or fails invert_test()
+ if (!itemlist[row].Selectable()
+ || (!itemlist[row].selected && !isSelected(row))
+ || !menuitem_invert_test(2, itemlist[row].itemflags, TRUE))
+ continue;
+ itemlist[row].selected = false;
+
+ QTableWidgetItem *count = table->item(row, 0);
+ if (count != NULL) {
+ count->setText("");
+ }
+ QCheckBox *cb = dynamic_cast (table->cellWidget(row, 1));
+ if (cb != NULL) {
+ cb->setChecked(Qt::Unchecked);
+ }
+ }
+ if (biggestcount > 0L) { // had one or more counts
+ UpdateCountColumn(-1L); // all counts are now gone
+ } else {
+ table->repaint();
+ }
+}
+
+void NetHackQtMenuWindow::Invert()
+{
+ if (how == PICK_NONE)
+ return;
+
+ if (counting)
+ ClearCount(); // discard any pending count
+ for (int row = 0; row < itemcount; ++row) {
+ itemlist[row].preselected = false; // stale for all rows
+ if (!itemlist[row].Selectable()
+ || !menuitem_invert_test(0, itemlist[row].itemflags,
+ itemlist[row].selected))
+ continue;
+ ToggleSelect(row, false);
+ }
+ if (biggestcount > 0L) { // had one or more counts
+ UpdateCountColumn(-1L); // all counts are now gone
+ } else {
+ table->repaint();
+ }
+}
+
+void NetHackQtMenuWindow::Search()
+{
+ if (how == PICK_NONE)
+ return;
+
+ searching = true;
+ NetHackQtStringRequestor requestor(this, "Search for:");
+ char line[BUFSZ];
+ line[0] = '\0'; /* for EDIT_GETLIN */
+ if (requestor.Get(line)) {
+ for (int i=0; i (table->cellWidget(row, 1));
+ if (cb == NULL)
+ return;
+
+ if (how == PICK_ONE) {
+ // explicitly picking a preselected item in a pick-one menu
+ // chooses that item rather than toggling preselection off;
+ // by clearing whole menu, the code below will select item #row
+ ChooseNone();
+ already_toggled = false;
+ // FIXME? this won't handle a pending count properly;
+ // are there any pick-one menus with preselected choice
+ // where a count is useful?
+ } else {
+ itemlist[row].preselected = false; // flag is now out-of-date
+ }
+
+ QTableWidgetItem *countfield = table->item(row, 0);
+ if (!counting) {
+ if (!already_toggled)
+ cb->setChecked((cb->checkState() == Qt::Unchecked)); // toggle
+ itemlist[row].selected = (cb->checkState() != Qt::Unchecked);
+ if (countfield != NULL)
+ countfield->setText("");
+ } else {
+ long amt = 1L;
+ if (countfield != NULL) {
+ countfield->setText(countstr); // store in item(row,0)
+ amt = count(row); // fetch item(row,0) as a number
+ QString Amt = "";
+ if (amt > 0L)
+ Amt = nh_qsprintf("%*ld", countdigits, amt);
+ countfield->setText(Amt); // store right-justified value
+ }
+ ClearCount(); // blank out 'countstr' and reset 'counting'
+
+ // TODO: use a custom icon for check mark, like tty's '#' vs '+'
+ // [maybe not necessary since unlike tty menus, count is visible]
+
+ // uncheck if count is explicitly 0, otherwise check
+ cb->setChecked((amt > 0L));
+ itemlist[row].selected = (cb->checkState() != Qt::Unchecked);
+
+ // if this count is larger than the biggest we've seen
+ // so far, it might need more digits to render; if so,
+ // all pending counts should be reformatted with new width
+ if (amt > biggestcount)
+ UpdateCountColumn(amt);
+ }
+
+ if (how == PICK_ONE && isSelected(row))
+ accept();
+ else
+ table->repaint();
+ }
+}
+
+// table cell click handler for cells (*,col) where col != 1
+void NetHackQtMenuWindow::TableCellClicked(int row, int col UNUSED)
+{
+ ToggleSelect(row, false);
+}
+
+// checkbox click handler for table cells (*,1);
+// presence of a checkbox in the clicked cell prevents the table cell click
+// handler above from being called even if this handler doesn't get set up
+void NetHackQtMenuWindow::CheckboxClicked(bool on_off UNUSED)
+{
+ // find which checkbox just got toggled by looking for one whose
+ // check state doesn't match corresponding itemlist[].selected flag
+ // [there's got to be a more direct way of achieving this...]
+ for (int row = 0; row < itemcount; ++row) {
+ // for pick-one menu, ToggleSelect() will return to menu's caller
+ if (itemlist[row].Selectable()) {
+ if (!isSelected(row) ^ !itemlist[row].selected) {
+ // signal dispatcher has already checked or unchecked this box
+ ToggleSelect(row, true);
+ return;
+ }
+ }
+ }
+ // didn't find any changed checkbox; should never happen; what to do?
+}
+
+bool NetHackQtMenuWindow::isSelected(int row)
+{
+ QCheckBox *cb = dynamic_cast (table->cellWidget(row, 1));
+ return cb ? (cb->checkState() != Qt::Unchecked) : false;
+}
+
+// convert text count to numeric for final result
+long NetHackQtMenuWindow::count(int row)
+{
+ QTableWidgetItem *count = table->item(row, 0);
+ if (count == NULL)
+ return -1L;
+ QString cstr = count->text();
+ return cstr.isEmpty() ? -1L : cstr.toLong();
+}
+
+// initialize a text window
+NetHackQtTextWindow::NetHackQtTextWindow(QWidget *parent) :
+ QDialog(parent),
+ use_rip(false),
+ str_fixed(false),
+ textsearching(false),
+ ok("&Dismiss", this),
+ search("&Search", this),
+ lines(new NetHackQtTextListBox(this)),
+ target(""),
+ rip(this)
+{
+ //
+ // TODO?
+ // Searching would be far more convenient if the window contained
+ // the search string requestor widget instead of just a [Search]
+ // button to request a popup for that.
+ // Also, searching should probably be disabled if the entire text
+ // fits within the window so there's nothing to scroll through.
+ //
+
+ ok.setDefault(true);
+ connect(&ok,SIGNAL(clicked()), this, SLOT(doDismiss()));
+ connect(&search, SIGNAL(clicked()), this, SLOT(Search()));
+ connect(qt_settings, SIGNAL(fontChanged()), this, SLOT(doUpdate()));
+
+ QVBoxLayout* vb = new QVBoxLayout(this);
+ vb->addWidget(&rip);
+ QHBoxLayout* hb = new QHBoxLayout();
+ vb->addLayout(hb);
+ hb->addWidget(&ok);
+ hb->addWidget(&search);
+ vb->addWidget(lines);
+
+ // we don't want keystrokes being sent to the main window for use as
+ // commands while this text window is popped up
+ setFocusPolicy(Qt::StrongFocus);
+ // needed so that keystrokes get sent to our keyPressEvent()
+ lines->setFocusPolicy(Qt::NoFocus);
+ setModal(true);
+}
+
+void NetHackQtTextWindow::doUpdate()
+{
+ update();
+}
+
+
+NetHackQtTextWindow::~NetHackQtTextWindow()
+{
+}
+
+QWidget* NetHackQtTextWindow::Widget()
+{
+ return this;
+}
+
+bool NetHackQtTextWindow::Destroy()
+{
+ return true; /*!isVisible();*/
+}
+
+void NetHackQtTextWindow::doDismiss()
+{
+ // [Clear() was needed when the search target string was kept in
+ // a static buffer but is superfluous now that that's part of
+ // the TextWindow class and initialized in the constructor.]
+ Clear();
+ accept();
+}
+
+void NetHackQtTextWindow::UseRIP(int how, time_t when)
+{
+// Code from X11 windowport
+#define STONE_LINE_LEN 16 /* # chars that fit on one line */
+#define NAME_LINE 0 /* line # for player name */
+#define GOLD_LINE 1 /* line # for amount of gold */
+#define DEATH_LINE 2 /* line # for death description */
+#define YEAR_LINE 6 /* line # for year */
+
+ static char **rip_line = 0;
+ if (!rip_line) {
+ rip_line=new char*[YEAR_LINE+1];
+ for (int i=0; i 999999999L)
+ cash = 999999999L;
+ (void) snprintf(rip_line[GOLD_LINE], STONE_LINE_LEN + 1, "%ld Au", cash);
+
+ /* Put together death description */
+ formatkiller(buf, sizeof buf, how, FALSE);
+ //str_copy(buf, killer, SIZE(buf));
+
+ /* Put death type on stone */
+ for (line = DEATH_LINE, dpx = buf; line < YEAR_LINE; ++line) {
+ char tmpchar;
+ int i, i0 = (int) strlen(dpx);
+
+ if (i0 > STONE_LINE_LEN) {
+ for (i = STONE_LINE_LEN; (i > 0) && (i0 > STONE_LINE_LEN); --i)
+ if (dpx[i] == ' ')
+ i0 = i;
+ if (!i)
+ i0 = STONE_LINE_LEN;
+ }
+ tmpchar = dpx[i0];
+ dpx[i0] = 0;
+ (void) str_copy(rip_line[line], dpx, STONE_LINE_LEN + 1);
+ if (tmpchar != ' ') {
+ dpx[i0] = tmpchar;
+ dpx= &dpx[i0];
+ } else {
+ dpx= &dpx[i0 + 1];
+ }
+ }
+
+ /* Put year on stone;
+ 64 bit configuration with 64 bit int is capable of overflowing
+ STONE_LINE_LEN characters; a compiler might warn about that,
+ so force a value that it can recognize as fitting within buffer's
+ range ("%4d" imposes a minimum number of digits, not a maximum) */
+ int year = (int) ((yyyymmdd(when) / 10000L) % 10000L); /* Y10K bug! */
+ (void) snprintf(rip_line[YEAR_LINE], STONE_LINE_LEN + 1, "%4d", year);
+
+ rip.setLines(rip_line, YEAR_LINE + 1);
+ use_rip = true;
+}
+
+void NetHackQtTextWindow::Clear()
+{
+ lines->clear();
+ target[0] = '\0'; // discard search target string
+ use_rip = false;
+ str_fixed = false;
+ textsearching = false;
+}
+
+void NetHackQtTextWindow::Display(bool block UNUSED)
+{
+ // make sure window isn't completely empty
+ if (!lines->count())
+ PutStr(ATR_NONE, "");
+
+ if (str_fixed) {
+ lines->setFont(qt_settings->normalFixedFont());
+ } else {
+ lines->setFont(qt_settings->normalFont());
+ }
+
+ /* int h=0; */
+ if (use_rip) {
+ /* h+=rip.height(); */
+ (void) rip.height();
+ ok.hide();
+ search.hide();
+ rip.show();
+ } else {
+ /* h+=ok.height()*2 + 7; */
+ (void) ok.height();
+ ok.show();
+ search.show();
+ rip.hide();
+ }
+#if QT_VERSION < 0x060000
+ QSize screensize = QApplication::desktop()->size();
+#else
+ QSize screensize = screen()->size();
+#endif
+ int mh = screensize.height()*3/5;
+ if ( (qt_compact_mode && lines->TotalHeight() > mh) || use_rip ) {
+ showNormal();
+ } else {
+ move(0, 0);
+ adjustSize();
+ centerOnMain(this);
+ show();
+ }
+
+ lines->clearSelection(); // affects [Search]
+
+ exec();
+ textsearching = false;
+}
+
+// handle a line of text for a text window
+void NetHackQtTextWindow::PutStr(int attr UNUSED, const QString& text)
+{
+#if 1
+ // 5.0: Always render text windows with fixed-width font. The majority
+ // of text files we'll ever display including ('license' and 'history')
+ // happen to have some lines with four spaces anyway and/or they have
+ // been pre-formatted to fit within less than 80 columns. For data.base
+ // entries, some do have four spaces (usually the final attribution)
+ // and some don't, resulting in inconsistent display from one entry to
+ // another if the default proportional font is ever used.
+ str_fixed = true;
+#else
+ // if any line contains four consecutive spaces, render this text window
+ // using fixed-width font; skip substring lookup if flag is already set
+ str_fixed = str_fixed || text.contains(" ");
+#endif
+ // instead of outputting the line directly, save it for future rendering
+ lines->addItem(text);
+}
+
+// prompt for a target string and search current text window for it;
+// if found, highlight the next line target occurs on;
+// multiple searches with same or different search string are supported
+void NetHackQtTextWindow::Search()
+{
+ textsearching = true;
+ NetHackQtStringRequestor requestor(this, "Search for:", "Done", "Find");
+ requestor.SetDefault(target);
+ boolean get_a_line = requestor.Get(target, (int) sizeof target);
+
+ // FIXME:
+ // Force text window to be on top. Without this, it moves behind
+ // the map after the string requestor completes. Then it can't
+ // be seen or accessed (unless the game window is minimized or
+ // dragged out of the way). Unfortunately the window noticeably
+ // vanishes and then immediately gets redrawn.
+ if (!this->isActiveWindow()) {
+ this->activateWindow();
+ this->raise();
+ }
+
+ if (get_a_line && target[0]) {
+ int linecount = lines->count();
+ int current = lines->currentRow();
+ if (current == -1)
+ current = 0;
+ // when no row is highlighted (selected), start the search
+ // on the current row, otherwise start on the row after it
+ // [normally means that the very first row is a candidate
+ // for containing the target during the very first search]
+ int startln = lines->selectedItems().count();
+ for (int i = startln; i < linecount; ++i) {
+ int lnum = (i + current) % linecount;
+ const QString &str = lines->item(lnum)->text();
+ // Check whether target occurs on this line. If it does,
+ // the line is highlighted and this search finishes.
+ // When not currently within view, highlighting also
+ // scrolls the view to make it become the bottom line.
+ // A subsequent search will remember the target string
+ // and start searching on the line past the highlighted
+ // one (even if a new target is specified).
+ if (str.contains(target, Qt::CaseInsensitive)) {
+ lines->setCurrentRow(lnum);
+ return;
+ }
+ }
+ lines->setCurrentItem(NULL);
+ } else {
+ target[0] = '\0';
+ }
+ textsearching = false;
+ return;
+}
+
+void NetHackQtTextWindow::keyPressEvent(QKeyEvent *key_event)
+{
+ uchar key = keyValue(key_event);
+
+ if (key == MENU_SEARCH) {
+ if (!use_rip)
+ Search();
+ } else if (key == '\n' || key == '\r' || key == ' ') {
+ if (!textsearching)
+ accept();
+ else
+ textsearching = FALSE;
+ } else if (key == '\033') {
+ reject();
+ } else {
+ // ignore the current key instead of passing it along
+ //- QDialog::keyPressEvent(key_event);
+ }
+}
+
+NetHackQtMenuOrTextWindow::NetHackQtMenuOrTextWindow(QWidget *parent_) :
+ actual(0),
+ parent(parent_)
+{
+}
+
+// StartMenu() turns a MenuOrTextWindow into a MenuWindow,
+// PutStr() turns one into a TextWindow;
+// calling any other MenuOrTextWindow routine before either of those
+// elicits a warning. (Should probably quit via panic() instead.)
+void NetHackQtMenuOrTextWindow::MenuOrText_too_soon_warning(const char *which)
+{
+ impossible("'%s' called before we know whether window is Menu or Text.",
+ which);
+}
+
+QWidget* NetHackQtMenuOrTextWindow::Widget()
+{
+ QWidget *result = NULL;
+ if (!actual)
+ MenuOrText_too_soon_warning("Widget");
+ else
+ result = actual->Widget();
+ return result;
+}
+
+// Text
+void NetHackQtMenuOrTextWindow::Clear()
+{
+ if (!actual)
+ MenuOrText_too_soon_warning("Clear");
+ else
+ actual->Clear();
+}
+void NetHackQtMenuOrTextWindow::Display(bool block)
+{
+ if (!actual)
+ MenuOrText_too_soon_warning("Display");
+ else
+ actual->Display(block);
+}
+bool NetHackQtMenuOrTextWindow::Destroy()
+{
+ bool result = false;
+ if (!actual)
+ MenuOrText_too_soon_warning("Destroy");
+ else
+ result = actual->Destroy();
+ return result;
+}
+void NetHackQtMenuOrTextWindow::PutStr(int attr, const QString& text)
+{
+ if (!actual)
+ actual = new NetHackQtTextWindow(parent);
+ actual->PutStr(attr, text);
+}
+
+// Menu
+void NetHackQtMenuOrTextWindow::StartMenu(bool using_WIN_INVEN)
+{
+ if (!actual)
+ actual = new NetHackQtMenuWindow(parent);
+ actual->StartMenu(using_WIN_INVEN);
+}
+void NetHackQtMenuOrTextWindow::AddMenu(
+ int glyph, const ANY_P* identifier,
+ char ch, char gch, int attr, int clr,
+ const QString& str, unsigned itemflags)
+{
+ if (!actual)
+ MenuOrText_too_soon_warning("AddMenu");
+ else
+ actual->AddMenu(glyph, identifier, ch, gch, attr, clr, str, itemflags);
+}
+void NetHackQtMenuOrTextWindow::EndMenu(const QString& prompt)
+{
+ if (!actual)
+ MenuOrText_too_soon_warning("EndMenu");
+ else
+ actual->EndMenu(prompt);
+}
+int NetHackQtMenuOrTextWindow::SelectMenu(int how, MENU_ITEM_P **menu_list)
+{
+ int result = -1; // cancelled
+ if (!actual)
+ MenuOrText_too_soon_warning("SelectMenu");
+ else
+ result = actual->SelectMenu(how, menu_list);
+ return result;
+}
+
+} // namespace nethack_qt_
diff --git a/win/Qt4/qt4menu.h b/win/Qt/qt_menu.h
similarity index 58%
rename from win/Qt4/qt4menu.h
rename to win/Qt/qt_menu.h
index 5bc265920..844a470f4 100644
--- a/win/Qt4/qt4menu.h
+++ b/win/Qt/qt_menu.h
@@ -2,15 +2,18 @@
// Qt4 conversion copyright (c) Ray Chason, 2012-2014.
// NetHack may be freely redistributed. See license for details.
-// qt4menu.cpp -- a menu or text-list widget
+// qt_menu.cpp -- a menu or text-list widget
#ifndef QT4MENU_H
#define QT4MENU_H
-#include "qt4win.h"
-#include "qt4rip.h"
+#include "qt_win.h"
+#include "qt_rip.h"
-namespace nethack_qt4 {
+// some menu fields aren't wide enough even though sized for measured text
+#define MENU_WIDTH_SLOP 10 /* this should not be necessary */
+
+namespace nethack_qt_ {
class NetHackQtTextListBox : public QListWidget {
public:
@@ -21,7 +24,7 @@ class NetHackQtTextListBox : public QListWidget {
int width = 0;
QFontMetrics fm(font());
for (int i = 0; i < count(); i++) {
- int lwidth = fm.width(item(i)->text());
+ int lwidth = fm.QFM_WIDTH(item(i)->text());
width = std::max(width, lwidth);
}
return width;
@@ -53,21 +56,24 @@ class NetHackQtMenuWindow : public QDialog, public NetHackQtWindow {
virtual QWidget* Widget();
- virtual void StartMenu();
- virtual void AddMenu(int glyph, const ANY_P* identifier, char ch, char gch, int attr,
- const QString& str, bool presel);
+ virtual void StartMenu(bool using_WIN_INVEN = false);
+ virtual void AddMenu(int glyph, const ANY_P *identifier,
+ char ch, char gch, int attr, int clr,
+ const QString& str, unsigned itemflags);
virtual void EndMenu(const QString& prompt);
virtual int SelectMenu(int how, MENU_ITEM_P **menu_list);
+ bool is_invent; // using core's WIN_INVEN
+
public slots:
void All();
void ChooseNone();
void Invert();
void Search();
- void ToggleSelect(int);
- void cellToggleSelect(int, int);
- void DoSelection(bool);
+ void ToggleSelect(int row, bool alyready_checked);
+ void TableCellClicked(int row, int col);
+ void CheckboxClicked(bool on_off);
protected:
virtual void keyPressEvent(QKeyEvent*);
@@ -81,10 +87,12 @@ public slots:
ANY_P identifier;
int attr;
QString str;
- int count;
+ long count;
char ch;
char gch;
- bool selected;
+ bool selected; // True if checkbox is set
+ bool preselected; // True if caller told us to set checkbox
+ unsigned itemflags;
unsigned color;
bool Selectable() const { return identifier.a_void!=0; }
@@ -107,19 +115,27 @@ public slots:
// Count replaces prompt while it is being input
QString promptstr;
QString countstr;
- bool counting;
+ long biggestcount; // determines width of field #0
+ int countdigits; // number of digits to format biggestcount
+ bool counting; // in midst of entering a count
+ bool searching; // in midst of entering a search string
void InputCount(char key);
void ClearCount(void);
- int how;
-
- bool has_glyphs;
+ int how; // pick-none, pick-one, pick-any
+ bool has_glyphs; // at least one item specified a glyph
bool isSelected(int row);
- int count(int row);
+ long count(int row);
+ void SetTwiAttr(QTableWidgetItem *twi, int color, int attr);
void AddRow(int row, const MenuItem& mi);
void WidenColumn(int column, int width);
+ void PadMenuColumns(bool split_descr);
+ void MenuResize();
+ void UpdateCountColumn(long newcount);
+
+ void ClearSearch();
};
class NetHackQtTextWindow : public QDialog, public NetHackQtWindow {
@@ -140,15 +156,21 @@ public slots:
void Search();
private slots:
+ void doDismiss();
void doUpdate();
+protected:
+ virtual void keyPressEvent(QKeyEvent *);
+
private:
bool use_rip;
bool str_fixed;
+ bool textsearching;
QPushButton ok;
QPushButton search;
NetHackQtTextListBox* lines;
+ char target[BUFSZ];
NetHackQtRIP rip;
};
@@ -156,7 +178,9 @@ private slots:
class NetHackQtMenuOrTextWindow : public NetHackQtWindow {
private:
NetHackQtWindow* actual;
- QWidget *parent;
+ QWidget *parent;
+
+ static void MenuOrText_too_soon_warning(const char *);
public:
NetHackQtMenuOrTextWindow(QWidget *parent = NULL);
@@ -170,14 +194,15 @@ class NetHackQtMenuOrTextWindow : public NetHackQtWindow {
virtual void PutStr(int attr, const QString& text);
// Menu
- virtual void StartMenu();
- virtual void AddMenu(int glyph, const ANY_P* identifier, char ch, char gch, int attr,
- const QString& str, bool presel);
+ virtual void StartMenu(bool using_WIN_INVENT = false);
+ virtual void AddMenu(int glyph, const ANY_P *identifier,
+ char ch, char gch, int attr, int clr,
+ const QString& str, unsigned itemflags);
virtual void EndMenu(const QString& prompt);
virtual int SelectMenu(int how, MENU_ITEM_P **menu_list);
};
-} // namespace nethack_qt4
+} // namespace nethack_qt_
#endif
diff --git a/win/Qt/qt_msg.cpp b/win/Qt/qt_msg.cpp
new file mode 100644
index 000000000..f61549d81
--- /dev/null
+++ b/win/Qt/qt_msg.cpp
@@ -0,0 +1,230 @@
+// Copyright (c) Warwick Allison, 1999.
+// Qt4 conversion copyright (c) Ray Chason, 2012-2014.
+// NetHack may be freely redistributed. See license for details.
+
+// qt_msg.cpp -- a message window
+
+extern "C" {
+#include "hack.h"
+}
+
+#include "qt_pre.h"
+#include
+#if QT_VERSION >= 0x050000
+#include
+#endif
+#include "qt_post.h"
+#include "qt_msg.h"
+#include "qt_msg.moc"
+#include "qt_map.h"
+#include "qt_set.h"
+#include "qt_str.h"
+
+namespace nethack_qt_ {
+
+NetHackQtMessageWindow::NetHackQtMessageWindow() :
+ list(new QListWidget()),
+ scrollarea(new QScrollArea())
+{
+ list->setFocusPolicy(Qt::NoFocus);
+ scrollarea->setFocusPolicy(Qt::NoFocus);
+ scrollarea->takeWidget();
+ ::iflags.window_inited = 1;
+ map = 0;
+ currgetmsg = 0;
+ connect(qt_settings,SIGNAL(fontChanged()),this,SLOT(updateFont()));
+ updateFont();
+}
+
+NetHackQtMessageWindow::~NetHackQtMessageWindow()
+{
+ ::iflags.window_inited = 0;
+ delete list;
+}
+
+QWidget* NetHackQtMessageWindow::Widget() {
+ return list;
+}
+
+void NetHackQtMessageWindow::setMap(NetHackQtMapWindow2* m)
+{
+ map = m;
+ updateFont();
+}
+
+void NetHackQtMessageWindow::updateFont()
+{
+ list->setFont(qt_settings->normalFont());
+ if ( map )
+ map->setFont(qt_settings->normalFont());
+}
+
+void NetHackQtMessageWindow::Scroll(int dx UNUSED, int dy UNUSED)
+{
+ //RLC Is this necessary?
+ //RLC list->Scroll(dx,dy);
+}
+
+void NetHackQtMessageWindow::Clear()
+{
+ if (list)
+ NetHackQtMessageWindow::unhighlight_mesgs();
+
+ if (map)
+ map->clearMessages();
+}
+
+void NetHackQtMessageWindow::ClearMessages()
+{
+ if (list)
+ list->clear();
+}
+
+void NetHackQtMessageWindow::Display(bool block)
+{
+ if (changed) {
+ list->repaint();
+ changed=false;
+ }
+ if (block) {
+ // we don't care what the response is here
+ (void) NetHackQtBind::qt_more();
+ }
+}
+
+const char * NetHackQtMessageWindow::GetStr(bool init)
+{
+ if (init)
+ currgetmsg = 0;
+
+ QListWidgetItem *item = list->item(currgetmsg++);
+ if (item) {
+ QString str = item->text();
+ if (str.toLatin1().length() < (int) sizeof historybuf) {
+ return strcpy(historybuf, str.toLatin1().constData());
+ //raw_printf("getstr[%d]='%s'", currgetmsg, result);
+ }
+ }
+ return NULL;
+}
+
+void NetHackQtMessageWindow::PutStr(int attr, const QString& text)
+{
+ changed=true;
+
+ // If the line is output from the "/" command, map the first character
+ // as a symbol
+ QString text2;
+ if (text.mid(1, 3) == " ") {
+ text2 = QChar(cp437(text.at(0).unicode())) + text.mid(1);
+ } else {
+ text2 = text;
+ }
+
+#if 0
+ if (attr != ATR_NONE) {
+ QListWidgetItem *item = new QListWidgetItem(text2);
+ if (attr != ATR_DIM && attr != ATR_INVERSE) {
+ QFont font = item->font();
+ font.setUnderline(attr == ATR_ULINE);
+ font.setWeight((attr == ATR_BOLD) ? QFont::Bold : QFont::Normal);
+ item->setFont(font);
+ // ATR_BLINK not supported
+ } else {
+ // ATR_DIM or ATR_INVERSE
+ QBrush fg = item->foreground();
+ QBrush bg = item->background();
+ if (fg.color() == bg.color()) { // from menu coloring [AddRow()]
+ // default foreground and background come up the same for
+ // some unknown reason
+ //[pr: both are set to 'Qt::color1' which has same RGB
+ // value as 'Qt::black'; X11 on OSX behaves similarly]
+ if (fg.color() == Qt::color1) {
+ fg = Qt::black;
+ bg = Qt::white;
+ } else {
+ fg = (bg.color() == Qt::white) ? Qt::black : Qt::white;
+ }
+ }
+ if (attr == ATR_DIM) {
+ QColor fg_clr = fg.color();
+ fg_clr.setAlpha(fg_clr.alpha() / 2);
+ item->setFlags(Qt::NoItemFlags);
+ } else if (attr == ATR_INVERSE) {
+ QBrush swapfb;
+ swapfb = fg; fg = bg; bg = swapfb;
+ }
+ item->setForeground(fg);
+ item->setBackground(bg);
+ }
+ }
+#else
+ nhUse(attr);
+#endif
+
+ if (list->count() >= (int) ::iflags.msg_history)
+ delete list->item(0);
+ list->addItem(text2);
+ /* assert( list->count() > 0 ); */
+
+ // force scrollbar to bottom;
+ // selects most recent message, which causes it to be highlighted
+ list->setCurrentRow(list->count() - 1);
+
+ // if message window has been scrolled right, force back to left edge
+ QScrollBar *sb = list->horizontalScrollBar();
+ if (sb && sb->value() > 0) {
+ sb->setValue(0);
+ this->viewport()->update();
+ }
+
+ if (map)
+ map->putMessage(attr, text2);
+}
+
+// append to the last message; usually the user's answer to a prompt
+void NetHackQtMessageWindow::AddToStr(const char *answer)
+{
+ if (list) {
+ QListWidgetItem *item = list->currentItem();
+ int ct = 0;
+ if (!item && (ct = list->count()) > 0) {
+ list->setCurrentRow(ct - 1);
+ item = list->currentItem();
+ }
+ if (item)
+ item->setText(item->text() + QString(" %1").arg(answer));
+ else // just in case...
+ NetHackQtMessageWindow::PutStr(ATR_NONE, answer);
+ }
+}
+
+// used when yn_function() or more() rejects player's input and tries again
+void NetHackQtMessageWindow::RehighlightPrompt()
+{
+ // selects most recent message, which causes it to be highlighted
+ if (list && list->count())
+ list->setCurrentRow(list->count() - 1);
+}
+
+// are there any highlighted messages?
+bool NetHackQtMessageWindow::hilit_mesgs()
+{
+ // PutStr() uses setCurrentRow() to select the last message line;
+ // being selected causes that line to be highlighted.
+ //
+ // We could/should keep track of whether anything is currently
+ // highlighted instead of just assuming that last message still is.
+ if (list && list->count())
+ return true;
+ return false;
+}
+
+// unhighlight any highlighted messages
+void NetHackQtMessageWindow::unhighlight_mesgs()
+{
+ if (list)
+ list->clearSelection();
+}
+
+} // namespace nethack_qt_
diff --git a/win/Qt4/qt4msg.h b/win/Qt/qt_msg.h
similarity index 58%
rename from win/Qt4/qt4msg.h
rename to win/Qt/qt_msg.h
index f4091ad18..9c5624d8b 100644
--- a/win/Qt4/qt4msg.h
+++ b/win/Qt/qt_msg.h
@@ -2,18 +2,18 @@
// Qt4 conversion copyright (c) Ray Chason, 2012-2014.
// NetHack may be freely redistributed. See license for details.
-// qt4msg.h -- a message window
+// qt_msg.h -- a message window
#ifndef QT4MSG_H
#define QT4MSG_H
-#include "qt4win.h"
+#include "qt_win.h"
-namespace nethack_qt4 {
+namespace nethack_qt_ {
class NetHackQtMapWindow2;
-class NetHackQtMessageWindow : QObject, public NetHackQtWindow {
+class NetHackQtMessageWindow : QScrollArea, public NetHackQtWindow {
Q_OBJECT
public:
NetHackQtMessageWindow();
@@ -30,16 +30,24 @@ class NetHackQtMessageWindow : QObject, public NetHackQtWindow {
void setMap(NetHackQtMapWindow2*);
+ void RehighlightPrompt();
+ bool hilit_mesgs();
+ void unhighlight_mesgs();
+ // for adding the answer for y_n() to its prompt string
+ void AddToStr(const char *answerbuf);
+
private:
- QListWidget* list;
- bool changed;
+ QListWidget *list;
+ QScrollArea *scrollarea;
+ bool changed;
int currgetmsg;
NetHackQtMapWindow2* map;
+ char historybuf[BUFSZ];
private slots:
void updateFont();
};
-} // namespace nethack_qt4
+} // namespace nethack_qt_
#endif
diff --git a/win/Qt/qt_plsel.cpp b/win/Qt/qt_plsel.cpp
new file mode 100644
index 000000000..a280f07fc
--- /dev/null
+++ b/win/Qt/qt_plsel.cpp
@@ -0,0 +1,742 @@
+// Copyright (c) Warwick Allison, 1999.
+// Qt4 conversion copyright (c) Ray Chason, 2012-2014.
+// NetHack may be freely redistributed. See license for details.
+
+// qt_plsel.cpp -- player selector dialog
+
+//
+// TODO:
+// increase height so that no scrolling is needed for role list [needs
+// to be done properly instead of forcing logo string to be taller]
+// make race first vs role first dynamically selectable (tty allows
+// gender first and alignment first too);
+// maybe add a set of radio buttons for normal mode vs explore mode
+// [vs wizard mode if eligible]
+// gray out character name / disable name specification box if player
+// shouldn't be allowed to change it ("wizard" for debug mode, use
+// of some forced value for multi-user system).
+//
+
+extern "C" {
+#include "hack.h"
+}
+
+#include "qt_pre.h"
+#include
+#if QT_VERSION >= 0x050000
+#include
+#endif
+#include "qt_post.h"
+#include "qt_plsel.h"
+#include "qt_plsel.moc"
+#include "qt_bind.h"
+#include "qt_glyph.h"
+#include "qt_set.h"
+#include "qt_str.h"
+
+// Warwick prefers it this way...
+#define QT_CHOOSE_RACE_FIRST
+
+/* check whether plname[] is among the list of generic user names */
+static bool generic_plname()
+{
+ if (*svp.plname) {
+ const char *sptr, *p;
+ const char *genericusers = sysopt.genericusers;
+ int ln = (int) strlen(svp.plname);
+
+ if (!genericusers || !*genericusers)
+ genericusers = "player games";
+ else if (!strcmp(genericusers, "*")) /* "*" => always ask for name */
+ return true;
+
+ while ((sptr = strstri(genericusers, svp.plname)) != NULL) {
+ /* check for full word: start of list or following a space */
+ if ((sptr == genericusers || sptr[-1] == ' ')
+ /* and also preceding a space or at end of list */
+ && (sptr[ln] == ' ' || sptr[ln] == '\0'))
+ return true;
+ /* doesn't match full word, but maybe we got a false hit when
+ looking for "play" in list "player play" so keep going */
+ if ((p = strchr(sptr + 1, ' ')) == NULL)
+ break;
+ genericusers = p + 1;
+ }
+ }
+ return false;
+}
+
+namespace nethack_qt_ {
+
+// temporary
+void centerOnMain( QWidget* w );
+// end temporary
+
+// hack: padded with blank lines by inserting breaks above and below in
+// order to force window to be tall enough to show all the roles at once
+static const char nh_attribution[] = "
NetHack %1"
+ "
by the NetHack DevTeam
";
+
+//
+// None of these extra classes seem to be used except for NhPSListView. [pr]
+// If NhPSListViewRole and NhPSListViewRace ever start being used,
+// they'll need access to NetHackQtPlayerSelector::chosen_gend to use
+// the correct tile for the icon.
+//
+
+class NhPSListViewItem : public QTableWidgetItem {
+public:
+ NhPSListViewItem( QTableWidget* parent UNUSED, const QString& name ) :
+ QTableWidgetItem(name)
+ {
+ }
+
+ void setGlyph(int g, int tileidx)
+ {
+ NetHackQtGlyphs& glyphs = qt_settings->glyphs();
+ int gw = glyphs.width();
+ int gh = glyphs.height();
+ QPixmap pm(gw,gh);
+ QPainter p(&pm);
+ glyphs.drawGlyph(p, g, tileidx, 0, 0, false);
+ p.end();
+ setIcon(QIcon(pm));
+ //RLC setHeight(std::max(pm.height()+1,height()));
+ }
+
+#if 0 //RLC
+ void paintCell( QPainter *p, const QColorGroup &cg,
+ int column, int width, int alignment )
+ {
+ if ( isSelectable() ) {
+ QTableWidgetItem::paintCell( p, cg, column, width, alignment );
+ } else {
+ QColorGroup disabled(
+ cg.foreground().light(),
+ cg.button().light(),
+ cg.light(), cg.dark(), cg.mid(),
+ Qt::gray, cg.base() );
+ QTableWidgetItem::paintCell( p, disabled, column, width, alignment );
+ }
+ }
+#endif
+};
+
+class NhPSListViewRole : public NhPSListViewItem {
+public:
+ NhPSListViewRole( QTableWidget* parent, int id ) :
+ NhPSListViewItem(parent,
+#ifdef QT_CHOOSE_RACE_FIRST // Lowerize - looks better
+ QString(roles[id].name.m).toLower()
+#else
+ roles[id].name.m
+#endif
+ )
+ {
+ glyph_info gi;
+ int glyph = monnum_to_glyph(roles[id].mnum, MALE);
+ map_glyphinfo(0, 0, glyph, 0, &gi);
+ setGlyph(glyph, gi.gm.tileidx);
+ }
+};
+
+class NhPSListViewRace : public NhPSListViewItem {
+public:
+ NhPSListViewRace( QTableWidget* parent, int id ) :
+ NhPSListViewItem(parent,
+#ifdef QT_CHOOSE_RACE_FIRST // Capitalize - looks better
+ str_titlecase(races[id].noun)
+#else
+ races[id].noun
+#endif
+ )
+ {
+ glyph_info gi;
+ int glyph = monnum_to_glyph(races[id].mnum, MALE);
+ map_glyphinfo(0, 0, glyph, 0, &gi);
+ setGlyph(glyph, gi.gm.tileidx);
+ }
+};
+
+class NhPSListView : public QTableWidget {
+public:
+ NhPSListView( QWidget* parent ) :
+ QTableWidget(parent)
+ {
+ setColumnCount(1);
+ verticalHeader()->hide();
+#if QT_VERSION >= 0x050000
+ horizontalHeader()->setSectionsClickable(false);
+#else
+ horizontalHeader()->setClickable(false);
+#endif
+ }
+
+ QSizePolicy sizePolicy() const
+ {
+ return QSizePolicy(QSizePolicy::Expanding,QSizePolicy::Expanding);
+ }
+
+ QSize minimumSizeHint() const
+ {
+ return sizeHint();
+ }
+
+ QSize sizeHint() const
+ {
+ return QSize(columnWidth(0), QTableWidget::sizeHint().height());
+ }
+};
+
+// constructor for player's name+role/race/gender/alignment selection
+NetHackQtPlayerSelector::NetHackQtPlayerSelector(
+ NetHackQtKeyBuffer& ks UNUSED) :
+ QDialog(NetHackQtBind::mainWidget()),
+ fully_specified_role(true),
+ chosen_gend(ROLE_NONE),
+ chosen_align(ROLE_NONE),
+ cleric_role_row(0),
+ human_race_row(0),
+ rand_btn(new QPushButton("Random")),
+ play_btn(new QPushButton("Play")),
+ quit_btn(new QPushButton("Quit"))
+{
+ /*
+ 0 1 2
+ + Name --------------------------------------+
+ 0 | |
+ + -------------------------------------------+
+ + Race ----+ + Role ----+ + Gender ------+
+ | human | | Archeolog| | * Male |
+ 1 | elf | | Barbarian| | * Female |
+ | dwarf | | | +--------------+
+ | gnome | | |
+ | orc | | | + Alignment ---+
+ 2 | | | . | | * Lawful |
+ | | | . | | * Neutral |
+ | | | . | | * Chaotic |
+ | | | | +--------------+
+ 3 | | | | ...stretch...
+ | | | |
+ 4 | | | Valkyrie | [ Random ]
+ 5 | | | Wizard | [ Play ]
+ 6 | | | | [ Quit ]
+ +----------+ +----------+
+ *
+ * Both Race and Role entries are actually two-part: an icon (the map
+ * tile for the corresponding monster) and text (race or role name);
+ * Race column is as tall as role one but mostly blank;
+ * Role names aren't truncated in the actual display, just here; the
+ * race and role columns do have equal width;
+ * Roles with gender-specific names get changed to match chosen gender;
+ * Each of the four role/race/gender/alignment categories always has
+ * one entry checked; [Random] will change to a new set;
+ * [Play] is selected by default if [Name] is non-empty but grayed out
+ * if it is empty;
+ * [Quit] is selected by default when [Name] is empty;
+ * ...stretch... is "NetHack x.y.z" in large text over
+ * "by the NetHack DevTeam" is smaller text with blank space above
+ * and below the two lines of text.
+ *
+ * If currently selected race isn't allowed to be some roles, they'll
+ * be grayed out. To switch to one of those, first check "human" which
+ * offers access to all roles (except Valk which will be grayed out if
+ * "male" is checked), pick the role of interest, and then re-pick race
+ * (some of which will be grayed out if chosen role doesn't allow them).
+ * To pick alignment first, check "human" and "priest[ess]" to make
+ * all three alignments accessible, pick the one of interest, then pick
+ * among the races and roles that are acceptable for that alignment.
+ * Gender can be picked at any time, except for male when Valkyrie is
+ * selected.
+ */
+
+ QGridLayout *l = new QGridLayout(this);
+ l->setColumnStretch(2, 1);
+ sizePolicy().setHorizontalPolicy(QSizePolicy::Minimum);
+
+ QGroupBox* namebox = new QGroupBox("Name", this);
+ QVBoxLayout *namelayout = new QVBoxLayout(namebox);
+ QLineEdit* name = new QLineEdit(namebox);
+ namelayout->addWidget(name);
+ name->setMaxLength(PL_NSIZ - 1);
+ name->setPlaceholderText(QString(" (required)")); // grayed out
+
+ // if plname[] contains a generic user name, clear it
+ if (generic_plname())
+ *svp.plname = '\0';
+ name->setText(svp.plname);
+ connect(name, SIGNAL(textChanged(const QString&)),
+ this, SLOT(selectName(const QString&)));
+ name->setFocus();
+
+ // changed to move gender and alignment labels inside their boxes (below)
+ QGroupBox *genderbox = new QGroupBox();
+ QButtonGroup *gendergroup = new QButtonGroup(this);
+ QGroupBox *alignbox = new QGroupBox();
+ QButtonGroup *aligngroup = new QButtonGroup(this);
+ // these two QVBoxLayout pointers aren't used, the vertical box layouts
+ // being assigned to them are...
+ QVBoxLayout* vbgb UNUSED = new QVBoxLayout(genderbox);
+ QVBoxLayout* vbab UNUSED = new QVBoxLayout(alignbox);
+ char versionbuf[QBUFSZ];
+ QLabel *logo = new QLabel(QString(nh_attribution).arg(
+ version_string(versionbuf, sizeof versionbuf)), this);
+
+ l->addWidget( namebox, 0,0,1,3 );
+ role = new NhPSListView(this);
+ race = new NhPSListView(this);
+#ifdef QT_CHOOSE_RACE_FIRST
+ l->addWidget( race, 1,0,6,1 );
+ l->addWidget( role, 1,1,6,1 );
+#else
+ l->addWidget( role, 1,0,6,1 );
+ l->addWidget( race, 1,1,6,1 );
+#endif
+
+ l->addWidget( genderbox, 1, 2 );
+ l->addWidget( alignbox, 2, 2 );
+ l->addWidget( logo, 3, 2, Qt::AlignCenter );
+ l->setRowStretch( 3, 6 );
+
+ QTableWidgetItem *item;
+ int i, nrole, nrace;
+
+ chosen_gend = flags.initgend;
+ chosen_align = flags.initalign;
+
+ // XXX QListView unsorted goes in rev.
+ for (nrole=0; roles[nrole].name.m; nrole++)
+ ;
+ role->setRowCount(nrole);
+ for (i = 0; i < nrole; ++i) {
+ item = new QTableWidgetItem();
+ role->setItem(i, 0, item);
+
+ if (roles[i].mnum == PM_CLERIC)
+ cleric_role_row = i; // for populate_races()
+ }
+
+ for (nrace=0; races[nrace].noun; nrace++)
+ ;
+ race->setRowCount(nrace);
+ for (i = 0; i < nrace; ++i) {
+ item = new QTableWidgetItem();
+ race->setItem(i, 0, item);
+
+ if (races[i].mnum == PM_HUMAN)
+ human_race_row = i; // (always i==0) for populate_roles()
+ }
+
+#ifdef QT_CHOOSE_RACE_FIRST
+ populate_races();
+ populate_roles();
+#else
+ populate_roles();
+ populate_races();
+#endif
+
+ connect(role, SIGNAL(currentCellChanged(int, int, int, int)),
+ this, SLOT(selectRole(int, int, int, int)));
+ role->setHorizontalHeaderLabels(QStringList("Role"));
+ role->resizeColumnToContents(0);
+
+ connect(race, SIGNAL(currentCellChanged(int, int, int, int)),
+ this, SLOT(selectRace(int, int, int, int)));
+ race->setHorizontalHeaderLabels(QStringList("Race"));
+ race->resizeColumnToContents(0);
+
+ // TODO:
+ // Render the alignment and gender labels smaller to match the
+ // horizontal header labels for role and race. (Getting the font from
+ // race table above and setting it for labels below made no difference.)
+
+ QLabel *gendlabel = new QLabel("Gender");
+ genderbox->layout()->addWidget(gendlabel);
+ gender = new QRadioButton*[ROLE_GENDERS];
+ for (i=0; ilayout()->addWidget(gender[i]);
+ gendergroup->addButton(gender[i], i);
+ }
+ connect(gendergroup, SIGNAL(buttonClicked(int)),
+ this, SLOT(selectGender(int)));
+
+ QLabel *alignlabel = new QLabel("Alignment");
+ alignbox->layout()->addWidget(alignlabel);
+ alignment = new QRadioButton*[ROLE_ALIGNS];
+ for (i=0; ilayout()->addWidget(alignment[i]);
+ aligngroup->addButton(alignment[i], i);
+ }
+ connect(aligngroup, SIGNAL(buttonClicked(int)),
+ this, SLOT(selectAlignment(int)));
+
+ l->addWidget(rand_btn, 4, 2);
+ connect(rand_btn, SIGNAL(clicked()), this, SLOT(Randomize()));
+ l->addWidget(play_btn, 5, 2);
+ connect(play_btn, SIGNAL(clicked()), this, SLOT(accept()));
+ l->addWidget(quit_btn, 6, 2);
+ connect(quit_btn, SIGNAL(clicked()), this, SLOT(reject()));
+ // if plname[] is non-empty, the Play button is enabled and the default;
+ // otherwise, Play is disabled and Quit is the default
+ plnamePlayVsQuit();
+
+ Randomize();
+}
+
+// update the role column in the PlayerSelector widget
+void
+NetHackQtPlayerSelector::populate_roles()
+{
+ //
+ // entry for each row in the role column shows a player-character tile
+ // (always gender-specific) and role's name (sometimes gender-specific)
+ //
+ QTableWidgetItem *item;
+ const char *rolename;
+ glyph_info gi;
+ int v, gf, gn = chosen_gend, al = chosen_align;
+ // if no race yet, we use human for gender check (gender doesn't affect
+ // race but we need a valid race when filtering Valkyrie out or back in)
+ int ra = race->currentRow(), hu = human_race_row;
+ bool is_f = (gn == 1);
+ NetHackQtGlyphs& glyphs = qt_settings->glyphs();
+ for (int i = 0; roles[i].name.m; ++i) {
+ rolename = (is_f && roles[i].name.f) ? roles[i].name.f
+ : roles[i].name.m;
+ gf = monnum_to_glyph(roles[i].mnum, is_f ? FEMALE : MALE);
+ map_glyphinfo(0, 0, gf, 0, &gi);
+ v = ((ra < 0 || validrace(i, ra))
+ && (gn < 0 || validgend(i, (ra >= 0) ? ra : hu, gn))
+ && (al < 0 || validalign(i, (ra >= 0) ? ra : hu, al)));
+ item = role->item(i, 0);
+ item->setText(rolename);
+ item->setIcon(QIcon(glyphs.glyph(gf, gi.gm.tileidx)));
+ item->setFlags(v ? Qt::ItemIsEnabled | Qt::ItemIsSelectable
+ : Qt::NoItemFlags);
+ }
+ role->repaint(); // role->update() seems to be inadequate
+}
+
+// update the race column in the PlayerSelector widget
+void
+NetHackQtPlayerSelector::populate_races()
+{
+ //
+ // entry for each row in race column shows race's generic monster tile
+ // (always gender-specific) and race's name (never gender-specific)
+ //
+ QTableWidgetItem *item;
+ glyph_info gi;
+ int v, gf, gn = chosen_gend, al = chosen_align;
+ // if no role yet, use cleric so that alignment won't rule anything out
+ int ro = role->currentRow(), cl = cleric_role_row;
+ bool is_f = (gn == 1);
+ NetHackQtGlyphs& glyphs = qt_settings->glyphs();
+ for (int j = 0; races[j].noun; ++j) {
+ gf = monnum_to_glyph(races[j].mnum, is_f ? FEMALE : MALE);
+ map_glyphinfo(0, 0, gf, 0, &gi);
+ v = ((ro < 0 || validrace(ro, j))
+ && (al < 0 || validalign((ro >= 0) ? ro : cl, j, al)));
+ item = race->item(j, 0);
+ item->setText(races[j].noun);
+ item->setIcon(QIcon(glyphs.glyph(gf, gi.gm.tileidx)));
+ item->setFlags(v ? Qt::ItemIsEnabled | Qt::ItemIsSelectable
+ : Qt::NoItemFlags);
+ }
+ race->repaint();
+}
+
+void NetHackQtPlayerSelector::Randomize()
+{
+ int nrole = role->rowCount();
+ int nrace = race->rowCount();
+
+ boolean picksomething = (flags.initrole == ROLE_NONE
+ || flags.initrace == ROLE_NONE
+ || flags.initgend == ROLE_NONE
+ || flags.initalign == ROLE_NONE);
+
+ if (flags.randomall && picksomething) {
+ if (flags.initrole == ROLE_NONE)
+ flags.initrole = ROLE_RANDOM;
+ if (flags.initrace == ROLE_NONE)
+ flags.initrace = ROLE_RANDOM;
+ if (flags.initgend == ROLE_NONE)
+ flags.initgend = ROLE_RANDOM;
+ if (flags.initalign == ROLE_NONE)
+ flags.initalign = ROLE_RANDOM;
+ }
+
+ rigid_role_checks();
+
+ // Randomize race and role, unless specified in config
+ int ro = flags.initrole;
+ if (ro == ROLE_NONE || ro == ROLE_RANDOM) {
+ ro = rn2(nrole);
+ if (flags.initrole != ROLE_RANDOM) {
+ fully_specified_role = false;
+ }
+ }
+ int ra = flags.initrace;
+ if (ra == ROLE_NONE || ra == ROLE_RANDOM) {
+ ra = rn2(nrace);
+ if (flags.initrace != ROLE_RANDOM) {
+ fully_specified_role = false;
+ }
+ }
+
+ // make sure we have a valid combination, honoring
+ // the user's request if possible.
+ bool choose_race_first;
+#ifdef QT_CHOOSE_RACE_FIRST
+ choose_race_first = true;
+ if (flags.initrole >= 0 && flags.initrace < 0) {
+ choose_race_first = false;
+ }
+#else
+ choose_race_first = false;
+ if (flags.initrace >= 0 && flags.initrole < 0) {
+ choose_race_first = true;
+ }
+#endif
+ while (!validrace(ro,ra)) {
+ if (choose_race_first) {
+ ro = rn2(nrole);
+ if (flags.initrole != ROLE_RANDOM) {
+ fully_specified_role = false;
+ }
+ } else {
+ ra = rn2(nrace);
+ if (flags.initrace != ROLE_RANDOM) {
+ fully_specified_role = false;
+ }
+ }
+ }
+
+ int g = flags.initgend;
+ if (g < 0) {
+ g = rn2(ROLE_GENDERS);
+ fully_specified_role = false;
+ }
+ while (!validgend(ro,ra,g)) {
+ g = rn2(ROLE_GENDERS);
+ }
+ gender[g]->setChecked(true);
+ selectGender(g);
+
+ int a = flags.initalign;
+ if (a < 0) {
+ a = rn2(ROLE_ALIGNS);
+ fully_specified_role = false;
+ }
+ while (!validalign(ro,ra,a)) {
+ a = rn2(ROLE_ALIGNS);
+ }
+ alignment[a]->setChecked(true);
+ selectAlignment(a);
+
+ role->setCurrentCell(ro, 0);
+
+ race->setCurrentCell(ra, 0);
+}
+
+// if plname[] is empty, disable [Play], otherwise [Play] is the default
+void NetHackQtPlayerSelector::plnamePlayVsQuit()
+{
+ if (*svp.plname) {
+ play_btn->setEnabled(true);
+ play_btn->setDefault(true);
+ //quit_btn->setDefault(false);
+ } else {
+ play_btn->setEnabled(false); // [Play] still visible but grayed out
+ //play_btn->setDefault(false);
+ quit_btn->setDefault(true);
+ }
+}
+
+// the line edit widget for the name field has received input
+void NetHackQtPlayerSelector::selectName(const QString& n)
+{
+ const char *name_str = n.toLatin1().constData();
+ // skip any leading spaces
+ // (it would be better to set up a validator that rejects leading spaces)
+ while (*name_str == ' ')
+ ++name_str;
+ str_copy(svp.plname, name_str, PL_NSIZ);
+ // possibly enable or disable the [Play] button
+ plnamePlayVsQuit();
+}
+
+void NetHackQtPlayerSelector::selectRole(int crow, int ccol,
+ int prow, int pcol)
+{
+ int ra = race->currentRow();
+ int ro = role->currentRow();
+ if (ra == -1 || ro == -1)
+ return;
+ QTableWidgetItem *item = role->item(prow, 0);
+ if (item != NULL)
+ item->setSelected(false);
+
+#ifdef QT_CHOOSE_RACE_FIRST
+ selectRace(crow, ccol, prow, pcol);
+#else
+ QTableWidgetItem *i = role->currentItem();
+ QTableWidgetItem *valid = 0;
+ for (int j = 0; roles[j].name.m; ++j) {
+ if (!valid && (ra < 0 || validrace(j, ra))) {
+ valid = role->item(j, 0);
+ break;
+ }
+ }
+ if (!validrace(role->currentRow(), ra))
+ i = valid;
+ role->setCurrentItem(i, 0);
+ for (int j = 0; roles[j].name.m; ++j) {
+ item = role->item(j, 0);
+ item->setSelected(item == i);
+ /* used to call setFlags here, but setupOthers() -> selectGender()
+ (and selectAlignment()) -> populate_roles() takes care of that */
+ }
+ nhUse(crow);
+ nhUse(ccol);
+ nhUse(pcol);
+#endif
+
+ //flags.initrole = role->currentRow();
+ setupOthers();
+}
+
+void NetHackQtPlayerSelector::selectRace(int crow, int ccol,
+ int prow, int pcol)
+{
+ int ra = race->currentRow();
+ int ro = role->currentRow();
+ if (ra == -1 || ro == -1)
+ return;
+ QTableWidgetItem *item = race->item(prow, 0);
+ if (item != NULL)
+ item->setSelected(false);
+
+#ifndef QT_CHOOSE_RACE_FIRST
+ selectRole(crow, ccol, prow, pcol);
+#else
+ QTableWidgetItem *i = race->currentItem();
+ QTableWidgetItem *valid = 0;
+ for (int j = 0; races[j].noun; ++j) {
+ if (!valid && (ro < 0 || validrace(ro, j))) {
+ valid = race->item(j, 0);
+ break;
+ }
+ }
+ if (!validrace(ro, race->currentRow()))
+ i = valid;
+ for (int j = 0; races[j].noun; ++j) {
+ item = race->item(j, 0);
+ item->setSelected(item == i);
+ /* used to call setFlags here, but setupOthers() -> selectGender()
+ (and selectAlignment()) -> populate_races() takes care of that */
+ }
+ nhUse(crow);
+ nhUse(ccol);
+ nhUse(pcol);
+#endif
+
+ //flags.initrace = race->currentRow();
+ setupOthers();
+}
+
+void NetHackQtPlayerSelector::setupOthers()
+{
+ int ro = role->currentRow();
+ int ra = race->currentRow();
+ int valid=-1;
+ int c=0;
+ int j;
+ for (j=0; jisChecked() )
+ c = j;
+ gender[j]->setEnabled(v);
+ if ( valid<0 && v ) valid = j;
+ }
+ if ( !validgend(ro,ra,c) )
+ c = valid;
+ int k;
+ for (k=0; ksetChecked(c==k);
+ }
+ selectGender(c);
+
+ valid=-1;
+ for (j=0; jisChecked() )
+ c = j;
+ alignment[j]->setEnabled(v);
+ if ( valid<0 && v ) valid = j;
+ }
+ if ( !validalign(ro,ra,c) )
+ c = valid;
+ for (k=0; ksetChecked(c==k);
+ }
+ selectAlignment(c);
+}
+
+void NetHackQtPlayerSelector::selectGender(int i)
+{
+ chosen_gend = i;
+ // if gender has changed, tiles and some role titles will change
+ populate_roles();
+ populate_races();
+}
+
+void NetHackQtPlayerSelector::selectAlignment(int i)
+{
+ chosen_align = i;
+ // if alignment has changed, some roles or races may no longer be
+ // available and some previously excluded ones might become available
+ populate_roles();
+ populate_races();
+}
+
+void NetHackQtPlayerSelector::Quit()
+{
+ done(R_Quit);
+}
+
+void NetHackQtPlayerSelector::Random()
+{
+ done(R_Rand);
+}
+
+bool NetHackQtPlayerSelector::Choose()
+{
+ if (fully_specified_role)
+ return true;
+
+#if defined(QWS) // probably safe with Qt 3, too (where show!=exec in QDialog).
+ if ( qt_compact_mode ) {
+ showMaximized();
+ } else
+#endif
+ {
+ adjustSize();
+ centerOnMain(this);
+ }
+
+ if ( exec() ) {
+ flags.initrace = race->currentRow();
+ flags.initrole = role->currentRow();
+ flags.initgend = chosen_gend;
+ flags.initalign = chosen_align;
+ return true;
+ } else {
+ return false;
+ }
+}
+
+} // namespace nethack_qt_
diff --git a/win/Qt4/qt4plsel.h b/win/Qt/qt_plsel.h
similarity index 72%
rename from win/Qt4/qt4plsel.h
rename to win/Qt/qt_plsel.h
index de070d147..a30133711 100644
--- a/win/Qt4/qt4plsel.h
+++ b/win/Qt/qt_plsel.h
@@ -2,12 +2,12 @@
// Qt4 conversion copyright (c) Ray Chason, 2012-2014.
// NetHack may be freely redistributed. See license for details.
-// qt4plsel.h -- player selector dialog
+// qt_plsel.h -- player selector dialog
#ifndef QT4PLSEL_H
#define QT4PLSEL_H
-namespace nethack_qt4 {
+namespace nethack_qt_ {
class NetHackQtKeyBuffer;
@@ -22,6 +22,10 @@ public slots:
void Quit();
void Random();
void Randomize();
+ void plnamePlayVsQuit();
+
+ void populate_roles();
+ void populate_races();
void selectName(const QString& n);
void selectRole(int current, int, int previous, int);
@@ -38,11 +42,18 @@ public slots:
QTableWidget* race;
QRadioButton **gender;
QRadioButton **alignment;
+
bool fully_specified_role;
int chosen_gend;
int chosen_align;
+ int cleric_role_row;
+ int human_race_row;
+
+ QPushButton *rand_btn;
+ QPushButton *play_btn;
+ QPushButton *quit_btn;
};
-} // namespace nethack_qt4
+} // namespace nethack_qt_
#endif
diff --git a/win/Qt/qt_post.h b/win/Qt/qt_post.h
new file mode 100644
index 000000000..6c783cf00
--- /dev/null
+++ b/win/Qt/qt_post.h
@@ -0,0 +1,17 @@
+/* NetHack 5.0 qt_post.h $NHDT-Date: 1597276832 2020/08/13 00:00:32 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.0 $ */
+
+/*
+ * qt_post.h -- reverse part of qt_pre.h.
+ *
+ * #include after .
+ */
+
+#if defined(__cplusplus)
+#ifdef __clang__
+#pragma clang diagnostic pop
+#elif defined(__GNUC__)
+#pragma GCC diagnostic pop
+#endif /* compiler-specific bits */
+#endif /* __cplusplus */
+
+/*qt_post.h*/
diff --git a/win/Qt/qt_pre.h b/win/Qt/qt_pre.h
new file mode 100644
index 000000000..1dddde25b
--- /dev/null
+++ b/win/Qt/qt_pre.h
@@ -0,0 +1,76 @@
+/* NetHack 5.0 qt_pre.h $NHDT-Date: 1597276835 2020/08/13 00:00:35 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.0 $ */
+
+/*
+ * qt_pre.h -- undefine some nethack macros which conflict with Qt headers.
+ *
+ * #include after "hack.h", before .
+ */
+
+#undef C // conflicts with Qt6 header
+#undef Invisible
+#undef Warning
+#undef msleep
+#undef wizard
+#undef min
+#undef max
+
+#ifdef NOT_C99
+#ifdef NEED_INDEX
+#undef index
+#endif
+#ifdef NEED_RINDX
+#undef rindex
+#endif
+#endif
+
+#if defined(__cplusplus)
+
+#ifdef __clang__
+#pragma clang diagnostic push
+#endif
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#endif
+/* the diagnostic pop is in qt_post.h */
+
+#ifdef __clang__
+/* disable warnings for shadowed names; some of the Qt prototypes use
+ placeholder argument names which conflict with nethack variables
+ ('u' and 'flags') */
+#pragma clang diagnostic ignored "-Wshadow"
+#elif defined(__GNUC__)
+#pragma GCC diagnostic ignored "-Wshadow"
+#endif
+
+#include
+
+/* QFontMetrics::width was deprecated in Qt 5.11 */
+#if QT_VERSION < QT_VERSION_CHECK(5, 11, 0)
+#define QFM_WIDTH(foo) width(foo)
+#else
+#define QFM_WIDTH(foo) horizontalAdvance(foo)
+#endif
+
+#if __cplusplus >= 202002L
+/* c++20 or newer */
+#if QT_VERSION < 0x060000
+/*
+ * qt5/QtWidgets/qsizepolicy.h
+ * Qt5 header file issue under c++ 20
+ *
+ * warning: bitwise operation between different enumeration types
+ * ‘QSizePolicy::Policy’ and ‘QSizePolicy::PolicyFlag’
+ * is deprecated [-Wdeprecated-enum-enum-conversion]
+ */
+#if defined(__GNUC__)
+#pragma GCC diagnostic ignored "-Wdeprecated-enum-enum-conversion"
+#endif
+#if defined(__clang__)
+#pragma clang diagnostic ignored "-Wdeprecated-enum-enum-conversion"
+#endif
+#endif /* QT_VERSION < 0x060000 */
+#endif /* __cplusplus >= 202002L */
+#endif /* __cplusplus */
+
+/*qt_pre.h*/
+
diff --git a/win/Qt4/qt4rip.cpp b/win/Qt/qt_rip.cpp
similarity index 70%
rename from win/Qt4/qt4rip.cpp
rename to win/Qt/qt_rip.cpp
index d509f8895..cb2873dba 100644
--- a/win/Qt4/qt4rip.cpp
+++ b/win/Qt/qt_rip.cpp
@@ -2,28 +2,23 @@
// Qt4 conversion copyright (c) Ray Chason, 2012-2014.
// NetHack may be freely redistributed. See license for details.
-// qt4rip.cpp -- tombstone window
+// qt_rip.cpp -- tombstone window
+extern "C" {
#include "hack.h"
-#undef Invisible
-#undef Warning
-#undef index
-#undef msleep
-#undef rindex
-#undef wizard
-#undef yn
-#undef min
-#undef max
+}
+#include "qt_pre.h"
#include
#if QT_VERSION >= 0x050000
#include
#endif
-#include "qt4rip.h"
-#include "qt4bind.h"
-#include "qt4str.h"
+#include "qt_post.h"
+#include "qt_rip.h"
+#include "qt_bind.h"
+#include "qt_str.h"
-namespace nethack_qt4 {
+namespace nethack_qt_ {
QPixmap* NetHackQtRIP::pixmap=0;
@@ -41,7 +36,7 @@ tryload(QPixmap& pm, const char* fn)
{
if (!pm.load(fn)) {
QString msg;
- msg.sprintf("Cannot load \"%s\"", fn);
+ msg = nh_qsprintf("Cannot load \"%s\"", fn);
QMessageBox::warning(NetHackQtBind::mainWidget(), "IO Error", msg);
}
}
@@ -69,7 +64,7 @@ QSize NetHackQtRIP::sizeHint() const
return pixmap->size();
}
-void NetHackQtRIP::paintEvent(QPaintEvent* event)
+void NetHackQtRIP::paintEvent(QPaintEvent* event UNUSED)
{
if ( riplines ) {
int pix_x=(width()-pixmap->width())/2;
@@ -84,11 +79,17 @@ void NetHackQtRIP::paintEvent(QPaintEvent* event)
painter.begin(this);
painter.drawPixmap(pix_x,pix_y,*pixmap);
for (int i=0; i= 202002L
+ static_cast(Qt::TextDontClip)
+ | static_cast(Qt::AlignHCenter),
+#else
+ Qt::TextDontClip|Qt::AlignHCenter,
+#endif
+ line[i]);
}
painter.end();
}
}
-} // namespace nethack_qt4
+} // namespace nethack_qt_
diff --git a/win/Qt4/qt4rip.h b/win/Qt/qt_rip.h
similarity index 84%
rename from win/Qt4/qt4rip.h
rename to win/Qt/qt_rip.h
index 792a4e32f..97670f0d0 100644
--- a/win/Qt4/qt4rip.h
+++ b/win/Qt/qt_rip.h
@@ -2,12 +2,12 @@
// Qt4 conversion copyright (c) Ray Chason, 2012-2014.
// NetHack may be freely redistributed. See license for details.
-// qt4rip.h -- tombstone window
+// qt_rip.h -- tombstone window
#ifndef QT4RIP_H
#define QT4RIP_H
-namespace nethack_qt4 {
+namespace nethack_qt_ {
class NetHackQtRIP : public QWidget {
private:
@@ -25,6 +25,6 @@ class NetHackQtRIP : public QWidget {
QSize sizeHint() const;
};
-} // namespace nethack_qt4
+} // namespace nethack_qt_
#endif
diff --git a/win/Qt/qt_set.cpp b/win/Qt/qt_set.cpp
new file mode 100644
index 000000000..2823e4dc0
--- /dev/null
+++ b/win/Qt/qt_set.cpp
@@ -0,0 +1,344 @@
+// Copyright (c) Warwick Allison, 1999.
+// Qt4 conversion copyright (c) Ray Chason, 2012-2014.
+// NetHack may be freely redistributed. See license for details.
+
+// qt_set.cpp -- Qt-specific settings, saved and restored by Qt so
+// persist not just across save/restore but into new games.
+
+extern "C" {
+#include "hack.h"
+}
+
+#include "qt_pre.h"
+#include
+#if QT_VERSION >= 0x050000
+#include
+#endif
+#include "qt_post.h"
+#include "qt_set.h"
+#include "qt_set.moc"
+#include "qt_glyph.h"
+#include "qt_main.h"
+#include "qt_bind.h"
+#include "qt_xcmd.h"
+#include "qt_str.h"
+
+// Dialog box accessed via "Qt Settings..." in the games menu (non-OSX)
+// or via "Preferences..." in the application menu (OSX):
+//--
+// "Qt NetHack Settings"
+// "Map:" [ ] Zoomed -- check box
+// tilewidth -- number entry spinner
+// tileheight -- ditto
+// "Invent:" [ ] Shown -- check box
+// dollwidth -- number entry spinner
+// dollheight -- ditto
+// "Font:" fontsize -- Huge:18pt, Large:14, Medium:12, Small:10, Tiny:8
+// [dismiss] -- button
+//--
+// Map remembers 2 size pairs, one for Zoomed unchecked, another for checked.
+// (Player controls whether the box is checked, using the dialog to manually
+// switch back and forth if desired; nothing forces the Zoomed setting to
+// specify larger tile size than not-Zoomed.)
+// Paper doll inventory subset is shown or suppressed depending on check box.
+// (It only remembers one tile size pair and that only matters when shown.
+// The size could be different from both map settings but it is highly
+// recommended that it match one of those unless Zoomed is never toggled.)
+// Font size is used for message window and for text in the status window.
+// (TODO: support separate font sizes for the two windows.)
+// There's no way to undo or avoid saving any changes which player makes but
+// all of the fields can be manually reversed.
+
+/* Used by tile/font-size patch below and in ../../src/files.c */
+char *qt_tilewidth=NULL;
+char *qt_tileheight=NULL;
+char *qt_fontsize=NULL;
+#if defined(QWS)
+int qt_compact_mode = 1;
+#else
+int qt_compact_mode = 0;
+#endif
+
+namespace nethack_qt_ {
+
+#define TILEWMIN 6
+#define TILEHMIN 6
+
+NetHackQtSettings::NetHackQtSettings() :
+ settings(),
+ whichsize("&Zoomed", this),
+ tilewidth(this),
+ tileheight(this),
+ widthlbl("Tile &width:", this),
+ heightlbl("Tile &height:", this),
+#ifdef ENHANCED_PAPERDOLL
+ dollshown("&Shown", this),
+ dollwidth(this),
+ dollheight(this),
+ dollwidthlbl("&Doll width:", this), // should "Doll tile width"...
+ dollheightlbl("Doll height:", this), // ...but that's too verbose
+#endif
+ fontsize(this),
+ normal("times"),
+#ifdef WS_WIN
+ normalfixed("courier new"),
+#else
+ normalfixed("courier"),
+#endif
+ large("times"),
+ small("times"),
+ theglyphs(0)
+{
+ int default_fontsize;
+
+ widthlbl.setBuddy(&tilewidth);
+ tilewidth.setRange(TILEWMIN, 128);
+ heightlbl.setBuddy(&tileheight);
+ tileheight.setRange(TILEHMIN, 128);
+ tilewidth.setValue(settings.value("tilewidth", 16).toInt());
+ tileheight.setValue(settings.value("tileheight", 16).toInt());
+#ifdef ENHANCED_PAPERDOLL
+ dollwidthlbl.setBuddy(&dollwidth);
+ dollwidth.setRange(TILEWMIN, 48);
+ dollheightlbl.setBuddy(&dollheight);
+ dollheight.setRange(TILEHMIN, 48);
+ dollwidth.setValue(settings.value("dollwidth", 32).toInt());
+ dollheight.setValue(settings.value("dollheight", 32).toInt());
+ doll_is_shown = settings.value("dollShown", true).toBool();
+ // needed the very first time
+ settings.setValue("dollShown", QVariant(doll_is_shown));
+#endif
+ default_fontsize = settings.value("fontsize", 2).toInt();
+
+ // these aren't currently part of the settings dialog; they're managed
+ // by the extended commands menu ('#' command) and updateXcmd() below
+ // but are included in qt_settings to be remembered across play sessions
+ xcmd_by_row = settings.value("xcmdByRow", false).toBool();
+ xcmd_set = settings.value("xcmdSet", all_cmds).toInt();
+
+ // Tile/font sizes read from .nethackrc
+ if (qt_tilewidth != NULL) {
+ tilewidth.setValue(atoi(qt_tilewidth));
+ free(qt_tilewidth);
+ qt_tilewidth = NULL;
+ }
+ if (qt_tileheight != NULL) {
+ tileheight.setValue(atoi(qt_tileheight));
+ free(qt_tileheight);
+ qt_tileheight = NULL;
+ }
+ if (qt_fontsize != NULL) {
+ switch (tolower(qt_fontsize[0])) {
+ case 'h': default_fontsize = 0; break;
+ case 'l': default_fontsize = 1; break;
+ case 'm': default_fontsize = 2; break;
+ case 's': default_fontsize = 3; break;
+ case 't': default_fontsize = 4; break;
+ }
+ free(qt_fontsize);
+ qt_fontsize = NULL;
+ }
+
+ theglyphs=new NetHackQtGlyphs();
+ if (!theglyphs->no_tiles) {
+ resizeTiles();
+
+ connect(&whichsize, SIGNAL(toggled(bool)), this,
+ SLOT(setGlyphSize(bool)));
+ connect(&tilewidth, SIGNAL(valueChanged(int)), this,
+ SLOT(resizeTiles()));
+ connect(&tileheight, SIGNAL(valueChanged(int)), this,
+ SLOT(resizeTiles()));
+
+#ifdef ENHANCED_PAPERDOLL
+ connect(&dollshown, SIGNAL(toggled(bool)), this,
+ SLOT(setDollShown(bool)));
+ connect(&dollwidth, SIGNAL(valueChanged(int)), this,
+ SLOT(resizeDoll()));
+ connect(&dollheight, SIGNAL(valueChanged(int)), this,
+ SLOT(resizeDoll()));
+#endif
+ } else {
+ // paper doll requires map tiles and those just failed to load
+ doll_is_shown = false;
+ }
+
+ fontsize.setMinimumContentsLength((int) strlen("Medium"));
+ fontsize.addItem("Huge");
+ fontsize.addItem("Large");
+ fontsize.addItem("Medium");
+ fontsize.addItem("Small");
+ fontsize.addItem("Tiny");
+ fontsize.setCurrentIndex(default_fontsize);
+ connect(&fontsize, SIGNAL(activated(int)), this, SLOT(changedFont()));
+
+ int row = 0; // used like X11-style XtSetArg(), ++argc
+ QGridLayout *grid = new QGridLayout(this);
+ // dialog box label, spans first two rows and all three columns
+ QLabel *settings_label = new QLabel("Qt NetHack Settings\n", this);
+ grid->addWidget(settings_label, row, 0, 2, 3), row += 2; // uses extra row
+ settings_label->setAlignment(Qt::AlignHCenter | Qt::AlignTop);
+
+ QLabel *map_label = new QLabel("&Map:", this);
+ map_label->setBuddy(&whichsize);
+ grid->addWidget(map_label, row, 0), // "Map: [ ]Zoomed"
+ grid->addWidget(&whichsize, row, 1), ++row;
+ grid->addWidget(&widthlbl, row, 1),
+ grid->addWidget(&tilewidth, row, 2), ++row;
+ grid->addWidget(&heightlbl, row, 1),
+ grid->addWidget(&tileheight, row, 2), ++row;
+
+#ifdef ENHANCED_PAPERDOLL
+ dollshown.QAbstractButton::setChecked(doll_is_shown);
+ QLabel *doll_label = new QLabel("&Invent:", this);
+ doll_label->setBuddy(&dollshown);
+ grid->addWidget(doll_label, row, 0), // "Invent: [ ]Shown"
+ grid->addWidget(&dollshown, row, 1), ++row;
+ grid->addWidget(&dollwidthlbl, row, 1),
+ grid->addWidget(&dollwidth, row, 2), ++row;
+ grid->addWidget(&dollheightlbl, row, 1),
+ grid->addWidget(&dollheight, row, 2), ++row;
+#endif
+
+ QLabel *flabel = new QLabel("&Font:", this);
+ flabel->setBuddy(&fontsize);
+ grid->addWidget(flabel, row, 0),
+ grid->addWidget(&fontsize, row, 1), ++row;
+
+ QPushButton *dismiss = new QPushButton("Dismiss", this);
+ dismiss->setDefault(true);
+ grid->addWidget(dismiss, row, 0, 1, 3), ++row;
+ grid->setRowStretch(row - 1, 0);
+ grid->setColumnStretch(1, 1);
+ grid->setColumnStretch(2, 2);
+ grid->activate();
+
+ connect(dismiss, SIGNAL(clicked()), this, SLOT(accept()));
+ resize(150, 140);
+}
+
+NetHackQtGlyphs& NetHackQtSettings::glyphs()
+{
+ // Caveat:
+ // 'theglyphs' will be Null if the tiles file couldn't be loaded;
+ // the game can still proceed with an ascii map in that situation.
+ return *theglyphs;
+}
+
+void NetHackQtSettings::changedFont()
+{
+ settings.setValue("fontsize", fontsize.currentIndex());
+ emit fontChanged();
+}
+
+void NetHackQtSettings::resizeTiles()
+{
+ tileWidth = tilewidth.value();
+ tileHeight = tileheight.value();
+
+ settings.setValue("tilewidth", tileWidth);
+ settings.setValue("tileheight", tileHeight);
+
+ if (theglyphs) {
+ theglyphs->setSize(tileWidth, tileHeight);
+ emit tilesChanged();
+ }
+}
+
+void NetHackQtSettings::toggleGlyphSize()
+{
+ whichsize.toggle();
+}
+
+void NetHackQtSettings::setGlyphSize(bool which UNUSED)
+{
+ QSize n = QSize(tilewidth.value(),tileheight.value());
+ if ( othersize.isValid() ) {
+ tilewidth.blockSignals(true);
+ tileheight.blockSignals(true);
+ tilewidth.setValue(othersize.width());
+ tileheight.setValue(othersize.height());
+ tileheight.blockSignals(false);
+ tilewidth.blockSignals(false);
+ resizeTiles();
+ }
+ othersize = n;
+}
+
+#ifdef ENHANCED_PAPERDOLL
+void NetHackQtSettings::resizeDoll()
+{
+ dollWidth = dollwidth.value();
+ dollHeight = dollheight.value();
+
+ settings.setValue("dollwidth", dollWidth);
+ settings.setValue("dollheight", dollHeight);
+ settings.setValue("dollShown", doll_is_shown);
+
+ //NetHackQtMainWindow::resizePaperDoll(doll_is_shown);
+ NetHackQtMainWindow *w = static_cast
+ (NetHackQtBind::mainWidget());
+ w->resizePaperDoll(doll_is_shown);
+}
+
+void NetHackQtSettings::toggleDollShown()
+{
+ dollshown.toggle();
+}
+
+void NetHackQtSettings::setDollShown(bool on_off)
+{
+ if (on_off != doll_is_shown) {
+ dollshown.QAbstractButton::setChecked(on_off);
+ doll_is_shown = on_off;
+ resizeDoll();
+ }
+}
+#endif
+
+// called from NetHackQtExtCmdRequestor::Retry()
+void NetHackQtSettings::updateXcmd(bool by_row, int which_set)
+{
+ // update 'settings' to have Qt store the revised values for next session
+ xcmd_by_row = by_row;
+ settings.setValue("xcmdByRow", QVariant(xcmd_by_row));
+ xcmd_set = which_set;
+ settings.setValue("xcmdSet", xcmd_set);
+}
+
+const QFont& NetHackQtSettings::normalFont()
+{
+ static int size[]={ 18, 14, 12, 10, 8 };
+ normal.setPointSize(size[fontsize.currentIndex()]);
+ return normal;
+}
+
+const QFont& NetHackQtSettings::normalFixedFont()
+{
+ static int size[]={ 18, 14, 13, 10, 8 };
+ normalfixed.setPointSize(size[fontsize.currentIndex()]);
+ return normalfixed;
+}
+
+const QFont& NetHackQtSettings::largeFont()
+{
+ static int size[]={ 24, 18, 14, 12, 10 };
+ large.setPointSize(size[fontsize.currentIndex()]);
+ return large;
+}
+
+const QFont& NetHackQtSettings::smallFont()
+{
+ static int size[]={ 14, 12, 10, 8, 8 };
+ small.setPointSize(size[fontsize.currentIndex()]);
+ return small;
+}
+
+bool NetHackQtSettings::ynInMessages()
+{
+ return !qt_compact_mode && !iflags.wc_popup_dialog;
+}
+
+NetHackQtSettings* qt_settings;
+
+} // namespace nethack_qt_
diff --git a/win/Qt/qt_set.h b/win/Qt/qt_set.h
new file mode 100644
index 000000000..99a2cf3cd
--- /dev/null
+++ b/win/Qt/qt_set.h
@@ -0,0 +1,95 @@
+// Copyright (c) Warwick Allison, 1999.
+// Qt4 conversion copyright (c) Ray Chason, 2012-2014.
+// NetHack may be freely redistributed. See license for details.
+
+// qt_set.h -- the Qt settings
+
+#ifndef QT4SET_H
+#define QT4SET_H
+
+#define ENHANCED_PAPERDOLL /* separate size from map tiles, can be hidden */
+
+#include "qt_bind.h" // needed for mainWidget() for updateInventory()
+
+namespace nethack_qt_ {
+
+class NetHackQtGlyphs;
+class NetHackQtMainWindow;
+
+class NetHackQtSettings : public QDialog {
+ Q_OBJECT
+public:
+ int tileWidth = 16, tileHeight = 16;
+#ifdef ENHANCED_PAPERDOLL
+ int dollWidth = 32, dollHeight = 32;
+ bool doll_is_shown = true;
+#endif
+ bool xcmd_by_row = false;
+ int xcmd_set = 0; // all_cmds
+
+ // dialog box for Qt-specific settings
+ NetHackQtSettings();
+
+ void updateXcmd(bool by_row, int which_set);
+
+ NetHackQtGlyphs& glyphs();
+ const QFont& normalFont();
+ const QFont& normalFixedFont();
+ const QFont& largeFont();
+ const QFont& smallFont();
+
+ bool ynInMessages();
+
+signals:
+ void fontChanged();
+ void tilesChanged();
+
+public slots:
+ void toggleGlyphSize();
+ void setGlyphSize(bool);
+#ifdef ENHANCED_PAPERDOLL
+ void toggleDollShown();
+ void setDollShown(bool);
+ void resizeDoll();
+#endif
+
+private:
+ QSettings settings;
+
+ QCheckBox whichsize;
+ QSpinBox tilewidth;
+ QSpinBox tileheight;
+ QLabel widthlbl;
+ QLabel heightlbl;
+ QSize othersize;
+#ifdef ENHANCED_PAPERDOLL
+ QCheckBox dollshown;
+ QSpinBox dollwidth;
+ QSpinBox dollheight;
+ QLabel dollwidthlbl;
+ QLabel dollheightlbl;
+#endif
+
+ QComboBox fontsize;
+
+ QFont normal, normalfixed, large, small;
+
+ NetHackQtGlyphs* theglyphs;
+#if 0
+ void updateInventory()
+ {
+ static_cast (NetHackQtBind::mainWidget())
+ ->updateInventory();
+ }
+#endif
+
+private slots:
+ void resizeTiles();
+ void changedFont();
+};
+
+extern NetHackQtSettings* qt_settings;
+
+} // namespace nethack_qt_
+
+#endif
diff --git a/win/Qt/qt_stat.cpp b/win/Qt/qt_stat.cpp
new file mode 100644
index 000000000..13aae4108
--- /dev/null
+++ b/win/Qt/qt_stat.cpp
@@ -0,0 +1,1088 @@
+// Copyright (c) Warwick Allison, 1999.
+// Qt4 conversion copyright (c) Ray Chason, 2012-2014.
+// NetHack may be freely redistributed. See license for details.
+
+// qt_stat.cpp -- status window, upper right portion of the overall window
+//
+// The Qt status window consists of many lines:
+//
+// hitpoint bar (when enabled)
+// Title (plname the Rank or plname the MonsterSpecies)
+// Dungeon location (branch and level)
+// separator line
+// six icons (special 40x40 tiles, paired with...)
+// six characteristic texts ("Str:18/03", "Dex:15", &c)
+// separator line
+// five status fields without icons (some containing two values:
+// HP/HPmax, Energy/Enmax, AC, XpLevel/ExpPoints or HD, [blank], Gold)
+// separator line
+// line with two optional text fields (Time:1234, Score:89), maybe blank
+// varying number of icons (one or more, each paired with...)
+// corresponding text (Alignment plus zero or more status conditions
+// including Hunger if not "normal" and encumbrance if not "normal")
+// and version description (text only) right justified (when enabled)
+//
+// The hitpoint bar spans the width of the status window when enabled.
+// Title and location are centered.
+// The icons and text for the six characteristics are evenly spaced;
+// this pair of lines is sometimes referred to as "row 1" below.
+// The five main stats or slash-separated stat pairs are padded with an
+// empty slot between Xp and Gold; adding the sixth makes that row
+// line up with the characteristics; this line is sometimes referred
+// to as "row 2".
+// Time and Score are spaced as if each were three fields wide; their
+// line is "row 3" relative to statuslines:2 vs statuslines:3.
+// Icons and texts for alignment and conditions are left justified.
+// The separator lines are thin and don't take up much vertical space.
+// When enabled, the hitpoint bar bisects the margin above Title,
+// increasing the overall status height by 9 pixels; when disabled,
+// the status shifts up by those 9 pixels.
+// When row 3 (Time, Score) is blank, it still takes up the vertical
+// space that would be used to show those values.
+//
+// The above is for statuslines:3, which used to be the default. For
+// statuslines:2, rows 1 and 2 are extended from six to seven fields
+// and row 3 (optional Time, Score) is eliminated. Alignment is
+// moved from the beginning of the Conditions pair (icon over text)
+// of lines up to the end of row 1, the Characteristics pair of lines,
+// with a separator between Cha:NN and it. Time, when active, is
+// placed after Gold. Score, if enabled and active, is shown in the
+// filler slot before Gold. When there are no Conditions to display,
+// there is an invisible fake one (blank icon over blank text)
+// rendered in order to preserve the vertical space they need.
+//
+// FIXME:
+// When hitpoint bar is shown, attempting to resize horizontally won't
+// do anything. Toggling it off, then resizing, and back On works.
+// (Caused by specifying min-width and max-width constraints in the
+// style sheets used to control color, but removing those constraints
+// causes the bar display to get screwed up.)
+// There are separate icons for Satiated and Hungry, but Weak, Fainting,
+// and Fainted all share the Hungry one. Weak should have its own,
+// Fainting+Fainted should have another. The current two depict
+// plates with cutlery which is a bit of an anachronism. Satiated
+// could be replaced by a figure in profile with a bulging belly,
+// Hungry similar but with a slightly concave belly, Weak either a
+// collapsing figure or a much larger concavity or both, Fainting/
+// Fainted a fully collapsed figure.
+// If 'version' is being shown but gets squeezed by the cumulative width
+// of conditions, the default clipping shows the center portion of the
+// text string with beginning and end omitted. We want to force the
+// end of the string to be shown with only the beginning omitted.
+//
+// TODO:
+// If/when status conditions become too wide for the status window, scale
+// down their icons and switch their text to a smaller font to match.
+// Title and Location are explicitly rendered with a bigger font than
+// the rest of status. That takes up more space, which is ok, but it
+// also increases the vertical margin in between them by more than is
+// necessary. Should squeeze some of that excess blank space out.
+//
+
+extern "C" {
+#include "hack.h"
+
+extern const char *const enc_stat[]; /* from botl.c */
+extern const char *const hu_stat[]; /* from eat.c */
+}
+
+#include "qt_pre.h"
+#include
+#if QT_VERSION >= 0x050000
+#include
+#endif
+#include "qt_post.h"
+#include "qt_stat.h"
+#include "qt_stat.moc"
+#include "qt_set.h"
+#include "qt_str.h"
+#include "qt_xpms.h"
+
+extern int qt_compact_mode;
+
+namespace nethack_qt_ {
+
+NetHackQtStatusWindow::NetHackQtStatusWindow() :
+ /* first three rows: hitpoint bar, title (plname the Rank), location */
+ hpbar_health(this),
+ hpbar_injury(this),
+ name(this,"(name)"),
+ dlevel(this,"(dlevel)"),
+ /* next two rows: icon over text label for the six characteristics */
+ str(this, "Str"),
+ dex(this, "Dex"),
+ con(this, "Con"),
+ intel(this, "Int"),
+ wis(this, "Wis"),
+ cha(this, "Cha"),
+ /* sixth row, text only: some contain two slash-separated values */
+ hp(this,"Hit Points"),
+ power(this,"Power"),
+ ac(this,"Armor Class"),
+ level(this,"Level"), // Xp level, with "/"+Exp points optionally appended
+ blank1(this, ""), // used for padding to align columns (was once 'exp')
+ gold(this,"Gold"), // gold used to be this row's first column, now last
+ /* seventh row: two optionally displayed values (just text, no icons) */
+ time(this,"Time"), // if 'time' option On
+ score(this,"Score"), // if SCORE_ON_BOTL defined and 'showscore' option On
+ /* last two rows: alignment followed by conditions (icons over text) */
+ align(this,"Alignment"),
+ blank2(this, " "), // used to prevent Conditions row from being empty
+ hunger(this,""),
+ encumber(this,""),
+ stoned(this,"Stone"), // major conditions
+ slimed(this,"Slime"),
+ strngld(this,"Strngl"),
+ sick_fp(this,"FoodPois"),
+ sick_il(this,"TermIll"),
+ stunned(this,"Stun"), // minor conditions
+ confused(this,"Conf"),
+ hallu(this,"Hallu"),
+ blind(this,"Blind"),
+ deaf(this,"Deaf"),
+ lev(this,"Lev"), // 'other' conditions
+ fly(this,"Fly"),
+ ride(this,"Ride"),
+ vers(this,""), // optional, right justified after 'conditions'
+ hline1(this), // separators
+ hline2(this),
+ hline3(this),
+ vline1(this), // vertical separator between Characteristics and Alignment
+ vline2(this), // padding for row 2 to match row 1's separator; not shown
+ /* miscellaneous; not display fields */
+ cursy(0),
+ first_set(true),
+ alreadyfullhp(false),
+ was_polyd(false),
+ had_exp(false),
+ had_score(false),
+ prev_versinfo(0U)
+{
+ if (!qt_compact_mode) {
+ int w = NetHackQtBind::mainWidget()->width();
+ setMaximumWidth(w / 2);
+ }
+ // for tool tips; they mostly work without this but sometimes changes
+ // to hunger or encumbrance seemed to cause tip display to stop
+ setMouseTracking(true);
+
+ p_str = QPixmap(str_xpm);
+ p_str = QPixmap(str_xpm);
+ p_dex = QPixmap(dex_xpm);
+ p_con = QPixmap(cns_xpm);
+ p_int = QPixmap(int_xpm);
+ p_wis = QPixmap(wis_xpm);
+ p_cha = QPixmap(cha_xpm);
+
+ p_chaotic = QPixmap(chaotic_xpm);
+ p_neutral = QPixmap(neutral_xpm);
+ p_lawful = QPixmap(lawful_xpm);
+ p_blank2 = QPixmap(blank_xpm);
+
+ p_satiated = QPixmap(satiated_xpm);
+ p_hungry = QPixmap(hungry_xpm);
+
+ p_encumber[0] = QPixmap(slt_enc_xpm);
+ p_encumber[1] = QPixmap(mod_enc_xpm);
+ p_encumber[2] = QPixmap(hvy_enc_xpm);
+ p_encumber[3] = QPixmap(ext_enc_xpm);
+ p_encumber[4] = QPixmap(ovr_enc_xpm);
+
+ p_stoned = QPixmap(stone_xpm);
+ p_slimed = QPixmap(slime_xpm);
+ p_strngld = QPixmap(strngl_xpm);
+ p_sick_fp = QPixmap(sick_fp_xpm);
+ p_sick_il = QPixmap(sick_il_xpm);
+ p_stunned = QPixmap(stunned_xpm);
+ p_confused = QPixmap(confused_xpm);
+ p_hallu = QPixmap(hallu_xpm);
+ p_blind = QPixmap(blind_xpm);
+ p_deaf = QPixmap(deaf_xpm);
+ p_lev = QPixmap(lev_xpm);
+ p_fly = QPixmap(fly_xpm);
+ p_ride = QPixmap(ride_xpm);
+
+ p_vers = QPixmap(blank_xpm); // same all-background pixmap as blank2
+
+ str.setIcon(p_str, "strength");
+ dex.setIcon(p_dex, "dexterity");
+ con.setIcon(p_con, "constitution");
+ intel.setIcon(p_int, "intelligence");
+ wis.setIcon(p_wis, "wisdom");
+ cha.setIcon(p_cha, "charisma");
+
+ align.setIcon(p_neutral);
+ blank2.setIcon(p_blank2); // used for spacing when Conditions row is empty
+ hunger.setIcon(p_hungry);
+ encumber.setIcon(p_encumber[0]);
+
+ stoned.setIcon(p_stoned, "turning to stone");
+ slimed.setIcon(p_slimed, "turning into slime");
+ strngld.setIcon(p_strngld, "being strangled");
+ sick_fp.setIcon(p_sick_fp, "severe food poisoning");
+ sick_il.setIcon(p_sick_il, "terminal illness");
+ stunned.setIcon(p_stunned, "stunned");
+ confused.setIcon(p_confused, "confused");
+ hallu.setIcon(p_hallu, "hallucinating");
+ blind.setIcon(p_blind, "cannot see");
+ deaf.setIcon(p_deaf, "cannot hear");
+ lev.setIcon(p_lev, "levitating");
+ fly.setIcon(p_fly, "flying");
+ ride.setIcon(p_ride, "riding");
+
+ vers.setIcon(p_vers); // used to align text-only version with conditions
+
+ // separator lines
+#if __cplusplus >= 202002L
+ hline1.setFrameStyle(static_cast(QFrame::HLine)
+ | static_cast(QFrame::Sunken));
+ hline2.setFrameStyle(static_cast(QFrame::HLine)
+ | static_cast(QFrame::Sunken));
+ hline3.setFrameStyle(static_cast(QFrame::HLine)
+ | static_cast(QFrame::Sunken));
+#else
+ hline1.setFrameStyle(QFrame::HLine | QFrame::Sunken);
+ hline2.setFrameStyle(QFrame::HLine | QFrame::Sunken);
+ hline3.setFrameStyle(QFrame::HLine | QFrame::Sunken);
+#endif
+ hline1.setLineWidth(1);
+ hline2.setLineWidth(1);
+ hline3.setLineWidth(1);
+ // vertical separators for condensed layout (statuslines:2)
+#if __cplusplus >= 202002L
+ vline1.setFrameStyle(static_cast(QFrame::VLine)
+ | static_cast(QFrame::Sunken));
+ vline2.setFrameStyle(static_cast(QFrame::VLine)
+ | static_cast(QFrame::Sunken));
+#else
+ vline1.setFrameStyle(QFrame::VLine | QFrame::Sunken);
+ vline2.setFrameStyle(QFrame::VLine | QFrame::Sunken);
+#endif
+ vline1.setLineWidth(1); // separates Alignment from Charisma
+ vline2.setLineWidth(1);
+ vline2.hide(); // padding to keep row 2 aligned with row 1, never shown
+
+ // when 'hitpointbar' is On, the bar gets drawn above name/title
+ QHBoxLayout *hpbar = InitHitpointBar();
+
+ // 'statuslines' takes a value of 2 or 3; we use 3 as a request to put
+ // Alignment in front of status conditions so that line is never empty
+ // and to show Time and/or Score on their own line which might be empty
+ boolean spreadout = (::iflags.wc2_statuslines != 2);
+
+#if 1 //RLC
+ name.setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum);
+ dlevel.setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum);
+ QVBoxLayout *vbox = new QVBoxLayout();
+ vbox->setSpacing(0);
+ vbox->addLayout(hpbar); // when 'hitpointbar' is enabled, it comes first
+ vbox->addWidget(&name);
+ vbox->addWidget(&dlevel);
+ vbox->addWidget(&hline1);
+ QHBoxLayout *charbox = new QHBoxLayout(); // Characteristics
+ charbox->addWidget(&str);
+ charbox->addWidget(&dex);
+ charbox->addWidget(&con);
+ charbox->addWidget(&intel);
+ charbox->addWidget(&wis);
+ charbox->addWidget(&cha);
+ if (!spreadout) {
+ // when condensed, include Alignment with Characteristics
+ charbox->addWidget(&vline1); // show a short vertical separator
+ charbox->addWidget(&align);
+ }
+ vbox->addLayout(charbox);
+ vbox->addWidget(&hline2);
+ QHBoxLayout *statbox = new QHBoxLayout(); // core status fields
+ statbox->addWidget(&hp);
+ statbox->addWidget(&power);
+ statbox->addWidget(&ac);
+ statbox->addWidget(&level);
+ if (spreadout) {
+ // when not condensed, put a blank field in front of Gold;
+ // Time and Score will be shown on their own separate line
+ statbox->addWidget(&blank1); // empty column #5 of 6
+ statbox->addWidget(&gold);
+ } else {
+ // when condensed, display Time and Score on HP,...,Gold row
+#ifndef SCORE_ON_BOTL
+ statbox->addWidget(&blank1); // empty column #5 of 7
+#else
+ statbox->addWidget(&score); // usually empty column #5
+#endif
+ statbox->addWidget(&gold); // columns 6 and maybe empty 7
+ statbox->addWidget(&vline2); // padding between 6 and 7; not shown
+ statbox->addWidget(&time);
+ }
+ vbox->addLayout(statbox);
+ vbox->addWidget(&hline3); // separator before Time+Score or Conditions
+ if (spreadout) {
+ // when not condensed, put Time and Score on an extra row; since
+ // they're both optionally displayed, their row might be empty
+ // TODO? when neither will be shown, set their heights smaller
+ // and if either gets toggled On, set height back to normal
+ QHBoxLayout *timebox = new QHBoxLayout();
+ timebox->addWidget(&time);
+ timebox->addWidget(&score);
+ vbox->addLayout(timebox);
+ }
+ QHBoxLayout *condbox = new QHBoxLayout(); // Conditions
+ if (spreadout) {
+ // when not condensed, include Alignment with Conditions to
+ // spread things out and also so that their row is never empty
+ condbox->addWidget(&align);
+ } else {
+ // otherwise place a padding widget on this row; it will be
+ // hidden if any Conditions are shown, or shown (with blank
+ // icon and empty text) when there aren't any, reserving
+ // space (the height of the row) for later conditions
+ condbox->addWidget(&blank2);
+ }
+ condbox->addWidget(&hunger);
+ condbox->addWidget(&encumber);
+ condbox->addWidget(&stoned);
+ condbox->addWidget(&slimed);
+ condbox->addWidget(&strngld);
+ condbox->addWidget(&sick_fp);
+ condbox->addWidget(&sick_il);
+ condbox->addWidget(&stunned);
+ condbox->addWidget(&confused);
+ condbox->addWidget(&hallu);
+ condbox->addWidget(&blind);
+ condbox->addWidget(&deaf);
+ condbox->addWidget(&lev);
+ condbox->addWidget(&fly);
+ condbox->addWidget(&ride);
+ condbox->setAlignment(Qt::AlignLeft | Qt::AlignVCenter);
+ // left justify conditions, whether 'vers' is present or absent
+ int stretch = 0;
+ condbox->addStretch(++stretch); // stretch==1
+ // to right justify 'vers', use bigger stretch than condbox separator
+ condbox->addWidget(&vers, ++stretch, // stretch==2
+ // text is below a blank icon, so bottom-aligned with the rest
+ // of the line with its text centered within that bottom area
+ Qt::AlignRight | Qt::AlignVCenter);
+ vbox->addLayout(condbox);
+ setLayout(vbox);
+#endif
+
+ connect(qt_settings, SIGNAL(fontChanged()), this, SLOT(doUpdate()));
+ doUpdate();
+}
+
+void NetHackQtStatusWindow::doUpdate()
+{
+ const QFont& large=qt_settings->largeFont();
+ name.setFont(large);
+ dlevel.setFont(large);
+
+ const QFont& normal=qt_settings->normalFont();
+ str.setFont(normal);
+ dex.setFont(normal);
+ con.setFont(normal);
+ intel.setFont(normal);
+ wis.setFont(normal);
+ cha.setFont(normal);
+ hp.setFont(normal);
+ power.setFont(normal);
+ ac.setFont(normal);
+ level.setFont(normal);
+ blank1.setFont(normal); // padding
+ gold.setFont(normal);
+ time.setFont(normal);
+ score.setFont(normal);
+ align.setFont(normal);
+ // blank2 is used as a dummy condition when Alignment has been moved
+ // elsewhere (statuslines:2) and no other conditions currently apply;
+ // it has a blank icon with a label of a single space (if the label
+ // is completely empty, the rest of status shifts down a little when
+ // one or more real conditions replace it and shifts up again when
+ // all conditions are removed and this one is reinstated--as if "" is
+ // slightly taller than " ")
+ blank2.setFont(normal);
+ hunger.setFont(normal);
+ encumber.setFont(normal);
+ stoned.setFont(normal);
+ slimed.setFont(normal);
+ strngld.setFont(normal);
+ sick_fp.setFont(normal);
+ sick_il.setFont(normal);
+ stunned.setFont(normal);
+ confused.setFont(normal);
+ hallu.setFont(normal);
+ blind.setFont(normal);
+ deaf.setFont(normal);
+ lev.setFont(normal);
+ fly.setFont(normal);
+ ride.setFont(normal);
+ vers.setFont(normal); // shouldn't need small font
+
+ updateStats();
+}
+
+QWidget* NetHackQtStatusWindow::Widget() { return this; }
+
+void NetHackQtStatusWindow::Clear()
+{
+}
+void NetHackQtStatusWindow::Display(bool block UNUSED)
+{
+}
+void NetHackQtStatusWindow::CursorTo(int,int y)
+{
+ cursy=y;
+}
+void NetHackQtStatusWindow::PutStr(int attr UNUSED, const QString& text UNUSED)
+{
+ // do a complete update when line 0 is done (as per X11 fancy status)
+ if (cursy==0) updateStats();
+}
+
+#if 0 // RLC
+void NetHackQtStatusWindow::resizeEvent(QResizeEvent*)
+{
+#if 0
+ const float SP_name=0.13; // the (large)
+ const float SP_dlev=0.13; // Level 3 in The Dungeons of Doom (large)
+ const float SP_atr1=0.25; // STR DEX CON INT WIS CHA
+ const float SP_hln1=0.02; // ---
+ const float SP_atr2=0.09; // Au HP PW AC LVL EXP
+ const float SP_hln2=0.02; // ---
+ const float SP_time=0.09; // time score
+ const float SP_hln3=0.02; // ---
+ const float SP_stat=0.25; // Alignment, Poisoned, Hungry, Sick, etc.
+
+ int h=height();
+ int x=0,y=0;
+
+ int iw; // Width of an item across line
+ int lh; // Height of a line of values
+
+ lh=int(h*SP_name);
+ name.setGeometry(0,0,width(),lh); y+=lh;
+ lh=int(h*SP_dlev);
+ dlevel.setGeometry(0,y,width(),lh); y+=lh;
+
+ lh=int(h*SP_hln1);
+ hline1.setGeometry(0,y,width(),lh); y+=lh;
+
+ lh=int(h*SP_atr1);
+ iw=width()/6;
+ str.setGeometry(x,y,iw,lh); x+=iw;
+ dex.setGeometry(x,y,iw,lh); x+=iw;
+ con.setGeometry(x,y,iw,lh); x+=iw;
+ intel.setGeometry(x,y,iw,lh); x+=iw;
+ wis.setGeometry(x,y,iw,lh); x+=iw;
+ cha.setGeometry(x,y,iw,lh); x+=iw;
+ x=0; y+=lh;
+
+ lh=int(h*SP_hln2);
+ hline2.setGeometry(0,y,width(),lh); y+=lh;
+
+ lh=int(h*SP_atr2);
+ iw=width()/6;
+ gold.setGeometry(x,y,iw,lh); x+=iw;
+ hp.setGeometry(x,y,iw,lh); x+=iw;
+ power.setGeometry(x,y,iw,lh); x+=iw;
+ ac.setGeometry(x,y,iw,lh); x+=iw;
+ level.setGeometry(x,y,iw,lh); x+=iw;
+ //exp.setGeometry(x,y,iw,lh); x+=iw;
+ x=0; y+=lh;
+
+ lh=int(h*SP_hln3);
+ hline3.setGeometry(0,y,width(),lh); y+=lh;
+
+ lh=int(h*SP_time);
+ iw=width()/3; x+=iw/2;
+ time.setGeometry(x,y,iw,lh); x+=iw;
+ score.setGeometry(x,y,iw,lh); x+=iw;
+ x=0; y+=lh;
+
+ lh=int(h*SP_stat);
+ iw=width()/9;
+ align.setGeometry(x,y,iw,lh); x+=iw;
+ hunger.setGeometry(x,y,iw,lh); x+=iw;
+ encumber.setGeometry(x,y,iw,lh); x+=iw;
+ stoned.setGeometry(x,y,iw,lh); x+=iw;
+ slimed.setGeometry(x,y,iw,lh); x+=iw;
+ strngld.setGeometry(x,y,iw,lh); x+=iw;
+ sick_fp.setGeometry(x,y,iw,lh); x+=iw;
+ sick_il.setGeometry(x,y,iw,lh); x+=iw;
+ stunned.setGeometry(x,y,iw,lh); x+=iw;
+ confused.setGeometry(x,y,iw,lh); x+=iw;
+ hallu.setGeometry(x,y,iw,lh); x+=iw;
+ blind.setGeometry(x,y,iw,lh); x+=iw;
+ deaf.setGeometry(x,y,iw,lh); x+=iw;
+ lev.setGeometry(x,y,iw,lh); x+=iw;
+ fly.setGeometry(x,y,iw,lh); x+=iw;
+ ride.setGeometry(x,y,iw,lh); x+=iw;
+#if 0
+ // [not fully implemented; this big chunk of code is no longer used]
+ //X = [get version, set font, measure width of version string]
+ vers.setGeometry(width() - X, y, width(), lh); x=width();
+#endif
+ x=0; y+=lh;
+#else
+ // This is clumsy. But QLayout objects are proving balky.
+
+ int row[10];
+
+ row[0] = name.sizeHint().height();
+ row[1] = dlevel.sizeHint().height();
+ row[2] = h.sizeHint().height();
+#endif
+}
+#endif
+
+
+/*
+ * Set all widget values to a null string. This is used after all spacings
+ * have been calculated so that when the window is popped up we don't get all
+ * kinds of funny values being displayed. [Actually it isn't used at all.]
+ */
+void NetHackQtStatusWindow::nullOut()
+{
+}
+
+void NetHackQtStatusWindow::fadeHighlighting()
+{
+ name.dissipateHighlight();
+ dlevel.dissipateHighlight();
+
+ str.dissipateHighlight();
+ dex.dissipateHighlight();
+ con.dissipateHighlight();
+ intel.dissipateHighlight();
+ wis.dissipateHighlight();
+ cha.dissipateHighlight();
+
+ gold.dissipateHighlight();
+ hp.dissipateHighlight();
+ power.dissipateHighlight();
+ ac.dissipateHighlight();
+ level.dissipateHighlight();
+ align.dissipateHighlight();
+
+ //time.dissipateHighlight();
+ score.dissipateHighlight();
+ //vers.dissipateHighlight(); // never gets highlighted
+
+ hunger.dissipateHighlight();
+ encumber.dissipateHighlight();
+ stoned.dissipateHighlight();
+ slimed.dissipateHighlight();
+ strngld.dissipateHighlight();
+ sick_fp.dissipateHighlight();
+ sick_il.dissipateHighlight();
+ stunned.dissipateHighlight();
+ confused.dissipateHighlight();
+ hallu.dissipateHighlight();
+ blind.dissipateHighlight();
+ deaf.dissipateHighlight();
+ lev.dissipateHighlight();
+ fly.dissipateHighlight();
+ ride.dissipateHighlight();
+}
+
+// hitpointbar: two panels: left==current health, right==missing max health
+QHBoxLayout *NetHackQtStatusWindow::InitHitpointBar()
+{
+ hpbar_health.setFrameStyle(QFrame::NoFrame);
+ hpbar_health.setMaximumHeight(9);
+ hpbar_health.setAutoFillBackground(true);
+ if (!iflags.wc2_hitpointbar)
+ hpbar_health.hide();
+
+ hpbar_injury.setFrameStyle(QFrame::NoFrame);
+ /* health portion has thickness 9, injury portion just 3 */
+ hpbar_injury.setMaximumHeight(3);
+ hpbar_injury.setContentsMargins(0, 3, 0, 3); // left,top,right,bottom
+ hpbar_injury.setAutoFillBackground(true);
+ hpbar_injury.hide(); // only shown when hitpointbar is On and uhp < uhpmax
+
+ QHBoxLayout *hpbar = new QHBoxLayout;
+ hpbar->setSpacing(0);
+#if QT_VERSION < 0x060000
+ hpbar->setMargin(0);
+#endif
+ hpbar->addWidget(&hpbar_health);
+ hpbar->setAlignment(&hpbar_health, Qt::AlignLeft);
+ hpbar->addWidget(&hpbar_injury);
+ hpbar->setAlignment(&hpbar_injury, Qt::AlignRight);
+ return hpbar; // caller will add our result to vbox layout
+}
+
+DISABLE_WARNING_FORMAT_NONLITERAL
+
+// when hitpoint bar is enabled, calculate and draw it, otherwise remove it
+void NetHackQtStatusWindow::HitpointBar()
+{
+ // a style sheet is used to specify color for otherwise blank labels;
+ // barcolors[][*]: column [0=left] is current health, [1=right] is injury
+ static const char
+ *styleformat = "QLabel { background-color : %s ; color : transparent ;"
+ " min-width : %d ; max-width %d }",
+ *barcolors[6][2] = {
+ { "black", "black" }, // 100% /* second black never shown */
+ { "blue", "darkBlue" }, //75..99
+ /* gray is darker than darkGray for some reason (at least on OSX);
+ default green is too dark compared to blue, yellow, orange,
+ and red so is changed here to green.lighter(150) */
+ { "#00c000", "gray" }, //50..74 /* "green"=="#008000" */
+ { "yellow", "darkGray" }, //25..49
+ { "orange", "lightGray" }, //10..24
+ { "red", "white" }, // 0..9
+ };
+
+ /*
+ * tty and curses use inverse video characters in the left portion
+ * of the name+rank string to reflect hero's health. We draw a
+ * separate line above the name+rank field instead. The left side
+ * of the line indicates current health. The right side is only
+ * shown when injured and indicates missing amount of maximum health.
+ */
+ if (iflags.wc2_hitpointbar) {
+ int colorindx, w,
+ ihp = Upolyd ? u.mh : u.uhp,
+ ihpmax = Upolyd ? u.mhmax : u.uhpmax;
+ ihp = std::max(std::min(ihp, ihpmax), 0);
+ int pct = 100 * ihp / ihpmax,
+ lox = hline1.x(),
+ hix = lox + hline1.width() - 1;
+ QRect geoH = hpbar_health.geometry(),
+ geoI = hpbar_injury.geometry();
+ QString styleH, styleI;
+
+ if (ihp < ihpmax) {
+ // health is less than full;
+ // use red for extreme low health even if the percentage is
+ // above the usual threshold (which will happen when maximum
+ // health is very low); do a similar threshold override for
+ // orange even though it can be distracting for low level hero
+ colorindx = (pct < 10 || ihp < 5) ? 5 // red | white
+ : (pct < 25 || ihp < 10 ) ? 4 // orange | lightGray
+ : (pct < 50) ? 3 // yellow | darkGray*
+ : (pct < 75) ? 2 // green | gray*
+ : 1; // blue | darkBlue
+
+ int pxl_health = (hix - lox + 1) * ihp / ihpmax;
+ geoH.setRight(std::min(lox + pxl_health - 1, hix));
+ hpbar_health.setGeometry(geoH);
+ w = geoH.right() - geoH.left() + 1; // might yield 0 (ie, if dead)
+ styleH = nh_qsprintf(styleformat, barcolors[colorindx][0], w, w);
+ hpbar_health.setStyleSheet(styleH);
+ // when healing, having the old injury-side shown while the new
+ // health-side expands pushes the injury farther right and it's
+ // momentarily visible there before it gets recalculated+redrawn
+ hpbar_injury.hide(); // will re-show below
+ hpbar_health.show(); // don't need to hide() if/when width is 0
+
+ int oldleft = geoI.left();
+ geoI.setLeft(geoH.right() + 1);
+ geoI.setRight(hix);
+ hpbar_injury.setGeometry(geoI);
+ w = geoI.right() - geoI.left() + 1;
+ styleI = nh_qsprintf(styleformat, barcolors[colorindx][1], w, w);
+ hpbar_injury.setStyleSheet(styleI);
+ if (geoI.left() != oldleft)
+ hpbar_injury.move(geoI.left(), geoI.top());
+ hpbar_injury.show();
+
+ alreadyfullhp = false;
+ } else if (!alreadyfullhp) { // skip if unchanged
+ // health is full
+ colorindx = 0; // black | (not used)
+
+ hpbar_injury.hide();
+ geoI.setLeft(hix); // hix + 1
+ hpbar_injury.setGeometry(geoI);
+
+ geoH.setRight(hix);
+ hpbar_health.setGeometry(geoH);
+ w = geoH.right() - geoH.left() + 1;
+ styleH = nh_qsprintf(styleformat, barcolors[colorindx][0], w, w);
+ hpbar_health.setStyleSheet(styleH);
+ hpbar_health.show();
+
+ alreadyfullhp = true;
+ }
+ } else {
+ // hitpoint bar is disabled
+ hpbar_health.hide();
+ hpbar_injury.hide();
+ alreadyfullhp = false;
+ }
+}
+
+RESTORE_WARNING_FORMAT_NONLITERAL
+
+/*
+ * Update the displayed status. The current code in botl.c updates
+ * two lines of information. Both lines are always updated one after
+ * the other. So only do our update when we update the second line.
+ *
+ * Information on the first line:
+ * name, Str/Dex/&c characteristics, alignment, score
+ *
+ * Information on the second line:
+ * dlvl, gold, hp, power, ac, {level & exp or HD **}
+ * status (hunger, encumbrance, sick, stun, conf, halu, blind), time
+ *
+ * [**] HD is shown instead of level and exp when hero is polymorphed.
+ */
+void NetHackQtStatusWindow::updateStats()
+{
+ if (!parentWidget()) return;
+ if (cursy != 0) return; /* do a complete update when line 0 is done */
+
+ QString buf;
+
+ if (first_set) {
+ // set toggle-detection flags for optional fields
+ was_polyd = Upolyd ? true : false;
+ had_exp = ::flags.showexp ? true : false;
+ // not conditionalized upon '#ifdef SCORE_ON_BOTL' here
+ had_score = ::flags.showscore ? true : false; // false when disabled
+ score.setLabel(""); // init if enabled, one-time set if disabled
+ }
+ // display hitpoint bar if it is active; it isn't subject to field
+ // highlighting so we don't track whether it has just been toggled On|Off
+ HitpointBar();
+
+ int st = ACURR(A_STR);
+ if (st > STR18(100)) {
+ buf = nh_qsprintf("Str:%d", st - 100); // 19..25
+ } else if (st == STR18(100)) {
+ buf = nh_qsprintf("Str:18/**"); // 18/100
+ } else if (st > 18) {
+ buf = nh_qsprintf("Str:18/%02d", st - 18); // 18/01..18/99
+ } else {
+ buf = nh_qsprintf("Str:%d", st); // 3..18
+ }
+ str.setLabel(buf, NetHackQtLabelledIcon::NoNum, (long) st);
+ dex.setLabel("Dex:", (long) ACURR(A_DEX));
+ con.setLabel("Con:", (long) ACURR(A_CON));
+ intel.setLabel("Int:", (long) ACURR(A_INT));
+ wis.setLabel("Wis:", (long) ACURR(A_WIS));
+ cha.setLabel("Cha:", (long) ACURR(A_CHA));
+
+ boolean spreadout = (::iflags.wc2_statuslines != 2);
+ int k = 0; // number of conditions shown
+
+ long qt_uhs = 0L;
+ const char *hung = hu_stat[u.uhs];
+ QString qhung = QString(hung).trimmed();
+ if (hung[0]==' ') {
+ if (!hunger.isHidden()) {
+ hunger.setLabel("", NetHackQtLabelledIcon::NoNum, qt_uhs);
+ hunger.hide();
+ }
+ } else {
+ // satiated is worse (due to risk of death from overeating)
+ // than not-hungry and we'll treat it as also worse than hungry,
+ // but better than weak or fainting; the u.uhs enum values
+ // order them differently so we jump through a hoop
+ switch (u.uhs) {
+ case NOT_HUNGRY: qt_uhs = 0L; break;
+ case HUNGRY: qt_uhs = 1L; break;
+ case SATIATED: qt_uhs = 2L; break;
+ case WEAK: qt_uhs = 3L; break;
+ case FAINTING: qt_uhs = 4L; break;
+ default: qt_uhs = 5L; break; // fainted, starved
+ }
+ hunger.setIcon(u.uhs ? p_hungry : p_satiated, qhung.toLower());
+ hunger.setLabel(qhung, NetHackQtLabelledIcon::NoNum, qt_uhs);
+ hunger.ForceResize();
+ ++k, hunger.show();
+ }
+ long encindx = (long) near_capacity();
+ const char *enc = enc_stat[encindx];
+ if (enc[0]==' ' || !enc[0]) {
+ if (!encumber.isHidden()) {
+ encumber.setLabel("", NetHackQtLabelledIcon::NoNum, encindx);
+ encumber.hide();
+ }
+ } else {
+ encumber.setIcon(p_encumber[encindx - 1], QString(enc).toLower());
+ encumber.setLabel(enc, NetHackQtLabelledIcon::NoNum, encindx);
+ encumber.ForceResize();
+ ++k, encumber.show();
+ }
+
+ if (Stoned) ++k, stoned.show(); else stoned.hide();
+ if (Slimed) ++k, slimed.show(); else slimed.hide();
+ if (Strangled) ++k, strngld.show(); else strngld.hide();
+ if (Sick) {
+ /* FoodPois or TermIll or both */
+ if (u.usick_type & SICK_VOMITABLE) { /* food poisoning */
+ ++k, sick_fp.show();
+ } else {
+ sick_fp.hide();
+ }
+ if (u.usick_type & SICK_NONVOMITABLE) { /* terminally ill */
+ ++k, sick_il.show();
+ } else {
+ sick_il.hide();
+ }
+ } else {
+ sick_fp.hide();
+ sick_il.hide();
+ }
+ if (Stunned) ++k, stunned.show(); else stunned.hide();
+ if (Confusion) ++k, confused.show(); else confused.hide();
+ if (Hallucination) ++k, hallu.show(); else hallu.hide();
+ if (Blind) ++k, blind.show(); else blind.hide();
+ if (Deaf) ++k, deaf.show(); else deaf.hide();
+
+ // flying is blocked when levitating, so Lev and Fly are mutually exclusive
+ if (Levitation) ++k, lev.show(); else lev.hide();
+ if (Flying) ++k, fly.show(); else fly.hide();
+ if (u.usteed) ++k, ride.show(); else ride.hide();
+
+ // version is optional; displayed to the right of conditions when present
+ if (::flags.showvers) {
+ // the value only changes if user modifies the 'versinfo' option
+ if (::flags.versinfo != prev_versinfo) {
+ char vbuf[80], *cvers = status_version(vbuf, sizeof vbuf, FALSE);
+ vers.setLabel(QString(cvers));
+ // FIXME: this shouldn't be necessary but without hide() before
+ // forthcoming show(), the new value isn't appearing
+ if (!vers.isHidden()) vers.hide();
+ prev_versinfo = ::flags.versinfo;
+ }
+ ++k, vers.show();
+ } else
+ vers.hide();
+
+ if (Upolyd) {
+ buf = nh_capitalize_words(pmname(&mons[u.umonnum],
+ ::flags.female ? FEMALE : MALE));
+ } else {
+ buf = rank_of(u.ulevel, svp.pl_character[0], ::flags.female);
+ }
+ QString buf2;
+ char buf3[BUFSZ];
+ buf2 = nh_qsprintf("%s the %s", upstart(strcpy(buf3, svp.plname)),
+ buf.toLatin1().constData());
+ name.setLabel(buf2, NetHackQtLabelledIcon::NoNum, u.ulevel);
+
+ if (!describe_level(buf3, 0)) {
+ Sprintf(buf3, "%s, level %d",
+ svd.dungeons[u.uz.dnum].dname, ::depth(&u.uz));
+ }
+ dlevel.setLabel(buf3);
+
+ int poly_toggled = !was_polyd ^ !Upolyd;
+ int exp_toggled = !had_exp ^ !::flags.showexp;
+ if (poly_toggled)
+ // for this update, changed values aren't better|worse, just different
+ hp.setCompareMode(NeitherIsBetter);
+ if (poly_toggled || exp_toggled)
+ level.setCompareMode(NeitherIsBetter);
+ if (Upolyd) {
+ // You're a monster!
+ buf = nh_qsprintf("/%d", u.mhmax);
+ hp.setLabel("HP:", std::max((long) u.mh, 0L), buf);
+ level.setLabel("HD:", (long) mons[u.umonnum].mlevel); // hit dice
+ // Exp points are not shown when HD is displayed instead of Xp level
+ } else {
+ // You're normal.
+ buf = nh_qsprintf("/%d", u.uhpmax);
+ hp.setLabel("HP:", std::max((long) u.uhp, 0L), buf);
+ // if Exp points are to be displayed, append them to Xp level;
+ // up/down highlighting becomes tricky--don't try very hard;
+ // depending upon font size and status layout, "Level:NN/nnnnnnnn"
+ // might be too wide to fit
+ static const char *const lvllbl[3] = { "Level:", "Lvl:", "L:" };
+ QFontMetrics fm(level.label->font());
+ for (int i = ::flags.showexp ? 0 : 3; i < 4; ++i) {
+ // passes 0,1,2 are with Exp, 3 is without Exp and always fits
+ if (i < 3) {
+ buf = nh_qsprintf("%s%ld/%ld", lvllbl[i], (long) u.ulevel,
+ u.uexp);
+ } else {
+ buf = nh_qsprintf("%s%ld", lvllbl[i - 3], (long) u.ulevel);
+ }
+ // +2: allow a couple of pixels at either end to be clipped off
+ if (fm.size(0, buf).width() <= (2 + level.label->width() + 2))
+ break;
+ }
+ level.setLabel(buf, NetHackQtLabelledIcon::NoNum,
+ // if we intended to show Exp but must settle
+ // for Xp due to width, we still want to use
+ // Exp for setLabel()'s Up|Down highlighting
+ ::flags.showexp ? u.uexp : (long) u.ulevel);
+ }
+ if (poly_toggled)
+ // for next update, changed values will be better|worse as usual
+ hp.setCompareMode(BiggerIsBetter);
+ if (poly_toggled || exp_toggled)
+ level.setCompareMode(BiggerIsBetter);
+ was_polyd = Upolyd ? true : false;
+ had_exp = (::flags.showexp && !was_polyd) ? true : false;
+
+ buf = nh_qsprintf("/%d", u.uenmax);
+ power.setLabel("Pow:", (long) u.uen, buf);
+ ac.setLabel("AC:", (long) u.uac);
+ // gold prefix used to be "Au:", tty uses "$:"; never too wide to fit;
+ // practical limit due to carrying capacity limit is less than 300K
+ long goldamt = money_cnt(gi.invent);
+ goldamt = std::max(goldamt, 0L); // sanity; core's botl() does likewise
+ goldamt = std::min(goldamt, 99999999L); // ditto
+ gold.setLabel("Gold:", goldamt);
+
+ const char *text;
+ QString qtext;
+ QPixmap *pxmp;
+ if (u.ualign.type == A_LAWFUL) {
+ pxmp = &p_lawful;
+ text = "Lawful";
+ } else if (u.ualign.type == A_NEUTRAL) {
+ pxmp = &p_neutral;
+ text = "Neutral";
+ } else {
+ pxmp = &p_chaotic;
+ // Unaligned should never happen
+ text = (u.ualign.type == A_CHAOTIC) ? "Chaotic"
+ : (u.ualign.type == A_NONE) ? "unaligned"
+ : "other?";
+ }
+ qtext = nh_qsprintf("%sly aligned", text);
+ align.setIcon(*pxmp, qtext.toLower());
+ align.setLabel(QString(text));
+ // without this, the ankh pixmap shifts from centered to left
+ // justified relative to the label text for some unknown reason...
+ align.ForceResize();
+ if (spreadout)
+ ++k; // when not condensed, Alignment is shown on the Conditions row
+
+ if (!k) {
+ blank2.show(); // for vertical spacing: force the row to be non-empty
+ } else
+ blank2.hide();
+
+ // Time isn't highlighted (due to constantly changing) so we don't keep
+ // track of whether it has just been toggled On or Off
+ if (::flags.time) {
+ // hypothetically Time could grow to enough digits to have trouble
+ // fitting, but it's not worth worrying about
+ time.setLabel("Time:", (long) svm.moves);
+ } else {
+ time.setLabel("");
+ }
+
+#ifdef SCORE_ON_BOTL
+ int score_toggled = !had_score ^ !::flags.showscore;
+ if (::flags.showscore) {
+ if (score_toggled) // toggled On
+ score.setCompareMode(NeitherIsBetter);
+ long pts = botl_score();
+ if (spreadout) {
+ // plenty of room; Time and Score both have the width of 3 fields
+ score.setLabel("Score:", pts);
+ } else {
+ // depending upon font size and status layout, "Score:nnnnnnnn"
+ // might be too wide to fit (simpler version of Level:NN/nnnnnnnn)
+ static const char *const scrlbl[3] = { "Score:", "Scr:", "S:" };
+ QFontMetrics fm(score.label->font());
+ for (int i = 0; i < 3; ++i) {
+ buf = nh_qsprintf("%s%ld", scrlbl[i], pts);
+ // +2: allow couple of pixels at either end to be clipped off
+ if (fm.size(0, buf).width() <= (2 + score.width() + 2))
+ break;
+ }
+ score.setLabel(buf, NetHackQtLabelledIcon::NoNum, pts);
+ // with Xp/Exp, we fallback to Xp if the shortest label prefix
+ // is still too long; here we just show a clipped value and
+ // let user either live with it or turn 'showscore' off (or
+ // set statuslines:3 to take advantage of the extra room that
+ // the spread out status layout provides)
+ }
+ } else {
+ if (score_toggled) { // toggled Off; if already Off, no need to set ""
+ score.setCompareMode(NoCompare);
+ score.setLabel(""); // blank when not active
+ }
+ }
+ if (score_toggled)
+ score.setCompareMode(BiggerIsBetter);
+ had_score = ::flags.showscore ? true : false;
+#endif /* SCORE_ON_BOTL */
+
+ if (first_set) {
+ first_set=false;
+
+ /*
+ * Default compareMode is BiggerIsBetter: an increased value
+ * is an improvement.
+ */
+ name.highlightWhenChanging();
+ dlevel.highlightWhenChanging();
+ dlevel.setCompareMode(NeitherIsBetter);
+
+ str.highlightWhenChanging();
+ dex.highlightWhenChanging();
+ con.highlightWhenChanging();
+ intel.highlightWhenChanging();
+ wis.highlightWhenChanging();
+ cha.highlightWhenChanging();
+
+ hp.highlightWhenChanging();
+ power.highlightWhenChanging();
+ ac.highlightWhenChanging();
+ ac.setCompareMode(SmallerIsBetter);
+ level.highlightWhenChanging();
+ gold.highlightWhenChanging();
+
+ // don't highlight 'time' because it changes almost continuously
+ // [if we did highlight it, we wouldn't show increase as 'Better']
+ //time.highlightWhenChanging(); time.setCompareMode(NeitherIsBetter);
+ score.highlightWhenChanging();
+
+ align.highlightWhenChanging();
+ align.setCompareMode(NeitherIsBetter);
+
+ hunger.highlightWhenChanging();
+ hunger.setCompareMode(SmallerIsBetter);
+ encumber.highlightWhenChanging();
+ encumber.setCompareMode(SmallerIsBetter);
+ stoned.highlightWhenChanging();
+ slimed.highlightWhenChanging();
+ strngld.highlightWhenChanging();
+ sick_fp.highlightWhenChanging();
+ sick_il.highlightWhenChanging();
+ stunned.highlightWhenChanging();
+ confused.highlightWhenChanging();
+ hallu.highlightWhenChanging();
+ blind.highlightWhenChanging();
+ deaf.highlightWhenChanging();
+ // the default behavior is to highlight a newly shown condition
+ // as "worse" but that isn't appropriate for 'other' conds;
+ // NetHackQtLabelledIcon::show() uses NeitherIsBetter to handle it
+ lev.highlightWhenChanging();
+ lev.setCompareMode(NeitherIsBetter);
+ fly.highlightWhenChanging();
+ fly.setCompareMode(NeitherIsBetter);
+ ride.highlightWhenChanging();
+ ride.setCompareMode(NeitherIsBetter);
+ // not a true status condition; doesn't change (unless 'showvers'
+ // gets toggled or 'versinfo' is modified) so doesn't get highlighted
+ vers.setCompareMode(NoCompare);
+ }
+}
+
+/*
+ * Turn off hilighted status values after a certain amount of turns.
+ */
+void NetHackQtStatusWindow::checkTurnEvents()
+{
+}
+
+// clicking on status window runs #attributes (^X)
+void NetHackQtStatusWindow::mousePressEvent(QMouseEvent *event UNUSED)
+{
+ QWidget *main = NetHackQtBind::mainWidget();
+ (static_cast (main))->FuncAsCommand(doattributes);
+}
+
+} // namespace nethack_qt_
diff --git a/win/Qt/qt_stat.h b/win/Qt/qt_stat.h
new file mode 100644
index 000000000..43cf2f154
--- /dev/null
+++ b/win/Qt/qt_stat.h
@@ -0,0 +1,160 @@
+// Copyright (c) Warwick Allison, 1999.
+// Qt4 conversion copyright (c) Ray Chason, 2012-2014.
+// NetHack may be freely redistributed. See license for details.
+
+// qt_stat.h -- bindings between the Qt 4 interface and the main code
+
+#ifndef QT4STAT_H
+#define QT4STAT_H
+
+#include "qt_win.h"
+#include "qt_icon.h"
+
+namespace nethack_qt_ {
+
+class NetHackQtStatusWindow : QWidget, public NetHackQtWindow {
+ Q_OBJECT
+public:
+ NetHackQtStatusWindow();
+
+ virtual QWidget* Widget();
+
+ virtual void Clear();
+ virtual void Display(bool block);
+ virtual void CursorTo(int x,int y);
+ virtual void PutStr(int attr, const QString& text);
+
+ void fadeHighlighting();
+
+protected:
+ virtual void mousePressEvent(QMouseEvent *event);
+ //RLC void resizeEvent(QResizeEvent*);
+
+private slots:
+ void doUpdate();
+
+private:
+ enum { hilight_time=1 };
+
+ QPixmap p_str;
+ QPixmap p_dex;
+ QPixmap p_con;
+ QPixmap p_int;
+ QPixmap p_wis;
+ QPixmap p_cha;
+
+ QPixmap p_chaotic;
+ QPixmap p_neutral;
+ QPixmap p_lawful;
+ QPixmap p_blank2; // conditionally used for vertical spacing
+
+ QPixmap p_satiated;
+ QPixmap p_hungry;
+ QPixmap p_encumber[5];
+
+ QPixmap p_stoned;
+ QPixmap p_slimed;
+ QPixmap p_strngld;
+ QPixmap p_sick_fp;
+ QPixmap p_sick_il;
+ QPixmap p_stunned;
+ QPixmap p_confused;
+ QPixmap p_hallu;
+ QPixmap p_blind;
+ QPixmap p_deaf;
+ QPixmap p_lev;
+ QPixmap p_fly;
+ QPixmap p_ride;
+ QPixmap p_vers; // version, when shown, is like a pseudo-condition
+
+ /*
+ * Status fields, in display order (the three separator lines
+ * are exceptions). Hitpoint bar is optionally displayed and
+ * contains two side-by-side parts; neither part is labelled.
+ */
+ QLabel hpbar_health; // hit point bar, left half
+ QLabel hpbar_injury; // hit point bar, right half
+ NetHackQtLabelledIcon name; // (aka title) centered on its own row
+ NetHackQtLabelledIcon dlevel; // (aka location) likewise
+
+ /* the six characteristics; each is shown with a 40x40 icon above
+ and a text label below, so implicitly two rows */
+ NetHackQtLabelledIcon str;
+ NetHackQtLabelledIcon dex;
+ NetHackQtLabelledIcon con;
+ NetHackQtLabelledIcon intel;
+ NetHackQtLabelledIcon wis;
+ NetHackQtLabelledIcon cha;
+
+ /* five various status fields, some showing two values, shown as
+ a row of text only; 'exp' used to be a separate field but is
+ now displayed with 'level', with a blank field where it was so
+ that there continue to be six columns which line up beneath the
+ characteristics; gold used to be left-most but doesn't warrant
+ that position; Xp or Xp/Exp is replaced by HD when polymorphed */
+ NetHackQtLabelledIcon hp; // current HP / maximum HP
+ NetHackQtLabelledIcon power; // current energy / maximum energy
+ NetHackQtLabelledIcon ac; // armor class
+ NetHackQtLabelledIcon level; // Xp level / Exp points (if 'showexp')
+ NetHackQtLabelledIcon blank1; // pads the line to six columns
+ NetHackQtLabelledIcon gold; // used to come before HP
+
+ /* next row: two more fields, possibly blank; when present, each
+ is sized as if for three fields, so their centered values line
+ up with 2nd and 5th columns of the rows above */
+ NetHackQtLabelledIcon time; // moves counter (if 'time' is set)
+ NetHackQtLabelledIcon score; // tentative score (if compiled with
+ // SCORE_ON_BOTL and 'showscore' is set)
+
+ /* last rows: alignment and zero or more status conditions;
+ like the characteristics, they are shown as if in two rows with
+ a 40x40 icon above and text lebel below; blank values are omitted
+ and non-blank values are left justified */
+ NetHackQtLabelledIcon align; // w/ alignment-specific ankh icon
+ NetHackQtLabelledIcon blank2; // used for spacing if Align is moved
+ NetHackQtLabelledIcon hunger; // blank if 'normal'
+ NetHackQtLabelledIcon encumber; // blank if 'unencumbered' ('normal')
+ /* zero or more status conditions; in major, minor, 'other' order */
+ NetHackQtLabelledIcon stoned;
+ NetHackQtLabelledIcon slimed;
+ NetHackQtLabelledIcon strngld;
+ NetHackQtLabelledIcon sick_fp;
+ NetHackQtLabelledIcon sick_il;
+ NetHackQtLabelledIcon stunned;
+ NetHackQtLabelledIcon confused;
+ NetHackQtLabelledIcon hallu;
+ NetHackQtLabelledIcon blind;
+ NetHackQtLabelledIcon deaf;
+ NetHackQtLabelledIcon lev;
+ NetHackQtLabelledIcon fly;
+ NetHackQtLabelledIcon ride;
+ /* to right of conditions, right justified */
+ NetHackQtLabelledIcon vers; // version
+
+ QFrame hline1; // between dlevel and characteristics
+ QFrame hline2; // between characteristics and regular status fields
+ QFrame hline3; // between regular fields and time,score or conditions
+ QFrame vline1; // for statuslines:2, between Cha and Alignment
+ QFrame vline2; // for statuslines:2, padding between Gold and Time
+
+ int cursy;
+ bool first_set;
+ bool alreadyfullhp;
+
+ // for some fields, we need to know more than just "changed since
+ // last update"; there's no 'had_time' because Time isn't highlighted
+ bool was_polyd;
+ bool had_exp;
+ bool had_score;
+ unsigned prev_versinfo;
+
+ QHBoxLayout *InitHitpointBar();
+ void HitpointBar();
+ void nullOut();
+ void updateStats();
+ void checkTurnEvents();
+};
+
+} // namespace nethack_qt_
+
+#endif
diff --git a/win/Qt4/qt4str.cpp b/win/Qt/qt_str.cpp
similarity index 84%
rename from win/Qt4/qt4str.cpp
rename to win/Qt/qt_str.cpp
index b6b4440eb..764dd07bd 100644
--- a/win/Qt4/qt4str.cpp
+++ b/win/Qt/qt_str.cpp
@@ -2,25 +2,26 @@
// Qt4 conversion copyright (c) Ray Chason, 2012-2014.
// NetHack may be freely redistributed. See license for details.
-// qt4str.cpp -- some string functions
+// qt_str.cpp -- some string functions
#include
#include
-#include "qt4str.h"
+#include
+#include "qt_str.h"
-namespace nethack_qt4 {
+namespace nethack_qt_ {
// Bounded string copy
size_t str_copy(char *dest, const char *src, size_t max)
{
- size_t len = strlen(src);
+ size_t len = 0;
if (max != 0) {
- size_t csize = len;
+ len = strlen(src);
if (len > max - 1) {
len = max - 1;
}
- memcpy(dest, src, csize);
- dest[csize] = '\0';
+ memcpy(dest, src, len);
+ dest[len] = '\0';
}
return len;
}
@@ -35,7 +36,7 @@ QString str_titlecase(const QString& str)
QString nh_capitalize_words(const QString& str)
{
QStringList words = str.split(" ");
- for (size_t i = 0; i < words.size(); ++i) {
+ for (size_t i = 0; i < (size_t) words.size(); ++i) {
words[i] = str_titlecase(words[i]);
}
return words.join(" ");
@@ -80,4 +81,20 @@ int cp437(int ch)
return cp437table[(unsigned char)ch];
}
-} // namespace nethack_qt4
+QString
+nh_qsprintf(const char *format, ...)
+{
+ QString msg;
+ std::va_list args;
+
+ va_start(args, format);
+#if QT_VERSION >= QT_VERSION_CHECK(5, 5, 0)
+ msg = QString::vasprintf(format, args);
+#else
+ msg.vsprintf(format, args);
+#endif
+ va_end(args);
+ return msg;
+}
+
+} // namespace nethack_qt_
diff --git a/win/Qt4/qt4str.h b/win/Qt/qt_str.h
similarity index 65%
rename from win/Qt4/qt4str.h
rename to win/Qt/qt_str.h
index 05f25f4c4..9bc8f66e0 100644
--- a/win/Qt4/qt4str.h
+++ b/win/Qt/qt_str.h
@@ -2,12 +2,12 @@
// Qt4 conversion copyright (c) Ray Chason, 2012-2014.
// NetHack may be freely redistributed. See license for details.
-// qt4str.h -- various string functions
+// qt_str.h -- various string functions
#ifndef QT4STR_H
#define QT4STR_H
-namespace nethack_qt4 {
+namespace nethack_qt_ {
// Bounded string copy
extern size_t str_copy(char *dest, const char *src, size_t max);
@@ -19,6 +19,13 @@ extern QString nh_capitalize_words(const QString& str);
// Map symbol conversion
extern int cp437(int ch);
-} // namespace nethack_qt4
+// sprintf
+extern QString nh_qsprintf(const char *format, ...)
+#if defined(__GNUC__) && (__GNUC__ >= 2)
+ __attribute__((format(printf, 1, 2)))
+#endif
+;
+
+} // namespace nethack_qt_
#endif
diff --git a/win/Qt/qt_streq.cpp b/win/Qt/qt_streq.cpp
new file mode 100644
index 000000000..dc6712a4d
--- /dev/null
+++ b/win/Qt/qt_streq.cpp
@@ -0,0 +1,112 @@
+// Copyright (c) Warwick Allison, 1999.
+// Qt4 conversion copyright (c) Ray Chason, 2012-2014.
+// NetHack may be freely redistributed. See license for details.
+
+// qt_streq.cpp -- string requestor
+
+extern "C" {
+#include "hack.h"
+}
+
+#include "qt_pre.h"
+#include
+#if QT_VERSION >= 0x050000
+#include
+#endif
+#include "qt_post.h"
+#include "qt_streq.h"
+#include "qt_str.h"
+#include "qt_set.h"
+
+namespace nethack_qt_ {
+
+// temporary
+void centerOnMain(QWidget *);
+// end temporary
+
+NetHackQtStringRequestor::NetHackQtStringRequestor(QWidget *parent,
+ const char *p, const char *cancelstr, const char *okaystr) :
+ QDialog(parent),
+ prompt(QString::fromLatin1(p),this),
+ input(this,"input")
+{
+ if (qt_settings)
+ input.setFont(qt_settings->normalFixedFont());
+
+ cancel=new QPushButton(cancelstr,this);
+ connect(cancel,SIGNAL(clicked()),this,SLOT(reject()));
+
+ okay = new QPushButton(okaystr, this);
+ connect(okay,SIGNAL(clicked()),this,SLOT(accept()));
+ connect(&input,SIGNAL(returnPressed()),this,SLOT(accept()));
+ okay->setDefault(true);
+
+ setFocusPolicy(Qt::StrongFocus);
+}
+
+void NetHackQtStringRequestor::resizeEvent(QResizeEvent*)
+{
+ const int margin=5;
+ const int gutter=5;
+
+ int h = (height() - margin * 2 - gutter);
+ int w = (width() - margin * 2 - gutter);
+ int ifw = input.hasFrame() ? 3 : 0; // hack alert for input.frameWidth()
+ if (prompt.text().size() > 16) {
+ h /= 3;
+ prompt.setGeometry(margin + ifw * 2 + 1, margin, w + gutter, h);
+ input.setGeometry(width() * 1 / 5 - ifw, margin + h + gutter,
+ w * 4 / 5, h);
+ } else {
+ h /= 2;
+ prompt.setGeometry(margin + ifw * 2 + 1, margin, w * 2 / 5, h);
+ input.setGeometry(prompt.geometry().right() + gutter
+ - (ifw * 2 + 1) - ifw * 2,
+ margin, w * 3 / 5, h);
+ }
+
+ cancel->setGeometry(margin, input.geometry().bottom() + gutter, w / 2, h);
+ okay->setGeometry(cancel->geometry().right() + gutter,
+ cancel->geometry().y(), w / 2, h);
+}
+
+void NetHackQtStringRequestor::SetDefault(const char *d)
+{
+ input.setText(d);
+}
+
+bool NetHackQtStringRequestor::Get(char *buffer, int maxchar, int minchar)
+{
+ input.setMaxLength(maxchar - 1);
+
+ const QString &txt = prompt.text();
+ int pw = fontMetrics().QFM_WIDTH(txt),
+ ww = minchar * input.fontMetrics().QFM_WIDTH(QChar('X'));
+ int heightfactor = ((txt.size() > 16) ? 3 : 2) * 2; // 2 or 3 lines high
+ int widthfudge = (((txt.size() > 16) ? 1 : 2) * 5) * 2; // 5: margn, guttr
+ resize(pw + ww + widthfudge, fontMetrics().height() * heightfactor);
+
+#ifdef EDIT_GETLIN
+ input.setText(buffer);
+#endif
+ centerOnMain(this);
+ show();
+ // Make sure that setFocus() really does change keyboard focus.
+ // This allows typing to go directly to the NetHackQtLineEdit
+ // widget without clicking on or in it first. Not needed for
+ // qt_getline() but is needed for menu Search to prevent typed
+ // characters being treated as making menu selections.
+ if (!input.isActiveWindow())
+ input.activateWindow();
+ input.setFocus();
+ exec();
+
+ if (result()) {
+ str_copy(buffer, input.text().toLatin1().constData(), maxchar);
+ return true;
+ } else {
+ return false;
+ }
+}
+
+} // namespace nethack_qt_
diff --git a/win/Qt/qt_streq.h b/win/Qt/qt_streq.h
new file mode 100644
index 000000000..89894dc03
--- /dev/null
+++ b/win/Qt/qt_streq.h
@@ -0,0 +1,33 @@
+// Copyright (c) Warwick Allison, 1999.
+// Qt4 conversion copyright (c) Ray Chason, 2012-2014.
+// NetHack may be freely redistributed. See license for details.
+
+// qt_streq.h -- string requestor
+
+#ifndef QT4STREQ_H
+#define QT4STREQ_H
+
+#include "qt_line.h"
+
+namespace nethack_qt_ {
+
+class NetHackQtStringRequestor : QDialog {
+private:
+ QLabel prompt;
+ NetHackQtLineEdit input;
+ QPushButton* okay;
+ QPushButton* cancel;
+
+public:
+ NetHackQtStringRequestor(QWidget *parent, const char *p,
+ const char *cancelstr = "Cancel",
+ const char *okaystr = "Okay");
+ void SetDefault(const char *);
+ // maxchar is size of buffer[], minchar is size of line edit widget
+ bool Get(char *buffer, int maxchar = 80, int minchar = 20);
+ virtual void resizeEvent(QResizeEvent *);
+};
+
+} // namespace nethack_qt_
+
+#endif
diff --git a/win/Qt/qt_svsel.cpp b/win/Qt/qt_svsel.cpp
new file mode 100644
index 000000000..f08c0aa25
--- /dev/null
+++ b/win/Qt/qt_svsel.cpp
@@ -0,0 +1,121 @@
+// Copyright (c) Warwick Allison, 1999.
+// Qt4 conversion copyright (c) Ray Chason, 2012-2014.
+// NetHack may be freely redistributed. See license for details.
+
+// qt_svsel.cpp -- saved game selector
+//
+// Popup's layout:
+//----
+// NetHack 5.0.x (literal text w/ dynamic version number)
+// /----------------------\ (text to prevent multi-line comment warning)
+// | |
+// | |
+// | splash image | nhsplash.xpm (red dragon w/ rider)
+// | |
+// | |
+// \----------------------/
+// by the NetHack DevTeam (literal text)
+// [ Quit ] [New-Game] side-by-side buttons
+// Saved characters (literal text in small font)
+// [ character one ] button with character name
+// [ character two ] button with another character name
+// [ character three ] button with yet another character name
+// ... as many buttons as needed
+//----
+//
+// FIXME:
+// If there are a lot of saved games available, the selection dialog
+// needs vertical scrolling capability.
+//
+// Note:
+// The code in this file is not used if the program is built without
+// having SELECTSAVED defined or if the run-time option 'selectsaved'
+// is False. SELECTSAVED used to be forced for Qt but isn't any more.
+// However, we include this code unconditionally.
+//
+
+extern "C" {
+#include "hack.h"
+}
+
+#include "qt_pre.h"
+#include
+#if QT_VERSION >= 0x050000
+#include
+#endif
+#include "qt_post.h"
+#include "qt_svsel.h"
+#include "qt_bind.h"
+#include "qt_str.h"
+
+namespace nethack_qt_ {
+
+//
+// popup dialog at start of game to choose between a new game or which save
+// file to load if user has at least one saved game and either hasn't supplied
+// any character name or has supplied one which doesn't have a save file
+//
+NetHackQtSavedGameSelector::NetHackQtSavedGameSelector(const char** saved) :
+ QDialog(NetHackQtBind::mainWidget())
+{
+ QVBoxLayout *vbl = new QVBoxLayout(this);
+ QHBoxLayout* hb;
+
+ char cvers[BUFSZ];
+ QString qvers = QString("NetHack ") + QString(version_string(cvers, sizeof cvers));
+ QLabel *vers = new QLabel(qvers, this);
+ vers->setAlignment(Qt::AlignCenter);
+ vbl->addWidget(vers);
+
+ QLabel *logo = new QLabel(this);
+ logo->setAlignment(Qt::AlignCenter);
+ logo->setPixmap(QPixmap("nhsplash.xpm"));
+ vbl->addWidget(logo);
+
+ QLabel *attr = new QLabel("by the NetHack DevTeam", this);
+ attr->setAlignment(Qt::AlignCenter);
+ vbl->addWidget(attr);
+ vbl->addStretch(2);
+
+ /* With Qt5, this next line triggers a complaint to stderr:
+QLayout: Attempting to add QLayout "" to QDialog "", which already has a layout
+ hb = new QHBoxLayout(this);
+ */
+ hb = new QHBoxLayout((QWidget *) NULL);
+ vbl->addLayout(hb, Qt::AlignCenter);
+
+ QPushButton *q = new QPushButton("Quit", this);
+ hb->addWidget(q);
+ connect(q, SIGNAL(clicked()), this, SLOT(reject()));
+ QPushButton *c = new QPushButton("New Game", this);
+ hb->addWidget(c);
+ connect(c, SIGNAL(clicked()), this, SLOT(accept()));
+ c->setDefault(true);
+
+ QGroupBox *box = new QGroupBox("Saved Characters", this);
+ QVBoxLayout *bgl = new QVBoxLayout();
+ QButtonGroup *bg = new QButtonGroup();
+#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0)
+ connect(bg, SIGNAL(idPressed(int)), this, SLOT(done(int)));
+#else
+ connect(bg, SIGNAL(buttonPressed(int)), this, SLOT(done(int)));
+#endif
+ for (int i = 0; saved[i]; ++i) {
+ QPushButton *b = new QPushButton(saved[i]);
+ bgl->addWidget(b);
+ bg->addButton(b, i + 2);
+ }
+ box->setLayout(bgl);
+ vbl->addWidget(box);
+}
+
+int NetHackQtSavedGameSelector::choose()
+{
+#if defined(QWS) // probably safe with Qt 3, too (where show!=exec in QDialog).
+ if ( qt_compact_mode )
+ showMaximized();
+#endif
+ return exec() - 2;
+}
+
+} // namespace nethack_qt_
diff --git a/win/Qt4/qt4svsel.h b/win/Qt/qt_svsel.h
similarity index 79%
rename from win/Qt4/qt4svsel.h
rename to win/Qt/qt_svsel.h
index 918e6f7e3..3a5498758 100644
--- a/win/Qt4/qt4svsel.h
+++ b/win/Qt/qt_svsel.h
@@ -2,12 +2,12 @@
// Qt4 conversion copyright (c) Ray Chason, 2012-2014.
// NetHack may be freely redistributed. See license for details.
-// qt4svsel.h -- saved game selector
+// qt_svsel.h -- saved game selector
#ifndef QT4SVSEL_H
#define QT4SVSEL_H
-namespace nethack_qt4 {
+namespace nethack_qt_ {
class NetHackQtSavedGameSelector : public QDialog {
public:
@@ -16,6 +16,6 @@ class NetHackQtSavedGameSelector : public QDialog {
int choose();
};
-} // namespace nethack_qt4
+} // namespace nethack_qt_
#endif
diff --git a/win/Qt/qt_win.cpp b/win/Qt/qt_win.cpp
index 6d560f1ce..db66579f6 100644
--- a/win/Qt/qt_win.cpp
+++ b/win/Qt/qt_win.cpp
@@ -1,8 +1,8 @@
-// NetHack 3.6 qt_win.cpp $NHDT-Date: 1524684508 2018/04/25 19:28:28 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.77 $
// Copyright (c) Warwick Allison, 1999.
+// Qt4 conversion copyright (c) Ray Chason, 2012-2014.
// NetHack may be freely redistributed. See license for details.
-// Qt Binding for NetHack 3.4
+// Qt Windowing interface for NetHack 5.0
//
// Copyright (C) 1996-2001 by Warwick W. Allison (warwick@troll.no)
//
@@ -22,11 +22,11 @@
// and also because this is my first major application of Qt.
//
// The problem of NetHack's getkey requirement is solved by intercepting
-// key events by overiding QApplicion::notify(...), and putting them in
+// key events by overriding QApplication::notify(...), and putting them in
// a buffer. Mouse clicks on the map window are treated with a similar
// buffer. When the NetHack engine calls for a key, one is taken from
-// the buffer, or if that is empty, QApplication::enter_loop() is called.
-// Whenever keys or clicks go into the buffer, QApplication::exit_loop()
+// the buffer, or if that is empty, QApplication::exec() is called.
+// Whenever keys or clicks go into the buffer, QApplication::exit()
// is called.
//
// Another problem is that some NetHack players are decade-long players who
@@ -40,1400 +40,55 @@
// by the key event buffer.
//
-extern "C" {
-
// This includes all the definitions we need from the NetHack main
// engine. We pretend MSC is a STDC compiler, because C++ is close
// enough, and we undefine NetHack macros which conflict with Qt
-// identifiers.
-
-#define alloc hide_alloc // avoid treading on STL symbol
-#define lock hide_lock // avoid treading on STL symbol
-#ifdef _MSC_VER
-#define NHSTDC
-#endif
-#include "hack.h"
-#include "func_tab.h"
-#include "dlb.h"
-#include "patchlevel.h"
-#include "tile2x11.h"
-#undef Invisible
-#undef Warning
-#undef red
-#undef green
-#undef blue
-#undef Black
-#undef curs
-#undef TRUE
-#undef FALSE
-#undef min
-#undef max
-#undef alloc
-#undef lock
-#undef yn
-
-}
-
-#include "qt_win.h"
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-//#include
-//#include
-
-#include
-
-#include "qt_clust.h"
-#include "qt_xpms.h"
-
-#include
-#ifdef Q_WS_MACX
-# include
-#else
-# include
-#endif
-
-#ifdef _WS_X11_
-// For userid control
-#include
-#endif
-
-// Some distributors released Qt 2.1.0beta4
-#if QT_VERSION < 220
-# define nh_WX11BypassWM 0x01000000
-#else
-# define nh_WX11BypassWM WX11BypassWM
-#endif
-
-#ifdef USER_SOUNDS
-# if QT_VERSION < 220
-# undef USER_SOUNDS
-# else
-# include
-# endif
-#endif
-
-
-#ifdef USER_SOUNDS
-extern "C" void play_sound_for_message(const char* str);
-#endif
-
-#ifdef SAFERHANGUP
-#include
-#endif
-
-// Warwick prefers it this way...
-#define QT_CHOOSE_RACE_FIRST
-
-static const char nh_attribution[] = "NetHack"
- "
by the NetHack DevTeam";
-
-static QString
-aboutMsg()
-{
- QString msg;
- msg.sprintf(
- "Qt NetHack is a version of NetHack built\n"
-#ifdef KDE
- "using KDE and the Qt GUI toolkit.\n"
-#else
- "using the Qt GUI toolkit.\n"
-#endif
- "This is version %d.%d.%d\n\n"
- "Homepage:\n http://trolls.troll.no/warwick/nethack/\n\n"
-#ifdef KDE
- "KDE:\n http://www.kde.org\n"
-#endif
- "Qt:\n http://www.troll.no",
- VERSION_MAJOR,
- VERSION_MINOR,
- PATCHLEVEL);
- return msg;
-}
-
-static void
-centerOnMain( QWidget* w )
-{
- QWidget* m = qApp->mainWidget();
- if (!m) m = qApp->desktop();
- QPoint p = m->mapToGlobal(QPoint(0,0));
- w->move( p.x() + m->width()/2 - w->width()/2,
- p.y() + m->height()/2 - w->height()/2 );
-}
-
-NetHackQtLineEdit::NetHackQtLineEdit() :
- QLineEdit(0)
-{
-}
-
-NetHackQtLineEdit::NetHackQtLineEdit(QWidget* parent, const char* name) :
- QLineEdit(parent,name)
-{
-}
-
-void NetHackQtLineEdit::fakeEvent(int key, int ascii, int state)
-{
- QKeyEvent fake(QEvent::KeyPress,key,ascii,state);
- keyPressEvent(&fake);
-}
+// identifiers (now done in qt_pre.h).
+#define QT_DEPRECATED_WARNINGS
extern "C" {
-/* Used by tile/font-size patch below and in ../../src/files.c */
-char *qt_tilewidth=NULL;
-char *qt_tileheight=NULL;
-char *qt_fontsize=NULL;
-#if defined(QWS)
-int qt_compact_mode = 1;
-#else
-int qt_compact_mode = 0;
-#endif
-extern const char *enc_stat[]; /* from botl.c */
-extern const char *hu_stat[]; /* from eat.c */
-extern int total_tiles_used; // from tile.c
-extern short glyph2tile[]; // from tile.c
-}
-
-static int tilefile_tile_W=16;
-static int tilefile_tile_H=16;
-
-#define TILEWMIN 1
-#define TILEHMIN 1
-
-
-/* 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$",
-"$$$$$$$$$$$$$$$$"
-};
-
-/* 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"};
-/* 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 * get_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 * rest_xpm[] = {
-"12 13 2 1",
-" c None",
-". c #000000000000",
-" ..... ",
-" . ",
-" . ",
-" . ....",
-" ..... . ",
-" . ",
-" ....",
-" ",
-" .... ",
-" . ",
-" . ",
-" .... ",
-" "};
-/* XPM */
-static const char * cast_a_xpm[] = {
-"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[] = {
-"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[] = {
-"12 13 3 1",
-" c None",
-". c #FFFF6DB60000",
-"X c #000000000000",
-" . ",
-" . ",
-" .. ",
-" .. ",
-" .. . ",
-" .. . ",
-" ...... ",
-" .. .. XX ",
-" .. X X ",
-" .. X ",
-" .. X ",
-" . X X ",
-" . XX "};
-
-NetHackQtSettings::NetHackQtSettings(int w, int h) :
- tilewidth(TILEWMIN,64,1,this),
- tileheight(TILEHMIN,64,1,this),
- widthlbl(&tilewidth,"&Width:",this),
- heightlbl(&tileheight,"&Height:",this),
- whichsize("&Zoomed",this),
- fontsize(this),
- normal("times"),
-#ifdef WS_WIN
- normalfixed("courier new"),
-#else
- normalfixed("fixed"),
-#endif
- large("times"),
- theglyphs(0)
-
-{
- int default_fontsize;
-
- if (w<=300) {
- // ~240x320
- default_fontsize=4;
- tilewidth.setValue(8);
- tileheight.setValue(12);
- } else if (w<=700) {
- // ~640x480
- default_fontsize=3;
- tilewidth.setValue(8);
- tileheight.setValue(14);
- } else if (w<=900) {
- // ~800x600
- default_fontsize=3;
- tilewidth.setValue(10);
- tileheight.setValue(17);
- } else if (w<=1100) {
- // ~1024x768
- default_fontsize=2;
- tilewidth.setValue(12);
- tileheight.setValue(22);
- } else if (w<=1200) {
- // ~1152x900
- default_fontsize=1;
- tilewidth.setValue(14);
- tileheight.setValue(26);
- } else {
- // ~1280x1024 and larger
- default_fontsize=0;
- tilewidth.setValue(16);
- tileheight.setValue(30);
- }
-
- // Tile/font sizes read from .nethackrc
- if (qt_tilewidth != NULL) {
- tilewidth.setValue(atoi(qt_tilewidth));
- free(qt_tilewidth);
- }
- if (qt_tileheight != NULL) {
- tileheight.setValue(atoi(qt_tileheight));
- free(qt_tileheight);
- }
- if (qt_fontsize != NULL) {
- switch (tolower(qt_fontsize[0])) {
- case 'h': default_fontsize = 0; break;
- case 'l': default_fontsize = 1; break;
- case 'm': default_fontsize = 2; break;
- case 's': default_fontsize = 3; break;
- case 't': default_fontsize = 4; break;
- }
- free(qt_fontsize);
- }
-
- theglyphs=new NetHackQtGlyphs();
- resizeTiles();
-
- connect(&tilewidth,SIGNAL(valueChanged(int)),this,SLOT(resizeTiles()));
- connect(&tileheight,SIGNAL(valueChanged(int)),this,SLOT(resizeTiles()));
- connect(&whichsize,SIGNAL(toggled(bool)),this,SLOT(setGlyphSize(bool)));
-
- fontsize.insertItem("Huge");
- fontsize.insertItem("Large");
- fontsize.insertItem("Medium");
- fontsize.insertItem("Small");
- fontsize.insertItem("Tiny");
- fontsize.setCurrentItem(default_fontsize);
- connect(&fontsize,SIGNAL(activated(int)),this,SIGNAL(fontChanged()));
-
- QGridLayout* grid = new QGridLayout(this, 5, 2, 8);
- grid->addMultiCellWidget(&whichsize, 0, 0, 0, 1);
- grid->addWidget(&tilewidth, 1, 1); grid->addWidget(&widthlbl, 1, 0);
- grid->addWidget(&tileheight, 2, 1); grid->addWidget(&heightlbl, 2, 0);
- QLabel* flabel=new QLabel(&fontsize, "&Font:",this);
- grid->addWidget(flabel, 3, 0); grid->addWidget(&fontsize, 3, 1);
- QPushButton* dismiss=new QPushButton("Dismiss",this);
- dismiss->setDefault(TRUE);
- grid->addMultiCellWidget(dismiss, 4, 4, 0, 1);
- grid->setRowStretch(4,0);
- grid->setColStretch(1,1);
- grid->setColStretch(2,2);
- grid->activate();
-
- connect(dismiss,SIGNAL(clicked()),this,SLOT(accept()));
- resize(150,140);
-}
-
-NetHackQtGlyphs& NetHackQtSettings::glyphs()
-{
- return *theglyphs;
-}
-
-void NetHackQtSettings::resizeTiles()
-{
- int w = tilewidth.value();
- int h = tileheight.value();
-
- theglyphs->setSize(w,h);
- emit tilesChanged();
-}
-
-void NetHackQtSettings::toggleGlyphSize()
-{
- whichsize.toggle();
-}
-
-void NetHackQtSettings::setGlyphSize(bool which)
-{
- QSize n = QSize(tilewidth.value(),tileheight.value());
- if ( othersize.isValid() ) {
- tilewidth.blockSignals(TRUE);
- tileheight.blockSignals(TRUE);
- tilewidth.setValue(othersize.width());
- tileheight.setValue(othersize.height());
- tileheight.blockSignals(FALSE);
- tilewidth.blockSignals(FALSE);
- resizeTiles();
- }
- othersize = n;
-}
-
-const QFont& NetHackQtSettings::normalFont()
-{
- static int size[]={ 18, 14, 12, 10, 8 };
- normal.setPointSize(size[fontsize.currentItem()]);
- return normal;
-}
-
-const QFont& NetHackQtSettings::normalFixedFont()
-{
- static int size[]={ 18, 14, 13, 10, 8 };
- normalfixed.setPointSize(size[fontsize.currentItem()]);
- return normalfixed;
-}
-
-const QFont& NetHackQtSettings::largeFont()
-{
- static int size[]={ 24, 18, 14, 12, 10 };
- large.setPointSize(size[fontsize.currentItem()]);
- return large;
-}
-
-bool NetHackQtSettings::ynInMessages()
-{
- return !qt_compact_mode;
-}
-
-
-NetHackQtSettings* qt_settings;
-
-
-
-NetHackQtKeyBuffer::NetHackQtKeyBuffer() :
- in(0), out(0)
-{
-}
-
-bool NetHackQtKeyBuffer::Empty() const { return in==out; }
-bool NetHackQtKeyBuffer::Full() const { return (in+1)%maxkey==out; }
-
-void NetHackQtKeyBuffer::Put(int k, int a, int state)
-{
- if ( Full() ) return; // Safety
- key[in]=k;
- ascii[in]=a;
- in=(in+1)%maxkey;
-}
-
-void NetHackQtKeyBuffer::Put(char a)
-{
- Put(0,a,0);
-}
-
-void NetHackQtKeyBuffer::Put(const char* str)
-{
- while (*str) Put(*str++);
-}
-
-int NetHackQtKeyBuffer::GetKey()
-{
- if ( Empty() ) return 0;
- int r=TopKey();
- out=(out+1)%maxkey;
- return r;
-}
-
-int NetHackQtKeyBuffer::GetAscii()
-{
- if ( Empty() ) return 0; // Safety
- int r=TopAscii();
- out=(out+1)%maxkey;
- return r;
-}
-
-int NetHackQtKeyBuffer::GetState()
-{
- if ( Empty() ) return 0;
- int r=TopState();
- out=(out+1)%maxkey;
- return r;
-}
-
-int NetHackQtKeyBuffer::TopKey() const
-{
- if ( Empty() ) return 0;
- return key[out];
-}
-
-int NetHackQtKeyBuffer::TopAscii() const
-{
- if ( Empty() ) return 0;
- return ascii[out];
-}
-
-int NetHackQtKeyBuffer::TopState() const
-{
- if ( Empty() ) return 0;
- return state[out];
-}
-
-
-NetHackQtClickBuffer::NetHackQtClickBuffer() :
- in(0), out(0)
-{
-}
-
-bool NetHackQtClickBuffer::Empty() const { return in==out; }
-bool NetHackQtClickBuffer::Full() const { return (in+1)%maxclick==out; }
-
-void NetHackQtClickBuffer::Put(int x, int y, int mod)
-{
- click[in].x=x;
- click[in].y=y;
- click[in].mod=mod;
- in=(in+1)%maxclick;
-}
-
-int NetHackQtClickBuffer::NextX() const { return click[out].x; }
-int NetHackQtClickBuffer::NextY() const { return click[out].y; }
-int NetHackQtClickBuffer::NextMod() const { return click[out].mod; }
-
-void NetHackQtClickBuffer::Get()
-{
- out=(out+1)%maxclick;
-}
-
-class NhPSListViewItem : public QListViewItem {
-public:
- NhPSListViewItem( QListView* parent, const QString& name ) :
- QListViewItem(parent, name)
- {
- }
-
- void setGlyph(int g)
- {
- NetHackQtGlyphs& glyphs = qt_settings->glyphs();
- int gw = glyphs.width();
- int gh = glyphs.height();
- QPixmap pm(gw,gh);
- QPainter p(&pm);
- glyphs.drawGlyph(p, g, 0, 0);
- p.end();
- setPixmap(0,pm);
- setHeight(QMAX(pm.height()+1,height()));
- }
-
- void paintCell( QPainter *p, const QColorGroup &cg,
- int column, int width, int alignment )
- {
- if ( isSelectable() ) {
- QListViewItem::paintCell( p, cg, column, width, alignment );
- } else {
- QColorGroup disabled(
- cg.foreground().light(),
- cg.button().light(),
- cg.light(), cg.dark(), cg.mid(),
- gray, cg.base() );
- QListViewItem::paintCell( p, disabled, column, width, alignment );
- }
- }
-};
-
-class NhPSListViewRole : public NhPSListViewItem {
-public:
- NhPSListViewRole( QListView* parent, int id ) :
- NhPSListViewItem(parent,
-#ifdef QT_CHOOSE_RACE_FIRST // Lowerize - looks better
- QString(QChar(roles[id].name.m[0])).lower()+QString(roles[id].name.m+1)
-#else
- roles[id].name.m
-#endif
- )
- {
- setGlyph(monnum_to_glyph(roles[id].malenum));
- }
-};
-
-class NhPSListViewRace : public NhPSListViewItem {
-public:
- NhPSListViewRace( QListView* parent, int id ) :
- NhPSListViewItem(parent,
-#ifdef QT_CHOOSE_RACE_FIRST // Capitalize - looks better
- QString(QChar(races[id].noun[0])).upper()+QString(races[id].noun+1)
-#else
- QString(QChar(races[id].noun[0])+QString(races[id].noun+1))
-#endif
- )
- {
- setGlyph(monnum_to_glyph(races[id].malenum));
- }
-};
-
-class NhPSListView : public QListView {
-public:
- NhPSListView( QWidget* parent ) :
- QListView(parent)
- {
- setSorting(-1); // order is identity
- header()->setClickEnabled(FALSE);
- }
-
- QSizePolicy sizePolicy() const
- {
- return QSizePolicy(QSizePolicy::Expanding,QSizePolicy::Expanding);
- }
-
- QSize minimumSizeHint() const
- {
- return sizeHint();
- }
-
- QSize sizeHint() const
- {
- QListView::sizeHint();
- QSize sz = header()->sizeHint();
- int h=0;
- QListViewItem* c=firstChild();
- while (c) h+=c->height(),c = c->nextSibling();
- sz += QSize(frameWidth()*2, h+frameWidth()*2);
- return sz;
- }
-
- int selectedItemNumber() const
- {
- int i=0;
- QListViewItem* c = firstChild();
- while (c) {
- if (c == selectedItem()) {
- return i;
- }
- i++;
- c = c->nextSibling();
- }
- return -1;
- }
-
- void setSelectedItemNumber(int i)
- {
- QListViewItem* c=firstChild();
- while (i--)
- c = c->nextSibling();
- c->setSelected(TRUE);
- }
-};
-
-NetHackQtPlayerSelector::NetHackQtPlayerSelector(NetHackQtKeyBuffer& ks) :
- QDialog(qApp->mainWidget(),"plsel",TRUE),
- keysource(ks),
- fully_specified_role(TRUE)
-{
- /*
- 0 1 2
- + Name ------------------------------------+
- 0 | |
- + ---- ------------------------------------+
- + Role ---+ + Race ---+ + Gender ------+
- | | | | | * Male |
- 1 | | | | | * Female |
- | | | | +--------------+
- | | | |
- | | | | + Alignment ---+
- 2 | | | | | * Male |
- | | | | | * Female |
- | | | | +--------------+
- 3 | | | | ...stretch...
- | | | |
- 4 | | | | [ Play ]
- 5 | | | | [ Quit ]
- +---------+ +---------+
- */
-
- int marg=4;
- QGridLayout *l = new QGridLayout(this,6,3,marg,marg);
-
- QButtonGroup* namebox = new QButtonGroup(1,Horizontal,"Name",this);
- QLineEdit* name = new QLineEdit(namebox);
- name->setMaxLength(sizeof(plname)-1);
- if ( strncmp(plname,"player",6) && strncmp(plname,"games",5) )
- name->setText(plname);
- connect(name, SIGNAL(textChanged(const QString&)),
- this, SLOT(selectName(const QString&)) );
- name->setFocus();
- QButtonGroup* genderbox = new QButtonGroup("Sex",this);
- QButtonGroup* alignbox = new QButtonGroup("Alignment",this);
- QVBoxLayout* vbgb = new QVBoxLayout(genderbox,3,1);
- vbgb->setAutoAdd(TRUE);
- vbgb->addSpacing(fontMetrics().height()*3/4);
- QVBoxLayout* vbab = new QVBoxLayout(alignbox,3,1);
- vbab->setAutoAdd(TRUE);
- vbab->addSpacing(fontMetrics().height());
- QLabel* logo = new QLabel(nh_attribution, this);
-
- l->addMultiCellWidget( namebox, 0,0,0,2 );
-#ifdef QT_CHOOSE_RACE_FIRST
- race = new NhPSListView(this);
- role = new NhPSListView(this);
- l->addMultiCellWidget( race, 1,5,0,0 );
- l->addMultiCellWidget( role, 1,5,1,1 );
-#else
- role = new NhPSListView(this);
- race = new NhPSListView(this);
- l->addMultiCellWidget( role, 1,5,0,0 );
- l->addMultiCellWidget( race, 1,5,1,1 );
-#endif
- role->addColumn("Role");
- race->addColumn("Race");
-
- l->addWidget( genderbox, 1, 2 );
- l->addWidget( alignbox, 2, 2 );
- l->addWidget( logo, 3, 2, AlignCenter );
- l->setRowStretch( 3, 5 );
-
- int i;
- int nrole;
-
- for (nrole=0; roles[nrole].name.m; nrole++)
- ;
- for (i=nrole-1; i>=0; i--) { // XXX QListView unsorted goes in rev.
- new NhPSListViewRole( role, i );
- }
- connect( role, SIGNAL(selectionChanged()), this, SLOT(selectRole()) );
-
- int nrace;
- for (nrace=0; races[nrace].noun; nrace++)
- ;
- for (i=nrace-1; i>=0; i--) {
- new NhPSListViewRace( race, i );
- }
- connect( race, SIGNAL(selectionChanged()), this, SLOT(selectRace()) );
-
- gender = new QRadioButton*[ROLE_GENDERS];
- for (i=0; iaddWidget( ok, 4, 2 );
- ok->setDefault(TRUE);
- connect( ok, SIGNAL(clicked()), this, SLOT(accept()) );
-
- QPushButton* cancel = new QPushButton("Quit",this);
- l->addWidget( cancel, 5, 2 );
- connect( cancel, SIGNAL(clicked()), this, SLOT(reject()) );
-
- // Randomize race and role, unless specified in config
- int ro = flags.initrole;
- if (ro == ROLE_NONE || ro == ROLE_RANDOM) {
- ro = rn2(nrole);
- if (flags.initrole != ROLE_RANDOM) {
- fully_specified_role = FALSE;
- }
- }
- int ra = flags.initrace;
- if (ra == ROLE_NONE || ra == ROLE_RANDOM) {
- ra = rn2(nrace);
- if (flags.initrace != ROLE_RANDOM) {
- fully_specified_role = FALSE;
- }
- }
-
- // make sure we have a valid combination, honoring
- // the users request if possible.
- bool choose_race_first;
-#ifdef QT_CHOOSE_RACE_FIRST
- choose_race_first = TRUE;
- if (flags.initrole >= 0 && flags.initrace < 0) {
- choose_race_first = FALSE;
- }
-#else
- choose_race_first = FALSE;
- if (flags.initrace >= 0 && flags.initrole < 0) {
- choose_race_first = TRUE;
- }
-#endif
- while (!validrace(ro,ra)) {
- if (choose_race_first) {
- ro = rn2(nrole);
- if (flags.initrole != ROLE_RANDOM) {
- fully_specified_role = FALSE;
- }
- } else {
- ra = rn2(nrace);
- if (flags.initrace != ROLE_RANDOM) {
- fully_specified_role = FALSE;
- }
- }
- }
-
- int g = flags.initgend;
- if (g == -1) {
- g = rn2(ROLE_GENDERS);
- fully_specified_role = FALSE;
- }
- while (!validgend(ro,ra,g)) {
- g = rn2(ROLE_GENDERS);
- }
- gender[g]->setChecked(TRUE);
- selectGender(g);
-
- int a = flags.initalign;
- if (a == -1) {
- a = rn2(ROLE_ALIGNS);
- fully_specified_role = FALSE;
- }
- while (!validalign(ro,ra,a)) {
- a = rn2(ROLE_ALIGNS);
- }
- alignment[a]->setChecked(TRUE);
- selectAlignment(a);
-
- QListViewItem* li;
-
- li = role->firstChild();
- while (ro--) li=li->nextSibling();
- role->setSelected(li,TRUE);
-
- li = race->firstChild();
- while (ra--) li=li->nextSibling();
- race->setSelected(li,TRUE);
-
- flags.initrace = race->selectedItemNumber();
- flags.initrole = role->selectedItemNumber();
-}
-
-
-void NetHackQtPlayerSelector::selectName(const QString& n)
-{
- strncpy(plname,n.latin1(),sizeof(plname)-1);
-}
-
-void NetHackQtPlayerSelector::selectRole()
-{
- int ra = race->selectedItemNumber();
- int ro = role->selectedItemNumber();
- if (ra == -1 || ro == -1) return;
-
-#ifdef QT_CHOOSE_RACE_FIRST
- selectRace();
-#else
- QListViewItem* i=role->currentItem();
- QListViewItem* valid=0;
- int j;
- NhPSListViewItem* item;
- item = (NhPSListViewItem*)role->firstChild();
- for (j=0; roles[j].name.m; j++) {
- bool v = validrace(j,ra);
- item->setSelectable(TRUE);
- if ( !valid && v ) valid = item;
- item=(NhPSListViewItem*)item->nextSibling();
- }
- if ( !validrace(role->selectedItemNumber(),ra) )
- i = valid;
- role->setSelected(i,TRUE);
- item = (NhPSListViewItem*)role->firstChild();
- for (j=0; roles[j].name.m; j++) {
- bool v = validrace(j,ra);
- item->setSelectable(v);
- item->repaint();
- item=(NhPSListViewItem*)item->nextSibling();
- }
-#endif
-
- flags.initrole = role->selectedItemNumber();
- setupOthers();
-}
-
-void NetHackQtPlayerSelector::selectRace()
-{
- int ra = race->selectedItemNumber();
- int ro = role->selectedItemNumber();
- if (ra == -1 || ro == -1) return;
-
-#ifndef QT_CHOOSE_RACE_FIRST
- selectRole();
-#else
- QListViewItem* i=race->currentItem();
- QListViewItem* valid=0;
- int j;
- NhPSListViewItem* item;
- item = (NhPSListViewItem*)race->firstChild();
- for (j=0; races[j].noun; j++) {
- bool v = validrace(ro,j);
- item->setSelectable(TRUE);
- if ( !valid && v ) valid = item;
- item=(NhPSListViewItem*)item->nextSibling();
- }
- if ( !validrace(ro,race->selectedItemNumber()) )
- i = valid;
- race->setSelected(i,TRUE);
- item = (NhPSListViewItem*)race->firstChild();
- for (j=0; races[j].noun; j++) {
- bool v = validrace(ro,j);
- item->setSelectable(v);
- item->repaint();
- item=(NhPSListViewItem*)item->nextSibling();
- }
-#endif
-
- flags.initrace = race->selectedItemNumber();
- setupOthers();
-}
-
-void NetHackQtPlayerSelector::setupOthers()
-{
- int ro = role->selectedItemNumber();
- int ra = race->selectedItemNumber();
- int valid=-1;
- int c=0;
- int j;
- for (j=0; jisChecked() )
- c = j;
- gender[j]->setEnabled(v);
- if ( valid<0 && v ) valid = j;
- }
- if ( !validgend(ro,ra,c) )
- c = valid;
- int k;
- for (k=0; ksetChecked(c==k);
- }
- selectGender(c);
-
- valid=-1;
- for (j=0; jisChecked() )
- c = j;
- alignment[j]->setEnabled(v);
- if ( valid<0 && v ) valid = j;
- }
- if ( !validalign(ro,ra,c) )
- c = valid;
- for (k=0; ksetChecked(c==k);
- }
- selectAlignment(c);
-}
-
-void NetHackQtPlayerSelector::selectGender(int i)
-{
- flags.initgend = i;
-}
-
-void NetHackQtPlayerSelector::selectAlignment(int i)
-{
- flags.initalign = i;
-}
-
-
-void NetHackQtPlayerSelector::done(int i)
-{
- setResult(i);
- qApp->exit_loop();
-}
-
-void NetHackQtPlayerSelector::Quit()
-{
- done(R_Quit);
- qApp->exit_loop();
-}
-
-void NetHackQtPlayerSelector::Random()
-{
- done(R_Rand);
- qApp->exit_loop();
+#include "hack.h"
}
-bool NetHackQtPlayerSelector::Choose()
-{
- if (fully_specified_role) return TRUE;
-
-#if defined(QWS) // probably safe with Qt 3, too (where show!=exec in QDialog).
- if ( qt_compact_mode ) {
- showMaximized();
- } else
+#include "qt_pre.h"
+#include
+#if QT_VERSION >= 0x050000
+#include
#endif
- {
- adjustSize();
- centerOnMain(this);
- }
-
- if ( exec() ) {
- return TRUE;
- } else {
- return FALSE;
- }
-}
-
-
-NetHackQtStringRequestor::NetHackQtStringRequestor(NetHackQtKeyBuffer& ks, const char* p, const char* cancelstr) :
- QDialog(qApp->mainWidget(),"string",FALSE),
- prompt(p,this,"prompt"),
- input(this,"input"),
- keysource(ks)
-{
- cancel=new QPushButton(cancelstr,this);
- connect(cancel,SIGNAL(clicked()),this,SLOT(reject()));
-
- okay=new QPushButton("Okay",this);
- connect(okay,SIGNAL(clicked()),this,SLOT(accept()));
- connect(&input,SIGNAL(returnPressed()),this,SLOT(accept()));
- okay->setDefault(TRUE);
-
- setFocusPolicy(StrongFocus);
-}
-
-void NetHackQtStringRequestor::resizeEvent(QResizeEvent*)
-{
- const int margin=5;
- const int gutter=5;
-
- int h=(height()-margin*2-gutter);
-
- if (strlen(prompt.text()) > 16) {
- h/=3;
- prompt.setGeometry(margin,margin,width()-margin*2,h);
- input.setGeometry(width()*1/5,margin+h+gutter,
- (width()-margin-2-gutter)*4/5,h);
- } else {
- h/=2;
- prompt.setGeometry(margin,margin,(width()-margin*2-gutter)*2/5,h);
- input.setGeometry(prompt.geometry().right()+gutter,margin,
- (width()-margin-2-gutter)*3/5,h);
- }
+#include "qt_post.h"
- cancel->setGeometry(margin,input.geometry().bottom()+gutter,
- (width()-margin*2-gutter)/2,h);
- okay->setGeometry(cancel->geometry().right()+gutter,cancel->geometry().y(),
- cancel->width(),h);
-}
-
-void NetHackQtStringRequestor::SetDefault(const char* d)
-{
- input.setText(d);
-}
+// Many of these headers are not needed here. It's a holdover
+// from when most of the Qt code was in one big file.
+#include "qt_win.h"
+#include "qt_bind.h"
+#include "qt_click.h"
+#include "qt_glyph.h"
+#include "qt_inv.h"
+#include "qt_key.h"
+#include "qt_icon.h"
+#include "qt_map.h"
+#include "qt_menu.h"
+#include "qt_msg.h"
+#include "qt_set.h"
-bool NetHackQtStringRequestor::Get(char* buffer, int maxchar)
-{
- input.setMaxLength(maxchar);
- if (strlen(prompt.text()) > 16) {
- resize(fontMetrics().width(prompt.text())+50,fontMetrics().height()*6);
- } else {
- resize(fontMetrics().width(prompt.text())*2+50,fontMetrics().height()*4);
- }
+#include "qt_clust.h"
- centerOnMain(this);
- show();
- input.setFocus();
- setResult(-1);
- while (result()==-1) {
- // Put keys in buffer (eg. from macros, from out-of-focus input)
- if (!keysource.Empty()) {
- while (!keysource.Empty()) {
- int key=keysource.TopKey();
- int ascii=keysource.TopAscii();
- int state=keysource.GetState();
- if (ascii=='\r' || ascii=='\n') {
- // CR or LF in buffer causes confirmation
- strcpy(buffer,input.text());
- return TRUE;
- } else if (ascii=='\033') {
- return FALSE;
- } else {
- input.fakeEvent(key,ascii,state);
- }
- }
- }
- qApp->enter_loop();
- }
- // XXX Get rid of extra keys, since we couldn't get focus!
- while (!keysource.Empty()) keysource.GetKey();
+namespace nethack_qt_ {
- if (result()) {
- strcpy(buffer,input.text());
- return TRUE;
- } else {
- return FALSE;
- }
-}
-void NetHackQtStringRequestor::done(int i)
+void
+centerOnMain(QWidget *w)
{
- setResult(i);
- qApp->exit_loop();
+ QPoint p(0, 0);
+ QWidget *m = NetHackQtBind::mainWidget();
+ if (m)
+ p = m->mapToGlobal(p);
+ w->move(p.x() + m->width() / 2 - w->width() / 2,
+ p.y() + m->height() / 2 - w->height() / 2);
}
-
NetHackQtWindow::NetHackQtWindow()
{
}
-
NetHackQtWindow::~NetHackQtWindow()
{
}
@@ -1441,3872 +96,22 @@ NetHackQtWindow::~NetHackQtWindow()
// XXX Use "expected ..." for now, abort or default later.
//
void NetHackQtWindow::Clear() { puts("unexpected Clear"); }
-void NetHackQtWindow::Display(bool block) { puts("unexpected Display"); }
-bool NetHackQtWindow::Destroy() { return TRUE; }
-void NetHackQtWindow::CursorTo(int x,int y) { puts("unexpected CursorTo"); }
-void NetHackQtWindow::PutStr(int attr, const char* text) { puts("unexpected PutStr"); }
-void NetHackQtWindow::StartMenu() { puts("unexpected StartMenu"); }
-void NetHackQtWindow::AddMenu(int glyph, const ANY_P* identifier, char ch, char gch, int attr,
- const char* str, bool presel) { puts("unexpected AddMenu"); }
-void NetHackQtWindow::EndMenu(const char* prompt) { puts("unexpected EndMenu"); }
-int NetHackQtWindow::SelectMenu(int how, MENU_ITEM_P **menu_list) { puts("unexpected SelectMenu"); return 0; }
-void NetHackQtWindow::ClipAround(int x,int y) { puts("unexpected ClipAround"); }
-void NetHackQtWindow::PrintGlyph(int x,int y,int glyph) { puts("unexpected PrintGlyph"); }
+void NetHackQtWindow::Display(bool block UNUSED) { puts("unexpected Display"); }
+bool NetHackQtWindow::Destroy() { return true; }
+void NetHackQtWindow::CursorTo(int x UNUSED,int y UNUSED) { puts("unexpected CursorTo"); }
+void NetHackQtWindow::PutStr(int attr UNUSED, const QString& text UNUSED) { puts("unexpected PutStr"); }
+void NetHackQtWindow::StartMenu(bool using_WIN_INVEN UNUSED)
+ { puts("unexpected StartMenu"); }
+void NetHackQtWindow::AddMenu(int glyph UNUSED, const ANY_P* identifier UNUSED,
+ char ch UNUSED, char gch UNUSED, int attr UNUSED, int clr UNUSED,
+ const QString& str UNUSED, unsigned itemflags UNUSED)
+ { puts("unexpected AddMenu"); }
+void NetHackQtWindow::EndMenu(const QString& prompt UNUSED) { puts("unexpected EndMenu"); }
+int NetHackQtWindow::SelectMenu(int how UNUSED, MENU_ITEM_P **menu_list UNUSED)
+ { puts("unexpected SelectMenu"); return 0; }
+void NetHackQtWindow::ClipAround(int x UNUSED,int y UNUSED) { puts("unexpected ClipAround"); }
+void NetHackQtWindow::PrintGlyph(int x UNUSED,int y UNUSED,const glyph_info *glyphinfo UNUSED,const glyph_info *bkglyphinfo UNUSED) { puts("unexpected PrintGlyph"); }
//void NetHackQtWindow::PrintGlyphCompose(int x,int y,int,int) { puts("unexpected PrintGlyphCompose"); }
-void NetHackQtWindow::UseRIP(int how, time_t when) { puts("unexpected UseRIP"); }
-
-
-
-// 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);
-
- setBackgroundColor(black);
- viewport.setBackgroundColor(black);
+void NetHackQtWindow::UseRIP(int how UNUSED, time_t when UNUSED) { puts("unexpected UseRIP"); }
- pet_annotation = QPixmap(qt_compact_mode ? pet_mark_small_xpm : pet_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(StrongFocus);
-#ifdef SAFERHANGUP
- QTimer* deadman = new QTimer(this);
- connect(deadman, SIGNAL(timeout()), SLOT(timeout()));
- deadman->start(2000); // deadman timer every 2 seconds
-#endif
-}
-
-#ifdef SAFERHANGUP
-// The "deadman" timer is received by this slot
-void NetHackQtMapWindow::timeout() {}
-#endif
-
-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 char* text)
-{
- if ( !messages.isEmpty() )
- messages += "\n";
- messages += text;
- QFontMetrics fm = fontMetrics();
- messages_rect = fm.boundingRect(viewport.contentsX(), viewport.contentsY(),
- viewport.width(), 0,
- WordBreak|AlignTop|AlignLeft|DontClip,
- 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()->setSteps(gh,gh);
- viewport.horizontalScrollBar()->setSteps(gw,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);
- recreate(0,0,QPoint(0,0));
-}
-
-QWidget* NetHackQtMapWindow::Widget()
-{
- return &viewport;
-}
-
-void NetHackQtMapWindow::Scroll(int dx, int dy)
-{
- if (viewport.horizontalScrollBar()->isVisible()) {
- while (dx<0) { viewport.horizontalScrollBar()->subtractPage(); dx++; }
- while (dx>0) { viewport.horizontalScrollBar()->addPage(); dx--; }
- }
- if (viewport.verticalScrollBar()->isVisible()) {
- while (dy<0) { viewport.verticalScrollBar()->subtractPage(); dy++; }
- while (dy>0) { viewport.verticalScrollBar()->addPage(); dy--; }
- }
-}
-
-void NetHackQtMapWindow::Clear()
-{
- unsigned short stone=cmap_to_glyph(S_stone);
-
- for (int j=0; jexit_loop();
-}
-
-void NetHackQtMapWindow::mousePressEvent(QMouseEvent* event)
-{
- clicksink.Put(
- event->pos().x()/qt_settings->glyphs().width(),
- event->pos().y()/qt_settings->glyphs().height(),
- event->button()==LeftButton ? CLICK_1 : CLICK_2
- );
- qApp->exit_loop();
-}
-
-#ifdef TEXTCOLOR
-static
-const QPen& nhcolor_to_pen(int c)
-{
- static QPen* pen=0;
- if ( !pen ) {
- pen = new QPen[17];
- pen[0] = QColor(24,24,24); // "black" on black
- pen[1] = Qt::red;
- pen[2] = QColor(0,191,0);
- pen[3] = QColor(127,127,0);
- pen[4] = Qt::blue;
- pen[5] = Qt::magenta;
- pen[6] = Qt::cyan;
- pen[7] = Qt::gray;
- pen[8] = Qt::white; // no color
- pen[9] = QColor(255,127,0);
- pen[10] = QColor(127,255,127);
- pen[11] = Qt::yellow;
- pen[12] = QColor(127,127,255);
- pen[13] = QColor(255,127,255);
- pen[14] = QColor(127,255,255);
- pen[15] = Qt::white;
- pen[16] = QColor(24,24,24); // "black" on black
- }
-
- return pen[c];
-}
-#endif
-
-void NetHackQtMapWindow::paintEvent(QPaintEvent* event)
-{
- QRect area=event->rect();
- QRect garea;
- garea.setCoords(
- QMAX(0,area.left()/qt_settings->glyphs().width()),
- QMAX(0,area.top()/qt_settings->glyphs().height()),
- QMIN(COLNO-1,area.right()/qt_settings->glyphs().width()),
- QMIN(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(), 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).lower() == "-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);
- uchar ch;
- int color, och;
- unsigned special;
-
- painter.setPen( green );
- /* map glyph to character and color */
- (void)mapglyph(g, &och, &color, &special, i, j, 0);
- ch = (uchar)och;
-#ifdef TEXTCOLOR
- painter.setPen( nhcolor_to_pen(color) );
-#endif
- painter.drawText(
- i*qt_settings->glyphs().width(),
- j*qt_settings->glyphs().height(),
- qt_settings->glyphs().width(),
- qt_settings->glyphs().height(),
- AlignCenter,
- (const char*)&ch, 1
- );
- if (glyph_is_pet(g)
-#ifdef TEXTCOLOR
- && ::iflags.hilite_pet
-#endif
- ) {
- painter.drawPixmap(QPoint(i*qt_settings->glyphs().width(),
- j*qt_settings->glyphs().height()),
- pet_annotation);
- }
- }
- }
-
- 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);
- qt_settings->glyphs().drawCell(painter, g, i, j);
- if (glyph_is_pet(g)
-#ifdef TEXTCOLOR
- && ::iflags.hilite_pet
-#endif
- ) {
- painter.drawPixmap(QPoint(i*qt_settings->glyphs().width(),
- j*qt_settings->glyphs().height()),
- pet_annotation);
- }
- }
- }
- }
-
- if (garea.contains(cursor)) {
- if (Is_rogue_level(&u.uz)) {
-#ifdef TEXTCOLOR
- painter.setPen( white );
-#else
- painter.setPen( green ); // REALLY primitive
-#endif
- } else
- {
- int hp100;
- if (u.mtimedone) {
- hp100=u.mhmax ? u.mh*100/u.mhmax : 100;
- } else {
- hp100=u.uhpmax ? u.uhp*100/u.uhpmax : 100;
- }
-
- if (hp100 > 75) painter.setPen(white);
- else if (hp100 > 50) painter.setPen(yellow);
- else if (hp100 > 25) painter.setPen(QColor(0xff,0xbf,0x00)); // orange
- else if (hp100 > 10) painter.setPen(red);
- else painter.setPen(magenta);
- }
-
- painter.drawRect(
- cursor.x()*qt_settings->glyphs().width(),cursor.y()*qt_settings->glyphs().height(),
- qt_settings->glyphs().width(),qt_settings->glyphs().height());
- }
-
- if (area.intersects(messages_rect)) {
- painter.setPen(black);
- painter.drawText(viewport.contentsX()+1,viewport.contentsY()+1,
- viewport.width(),0, WordBreak|AlignTop|AlignLeft|DontClip, messages);
- painter.setPen(white);
- painter.drawText(viewport.contentsX(),viewport.contentsY(),
- viewport.width(),0, WordBreak|AlignTop|AlignLeft|DontClip, messages);
- }
-
- painter.end();
-}
-
-void NetHackQtMapWindow::Display(bool block)
-{
- for (int i=0; iglyphs().width(),
- ch.y()*qt_settings->glyphs().height(),
- ch.width()*qt_settings->glyphs().width(),
- ch.height()*qt_settings->glyphs().height(),
- FALSE
- );
- }
-
- 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 char* 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,int glyph)
-{
- Glyph(x,y)=glyph;
- 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);
-}
-
-
-class NetHackQtScrollText : public QTableView {
- struct UData {
- UData() : text(0), attr(0) { }
- ~UData() { if (text) free(text); }
-
- char* text;
- int attr;
- };
-public:
- int uncleared;
-
- NetHackQtScrollText(int maxlength) :
- uncleared(0),
- maxitems(maxlength),
- first(0),
- count(0),
- item_cycle(maxlength)
- {
- setNumCols(1);
- setCellWidth(200);
- setCellHeight(fontMetrics().height());
- setBackgroundColor(white);
- setTableFlags(Tbl_vScrollBar
- |Tbl_autoHScrollBar
- |Tbl_clipCellPainting
- |Tbl_smoothScrolling);
- }
-
- ~NetHackQtScrollText()
- {
- }
-
- void Scroll(int dx, int dy)
- {
- setXOffset(xOffset()+dx*viewWidth());
- setYOffset(yOffset()+dy*viewHeight());
- }
-
- void insertItem(int attr, const char* text)
- {
- setTopCell(count);
-
- setAutoUpdate(FALSE);
-
- int i;
- if (count cellWidth()) {
- // Get wider.
- setCellWidth(w);
- }
- setTopCell(count);
-
- setAutoUpdate(TRUE);
-
- if (viewHeight() >= totalHeight()-cellHeight()) {
- repaint();
- } else {
- scroll(0,cellHeight());
- }
- }
-
- virtual void setFont(const QFont& font)
- {
- QTableView::setFont(font);
- setCellHeight(fontMetrics().height());
- }
-
-protected:
-
- UData& item(int i)
- {
- return item_cycle[(first+i)%maxitems];
- }
-
- const int maxitems;
- int first, count;
- QArray item_cycle;
-
- int datumWidth(const UData& uitem)
- {
- if (uitem.text) {
- int width=fontMetrics().width(uitem.text)+3;
- if (uitem.attr) {
- // XXX Too expensive to do properly, because
- // XXX we have to set the font of the widget
- // XXX just to get the font metrics information!
- // XXX Could hold a fake widget for that
- // XXX purpose, but this hack is less ugly.
- width+=width/10;
- }
- return width;
- } else {
- return 0;
- }
- }
-
- virtual void setupPainter(QPainter *p)
- {
- // XXX This shouldn't be needed - we set the bg in the constructor.
- p->setBackgroundColor(white);
- }
-
- virtual void paintCell(QPainter *p, int row, int col)
- {
- bool sel=FALSE;
- UData& uitem=item(row);
-
- if (!sel && row < count-uncleared) {
- p->setPen(darkGray);
- } else {
- p->setPen(black);
- }
-
- if (uitem.attr) {
- // XXX only bold
- QFont bold(font().family(),font().pointSize(),QFont::Bold);
- p->setFont(bold);
- }
-
- p->drawText(3, 0, cellWidth(), cellHeight(),
- AlignLeft|AlignVCenter, uitem.text);
-
- if (uitem.attr) {
- p->setFont(font());
- }
- }
-};
-
-NetHackQtMessageWindow::NetHackQtMessageWindow() :
- list(new NetHackQtScrollText(::iflags.msg_history))
-{
- ::iflags.window_inited = 1;
- map = 0;
- connect(qt_settings,SIGNAL(fontChanged()),this,SLOT(updateFont()));
- updateFont();
-}
-
-NetHackQtMessageWindow::~NetHackQtMessageWindow()
-{
- ::iflags.window_inited = 0;
- delete list;
-}
-
-QWidget* NetHackQtMessageWindow::Widget() { return list; }
-
-void NetHackQtMessageWindow::setMap(NetHackQtMapWindow* m)
-{
- map = m;
- updateFont();
-}
-
-void NetHackQtMessageWindow::updateFont()
-{
- list->setFont(qt_settings->normalFont());
- if ( map )
- map->setFont(qt_settings->normalFont());
-}
-
-void NetHackQtMessageWindow::Scroll(int dx, int dy)
-{
- list->Scroll(dx,dy);
-}
-
-void NetHackQtMessageWindow::Clear()
-{
- if ( map )
- map->clearMessages();
- if (list->uncleared) {
- list->uncleared=0;
- changed=TRUE;
- Display(FALSE);
- }
-}
-
-void NetHackQtMessageWindow::Display(bool block)
-{
- if (changed) {
- list->repaint();
- changed=FALSE;
- }
-}
-
-void NetHackQtMessageWindow::PutStr(int attr, const char* text)
-{
-#ifdef USER_SOUNDS
- play_sound_for_message(text);
-#endif
-
- changed=TRUE;
- list->uncleared++;
- list->insertItem(attr,text);
-
- // Force scrollbar to bottom
- // XXX list->setTopItem(list->count());
-
- if ( map )
- map->putMessage(attr, text);
-}
-
-
-
-NetHackQtLabelledIcon::NetHackQtLabelledIcon(QWidget* parent, const char* l) :
- QWidget(parent),
- low_is_good(FALSE),
- prev_value(-123),
- turn_count(-1),
- label(new QLabel(l,this)),
- icon(0)
-{
- initHighlight();
-}
-NetHackQtLabelledIcon::NetHackQtLabelledIcon(QWidget* parent, const char* l, const QPixmap& i) :
- QWidget(parent),
- low_is_good(FALSE),
- prev_value(-123),
- turn_count(-1),
- label(new QLabel(l,this)),
- icon(new QLabel(this))
-{
- setIcon(i);
- initHighlight();
-}
-void NetHackQtLabelledIcon::initHighlight()
-{
- const QPalette& pal=palette();
- const QColorGroup& pa=pal.normal();
- //QColorGroup good(white,darkGreen,pa.light(),pa.dark(),pa.mid(),white,pa.base());
- QColorGroup good(black,green,pa.light(),pa.dark(),pa.mid(),black,pa.base());
- QColorGroup bad(white,red,pa.light(),pa.dark(),pa.mid(),white,pa.base());
- hl_good=pal.copy();
- hl_good.setNormal(good);
- hl_good.setActive(good);
- hl_bad=pal.copy();
- hl_bad.setNormal(bad);
- hl_bad.setActive(bad);
-}
-
-void NetHackQtLabelledIcon::setLabel(const char* t, bool lower)
-{
- if (!label) {
- label=new QLabel(this);
- label->setFont(font());
- resizeEvent(0);
- }
- if (0!=strcmp(label->text(),t)) {
- label->setText(t);
- highlight(lower==low_is_good ? hl_good : hl_bad);
- }
-}
-void NetHackQtLabelledIcon::setLabel(const char* t, long v, long cv, const char* tail)
-{
- char buf[BUFSZ];
- if (v==NoNum) {
- Sprintf(buf,"%s%s",t,tail);
- } else {
- Sprintf(buf,"%s%ld%s",t,v,tail);
- }
- setLabel(buf,cvsetPixmap(i);
- else { icon=new QLabel(this); icon->setPixmap(i); resizeEvent(0); }
- icon->resize(i.width(),i.height());
-}
-void NetHackQtLabelledIcon::setFont(const QFont& f)
-{
- QWidget::setFont(f);
- if (label) label->setFont(f);
-}
-void NetHackQtLabelledIcon::show()
-{
-#if QT_VERSION >= 300
- if (isHidden())
-#else
- if (!isVisible())
-#endif
- highlight(hl_bad);
- QWidget::show();
-}
-void NetHackQtLabelledIcon::highlightWhenChanging()
-{
- turn_count=0;
-}
-void NetHackQtLabelledIcon::lowIsGood()
-{
- low_is_good=TRUE;
-}
-void NetHackQtLabelledIcon::dissipateHighlight()
-{
- if (turn_count>0) {
- turn_count--;
- if (!turn_count)
- unhighlight();
- }
-}
-void NetHackQtLabelledIcon::highlight(const QPalette& hl)
-{
- if (label) { // Surely it is?!
- if (turn_count>=0) {
- label->setPalette(hl);
- turn_count=4;
- // `4' includes this turn, so dissipates after
- // 3 more keypresses.
- } else {
- label->setPalette(palette());
- }
- }
-}
-void NetHackQtLabelledIcon::unhighlight()
-{
- if (label) { // Surely it is?!
- label->setPalette(palette());
- }
-}
-void NetHackQtLabelledIcon::resizeEvent(QResizeEvent*)
-{
- setAlignments();
-
- //int labw=label ? label->fontMetrics().width(label->text()) : 0;
- int labh=label ? label->fontMetrics().height() : 0;
- int icoh=icon ? icon->height() : 0;
- int h=icoh+labh;
- int icoy=(h>height() ? height()-labh-icoh : height()/2-h/2);
- int laby=icoy+icoh;
- if (icon) {
- icon->setGeometry(0,icoy,width(),icoh);
- }
- if (label) {
- label->setGeometry(0,laby,width(),labh);
- }
-}
-
-void NetHackQtLabelledIcon::setAlignments()
-{
- if (label) label->setAlignment(AlignHCenter|AlignVCenter);
- if (icon) icon->setAlignment(AlignHCenter|AlignVCenter);
-}
-
-static void
-tryload(QPixmap& pm, const char* fn)
-{
- if (!pm.load(fn)) {
- QString msg;
- msg.sprintf("Cannot load \"%s\"", fn);
- QMessageBox::warning(0, "IO Error", msg);
- }
-}
-
-NetHackQtStatusWindow::NetHackQtStatusWindow() :
- // Notes:
- // Alignment needs -2 init value, because -1 is an alignment.
- // Armor Class is an schar, so 256 is out of range.
- // Blank value is 0 and should never change.
- name(this,"(name)"),
- dlevel(this,"(dlevel)"),
- str(this,"STR"),
- dex(this,"DEX"),
- con(this,"CON"),
- intel(this,"INT"),
- wis(this,"WIS"),
- cha(this,"CHA"),
- gold(this,"Gold"),
- hp(this,"Hit Points"),
- power(this,"Power"),
- ac(this,"Armour Class"),
- level(this,"Level"),
- exp(this,"Experience"),
- align(this,"Alignment"),
- time(this,"Time"),
- score(this,"Score"),
- hunger(this,""),
- confused(this,"Confused"),
- sick_fp(this,"Sick"),
- sick_il(this,"Ill"),
- blind(this,"Blind"),
- stunned(this,"Stunned"),
- hallu(this,"Hallu"),
- encumber(this,""),
- hline1(this),
- hline2(this),
- hline3(this),
- first_set(TRUE)
-{
- p_str = QPixmap(str_xpm);
- p_str = QPixmap(str_xpm);
- p_dex = QPixmap(dex_xpm);
- p_con = QPixmap(cns_xpm);
- p_int = QPixmap(int_xpm);
- p_wis = QPixmap(wis_xpm);
- p_cha = QPixmap(cha_xpm);
-
- p_chaotic = QPixmap(chaotic_xpm);
- p_neutral = QPixmap(neutral_xpm);
- p_lawful = QPixmap(lawful_xpm);
-
- p_satiated = QPixmap(satiated_xpm);
- p_hungry = QPixmap(hungry_xpm);
-
- p_confused = QPixmap(confused_xpm);
- p_sick_fp = QPixmap(sick_fp_xpm);
- p_sick_il = QPixmap(sick_il_xpm);
- p_blind = QPixmap(blind_xpm);
- p_stunned = QPixmap(stunned_xpm);
- p_hallu = QPixmap(hallu_xpm);
-
- p_encumber[0] = QPixmap(slt_enc_xpm);
- p_encumber[1] = QPixmap(mod_enc_xpm);
- p_encumber[2] = QPixmap(hvy_enc_xpm);
- p_encumber[3] = QPixmap(ext_enc_xpm);
- p_encumber[4] = QPixmap(ovr_enc_xpm);
-
- str.setIcon(p_str);
- dex.setIcon(p_dex);
- con.setIcon(p_con);
- intel.setIcon(p_int);
- wis.setIcon(p_wis);
- cha.setIcon(p_cha);
-
- align.setIcon(p_neutral);
- hunger.setIcon(p_hungry);
-
- confused.setIcon(p_confused);
- sick_fp.setIcon(p_sick_fp);
- sick_il.setIcon(p_sick_il);
- blind.setIcon(p_blind);
- stunned.setIcon(p_stunned);
- hallu.setIcon(p_hallu);
-
- encumber.setIcon(p_encumber[0]);
-
- hline1.setFrameStyle(QFrame::HLine|QFrame::Sunken);
- hline2.setFrameStyle(QFrame::HLine|QFrame::Sunken);
- hline3.setFrameStyle(QFrame::HLine|QFrame::Sunken);
- hline1.setLineWidth(1);
- hline2.setLineWidth(1);
- hline3.setLineWidth(1);
-
- connect(qt_settings,SIGNAL(fontChanged()),this,SLOT(doUpdate()));
- doUpdate();
-}
-
-void NetHackQtStatusWindow::doUpdate()
-{
- const QFont& large=qt_settings->largeFont();
- name.setFont(large);
- dlevel.setFont(large);
-
- const QFont& normal=qt_settings->normalFont();
- str.setFont(normal);
- dex.setFont(normal);
- con.setFont(normal);
- intel.setFont(normal);
- wis.setFont(normal);
- cha.setFont(normal);
- gold.setFont(normal);
- hp.setFont(normal);
- power.setFont(normal);
- ac.setFont(normal);
- level.setFont(normal);
- exp.setFont(normal);
- align.setFont(normal);
- time.setFont(normal);
- score.setFont(normal);
- hunger.setFont(normal);
- confused.setFont(normal);
- sick_fp.setFont(normal);
- sick_il.setFont(normal);
- blind.setFont(normal);
- stunned.setFont(normal);
- hallu.setFont(normal);
- encumber.setFont(normal);
-
- updateStats();
-}
-
-QWidget* NetHackQtStatusWindow::Widget() { return this; }
-
-void NetHackQtStatusWindow::Clear()
-{
-}
-void NetHackQtStatusWindow::Display(bool block)
-{
-}
-void NetHackQtStatusWindow::CursorTo(int,int y)
-{
- cursy=y;
-}
-void NetHackQtStatusWindow::PutStr(int attr, const char* text)
-{
- // do a complete update when line 0 is done (as per X11 fancy status)
- if (cursy==0) updateStats();
-}
-
-void NetHackQtStatusWindow::resizeEvent(QResizeEvent*)
-{
- const float SP_name=0.13; // the (large)
- const float SP_dlev=0.13; // Level 3 in The Dungeons of Doom (large)
- const float SP_atr1=0.25; // STR DEX CON INT WIS CHA
- const float SP_hln1=0.02; // ---
- const float SP_atr2=0.09; // Au HP PW AC LVL EXP
- const float SP_hln2=0.02; // ---
- const float SP_time=0.09; // time score
- const float SP_hln3=0.02; // ---
- const float SP_stat=0.25; // Alignment, Poisoned, Hungry, Sick, etc.
-
- int h=height();
- int x=0,y=0;
-
- int iw; // Width of an item across line
- int lh; // Height of a line of values
-
- lh=int(h*SP_name);
- name.setGeometry(0,0,width(),lh); y+=lh;
- lh=int(h*SP_dlev);
- dlevel.setGeometry(0,y,width(),lh); y+=lh;
-
- lh=int(h*SP_hln1);
- hline1.setGeometry(0,y,width(),lh); y+=lh;
-
- lh=int(h*SP_atr1);
- iw=width()/6;
- str.setGeometry(x,y,iw,lh); x+=iw;
- dex.setGeometry(x,y,iw,lh); x+=iw;
- con.setGeometry(x,y,iw,lh); x+=iw;
- intel.setGeometry(x,y,iw,lh); x+=iw;
- wis.setGeometry(x,y,iw,lh); x+=iw;
- cha.setGeometry(x,y,iw,lh); x+=iw;
- x=0; y+=lh;
-
- lh=int(h*SP_hln2);
- hline2.setGeometry(0,y,width(),lh); y+=lh;
-
- lh=int(h*SP_atr2);
- iw=width()/6;
- gold.setGeometry(x,y,iw,lh); x+=iw;
- hp.setGeometry(x,y,iw,lh); x+=iw;
- power.setGeometry(x,y,iw,lh); x+=iw;
- ac.setGeometry(x,y,iw,lh); x+=iw;
- level.setGeometry(x,y,iw,lh); x+=iw;
- exp.setGeometry(x,y,iw,lh); x+=iw;
- x=0; y+=lh;
-
- lh=int(h*SP_hln3);
- hline3.setGeometry(0,y,width(),lh); y+=lh;
-
- lh=int(h*SP_time);
- iw=width()/3; x+=iw/2;
- time.setGeometry(x,y,iw,lh); x+=iw;
- score.setGeometry(x,y,iw,lh); x+=iw;
- x=0; y+=lh;
-
- lh=int(h*SP_stat);
- iw=width()/9;
- align.setGeometry(x,y,iw,lh); x+=iw;
- hunger.setGeometry(x,y,iw,lh); x+=iw;
- confused.setGeometry(x,y,iw,lh); x+=iw;
- sick_fp.setGeometry(x,y,iw,lh); x+=iw;
- sick_il.setGeometry(x,y,iw,lh); x+=iw;
- blind.setGeometry(x,y,iw,lh); x+=iw;
- stunned.setGeometry(x,y,iw,lh); x+=iw;
- hallu.setGeometry(x,y,iw,lh); x+=iw;
- encumber.setGeometry(x,y,iw,lh); x+=iw;
- x=0; y+=lh;
-}
-
-
-/*
- * Set all widget values to a null string. This is used after all spacings
- * have been calculated so that when the window is popped up we don't get all
- * kinds of funny values being displayed.
- */
-void NetHackQtStatusWindow::nullOut()
-{
-}
-
-void NetHackQtStatusWindow::fadeHighlighting()
-{
- name.dissipateHighlight();
- dlevel.dissipateHighlight();
-
- str.dissipateHighlight();
- dex.dissipateHighlight();
- con.dissipateHighlight();
- intel.dissipateHighlight();
- wis.dissipateHighlight();
- cha.dissipateHighlight();
-
- gold.dissipateHighlight();
- hp.dissipateHighlight();
- power.dissipateHighlight();
- ac.dissipateHighlight();
- level.dissipateHighlight();
- exp.dissipateHighlight();
- align.dissipateHighlight();
-
- time.dissipateHighlight();
- score.dissipateHighlight();
-
- hunger.dissipateHighlight();
- confused.dissipateHighlight();
- sick_fp.dissipateHighlight();
- sick_il.dissipateHighlight();
- blind.dissipateHighlight();
- stunned.dissipateHighlight();
- hallu.dissipateHighlight();
- encumber.dissipateHighlight();
-}
-
-/*
- * Update the displayed status. The current code in botl.c updates
- * two lines of information. Both lines are always updated one after
- * the other. So only do our update when we update the second line.
- *
- * Information on the first line:
- * name, attributes, alignment, score
- *
- * Information on the second line:
- * dlvl, gold, hp, power, ac, {level & exp or HD **}
- * status (hunger, conf, halu, stun, sick, blind), time, encumbrance
- *
- * [**] HD is shown instead of level and exp if mtimedone is non-zero.
- */
-void NetHackQtStatusWindow::updateStats()
-{
- if (!parentWidget()) return;
-
- char buf[BUFSZ];
-
- if (cursy != 0) return; /* do a complete update when line 0 is done */
-
- if (ACURR(A_STR) > 118) {
- Sprintf(buf,"STR:%d",ACURR(A_STR)-100);
- } else if (ACURR(A_STR)==118) {
- Sprintf(buf,"STR:18/**");
- } else if(ACURR(A_STR) > 18) {
- Sprintf(buf,"STR:18/%02d",ACURR(A_STR)-18);
- } else {
- Sprintf(buf,"STR:%d",ACURR(A_STR));
- }
- str.setLabel(buf,NetHackQtLabelledIcon::NoNum,ACURR(A_STR));
-
- dex.setLabel("DEX:",(long)ACURR(A_DEX));
- con.setLabel("CON:",(long)ACURR(A_CON));
- intel.setLabel("INT:",(long)ACURR(A_INT));
- wis.setLabel("WIS:",(long)ACURR(A_WIS));
- cha.setLabel("CHA:",(long)ACURR(A_CHA));
- const char* hung=hu_stat[u.uhs];
- if (hung[0]==' ') {
- hunger.hide();
- } else {
- hunger.setIcon(u.uhs ? p_hungry : p_satiated);
- hunger.setLabel(hung);
- hunger.show();
- }
- if (Confusion) confused.show(); else confused.hide();
- if (Sick) {
- if (u.usick_type & SICK_VOMITABLE) {
- sick_fp.show();
- } else {
- sick_fp.hide();
- }
- if (u.usick_type & SICK_NONVOMITABLE) {
- sick_il.show();
- } else {
- sick_il.hide();
- }
- } else {
- sick_fp.hide();
- sick_il.hide();
- }
- if (Blind) blind.show(); else blind.hide();
- if (Stunned) stunned.show(); else stunned.hide();
- if (Hallucination) hallu.show(); else hallu.hide();
- const char* enc=enc_stat[near_capacity()];
- if (enc[0]==' ' || !enc[0]) {
- encumber.hide();
- } else {
- encumber.setIcon(p_encumber[near_capacity()-1]);
- encumber.setLabel(enc);
- encumber.show();
- }
- Strcpy(buf, plname);
- if ('a' <= buf[0] && buf[0] <= 'z') buf[0] += 'A'-'a';
- Strcat(buf, " the ");
- if (u.mtimedone) {
- char mname[BUFSZ];
- int k = 0;
-
- Strcpy(mname, mons[u.umonnum].mname);
- while(mname[k] != 0) {
- if ((k == 0 || (k > 0 && mname[k-1] == ' '))
- && 'a' <= mname[k] && mname[k] <= 'z')
- {
- mname[k] += 'A' - 'a';
- }
- k++;
- }
- Strcat(buf, mname);
- } else {
- Strcat(buf, rank_of(u.ulevel, pl_character[0], ::flags.female));
- }
- name.setLabel(buf,NetHackQtLabelledIcon::NoNum,u.ulevel);
-
- if (describe_level(buf)) {
- dlevel.setLabel(buf,(bool)TRUE);
- } else {
- Sprintf(buf, "%s, level ", dungeons[u.uz.dnum].dname);
- dlevel.setLabel(buf,(long)depth(&u.uz));
- }
-
- gold.setLabel("Au:", money_cnt(invent));
- if (u.mtimedone) {
- // You're a monster!
-
- Sprintf(buf, "/%d", u.mhmax);
- hp.setLabel("HP:",u.mh > 0 ? u.mh : 0,buf);
- level.setLabel("HD:",(long)mons[u.umonnum].mlevel);
- } else {
- // You're normal.
-
- Sprintf(buf, "/%d", u.uhpmax);
- hp.setLabel("HP:",u.uhp > 0 ? u.uhp : 0,buf);
- level.setLabel("Level:",(long)u.ulevel);
- }
- Sprintf(buf, "/%d", u.uenmax);
- power.setLabel("Pow:",u.uen,buf);
- ac.setLabel("AC:",(long)u.uac);
- if (::flags.showexp) {
- exp.setLabel("Exp:",(long)u.uexp);
- } else
- {
- exp.setLabel("");
- }
- if (u.ualign.type==A_CHAOTIC) {
- align.setIcon(p_chaotic);
- align.setLabel("Chaotic");
- } else if (u.ualign.type==A_NEUTRAL) {
- align.setIcon(p_neutral);
- align.setLabel("Neutral");
- } else {
- align.setIcon(p_lawful);
- align.setLabel("Lawful");
- }
-
- if (::flags.time) time.setLabel("Time:",(long)moves);
- else time.setLabel("");
-#ifdef SCORE_ON_BOTL
- if (::flags.showscore) {
- score.setLabel("Score:",(long)botl_score());
- } else
-#endif
- {
- score.setLabel("");
- }
-
- if (first_set)
- {
- first_set=FALSE;
-
- name.highlightWhenChanging();
- dlevel.highlightWhenChanging();
-
- str.highlightWhenChanging();
- dex.highlightWhenChanging();
- con.highlightWhenChanging();
- intel.highlightWhenChanging();
- wis.highlightWhenChanging();
- cha.highlightWhenChanging();
-
- gold.highlightWhenChanging();
- hp.highlightWhenChanging();
- power.highlightWhenChanging();
- ac.highlightWhenChanging(); ac.lowIsGood();
- level.highlightWhenChanging();
- exp.highlightWhenChanging();
- align.highlightWhenChanging();
-
- //time.highlightWhenChanging();
- score.highlightWhenChanging();
-
- hunger.highlightWhenChanging();
- confused.highlightWhenChanging();
- sick_fp.highlightWhenChanging();
- sick_il.highlightWhenChanging();
- blind.highlightWhenChanging();
- stunned.highlightWhenChanging();
- hallu.highlightWhenChanging();
- encumber.highlightWhenChanging();
- }
-}
-
-/*
- * Turn off hilighted status values after a certain amount of turns.
- */
-void NetHackQtStatusWindow::checkTurnEvents()
-{
-}
-
-
-
-NetHackQtMenuDialog::NetHackQtMenuDialog() :
- QDialog(qApp->mainWidget(),0,FALSE)
-{
-}
-
-void NetHackQtMenuDialog::resizeEvent(QResizeEvent*)
-{
- emit Resized();
-}
-
-void NetHackQtMenuDialog::Accept()
-{
- accept();
-}
-
-void NetHackQtMenuDialog::Reject()
-{
- reject();
-}
-
-void NetHackQtMenuDialog::SetResult(int r)
-{
- setResult(r);
-}
-
-void NetHackQtMenuDialog::done(int i)
-{
- setResult(i);
- qApp->exit_loop();
-}
-
-// Table view columns:
-//
-// [pick-count] [accel] [glyph] [string]
-//
-// Maybe accel should be near string. We'll see.
-// pick-count normally blank.
-// double-clicking or click-on-count gives pop-up entry
-// string is green when selected
-//
-NetHackQtMenuWindow::NetHackQtMenuWindow(NetHackQtKeyBuffer& ks) :
- QTableView(),
- keysource(ks),
- dialog(new NetHackQtMenuDialog()),
- prompt(0),
- pressed(-1)
-{
- setNumCols(4);
- setCellHeight(QMAX(qt_settings->glyphs().height()+1,fontMetrics().height()));
- setBackgroundColor(lightGray);
- setFrameStyle(Panel|Sunken);
- setLineWidth(2);
-
- ok=new QPushButton("Ok",dialog);
- connect(ok,SIGNAL(clicked()),dialog,SLOT(accept()));
-
- cancel=new QPushButton("Cancel",dialog);
- connect(cancel,SIGNAL(clicked()),dialog,SLOT(reject()));
-
- all=new QPushButton("All",dialog);
- connect(all,SIGNAL(clicked()),this,SLOT(All()));
-
- none=new QPushButton("None",dialog);
- connect(none,SIGNAL(clicked()),this,SLOT(ChooseNone()));
-
- invert=new QPushButton("Invert",dialog);
- connect(invert,SIGNAL(clicked()),this,SLOT(Invert()));
-
- search=new QPushButton("Search",dialog);
- connect(search,SIGNAL(clicked()),this,SLOT(Search()));
-
- QPoint pos(0,ok->height());
- recreate(dialog,0,pos);
- prompt.recreate(dialog,0,pos);
-
- setBackgroundColor(lightGray);
-
- connect(dialog,SIGNAL(Resized()),this,SLOT(Layout()));
-
- setTableFlags(Tbl_autoHScrollBar|Tbl_autoVScrollBar
- |Tbl_smoothScrolling|Tbl_clipCellPainting);
- setFocusPolicy(StrongFocus);
-}
-
-NetHackQtMenuWindow::~NetHackQtMenuWindow()
-{
- // Remove from dialog before we destruct it
- recreate(0,0,QPoint(0,0));
- delete dialog;
-}
-
-void NetHackQtMenuWindow::focusInEvent(QFocusEvent *)
-{
- // Don't repaint at all, since nothing is using the focus colour
-}
-void NetHackQtMenuWindow::focusOutEvent(QFocusEvent *)
-{
- // Don't repaint at all, since nothing is using the focus colour
-}
-
-int NetHackQtMenuWindow::cellWidth(int col)
-{
- switch (col) {
- case 0:
- return fontMetrics().width("All ");
- break; case 1:
- return fontMetrics().width(" m ");
- break; case 2:
- return qt_settings->glyphs().width();
- break; case 3:
- return str_width;
- }
- impossible("Extra column (#%d) in MenuWindow",col);
- return 0;
-}
-
-QWidget* NetHackQtMenuWindow::Widget() { return dialog; }
-
-void NetHackQtMenuWindow::StartMenu()
-{
- setNumRows((itemcount=0));
- str_width=200;
- str_fixed=FALSE;
- next_accel=0;
- has_glyphs=FALSE;
-}
-
-NetHackQtMenuWindow::MenuItem::MenuItem() :
- str(0)
-{
-}
-
-NetHackQtMenuWindow::MenuItem::~MenuItem()
-{
- if (str) free((void*)str);
-}
-
-#define STR_MARGIN 4
-
-void NetHackQtMenuWindow::AddMenu(int glyph, const ANY_P* identifier,
- char ch, char gch, int attr, const char* str, bool presel)
-{
- if (!ch && identifier->a_void!=0) {
- // Supply a keyboard accelerator. Limited supply.
- static char accel[]="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
- if (accel[next_accel]) {
- ch=accel[next_accel++];
- }
- }
-
- if ((int)item.size() < itemcount+1) {
- item.resize(itemcount*4+10);
- }
- item[itemcount].glyph=glyph;
- item[itemcount].identifier=*identifier;
- item[itemcount].ch=ch;
- item[itemcount].attr=attr;
- item[itemcount].str=strdup(str);
- item[itemcount].selected=presel;
- item[itemcount].count=-1;
- ++itemcount;
-
- str_fixed=str_fixed || strstr(str," ");
- if (glyph!=NO_GLYPH) has_glyphs=TRUE;
-}
-void NetHackQtMenuWindow::EndMenu(const char* p)
-{
- prompt.setText(p ? p : "");
-}
-void NetHackQtMenuWindow::Layout()
-{
- int butw=totalWidth()/6; // 6 buttons
- int buth=fontMetrics().height()+8; // 8 for spacing & mitres
- int prompth=(prompt.text().isNull() ? 0 : buth);
-
- prompt.setGeometry(6,buth,dialog->width()-6,prompth);
- int h=dialog->height()-buth-prompth;
- setGeometry(0,buth+prompth, dialog->width(), h);
-
- // Below, we take care to use up full width
- int x=0;
- ok->setGeometry(x,0,butw,buth); x+=butw; butw=(dialog->width()-x)/5;
- cancel->setGeometry(x,0,butw,buth); x+=butw; butw=(dialog->width()-x)/4;
- all->setGeometry(x,0,butw,buth); x+=butw; butw=(dialog->width()-x)/3;
- none->setGeometry(x,0,butw,buth); x+=butw; butw=(dialog->width()-x)/2;
- invert->setGeometry(x,0,butw,buth); x+=butw; butw=(dialog->width()-x)/1;
- search->setGeometry(x,0,butw,buth);
-}
-
-int NetHackQtMenuWindow::SelectMenu(int h, MENU_ITEM_P **menu_list)
-{
- setFont(str_fixed ?
- qt_settings->normalFixedFont() : qt_settings->normalFont());
-
- for (int i=0; iglyphs().height()+1,fontMetrics().height()));
- setNumRows(itemcount);
-
- int buth=fontMetrics().height()+8; // 8 for spacing & mitres
-
- how=h;
-
- ok->setEnabled(how!=PICK_ONE);ok->setDefault(how!=PICK_ONE);
- cancel->setEnabled(TRUE);
- all->setEnabled(how==PICK_ANY);
- none->setEnabled(how==PICK_ANY);
- invert->setEnabled(how==PICK_ANY);
- search->setEnabled(how!=PICK_NONE);
-
- dialog->SetResult(-1);
-
- // 20 allows for scrollbar or spacing
- // 4 for frame borders
- int mh = QApplication::desktop()->height()*3/5;
- if ( qt_compact_mode && totalHeight() > mh ) {
- // big, so make it fill
- dialog->showMaximized();
- } else {
- dialog->resize(totalWidth()+20,
- QMIN(totalHeight(), mh)+buth+4+(prompt.text().isNull() ? 0 : buth));
- if ( dialog->width() > QApplication::desktop()->width() )
- dialog->resize(QApplication::desktop()->width(),dialog->height()+16);
- centerOnMain(dialog);
- dialog->show();
- }
-
- setFocus();
- while (dialog->result()<0) {
- // changed the defaults below to the values in wintype.h 000119 - azy
- if (!keysource.Empty()) {
- char k=keysource.GetAscii();
- k=map_menu_cmd(k); /* added 000119 - azy */
- if (k=='\033')
- dialog->Reject();
- else if (k=='\r' || k=='\n' || k==' ')
- dialog->Accept();
- else if (k==MENU_SEARCH)
- Search();
- else if (k==MENU_SELECT_ALL)
- All();
- else if (k==MENU_INVERT_ALL)
- Invert();
- else if (k==MENU_UNSELECT_ALL)
- ChooseNone();
- else {
- for (int i=0; iresult()<0)
- qApp->enter_loop();
- }
- //if ( (nhid != WIN_INVEN || !iflags.perm_invent) ) // doesn't work yet
- {
- dialog->hide();
- }
- int result=dialog->result();
-
- // Consume ^M (which QDialog steals for default button)
- while (!keysource.Empty() &&
- (keysource.TopAscii()=='\n' || keysource.TopAscii()=='\r'))
- keysource.GetAscii();
-
- *menu_list=0;
- if (how==PICK_NONE)
- return result==0 ? -1 : 0;
-
- if (result>0) {
- if (how==PICK_ONE) {
- int i;
- for (i=0; istate()&ShiftButton)) {
- if (event->key()==Key_Prior) {
- setYOffset(yOffset()-viewHeight());
- } else if (event->key()==Key_Next) {
- setYOffset(yOffset()+viewHeight());
- } else {
- event->ignore();
- }
- } else {
- event->ignore();
- }
-}
-
-void NetHackQtMenuWindow::All()
-{
- for (int i=0; iAccept();
- }
- }
-}
-
-
-void NetHackQtMenuWindow::paintCell(QPainter* painter, int row, int col)
-{
- // [pick-count] [accel] [glyph] [string]
-
- MenuItem& i = item[row];
-
- painter->setPen(black);
- painter->setFont(font());
-
- if (i.selected) {
- painter->setPen(darkGreen);
- }
-
- switch (col) {
- case 0:
- if ( i.ch || i.attr!=ATR_INVERSE ) {
- QString text;
- if ( i.selected && i.count == -1 ) {
- if ( i.str[0]>='0' && i.str[0]<='9' )
- text = "All";
- else
- text = "*";
- } else if ( i.count<0 ) {
- text = "-";
- } else {
- text.sprintf("%d",i.count);
- }
- painter->drawText(0,0,cellWidth(col),cellHeight(),
- AlignHCenter|AlignVCenter,text);
- }
- break; case 1:
- if ((signed char)i.ch >= 0) {
- char text[2]={i.ch,0};
- painter->drawText(0,0,cellWidth(col),cellHeight(),
- AlignHCenter|AlignVCenter,text);
- }
- break; case 2:
- if (i.glyph!=NO_GLYPH) {
- // Centered in height
- int y=(cellHeight()-qt_settings->glyphs().height())/2;
- if (y<0) y=0;
- qt_settings->glyphs().drawGlyph(*painter, i.glyph, 0, y);
- }
- break; case 3:
- // XXX should qt_settings have ALL the various fonts
- QFont newfont=font();
-
- if (i.attr) {
- switch(i.attr) {
- case ATR_ULINE:
- newfont.setUnderline(TRUE);
- break; case ATR_BOLD:
- painter->setPen(red);
- break; case ATR_BLINK:
- newfont.setItalic(TRUE);
- break; case ATR_INVERSE:
- newfont=qt_settings->largeFont();
- newfont.setWeight(QFont::Bold);
-
- if (i.selected) {
- painter->setPen(blue);
- } else {
- painter->setPen(darkBlue);
- }
- }
- }
- painter->setFont(newfont);
-
- painter->drawText(STR_MARGIN,0,cellWidth(col),cellHeight(),
- AlignLeft|AlignVCenter,i.str);
- }
-}
-
-void NetHackQtMenuWindow::mousePressEvent(QMouseEvent* event)
-{
- int col=findCol(event->pos().x());
- int row=findRow(event->pos().y());
-
- if (col<0 || row<0 || !item[row].Selectable()) return;
-
- if (how!=PICK_NONE) {
- if (col==0) {
- // Changing count.
- NetHackQtStringRequestor requestor(keysource,"Count:");
- char buf[BUFSZ];
-
- if (item[row].count>0)
- Sprintf(buf,"%d", item[row].count);
- else
- Strcpy(buf, "");
-
- requestor.SetDefault(buf);
- if (requestor.Get(buf)) {
- item[row].count=atoi(buf);
- if (item[row].count==0) {
- item[row].count=-1;
- if (item[row].selected) ToggleSelect(row);
- } else {
- if (!item[row].selected) ToggleSelect(row);
- }
- updateCell(row,0);
- }
- } else {
- pressed=row;
- was_sel=item[row].selected;
- ToggleSelect(row);
- updateCell(row,0);
- }
- }
-}
-
-void NetHackQtMenuWindow::mouseReleaseEvent(QMouseEvent* event)
-{
- if (pressed>=0) {
- int p=pressed;
- pressed=-1;
- updateCell(p,3);
- }
-}
-
-void NetHackQtMenuWindow::mouseMoveEvent(QMouseEvent* event)
-{
- if (pressed>=0) {
- int col=findCol(event->pos().x());
- int row=findRow(event->pos().y());
-
- if (row>=0 && col>=0) {
- if (pressed!=row) {
- // reset to initial state
- if (item[pressed].selected!=was_sel)
- ToggleSelect(pressed);
- } else {
- // reset to new state
- if (item[pressed].selected==was_sel)
- ToggleSelect(pressed);
- }
- }
- }
-}
-
-
-class NetHackQtTextListBox : public QListBox {
-public:
- NetHackQtTextListBox(QWidget* parent) : QListBox(parent) { }
-
- int TotalWidth()
- {
- doLayout();
- return contentsWidth();
- }
- int TotalHeight()
- {
- doLayout();
- return contentsHeight();
- }
-
- virtual void setFont(const QFont &font)
- {
- QListBox::setFont(font);
- }
- void keyPressEvent(QKeyEvent* e)
- {
- QListBox::keyPressEvent(e);
- }
-};
-
-
-QPixmap* NetHackQtRIP::pixmap=0;
-
-NetHackQtRIP::NetHackQtRIP(QWidget* parent) :
- QWidget(parent)
-{
- if (!pixmap) {
- pixmap=new QPixmap;
- tryload(*pixmap, "rip.xpm");
- }
- riplines=0;
- resize(pixmap->width(),pixmap->height());
- setFont(QFont("times",12)); // XXX may need to be configurable
-}
-
-void NetHackQtRIP::setLines(char** l, int n)
-{
- line=l;
- riplines=n;
-}
-
-QSize NetHackQtRIP::sizeHint() const
-{
- return pixmap->size();
-}
-
-void NetHackQtRIP::paintEvent(QPaintEvent* event)
-{
- if ( riplines ) {
- int pix_x=(width()-pixmap->width())/2;
- int pix_y=(height()-pixmap->height())/2;
-
- // XXX positions based on RIP image
- int rip_text_x=pix_x+156;
- int rip_text_y=pix_y+67;
- int rip_text_h=94/riplines;
-
- QPainter painter;
- painter.begin(this);
- painter.drawPixmap(pix_x,pix_y,*pixmap);
- for (int i=0; imainWidget(),0,FALSE),
- keysource(ks),
- use_rip(FALSE),
- str_fixed(FALSE),
- ok("Dismiss",this),
- search("Search",this),
- lines(new NetHackQtTextListBox(this)),
- rip(this)
-{
- ok.setDefault(TRUE);
- connect(&ok,SIGNAL(clicked()),this,SLOT(accept()));
- connect(&search,SIGNAL(clicked()),this,SLOT(Search()));
- connect(qt_settings,SIGNAL(fontChanged()),this,SLOT(doUpdate()));
-
- QVBoxLayout* vb = new QVBoxLayout(this);
- vb->addWidget(&rip);
- QHBoxLayout* hb = new QHBoxLayout(vb);
- hb->addWidget(&ok);
- hb->addWidget(&search);
- vb->addWidget(lines);
-}
-
-void NetHackQtTextWindow::doUpdate()
-{
- update();
-}
-
-
-NetHackQtTextWindow::~NetHackQtTextWindow()
-{
-
-}
-
-QWidget* NetHackQtTextWindow::Widget()
-{
- return this;
-}
-
-bool NetHackQtTextWindow::Destroy()
-{
- return !isVisible();
-}
-
-void NetHackQtTextWindow::UseRIP(int how, time_t when)
-{
-// Code from X11 windowport
-#define STONE_LINE_LEN 16 /* # chars that fit on one line */
-#define NAME_LINE 0 /* line # for player name */
-#define GOLD_LINE 1 /* line # for amount of gold */
-#define DEATH_LINE 2 /* line # for death description */
-#define YEAR_LINE 6 /* line # for year */
-
-static char** rip_line=0;
- if (!rip_line) {
- rip_line=new char*[YEAR_LINE+1];
- for (int i=0; i STONE_LINE_LEN) {
- for(i = STONE_LINE_LEN;
- ((i0 > STONE_LINE_LEN) && i); i--)
- if(dpx[i] == ' ') i0 = i;
- if(!i) i0 = STONE_LINE_LEN;
- }
- tmpchar = dpx[i0];
- dpx[i0] = 0;
- strcpy(rip_line[line], dpx);
- if (tmpchar != ' ') {
- dpx[i0] = tmpchar;
- dpx= &dpx[i0];
- } else dpx= &dpx[i0+1];
- }
-
- /* Put year on stone */
- year = yyyymmdd(when) / 10000L;
- Sprintf(rip_line[YEAR_LINE], "%4ld", year);
-
- rip.setLines(rip_line,YEAR_LINE+1);
-
- use_rip=TRUE;
-}
-
-void NetHackQtTextWindow::Clear()
-{
- lines->clear();
- use_rip=FALSE;
- str_fixed=FALSE;
-}
-
-void NetHackQtTextWindow::Display(bool block)
-{
- if (str_fixed) {
- lines->setFont(qt_settings->normalFixedFont());
- } else {
- lines->setFont(qt_settings->normalFont());
- }
-
- int h=0;
- if (use_rip) {
- h+=rip.height();
- ok.hide();
- search.hide();
- rip.show();
- } else {
- h+=ok.height()*2;
- ok.show();
- search.show();
- rip.hide();
- }
- int mh = QApplication::desktop()->height()*3/5;
- if ( qt_compact_mode && (lines->TotalHeight() > mh || use_rip) ) {
- // big, so make it fill
- showMaximized();
- } else {
- resize(QMAX(use_rip ? rip.width() : 200,
- lines->TotalWidth()+24),
- QMIN(mh, lines->TotalHeight()+h));
- centerOnMain(this);
- show();
- }
- if (block) {
- setResult(-1);
- while (result()==-1) {
- qApp->enter_loop();
- if (result()==-1 && !keysource.Empty()) {
- char k=keysource.GetAscii();
- if (k=='\033' || k==' ' || k=='\r' || k=='\n') {
- accept();
- } else if (k=='/') {
- Search();
- }
- }
- }
- }
-}
-
-void NetHackQtTextWindow::PutStr(int attr, const char* text)
-{
- str_fixed=str_fixed || strstr(text," ");
- lines->insertItem(text);
-}
-
-void NetHackQtTextWindow::done(int i)
-{
- setResult(i+1000);
- hide();
- qApp->exit_loop();
-}
-
-void NetHackQtTextWindow::keyPressEvent(QKeyEvent* e)
-{
- if ( e->ascii() != '\r' && e->ascii() != '\n' && e->ascii() != '\033' )
- lines->keyPressEvent(e);
- else
- QDialog::keyPressEvent(e);
-}
-
-void NetHackQtTextWindow::Search()
-{
- NetHackQtStringRequestor requestor(keysource,"Search for:");
- static char line[256]="";
- requestor.SetDefault(line);
- if (requestor.Get(line)) {
- int current=lines->currentItem();
- for (uint i=1; icount(); i++) {
- int lnum=(i+current)%lines->count();
- QString str=lines->text(lnum);
- if (str.contains(line)) {
- lines->setCurrentItem(lnum);
- lines->centerCurrentItem();
- return;
- }
- }
- lines->setCurrentItem(-1);
- }
-}
-
-
-NetHackQtDelay::NetHackQtDelay(int ms) :
- msec(ms)
-{
-}
-
-void NetHackQtDelay::wait()
-{
- startTimer(msec);
- qApp->enter_loop();
-}
-
-void NetHackQtDelay::timerEvent(QTimerEvent* timer)
-{
- qApp->exit_loop();
- killTimers();
-}
-
-NetHackQtInvUsageWindow::NetHackQtInvUsageWindow(QWidget* parent) :
- QWidget(parent)
-{
-}
-
-void NetHackQtInvUsageWindow::drawWorn(QPainter& painter, obj* nhobj, int x, int y, bool canbe)
-{
- short int glyph;
- if (nhobj)
- glyph=obj_to_glyph(nhobj, rn2_on_display_rng);
- else if (canbe)
- glyph=cmap_to_glyph(S_room);
- else
- glyph=cmap_to_glyph(S_stone);
-
- qt_settings->glyphs().drawCell(painter,glyph,x,y);
-}
-
-void NetHackQtInvUsageWindow::paintEvent(QPaintEvent*)
-{
- // 012
- //
- //0 WhB
- //1 s"w
- //2 gCg
- //3 =A=
- //4 T
- //5 S
-
- QPainter painter;
- painter.begin(this);
-
- // Blanks
- drawWorn(painter,0,0,4,FALSE);
- drawWorn(painter,0,0,5,FALSE);
- drawWorn(painter,0,2,4,FALSE);
- drawWorn(painter,0,2,5,FALSE);
-
- drawWorn(painter,uarm,1,3); // Armour
- drawWorn(painter,uarmc,1,2); // Cloak
- drawWorn(painter,uarmh,1,0); // Helmet
- drawWorn(painter,uarms,0,1); // Shield
- drawWorn(painter,uarmg,0,2); // Gloves - repeated
- drawWorn(painter,uarmg,2,2); // Gloves - repeated
- drawWorn(painter,uarmf,1,5); // Shoes (feet)
- drawWorn(painter,uarmu,1,4); // Undershirt
- drawWorn(painter,uleft,0,3); // RingL
- drawWorn(painter,uright,2,3); // RingR
-
- drawWorn(painter,uwep,2,1); // Weapon
- drawWorn(painter,uswapwep,0,0); // Secondary weapon
- drawWorn(painter,uamul,1,1); // Amulet
- drawWorn(painter,ublindf,2,0); // Blindfold
-
- painter.end();
-}
-
-class SmallToolButton : public QToolButton {
-public:
- SmallToolButton(const QPixmap & pm, const QString &textLabel,
- const QString& grouptext,
- QObject * receiver, const char* slot,
- QToolBar * parent) :
- QToolButton(pm, textLabel,
-#if QT_VERSION < 210
- QString::null,
-#else
- grouptext,
-#endif
- receiver, slot, parent)
- {
- }
-
- 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),
- keysink(ks), dirkey(0)
-{
- QToolBar* toolbar = new QToolBar(this);
-#if QT_VERSION >= 210
- setToolBarsMovable(FALSE);
- toolbar->setHorizontalStretchable(TRUE);
- toolbar->setVerticalStretchable(TRUE);
-#endif
- addToolBar(toolbar);
- menubar = menuBar();
-
- setCaption("Qt NetHack");
- if ( qt_compact_mode )
- setIcon(QPixmap(nh_icon_small));
- else
- setIcon(QPixmap(nh_icon));
-
- QPopupMenu* game=new QPopupMenu;
- QPopupMenu* apparel=new QPopupMenu;
- QPopupMenu* act1=new QPopupMenu;
- QPopupMenu* act2 = qt_compact_mode ? new QPopupMenu : act1;
- QPopupMenu* magic=new QPopupMenu;
- QPopupMenu* info=new QPopupMenu;
-
- QPopupMenu *help;
-
-#ifdef KDE
- help = kapp->getHelpMenu( TRUE, "" );
- help->insertSeparator();
-#else
- help = qt_compact_mode ? info : new QPopupMenu;
-#endif
-
- enum { OnDesktop=1, OnHandhelds=2 };
- struct Macro {
- QPopupMenu* menu;
- const char* name;
- const char* action;
- int flags;
- } item[] = {
- { game, 0, 0, 3},
- { game, "Version\tv", "v", 3},
- { game, "Compilation\tAlt+V", "\366", 3},
- { game, "History\tShift+V", "V", 3},
- { game, "Redraw\tCtrl+R", "\022", 0}, // useless
- { game, "Options\tShift+O", "O", 3},
- { game, "Explore mode\tShift+X", "X", 3},
- { game, 0, 0, 3},
- { game, "Save\tSy", "Sy", 3},
- { game, "Quit\tAlt+Q", "\361", 3},
-
- { apparel, "Apparel off\tShift+A", "A", 2},
- { apparel, "Remove many\tShift+A", "A", 1},
- { apparel, 0, 0, 3},
- { apparel, "Wield weapon\tw", "w", 3},
- { apparel, "Exchange weapons\tx", "x", 3},
- { apparel, "Two weapon combat\t#two", "#tw", 3},
- { apparel, "Load quiver\tShift+Q", "Q", 3},
- { apparel, 0, 0, 3},
- { apparel, "Wear armour\tShift+W", "W", 3},
- { apparel, "Take off armour\tShift+T", "T", 3},
- { apparel, 0, 0, 3},
- { apparel, "Put on non-armour\tShift+P", "P", 3},
- { apparel, "Remove non-armour\tShift+R", "R", 3},
-
- { act1, "Again\tCtrl+A", "\001", 2},
- { act1, 0, 0, 3},
- { act1, "Apply\ta?", "a?", 3},
- { act1, "Chat\tAlt+C", "\343", 3},
- { act1, "Close door\tc", "c", 3},
- { act1, "Down\t>", ">", 3},
- { act1, "Drop many\tShift+D", "D", 2},
- { act1, "Drop\td?", "d?", 2},
- { act1, "Eat\te?", "e?", 2},
- { act1, "Engrave\tShift+E", "E", 3},
- { act1, "Fight\tShift+F", "F", 3},
- { act1, "Fire from quiver\tf", "f", 2},
- { act1, "Force\tAlt+F", "\346", 3},
- { act1, "Get\t,", ",", 2},
- { act1, "Jump\tAlt+J", "\352", 3},
- { act2, "Kick\tCtrl+D", "\004", 2},
- { act2, "Loot\tAlt+L", "\354", 3},
- { act2, "Open door\to", "o", 3},
- { act2, "Pay\tp", "p", 3},
- { act2, "Rest\t.", ".", 2},
- { act2, "Ride\t#ri", "#ri", 3},
- { act2, "Search\ts", "s", 3},
- { act2, "Sit\tAlt+S", "\363", 3},
- { act2, "Throw\tt", "t", 2},
- { act2, "Untrap\t#u", "#u", 3},
- { act2, "Up\t<", "<", 3},
- { act2, "Wipe face\tAlt+W", "\367", 3},
-
- { magic, "Quaff potion\tq?", "q?", 3},
- { magic, "Read scroll/book\tr?", "r?", 3},
- { magic, "Zap wand\tz?", "z?", 3},
- { magic, "Zap spell\tShift+Z", "Z", 3},
- { magic, "Dip\tAlt+D", "\344", 3},
- { magic, "Rub\tAlt+R", "\362", 3},
- { magic, "Invoke\tAlt+I", "\351", 3},
- { magic, 0, 0, 3},
- { magic, "Offer\tAlt+O", "\357", 3},
- { magic, "Pray\tAlt+P", "\360", 3},
- { magic, 0, 0, 3},
- { magic, "Teleport\tCtrl+T", "\024", 3},
- { magic, "Monster action\tAlt+M", "\355", 3},
- { magic, "Turn undead\tAlt+T", "\364", 3},
-
- { help, "Help\t?", "?", 3},
- { help, 0, 0, 3},
- { help, "What is here\t:", ":", 3},
- { help, "What is there\t;", ";", 3},
- { help, "What is...\t/y", "/y", 2},
- { help, 0, 0, 1},
-
- { info, "Inventory\ti", "i", 3},
-#ifdef SLASHEM
- { info, "Angbandish inventory\t*", "*", 3},
-#endif
- { info, "Conduct\t#co", "#co", 3},
- { info, "Discoveries\t\\", "\\", 3},
- { info, "List/reorder spells\t+", "+", 3},
- { info, "Adjust letters\tAlt+A", "\341", 2},
- { info, 0, 0, 3},
- { info, "Name object\tAlt+N", "\356y?", 3},
- { info, "Name object type\tAlt+N", "\356n?", 3},
- { info, "Name creature\tShift+C", "C", 3},
- { info, 0, 0, 3},
- { info, "Qualifications\tAlt+E", "\345", 3},
-
- { 0, 0, 0, 0 }
- };
-
- int i;
- int count=0;
- for (i=0; item[i].menu; i++)
- if (item[i].name) count++;
-
- macro=new const char* [count];
-
- game->insertItem("Qt settings...",1000);
- help->insertItem("About Qt NetHack...",2000);
- //help->insertItem("NetHack Guidebook...",3000);
- help->insertSeparator();
-
- count=0;
- for (i=0; item[i].menu; i++) {
- if ( item[i].flags & (qt_compact_mode ? 1 : 2) ) {
- if (item[i].name) {
- QString name = item[i].name;
- if ( qt_compact_mode ) // accelerators aren't
- name.replace(QRegExp("\t.*"),"");
- item[i].menu->insertItem(name,count);
- macro[count++]=item[i].action;
- } else {
- item[i].menu->insertSeparator();
- }
- }
- }
-
- menubar->insertItem("Game",game);
- menubar->insertItem("Gear",apparel);
-
- if ( qt_compact_mode ) {
- menubar->insertItem("A-J",act1);
- menubar->insertItem("K-Z",act2);
- menubar->insertItem("Magic",magic);
- menubar->insertItem(QPixmap(info_xpm),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()));
- } else {
- menubar->insertItem("Action",act1);
- menubar->insertItem("Magic",magic);
- menubar->insertItem("Info",info);
- menubar->insertSeparator();
- menubar->insertItem("Help",help);
- }
-
- QSignalMapper* sm = new QSignalMapper(this);
- connect(sm, SIGNAL(mapped(const QString&)), this, SLOT(doKeys(const QString&)));
- QToolButton* tb;
- tb = new SmallToolButton( QPixmap(again_xpm),"Again","Action", sm, SLOT(map()), toolbar );
- sm->setMapping(tb, "\001" );
- tb = new SmallToolButton( QPixmap(get_xpm),"Get","Action", sm, SLOT(map()), toolbar );
- sm->setMapping(tb, "," );
- tb = new SmallToolButton( QPixmap(kick_xpm),"Kick","Action", sm, SLOT(map()), toolbar );
- sm->setMapping(tb, "\004" );
- tb = new SmallToolButton( QPixmap(throw_xpm),"Throw","Action", sm, SLOT(map()), toolbar );
- sm->setMapping(tb, "t" );
- tb = new SmallToolButton( QPixmap(fire_xpm),"Fire","Action", sm, SLOT(map()), toolbar );
- sm->setMapping(tb, "f" );
- tb = new SmallToolButton( QPixmap(drop_xpm),"Drop","Action", sm, SLOT(map()), toolbar );
- sm->setMapping(tb, "D" );
- tb = new SmallToolButton( QPixmap(eat_xpm),"Eat","Action", sm, SLOT(map()), toolbar );
- sm->setMapping(tb, "e" );
- tb = new SmallToolButton( QPixmap(rest_xpm),"Rest","Action", sm, SLOT(map()), toolbar );
- sm->setMapping(tb, "." );
- tb = new SmallToolButton( QPixmap(cast_a_xpm),"Cast A","Magic", sm, SLOT(map()), toolbar );
- sm->setMapping(tb, "Za" );
- tb = new SmallToolButton( QPixmap(cast_b_xpm),"Cast B","Magic", sm, SLOT(map()), toolbar );
- sm->setMapping(tb, "Zb" );
- tb = new SmallToolButton( QPixmap(cast_c_xpm),"Cast C","Magic", sm, SLOT(map()), toolbar );
- sm->setMapping(tb, "Zc" );
- if ( !qt_compact_mode ) {
- QWidget* filler = new QWidget(toolbar);
- filler->setBackgroundMode(PaletteButton);
- toolbar->setStretchableWidget(filler);
- }
-
- connect(menubar,SIGNAL(activated(int)),this,SLOT(doMenuItem(int)));
-
-#ifdef KDE
- setMenu (menubar);
-#endif
-
- int x=0,y=0;
- int w=QApplication::desktop()->width()-10; // XXX arbitrary extra space for frame
- int h=QApplication::desktop()->height()-50;
-
- int maxwn;
- int maxhn;
- if (qt_tilewidth != NULL) {
- maxwn = atoi(qt_tilewidth) * COLNO + 10;
- } else {
- maxwn = 1400;
- }
- if (qt_tileheight != NULL) {
- maxhn = atoi(qt_tileheight) * ROWNO * 6/4;
- } else {
- maxhn = 1024;
- }
-
- // 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 QWidgetStack(this);
- setCentralWidget(stack);
- } else {
- setCentralWidget(new QWidget(this));
- invusage = new NetHackQtInvUsageWindow(centralWidget());
- }
-}
-
-void NetHackQtMainWindow::zoomMap()
-{
- qt_settings->toggleGlyphSize();
-}
-
-void NetHackQtMainWindow::raiseMap()
-{
- if ( stack->id(stack->visibleWidget()) == 0 ) {
- zoomMap();
- } else {
- stack->raiseWidget(0);
- }
-}
-
-void NetHackQtMainWindow::raiseMessages()
-{
- stack->raiseWidget(1);
-}
-
-void NetHackQtMainWindow::raiseStatus()
-{
- stack->raiseWidget(2);
-}
-
-class NetHackMimeSourceFactory : public QMimeSourceFactory {
-public:
- const QMimeSource* data(const QString& abs_name) const
- {
- const QMimeSource* r = 0;
- if ( (NetHackMimeSourceFactory*)this == QMimeSourceFactory::defaultFactory() )
- r = QMimeSourceFactory::data(abs_name);
- else
- r = QMimeSourceFactory::defaultFactory()->data(abs_name);
- if ( !r ) {
- int sl = abs_name.length();
- do {
- sl = abs_name.findRev('/',sl-1);
- QString name = sl>=0 ? abs_name.mid(sl+1) : abs_name;
- int dot = name.findRev('.');
- if ( dot >= 0 )
- name = name.left(dot);
- if ( name == "map" )
- r = new QImageDrag(QImage(map_xpm));
- else if ( name == "msg" )
- r = new QImageDrag(QImage(msg_xpm));
- else if ( name == "stat" )
- r = new QImageDrag(QImage(stat_xpm));
- } while (!r && sl>0);
- }
- return r;
- }
-};
-
-void NetHackQtMainWindow::doMenuItem(int id)
-{
- switch (id) {
- case 1000:
- centerOnMain(qt_settings);
- qt_settings->show();
- break;
- case 2000:
- QMessageBox::about(this, "About Qt NetHack", aboutMsg());
- break;
- case 3000: {
- QDialog dlg(this,0,TRUE);
- (new QVBoxLayout(&dlg))->setAutoAdd(TRUE);
- QTextBrowser browser(&dlg);
- NetHackMimeSourceFactory ms;
- browser.setMimeSourceFactory(&ms);
- browser.setSource(QDir::currentDirPath()+"/Guidebook.html");
- if ( qt_compact_mode )
- dlg.showMaximized();
- dlg.exec();
- }
- break;
- default:
- if ( id >= 0 )
- doKeys(macro[id]);
- }
-}
-
-void NetHackQtMainWindow::doKeys(const QString& k)
-{
- keysink.Put(k);
- qApp->exit_loop();
-}
-
-void NetHackQtMainWindow::AddMessageWindow(NetHackQtMessageWindow* window)
-{
- message=window;
- ShowIfReady();
-}
-
-void NetHackQtMainWindow::AddMapWindow(NetHackQtMapWindow* window)
-{
- map=window;
- ShowIfReady();
- connect(map,SIGNAL(resized()),this,SLOT(layout()));
-}
-
-void NetHackQtMainWindow::AddStatusWindow(NetHackQtStatusWindow* window)
-{
- status=window;
- 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(FALSE);
-}
-
-void NetHackQtMainWindow::fadeHighlighting()
-{
- if (status) {
- status->fadeHighlighting();
- }
-}
-
-void NetHackQtMainWindow::layout()
-{
- if ( qt_compact_mode )
- return;
- if (message && map && status) {
- QSize maxs=map->Widget()->maximumSize();
- int maph=QMIN(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(QMAX(0,(c->width()-maxs.width())/2),
- toph,c->width(),maph);
- }
-}
-
-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() >= Key_Left && event->key() <= Key_Down )
- return;
-
- const char* d = Cmd.dirchars;
- switch (event->key()) {
- case Key_Up:
- if ( dirkey == d[0] )
- dirkey = d[1];
- else if ( dirkey == d[4] )
- dirkey = d[3];
- else
- dirkey = d[2];
- break; case Key_Down:
- if ( dirkey == d[0] )
- dirkey = d[7];
- else if ( dirkey == d[4] )
- dirkey = d[5];
- else
- dirkey = d[6];
- break; case Key_Left:
- if ( dirkey == d[2] )
- dirkey = d[1];
- else if ( dirkey == d[6] )
- dirkey = d[7];
- else
- dirkey = d[0];
- break; case Key_Right:
- if ( dirkey == d[2] )
- dirkey = d[3];
- else if ( dirkey == d[6] )
- dirkey = d[5];
- else
- dirkey = d[4];
- break; case Key_Prior:
- dirkey = 0;
- if (message) message->Scroll(0,-1);
- break; case Key_Next:
- dirkey = 0;
- if (message) message->Scroll(0,+1);
- break; case Key_Space:
- if ( flags.rest_on_space ) {
- event->ignore();
- return;
- }
- case Key_Enter:
- if ( map )
- map->clickCursor();
- break; default:
- dirkey = 0;
- event->ignore();
- }
-}
-
-void NetHackQtMainWindow::closeEvent(QCloseEvent* e)
-{
- if ( program_state.something_worth_saving ) {
- switch ( QMessageBox::information( this, "NetHack",
- "This will end your NetHack session",
- "&Save", "&Cancel", 0, 1 ) )
- {
- case 0:
- // See dosave() function
- if (dosave0()) {
- u.uhp = -1;
- NetHackQtBind::qt_exit_nhwindows(0);
- nh_terminate(EXIT_SUCCESS);
- }
- break;
- case 1:
- break; // ignore the event
- }
- } else {
- e->accept();
- }
-}
-
-void NetHackQtMainWindow::ShowIfReady()
-{
- if (message && map && status) {
- QPoint pos(0,0);
- QWidget* p = qt_compact_mode ? stack : centralWidget();
- message->Widget()->recreate(p,0,pos);
- map->Widget()->recreate(p,0,pos);
- status->Widget()->recreate(p,0,pos);
- if ( qt_compact_mode ) {
- message->setMap(map);
- stack->addWidget(map->Widget(), 0);
- stack->addWidget(message->Widget(), 1);
- stack->addWidget(status->Widget(), 2);
- raiseMap();
- } else {
- layout();
- }
- showMaximized();
- } else if (isVisible()) {
- hide();
- }
-}
-
-
-NetHackQtYnDialog::NetHackQtYnDialog(NetHackQtKeyBuffer& keysrc,const char* q,const char* ch,char df) :
- QDialog(qApp->mainWidget(),0,FALSE),
- question(q), choices(ch), def(df),
- keysource(keysrc)
-{
- setCaption("NetHack: Question");
-}
-
-char NetHackQtYnDialog::Exec()
-{
- QString ch(choices);
- int ch_per_line=6;
- QString qlabel;
- QString enable;
- if ( qt_compact_mode && !choices ) {
- // expand choices from prompt
- // ##### why isn't choices set properly???
- const char* c=question;
- while ( *c && *c != '[' )
- c++;
- qlabel = QString(question).left(c-question);
- if ( *c ) {
- c++;
- if ( *c == '-' )
- ch.append(*c++);
- char from=0;
- while ( *c && *c != ']' && *c != ' ' ) {
- if ( *c == '-' ) {
- from = c[-1];
- } else if ( from ) {
- for (char f=from+1; f<=*c; f++)
- ch.append(f);
- from = 0;
- } else {
- ch.append(*c);
- from = 0;
- }
- c++;
- }
- if ( *c == ' ' ) {
- while ( *c && *c != ']' ) {
- if ( *c == '*' || *c == '?' )
- ch.append(*c);
- c++;
- }
- }
- }
- if ( strstr(question, "what direction") ) {
- // We replace this regardless, since sometimes you get choices.
- const char* d = Cmd.dirchars;
- enable=ch;
- ch="";
- ch.append(d[1]);
- ch.append(d[2]);
- ch.append(d[3]);
- ch.append(d[0]);
- ch.append('.');
- ch.append(d[4]);
- ch.append(d[7]);
- ch.append(d[6]);
- ch.append(d[5]);
- ch.append(d[8]);
- ch.append(d[9]);
- ch_per_line = 3;
- def = ' ';
- } else {
- // Hmm... they'll have to use a virtual keyboard
- }
- } else {
- qlabel = question;
- }
- if (!ch.isNull()) {
- QVBoxLayout vb(this);
- vb.setAutoAdd(TRUE);
- bool bigq = qlabel.length()>40;
- if ( bigq ) {
- QLabel* q = new QLabel(qlabel,this);
- q->setAlignment(AlignLeft|WordBreak);
- q->setMargin(4);
- }
- QButtonGroup group(ch_per_line, Horizontal,
- bigq ? QString::null : qlabel, this);
-
- int nchoices=ch.length();
-
- bool allow_count=ch.contains('#');
-
- const int margin=8;
- const int gutter=8;
- const int extra=fontMetrics().height(); // Extra for group
- int x=margin, y=extra+margin;
- int butsize=fontMetrics().height()*2+5;
-
- QPushButton* button;
- for (int i=0; isetEnabled(FALSE);
- }
- button->setFixedSize(butsize,butsize); // Square
- if (ch[i]==def) button->setDefault(TRUE);
- if (i%10==9) {
- // last in row
- x=margin;
- y+=butsize+gutter;
- } else {
- x+=butsize+gutter;
- }
- }
-
- connect(&group,SIGNAL(clicked(int)),this,SLOT(doneItem(int)));
-
- QLabel* lb=0;
- QLineEdit* le=0;
-
- if (allow_count) {
- QHBox *hb = new QHBox(this);
- lb=new QLabel("Count: ",hb);
- le=new QLineEdit(hb);
- }
-
- adjustSize();
- centerOnMain(this);
- show();
- char choice=0;
- char ch_esc=0;
- for (uint i=0; i= 1000 ) {
- choice = ch[result() - 1000].latin1();
- }
- if ( !choice )
- qApp->enter_loop();
- }
- hide();
- if (allow_count && !le->text().isEmpty()) {
- yn_number=atoi(le->text());
- choice='#';
- }
- return choice;
- } else {
- QLabel label(qlabel,this);
- QPushButton cancel("Dismiss",this);
- label.setFrameStyle(QFrame::Box|QFrame::Sunken);
- label.setAlignment(AlignCenter);
- label.resize(fontMetrics().width(qlabel)+60,30+fontMetrics().height());
- cancel.move(width()/2-cancel.width()/2,label.geometry().bottom()+8);
- connect(&cancel,SIGNAL(clicked()),this,SLOT(reject()));
- centerOnMain(this);
- setResult(-1);
- show();
- while (result()<0 && keysource.Empty()) {
- qApp->enter_loop();
- }
- hide();
- if (keysource.Empty()) {
- return '\033';
- } else {
- return keysource.GetAscii();
- }
- }
-}
-void NetHackQtYnDialog::keyPressEvent(QKeyEvent* event)
-{
- // Don't want QDialog's Return/Esc behaviour
- event->ignore();
-}
-
-void NetHackQtYnDialog::doneItem(int i)
-{
- done(i+1000);
-}
-
-void NetHackQtYnDialog::done(int i)
-{
- setResult(i);
- qApp->exit_loop();
-}
-
-NetHackQtGlyphs::NetHackQtGlyphs()
-{
- const char* tile_file = "nhtiles.bmp";
- if ( iflags.wc_tile_file )
- tile_file = iflags.wc_tile_file;
-
- if (!img.load(tile_file)) {
- tile_file = "x11tiles";
- if (!img.load(tile_file)) {
- QString msg;
- msg.sprintf("Cannot load x11tiles or nhtiles.bmp");
- QMessageBox::warning(0, "IO Error", msg);
- } else {
- tiles_per_row = TILES_PER_ROW;
- if (img.width()%tiles_per_row) {
- impossible(
- "Tile file \"%s\" has %d columns, not multiple of row count (%d)",
- tile_file, img.width(), tiles_per_row);
- }
- }
- } else {
- tiles_per_row = 40;
- }
-
- if ( iflags.wc_tile_width )
- tilefile_tile_W = iflags.wc_tile_width;
- else
- tilefile_tile_W = img.width() / tiles_per_row;
- if ( iflags.wc_tile_height )
- tilefile_tile_H = iflags.wc_tile_height;
- else
- tilefile_tile_H = tilefile_tile_W;
-
- setSize(tilefile_tile_W, tilefile_tile_H);
-}
-
-void NetHackQtGlyphs::drawGlyph(QPainter& painter, int glyph, int x, int y)
-{
- int tile = glyph2tile[glyph];
- int px = (tile%tiles_per_row)*width();
- int py = tile/tiles_per_row*height();
-
- painter.drawPixmap(
- x,
- y,
- pm,
- px,py,
- width(),height()
- );
-}
-void NetHackQtGlyphs::drawCell(QPainter& painter, int glyph, int cellx, int celly)
-{
- drawGlyph(painter,glyph,cellx*width(),celly*height());
-}
-void NetHackQtGlyphs::setSize(int w, int h)
-{
- if ( size == QSize(w,h) )
- return;
-
- bool was1 = size == pm1.size();
- size = QSize(w,h);
- if (!w || !h)
- return; // Still not decided
-
- if ( size == pm1.size() ) {
- pm = pm1;
- return;
- }
- if ( size == pm2.size() ) {
- pm = pm2;
- return;
- }
-
- if (w==tilefile_tile_W && h==tilefile_tile_H) {
- pm.convertFromImage(img);
- } else {
- QApplication::setOverrideCursor( Qt::waitCursor );
- QImage scaled = img.smoothScale(
- w*img.width()/tilefile_tile_W,
- h*img.height()/tilefile_tile_H
- );
- pm.convertFromImage(scaled,Qt::ThresholdDither|Qt::PreferDither);
- QApplication::restoreOverrideCursor();
- }
- (was1 ? pm2 : pm1) = pm;
-}
-
-
-//////////////////////////////////////////////////////////////
-//
-// The ugly C binding classes...
-//
-//////////////////////////////////////////////////////////////
-
-
-NetHackQtMenuOrTextWindow::NetHackQtMenuOrTextWindow(NetHackQtKeyBuffer& ks) :
- actual(0),
- keysource(ks)
-{
-}
-
-QWidget* NetHackQtMenuOrTextWindow::Widget()
-{
- if (!actual) impossible("Widget called before we know if Menu or Text");
- return actual->Widget();
-}
-
-// Text
-void NetHackQtMenuOrTextWindow::Clear()
-{
- if (!actual)
- impossible("Clear called before we know if Menu or Text");
- else
- actual->Clear();
-}
-
-void NetHackQtMenuOrTextWindow::Display(bool block)
-{
- if (!actual)
- impossible("Display called before we know if Menu or Text");
- else
- actual->Display(block);
-}
-
-bool NetHackQtMenuOrTextWindow::Destroy()
-{
- bool res = FALSE;
-
- if (!actual)
- impossible("Destroy called before we know if Menu or Text");
- else
- res = actual->Destroy();
-
- return res;
-}
-
-void NetHackQtMenuOrTextWindow::PutStr(int attr, const char* text)
-{
- if (!actual) actual=new NetHackQtTextWindow(keysource);
- actual->PutStr(attr,text);
-}
-
-// Menu
-void NetHackQtMenuOrTextWindow::StartMenu()
-{
- if (!actual) actual=new NetHackQtMenuWindow(keysource);
- actual->StartMenu();
-}
-
-void NetHackQtMenuOrTextWindow::AddMenu(int glyph, const ANY_P* identifier, char ch, char gch, int attr,
- const char* str, bool presel)
-{
- if (!actual) impossible("AddMenu called before we know if Menu or Text");
- actual->AddMenu(glyph,identifier,ch,gch,attr,str,presel);
-}
-
-void NetHackQtMenuOrTextWindow::EndMenu(const char* prompt)
-{
- if (!actual) impossible("EndMenu called before we know if Menu or Text");
- actual->EndMenu(prompt);
-}
-
-int NetHackQtMenuOrTextWindow::SelectMenu(int how, MENU_ITEM_P **menu_list)
-{
- if (!actual) impossible("SelectMenu called before we know if Menu or Text");
- return actual->SelectMenu(how,menu_list);
-}
-
-
-// XXX Should be from Options
-//
-// XXX Hmm. Tricky part is that perhaps some macros should only be active
-// XXX when a key is about to be gotten. For example, the user could
-// XXX define "-" to do "E-yyyyyyyy\r", but would still need "-" for
-// XXX other purposes. Maybe just too bad.
-//
-struct {
- int key;
- int state;
- const char* macro;
-} key_macro[]={
- { Qt::Key_F1, 0, "n100." }, // Rest (x100)
- { Qt::Key_F2, 0, "n20s" }, // Search (x20)
- { Qt::Key_F3, 0, "o8o4o6o2o8o4o6o2o8o4o6o2" }, // Open all doors (x3)
- { Qt::Key_Tab, 0, "\001" },
- { 0, 0, 0 }
-};
-
-
-NetHackQtBind::NetHackQtBind(int& argc, char** argv) :
-#ifdef KDE
- KApplication(argc,argv)
-#elif defined(QWS) // not quite the right condition
- QPEApplication(argc,argv)
-#else
- QApplication(argc,argv)
-#endif
-{
- QPixmap pm("nhsplash.xpm");
- if ( iflags.wc_splash_screen && !pm.isNull() ) {
- QVBox *vb = new QVBox(0,0,
- WStyle_Customize | WStyle_NoBorder | nh_WX11BypassWM | WStyle_StaysOnTop );
- splash = vb;
- QLabel *lsplash = new QLabel(vb);
- lsplash->setAlignment(AlignCenter);
- lsplash->setPixmap(pm);
- QLabel* capt = new QLabel("Loading...",vb);
- capt->setAlignment(AlignCenter);
- if ( pm.mask() ) {
- lsplash->setFixedSize(pm.size());
- lsplash->setMask(*pm.mask());
- }
- splash->move((QApplication::desktop()->width()-pm.width())/2,
- (QApplication::desktop()->height()-pm.height())/2);
- //splash->setGeometry(0,0,100,100);
- if ( qt_compact_mode ) {
- splash->showMaximized();
- } else {
- vb->setFrameStyle(QFrame::WinPanel|QFrame::Raised);
- vb->setMargin(10);
- splash->adjustSize();
- splash->show();
- }
-
- // force content refresh outside event loop
- splash->repaint(FALSE);
- lsplash->repaint(FALSE);
- capt->repaint(FALSE);
- qApp->flushX();
-
- } else {
- splash = 0;
- }
- main = new NetHackQtMainWindow(keybuffer);
-#if defined(QWS) // not quite the right condition
- showMainWidget(main);
-#else
- setMainWidget(main);
-#endif
- qt_settings=new NetHackQtSettings(main->width(),main->height());
-}
-
-void NetHackQtBind::qt_init_nhwindows(int* argc, char** argv)
-{
-#ifdef UNIX
-// Userid control
-//
-// Michael Hohmuth ...
-//
-// As the game runs setuid games, it must seteuid(getuid()) before
-// calling XOpenDisplay(), and reset the euid afterwards.
-// Otherwise, it can't read the $HOME/.Xauthority file and whines about
-// not being able to open the X display (if a magic-cookie
-// authorization mechanism is being used).
-
- uid_t gamesuid=geteuid();
- seteuid(getuid());
-#endif
-
- QApplication::setColorSpec(ManyColor);
- instance=new NetHackQtBind(*argc,argv);
-
-#ifdef UNIX
- seteuid(gamesuid);
-#endif
-
-#ifdef _WS_WIN_
- // This nethack engine feature should be moved into windowport API
- nt_kbhit = NetHackQtBind::qt_kbhit;
-#endif
-}
-
-int NetHackQtBind::qt_kbhit()
-{
- return !keybuffer.Empty();
-}
-
-static bool have_asked = FALSE;
-
-void NetHackQtBind::qt_player_selection()
-{
- if ( !have_asked )
- qt_askname();
-}
-
-NetHackQtSavedGameSelector::NetHackQtSavedGameSelector(const char** saved) :
- QDialog(qApp->mainWidget(),"sgsel",TRUE)
-{
- QVBoxLayout *vbl = new QVBoxLayout(this,6);
- QHBox* hb;
-
- QLabel* logo = new QLabel(this); vbl->addWidget(logo);
- logo->setAlignment(AlignCenter);
- logo->setPixmap(QPixmap("nhsplash.xpm"));
- QLabel* attr = new QLabel("by the NetHack DevTeam",this);
- attr->setAlignment(AlignCenter);
- vbl->addWidget(attr);
- vbl->addStretch(2);
- /*
- QLabel* logo = new QLabel(hb);
- hb = new QHBox(this);
- vbl->addWidget(hb, AlignCenter);
- logo->setPixmap(QPixmap(nh_icon));
- logo->setAlignment(AlignRight|AlignVCenter);
- new QLabel(nh_attribution,hb);
- */
-
- hb = new QHBox(this);
- vbl->addWidget(hb, AlignCenter);
- QPushButton* q = new QPushButton("Quit",hb);
- connect(q, SIGNAL(clicked()), this, SLOT(reject()));
- QPushButton* c = new QPushButton("New Game",hb);
- connect(c, SIGNAL(clicked()), this, SLOT(accept()));
- c->setDefault(TRUE);
-
- QButtonGroup* bg = new QButtonGroup(3, Horizontal, "Saved Characters",this);
- vbl->addWidget(bg);
- connect(bg, SIGNAL(clicked(int)), this, SLOT(done(int)));
- for (int i=0; saved[i]; i++) {
- QPushButton* b = new QPushButton(saved[i],bg);
- bg->insert(b, i+2);
- }
-}
-
-int NetHackQtSavedGameSelector::choose()
-{
-#if defined(QWS) // probably safe with Qt 3, too (where show!=exec in QDialog).
- if ( qt_compact_mode )
- showMaximized();
-#endif
- return exec()-2;
-}
-
-void NetHackQtBind::qt_askname()
-{
- have_asked = TRUE;
-
- // We do it all here, and nothing in askname
-
- char** saved = get_saved_games();
- int ch = -1;
- if ( saved && *saved ) {
- if ( splash ) splash->hide();
- NetHackQtSavedGameSelector sgsel((const char**)saved);
- ch = sgsel.choose();
- if ( ch >= 0 )
- strcpy(plname,saved[ch]);
- }
- free_saved_games(saved);
-
- switch (ch) {
- case -1:
- if ( splash ) splash->hide();
- if (NetHackQtPlayerSelector(keybuffer).Choose())
- return;
- case -2:
- break;
- default:
- return;
- }
-
- // Quit
- clearlocks();
- qt_exit_nhwindows(0);
- nh_terminate(0);
-}
-
-void NetHackQtBind::qt_get_nh_event()
-{
-}
-
-#if defined(QWS)
-// Kludge to access lastWindowClosed() signal.
-class TApp : public QApplication {
-public:
- TApp(int& c, char**v) : QApplication(c,v) {}
- void lwc() { emit lastWindowClosed(); }
-};
-#endif
-
-void NetHackQtBind::qt_exit_nhwindows(const char *)
-{
-#if defined(QWS)
- // Avoids bug in SHARP SL5500
- ((TApp*)qApp)->lwc();
- qApp->quit();
-#endif
-
- delete instance; // ie. qApp
-}
-
-void NetHackQtBind::qt_suspend_nhwindows(const char *)
-{
-}
-
-void NetHackQtBind::qt_resume_nhwindows()
-{
-}
-
-static QArray id_to_window;
-
-winid NetHackQtBind::qt_create_nhwindow(int type)
-{
- winid id;
- for (id = 0; id < (winid) id_to_window.size(); id++) {
- if ( !id_to_window[id] )
- break;
- }
- if ( id == (winid) id_to_window.size() )
- id_to_window.resize(id+1);
-
- NetHackQtWindow* window=0;
-
- switch (type) {
- case NHW_MAP: {
- NetHackQtMapWindow* w=new NetHackQtMapWindow(clickbuffer);
- main->AddMapWindow(w);
- window=w;
- } break; case NHW_MESSAGE: {
- NetHackQtMessageWindow* w=new NetHackQtMessageWindow;
- main->AddMessageWindow(w);
- window=w;
- } break; case NHW_STATUS: {
- NetHackQtStatusWindow* w=new NetHackQtStatusWindow;
- main->AddStatusWindow(w);
- window=w;
- } break; case NHW_MENU:
- window=new NetHackQtMenuOrTextWindow(keybuffer);
- break; case NHW_TEXT:
- window=new NetHackQtTextWindow(keybuffer);
- }
-
- window->nhid = id;
-
- // Note: use of isHidden does not work with Qt 2.1
- if ( splash
-#if QT_VERSION >= 300
- && !main->isHidden()
-#else
- && main->isVisible()
-#endif
- )
- {
- delete splash;
- splash = 0;
- }
-
- id_to_window[id] = window;
- return id;
-}
-
-void NetHackQtBind::qt_clear_nhwindow(winid wid)
-{
- NetHackQtWindow* window=id_to_window[wid];
- window->Clear();
-}
-
-void NetHackQtBind::qt_display_nhwindow(winid wid, BOOLEAN_P block)
-{
- NetHackQtWindow* window=id_to_window[wid];
- window->Display(block);
-}
-
-void NetHackQtBind::qt_destroy_nhwindow(winid wid)
-{
- NetHackQtWindow* window=id_to_window[wid];
- main->RemoveWindow(window);
- if (window->Destroy())
- delete window;
- id_to_window[wid] = 0;
-}
-
-void NetHackQtBind::qt_curs(winid wid, int x, int y)
-{
- NetHackQtWindow* window=id_to_window[wid];
- window->CursorTo(x,y);
-}
-
-void NetHackQtBind::qt_putstr(winid wid, int attr, const char *text)
-{
- NetHackQtWindow* window=id_to_window[wid];
- window->PutStr(attr,text);
-}
-
-void NetHackQtBind::qt_display_file(const char *filename, BOOLEAN_P must_exist)
-{
- NetHackQtTextWindow* window=new NetHackQtTextWindow(keybuffer);
- bool complain = FALSE;
-
-#ifdef DLB
- {
- dlb *f;
- char buf[BUFSZ];
- char *cr;
-
- window->Clear();
- f = dlb_fopen(filename, "r");
- if (!f) {
- complain = must_exist;
- } else {
- while (dlb_fgets(buf, BUFSZ, f)) {
- if ((cr = index(buf, '\n')) != 0) *cr = 0;
-#ifdef MSDOS
- if ((cr = index(buf, '\r')) != 0) *cr = 0;
-#endif
- if (index(buf, '\t') != 0) (void) tabexpand(buf);
- window->PutStr(ATR_NONE, buf);
- }
- window->Display(FALSE);
- (void) dlb_fclose(f);
- }
- }
-#else
- QFile file(filename);
-
- if (file.open(IO_ReadOnly)) {
- char line[128];
- while (file.readLine(line,127) >= 0) {
- line[strlen(line)-1]=0;// remove newline
- window->PutStr(ATR_NONE,line);
- }
- window->Display(FALSE);
- } else {
- complain = must_exist;
- }
-#endif
-
- if (complain) {
- QString message;
- message.sprintf("File not found: %s\n",filename);
- QMessageBox::message("File Error", (const char*)message, "Ignore");
- }
-}
-
-void NetHackQtBind::qt_start_menu(winid wid)
-{
- NetHackQtWindow* window=id_to_window[wid];
- window->StartMenu();
-}
-
-void NetHackQtBind::qt_add_menu(winid wid, int glyph,
- const ANY_P * identifier, CHAR_P ch, CHAR_P gch, int attr,
- const char *str, BOOLEAN_P presel)
-{
- NetHackQtWindow* window=id_to_window[wid];
- window->AddMenu(glyph, identifier, ch, gch, attr, str, presel);
-}
-
-void NetHackQtBind::qt_end_menu(winid wid, const char *prompt)
-{
- NetHackQtWindow* window=id_to_window[wid];
- window->EndMenu(prompt);
-}
-
-int NetHackQtBind::qt_select_menu(winid wid, int how, MENU_ITEM_P **menu_list)
-{
- NetHackQtWindow* window=id_to_window[wid];
- return window->SelectMenu(how,menu_list);
-}
-
-void NetHackQtBind::qt_update_inventory()
-{
- if (main)
- main->updateInventory();
- /* doesn't work yet
- if (program_state.something_worth_saving && iflags.perm_invent)
- display_inventory(NULL, FALSE);
- */
-}
-
-void NetHackQtBind::qt_mark_synch()
-{
-}
-
-void NetHackQtBind::qt_wait_synch()
-{
-}
-
-void NetHackQtBind::qt_cliparound(int x, int y)
-{
- // XXXNH - winid should be a parameter!
- qt_cliparound_window(WIN_MAP,x,y);
-}
-
-void NetHackQtBind::qt_cliparound_window(winid wid, int x, int y)
-{
- NetHackQtWindow* window=id_to_window[wid];
- window->ClipAround(x,y);
-}
-void NetHackQtBind::qt_print_glyph(winid wid,XCHAR_P x,XCHAR_P y,int glyph, int bkglyph)
-{
- NetHackQtWindow* window=id_to_window[wid];
- window->PrintGlyph(x,y,glyph);
-}
-//void NetHackQtBind::qt_print_glyph_compose(winid wid,XCHAR_P x,XCHAR_P y,int glyph1, int glyph2)
-//{
- //NetHackQtWindow* window=id_to_window[wid];
- //window->PrintGlyphCompose(x,y,glyph1,glyph2);
-//}
-
-void NetHackQtBind::qt_raw_print(const char *str)
-{
- puts(str);
-}
-
-void NetHackQtBind::qt_raw_print_bold(const char *str)
-{
- puts(str);
-}
-
-int NetHackQtBind::qt_nhgetch()
-{
- if (main)
- main->fadeHighlighting();
-
- // Process events until a key arrives.
- //
- while (keybuffer.Empty()
-#ifdef SAFERHANGUP
- && !program_state.done_hup
-#endif
- ) {
- qApp->enter_loop();
- }
-
-#ifdef SAFERHANGUP
- if (program_state.done_hup && keybuffer.Empty()) return '\033';
-#endif
- return keybuffer.GetAscii();
-}
-
-int NetHackQtBind::qt_nh_poskey(int *x, int *y, int *mod)
-{
- if (main)
- main->fadeHighlighting();
-
- // Process events until a key or map-click arrives.
- //
- while (keybuffer.Empty() && clickbuffer.Empty()
-#ifdef SAFERHANGUP
- && !program_state.done_hup
-#endif
- ) {
- qApp->enter_loop();
- }
-#ifdef SAFERHANGUP
- if (program_state.done_hup && keybuffer.Empty()) return '\033';
-#endif
- if (!keybuffer.Empty()) {
- return keybuffer.GetAscii();
- } else {
- *x=clickbuffer.NextX();
- *y=clickbuffer.NextY();
- *mod=clickbuffer.NextMod();
- clickbuffer.Get();
- return 0;
- }
-}
-
-void NetHackQtBind::qt_nhbell()
-{
- QApplication::beep();
-}
-
-int NetHackQtBind::qt_doprev_message()
-{
- // Don't need it - uses scrollbar
- // XXX but could make this a shortcut
- return 0;
-}
-
-char NetHackQtBind::qt_yn_function(const char *question, const char *choices, CHAR_P def)
-{
- if (qt_settings->ynInMessages() && WIN_MESSAGE!=WIN_ERR) {
- // Similar to X11 windowport `slow' feature.
-
- char message[BUFSZ];
- char yn_esc_map='\033';
-
- if (choices) {
- char *cb, choicebuf[QBUFSZ];
- Strcpy(choicebuf, choices);
- if ((cb = index(choicebuf, '\033')) != 0) {
- // anything beyond is hidden
- *cb = '\0';
- }
- (void)strncpy(message, question, QBUFSZ-1);
- message[QBUFSZ-1] = '\0';
- Sprintf(eos(message), " [%s]", choicebuf);
- if (def) Sprintf(eos(message), " (%c)", def);
- Strcat(message, " ");
- // escape maps to 'q' or 'n' or default, in that order
- yn_esc_map = (index(choices, 'q') ? 'q' :
- (index(choices, 'n') ? 'n' : def));
- } else {
- Strcpy(message, question);
- }
-
-#ifdef USE_POPUPS
- // Improve some special-cases (DIRKS 08/02/23)
- if (strcmp (choices,"ynq") == 0) {
- switch (QMessageBox::information (qApp->mainWidget(),"NetHack",question,"&Yes","&No","&Quit",0,2))
- {
- case 0: return 'y';
- case 1: return 'n';
- case 2: return 'q';
- }
- }
-
- if (strcmp (choices,"yn") == 0) {
- switch (QMessageBox::information(qApp->mainWidget(),"NetHack",question,"&Yes", "&No",0,1))
- {
- case 0: return 'y';
- case 1: return 'n';
- }
- }
-#endif
-
- NetHackQtBind::qt_putstr(WIN_MESSAGE, ATR_BOLD, message);
-
- int result=-1;
- while (result<0) {
- char ch=NetHackQtBind::qt_nhgetch();
- if (ch=='\033') {
- result=yn_esc_map;
- } else if (choices && !index(choices,ch)) {
- if (def && (ch==' ' || ch=='\r' || ch=='\n')) {
- result=def;
- } else {
- NetHackQtBind::qt_nhbell();
- // and try again...
- }
- } else {
- result=ch;
- }
- }
-
- NetHackQtBind::qt_clear_nhwindow(WIN_MESSAGE);
-
- return result;
- } else {
- NetHackQtYnDialog dialog(keybuffer,question,choices,def);
- return dialog.Exec();
- }
-}
-
-void NetHackQtBind::qt_getlin(const char *prompt, char *line)
-{
- NetHackQtStringRequestor requestor(keybuffer,prompt);
- if (!requestor.Get(line)) {
- line[0]=0;
- }
-}
-
-NetHackQtExtCmdRequestor::NetHackQtExtCmdRequestor(NetHackQtKeyBuffer& ks) :
- QDialog(qApp->mainWidget(), "ext-cmd", FALSE),
- keysource(ks)
-{
- int marg=4;
- QVBoxLayout *l = new QVBoxLayout(this,marg,marg);
-
- QPushButton* can = new QPushButton("Cancel", this);
- can->setDefault(TRUE);
- can->setMinimumSize(can->sizeHint());
- l->addWidget(can);
-
- QButtonGroup *group=new QButtonGroup("",0);
- QGroupBox *grid=new QGroupBox("Extended commands",this);
- l->addWidget(grid);
-
- int i;
- int butw=50;
- QFontMetrics fm = fontMetrics();
- for (i=0; extcmdlist[i].ef_txt; i++) {
- butw = QMAX(butw,30+fm.width(extcmdlist[i].ef_txt));
- }
- int ncols=4;
- int nrows=(i+ncols-1)/ncols;
-
- QVBoxLayout* bl = new QVBoxLayout(grid,marg);
- bl->addSpacing(fm.height());
- QGridLayout* gl = new QGridLayout(nrows,ncols,marg);
- bl->addLayout(gl);
- for (i=0; extcmdlist[i].ef_txt; i++) {
- QPushButton* pb=new QPushButton(extcmdlist[i].ef_txt, grid);
- pb->setMinimumSize(butw,pb->sizeHint().height());
- group->insert(pb);
- gl->addWidget(pb,i/ncols,i%ncols);
- }
- connect(group,SIGNAL(clicked(int)),this,SLOT(done(int)));
-
- bl->activate();
- l->activate();
- resize(1,1);
-
- connect(can,SIGNAL(clicked()),this,SLOT(cancel()));
-}
-
-void NetHackQtExtCmdRequestor::cancel()
-{
- setResult(-1);
- qApp->exit_loop();
-}
-
-void NetHackQtExtCmdRequestor::done(int i)
-{
- setResult(i);
- qApp->exit_loop();
-}
-
-int NetHackQtExtCmdRequestor::get()
-{
- const int none = -10;
- char str[32];
- int cursor=0;
- resize(1,1); // pack
- centerOnMain(this);
- show();
- setResult(none);
- while (result()==none) {
- while (result()==none && !keysource.Empty()) {
- char k=keysource.GetAscii();
- if (k=='\r' || k=='\n' || k==' ' || k=='\033') {
- setResult(-1);
- } else {
- str[cursor++] = k;
- int r=-1;
- for (int i=0; extcmdlist[i].ef_txt; i++) {
- if (qstrnicmp(str, extcmdlist[i].ef_txt, cursor)==0) {
- if ( r == -1 )
- r = i;
- else
- r = -2;
- }
- }
- if ( r == -1 ) { // no match!
- QApplication::beep();
- cursor=0;
- } else if ( r != -2 ) { // only one match
- setResult(r);
- }
- }
- }
- if (result()==none)
- qApp->enter_loop();
- }
- hide();
- return result();
-}
-
-
-int NetHackQtBind::qt_get_ext_cmd()
-{
- NetHackQtExtCmdRequestor requestor(keybuffer);
- return requestor.get();
-}
-
-void NetHackQtBind::qt_number_pad(int)
-{
- // Ignore.
-}
-
-void NetHackQtBind::qt_delay_output()
-{
- NetHackQtDelay delay(15);
- delay.wait();
-}
-
-void NetHackQtBind::qt_start_screen()
-{
- // Ignore.
-}
-
-void NetHackQtBind::qt_end_screen()
-{
- // Ignore.
-}
-
-void NetHackQtBind::qt_outrip(winid wid, int how, time_t when)
-{
- NetHackQtWindow* window=id_to_window[wid];
-
- window->UseRIP(how, when);
-}
-
-bool NetHackQtBind::notify(QObject *receiver, QEvent *event)
-{
- // Ignore Alt-key navigation to menubar, it's annoying when you
- // use Alt-Direction to move around.
- if ( main && event->type()==QEvent::KeyRelease && main==receiver
- && ((QKeyEvent*)event)->key() == Key_Alt )
- return TRUE;
-
- bool result=QApplication::notify(receiver,event);
-#ifdef SAFERHANGUP
- if (program_state.done_hup) {
- keybuffer.Put('\033');
- qApp->exit_loop();
- return TRUE;
- }
-#endif
- if (event->type()==QEvent::KeyPress) {
- QKeyEvent* key_event=(QKeyEvent*)event;
-
- if (!key_event->isAccepted()) {
- const int k=key_event->key();
- bool macro=FALSE;
- for (int i=0; !macro && key_macro[i].key; i++) {
- if (key_macro[i].key==k
- && ((key_macro[i].state&key_event->state())==key_macro[i].state))
- {
- keybuffer.Put(key_macro[i].macro);
- macro=TRUE;
- }
- }
- char ch=key_event->ascii();
- if ( !ch && (key_event->state() & Qt::ControlButton) ) {
- // On Mac, it aint-ncessarily-control
- if ( k>=Qt::Key_A && k<=Qt::Key_Z )
- ch = k - Qt::Key_A + 1;
- }
- if (!macro && ch) {
- bool alt = (key_event->state()&AltButton) ||
- (k >= Key_0 && k <= Key_9 && (key_event->state()&ControlButton));
- keybuffer.Put(key_event->key(),ch + (alt ? 128 : 0),
- key_event->state());
- key_event->accept();
- result=TRUE;
- }
-
- if (ch || macro) {
- qApp->exit_loop();
- }
- }
- }
- return result;
-}
-
-NetHackQtBind* NetHackQtBind::instance=0;
-NetHackQtKeyBuffer NetHackQtBind::keybuffer;
-NetHackQtClickBuffer NetHackQtBind::clickbuffer;
-NetHackQtMainWindow* NetHackQtBind::main=0;
-QWidget* NetHackQtBind::splash=0;
-
-
-extern "C" struct window_procs Qt_procs;
-
-struct window_procs Qt_procs = {
- "Qt",
- WC_COLOR|WC_HILITE_PET|
- WC_ASCII_MAP|WC_TILED_MAP|
- WC_FONT_MAP|WC_TILE_FILE|WC_TILE_WIDTH|WC_TILE_HEIGHT|
- WC_PLAYER_SELECTION|WC_SPLASH_SCREEN,
- 0L,
- {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, /* color availability */
- NetHackQtBind::qt_init_nhwindows,
- NetHackQtBind::qt_player_selection,
- NetHackQtBind::qt_askname,
- NetHackQtBind::qt_get_nh_event,
- NetHackQtBind::qt_exit_nhwindows,
- NetHackQtBind::qt_suspend_nhwindows,
- NetHackQtBind::qt_resume_nhwindows,
- NetHackQtBind::qt_create_nhwindow,
- NetHackQtBind::qt_clear_nhwindow,
- NetHackQtBind::qt_display_nhwindow,
- NetHackQtBind::qt_destroy_nhwindow,
- NetHackQtBind::qt_curs,
- NetHackQtBind::qt_putstr,
- genl_putmixed,
- NetHackQtBind::qt_display_file,
- NetHackQtBind::qt_start_menu,
- NetHackQtBind::qt_add_menu,
- NetHackQtBind::qt_end_menu,
- NetHackQtBind::qt_select_menu,
- genl_message_menu, /* no need for X-specific handling */
- NetHackQtBind::qt_update_inventory,
- NetHackQtBind::qt_mark_synch,
- NetHackQtBind::qt_wait_synch,
-#ifdef CLIPPING
- NetHackQtBind::qt_cliparound,
-#endif
-#ifdef POSITIONBAR
- donull,
-#endif
- NetHackQtBind::qt_print_glyph,
- //NetHackQtBind::qt_print_glyph_compose,
- NetHackQtBind::qt_raw_print,
- NetHackQtBind::qt_raw_print_bold,
- NetHackQtBind::qt_nhgetch,
- NetHackQtBind::qt_nh_poskey,
- NetHackQtBind::qt_nhbell,
- NetHackQtBind::qt_doprev_message,
- NetHackQtBind::qt_yn_function,
- NetHackQtBind::qt_getlin,
- NetHackQtBind::qt_get_ext_cmd,
- NetHackQtBind::qt_number_pad,
- NetHackQtBind::qt_delay_output,
-#ifdef CHANGE_COLOR /* only a Mac option currently */
- donull,
- donull,
-#endif
- /* other defs that really should go away (they're tty specific) */
- NetHackQtBind::qt_start_screen,
- NetHackQtBind::qt_end_screen,
-#ifdef GRAPHIC_TOMBSTONE
- NetHackQtBind::qt_outrip,
-#else
- genl_outrip,
-#endif
- genl_preference_update,
- genl_getmsghistory,
- genl_putmsghistory,
- genl_status_init,
- genl_status_finish,
- genl_status_enablefield,
- genl_status_update,
- genl_can_suspend_yes,
-};
-
-extern "C" void play_usersound(const char* filename, int volume)
-{
-#ifdef USER_SOUNDS
-#ifndef QT_NO_SOUND
- QSound::play(filename);
-#endif
-#endif
-}
-
-#include "qt_win.moc"
-#ifndef KDE
-#include "qt_kde0.moc"
-#endif
-#if QT_VERSION >= 300
-#include "qttableview.moc"
-#endif
+} // namespace nethack_qt_
diff --git a/win/Qt4/qt4win.h b/win/Qt/qt_win.h
similarity index 56%
rename from win/Qt4/qt4win.h
rename to win/Qt/qt_win.h
index 02e96cd31..8edb91974 100644
--- a/win/Qt4/qt4win.h
+++ b/win/Qt/qt_win.h
@@ -2,8 +2,9 @@
// Qt4 conversion copyright (c) Ray Chason, 2012-2014.
// NetHack may be freely redistributed. See license for details.
-// Qt Binding for NetHack 3.4
+// Qt Binding for NetHack 5.0
//
+// [original comment from Warwick]
// Unfortunately, this doesn't use Qt as well as I would like,
// primarily because NetHack is fundamentally a getkey-type
// program rather than being event driven (hence the ugly key
@@ -11,39 +12,43 @@
// major application of Qt.
//
-#ifndef qt4win_h
-#define qt4win_h
+#ifndef qt_win_h
+#define qt_win_h
-namespace nethack_qt4 {
+namespace nethack_qt_ {
+
+void centerOnMain(QWidget *); /* in the namespace but not in any class */
class NetHackQtWindow {
public:
NetHackQtWindow();
virtual ~NetHackQtWindow();
- virtual QWidget* Widget() =0;
+ virtual QWidget* Widget() = 0;
virtual void Clear();
virtual void Display(bool block);
virtual bool Destroy();
- virtual void CursorTo(int x,int y);
+ virtual void CursorTo(int x, int y);
virtual void PutStr(int attr, const QString& text);
void PutStr(int attr, const char *text)
{
PutStr(attr, QString::fromUtf8(text).replace(QChar(0x200B), ""));
}
- virtual void StartMenu();
- virtual void AddMenu(int glyph, const ANY_P* identifier, char ch, char gch, int attr,
- const QString& str, bool presel);
+ virtual void StartMenu(bool using_WIN_INVEN = false);
+ virtual void AddMenu(int glyph, const ANY_P* identifier,
+ char ch, char gch, int attr, int clr,
+ const QString& str, unsigned itemflags);
virtual void EndMenu(const QString& prompt);
virtual int SelectMenu(int how, MENU_ITEM_P **menu_list);
- virtual void ClipAround(int x,int y);
- virtual void PrintGlyph(int x,int y,int glyph);
+ virtual void ClipAround(int x, int y);
+ virtual void PrintGlyph(int x, int y, const glyph_info *glyphinfo,
+ const glyph_info *bkglyphinfo);
virtual void UseRIP(int how, time_t when);
int nhid;
};
-} // namespace nethack_qt4
+} // namespace nethack_qt_
#endif
diff --git a/win/Qt/qt_xcmd.cpp b/win/Qt/qt_xcmd.cpp
new file mode 100644
index 000000000..505949398
--- /dev/null
+++ b/win/Qt/qt_xcmd.cpp
@@ -0,0 +1,613 @@
+// Copyright (c) Warwick Allison, 1999.
+// Qt4 conversion copyright (c) Ray Chason, 2012-2014.
+// NetHack may be freely redistributed. See license for details.
+
+// qt_xcmd.cpp -- extended command widget
+//
+// TODO:
+// Either disable [Layout] when prompt has a partial response, or
+// preserve that partial response across widget tear-down/rebuild.
+// Maybe make the number of grid columns user settable? Or a way to
+// specify a different font (smaller might be necessary for some folks;
+// the font set up in "Qt settings" or "Preferences" applies to the
+// message and status windows but not to extended command choosing).
+//
+
+//
+// Widget appearance (excluding window title bar):
+// +----------------------------------------------------+
+// | [Cancel] [Filter] [Layout] [Reset] | control buttons
+// |# Extended commands | text entry & title
+// +----------------------------------------------------+
+// | [cmmnd_1] [cmnd_14] ... [cmnd_92] [cmd_105] | boxed grid of...
+// | [cmmnd_2] [cmnd_15] ... [cmnd_93] [cmd_106] | ...command buttons
+// ...
+// | [cmnd_13] [cmnd_26] ... [cmd_104] blank |
+// +----------------------------------------------------+
+//
+// Typed input gets appended to "#". When enough to be unambiguous has
+// accumulated, the matching command is immediately chosen (except for
+// the prefix special case mentioned for [Cancel]);
+// Title is centered and describes which [sub]set of commands are shown.
+// It shares the prompt line to conserve vertical space.
+// [Cancel] is highlighted as the default and applies if is typed,
+// with special handling when player has typed up to the end of one
+// command which is a prefix of another; there, or is
+// used to select the shorter while still providing opportunity to type
+// more of the longer command; (there are several such cases:
+// "#drop[type]", "#known[class]", "#takeoff[all]", "#version[short]");
+// button is left justified (prior to addition of the filter/layout/reset
+// buttons, [Cancel] stretched all the way across the top of the widget);
+// [Filter] toggles between normal and autocomplete when playing in normal
+// or explore mode, cycles through "all", "normal", "autocomplete", and
+// "wizard mode extra commands only" when playing in wizard mode; that's
+// kind of clumsy but probably not important enough to implement a more
+// sophisticated interface;
+// [Layout] toggles between displaying the command buttons down columns
+// (as shown above) versus across rows ([cmd_1][cmd_2]...[cmd_9], &c);
+// [Reset] clears typed partial response, if any, and sets filtering back
+// to "all commands" and/or toggles layout back to by-column if either
+// of those differ from their defaults;
+// [cmd_N] are buttons labelled with command names; clicking returns the
+// index for the name.
+//
+// Changing filter or layout returns xcmdNoMatch to qt_get_ext_cmd() which
+// then calls us again (current filter and layout are kept in qt_settings
+// so persist, not just through return and call back but across games);
+// much simpler than reorganizing the button grid's contents on the fly.
+// Current grid size with SHELL and SUSPEND enabled is 13x9 for all
+// commands, 13x7 for normal mode commands, and 7x4 (when by-column) or
+// 4x7 (if by-row) for wizard mode commands. Column counts are hardcoded
+// and row counts are adjusted to fit (the command list, not the screen).
+// Maybe move prompt and title above control buttons? However, menus have
+// their count entry feedback positioned between control buttons and the
+// rest of the information--current layout matches that.
+// The popup is displayed as full-fledged window but the window title bar
+// is blank (at least on OSX).
+// If clicking on [Filter] or [Layout] (or [Reset], but there isn't any
+// particular reason to try to run it twice in a row) places the pointer
+// inside any button, clicking again won't do anything unless the pointer
+// is moved (again, at least on OSX); a single pixel probably suffices.
+// Possibly because despite not moving it has effectively gone into a
+// whole new window since the old one gets torn down and is replaced by
+// a new one that uses revised filter or layout settings.
+//
+
+extern "C" {
+#include "hack.h"
+#include "func_tab.h"
+}
+
+#include "qt_pre.h"
+#include
+#if QT_VERSION >= 0x050000
+#include
+#endif
+#include "qt_post.h"
+#include "qt_xcmd.h"
+#include "qt_xcmd.moc"
+#include "qt_key.h" // for keyValue()
+#include "qt_bind.h"
+#include "qt_set.h"
+#include "qt_str.h"
+
+// temporary
+extern int qt_compact_mode;
+// end temporary
+
+namespace nethack_qt_ {
+
+/* 'wizard' is #undef'd above (now in qt_pre.h) because a Qt header uses
+ that token, so create our own based on knowledge of 'wizard's internals */
+#define WizardMode (::flags.debug)
+
+extern uchar keyValue(QKeyEvent *key_event); // from qt_menu.cpp
+
+// temporary
+void centerOnMain(QWidget *);
+// end temporary
+
+static /*inline*/ bool
+interesting_command(unsigned indx, int cmds)
+{
+ bool skip_wizard = !WizardMode || cmds == normal_cmds;
+
+ // entry 0 is a no-op; don't bother displaying it in the command grid
+ if (indx == 0 && !strcmp("#", extcmdlist[indx].ef_txt))
+ return false;
+ // treat '?' as both normal mode and debug mode
+ if (!strcmp("?", extcmdlist[indx].ef_txt))
+ return true;
+ // some commands might have been compiled-out; don't show them
+ if ((extcmdlist[indx].flags & (CMD_NOT_AVAILABLE|INTERNALCMD)) != 0)
+ return false;
+ // if picking from normal mode-only don't show wizard mode commands
+ // or if picking from wizard mode-only don't show normal commands
+ if ((skip_wizard && (extcmdlist[indx].flags & WIZMODECMD) != 0)
+ || (cmds == wizard_cmds && (extcmdlist[indx].flags & WIZMODECMD) == 0))
+ return false;
+ // autocomplete subset is essentially the traditional set of extended
+ // commands; many can be invoked by Alt+char but not by ordinary char
+ // or Ctrl+char; [X11's extended command selection uses this subset]
+ if (cmds == autocomplete_cmds
+ && (extcmdlist[indx].flags & AUTOCOMPLETE) == 0)
+ return false;
+ // if we've gotten here, this command isn't filtered away, so show it
+ return true;
+}
+
+NetHackQtExtCmdRequestor::NetHackQtExtCmdRequestor(QWidget *parent) :
+ QDialog(parent),
+ prompt(new QLabel("#", this)),
+ cancel_btn(new QPushButton("Cancel", this)),
+ byRow(qt_settings->xcmd_by_row),
+ set(qt_settings->xcmd_set),
+ butoffset(0),
+ exactmatchindx(xcmdNoMatch)
+{
+ if (!WizardMode && set != normal_cmds)
+ set = autocomplete_cmds; // {all,wizard}_cmds are wizard mode only
+
+ QVBoxLayout *xl = new QVBoxLayout(this); // overall xcmd layout
+ int butw = 50; // initial button width; will be increased if too small
+ // should probably use the qt_settings font size as a spacing hint;
+ // tiny font, tiny internal margins; small font, small margins;
+ // medium or bigger, default margins (9 or 11?)
+ int spacing = qt_compact_mode ? 3 : -1; // 0 would abut; -1 gives default
+
+ // first, the popup's controls: a row of buttons along the top;
+ // the two padding widgets make the control buttons line up better
+ // with the grid of xcmd choice buttons (closer but not exactly)
+ QHBoxLayout *ctrls = new QHBoxLayout();
+ ctrls->setSpacing(spacing); // only seems to affect horizontal, not vert.
+ ctrls->addWidget(new QLabel(" ")); // padding
+ // Cancel, created during constructor setup (accessed in other routines)
+ DefaultActionIsCancel(true); /* cancel_btn->setDefault(true); */
+ cancel_btn->setMinimumSize(cancel_btn->sizeHint());
+ butw = std::max(butw, cancel_btn->width());
+ ctrls->addWidget(cancel_btn);
+ ctrls->addStretch(0); // Cancel will be left justified, others far right
+ // Filter: change the [sub]set of commands that get shown;
+ // presently only useful when running in wizard mode
+ QPushButton *filter_btn = new QPushButton("Filter", this);
+#if 0 /* [later] normal vs autocomplete matters regardless of wizard mode */
+ if (!WizardMode) { // nothing to filter if not in wizard mode
+ filter_btn->setEnabled(false); // gray the [Filter] button out
+#if 0 /* This works but makes [Reset] seem to be redundant. */
+ // graying out may not be adequate; conceal [Filter] so that
+ // players without access to wizard mode won't become concerned
+ // about something that seems to them to always be disabled
+ filter_btn->hide();
+#endif
+ }
+#endif
+ filter_btn->setMinimumSize(filter_btn->sizeHint());
+ butw = std::max(butw, filter_btn->width());
+ ctrls->addWidget(filter_btn);
+ // Layout: switch from by-column grid to by-row grid or vice versa
+ QPushButton *layout_btn = new QPushButton("Layout", this);
+ layout_btn->setMinimumSize(layout_btn->sizeHint());
+ butw = std::max(butw, layout_btn->width());
+ ctrls->addWidget(layout_btn);
+ // Reset: switch filter back to all commands and layout back to by-column
+ QPushButton *reset__btn = new QPushButton("Reset", this);
+ reset__btn->setMinimumSize(reset__btn->sizeHint());
+ butw = std::max(butw, reset__btn->width());
+ ctrls->addWidget(reset__btn);
+ ctrls->addWidget(new QLabel(" ")); // padding
+ xl->addLayout(ctrls);
+
+ // text entry takes place below the row of control buttons and above
+ // the grid of command buttons; show typed text in fixed-width font
+ prompt->setFont(qt_settings->normalFixedFont());
+
+ // grid title rather than overall popup title
+ const char *ctitle = ((set == all_cmds) // implies wizard mode
+ ? "All commands"
+ : (set == normal_cmds)
+ ? (WizardMode ? "Normal mode commands"
+ : "Available commands")
+ : (set == autocomplete_cmds)
+ ? "Traditional extended commands"
+ : (set == wizard_cmds)
+ ? "Debug mode commands"
+ : "(unknown)"); // won't happen
+ const QString &qtitle = QString(ctitle);
+ // rectangular grid to hold a button for each extended command name
+ QGroupBox *grid = new QGroupBox(); /* new QGroupBox(title, this); */
+ // used to connect the buttons with their click handling routine
+ QButtonGroup *group = new QButtonGroup(this);
+
+ // put grid title on same line as prompt (the padding simplifies centering)
+ QHBoxLayout *pl = new QHBoxLayout(); // prompt line
+ pl->addWidget(prompt);
+ QLabel *tt = new QLabel(qtitle);
+ tt->setAlignment(Qt::AlignHCenter); // center title horizontally
+ pl->addWidget(tt);
+ pl->addWidget(new QLabel(" ")); // padding to balance prompt
+ xl->addLayout(pl);
+ xl->addWidget(grid);
+
+ // having the controls in the same button group as the extended command
+ // choices means that they use the same click callback [a holdover from
+ // when Cancel was the only one; using a separate group and separate
+ // click callback would eliminate the need for butoffset in Button()]
+ group->addButton(cancel_btn, butoffset), ++butoffset; // (,0), 1
+ group->addButton(filter_btn, butoffset), ++butoffset; // (,1), 2
+ group->addButton(layout_btn, butoffset), ++butoffset; // (,2), 3
+ group->addButton(reset__btn, butoffset), ++butoffset; // (,3), 4
+
+ unsigned i, j, ncmds = 0;
+ QFontMetrics fm = fontMetrics();
+ // count the number of commands in current [sub]set and find the size of
+ // the widest choice button; starting size is from widest control button
+ for (i = 0; extcmdlist[i].ef_txt; ++i) {
+ if (interesting_command(i, set)) {
+ ++ncmds;
+ butw = std::max(butw, 30 + fm.QFM_WIDTH(extcmdlist[i].ef_txt));
+ }
+ }
+ // if any of the choice buttons were bigger than the control buttons,
+ // make the control buttons bigger to match
+ if (cancel_btn->width() < butw)
+ cancel_btn->setMinimumWidth(butw);
+ if (filter_btn->width() < butw)
+ filter_btn->setMinimumWidth(butw);
+ if (layout_btn->width() < butw)
+ layout_btn->setMinimumWidth(butw);
+ if (reset__btn->width() < butw)
+ reset__btn->setMinimumWidth(butw);
+
+ QVBoxLayout *bl = new QVBoxLayout(grid);
+ QGridLayout *gl = new QGridLayout();
+ // for qt_compact_mode, put buttons closer together
+ gl->setSpacing(spacing);
+ bl->addLayout(gl);
+ // could grow the buttons[] vector one element at a time but since we
+ // know the ultimate size, grow to that in one operation
+ buttons.resize((int) ncmds);
+
+ /* 'ncols' could be calculated to fit (or enable a vertical scrollbar
+ when resulting 'nrows' is too big, if GroupBox supports that);
+ it used to be hardcoded 4, but once every command became accessible
+ as an extended command, that resulted in so many rows that some of
+ the grid was chopped off at the bottom of the screen and the buttons
+ in that portion were out of reach */
+ unsigned ncols = (set == all_cmds) ? 9
+ : (set == normal_cmds) ? 8
+ : (set == autocomplete_cmds) ? (WizardMode ? 6 : 5)
+ : (set == wizard_cmds) ? (byRow ? 6 : 5)
+ : 1; // can't happen
+ unsigned nrows = (ncmds + ncols - 1) / ncols;
+ /*
+ * Grid layout: by-column is the default. Can be toggled by clicking
+ * on the [Layout] control button.
+ *
+ * by-row vs by-column
+ * a b c a e i
+ * d e f b f j
+ * g h i c g -
+ * j - - d h -
+ */
+ for (i = j = 0; extcmdlist[i].ef_txt; ++i) {
+ if (interesting_command(i, set)) {
+ QString btn_lbl = extcmdlist[i].ef_txt;
+ if (btn_lbl == "wait")
+ btn_lbl += " (rest)";
+ QString btn_tip = nh_qsprintf(" %s ", extcmdlist[i].ef_desc);
+ QPushButton *pb = new QPushButton(btn_lbl, grid);
+ pb->setMinimumSize(butw, pb->sizeHint().height());
+ // force the button to have fixed width or it can move around a
+ // pixel or two (tiny but visibly noticeable) when enableButtons()
+ // hides whole columns [see stretch comment below]
+ pb->setMaximumSize(pb->minimumSize());
+ // i+butoffset is value that will be passed to the click handler
+ group->addButton(pb, i + butoffset);
+ // gray out "repeat" because picking it would just repeat the "#"
+ // that caused us to be called rather than whatever came before;
+ // it can still be chosen by typing "rep" but appears grayed out
+ // while in the process so having it not behave usefully shouldn't
+ // come as much of a surprise
+ if (btn_lbl == "repeat")
+ pb->setEnabled(false);
+ // show command description if mouse hovers over this button
+ pb->setToolTip(btn_tip); // extcmdlist[i].ef_desc
+ /*
+ * by column: xcmd_by_row==false, the default
+ * 0..R-1 down first column, R..2*R-1 down second column, ...
+ * otherwise: by row
+ * 0..C-1 across first row, C..2*C-1 across second row, ...
+ */
+ unsigned row = !byRow ? j % nrows : j / ncols;
+ unsigned col = !byRow ? j / nrows : j % ncols;
+ gl->addWidget(pb, row, col);
+ // these stretch settings prevent the grid from becoming very
+ // ugly when enableButtons() disables whole rows and/or columns
+ // as typed characters reduce the pool of possible matches
+ if (row == 0)
+ gl->setColumnStretch(col, 1);
+ if (col == 0)
+ gl->setRowStretch(row, 1);
+
+ // buttons[] vector is used by enableButtons()
+ buttons[j] = pb; // buttons.append(pb);
+ ++j;
+ }
+ }
+
+#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0)
+ connect(group, SIGNAL(idPressed(int)), this, SLOT(Button(int)));
+#else
+ connect(group, SIGNAL(buttonPressed(int)), this, SLOT(Button(int)));
+#endif
+
+ bl->activate();
+ xl->activate();
+ resize(1,1);
+}
+
+// Click handler for the ExtCmdRequestor widget
+int NetHackQtExtCmdRequestor::Button(int butnum)
+{
+ // 0..3 are control buttons, 4..N+3 are choice buttons.
+ // Widget return value is -1 for cancel (via reject), xcmdNoMatch
+ // for filter, layout, reset (via accept if circumstances warrant),
+ // 1..N for command choices (choice 0 is '#' and it isn't shown as
+ // a candidate since picking it is not useful).
+ switch (butnum) {
+ case 0:
+ Cancel();
+ /*NOTREACHED*/
+ break;
+ case 1:
+ Filter();
+ break;
+ case 2:
+ Layout();
+ break;
+ case 3:
+ Reset();
+ break;
+ default:
+ // 4..N-3 are the extended commands
+ done(butnum - butoffset + 1);
+ /*NOTREACHED*/
+ break;
+ }
+ return 0;
+}
+
+// Respond to a click on the [Cancel] button
+void NetHackQtExtCmdRequestor::Cancel()
+{
+ reject();
+ /*NOTREACHED*/
+}
+
+// Respond to a click on the [Filter] button
+void NetHackQtExtCmdRequestor::Filter()
+{
+ do {
+ if (++set > std::max(std::max(all_cmds, normal_cmds),
+ std::max(autocomplete_cmds, wizard_cmds)))
+ set = std::min(std::min(all_cmds, normal_cmds),
+ std::min(autocomplete_cmds, wizard_cmds));
+ if (WizardMode)
+ break;
+ } while (set != normal_cmds && set != autocomplete_cmds);
+
+ if (set != qt_settings->xcmd_set) {
+ Retry();
+ /*NOTREACHED*/
+ }
+ return;
+}
+
+// Respond to a click on the [Layout] button
+void NetHackQtExtCmdRequestor::Layout()
+{
+ byRow = !byRow;
+ Retry();
+ /*NOTREACHED*/
+}
+
+// Respond to a click on the [Reset] button
+void NetHackQtExtCmdRequestor::Reset()
+{
+ // clear any typed text first (in case future changes are made to
+ // remember it across accept (retry); that would be intended for the
+ // [Layout] case rather than for [Reset])
+ bool clearprompt = (prompt->text() != "#");
+ if (clearprompt)
+ prompt->setText("#");
+
+ int teardown = 0;
+ if (set != (WizardMode ? all_cmds : normal_cmds))
+ set = all_cmds, ++teardown;
+ if (byRow)
+ byRow = false, ++teardown;
+ if (teardown) {
+ Retry();
+ /*NOTREACHED*/
+ }
+
+ if (clearprompt) { // was a subset, now need to show full set
+ DefaultActionIsCancel(true); // in case keyPressEvent cleared it
+ enableButtons(); // redraws the grid after discarding typed text above
+ }
+}
+
+// Return to ExtCmdRequestor::get()'s caller in order to be called back
+void NetHackQtExtCmdRequestor::Retry()
+{
+ // remember the current settings; they'll persist until changed again
+ qt_settings->updateXcmd(byRow, set);
+
+ // return to qt_get_ext_cmd() and have it run ExtCmdRequestor again;
+ // current selection grid will be torn down, then new one created;
+ setResult(xcmdNoMatch);
+ accept();
+ /*NOTREACHED*/
+}
+
+#define Ctrl(c) (0x1f & (c)) /* ASCII */
+// Note: we don't necessarily have access to a terminal to query
+// it for user's preferred kill character, so use hardcoded ^U.
+// Player who prefers something else can cope by using ESC instead.
+#define KILL_CHAR Ctrl('u')
+
+// used by keyPressEvent() and enableButtons()
+static const QString &rest = "rest"; // informal synonym for "wait"
+
+// Receive the next character of typed input
+void NetHackQtExtCmdRequestor::keyPressEvent(QKeyEvent *event)
+{
+ /*
+ * This will select a command outright--as soon as enough chars
+ * to not be ambiguous are entered--but also narrows down visible
+ * choices [via enableButtons()] in the grid of clickable command
+ * buttons as the text-so-far makes many become impossible to match.
+ * Use of backspace/delete or ESC/kill restores suppressed choices
+ * to the grid as they become matchable again.
+ */
+
+ unsigned saveexactmatchindx = exactmatchindx;
+ // if previous KeyPressEvent cleared default, restore it now
+ DefaultActionIsCancel(true);
+ QString promptstr = prompt->text();
+ uchar uc = keyValue(event);
+
+ if (!uc) {
+ // shift or control or meta, another character should be coming
+ QWidget::keyPressEvent(event);
+ } else if (uc == '\033' || uc == KILL_CHAR) {
+ // when partial response is present kills that text
+ // but keeps prompting; when response is empty cancels.
+ // Kill gets rid of pending text, if any, and always re-prompts.
+ if (uc == '\033' && promptstr == "#")
+ reject(); // cancel() if ESC used when string is empty
+ prompt->setText("#"); // reset to empty ('#' is always present)
+ enableButtons();
+ } else if (uc == '\b' || uc == '\177') {
+ if (promptstr != "#")
+ prompt->setText(promptstr.left(promptstr.size() - 1));
+ enableButtons();
+ } else if ((uc < ' ' && !(uc == '\n' || uc == '\r'))
+ || uc > std::max('z', 'Z')) {
+ reject(); // done()
+ } else {
+ /*
+ * or is necessary if one command is a
+ * leading substring of another and superfluous otherwise.
+ * (When a command is not a prefix of another, it will have
+ * been selected before reaching its last letter.)
+ *
+ * If we got an exact match with the last key, we're expecting
+ * a or to explicitly choose it now but might
+ * get next letter of the longer command (or get a backspace).
+ *
+ * If we get an exact match this time, then stop showing
+ * [Cancel] as the default action for .
+ * (That's a visual cue for the player, not a requirement to
+ * prevent from triggering the default action.)
+ * If it's not the default action upon the next key press,
+ * we'll change that back (done above).
+ *
+ * TODO?
+ * Implement support: if promptstr matches multiple
+ * commands but they all have the next one or more letters in
+ * common, allow to add the common letters to promptstr.
+ */
+ bool checkexact = (uc == '\n' || uc == '\r' || uc == ' ');
+ if (!checkexact) {
+ // force lower case instead of rejecting upper case
+ if (isupper(uc))
+ uc = tolower(uc);
+ promptstr += QChar(uc); // add new char to typed text
+ }
+ QString typedstr = promptstr.mid(1); // skip the '#'
+ if (typedstr == rest)
+ typedstr = "wait";
+ std::size_t len = typedstr.size();
+ unsigned matches = 0;
+ unsigned matchindx = 0;
+ for (unsigned i = 0; extcmdlist[i].ef_txt; ++i) {
+ if (!interesting_command(i, set))
+ continue;
+ const QString &cmdtxt = QString(extcmdlist[i].ef_txt);
+ if (cmdtxt.startsWith(typedstr)) {
+ bool is_exact = (cmdtxt == typedstr);
+ if (checkexact) {
+ if (is_exact) {
+ matchindx = i;
+ matches = 1;
+ break;
+ }
+ } else {
+ if (is_exact)
+ DefaultActionIsCancel(false, i); // clear default
+ if (++matches >= 2)
+ break;
+ matchindx = i;
+ }
+ }
+ }
+ if (matches == 1) {
+ done(matchindx + 1);
+ } else if (checkexact) {
+ // or without a pending exact match; cancel
+ reject();
+ } else if (matches >= 2
+ || promptstr.mid(1, len) == rest.left(len)) {
+ // update the text-so-far
+ prompt->setText(promptstr);
+ } else if (saveexactmatchindx != xcmdNoMatch) {
+ // had a pending exact match but typed something other than
+ // which didn't yield another match; prompt string
+ // hasn't been updated so still have a pending exact match
+ DefaultActionIsCancel(false, saveexactmatchindx);
+ }
+ enableButtons();
+ }
+}
+
+// Actual widget execution, used after calling NetHackQtExtCmdRequestor().
+int NetHackQtExtCmdRequestor::get()
+{
+ resize(1,1); // pack
+ centerOnMain(this);
+ // Add any keys presently buffered to the prompt
+ setResult(xcmdNone);
+ while (NetHackQtBind::qt_kbhit() && result() == xcmdNone) {
+ int ch = NetHackQtBind::qt_nhgetch();
+ QKeyEvent event(QEvent::KeyPress, 0, Qt::NoModifier, QChar(ch));
+ keyPressEvent(&event);
+ }
+ if (result() == xcmdNone)
+ exec();
+
+ int ret = result() - 1;
+ return ret;
+}
+
+// Enable only buttons that match the current prompt string
+void NetHackQtExtCmdRequestor::enableButtons()
+{
+ QString typedstr = prompt->text().mid(1); // skip the '#'
+ std::size_t len = typedstr.size();
+
+ // This used to look really bad when whole rows became empty: the
+ // grid shrank and the one line prompt area expanded to fill the
+ // vacated vertical space. Hiding whole columns looked bad too,
+ // remaining buttons were widened to take the space. Now the grid is
+ // forced to have fixed layout (via stretch settings in constructor).
+ for (auto b = buttons.begin(); b != buttons.end(); ++b) {
+ const QString &buttext = (*b)->text();
+ bool showit = (buttext.left(len) == typedstr
+ || (buttext.contains("(rest)")
+ && typedstr == rest.left(len)));
+ (*b)->setVisible(showit);
+ }
+}
+
+} // namespace nethack_qt_
diff --git a/win/Qt/qt_xcmd.h b/win/Qt/qt_xcmd.h
new file mode 100644
index 000000000..4820d2d4d
--- /dev/null
+++ b/win/Qt/qt_xcmd.h
@@ -0,0 +1,64 @@
+// Copyright (c) Warwick Allison, 1999.
+// Qt4 conversion copyright (c) Ray Chason, 2012-2014.
+// NetHack may be freely redistributed. See license for details.
+
+// qt_xcmd.h -- extended command widget
+
+#ifndef QT4XCMD_H
+#define QT4XCMD_H
+
+namespace nethack_qt_ {
+
+// [Filter] setting; the X11 interface uses the autocomplete list
+enum xcmdSets {
+ all_cmds = 0, // everything in extcmdlist[]
+ normal_cmds = 1, // all non-wizard mode commands
+ autocomplete_cmds = 2, // mostly commands which need Alt+char
+ wizard_cmds = 3 // commands only useable in wizard mode
+};
+enum xcmdMisc { xcmdNone = -10, xcmdNoMatch = 9999 };
+
+class NetHackQtExtCmdRequestor : public QDialog {
+ Q_OBJECT
+
+protected:
+ virtual void keyPressEvent(QKeyEvent *event);
+
+public:
+ NetHackQtExtCmdRequestor(QWidget *parent);
+ int get();
+
+private:
+ QLabel *prompt;
+ QPushButton *cancel_btn;
+ QVector buttons;
+ bool byRow; // local copy of qt_settings->xcmd_by_row;
+ int set; // local copy of qt_settings->xcmd_set;
+ int butoffset; // number of control buttons (cancel, filter, &c)
+ unsigned exactmatchindx;
+
+ void enableButtons();
+ void Cancel(); // not selecting a command after all
+ void Filter(); // choose command set (all, normal mode, wizard mode)
+ void Layout(); // by-column vs by-row for button grid
+ void Reset(); // go back to default filter and layout
+
+ void Retry(); // returns to caller in order to be called back...
+ // ...and restart with revised settings
+
+ inline void DefaultActionIsCancel(bool make_it_so,
+ unsigned matchindx = xcmdNoMatch)
+ {
+ if (!make_it_so ^ !cancel_btn->isDefault()) {
+ cancel_btn->setDefault(make_it_so);
+ exactmatchindx = matchindx;
+ }
+ }
+
+private slots:
+ int Button(int); // click handler
+};
+
+} // namespace nethack_qt_
+
+#endif
diff --git a/win/gnome/gn_xpms.h b/win/Qt/qt_xpms.h
similarity index 71%
rename from win/gnome/gn_xpms.h
rename to win/Qt/qt_xpms.h
index 90bb7b3b1..7ea343590 100644
--- a/win/gnome/gn_xpms.h
+++ b/win/Qt/qt_xpms.h
@@ -1,18 +1,66 @@
-/* NetHack 3.6 gn_xpms.h $NHDT-Date: 1432512805 2015/05/25 00:13:25 $ $NHDT-Branch: master $:$NHDT-Revision: 1.9 $ */
-/* Copyright (C) 1998 by Erik Andersen */
-/* NetHack may be freely redistributed. See license for details. */
-/* These XPMs are the artwork of Warwick Allison
- * . They have been borrowed from
- * the most excellent NetHackQt, until such time as
- * we can come up with something better.
- *
- * More information about NetHackQt can be had from:
- * http://www.troll.no/~warwick/nethack/
- */
+// qt_xpms.h - static xpm arrays for use in status display
+//
+// In alphabetical order by array name. Probably not the best ordering...
/* clang-format off */
+
+// blank icon for use as placeholder
/* XPM */
-static char *blind_xpm[] = {
+static const char *blank_xpm[] = {
+/* width height ncolors chars_per_pixel */
+"40 40 5 1",
+/* colors */
+" c #000000",
+". c None",
+/* not used here */
+"X c #909090",
+"o c #606060",
+"O c #303030",
+/* pixels */
+"........................................",
+"........................................",
+"........................................",
+"........................................",
+"........................................",
+"........................................",
+"........................................",
+"........................................",
+"........................................",
+"........................................",
+"........................................",
+"........................................",
+"........................................",
+"........................................",
+"........................................",
+"........................................",
+"........................................",
+"........................................",
+"........................................",
+"........................................",
+"........................................",
+"........................................",
+"........................................",
+"........................................",
+"........................................",
+"........................................",
+"........................................",
+"........................................",
+"........................................",
+"........................................",
+"........................................",
+"........................................",
+"........................................",
+"........................................",
+"........................................",
+"........................................",
+"........................................",
+"........................................",
+"........................................",
+"........................................"
+};
+
+// Characteristics, Alignment, and Conditions
+static const char *blind_xpm[] = {
/* width height ncolors chars_per_pixel */
"40 40 5 1",
/* colors */
@@ -64,7 +112,7 @@ static char *blind_xpm[] = {
"........................................"
};
/* XPM */
-static char *cha_xpm[] = {
+static const char *cha_xpm[] = {
/* width height ncolors chars_per_pixel */
"40 40 14 1",
/* colors */
@@ -125,7 +173,7 @@ static char *cha_xpm[] = {
"++++++++++++++++++++++++++++++++++++++++"
};
/* XPM */
-static char *chaotic_xpm[] = {
+static const char *chaotic_xpm[] = {
/* width height ncolors chars_per_pixel */
"40 40 9 1",
/* colors */
@@ -181,7 +229,7 @@ static char *chaotic_xpm[] = {
"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
};
/* XPM */
-static char *cns_xpm[] = {
+static const char *cns_xpm[] = {
/* width height ncolors chars_per_pixel */
"40 40 19 1",
/* colors */
@@ -247,7 +295,7 @@ static char *cns_xpm[] = {
"@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"
};
/* XPM */
-static char *confused_xpm[] = {
+static const char *confused_xpm[] = {
/* width height ncolors chars_per_pixel */
"40 40 13 1",
/* colors */
@@ -265,6 +313,49 @@ static char *confused_xpm[] = {
"* c #303030",
"= c #6C91B6",
/* pixels */
+#if 1
+/* mirror image of original; confused brain is facing the other way */
+"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO",
+"OOOOOOO+.OO+O+OO.O+.=OO+.=.OOOOOOOOOOOOO",
+"OOOOOO+O=++==+O=+=====O=====++OOOOOOOOOO",
+"OOOOO+=O+==OO===++++=.=====.=+OOOOOOOOOO",
+"OOOO======OoO&+===o==o=+.===+=OOOOOOOOOO",
+"O.O.=+==+Oo&o==oO&&&&o=+OO====+O+OOOOOOO",
+"O=+=O==Oooo&=ooo&o&oOooo=o&&+==O+=+.+OOO",
+"O==++==+o&==o=oo&&o&=&oo=oo===O++OOOOOOO",
+"OO=======oo&&o&oo&o&OO&o====O=.o=OOOOOOO",
+"OOOO=====O&o=oOOoooo=Ooo=O=O=+===oOOOOOO",
+"OOOO+===O=o=O====oo=O=======+==+OOOOOOOO",
+"OOOOO======O========O====+=X=#=.OOOOOOOO",
+"OOOO+==OO==========O====%#=.++oX#.OOOOOO",
+"OOOO+==+=+=O====+====X==.=#.+#+#oX+OOOOO",
+"OOOOO.OO+o===##Xo====.X=#.##===O+.+.OOOO",
+"OOOO+=oOO=...+#O#X#==+#.o##O#O####+#OOOO",
+"OOOOo=OO+==+X+#.X#+#.O#.#++++X+#+o#++OOO",
+"OOOOOOO..+##+#XX+..#++#++X##.+X..+.+#OOO",
+"OOOOOOO#+#+..X#+#+X+#++.+#++#+O....##OOO",
+"OOOOOO$X.++#.##++.#XX#X#X+O#+#.+.+#++OOO",
+"OOOOO**+##X+X+###X+##+++.++#+++.+#+#OOOO",
+"OOOO@ *#+#+X#+.++..+.###o##.+#OO#..#OOOO",
+"OOOO$ *#.+###++##+###.+++.O#+#+O#.#+OOOO",
+"OOOO* ###+#.##..+#++##X..o#+#+#+XXOOOOO",
+"OOOO %%XX%####+..+#.+#+#+#+X#.#XOOOOOO",
+"OOOO* %.=++X.+#+#+#++.#+#+#.X%%.OOOOOOO",
+"OOOO$ %#%%%%XX+.####O.+#+##* *.OOOOOOOO",
+"OOOO$ X#+++.=XXX+++#.+.X% .OOOOOOOOOO",
+"OOOO$ *X%####.=%X#..X%% *.OOOOOOOOOOO",
+"OOOOO *=###%X#.=%%%XX* $.OOOOOOOOOOOOO",
+"OOOOO@ *=#.+.#%%=%%%+OOOOOOOOOOOOOOOOO",
+"OOOOOO *%X##X==%%%=oOOOOOOOOOOOOOOOOO",
+"OOOOOO@ *%=X%%%%X+OOOOOOOOOOOOOOOOOO",
+"OOOOOOO@* X%%%%XOOOOOOOOOOOOOOOOOOO",
+"OOOOOOOOO$$* *X%%%=OOOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOO. =%%X+OOOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOO %%%XOOOOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOO$ *%%=OOOOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOO$ %%%=OOOOOOOOOOOOOOOOOOOO",
+"OOOOOOOOOOOOOO$ %%%+OOOOOOOOOOOOOOOOOOOO"
+#else
"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO",
"OOOOOOOOOOOOOO.=.+OO=.+O.OO+O+OO.+OOOOOO",
"OOOOOOOOOOO++=====O=====+=O+==++=O+OOOOO",
@@ -305,9 +396,59 @@ static char *confused_xpm[] = {
"OOOOOOOOOOOOOOOOOOOOO=%%* $OOOOOOOOOOOOO",
"OOOOOOOOOOOOOOOOOOOOO=%%% $OOOOOOOOOOOOO",
"OOOOOOOOOOOOOOOOOOOOO+%%% $OOOOOOOOOOOOO"
+#endif
};
/* XPM */
-static char *dex_xpm[] = {
+static const char *deaf_xpm[] = { // placeholder for Deaf condition
+/* width height ncolors chars_per_pixel */
+"40 40 2 1",
+/* colors */
+"X c None",
+"o c #dfdf40",
+/* pixels */
+"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
+"XooooooooooooooooooooooooooooooooooooooX",
+"XooooooooooooooooooooooooooooooooooooooX",
+"XooooooooooooooooooooooooooooooooooooooX",
+"XooooooooooooooooooooooooooooooooooooooX",
+"XooooooooooooooooooooooooooooooooooooooX",
+"XooooooooooooooooooooooooooooooooooooooX",
+"XooooooooooooooooooooooooooooooooooooooX",
+"XooooooooooooooooooooooooooooooooooooooX",
+"XooooooXXXXooooooooooooooooooooooooooooX",
+"XooooooXoooXoooooooooooooooooooooooooooX",
+"XooooooXoooXoooooooooooooooooooooooooooX",
+"XooooooXoooXoooooooooooooooooooooooooooX",
+"XooooooXoooXoooooooooooooooooooooooooooX",
+"XooooooXoooXooXXXXXooooooooooooooooooooX",
+"XooooooXXXXoooXooooooooooooooooooooooooX",
+"XoooooooooooooXooooooooooooooooooooooooX",
+"XoooooooooooooXXXXoooooooooooooooooooooX",
+"XoooooooooooooXooooooooooooooooooooooooX",
+"XoooooooooooooXooooooooXoooooooooooooooX",
+"XoooooooooooooXXXXXoooXoXooooooooooooooX",
+"XooooooooooooooooooooXoooXoooooooooooooX",
+"XooooooooooooooooooooXoooXoooooooooooooX",
+"XooooooooooooooooooooXXXXXoooooooooooooX",
+"XooooooooooooooooooooXoooXooXXXXXooooooX",
+"XooooooooooooooooooooXoooXooXooooooooooX",
+"XoooooooooooooooooooooooooooXooooooooooX",
+"XoooooooooooooooooooooooooooXXXXoooooooX",
+"XoooooooooooooooooooooooooooXooooooooooX",
+"XoooooooooooooooooooooooooooXooooooooooX",
+"XoooooooooooooooooooooooooooXooooooooooX",
+"XooooooooooooooooooooooooooooooooooooooX",
+"XooooooooooooooooooooooooooooooooooooooX",
+"XooooooooooooooooooooooooooooooooooooooX",
+"XooooooooooooooooooooooooooooooooooooooX",
+"XooooooooooooooooooooooooooooooooooooooX",
+"XooooooooooooooooooooooooooooooooooooooX",
+"XooooooooooooooooooooooooooooooooooooooX",
+"XooooooooooooooooooooooooooooooooooooooX",
+"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
+};
+/* XPM */
+static const char *dex_xpm[] = {
/* width height ncolors chars_per_pixel */
"40 40 19 1",
/* colors */
@@ -373,7 +514,7 @@ static char *dex_xpm[] = {
"#################O######################"
};
/* XPM */
-static char *ext_enc_xpm[] = {
+static const char *ext_enc_xpm[] = {
/* width height ncolors chars_per_pixel */
"40 40 13 1",
/* colors */
@@ -433,7 +574,105 @@ static char *ext_enc_xpm[] = {
"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO"
};
/* XPM */
-static char *hallu_xpm[] = {
+static const char *fly_xpm[] = { // placeholder for Flying condition
+/* width height ncolors chars_per_pixel */
+"40 40 2 1",
+/* colors */
+"X c None",
+"o c #7fefef",
+/* pixels */
+"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
+"XooooooooooooooooooooooooooooooooooooooX",
+"XooooooooooooooooooooooooooooooooooooooX",
+"XooooooooooooooooooooooooooooooooooooooX",
+"XooooooooooooooooooooooooooooooooooooooX",
+"XooooooooooooooooooooooooooooooooooooooX",
+"XooooooooooooooooooooooooooooooooooooooX",
+"XooooooooooooooooooooooooooooooooooooooX",
+"XooooooooooooooooooooooooooooooooooooooX",
+"XooooooooooooooooooooooooooooooooooooooX",
+"XooooooooooooooooooooooooooooooooooooooX",
+"XooooooooooooooooooooooooooooooooooooooX",
+"XooooooooooooooooooooooooooooooooooooooX",
+"XooooooooooooooooooooooooooooooooooooooX",
+"XooooooooooooooooooooooXoooXoooooooooooX",
+"XooooooooooooooooooooooXoooXoooooooooooX",
+"XoooooooooooooooooXoooooXoXooooooooooooX",
+"XoooooooooooooooooXoooooXoXooooooooooooX",
+"XooooooooooXXXXXooXooooooXoooooooooooooX",
+"XooooooooooXooooooXooooooXoooooooooooooX",
+"XooooooooooXooooooXooooooXoooooooooooooX",
+"XooooooooooXXXXoooXooooooooooooooooooooX",
+"XooooooooooXooooooXXXXoooooooooooooooooX",
+"XooooooooooXoooooooooooooooooooooooooooX",
+"XooooooooooXoooooooooooooooooooooooooooX",
+"XooooooooooooooooooooooooooooooooooooooX",
+"XooooooooooooooooooooooooooooooooooooooX",
+"XooooooooooooooooooooooooooooooooooooooX",
+"XooooooooooooooooooooooooooooooooooooooX",
+"XooooooooooooooooooooooooooooooooooooooX",
+"XooooooooooooooooooooooooooooooooooooooX",
+"XooooooooooooooooooooooooooooooooooooooX",
+"XooooooooooooooooooooooooooooooooooooooX",
+"XooooooooooooooooooooooooooooooooooooooX",
+"XooooooooooooooooooooooooooooooooooooooX",
+"XooooooooooooooooooooooooooooooooooooooX",
+"XooooooooooooooooooooooooooooooooooooooX",
+"XooooooooooooooooooooooooooooooooooooooX",
+"XooooooooooooooooooooooooooooooooooooooX",
+"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
+};
+/* XPM */
+static const char *lev_xpm[] = { // placeholder for Levitating condition
+/* width height ncolors chars_per_pixel */
+"40 40 2 1",
+/* colors */
+"X c None",
+"o c #df1010",
+/* pixels */
+"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
+"XooooooooooooooooooooooooooooooooooooooX",
+"XooooooooooooooooooooooooooooooooooooooX",
+"XooooooooooooooooooooooooooooooooooooooX",
+"XooooooooooooooooooooooooooooooooooooooX",
+"XooooooooooooooooooooooooooooooooooooooX",
+"XooooooooooooooooooooooooooooooooooooooX",
+"XooooooooooooooooooooooooooooooooooooooX",
+"XooooooooooooooooooooooooooooooooooooooX",
+"XooooooooooooooooooooooooooooooooooooooX",
+"XooooooooooooooooooooooooooooooooooooooX",
+"XooooooooooooooooooooooooooooooooooooooX",
+"XooooooooooooooooooooooooooooooooooooooX",
+"XooooooooooooooooooooooooooooooooooooooX",
+"XooooooooooooooooooooooXoooooXoooooooooX",
+"XooooooooooooooooooooooXoooooXoooooooooX",
+"XoooooooooooooooXXXXXoooXoooXooooooooooX",
+"XoooooooooooooooXoooooooXoooXooooooooooX",
+"XoooooooooXoooooXooooooooXoXoooooooooooX",
+"XoooooooooXoooooXXXXoooooXoXoooooooooooX",
+"XoooooooooXoooooXoooooooooXooooooooooooX",
+"XoooooooooXoooooXooooooooooooooooooooooX",
+"XoooooooooXoooooXXXXXooooooooooooooooooX",
+"XoooooooooXooooooooooooooooooooooooooooX",
+"XoooooooooXXXXoooooooooooooooooooooooooX",
+"XooooooooooooooooooooooooooooooooooooooX",
+"XooooooooooooooooooooooooooooooooooooooX",
+"XooooooooooooooooooooooooooooooooooooooX",
+"XooooooooooooooooooooooooooooooooooooooX",
+"XooooooooooooooooooooooooooooooooooooooX",
+"XooooooooooooooooooooooooooooooooooooooX",
+"XooooooooooooooooooooooooooooooooooooooX",
+"XooooooooooooooooooooooooooooooooooooooX",
+"XooooooooooooooooooooooooooooooooooooooX",
+"XooooooooooooooooooooooooooooooooooooooX",
+"XooooooooooooooooooooooooooooooooooooooX",
+"XooooooooooooooooooooooooooooooooooooooX",
+"XooooooooooooooooooooooooooooooooooooooX",
+"XooooooooooooooooooooooooooooooooooooooX",
+"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
+};
+/* XPM */
+static const char *hallu_xpm[] = {
/* width height ncolors chars_per_pixel */
"40 40 30 1",
/* colors */
@@ -510,7 +749,7 @@ static char *hallu_xpm[] = {
"$$$$$$$$$$$$$$$$$$$$$%$$+$$$$$$$$$$$$$$$"
};
/* XPM */
-static char *hungry_xpm[] = {
+static const char *hungry_xpm[] = {
/* width height ncolors chars_per_pixel */
"40 40 15 1",
/* colors */
@@ -572,7 +811,7 @@ static char *hungry_xpm[] = {
"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO"
};
/* XPM */
-static char *hvy_enc_xpm[] = {
+static const char *hvy_enc_xpm[] = {
/* width height ncolors chars_per_pixel */
"40 40 13 1",
/* colors */
@@ -632,7 +871,7 @@ static char *hvy_enc_xpm[] = {
"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO"
};
/* XPM */
-static char *int_xpm[] = {
+static const char *int_xpm[] = {
/* width height ncolors chars_per_pixel */
"40 40 12 1",
/* colors */
@@ -691,7 +930,7 @@ static char *int_xpm[] = {
"OOOOOOOOOOOOOOOOOOOOOOOoOOOOOOOOOOOOOOOO"
};
/* XPM */
-static char *lawful_xpm[] = {
+static const char *lawful_xpm[] = {
/* width height ncolors chars_per_pixel */
"40 40 10 1",
/* colors */
@@ -748,7 +987,7 @@ static char *lawful_xpm[] = {
"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO"
};
/* XPM */
-static char *mod_enc_xpm[] = {
+static const char *mod_enc_xpm[] = {
/* width height ncolors chars_per_pixel */
"40 40 13 1",
/* colors */
@@ -808,7 +1047,7 @@ static char *mod_enc_xpm[] = {
"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO"
};
/* XPM */
-static char *neutral_xpm[] = {
+static const char *neutral_xpm[] = {
/* width height ncolors chars_per_pixel */
"40 40 14 1",
/* colors */
@@ -869,7 +1108,7 @@ static char *neutral_xpm[] = {
"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO"
};
/* XPM */
-static char *ovr_enc_xpm[] = {
+static const char *ovr_enc_xpm[] = {
/* width height ncolors chars_per_pixel */
"40 40 13 1",
/* colors */
@@ -929,7 +1168,56 @@ static char *ovr_enc_xpm[] = {
"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO"
};
/* XPM */
-static char *satiated_xpm[] = {
+static const char *ride_xpm[] = { // placeholder for Riding condition
+/* width height ncolors chars_per_pixel */
+"40 40 2 1",
+/* colors */
+"X c None",
+"o c #df7f00",
+/* pixels */
+"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
+"XooooooooooooooooooooooooooooooooooooooX",
+"XooooooooooooooooooooooooooooooooooooooX",
+"XooooooooooooooooooooooooooooooooooooooX",
+"XooooooooooooooooooooooooooooooooooooooX",
+"XooooooooooooooooooooooooooooooooooooooX",
+"XooooooooooooooooooooooooooooooooooooooX",
+"XooooooooooooooooooooooooooooooooooooooX",
+"XooooooooooooooooooooooooooooooooooooooX",
+"XooooooooooooooooooooooooooooooooooooooX",
+"XooooooooooooooooooooooooooooooooooooooX",
+"XooooooooooooooooooooooooooooooooooooooX",
+"XooooooooooooooooooooooooooooooooooooooX",
+"XooooooooooooooooooooooooooooooooooooooX",
+"XooooooooooooooooooooooooooooooooooooooX",
+"XooooooooooooooooooooooooooooooooooooooX",
+"XoooooooXXXXoooXXXooXXXXoooXXXXXoooooooX",
+"XoooooooXoooXoooXoooXoooXooXoooooooooooX",
+"XoooooooXoooXoooXoooXoooXooXoooooooooooX",
+"XoooooooXXXXooooXoooXoooXooXXXXooooooooX",
+"XoooooooXoXoooooXoooXoooXooXoooooooooooX",
+"XoooooooXooXooooXoooXoooXooXoooooooooooX",
+"XoooooooXoooXooXXXooXXXXoooXXXXXoooooooX",
+"XooooooooooooooooooooooooooooooooooooooX",
+"XooooooooooooooooooooooooooooooooooooooX",
+"XooooooooooooooooooooooooooooooooooooooX",
+"XooooooooooooooooooooooooooooooooooooooX",
+"XooooooooooooooooooooooooooooooooooooooX",
+"XooooooooooooooooooooooooooooooooooooooX",
+"XooooooooooooooooooooooooooooooooooooooX",
+"XooooooooooooooooooooooooooooooooooooooX",
+"XooooooooooooooooooooooooooooooooooooooX",
+"XooooooooooooooooooooooooooooooooooooooX",
+"XooooooooooooooooooooooooooooooooooooooX",
+"XooooooooooooooooooooooooooooooooooooooX",
+"XooooooooooooooooooooooooooooooooooooooX",
+"XooooooooooooooooooooooooooooooooooooooX",
+"XooooooooooooooooooooooooooooooooooooooX",
+"XooooooooooooooooooooooooooooooooooooooX",
+"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
+};
+/* XPM */
+static const char *satiated_xpm[] = {
/* width height ncolors chars_per_pixel */
"40 40 23 1",
/* colors */
@@ -999,7 +1287,7 @@ static char *satiated_xpm[] = {
"########################################"
};
/* XPM */
-static char *sick_fp_xpm[] = {
+static const char *sick_fp_xpm[] = {
/* width height ncolors chars_per_pixel */
"40 40 30 1",
/* colors */
@@ -1076,7 +1364,7 @@ static char *sick_fp_xpm[] = {
"*****************=*=********************"
};
/* XPM */
-static char *sick_il_xpm[] = {
+static const char *sick_il_xpm[] = {
/* width height ncolors chars_per_pixel */
"40 40 23 1",
/* colors */
@@ -1146,7 +1434,56 @@ static char *sick_il_xpm[] = {
"#################$#$####################"
};
/* XPM */
-static char *slt_enc_xpm[] = {
+static const char *slime_xpm[] = { // placeholder for Slimed condition
+/* width height ncolors chars_per_pixel */
+"40 40 2 1",
+/* colors */
+"X c None",
+"o c #40df40",
+/* pixels */
+"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
+"XooooooooooooooooooooooooooooooooooooooX",
+"XooooooooooooooooooooooooooooooooooooooX",
+"XooooooooooooooooooooooooooooooooooooooX",
+"XooooooooooooooooooooooooooooooooooooooX",
+"XooooooooooooooooooooooooooooooooooooooX",
+"XooooXXXoooooooooooooooooooooooooooooooX",
+"XoooXooooooooooooooooooooooooooooooooooX",
+"XoooXooooooooooooooooooooooooooooooooooX",
+"XooooXXXoooooooooooooooooooooooooooooooX",
+"XoooooooXooooooooooooooooooooooooooooooX",
+"XoooooooXooXoooooooooooooooooooooooooooX",
+"XooooXXXoooXoooooooooooooooooooooooooooX",
+"XooooooooooXoooooooooooooooooooooooooooX",
+"XooooooooooXoooooooooooooooooooooooooooX",
+"XooooooooooXooooooXXXooooooooooooooooooX",
+"XooooooooooXoooooooXoooooooooooooooooooX",
+"XooooooooooXXXXXoooXoooooooooooooooooooX",
+"XooooooooooooooooooXoooooooooooooooooooX",
+"XooooooooooooooooooXoooooooooooooooooooX",
+"XooooooooooooooooooXoooXoooooXoooooooooX",
+"XoooooooooooooooooXXXooXXoooXXoooooooooX",
+"XooooooooooooooooooooooXXXoXXXoooooooooX",
+"XooooooooooooooooooooooXoXXXoXoooooooooX",
+"XooooooooooooooooooooooXooXooXoooooooooX",
+"XooooooooooooooooooooooXoooooXooXXXXXooX",
+"XooooooooooooooooooooooXoooooXooXooooooX",
+"XoooooooooooooooooooooooooooooooXooooooX",
+"XoooooooooooooooooooooooooooooooXXXXoooX",
+"XoooooooooooooooooooooooooooooooXooooooX",
+"XoooooooooooooooooooooooooooooooXooooooX",
+"XoooooooooooooooooooooooooooooooXXXXXooX",
+"XooooooooooooooooooooooooooooooooooooooX",
+"XooooooooooooooooooooooooooooooooooooooX",
+"XooooooooooooooooooooooooooooooooooooooX",
+"XooooooooooooooooooooooooooooooooooooooX",
+"XooooooooooooooooooooooooooooooooooooooX",
+"XooooooooooooooooooooooooooooooooooooooX",
+"XooooooooooooooooooooooooooooooooooooooX",
+"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
+};
+/* XPM */
+static const char *slt_enc_xpm[] = {
/* width height ncolors chars_per_pixel */
"40 40 13 1",
/* colors */
@@ -1206,7 +1543,56 @@ static char *slt_enc_xpm[] = {
"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO"
};
/* XPM */
-static char *str_xpm[] = {
+static const char *stone_xpm[] = { // placeholder for Stoned condition
+/* width height ncolors chars_per_pixel */
+"40 40 2 1",
+/* colors */
+"X c None",
+"o c #6c91b6",
+/* pixels */
+"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
+"XooooooooooooooooooooooooooooooooooooooX",
+"XooooooooooooooooooooooooooooooooooooooX",
+"XooooooooooooooooooooooooooooooooooooooX",
+"XooooooooooooooooooooooooooooooooooooooX",
+"XooooooooooooooooooooooooooooooooooooooX",
+"XooooXXXoooooooooooooooooooooooooooooooX",
+"XoooXooooooooooooooooooooooooooooooooooX",
+"XoooXooooooooooooooooooooooooooooooooooX",
+"XooooXXXoooooooooooooooooooooooooooooooX",
+"XoooooooXooooooooooooooooooooooooooooooX",
+"XoooooooXooXXXXXoooooooooooooooooooooooX",
+"XooooXXXoooooXoooooooooooooooooooooooooX",
+"XooooooooooooXoooooooooooooooooooooooooX",
+"XooooooooooooXoooooooooooooooooooooooooX",
+"XooooooooooooXooooXXXooooooooooooooooooX",
+"XooooooooooooXoooXoooXoooooooooooooooooX",
+"XooooooooooooXoooXoooXoooooooooooooooooX",
+"XooooooooooooooooXoooXoooooooooooooooooX",
+"XooooooooooooooooXoooXoooooooooooooooooX",
+"XooooooooooooooooXoooXooXoooXooooooooooX",
+"XoooooooooooooooooXXXoooXXooXooooooooooX",
+"XoooooooooooooooooooooooXXooXooooooooooX",
+"XoooooooooooooooooooooooXoXoXooooooooooX",
+"XoooooooooooooooooooooooXooXXooooooooooX",
+"XoooooooooooooooooooooooXooXXooXXXXXoooX",
+"XoooooooooooooooooooooooXoooXooXoooooooX",
+"XooooooooooooooooooooooooooooooXoooooooX",
+"XooooooooooooooooooooooooooooooXXXXooooX",
+"XooooooooooooooooooooooooooooooXoooooooX",
+"XooooooooooooooooooooooooooooooXoooooooX",
+"XooooooooooooooooooooooooooooooXXXXXoooX",
+"XooooooooooooooooooooooooooooooooooooooX",
+"XooooooooooooooooooooooooooooooooooooooX",
+"XooooooooooooooooooooooooooooooooooooooX",
+"XooooooooooooooooooooooooooooooooooooooX",
+"XooooooooooooooooooooooooooooooooooooooX",
+"XooooooooooooooooooooooooooooooooooooooX",
+"XooooooooooooooooooooooooooooooooooooooX",
+"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
+};
+/* XPM */
+static const char *str_xpm[] = {
/* width height ncolors chars_per_pixel */
"40 40 17 1",
/* colors */
@@ -1270,7 +1656,56 @@ static char *str_xpm[] = {
"++++++++++++++++++++++++++++++++++++++++"
};
/* XPM */
-static char *stunned_xpm[] = {
+static const char *strngl_xpm[] = { // placeholder for Strangled condition
+/* width height ncolors chars_per_pixel */
+"40 40 2 1",
+/* colors */
+"X c None",
+"o c #bf40ff",
+/* pixels */
+"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
+"XooooooooooooooooooooooooooooooooooooooX",
+"XooooooooooooooooooooooooooooooooooooooX",
+"XooooooooooooooooooooooooooooooooooooooX",
+"XooXXXoooooooooooooooooooooooooooooooooX",
+"XoXooooooooooooooooooooooooooooooooooooX",
+"XoXooooooooooooooooooooooooooooooooooooX",
+"XoXXXXoooooooooooooooooooooooooooooooooX",
+"XoooooXooooooooooooooooooooooooooooooooX",
+"XoooooXooXXXXXoooooooooooooooooooooooooX",
+"XooXXXoooooXoooooooooooooooooooooooooooX",
+"XooooooooooXoooooooooooooooooooooooooooX",
+"XooooooooooXoooooooooooooooooooooooooooX",
+"XooooooooooXoooooooooooooooooooooooooooX",
+"XooooooooooXooXXXXoooooooooooooooooooooX",
+"XooooooooooXooXoooXooooooooooooooooooooX",
+"XoooooooooooooXoooXooooooooooooooooooooX",
+"XoooooooooooooXXXXoooooooooooooooooooooX",
+"XoooooooooooooXoXooooooooooooooooooooooX",
+"XoooooooooooooXooXoooXoooXoooooooooooooX",
+"XoooooooooooooXoooXooXXooXoooooooooooooX",
+"XooooooooooooooooooooXXooXoooooooooooooX",
+"XooooooooooooooooooooXoXoXoooooooooooooX",
+"XooooooooooooooooooooXooXXoooooooooooooX",
+"XooooooooooooooooooooXooXXoooXXXoooooooX",
+"XooooooooooooooooooooXoooXooXooooooooooX",
+"XoooooooooooooooooooooooooooXooooooooooX",
+"XoooooooooooooooooooooooooooXoXXXooooooX",
+"XoooooooooooooooooooooooooooXoooXooooooX",
+"XoooooooooooooooooooooooooooXoooXooXoooX",
+"XooooooooooooooooooooooooooooXXXoooXoooX",
+"XooooooooooooooooooooooooooooooooooXoooX",
+"XooooooooooooooooooooooooooooooooooXoooX",
+"XooooooooooooooooooooooooooooooooooXoooX",
+"XooooooooooooooooooooooooooooooooooXoooX",
+"XooooooooooooooooooooooooooooooooooXXXXX",
+"XooooooooooooooooooooooooooooooooooooooX",
+"XooooooooooooooooooooooooooooooooooooooX",
+"XooooooooooooooooooooooooooooooooooooooX",
+"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
+};
+/* XPM */
+static const char *stunned_xpm[] = {
/* width height ncolors chars_per_pixel */
"40 40 12 1",
/* colors */
@@ -1329,7 +1764,7 @@ static char *stunned_xpm[] = {
"OOOOOOOOOOOOOOOOOOOOO.X%& $OOOOOOOOOOOOO"
};
/* XPM */
-static char *wis_xpm[] = {
+static const char *wis_xpm[] = {
/* width height ncolors chars_per_pixel */
"40 40 13 1",
/* colors */
@@ -1359,12 +1794,6 @@ static char *wis_xpm[] = {
"oooooooooooooooooooooooooooooooooooooooo",
"oooooooooooooooooooooooooooooooooooooooo",
"oooooooooooooooooooooooooooooooooooooooo",
-"oooooooooooooooooooooooooooooooooooooooo",
-"oooooooooooooooooooooooooooooooooooooooo",
-"oooooooooooooooooooooooooooooooooooooooo",
-"oooooooooooooooooooooooooooooooooooooooo",
-"oooooooooooooooooooooooooooooooooooooooo",
-"oooooooooooooooooooooooooooooooooooooooo",
"oooooooooooooo+#& oooooooooooooooooooo",
"oooooooooooo+& #oooooooooooooooooo",
"ooooooooooo+ &====&& &ooooooooooooooooo",
@@ -1386,60 +1815,6 @@ static char *wis_xpm[] = {
"oooooooooooooooooooooooooooooooooooooooo",
"oooooooooooooooooooooooooooooooooooooooo",
"oooooooooooooooooooooooooooooooooooooooo",
-"oooooooooooooooooooooooooooooooooooooooo"
-};
-/* XPM */
-static char *nothing_xpm[] = {
-/* width height ncolors chars_per_pixel */
-"40 40 13 1",
-/* colors */
-" c #000000",
-". c #949E9E",
-"X c #5C7A7A",
-"o c None",
-"O c #B0B0B0",
-"+ c #909090",
-"@ c #788C8C",
-"# c #606060",
-"$ c #406868",
-"% c #FFFFFF",
-"& c #303030",
-"* c #6C91B6",
-"= c #0000FF",
-/* pixels */
-"oooooooooooooooooooooooooooooooooooooooo",
-"oooooooooooooooooooooooooooooooooooooooo",
-"oooooooooooooooooooooooooooooooooooooooo",
-"oooooooooooooooooooooooooooooooooooooooo",
-"oooooooooooooooooooooooooooooooooooooooo",
-"oooooooooooooooooooooooooooooooooooooooo",
-"oooooooooooooooooooooooooooooooooooooooo",
-"oooooooooooooooooooooooooooooooooooooooo",
-"oooooooooooooooooooooooooooooooooooooooo",
-"oooooooooooooooooooooooooooooooooooooooo",
-"oooooooooooooooooooooooooooooooooooooooo",
-"oooooooooooooooooooooooooooooooooooooooo",
-"oooooooooooooooooooooooooooooooooooooooo",
-"oooooooooooooooooooooooooooooooooooooooo",
-"oooooooooooooooooooooooooooooooooooooooo",
-"oooooooooooooooooooooooooooooooooooooooo",
-"oooooooooooooooooooooooooooooooooooooooo",
-"oooooooooooooooooooooooooooooooooooooooo",
-"oooooooooooooooooooooooooooooooooooooooo",
-"oooooooooooooooooooooooooooooooooooooooo",
-"oooooooooooooooooooooooooooooooooooooooo",
-"oooooooooooooooooooooooooooooooooooooooo",
-"oooooooooooooooooooooooooooooooooooooooo",
-"oooooooooooooooooooooooooooooooooooooooo",
-"oooooooooooooooooooooooooooooooooooooooo",
-"oooooooooooooooooooooooooooooooooooooooo",
-"oooooooooooooooooooooooooooooooooooooooo",
-"oooooooooooooooooooooooooooooooooooooooo",
-"oooooooooooooooooooooooooooooooooooooooo",
-"oooooooooooooooooooooooooooooooooooooooo",
-"oooooooooooooooooooooooooooooooooooooooo",
-"oooooooooooooooooooooooooooooooooooooooo",
-"oooooooooooooooooooooooooooooooooooooooo",
"oooooooooooooooooooooooooooooooooooooooo",
"oooooooooooooooooooooooooooooooooooooooo",
"oooooooooooooooooooooooooooooooooooooooo",
@@ -1448,4 +1823,5 @@ static char *nothing_xpm[] = {
"oooooooooooooooooooooooooooooooooooooooo",
"oooooooooooooooooooooooooooooooooooooooo"
};
+
/* clang-format on */
diff --git a/win/Qt/qt_yndlg.cpp b/win/Qt/qt_yndlg.cpp
new file mode 100644
index 000000000..57e2f212f
--- /dev/null
+++ b/win/Qt/qt_yndlg.cpp
@@ -0,0 +1,429 @@
+// Copyright (c) Warwick Allison, 1999.
+// Qt4 conversion copyright (c) Ray Chason, 2012-2014.
+// NetHack may be freely redistributed. See license for details.
+
+// qt_yndlg.cpp -- yes/no dialog
+
+extern "C" {
+#include "hack.h"
+}
+
+#include "qt_pre.h"
+#include
+#if QT_VERSION >= 0x050000
+#include
+#endif
+#include "qt_post.h"
+#include "qt_yndlg.h"
+#include "qt_yndlg.moc"
+#include "qt_key.h" // for keyValue()
+#include "qt_str.h"
+
+// temporary
+extern int qt_compact_mode;
+// end temporary
+
+namespace nethack_qt_ {
+
+static const char lrq[] = "lr\033LRq";
+char altchoices[BUFSZ + 12];
+
+// temporary
+void centerOnMain(QWidget *);
+// end temporary
+
+NetHackQtYnDialog::NetHackQtYnDialog(QWidget *parent, const QString &q,
+ const char *ch, char df) :
+ QDialog(parent),
+ question(q), choices(ch), def(df),
+ keypress('\033'),
+ allow_count(false),
+ le((QLineEdit *) NULL),
+ y_btn((QPushButton *) NULL)
+{
+ setWindowTitle("NetHack: Question");
+
+ // plain prompt doesn't show any room for an answer (answer won't be
+ // echoed but the fact that a prompt is pending and accepts typed
+ // input as an alternative to mouse click seems clearer when there
+ // is some space available to accept it)
+ if (!question.endsWith(" ") && !question.endsWith("_"))
+ question += " _"; // an underlined space would be better
+
+ if (choices) {
+ // special handling for wearing rings; prompt asks "right or left?"
+ // but side-by-side buttons look better with [left][right] instead
+ // (assumes that we're using left to right layout)
+ if (!strcmp(choices, "rl")) {
+ choices = lrq;
+ if (!def)
+ def = 'r';
+
+ // if count is allowed, explicitly add the digits as valid
+ } else if (!strncmp(choices, "yn#", (size_t) 3)) {
+ ::yn_number = 0L;
+ allow_count = true;
+
+ if (!strchr(choices, '9')) {
+ copynchars(altchoices, choices, BUFSZ - 1);
+ // duplicate # is intentional; explicitly separates \... and 0
+ choices = strcat(altchoices, "\033#0123456789");
+ }
+ }
+ }
+ alt_answer[0] = alt_result[0] = '\0';
+}
+
+char NetHackQtYnDialog::Exec()
+{
+ QString ch(QString::fromLatin1(choices));
+// int ch_per_line=6;
+ QString qlabel;
+ QString enable;
+ if ( qt_compact_mode && !choices ) {
+ ch = "";
+ // expand choices from prompt
+ // ##### why isn't choices set properly???
+ int c = question.indexOf(QChar('['));
+ qlabel = QString(question).left(c);
+ if ( c >= 0 ) {
+ c++;
+ if ( question[c] == '-' )
+ ch.append(question[c++]);
+ unsigned from=0;
+ while (c < question.size()
+ && question[c] != ']' && question[c] != ' ') {
+ if ( question[c] == '-' ) {
+ from = question[c - 1].cell();
+ } else if ( from != 0 ) {
+ for (unsigned f=from+1; QChar(f)<=question[c]; f++)
+ ch.append(QChar(f));
+ from = 0;
+ } else {
+ ch.append(question[c]);
+ from = 0;
+ }
+ c++;
+ }
+ if ( question[c] == ' ' ) {
+ while ( c < question.size() && question[c] != ']' ) {
+ if ( question[c] == '*' || question[c] == '?' )
+ ch.append(question[c]);
+ c++;
+ }
+ }
+ }
+ if ( question.indexOf("what direction") >= 0 ) {
+ // We replace this regardless, since sometimes you get choices.
+ const char* d = gc.Cmd.dirchars;
+ enable=ch;
+ ch="";
+ ch.append(d[1]);
+ ch.append(d[2]);
+ ch.append(d[3]);
+ ch.append(d[0]);
+ ch.append('.');
+ ch.append(d[4]);
+ ch.append(d[7]);
+ ch.append(d[6]);
+ ch.append(d[5]);
+ ch.append(d[8]);
+ ch.append(d[9]);
+// ch_per_line = 3;
+ def = ' ';
+ } else {
+ // Hmm... they'll have to use a virtual keyboard
+ }
+ } else {
+ ch = QString::fromLatin1(choices);
+ qlabel = question.replace(QChar(0x200B), QString(""));
+ }
+ if (!ch.isNull()) {
+ QVBoxLayout *vb = new QVBoxLayout;
+ bool bigq = (qlabel.length() > (qt_compact_mode ? 40 : 60));
+ if (bigq) {
+ QLabel *q = new QLabel(qlabel, this);
+ q->setAlignment(Qt::AlignLeft);
+ q->setWordWrap(true);
+ q->setMargin(4);
+ vb->addWidget(q);
+ }
+ QGroupBox *group = new QGroupBox(bigq ? QString() : qlabel, this);
+ vb->addWidget(group);
+ QHBoxLayout *groupbox = new QHBoxLayout();
+ group->setLayout(groupbox);
+ QButtonGroup *bgroup = new QButtonGroup(group);
+
+ int nchoices=ch.length();
+ // note: is_ynaq covers nyaq too because the choices string is
+ // "ynaq" for both; only the default differs; likewise for nyNaq
+ bool is_ynaq = (ch == QString("ynaq") // [Yes ][ No ][All ][Stop]
+ || ch == QString("yn#aq")
+ || ch == altchoices), // alternate "yn#aq"
+ is_ynq = (ch == QString("ynq")), // [ Yes ][ No ][Cancel]
+ is_yn = (ch == QString("yn")), // [Yes ][ No ]
+ is_lr = (ch == QString(lrq)); // [ Left ][Right ]
+
+#if 0
+ const int margin=8;
+ const int gutter=8;
+ const int extra=fontMetrics().height(); // Extra for group
+ int x=margin, y=extra+margin;
+#endif
+ int butheight = fontMetrics().height() * 2 + 5,
+ butwidth = (butheight - 5) * ((is_ynq || is_lr) ? 3
+ : (is_ynaq || is_yn) ? 2 : 1) + 5;
+ if (butwidth == butheight) { // square, enough room for C or ^C
+ // some characters will be labelled by name rather than by
+ // keystroke so will need wider buttons
+ for (int i = 0; i < nchoices; ++i) {
+ if (ch[i] == '\033')
+ break; // ESC and anything after are hidden
+ if (ch[i] == ' ' || ch[i] == '\n' || ch[i] == '\r') {
+ butwidth = (butheight - 5) * 2 + 5;
+ break;
+ }
+ }
+ }
+
+ QPushButton *button;
+ for (int i = 0; i < nchoices; ++i) {
+ bool making_y = false;
+ if (ch[i] == '\033')
+ break; // ESC and anything after are hidden
+ if (ch[i] == '#' && allow_count)
+ continue; // don't show a button for '#'; has Count box instead
+ QString button_name = QString(visctrl((char) ch[i].cell()));
+ if (is_yn || is_ynq || is_ynaq || is_lr) {
+ // FIXME: a better way to recognize which labels should
+ // use alternate text is needed
+ switch (ch[i].cell()) {
+ case 'y':
+ button_name = "Yes";
+ making_y = true;
+ break;
+ case 'n':
+ button_name = "No";
+ break;
+ case 'a':
+ // the display of vanquished monsters uses "ynaq" for
+ // convenience, where 'a' requests a sort-by menu;
+ // show "sort" instead of "all" and allow player to
+ // type either 'a' or 's' when not clicking on button
+ if (question.contains(QString("vanquished?")))
+ button_name = "Sort", AltChoice('s', 'a');
+ else
+ button_name = "All";
+ break;
+ case 'q':
+ // most 'q' replies are actually for "cancel" but
+ // for "ynaq" (where "all" is a choice) it's "stop"
+ // and for end of game disclosure it really is "quit"
+ if (question.left(10) == QString("Dump core?")
+ || (::program_state.gameover
+ && question.left(11) == QString("Do you want")))
+ button_name = "Quit";
+ else if (is_ynaq)
+ button_name = "Stop", AltChoice('s', 'q');
+ else
+ button_name = "Cancel", AltChoice('c', 'q');
+ break;
+ case 'l':
+ button_name = "Left";
+ break;
+ case 'r':
+ button_name = "Right";
+ break;
+ }
+ } else {
+ // special characters usually aren't listed among choices
+ // but if they are, label the buttons for them with sensible
+ // names; we want to avoid "^J" and "^M" for \n and \r;
+ // and are equivalent to each other but
+ // labelling \n as newline or line-feed seems confusing;
+ switch (ch[i].cell()) {
+ case ' ':
+ button_name = "Spc";
+ break;
+ case '\n':
+ button_name = "Ent";
+ break;
+ case '\r':
+ button_name = "Ret";
+ break;
+ case '\033': // won't happen; ESC is hidden
+ button_name = "Esc";
+ break;
+ case '&':
+ // ampersand is used as a hidden quote char to flag
+ // next character as a keyboard shortcut associated
+ // with the current action--that's inappropriate here;
+ // two consecutive ampersands are needed to display
+ // one in a button label; first check whether caller
+ // has already done that, skip this one if so
+ if (i > 0 && ch[i - 1].cell() == '&')
+ continue; // next i
+ button_name = "&&";
+ break;
+ }
+ }
+ button=new QPushButton(button_name);
+ if (making_y && allow_count)
+ y_btn = button; // to change default in keyPressEvent()
+ if (!enable.isNull()) {
+ if (!enable.contains(ch[i]))
+ button->setEnabled(false);
+ }
+ button->setFixedSize(butwidth, butheight);
+ if (ch[i] == def)
+ button->setDefault(true);
+#if 0
+ // 'x' and 'y' don't seem to actually used anywhere
+ // and limit of 10 buttons per row isn't enforced
+ if (i % 10 == 9) {
+ // last in row
+ x = margin;
+ y += butheight + gutter;
+ } else {
+ x += butwidth + gutter;
+ }
+#endif
+ groupbox->addWidget(button);
+ bgroup->addButton(button, i);
+ }
+
+ connect(bgroup, SIGNAL(buttonClicked(int)), this, SLOT(doneItem(int)));
+
+ QLabel *lb = 0;
+ if (allow_count) {
+ // insert Count widget in front of [n], between [y] and [n][a][q]
+ lb = new QLabel("Count:");
+ groupbox->insertWidget(1, lb); // [y] button is item #0, [n] is #1
+ le = new QLineEdit();
+ groupbox->insertWidget(2, le); // [n] became #2, Count label is #1
+ le->setPlaceholderText(QString("#")); // grayed out
+ }
+ // add an invisible right-most field to left justify the buttons
+ groupbox->addStretch(80);
+
+ setLayout(vb);
+ adjustSize();
+ centerOnMain(this);
+ show();
+ char choice=0;
+ char ch_esc=0;
+ for (int i = 0; i < ch.length(); ++i) {
+ if (ch[i].cell() == 'q')
+ ch_esc = 'q';
+ else if (!ch_esc && ch[i].cell() == 'n')
+ ch_esc = 'n';
+ }
+
+ //
+ // When a count is allowed, clicking on the count widget then
+ // typing in digits followed by is 'normal' operation.
+ // However, typing a digit without clicking first will set focus
+ // to the count widget with that typed digit preloaded.
+ //
+ exec();
+ int res = result();
+ if (res == 0) {
+ choice = is_lr ? '\033' : ch_esc ? ch_esc : def ? def : ' ';
+ } else if (res == 1) {
+ if (keypress)
+ choice = keypress;
+ else
+ choice = def ? def : ch_esc ? ch_esc : ' ';
+ } else if (res >= 1000) {
+ choice = (char) ch[res - 1000].cell();
+ }
+
+ // non-Null 'le' implies 'allow_count'; having a grayed-out '#'
+ // present in the QLineEdit widget doesn't affect its isEmpty() test
+ if (le && !le->text().isEmpty()) {
+ QString text(le->text());
+ if (text.at(0) == QChar('#'))
+ text = text.mid(1); // rest of string past [0]
+ ::yn_number = text.toLong();
+ choice = '#';
+ }
+ keypress = choice;
+
+ } else {
+ QLabel label(qlabel,this);
+ QPushButton cancel("Dismiss",this);
+#if __cplusplus >= 202002L
+ label.setFrameStyle(static_cast(QFrame::Box)
+ | static_cast(QFrame::Sunken));
+#else
+ label.setFrameStyle(QFrame::Box|QFrame::Sunken);
+#endif
+ label.setAlignment(Qt::AlignCenter);
+ label.resize(fontMetrics().QFM_WIDTH(qlabel)+60,30+fontMetrics().height());
+ cancel.move(width()/2-cancel.width()/2,label.geometry().bottom()+8);
+ connect(&cancel,SIGNAL(clicked()),this,SLOT(reject()));
+ centerOnMain(this);
+ setResult(-1);
+ show();
+ keypress = '\033';
+ exec();
+ }
+ return keypress;
+}
+
+void NetHackQtYnDialog::AltChoice(char ans, char res)
+{
+ if (ans && !strchr(alt_answer, ans)) {
+ (void) strkitten(alt_answer, ans);
+ (void) strkitten(alt_result, res);
+ }
+}
+
+void NetHackQtYnDialog::keyPressEvent(QKeyEvent *event)
+{
+ keypress = keyValue(event);
+ if (!keypress)
+ return;
+
+ char *p = NULL;
+ if (*alt_answer && (p = strchr(alt_answer, keypress)) != 0)
+ keypress = alt_result[p - alt_answer];
+
+ if (!choices || !*choices || !keypress) {
+ this->done(1);
+
+ } else {
+ int where = QString::fromLatin1(choices).indexOf(QChar(keypress));
+
+ if (allow_count && strchr("#0123456789", keypress)) {
+ if (keypress == '#') {
+ // 0 will be preselected; typing anything replaces it
+ le->setText(QString("0"));
+ le->home(true);
+ } else {
+ // digit will not be preselected; typing another appends
+ le->setText(QChar(keypress));
+ le->end(false);
+ }
+ // (don't know whether this actually does anything useful)
+ le->setAttribute(Qt::WA_KeyboardFocusChange, true);
+ // this is definitely useful...
+ le->setFocus(Qt::ActiveWindowFocusReason);
+ // change default button from 'n' to 'y'
+ if (y_btn)
+ y_btn->setDefault(true);
+ } else if (where != -1) {
+ this->done(where + 1000);
+
+ } else {
+ QDialog::keyPressEvent(event);
+ }
+ }
+}
+
+void NetHackQtYnDialog::doneItem(int i)
+{
+ this->done(i + 1000);
+}
+
+} // namespace nethack_qt_
diff --git a/win/Qt4/qt4yndlg.h b/win/Qt/qt_yndlg.h
similarity index 60%
rename from win/Qt4/qt4yndlg.h
rename to win/Qt/qt_yndlg.h
index d1474f541..0dd5d39e1 100644
--- a/win/Qt4/qt4yndlg.h
+++ b/win/Qt/qt_yndlg.h
@@ -2,12 +2,12 @@
// Qt4 conversion copyright (c) Ray Chason, 2012-2014.
// NetHack may be freely redistributed. See license for details.
-// qt4yndlg.h -- yes/no dialog
+// qt_yndlg.h -- yes/no dialog
#ifndef QT4YNDLG_H
#define QT4YNDLG_H
-namespace nethack_qt4 {
+namespace nethack_qt_ {
class NetHackQtYnDialog : QDialog {
Q_OBJECT
@@ -16,9 +16,16 @@ class NetHackQtYnDialog : QDialog {
const char* choices;
char def;
char keypress;
+ bool allow_count;
+ QLineEdit *le;
+ QPushButton *y_btn;
+
+ // arbitrary size; might need to be more sophisticated someday
+ char alt_answer[26 + 1], alt_result[26 + 1];
protected:
virtual void keyPressEvent(QKeyEvent*);
+ void AltChoice(char answer, char result);
private slots:
void doneItem(int);
@@ -29,6 +36,6 @@ private slots:
char Exec();
};
-} // namespace nethack_qt4
+} // namespace nethack_qt_
#endif
diff --git a/win/Qt/qttableview.cpp b/win/Qt/qttableview.cpp
deleted file mode 100644
index b53e8a415..000000000
--- a/win/Qt/qttableview.cpp
+++ /dev/null
@@ -1,2276 +0,0 @@
-/**********************************************************************
-** $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.4 $ $NHDT-Date: 1524684508 2018/04/25 19:28:28 $
-** $Id: qttableview.cpp,v 1.2 2002/03/09 03:13:15 jwalz Exp $
-**
-** Implementation of QtTableView class
-**
-** Created : 941115
-**
-** Copyright (C) 1992-2000 Trolltech AS. All rights reserved.
-**
-** This file contains a class moved out of the Qt GUI Toolkit API. It
-** may be used, distributed and modified without limitation.
-**
-**********************************************************************/
-
-#include "qttableview.h"
-#if QT_VERSION >= 300
-#ifndef QT_NO_QTTABLEVIEW
-#include
-#include
-#include
-#include
-
-enum ScrollBarDirtyFlags {
- verGeometry = 0x01,
- verSteps = 0x02,
- verRange = 0x04,
- verValue = 0x08,
- horGeometry = 0x10,
- horSteps = 0x20,
- horRange = 0x40,
- horValue = 0x80,
- verMask = 0x0F,
- horMask = 0xF0
-};
-
-
-#define HSBEXT horizontalScrollBar()->sizeHint().height()
-#define VSBEXT verticalScrollBar()->sizeHint().width()
-
-
-class QCornerSquare : public QWidget // internal class
-{
-public:
- QCornerSquare( QWidget *, const char* = 0 );
- void paintEvent( QPaintEvent * );
-};
-
-QCornerSquare::QCornerSquare( QWidget *parent, const char *name )
- : QWidget( parent, name )
-{
-}
-
-void QCornerSquare::paintEvent( QPaintEvent * )
-{
-}
-
-
-// NOT REVISED
-/*!
- \class QtTableView qttableview.h
- \brief The QtTableView class provides an abstract base for tables.
-
- \obsolete
-
- A table view consists of a number of abstract cells organized in rows
- and columns, and a visible part called a view. The cells are identified
- with a row index and a column index. The top-left cell is in row 0,
- column 0.
-
- The behavior of the widget can be finely tuned using
- setTableFlags(); a typical subclass will consist of little more than a
- call to setTableFlags(), some table content manipulation and an
- implementation of paintCell(). Subclasses that need cells with
- variable width or height must reimplement cellHeight() and/or
- cellWidth(). Use updateTableSize() to tell QtTableView when the
- width or height has changed.
-
- When you read this documentation, it is important to understand the
- distinctions among the four pixel coordinate systems involved.
-
- \list 1
- \i The \e cell coordinates. (0,0) is the top-left corner of a cell.
- Cell coordinates are used by functions such as paintCell().
-
- \i The \e table coordinates. (0,0) is the top-left corner of the cell at
- row 0 and column 0. These coordinates are absolute; that is, they are
- independent of what part of the table is visible at the moment. They are
- used by functions such as setXOffset() or maxYOffset().
-
- \i The \e widget coordinates. (0,0) is the top-left corner of the widget,
- \e including the frame. They are used by functions such as repaint().
-
- \i The \e view coordinates. (0,0) is the top-left corner of the view, \e
- excluding the frame. This is the least-used coordinate system; it is used by
- functions such as viewWidth(). \endlist
-
- It is rather unfortunate that we have to use four different
- coordinate systems, but there was no alternative to provide a flexible and
- powerful base class.
-
- Note: The row,column indices are always given in that order,
- i.e., first the vertical (row), then the horizontal (column). This is
- the opposite order of all pixel operations, which take first the
- horizontal (x) and then the vertical (y).
-
-
-
- \warning the functions setNumRows(), setNumCols(), setCellHeight(),
- setCellWidth(), setTableFlags() and clearTableFlags() may cause
- virtual functions such as cellWidth() and cellHeight() to be called,
- even if autoUpdate() is FALSE. This may cause errors if relevant
- state variables are not initialized.
-
- \warning Experience has shown that use of this widget tends to cause
- more bugs than expected and our analysis indicates that the widget's
- very flexibility is the problem. If QScrollView or QListBox can
- easily be made to do the job you need, we recommend subclassing
- those widgets rather than QtTableView. In addition, QScrollView makes
- it easy to have child widgets inside tables, which QtTableView
- doesn't support at all.
-
- \sa QScrollView
- \link guibooks.html#fowler GUI Design Handbook: Table\endlink
-*/
-
-
-/*!
- Constructs a table view. The \a parent, \a name and \f arguments
- are passed to the QFrame constructor.
-
- The \link setTableFlags() table flags\endlink are all cleared (set to 0).
- Set \c Tbl_autoVScrollBar or \c Tbl_autoHScrollBar to get automatic scroll
- bars and \c Tbl_clipCellPainting to get safe clipping.
-
- The \link setCellHeight() cell height\endlink and \link setCellWidth()
- cell width\endlink are set to 0.
-
- Frame line shapes (QFrame::HLink and QFrame::VLine) are disallowed;
- see QFrame::setFrameStyle().
-
- Note that the \a f argument is \e not \link setTableFlags() table
- flags \endlink but rather \link QWidget::QWidget() widget
- flags. \endlink
-
-*/
-
-QtTableView::QtTableView( QWidget *parent, const char *name, WFlags f )
- : QFrame( parent, name, f )
-{
- nRows = nCols = 0; // zero rows/cols
- xCellOffs = yCellOffs = 0; // zero offset
- xCellDelta = yCellDelta = 0; // zero cell offset
- xOffs = yOffs = 0; // zero total pixel offset
- cellH = cellW = 0; // user defined cell size
- tFlags = 0;
- vScrollBar = hScrollBar = 0; // no scroll bars
- cornerSquare = 0;
- sbDirty = 0;
- eraseInPaint = FALSE;
- verSliding = FALSE;
- verSnappingOff = FALSE;
- horSliding = FALSE;
- horSnappingOff = FALSE;
- coveringCornerSquare = FALSE;
- inSbUpdate = FALSE;
-}
-
-/*!
- Destroys the table view.
-*/
-
-QtTableView::~QtTableView()
-{
- delete vScrollBar;
- delete hScrollBar;
- delete cornerSquare;
-}
-
-
-/*!
- \internal
- Reimplements QWidget::setBackgroundColor() for binary compatibility.
- \sa setPalette()
-*/
-
-void QtTableView::setBackgroundColor( const QColor &c )
-{
- QWidget::setBackgroundColor( c );
-}
-
-/*!\reimp
-*/
-
-void QtTableView::setPalette( const QPalette &p )
-{
- QWidget::setPalette( p );
-}
-
-/*!\reimp
-*/
-
-void QtTableView::show()
-{
- showOrHideScrollBars();
- QWidget::show();
-}
-
-
-/*!
- \overload void QtTableView::repaint( bool erase )
- Repaints the entire view.
-*/
-
-/*!
- Repaints the table view directly by calling paintEvent() directly
- unless updates are disabled.
-
- Erases the view area \a (x,y,w,h) if \a erase is TRUE. Parameters \a
- (x,y) are in \e widget coordinates.
-
- If \a w is negative, it is replaced with width() - x.
- If \a h is negative, it is replaced with height() - y.
-
- Doing a repaint() usually is faster than doing an update(), but
- calling update() many times in a row will generate a single paint
- event.
-
- At present, QtTableView is the only widget that reimplements \link
- QWidget::repaint() repaint()\endlink. It does this because by
- clearing and then repainting one cell at at time, it can make the
- screen flicker less than it would otherwise. */
-
-void QtTableView::repaint( int x, int y, int w, int h, bool erase )
-{
- if ( !isVisible() || testWState(WState_BlockUpdates) )
- return;
- if ( w < 0 )
- w = width() - x;
- if ( h < 0 )
- h = height() - y;
- QRect r( x, y, w, h );
- if ( r.isEmpty() )
- return; // nothing to do
- QPaintEvent e( r );
- if ( erase && backgroundMode() != NoBackground )
- eraseInPaint = TRUE; // erase when painting
- paintEvent( &e );
- eraseInPaint = FALSE;
-}
-
-/*!
- \overload void QtTableView::repaint( const QRect &r, bool erase )
- Replaints rectangle \a r. If \a erase is TRUE draws the background
- using the palette's background.
-*/
-
-
-/*!
- \fn int QtTableView::numRows() const
- Returns the number of rows in the table.
- \sa numCols(), setNumRows()
-*/
-
-/*!
- Sets the number of rows of the table to \a rows (must be non-negative).
- Does not change topCell().
-
- The table repaints itself automatically if autoUpdate() is set.
-
- \sa numCols(), setNumCols(), numRows()
-*/
-
-void QtTableView::setNumRows( int rows )
-{
- if ( rows < 0 ) {
-#if defined(QT_CHECK_RANGE)
- qWarning( "QtTableView::setNumRows: (%s) Negative argument %d.",
- name( "unnamed" ), rows );
-#endif
- return;
- }
- if ( nRows == rows )
- return;
-
- if ( autoUpdate() && isVisible() ) {
- int oldLastVisible = lastRowVisible();
- int oldTopCell = topCell();
- nRows = rows;
- if ( autoUpdate() && isVisible() &&
- ( oldLastVisible != lastRowVisible() || oldTopCell != topCell() ) )
- repaint( oldTopCell != topCell() );
- } else {
- // Be more careful - if destructing, bad things might happen.
- nRows = rows;
- }
- updateScrollBars( verRange );
- updateFrameSize();
-}
-
-/*!
- \fn int QtTableView::numCols() const
- Returns the number of columns in the table.
- \sa numRows(), setNumCols()
-*/
-
-/*!
- Sets the number of columns of the table to \a cols (must be non-negative).
- Does not change leftCell().
-
- The table repaints itself automatically if autoUpdate() is set.
-
- \sa numCols(), numRows(), setNumRows()
-*/
-
-void QtTableView::setNumCols( int cols )
-{
- if ( cols < 0 ) {
-#if defined(QT_CHECK_RANGE)
- qWarning( "QtTableView::setNumCols: (%s) Negative argument %d.",
- name( "unnamed" ), cols );
-#endif
- return;
- }
- if ( nCols == cols )
- return;
- int oldCols = nCols;
- nCols = cols;
- if ( autoUpdate() && isVisible() ) {
- int maxCol = lastColVisible();
- if ( maxCol >= oldCols || maxCol >= nCols )
- repaint();
- }
- updateScrollBars( horRange );
- updateFrameSize();
-}
-
-
-/*!
- \fn int QtTableView::topCell() const
- Returns the index of the first row in the table that is visible in
- the view. The index of the first row is 0.
- \sa leftCell(), setTopCell()
-*/
-
-/*!
- Scrolls the table so that \a row becomes the top row.
- The index of the very first row is 0.
- \sa setYOffset(), setTopLeftCell(), setLeftCell()
-*/
-
-void QtTableView::setTopCell( int row )
-{
- setTopLeftCell( row, -1 );
- return;
-}
-
-/*!
- \fn int QtTableView::leftCell() const
- Returns the index of the first column in the table that is visible in
- the view. The index of the very leftmost column is 0.
- \sa topCell(), setLeftCell()
-*/
-
-/*!
- Scrolls the table so that \a col becomes the leftmost
- column. The index of the leftmost column is 0.
- \sa setXOffset(), setTopLeftCell(), setTopCell()
-*/
-
-void QtTableView::setLeftCell( int col )
-{
- setTopLeftCell( -1, col );
- return;
-}
-
-/*!
- Scrolls the table so that the cell at row \a row and colum \a
- col becomes the top-left cell in the view. The cell at the extreme
- top left of the table is at position (0,0).
- \sa setLeftCell(), setTopCell(), setOffset()
-*/
-
-void QtTableView::setTopLeftCell( int row, int col )
-{
- int newX = xOffs;
- int newY = yOffs;
-
- if ( col >= 0 ) {
- if ( cellW ) {
- newX = col*cellW;
- if ( newX > maxXOffset() )
- newX = maxXOffset();
- } else {
- newX = 0;
- while ( col )
- newX += cellWidth( --col ); // optimize using current! ###
- }
- }
- if ( row >= 0 ) {
- if ( cellH ) {
- newY = row*cellH;
- if ( newY > maxYOffset() )
- newY = maxYOffset();
- } else {
- newY = 0;
- while ( row )
- newY += cellHeight( --row ); // optimize using current! ###
- }
- }
- setOffset( newX, newY );
-}
-
-
-/*!
- \fn int QtTableView::xOffset() const
-
- Returns the x coordinate in \e table coordinates of the pixel that is
- currently on the left edge of the view.
-
- \sa setXOffset(), yOffset(), leftCell() */
-
-/*!
- Scrolls the table so that \a x becomes the leftmost pixel in the view.
- The \a x parameter is in \e table coordinates.
-
- The interaction with \link setTableFlags() Tbl_snapToHGrid
- \endlink is tricky.
-
- \sa xOffset(), setYOffset(), setOffset(), setLeftCell()
-*/
-
-void QtTableView::setXOffset( int x )
-{
- setOffset( x, yOffset() );
-}
-
-/*!
- \fn int QtTableView::yOffset() const
-
- Returns the y coordinate in \e table coordinates of the pixel that is
- currently on the top edge of the view.
-
- \sa setYOffset(), xOffset(), topCell()
-*/
-
-
-/*!
- Scrolls the table so that \a y becomes the top pixel in the view.
- The \a y parameter is in \e table coordinates.
-
- The interaction with \link setTableFlags() Tbl_snapToVGrid
- \endlink is tricky.
-
- \sa yOffset(), setXOffset(), setOffset(), setTopCell()
-*/
-
-void QtTableView::setYOffset( int y )
-{
- setOffset( xOffset(), y );
-}
-
-/*!
- Scrolls the table so that \a (x,y) becomes the top-left pixel
- in the view. Parameters \a (x,y) are in \e table coordinates.
-
- The interaction with \link setTableFlags() Tbl_snapTo*Grid \endlink
- is tricky. If \a updateScrBars is TRUE, the scroll bars are
- updated.
-
- \sa xOffset(), yOffset(), setXOffset(), setYOffset(), setTopLeftCell()
-*/
-
-void QtTableView::setOffset( int x, int y, bool updateScrBars )
-{
- if ( (!testTableFlags(Tbl_snapToHGrid) || xCellDelta == 0) &&
- (!testTableFlags(Tbl_snapToVGrid) || yCellDelta == 0) &&
- (x == xOffs && y == yOffs) )
- return;
-
- if ( x < 0 )
- x = 0;
- if ( y < 0 )
- y = 0;
-
- if ( cellW ) {
- if ( x > maxXOffset() )
- x = maxXOffset();
- xCellOffs = x / cellW;
- if ( !testTableFlags(Tbl_snapToHGrid) ) {
- xCellDelta = (short)(x % cellW);
- } else {
- x = xCellOffs*cellW;
- xCellDelta = 0;
- }
- } else {
- int xn=0, xcd=0, col = 0;
- while ( col < nCols-1 && x >= xn+(xcd=cellWidth(col)) ) {
- xn += xcd;
- col++;
- }
- xCellOffs = col;
- if ( testTableFlags(Tbl_snapToHGrid) ) {
- xCellDelta = 0;
- x = xn;
- } else {
- xCellDelta = (short)(x-xn);
- }
- }
- if ( cellH ) {
- if ( y > maxYOffset() )
- y = maxYOffset();
- yCellOffs = y / cellH;
- if ( !testTableFlags(Tbl_snapToVGrid) ) {
- yCellDelta = (short)(y % cellH);
- } else {
- y = yCellOffs*cellH;
- yCellDelta = 0;
- }
- } else {
- int yn=0, yrd=0, row=0;
- while ( row < nRows-1 && y >= yn+(yrd=cellHeight(row)) ) {
- yn += yrd;
- row++;
- }
- yCellOffs = row;
- if ( testTableFlags(Tbl_snapToVGrid) ) {
- yCellDelta = 0;
- y = yn;
- } else {
- yCellDelta = (short)(y-yn);
- }
- }
- int dx = (x - xOffs);
- int dy = (y - yOffs);
- xOffs = x;
- yOffs = y;
- if ( autoUpdate() && isVisible() )
- scroll( dx, dy );
- if ( updateScrBars )
- updateScrollBars( verValue | horValue );
-}
-
-
-/*!
- \overload int QtTableView::cellWidth() const
-
- Returns the column width in pixels. Returns 0 if the columns have
- variable widths.
-
- \sa setCellWidth(), cellHeight()
-*/
-
-/*!
- Returns the width of column \a col in pixels.
-
- This function is virtual and must be reimplemented by subclasses that
- have variable cell widths. Note that if the total table width
- changes, updateTableSize() must be called.
-
- \sa setCellWidth(), cellHeight(), totalWidth(), updateTableSize()
-*/
-
-int QtTableView::cellWidth( int )
-{
- return cellW;
-}
-
-
-/*!
- Sets the width in pixels of the table cells to \a cellWidth.
-
- Setting it to 0 means that the column width is variable. When
- set to 0 (this is the default) QtTableView calls the virtual function
- cellWidth() to get the width.
-
- \sa cellWidth(), setCellHeight(), totalWidth(), numCols()
-*/
-
-void QtTableView::setCellWidth( int cellWidth )
-{
- if ( cellW == cellWidth )
- return;
-#if defined(QT_CHECK_RANGE)
- if ( cellWidth < 0 || cellWidth > SHRT_MAX ) {
- qWarning( "QtTableView::setCellWidth: (%s) Argument out of range (%d)",
- name( "unnamed" ), cellWidth );
- return;
- }
-#endif
- cellW = (short)cellWidth;
-
- updateScrollBars( horSteps | horRange );
- if ( autoUpdate() && isVisible() )
- repaint();
-
-}
-
-/*!
- \overload int QtTableView::cellHeight() const
-
- Returns the row height, in pixels. Returns 0 if the rows have
- variable heights.
-
- \sa setCellHeight(), cellWidth()
-*/
-
-
-/*!
- Returns the height of row \a row in pixels.
-
- This function is virtual and must be reimplemented by subclasses that
- have variable cell heights. Note that if the total table height
- changes, updateTableSize() must be called.
-
- \sa setCellHeight(), cellWidth(), totalHeight()
-*/
-
-int QtTableView::cellHeight( int )
-{
- return cellH;
-}
-
-/*!
- Sets the height in pixels of the table cells to \a cellHeight.
-
- Setting it to 0 means that the row height is variable. When set
- to 0 (this is the default), QtTableView calls the virtual function
- cellHeight() to get the height.
-
- \sa cellHeight(), setCellWidth(), totalHeight(), numRows()
-*/
-
-void QtTableView::setCellHeight( int cellHeight )
-{
- if ( cellH == cellHeight )
- return;
-#if defined(QT_CHECK_RANGE)
- if ( cellHeight < 0 || cellHeight > SHRT_MAX ) {
- qWarning( "QtTableView::setCellHeight: (%s) Argument out of range (%d)",
- name( "unnamed" ), cellHeight );
- return;
- }
-#endif
- cellH = (short)cellHeight;
- if ( autoUpdate() && isVisible() )
- repaint();
- updateScrollBars( verSteps | verRange );
-}
-
-
-/*!
- Returns the total width of the table in pixels.
-
- This function is virtual and should be reimplemented by subclasses that
- have variable cell widths and a non-trivial cellWidth() function, or a
- large number of columns in the table.
-
- The default implementation may be slow for very wide tables.
-
- \sa cellWidth(), totalHeight() */
-
-int QtTableView::totalWidth()
-{
- if ( cellW ) {
- return cellW*nCols;
- } else {
- int tw = 0;
- for( int i = 0 ; i < nCols ; i++ )
- tw += cellWidth( i );
- return tw;
- }
-}
-
-/*!
- Returns the total height of the table in pixels.
-
- This function is virtual and should be reimplemented by subclasses that
- have variable cell heights and a non-trivial cellHeight() function, or a
- large number of rows in the table.
-
- The default implementation may be slow for very tall tables.
-
- \sa cellHeight(), totalWidth()
-*/
-
-int QtTableView::totalHeight()
-{
- if ( cellH ) {
- return cellH*nRows;
- } else {
- int th = 0;
- for( int i = 0 ; i < nRows ; i++ )
- th += cellHeight( i );
- return th;
- }
-}
-
-
-/*!
- \fn uint QtTableView::tableFlags() const
-
- Returns the union of the table flags that are currently set.
-
- \sa setTableFlags(), clearTableFlags(), testTableFlags()
-*/
-
-/*!
- \fn bool QtTableView::testTableFlags( uint f ) const
-
- Returns TRUE if any of the table flags in \a f are currently set,
- otherwise FALSE.
-
- \sa setTableFlags(), clearTableFlags(), tableFlags()
-*/
-
-/*!
- Sets the table flags to \a f.
-
- If a flag setting changes the appearance of the table, the table is
- repainted if - and only if - autoUpdate() is TRUE.
-
- The table flags are mostly single bits, though there are some multibit
- flags for convenience. Here is a complete list:
-
-
- - Tbl_vScrollBar
- - The table has a vertical scroll bar.
-
- Tbl_hScrollBar
- - The table has a horizontal scroll bar.
-
- Tbl_autoVScrollBar
- - The table has a vertical scroll bar if
- - and only if - the table is taller than the view.
-
- Tbl_autoHScrollBar
- The table has a horizontal scroll bar if
- - and only if - the table is wider than the view.
-
- Tbl_autoScrollBars
- - The union of the previous two flags.
-
- Tbl_clipCellPainting
- - The table uses QPainter::setClipRect() to
- make sure that paintCell() will not draw outside the cell
- boundaries.
-
- Tbl_cutCellsV
- - The table will never show part of a
- cell at the bottom of the table; if there is not space for all of
- a cell, the space is left blank.
-
- Tbl_cutCellsH
- - The table will never show part of a
- cell at the right side of the table; if there is not space for all of
- a cell, the space is left blank.
-
- Tbl_cutCells
- - The union of the previous two flags.
-
- Tbl_scrollLastHCell
- - When the user scrolls horizontally,
- let him/her scroll the last cell left until it is at the left
- edge of the view. If this flag is not set, the user can only scroll
- to the point where the last cell is completely visible.
-
- Tbl_scrollLastVCell
- - When the user scrolls vertically, let
- him/her scroll the last cell up until it is at the top edge of
- the view. If this flag is not set, the user can only scroll to the
- point where the last cell is completely visible.
-
- Tbl_scrollLastCell
- - The union of the previous two flags.
-
- Tbl_smoothHScrolling
- - The table scrolls as smoothly as
- possible when the user scrolls horizontally. When this flag is not
- set, scrolling is done one cell at a time.
-
- Tbl_smoothVScrolling
- - The table scrolls as smoothly as
- possible when scrolling vertically. When this flag is not set,
- scrolling is done one cell at a time.
-
- Tbl_smoothScrolling
- - The union of the previous two flags.
-
- Tbl_snapToHGrid
- - Except when the user is actually scrolling,
- the leftmost column shown snaps to the leftmost edge of the view.
-
- Tbl_snapToVGrid
- - Except when the user is actually
- scrolling, the top row snaps to the top edge of the view.
-
- Tbl_snapToGrid
- - The union of the previous two flags.
-
-
- You can specify more than one flag at a time using bitwise OR.
-
- Example:
- \code
- setTableFlags( Tbl_smoothScrolling | Tbl_autoScrollBars );
- \endcode
-
- \warning The cutCells options (\c Tbl_cutCells, \c Tbl_cutCellsH and
- Tbl_cutCellsV) may cause painting problems when scrollbars are
- enabled. Do not combine cutCells and scrollbars.
-
-
- \sa clearTableFlags(), testTableFlags(), tableFlags()
-*/
-
-void QtTableView::setTableFlags( uint f )
-{
- f = (f ^ tFlags) & f; // clear flags already set
- tFlags |= f;
-
- bool updateOn = autoUpdate();
- setAutoUpdate( FALSE );
-
- uint repaintMask = Tbl_cutCellsV | Tbl_cutCellsH;
-
- if ( f & Tbl_vScrollBar ) {
- setVerScrollBar( TRUE );
- }
- if ( f & Tbl_hScrollBar ) {
- setHorScrollBar( TRUE );
- }
- if ( f & Tbl_autoVScrollBar ) {
- updateScrollBars( verRange );
- }
- if ( f & Tbl_autoHScrollBar ) {
- updateScrollBars( horRange );
- }
- if ( f & Tbl_scrollLastHCell ) {
- updateScrollBars( horRange );
- }
- if ( f & Tbl_scrollLastVCell ) {
- updateScrollBars( verRange );
- }
- if ( f & Tbl_snapToHGrid ) {
- updateScrollBars( horRange );
- }
- if ( f & Tbl_snapToVGrid ) {
- updateScrollBars( verRange );
- }
- if ( f & Tbl_snapToGrid ) { // Note: checks for 2 flags
- if ( (f & Tbl_snapToHGrid) != 0 && xCellDelta != 0 || //have to scroll?
- (f & Tbl_snapToVGrid) != 0 && yCellDelta != 0 ) {
- snapToGrid( (f & Tbl_snapToHGrid) != 0, // do snapping
- (f & Tbl_snapToVGrid) != 0 );
- repaintMask |= Tbl_snapToGrid; // repaint table
- }
- }
-
- if ( updateOn ) {
- setAutoUpdate( TRUE );
- updateScrollBars();
- if ( isVisible() && (f & repaintMask) )
- repaint();
- }
-
-}
-
-/*!
- Clears the \link setTableFlags() table flags\endlink that are set
- in \a f.
-
- Example (clears a single flag):
- \code
- clearTableFlags( Tbl_snapToGrid );
- \endcode
-
- The default argument clears all flags.
-
- \sa setTableFlags(), testTableFlags(), tableFlags()
-*/
-
-void QtTableView::clearTableFlags( uint f )
-{
- f = (f ^ ~tFlags) & f; // clear flags that are already 0
- tFlags &= ~f;
-
- bool updateOn = autoUpdate();
- setAutoUpdate( FALSE );
-
- uint repaintMask = Tbl_cutCellsV | Tbl_cutCellsH;
-
- if ( f & Tbl_vScrollBar ) {
- setVerScrollBar( FALSE );
- }
- if ( f & Tbl_hScrollBar ) {
- setHorScrollBar( FALSE );
- }
- if ( f & Tbl_scrollLastHCell ) {
- int maxX = maxXOffset();
- if ( xOffs > maxX ) {
- setOffset( maxX, yOffs );
- repaintMask |= Tbl_scrollLastHCell;
- }
- updateScrollBars( horRange );
- }
- if ( f & Tbl_scrollLastVCell ) {
- int maxY = maxYOffset();
- if ( yOffs > maxY ) {
- setOffset( xOffs, maxY );
- repaintMask |= Tbl_scrollLastVCell;
- }
- updateScrollBars( verRange );
- }
- if ( f & Tbl_smoothScrolling ) { // Note: checks for 2 flags
- if ((f & Tbl_smoothHScrolling) != 0 && xCellDelta != 0 ||//must scroll?
- (f & Tbl_smoothVScrolling) != 0 && yCellDelta != 0 ) {
- snapToGrid( (f & Tbl_smoothHScrolling) != 0, // do snapping
- (f & Tbl_smoothVScrolling) != 0 );
- repaintMask |= Tbl_smoothScrolling; // repaint table
- }
- }
- if ( f & Tbl_snapToHGrid ) {
- updateScrollBars( horRange );
- }
- if ( f & Tbl_snapToVGrid ) {
- updateScrollBars( verRange );
- }
- if ( updateOn ) {
- setAutoUpdate( TRUE );
- updateScrollBars(); // returns immediately if nothing to do
- if ( isVisible() && (f & repaintMask) )
- repaint();
- }
-
-}
-
-
-/*!
- \fn bool QtTableView::autoUpdate() const
-
- Returns TRUE if the view updates itself automatically whenever it
- is changed in some way.
-
- \sa setAutoUpdate()
-*/
-
-/*!
- Sets the auto-update option of the table view to \a enable.
-
- If \a enable is TRUE (this is the default), the view updates itself
- automatically whenever it has changed in some way (for example, when a
- \link setTableFlags() flag\endlink is changed).
-
- If \a enable is FALSE, the view does NOT repaint itself or update
- its internal state variables when it is changed. This can be
- useful to avoid flicker during large changes and is singularly
- useless otherwise. Disable auto-update, do the changes, re-enable
- auto-update and call repaint().
-
- \warning Do not leave the view in this state for a long time
- (i.e., between events). If, for example, the user interacts with the
- view when auto-update is off, strange things can happen.
-
- Setting auto-update to TRUE does not repaint the view; you must call
- repaint() to do this.
-
- \sa autoUpdate(), repaint()
-*/
-
-void QtTableView::setAutoUpdate( bool enable )
-{
- if ( isUpdatesEnabled() == enable )
- return;
- setUpdatesEnabled( enable );
- if ( enable ) {
- showOrHideScrollBars();
- updateScrollBars();
- }
-}
-
-
-/*!
- Repaints the cell at row \a row, column \a col if it is inside the view.
-
- If \a erase is TRUE, the relevant part of the view is cleared to the
- background color/pixmap before the contents are repainted.
-
- \sa isVisible()
-*/
-
-void QtTableView::updateCell( int row, int col, bool erase )
-{
- int xPos, yPos;
- if ( !colXPos( col, &xPos ) )
- return;
- if ( !rowYPos( row, &yPos ) )
- return;
- QRect uR = QRect( xPos, yPos,
- cellW ? cellW : cellWidth(col),
- cellH ? cellH : cellHeight(row) );
- repaint( uR.intersect(viewRect()), erase );
-}
-
-
-/*!
- \fn QRect QtTableView::cellUpdateRect() const
-
- This function should be called only from the paintCell() function in
- subclasses. It returns the portion of a cell that actually needs to be
- updated in \e cell coordinates. This is useful only for non-trivial
- paintCell().
-
-*/
-
-/*!
- Returns the rectangle that is the actual table, excluding any
- frame, in \e widget coordinates.
-*/
-
-QRect QtTableView::viewRect() const
-{
- return QRect( frameWidth(), frameWidth(), viewWidth(), viewHeight() );
-}
-
-
-/*!
- Returns the index of the last (bottom) row in the view.
- The index of the first row is 0.
-
- If no rows are visible it returns -1. This can happen if the
- view is too small for the first row and Tbl_cutCellsV is set.
-
- \sa lastColVisible()
-*/
-
-int QtTableView::lastRowVisible() const
-{
- int cellMaxY;
- int row = findRawRow( maxViewY(), &cellMaxY );
- if ( row == -1 || row >= nRows ) { // maxViewY() past end?
- row = nRows - 1; // yes: return last row
- } else {
- if ( testTableFlags(Tbl_cutCellsV) && cellMaxY > maxViewY() ) {
- if ( row == yCellOffs ) // cut by right margin?
- return -1; // yes, nothing in the view
- else
- row = row - 1; // cut by margin, one back
- }
- }
- return row;
-}
-
-/*!
- Returns the index of the last (right) column in the view.
- The index of the first column is 0.
-
- If no columns are visible it returns -1. This can happen if the
- view is too narrow for the first column and Tbl_cutCellsH is set.
-
- \sa lastRowVisible()
-*/
-
-int QtTableView::lastColVisible() const
-{
- int cellMaxX;
- int col = findRawCol( maxViewX(), &cellMaxX );
- if ( col == -1 || col >= nCols ) { // maxViewX() past end?
- col = nCols - 1; // yes: return last col
- } else {
- if ( testTableFlags(Tbl_cutCellsH) && cellMaxX > maxViewX() ) {
- if ( col == xCellOffs ) // cut by bottom margin?
- return -1; // yes, nothing in the view
- else
- col = col - 1; // cell by margin, one back
- }
- }
- return col;
-}
-
-/*!
- Returns TRUE if \a row is at least partially visible.
- \sa colIsVisible()
-*/
-
-bool QtTableView::rowIsVisible( int row ) const
-{
- return rowYPos( row, 0 );
-}
-
-/*!
- Returns TRUE if \a col is at least partially visible.
- \sa rowIsVisible()
-*/
-
-bool QtTableView::colIsVisible( int col ) const
-{
- return colXPos( col, 0 );
-}
-
-
-/*!
- \internal
- Called when both scroll bars are active at the same time. Covers the
- bottom left corner between the two scroll bars with an empty widget.
-*/
-
-void QtTableView::coverCornerSquare( bool enable )
-{
- coveringCornerSquare = enable;
- if ( !cornerSquare && enable ) {
- cornerSquare = new QCornerSquare( this );
- Q_CHECK_PTR( cornerSquare );
- cornerSquare->setGeometry( maxViewX() + frameWidth() + 1,
- maxViewY() + frameWidth() + 1,
- VSBEXT,
- HSBEXT);
- }
- if ( autoUpdate() && cornerSquare ) {
- if ( enable )
- cornerSquare->show();
- else
- cornerSquare->hide();
- }
-}
-
-
-/*!
- \internal
- Scroll the view to a position such that:
-
- If \a horizontal is TRUE, the leftmost column shown fits snugly
- with the left edge of the view.
-
- If \a vertical is TRUE, the top row shown fits snugly with the top
- of the view.
-
- You can achieve the same effect automatically by setting any of the
- \link setTableFlags() Tbl_snapTo*Grid \endlink table flags.
-*/
-
-void QtTableView::snapToGrid( bool horizontal, bool vertical )
-{
- int newXCell = -1;
- int newYCell = -1;
- if ( horizontal && xCellDelta != 0 ) {
- int w = cellW ? cellW : cellWidth( xCellOffs );
- if ( xCellDelta >= w/2 )
- newXCell = xCellOffs + 1;
- else
- newXCell = xCellOffs;
- }
- if ( vertical && yCellDelta != 0 ) {
- int h = cellH ? cellH : cellHeight( yCellOffs );
- if ( yCellDelta >= h/2 )
- newYCell = yCellOffs + 1;
- else
- newYCell = yCellOffs;
- }
- setTopLeftCell( newYCell, newXCell ); //row,column
-}
-
-/*!
- \internal
- This internal slot is connected to the horizontal scroll bar's
- QScrollBar::valueChanged() signal.
-
- Moves the table horizontally to offset \a val without updating the
- scroll bar.
-*/
-
-void QtTableView::horSbValue( int val )
-{
- if ( horSliding ) {
- horSliding = FALSE;
- if ( horSnappingOff ) {
- horSnappingOff = FALSE;
- tFlags |= Tbl_snapToHGrid;
- }
- }
- setOffset( val, yOffs, FALSE );
-}
-
-/*!
- \internal
- This internal slot is connected to the horizontal scroll bar's
- QScrollBar::sliderMoved() signal.
-
- Scrolls the table smoothly horizontally even if \c Tbl_snapToHGrid is set.
-*/
-
-void QtTableView::horSbSliding( int val )
-{
- if ( testTableFlags(Tbl_snapToHGrid) &&
- testTableFlags(Tbl_smoothHScrolling) ) {
- tFlags &= ~Tbl_snapToHGrid; // turn off snapping while sliding
- setOffset( val, yOffs, FALSE );
- tFlags |= Tbl_snapToHGrid; // turn on snapping again
- } else {
- setOffset( val, yOffs, FALSE );
- }
-}
-
-/*!
- \internal
- This internal slot is connected to the horizontal scroll bar's
- QScrollBar::sliderReleased() signal.
-*/
-
-void QtTableView::horSbSlidingDone( )
-{
- if ( testTableFlags(Tbl_snapToHGrid) &&
- testTableFlags(Tbl_smoothHScrolling) )
- snapToGrid( TRUE, FALSE );
-}
-
-/*!
- \internal
- This internal slot is connected to the vertical scroll bar's
- QScrollBar::valueChanged() signal.
-
- Moves the table vertically to offset \a val without updating the
- scroll bar.
-*/
-
-void QtTableView::verSbValue( int val )
-{
- if ( verSliding ) {
- verSliding = FALSE;
- if ( verSnappingOff ) {
- verSnappingOff = FALSE;
- tFlags |= Tbl_snapToVGrid;
- }
- }
- setOffset( xOffs, val, FALSE );
-}
-
-/*!
- \internal
- This internal slot is connected to the vertical scroll bar's
- QScrollBar::sliderMoved() signal.
-
- Scrolls the table smoothly vertically even if \c Tbl_snapToVGrid is set.
-*/
-
-void QtTableView::verSbSliding( int val )
-{
- if ( testTableFlags(Tbl_snapToVGrid) &&
- testTableFlags(Tbl_smoothVScrolling) ) {
- tFlags &= ~Tbl_snapToVGrid; // turn off snapping while sliding
- setOffset( xOffs, val, FALSE );
- tFlags |= Tbl_snapToVGrid; // turn on snapping again
- } else {
- setOffset( xOffs, val, FALSE );
- }
-}
-
-/*!
- \internal
- This internal slot is connected to the vertical scroll bar's
- QScrollBar::sliderReleased() signal.
-*/
-
-void QtTableView::verSbSlidingDone( )
-{
- if ( testTableFlags(Tbl_snapToVGrid) &&
- testTableFlags(Tbl_smoothVScrolling) )
- snapToGrid( FALSE, TRUE );
-}
-
-
-/*!
- This virtual function is called before painting of table cells
- is started. It can be reimplemented by subclasses that want to
- to set up the painter in a special way and that do not want to
- do so for each cell.
-*/
-
-void QtTableView::setupPainter( QPainter * )
-{
-}
-
-/*!
- \fn void QtTableView::paintCell( QPainter *p, int row, int col )
-
- This pure virtual function is called to paint the single cell at \a
- (row,col) using \a p, which is open when paintCell() is called and
- must remain open.
-
- The coordinate system is \link QPainter::translate() translated \endlink
- so that the origin is at the top-left corner of the cell to be
- painted, i.e. \e cell coordinates. Do not scale or shear the coordinate
- system (or if you do, restore the transformation matrix before you
- return).
-
- The painter is not clipped by default and for maximum efficiency. For safety,
- call setTableFlags(Tbl_clipCellPainting) to enable clipping.
-
- \sa paintEvent(), setTableFlags() */
-
-
-/*!
- Handles paint events, \a e, for the table view.
-
- Calls paintCell() for the cells that needs to be repainted.
-*/
-
-void QtTableView::paintEvent( QPaintEvent *e )
-{
- QRect updateR = e->rect(); // update rectangle
- if ( sbDirty ) {
- bool e = eraseInPaint;
- updateScrollBars();
- eraseInPaint = e;
- }
-
- QPainter paint( this );
-
- if ( !contentsRect().contains( updateR, TRUE ) ) {// update frame ?
- drawFrame( &paint );
- if ( updateR.left() < frameWidth() ) //###
- updateR.setLeft( frameWidth() );
- if ( updateR.top() < frameWidth() )
- updateR.setTop( frameWidth() );
- }
-
- int maxWX = maxViewX();
- int maxWY = maxViewY();
- if ( updateR.right() > maxWX )
- updateR.setRight( maxWX );
- if ( updateR.bottom() > maxWY )
- updateR.setBottom( maxWY );
-
- setupPainter( &paint ); // prepare for painting table
-
- int firstRow = findRow( updateR.y() );
- int firstCol = findCol( updateR.x() );
- int xStart, yStart;
- if ( !colXPos( firstCol, &xStart ) || !rowYPos( firstRow, &yStart ) ) {
- paint.eraseRect( updateR ); // erase area outside cells but in view
- return;
- }
- int maxX = updateR.right();
- int maxY = updateR.bottom();
- int row = firstRow;
- int col;
- int yPos = yStart;
- int xPos = maxX+1; // in case the while() is empty
- int nextX;
- int nextY;
- QRect winR = viewRect();
- QRect cellR;
- QRect cellUR;
-#ifndef QT_NO_TRANSFORMATIONS
- QWMatrix matrix;
-#endif
-
- while ( yPos <= maxY && row < nRows ) {
- nextY = yPos + (cellH ? cellH : cellHeight( row ));
- if ( testTableFlags( Tbl_cutCellsV ) && nextY > ( maxWY + 1 ) )
- break;
- col = firstCol;
- xPos = xStart;
- while ( xPos <= maxX && col < nCols ) {
- nextX = xPos + (cellW ? cellW : cellWidth( col ));
- if ( testTableFlags( Tbl_cutCellsH ) && nextX > ( maxWX + 1 ) )
- break;
-
- cellR.setRect( xPos, yPos, cellW ? cellW : cellWidth(col),
- cellH ? cellH : cellHeight(row) );
- cellUR = cellR.intersect( updateR );
- if ( cellUR.isValid() ) {
- cellUpdateR = cellUR;
- cellUpdateR.moveBy( -xPos, -yPos ); // cell coordinates
- if ( eraseInPaint )
- paint.eraseRect( cellUR );
-
-#ifndef QT_NO_TRANSFORMATIONS
- matrix.translate( xPos, yPos );
- paint.setWorldMatrix( matrix );
- if ( testTableFlags(Tbl_clipCellPainting) ||
- frameWidth() > 0 && !winR.contains( cellR ) ) { //##arnt
- paint.setClipRect( cellUR );
- paintCell( &paint, row, col );
- paint.setClipping( FALSE );
- } else {
- paintCell( &paint, row, col );
- }
- matrix.reset();
- paint.setWorldMatrix( matrix );
-#else
- paint.translate( xPos, yPos );
- if ( testTableFlags(Tbl_clipCellPainting) ||
- frameWidth() > 0 && !winR.contains( cellR ) ) { //##arnt
- paint.setClipRect( cellUR );
- paintCell( &paint, row, col );
- paint.setClipping( FALSE );
- } else {
- paintCell( &paint, row, col );
- }
- paint.translate( -xPos, -yPos );
-#endif
- }
- col++;
- xPos = nextX;
- }
- row++;
- yPos = nextY;
- }
-
- // while painting we have to erase any areas in the view that
- // are not covered by cells but are covered by the paint event
- // rectangle these must be erased. We know that xPos is the last
- // x pixel updated + 1 and that yPos is the last y pixel updated + 1.
-
- // Note that this needs to be done regardless whether we do
- // eraseInPaint or not. Reason: a subclass may implement
- // flicker-freeness and encourage the use of repaint(FALSE).
- // The subclass, however, cannot draw all pixels, just those
- // inside the cells. So QtTableView is reponsible for all pixels
- // outside the cells.
-
- QRect viewR = viewRect();
- const QColorGroup g = colorGroup();
-
- if ( xPos <= maxX ) {
- QRect r = viewR;
- r.setLeft( xPos );
- r.setBottom( yPossetCursor( arrowCursor );
-#endif
- sb->resize( sb->sizeHint() ); // height is irrelevant
- Q_CHECK_PTR(sb);
- sb->setTracking( FALSE );
- sb->setFocusPolicy( NoFocus );
- connect( sb, SIGNAL(valueChanged(int)),
- SLOT(verSbValue(int)));
- connect( sb, SIGNAL(sliderMoved(int)),
- SLOT(verSbSliding(int)));
- connect( sb, SIGNAL(sliderReleased()),
- SLOT(verSbSlidingDone()));
- sb->hide();
- that->vScrollBar = sb;
- return sb;
- }
- return vScrollBar;
-}
-
-/*!
- Returns a pointer to the horizontal scroll bar mainly so you can
- connect() to its signals. Note that the scroll bar works in pixel
- values; use findCol() to translate to cell numbers.
-*/
-
-QScrollBar *QtTableView::horizontalScrollBar() const
-{
- QtTableView *that = (QtTableView*)this; // semantic const
- if ( !hScrollBar ) {
- QScrollBar *sb = new QScrollBar( QScrollBar::Horizontal, that );
-#ifndef QT_NO_CURSOR
- sb->setCursor( arrowCursor );
-#endif
- sb->resize( sb->sizeHint() ); // width is irrelevant
- sb->setFocusPolicy( NoFocus );
- Q_CHECK_PTR(sb);
- sb->setTracking( FALSE );
- connect( sb, SIGNAL(valueChanged(int)),
- SLOT(horSbValue(int)));
- connect( sb, SIGNAL(sliderMoved(int)),
- SLOT(horSbSliding(int)));
- connect( sb, SIGNAL(sliderReleased()),
- SLOT(horSbSlidingDone()));
- sb->hide();
- that->hScrollBar = sb;
- return sb;
- }
- return hScrollBar;
-}
-
-/*!
- Enables or disables the horizontal scroll bar, as required by
- setAutoUpdate() and the \link setTableFlags() table flags\endlink.
-*/
-
-void QtTableView::setHorScrollBar( bool on, bool update )
-{
- if ( on ) {
- tFlags |= Tbl_hScrollBar;
- horizontalScrollBar(); // created
- if ( update )
- updateScrollBars( horMask | verMask );
- else
- sbDirty = sbDirty | (horMask | verMask);
- if ( testTableFlags( Tbl_vScrollBar ) )
- coverCornerSquare( TRUE );
- if ( autoUpdate() )
- sbDirty = sbDirty | horMask;
- } else {
- tFlags &= ~Tbl_hScrollBar;
- if ( !hScrollBar )
- return;
- coverCornerSquare( FALSE );
- bool hideScrollBar = autoUpdate() && hScrollBar->isVisible();
- if ( hideScrollBar )
- hScrollBar->hide();
- if ( update )
- updateScrollBars( verMask );
- else
- sbDirty = sbDirty | verMask;
- if ( hideScrollBar && isVisible() )
- repaint( hScrollBar->x(), hScrollBar->y(),
- width() - hScrollBar->x(), hScrollBar->height() );
- }
- if ( update )
- updateFrameSize();
-}
-
-
-/*!
- Enables or disables the vertical scroll bar, as required by
- setAutoUpdate() and the \link setTableFlags() table flags\endlink.
-*/
-
-void QtTableView::setVerScrollBar( bool on, bool update )
-{
- if ( on ) {
- tFlags |= Tbl_vScrollBar;
- verticalScrollBar(); // created
- if ( update )
- updateScrollBars( verMask | horMask );
- else
- sbDirty = sbDirty | (horMask | verMask);
- if ( testTableFlags( Tbl_hScrollBar ) )
- coverCornerSquare( TRUE );
- if ( autoUpdate() )
- sbDirty = sbDirty | verMask;
- } else {
- tFlags &= ~Tbl_vScrollBar;
- if ( !vScrollBar )
- return;
- coverCornerSquare( FALSE );
- bool hideScrollBar = autoUpdate() && vScrollBar->isVisible();
- if ( hideScrollBar )
- vScrollBar->hide();
- if ( update )
- updateScrollBars( horMask );
- else
- sbDirty = sbDirty | horMask;
- if ( hideScrollBar && isVisible() )
- repaint( vScrollBar->x(), vScrollBar->y(),
- vScrollBar->width(), height() - vScrollBar->y() );
- }
- if ( update )
- updateFrameSize();
-}
-
-
-
-
-int QtTableView::findRawRow( int yPos, int *cellMaxY, int *cellMinY,
- bool goOutsideView ) const
-{
- int r = -1;
- if ( nRows == 0 )
- return r;
- if ( goOutsideView || yPos >= minViewY() && yPos <= maxViewY() ) {
- if ( yPos < minViewY() ) {
-#if defined(QT_CHECK_RANGE)
- qWarning( "QtTableView::findRawRow: (%s) internal error: "
- "yPos < minViewY() && goOutsideView "
- "not supported. (%d,%d)",
- name( "unnamed" ), yPos, yOffs );
-#endif
- return -1;
- }
- if ( cellH ) { // uniform cell height
- r = (yPos - minViewY() + yCellDelta)/cellH; // cell offs from top
- if ( cellMaxY )
- *cellMaxY = (r + 1)*cellH + minViewY() - yCellDelta - 1;
- if ( cellMinY )
- *cellMinY = r*cellH + minViewY() - yCellDelta;
- r += yCellOffs; // absolute cell index
- } else { // variable cell height
- QtTableView *tw = (QtTableView *)this;
- r = yCellOffs;
- int h = minViewY() - yCellDelta; //##arnt3
- int oldH = h;
- Q_ASSERT( r < nRows );
- while ( r < nRows ) {
- oldH = h;
- h += tw->cellHeight( r ); // Start of next cell
- if ( yPos < h )
- break;
- r++;
- }
- if ( cellMaxY )
- *cellMaxY = h - 1;
- if ( cellMinY )
- *cellMinY = oldH;
- }
- }
- return r;
-
-}
-
-
-int QtTableView::findRawCol( int xPos, int *cellMaxX, int *cellMinX ,
- bool goOutsideView ) const
-{
- int c = -1;
- if ( nCols == 0 )
- return c;
- if ( goOutsideView || xPos >= minViewX() && xPos <= maxViewX() ) {
- if ( xPos < minViewX() ) {
-#if defined(QT_CHECK_RANGE)
- qWarning( "QtTableView::findRawCol: (%s) internal error: "
- "xPos < minViewX() && goOutsideView "
- "not supported. (%d,%d)",
- name( "unnamed" ), xPos, xOffs );
-#endif
- return -1;
- }
- if ( cellW ) { // uniform cell width
- c = (xPos - minViewX() + xCellDelta)/cellW; //cell offs from left
- if ( cellMaxX )
- *cellMaxX = (c + 1)*cellW + minViewX() - xCellDelta - 1;
- if ( cellMinX )
- *cellMinX = c*cellW + minViewX() - xCellDelta;
- c += xCellOffs; // absolute cell index
- } else { // variable cell width
- QtTableView *tw = (QtTableView *)this;
- c = xCellOffs;
- int w = minViewX() - xCellDelta; //##arnt3
- int oldW = w;
- Q_ASSERT( c < nCols );
- while ( c < nCols ) {
- oldW = w;
- w += tw->cellWidth( c ); // Start of next cell
- if ( xPos < w )
- break;
- c++;
- }
- if ( cellMaxX )
- *cellMaxX = w - 1;
- if ( cellMinX )
- *cellMinX = oldW;
- }
- }
- return c;
-}
-
-
-/*!
- Returns the index of the row at position \a yPos, where \a yPos is in
- \e widget coordinates. Returns -1 if \a yPos is outside the valid
- range.
-
- \sa findCol(), rowYPos()
-*/
-
-int QtTableView::findRow( int yPos ) const
-{
- int cellMaxY;
- int row = findRawRow( yPos, &cellMaxY );
- if ( testTableFlags(Tbl_cutCellsV) && cellMaxY > maxViewY() )
- row = - 1; // cell cut by bottom margin
- if ( row >= nRows )
- row = -1;
- return row;
-}
-
-
-/*!
- Returns the index of the column at position \a xPos, where \a xPos is
- in \e widget coordinates. Returns -1 if \a xPos is outside the valid
- range.
-
- \sa findRow(), colXPos()
-*/
-
-int QtTableView::findCol( int xPos ) const
-{
- int cellMaxX;
- int col = findRawCol( xPos, &cellMaxX );
- if ( testTableFlags(Tbl_cutCellsH) && cellMaxX > maxViewX() )
- col = - 1; // cell cut by right margin
- if ( col >= nCols )
- col = -1;
- return col;
-}
-
-
-/*!
- Computes the position in the widget of row \a row.
-
- Returns TRUE and stores the result in \a *yPos (in \e widget
- coordinates) if the row is visible. Returns FALSE and does not modify
- \a *yPos if \a row is invisible or invalid.
-
- \sa colXPos(), findRow()
-*/
-
-bool QtTableView::rowYPos( int row, int *yPos ) const
-{
- int y;
- if ( row >= yCellOffs ) {
- if ( cellH ) {
- int lastVisible = lastRowVisible();
- if ( row > lastVisible || lastVisible == -1 )
- return FALSE;
- y = (row - yCellOffs)*cellH + minViewY() - yCellDelta;
- } else {
- //##arnt3
- y = minViewY() - yCellDelta; // y of leftmost cell in view
- int r = yCellOffs;
- QtTableView *tw = (QtTableView *)this;
- int maxY = maxViewY();
- while ( r < row && y <= maxY )
- y += tw->cellHeight( r++ );
- if ( y > maxY )
- return FALSE;
-
- }
- } else {
- return FALSE;
- }
- if ( yPos )
- *yPos = y;
- return TRUE;
-}
-
-
-/*!
- Computes the position in the widget of column \a col.
-
- Returns TRUE and stores the result in \a *xPos (in \e widget
- coordinates) if the column is visible. Returns FALSE and does not
- modify \a *xPos if \a col is invisible or invalid.
-
- \sa rowYPos(), findCol()
-*/
-
-bool QtTableView::colXPos( int col, int *xPos ) const
-{
- int x;
- if ( col >= xCellOffs ) {
- if ( cellW ) {
- int lastVisible = lastColVisible();
- if ( col > lastVisible || lastVisible == -1 )
- return FALSE;
- x = (col - xCellOffs)*cellW + minViewX() - xCellDelta;
- } else {
- //##arnt3
- x = minViewX() - xCellDelta; // x of uppermost cell in view
- int c = xCellOffs;
- QtTableView *tw = (QtTableView *)this;
- int maxX = maxViewX();
- while ( c < col && x <= maxX )
- x += tw->cellWidth( c++ );
- if ( x > maxX )
- return FALSE;
- }
- } else {
- return FALSE;
- }
- if ( xPos )
- *xPos = x;
- return TRUE;
-}
-
-
-/*!
- Moves the visible area of the table right by \a xPixels and
- down by \a yPixels pixels. Both may be negative.
-
- \warning You might find that QScrollView offers a higher-level of
- functionality than using QtTableView and this function.
-
- This function is \e not the same as QWidget::scroll(); in particular,
- the signs of \a xPixels and \a yPixels have the reverse semantics.
-
- \sa setXOffset(), setYOffset(), setOffset(), setTopCell(),
- setLeftCell()
-*/
-
-void QtTableView::scroll( int xPixels, int yPixels )
-{
- QWidget::scroll( -xPixels, -yPixels, contentsRect() );
-}
-
-
-/*!
- Returns the leftmost pixel of the table view in \e view
- coordinates. This excludes the frame and any header.
-
- \sa maxViewY(), viewWidth(), contentsRect()
-*/
-
-int QtTableView::minViewX() const
-{
- return frameWidth();
-}
-
-
-/*!
- Returns the top pixel of the table view in \e view
- coordinates. This excludes the frame and any header.
-
- \sa maxViewX(), viewHeight(), contentsRect()
-*/
-
-int QtTableView::minViewY() const
-{
- return frameWidth();
-}
-
-
-/*!
- Returns the rightmost pixel of the table view in \e view
- coordinates. This excludes the frame and any scroll bar, but
- includes blank pixels to the right of the visible table data.
-
- \sa maxViewY(), viewWidth(), contentsRect()
-*/
-
-int QtTableView::maxViewX() const
-{
- return width() - 1 - frameWidth()
- - (tFlags & Tbl_vScrollBar ? VSBEXT
- : 0);
-}
-
-
-/*!
- Returns the bottom pixel of the table view in \e view
- coordinates. This excludes the frame and any scroll bar, but
- includes blank pixels below the visible table data.
-
- \sa maxViewX(), viewHeight(), contentsRect()
-*/
-
-int QtTableView::maxViewY() const
-{
- return height() - 1 - frameWidth()
- - (tFlags & Tbl_hScrollBar ? HSBEXT
- : 0);
-}
-
-
-/*!
- Returns the width of the table view, as such, in \e view
- coordinates. This does not include any header, scroll bar or frame,
- but it does include background pixels to the right of the table data.
-
- \sa minViewX() maxViewX(), viewHeight(), contentsRect() viewRect()
-*/
-
-int QtTableView::viewWidth() const
-{
- return maxViewX() - minViewX() + 1;
-}
-
-
-/*!
- Returns the height of the table view, as such, in \e view
- coordinates. This does not include any header, scroll bar or frame,
- but it does include background pixels below the table data.
-
- \sa minViewY() maxViewY() viewWidth() contentsRect() viewRect()
-*/
-
-int QtTableView::viewHeight() const
-{
- return maxViewY() - minViewY() + 1;
-}
-
-
-void QtTableView::doAutoScrollBars()
-{
- int viewW = width() - frameWidth() - minViewX();
- int viewH = height() - frameWidth() - minViewY();
- bool vScrollOn = testTableFlags(Tbl_vScrollBar);
- bool hScrollOn = testTableFlags(Tbl_hScrollBar);
- int w = 0;
- int h = 0;
- int i;
-
- if ( testTableFlags(Tbl_autoHScrollBar) ) {
- if ( cellW ) {
- w = cellW*nCols;
- } else {
- i = 0;
- while ( i < nCols && w <= viewW )
- w += cellWidth( i++ );
- }
- if ( w > viewW )
- hScrollOn = TRUE;
- else
- hScrollOn = FALSE;
- }
-
- if ( testTableFlags(Tbl_autoVScrollBar) ) {
- if ( cellH ) {
- h = cellH*nRows;
- } else {
- i = 0;
- while ( i < nRows && h <= viewH )
- h += cellHeight( i++ );
- }
-
- if ( h > viewH )
- vScrollOn = TRUE;
- else
- vScrollOn = FALSE;
- }
-
- if ( testTableFlags(Tbl_autoHScrollBar) && vScrollOn && !hScrollOn )
- if ( w > viewW - VSBEXT )
- hScrollOn = TRUE;
-
- if ( testTableFlags(Tbl_autoVScrollBar) && hScrollOn && !vScrollOn )
- if ( h > viewH - HSBEXT )
- vScrollOn = TRUE;
-
- setHorScrollBar( hScrollOn, FALSE );
- setVerScrollBar( vScrollOn, FALSE );
- updateFrameSize();
-}
-
-
-/*!
- \fn void QtTableView::updateScrollBars()
-
- Updates the scroll bars' contents and presence to match the table's
- state. Generally, you should not need to call this.
-
- \sa setTableFlags()
-*/
-
-/*!
- Updates the scroll bars' contents and presence to match the table's
- state \c or \a f.
-
- \sa setTableFlags()
-*/
-
-void QtTableView::updateScrollBars( uint f )
-{
- sbDirty = sbDirty | f;
- if ( inSbUpdate )
- return;
- inSbUpdate = TRUE;
-
- if ( testTableFlags(Tbl_autoHScrollBar) && (sbDirty & horRange) ||
- testTableFlags(Tbl_autoVScrollBar) && (sbDirty & verRange) )
- // if range change and auto
- doAutoScrollBars(); // turn scroll bars on/off if needed
-
- if ( !autoUpdate() ) {
- inSbUpdate = FALSE;
- return;
- }
- if ( yOffset() > 0 && testTableFlags( Tbl_autoVScrollBar ) &&
- !testTableFlags( Tbl_vScrollBar ) ) {
- setYOffset( 0 );
- }
- if ( xOffset() > 0 && testTableFlags( Tbl_autoHScrollBar ) &&
- !testTableFlags( Tbl_hScrollBar ) ) {
- setXOffset( 0 );
- }
- if ( !isVisible() ) {
- inSbUpdate = FALSE;
- return;
- }
-
- if ( testTableFlags(Tbl_hScrollBar) && (sbDirty & horMask) != 0 ) {
- if ( sbDirty & horGeometry )
- hScrollBar->setGeometry( 0,height() - HSBEXT,
- viewWidth() + frameWidth()*2,
- HSBEXT);
-
- if ( sbDirty & horSteps ) {
- if ( cellW )
- hScrollBar->setSteps( QMIN(cellW,viewWidth()/2), viewWidth() );
- else
- hScrollBar->setSteps( 16, viewWidth() );
- }
-
- if ( sbDirty & horRange )
- hScrollBar->setRange( 0, maxXOffset() );
-
- if ( sbDirty & horValue )
- hScrollBar->setValue( xOffs );
-
- // show scrollbar only when it has a sane geometry
- if ( !hScrollBar->isVisible() )
- hScrollBar->show();
- }
-
- if ( testTableFlags(Tbl_vScrollBar) && (sbDirty & verMask) != 0 ) {
- if ( sbDirty & verGeometry )
- vScrollBar->setGeometry( width() - VSBEXT, 0,
- VSBEXT,
- viewHeight() + frameWidth()*2 );
-
- if ( sbDirty & verSteps ) {
- if ( cellH )
- vScrollBar->setSteps( QMIN(cellH,viewHeight()/2), viewHeight() );
- else
- vScrollBar->setSteps( 16, viewHeight() ); // fttb! ###
- }
-
- if ( sbDirty & verRange )
- vScrollBar->setRange( 0, maxYOffset() );
-
- if ( sbDirty & verValue )
- vScrollBar->setValue( yOffs );
-
- // show scrollbar only when it has a sane geometry
- if ( !vScrollBar->isVisible() )
- vScrollBar->show();
- }
- if ( coveringCornerSquare &&
- ( (sbDirty & verGeometry ) || (sbDirty & horGeometry)) )
- cornerSquare->move( maxViewX() + frameWidth() + 1,
- maxViewY() + frameWidth() + 1 );
-
- sbDirty = 0;
- inSbUpdate = FALSE;
-}
-
-
-void QtTableView::updateFrameSize()
-{
- int rw = width() - ( testTableFlags(Tbl_vScrollBar) ?
- VSBEXT : 0 );
- int rh = height() - ( testTableFlags(Tbl_hScrollBar) ?
- HSBEXT : 0 );
- if ( rw < 0 )
- rw = 0;
- if ( rh < 0 )
- rh = 0;
-
- if ( autoUpdate() ) {
- int fh = frameRect().height();
- int fw = frameRect().width();
- setFrameRect( QRect(0,0,rw,rh) );
-
- if ( rw != fw )
- update( QMIN(fw,rw) - frameWidth() - 2, 0, frameWidth()+4, rh );
- if ( rh != fh )
- update( 0, QMIN(fh,rh) - frameWidth() - 2, rw, frameWidth()+4 );
- }
-}
-
-
-/*!
- Returns the maximum horizontal offset within the table of the
- view's left edge in \e table coordinates.
-
- This is used mainly to set the horizontal scroll bar's range.
-
- \sa maxColOffset(), maxYOffset(), totalWidth()
-*/
-
-int QtTableView::maxXOffset()
-{
- int tw = totalWidth();
- int maxOffs;
- if ( testTableFlags(Tbl_scrollLastHCell) ) {
- if ( nCols != 1)
- maxOffs = tw - ( cellW ? cellW : cellWidth( nCols - 1 ) );
- else
- maxOffs = tw - viewWidth();
- } else {
- if ( testTableFlags(Tbl_snapToHGrid) ) {
- if ( cellW ) {
- maxOffs = tw - (viewWidth()/cellW)*cellW;
- } else {
- int goal = tw - viewWidth();
- int pos = tw;
- int nextCol = nCols - 1;
- int nextCellWidth = cellWidth( nextCol );
- while( nextCol > 0 && pos > goal + nextCellWidth ) {
- pos -= nextCellWidth;
- nextCellWidth = cellWidth( --nextCol );
- }
- if ( goal + nextCellWidth == pos )
- maxOffs = goal;
- else if ( goal < pos )
- maxOffs = pos;
- else
- maxOffs = 0;
- }
- } else {
- maxOffs = tw - viewWidth();
- }
- }
- return maxOffs > 0 ? maxOffs : 0;
-}
-
-
-/*!
- Returns the maximum vertical offset within the table of the
- view's top edge in \e table coordinates.
-
- This is used mainly to set the vertical scroll bar's range.
-
- \sa maxRowOffset(), maxXOffset(), totalHeight()
-*/
-
-int QtTableView::maxYOffset()
-{
- int th = totalHeight();
- int maxOffs;
- if ( testTableFlags(Tbl_scrollLastVCell) ) {
- if ( nRows != 1)
- maxOffs = th - ( cellH ? cellH : cellHeight( nRows - 1 ) );
- else
- maxOffs = th - viewHeight();
- } else {
- if ( testTableFlags(Tbl_snapToVGrid) ) {
- if ( cellH ) {
- maxOffs = th - (viewHeight()/cellH)*cellH;
- } else {
- int goal = th - viewHeight();
- int pos = th;
- int nextRow = nRows - 1;
- int nextCellHeight = cellHeight( nextRow );
- while( nextRow > 0 && pos > goal + nextCellHeight ) {
- pos -= nextCellHeight;
- nextCellHeight = cellHeight( --nextRow );
- }
- if ( goal + nextCellHeight == pos )
- maxOffs = goal;
- else if ( goal < pos )
- maxOffs = pos;
- else
- maxOffs = 0;
- }
- } else {
- maxOffs = th - viewHeight();
- }
- }
- return maxOffs > 0 ? maxOffs : 0;
-}
-
-
-/*!
- Returns the index of the last column, which may be at the left edge
- of the view.
-
- Depending on the \link setTableFlags() Tbl_scrollLastHCell\endlink flag,
- this may or may not be the last column.
-
- \sa maxXOffset(), maxRowOffset()
-*/
-
-int QtTableView::maxColOffset()
-{
- int mx = maxXOffset();
- if ( cellW )
- return mx/cellW;
- else {
- int xcd=0, col=0;
- while ( col < nCols && mx > (xcd=cellWidth(col)) ) {
- mx -= xcd;
- col++;
- }
- return col;
- }
-}
-
-
-/*!
- Returns the index of the last row, which may be at the top edge of
- the view.
-
- Depending on the \link setTableFlags() Tbl_scrollLastVCell\endlink flag,
- this may or may not be the last row.
-
- \sa maxYOffset(), maxColOffset()
-*/
-
-int QtTableView::maxRowOffset()
-{
- int my = maxYOffset();
- if ( cellH )
- return my/cellH;
- else {
- int ycd=0, row=0;
- while ( row < nRows && my > (ycd=cellHeight(row)) ) {
- my -= ycd;
- row++;
- }
- return row;
- }
-}
-
-
-void QtTableView::showOrHideScrollBars()
-{
- if ( !autoUpdate() )
- return;
- if ( vScrollBar ) {
- if ( testTableFlags(Tbl_vScrollBar) ) {
- if ( !vScrollBar->isVisible() )
- sbDirty = sbDirty | verMask;
- } else {
- if ( vScrollBar->isVisible() )
- vScrollBar->hide();
- }
- }
- if ( hScrollBar ) {
- if ( testTableFlags(Tbl_hScrollBar) ) {
- if ( !hScrollBar->isVisible() )
- sbDirty = sbDirty | horMask;
- } else {
- if ( hScrollBar->isVisible() )
- hScrollBar->hide();
- }
- }
- if ( cornerSquare ) {
- if ( testTableFlags(Tbl_hScrollBar) &&
- testTableFlags(Tbl_vScrollBar) ) {
- if ( !cornerSquare->isVisible() )
- cornerSquare->show();
- } else {
- if ( cornerSquare->isVisible() )
- cornerSquare->hide();
- }
- }
-}
-
-
-/*!
- Updates the scroll bars and internal state.
-
- Call this function when the table view's total size is changed;
- typically because the result of cellHeight() or cellWidth() have changed.
-
- This function does not repaint the widget.
-*/
-
-void QtTableView::updateTableSize()
-{
- bool updateOn = autoUpdate();
- setAutoUpdate( FALSE );
- int xofs = xOffset();
- xOffs++; //so that setOffset will not return immediately
- setOffset(xofs,yOffset(),FALSE); //to calculate internal state correctly
- setAutoUpdate(updateOn);
-
- updateScrollBars( horSteps | horRange |
- verSteps | verRange );
- showOrHideScrollBars();
-}
-
-
-#endif
-#endif
diff --git a/win/Qt/tileedit.cpp b/win/Qt/tileedit.cpp
deleted file mode 100644
index cbde51867..000000000
--- a/win/Qt/tileedit.cpp
+++ /dev/null
@@ -1,413 +0,0 @@
-/* NetHack 3.6 tileedit.cpp $NHDT-Date: 1524684508 2018/04/25 19:28:28 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.10 $ */
-/* Copyright (c) Warwick Allison, 1999. */
-/* NetHack may be freely redistributed. See license for details. */
-/*
-Build this little utility program if you want to use it to edit the tile
-files. Move tileedit.cpp and tileedit.h to ../../util, add the
-3 lines below to the Makefile there and "make tileedit".
-
-tileedit: tileedit.cpp $(TEXT_IO)
- moc -o tileedit.moc tileedit.h
- $(CC) -o tileedit -I../include -I$(QTDIR)/include -L$(QTDIR)/lib tileedit.cpp $(TEXT_IO) -lqt
-*/
-
-
-#include "tileedit.h"
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-
-extern "C" {
-#include "config.h"
-#include "tile.h"
-extern const char *FDECL(tilename, (int, int));
-}
-
-#define TILES_ACROSS 20
-
-TilePickerTab::TilePickerTab(const char* basename, int i, QWidget* parent) :
- QWidget(parent)
-{
- id = i;
- filename = basename;
- filename += ".txt";
- num = 0;
- int index = 0;
- for (int real=0; real<2; real++) {
- if ( real ) {
- image.create( TILES_ACROSS*TILE_X,
- ((num+TILES_ACROSS-1)/TILES_ACROSS)*TILE_Y, 32 );
- }
- if ( !fopen_text_file(filename.latin1(), RDTMODE) ) {
- // XXX handle better
- exit(1);
- }
- pixel p[TILE_Y][TILE_X];
- while ( read_text_tile(p) ) {
- if ( real ) {
- int ox = (index%TILES_ACROSS)*TILE_X;
- int oy = (index/TILES_ACROSS)*TILE_Y;
- for ( int y=0; yx()-e->x()%TILE_X;
- int oy = e->y()-e->y()%TILE_Y;
- QImage subimage = image.copy(ox,oy,TILE_X,TILE_Y);
- if ( e->button() == RightButton ) {
- setCurrent(subimage);
- } else {
- last_pick = ox/TILE_X + oy/TILE_Y*TILES_ACROSS;
- }
- emit pick(subimage);
- emit pickName(tilename(id, last_pick));
-}
-
-void TilePickerTab::setCurrent(const QImage& i)
-{
- int ox = last_pick%TILES_ACROSS * TILE_X;
- int oy = last_pick/TILES_ACROSS * TILE_Y;
- bitBlt( &image, ox, oy, &i );
- bitBlt( &pixmap, ox, oy, &i );
- repaint( ox, oy, TILE_X, TILE_Y, FALSE );
-}
-
-QSize TilePickerTab::sizeHint() const
-{
- return pixmap.size();
-}
-
-void TilePickerTab::paintEvent( QPaintEvent* )
-{
- QPainter p(this);
- p.drawPixmap(0,0,pixmap);
-}
-
-static struct {
- const char* name;
- TilePickerTab* tab;
-} tileset[] = {
- { "monsters", 0 },
- { "objects", 0 },
- { "other", 0 },
- { 0 }
-};
-
-TilePicker::TilePicker(QWidget* parent) :
- QTabWidget(parent)
-{
- for (int i=0; tileset[i].name; i++) {
- QString tabname = tileset[i].name;
- tabname[0] = tabname[0].upper();
- tileset[i].tab = new TilePickerTab(tileset[i].name,i+1,this);
- addTab( tileset[i].tab, tabname );
- connect( tileset[i].tab, SIGNAL(pick(const QImage&)),
- this, SIGNAL(pick(const QImage&)) );
- connect( tileset[i].tab, SIGNAL(pickName(const QString&)),
- this, SIGNAL(pickName(const QString&)) );
- }
-}
-
-void TilePicker::setCurrent(const QImage& i)
-{
- ((TilePickerTab*)currentPage())->setCurrent(i);
-}
-
-void TilePicker::save()
-{
- for (int i=0; tileset[i].tab; i++) {
- tileset[i].tab->save();
- }
-}
-
-TrivialTileEditor::TrivialTileEditor( QWidget* parent ) :
- QWidget(parent)
-{
-}
-
-const QImage& TrivialTileEditor::image() const
-{
- return img;
-}
-
-void TrivialTileEditor::setColor( QRgb rgb )
-{
- pen = rgb;
- for (penpixel = 0;
- penpixelrect();
- QPoint tl = imagePoint(r.topLeft());
- QPoint br = imagePoint(r.bottomRight());
- r = QRect(tl,br).intersect(img.rect());
- QPainter painter(this);
- for (int y=r.top(); y<=r.bottom(); y++) {
- for (int x=r.left(); x<=r.right(); x++) {
- paintPoint(painter,QPoint(x,y));
- }
- }
-}
-
-void TrivialTileEditor::paintPoint(QPainter& painter, QPoint p)
-{
- QPoint p1 = screenPoint(p);
- QPoint p2 = screenPoint(p+QPoint(1,1));
- QColor c = img.color(img.scanLine(p.y())[p.x()]);
- painter.fillRect(QRect(p1,p2-QPoint(1,1)), c);
-}
-
-void TrivialTileEditor::mousePressEvent(QMouseEvent* e)
-{
- QPoint p = imagePoint(e->pos());
- if ( !img.rect().contains(p) )
- return;
- uchar& pixel = img.scanLine(p.y())[p.x()];
- if ( e->button() == LeftButton ) {
- pixel = penpixel;
- QPainter painter(this);
- paintPoint(painter,p);
- } else if ( e->button() == RightButton ) {
- emit pick( img.color(pixel) );
- } else if ( e->button() == MidButton ) {
- QPainter painter(this);
- if ( pixel != penpixel )
- fill(painter,p,pixel);
- }
-}
-
-void TrivialTileEditor::fill(QPainter& painter, QPoint p, uchar from)
-{
- if ( img.rect().contains(p) ) {
- uchar& pixel = img.scanLine(p.y())[p.x()];
- if ( pixel == from ) {
- pixel = penpixel;
- paintPoint(painter,p);
- fill(painter, p+QPoint(-1,0), from);
- fill(painter, p+QPoint(+1,0), from);
- fill(painter, p+QPoint(0,-1), from);
- fill(painter, p+QPoint(0,+1), from);
- }
- }
-}
-
-void TrivialTileEditor::mouseReleaseEvent(QMouseEvent* e)
-{
- emit edited(image());
-}
-
-void TrivialTileEditor::mouseMoveEvent(QMouseEvent* e)
-{
- QPoint p = imagePoint(e->pos());
- if ( !img.rect().contains(p) )
- return;
- uchar& pixel = img.scanLine(p.y())[p.x()];
- pixel = penpixel;
- QPainter painter(this);
- paintPoint(painter,p);
-}
-
-QPoint TrivialTileEditor::imagePoint(QPoint p) const
-{
- return QPoint(p.x()*TILE_X/width(), p.y()*TILE_Y/height());
-}
-
-QPoint TrivialTileEditor::screenPoint(QPoint p) const
-{
- return QPoint(p.x()*width()/TILE_X, p.y()*height()/TILE_Y);
-}
-
-QSizePolicy TrivialTileEditor::sizePolicy() const
-{
- return QSizePolicy( QSizePolicy::Expanding, QSizePolicy::Expanding, TRUE );
-}
-
-QSize TrivialTileEditor::sizeHint() const
-{
- return sizeForWidth(-1);
-}
-
-QSize TrivialTileEditor::sizeForWidth(int w) const
-{
- if ( w < 0 )
- return QSize(TILE_X*32,TILE_Y*32);
- else
- return QSize(w,w*TILE_Y/TILE_X);
-}
-
-
-TilePalette::TilePalette( QWidget* parent ) :
- QWidget(parent)
-{
- num = 0;
- rgb = 0;
-}
-
-TilePalette::~TilePalette()
-{
- delete rgb;
-}
-
-void TilePalette::setFromImage( const QImage& i )
-{
- num = i.numColors();
- rgb = new QRgb[num];
- memcpy(rgb, i.colorTable(), num*sizeof(QRgb));
- repaint(FALSE);
-}
-
-void TilePalette::setColor(QRgb c)
-{
- for (int i=0; ix()*num/width();
- emit pick(rgb[c]);
-}
-
-TileEditor::TileEditor(QWidget* parent) :
- QVBox(parent),
- editor(this),
- palette(this)
-{
- connect( &palette, SIGNAL(pick(QRgb)),
- &editor, SLOT(setColor(QRgb)) );
- connect( &editor, SIGNAL(pick(QRgb)),
- &palette, SLOT(setColor(QRgb)) );
- connect( &editor, SIGNAL(edited(const QImage&)),
- this, SIGNAL(edited(const QImage&)) );
-}
-
-void TileEditor::edit(const QImage& i)
-{
- editor.setImage(i);
- palette.setFromImage(i);
-}
-
-const QImage& TileEditor::image() const
-{
- return editor.image();
-}
-
-class Main : public QMainWindow {
-public:
- Main() :
- central(this),
- editor(¢ral),
- picker(¢ral)
- {
- QPopupMenu* file = new QPopupMenu(menuBar());
- file->insertItem("&Save", &picker, SLOT(save()), CTRL+Key_S);
- file->insertSeparator();
- file->insertItem("&Exit", qApp, SLOT(quit()), CTRL+Key_Q);
- menuBar()->insertItem("&File", file);
-
- connect( &picker, SIGNAL(pick(const QImage&)),
- &editor, SLOT(edit(const QImage&)) );
- connect( &picker, SIGNAL(pickName(const QString&)),
- statusBar(), SLOT(message(const QString&)) );
- connect( &editor, SIGNAL(edited(const QImage&)),
- &picker, SLOT(setCurrent(const QImage&)) );
-
- setCentralWidget(¢ral);
- }
-
-private:
- QHBox central;
- TileEditor editor;
- TilePicker picker;
-};
-
-main(int argc, char** argv)
-{
- QApplication app(argc,argv);
- Main m;
- app.setMainWidget(&m);
- m.show();
- return app.exec();
-}
-
-#include "tileedit.moc"
diff --git a/win/Qt/tileedit.h b/win/Qt/tileedit.h
deleted file mode 100644
index 550e65e03..000000000
--- a/win/Qt/tileedit.h
+++ /dev/null
@@ -1,135 +0,0 @@
-/* NetHack 3.6 tileedit.h $NHDT-Date: 1432512809 2015/05/25 00:13:29 $ $NHDT-Branch: master $:$NHDT-Revision: 1.8 $ */
-/* Copyright (c) Warwick Allison, 1999. */
-/* NetHack may be freely redistributed. See license for details. */
-#ifndef QNHTILEEDIT_H
-#define QNHTILEEDIT_H
-
-#include
-#include
-#include
-#include
-
-class TilePickerTab : public QWidget
-{
- Q_OBJECT
- public:
- TilePickerTab(const char *basename, int id, QWidget *parent);
-
- bool save();
- int numTiles();
-
- signals:
- void pick(const QImage &);
- void pickName(const QString &);
-
- public slots:
- void setCurrent(const QImage &);
-
- protected:
- void paintEvent(QPaintEvent *);
- QSize sizeHint() const;
- void mousePressEvent(QMouseEvent *);
-
- private:
- QString filename;
- int id;
- int last_pick;
- int num;
- QPixmap pixmap;
- QImage image;
-};
-
-class TilePicker : public QTabWidget
-{
- Q_OBJECT
- public:
- TilePicker(QWidget *parent);
-
- void setTile(int tilenum, const QImage &);
-
- signals:
- void pick(const QImage &);
- void pickName(const QString &);
-
- public slots:
- void setCurrent(const QImage &);
- void save();
-};
-
-class TrivialTileEditor : public QWidget
-{
- Q_OBJECT
- public:
- TrivialTileEditor(QWidget *parent);
- const QImage &image() const;
-
- signals:
- void edited(const QImage &);
- void pick(QRgb);
-
- public slots:
- void setColor(QRgb);
- void setImage(const QImage &);
-
- protected:
- void paintEvent(QPaintEvent *);
- void mousePressEvent(QMouseEvent *);
- void mouseReleaseEvent(QMouseEvent *);
- void mouseMoveEvent(QMouseEvent *);
- QSize sizeHint() const;
- QSize sizeForWidth(int) const;
- QSizePolicy sizePolicy() const;
-
- private:
- void fill(QPainter &painter, QPoint p, uchar from);
- QImage img;
- QColor pen;
- int penpixel;
- void paintPoint(QPainter &painter, QPoint p);
- QPoint screenPoint(QPoint) const;
- QPoint imagePoint(QPoint) const;
-};
-
-class TilePalette : public QWidget
-{
- Q_OBJECT
- public:
- TilePalette(QWidget *parent);
- ~TilePalette();
- void setFromImage(const QImage &);
-
- protected:
- void paintEvent(QPaintEvent *);
- void mousePressEvent(QMouseEvent *);
- QSize sizeHint() const;
- QSizePolicy sizePolicy() const;
- signals:
- void pick(QRgb);
- public slots:
- void setColor(QRgb);
-
- private:
- int num;
- QRgb *rgb;
-};
-
-class TileEditor : public QVBox
-{
- Q_OBJECT
- public:
- TileEditor(QWidget *parent);
-
- const QImage &image() const;
-
- signals:
- void edited(const QImage &);
-
- public slots:
- void edit(const QImage &);
-
- private:
- TrivialTileEditor editor;
- TilePalette palette;
-};
-
-#endif
diff --git a/win/Qt4/.gitattributes b/win/Qt4/.gitattributes
deleted file mode 100644
index 68792d904..000000000
--- a/win/Qt4/.gitattributes
+++ /dev/null
@@ -1 +0,0 @@
-* NH_filestag=(file%s_for_the_Qt_4_widget_library_-_X11,_Windows,_Mac_OS_X)
diff --git a/win/Qt4/.gitignore b/win/Qt4/.gitignore
deleted file mode 100644
index e978b1085..000000000
--- a/win/Qt4/.gitignore
+++ /dev/null
@@ -1 +0,0 @@
-*.moc
diff --git a/win/Qt4/qt4bind.cpp b/win/Qt4/qt4bind.cpp
deleted file mode 100644
index 5395787ec..000000000
--- a/win/Qt4/qt4bind.cpp
+++ /dev/null
@@ -1,831 +0,0 @@
-// Copyright (c) Warwick Allison, 1999.
-// Qt4 conversion copyright (c) Ray Chason, 2012-2014.
-// NetHack may be freely redistributed. See license for details.
-
-// qt4bind.cpp -- bindings between the Qt 4 interface and the main code
-
-extern "C" {
-#include "hack.h"
-}
-#undef Invisible
-#undef Warning
-#undef index
-#undef msleep
-#undef rindex
-#undef wizard
-#undef yn
-#undef min
-#undef max
-
-#include
-#include
-#if QT_VERSION >= 0x050000
-#include
-#include
-#else
-#include
-#endif
-#include "qt4bind.h"
-#include "qt4click.h"
-#ifdef TIMED_DELAY
-#include "qt4delay.h"
-#endif
-#include "qt4xcmd.h"
-#include "qt4key.h"
-#include "qt4map.h"
-#include "qt4menu.h"
-#include "qt4msg.h"
-#include "qt4plsel.h"
-#include "qt4svsel.h"
-#include "qt4set.h"
-#include "qt4stat.h"
-#include "qt4streq.h"
-#include "qt4yndlg.h"
-#include "qt4str.h"
-
-extern "C" {
-#include "dlb.h"
-}
-
-// temporary
-extern int qt_compact_mode;
-// end temporary
-
-namespace nethack_qt4 {
-
-// XXX Should be from Options
-//
-// XXX Hmm. Tricky part is that perhaps some macros should only be active
-// XXX when a key is about to be gotten. For example, the user could
-// XXX define "-" to do "E-yyyyyyyy\r", but would still need "-" for
-// XXX other purposes. Maybe just too bad.
-//
-static struct key_macro_rec {
- int key;
- int state;
- const char* macro;
-} key_macro[]={
- { Qt::Key_F1, 0, "n100." }, // Rest (x100)
- { Qt::Key_F2, 0, "n20s" }, // Search (x20)
- { Qt::Key_Tab, 0, "\001" },
- { 0, 0, 0 }
-};
-
-NetHackQtBind::NetHackQtBind(int& argc, char** argv) :
-#ifdef KDE
- KApplication(argc,argv)
-#elif defined(QWS) // not quite the right condition
- QPEApplication(argc,argv)
-#else
- QApplication(argc,argv)
-#endif
-{
- QPixmap pm("nhsplash.xpm");
- if ( iflags.wc_splash_screen && !pm.isNull() ) {
- splash = new QFrame(NULL,
- Qt::FramelessWindowHint | Qt::X11BypassWindowManagerHint | Qt::WindowStaysOnTopHint );
- QVBoxLayout *vb = new QVBoxLayout(splash);
- QLabel *lsplash = new QLabel(splash);
- vb->addWidget(lsplash);
- lsplash->setAlignment(Qt::AlignCenter);
- lsplash->setPixmap(pm);
- QLabel* capt = new QLabel("Loading...",splash);
- vb->addWidget(capt);
- capt->setAlignment(Qt::AlignCenter);
- if ( !pm.isNull() ) {
- lsplash->setFixedSize(pm.size());
- lsplash->setMask(pm);
- }
- splash->move((QApplication::desktop()->width()-pm.width())/2,
- (QApplication::desktop()->height()-pm.height())/2);
- //splash->setGeometry(0,0,100,100);
- if ( qt_compact_mode ) {
- splash->showMaximized();
- } else {
- splash->setFrameStyle(QFrame::WinPanel|QFrame::Raised);
- splash->setLineWidth(10);
- splash->adjustSize();
- splash->show();
- }
-
- // force content refresh outside event loop
- splash->repaint();
- lsplash->repaint();
- capt->repaint();
- qApp->flush();
-
- } else {
- splash = 0;
- }
- main = new NetHackQtMainWindow(keybuffer);
- connect(qApp, SIGNAL(lastWindowClosed()), qApp, SLOT(quit()));
- qt_settings=new NetHackQtSettings(main->width(),main->height());
- msgs_strings = new QStringList();
- msgs_initd = false;
- msgs_saved = false;
-}
-
-void NetHackQtBind::qt_init_nhwindows(int* argc, char** argv)
-{
- iflags.menu_tab_sep = true;
-
-#ifdef UNIX
-// Userid control
-//
-// Michael Hohmuth ...
-//
-// As the game runs setuid games, it must seteuid(getuid()) before
-// calling XOpenDisplay(), and reset the euid afterwards.
-// Otherwise, it can't read the $HOME/.Xauthority file and whines about
-// not being able to open the X display (if a magic-cookie
-// authorization mechanism is being used).
-
- uid_t gamesuid=geteuid();
- seteuid(getuid());
-#endif
-
- QApplication::setColorSpec(ManyColor);
- instance=new NetHackQtBind(*argc,argv);
-
-#ifdef UNIX
- seteuid(gamesuid);
-#endif
-
-#ifdef _WS_WIN_
- // This nethack engine feature should be moved into windowport API
- nt_kbhit = NetHackQtBind::qt_kbhit;
-#endif
-}
-
-int NetHackQtBind::qt_kbhit()
-{
- return !keybuffer.Empty();
-}
-
-
-static bool have_asked = false;
-
-void NetHackQtBind::qt_player_selection()
-{
- if ( !have_asked )
- qt_askname();
-}
-
-void NetHackQtBind::qt_askname()
-{
- have_asked = true;
-
- // We do it all here, and nothing in askname
-
- char** saved = get_saved_games();
- int ch = -1;
- if ( saved && *saved ) {
- if ( splash ) splash->hide();
- NetHackQtSavedGameSelector sgsel((const char**)saved);
- ch = sgsel.choose();
- if ( ch >= 0 )
- str_copy(plname, saved[ch], SIZE(plname));
- }
- free_saved_games(saved);
-
- switch (ch) {
- case -1:
- if ( splash ) splash->hide();
- if (NetHackQtPlayerSelector(keybuffer).Choose())
- return;
- case -2:
- break;
- default:
- return;
- }
-
- // Quit
- clearlocks();
- qt_exit_nhwindows(0);
- nh_terminate(0);
-}
-
-void NetHackQtBind::qt_get_nh_event()
-{
-}
-
-#if defined(QWS)
-// Kludge to access lastWindowClosed() signal.
-class TApp : public QApplication {
-public:
- TApp(int& c, char**v) : QApplication(c,v) {}
- void lwc() { emit lastWindowClosed(); }
-};
-#endif
-
-void NetHackQtBind::qt_exit_nhwindows(const char *)
-{
-#if defined(QWS)
- // Avoids bug in SHARP SL5500
- ((TApp*)qApp)->lwc();
- qApp->quit();
-#endif
-
- delete instance; // ie. qApp
-}
-
-void NetHackQtBind::qt_suspend_nhwindows(const char *)
-{
-}
-
-void NetHackQtBind::qt_resume_nhwindows()
-{
-}
-
-static QVector id_to_window;
-
-winid NetHackQtBind::qt_create_nhwindow(int type)
-{
- winid id;
- for (id = 0; id < (winid) id_to_window.size(); id++) {
- if ( !id_to_window[(int)id] )
- break;
- }
- if ( id == (winid) id_to_window.size() )
- id_to_window.resize(id+1);
-
- NetHackQtWindow* window=0;
-
- switch (type) {
- case NHW_MAP: {
- NetHackQtMapWindow2* w=new NetHackQtMapWindow2(clickbuffer);
- main->AddMapWindow(w);
- window=w;
- } break; case NHW_MESSAGE: {
- NetHackQtMessageWindow* w=new NetHackQtMessageWindow;
- main->AddMessageWindow(w);
- window=w;
- } break; case NHW_STATUS: {
- NetHackQtStatusWindow* w=new NetHackQtStatusWindow;
- main->AddStatusWindow(w);
- window=w;
- } break; case NHW_MENU:
- window=new NetHackQtMenuOrTextWindow(mainWidget());
- break; case NHW_TEXT:
- window=new NetHackQtTextWindow(mainWidget());
- }
-
- window->nhid = id;
-
- // Note: use of isHidden does not work with Qt 2.1
- if ( splash
-#if QT_VERSION >= 300
- && !main->isHidden()
-#else
- && main->isVisible()
-#endif
- )
- {
- delete splash;
- splash = 0;
- }
-
- id_to_window[(int)id] = window;
- return id;
-}
-
-void NetHackQtBind::qt_clear_nhwindow(winid wid)
-{
- NetHackQtWindow* window=id_to_window[(int)wid];
- window->Clear();
-}
-
-void NetHackQtBind::qt_display_nhwindow(winid wid, BOOLEAN_P block)
-{
- NetHackQtWindow* window=id_to_window[(int)wid];
- window->Display(block);
-}
-
-void NetHackQtBind::qt_destroy_nhwindow(winid wid)
-{
- NetHackQtWindow* window=id_to_window[(int)wid];
- main->RemoveWindow(window);
- if (window->Destroy())
- delete window;
- id_to_window[(int)wid] = 0;
-}
-
-void NetHackQtBind::qt_curs(winid wid, int x, int y)
-{
- NetHackQtWindow* window=id_to_window[(int)wid];
- window->CursorTo(x,y);
-}
-
-void NetHackQtBind::qt_putstr(winid wid, int attr, const char *text)
-{
- NetHackQtWindow* window=id_to_window[(int)wid];
- window->PutStr(attr,QString::fromLatin1(text));
-}
-
-void NetHackQtBind::qt_putstr(winid wid, int attr, const std::string& text)
-{
- NetHackQtWindow* window=id_to_window[(int)wid];
- window->PutStr(attr,QString::fromLatin1(text.c_str(), text.size()));
-}
-
-void NetHackQtBind::qt_putstr(winid wid, int attr, const QString& text)
-{
- NetHackQtWindow* window=id_to_window[(int)wid];
- window->PutStr(attr,text);
-}
-
-void NetHackQtBind::qt_display_file(const char *filename, BOOLEAN_P must_exist)
-{
- NetHackQtTextWindow* window=new NetHackQtTextWindow(mainWidget());
- bool complain = false;
-
- {
- dlb *f;
- char buf[BUFSZ];
- char *cr;
-
- window->Clear();
- f = dlb_fopen(filename, "r");
- if (!f) {
- complain = must_exist;
- } else {
- while (dlb_fgets(buf, BUFSZ, f)) {
- if ((cr = strchr(buf, '\n')) != 0) *cr = 0;
-#ifdef MSDOS
- if ((cr = strchr(buf, '\r')) != 0) *cr = 0;
-#endif
- window->PutStr(ATR_NONE, tabexpand(buf));
- }
- window->Display(false);
- (void) dlb_fclose(f);
- }
- }
-
- if (complain) {
- QString message;
- message.sprintf("File not found: %s\n",filename);
- QMessageBox::warning(NULL, "File Error", message, QMessageBox::Ignore);
- }
-}
-
-void NetHackQtBind::qt_start_menu(winid wid)
-{
- NetHackQtWindow* window=id_to_window[(int)wid];
- window->StartMenu();
-}
-
-void NetHackQtBind::qt_add_menu(winid wid, int glyph,
- const ANY_P * identifier, CHAR_P ch, CHAR_P gch, int attr,
- const char *str, BOOLEAN_P presel)
-{
- NetHackQtWindow* window=id_to_window[(int)wid];
- window->AddMenu(glyph, identifier, ch, gch, attr,
- QString::fromLatin1(str),
- presel);
-}
-
-void NetHackQtBind::qt_end_menu(winid wid, const char *prompt)
-{
- NetHackQtWindow* window=id_to_window[(int)wid];
- window->EndMenu(prompt);
-}
-
-int NetHackQtBind::qt_select_menu(winid wid, int how, MENU_ITEM_P **menu_list)
-{
- NetHackQtWindow* window=id_to_window[(int)wid];
- return window->SelectMenu(how,menu_list);
-}
-
-void NetHackQtBind::qt_update_inventory()
-{
- if (main)
- main->updateInventory();
- /* doesn't work yet
- if (program_state.something_worth_saving && iflags.perm_invent)
- display_inventory(NULL, false);
- */
-}
-
-void NetHackQtBind::qt_mark_synch()
-{
-}
-
-void NetHackQtBind::qt_wait_synch()
-{
-}
-
-void NetHackQtBind::qt_cliparound(int x, int y)
-{
- // XXXNH - winid should be a parameter!
- qt_cliparound_window(WIN_MAP,x,y);
-}
-
-void NetHackQtBind::qt_cliparound_window(winid wid, int x, int y)
-{
- NetHackQtWindow* window=id_to_window[(int)wid];
- window->ClipAround(x,y);
-}
-void NetHackQtBind::qt_print_glyph(winid wid,XCHAR_P x,XCHAR_P y,int glyph,int bkglyph)
-{
- /* TODO: bkglyph */
- NetHackQtWindow* window=id_to_window[(int)wid];
- window->PrintGlyph(x,y,glyph);
-}
-//void NetHackQtBind::qt_print_glyph_compose(winid wid,xchar x,xchar y,int glyph1, int glyph2)
-//{
- //NetHackQtWindow* window=id_to_window[(int)wid];
- //window->PrintGlyphCompose(x,y,glyph1,glyph2);
-//}
-
-void NetHackQtBind::qt_raw_print(const char *str)
-{
- puts(str);
-}
-
-void NetHackQtBind::qt_raw_print_bold(const char *str)
-{
- puts(str);
-}
-
-int NetHackQtBind::qt_nhgetch()
-{
- if (main)
- main->fadeHighlighting();
-
- // Process events until a key arrives.
- //
- while (keybuffer.Empty()) {
- int exc = qApp->exec();
- /*
- * On OSX (possibly elsewhere), this prevents an infinite
- * loop repeatedly issuing the complaint:
-QCoreApplication::exec: The event loop is already running
- * to stderr if you syncronously start nethack from a terminal
- * then switch focus back to that terminal and type ^C.
- * SIGINT -> done1() -> done2() -> yn_function("Really quit?")
- * in the core asks for another keystroke.
- *
- * However, it still issues one such complaint, and whatever
- * prompt wanted a response ("Really quit?") is shown in the
- * message window but is auto-answered with ESC.
- */
- if (exc == -1)
- keybuffer.Put('\033');
- }
-
- return keybuffer.GetAscii();
-}
-
-int NetHackQtBind::qt_nh_poskey(int *x, int *y, int *mod)
-{
- if (main)
- main->fadeHighlighting();
-
- // Process events until a key or map-click arrives.
- //
- while (keybuffer.Empty() && clickbuffer.Empty()) {
- int exc = qApp->exec();
- // [see comment above in qt_nhgetch()]
- if (exc == -1)
- keybuffer.Put('\033');
- }
- if (!keybuffer.Empty()) {
- return keybuffer.GetAscii();
- } else {
- *x=clickbuffer.NextX();
- *y=clickbuffer.NextY();
- *mod=clickbuffer.NextMod();
- clickbuffer.Get();
- return 0;
- }
-}
-
-void NetHackQtBind::qt_nhbell()
-{
- QApplication::beep();
-}
-
-int NetHackQtBind::qt_doprev_message()
-{
- // Don't need it - uses scrollbar
- // XXX but could make this a shortcut
- return 0;
-}
-
-char NetHackQtBind::qt_yn_function(const char *question_, const char *choices, CHAR_P def)
-{
- QString question(QString::fromLatin1(question_));
- QString message;
- char yn_esc_map='\033';
-
- if (choices) {
- // anything beyond is hidden>
- QString choicebuf = choices;
- size_t cb = choicebuf.indexOf('\033');
- choicebuf = choicebuf.mid(0U, cb);
- message = QString("%1 [%2] ").arg(question, choicebuf);
- if (def) message += QString("(%1) ").arg(QChar(def));
- // escape maps to 'q' or 'n' or default, in that order
- yn_esc_map = (strchr(choices, 'q') ? 'q' :
- (strchr(choices, 'n') ? 'n' : def));
- } else {
- message = question;
- }
-
- if (qt_settings->ynInMessages() && WIN_MESSAGE!=WIN_ERR) {
- // Similar to X11 windowport `slow' feature.
-
- int result = -1;
-
-#ifdef USE_POPUPS
- if (choices) {
- if (!strcmp(choices,"ynq"))
- result = QMessageBox::information (NetHackQtBind::mainWidget(),"NetHack",question,"&Yes","&No","&Quit",0,2);
- else if (!strcmp(choices,"yn"))
- result = QMessageBox::information(NetHackQtBind::mainWidget(),"NetHack",question,"&Yes", "&No",0,1);
- else if (!strcmp(choices, "rl"))
- result = QMessageBox::information(NetHackQtBind::mainWidget(),"NetHack",question,"&Right", "&Left",0,1);
-
- if (result >= 0 && result < strlen(choices)) {
- char yn_resp = choices[result];
- message += QString(" %1").arg(yn_resp);
- result = yn_resp;
- }
- }
-#endif
-
- NetHackQtBind::qt_putstr(WIN_MESSAGE, ATR_BOLD, message);
-
- while (result < 0) {
- char ch=NetHackQtBind::qt_nhgetch();
- if (ch=='\033') {
- result=yn_esc_map;
- } else if (choices && !strchr(choices,ch)) {
- if (def && (ch==' ' || ch=='\r' || ch=='\n')) {
- result=def;
- } else {
- NetHackQtBind::qt_nhbell();
- // and try again...
- }
- } else {
- result=ch;
- }
- }
-
- NetHackQtBind::qt_clear_nhwindow(WIN_MESSAGE);
-
- return result;
- } else {
- NetHackQtYnDialog dialog(mainWidget(),question,choices,def);
- char ret = dialog.Exec();
- if (!(ret == '\0' || ret == '\033') && choices)
- message += QString(" %1").arg(ret);
- else if (def)
- message += QString(" %1").arg(def);
- NetHackQtBind::qt_putstr(WIN_MESSAGE, ATR_BOLD, message);
-
- return ret;
- }
-}
-
-void NetHackQtBind::qt_getlin(const char *prompt, char *line)
-{
- NetHackQtStringRequestor requestor(mainWidget(),prompt);
- if (!requestor.Get(line)) {
- line[0]=0;
- }
-}
-
-int NetHackQtBind::qt_get_ext_cmd()
-{
- NetHackQtExtCmdRequestor requestor(mainWidget());
- return requestor.get();
-}
-
-void NetHackQtBind::qt_number_pad(int)
-{
- // Ignore.
-}
-
-void NetHackQtBind::qt_delay_output()
-{
-#ifdef TIMED_DELAY
- NetHackQtDelay delay(50);
- delay.wait();
-#endif
-}
-
-void NetHackQtBind::qt_start_screen()
-{
- // Ignore.
-}
-
-void NetHackQtBind::qt_end_screen()
-{
- // Ignore.
-}
-
-void NetHackQtBind::qt_outrip(winid wid, int how, time_t when)
-{
- NetHackQtWindow* window=id_to_window[(int)wid];
- window->UseRIP(how, when);
-}
-
-char * NetHackQtBind::qt_getmsghistory(BOOLEAN_P init)
-{
- NetHackQtMessageWindow* window = main->GetMessageWindow();
- if (window)
- return (char *)window->GetStr(init);
- return NULL;
-}
-
-void NetHackQtBind::qt_putmsghistory(const char *msg, BOOLEAN_P is_restoring)
-{
- NetHackQtMessageWindow* window = main->GetMessageWindow();
- if (!window)
- return;
-
- if (is_restoring && !msgs_initd) {
- /* we're restoring history from the previous session, but new
- messages have already been issued this session */
- int i = 0;
- const char *str;
-
- while ((str = window->GetStr((i == 0)))) {
- msgs_strings->append(str);
- i++;
- }
- msgs_initd = true;
- msgs_saved = (i > 0);
- window->ClearMessages();
- }
-
- if (msg) {
- //raw_printf("msg='%s'", msg);
- window->PutStr(ATR_NONE, QString::fromLatin1(msg));
-#ifdef DUMPLOG
- dumplogmsg(msg);
-#endif
- } else if (msgs_saved) {
- /* restore strings */
- int i;
- for (i = 0; i < msgs_strings->size(); i++) {
- window->PutStr(ATR_NONE, msgs_strings->at((i)));
-#ifdef DUMPLOG
- dumplogmsg(msgs_strings->at(i).toLatin1().constData());
-#endif
- }
- delete msgs_strings;
- msgs_initd = false;
- }
-}
-
-bool NetHackQtBind::notify(QObject *receiver, QEvent *event)
-{
- // Ignore Alt-key navigation to menubar, it's annoying when you
- // use Alt-Direction to move around.
- if ( main && event->type()==QEvent::KeyRelease && main==receiver
- && ((QKeyEvent*)event)->key() == Qt::Key_Alt )
- return true;
-
- bool result=QApplication::notify(receiver,event);
- if (event->type()==QEvent::KeyPress) {
- QKeyEvent* key_event=(QKeyEvent*)event;
-
- if (!key_event->isAccepted()) {
- const int k=key_event->key();
- bool macro=false;
- for (int i=0; !macro && key_macro[i].key; i++) {
- if (key_macro[i].key==k
- && ((key_macro[i].state&key_event->modifiers())==key_macro[i].state))
- {
- keybuffer.Put(key_macro[i].macro);
- macro=true;
- }
- }
- QString key=key_event->text();
- QChar ch = !key.isEmpty() ? key.at(0) : 0;
- if (ch > 128) ch = 0;
- if ( ch == 0 && (key_event->modifiers() & Qt::ControlModifier) ) {
- // On Mac, ascii control codes are not sent, force them.
- if ( k>=Qt::Key_A && k<=Qt::Key_Z )
- ch = k - Qt::Key_A + 1;
- }
- if (!macro && ch != 0) {
- bool alt = (key_event->modifiers()&Qt::AltModifier) ||
- (k >= Qt::Key_0 && k <= Qt::Key_9 && (key_event->modifiers()&Qt::ControlModifier));
- keybuffer.Put(key_event->key(),ch.cell() + (alt ? 128 : 0),
- key_event->modifiers());
- key_event->accept();
- result=true;
- }
-
- if (ch != 0 || macro) {
- qApp->exit();
- }
- }
- }
- return result;
-}
-
-NetHackQtBind* NetHackQtBind::instance=0;
-NetHackQtKeyBuffer NetHackQtBind::keybuffer;
-NetHackQtClickBuffer NetHackQtBind::clickbuffer;
-NetHackQtMainWindow* NetHackQtBind::main=0;
-QFrame* NetHackQtBind::splash=0;
-QStringList *NetHackQtBind::msgs_strings;
-boolean NetHackQtBind::msgs_saved = false;
-boolean NetHackQtBind::msgs_initd = false;
-
-static void Qt_positionbar(char *) {}
-
-} // namespace nethack_qt4
-
-struct window_procs Qt_procs = {
- "Qt",
- WC_COLOR | WC_HILITE_PET
- | WC_ASCII_MAP | WC_TILED_MAP
- | WC_FONT_MAP | WC_TILE_FILE | WC_TILE_WIDTH | WC_TILE_HEIGHT
- | WC_PLAYER_SELECTION | WC_SPLASH_SCREEN,
- 0L,
- {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, /* color availability */
- nethack_qt4::NetHackQtBind::qt_init_nhwindows,
- nethack_qt4::NetHackQtBind::qt_player_selection,
- nethack_qt4::NetHackQtBind::qt_askname,
- nethack_qt4::NetHackQtBind::qt_get_nh_event,
- nethack_qt4::NetHackQtBind::qt_exit_nhwindows,
- nethack_qt4::NetHackQtBind::qt_suspend_nhwindows,
- nethack_qt4::NetHackQtBind::qt_resume_nhwindows,
- nethack_qt4::NetHackQtBind::qt_create_nhwindow,
- nethack_qt4::NetHackQtBind::qt_clear_nhwindow,
- nethack_qt4::NetHackQtBind::qt_display_nhwindow,
- nethack_qt4::NetHackQtBind::qt_destroy_nhwindow,
- nethack_qt4::NetHackQtBind::qt_curs,
- nethack_qt4::NetHackQtBind::qt_putstr,
- genl_putmixed,
- nethack_qt4::NetHackQtBind::qt_display_file,
- nethack_qt4::NetHackQtBind::qt_start_menu,
- nethack_qt4::NetHackQtBind::qt_add_menu,
- nethack_qt4::NetHackQtBind::qt_end_menu,
- nethack_qt4::NetHackQtBind::qt_select_menu,
- genl_message_menu, /* no need for X-specific handling */
- nethack_qt4::NetHackQtBind::qt_update_inventory,
- nethack_qt4::NetHackQtBind::qt_mark_synch,
- nethack_qt4::NetHackQtBind::qt_wait_synch,
-#ifdef CLIPPING
- nethack_qt4::NetHackQtBind::qt_cliparound,
-#endif
-#ifdef POSITIONBAR
- nethack_qt4::Qt_positionbar,
-#endif
- nethack_qt4::NetHackQtBind::qt_print_glyph,
- //NetHackQtBind::qt_print_glyph_compose,
- nethack_qt4::NetHackQtBind::qt_raw_print,
- nethack_qt4::NetHackQtBind::qt_raw_print_bold,
- nethack_qt4::NetHackQtBind::qt_nhgetch,
- nethack_qt4::NetHackQtBind::qt_nh_poskey,
- nethack_qt4::NetHackQtBind::qt_nhbell,
- nethack_qt4::NetHackQtBind::qt_doprev_message,
- nethack_qt4::NetHackQtBind::qt_yn_function,
- nethack_qt4::NetHackQtBind::qt_getlin,
- nethack_qt4::NetHackQtBind::qt_get_ext_cmd,
- nethack_qt4::NetHackQtBind::qt_number_pad,
- nethack_qt4::NetHackQtBind::qt_delay_output,
-#ifdef CHANGE_COLOR /* only a Mac option currently */
- donull,
- donull,
- donull,
- donull,
-#endif
- /* other defs that really should go away (they're tty specific) */
- nethack_qt4::NetHackQtBind::qt_start_screen,
- nethack_qt4::NetHackQtBind::qt_end_screen,
-#ifdef GRAPHIC_TOMBSTONE
- nethack_qt4::NetHackQtBind::qt_outrip,
-#else
- genl_outrip,
-#endif
- genl_preference_update,
-
- nethack_qt4::NetHackQtBind::qt_getmsghistory,
- nethack_qt4::NetHackQtBind::qt_putmsghistory,
- genl_status_init,
- genl_status_finish, genl_status_enablefield,
-#ifdef STATUS_HILITES
- genl_status_update,
-#else
- genl_status_update,
-#endif
- genl_can_suspend_yes,
-};
-
-#ifndef WIN32
-extern "C" void play_usersound(const char* filename, int volume)
-{
-#ifdef USER_SOUNDS
-#ifndef QT_NO_SOUND
- QSound::play(filename);
-#endif
-#endif
-}
-#endif
diff --git a/win/Qt4/qt4bind.h b/win/Qt4/qt4bind.h
deleted file mode 100644
index 820341cae..000000000
--- a/win/Qt4/qt4bind.h
+++ /dev/null
@@ -1,99 +0,0 @@
-// Copyright (c) Warwick Allison, 1999.
-// Qt4 conversion copyright (c) Ray Chason, 2012-2014.
-// NetHack may be freely redistributed. See license for details.
-
-// qt4bind.h -- bindings between the Qt 4 interface and the main code
-
-#ifndef QT4BIND_H
-#define QT4BIND_H
-
-#include "qt4main.h"
-
-namespace nethack_qt4 {
-
-class NetHackQtClickBuffer;
-
-#ifdef KDE
-#define NetHackQtBindBase KApplication
-#elif defined(QWS)
-#define NetHackQtBindBase QPEApplication
-#else
-#define NetHackQtBindBase QApplication
-#endif
-
-class NetHackQtBind : NetHackQtBindBase {
-private:
- // Single-instance preservation...
- NetHackQtBind(int& argc, char** argv);
-
- static NetHackQtBind* instance;
-
- static NetHackQtKeyBuffer keybuffer;
- static NetHackQtClickBuffer clickbuffer;
-
- static QFrame* splash;
- static NetHackQtMainWindow* main;
-
-public:
- static void qt_init_nhwindows(int* argc, char** argv);
- static void qt_player_selection();
- static void qt_askname();
- static void qt_get_nh_event();
- static void qt_exit_nhwindows(const char *);
- static void qt_suspend_nhwindows(const char *);
- static void qt_resume_nhwindows();
- static winid qt_create_nhwindow(int type);
- static void qt_clear_nhwindow(winid wid);
- static void qt_display_nhwindow(winid wid, BOOLEAN_P block);
- static void qt_destroy_nhwindow(winid wid);
- static void qt_curs(winid wid, int x, int y);
- static void qt_putstr(winid wid, int attr, const char *text);
- static void qt_putstr(winid wid, int attr, const std::string& text);
- static void qt_putstr(winid wid, int attr, const QString& text);
- static void qt_display_file(const char *filename, BOOLEAN_P must_exist);
- static void qt_start_menu(winid wid);
- static void qt_add_menu(winid wid, int glyph,
- const ANY_P * identifier, CHAR_P ch, CHAR_P gch, int attr,
- const char *str, BOOLEAN_P presel);
- static void qt_end_menu(winid wid, const char *prompt);
- static int qt_select_menu(winid wid, int how, MENU_ITEM_P **menu_list);
- static void qt_update_inventory();
- static void qt_mark_synch();
- static void qt_wait_synch();
-
- static void qt_cliparound(int x, int y);
- static void qt_cliparound_window(winid wid, int x, int y);
- static void qt_print_glyph(winid wid,XCHAR_P x,XCHAR_P y,int glyph,int bkglyph);
- static void qt_raw_print(const char *str);
- static void qt_raw_print_bold(const char *str);
- static int qt_nhgetch();
- static int qt_nh_poskey(int *x, int *y, int *mod);
- static void qt_nhbell();
- static int qt_doprev_message();
- static char qt_yn_function(const char *question, const char *choices, CHAR_P def);
- static void qt_getlin(const char *prompt, char *line);
- static int qt_get_ext_cmd();
- static void qt_number_pad(int);
- static void qt_delay_output();
- static void qt_start_screen();
- static void qt_end_screen();
-
- static char *qt_getmsghistory(BOOLEAN_P init);
- static void qt_putmsghistory(const char *msg, BOOLEAN_P is_restoring);
-
- static void qt_outrip(winid wid, int how, time_t when);
- static int qt_kbhit();
-
- static QWidget *mainWidget() { return main; }
-
-private:
- virtual bool notify(QObject *receiver, QEvent *event);
-
- static QStringList *msgs_strings;
- static boolean msgs_saved;
- static boolean msgs_initd;
-};
-
-} // namespace nethack_qt4
-
-#endif
diff --git a/win/Qt4/qt4clust.cpp b/win/Qt4/qt4clust.cpp
deleted file mode 100644
index 1cd080c11..000000000
--- a/win/Qt4/qt4clust.cpp
+++ /dev/null
@@ -1,167 +0,0 @@
-/* SCCS Id: @(#)qt_clust.cpp 3.4 1999/11/19 */
-/* Copyright (c) Warwick Allison, 1999. */
-/* NetHack may be freely redistributed. See license for details. */
-#include "qt4clust.h"
-
-static void include(QRect& r, const QRect& rect)
-{
- if (rect.left()r.right()) {
- r.setRight(rect.right());
- }
- if (rect.top()r.bottom()) {
- r.setBottom(rect.bottom());
- }
-}
-
-/*
-A Clusterizer groups rectangles (QRects) into non-overlapping rectangles
-by a merging heuristic.
-*/
-Clusterizer::Clusterizer(int maxclusters) :
- cluster(new QRect[maxclusters]),
- count(0),
- max(maxclusters)
-{ }
-
-Clusterizer::~Clusterizer()
-{
- delete [] cluster;
-}
-
-void Clusterizer::clear()
-{
- count=0;
-}
-
-void Clusterizer::add(int x, int y)
-{
- add(QRect(x,y,1,1));
-}
-
-void Clusterizer::add(int x, int y, int w, int h)
-{
- add(QRect(x,y,w,h));
-}
-
-void Clusterizer::add(const QRect& rect)
-{
- QRect biggerrect(rect.x()-1,rect.y()-1,rect.width()+2,rect.height()+2);
-
- //assert(rect.width()>0 && rect.height()>0);
-
- int cursor;
-
- for (cursor=0; cursor=0) {
- include(cluster[cheapest],rect);
- return;
- }
-
- if (count < max) {
- cluster[count++]=rect;
- return;
- }
-
- // Do cheapest of:
- // add to closest cluster
- // do cheapest cluster merge, add to new cluster
-
- lowestcost=9999999;
- cheapest=-1;
- for (cursor=0; cursor=0) {
- include(cluster[cheapestmerge1],cluster[cheapestmerge2]);
- cluster[cheapestmerge2]=cluster[count--];
- } else {
- // if (!cheapest) debugRectangles(rect);
- include(cluster[cheapest],rect);
- }
-
- // NB: clusters do not intersect (or intersection will
- // overwrite). This is a result of the above algorithm,
- // given the assumption that (x,y) are ordered topleft
- // to bottomright.
-}
-
-const QRect& Clusterizer::operator[](int i)
-{
- return cluster[i];
-}
diff --git a/win/Qt4/qt4glyph.cpp b/win/Qt4/qt4glyph.cpp
deleted file mode 100644
index 942f3a1ab..000000000
--- a/win/Qt4/qt4glyph.cpp
+++ /dev/null
@@ -1,141 +0,0 @@
-// Copyright (c) Warwick Allison, 1999.
-// Qt4 conversion copyright (c) Ray Chason, 2012-2014.
-// NetHack may be freely redistributed. See license for details.
-
-// qt4glyph.cpp -- class to manage the glyphs in a tile set
-
-extern "C" {
-#include "hack.h"
-}
-#include "tile2x11.h"
-#undef Invisible
-#undef Warning
-#undef index
-#undef msleep
-#undef rindex
-#undef wizard
-#undef yn
-#undef min
-#undef max
-
-#include
-#if QT_VERSION >= 0x050000
-#include
-#endif
-#include "qt4glyph.h"
-#include "qt4set.h"
-#include "qt4str.h"
-
-extern short glyph2tile[]; // from tile.c
-
-namespace nethack_qt4 {
-
-static int tilefile_tile_W=16;
-static int tilefile_tile_H=16;
-
-// Debian uses a separate PIXMAPDIR
-#ifndef PIXMAPDIR
-# ifdef HACKDIR
-# define PIXMAPDIR HACKDIR
-# else
-# define PIXMAPDIR "."
-# endif
-#endif
-
-NetHackQtGlyphs::NetHackQtGlyphs()
-{
- const char* tile_file = PIXMAPDIR "/nhtiles.bmp";
- if ( iflags.wc_tile_file )
- tile_file = iflags.wc_tile_file;
-
- if (!img.load(tile_file)) {
- tile_file = PIXMAPDIR "/x11tiles";
- if (!img.load(tile_file)) {
- QString msg;
- msg.sprintf("Cannot load x11tiles or nhtiles.bmp");
- QMessageBox::warning(0, "IO Error", msg);
- } else {
- tiles_per_row = TILES_PER_ROW;
- if (img.width()%tiles_per_row) {
- impossible("Tile file \"%s\" has %d columns, not multiple of row count (%d)",
- tile_file, img.width(), tiles_per_row);
- }
- }
- } else {
- tiles_per_row = 40;
- }
-
- if ( iflags.wc_tile_width )
- tilefile_tile_W = iflags.wc_tile_width;
- else
- tilefile_tile_W = img.width() / tiles_per_row;
- if ( iflags.wc_tile_height )
- tilefile_tile_H = iflags.wc_tile_height;
- else
- tilefile_tile_H = tilefile_tile_W;
-
- setSize(tilefile_tile_W, tilefile_tile_H);
-}
-
-void NetHackQtGlyphs::drawGlyph(QPainter& painter, int glyph, int x, int y)
-{
- int tile = glyph2tile[glyph];
- int px = (tile%tiles_per_row)*width();
- int py = tile/tiles_per_row*height();
-
- painter.drawPixmap(
- x,
- y,
- pm,
- px,py,
- width(),height()
- );
-}
-void NetHackQtGlyphs::drawCell(QPainter& painter, int glyph, int cellx, int celly)
-{
- drawGlyph(painter,glyph,cellx*width(),celly*height());
-}
-QPixmap NetHackQtGlyphs::glyph(int glyph)
-{
- int tile = glyph2tile[glyph];
- int px = (tile%tiles_per_row)*tilefile_tile_W;
- int py = tile/tiles_per_row*tilefile_tile_H;
-
- return QPixmap::fromImage(img.copy(px, py, tilefile_tile_W, tilefile_tile_H));
-}
-void NetHackQtGlyphs::setSize(int w, int h)
-{
- if ( size == QSize(w,h) )
- return;
-
- bool was1 = size == pm1.size();
- size = QSize(w,h);
- if (!w || !h)
- return; // Still not decided
-
- if ( size == pm1.size() ) {
- pm = pm1;
- return;
- }
- if ( size == pm2.size() ) {
- pm = pm2;
- return;
- }
-
- if (w==tilefile_tile_W && h==tilefile_tile_H) {
- pm.convertFromImage(img);
- } else {
- QApplication::setOverrideCursor( Qt::WaitCursor );
- QImage scaled = img.scaled(
- w*img.width()/tilefile_tile_W,
- h*img.height()/tilefile_tile_H,
- Qt::IgnoreAspectRatio,
- Qt::FastTransformation
- );
- pm.convertFromImage(scaled,Qt::ThresholdDither|Qt::PreferDither);
- QApplication::restoreOverrideCursor();
- }
- (was1 ? pm2 : pm1) = pm;
-}
-
-} // namespace nethack_qt4
diff --git a/win/Qt4/qt4glyph.h b/win/Qt4/qt4glyph.h
deleted file mode 100644
index 12fd915fd..000000000
--- a/win/Qt4/qt4glyph.h
+++ /dev/null
@@ -1,34 +0,0 @@
-// Copyright (c) Warwick Allison, 1999.
-// Qt4 conversion copyright (c) Ray Chason, 2012-2014.
-// NetHack may be freely redistributed. See license for details.
-
-// qt4glyph.h -- class to manage the glyphs in a tile set
-
-#ifndef QT4GLYPH_H
-#define QT4GLYPH_H
-
-namespace nethack_qt4 {
-
-class NetHackQtGlyphs {
-public:
- NetHackQtGlyphs();
-
- int width() const { return size.width(); }
- int height() const { return size.height(); }
- void toggleSize();
- void setSize(int w, int h);
-
- void drawGlyph(QPainter&, int glyph, int pixelx, int pixely);
- void drawCell(QPainter&, int glyph, int cellx, int celly);
- QPixmap glyph(int glyph);
-
-private:
- QImage img;
- QPixmap pm,pm1, pm2;
- QSize size;
- int tiles_per_row;
-};
-
-} // namespace nethack_qt4
-
-#endif
diff --git a/win/Qt4/qt4icon.cpp b/win/Qt4/qt4icon.cpp
deleted file mode 100644
index 0876cb59d..000000000
--- a/win/Qt4/qt4icon.cpp
+++ /dev/null
@@ -1,203 +0,0 @@
-// Copyright (c) Warwick Allison, 1999.
-// Qt4 conversion copyright (c) Ray Chason, 2012-2014.
-// NetHack may be freely redistributed. See license for details.
-
-// qt4icon.cpp -- a labelled icon
-
-#include "hack.h"
-#undef Invisible
-#undef Warning
-#undef index
-#undef msleep
-#undef rindex
-#undef wizard
-#undef yn
-#undef min
-#undef max
-
-#include
-#if QT_VERSION >= 0x050000
-#include
-#endif
-#include "qt4icon.h"
-
-namespace nethack_qt4 {
-
-NetHackQtLabelledIcon::NetHackQtLabelledIcon(QWidget* parent, const char* l) :
- QWidget(parent),
- low_is_good(false),
- prev_value(-123),
- turn_count(-1),
- label(new QLabel(l,this)),
- icon(0)
-{
- initHighlight();
-}
-
-NetHackQtLabelledIcon::NetHackQtLabelledIcon(QWidget* parent, const char* l, const QPixmap& i) :
- QWidget(parent),
- low_is_good(false),
- prev_value(-123),
- turn_count(-1),
- label(new QLabel(l,this)),
- icon(new QLabel(this))
-{
- setIcon(i);
- initHighlight();
-}
-
-void NetHackQtLabelledIcon::initHighlight()
-{
- hl_good = "QLabel { background-color : green; color : white }";
- hl_bad = "QLabel { background-color : red ; color : white }";
-}
-
-void NetHackQtLabelledIcon::setLabel(const QString& t, bool lower)
-{
- if (!label) {
- label=new QLabel(this);
- label->setFont(font());
- resizeEvent(0);
- }
- if (label->text() != t) {
- label->setText(t);
- highlight(lower==low_is_good ? hl_good : hl_bad);
- }
-}
-
-void NetHackQtLabelledIcon::setLabel(const QString& t, long v, long cv, const QString& tail)
-{
- QString buf;
- if (v==NoNum) {
- buf = "";
- } else {
- buf.sprintf("%ld", v);
- }
- setLabel(t + buf + tail, cv < prev_value);
- prev_value=cv;
-}
-
-void NetHackQtLabelledIcon::setLabel(const QString& t, long v, const QString& tail)
-{
- setLabel(t,v,v,tail);
-}
-
-void NetHackQtLabelledIcon::setIcon(const QPixmap& i)
-{
- if (icon) icon->setPixmap(i);
- else { icon=new QLabel(this); icon->setPixmap(i); resizeEvent(0); }
- icon->resize(i.width(),i.height());
-}
-
-void NetHackQtLabelledIcon::setFont(const QFont& f)
-{
- QWidget::setFont(f);
- if (label) label->setFont(f);
-}
-
-void NetHackQtLabelledIcon::show()
-{
-#if QT_VERSION >= 300
- if (isHidden())
-#else
- if (!isVisible())
-#endif
- highlight(hl_bad);
- QWidget::show();
-}
-
-QSize NetHackQtLabelledIcon::sizeHint() const
-{
- QSize iconsize, textsize;
-
- if (label && !icon) return label->sizeHint();
- if (icon && !label) return icon->sizeHint();
- if (!label && !icon) return QWidget::sizeHint();
-
- iconsize = icon->sizeHint();
- textsize = label->sizeHint();
- return QSize(
- std::max(iconsize.width(), textsize.width()),
- iconsize.height() + textsize.height());
-}
-
-QSize NetHackQtLabelledIcon::minimumSizeHint() const
-{
- QSize iconsize, textsize;
-
- if (label && !icon) return label->minimumSizeHint();
- if (icon && !label) return icon->minimumSizeHint();
- if (!label && !icon) return QWidget::minimumSizeHint();
-
- iconsize = icon->minimumSizeHint();
- textsize = label->minimumSizeHint();
- return QSize(
- std::max(iconsize.width(), textsize.width()),
- iconsize.height() + textsize.height());
-}
-
-void NetHackQtLabelledIcon::highlightWhenChanging()
-{
- turn_count=0;
-}
-
-void NetHackQtLabelledIcon::lowIsGood()
-{
- low_is_good=true;
-}
-
-void NetHackQtLabelledIcon::dissipateHighlight()
-{
- if (turn_count>0) {
- turn_count--;
- if (!turn_count)
- unhighlight();
- }
-}
-
-void NetHackQtLabelledIcon::highlight(const QString& hl)
-{
- if (label) { // Surely it is?!
- if (turn_count>=0) {
- label->setStyleSheet(hl);
- turn_count=4;
- // `4' includes this turn, so dissipates after
- // 3 more keypresses.
- } else {
- label->setStyleSheet("");
- }
- }
-}
-
-void NetHackQtLabelledIcon::unhighlight()
-{
- if (label) { // Surely it is?!
- label->setStyleSheet("");
- }
-}
-
-void NetHackQtLabelledIcon::resizeEvent(QResizeEvent*)
-{
- setAlignments();
-
- //int labw=label ? label->fontMetrics().width(label->text()) : 0;
- int labh=label ? label->fontMetrics().height() : 0;
- int icoh=icon ? icon->height() : 0;
- int h=icoh+labh;
- int icoy=(h>height() ? height()-labh-icoh : height()/2-h/2);
- int laby=icoy+icoh;
- if (icon) {
- icon->setGeometry(0,icoy,width(),icoh);
- }
- if (label) {
- label->setGeometry(0,laby,width(),labh);
- }
-}
-
-void NetHackQtLabelledIcon::setAlignments()
-{
- if (label) label->setAlignment(Qt::AlignHCenter|Qt::AlignVCenter);
- if (icon) icon->setAlignment(Qt::AlignHCenter|Qt::AlignVCenter);
-}
-
-} // namespace nethack_qt4
diff --git a/win/Qt4/qt4icon.h b/win/Qt4/qt4icon.h
deleted file mode 100644
index bdaf8183c..000000000
--- a/win/Qt4/qt4icon.h
+++ /dev/null
@@ -1,53 +0,0 @@
-// Copyright (c) Warwick Allison, 1999.
-// Qt4 conversion copyright (c) Ray Chason, 2012-2014.
-// NetHack may be freely redistributed. See license for details.
-
-// qt4icon.cpp -- a labelled icon
-
-#ifndef QT4ICON_H
-#define QT4ICON_H
-
-namespace nethack_qt4 {
-
-class NetHackQtLabelledIcon : public QWidget {
-public:
- NetHackQtLabelledIcon(QWidget* parent, const char* label);
- NetHackQtLabelledIcon(QWidget* parent, const char* label, const QPixmap& icon);
-
- enum { NoNum=-99999 };
- void setLabel(const QString&, bool lower=true); // a string
- void setLabel(const QString&, long, const QString& tail=""); // a number
- void setLabel(const QString&, long show_value, long comparative_value, const QString& tail="");
- void setIcon(const QPixmap&);
- virtual void setFont(const QFont&);
-
- void highlightWhenChanging();
- void lowIsGood();
- void dissipateHighlight();
-
- virtual void show();
- virtual QSize sizeHint() const;
- virtual QSize minimumSizeHint() const;
-
-protected:
- void resizeEvent(QResizeEvent*);
-
-private:
- void initHighlight();
- void setAlignments();
- void highlight(const QString& highlight);
- void unhighlight();
-
- bool low_is_good;
- int prev_value;
- int turn_count; /* last time the value changed */
- QString hl_good;
- QString hl_bad;
-
- QLabel* label;
- QLabel* icon;
-};
-
-} // namespace nethack_qt4
-
-#endif
diff --git a/win/Qt4/qt4inv.cpp b/win/Qt4/qt4inv.cpp
deleted file mode 100644
index 6d1a201b4..000000000
--- a/win/Qt4/qt4inv.cpp
+++ /dev/null
@@ -1,99 +0,0 @@
-// Copyright (c) Warwick Allison, 1999.
-// Qt4 conversion copyright (c) Ray Chason, 2012-2014.
-// NetHack may be freely redistributed. See license for details.
-
-// qt4inv.cpp -- inventory usage window
-// This is at the top center of the main window
-
-extern "C" {
-#include "hack.h"
-}
-#undef Invisible
-#undef Warning
-#undef index
-#undef msleep
-#undef rindex
-#undef wizard
-#undef yn
-#undef min
-#undef max
-
-#include
-#if QT_VERSION >= 0x050000
-#include
-#endif
-#include "qt4inv.h"
-#include "qt4glyph.h"
-#include "qt4set.h"
-
-namespace nethack_qt4 {
-
-NetHackQtInvUsageWindow::NetHackQtInvUsageWindow(QWidget* parent) :
- QWidget(parent)
-{
- setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
-}
-
-void NetHackQtInvUsageWindow::drawWorn(QPainter& painter, obj* nhobj, int x, int y, bool canbe)
-{
- short int glyph;
- if (nhobj)
- glyph=obj_to_glyph(nhobj, rn2_on_display_rng);
- else if (canbe)
- glyph=cmap_to_glyph(S_room);
- else
- glyph=cmap_to_glyph(S_stone);
-
- qt_settings->glyphs().drawCell(painter,glyph,x,y);
-}
-
-void NetHackQtInvUsageWindow::paintEvent(QPaintEvent*)
-{
- // 012
- //
- //0 WhB
- //1 s"w
- //2 gCg
- //3 =A=
- //4 T
- //5 S
-
- QPainter painter;
- painter.begin(this);
-
- // Blanks
- drawWorn(painter,0,0,4,false);
- drawWorn(painter,0,0,5,false);
- drawWorn(painter,0,2,4,false);
- drawWorn(painter,0,2,5,false);
-
- drawWorn(painter,uarm,1,3); // Armour
- drawWorn(painter,uarmc,1,2); // Cloak
- drawWorn(painter,uarmh,1,0); // Helmet
- drawWorn(painter,uarms,0,1); // Shield
- drawWorn(painter,uarmg,0,2); // Gloves - repeated
- drawWorn(painter,uarmg,2,2); // Gloves - repeated
- drawWorn(painter,uarmf,1,5); // Shoes (feet)
- drawWorn(painter,uarmu,1,4); // Undershirt
- drawWorn(painter,uleft,0,3); // RingL
- drawWorn(painter,uright,2,3); // RingR
-
- drawWorn(painter,uwep,2,1); // Weapon
- drawWorn(painter,uswapwep,0,0); // Secondary weapon
- drawWorn(painter,uamul,1,1); // Amulet
- drawWorn(painter,ublindf,2,0); // Blindfold
-
- painter.end();
-}
-
-QSize NetHackQtInvUsageWindow::sizeHint(void) const
-{
- if (qt_settings) {
- return QSize(qt_settings->glyphs().width()*3,
- qt_settings->glyphs().height()*6);
- } else {
- return QWidget::sizeHint();
- }
-}
-
-} // namespace nethack_qt4
diff --git a/win/Qt4/qt4inv.h b/win/Qt4/qt4inv.h
deleted file mode 100644
index 51cdd4d0b..000000000
--- a/win/Qt4/qt4inv.h
+++ /dev/null
@@ -1,25 +0,0 @@
-// Copyright (c) Warwick Allison, 1999.
-// Qt4 conversion copyright (c) Ray Chason, 2012-2014.
-// NetHack may be freely redistributed. See license for details.
-
-// qt4inv.h -- inventory usage window
-// This is at the top center of the main window
-
-#ifndef QT4INV_H
-#define QT4INV_H
-
-namespace nethack_qt4 {
-
-class NetHackQtInvUsageWindow : public QWidget {
-public:
- NetHackQtInvUsageWindow(QWidget* parent);
- virtual void paintEvent(QPaintEvent*);
- virtual QSize sizeHint(void) const;
-
-private:
- void drawWorn(QPainter& painter, obj*, int x, int y, bool canbe=true);
-};
-
-} // namespace nethack_qt4
-
-#endif
diff --git a/win/Qt4/qt4key.cpp b/win/Qt4/qt4key.cpp
deleted file mode 100644
index ff16616fe..000000000
--- a/win/Qt4/qt4key.cpp
+++ /dev/null
@@ -1,91 +0,0 @@
-// Copyright (c) Warwick Allison, 1999.
-// Qt4 conversion copyright (c) Ray Chason, 2012-2014.
-// NetHack may be freely redistributed. See license for details.
-
-// qt4key.cpp -- a key buffer
-
-#include "hack.h"
-#undef Invisible
-#undef Warning
-#undef index
-#undef msleep
-#undef rindex
-#undef wizard
-#undef yn
-#undef min
-#undef max
-
-#include
-#include "qt4key.h"
-
-namespace nethack_qt4 {
-
-NetHackQtKeyBuffer::NetHackQtKeyBuffer() :
- in(0), out(0)
-{
-}
-
-bool NetHackQtKeyBuffer::Empty() const { return in==out; }
-bool NetHackQtKeyBuffer::Full() const { return (in+1)%maxkey==out; }
-
-void NetHackQtKeyBuffer::Put(int k, int a, int state)
-{
- if ( Full() ) return; // Safety
- key[in]=k;
- ascii[in]=a;
- in=(in+1)%maxkey;
-}
-
-void NetHackQtKeyBuffer::Put(char a)
-{
- Put(0,a,0);
-}
-
-void NetHackQtKeyBuffer::Put(const char* str)
-{
- while (*str) Put(*str++);
-}
-
-int NetHackQtKeyBuffer::GetKey()
-{
- if ( Empty() ) return 0;
- int r=TopKey();
- out=(out+1)%maxkey;
- return r;
-}
-
-int NetHackQtKeyBuffer::GetAscii()
-{
- if ( Empty() ) return 0; // Safety
- int r=TopAscii();
- out=(out+1)%maxkey;
- return r;
-}
-
-Qt::KeyboardModifiers NetHackQtKeyBuffer::GetState()
-{
- if ( Empty() ) return 0;
- Qt::KeyboardModifiers r=TopState();
- out=(out+1)%maxkey;
- return r;
-}
-
-int NetHackQtKeyBuffer::TopKey() const
-{
- if ( Empty() ) return 0;
- return key[out];
-}
-
-int NetHackQtKeyBuffer::TopAscii() const
-{
- if ( Empty() ) return 0;
- return ascii[out];
-}
-
-Qt::KeyboardModifiers NetHackQtKeyBuffer::TopState() const
-{
- if ( Empty() ) return 0;
- return state[out];
-}
-
-} // namespace nethack_qt4
diff --git a/win/Qt4/qt4main.cpp b/win/Qt4/qt4main.cpp
deleted file mode 100644
index 0a28399bb..000000000
--- a/win/Qt4/qt4main.cpp
+++ /dev/null
@@ -1,1076 +0,0 @@
-// Copyright (c) Warwick Allison, 1999.
-// Qt4 conversion copyright (c) Ray Chason, 2012-2014.
-// NetHack may be freely redistributed. See license for details.
-
-// qt4main.cpp -- the main window
-
-extern "C" {
-#include "hack.h"
-}
-#include "patchlevel.h"
-#undef Invisible
-#undef Warning
-#undef index
-#undef msleep
-#undef rindex
-#undef wizard
-#undef yn
-#undef min
-#undef max
-
-#include
-#if QT_VERSION >= 0x050000
-#include
-#endif
-#include "qt4main.h"
-#include "qt4main.moc"
-#include "qt4bind.h"
-#include "qt4glyph.h"
-#include "qt4inv.h"
-#include "qt4key.h"
-#include "qt4map.h"
-#include "qt4msg.h"
-#include "qt4set.h"
-#include "qt4stat.h"
-#include "qt4str.h"
-
-#ifndef KDE
-#include "qt4kde0.moc"
-#endif
-
-// temporary
-extern char *qt_tilewidth;
-extern char *qt_tileheight;
-extern int qt_compact_mode;
-// end temporary
-
-namespace nethack_qt4 {
-
-// 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 * get_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 * rest_xpm[] = {
-"12 13 2 1",
-" c None",
-". c #000000000000",
-" ..... ",
-" . ",
-" . ",
-" . ....",
-" ..... . ",
-" . ",
-" ....",
-" ",
-" .... ",
-" . ",
-" . ",
-" .... ",
-" "};
-/* XPM */
-static const char * cast_a_xpm[] = {
-"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[] = {
-"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[] = {
-"12 13 3 1",
-" c None",
-". c #FFFF6DB60000",
-"X c #000000000000",
-" . ",
-" . ",
-" .. ",
-" .. ",
-" .. . ",
-" .. . ",
-" ...... ",
-" .. .. XX ",
-" .. X X ",
-" .. X ",
-" .. X ",
-" . X X ",
-" . XX "};
-
-static QString
-aboutMsg()
-{
- QString msg;
- msg.sprintf(
- "Qt NetHack is a version of NetHack built\n"
-#ifdef KDE
- "using KDE and the Qt GUI toolkit.\n"
-#else
- "using the Qt GUI toolkit.\n"
-#endif
- "This is version %d.%d.%d\n\n"
- "Homepage:\n http://trolls.troll.no/warwick/nethack/\n\n"
-#ifdef KDE
- "KDE:\n http://www.kde.org\n"
-#endif
- "Qt:\n http://www.troll.no",
- VERSION_MAJOR,
- VERSION_MINOR,
- PATCHLEVEL);
- 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();
-
- QCoreApplication::setOrganizationName("The NetHack DevTeam");
- QCoreApplication::setOrganizationDomain("nethack.org");
- QCoreApplication::setApplicationName("NetHack");
-
- setWindowTitle("Qt NetHack");
- if ( qt_compact_mode )
- setWindowIcon(QIcon(QPixmap(nh_icon_small)));
- else
- setWindowIcon(QIcon(QPixmap(nh_icon)));
-
- 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;
- int NDECL((*funct));
- } item[] = {
- { game, 0, 3},
- { game, "Version", 3, doversion},
- { game, "Compilation", 3, doextversion},
- { game, "History", 3, dohistory},
- { game, "Redraw", 0, doredraw}, // useless
- { game, "Options", 3, doset},
- { game, "Explore mode", 3, enter_explore_mode},
- { game, 0, 3},
- { game, "Save", 3, dosave},
- { game, "Quit", 3, done2},
-
- { apparel, "Apparel off", 2, doddoremarm},
- { apparel, "Remove many", 1, doddoremarm},
- { apparel, 0, 3},
- { apparel, "Wield weapon", 3, dowield},
- { apparel, "Exchange weapons", 3, doswapweapon},
- { apparel, "Two weapon combat", 3, dotwoweapon},
- { apparel, "Load quiver", 3, dowieldquiver},
- { apparel, 0, 3},
- { apparel, "Wear armour", 3, dowear},
- { apparel, "Take off armour", 3, dotakeoff},
- { apparel, 0, 3},
- { apparel, "Put on non-armour", 3, doputon},
- { apparel, "Remove non-armour", 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, "Get", 2, dopickup},
- { act1, "Jump", 3, dojump},
- { act2, "Kick", 2, dokick},
- { act2, "Loot", 3, doloot},
- { act2, "Open door", 3, doopen},
- { act2, "Pay", 3, dopay},
- { 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},
- { magic, "Offer", 3, dosacrifice},
- { magic, "Pray", 3, dopray},
- { magic, 0, 3},
- { magic, "Teleport", 3, dotelecmd},
- { magic, "Monster action", 3, domonability},
- { magic, "Turn undead", 3, doturn},
-
- { help, "Help", 3, dohelp},
- { help, 0, 3},
- { help, "What is here", 3, dolook},
- { help, "What is there", 3, doquickwhatis},
- { help, "What is...", 2, dowhatis},
- { help, 0, 1},
-
- { info, "Inventory", 3, ddoinv},
- { info, "Conduct", 3, doconduct},
- { info, "Discoveries", 3, dodiscovered},
- { info, "List/reorder spells", 3, dovspell},
- { info, "Adjust letters", 2, doorganize},
- { info, 0, 3},
- { info, "Name object or creature", 3, docallcmd},
- { info, 0, 3},
- { info, "Skills", 3, enhance_weapon_skill},
-
- { 0, 0, 0 }
- };
-
- int i;
-
- game->addAction("Qt settings...",this,SLOT(doQtSettings(bool)));
- help->addAction("About Qt NetHack...",this,SLOT(doAbout(bool)));
- //help->addAction("NetHack Guidebook...",this,SLOT(doGuidebook(bool)));
- help->addSeparator();
-
- for (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] = '\0';
- if (item[i].funct) {
- actchar[0] = cmd_from_func(item[i].funct);
- actchar[1] = '\0';
- }
- if (actchar[0] && !qt_compact_mode)
- Sprintf(menuitem, "%s\t%s", item[i].name,
- visctrl(actchar[0]));
- else
- Sprintf(menuitem, "%s", item[i].name);
- if (actchar[0]) {
- QString name = menuitem;
- QAction *action = item[i].menu->addAction(name);
- action->setData(actchar);
- }
- } 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();
- help->setTitle("Help");
- menubar->addMenu(help);
- }
-
- QSignalMapper* sm = new QSignalMapper(this);
- connect(sm, SIGNAL(mapped(const QString&)), this, SLOT(doKeys(const QString&)));
- QToolButton* tb;
- char actchar[32];
- tb = new SmallToolButton( QPixmap(again_xpm),"Again","Action", sm, SLOT(map()), toolbar );
- Sprintf(actchar, "%c", Cmd.spkeys[NHKF_DOAGAIN]);
- sm->setMapping(tb, actchar );
- toolbar->addWidget(tb);
- tb = new SmallToolButton( QPixmap(get_xpm),"Get","Action", sm, SLOT(map()), toolbar );
- Sprintf(actchar, "%c", cmd_from_func(dopickup));
- sm->setMapping(tb, actchar );
- toolbar->addWidget(tb);
- tb = new SmallToolButton( QPixmap(kick_xpm),"Kick","Action", sm, SLOT(map()), toolbar );
- Sprintf(actchar, "%c", cmd_from_func(dokick));
- sm->setMapping(tb, actchar );
- toolbar->addWidget(tb);
- tb = new SmallToolButton( QPixmap(throw_xpm),"Throw","Action", sm, SLOT(map()), toolbar );
- Sprintf(actchar, "%c", cmd_from_func(dothrow));
- sm->setMapping(tb, actchar );
- toolbar->addWidget(tb);
- tb = new SmallToolButton( QPixmap(fire_xpm),"Fire","Action", sm, SLOT(map()), toolbar );
- Sprintf(actchar, "%c", cmd_from_func(dofire));
- sm->setMapping(tb, actchar );
- toolbar->addWidget(tb);
- tb = new SmallToolButton( QPixmap(drop_xpm),"Drop","Action", sm, SLOT(map()), toolbar );
- Sprintf(actchar, "%c", cmd_from_func(doddrop));
- sm->setMapping(tb, actchar );
- toolbar->addWidget(tb);
- tb = new SmallToolButton( QPixmap(eat_xpm),"Eat","Action", sm, SLOT(map()), toolbar );
- Sprintf(actchar, "%c", cmd_from_func(doeat));
- sm->setMapping(tb, actchar );
- toolbar->addWidget(tb);
- tb = new SmallToolButton( QPixmap(rest_xpm),"Rest","Action", sm, SLOT(map()), toolbar );
- Sprintf(actchar, "%c", cmd_from_func(donull));
- sm->setMapping(tb, actchar );
- toolbar->addWidget(tb);
-
- 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
-
- int x=0,y=0;
- int w=QApplication::desktop()->width()-10; // XXX arbitrary extra space for frame
- int h=QApplication::desktop()->height()-50;
-
- int maxwn;
- int maxhn;
- if (qt_tilewidth != NULL) {
- maxwn = atoi(qt_tilewidth) * COLNO + 10;
- } else {
- maxwn = 1400;
- }
- if (qt_tileheight != NULL) {
- maxhn = atoi(qt_tileheight) * ROWNO * 6/4;
- } else {
- maxhn = 1024;
- }
-
- // 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);
- }
-}
-
-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
-
-void NetHackQtMainWindow::doMenuItem(QAction *action)
-{
- doKeys(action->data().toString());
-}
-
-void NetHackQtMainWindow::doQtSettings(bool)
-{
- centerOnMain(qt_settings);
- qt_settings->show();
-}
-
-void NetHackQtMainWindow::doAbout(bool)
-{
- QMessageBox::about(this, "About Qt NetHack", aboutMsg());
-}
-
-#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 QString& k)
-{
- keysink.Put(k.toLatin1().constData());
- qApp->exit();
-}
-
-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()
-{
- if (status) {
- status->fadeHighlighting();
- }
-}
-
-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
-}
-
-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 = 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();
- return;
- }
- case Qt::Key_Enter:
- if ( map )
- map->clickCursor();
- break; default:
- dirkey = 0;
- event->ignore();
- }
-}
-
-void NetHackQtMainWindow::closeEvent(QCloseEvent* e)
-{
- if ( program_state.something_worth_saving ) {
- switch ( QMessageBox::information( this, "NetHack",
- "This will end your NetHack session",
- "&Save", "&Cancel", 0, 1 ) )
- {
- case 0:
- // See dosave() function
- if (dosave0()) {
- u.uhp = -1;
- NetHackQtBind::qt_exit_nhwindows(0);
- nh_terminate(EXIT_SUCCESS);
- }
- break;
- case 1:
- break; // ignore the event
- }
- } else {
- e->accept();
- }
-}
-
-void NetHackQtMainWindow::ShowIfReady()
-{
- if (message && map && status) {
- QWidget* hp = qt_compact_mode ? static_cast(stack) : static_cast(hsplitter);
- QWidget* vp = qt_compact_mode ? static_cast(stack) : static_cast(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_qt4
diff --git a/win/Qt4/qt4map.cpp b/win/Qt4/qt4map.cpp
deleted file mode 100644
index 00598e79b..000000000
--- a/win/Qt4/qt4map.cpp
+++ /dev/null
@@ -1,974 +0,0 @@
-// Copyright (c) Warwick Allison, 1999.
-// Qt4 conversion copyright (c) Ray Chason, 2012-2014.
-// NetHack may be freely redistributed. See license for details.
-
-// qt4map.cpp -- the map window
-
-extern "C" {
-#include "hack.h"
-}
-#undef Invisible
-#undef Warning
-#undef index
-#undef msleep
-#undef rindex
-#undef wizard
-#undef yn
-#undef min
-#undef max
-
-#include
-#if QT_VERSION >= 0x050000
-#include
-#endif
-#include "qt4map.h"
-#include "qt4map.moc"
-#include "qt4click.h"
-#include "qt4glyph.h"
-#include "qt_xpms.h"
-#include "qt4set.h"
-#include "qt4str.h"
-
-// temporary
-extern int qt_compact_mode;
-// end temporary
-
-namespace nethack_qt4 {
-
-#ifdef TEXTCOLOR
-static const QPen& nhcolor_to_pen(int c)
-{
- static QPen* pen=0;
- if ( !pen ) {
- pen = new QPen[17];
- pen[0] = QColor(64,64,64);
- pen[1] = QColor(Qt::red);
- pen[2] = QColor(0,191,0);
- pen[3] = QColor(127,127,0);
- pen[4] = QColor(Qt::blue);
- pen[5] = QColor(Qt::magenta);
- pen[6] = QColor(Qt::cyan);
- pen[7] = QColor(Qt::gray);
- pen[8] = QColor(Qt::white); // no color
- pen[9] = QColor(255,127,0);
- pen[10] = QColor(127,255,127);
- pen[11] = QColor(Qt::yellow);
- pen[12] = QColor(127,127,255);
- pen[13] = QColor(255,127,255);
- pen[14] = QColor(127,255,255);
- pen[15] = QColor(Qt::white);
- pen[16] = QColor(Qt::black);
- }
-
- return pen[c];
-}
-#endif
-
-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();
- cursor.setX(0);
- cursor.setY(0);
-}
-
-NetHackQtMapViewport::~NetHackQtMapViewport(void)
-{
- delete rogue_font;
-}
-
-void NetHackQtMapViewport::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 : "Monospace";
- 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);
- int color;
- int ch;
- unsigned special;
-
- painter.setPen( Qt::green );
- /* map glyph to character and color */
- mapglyph(g, &ch, &color, &special, i, j, 0);
- ch = cp437(ch);
-#ifdef TEXTCOLOR
- painter.setPen( nhcolor_to_pen(color) );
-#endif
- if (!DrawWalls(
- painter,
- i*qt_settings->glyphs().width(),
- j*qt_settings->glyphs().height(),
- qt_settings->glyphs().width(),
- qt_settings->glyphs().height(),
- ch)) {
- 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)
- );
- }
-#ifdef TEXTCOLOR
- 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);
- }
-#endif
- }
- }
-
- 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);
- int color;
- int ch;
- unsigned special;
- mapglyph(g, &ch, &color, &special, i, j, 0);
- qt_settings->glyphs().drawCell(painter, g, i, j);
-#ifdef TEXTCOLOR
- 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);
- }
-#endif
- }
- }
- }
-
- if (garea.contains(cursor)) {
- if (Is_rogue_level(&u.uz)) {
-#ifdef TEXTCOLOR
- painter.setPen( Qt::white );
-#else
- painter.setPen( Qt::green ); // REALLY primitive
-#endif
- } else
- {
- int hp100;
- if (u.mtimedone) {
- 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 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 ch)
-{
- enum
- {
- 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();
-}
-
-void NetHackQtMapViewport::Clear()
-{
- unsigned short stone=cmap_to_glyph(S_stone);
-
- for (int j=0; jglyphs().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 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,int glyph)
-{
- Glyph(x,y)=glyph;
- 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, const QString& text)
-{
- if ( !messages.isEmpty() )
- messages += "\n";
- messages += QString(text).replace(QChar(0x200B), "");
- QFontMetrics fm = fontMetrics();
-#if 0
- 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, const QString& text)
-{
- 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,int glyph)
-{
- m_viewport->PrintGlyph(x, y, glyph);
-}
-
-#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()
-{
- unsigned short stone=cmap_to_glyph(S_stone);
-
- for (int j=0; jexit();
-}
-
-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);
- int color;
- char32_t ch;
- unsigned special;
-
- painter.setPen( Qt::green );
- /* map glyph to character and color */
- mapglyph(g, &ch, &color, &special, i, j, 0);
-#ifdef TEXTCOLOR
- painter.setPen( nhcolor_to_pen(color) );
-#endif
- 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)
- );
-#ifdef TEXTCOLOR
- 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);
- }
-#endif
- }
- }
-
- 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);
- int color;
- int ch;
- unsigned special;
- mapglyph(g, &ch, &color, &special, i, j, 0);
- qt_settings->glyphs().drawCell(painter, g, i, j);
-#ifdef TEXTCOLOR
- 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);
- }
-#endif
- }
- }
- }
-
- if (garea.contains(cursor)) {
- if (Is_rogue_level(&u.uz)) {
-#ifdef TEXTCOLOR
- painter.setPen( Qt::white );
-#else
- painter.setPen( Qt::green ); // REALLY primitive
-#endif
- } else
- {
- int hp100;
- if (u.mtimedone) {
- 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; iglyphs().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,int glyph)
-{
- Glyph(x,y)=glyph;
- 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
-
-} // namespace nethack_qt4
diff --git a/win/Qt4/qt4map.h b/win/Qt4/qt4map.h
deleted file mode 100644
index 337a726aa..000000000
--- a/win/Qt4/qt4map.h
+++ /dev/null
@@ -1,82 +0,0 @@
-// Copyright (c) Warwick Allison, 1999.
-// Qt4 conversion copyright (c) Ray Chason, 2012-2014.
-// NetHack may be freely redistributed. See license for details.
-
-// qt4map.h -- the map window
-
-#ifndef QT4MAP_H
-#define QT4MAP_H
-
-#include "qt4win.h"
-#include "qt4clust.h"
-
-namespace nethack_qt4 {
-
-class NetHackQtClickBuffer;
-
-class NetHackQtMapViewport : public QWidget {
- Q_OBJECT
-public:
- NetHackQtMapViewport(NetHackQtClickBuffer& click_sink);
- ~NetHackQtMapViewport(void);
-
-protected:
- virtual void paintEvent(QPaintEvent* event);
- bool DrawWalls(QPainter& painter, int x, int y, int w, int h, unsigned ch);
- virtual QSize sizeHint() const;
- virtual QSize minimumSizeHint() const;
- virtual void mousePressEvent(QMouseEvent* event);
-
-private:
- QFont *rogue_font;
- unsigned short glyph[ROWNO][COLNO];
- unsigned short& Glyph(int x, int y) { return glyph[y][x]; }
- QPoint cursor;
- QPixmap pet_annotation;
- QPixmap pile_annotation;
- NetHackQtClickBuffer& clicksink;
- Clusterizer change;
-
- void clickCursor();
- void Clear();
- void Display(bool block);
- void CursorTo(int x,int y);
- void PrintGlyph(int x,int y,int glyph);
- void Changed(int x, int y);
- void updateTiles();
-
- // NetHackQtMapWindow2 passes through many calls to the viewport
- friend class NetHackQtMapWindow2;
-};
-
-class NetHackQtMapWindow2 : public QScrollArea, public NetHackQtWindow {
- Q_OBJECT
-public:
- NetHackQtMapWindow2(NetHackQtClickBuffer& click_sink);
- void clearMessages();
- void putMessage(int attr, const QString& text);
- void clickCursor();
- virtual QWidget *Widget();
-
- virtual void Clear();
- virtual void Display(bool block);
- virtual void CursorTo(int x,int y);
- virtual void PutStr(int attr, const QString& text);
- virtual void ClipAround(int x,int y);
- virtual void PrintGlyph(int x,int y,int glyph);
-
-signals:
- void resized();
-
-private slots:
- void updateTiles();
-
-private:
- NetHackQtMapViewport *m_viewport;
- QRect messages_rect;
- QString messages;
-};
-
-} // namespace nethack_qt4
-
-#endif
diff --git a/win/Qt4/qt4menu.cpp b/win/Qt4/qt4menu.cpp
deleted file mode 100644
index 5ab053891..000000000
--- a/win/Qt4/qt4menu.cpp
+++ /dev/null
@@ -1,830 +0,0 @@
-// Copyright (c) Warwick Allison, 1999.
-// Qt4 conversion copyright (c) Ray Chason, 2012-2014.
-// NetHack may be freely redistributed. See license for details.
-
-// qt4menu.cpp -- a menu or text-list widget
-
-extern "C" {
-#include "hack.h"
-}
-#undef Invisible
-#undef Warning
-#undef index
-#undef msleep
-#undef rindex
-#undef wizard
-#undef yn
-#undef min
-#undef max
-
-#include
-#if QT_VERSION >= 0x050000
-#include
-#endif
-#include "qt4menu.h"
-#include "qt4menu.moc"
-#include "qt4glyph.h"
-#include "qt4set.h"
-#include "qt4streq.h"
-#include "qt4str.h"
-
-// temporary
-extern "C" int qt_compact_mode;
-// end temporary
-
-extern "C" struct menucoloring *menu_colorings;
-
-namespace nethack_qt4 {
-
-// temporary
-void centerOnMain( QWidget* w );
-// end temporary
-
-QSize NetHackQtTextListBox::sizeHint() const
-{
- QScrollBar *hscroll = horizontalScrollBar();
- int hsize = hscroll ? hscroll->height() : 0;
- return QSize(TotalWidth()+hsize, TotalHeight()+hsize);
-}
-
-int NetHackQtMenuListBox::TotalWidth() const
-{
- int width = 0;
-
- for (int col = 0; col < columnCount(); ++col) {
- width += columnWidth(col);
- }
- return width;
-}
-
-int NetHackQtMenuListBox::TotalHeight() const
-{
- int height = 0;
-
- for (int row = 0; row < rowCount(); ++row) {
- height += rowHeight(row);
- }
- return height;
-}
-
-QSize NetHackQtMenuListBox::sizeHint() const
-{
- QScrollBar *hscroll = horizontalScrollBar();
- int hsize = hscroll ? hscroll->height() : 0;
- return QSize(TotalWidth()+hsize, TotalHeight()+hsize);
-}
-
-// Table view columns:
-//
-// [pick-count] [accel] [glyph] [string]
-//
-// Maybe accel should be near string. We'll see.
-// pick-count normally blank.
-// double-clicking or click-on-count gives pop-up entry
-// string is green when selected
-//
-NetHackQtMenuWindow::NetHackQtMenuWindow(QWidget *parent) :
- QDialog(parent),
- table(new NetHackQtMenuListBox()),
- prompt(0),
- counting(false)
-{
- QGridLayout *grid = new QGridLayout();
- table->setColumnCount(5);
- table->setFrameStyle(QFrame::Panel|QFrame::Sunken);
- table->setLineWidth(2);
- table->setShowGrid(false);
- table->horizontalHeader()->hide();
- table->verticalHeader()->hide();
-
- ok=new QPushButton("Ok");
- connect(ok,SIGNAL(clicked()),this,SLOT(accept()));
-
- cancel=new QPushButton("Cancel");
- connect(cancel,SIGNAL(clicked()),this,SLOT(reject()));
-
- all=new QPushButton("All");
- connect(all,SIGNAL(clicked()),this,SLOT(All()));
-
- none=new QPushButton("None");
- connect(none,SIGNAL(clicked()),this,SLOT(ChooseNone()));
-
- invert=new QPushButton("Invert");
- connect(invert,SIGNAL(clicked()),this,SLOT(Invert()));
-
- search=new QPushButton("Search");
- connect(search,SIGNAL(clicked()),this,SLOT(Search()));
-
- QPoint pos(0,ok->height());
- move(pos);
- prompt.setParent(this,0);
- prompt.move(pos);
-
- grid->addWidget(ok, 0, 0);
- grid->addWidget(cancel, 0, 1);
- grid->addWidget(all, 0, 2);
- grid->addWidget(none, 0, 3);
- grid->addWidget(invert, 0, 4);
- grid->addWidget(search, 0, 5);
- grid->addWidget(&prompt, 1, 0, 1, 7);
- grid->addWidget(table, 2, 0, 1, 7);
- grid->setColumnStretch(6, 1);
- grid->setRowStretch(2, 1);
- setFocusPolicy(Qt::StrongFocus);
- table->setFocusPolicy(Qt::NoFocus);
- connect(table, SIGNAL(cellClicked(int,int)), this, SLOT(cellToggleSelect(int,int)));
-
- setLayout(grid);
-}
-
-NetHackQtMenuWindow::~NetHackQtMenuWindow()
-{
-}
-
-QWidget* NetHackQtMenuWindow::Widget() { return this; }
-
-void NetHackQtMenuWindow::StartMenu()
-{
- table->setRowCount((itemcount=0));
- next_accel=0;
- has_glyphs=false;
-}
-
-NetHackQtMenuWindow::MenuItem::MenuItem() :
- str("")
-{
-}
-
-NetHackQtMenuWindow::MenuItem::~MenuItem()
-{
-}
-
-void NetHackQtMenuWindow::AddMenu(int glyph, const ANY_P* identifier,
- char ch, char gch, int attr, const QString& str, bool presel)
-{
- if (!ch && identifier->a_void!=0) {
- // Supply a keyboard accelerator. Limited supply.
- static char accel[]="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
- if (accel[next_accel]) {
- ch=accel[next_accel++];
- }
- }
-
- if ((int)itemlist.size() < itemcount+1) {
- itemlist.resize(itemcount*4+10);
- }
- itemlist[itemcount].glyph=glyph;
- itemlist[itemcount].identifier=*identifier;
- itemlist[itemcount].ch=ch;
- itemlist[itemcount].gch=gch;
- itemlist[itemcount].attr=attr;
- itemlist[itemcount].str=str;
- itemlist[itemcount].selected=presel;
- itemlist[itemcount].count=-1;
- itemlist[itemcount].color = -1;
- // Display the boulder symbol correctly
- if (str.left(8) == "boulder\t") {
- int bracket = str.indexOf('[');
- if (bracket != -1) {
- itemlist[itemcount].str = str.left(bracket+1)
- + QChar(cp437(str.at(bracket+1).unicode()))
- + str.mid(bracket+2);
- }
- }
- int mcolor, mattr;
- if (attr == 0
- && get_menu_coloring(str.toLatin1().constData(), &mcolor, &mattr)) {
- itemlist[itemcount].attr = mattr;
- itemlist[itemcount].color = mcolor;
- }
- ++itemcount;
-
- if (glyph!=NO_GLYPH) has_glyphs=true;
-}
-
-void NetHackQtMenuWindow::EndMenu(const QString& p)
-{
- prompt.setText(p);
- promptstr = p;
-}
-
-int NetHackQtMenuWindow::SelectMenu(int h, MENU_ITEM_P **menu_list)
-{
- QFont tablefont(qt_settings->normalFont());
- table->setFont(tablefont);
-
- table->setRowCount(itemcount);
-
- how=h;
-
- ok->setEnabled(how!=PICK_ONE);ok->setDefault(how!=PICK_ONE);
- cancel->setEnabled(how!=PICK_NONE);
- all->setEnabled(how==PICK_ANY);
- none->setEnabled(how==PICK_ANY);
- invert->setEnabled(how==PICK_ANY);
- search->setEnabled(how!=PICK_NONE);
-
- setResult(-1);
-
- // Set contents of table
- QFontMetrics fm(table->font());
- for (int i = 0; i < 5; i++) {
- table->setColumnWidth(i, 0);
- }
- for (int i = 0; i < itemcount; i++) {
- AddRow(i, itemlist[i]);
- }
-
- // Determine column widths
- std::vector col_widths;
- for (std::size_t i = 0; i < itemlist.size(); ++i) {
- QStringList columns = itemlist[i].str.split("\t");
- if (!itemlist[i].Selectable() && columns.size() == 1)
- {
- // Nonselectable line with no column dividers
- // Assume this is a section header
- continue;
- }
- for (std::size_t j = 0U; j < columns.size(); ++j) {
- int w = fm.width(columns[j] + " \t");
- if (j >= col_widths.size()) {
- col_widths.push_back(w);
- } else if (col_widths[j] < w) {
- col_widths[j] = w;
- }
- }
- }
-
- // Pad each column to its column width
- for (std::size_t i = 0U; i < itemlist.size(); ++i) {
- QTableWidgetItem *twi = table->item(i, 4);
- if (twi == NULL) { continue; }
- QString text = twi->text();
- QStringList columns = text.split("\t");
- for (std::size_t j = 0U; j+1U < columns.size(); ++j) {
- columns[j] += "\t";
- int width = col_widths[j];
- while (fm.width(columns[j]) < width) {
- columns[j] += "\t";
- }
- }
- text = columns.join("");
- twi->setText(text);
- WidenColumn(4, fm.width(text));
- }
-
- // FIXME: size for compact mode
- //resize(this->width(), parent()->height()*7/8);
- move(0, 0);
- adjustSize();
- centerOnMain(this);
- exec();
- int result=this->result();
-
- *menu_list=0;
- if (result>0 && how!=PICK_NONE) {
- if (how==PICK_ONE) {
- int i;
- for (i=0; ifont());
- QTableWidgetItem *twi;
-
- if (mi.Selectable() && how != PICK_NONE) {
- // Count
- twi = new QTableWidgetItem("");
- table->setItem(row, 0, twi);
- twi->setFlags(Qt::ItemIsEnabled);
- WidenColumn(0, fm.width("999999"));
- // Check box, set if selected
- QCheckBox *cb = new QCheckBox();
- cb->setChecked(mi.selected);
- cb->setFocusPolicy(Qt::NoFocus);
- if (how == PICK_ONE)
- connect(cb, SIGNAL(clicked(bool)), this, SLOT(DoSelection(bool)));
- table->setCellWidget(row, 1, cb);
- WidenColumn(1, cb->width());
- }
- if (mi.glyph != NO_GLYPH) {
- // Icon
- QPixmap pm(qt_settings->glyphs().glyph(mi.glyph));
- twi = new QTableWidgetItem(QIcon(pm), "");
- table->setItem(row, 2, twi);
- twi->setFlags(Qt::ItemIsEnabled);
- WidenColumn(2, pm.width());
- }
- QString letter, text(mi.str);
- if (mi.ch != 0) {
- // Letter specified
- letter = QString(mi.ch) + " - ";
- }
- else {
- // Letter is left blank, except for skills display when # and * are
- // presented
- if (text.startsWith(" ")) {
- // If mi.str starts with " ", it's meant to line up with lines
- // that have a letter; we don't want that here
- text = text.mid(4);
- } else if (text.startsWith(" #") || text.startsWith(" *")) {
- // Put the * or # in the letter column
- letter = text.left(4);
- text = text.mid(4);
- }
- }
- twi = new QTableWidgetItem(letter);
- table->setItem(row, 3, twi);
- table->item(row, 3)->setFlags(Qt::ItemIsEnabled);
- WidenColumn(3, fm.width(letter));
- twi = new QTableWidgetItem(text);
- table->setItem(row, 4, twi);
- table->item(row, 4)->setFlags(Qt::ItemIsEnabled);
- WidenColumn(4, fm.width(text));
-
- if (mi.color != -1) {
- twi->setForeground(colors[mi.color]);
- }
-
- QFont itemfont(table->font());
- switch (mi.attr) {
- case ATR_BOLD:
- itemfont.setWeight(QFont::Bold);
- twi->setFont(itemfont);
- break;
-
- case ATR_DIM:
- twi->setFlags(Qt::NoItemFlags);
- break;
-
- case ATR_ULINE:
- itemfont.setUnderline(true);
- twi->setFont(itemfont);
- break;
-
- case ATR_INVERSE:
- {
- QBrush fg = twi->foreground();
- QBrush bg = twi->background();
- if (fg == bg) {
- // default foreground and background come up the same for
- // some unknown reason
- twi->setForeground(Qt::white);
- twi->setBackground(Qt::black);
- } else {
- twi->setForeground(bg);
- twi->setBackground(fg);
- }
- }
- break;
- }
-}
-
-void NetHackQtMenuWindow::WidenColumn(int column, int width)
-{
- // need to add a bit so the whole column displays
- width += 7;
- if (table->columnWidth(column) < width) {
- table->setColumnWidth(column, width);
- }
-}
-
-void NetHackQtMenuWindow::InputCount(char key)
-{
- if (key == '\b')
- {
- if (counting)
- {
- if (countstr.isEmpty())
- ClearCount();
- else
- countstr = countstr.mid(0, countstr.size() - 1);
- }
- }
- else
- {
- counting = true;
- countstr += QChar(key);
- }
- if (counting)
- prompt.setText("Count: " + countstr);
-}
-
-void NetHackQtMenuWindow::ClearCount(void)
-{
- counting = false;
- prompt.setText(promptstr);
- countstr = "";
-}
-
-void NetHackQtMenuWindow::keyPressEvent(QKeyEvent* event)
-{
- QString text = event->text();
-
- const QChar *uni = text.unicode();
- for (unsigned k = 0; uni[k] != 0; k++) {
- unsigned key = uni[k].unicode();
- if (key=='\033') {
- if (counting)
- ClearCount();
- else
- reject();
- } else if (key=='\r' || key=='\n' || key==' ')
- accept();
- else if (key==MENU_SEARCH)
- Search();
- else if (key==MENU_SELECT_ALL || key==MENU_SELECT_PAGE)
- All();
- else if (key==MENU_INVERT_ALL || key==MENU_INVERT_PAGE)
- Invert();
- else if (key==MENU_UNSELECT_ALL || key==MENU_UNSELECT_PAGE)
- ChooseNone();
- else if (('0' <= key && key <= '9') || key == '\b')
- InputCount(key);
- else {
- for (int i=0; iitem(i, 0);
- if (count != NULL) count->setText("");
-
- QCheckBox *cb = dynamic_cast(table->cellWidget(i, 1));
- if (cb != NULL) cb->setChecked(true);
- }
-}
-void NetHackQtMenuWindow::ChooseNone()
-{
- if (how != PICK_ANY)
- return;
-
- for (int i=0; iitem(i, 0);
- if (count != NULL) count->setText("");
-
- QCheckBox *cb = dynamic_cast(table->cellWidget(i, 1));
- if (cb != NULL) cb->setChecked(false);
- }
-}
-void NetHackQtMenuWindow::Invert()
-{
- if (how != PICK_ANY)
- return;
-
- for (int i=0; i