OSDN Git Service

upgrade to 3.6.2
[jnethack/source.git] / win / Qt4 / qt4main.cpp
1 // Copyright (c) Warwick Allison, 1999.
2 // Qt4 conversion copyright (c) Ray Chason, 2012-2014.
3 // NetHack may be freely redistributed.  See license for details.
4
5 // qt4main.cpp -- the main window
6
7 extern "C" {
8 #include "hack.h"
9 }
10 #include "patchlevel.h"
11 #undef Invisible
12 #undef Warning
13 #undef index
14 #undef msleep
15 #undef rindex
16 #undef wizard
17 #undef yn
18 #undef min
19 #undef max
20
21 #include <QtGui/QtGui>
22 #if QT_VERSION >= 0x050000
23 #include <QtWidgets/QtWidgets>
24 #endif
25 #include "qt4main.h"
26 #include "qt4main.moc"
27 #include "qt4bind.h"
28 #include "qt4glyph.h"
29 #include "qt4inv.h"
30 #include "qt4key.h"
31 #include "qt4map.h"
32 #include "qt4msg.h"
33 #include "qt4set.h"
34 #include "qt4stat.h"
35 #include "qt4str.h"
36
37 #ifndef KDE
38 #include "qt4kde0.moc"
39 #endif
40
41 // temporary
42 extern char *qt_tilewidth;
43 extern char *qt_tileheight;
44 extern int qt_compact_mode;
45 // end temporary
46
47 namespace nethack_qt4 {
48
49 // temporary
50 void centerOnMain( QWidget* w );
51 // end temporary
52
53 /* XPM */
54 static const char * nh_icon[] = {
55 "40 40 6 1",
56 "       s None c none",
57 ".      c #ffffff",
58 "X      c #dadab6",
59 "o      c #6c91b6",
60 "O      c #476c6c",
61 "+      c #000000",
62 "                                        ",
63 "                                        ",
64 "                                        ",
65 "        .      .X..XX.XX      X         ",
66 "        ..   .....X.XXXXXX   XX         ",
67 "        ... ....X..XX.XXXXX XXX         ",
68 "   ..   ..........X.XXXXXXXXXXX   XX    ",
69 "   .... ........X..XX.XXXXXXXXX XXXX    ",
70 "   .... ..........X.XXXXXXXXXXX XXXX    ",
71 "   ooOOO..ooooooOooOOoOOOOOOOXX+++OO++  ",
72 "   ooOOO..ooooooooOoOOOOOOOOOXX+++OO++  ",
73 "   ....O..ooooooOooOOoOOOOOOOXX+XXXX++  ",
74 "   ....O..ooooooooOoOOOOOOOOOXX+XXXX++  ",
75 "   ..OOO..ooooooOooOOoOOOOOOOXX+++XX++  ",
76 "    ++++..ooooooooOoOOOOOOOOOXX+++ +++  ",
77 "     +++..ooooooOooOOoOOOOOOOXX+++  +   ",
78 "      ++..ooooooooOoOOOOOOOOOXX+++      ",
79 "        ..ooooooOooOOoOOOOOOOXX+++      ",
80 "        ..ooooooooOoOOOOOOOOOXX+++      ",
81 "        ..ooooooOooOOoOOOOOOOXX+++      ",
82 "        ..ooooooooOoOOOOOOOOOXX+++      ",
83 "         ..oooooOooOOoOOOOOOXX+++       ",
84 "         ..oooooooOoOOOOOOOOXX+++       ",
85 "          ..ooooOooOOoOOOOOXX+++        ",
86 "          ..ooooooOoOOOOOOOXX++++       ",
87 "        ..o..oooOooOOoOOOOXX+XX+++      ",
88 "       ...o..oooooOoOOOOOXX++XXX++      ",
89 "      ....OO..ooOooOOoOOXX+++XXXX++     ",
90 "     ...oo..+..oooOoOOOXX++XXooXXX++    ",
91 "    ...ooo..++..OooOOoXX+++XXooOXXX+    ",
92 "   ..oooOOXX+++....XXXX++++XXOOoOOXX+   ",
93 "   ..oooOOXX+++ ...XXX+++++XXOOooOXX++  ",
94 "   ..oooOXXX+++  ..XX+++  +XXOOooOXX++  ",
95 "   .....XXX++++             XXXXXXX++   ",
96 "    ....XX++++              XXXXXXX+    ",
97 "     ...XX+++                XXXXX++    ",
98 "                                        ",
99 "                                        ",
100 "                                        ",
101 "                                        "};
102 /* XPM */
103 static const char * nh_icon_small[] = {
104 /* width height ncolors chars_per_pixel */
105 "16 16 16 1",
106 /* colors */
107 "  c #587070",
108 ". c #D1D5C9",
109 "X c #8B8C84",
110 "o c #2A2A28",
111 "O c #9AABA9",
112 "+ c #6A8FB2",
113 "@ c #C4CAC4",
114 "# c #B6BEB6",
115 "$ c None",
116 "% c #54564E",
117 "& c #476C6C",
118 "* c #ADB2AB",
119 "= c #ABABA2",
120 "- c #5E8295",
121 "; c #8B988F",
122 ": c #E8EAE7",
123 /* pixels */
124 "$$$$$$$$$$$$$$$$",
125 "$$$.$#::.#==*$$$",
126 "$.*:::::....#*=$",
127 "$@#:..@#*==#;XX;",
128 "$@O:+++- &&; X%X",
129 "$#%.+++- &&;% oX",
130 "$$o.++-- &&;%%X$",
131 "$$$:++-- &&;%%$$",
132 "$$$.O++- &&=o $$",
133 "$$$=:++- & XoX$$",
134 "$$*:@O--  ;%Xo$$",
135 "$*:O#$+--;oOOX $",
136 "$:+ =o::=oo=-;%X",
137 "$::.%o$*;X;##@%$",
138 "$$@# ;$$$$$=*;X$",
139 "$$$$$$$$$$$$$$$$"
140 };
141
142 #if 0 // RLC
143 /* XPM */
144 static const char * map_xpm[] = {
145 "12 13 4 1",
146 ".      c None",
147 "       c #000000000000",
148 "X      c #0000B6DAFFFF",
149 "o      c #69A69248B6DA",
150 "           .",
151 " XXXXX ooo  ",
152 " XoooX o    ",
153 " XoooX o o  ",
154 " XoooX ooo  ",
155 " XXoXX o    ",
156 "  oooooXXX  ",
157 " oo o oooX  ",
158 "    o XooX  ",
159 " oooo XooX  ",
160 " o  o XXXX  ",
161 "            ",
162 ".           "};
163 /* XPM */
164 static const char * msg_xpm[] = {
165 "12 13 4 1",
166 ".      c None",
167 "       c #FFFFFFFFFFFF",
168 "X      c #69A69248B6DA",
169 "o      c #000000000000",
170 "           .",
171 " XXX XXX X o",
172 "           o",
173 " XXXXX XX  o",
174 "           o",
175 " XX XXXXX  o",
176 "           o",
177 " XXXXXX    o",
178 "           o",
179 " XX XXX XX o",
180 "           o",
181 "           o",
182 ".ooooooooooo"};
183 /* XPM */
184 static const char * stat_xpm[] = {
185 "12 13 5 1",
186 "  c None",
187 ".      c #FFFF00000000",
188 "X      c #000000000000",
189 "o      c #FFFFFFFF0000",
190 "O      c #69A6FFFF0000",
191 "            ",
192 "            ",
193 "...         ",
194 "...X        ",
195 "...X    ... ",
196 "oooX    oooX",
197 "oooXooo oooX",
198 "OOOXOOOXOOOX",
199 "OOOXOOOXOOOX",
200 "OOOXOOOXOOOX",
201 "OOOXOOOXOOOX",
202 "OOOXOOOXOOOX",
203 " XXXXXXXXXXX"};
204 #endif
205 /* XPM */
206 static const char * info_xpm[] = {
207 "12 13 4 1",
208 "  c None",
209 ".      c #00000000FFFF",
210 "X      c #FFFFFFFFFFFF",
211 "o      c #000000000000",
212 "    ...     ",
213 "  .......   ",
214 " ...XXX...  ",
215 " .........o ",
216 "...XXXX.... ",
217 "....XXX....o",
218 "....XXX....o",
219 "....XXX....o",
220 " ...XXX...oo",
221 " ..XXXXX..o ",
222 "  .......oo ",
223 "   o...ooo  ",
224 "     ooo    "};
225
226
227 /* XPM */
228 static const char * again_xpm[] = {
229 "12 13 2 1",
230 "       c None",
231 ".      c #000000000000",
232 "    ..      ",
233 "     ..     ",
234 "   .....    ",
235 " .......    ",
236 "...  ..  .. ",
237 "..  ..   .. ",
238 "..        ..",
239 "..        ..",
240 "..        ..",
241 " ..      .. ",
242 " .......... ",
243 "   ......   ",
244 "            "};
245 /* XPM */
246 static const char * kick_xpm[] = {
247 "12 13 3 1",
248 "       c None",
249 ".      c #000000000000",
250 "X      c #FFFF6DB60000",
251 "            ",
252 "            ",
253 "   .  .  .  ",
254 "  ...  .  . ",
255 "   ...  .   ",
256 "    ...  .  ",
257 "     ...    ",
258 "XXX   ...   ",
259 "XXX.  ...   ",
260 "XXX. ...    ",
261 "XXX. ..     ",
262 " ...        ",
263 "            "};
264 /* XPM */
265 static const char * throw_xpm[] = {
266 "12 13 3 1",
267 "       c None",
268 ".      c #FFFF6DB60000",
269 "X      c #000000000000",
270 "            ",
271 "            ",
272 "            ",
273 "            ",
274 "....     X  ",
275 "....X     X ",
276 "....X XXXXXX",
277 "....X     X ",
278 " XXXX    X  ",
279 "            ",
280 "            ",
281 "            ",
282 "            "};
283 /* XPM */
284 static const char * fire_xpm[] = {
285 "12 13 5 1",
286 "       c None",
287 ".      c #B6DA45140000",
288 "X      c #FFFFB6DA9658",
289 "o      c #000000000000",
290 "O      c #FFFF6DB60000",
291 " .          ",
292 " X.         ",
293 " X .        ",
294 " X .o       ",
295 " X  .    o  ",
296 " X  .o    o ",
297 "OOOOOOOOoooo",
298 " X  .o    o ",
299 " X . o   o  ",
300 " X .o       ",
301 " X. o       ",
302 " . o        ",
303 "  o         "};
304 /* XPM */
305 static const char * get_xpm[] = {
306 "12 13 3 1",
307 "       c None",
308 ".      c #000000000000",
309 "X      c #FFFF6DB60000",
310 "            ",
311 "     .      ",
312 "    ...     ",
313 "   . . .    ",
314 "     .      ",
315 "     .      ",
316 "            ",
317 "   XXXXX    ",
318 "   XXXXX.   ",
319 "   XXXXX.   ",
320 "   XXXXX.   ",
321 "    .....   ",
322 "            "};
323 /* XPM */
324 static const char * drop_xpm[] = {
325 "12 13 3 1",
326 "       c None",
327 ".      c #FFFF6DB60000",
328 "X      c #000000000000",
329 "            ",
330 "   .....    ",
331 "   .....X   ",
332 "   .....X   ",
333 "   .....X   ",
334 "    XXXXX   ",
335 "            ",
336 "      X     ",
337 "      X     ",
338 "    X X X   ",
339 "     XXX    ",
340 "      X     ",
341 "            "};
342 /* XPM */
343 static const char * eat_xpm[] = {
344 "12 13 4 1",
345 "       c None",
346 ".      c #000000000000",
347 "X      c #FFFFB6DA9658",
348 "o      c #FFFF6DB60000",
349 "  .X.  ..   ",
350 "  .X.  ..   ",
351 "  .X.  ..   ",
352 "  .X.  ..   ",
353 "  ...  ..   ",
354 "   ..  ..   ",
355 "   ..  ..   ",
356 "   oo  oo   ",
357 "   oo  oo   ",
358 "   oo  oo   ",
359 "   oo  oo   ",
360 "   oo  oo   ",
361 "   oo  oo   "};
362 /* XPM */
363 static const char * rest_xpm[] = {
364 "12 13 2 1",
365 "       c None",
366 ".      c #000000000000",
367 "  .....     ",
368 "     .      ",
369 "    .       ",
370 "   .    ....",
371 "  .....   . ",
372 "         .  ",
373 "        ....",
374 "            ",
375 "     ....   ",
376 "       .    ",
377 "      .     ",
378 "     ....   ",
379 "            "};
380 /* XPM */
381 static const char * cast_a_xpm[] = {
382 "12 13 3 1",
383 "       c None",
384 ".      c #FFFF6DB60000",
385 "X      c #000000000000",
386 "    .       ",
387 "    .       ",
388 "   ..       ",
389 "   ..       ",
390 "  ..  .     ",
391 "  ..  .     ",
392 " ......     ",
393 " .. ..  XX  ",
394 "    .. X  X ",
395 "   ..  X  X ",
396 "   ..  XXXX ",
397 "   .   X  X ",
398 "   .   X  X "};
399 /* XPM */
400 static const char * cast_b_xpm[] = {
401 "12 13 3 1",
402 "       c None",
403 ".      c #FFFF6DB60000",
404 "X      c #000000000000",
405 "    .       ",
406 "    .       ",
407 "   ..       ",
408 "   ..       ",
409 "  ..  .     ",
410 "  ..  .     ",
411 " ......     ",
412 " .. .. XXX  ",
413 "    .. X  X ",
414 "   ..  XXX  ",
415 "   ..  X  X ",
416 "   .   X  X ",
417 "   .   XXX  "};
418 /* XPM */
419 static const char * cast_c_xpm[] = {
420 "12 13 3 1",
421 "       c None",
422 ".      c #FFFF6DB60000",
423 "X      c #000000000000",
424 "    .       ",
425 "    .       ",
426 "   ..       ",
427 "   ..       ",
428 "  ..  .     ",
429 "  ..  .     ",
430 " ......     ",
431 " .. ..  XX  ",
432 "    .. X  X ",
433 "   ..  X    ",
434 "   ..  X    ",
435 "   .   X  X ",
436 "   .    XX  "};
437
438 static QString
439 aboutMsg()
440 {
441     QString msg;
442     msg.sprintf(
443     "Qt NetHack is a version of NetHack built\n"
444 #ifdef KDE
445     "using KDE and the Qt GUI toolkit.\n"
446 #else
447     "using the Qt GUI toolkit.\n"
448 #endif
449     "This is version %d.%d.%d\n\n"
450     "Homepage:\n     http://trolls.troll.no/warwick/nethack/\n\n"
451 #ifdef KDE
452           "KDE:\n     http://www.kde.org\n"
453 #endif
454           "Qt:\n     http://www.troll.no",
455         VERSION_MAJOR,
456         VERSION_MINOR,
457         PATCHLEVEL);
458     return msg;
459 }
460
461 class SmallToolButton : public QToolButton {
462 public:
463     SmallToolButton(const QPixmap & pm, const QString &textLabel,
464                  const QString& grouptext,
465                  QObject * receiver, const char* slot,
466                  QWidget * parent) :
467         QToolButton(parent)
468     {
469         setIcon(QIcon(pm));
470         setToolTip(textLabel);
471         setStatusTip(grouptext);
472         connect(this, SIGNAL(clicked(bool)), receiver, slot);
473     }
474
475     QSize sizeHint() const
476     {
477         // get just a couple more pixels for the map
478         return QToolButton::sizeHint()-QSize(0,2);
479     }
480 };
481
482 NetHackQtMainWindow::NetHackQtMainWindow(NetHackQtKeyBuffer& ks) :
483     message(0), map(0), status(0), invusage(0),
484     hsplitter(0), vsplitter(0),
485     keysink(ks), dirkey(0)
486 {
487     QToolBar* toolbar = new QToolBar(this);
488     toolbar->setMovable(false);
489     toolbar->setFocusPolicy(Qt::NoFocus);
490     addToolBar(toolbar);
491     menubar = menuBar();
492
493     QCoreApplication::setOrganizationName("The NetHack DevTeam");
494     QCoreApplication::setOrganizationDomain("nethack.org");
495     QCoreApplication::setApplicationName("NetHack");
496
497     setWindowTitle("Qt NetHack");
498     if ( qt_compact_mode )
499         setWindowIcon(QIcon(QPixmap(nh_icon_small)));
500     else
501         setWindowIcon(QIcon(QPixmap(nh_icon)));
502
503     QMenu* game=new QMenu;
504     QMenu* apparel=new QMenu;
505     QMenu* act1=new QMenu;
506     QMenu* act2 = qt_compact_mode ? new QMenu : act1;
507     QMenu* magic=new QMenu;
508     QMenu* info=new QMenu;
509
510     QMenu *help;
511
512 #ifdef KDE
513     help = kapp->getHelpMenu( true, "" );
514     help->addSeparator();
515 #else
516     help = qt_compact_mode ? info : new QMenu;
517 #endif
518
519     enum { OnDesktop=1, OnHandhelds=2 };
520     struct Macro {
521         QMenu* menu;
522         const char* name;
523         int flags;
524         int NDECL((*funct));
525     } item[] = {
526         { game,    0, 3},
527         { game,    "Version",            3, doversion},
528         { game,    "Compilation",        3, doextversion},
529         { game,    "History",            3, dohistory},
530         { game,    "Redraw",             0, doredraw}, // useless
531         { game,    "Options",            3, doset},
532         { game,    "Explore mode",       3, enter_explore_mode},
533         { game,    0, 3},
534         { game,    "Save",               3, dosave},
535         { game,    "Quit",               3, done2},
536
537         { apparel, "Apparel off",        2, doddoremarm},
538         { apparel, "Remove many",        1, doddoremarm},
539         { apparel, 0, 3},
540         { apparel, "Wield weapon",       3, dowield},
541         { apparel, "Exchange weapons",   3, doswapweapon},
542         { apparel, "Two weapon combat",  3, dotwoweapon},
543         { apparel, "Load quiver",        3, dowieldquiver},
544         { apparel, 0, 3},
545         { apparel, "Wear armour",        3, dowear},
546         { apparel, "Take off armour",    3, dotakeoff},
547         { apparel, 0, 3},
548         { apparel, "Put on non-armour",  3, doputon},
549         { apparel, "Remove non-armour",  3, doremring},
550
551         /* { act1,      "Again\tCtrl+A",           "\001", 2},
552         { act1, 0, 0, 3}, */
553         { act1, "Apply",             3, doapply},
554         { act1, "Chat",              3, dotalk},
555         { act1, "Close door",        3, doclose},
556         { act1, "Down",              3, dodown},
557         { act1, "Drop many",         2, doddrop},
558         { act1, "Drop",              2, dodrop},
559         { act1, "Eat",               2, doeat},
560         { act1, "Engrave",           3, doengrave},
561         /* { act1,      "Fight\tShift+F",             "F", 3}, */
562         { act1, "Fire from quiver",  2, dofire},
563         { act1, "Force",             3, doforce},
564         { act1, "Get",               2, dopickup},
565         { act1, "Jump",              3, dojump},
566         { act2, "Kick",              2, dokick},
567         { act2, "Loot",              3, doloot},
568         { act2, "Open door",         3, doopen},
569         { act2, "Pay",               3, dopay},
570         { act2, "Rest",              2, donull},
571         { act2, "Ride",              3, doride},
572         { act2, "Search",            3, dosearch},
573         { act2, "Sit",               3, dosit},
574         { act2, "Throw",             2, dothrow},
575         { act2, "Untrap",            3, dountrap},
576         { act2, "Up",                3, doup},
577         { act2, "Wipe face",         3, dowipe},
578
579         { magic, "Quaff potion",     3, dodrink},
580         { magic, "Read scroll/book", 3, doread},
581         { magic, "Zap wand",         3, dozap},
582         { magic, "Zap spell",        3, docast},
583         { magic, "Dip",              3, dodip},
584         { magic, "Rub",              3, dorub},
585         { magic, "Invoke",           3, doinvoke},
586         { magic, 0, 3},
587         { magic, "Offer",            3, dosacrifice},
588         { magic, "Pray",             3, dopray},
589         { magic, 0, 3},
590         { magic, "Teleport",         3, dotelecmd},
591         { magic, "Monster action",   3, domonability},
592         { magic, "Turn undead",      3, doturn},
593
594         { help,  "Help",             3, dohelp},
595         { help,  0, 3},
596         { help,  "What is here",     3, dolook},
597         { help,  "What is there",    3, doquickwhatis},
598         { help,  "What is...",       2, dowhatis},
599         { help,  0, 1},
600
601         { info,  "Inventory",        3, ddoinv},
602         { info,  "Conduct",          3, doconduct},
603         { info,  "Discoveries",      3, dodiscovered},
604         { info,  "List/reorder spells",  3, dovspell},
605         { info,  "Adjust letters",   2, doorganize},
606         { info,  0, 3},
607         { info,  "Name object or creature", 3, docallcmd},
608         { info,  0, 3},
609         { info,  "Skills",  3, enhance_weapon_skill},
610
611         { 0, 0, 0 }
612     };
613
614     int i;
615
616     game->addAction("Qt settings...",this,SLOT(doQtSettings(bool)));
617     help->addAction("About Qt NetHack...",this,SLOT(doAbout(bool)));
618     //help->addAction("NetHack Guidebook...",this,SLOT(doGuidebook(bool)));
619     help->addSeparator();
620
621     for (i=0; item[i].menu; i++) {
622         if ( item[i].flags & (qt_compact_mode ? 1 : 2) ) {
623             if (item[i].name) {
624                 char actchar[32];
625                 char menuitem[BUFSZ];
626                 actchar[0] = '\0';
627                 if (item[i].funct) {
628                     actchar[0] = cmd_from_func(item[i].funct);
629                     actchar[1] = '\0';
630                 }
631                 if (actchar[0] && !qt_compact_mode)
632                     Sprintf(menuitem, "%s\t%s", item[i].name,
633                             visctrl(actchar[0]));
634                 else
635                     Sprintf(menuitem, "%s", item[i].name);
636                 if (actchar[0]) {
637                     QString name = menuitem;
638                     QAction *action = item[i].menu->addAction(name);
639                     action->setData(actchar);
640                 }
641             } else {
642                 item[i].menu->addSeparator();
643             }
644         }
645     }
646
647     game->setTitle("Game");
648     menubar->addMenu(game);
649     apparel->setTitle("Gear");
650     menubar->addMenu(apparel);
651
652     if ( qt_compact_mode ) {
653         act1->setTitle("A-J");
654         menubar->addMenu(act1);
655         act2->setTitle("K-Z");
656         menubar->addMenu(act2);
657         magic->setTitle("Magic");
658         menubar->addMenu(magic);
659         info->setIcon(QIcon(QPixmap(info_xpm)));
660         info->setTitle("Info");
661         menubar->addMenu(info);
662         //menubar->insertItem(QPixmap(map_xpm), this, SLOT(raiseMap()));
663         //menubar->insertItem(QPixmap(msg_xpm), this, SLOT(raiseMessages()));
664         //menubar->insertItem(QPixmap(stat_xpm), this, SLOT(raiseStatus()));
665         info->addSeparator();
666         info->addAction("Map", this, SLOT(raiseMap()));
667         info->addAction("Messages", this, SLOT(raiseMessages()));
668         info->addAction("Status", this, SLOT(raiseStatus()));
669     } else {
670         act1->setTitle("Action");
671         menubar->addMenu(act1);
672         magic->setTitle("Magic");
673         menubar->addMenu(magic);
674         info->setTitle("Info");
675         menubar->addMenu(info);
676         menubar->addSeparator();
677         help->setTitle("Help");
678         menubar->addMenu(help);
679     }
680
681     QSignalMapper* sm = new QSignalMapper(this);
682     connect(sm, SIGNAL(mapped(const QString&)), this, SLOT(doKeys(const QString&)));
683     QToolButton* tb;
684     char actchar[32];
685     tb = new SmallToolButton( QPixmap(again_xpm),"Again","Action", sm, SLOT(map()), toolbar );
686     Sprintf(actchar, "%c", Cmd.spkeys[NHKF_DOAGAIN]);
687     sm->setMapping(tb, actchar );
688     toolbar->addWidget(tb);
689     tb = new SmallToolButton( QPixmap(get_xpm),"Get","Action", sm, SLOT(map()), toolbar );
690     Sprintf(actchar, "%c", cmd_from_func(dopickup));
691     sm->setMapping(tb, actchar );
692     toolbar->addWidget(tb);
693     tb = new SmallToolButton( QPixmap(kick_xpm),"Kick","Action", sm, SLOT(map()), toolbar );
694     Sprintf(actchar, "%c", cmd_from_func(dokick));
695     sm->setMapping(tb, actchar );
696     toolbar->addWidget(tb);
697     tb = new SmallToolButton( QPixmap(throw_xpm),"Throw","Action", sm, SLOT(map()), toolbar );
698     Sprintf(actchar, "%c", cmd_from_func(dothrow));
699     sm->setMapping(tb, actchar );
700     toolbar->addWidget(tb);
701     tb = new SmallToolButton( QPixmap(fire_xpm),"Fire","Action", sm, SLOT(map()), toolbar );
702     Sprintf(actchar, "%c", cmd_from_func(dofire));
703     sm->setMapping(tb, actchar );
704     toolbar->addWidget(tb);
705     tb = new SmallToolButton( QPixmap(drop_xpm),"Drop","Action", sm, SLOT(map()), toolbar );
706     Sprintf(actchar, "%c", cmd_from_func(doddrop));
707     sm->setMapping(tb, actchar );
708     toolbar->addWidget(tb);
709     tb = new SmallToolButton( QPixmap(eat_xpm),"Eat","Action", sm, SLOT(map()), toolbar );
710     Sprintf(actchar, "%c", cmd_from_func(doeat));
711     sm->setMapping(tb, actchar );
712     toolbar->addWidget(tb);
713     tb = new SmallToolButton( QPixmap(rest_xpm),"Rest","Action", sm, SLOT(map()), toolbar );
714     Sprintf(actchar, "%c", cmd_from_func(donull));
715     sm->setMapping(tb, actchar );
716     toolbar->addWidget(tb);
717
718     connect(game,SIGNAL(triggered(QAction *)),this,SLOT(doMenuItem(QAction *)));
719     connect(apparel,SIGNAL(triggered(QAction *)),this,SLOT(doMenuItem(QAction *)));
720     connect(act1,SIGNAL(triggered(QAction *)),this,SLOT(doMenuItem(QAction *)));
721     if (act2 != act1)
722         connect(act2,SIGNAL(triggered(QAction *)),this,SLOT(doMenuItem(QAction *)));
723     connect(magic,SIGNAL(triggered(QAction *)),this,SLOT(doMenuItem(QAction *)));
724     connect(info,SIGNAL(triggered(QAction *)),this,SLOT(doMenuItem(QAction *)));
725     connect(help,SIGNAL(triggered(QAction *)),this,SLOT(doMenuItem(QAction *)));
726
727 #ifdef KDE
728     setMenu (menubar);
729 #endif
730
731     int x=0,y=0;
732     int w=QApplication::desktop()->width()-10; // XXX arbitrary extra space for frame
733     int h=QApplication::desktop()->height()-50;
734
735     int maxwn;
736     int maxhn;
737     if (qt_tilewidth != NULL) {
738         maxwn = atoi(qt_tilewidth) * COLNO + 10;
739     } else {
740         maxwn = 1400;
741     }
742     if (qt_tileheight != NULL) {
743         maxhn = atoi(qt_tileheight) * ROWNO * 6/4;
744     } else {
745         maxhn = 1024;
746     }
747
748     // Be exactly the size we want to be - full map...
749     if (w>maxwn) {
750         x+=(w-maxwn)/2;
751         w=maxwn; // Doesn't need to be any wider
752     }
753     if (h>maxhn) {
754         y+=(h-maxhn)/2;
755         h=maxhn; // Doesn't need to be any taller
756     }
757
758     setGeometry(x,y,w,h);
759
760     if ( qt_compact_mode ) {
761         stack = new QStackedWidget(this);
762         setCentralWidget(stack);
763     } else {
764         vsplitter = new QSplitter(Qt::Vertical);
765         setCentralWidget(vsplitter);
766         hsplitter = new QSplitter(Qt::Horizontal);
767         invusage = new NetHackQtInvUsageWindow(hsplitter);
768         vsplitter->insertWidget(0, hsplitter);
769         hsplitter->insertWidget(1, invusage);
770     }
771 }
772
773 void NetHackQtMainWindow::zoomMap()
774 {
775     qt_settings->toggleGlyphSize();
776 }
777
778 void NetHackQtMainWindow::raiseMap()
779 {
780     if ( stack->currentWidget() == map->Widget() ) {
781         zoomMap();
782     } else {
783         stack->setCurrentWidget(map->Widget());
784     }
785 }
786
787 void NetHackQtMainWindow::raiseMessages()
788 {
789     stack->setCurrentWidget(message->Widget());
790 }
791
792 void NetHackQtMainWindow::raiseStatus()
793 {
794     stack->setCurrentWidget(status->Widget());
795 }
796
797 #if 0 // RLC this isn't used
798 class NetHackMimeSourceFactory : public Q3MimeSourceFactory {
799 public:
800     const QMimeSource* data(const QString& abs_name) const
801     {
802         const QMimeSource* r = 0;
803         if ( (NetHackMimeSourceFactory*)this == Q3MimeSourceFactory::defaultFactory() )
804             r = Q3MimeSourceFactory::data(abs_name);
805         else
806             r = Q3MimeSourceFactory::defaultFactory()->data(abs_name);
807         if ( !r ) {
808             int sl = abs_name.length();
809             do {
810                 sl = abs_name.lastIndexOf('/',sl-1);
811                 QString name = sl>=0 ? abs_name.mid(sl+1) : abs_name;
812                 int dot = name.lastIndexOf('.');
813                 if ( dot >= 0 )
814                     name = name.left(dot);
815                 if ( name == "map" )
816                     r = new Q3ImageDrag(QImage(map_xpm));
817                 else if ( name == "msg" )
818                     r = new Q3ImageDrag(QImage(msg_xpm));
819                 else if ( name == "stat" )
820                     r = new Q3ImageDrag(QImage(stat_xpm));
821             } while (!r && sl>0);
822         }
823         return r;
824     }
825 };
826 #endif
827
828 void NetHackQtMainWindow::doMenuItem(QAction *action)
829 {
830     doKeys(action->data().toString());
831 }
832
833 void NetHackQtMainWindow::doQtSettings(bool)
834 {
835     centerOnMain(qt_settings);
836     qt_settings->show();
837 }
838
839 void NetHackQtMainWindow::doAbout(bool)
840 {
841     QMessageBox::about(this, "About Qt NetHack", aboutMsg());
842 }
843
844 #if 0 // RLC this isn't used
845 void NetHackQtMainWindow::doGuidebook(bool)
846 {
847     QDialog dlg(this);
848     new QVBoxLayout(&dlg);
849     Q3TextBrowser browser(&dlg);
850     NetHackMimeSourceFactory ms;
851     browser.setMimeSourceFactory(&ms);
852     browser.setSource(QDir::currentPath()+"/Guidebook.html");
853     if ( qt_compact_mode )
854         dlg.showMaximized();
855     dlg.exec();
856 }
857 #endif
858
859 void NetHackQtMainWindow::doKeys(const QString& k)
860 {
861     keysink.Put(k.toLatin1().constData());
862     qApp->exit();
863 }
864
865 void NetHackQtMainWindow::AddMessageWindow(NetHackQtMessageWindow* window)
866 {
867     message=window;
868     if (!qt_compact_mode)
869         hsplitter->insertWidget(0, message->Widget());
870     ShowIfReady();
871 }
872
873 NetHackQtMessageWindow * NetHackQtMainWindow::GetMessageWindow()
874 {
875     return message;
876 }
877
878 void NetHackQtMainWindow::AddMapWindow(NetHackQtMapWindow2* window)
879 {
880
881     map=window;
882     if (!qt_compact_mode)
883         vsplitter->insertWidget(1, map->Widget());
884     ShowIfReady();
885     connect(map,SIGNAL(resized()),this,SLOT(layout()));
886 }
887
888 void NetHackQtMainWindow::AddStatusWindow(NetHackQtStatusWindow* window)
889 {
890     status=window;
891     if (!qt_compact_mode)
892         hsplitter->insertWidget(2, status->Widget());
893     ShowIfReady();
894 }
895
896 void NetHackQtMainWindow::RemoveWindow(NetHackQtWindow* window)
897 {
898     if (window==status) {
899         status=0;
900         ShowIfReady();
901     } else if (window==map) {
902         map=0;
903         ShowIfReady();
904     } else if (window==message) {
905         message=0;
906         ShowIfReady();
907     }
908 }
909
910 void NetHackQtMainWindow::updateInventory()
911 {
912     if ( invusage )
913         invusage->repaint();
914 }
915
916 void NetHackQtMainWindow::fadeHighlighting()
917 {
918     if (status) {
919         status->fadeHighlighting();
920     }
921 }
922
923 void NetHackQtMainWindow::layout()
924 {
925 #if 0
926     if ( qt_compact_mode )
927         return;
928     if (message && map && status) {
929         QSize maxs=map->Widget()->maximumSize();
930         int maph=std::min(height()*2/3,maxs.height());
931
932         QWidget* c = centralWidget();
933         int h=c->height();
934         int toph=h-maph;
935         int iuw=3*qt_settings->glyphs().width();
936         int topw=(c->width()-iuw)/2;
937
938         message->Widget()->setGeometry(0,0,topw,toph);
939         invusage->setGeometry(topw,0,iuw,toph);
940         status->Widget()->setGeometry(topw+iuw,0,topw,toph);
941         map->Widget()->setGeometry(std::max(0,(c->width()-maxs.width())/2),
942                                    toph,c->width(),maph);
943     }
944 #endif
945 }
946
947 void NetHackQtMainWindow::resizeEvent(QResizeEvent*)
948 {
949     layout();
950 #ifdef KDE
951     updateRects();
952 #endif
953 }
954
955 void NetHackQtMainWindow::keyReleaseEvent(QKeyEvent* event)
956 {
957     if ( dirkey ) {
958         doKeys(QString(QChar(dirkey)));
959         if ( !event->isAutoRepeat() )
960             dirkey = 0;
961     }
962 }
963
964 void NetHackQtMainWindow::keyPressEvent(QKeyEvent* event)
965 {
966     // Global key controls
967
968     // For desktop, arrow keys scroll map, since we don't want players
969     // to think that's the way to move. For handhelds, the normal way is to
970     // click-to-travel, so we allow the cursor keys for fine movements.
971
972     //  321
973     //  4 0
974     //  567
975
976     if ( event->isAutoRepeat() &&
977         event->key() >= Qt::Key_Left && event->key() <= Qt::Key_Down )
978         return;
979
980     const char* d = Cmd.dirchars;
981     switch (event->key()) {
982      case Qt::Key_Up:
983         if ( dirkey == d[0] )
984             dirkey = d[1];
985         else if ( dirkey == d[4] )
986             dirkey = d[3];
987         else
988             dirkey = d[2];
989     break; case Qt::Key_Down:
990         if ( dirkey == d[0] )
991             dirkey = d[7];
992         else if ( dirkey == d[4] )
993             dirkey = d[5];
994         else
995             dirkey = d[6];
996     break; case Qt::Key_Left:
997         if ( dirkey == d[2] )
998             dirkey = d[1];
999         else if ( dirkey == d[6] )
1000             dirkey = d[7];
1001         else
1002             dirkey = d[0];
1003     break; case Qt::Key_Right:
1004         if ( dirkey == d[2] )
1005             dirkey = d[3];
1006         else if ( dirkey == d[6] )
1007             dirkey = d[5];
1008         else
1009             dirkey = d[4];
1010     break; case Qt::Key_PageUp:
1011         dirkey = 0;
1012         if (message) message->Scroll(0,-1);
1013     break; case Qt::Key_PageDown:
1014         dirkey = 0;
1015         if (message) message->Scroll(0,+1);
1016     break; case Qt::Key_Space:
1017         if ( flags.rest_on_space ) {
1018             event->ignore();
1019             return;
1020         }
1021         case Qt::Key_Enter:
1022         if ( map )
1023             map->clickCursor();
1024     break; default:
1025         dirkey = 0;
1026         event->ignore();
1027     }
1028 }
1029
1030 void NetHackQtMainWindow::closeEvent(QCloseEvent* e)
1031 {
1032     if ( program_state.something_worth_saving ) {
1033         switch ( QMessageBox::information( this, "NetHack",
1034             "This will end your NetHack session",
1035             "&Save", "&Cancel", 0, 1 ) )
1036         {
1037             case 0:
1038                 // See dosave() function
1039                 if (dosave0()) {
1040                     u.uhp = -1;
1041                     NetHackQtBind::qt_exit_nhwindows(0);
1042                     nh_terminate(EXIT_SUCCESS);
1043                 }
1044                 break;
1045             case 1:
1046                 break; // ignore the event
1047         }
1048     } else {
1049         e->accept();
1050     }
1051 }
1052
1053 void NetHackQtMainWindow::ShowIfReady()
1054 {
1055     if (message && map && status) {
1056         QWidget* hp = qt_compact_mode ? static_cast<QWidget *>(stack) : static_cast<QWidget *>(hsplitter);
1057         QWidget* vp = qt_compact_mode ? static_cast<QWidget *>(stack) : static_cast<QWidget *>(vsplitter);
1058         message->Widget()->setParent(hp);
1059         map->Widget()->setParent(vp);
1060         status->Widget()->setParent(hp);
1061         if ( qt_compact_mode ) {
1062             message->setMap(map);
1063             stack->addWidget(map->Widget());
1064             stack->addWidget(message->Widget());
1065             stack->addWidget(status->Widget());
1066             raiseMap();
1067         } else {
1068             layout();
1069         }
1070         showMaximized();
1071     } else if (isVisible()) {
1072         hide();
1073     }
1074 }
1075
1076 } // namespace nethack_qt4