moved almost all hardcoded constants to "define.dat"
[k8-i-v-a-n.git] / src / felib / felist.cpp
blobca1b1705bb685d9a44c6b22bd0ca90294e303b40
1 /*
3 * Iter Vehemens ad Necem (IVAN)
4 * Copyright (C) Timo Kiviluoto
5 * Released under the GNU General
6 * Public License
8 * See LICENSING which should be included
9 * along with this file for more details
12 #include <fstream>
14 #include "felist.h"
15 #include "graphics.h"
16 #include "bitmap.h"
17 #include "whandler.h"
18 #include "rawbit.h"
19 #include "fesave.h"
20 #include "festring.h"
23 const felist *FelistCurrentlyDrawn = 0;
24 truth fastListMode = 0;
27 truth felist::GetFastListMode () { return fastListMode; }
28 void felist::SetFastListMode (truth modeon) { fastListMode = modeon; }
31 truth FelistDrawController () {
32 FelistCurrentlyDrawn->DrawPage(DOUBLE_BUFFER);
33 return true;
37 struct felistentry {
38 felistentry () : ImageKey(NO_IMAGE) {}
39 felistentry (cfestring &String, col16 Color, uInt Marginal, uInt ImageKey, truth Selectable, feuLong udata) :
40 String(String),
41 Color(Color),
42 Marginal(Marginal),
43 ImageKey(ImageKey),
44 Selectable(Selectable),
45 UData(udata) {}
47 festring String;
48 col16 Color;
49 uInt Marginal;
50 uInt ImageKey;
51 truth Selectable;
52 feuLong UData;
56 outputfile &operator << (outputfile &SaveFile, const felistentry *Entry) {
57 SaveFile << Entry->String << Entry->Color << Entry->Marginal << Entry->Selectable;
58 return SaveFile;
62 inputfile &operator >> (inputfile &SaveFile, felistentry *&Entry) {
63 Entry = new felistentry;
64 SaveFile >> Entry->String >> Entry->Color >> Entry->Marginal >> Entry->Selectable;
65 return SaveFile;
69 struct felistdescription {
70 felistdescription () {}
71 felistdescription (cfestring &String, col16 Color)
72 : String(String), Color(Color) {}
73 festring String;
74 col16 Color;
78 felist::felist (cfestring &Topic, col16 TopicColor, uInt Maximum) :
79 mSaveSelector(false),
80 mSaveDir(""),
81 Maximum(Maximum),
82 Selected(0),
83 Pos(10, 10),
84 Width(780),
85 PageLength(26+10),
86 BackColor(0),
87 Flags(SELECTABLE|FADE),
88 UpKey(KEY_UP),
89 DownKey(KEY_DOWN),
90 EntryDrawer(0)
92 AddDescription(Topic, TopicColor);
96 felist::~felist () {
97 Empty();
98 for (uInt c = 0; c < Description.size(); ++c) delete Description[c];
102 truth felist::IsEntrySelectable (uInt idx) const {
103 return (idx < Entry.size() ? Entry[idx]->Selectable : false);
107 feuLong felist::GetEntryUData (uInt idx) const {
108 return (idx < Entry.size() ? Entry[idx]->UData : 0);
112 void felist::SetEntryUData (uInt idx, feuLong udata) {
113 if (idx < Entry.size()) Entry[idx]->UData = udata;
117 void felist::Pop () {
118 delete Entry[GetLastEntryIndex()];
119 Entry.pop_back();
123 uInt felist::Draw () {
124 while (Entry.size() && Entry[GetLastEntryIndex()]->String.IsEmpty()) Pop();
125 if (Entry.empty()) return LIST_WAS_EMPTY;
127 FelistCurrentlyDrawn = this;
128 if (globalwindowhandler::ControlLoopsInstalled()) globalwindowhandler::InstallControlLoop(FelistDrawController);
130 bitmap BackGround(RES);
131 bitmap*Buffer;
133 BackGround.ActivateFastFlag();
134 if (Flags&FADE) {
135 Buffer = new bitmap(RES, 0);
136 Buffer->ActivateFastFlag();
137 BackGround.ClearToColor(0);
138 } else {
139 Buffer = DOUBLE_BUFFER;
140 Buffer->FastBlit(&BackGround);
143 uInt c;
144 uInt Return, Selectables = 0;
145 truth JustSelectMove = false;
146 for (c = 0; c < Entry.size(); ++c) if (Entry[c]->Selectable) ++Selectables;
147 if (Selected >= Selectables) Selected = Selectables-1;
149 if (Flags&SELECTABLE) PageBegin = Selected-Selected%PageLength;
150 else if (Flags&INVERSE_MODE) PageBegin = GetLastEntryIndex()-GetLastEntryIndex()%PageLength;
151 else PageBegin = 0;
153 for (;;) {
154 truth AtTheEnd = DrawPage(Buffer);
155 if (Flags&FADE) {
156 if (JustSelectMove) {
157 Buffer->FastBlit(DOUBLE_BUFFER);
158 graphics::BlitDBToScreen();
159 } else {
160 Buffer->FadeToScreen();
162 JustSelectMove = false;
163 } else {
164 graphics::BlitDBToScreen();
167 uInt Pressed = GET_KEY(false);
169 if (Flags&SELECTABLE) {
170 // list movement and selections
171 int prs = -1;
173 if (Pressed >= 'a' && Pressed <= 'z') prs = Pressed-'a';
174 else if (Pressed >= 'A' && Pressed <= 'Z') prs = Pressed-'A';
175 else if (Pressed >= '0' && Pressed <= '9') prs = Pressed-'0'+26;
177 if (prs >= 0) {
178 if ((uInt)prs < PageLength && (uInt)prs+PageBegin < Selectables) {
179 Return = Selected = (uInt)prs+PageBegin;
180 if (fastListMode) {
181 JustSelectMove = true;
182 continue;
183 } else {
184 break;
187 continue;
190 if (Pressed == UpKey) {
191 if (Selected) {
192 --Selected;
193 if (Selected < PageBegin) {
194 BackGround.FastBlit(Buffer);
195 PageBegin -= PageLength;
196 } else {
197 JustSelectMove = true;
199 } else {
200 for (c = 0, Selected = 0; c < Entry.size(); ++c) if (Entry[c]->Selectable) ++Selected;
201 --Selected;
202 if (PageBegin == Selected-Selected%PageLength) JustSelectMove = true;
203 else {
204 BackGround.FastBlit(Buffer);
205 PageBegin = Selected-Selected%PageLength;
208 continue;
211 if (Pressed == DownKey) {
212 if (!AtTheEnd || Selected != Selectables-1) {
213 ++Selected;
214 if (Selected > PageBegin+PageLength-1) {
215 PageBegin += PageLength;
216 BackGround.FastBlit(Buffer);
217 } else {
218 JustSelectMove = true;
220 } else {
221 if (!PageBegin) JustSelectMove = true; else BackGround.FastBlit(Buffer);
222 Selected = PageBegin = 0;
224 continue;
227 if (Pressed == KEY_HOME) {
228 Selected = PageBegin;
229 JustSelectMove = true;
230 continue;
233 if (Pressed == KEY_END) {
234 //fprintf(stderr, "sel: %u; pb: %u; pl: %u; ss: %u; ae: %s\n", Selected, PageBegin, PageLength, Selectables, AtTheEnd ? "end" : "not end");
235 if (Selectables) {
236 Selected = PageBegin+PageLength-1;
237 if (Selected >= Selectables) Selected = Selectables-1;
239 JustSelectMove = true;
240 continue;
243 if (Pressed == KEY_LEFT) {
244 // previous page
245 if (Selectables && PageBegin > 0) {
246 PageBegin = (PageBegin < PageLength ? 0 : PageBegin-PageLength);
247 Selected = PageBegin;
248 BackGround.FastBlit(Buffer);
250 continue;
253 if (Pressed == KEY_RIGHT) {
254 // next page
255 if (Selectables) {
256 uInt pgend = PageBegin+PageLength;
257 if (pgend < Selectables) {
258 PageBegin += PageLength;
259 Selected = PageBegin;
260 BackGround.FastBlit(Buffer);
263 continue;
266 if (Pressed == KEY_ENTER) {
267 Return = Selected;
268 break;
270 } else {
271 // not selectable: allow navigation with left/right
272 if (Pressed == KEY_LEFT) {
273 if (PageBegin > 0) {
274 PageBegin -= (PageBegin < PageLength ? PageBegin : PageLength);
275 BackGround.FastBlit(Buffer);
277 continue;
280 if (Pressed == KEY_RIGHT) {
281 if (!AtTheEnd) {
282 PageBegin += PageLength;
283 BackGround.FastBlit(Buffer);
285 continue;
289 if (Pressed == KEY_ESC) {
290 Return = ESCAPED;
291 break;
294 if ((AtTheEnd && !(Flags&INVERSE_MODE)) || (!PageBegin && (Flags&INVERSE_MODE))) {
295 if (Flags&FELIST_NO_BADKEY_EXIT) continue;
296 Return = NOTHING_SELECTED;
297 break;
298 } else {
299 BackGround.FastBlit(Buffer);
300 if (Flags&INVERSE_MODE) PageBegin -= PageLength; else PageBegin += PageLength;
301 if (Flags&SELECTABLE) Selected = PageBegin;
305 if (!(Flags&FADE)) {
306 if (Flags&DRAW_BACKGROUND_AFTERWARDS) BackGround.FastBlit(DOUBLE_BUFFER);
307 if (Flags&BLIT_AFTERWARDS) graphics::BlitDBToScreen();
308 } else {
309 delete Buffer;
312 globalwindowhandler::DeInstallControlLoop(FelistDrawController);
313 return Return;
317 //static festring Str;
319 truth felist::DrawPage (bitmap *Buffer) const {
320 uInt LastFillBottom = Pos.Y+23+Description.size()*10;
321 festring Str;
323 DrawDescription(Buffer);
324 uInt c, i; // c == entry index, i == selectable index
325 int selIdx = -1;
326 for (c = 0, i = 0; i != PageBegin; ++c) if (Entry[c]->Selectable) ++i;
327 while (!Entry[c]->Selectable && Entry[c]->String.IsEmpty()) ++c;
328 std::vector<festring> Chapter;
330 //col16 selBack = BackColor^0xFFFF, selText = BackColor;
331 //col16 selBack = LIGHT_GRAY, selText = BLACK;
332 col16 selBack = SEL_BLUE, selText = WHITE;
334 for (;;) {
335 Str.Empty();
336 uInt Marginal = Entry[c]->Marginal;
337 if ((Flags&SELECTABLE) && Entry[c]->Selectable) {
338 if (i-PageBegin <= 25) Str << char('A'+(i-PageBegin)); else Str << char('0'+(i-PageBegin-26));
339 Str << ": ";
340 Marginal += 3;
342 Str << Entry[c]->String;
343 bool selected = (Flags&SELECTABLE && Entry[c]->Selectable && Selected == i);
344 if (selected) selIdx = (int)c;
345 col16 ecolor = Entry[c]->Color;
346 if (selected) {
347 if (ecolor != RED && ecolor != GREEN && ecolor != PINK && ecolor != ORANGE) ecolor = selText;
349 if (Entry[c]->ImageKey != NO_IMAGE) {
350 if (Str.rawLength() <= (Width-50)>>3) {
351 Buffer->Fill(Pos.X+3, LastFillBottom, Width-6, 20, (!selected ? BackColor : selBack));
352 if (EntryDrawer) EntryDrawer(Buffer, v2(Pos.X+13, LastFillBottom), Entry[c]->ImageKey);
353 if (selected) {
354 FONT->PrintfUnshadedColored(Buffer, v2(Pos.X+37, LastFillBottom+4), ecolor, "%s", Str.CStr());
355 } else {
356 FONT->PrintfColored(Buffer, v2(Pos.X+37, LastFillBottom+4), ecolor, "%s", Str.CStr());
358 LastFillBottom += 20;
359 } else {
360 uInt ChapterSize = festring::SplitStringColored(Str, Chapter, (Width-50)>>3, Marginal);
361 uInt PictureTop = LastFillBottom+ChapterSize*5-9;
362 for (uInt l = 0; l < ChapterSize; ++l) {
363 Buffer->Fill(Pos.X+3, LastFillBottom, Width-6, 10, !selected ? BackColor : selBack);
364 if (selected) {
365 FONT->PrintfUnshadedColored(Buffer, v2(Pos.X+37, LastFillBottom), ecolor, "%s", Chapter[l].CStr());
366 } else {
367 FONT->PrintfColored(Buffer, v2(Pos.X+37, LastFillBottom), ecolor, "%s", Chapter[l].CStr());
369 LastFillBottom += 10;
371 if (EntryDrawer) EntryDrawer(Buffer, v2(Pos.X+13, PictureTop), Entry[c]->ImageKey);
373 } else {
374 uInt ChapterSize = festring::SplitStringColored(Str, Chapter, (Width-26)>>3, Marginal);
375 for (uInt l = 0; l < ChapterSize; ++l) {
376 Buffer->Fill(Pos.X+3, LastFillBottom, Width-6, 10, !selected ? BackColor : selBack);
377 if (selected) {
378 FONT->PrintfUnshadedColored(Buffer, v2(Pos.X+13, LastFillBottom), ecolor, "%s", Chapter[l].CStr());
379 } else {
380 FONT->PrintfColored(Buffer, v2(Pos.X+13, LastFillBottom), ecolor, "%s", Chapter[l].CStr());
382 LastFillBottom += 10;
385 if ((i-PageBegin == PageLength-1 && Entry[c]->Selectable) || c == Entry.size()-1) {
386 if ((!(Flags&INVERSE_MODE) && c != Entry.size()-1) || (Flags&INVERSE_MODE && PageBegin)) {
387 Buffer->Fill(Pos.X+3, LastFillBottom, Width-6, 30, BackColor);
388 FONT->PrintfColored(Buffer, v2(Pos.X+13, LastFillBottom+10), WHITE, "- Press SPACE to continue, ESC to exit -");
389 LastFillBottom += 30;
390 } else {
391 Buffer->Fill(Pos.X+3, LastFillBottom, Width-6, 10, BackColor);
392 LastFillBottom += 10;
394 Buffer->DrawRectangle(Pos.X+1, Pos.Y+1, Pos.X+Width-2, LastFillBottom+1, DARK_GRAY, true);
395 break;
397 if (Entry[c++]->Selectable) ++i;
399 if (selIdx != -1 && mSaveSelector) {
400 bitmap bmp(ZERO_V2);
401 festring imgName = Entry[selIdx]->String;
402 festring::sizetype pos = imgName.FindLast(".sav");
403 if (pos != festring::NPos) {
404 imgName.Erase(pos, 4); // remove '.sav'
405 #if defined(SGAME_SHOTS_IPU) || (!defined(HAVE_IMLIB2) && !defined(HAVE_LIBPNG))
406 imgName = mSaveDir+imgName+".ipu";
407 #else
408 imgName = mSaveDir+imgName+".png";
409 #endif
410 //fprintf(stderr, "sel=%d; img=%s\n", selIdx, imgName.CStr());
411 #if defined(SGAME_SHOTS_IPU) || (!defined(HAVE_IMLIB2) && !defined(HAVE_LIBPNG))
412 if (bmp.LoadIPU(imgName))
413 #else
414 if (bmp.LoadPNG(imgName))
415 #endif
417 //fprintf(stderr, " LOADED! %dx%d\n", bmp.GetSize().X, bmp.GetSize().Y);
418 int x = Buffer->GetSize().X-bmp.GetSize().X-2;
419 int y = Buffer->GetSize().Y-bmp.GetSize().Y-2;
420 int w = bmp.GetSize().X;
421 int h = bmp.GetSize().Y;
422 blitdata bd = {
423 Buffer,
424 {0, 0}, //src
425 {x, y}, //dest
426 {w, h}, //border
427 {0}, // luminance/flags
428 0xDEAD, // mask color
429 0 // custom data
431 bmp.NormalBlit(bd);
432 Buffer->DrawRectangle(x-2, y-2, x+w, y+h, DARK_GRAY, true);
436 return c == Entry.size()-1;
440 void felist::DrawDescription (bitmap *Buffer) const {
441 Buffer->Fill(Pos.X+3, Pos.Y+3, Width-6, 20, BackColor);
442 for (uInt c = 0; c < Description.size(); ++c) {
443 Buffer->Fill(Pos.X+3, Pos.Y+13+c*10, Width-6, 10, BackColor);
444 FONT->PrintfColored(Buffer, v2(Pos.X+13, Pos.Y+13+c*10), Description[c]->Color, "%s", Description[c]->String.CStr());
446 Buffer->Fill(Pos.X+3, Pos.Y+13+Description.size()*10, Width-6, 10, BackColor);
450 /* We suppose InverseMode != false here */
451 void felist::QuickDraw (bitmap *Bitmap, uInt PageLength) const {
452 static std::vector<festring> Chapter;
453 uInt Width = Bitmap->GetSize().X;
454 Bitmap->Fill(3, 3, Width-6, 20+PageLength*10, 0);
455 Bitmap->DrawRectangle(1, 1, Width-2, 24+PageLength*10, DARK_GRAY, true);
456 uInt LineSize = (Width-26)>>3;
457 uInt Index = 0;
458 uInt Bottom = PageLength*10+3;
459 for (uInt c1 = 0; c1 <= Selected; ++c1) {
460 const felistentry* CurrentEntry = Entry[Selected-c1];
461 uInt ChapterSize = festring::SplitStringColored(CurrentEntry->String, Chapter, LineSize, CurrentEntry->Marginal);
462 for (uInt c2 = 0; c2 < ChapterSize; ++c2) {
463 col16 Color = CurrentEntry->Color;
464 Color = MakeRGB16(
465 GetRed16(Color)-((GetRed16(Color)*3*Index/PageLength)>>2),
466 GetGreen16(Color)-((GetGreen16(Color)*3*Index/PageLength)>>2),
467 GetBlue16(Color)-((GetBlue16(Color)*3*Index/PageLength)>>2));
468 FONT->PrintfColored(Bitmap, v2(13, Bottom), Color, "%s", Chapter[ChapterSize-c2-1].CStr());
469 Bottom -= 10;
470 if (++Index == PageLength) return;
476 void felist::CreateQuickDrawFontCaches (rawbitmap *Font, col16 Color, uInt PageLength) {
477 if (PageLength < 2) return;
478 for (uInt c = 0; c < PageLength; ++c)
479 Font->CreateFontCache(
480 MakeRGB16(
481 GetRed16(Color)-((GetRed16(Color)*3*c/PageLength)>>2),
482 GetGreen16(Color)-((GetGreen16(Color)*3*c/PageLength)>>2),
483 GetBlue16(Color)-((GetBlue16(Color)*3*c/PageLength)>>2)));
487 void felist::Empty () {
488 for (uInt c = 0; c < Entry.size(); ++c) delete Entry[c];
489 Entry.clear();
493 void felist::AddEntry (cfestring &Str, col16 Color, uInt Marginal, uInt Key, truth Selectable, feuLong udata) {
494 Entry.push_back(new felistentry(Str, Color, Marginal, Key, Selectable, udata));
495 if (Maximum && Entry.size() > feuLong(Maximum)) {
496 delete Entry[0];
497 Entry.erase(Entry.begin());
502 void felist::Save (outputfile &SaveFile) const {
503 SaveFile << Entry << Maximum << Selected;
507 void felist::Load (inputfile& SaveFile) {
508 SaveFile >> Entry >> Maximum >> Selected;
512 void felist::PrintToFile (cfestring& FileName) {
513 std::ofstream SaveFile(FileName.CStr(), std::ios::out);
514 if (!SaveFile.is_open()) return;
515 uInt c;
516 for (c = 0; c < Description.size(); ++c) SaveFile << Description[c]->String.CStr() << std::endl;
517 SaveFile << std::endl;
518 for (c = 0; c < Entry.size(); ++c) {
519 if (Entry[c]->ImageKey != NO_IMAGE) SaveFile << " ";
520 SaveFile << Entry[c]->String.CStr() << std::endl;
525 void felist::AddDescription (cfestring &Str, col16 Color) {
526 Description.push_back(new felistdescription(Str, Color));
530 festring felist::GetEntry (uInt I) const {
531 return Entry[I]->String;
535 col16 felist::GetColor (uInt I) const {
536 return Entry[I]->Color;
540 void felist::SetColor (uInt I, col16 What) {
541 Entry[I]->Color = What;