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