home/end now works in lists
[k8-i-v-a-n.git] / src / felib / felist.cpp
blob15e25fe97bc168b223f154738ab14c794b5ebfe9
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 "save.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) :
40 String(String),
41 Color(Color),
42 Marginal(Marginal),
43 ImageKey(ImageKey),
44 Selectable(Selectable) {}
46 festring String;
47 col16 Color;
48 uint Marginal;
49 uint ImageKey;
50 truth Selectable;
54 outputfile &operator << (outputfile &SaveFile, const felistentry *Entry) {
55 SaveFile << Entry->String << Entry->Color << Entry->Marginal << Entry->Selectable;
56 return SaveFile;
60 inputfile &operator >> (inputfile &SaveFile, felistentry *&Entry) {
61 Entry = new felistentry;
62 SaveFile >> Entry->String >> Entry->Color >> Entry->Marginal >> Entry->Selectable;
63 return SaveFile;
67 struct felistdescription {
68 felistdescription () {}
69 felistdescription (cfestring &String, col16 Color)
70 : String(String), Color(Color) {}
71 festring String;
72 col16 Color;
76 felist::felist (cfestring &Topic, col16 TopicColor, uint Maximum) :
77 Maximum(Maximum),
78 Selected(0),
79 Pos(10, 10),
80 Width(780),
81 PageLength(30),
82 BackColor(0),
83 Flags(SELECTABLE|FADE),
84 UpKey(KEY_UP),
85 DownKey(KEY_DOWN),
86 EntryDrawer(0)
88 AddDescription(Topic, TopicColor);
92 felist::~felist () {
93 Empty();
94 for (uint c = 0; c < Description.size(); ++c) delete Description[c];
98 void felist::Pop () {
99 delete Entry[GetLastEntryIndex()];
100 Entry.pop_back();
104 uint felist::Draw () {
105 while (Entry.size() && Entry[GetLastEntryIndex()]->String.IsEmpty()) Pop();
106 if (Entry.empty()) return LIST_WAS_EMPTY;
107 FelistCurrentlyDrawn = this;
108 if (globalwindowhandler::ControlLoopsInstalled()) globalwindowhandler::InstallControlLoop(FelistDrawController);
109 bitmap BackGround(RES);
110 BackGround.ActivateFastFlag();
111 bitmap *Buffer;
112 if (Flags & FADE) {
113 Buffer = new bitmap(RES, 0);
114 Buffer->ActivateFastFlag();
115 BackGround.ClearToColor(0);
116 } else {
117 Buffer = DOUBLE_BUFFER;
118 Buffer->FastBlit(&BackGround);
120 uint c;
121 uint Return, Selectables = 0;
122 truth JustSelectMove = false;
123 for (c = 0; c < Entry.size(); ++c) if (Entry[c]->Selectable) ++Selectables;
124 if (Selected >= Selectables) Selected = Selectables-1;
125 if (Flags & SELECTABLE) PageBegin = Selected-Selected%PageLength;
126 else if (Flags & INVERSE_MODE) PageBegin = GetLastEntryIndex()-GetLastEntryIndex()%PageLength;
127 else PageBegin = 0;
128 for (;;) {
129 truth AtTheEnd = DrawPage(Buffer);
130 if (Flags & FADE) {
131 if (JustSelectMove) {
132 Buffer->FastBlit(DOUBLE_BUFFER);
133 graphics::BlitDBToScreen();
134 } else {
135 Buffer->FadeToScreen();
137 JustSelectMove = false;
138 } else {
139 graphics::BlitDBToScreen();
141 uint Pressed = GET_KEY(false);
142 if (Flags & SELECTABLE) {
143 // list movement and selections
144 if (Pressed >= 'a' && Pressed <= 'z') Pressed -= 32;
145 if (Pressed >= 'A' && Pressed <= 'Z') {
146 Pressed -= 65;
147 if (Pressed < PageLength && Pressed+PageBegin < Selectables) {
148 Return = Selected = Pressed+PageBegin;
149 if (fastListMode) {
150 JustSelectMove = true;
151 continue;
152 } else {
153 break;
156 continue;
158 if (Pressed == UpKey) {
159 if (Selected) {
160 --Selected;
161 if (Selected < PageBegin) {
162 BackGround.FastBlit(Buffer);
163 PageBegin -= PageLength;
164 } else {
165 JustSelectMove = true;
167 } else {
168 for (c = 0, Selected = 0; c < Entry.size(); ++c) if (Entry[c]->Selectable) ++Selected;
169 --Selected;
170 if (PageBegin == Selected-Selected%PageLength) JustSelectMove = true;
171 else {
172 BackGround.FastBlit(Buffer);
173 PageBegin = Selected-Selected%PageLength;
176 continue;
178 if (Pressed == DownKey) {
179 if (!AtTheEnd || Selected != Selectables-1) {
180 ++Selected;
181 if (Selected > PageBegin+PageLength-1) {
182 BackGround.FastBlit(Buffer);
183 PageBegin += PageLength;
184 } else {
185 JustSelectMove = true;
187 } else {
188 if (!PageBegin) JustSelectMove = true; else BackGround.FastBlit(Buffer);
189 Selected = PageBegin = 0;
191 continue;
193 if (Pressed == KEY_HOME) {
194 Selected = PageBegin;
195 JustSelectMove = true;
196 continue;
198 if (Pressed == KEY_END) {
199 //fprintf(stderr, "sel: %u; pb: %u; pl: %u; ss: %u; ae: %s\n", Selected, PageBegin, PageLength, Selectables, AtTheEnd ? "end" : "not end");
200 if (Selectables) {
201 Selected = PageBegin+PageLength-1;
202 if (Selected >= Selectables) Selected = Selectables-1;
204 JustSelectMove = true;
205 continue;
207 if (Pressed == KEY_ENTER) {
208 Return = Selected;
209 break;
212 if (Pressed == KEY_ESC) {
213 Return = ESCAPED;
214 break;
216 if ((AtTheEnd && !(Flags & INVERSE_MODE)) || (!PageBegin && (Flags & INVERSE_MODE))) {
217 if (Flags & FELIST_NO_BADKEY_EXIT) continue;
218 Return = NOTHING_SELECTED;
219 break;
220 } else {
221 BackGround.FastBlit(Buffer);
222 if (Flags & INVERSE_MODE) PageBegin -= PageLength; else PageBegin += PageLength;
223 if (Flags & SELECTABLE) Selected = PageBegin;
226 if (!(Flags & FADE)) {
227 if (Flags & DRAW_BACKGROUND_AFTERWARDS) BackGround.FastBlit(DOUBLE_BUFFER);
228 if (Flags & BLIT_AFTERWARDS) graphics::BlitDBToScreen();
229 } else {
230 delete Buffer;
232 globalwindowhandler::DeInstallControlLoop(FelistDrawController);
233 return Return;
237 static festring Str;
239 truth felist::DrawPage (bitmap *Buffer) const {
240 uint LastFillBottom = Pos.Y+23+Description.size()*10;
241 DrawDescription(Buffer);
242 uint c, i; // c == entry index, i == selectable index
243 for (c = 0, i = 0; i != PageBegin; ++c) if (Entry[c]->Selectable) ++i;
244 while (!Entry[c]->Selectable && Entry[c]->String.IsEmpty()) ++c;
245 std::vector<festring> Chapter;
246 //col16 selBack = BackColor^0xFFFF, selText = BackColor;
247 //col16 selBack = LIGHT_GRAY, selText = BLACK;
248 col16 selBack = BLUE, selText = WHITE;
249 for (;;) {
250 Str.Empty();
251 uint Marginal = Entry[c]->Marginal;
252 if (Flags & SELECTABLE && Entry[c]->Selectable) {
253 Str << char('A'+(i-PageBegin)) << ": ";
254 Marginal += 3;
256 Str << Entry[c]->String;
257 bool selected = (Flags & SELECTABLE && Entry[c]->Selectable && Selected == i);
258 if (Entry[c]->ImageKey != NO_IMAGE) {
259 if (Str.GetSize() <= (Width-50)>>3) {
260 Buffer->Fill(Pos.X+3, LastFillBottom, Width-6, 20, !selected ? BackColor : selBack);
261 if (EntryDrawer) EntryDrawer(Buffer, v2(Pos.X+13, LastFillBottom), Entry[c]->ImageKey);
262 if (selected) {
263 //FONT->PrintfUnshaded(Buffer, v2(Pos.X+38, LastFillBottom+5), WHITE, "%s", Str.CStr());
264 FONT->PrintfUnshaded(Buffer, v2(Pos.X+37, LastFillBottom+4), selText, "%s", Str.CStr());
265 } else {
266 FONT->Printf(Buffer, v2(Pos.X+37, LastFillBottom+4), Entry[c]->Color, "%s", Str.CStr());
268 LastFillBottom += 20;
269 } else {
270 uint ChapterSize = festring::SplitString(Str, Chapter, (Width-50)>>3, Marginal);
271 uint PictureTop = LastFillBottom+ChapterSize*5-9;
272 for (uint l = 0; l < ChapterSize; ++l) {
273 Buffer->Fill(Pos.X+3, LastFillBottom, Width-6, 10, !selected ? BackColor : selBack);
274 if (selected) {
275 //FONT->PrintfUnshaded(Buffer, v2(Pos.X+38, LastFillBottom+1), WHITE, "%s", Chapter[l].CStr());
276 FONT->PrintfUnshaded(Buffer, v2(Pos.X+37, LastFillBottom), selText, "%s", Chapter[l].CStr());
277 } else {
278 FONT->Printf(Buffer, v2(Pos.X+37, LastFillBottom), Entry[c]->Color, "%s", Chapter[l].CStr());
280 LastFillBottom += 10;
282 if (EntryDrawer) EntryDrawer(Buffer, v2(Pos.X+13, PictureTop), Entry[c]->ImageKey);
284 } else {
285 uint ChapterSize = festring::SplitString(Str, Chapter, (Width-26)>>3, Marginal);
286 for (uint l = 0; l < ChapterSize; ++l) {
287 Buffer->Fill(Pos.X+3, LastFillBottom, Width-6, 10, !selected ? BackColor : selBack);
288 if (selected) {
289 //FONT->PrintfUnshaded(Buffer, v2(Pos.X+14, LastFillBottom+1), WHITE, "%s", Chapter[l].CStr());
290 FONT->PrintfUnshaded(Buffer, v2(Pos.X+13, LastFillBottom), selText, "%s", Chapter[l].CStr());
291 } else {
292 FONT->Printf(Buffer, v2(Pos.X+13, LastFillBottom), Entry[c]->Color, "%s", Chapter[l].CStr());
294 LastFillBottom += 10;
297 if ((i-PageBegin == PageLength-1 && Entry[c]->Selectable) || c == Entry.size()-1) {
298 if ((!(Flags & INVERSE_MODE) && c != Entry.size()-1) || (Flags & INVERSE_MODE && PageBegin)) {
299 Buffer->Fill(Pos.X+3, LastFillBottom, Width-6, 30, BackColor);
300 FONT->Printf(Buffer, v2(Pos.X+13, LastFillBottom+10), WHITE, "- Press SPACE to continue, ESC to exit -");
301 LastFillBottom += 30;
302 } else {
303 Buffer->Fill(Pos.X+3, LastFillBottom, Width-6, 10, BackColor);
304 LastFillBottom += 10;
306 Buffer->DrawRectangle(Pos.X+1, Pos.Y+1, Pos.X+Width-2, LastFillBottom+1, DARK_GRAY, true);
307 break;
309 if (Entry[c++]->Selectable) ++i;
311 return c == Entry.size()-1;
315 void felist::DrawDescription (bitmap *Buffer) const {
316 Buffer->Fill(Pos.X+3, Pos.Y+3, Width-6, 20, BackColor);
317 for (uint c = 0; c < Description.size(); ++c) {
318 Buffer->Fill(Pos.X+3, Pos.Y+13+c*10, Width-6, 10, BackColor);
319 FONT->Printf(Buffer, v2(Pos.X+13, Pos.Y+13+c*10), Description[c]->Color, Description[c]->String.CStr());
321 Buffer->Fill(Pos.X+3, Pos.Y+13+Description.size()*10, Width-6, 10, BackColor);
325 /* We suppose InverseMode != false here */
326 void felist::QuickDraw (bitmap *Bitmap, uint PageLength) const {
327 static std::vector<festring> Chapter;
328 uint Width = Bitmap->GetSize().X;
329 Bitmap->Fill(3, 3, Width-6, 20+PageLength*10, 0);
330 Bitmap->DrawRectangle(1, 1, Width-2, 24+PageLength*10, DARK_GRAY, true);
331 uint LineSize = (Width-26)>>3;
332 uint Index = 0;
333 uint Bottom = PageLength*10+3;
334 for (uint c1 = 0; c1 <= Selected; ++c1) {
335 const felistentry* CurrentEntry = Entry[Selected-c1];
336 uint ChapterSize = festring::SplitString(CurrentEntry->String, Chapter, LineSize, CurrentEntry->Marginal);
337 for (uint c2 = 0; c2 < ChapterSize; ++c2) {
338 col16 Color = CurrentEntry->Color;
339 Color = MakeRGB16(
340 GetRed16(Color)-((GetRed16(Color)*3*Index/PageLength)>>2),
341 GetGreen16(Color)-((GetGreen16(Color)*3*Index/PageLength)>>2),
342 GetBlue16(Color)-((GetBlue16(Color)*3*Index/PageLength)>>2));
343 FONT->Printf(Bitmap, v2(13, Bottom), Color, "%s", Chapter[ChapterSize-c2-1].CStr());
344 Bottom -= 10;
345 if (++Index == PageLength) return;
351 void felist::CreateQuickDrawFontCaches (rawbitmap *Font, col16 Color, uint PageLength) {
352 if (PageLength < 2) return;
353 for (uint c = 0; c < PageLength; ++c)
354 Font->CreateFontCache(
355 MakeRGB16(
356 GetRed16(Color)-((GetRed16(Color)*3*c/PageLength)>>2),
357 GetGreen16(Color)-((GetGreen16(Color)*3*c/PageLength)>>2),
358 GetBlue16(Color)-((GetBlue16(Color)*3*c/PageLength)>>2)));
362 void felist::Empty () {
363 for (uint c = 0; c < Entry.size(); ++c) delete Entry[c];
364 Entry.clear();
368 void felist::AddEntry (cfestring &Str, col16 Color, uint Marginal, uint Key, truth Selectable) {
369 Entry.push_back(new felistentry(Str, Color, Marginal, Key, Selectable));
370 if (Maximum && Entry.size() > ulong(Maximum)) {
371 delete Entry[0];
372 Entry.erase(Entry.begin());
377 void felist::Save (outputfile &SaveFile) const {
378 SaveFile << Entry << Maximum << Selected;
382 void felist::Load (inputfile& SaveFile) {
383 SaveFile >> Entry >> Maximum >> Selected;
387 void felist::PrintToFile (cfestring& FileName) {
388 std::ofstream SaveFile(FileName.CStr(), std::ios::out);
389 if (!SaveFile.is_open()) return;
390 uint c;
391 for (c = 0; c < Description.size(); ++c) SaveFile << Description[c]->String.CStr() << std::endl;
392 SaveFile << std::endl;
393 for (c = 0; c < Entry.size(); ++c) {
394 if (Entry[c]->ImageKey != NO_IMAGE) SaveFile << " ";
395 SaveFile << Entry[c]->String.CStr() << std::endl;
400 void felist::AddDescription (cfestring &Str, col16 Color) {
401 Description.push_back(new felistdescription(Str, Color));
405 festring felist::GetEntry (uint I) const {
406 return Entry[I]->String;
410 col16 felist::GetColor (uint I) const {
411 return Entry[I]->Color;
415 void felist::SetColor (uint I, col16 What) {
416 Entry[I]->Color = What;