From: Pasi Kallinen Date: Sat, 7 Oct 2017 17:26:02 +0000 (+0300) Subject: Add Qt4 windowport X-Git-Tag: NetHack-3.6.1_RC01~309 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=ed335dd0a7470713b91aa299e3667f249543012d;p=nethack Add Qt4 windowport Originally by Ray Chason for 3.4.3, based on the Qt windowport by Warwick Allison. The look and feel is mostly the same. Some improvements over the Qt 3 interface are: * Panes are resizable * Full support for IBMgraphics, and walls and corridors are drawn with graphical primitives for a continuous appearance no matter what the font says * Lots of irritating glitches fixed * Menus support proportional fonts correctly Adding this because the old Qt windowport cannot be compiled on Qt4, even with Qt3 compatibility stuff. TODO: - background map glyphs - status hilites - menucolors --- diff --git a/doc/fixes36.1 b/doc/fixes36.1 index 8e2d0f486..e6f3e7c78 100644 --- a/doc/fixes36.1 +++ b/doc/fixes36.1 @@ -718,6 +718,7 @@ Ray Chason's proper background tiles for lava and water Ray Chason's MS-DOS port restored to functionality with credit to Reddit user b_helyer for the fix to sys/share/pcmain.c Ray Chason's MSDOS port support for some VESA modes +Ray Chason's Qt4 windowport Darshan Shaligram's pet ranged attack Jason Dorje Short's key rebinding Maxime Bacoux's new DUMPLOG: compile-time option to enable logging of diff --git a/include/extern.h b/include/extern.h index 54ec9440c..018094dd4 100644 --- a/include/extern.h +++ b/include/extern.h @@ -168,6 +168,9 @@ E boolean NDECL(status_hilite_menu); /* ### cmd.c ### */ +E int NDECL(doconduct); +E int NDECL(domonability); +E char FDECL(cmd_from_func, (int NDECL((*)))); E boolean FDECL(redraw_cmd, (CHAR_P)); #ifdef USE_TRAMPOLI E int NDECL(doextcmd); diff --git a/src/cmd.c b/src/cmd.c index 6849f2ca4..add6ebd52 100644 --- a/src/cmd.c +++ b/src/cmd.c @@ -117,7 +117,6 @@ static int NDECL((*timed_occ_fn)); STATIC_PTR int NDECL(doprev_message); STATIC_PTR int NDECL(timed_occupation); STATIC_PTR int NDECL(doextcmd); -STATIC_PTR int NDECL(domonability); STATIC_PTR int NDECL(dotravel); STATIC_PTR int NDECL(doterrain); STATIC_PTR int NDECL(wiz_wish); @@ -164,9 +163,7 @@ STATIC_DCL boolean FDECL(accept_menu_prefix, (int NDECL((*)))); STATIC_DCL int NDECL(wiz_port_debug); #endif STATIC_PTR int NDECL(wiz_rumor_check); -STATIC_DCL char FDECL(cmd_from_func, (int NDECL((*)))); STATIC_PTR int NDECL(doattributes); -STATIC_PTR int NDECL(doconduct); /**/ STATIC_DCL void FDECL(enlght_line, (const char *, const char *, const char *, const char *)); @@ -523,7 +520,7 @@ extcmd_via_menu() #endif /* TTY_GRAPHICS */ /* #monster command - use special monster ability while polymorphed */ -STATIC_PTR int +int domonability(VOID_ARGS) { if (can_breathe(youmonst.data)) @@ -2734,7 +2731,7 @@ int msgflag; /* for variant message phrasing */ /* KMH, #conduct * (shares enlightenment's tense handling) */ -STATIC_PTR int +int doconduct(VOID_ARGS) { show_conduct(0); @@ -3283,7 +3280,7 @@ dokeylist(VOID_ARGS) destroy_nhwindow(datawin); } -STATIC_OVL char +char cmd_from_func(fn) int NDECL((*fn)); { diff --git a/sys/unix/Makefile.src b/sys/unix/Makefile.src index 5488e6106..8c27b612c 100644 --- a/sys/unix/Makefile.src +++ b/sys/unix/Makefile.src @@ -201,6 +201,22 @@ WINX11OBJ = Window.o dialogs.o winX.o winmap.o winmenu.o winmesg.o \ WINQTSRC = ../win/Qt/qt_win.cpp ../win/Qt/qt_clust.cpp ../win/Qt/qttableview.cpp WINQTOBJ = qt_win.o qt_clust.o qttableview.o tile.o # +# Files for a Qt 4 or 5 port +# +WINQT4SRC = ../win/Qt4/qt4bind.cpp ../win/Qt4/qt4click.cpp \ + ../win/Qt4/qt4clust.cpp ../win/Qt4/qt4delay.cpp \ + ../win/Qt4/qt4glyph.cpp ../win/Qt4/qt4icon.cpp ../win/Qt4/qt4inv.cpp \ + ../win/Qt4/qt4key.cpp ../win/Qt4/qt4line.cpp ../win/Qt4/qt4main.cpp \ + ../win/Qt4/qt4map.cpp ../win/Qt4/qt4menu.cpp ../win/Qt4/qt4msg.cpp \ + ../win/Qt4/qt4plsel.cpp ../win/Qt4/qt4rip.cpp ../win/Qt4/qt4set.cpp \ + ../win/Qt4/qt4stat.cpp ../win/Qt4/qt4str.cpp ../win/Qt4/qt4streq.cpp \ + ../win/Qt4/qt4svsel.cpp ../win/Qt4/qt4win.cpp ../win/Qt4/qt4xcmd.cpp \ + ../win/Qt4/qt4yndlg.cpp +WINQT4OBJ = qt4bind.o qt4click.o qt4clust.o qt4delay.o qt4glyph.o qt4icon.o \ + qt4inv.o qt4key.o qt4line.o qt4main.o qt4map.o qt4menu.o qt4msg.o \ + qt4plsel.o qt4rip.o qt4set.o qt4stat.o qt4str.o qt4streq.o qt4svsel.o \ + qt4win.o qt4xcmd.o qt4yndlg.o tile.o +# # Files for a Gnome port # WINGNOMESRC = ../win/gnome/gnaskstr.c ../win/gnome/gnbind.c \ @@ -253,9 +269,12 @@ WINX11LIB = -lXaw -lXmu -lXext -lXt -lX11 # WINX11LIB = -lXaw -lXmu -lXext -lXt -lXpm -lX11 -lm # WINX11LIB = -lXaw -lXmu -lXpm -lXext -lXt -lX11 -lSM -lICE -lm # BSD/OS 2.0 # -# libraries for Qt +# libraries for Qt 3 WINQTLIB = -L$(QTDIR)/lib -lqt # +# libraries for Qt 4 +WINQT4LIB = `pkg-config QtGui --libs` +# # libraries for KDE (with Qt) WINKDELIB = -lkdecore -lkdeui -lXext # @@ -360,7 +379,7 @@ GENCSRC = monstr.c vis_tab.c #tile.c # all windowing-system-dependent .c (for dependencies and such) WINCSRC = $(WINTTYSRC) $(WINX11SRC) $(WINGNOMESRC) $(WINGEMSRC) # all windowing-system-dependent .cpp (for dependencies and such) -WINCXXSRC = $(WINQTSRC) $(WINBESRC) +WINCXXSRC = $(WINQTSRC) $(WINQT4SRC) $(WINBESRC) # Files for window system chaining. Requires SYSCF; include via HINTSRC/HINTOBJ CHAINSRC = ../win/chain/wc_chainin.c ../win/chain/wc_chainout.c \ @@ -486,7 +505,7 @@ objects.o: $(CC) $(CFLAGS) -c objects.c @rm -f $(MAKEDEFS) -# Qt windowport meta-object-compiler output +# Qt 3 windowport meta-object-compiler output qt_kde0.moc: ../include/qt_kde0.h $(QTDIR)/bin/moc -o qt_kde0.moc ../include/qt_kde0.h @@ -496,6 +515,28 @@ qt_win.moc: ../include/qt_win.h qttableview.moc: ../include/qttableview.h $(QTDIR)/bin/moc -o qttableview.moc ../include/qttableview.h +# Qt 4 windowport meta-object-compiler output +qt4kde0.moc : ../win/Qt4/qt4kde0.h + $(QTDIR)/bin/moc -o qt4kde0.moc ../win/Qt4/qt4kde0.h +qt4main.moc : ../win/Qt4/qt4main.h + $(QTDIR)/bin/moc -o qt4main.moc ../win/Qt4/qt4main.h +qt4map.moc : ../win/Qt4/qt4map.h + $(QTDIR)/bin/moc -o qt4map.moc ../win/Qt4/qt4map.h +qt4menu.moc : ../win/Qt4/qt4menu.h + $(QTDIR)/bin/moc -o qt4menu.moc ../win/Qt4/qt4menu.h +qt4msg.moc : ../win/Qt4/qt4msg.h + $(QTDIR)/bin/moc -o qt4msg.moc ../win/Qt4/qt4msg.h +qt4plsel.moc : ../win/Qt4/qt4plsel.h + $(QTDIR)/bin/moc -o qt4plsel.moc ../win/Qt4/qt4plsel.h +qt4set.moc : ../win/Qt4/qt4set.h + $(QTDIR)/bin/moc -o qt4set.moc ../win/Qt4/qt4set.h +qt4stat.moc : ../win/Qt4/qt4stat.h + $(QTDIR)/bin/moc -o qt4stat.moc ../win/Qt4/qt4stat.h +qt4xcmd.moc : ../win/Qt4/qt4xcmd.h + $(QTDIR)/bin/moc -o qt4xcmd.moc ../win/Qt4/qt4xcmd.h +qt4yndlg.moc : ../win/Qt4/qt4yndlg.h + $(QTDIR)/bin/moc -o qt4yndlg.moc ../win/Qt4/qt4yndlg.h + # build monst.o and objects.o before executing '$(MAKE) makedefs' $(MAKEDEFS): $(FIRSTOBJ) \ ../util/makedefs.c $(CONFIG_H) ../include/permonst.h \ @@ -737,6 +778,52 @@ qt_clust.o: ../win/Qt/qt_clust.cpp ../include/qt_clust.h $(CXX) $(CXXFLAGS) -c ../win/Qt/qt_clust.cpp qttableview.o: ../win/Qt/qttableview.cpp ../include/qttableview.h $(CXX) $(CXXFLAGS) -c ../win/Qt/qttableview.cpp +qt4bind.o : ../win/Qt4/qt4bind.cpp $(HACK_H) ../win/Qt4/qt4bind.h + $(CXX) $(CXXFLAGS) -c ../win/Qt4/qt4bind.cpp +qt4click.o : ../win/Qt4/qt4click.cpp $(HACK_H) ../win/Qt4/qt4click.h + $(CXX) $(CXXFLAGS) -c ../win/Qt4/qt4click.cpp +qt4clust.o : ../win/Qt4/qt4clust.cpp $(HACK_H) ../win/Qt4/qt4clust.h + $(CXX) $(CXXFLAGS) -c ../win/Qt4/qt4clust.cpp +qt4delay.o : ../win/Qt4/qt4delay.cpp $(HACK_H) ../win/Qt4/qt4delay.h + $(CXX) $(CXXFLAGS) -c ../win/Qt4/qt4delay.cpp +qt4glyph.o : ../win/Qt4/qt4glyph.cpp $(HACK_H) ../win/Qt4/qt4glyph.h + $(CXX) $(CXXFLAGS) -c ../win/Qt4/qt4glyph.cpp +qt4icon.o : ../win/Qt4/qt4icon.cpp $(HACK_H) ../win/Qt4/qt4icon.h + $(CXX) $(CXXFLAGS) -c ../win/Qt4/qt4icon.cpp +qt4inv.o : ../win/Qt4/qt4inv.cpp $(HACK_H) ../win/Qt4/qt4inv.h + $(CXX) $(CXXFLAGS) -c ../win/Qt4/qt4inv.cpp +qt4key.o : ../win/Qt4/qt4key.cpp $(HACK_H) ../win/Qt4/qt4key.h + $(CXX) $(CXXFLAGS) -c ../win/Qt4/qt4key.cpp +qt4line.o : ../win/Qt4/qt4line.cpp $(HACK_H) ../win/Qt4/qt4line.h + $(CXX) $(CXXFLAGS) -c ../win/Qt4/qt4line.cpp +qt4main.o : ../win/Qt4/qt4main.cpp $(HACK_H) qt4main.moc ../win/Qt4/qt4main.h qt4kde0.moc + $(CXX) $(CXXFLAGS) -c ../win/Qt4/qt4main.cpp +qt4map.o : ../win/Qt4/qt4map.cpp $(HACK_H) qt4map.moc ../win/Qt4/qt4map.h + $(CXX) $(CXXFLAGS) -c ../win/Qt4/qt4map.cpp +qt4menu.o : ../win/Qt4/qt4menu.cpp $(HACK_H) qt4menu.moc ../win/Qt4/qt4menu.h + $(CXX) $(CXXFLAGS) -c ../win/Qt4/qt4menu.cpp +qt4msg.o : ../win/Qt4/qt4msg.cpp $(HACK_H) qt4msg.moc ../win/Qt4/qt4msg.h + $(CXX) $(CXXFLAGS) -c ../win/Qt4/qt4msg.cpp +qt4plsel.o : ../win/Qt4/qt4plsel.cpp $(HACK_H) qt4plsel.moc ../win/Qt4/qt4plsel.h + $(CXX) $(CXXFLAGS) -c ../win/Qt4/qt4plsel.cpp +qt4rip.o : ../win/Qt4/qt4rip.cpp $(HACK_H) ../win/Qt4/qt4rip.h + $(CXX) $(CXXFLAGS) -c ../win/Qt4/qt4rip.cpp +qt4set.o : ../win/Qt4/qt4set.cpp $(HACK_H) qt4set.moc ../win/Qt4/qt4set.h + $(CXX) $(CXXFLAGS) -c ../win/Qt4/qt4set.cpp +qt4stat.o : ../win/Qt4/qt4stat.cpp $(HACK_H) qt4stat.moc ../win/Qt4/qt4stat.h + $(CXX) $(CXXFLAGS) -c ../win/Qt4/qt4stat.cpp +qt4str.o : ../win/Qt4/qt4str.cpp ../win/Qt4/qt4str.h + $(CXX) $(CXXFLAGS) -c ../win/Qt4/qt4str.cpp +qt4streq.o : ../win/Qt4/qt4streq.cpp $(HACK_H) ../win/Qt4/qt4streq.h + $(CXX) $(CXXFLAGS) -c ../win/Qt4/qt4streq.cpp +qt4svsel.o : ../win/Qt4/qt4svsel.cpp $(HACK_H) ../win/Qt4/qt4svsel.h + $(CXX) $(CXXFLAGS) -c ../win/Qt4/qt4svsel.cpp +qt4win.o : ../win/Qt4/qt4win.cpp $(HACK_H) ../win/Qt4/qt4win.h + $(CXX) $(CXXFLAGS) -c ../win/Qt4/qt4win.cpp +qt4xcmd.o : ../win/Qt4/qt4xcmd.cpp $(HACK_H) qt4xcmd.moc ../win/Qt4/qt4xcmd.h + $(CXX) $(CXXFLAGS) -c ../win/Qt4/qt4xcmd.cpp +qt4yndlg.o : ../win/Qt4/qt4yndlg.cpp $(HACK_H) qt4yndlg.moc ../win/Qt4/qt4yndlg.h + $(CXX) $(CXXFLAGS) -c ../win/Qt4/qt4yndlg.cpp wc_chainin.o: ../win/chain/wc_chainin.c $(HACK_H) $(CC) $(CFLAGS) -c ../win/chain/wc_chainin.c wc_chainout.o: ../win/chain/wc_chainout.c $(HACK_H) diff --git a/sys/unix/hints/linux-qt4 b/sys/unix/hints/linux-qt4 new file mode 100644 index 000000000..0feddb9b5 --- /dev/null +++ b/sys/unix/hints/linux-qt4 @@ -0,0 +1,47 @@ +# +# NetHack 3.6 linux-x11 $NHDT-Date: 1432512814 2015/05/25 00:13:34 $ $NHDT-Branch: master $:$NHDT-Revision: 1.12 $ +# Copyright (c) Kenneth Lorber, Kensington, Maryland, 2007. +# NetHack may be freely redistributed. See license for details. +# +#-PRE +# Linux hints file +# This hints file provides a single-user Qt4 build for Linux, specifically +# for Ubuntu dapper. + + +#PREFIX=/usr +PREFIX=$(wildcard ~)/nh/install +HACKDIR=$(PREFIX)/games/lib/$(GAME)dir +SHELLDIR = $(PREFIX)/games +INSTDIR=$(HACKDIR) +VARDIR = $(HACKDIR) + + +POSTINSTALL= cp -n sys/unix/sysconf $(INSTDIR)/sysconf; $(CHOWN) $(GAMEUID) $(INSTDIR)/sysconf; $(CHGRP) $(GAMEGRP) $(INSTDIR)/sysconf; chmod $(VARFILEPERM) $(INSTDIR)/sysconf; +POSTINSTALL+= bdftopcf win/X11/nh10.bdf > $(INSTDIR)/nh10.pcf; (cd $(INSTDIR); mkfontdir); + +CFLAGS=-O -I../include -DNOTPARMDECL +CFLAGS+=-DHACKDIR=\"$(HACKDIR)\" +CFLAGS+=-DSYSCF -DSYSCF_FILE=\"$(HACKDIR)/sysconf\" +CFLAGS+=-DCOMPRESS=\"/bin/gzip\" -DCOMPRESS_EXTENSION=\".gz\" +CFLAGS+=-DQT_GRAPHICS -DDEFAULT_WINDOW_SYS=\"Qt\" -DNOTTYGRAPHICS +CFLAGS+=`pkg-config QtGui --cflags` + +LINK=g++ +CXX=g++ + +WINSRC = $(WINQT4SRC) +WINOBJ = $(WINQT4OBJ) +WINLIB = $(WINQT4LIB) + +VARDATND = nhtiles.bmp rip.xpm nhsplash.xpm pet_mark.xbm pilemark.xbm + +QTDIR=/usr + +CHOWN=true +CHGRP=true +VARDIRPERM = 0755 +VARFILEPERM = 0600 +GAMEPERM = 0755 + +# note: needs libxt-dev libxaw7-dev libx11-dev bdftopcf diff --git a/win/Qt4/qt4bind.cpp b/win/Qt4/qt4bind.cpp new file mode 100644 index 000000000..5dc17de99 --- /dev/null +++ b/win/Qt4/qt4bind.cpp @@ -0,0 +1,745 @@ +// 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 +#if QT_VERSION >= 0x050000 +#include +#include +#else +#include +#endif +#include "qt4bind.h" +#include "qt4click.h" +#include "qt4delay.h" +#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()); +} + +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 = index(buf, '\n')) != 0) *cr = 0; +#ifdef MSDOS + if ((cr = index(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 && flags.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()) { + qApp->exec(); + } + + 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()) { + qApp->exec(); + } + 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_)); + + if (qt_settings->ynInMessages() && WIN_MESSAGE!=WIN_ERR) { + // Similar to X11 windowport `slow' feature. + + 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 = (index(choices, 'q') ? 'q' : + (index(choices, 'n') ? 'n' : def)); + } else { + message = question; + } + +#ifdef USE_POPUPS + // Improve some special-cases (DIRKS 08/02/23) + if (strcmp (choices,"ynq") == 0) { + switch (QMessageBox::information (NetHackQtBind::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(NetHackQtBind::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(mainWidget(),question,choices,def); + return dialog.Exec(); + } +} + +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() +{ + 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[(int)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() == 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; + +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, + 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, + nethack_qt4::NetHackQtBind::qt_putstr, /* FIXME: should be qt_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, + + genl_getmsghistory, genl_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, +}; + +extern "C" void play_usersound(const char* filename, int volume) +{ +#ifdef USER_SOUNDS +#ifndef QT_NO_SOUND + QSound::play(filename); +#endif +#endif +} diff --git a/win/Qt4/qt4bind.h b/win/Qt4/qt4bind.h new file mode 100644 index 000000000..99a2c0d11 --- /dev/null +++ b/win/Qt4/qt4bind.h @@ -0,0 +1,92 @@ +// 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 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); +}; + +} // namespace nethack_qt4 + +#endif diff --git a/win/Qt4/qt4click.cpp b/win/Qt4/qt4click.cpp new file mode 100644 index 000000000..78177a14f --- /dev/null +++ b/win/Qt4/qt4click.cpp @@ -0,0 +1,48 @@ +// Copyright (c) Warwick Allison, 1999. +// Qt4 conversion copyright (c) Ray Chason, 2012-2014. +// NetHack may be freely redistributed. See license for details. + +// qt4click.cpp -- a mouse click buffer + +#include "hack.h" +#undef Invisible +#undef Warning +#undef index +#undef msleep +#undef rindex +#undef wizard +#undef yn +#undef min +#undef max + +#include +#include "qt4click.h" + +namespace nethack_qt4 { + +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; +} + +} // namespace nethack_qt4 diff --git a/win/Qt4/qt4click.h b/win/Qt4/qt4click.h new file mode 100644 index 000000000..50fd8b1cc --- /dev/null +++ b/win/Qt4/qt4click.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. + +// qt4click.h -- a mouse click buffer + +#ifndef QT4CLICK_H +#define QT4CLICK_H + +namespace nethack_qt4 { + +class NetHackQtClickBuffer { +public: + NetHackQtClickBuffer(); + + bool Empty() const; + bool Full() const; + + void Put(int x, int y, int mod); + + int NextX() const; + int NextY() const; + int NextMod() const; + + void Get(); + +private: + enum { maxclick=64 }; + struct ClickRec { + int x,y,mod; + } click[maxclick]; + int in,out; +}; + +} // namespace nethack_qt4 + +#endif diff --git a/win/Qt4/qt4clust.cpp b/win/Qt4/qt4clust.cpp new file mode 100644 index 000000000..1cd080c11 --- /dev/null +++ b/win/Qt4/qt4clust.cpp @@ -0,0 +1,167 @@ +/* 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/qt4clust.h b/win/Qt4/qt4clust.h new file mode 100644 index 000000000..c7112ea11 --- /dev/null +++ b/win/Qt4/qt4clust.h @@ -0,0 +1,29 @@ +/* SCCS Id: @(#)qt_clust.h 3.4 1999/11/19 */ +/* Copyright (c) Warwick Allison, 1999. */ +/* NetHack may be freely redistributed. See license for details. */ + +#ifndef clusterizer_H +#define clusterizer_H + +#include + +class Clusterizer { +public: + Clusterizer(int maxclusters); + ~Clusterizer(); + + void add(int x, int y); // 1x1 rectangle (point) + void add(int x, int y, int w, int h); + void add(const QRect& rect); + + void clear(); + int clusters() { return count; } + const QRect& operator[](int i); + +private: + QRect* cluster; + int count; + const int max; +}; + +#endif diff --git a/win/Qt4/qt4delay.cpp b/win/Qt4/qt4delay.cpp new file mode 100644 index 000000000..eadf42a94 --- /dev/null +++ b/win/Qt4/qt4delay.cpp @@ -0,0 +1,42 @@ +// Copyright (c) Warwick Allison, 1999. +// Qt4 conversion copyright (c) Ray Chason, 2012-2014. +// NetHack may be freely redistributed. See license for details. + +// qt4delay.cpp -- implement a delay + +#include "hack.h" +#undef Invisible +#undef Warning +#undef index +#undef msleep +#undef rindex +#undef wizard +#undef yn +#undef min +#undef max + +#include +#include "qt4delay.h" + +namespace nethack_qt4 { + +// RLC Can we use QTimer::single_shot for this? +NetHackQtDelay::NetHackQtDelay(int ms) : + msec(ms), m_timer(0), m_loop(this) +{ +} + +void NetHackQtDelay::wait() +{ + m_timer = startTimer(msec); + m_loop.exec(); +} + +void NetHackQtDelay::timerEvent(QTimerEvent* timer) +{ + m_loop.exit(); + killTimer(m_timer); + m_timer = 0; +} + +} // namespace nethack_qt4 diff --git a/win/Qt4/qt4delay.h b/win/Qt4/qt4delay.h new file mode 100644 index 000000000..2e0085edf --- /dev/null +++ b/win/Qt4/qt4delay.h @@ -0,0 +1,26 @@ +// Copyright (c) Warwick Allison, 1999. +// Qt4 conversion copyright (c) Ray Chason, 2012-2014. +// NetHack may be freely redistributed. See license for details. + +// qt4delay.h -- implement a delay + +#ifndef QT4DELAY_H +#define QT4DELAY_H + +namespace nethack_qt4 { + +class NetHackQtDelay : QObject { +private: + int msec; + int m_timer; + QEventLoop m_loop; + +public: + NetHackQtDelay(int ms); + void wait(); + virtual void timerEvent(QTimerEvent* timer); +}; + +} // namespace nethack_qt4 + +#endif diff --git a/win/Qt4/qt4glyph.cpp b/win/Qt4/qt4glyph.cpp new file mode 100644 index 000000000..3ba56be6f --- /dev/null +++ b/win/Qt4/qt4glyph.cpp @@ -0,0 +1,141 @@ +// 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::SmoothTransformation + ); + 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 new file mode 100644 index 000000000..12fd915fd --- /dev/null +++ b/win/Qt4/qt4glyph.h @@ -0,0 +1,34 @@ +// 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 new file mode 100644 index 000000000..0876cb59d --- /dev/null +++ b/win/Qt4/qt4icon.cpp @@ -0,0 +1,203 @@ +// 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 new file mode 100644 index 000000000..bdaf8183c --- /dev/null +++ b/win/Qt4/qt4icon.h @@ -0,0 +1,53 @@ +// 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 new file mode 100644 index 000000000..9165d58b3 --- /dev/null +++ b/win/Qt4/qt4inv.cpp @@ -0,0 +1,104 @@ +// 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); + 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 +#ifdef TOURIST + drawWorn(painter,uarmf,1,5); // Shoes (feet) + drawWorn(painter,uarmu,1,4); // Undershirt +#else + drawWorn(painter,0 ,1,5,false); + drawWorn(painter,uarmf,1,4); // Shoes (feet) +#endif + 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 new file mode 100644 index 000000000..51cdd4d0b --- /dev/null +++ b/win/Qt4/qt4inv.h @@ -0,0 +1,25 @@ +// 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/qt4kde0.h b/win/Qt4/qt4kde0.h new file mode 100644 index 000000000..27a678c01 --- /dev/null +++ b/win/Qt4/qt4kde0.h @@ -0,0 +1,14 @@ +/* SCCS Id: @(#)qt_kde0.h 3.4 1999/11/19 */ +/* Copyright (c) Warwick Allison, 1999. */ +/* NetHack may be freely redistributed. See license for details. */ + +#ifndef QT_DUMMYKDE +#define QT_DUMMYKDE +namespace nethack_qt4 { + +class KTopLevelWidget : public QMainWindow { + Q_OBJECT +}; + +} +#endif diff --git a/win/Qt4/qt4key.cpp b/win/Qt4/qt4key.cpp new file mode 100644 index 000000000..ff16616fe --- /dev/null +++ b/win/Qt4/qt4key.cpp @@ -0,0 +1,91 @@ +// 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/qt4key.h b/win/Qt4/qt4key.h new file mode 100644 index 000000000..0333269cd --- /dev/null +++ b/win/Qt4/qt4key.h @@ -0,0 +1,40 @@ +// Copyright (c) Warwick Allison, 1999. +// Qt4 conversion copyright (c) Ray Chason, 2012-2014. +// NetHack may be freely redistributed. See license for details. + +// qt4key.h -- a key buffer + +#ifndef QT4KEY_H +#define QT4KEY_H + +namespace nethack_qt4 { + +class NetHackQtKeyBuffer { +public: + NetHackQtKeyBuffer(); + + bool Empty() const; + bool Full() const; + + void Put(int k, int ascii, int state); + void Put(char a); + void Put(const char* str); + int GetKey(); + int GetAscii(); + Qt::KeyboardModifiers GetState(); + + int TopKey() const; + int TopAscii() const; + Qt::KeyboardModifiers TopState() const; + +private: + enum { maxkey=64 }; + int key[maxkey]; + int ascii[maxkey]; + Qt::KeyboardModifiers state[maxkey]; + int in,out; +}; + +} // namespace nethack_qt4 + +#endif diff --git a/win/Qt4/qt4line.cpp b/win/Qt4/qt4line.cpp new file mode 100644 index 000000000..dd9b18c5f --- /dev/null +++ b/win/Qt4/qt4line.cpp @@ -0,0 +1,42 @@ +// Copyright (c) Warwick Allison, 1999. +// Qt4 conversion copyright (c) Ray Chason, 2012-2014. +// NetHack may be freely redistributed. See license for details. + +// qt4line.cpp -- a one line input window + +#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 "qt4line.h" + +namespace nethack_qt4 { + +NetHackQtLineEdit::NetHackQtLineEdit() : + QLineEdit(0) +{ +} + +NetHackQtLineEdit::NetHackQtLineEdit(QWidget* parent, const char* name) : + QLineEdit(parent) +{ +} + +void NetHackQtLineEdit::fakeEvent(int key, int ascii, Qt::KeyboardModifiers state) +{ + QKeyEvent fake(QEvent::KeyPress,key,state,QChar(ascii)); + keyPressEvent(&fake); +} + +} // namespace nethack_qt4 diff --git a/win/Qt4/qt4line.h b/win/Qt4/qt4line.h new file mode 100644 index 000000000..bb5067f79 --- /dev/null +++ b/win/Qt4/qt4line.h @@ -0,0 +1,22 @@ +// Copyright (c) Warwick Allison, 1999. +// Qt4 conversion copyright (c) Ray Chason, 2012-2014. +// NetHack may be freely redistributed. See license for details. + +// qt4line.h -- a one line input window + +#ifndef QT4LINE_H +#define QT4LINE_H + +namespace nethack_qt4 { + +class NetHackQtLineEdit : public QLineEdit { +public: + NetHackQtLineEdit(); + NetHackQtLineEdit(QWidget* parent, const char* name); + + void fakeEvent(int key, int ascii, Qt::KeyboardModifiers state); +}; + +} // namespace nethack_qt4 + +#endif diff --git a/win/Qt4/qt4main.cpp b/win/Qt4/qt4main.cpp new file mode 100644 index 000000000..ec7e58324 --- /dev/null +++ b/win/Qt4/qt4main.cpp @@ -0,0 +1,1063 @@ +// 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(); + + 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, dotele}, + { 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; + hsplitter->insertWidget(0, message->Widget()); + ShowIfReady(); +} + +void NetHackQtMainWindow::AddMapWindow(NetHackQtMapWindow2* window) +{ + map=window; + vsplitter->insertWidget(1, map->Widget()); + ShowIfReady(); + connect(map,SIGNAL(resized()),this,SLOT(layout())); +} + +void NetHackQtMainWindow::AddStatusWindow(NetHackQtStatusWindow* window) +{ + status=window; + 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/qt4main.h b/win/Qt4/qt4main.h new file mode 100644 index 000000000..33f5b2635 --- /dev/null +++ b/win/Qt4/qt4main.h @@ -0,0 +1,94 @@ +// Copyright (c) Warwick Allison, 1999. +// Qt4 conversion copyright (c) Ray Chason, 2012-2014. +// NetHack may be freely redistributed. See license for details. + +// qt4main.h -- the main window + +#ifndef QT4MAIN_H +#define QT4MAIN_H + +#ifdef KDE +#include +#include +#else +#include "qt4kde0.h" +#endif + +namespace nethack_qt4 { + +class NetHackQtInvUsageWindow; +class NetHackQtKeyBuffer; +class NetHackQtMapWindow2; +class NetHackQtMessageWindow; +class NetHackQtStatusWindow; +class NetHackQtWindow; + +// This class is the main widget for NetHack +// +// It is a collection of Message, Map, and Status windows. In the current +// version of nethack there is only one of each, and this class makes this +// assumption, not showing itself until all are inserted. +// +// This class simply knows how to layout such children sensibly. +// +// Since it is only responsible for layout, the class does not +// note the actual class of the windows. +// + +class NetHackQtMainWindow : public KTopLevelWidget { + Q_OBJECT +public: + NetHackQtMainWindow(NetHackQtKeyBuffer&); + + void AddMessageWindow(NetHackQtMessageWindow* window); + void AddMapWindow(NetHackQtMapWindow2* window); + void AddStatusWindow(NetHackQtStatusWindow* window); + void RemoveWindow(NetHackQtWindow* window); + void updateInventory(); + + void fadeHighlighting(); + +public slots: + void doMenuItem(QAction *); + void doQtSettings(bool); + void doAbout(bool); + //RLC void doGuidebook(bool); + void doKeys(const QString&); + +protected: + virtual void resizeEvent(QResizeEvent*); + virtual void keyPressEvent(QKeyEvent*); + virtual void keyReleaseEvent(QKeyEvent* event); + virtual void closeEvent(QCloseEvent*); + +private slots: + void layout(); + void raiseMap(); + void zoomMap(); + void raiseMessages(); + void raiseStatus(); + +private: + void ShowIfReady(); + +#ifdef KDE + KMenuBar* menubar; +#else + QMenuBar* menubar; +#endif + NetHackQtMessageWindow* message; + NetHackQtMapWindow2* map; + NetHackQtStatusWindow* status; + NetHackQtInvUsageWindow* invusage; + + QSplitter *hsplitter; + QSplitter *vsplitter; + + NetHackQtKeyBuffer& keysink; + QStackedWidget* stack; + int dirkey; +}; + +} // namespace nethack_qt4 + +#endif diff --git a/win/Qt4/qt4map.cpp b/win/Qt4/qt4map.cpp new file mode 100644 index 000000000..39c915ee5 --- /dev/null +++ b/win/Qt4/qt4map.cpp @@ -0,0 +1,964 @@ +// 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); + + 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); + 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) + ); + } + 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( 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); + + 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); +#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) + ); + 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( 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 new file mode 100644 index 000000000..da2df88ad --- /dev/null +++ b/win/Qt4/qt4map.h @@ -0,0 +1,81 @@ +// 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; + 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 new file mode 100644 index 000000000..b15aa0ee5 --- /dev/null +++ b/win/Qt4/qt4menu.cpp @@ -0,0 +1,840 @@ +// 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 + +#ifdef MENU_COLOR +extern "C" struct menucoloring *menu_colorings; +#endif + +namespace nethack_qt4 { + +// temporary +void centerOnMain( QWidget* w ); +// end temporary + +static boolean get_menu_coloring(char const *str, int *color, int *attr); + +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); + + 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); + } + } +#ifdef MENU_COLOR + int mcolor, mattr; + if (attr == 0 + && get_menu_coloring(str.toLatin1().constData(), &mcolor, &mattr)) { + itemlist[itemcount].attr = mattr; + itemlist[itemcount].color = mcolor; + } +#endif + ++itemcount; + + if (glyph!=NO_GLYPH) has_glyphs=true; +} + +#ifdef MENU_COLOR +static boolean +get_menu_coloring(char const *str, int *color, int *attr) +{ + struct menucoloring *tmpmc; + if (iflags.use_menu_color) + for (tmpmc = menu_colorings; tmpmc; tmpmc = tmpmc->next) +# ifdef MENU_COLOR_REGEX + if (re_search(&tmpmc->match, str, strlen(str), 0, 9999, 0) >= 0) { +# else + if (pmatch(tmpmc->match, str)) { +# endif + *color = tmpmc->color; + *attr = tmpmc->attr; + return TRUE; + } + return FALSE; +} +#endif /* MENU_COLOR */ + +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)); + +#ifdef MENU_COLOR + if (mi.color != -1) { + twi->setForeground(colors[mi.color]); + } +#endif + + 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) + All(); + else if (key==MENU_INVERT_ALL) + Invert(); + else if (key==MENU_UNSELECT_ALL) + 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() +{ + 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() +{ + 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(cb->checkState() == Qt::Unchecked); + } +} +void NetHackQtMenuWindow::Search() +{ + NetHackQtStringRequestor requestor(this, "Search for:"); + char line[256]; + if (requestor.Get(line)) { + for (int i=0; i(table->cellWidget(i, 1)); + if (cb == NULL) return; + + cb->setChecked((counting && !countstr.isEmpty()) + || cb->checkState() == Qt::Unchecked); + + QTableWidgetItem *count = table->item(i, 0); + if (count != NULL) count->setText(countstr); + + ClearCount(); + + if (how==PICK_ONE) { + accept(); + } + } +} + +void NetHackQtMenuWindow::DoSelection(bool) +{ + if (how == PICK_ONE) { + accept(); + } +} + +bool NetHackQtMenuWindow::isSelected(int row) +{ + QCheckBox *cb = dynamic_cast(table->cellWidget(row, 1)); + return cb != NULL && cb->checkState() != Qt::Unchecked; +} + +int NetHackQtMenuWindow::count(int row) +{ + QTableWidgetItem *count = table->item(row, 0); + if (count == NULL) return -1; + QString cstr = count->text(); + return cstr.isEmpty() ? -1 : cstr.toInt(); +} + +NetHackQtTextWindow::NetHackQtTextWindow(QWidget *parent) : + QDialog(parent), + 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->addLayout(hb); + 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; + 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 */ + snprintf(rip_line[YEAR_LINE], STONE_LINE_LEN+1, "%4d", getyear()); + + 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 + 7; + 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 { + move(0, 0); + adjustSize(); + centerOnMain(this); + show(); + } + exec(); +} + +void NetHackQtTextWindow::PutStr(int attr, const QString& text) +{ + str_fixed=str_fixed || text.contains(" "); + lines->addItem(text); +} + +void NetHackQtTextWindow::Search() +{ + NetHackQtStringRequestor requestor(this, "Search for:"); + static char line[256]=""; + requestor.SetDefault(line); + if (requestor.Get(line)) { + int current=lines->currentRow(); + for (int i=1; icount(); i++) { + int lnum=(i+current)%lines->count(); + QString str=lines->item(lnum)->text(); + if (str.contains(line)) { + lines->setCurrentRow(lnum); + return; + } + } + lines->setCurrentItem(NULL); + } +} + +NetHackQtMenuOrTextWindow::NetHackQtMenuOrTextWindow(QWidget *parent_) : + actual(0), + parent(parent_) +{ +} + +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"); + actual->Clear(); +} +void NetHackQtMenuOrTextWindow::Display(bool block) +{ + if (!actual) impossible("Display called before we know if Menu or Text"); + actual->Display(block); +} +bool NetHackQtMenuOrTextWindow::Destroy() +{ + if (!actual) impossible("Destroy called before we know if Menu or Text"); + return actual->Destroy(); +} + +void NetHackQtMenuOrTextWindow::PutStr(int attr, const QString& text) +{ + if (!actual) actual=new NetHackQtTextWindow(parent); + actual->PutStr(attr,text); +} + +// Menu +void NetHackQtMenuOrTextWindow::StartMenu() +{ + if (!actual) actual=new NetHackQtMenuWindow(parent); + actual->StartMenu(); +} +void NetHackQtMenuOrTextWindow::AddMenu(int glyph, const ANY_P* identifier, char ch, char gch, int attr, + const QString& 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 QString& 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); +} + +} // namespace nethack_qt4 diff --git a/win/Qt4/qt4menu.h b/win/Qt4/qt4menu.h new file mode 100644 index 000000000..ad15841bc --- /dev/null +++ b/win/Qt4/qt4menu.h @@ -0,0 +1,182 @@ +// 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 + +#ifndef QT4MENU_H +#define QT4MENU_H + +#include "qt4win.h" +#include "qt4rip.h" + +namespace nethack_qt4 { + +class NetHackQtTextListBox : public QListWidget { +public: + NetHackQtTextListBox(QWidget* parent = NULL) : QListWidget(parent) { } + + int TotalWidth() const + { + int width = 0; + QFontMetrics fm(font()); + for (int i = 0; i < count(); i++) { + int lwidth = fm.width(item(i)->text()); + width = std::max(width, lwidth); + } + return width; + } + int TotalHeight() const + { + QFontMetrics fm(font()); + return fm.height() * count(); + } + + virtual QSize sizeHint() const; +}; + +class NetHackQtMenuListBox : public QTableWidget { +public: + NetHackQtMenuListBox(QWidget* parent = NULL) : QTableWidget(parent) { } + + int TotalWidth() const; + int TotalHeight() const; + + virtual QSize sizeHint() const; +}; + +class NetHackQtMenuWindow : public QDialog, public NetHackQtWindow { + Q_OBJECT +public: + NetHackQtMenuWindow(QWidget *parent = NULL); + ~NetHackQtMenuWindow(); + + 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 EndMenu(const QString& prompt); + virtual int SelectMenu(int how, MENU_ITEM_P **menu_list); + +public slots: + void All(); + void ChooseNone(); + void Invert(); + void Search(); + + void ToggleSelect(int); + void DoSelection(bool); + +protected: + virtual void keyPressEvent(QKeyEvent*); + +private: + struct MenuItem { + MenuItem(); + ~MenuItem(); + + int glyph; + ANY_P identifier; + int attr; + QString str; + int count; + char ch; + char gch; + bool selected; + unsigned color; + + bool Selectable() const { return identifier.a_void!=0; } + }; + + QVector itemlist; + + int itemcount; + int next_accel; + + QTableWidget* table; + QPushButton* ok; + QPushButton* cancel; + QPushButton* all; + QPushButton* none; + QPushButton* invert; + QPushButton* search; + QLabel prompt; + + // Count replaces prompt while it is being input + QString promptstr; + QString countstr; + bool counting; + void InputCount(char key); + void ClearCount(void); + + int how; + + bool has_glyphs; + + bool isSelected(int row); + int count(int row); + + void AddRow(int row, const MenuItem& mi); + void WidenColumn(int column, int width); +}; + +class NetHackQtTextWindow : public QDialog, public NetHackQtWindow { + Q_OBJECT +public: + NetHackQtTextWindow(QWidget *parent = NULL); + ~NetHackQtTextWindow(); + + virtual QWidget* Widget(); + + virtual void Clear(); + virtual bool Destroy(); + virtual void Display(bool block); + virtual void PutStr(int attr, const QString& text); + virtual void UseRIP(int how, time_t when); + +public slots: + void Search(); + +private slots: + void doUpdate(); + +private: + bool use_rip; + bool str_fixed; + + QPushButton ok; + QPushButton search; + NetHackQtTextListBox* lines; + + NetHackQtRIP rip; +}; + +class NetHackQtMenuOrTextWindow : public NetHackQtWindow { +private: + NetHackQtWindow* actual; + QWidget *parent; + +public: + NetHackQtMenuOrTextWindow(QWidget *parent = NULL); + + virtual QWidget* Widget(); + + // Text + virtual void Clear(); + virtual bool Destroy(); + virtual void Display(bool block); + 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 EndMenu(const QString& prompt); + virtual int SelectMenu(int how, MENU_ITEM_P **menu_list); + +}; + +} // namespace nethack_qt4 + +#endif diff --git a/win/Qt4/qt4msg.cpp b/win/Qt4/qt4msg.cpp new file mode 100644 index 000000000..e1194795d --- /dev/null +++ b/win/Qt4/qt4msg.cpp @@ -0,0 +1,134 @@ +// Copyright (c) Warwick Allison, 1999. +// Qt4 conversion copyright (c) Ray Chason, 2012-2014. +// NetHack may be freely redistributed. See license for details. + +// qt4msg.cpp -- a message 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 "qt4msg.h" +#include "qt4msg.moc" +#include "qt4map.h" +#include "qt4set.h" +#include "qt4str.h" + +namespace nethack_qt4 { + +NetHackQtMessageWindow::NetHackQtMessageWindow() : + list(new QListWidget()) +{ + list->setFocusPolicy(Qt::NoFocus); + ::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(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, int dy) +{ + //RLC Is this necessary? + //RLC list->Scroll(dx,dy); +} + +void NetHackQtMessageWindow::Clear() +{ + if ( map ) + map->clearMessages(); +} + +void NetHackQtMessageWindow::Display(bool block) +{ + if (changed) { + list->repaint(); + changed=false; + } +} + +void NetHackQtMessageWindow::PutStr(int attr, const QString& text) +{ +#ifdef USER_SOUNDS + play_sound_for_message(text.toLatin1().constData()); +#endif + + 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 + QListWidgetItem *item = new QListWidgetItem(text2); + + QFont font = item->font(); + font.setUnderline(attr == ATR_ULINE); + font.setWeight((attr == ATR_BOLD) ? QFont::Bold : QFont::Normal); + item->setFont(font); + + QColor fg = item->foreground().color(); + QColor bg = item->background().color(); + if (attr == ATR_DIM) + { + fg.setAlpha(fg.alpha() / 2); + } + if (attr == ATR_INVERSE) + { + QColor swap; + swap = fg; fg = bg; bg = swap; + } + item->setForeground(fg); + item->setBackground(bg); +#endif + + // ATR_BLINK not supported + if (list->count() >= ::iflags.msg_history) + delete list->item(0); + list->addItem(text2); + + // Force scrollbar to bottom + list->setCurrentRow(list->count()-1); + + if ( map ) + map->putMessage(attr, text2); +} + +} // namespace nethack_qt4 diff --git a/win/Qt4/qt4msg.h b/win/Qt4/qt4msg.h new file mode 100644 index 000000000..5c391cc4f --- /dev/null +++ b/win/Qt4/qt4msg.h @@ -0,0 +1,42 @@ +// Copyright (c) Warwick Allison, 1999. +// Qt4 conversion copyright (c) Ray Chason, 2012-2014. +// NetHack may be freely redistributed. See license for details. + +// qt4msg.h -- a message window + +#ifndef QT4MSG_H +#define QT4MSG_H + +#include "qt4win.h" + +namespace nethack_qt4 { + +class NetHackQtMapWindow2; + +class NetHackQtMessageWindow : QObject, public NetHackQtWindow { + Q_OBJECT +public: + NetHackQtMessageWindow(); + ~NetHackQtMessageWindow(); + + virtual QWidget* Widget(); + virtual void Clear(); + virtual void Display(bool block); + virtual void PutStr(int attr, const QString& text); + + void Scroll(int dx, int dy); + + void setMap(NetHackQtMapWindow2*); + +private: + QListWidget* list; + bool changed; + NetHackQtMapWindow2* map; + +private slots: + void updateFont(); +}; + +} // namespace nethack_qt4 + +#endif diff --git a/win/Qt4/qt4plsel.cpp b/win/Qt4/qt4plsel.cpp new file mode 100644 index 000000000..56b8849bd --- /dev/null +++ b/win/Qt4/qt4plsel.cpp @@ -0,0 +1,502 @@ +// Copyright (c) Warwick Allison, 1999. +// Qt4 conversion copyright (c) Ray Chason, 2012-2014. +// NetHack may be freely redistributed. See license for details. + +// qt4plsel.cpp -- player selector dialog + +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 "qt4plsel.h" +#include "qt4plsel.moc" +#include "qt4bind.h" +#include "qt4glyph.h" +#include "qt4set.h" +#include "qt4str.h" + +// Warwick prefers it this way... +#define QT_CHOOSE_RACE_FIRST + +namespace nethack_qt4 { + +// temporary +void centerOnMain( QWidget* w ); +// end temporary + +static const char nh_attribution[] = "
NetHack" + "
by the NetHack DevTeam
"; + +class NhPSListViewItem : public QTableWidgetItem { +public: + NhPSListViewItem( QTableWidget* parent, const QString& name ) : + QTableWidgetItem(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(); + 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 + ) + { + setGlyph(monnum_to_glyph(roles[id].malenum)); + } +}; + +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 + ) + { + setGlyph(monnum_to_glyph(races[id].malenum)); + } +}; + +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()); + } +}; + +NetHackQtPlayerSelector::NetHackQtPlayerSelector(NetHackQtKeyBuffer& ks) : + QDialog(NetHackQtBind::mainWidget()), + 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 ] + +---------+ +---------+ + */ + + 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(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(); + QGroupBox* genderbox = new QGroupBox("Sex",this); + QButtonGroup *gendergroup = new QButtonGroup(this); + QGroupBox* alignbox = new QGroupBox("Alignment",this); + QButtonGroup *aligngroup = new QButtonGroup(this); + QVBoxLayout* vbgb = new QVBoxLayout(genderbox); + vbgb->addSpacing(fontMetrics().height()*3/4); + QVBoxLayout* vbab = new QVBoxLayout(alignbox); + vbab->addSpacing(fontMetrics().height()); + QLabel* logo = new QLabel(nh_attribution, this); + + l->addWidget( namebox, 0,0,1,3 ); +#ifdef QT_CHOOSE_RACE_FIRST + race = new NhPSListView(this); + role = new NhPSListView(this); + l->addWidget( race, 1,0,5,1 ); + l->addWidget( role, 1,1,5,1 ); +#else + role = new NhPSListView(this); + race = new NhPSListView(this); + l->addWidget( role, 1,0,5,1 ); + l->addWidget( race, 1,1,5,1 ); +#endif + + l->addWidget( genderbox, 1, 2 ); + l->addWidget( alignbox, 2, 2 ); + l->addWidget( logo, 3, 2, Qt::AlignCenter ); + l->setRowStretch( 3, 5 ); + + int i; + int nrole; + + // XXX QListView unsorted goes in rev. + for (nrole=0; roles[nrole].name.m; nrole++) + ; + role->setRowCount(nrole); + for (i=0; roles[i].name.m; i++) { + QTableWidgetItem *item = new QTableWidgetItem( + QIcon(qt_settings->glyphs().glyph(roles[i].malenum)), + roles[i].name.m); + item->setFlags(Qt::ItemIsEnabled|Qt::ItemIsSelectable); + role->setItem(i, 0, item); + } + connect( role, SIGNAL(currentCellChanged(int, int, int, int)), this, SLOT(selectRole(int, int, int, int)) ); + role->setHorizontalHeaderLabels(QStringList("Role")); + role->resizeColumnToContents(0); + + int nrace; + for (nrace=0; races[nrace].noun; nrace++) + ; + race->setRowCount(nrace); + for (i=0; races[i].noun; i++) { + QTableWidgetItem *item = new QTableWidgetItem( + QIcon(qt_settings->glyphs().glyph(races[i].malenum)), + races[i].noun); + item->setFlags(Qt::ItemIsEnabled|Qt::ItemIsSelectable); + race->setItem(i, 0, item); + } + connect( race, SIGNAL(currentCellChanged(int, int, int, int)), this, SLOT(selectRace(int, int, int, int)) ); + race->setHorizontalHeaderLabels(QStringList("Race")); + race->resizeColumnToContents(0); + + gender = new QRadioButton*[ROLE_GENDERS]; + for (i=0; ilayout()->addWidget(gender[i]); + gendergroup->addButton(gender[i], i); + } + connect( gendergroup, SIGNAL(buttonPressed(int)), this, SLOT(selectGender(int)) ); + + alignment = new QRadioButton*[ROLE_ALIGNS]; + for (i=0; ilayout()->addWidget(alignment[i]); + aligngroup->addButton(alignment[i], i); + } + connect( aligngroup, SIGNAL(buttonPressed(int)), this, SLOT(selectAlignment(int)) ); + + QPushButton* ok = new QPushButton("Play",this); + l->addWidget( 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); + + role->setCurrentCell(ro, 0); + + race->setCurrentCell(ra, 0); + + flags.initrace = race->currentRow(); + flags.initrole = role->currentRow(); +} + + +void NetHackQtPlayerSelector::selectName(const QString& n) +{ + str_copy(plname,n.toLatin1().constData(),SIZE(plname)); +} + +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; + 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; + int j; + for (j=0; roles[j].name.m; j++) { + bool v = validrace(j,ra); + item = role->item(j, 0); + item->setFlags(Qt::ItemIsEnabled|Qt::ItemIsSelectable); + if ( !valid && v ) valid = item; + } + if ( !validrace(role->currentRow(),ra) ) + i = valid; + role->setCurrentItem(i, 0); + for (j=0; roles[j].name.m; j++) { + item = role->item(j, 0); + item->setSelected(item == i); + bool v = validrace(j,ra); + item->setFlags( + v ? Qt::ItemIsEnabled|Qt::ItemIsSelectable + : Qt::NoItemFlags); + } +#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; + 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; + int j; + for (j=0; races[j].noun; j++) { + bool v = validrace(ro,j); + item = race->item(j, 0); + item->setFlags(Qt::ItemIsEnabled|Qt::ItemIsSelectable); + if ( !valid && v ) valid = item; + } + if ( !validrace(ro,race->currentRow()) ) + i = valid; + for (j=0; races[j].noun; j++) { + item = race->item(j, 0); + item->setSelected(item == i); + bool v = validrace(ro,j); + item->setFlags( + v ? Qt::ItemIsEnabled|Qt::ItemIsSelectable + : Qt::NoItemFlags); + } +#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) +{ + flags.initgend = i; +} + +void NetHackQtPlayerSelector::selectAlignment(int i) +{ + flags.initalign = i; +} + +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() ) { + return true; + } else { + return false; + } +} + +} // namespace nethack_qt4 diff --git a/win/Qt4/qt4plsel.h b/win/Qt4/qt4plsel.h new file mode 100644 index 000000000..b82341270 --- /dev/null +++ b/win/Qt4/qt4plsel.h @@ -0,0 +1,45 @@ +// Copyright (c) Warwick Allison, 1999. +// Qt4 conversion copyright (c) Ray Chason, 2012-2014. +// NetHack may be freely redistributed. See license for details. + +// qt4plsel.h -- player selector dialog + +#ifndef QT4PLSEL_H +#define QT4PLSEL_H + +namespace nethack_qt4 { + +class NetHackQtKeyBuffer; + +class NetHackQtPlayerSelector : private QDialog { + Q_OBJECT +public: + enum { R_None=-1, R_Quit=-2, R_Rand=-3 }; + + NetHackQtPlayerSelector(NetHackQtKeyBuffer&); + +public slots: + void Quit(); + void Random(); + + void selectName(const QString& n); + void selectRole(int current, int, int previous, int); + void selectRace(int current, int, int previous, int); + void setupOthers(); + void selectGender(int); + void selectAlignment(int); + +public: + bool Choose(); + +private: + QTableWidget* role; + QTableWidget* race; + QRadioButton **gender; + QRadioButton **alignment; + bool fully_specified_role; +}; + +} // namespace nethack_qt4 + +#endif diff --git a/win/Qt4/qt4rip.cpp b/win/Qt4/qt4rip.cpp new file mode 100644 index 000000000..d509f8895 --- /dev/null +++ b/win/Qt4/qt4rip.cpp @@ -0,0 +1,94 @@ +// Copyright (c) Warwick Allison, 1999. +// Qt4 conversion copyright (c) Ray Chason, 2012-2014. +// NetHack may be freely redistributed. See license for details. + +// qt4rip.cpp -- tombstone window + +#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 "qt4rip.h" +#include "qt4bind.h" +#include "qt4str.h" + +namespace nethack_qt4 { + +QPixmap* NetHackQtRIP::pixmap=0; + +// Debian uses a separate PIXMAPDIR +#ifndef PIXMAPDIR +# ifdef HACKDIR +# define PIXMAPDIR HACKDIR +# else +# define PIXMAPDIR "." +# endif +#endif + +static void +tryload(QPixmap& pm, const char* fn) +{ + if (!pm.load(fn)) { + QString msg; + msg.sprintf("Cannot load \"%s\"", fn); + QMessageBox::warning(NetHackQtBind::mainWidget(), "IO Error", msg); + } +} + +NetHackQtRIP::NetHackQtRIP(QWidget* parent) : + QWidget(parent) +{ + if (!pixmap) { + pixmap=new QPixmap; + tryload(*pixmap, PIXMAPDIR "/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; i +#if QT_VERSION >= 0x050000 +#include +#endif +#include "qt4set.h" +#include "qt4set.moc" +#include "qt4glyph.h" +#include "qt4str.h" + +/* 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_qt4 { + +#define TILEWMIN 1 +#define TILEHMIN 1 + +NetHackQtSettings::NetHackQtSettings(int w, int h) : + tilewidth(this), + tileheight(this), + widthlbl("&Width:",this), + heightlbl("&Height:",this), + whichsize("&Zoomed",this), + fontsize(this), + normal("times"), +#ifdef WS_WIN + normalfixed("courier new"), +#else + normalfixed("courier"), +#endif + large("times"), + theglyphs(0) + +{ + int default_fontsize; + + widthlbl.setBuddy(&tilewidth); + tilewidth.setRange(TILEWMIN, 128); + heightlbl.setBuddy(&tileheight); + tileheight.setRange(TILEHMIN, 128); + + default_fontsize=2; + tilewidth.setValue(16); + tileheight.setValue(16); + + // Tile/font sizes read from .nethackrc + if (qt_tilewidth != NULL) { + tilewidth.setValue(atoi(qt_tilewidth)); + delete[] qt_tilewidth; + } + if (qt_tileheight != NULL) { + tileheight.setValue(atoi(qt_tileheight)); + delete[] 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; + } + delete[] 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.addItem("Huge"); + fontsize.addItem("Large"); + fontsize.addItem("Medium"); + fontsize.addItem("Small"); + fontsize.addItem("Tiny"); + fontsize.setCurrentIndex(default_fontsize); + connect(&fontsize,SIGNAL(activated(int)),this,SIGNAL(fontChanged())); + + QGridLayout* grid = new QGridLayout(this); + grid->addWidget(&whichsize, 0, 0, 1, 2); + grid->addWidget(&tilewidth, 1, 1); grid->addWidget(&widthlbl, 1, 0); + grid->addWidget(&tileheight, 2, 1); grid->addWidget(&heightlbl, 2, 0); + QLabel* flabel=new QLabel("&Font:",this); + flabel->setBuddy(&fontsize); + grid->addWidget(flabel, 3, 0); grid->addWidget(&fontsize, 3, 1); + QPushButton* dismiss=new QPushButton("Dismiss",this); + dismiss->setDefault(true); + grid->addWidget(dismiss, 4, 0, 1, 2); + grid->setRowStretch(4,0); + grid->setColumnStretch(1,1); + grid->setColumnStretch(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.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; +} + +bool NetHackQtSettings::ynInMessages() +{ + return !qt_compact_mode && !iflags.wc_popup_dialog; +} + +NetHackQtSettings* qt_settings; + +} // namespace nethack_qt4 diff --git a/win/Qt4/qt4set.h b/win/Qt4/qt4set.h new file mode 100644 index 000000000..e2253a8d6 --- /dev/null +++ b/win/Qt4/qt4set.h @@ -0,0 +1,57 @@ +// Copyright (c) Warwick Allison, 1999. +// Qt4 conversion copyright (c) Ray Chason, 2012-2014. +// NetHack may be freely redistributed. See license for details. + +// qt4set.h -- the Qt settings + +#ifndef QT4SET_H +#define QT4SET_H + +namespace nethack_qt4 { + +class NetHackQtGlyphs; + +class NetHackQtSettings : public QDialog { + Q_OBJECT +public: + // Size of window - used to decide default sizes + NetHackQtSettings(int width, int height); + + NetHackQtGlyphs& glyphs(); + const QFont& normalFont(); + const QFont& normalFixedFont(); + const QFont& largeFont(); + + bool ynInMessages(); + +signals: + void fontChanged(); + void tilesChanged(); + +public slots: + void toggleGlyphSize(); + void setGlyphSize(bool); + +private: + QSpinBox tilewidth; + QSpinBox tileheight; + QLabel widthlbl; + QLabel heightlbl; + QCheckBox whichsize; + QSize othersize; + + QComboBox fontsize; + + QFont normal, normalfixed, large; + + NetHackQtGlyphs* theglyphs; + +private slots: + void resizeTiles(); +}; + +extern NetHackQtSettings* qt_settings; + +} // namespace nethack_qt4 + +#endif diff --git a/win/Qt4/qt4stat.cpp b/win/Qt4/qt4stat.cpp new file mode 100644 index 000000000..3a15604e5 --- /dev/null +++ b/win/Qt4/qt4stat.cpp @@ -0,0 +1,540 @@ +// Copyright (c) Warwick Allison, 1999. +// Qt4 conversion copyright (c) Ray Chason, 2012-2014. +// NetHack may be freely redistributed. See license for details. + +// qt4stat.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 +#if QT_VERSION >= 0x050000 +#include +#endif +#include "qt4stat.h" +#include "qt4stat.moc" +#include "qt4set.h" +#include "qt4str.h" +#include "qt_xpms.h" + +extern const char *enc_stat[]; /* from botl.c */ +extern const char *hu_stat[]; /* from eat.c */ + +namespace nethack_qt4 { + +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,""), + 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); + +#if 1 //RLC + name.setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum); + dlevel.setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum); + QVBoxLayout *vbox = new QVBoxLayout(); + vbox->setSpacing(0); + vbox->addWidget(&name); + vbox->addWidget(&dlevel); + vbox->addWidget(&hline1); + QHBoxLayout *atr1box = new QHBoxLayout(); + atr1box->addWidget(&str); + atr1box->addWidget(&dex); + atr1box->addWidget(&con); + atr1box->addWidget(&intel); + atr1box->addWidget(&wis); + atr1box->addWidget(&cha); + vbox->addLayout(atr1box); + vbox->addWidget(&hline2); + QHBoxLayout *atr2box = new QHBoxLayout(); + atr2box->addWidget(&gold); + atr2box->addWidget(&hp); + atr2box->addWidget(&power); + atr2box->addWidget(&ac); + atr2box->addWidget(&level); + atr2box->addWidget(&exp); + vbox->addLayout(atr2box); + vbox->addWidget(&hline3); + QHBoxLayout *timebox = new QHBoxLayout(); + timebox->addWidget(&time); + timebox->addWidget(&score); + vbox->addLayout(timebox); + QHBoxLayout *statbox = new QHBoxLayout(); + statbox->addWidget(&align); + statbox->addWidget(&hunger); + statbox->addWidget(&confused); + statbox->addWidget(&sick_fp); + statbox->addWidget(&sick_il); + statbox->addWidget(&blind); + statbox->addWidget(&stunned); + statbox->addWidget(&hallu); + statbox->addWidget(&encumber); + statbox->setAlignment(Qt::AlignLeft|Qt::AlignVCenter); + vbox->addLayout(statbox); + 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); + 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 QString& text) +{ + // 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; + 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; +#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. + */ +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; + + QString buf; + const char *text; + + if (cursy != 0) return; /* do a complete update when line 0 is done */ + + if (ACURR(A_STR) > 118) { + buf.sprintf("STR:%d",ACURR(A_STR)-100); + } else if (ACURR(A_STR)==118) { + buf.sprintf("STR:18/**"); + } else if(ACURR(A_STR) > 18) { + buf.sprintf("STR:18/%02d",ACURR(A_STR)-18); + } else { + buf.sprintf("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.setLabel("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(); + } + if (u.mtimedone) { + buf = nh_capitalize_words(mons[u.umonnum].mname); + } else { + buf = rank_of(u.ulevel, pl_character[0], ::flags.female); + } + QString buf2; + buf2.sprintf("%s the %s", plname, buf.toLatin1().constData()); + name.setLabel(buf2, NetHackQtLabelledIcon::NoNum, u.ulevel); + + char buf3[BUFSZ]; + if (describe_level(buf3)) { + dlevel.setLabel(buf3,true); + } else { + buf.sprintf("%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! + + buf.sprintf("/%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. + + buf.sprintf("/%d", u.uhpmax); + hp.setLabel("HP:", u.uhp > 0 ? u.uhp : 0, buf); + level.setLabel("Level:",(long)u.ulevel); + } + buf.sprintf("/%d", u.uenmax); + power.setLabel("Pow:", u.uen, buf); + ac.setLabel("AC:",(long)u.uac); +#ifdef EXP_ON_BOTL + if (::flags.showexp) { + exp.setLabel("Exp:",(long)u.uexp); + } else +#endif + { + exp.setLabel(""); + } + if (u.ualign.type==A_CHAOTIC) { + align.setIcon(p_chaotic); + text = "Chaotic"; + } else if (u.ualign.type==A_NEUTRAL) { + align.setIcon(p_neutral); + text = "Neutral"; + } else { + align.setIcon(p_lawful); + text = "Lawful"; + } + align.setLabel(text); + + 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() +{ +} + +} // namespace nethack_qt4 diff --git a/win/Qt4/qt4stat.h b/win/Qt4/qt4stat.h new file mode 100644 index 000000000..a0a00a46f --- /dev/null +++ b/win/Qt4/qt4stat.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. + +// qt4stat.h -- bindings between the Qt 4 interface and the main code + +#ifndef QT4STAT_H +#define QT4STAT_H + +#include "qt4win.h" +#include "qt4icon.h" + +namespace nethack_qt4 { + +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: + //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_satiated; + QPixmap p_hungry; + + QPixmap p_confused; + QPixmap p_sick_fp; + QPixmap p_sick_il; + QPixmap p_blind; + QPixmap p_stunned; + QPixmap p_hallu; + + QPixmap p_encumber[5]; + + NetHackQtLabelledIcon name; + NetHackQtLabelledIcon dlevel; + + NetHackQtLabelledIcon str; + NetHackQtLabelledIcon dex; + NetHackQtLabelledIcon con; + NetHackQtLabelledIcon intel; + NetHackQtLabelledIcon wis; + NetHackQtLabelledIcon cha; + + NetHackQtLabelledIcon gold; + NetHackQtLabelledIcon hp; + NetHackQtLabelledIcon power; + NetHackQtLabelledIcon ac; + NetHackQtLabelledIcon level; + NetHackQtLabelledIcon exp; + NetHackQtLabelledIcon align; + + NetHackQtLabelledIcon time; + NetHackQtLabelledIcon score; + + NetHackQtLabelledIcon hunger; + NetHackQtLabelledIcon confused; + NetHackQtLabelledIcon sick_fp; + NetHackQtLabelledIcon sick_il; + NetHackQtLabelledIcon blind; + NetHackQtLabelledIcon stunned; + NetHackQtLabelledIcon hallu; + NetHackQtLabelledIcon encumber; + + QFrame hline1; + QFrame hline2; + QFrame hline3; + + int cursy; + + bool first_set; + + void nullOut(); + void updateStats(); + void checkTurnEvents(); +}; + +} // namespace nethack_qt4 + +#endif diff --git a/win/Qt4/qt4str.cpp b/win/Qt4/qt4str.cpp new file mode 100644 index 000000000..b6b4440eb --- /dev/null +++ b/win/Qt4/qt4str.cpp @@ -0,0 +1,83 @@ +// Copyright (c) Warwick Allison, 1999. +// Qt4 conversion copyright (c) Ray Chason, 2012-2014. +// NetHack may be freely redistributed. See license for details. + +// qt4str.cpp -- some string functions + +#include +#include +#include "qt4str.h" + +namespace nethack_qt4 { + +// Bounded string copy +size_t str_copy(char *dest, const char *src, size_t max) +{ + size_t len = strlen(src); + if (max != 0) { + size_t csize = len; + if (len > max - 1) { + len = max - 1; + } + memcpy(dest, src, csize); + dest[csize] = '\0'; + } + return len; +} + +QString str_titlecase(const QString& str) +{ + if (str == "") { return str; } + + return str.left(1).toUpper() + str.mid(1).toLower(); +} + +QString nh_capitalize_words(const QString& str) +{ + QStringList words = str.split(" "); + for (size_t i = 0; i < words.size(); ++i) { + words[i] = str_titlecase(words[i]); + } + return words.join(" "); +} + +int cp437(int ch) +{ + static const unsigned short cp437table[] = { + 0x0000, 0x263A, 0x263B, 0x2665, 0x2666, 0x2663, 0x2660, 0x2022, + 0x25D8, 0x25CB, 0x25D9, 0x2642, 0x2640, 0x266A, 0x266B, 0x263C, + 0x25BA, 0x25C4, 0x2195, 0x203C, 0x00B6, 0x00A7, 0x25AC, 0x21A8, + 0x2191, 0x2193, 0x2192, 0x2190, 0x221F, 0x2194, 0x25B2, 0x25BC, + 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, + 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F, + 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, + 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F, + 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, + 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F, + 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, + 0x0058, 0x0059, 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F, + 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, + 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F, + 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, + 0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, 0x2302, + 0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x00E0, 0x00E5, 0x00E7, + 0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x00EC, 0x00C4, 0x00C5, + 0x00C9, 0x00E6, 0x00C6, 0x00F4, 0x00F6, 0x00F2, 0x00FB, 0x00F9, + 0x00FF, 0x00D6, 0x00DC, 0x00A2, 0x00A3, 0x00A5, 0x20A7, 0x0192, + 0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x00AA, 0x00BA, + 0x00BF, 0x2310, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB, + 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, + 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x255B, 0x2510, + 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F, + 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567, + 0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B, + 0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580, + 0x03B1, 0x00DF, 0x0393, 0x03C0, 0x03A3, 0x03C3, 0x00B5, 0x03C4, + 0x03A6, 0x0398, 0x03A9, 0x03B4, 0x221E, 0x03C6, 0x03B5, 0x2229, + 0x2261, 0x00B1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00F7, 0x2248, + 0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0, + }; + return cp437table[(unsigned char)ch]; +} + +} // namespace nethack_qt4 diff --git a/win/Qt4/qt4str.h b/win/Qt4/qt4str.h new file mode 100644 index 000000000..05f25f4c4 --- /dev/null +++ b/win/Qt4/qt4str.h @@ -0,0 +1,24 @@ +// Copyright (c) Warwick Allison, 1999. +// Qt4 conversion copyright (c) Ray Chason, 2012-2014. +// NetHack may be freely redistributed. See license for details. + +// qt4str.h -- various string functions + +#ifndef QT4STR_H +#define QT4STR_H + +namespace nethack_qt4 { + +// Bounded string copy +extern size_t str_copy(char *dest, const char *src, size_t max); + +// Case mappings +extern QString str_titlecase(const QString& str); +extern QString nh_capitalize_words(const QString& str); + +// Map symbol conversion +extern int cp437(int ch); + +} // namespace nethack_qt4 + +#endif diff --git a/win/Qt4/qt4streq.cpp b/win/Qt4/qt4streq.cpp new file mode 100644 index 000000000..5d03bb996 --- /dev/null +++ b/win/Qt4/qt4streq.cpp @@ -0,0 +1,99 @@ +// Copyright (c) Warwick Allison, 1999. +// Qt4 conversion copyright (c) Ray Chason, 2012-2014. +// NetHack may be freely redistributed. See license for details. + +// qt4streq.cpp -- string requestor + +#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 "qt4streq.h" +#include "qt4str.h" + +namespace nethack_qt4 { + +// temporary +void centerOnMain(QWidget *); +// end temporary + +NetHackQtStringRequestor::NetHackQtStringRequestor(QWidget *parent, const char* p, const char* cancelstr) : + QDialog(parent), + prompt(QString::fromLatin1(p),this), + input(this,"input") +{ + 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(Qt::StrongFocus); +} + +void NetHackQtStringRequestor::resizeEvent(QResizeEvent*) +{ + const int margin=5; + const int gutter=5; + + int h=(height()-margin*2-gutter); + + if (prompt.text().size() > 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); + } + + 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); +} + +bool NetHackQtStringRequestor::Get(char* buffer, int maxchar) +{ + input.setMaxLength(maxchar); + if (prompt.text().size() > 16) { + resize(fontMetrics().width(prompt.text())+50,fontMetrics().height()*6); + } else { + resize(fontMetrics().width(prompt.text())*2+50,fontMetrics().height()*4); + } + + centerOnMain(this); + show(); + input.setFocus(); + exec(); + + if (result()) { + str_copy(buffer,input.text().toLatin1().constData(),maxchar); + return true; + } else { + return false; + } +} + +} // namespace nethack_qt4 diff --git a/win/Qt4/qt4streq.h b/win/Qt4/qt4streq.h new file mode 100644 index 000000000..a5f05d769 --- /dev/null +++ b/win/Qt4/qt4streq.h @@ -0,0 +1,30 @@ +// Copyright (c) Warwick Allison, 1999. +// Qt4 conversion copyright (c) Ray Chason, 2012-2014. +// NetHack may be freely redistributed. See license for details. + +// qt4streq.h -- string requestor + +#ifndef QT4STREQ_H +#define QT4STREQ_H + +#include "qt4line.h" + +namespace nethack_qt4 { + +class NetHackQtStringRequestor : QDialog { +private: + QLabel prompt; + NetHackQtLineEdit input; + QPushButton* okay; + QPushButton* cancel; + +public: + NetHackQtStringRequestor(QWidget *parent, const char* p,const char* cancelstr="Cancel"); + void SetDefault(const char*); + bool Get(char* buffer, int maxchar=80); + virtual void resizeEvent(QResizeEvent*); +}; + +} // namespace nethack_qt4 + +#endif diff --git a/win/Qt4/qt4svsel.cpp b/win/Qt4/qt4svsel.cpp new file mode 100644 index 000000000..0b5271588 --- /dev/null +++ b/win/Qt4/qt4svsel.cpp @@ -0,0 +1,80 @@ +// Copyright (c) Warwick Allison, 1999. +// Qt4 conversion copyright (c) Ray Chason, 2012-2014. +// NetHack may be freely redistributed. See license for details. + +// qt4svsel.cpp -- saved game selector + +#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 "qt4svsel.h" +#include "qt4bind.h" +#include "qt4str.h" + +namespace nethack_qt4 { + +NetHackQtSavedGameSelector::NetHackQtSavedGameSelector(const char** saved) : + QDialog(NetHackQtBind::mainWidget()) +{ + QVBoxLayout *vbl = new QVBoxLayout(this); + QHBoxLayout* hb; + + QLabel* logo = new QLabel(this); vbl->addWidget(logo); + logo->setAlignment(Qt::AlignCenter); + logo->setPixmap(QPixmap("nhsplash.xpm")); + QLabel* attr = new QLabel("by the NetHack DevTeam",this); + attr->setAlignment(Qt::AlignCenter); + vbl->addWidget(attr); + vbl->addStretch(2); + /* + QLabel* logo = new QLabel(hb); + hb = new QHBox(this); + vbl->addWidget(hb, Qt::AlignCenter); + logo->setPixmap(QPixmap(nh_icon)); + logo->setAlignment(AlignRight|Qt::AlignVCenter); + new QLabel(nh_attribution,hb); + */ + + hb = new QHBoxLayout(this); + 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); + QButtonGroup *bg = new QButtonGroup(this); + vbl->addWidget(box); + QVBoxLayout *bgl = new QVBoxLayout(box); + connect(bg, SIGNAL(buttonPressed(int)), this, SLOT(done(int))); + for (int i=0; saved[i]; i++) { + QPushButton* b = new QPushButton(saved[i],box); + bg->addButton(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; +} + +} // namespace nethack_qt4 diff --git a/win/Qt4/qt4svsel.h b/win/Qt4/qt4svsel.h new file mode 100644 index 000000000..918e6f7e3 --- /dev/null +++ b/win/Qt4/qt4svsel.h @@ -0,0 +1,21 @@ +// Copyright (c) Warwick Allison, 1999. +// Qt4 conversion copyright (c) Ray Chason, 2012-2014. +// NetHack may be freely redistributed. See license for details. + +// qt4svsel.h -- saved game selector + +#ifndef QT4SVSEL_H +#define QT4SVSEL_H + +namespace nethack_qt4 { + +class NetHackQtSavedGameSelector : public QDialog { +public: + NetHackQtSavedGameSelector(const char** saved); + + int choose(); +}; + +} // namespace nethack_qt4 + +#endif diff --git a/win/Qt4/qt4win.cpp b/win/Qt4/qt4win.cpp new file mode 100644 index 000000000..ca0abe57b --- /dev/null +++ b/win/Qt4/qt4win.cpp @@ -0,0 +1,136 @@ +// 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 +// +// Copyright (C) 1996-2001 by Warwick W. Allison (warwick@troll.no) +// +// Contributors: +// Michael Hohmuth +// - Userid control +// Svante Gerhard +// - .nethackrc tile and font size settings +// Dirk Schoenberger +// - KDE support +// - SlashEm support +// and many others for bug reports. +// +// 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 and click buffer) +// 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 +// 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::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 +// demand complete keyboard control (while Qt and X11 conspire to make this +// difficult by having widget-based focus rather than application based - +// a good thing in general). This problem is solved by again using the key +// event buffer. +// +// Out of all this hackery comes a silver lining however, as macros for +// the super-expert and menus for the ultra-newbie are also made possible +// by the key event buffer. +// + +// 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 QT_DEPRECATED_WARNINGS +#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 "qt4win.h" +#include "qt4bind.h" +#include "qt4click.h" +#include "qt4glyph.h" +#include "qt4inv.h" +#include "qt4key.h" +#include "qt4icon.h" +#include "qt4map.h" +#include "qt4menu.h" +#include "qt4msg.h" +#include "qt4set.h" + +#include + +#include "qt4clust.h" + +#include + +#ifdef _WS_X11_ +// For userid control +#include +#endif + +#ifdef USER_SOUNDS +#if QT_VERSION >= 0x050000 +# include +# else +# include +# endif +#endif + + +#ifdef USER_SOUNDS +extern void play_sound_for_message(const std::string& str); +#endif + +namespace nethack_qt4 { + +void +centerOnMain( QWidget* w ) +{ + QWidget* m = NetHackQtBind::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 ); +} + +NetHackQtWindow::NetHackQtWindow() +{ +} +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 QString& 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 QString& str, bool presel) { puts("unexpected AddMenu"); } +void NetHackQtWindow::EndMenu(const QString& 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::PrintGlyphCompose(int x,int y,int,int) { puts("unexpected PrintGlyphCompose"); } +void NetHackQtWindow::UseRIP(int how, time_t when) { puts("unexpected UseRIP"); } + +} // namespace nethack_qt4 diff --git a/win/Qt4/qt4win.h b/win/Qt4/qt4win.h new file mode 100644 index 000000000..02e96cd31 --- /dev/null +++ b/win/Qt4/qt4win.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 Binding for NetHack 3.4 +// +// 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 +// and click buffer rather), but also because this is my first +// major application of Qt. +// + +#ifndef qt4win_h +#define qt4win_h + +namespace nethack_qt4 { + +class NetHackQtWindow { +public: + NetHackQtWindow(); + virtual ~NetHackQtWindow(); + + virtual QWidget* Widget() =0; + + virtual void Clear(); + virtual void Display(bool block); + virtual bool Destroy(); + 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 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 UseRIP(int how, time_t when); + + int nhid; +}; + +} // namespace nethack_qt4 + +#endif diff --git a/win/Qt4/qt4xcmd.cpp b/win/Qt4/qt4xcmd.cpp new file mode 100644 index 000000000..3e8703e49 --- /dev/null +++ b/win/Qt4/qt4xcmd.cpp @@ -0,0 +1,134 @@ +// Copyright (c) Warwick Allison, 1999. +// Qt4 conversion copyright (c) Ray Chason, 2012-2014. +// NetHack may be freely redistributed. See license for details. + +// qt4xcmd.cpp -- extended command widget + +#include "hack.h" +#include "func_tab.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 "qt4xcmd.h" +#include "qt4xcmd.moc" +#include "qt4bind.h" +#include "qt4set.h" +#include "qt4str.h" + +namespace nethack_qt4 { + +// temporary +void centerOnMain(QWidget *); +// end temporary + +NetHackQtExtCmdRequestor::NetHackQtExtCmdRequestor(QWidget *parent) : + QDialog(parent) +{ + QVBoxLayout *l = new QVBoxLayout(this); + + QPushButton* can = new QPushButton("Cancel", this); + can->setDefault(true); + can->setMinimumSize(can->sizeHint()); + l->addWidget(can); + + prompt = new QLabel("#", this); + l->addWidget(prompt); + + QButtonGroup *group=new QButtonGroup(this); + 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 = std::max(butw,30+fm.width(extcmdlist[i].ef_txt)); + } + int ncols=4; + + QVBoxLayout* bl = new QVBoxLayout(grid); + bl->addSpacing(fm.height()); + QGridLayout* gl = new QGridLayout(); + 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->addButton(pb, i+1); + gl->addWidget(pb,i/ncols,i%ncols); + } + group->addButton(can, 0); + connect(group,SIGNAL(buttonPressed(int)),this,SLOT(done(int))); + + bl->activate(); + l->activate(); + resize(1,1); +} + +void NetHackQtExtCmdRequestor::cancel() +{ + reject(); +} + +void NetHackQtExtCmdRequestor::keyPressEvent(QKeyEvent *event) +{ + QString text = event->text(); + if (text == "\r" || text == "\n" || text == " " || text == "\033") + { + reject(); + } + else if (text == "\b") + { + QString promptstr = prompt->text(); + if (promptstr != "#") + prompt->setText(promptstr.left(promptstr.size()-1)); + } + else + { + QString promptstr = prompt->text() + text; + QString typedstr = promptstr.mid(1); // skip the '#' + unsigned matches = 0; + unsigned match = 0; + for (unsigned i=0; extcmdlist[i].ef_txt; i++) { + if (QString(extcmdlist[i].ef_txt).startsWith(typedstr)) { + ++matches; + if (matches >= 2) + break; + match = i; + } + } + if (matches == 1) + done(match+1); + else if (matches >= 2) + prompt->setText(promptstr); + } +} + +int NetHackQtExtCmdRequestor::get() +{ + const int none = -10; + resize(1,1); // pack + centerOnMain(this); + // Add any keys presently buffered to the prompt + setResult(none); + while (NetHackQtBind::qt_kbhit() && result() == none) { + int ch = NetHackQtBind::qt_nhgetch(); + QKeyEvent event(QEvent::KeyPress, 0, Qt::NoModifier, QChar(ch)); + keyPressEvent(&event); + } + if (result() == none) + exec(); + return result()-1; +} + +} // namespace nethack_qt4 diff --git a/win/Qt4/qt4xcmd.h b/win/Qt4/qt4xcmd.h new file mode 100644 index 000000000..29ba23f0d --- /dev/null +++ b/win/Qt4/qt4xcmd.h @@ -0,0 +1,31 @@ +// Copyright (c) Warwick Allison, 1999. +// Qt4 conversion copyright (c) Ray Chason, 2012-2014. +// NetHack may be freely redistributed. See license for details. + +// qt4xcmd.h -- extended command widget + +#ifndef QT4XCMD_H +#define QT4XCMD_H + +namespace nethack_qt4 { + +class NetHackQtExtCmdRequestor : public QDialog { + Q_OBJECT + +protected: + virtual void keyPressEvent(QKeyEvent *event); + +public: + NetHackQtExtCmdRequestor(QWidget *parent); + int get(); + +private: + QLabel *prompt; + +private slots: + void cancel(); +}; + +} // namespace nethack_qt4 + +#endif diff --git a/win/Qt4/qt4yndlg.cpp b/win/Qt4/qt4yndlg.cpp new file mode 100644 index 000000000..e315189de --- /dev/null +++ b/win/Qt4/qt4yndlg.cpp @@ -0,0 +1,244 @@ +// Copyright (c) Warwick Allison, 1999. +// Qt4 conversion copyright (c) Ray Chason, 2012-2014. +// NetHack may be freely redistributed. See license for details. + +// qt4yndlg.cpp -- yes/no dialog + +#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 "qt4yndlg.h" +#include "qt4yndlg.moc" +#include "qt4str.h" + +// temporary +extern int qt_compact_mode; +// end temporary + +namespace nethack_qt4 { + +// 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') +{ + setWindowTitle("NetHack: Question"); +} + +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].unicode(); + } else if ( from != 0 ) { + for (unsigned f=from+1; 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 = 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()>40; + 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::null : qlabel, this); + vb->addWidget(group); + QHBoxLayout *groupbox = new QHBoxLayout(); + group->setLayout(groupbox); + QButtonGroup *bgroup = new QButtonGroup(group); + + int nchoices=ch.length(); + + bool allow_count=ch.contains('#'); + QString yn = "yn", ynq = "ynq"; + bool is_ynq = ch == yn || ch == ynq; + + 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; + } + groupbox->addWidget(button); + bgroup->addButton(button, i); + } + + connect(bgroup,SIGNAL(buttonClicked(int)),this,SLOT(doneItem(int))); + + QLabel* lb=0; + QLineEdit* le=0; + + if (allow_count) { + QHBoxLayout *hb = new QHBoxLayout(this); + lb=new QLabel("Count: "); + hb->addWidget(lb); + le=new QLineEdit(); + hb->addWidget(le); + vb->addLayout(hb); + } + + setLayout(vb); + adjustSize(); + centerOnMain(this); + show(); + char choice=0; + char ch_esc=0; + for (uint i=0; i= 1000 ) { + choice = ch[result() - 1000].unicode(); + } + if (allow_count && !le->text().isEmpty()) { + yn_number=le->text().toInt(); + choice='#'; + } + return choice; + } else { + QLabel label(qlabel,this); + QPushButton cancel("Dismiss",this); + label.setFrameStyle(QFrame::Box|QFrame::Sunken); + label.setAlignment(Qt::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(); + keypress = '\033'; + exec(); + return keypress; + } +} + +void NetHackQtYnDialog::keyPressEvent(QKeyEvent* event) +{ + // Don't want QDialog's Return/Esc behaviour + //RLC ...or do we? + QString text(event->text()); + if (choices == NULL || choices[0] == 0) { + if (text != "") { + keypress = text.toUcs4()[0]; + done(1); + } + } else { + int where = QString::fromLatin1(choices).indexOf(text); + if (where != -1 && text != "#") { + done(where+1000); + } else { + QDialog::keyPressEvent(event); + } + } +} + +void NetHackQtYnDialog::doneItem(int i) +{ + done(i+1000); +} + +} // namespace nethack_qt4 diff --git a/win/Qt4/qt4yndlg.h b/win/Qt4/qt4yndlg.h new file mode 100644 index 000000000..d1474f541 --- /dev/null +++ b/win/Qt4/qt4yndlg.h @@ -0,0 +1,34 @@ +// Copyright (c) Warwick Allison, 1999. +// Qt4 conversion copyright (c) Ray Chason, 2012-2014. +// NetHack may be freely redistributed. See license for details. + +// qt4yndlg.h -- yes/no dialog + +#ifndef QT4YNDLG_H +#define QT4YNDLG_H + +namespace nethack_qt4 { + +class NetHackQtYnDialog : QDialog { + Q_OBJECT +private: + QString question; + const char* choices; + char def; + char keypress; + +protected: + virtual void keyPressEvent(QKeyEvent*); + +private slots: + void doneItem(int); + +public: + NetHackQtYnDialog(QWidget *,const QString&,const char*,char); + + char Exec(); +}; + +} // namespace nethack_qt4 + +#endif