1 /***************************************************************************
2                           menueintrag.cpp  -  description
3                              -------------------
4     begin                : Mit Jul 12 22:54:51 MEST 2000
5     copyright            : (C) 2006 by Immi
6     email                : cuyo@pcpool.mathematik.uni-freiburg.de
7 
8 Modified 2006-2008,2010,2011,2014 by the cuyo developers
9 
10  ***************************************************************************/
11 
12 /***************************************************************************
13  *                                                                         *
14  *   This program is free software; you can redistribute it and/or modify  *
15  *   it under the terms of the GNU General Public License as published by  *
16  *   the Free Software Foundation; either version 2 of the License, or     *
17  *   (at your option) any later version.                                   *
18  *                                                                         *
19  ***************************************************************************/
20 
21 #include <stdio.h>
22 
23 
24 #include "sdltools.h"
25 
26 #include "font.h"
27 
28 #include "cuyointl.h"
29 #include "fehler.h"
30 #include "global.h"
31 
32 #include "prefsdaten.h"
33 
34 #include "layout.h"
35 #include "menueintrag.h"
36 #include "ui2cuyo.h"
37 #include "ui.h"
38 
39 #include "sound.h"
40 
41 #define HOT_ALIGN 1
42 
43 #define hotkey_keins (-1)
44 #define hotkey_rahmen (-2)  // Rahmen um alles falls subBereich == subbereich_hyperaktiv
45 
46 
47 /*****************************************************************************/
48 
DrawDing(const Str & text,int hotkey,int binSubBereich,int x,int y,int align,Font * font,int * xmin,int * xmax)49 DrawDing::DrawDing(const Str & text, int hotkey,
50    	           int binSubBereich, /* Subbereich, zu dem dieses Drawding geh�rt */
51                    int x, int y,
52 		   int align /*= AlignHCenter*/,   /* Akzeptiert nur waagerechtes Zeug,
53 				       senkrecht ist immer zentriert. */
54                    Font * font, /*= NULL*/  /* Default h�ngt von aktSubBereich ab */
55 		   int * xmin /*= NULL*/, int * xmax /*= NULL*/
56 		   /* Wenn die !=0 sind, wird dort schon mal unsere Ausdehung
57 		      reingeschrieben. */) :
58     mArt(dda_Text), mText(text),
59     mHotkey(hotkey == hotkey_rahmen ? hotkey_keins : hotkey),
60     mFont(font),
61     //mDx(hotkey==hotkey_rahmen ? L_menu_rand_lr : 0),
62     mRahmen(hotkey==hotkey_rahmen),
63     mBinSubBereich(binSubBereich),
64     mAbschneiden(false) {
65   /* Irgend eine Schrift brauchen wir, um die Breite zu messen: */
66   if (!font) font = Font::gMenu;
67 
68   int fh = font->getFontHeight();
69   mY0 = y - fh / 2 - L_menu_rand_ou;
70   mY1 = mY0 + fh + 2 * L_menu_rand_ou;
71 
72   int w = font->getLineWidth(mText.data()) + 2*L_menu_rand_lr;
73   switch (align) {
74     case AlignLeft: mX0=x; mX1=x+w; break;
75     case AlignRight: mX0=x-w; mX1=x; break;
76     case AlignHCenter:
77       mX0=x-(w+1)/2; mX1=x+w/2;
78       break;
79     default: throw iFehler("%s","Invalid alignment");
80   }
81   #if HOT_ALIGN
82       if (hotkey >= 0) {
83         int w2 = font->getLineWidth(mText.left(hotkey).data());
84         w2 += font->getLineWidth(mText.mid(hotkey, 1).data()) / 2;
85         mX0 = x - w2;
86         mX1 = mX0 + w;
87       }
88   #endif
89   mXPos = mX0 + L_menu_rand_lr;
90   if (xmin) *xmin=mX0;
91   if (xmax) *xmax=mX1;
92 }
93 
DrawDing(int bild,int bildchen,int x,int y)94 DrawDing::DrawDing(int bild, int bildchen, int x, int y) :
95     mArt(dda_Icon), mBild(bild), mBildchen(bildchen),
96     mBinSubBereich(subbereich_default),
97     mX0(x-gric/2), mX1(x+gric/2), mY0(y-gric/2), mY1(y+gric/2), mXPos(mX0),
98     mAbschneiden(false) {}
99 
100 /* Wenn man nicht m�chte, dass das Bild zur Gr��e des Hintergrundrahmens
101    beitr�gt, w�re es vielleicht inzwischen sauberer, binsubbereich auf
102    subbereich_keiner zu setzen (und in anzeigen() einbauen, dass das
103    erlaubt ist) */
104 /* Folgende Funktion geht grad nicht: */
105 // DrawDing::DrawDing(int bild, int xbd, int ybd, int x, int y) :
106 //     mArt(dda_Bild),
107 //     mBild(bild), mRect(SDLTools::rect(xbd,ybd,2*gric,2*gric)),
108 //     mBinSubBereich(subbereich_default),
109 //     mX0(x), mX1(x), mY0(y),mY1(y), mXPos(mX0-gric),
110 //     mAbschneiden(false) {}
DrawDing(int bild,int x,int y)111 DrawDing::DrawDing(int bild, int x, int y) :
112     mArt(dda_Bild),
113     mBild(bild),
114     mBinSubBereich(subbereich_default),
115     mX0(x), mX1(x), mY0(y), mY1(y),
116     mAbschneiden(false) {}
117 
118 
119 
abschneiden(int x0,int x1)120 void DrawDing::abschneiden(int x0, int x1) {
121   mX0 = x0;
122   mX1 = x1;
123   mAbschneiden = true;
124 }
125 
126 
127 
anzeigen(int subBereich,int x,int y) const128 void DrawDing::anzeigen(int subBereich, int x, int y) const {
129   if (mAbschneiden)
130     Area::setClip(SDLTools::rect(x + mX0, 0, mX1 - mX0, L_fenster_hoehe));
131   switch (mArt) {
132   case dda_Nichts:
133     CASSERT(false); break;
134   case dda_Text: {
135     int xh=0;
136     Str hotkey="";
137     bool bright = subBereich == subbereich_hyperaktiv || subBereich == mBinSubBereich;
138     Font * font = mFont;
139     if (subBereich == subbereich_keinStrom)
140       font = Font::gDimmed;
141     if (!font)
142       font = bright ? Font::gBright : Font::gMenu;
143 
144     if (mRahmen && subBereich == subbereich_hyperaktiv) {
145       Color colour = Color(130,130,220);
146       Area::fillRect(x+mX0,y+mY0,
147 		     mX1-mX0, 2, colour);
148       Area::fillRect(x+mX0,y+mY1-2,
149 		     mX1-mX0, 2, colour);
150       Area::fillRect(x+mX0,y+mY0,
151 		     2, mY1-mY0, colour);
152       Area::fillRect(x+mX1-2,y+mY0,
153 		     2, mY1-mY0, colour);
154     }
155 
156     int hot = mHotkey;
157     if (bright)
158       hot = hotkey_keins;
159 
160     if (hot>=0) {
161       xh = mXPos + font->getLineWidth(mText.left(mHotkey).data());
162       hotkey = mText.mid(mHotkey,1);
163 
164       if (subBereich != subbereich_keinStrom) {
165 	/* Einen Highlightkreis um den Hotkey malen */
166 	int x_ = x + xh+font->getLineWidth(hotkey.data())/2;
167 	int y_ = y + (mY0+mY1)/2;
168 	Bilddatei & bild = *Blatt::gBlattPics[blattpic_highlight];
169 	bild.malBildchen(x_-gric,y_-gric,0);
170 	bild.malBildchen(x_,y_-gric,2);
171 	bild.malBildchen(x_-gric,y_,6);
172 	bild.malBildchen(x_,y_,8);
173       }
174     }
175 
176     font->drawText(mText, x + mXPos, y + mY0 + L_menu_rand_ou,AlignTopLeft);
177 
178     if (hot>=0) {
179       (subBereich == subbereich_keinStrom ? Font::gBrightDimmed : Font::gBright)->
180          drawText(hotkey, x + xh, y + mY0 + L_menu_rand_ou, AlignTopLeft);
181     }
182 
183     } break;
184   case dda_Icon:
185     Blatt::gBlattPics[mBild]->malBildchen(x+mXPos,y+mY0,mBildchen);
186     break;
187   case dda_Bild: {
188       Bilddatei & bi = *Blatt::gBlattPics[mBild];
189       bi.malBild(x+mX0-bi.getBreite() / 2,y+mY0 - bi.getHoehe() / 2);
190       break;
191     }
192   }
193   if (mAbschneiden)
194     Area::noClip();
195 }
196 
197 
198 
199 
200 /*****************************************************************************/
201 
202 
MenuEintrag(BlattMenu * papi,Str na,void (* doret)(),int accel,int hoehe)203 MenuEintrag::MenuEintrag(BlattMenu * papi,
204 			 Str na /*= ""*/,
205 			 void(*doret)() /*= 0*/,
206 			 int accel /*= 0*/,
207 			 int hoehe /*= L_menueintrag_defaulthoehe*/):
208         mHoehe(hoehe), mPapi(papi),
209 	mName(na), mAccel(accel), mAccIndex(hotkey_keins), mDoReturn(doret),
210         mGetStrom(NULL),
211 	mArt(Art_normal), mX0(-11111), mUpdaten(false), mSubBereich(subbereich_nichtInitialisiert) {
212   /* Hotkey suchen */
213   if (mAccel==0) {
214     for (int i=0; i<mName.length(); i++)
215       if (mName[i]=='~')
216 	mAccIndex=i;
217     if (mAccIndex!=hotkey_keins) {
218       mName = mName.left(mAccIndex)+mName.right(mAccIndex+1);
219       mAccel = mName[mAccIndex];
220       if (mAccel>='a' && mAccel<='z')
221 	mAccel += 'A' - 'a';
222     }
223   }
224 }
225 
226 
MenuEintrag(BlattMenu * papi,Str na,Art ea,int hoehe)227 MenuEintrag::MenuEintrag(BlattMenu * papi, Str na, Art ea,
228 			 int hoehe /*= L_menueeintrag_defaulthoehe*/):
229         mHoehe(hoehe), mPapi(papi), mName(na),
230 	mAccel(0), mAccIndex(hotkey_keins), mDoReturn(NULL),
231         mGetStrom(NULL),
232 	mArt(ea), mX0(-11111), mUpdaten(false), mSubBereich(subbereich_nichtInitialisiert) {}
233 
234 
nieStrom()235 bool nieStrom() {return false;}
236 
setNieStrom()237 void MenuEintrag::setNieStrom() {
238   setGetStrom(nieStrom);
239 }
240 
241 
setSubBereich(int subBereich)242 void MenuEintrag::setSubBereich(int subBereich) {
243   int alt_sb = mSubBereich;
244   mSubBereich = subBereich;
245   if (!getStrom()) mSubBereich = subbereich_keinStrom;
246   if (mSubBereich != alt_sb)
247     updateDrawDinge();
248 }
249 
250 /* Aufrufen, wenn sich m�glicherweise der Stromstatus ge�ndert hat */
updateStrom()251 void MenuEintrag::updateStrom() {
252   bool neustrom = getStrom();
253   if (neustrom != (mSubBereich != subbereich_keinStrom))
254     setSubBereich(neustrom ? subbereich_keiner : subbereich_keinStrom);
255 }
256 
updateDrawDinge()257 void MenuEintrag::updateDrawDinge() {
258   CASSERT(mSubBereich != subbereich_nichtInitialisiert);
259   mAnzDraw = 0;
260   updateDDIntern();
261 
262   mX0 = L_fenster_breite_menus;
263   mX1 = -L_fenster_breite_menus;
264   for (int i=0; i<mAnzDraw; i++)
265     if (mDraw[i].mBinSubBereich == subbereich_default) {
266       if (mDraw[i].mX0<mX0) mX0=mDraw[i].mX0;
267       if (mDraw[i].mX1>mX1) mX1=mDraw[i].mX1;
268     }
269 
270   setUpdateFlag();
271   UI::nachEventAllesAnzeigen();
272 }
273 
274 
deactivateAccel()275 void MenuEintrag::deactivateAccel() {
276   mAccel=0;
277   mAccIndex=hotkey_keins;
278 }
279 
anzeigen(int x,int y,bool graue)280 void MenuEintrag::anzeigen(int x, int y, bool graue) {
281 
282   /* Unsch�n, k�nnte irgendwann mal ein Bug werden, tut aber im Moment:
283      Eigentlich m�sste ein Men�Eintrag informiert werden, wenn es sich
284      �ndert, ob die Grauen neben ihm sitzen oder nicht, damit er ein
285      Graphik-Update machen kann (mit setUpdateFlag()). Im Moment werden
286      die grauen aber immer nur dann verschoben, wenn auch was anderes am
287      Eintrag ver�ndert wird, so dass die erforderlichen Graphik-Updates
288      sowieso geschehen */
289 
290   CASSERT(mSubBereich != subbereich_nichtInitialisiert);
291 
292   if (!mUpdaten) return;
293   mUpdaten = false;
294 
295   //print_to_stderr(_sprintf("%s\n", mName.data()));
296 
297   if (mAnzDraw == 0)
298     return;
299 
300   /* Normaler Hintergrund */
301   Area::fillRect(0, y, L_fenster_breite_menus, mHoehe, Color(30, 30, 70));
302   Area::updateRect(0, y, L_fenster_breite_menus, mHoehe);
303 
304   /* Position von Highlight-Hintergrund und Grauen bestimmen */
305 
306   int hx0 = L_fenster_breite_menus, hx1 = 0; /* Hintergrund */
307   int hy0 = L_fenster_hoehe, hy1 = 0;
308 
309   int gx0 = L_fenster_breite_menus, gx1 = 0; /* Graue */
310 
311   for (int i=0; i<mAnzDraw; i++) {
312     if (mDraw[i].mX0<gx0) gx0=mDraw[i].mX0;
313     if (mDraw[i].mX1>gx1) gx1=mDraw[i].mX1;
314     if (mDraw[i].mBinSubBereich == mSubBereich || mSubBereich == subbereich_hyperaktiv) {
315       if (x+mDraw[i].mX0<hx0) hx0=x+mDraw[i].mX0;
316       if (x+mDraw[i].mX1>hx1) hx1=x+mDraw[i].mX1;
317       if (y+mDraw[i].mY0<hy0) hy0=y+mDraw[i].mY0;
318       if (y+mDraw[i].mY1>hy1) hy1=y+mDraw[i].mY1;
319     }
320   }
321 
322   /* Hintergrund malen */
323   if (hx1 > 0) {
324     Bilddatei & bild = *Blatt::gBlattPics[blattpic_highlight];
325     int w = hx1-hx0;
326     int h = hy1-hy0;
327     int w1,w2,w3, h1,h2,h3;
328     if (w>=2*L_menueintrag_highlight_rad) {
329       w1 = L_menueintrag_highlight_rad;
330       w2 = w-2*L_menueintrag_highlight_rad;
331       w3 = L_menueintrag_highlight_rad;
332     } else {
333       w1 = w/2;
334       w2 = 0;
335       w3 = w-w1;
336     }
337     if (h>=2*L_menueintrag_highlight_rad) {
338       h1 = L_menueintrag_highlight_rad;
339       h2 = h-2*L_menueintrag_highlight_rad;
340       h3 = L_menueintrag_highlight_rad;
341     } else {
342       h1 = h/2;
343       h2 = 0;
344       h3 = h-h1;
345     }
346     // Ecken
347     bild.malBildAusschnitt(hx0,hy0,SDLTools::rect(gric-w1,gric-h1,w1,h1));
348     bild.malBildAusschnitt(hx1-w3,hy0,SDLTools::rect(2*gric,gric-h1,w3,h1));
349     bild.malBildAusschnitt(hx0,hy1-h3,SDLTools::rect(gric-w1,2*gric,w1,h3));
350     bild.malBildAusschnitt(hx1-w3,hy1-h3,SDLTools::rect(2*gric,2*gric,w3,h3));
351     // Waagerechte Kanten
352     bild.malStreifenH(hx0+w1, hy0, w2, SDLTools::rect(gric,gric-h1,gric,h1));
353     bild.malStreifenH(hx0+w1, hy1-h3, w2, SDLTools::rect(gric,2*gric,gric,h3));
354     // Senkrechte Kanten
355     bild.malStreifenV(hx0, hy0+h1, h2, SDLTools::rect(gric-w1,gric,w1,gric));
356     bild.malStreifenV(hx1-w3, hy0+h1, h2, SDLTools::rect(2*gric,gric,w3,gric));
357     // Fl�che
358     if (w2>0 && h2>0)
359       Area::fillRect(hx0+w1, hy0+h1, w2, h2, Color(50, 50, 120));
360         /* Wenn diese Farbe ge�ndert wird, mu� das auch in
361 	   some_pic_sources/highlight.pov geschehen. */
362   }
363 
364   /* Eigentliches Zeug malen */
365   for (int i=0; i<mAnzDraw; i++)
366     mDraw[i].anzeigen(mSubBereich, x, y);
367 
368   /* Graue malen */
369   if (graue) {
370     Blatt::gBlattPics[blattpic_pfeile]->malBildchen(x+gx0-L_grausep-gric,
371 						     y+mHoehe/2-gric/2,
372 						     0);
373     Blatt::gBlattPics[blattpic_pfeile]->malBildchen(x+gx1+L_grausep,
374 						     y+mHoehe/2-gric/2,
375 						     1);
376   }
377 }
378 
379 
doReturn(bool)380 void MenuEintrag::doReturn(bool) {
381   if (mDoReturn) {
382     Sound::playSample(sample_menuclick,so_fenster);
383     mDoReturn();
384   }
385 }
386 
getStrom() const387 bool MenuEintrag::getStrom() const {
388   if (mGetStrom)
389     return mGetStrom();
390   else
391     return true;
392 }
393 
394 
getMausPos(int x,int)395 int MenuEintrag::getMausPos(int x, int /*y*/) {
396   CASSERT(mSubBereich != subbereich_nichtInitialisiert);
397 
398   return x >= mX0 && x < mX1 ? subbereich_default : subbereich_keiner;
399 }
400 
401 
402 
getWaehlbar() const403 bool MenuEintrag::getWaehlbar() const {
404   return mArt != Art_deko && getStrom();
405 }
406 
getAktiv() const407 bool MenuEintrag::getAktiv() const {
408   return mArt==Art_aktiv || mArt==Art_hyperakt;
409 }
410 
getHyper() const411 bool MenuEintrag::getHyper() const {
412   return mArt==Art_hyper || mArt==Art_hyperakt;
413 }
414 
415 
doPapiEscape()416 void MenuEintrag::doPapiEscape() {
417   mPapi->doEscape();
418 }
419 
doPapiNavigiere(int d)420 void MenuEintrag::doPapiNavigiere(int d) {
421   mPapi->navigiere(d);
422 }
423 
updateDDIntern()424 void MenuEintrag::updateDDIntern() {
425   neuDraw() = DrawDing(mName, mAccIndex, subbereich_default, 0, mHoehe / 2,
426 		       AlignHCenter,
427 		       mArt == Art_deko ? Font::gTitle : NULL);
428 }
429 
430 /*****************************************************************************/
431 
MenuEintragBild(BlattMenu * papi,int nr)432 MenuEintragBild::MenuEintragBild(BlattMenu * papi, int nr):
433    MenuEintrag(papi, "", MenuEintrag::Art_deko,
434 	       Blatt::gBlattPics[nr]->getHoehe()),
435    mBildNr(nr) {
436 }
437 
438 
updateDDIntern()439 void MenuEintragBild::updateDDIntern() {
440   neuDraw() = DrawDing(mBildNr, 0, mHoehe / 2);
441 }
442 
443 
444 
445 /*****************************************************************************/
446 
MenuEintragEscape(BlattMenu * papi)447 MenuEintragEscape::MenuEintragEscape(BlattMenu * papi) :
448     // TRANSLATORS: "Done" is a menu entry for quitting a submenu.
449     MenuEintrag(papi,_("Done"),NULL,SDLK_ESCAPE) {
450 }
451 
doReturn(bool)452 void MenuEintragEscape::doReturn(bool) {
453   /* Sound wird gespielt, wenn das Men� sich zumacht. */
454   doPapiEscape();
455 }
456 
457 
458 
459 /*****************************************************************************/
460 
MenuEintragSubmenu(BlattMenu * papi,const Str & name,BlattMenu * menu,int accel,int hoehe)461 MenuEintragSubmenu::MenuEintragSubmenu(BlattMenu * papi,
462 				       const Str & name, BlattMenu * menu,
463 				       int accel /*=0*/,
464 				       int hoehe
465 				         /*= L_menueintrag_defaulthoehe*/) :
466     MenuEintrag(papi,name,NULL,accel,hoehe), mSub(menu) {
467 }
468 
~MenuEintragSubmenu()469 MenuEintragSubmenu::~MenuEintragSubmenu() {
470   delete mSub;
471 }
472 
doReturn(bool durchMaus)473 void MenuEintragSubmenu::doReturn(bool durchMaus) {
474   Sound::playSample(sample_menuclick,so_fenster);
475   mSub->oeffnen(durchMaus);
476 }
477 
478 
479 
480 /*****************************************************************************/
481 
MenuEintragAuswahl(BlattMenu * papi,const Str & na,const Str & info,void (* doretint)(int),int arg,int accel)482 MenuEintragAuswahl::MenuEintragAuswahl(BlattMenu * papi,
483 				       const Str & na, const Str & info,
484 				       void(*doretint)(int), int arg,
485 				       int accel /*=0*/) :
486     MenuEintrag(papi,na,NULL,accel), mArg(arg), mInfo(info),
487     mDoReturnInt(doretint) {
488 }
489 
doReturn(bool)490 void MenuEintragAuswahl::doReturn(bool) {
491   /* Sound nicht abspielen; das tut schon doPapiEscape() */
492   //Sound::playSample(sample_menuclick,so_fenster);
493   /* Vorsicht: Im Moment *muss* das folgende in dieser Reihenfolge
494      passieren wegen des levelpack-menus: Bei doPapiEscape() wird
495      die Graphik des Levelpack-Men�eintrags geupdatet. Der neue
496      Levelpack muss davor schon ausgew�hlt worden sein. */
497   mDoReturnInt(mArg);
498   doPapiEscape();
499 }
500 
501 
502 
503 /*****************************************************************************/
504 
auswahlmenu(MenuEintragSubmenu * obereintrag,BlattMenu * obermenu,const std::vector<Str> & moeglichkeiten,const std::vector<Str> & infos,void (* doret)(int),const Str & titel,Str info,int & vorlauf)505 BlattMenu * auswahlmenu(MenuEintragSubmenu * obereintrag, BlattMenu * obermenu,
506                         const std::vector<Str> & moeglichkeiten,
507 			const std::vector<Str> & infos,
508 			void (*doret)(int),
509 			const Str & titel, Str info,
510 			int & vorlauf) {
511   BlattMenu * ret = new BlattMenu(true);  // true = scrollleiste immer da... und esc-button
512   ret->setObermenu(obermenu);
513   ret->setObereintrag(obereintrag);
514   if (titel=="")
515     vorlauf = 0;
516   else {
517     /* Erstmal alle '~' rausl�schen */
518     Str titel_ = titel;
519     for (int i=0; i<titel_.length(); i++)
520       if (titel_[i]=='~')
521 	titel_ = titel_.left(i)+titel_.right(i+1);
522     ret->neuerEintrag(new MenuEintrag(ret, titel_, MenuEintrag::Art_deko));
523     ret->neuerEintrag(new MenuEintrag(ret, "",
524 				      MenuEintrag::Art_deko, L_medskip));
525     vorlauf = 2;
526   }
527   for (size_t i=0; i<moeglichkeiten.size(); i++)
528     ret->neuerEintrag(new MenuEintragAuswahl(ret, moeglichkeiten[i],
529 					     i<infos.size() ? infos[i] : "",
530 					     doret, i));
531   if (info!=Str())
532     ret->neuerEintrag(new MenuEintrag(ret, "",
533 				      MenuEintrag::Art_deko, L_medskip));
534   while (info!=Str()) {
535     // Zeilenende suchen
536     int i;
537     for (i=0; i<info.length() ? (info[i]!='\n') : false; i++) {}
538     ret->neuerEintrag(new MenuEintrag(ret, info.left(i),
539 				      MenuEintrag::Art_deko));
540     if (i<info.length())
541       i++;
542     info = info.right(i);
543   }
544 
545   return ret;
546 }
547 
548 
MenuEintragAuswahlmenu(BlattMenu * papi,const Str & name,const std::vector<Str> * const auswahlen,const std::vector<Str> * const infos,int (* getakt)(),void (* doret)(int),const Str & info,int accel)549 MenuEintragAuswahlmenu::MenuEintragAuswahlmenu(BlattMenu * papi,
550 					       const Str & name,
551                                                const std::vector<Str> *const
552 					         auswahlen,
553 					       const std::vector<Str> *const
554 					         infos,
555 					       int (*getakt) (),
556 					       void (*doret)(int),
557 					       const Str & info /*= Str()*/,
558 					       int accel /*=0*/) :
559     MenuEintragSubmenu(papi, name,
560 		       auswahlmenu(this, papi, *auswahlen, *infos,
561 				   doret, name, info, mVorlauf),
562 		       accel,
563 		       L_menueintrag_defaulthoehe+L_font_height),
564     mAuswahlen(auswahlen), mGetAktuell(getakt),
565     mEintragDoReturn(doret),
566     mAnimation(0), mAnimationDX(0) {
567   mArt = Art_aktiv;
568 }
569 
getInfo()570 Str MenuEintragAuswahlmenu::getInfo() {
571   return mSubBereich == subbereich_default
572     ? _("Press `return' or click for a full list")
573     : "";
574 }
575 
doHyperaktiv(const SDL_keysym & key,int taste)576 void MenuEintragAuswahlmenu::doHyperaktiv(const SDL_keysym & key, int taste) {
577   switch (taste) {
578     case SDLK_RIGHT:
579       doPfeil(1);
580       break;
581     case SDLK_LEFT:
582       doPfeil(-1);
583       break;
584     default:
585       MenuEintragSubmenu::doHyperaktiv(key,taste);
586       break;
587   }
588 }
589 
590 
getMausPos(int x,int y)591 int MenuEintragAuswahlmenu::getMausPos(int x, int y) {
592 
593   /* Manuel zusammengeflicktes befindet-sich-die-Maus-�ber-einem-Pfeil.
594      Wenn wir irgendwann mehr solche SubBereiche haben, will man das
595      sch�ner machen. */
596 
597   if (y >= mHoehe/2) {
598     if (x >= mPfeil1X0 && x < mPfeil1X1)
599       return 1;
600     if (x >= mPfeil2X0 && x < mPfeil2X1)
601       return 2;
602   }
603 
604   return MenuEintrag::getMausPos(x, y);
605 }
606 
607 
608 
zeitSchritt()609 void MenuEintragAuswahlmenu::zeitSchritt() {
610   if (mAnimation != 0) {
611     mAnimation += mAnimation > 0 ? -1 : 1;
612     updateDrawDinge();
613   }
614 }
615 
616 
617 
doReturn(bool durchMaus)618 void MenuEintragAuswahlmenu::doReturn(bool durchMaus) {
619   if (mSubBereich == 1) {
620     doPfeil(-1);
621   } else if (mSubBereich == 2) {
622     doPfeil(1);
623   } else {
624     Sound::playSample(sample_menuclick,so_fenster);
625     mSub->oeffnen(durchMaus, mGetAktuell() + mVorlauf);
626   }
627 }
628 
629 
630 
doUntermenuSchliessen()631 void MenuEintragAuswahlmenu::doUntermenuSchliessen() {
632   updateDrawDinge();
633 }
634 
635 
updateDDIntern()636 void MenuEintragAuswahlmenu::updateDDIntern() {
637   int y = mHoehe/2-L_font_height/2;
638   int x0,x1;
639   neuDraw() = DrawDing(mName,mAccIndex, subbereich_default, 0, y, AlignHCenter,
640 		       NULL, &x0, &x1);
641 
642   int x_mitte = (x0 + x1) / 2;
643   y += L_font_height;
644   int aktuell = mGetAktuell();
645   Str tmpstr = (*mAuswahlen)[aktuell];
646   /*if (mSubBereich == subbereich_keiner)
647     tmpstr = "(" + tmpstr + ")";
648     */
649   int anim_x = x_mitte + mAnimation * mAnimationDX / L_auswahlmenu_anim_schritte;
650   DrawDing & dd = neuDraw();
651   dd = DrawDing(tmpstr,hotkey_keins, subbereich_default,
652 			        anim_x, y,
653 				AlignHCenter, Font::gData, &x0, &x1);
654   dd.abschneiden(x_mitte - L_auswahlmenu_pfeilsep,
655 	         x_mitte + L_auswahlmenu_pfeilsep);
656   if (mAnimation != 0) {
657     DrawDing & dd2 = neuDraw();
658     dd2 = DrawDing(mAnimationWahlAlt,hotkey_keins, subbereich_default,
659           anim_x + (mAnimation > 0 ? -mAnimationDX : mAnimationDX), y,
660 	  AlignHCenter, Font::gData, &x0, &x1);
661     dd2.abschneiden(x_mitte - L_auswahlmenu_pfeilsep,
662 	            x_mitte + L_auswahlmenu_pfeilsep);
663   }
664 
665   DrawDing & pf1 = neuDraw();
666   pf1 = DrawDing("\010", hotkey_keins, 1,
667 		       x_mitte - L_auswahlmenu_pfeilsep, y,
668 		       AlignRight, NULL);
669   mPfeil1X0 = pf1.mX0;
670   mPfeil1X1 = pf1.mX1;
671 
672   DrawDing & pf2 = neuDraw();
673   pf2 = DrawDing("\011", hotkey_keins, 2,
674 		       x_mitte + L_auswahlmenu_pfeilsep, y,
675 		       AlignLeft, NULL);
676   mPfeil2X0 = pf2.mX0;
677   mPfeil2X1 = pf2.mX1;
678 
679 
680 //   if (mSubBereich != subbereich_keiner) {
681 //     /* Erstmal deaktiviert, weil's mir nicht so gef�llt
682 //     neuDraw() = DrawDing((*mAuswahlen)[schiebAktuell(-1)],-1,
683 // 			 0,
684 // 			 x0-L_auswahlsep,y,
685 // 			 AlignRight, &x0);
686 //     neuDraw() = DrawDing((*mAuswahlen)[schiebAktuell(1)],-1,
687 // 			 0,
688 // 			 x1+L_auswahlsep,y,
689 // 			 AlignLeft, NULL, &x1);
690 //     */
691 //
692 //     /*
693 //     neuDraw() = DrawDing(blattpic_pfeile,2,x0-L_grausep-gric/2,y);
694 //     neuDraw() = DrawDing(blattpic_pfeile,2+1,x1+L_grausep+gric/2,y);
695 //     */
696 //   }
697 }
698 
699 
doPfeil(int d)700 void MenuEintragAuswahlmenu::doPfeil(int d) {
701 
702   Sound::playSample(sample_menuscroll,so_fenster);
703 
704   mAnimationWahlAlt = (*mAuswahlen)[mGetAktuell()];
705   mEintragDoReturn(schiebAktuell(d));
706 
707   mAnimation = L_auswahlmenu_anim_schritte * d;
708 
709   /* Abstand zwischen altem und neuem Text bestimmen. Soll eigentlich
710      L_auswahlmenu_anim_dx, aber evtl. mehr, wenn sonst der neue Text
711      schon vorher reingeguckt h�tte oder umgekehrt */
712   int w1 = Font::gMenu->getLineWidth(mAnimationWahlAlt.data()) / 2;
713   int w2 = Font::gMenu->getLineWidth((*mAuswahlen)[mGetAktuell()].data()) / 2;
714   if (w1 < L_auswahlmenu_pfeilsep - L_auswahlmenu_anim_dx)
715     w1 = L_auswahlmenu_pfeilsep - L_auswahlmenu_anim_dx;
716   if (w2 < L_auswahlmenu_pfeilsep - L_auswahlmenu_anim_dx)
717     w2 = L_auswahlmenu_pfeilsep - L_auswahlmenu_anim_dx;
718   mAnimationDX = w1 + w2 + L_auswahlmenu_anim_dx;
719 
720   updateDrawDinge();
721 }
722 
723 
schiebAktuell(int d)724 int MenuEintragAuswahlmenu::schiebAktuell(int d) {
725   int neu = mGetAktuell()+d;
726   if (neu<0)
727     neu=mAuswahlen->size()-1;
728   if (neu>=(int) mAuswahlen->size())
729     neu=0;
730   return neu;
731 }
732 
733 /*****************************************************************************/
734 
735 /* Wer hat zur Zeit das Kreuz? */
736 /* Wo ist diese Variable besser gekapselt? Wenn sie ein private Member von
737    MenuEintragSpielerModus ist oder wenn sie nur hier in dieser Datei steht
738    (und ein "static" hat, damit der Linker auch nicht verr�t, dass es diese
739    Variable gibt)? */
740 static MenuEintragSpielerModus * gMenuEintragSpielerModusAktuell = NULL;
741 
742 
doReturn(bool)743 void MenuEintragSpielerModus::doReturn(bool) {
744 
745   Sound::playSample(sample_menuclick,so_fenster);
746 
747   /* Keine neue Animation, wenn das bereits angekreuzt war */
748   if (Cuyo::getSpielerModus() == mModus)
749     return;
750   Cuyo::setSpielerModus(mModus);
751   mAnimation = 2; /* "ASCII"-Code des ersten Kreuzchen-Bildchens */
752 
753   if (gMenuEintragSpielerModusAktuell)
754     gMenuEintragSpielerModusAktuell->updateDrawDinge();
755 
756   /* Vermutlich wird restart-last-level stromlos */
757   //CASSERT(gMenuEintragRestartLastLevel);
758   //gMenuEintragRestartLastLevel->updateDrawDinge();
759 
760   /* Da steht im Moment die Funktion drin, die Restart-last-level
761      neu malt (wegen Strom�nderung).
762      Eigentlich k�nnte man hieraus auch gleich einen generischen
763      Ankreuzlisten-Men�EintragTyp machen, im Stil der anderen Auswahlmen�s. */
764   (*mDoWechsel)();
765 
766   updateDrawDinge();
767 }
768 
769 
updateDDIntern()770 void MenuEintragSpielerModus::updateDDIntern() {
771 #if HOT_ALIGN
772   int xkreuz;
773   neuDraw() = DrawDing(mName, mAccIndex, subbereich_default, 0, mHoehe/2,
774 		       AlignRight, NULL, NULL, &xkreuz);
775   xkreuz += L_datensep;
776 #else
777   neuDraw() = DrawDing(mName, mAccIndex, subbereich_default, 0, mHoehe/2,
778 		       AlignRight);
779   int xkreuz = x+L_datensep;
780 #endif
781   neuDraw() = DrawDing("\001", hotkey_keins, subbereich_default,
782 		       xkreuz, mHoehe/2, AlignLeft);
783 
784   if (Cuyo::getSpielerModus() == mModus) {
785     CASSERT(mAnimation >= 2);
786     Str tmpstr = _sprintf("%c", mAnimation);
787     neuDraw() = DrawDing(tmpstr, hotkey_keins, subbereich_default,
788 		         xkreuz, mHoehe/2, AlignLeft, Font::gData);
789     gMenuEintragSpielerModusAktuell = this;
790   }
791 }
792 
793 
zeitSchritt()794 void MenuEintragSpielerModus::zeitSchritt() {
795   if (mAnimation < 0 || mAnimation == 7)
796     return;
797 
798   mAnimation++;
799   if (mAnimation == 3 || mAnimation == 6)
800     mAnimation++;
801   updateDrawDinge();
802 }
803 
804 
805 
806 /*****************************************************************************/
807 
updateDDIntern()808 void MenuEintragTaste::updateDDIntern() {
809   neuDraw() = DrawDing(mName, mAccIndex,subbereich_default, 0, mHoehe/2,
810 		       AlignRight);
811 
812   Str ts = SDL_GetKeyName(PrefsDaten::getTaste(mSpieler, mTaste));
813   int x0,x1;
814   neuDraw() = DrawDing(ts, hotkey_rahmen,subbereich_default, 0, mHoehe/2,
815 		       AlignLeft, Font::gData, &x0, &x1);
816 }
817 
getInfo()818 Str MenuEintragTaste::getInfo() {
819   return mSubBereich == subbereich_hyperaktiv
820     ? _("Type a new key")
821     : _("To enter a new key, click or press `return' first");
822 }
823 
doHyperaktiv(const SDL_keysym & taste,int)824 void MenuEintragTaste::doHyperaktiv(const SDL_keysym & taste, int) {
825   if (taste.sym!=SDLK_ESCAPE) {
826     PrefsDaten::setTaste(mSpieler, mTaste, taste.sym);
827     doPapiNavigiere(1);
828   }
829 }
830 
831 
832 
833 /*****************************************************************************/
834 
updateDDIntern()835 void MenuEintragAI::updateDDIntern() {
836   int li, re;
837 
838   neuDraw() = DrawDing(mName, mAccIndex,subbereich_default, 0, mHoehe/2,
839 		       AlignRight, 0, &li, &re);
840 
841   Str ts = _sprintf("%d", PrefsDaten::getKIGeschwLog());
842   neuDraw() = DrawDing(ts, hotkey_rahmen,subbereich_default, 0, mHoehe/2,
843 		       AlignLeft, Font::gData);
844 
845   DrawDing & pf1 = neuDraw();
846   pf1 = DrawDing("\010", hotkey_keins, 1,
847 		       li - L_AI_pfeil_sep_li, mHoehe/2,
848 		       AlignRight, NULL);
849   mPfeil1X0 = pf1.mX0;
850   mPfeil1X1 = pf1.mX1;
851 
852   DrawDing & pf2 = neuDraw();
853   pf2 = DrawDing("\011", hotkey_keins, 2,
854 		       re + L_AI_pfeil_sep_re, mHoehe/2,
855 		       AlignLeft, NULL);
856   mPfeil2X0 = pf2.mX0;
857   mPfeil2X1 = pf2.mX1;
858 }
859 
860 
doHyperaktiv(const SDL_keysym &,int taste)861 void MenuEintragAI::doHyperaktiv(const SDL_keysym &, int taste) {
862   if (taste==SDLK_RIGHT)
863     doPfeil(1);
864   else if (taste==SDLK_LEFT)
865     doPfeil(-1);
866 }
867 
868 
doReturn(bool)869 void MenuEintragAI::doReturn(bool) {
870   if (mSubBereich == 1) {
871     doPfeil(-1);
872   } else if (mSubBereich == 2) {
873     doPfeil(1);
874   }
875 }
876 
877 
doPfeil(int d)878 void MenuEintragAI::doPfeil(int d) {
879   int alt = PrefsDaten::getKIGeschwLog();
880   int neu = alt + d;
881   if (neu<0) neu=0;
882   if (neu>9) neu=9;
883 
884   if (neu != alt) {
885     PrefsDaten::setKIGeschwLog(neu);
886     updateDrawDinge();
887   }
888 }
889 
890 
getMausPos(int x,int y)891 int MenuEintragAI::getMausPos(int x, int y) {
892 
893   /* Manuel zusammengeflicktes befindet-sich-die-Maus-�ber-einem-Pfeil.
894      Wenn wir irgendwann mehr solche SubBereiche haben, will man das
895      sch�ner machen. */
896 
897   if (x >= mPfeil1X0 && x < mPfeil1X1)
898     return 1;
899   if (x >= mPfeil2X0 && x < mPfeil2X1)
900     return 2;
901 
902   return MenuEintrag::getMausPos(x, y);
903 }
904 
905 
906 
907 
908 /*****************************************************************************/
909 
updateDDIntern()910 void MenuEintragSound::updateDDIntern() {
911   neuDraw() = DrawDing(mName, mAccIndex,subbereich_default, 0, mHoehe/2,
912 		       AlignRight);
913 
914   Str ts = mBitteWarten ? "..." : PrefsDaten::getSound() ? _("On") : _("Off");
915   neuDraw() = DrawDing(ts, hotkey_rahmen,subbereich_default, 0, mHoehe/2,
916 		       AlignLeft, Font::gData);
917 }
918 
919 
doReturn(bool)920 void MenuEintragSound::doReturn(bool) {
921   /* Da es auf manchen Rechnern ziemlich lange dauert, bis SDL merkt, dass
922      es den Sound doch nicht anschalten kann, f�r diese Wartezeit eine optische
923      R�ckkopplung */
924   mBitteWarten = true;
925   updateDrawDinge();
926   UI::sofortAllesAnzeigen();
927   mBitteWarten = false;
928 
929   setSound(!PrefsDaten::getSound());
930   updateDrawDinge();
931 }
932 
933 
doHyperaktiv(const SDL_keysym &,int taste)934 void MenuEintragSound::doHyperaktiv(const SDL_keysym &, int taste) {
935   bool alt = PrefsDaten::getSound();
936   bool neu = alt;
937 
938   if (taste=='0') neu = false;
939   else if (taste=='1') neu = true;
940   else if (taste==SDLK_RIGHT || taste==SDLK_LEFT || taste==SDLK_RETURN || taste==' ')
941     neu = !alt;
942 
943   if (neu == alt)
944     return;
945 
946   setSound(neu);
947   updateDrawDinge();
948 }
949 
950 
setSound(bool neu)951 void MenuEintragSound::setSound(bool neu) {
952   if (neu != PrefsDaten::getSound()) {
953     if (!neu)
954       Sound::setMusic("");
955     PrefsDaten::setSound(neu);
956     Sound::checkePrefsStatus();
957     if (neu)
958       Sound::setMusic("cuyo.it");
959   }
960 }
961 
962 
963 /*****************************************************************************/
964 
MenuEintragLevel(BlattMenu * papi,Str na,bool gewonnen,bool strom)965 MenuEintragLevel::MenuEintragLevel(BlattMenu * papi, Str na, bool gewonnen, bool strom):
966    MenuEintrag(papi, na), mGewonnen(gewonnen)
967 {
968   if (!strom)
969     setNieStrom();
970 }
971 
972 
973 
updateDDIntern()974 void MenuEintragLevel::updateDDIntern() {
975   int xmin;
976   neuDraw() = DrawDing(mName, hotkey_keins, subbereich_default, 0, mHoehe / 2,
977                        AlignLeft, 0, &xmin);
978   if (mGewonnen) {
979     xmin -= L_datensep;
980     neuDraw() = DrawDing("\013", hotkey_keins, subbereich_default, xmin, mHoehe / 2, AlignRight);
981   }
982 }
983