1 //=============================================================================
2 //
3 // Adventure Game Studio (AGS)
4 //
5 // Copyright (C) 1999-2011 Chris Jones and 2011-20xx others
6 // The full list of copyright holders can be found in the Copyright.txt
7 // file, which is part of this source code distribution.
8 //
9 // The AGS source code is provided under the Artistic License 2.0.
10 // A copy of this license can be found in the file License.txt and at
11 // http://www.opensource.org/licenses/artistic-license-2.0.php
12 //
13 //=============================================================================
14
15 #include <stdio.h>
16 #include <stdlib.h>
17 #include <string.h>
18 #include "gui/guilistbox.h"
19 #include "gui/guimain.h"
20 #include "font/fonts.h"
21 #include "util/stream.h"
22 #include "gfx/bitmap.h"
23 #include "util/wgt2allg.h"
24
25 using AGS::Common::Stream;
26 using AGS::Common::Bitmap;
27
28 std::vector<GUIListBox> guilist;
29 int numguilist = 0;
30
ChangeFont(int newfont)31 void GUIListBox::ChangeFont(int newfont) {
32 font = newfont;
33 rowheight = getfontheight(font) + get_fixed_pixel_size(2);
34 num_items_fit = hit / rowheight;
35 }
36
Resized()37 void GUIListBox::Resized()
38 {
39 if (rowheight == 0)
40 {
41 check_font(&font);
42 ChangeFont(font);
43 }
44
45 if (rowheight > 0)
46 num_items_fit = hit / rowheight;
47 }
48
WriteToFile(Stream * out)49 void GUIListBox::WriteToFile(Stream *out)
50 {
51 int a;
52
53 GUIObject::WriteToFile(out);
54 // MACPORT FIXES: swap
55 out->WriteArrayOfInt32(&numItems, 11);
56 out->WriteInt32(alignment);
57 out->WriteInt32(reserved1);
58 out->WriteInt32(selectedbgcol);
59 for (a = 0; a < numItems; a++)
60 items[a].Write(out);
61
62 if (exflags & GLF_SGINDEXVALID)
63 out->WriteArrayOfInt16(&saveGameIndex[0], numItems);
64 }
65
ReadFromFile(Stream * in,GuiVersion gui_version)66 void GUIListBox::ReadFromFile(Stream *in, GuiVersion gui_version)
67 {
68 int a, i;
69 char tempbuf[300];
70
71 Clear();
72
73 GUIObject::ReadFromFile(in, gui_version);
74 // MACPORT FIXES: swap
75 in->ReadArrayOfInt32(&numItems, 11);
76
77 if (gui_version >= kGuiVersion_272b) {
78 alignment = in->ReadInt32();
79 reserved1 = in->ReadInt32();
80 }
81 else {
82 alignment = GALIGN_LEFT;
83 reserved1 = 0;
84 }
85
86 if (gui_version >= kGuiVersion_unkn_107) {
87 selectedbgcol = in->ReadInt32();
88 }
89 else {
90 selectedbgcol = textcol;
91 if (selectedbgcol == 0)
92 selectedbgcol = 16;
93 }
94
95 for (a = 0; a < numItems; a++) {
96 i = 0;
97 while ((tempbuf[i] = in->ReadInt8()) != 0)
98 i++;
99
100 items[a] = tempbuf;
101 saveGameIndex[a] = -1;
102 }
103
104 if ((gui_version >= kGuiVersion_272d) && (exflags & GLF_SGINDEXVALID)) {
105 in->ReadArrayOfInt16(&saveGameIndex[0], numItems);
106 }
107
108 if (textcol == 0)
109 textcol = 16;
110 }
111
AddItem(const char * toadd)112 int GUIListBox::AddItem(const char *toadd)
113 {
114 if (numItems >= MAX_LISTBOX_ITEMS)
115 return -1;
116
117 guis_need_update = 1;
118 items[numItems] = toadd;
119 saveGameIndex[numItems] = -1;
120 numItems++;
121 return numItems - 1;
122 }
123
InsertItem(int index,const char * toadd)124 int GUIListBox::InsertItem(int index, const char *toadd)
125 {
126 int aa;
127
128 if (numItems >= MAX_LISTBOX_ITEMS)
129 return -1;
130
131 if ((index < 0) || (index > numItems))
132 return -1;
133
134 guis_need_update = 1;
135
136 for (aa = numItems; aa > index; aa--) {
137 items[aa] = items[aa - 1];
138 saveGameIndex[aa] = saveGameIndex[aa - 1];
139 }
140
141 items[index] = toadd;
142 saveGameIndex[index] = -1;
143 numItems++;
144
145 if (selected >= index)
146 selected++;
147
148 return numItems - 1;
149 }
150
SetItemText(int item,const char * newtext)151 void GUIListBox::SetItemText(int item, const char *newtext)
152 {
153 if ((item >= numItems) || (item < 0))
154 return;
155
156 guis_need_update = 1;
157 items[item] = newtext;
158 }
159
Clear()160 void GUIListBox::Clear()
161 {
162 int aa;
163 for (aa = 0; aa < numItems; aa++)
164 items[aa].Free();
165
166 numItems = 0;
167 selected = 0;
168 topItem = 0;
169 guis_need_update = 1;
170 }
171
RemoveItem(int index)172 void GUIListBox::RemoveItem(int index)
173 {
174 int aa;
175
176 if ((index < 0) || (index >= numItems))
177 return;
178
179 numItems--;
180 for (aa = index; aa < numItems; aa++) {
181 items[aa] = items[aa + 1];
182 saveGameIndex[aa] = saveGameIndex[aa + 1];
183 }
184
185 if (selected > index)
186 selected--;
187 if (selected >= numItems)
188 selected = -1;
189
190 guis_need_update = 1;
191 }
192
Draw(Common::Bitmap * ds)193 void GUIListBox::Draw(Common::Bitmap *ds)
194 {
195 wid--;
196 hit--;
197 int pixel_size = get_fixed_pixel_size(1);
198
199 check_font(&font);
200 color_t text_color = ds->GetCompatibleColor(textcol);
201 color_t draw_color = ds->GetCompatibleColor(textcol);
202 if ((exflags & GLF_NOBORDER) == 0) {
203 ds->DrawRect(Rect(x, y, x + wid + (pixel_size - 1), y + hit + (pixel_size - 1)), draw_color);
204 if (pixel_size > 1)
205 ds->DrawRect(Rect(x + 1, y + 1, x + wid, y + hit), draw_color);
206 }
207
208 int rightHandEdge = (x + wid) - pixel_size - 1;
209
210 // use ChangeFont to update the rowheight and num_items_fit
211 ChangeFont(font);
212
213 // draw the scroll bar in if necessary
214 if ((numItems > num_items_fit) && ((exflags & GLF_NOBORDER) == 0) && ((exflags & GLF_NOARROWS) == 0)) {
215 int xstrt, ystrt;
216 ds->DrawRect(Rect(x + wid - get_fixed_pixel_size(7), y, (x + (pixel_size - 1) + wid) - get_fixed_pixel_size(7), y + hit), draw_color);
217 ds->DrawRect(Rect(x + wid - get_fixed_pixel_size(7), y + hit / 2, x + wid, y + hit / 2 + (pixel_size - 1)), draw_color);
218
219 xstrt = (x + wid - get_fixed_pixel_size(6)) + (pixel_size - 1);
220 ystrt = (y + hit - 3) - get_fixed_pixel_size(5);
221
222 draw_color = ds->GetCompatibleColor(textcol);
223 ds->DrawTriangle(Triangle(xstrt, ystrt, xstrt + get_fixed_pixel_size(4), ystrt,
224 xstrt + get_fixed_pixel_size(2),
225 ystrt + get_fixed_pixel_size(5)), draw_color);
226
227 ystrt = y + 3;
228 ds->DrawTriangle(Triangle(xstrt, ystrt + get_fixed_pixel_size(5),
229 xstrt + get_fixed_pixel_size(4),
230 ystrt + get_fixed_pixel_size(5),
231 xstrt + get_fixed_pixel_size(2), ystrt), draw_color);
232
233 rightHandEdge -= get_fixed_pixel_size(7);
234 }
235
236 Draw_items_fix();
237
238 for (int a = 0; a < num_items_fit; a++) {
239 int thisyp;
240 if (a + topItem >= numItems)
241 break;
242
243 thisyp = y + pixel_size + a * rowheight;
244 if (a + topItem == selected) {
245 int stretchto = (x + wid) - pixel_size;
246
247 text_color = ds->GetCompatibleColor(backcol);
248
249 if (selectedbgcol > 0) {
250 // draw the selected item bar (if colour not transparent)
251 draw_color = ds->GetCompatibleColor(selectedbgcol);
252 if ((num_items_fit < numItems) && ((exflags & GLF_NOBORDER) == 0) && ((exflags & GLF_NOARROWS) == 0))
253 stretchto -= get_fixed_pixel_size(7);
254
255 ds->FillRect(Rect(x + pixel_size, thisyp, stretchto, thisyp + rowheight - pixel_size), draw_color);
256 }
257 }
258 else
259 text_color = ds->GetCompatibleColor(textcol);
260
261 int item_index = a + topItem;
262 char oritext[200]; // items[] can be not longer than 200 characters due declaration
263 Draw_set_oritext(oritext, items[item_index]);
264
265 if (alignment == GALIGN_LEFT)
266 wouttext_outline(ds, x + 1 + pixel_size, thisyp + 1, font, text_color, oritext);
267 else {
268 int textWidth = wgettextwidth(oritext, font);
269
270 if (alignment == GALIGN_RIGHT)
271 wouttext_outline(ds, rightHandEdge - textWidth, thisyp + 1, font, text_color, oritext);
272 else
273 wouttext_outline(ds, ((rightHandEdge - x) / 2) + x - (textWidth / 2), thisyp + 1, font, text_color, oritext);
274 }
275
276 }
277 wid++;
278 hit++;
279
280 Draw_items_unfix();
281 }
282
IsInRightMargin(int xx)283 int GUIListBox::IsInRightMargin(int xx) {
284
285 if ((xx >= (wid - get_fixed_pixel_size(6))) && ((exflags & GLF_NOBORDER) == 0) && ((exflags & GLF_NOARROWS) == 0)) {
286 return 1;
287 }
288 return 0;
289 }
290
GetIndexFromCoordinates(int xx,int yy)291 int GUIListBox::GetIndexFromCoordinates(int xx, int yy) {
292 if (rowheight <= 0 || IsInRightMargin(xx))
293 return -1;
294
295 int onindex = yy / rowheight + topItem;
296 if ((onindex < 0) || (onindex >= numItems))
297 return -1;
298
299 return onindex;
300 }
301
MouseDown()302 int GUIListBox::MouseDown()
303 {
304 if (IsInRightMargin(mousexp)) {
305 if ((mouseyp < hit / 2) && (topItem > 0))
306 topItem--;
307
308 if ((mouseyp >= hit / 2) && (numItems > topItem + num_items_fit))
309 topItem++;
310
311 return 0;
312 }
313
314 int newsel = GetIndexFromCoordinates(mousexp, mouseyp);
315 if (newsel < 0)
316 return 0;
317
318 selected = newsel;
319 activated = 1;
320 return 0;
321 }
322