1 #include "Font.h"
2 #include "Local.h"
3 #include "PopUpBox.h"
4 #include "SysUtil.h"
5 #include "Debug.h"
6 #include "VObject.h"
7 #include "Video.h"
8 #include "MemMan.h"
9 #include "VSurface.h"
10 #include "UILayout.h"
11 
12 #include <string_theory/string>
13 
14 #include <stdexcept>
15 
16 
17 #define MAX_POPUP_BOX_COUNT 20
18 
19 
20 struct PopUpString
21 {
22 	ST::utf32_buffer codepoints;
23 	UINT8 ubForegroundColor;
24 	UINT8 ubBackgroundColor;
25 	UINT8 ubHighLight;
26 	UINT8 ubShade;
27 	UINT8 ubSecondaryShade;
28 	BOOLEAN fHighLightFlag;
29 	BOOLEAN fShadeFlag;
30 	BOOLEAN fSecondaryShadeFlag;
31 };
32 
33 struct PopUpBox
34 {
35 	SGPBox pos;
36 	UINT32 uiLeftMargin;
37 	UINT32 uiRightMargin;
38 	UINT32 uiBottomMargin;
39 	UINT32 uiTopMargin;
40 	UINT32 uiLineSpace;
41 	const SGPVObject* iBorderObjectIndex;
42 	SGPVSurface* iBackGroundSurface;
43 	UINT32 uiFlags;
44 	SGPVSurface* uiBuffer;
45 	UINT32 uiSecondColumnMinimunOffset;
46 	UINT32 uiSecondColumnCurrentOffset;
47 	UINT32 uiBoxMinWidth;
48 	BOOLEAN fUpdated;
49 	BOOLEAN fShowBox;
50 	SGPFont font;
51 
52 	PopUpString* Text[MAX_POPUP_BOX_STRING_COUNT];
53 	PopUpString* pSecondColumnString[MAX_POPUP_BOX_STRING_COUNT];
54 };
55 
56 static PopUpBox* PopUpBoxList[MAX_POPUP_BOX_COUNT];
57 
58 #define FOR_EACH_POPUP_BOX(iter) \
59 	FOR_EACH(PopUpBox*, iter, PopUpBoxList) \
60 		if (*iter == NULL) continue; else
61 
62 
63 #define BORDER_WIDTH  16
64 #define BORDER_HEIGHT  8
65 #define TOP_LEFT_CORNER     0
66 #define TOP_EDGE            4
67 #define TOP_RIGHT_CORNER    1
68 #define SIDE_EDGE           5
69 #define BOTTOM_LEFT_CORNER  2
70 #define BOTTOM_EDGE         4
71 #define BOTTOM_RIGHT_CORNER 3
72 
73 
GetLineSpace(const PopUpBox * const box)74 UINT32 GetLineSpace(const PopUpBox* const box)
75 {
76 	// return number of pixels between lines for this box
77 	return box->uiLineSpace;
78 }
79 
80 
SpecifyBoxMinWidth(PopUpBox * const box,INT32 iMinWidth)81 void SpecifyBoxMinWidth(PopUpBox* const box, INT32 iMinWidth)
82 {
83 	box->uiBoxMinWidth = iMinWidth;
84 
85 	// check if the box is currently too small
86 	if (box->pos.w < iMinWidth) box->pos.w = iMinWidth;
87 }
88 
89 
CreatePopUpBox(const SGPPoint Position,const UINT32 uiFlags,SGPVSurface * const buffer,const SGPVObject * const border,SGPVSurface * const background,const UINT32 margin_l,const UINT32 margin_t,const UINT32 margin_b,const UINT32 margin_r,const UINT32 line_space)90 PopUpBox* CreatePopUpBox(const SGPPoint Position, const UINT32 uiFlags, SGPVSurface* const buffer, const SGPVObject* const border, SGPVSurface* const background, const UINT32 margin_l, const UINT32 margin_t, const UINT32 margin_b, const UINT32 margin_r, const UINT32 line_space)
91 {
92 	// find first free box
93 	FOR_EACH(PopUpBox*, i, PopUpBoxList)
94 	{
95 		if (*i == NULL)
96 		{
97 			PopUpBox* const box = new PopUpBox{};
98 			SetBoxXY(box, Position.iX, Position.iY);
99 			box->uiFlags            = uiFlags;
100 			box->uiBuffer           = buffer;
101 			box->iBorderObjectIndex = border;
102 			box->iBackGroundSurface = background;
103 			box->uiLeftMargin       = margin_l;
104 			box->uiRightMargin      = margin_r;
105 			box->uiTopMargin        = margin_t;
106 			box->uiBottomMargin     = margin_b;
107 			box->uiLineSpace        = line_space;
108 
109 			*i = box;
110 			return box;
111 		}
112 	}
113 
114 	// ran out of available popup boxes - probably not freeing them up right!
115 	throw std::runtime_error("Out of popup box slots");
116 }
117 
118 
GetTopMarginSize(const PopUpBox * const box)119 UINT32 GetTopMarginSize(const PopUpBox* const box)
120 {
121 	// return size of top margin, for mouse region offsets
122 	return box->uiTopMargin;
123 }
124 
125 
ShadeStringInBox(PopUpBox * const box,INT32 const line,bool const shade)126 void ShadeStringInBox(PopUpBox* const box, INT32 const line, bool const shade)
127 {
128 	PopUpString* const s = box->Text[line];
129 	if (s) s->fShadeFlag = shade;
130 }
131 
132 
ShadeStringInBox(PopUpBox * const box,INT32 const line,PopUpShade const shade)133 void ShadeStringInBox(PopUpBox* const box, INT32 const line, PopUpShade const shade)
134 {
135 	PopUpString* const s = box->Text[line];
136 	if (!s) return;
137 
138 	s->fShadeFlag          = shade == POPUP_SHADE;
139 	s->fSecondaryShadeFlag = shade == POPUP_SHADE_SECONDARY;
140 }
141 
142 
SetBoxXY(PopUpBox * const box,const INT16 x,const INT16 y)143 void SetBoxXY(PopUpBox* const box, const INT16 x, const INT16 y)
144 {
145 	box->pos.x    = x;
146 	box->pos.y    = y;
147 	box->fUpdated = FALSE;
148 }
149 
150 
SetBoxX(PopUpBox * const box,const INT16 x)151 void SetBoxX(PopUpBox* const box, const INT16 x)
152 {
153 	box->pos.x    = x;
154 	box->fUpdated = FALSE;
155 }
156 
157 
SetBoxY(PopUpBox * const box,const INT16 y)158 void SetBoxY(PopUpBox* const box, const INT16 y)
159 {
160 	box->pos.y    = y;
161 	box->fUpdated = FALSE;
162 }
163 
164 
GetBoxArea(PopUpBox const * const box)165 SGPBox const& GetBoxArea(PopUpBox const* const box)
166 {
167 	return box->pos;
168 }
169 
170 
171 // adds a FIRST column string to the CURRENT popup box
AddMonoString(PopUpBox * box,const ST::string & str)172 void AddMonoString(PopUpBox* box, const ST::string& str)
173 {
174 	INT32 iCounter = 0;
175 
176 	// find first free slot in list
177 	for (iCounter = 0; iCounter < MAX_POPUP_BOX_STRING_COUNT && box->Text[iCounter] != NULL; iCounter++);
178 
179 	if ( iCounter >= MAX_POPUP_BOX_STRING_COUNT )
180 	{
181 		// using too many text lines, or not freeing them up properly
182 		SLOGA("AddMonoString: too many text lines");
183 		return;
184 	}
185 
186 	PopUpString* const pStringSt    = new PopUpString{};
187 
188 	box->Text[iCounter]                      = pStringSt;
189 	box->Text[iCounter]->codepoints          = str.to_utf32();
190 	box->Text[iCounter]->fShadeFlag          = FALSE;
191 	box->Text[iCounter]->fHighLightFlag      = FALSE;
192 	box->Text[iCounter]->fSecondaryShadeFlag = FALSE;
193 
194 	box->fUpdated = FALSE;
195 }
196 
197 
198 static void RemoveBoxSecondaryText(PopUpBox*, INT32 hStringHandle);
199 
200 
AddSecondColumnMonoString(PopUpBox * box,const ST::string & str)201 void AddSecondColumnMonoString(PopUpBox* box, const ST::string& str)
202 {
203 	INT32 iCounter=0;
204 
205 	// find the LAST USED text string index
206 	for (iCounter = 0; iCounter + 1 < MAX_POPUP_BOX_STRING_COUNT && box->Text[iCounter + 1] != NULL; iCounter++);
207 
208 	if ( iCounter >= MAX_POPUP_BOX_STRING_COUNT )
209 	{
210 		// using too many text lines, or not freeing them up properly
211 		SLOGA("AddSecondColumnMonoString: too many text lines");
212 		return;
213 	}
214 
215 	PopUpString* const pStringSt    = new PopUpString{};
216 
217 	RemoveBoxSecondaryText(box, iCounter);
218 
219 	box->pSecondColumnString[iCounter]                 = pStringSt;
220 	box->pSecondColumnString[iCounter]->codepoints     = str.to_utf32();
221 	box->pSecondColumnString[iCounter]->fShadeFlag     = FALSE;
222 	box->pSecondColumnString[iCounter]->fHighLightFlag = FALSE;
223 }
224 
225 
GetNumberOfLinesOfTextInBox(const PopUpBox * const box)226 UINT32 GetNumberOfLinesOfTextInBox(const PopUpBox* const box)
227 {
228 	INT32 iCounter = 0;
229 
230 	// count number of lines
231 	// check string size
232 	for( iCounter = 0; iCounter < MAX_POPUP_BOX_STRING_COUNT; iCounter++ )
233 	{
234 		if (box->Text[iCounter] == NULL) break;
235 	}
236 
237 	return( iCounter );
238 }
239 
240 
SetBoxFont(PopUpBox * const box,SGPFont const font)241 void SetBoxFont(PopUpBox* const box, SGPFont const font)
242 {
243 	box->font     = font;
244 	box->fUpdated = FALSE;
245 }
246 
247 
SetBoxSecondColumnMinimumOffset(PopUpBox * const box,const UINT32 uiWidth)248 void SetBoxSecondColumnMinimumOffset(PopUpBox* const box, const UINT32 uiWidth)
249 {
250 	box->uiSecondColumnMinimunOffset = uiWidth;
251 }
252 
253 
GetBoxFont(const PopUpBox * const box)254 SGPFont GetBoxFont(const PopUpBox* const box)
255 {
256 	return box->font;
257 }
258 
259 
260 // set the foreground color of this string in this pop up box
SetBoxLineForeground(PopUpBox * const box,const INT32 iStringValue,const UINT8 ubColor)261 void SetBoxLineForeground(PopUpBox* const box, const INT32 iStringValue, const UINT8 ubColor)
262 {
263 	box->Text[iStringValue]->ubForegroundColor = ubColor;
264 }
265 
266 
SetBoxSecondaryShade(PopUpBox * const box,UINT8 const colour)267 void SetBoxSecondaryShade(PopUpBox* const box, UINT8 const colour)
268 {
269 	FOR_EACH(PopUpString*, i, box->Text)
270 	{
271 		PopUpString* const p = *i;
272 		if (p) p->ubSecondaryShade = colour;
273 	}
274 }
275 
276 
SetBoxForeground(PopUpBox * const box,UINT8 const colour)277 void SetBoxForeground(PopUpBox* const box, UINT8 const colour)
278 {
279 	FOR_EACH(PopUpString*, i, box->Text)
280 	{
281 		PopUpString* const p = *i;
282 		if (p) p->ubForegroundColor = colour;
283 	}
284 }
285 
286 
SetBoxBackground(PopUpBox * const box,UINT8 const colour)287 void SetBoxBackground(PopUpBox* const box, UINT8 const colour)
288 {
289 	FOR_EACH(PopUpString*, i, box->Text)
290 	{
291 		PopUpString* const p = *i;
292 		if (p) p->ubBackgroundColor = colour;
293 	}
294 }
295 
296 
SetBoxHighLight(PopUpBox * const box,UINT8 const colour)297 void SetBoxHighLight(PopUpBox* const box, UINT8 const colour)
298 {
299 	FOR_EACH(PopUpString*, i, box->Text)
300 	{
301 		PopUpString* const p = *i;
302 		if (p) p->ubHighLight = colour;
303 	}
304 }
305 
306 
SetBoxShade(PopUpBox * const box,UINT8 const colour)307 void SetBoxShade(PopUpBox* const box, UINT8 const colour)
308 {
309 	FOR_EACH(PopUpString*, i, box->Text)
310 	{
311 		PopUpString* const p = *i;
312 		if (p) p->ubShade = colour;
313 	}
314 }
315 
316 
SetBoxSecondColumnForeground(PopUpBox * const box,UINT8 const colour)317 void SetBoxSecondColumnForeground(PopUpBox* const box, UINT8 const colour)
318 {
319 	FOR_EACH(PopUpString*, i, box->pSecondColumnString)
320 	{
321 		PopUpString* const p = *i;
322 		if (p) p->ubForegroundColor = colour;
323 	}
324 }
325 
326 
SetBoxSecondColumnBackground(PopUpBox * const box,UINT8 const colour)327 void SetBoxSecondColumnBackground(PopUpBox* const box, UINT8 const colour)
328 {
329 	FOR_EACH(PopUpString*, i, box->pSecondColumnString)
330 	{
331 		PopUpString* const p = *i;
332 		if (p) p->ubBackgroundColor = colour;
333 	}
334 }
335 
336 
SetBoxSecondColumnHighLight(PopUpBox * const box,UINT8 const colour)337 void SetBoxSecondColumnHighLight(PopUpBox* const box, UINT8 const colour)
338 {
339 	FOR_EACH(PopUpString*, i, box->pSecondColumnString)
340 	{
341 		PopUpString* const p = *i;
342 		if (p) p->ubHighLight = colour;
343 	}
344 }
345 
346 
SetBoxSecondColumnShade(PopUpBox * const box,UINT8 const colour)347 void SetBoxSecondColumnShade(PopUpBox* const box, UINT8 const colour)
348 {
349 	FOR_EACH(PopUpString*, i, box->pSecondColumnString)
350 	{
351 		PopUpString* const p = *i;
352 		if (p) p->ubShade = colour;
353 	}
354 }
355 
356 
HighLightBoxLine(PopUpBox * const box,const INT32 iLineNumber)357 void HighLightBoxLine(PopUpBox* const box, const INT32 iLineNumber)
358 {
359 	// highlight iLineNumber Line in box
360 	PopUpString* const line = box->Text[iLineNumber];
361 	if (line != NULL)
362 	{
363 		line->fHighLightFlag = TRUE;
364 	}
365 }
366 
367 
GetBoxShadeFlag(const PopUpBox * const box,const INT32 iLineNumber)368 BOOLEAN GetBoxShadeFlag(const PopUpBox* const box, const INT32 iLineNumber)
369 {
370 	if (box->Text[iLineNumber] != NULL)
371 	{
372 		return box->Text[iLineNumber]->fShadeFlag;
373 	}
374 	return( FALSE );
375 }
376 
377 
UnHighLightBox(PopUpBox * const box)378 void UnHighLightBox(PopUpBox* const box)
379 {
380 	FOR_EACH(PopUpString*, i, box->Text)
381 	{
382 		PopUpString* const p = *i;
383 		if (p) p->fHighLightFlag = FALSE;
384 	}
385 }
386 
387 
388 static void RemoveBoxPrimaryText(PopUpBox*, INT32 hStringHandle);
389 
390 
RemoveAllBoxStrings(PopUpBox * const box)391 void RemoveAllBoxStrings(PopUpBox* const box)
392 {
393 	for (UINT32 i = 0; i < MAX_POPUP_BOX_STRING_COUNT; ++i)
394 	{
395 		RemoveBoxPrimaryText(box, i);
396 		RemoveBoxSecondaryText(box, i);
397 	}
398 	box->fUpdated = FALSE;
399 }
400 
401 
RemoveBox(PopUpBox * const box)402 void RemoveBox(PopUpBox* const box)
403 {
404 	FOR_EACH_POPUP_BOX(i)
405 	{
406 		if (*i == box)
407 		{
408 			*i = NULL;
409 			RemoveAllBoxStrings(box);
410 			delete box;
411 			return;
412 		}
413 	}
414 	SLOGA("RemoveBox: box doesn't exist");
415 }
416 
417 
ShowBox(PopUpBox * const box)418 void ShowBox(PopUpBox* const box)
419 {
420 	if (!box->fShowBox)
421 	{
422 		box->fShowBox = TRUE;
423 		box->fUpdated = FALSE;
424 	}
425 }
426 
427 
HideBox(PopUpBox * const box)428 void HideBox(PopUpBox* const box)
429 {
430 	if (box->fShowBox)
431 	{
432 		box->fShowBox = FALSE;
433 		box->fUpdated = FALSE;
434 	}
435 }
436 
437 
DisplayBoxes(SGPVSurface * const uiBuffer)438 void DisplayBoxes(SGPVSurface* const uiBuffer)
439 {
440 	FOR_EACH_POPUP_BOX(i)
441 	{
442 		DisplayOnePopupBox(*i, uiBuffer);
443 	}
444 }
445 
446 
447 static void DrawBox(const PopUpBox*);
448 static void DrawBoxText(const PopUpBox*);
449 
450 
DisplayOnePopupBox(PopUpBox * const box,SGPVSurface * const uiBuffer)451 void DisplayOnePopupBox(PopUpBox* const box, SGPVSurface* const uiBuffer)
452 {
453 	if (!box->fUpdated && box->fShowBox && box->uiBuffer == uiBuffer)
454 	{
455 		box->fUpdated = TRUE;
456 		if (box->uiFlags & POPUP_BOX_FLAG_RESIZE) ResizeBoxToText(box);
457 		DrawBox(box);
458 		DrawBoxText(box);
459 	}
460 }
461 
462 
ForceUpDateOfBox(PopUpBox * const box)463 void ForceUpDateOfBox(PopUpBox* const box)
464 {
465 	box->fUpdated = FALSE;
466 }
467 
468 
DrawBox(const PopUpBox * const box)469 static void DrawBox(const PopUpBox* const box)
470 {
471 	const UINT16 x = box->pos.x;
472 	const UINT16 y = box->pos.y;
473 	UINT16       w = box->pos.w;
474 	const UINT16 h = box->pos.h;
475 
476 	// make sure it will fit on screen!
477 	Assert(x + w <= SCREEN_WIDTH);
478 	Assert(y + h <= SCREEN_HEIGHT);
479 
480 	// subtract 4 because the 2 2-pixel corners are handled separately
481 	const UINT32 uiNumTilesWide = (w - 4) / BORDER_WIDTH;
482 	const UINT32 uiNumTilesHigh = (h - 4) / BORDER_HEIGHT;
483 
484 	SGPVSurface* const dst = box->uiBuffer;
485 
486 	// blit in texture first, then borders
487 	SGPBox const clip = { 0, 0, w, h };
488 	BltVideoSurface(dst, box->iBackGroundSurface, x, y, &clip);
489 
490 	const SGPVObject* const border = box->iBorderObjectIndex;
491 
492 	// blit in 4 corners (they're 2x2 pixels)
493 	BltVideoObject(dst, border, TOP_LEFT_CORNER,     x,         y);
494 	BltVideoObject(dst, border, TOP_RIGHT_CORNER,    x + w - 2, y);
495 	BltVideoObject(dst, border, BOTTOM_RIGHT_CORNER, x + w - 2, y + h - 2);
496 	BltVideoObject(dst, border, BOTTOM_LEFT_CORNER,  x,         y + h - 2);
497 
498 	// blit in edges
499 	if (uiNumTilesWide > 0)
500 	{
501 		// full pieces
502 		for (UINT32 i = 0; i < uiNumTilesWide; ++i)
503 		{
504 			const INT32 lx = x + 2 + i * BORDER_WIDTH;
505 			BltVideoObject(dst, border, TOP_EDGE,    lx, y);
506 			BltVideoObject(dst, border, BOTTOM_EDGE, lx, y + h - 2);
507 		}
508 
509 		// partial pieces
510 		const INT32 lx = x + w - 2 - BORDER_WIDTH;
511 		BltVideoObject(dst, border, TOP_EDGE,    lx, y);
512 		BltVideoObject(dst, border, BOTTOM_EDGE, lx, y + h - 2);
513 	}
514 	if (uiNumTilesHigh > 0)
515 	{
516 		// full pieces
517 		for (UINT32 i = 0; i < uiNumTilesHigh; ++i)
518 		{
519 			const INT32 ly = y + 2 + i * BORDER_HEIGHT;
520 			BltVideoObject(dst, border, SIDE_EDGE, x,         ly);
521 			BltVideoObject(dst, border, SIDE_EDGE, x + w - 2, ly);
522 		}
523 
524 		// partial pieces
525 		const INT32 ly = y + h - 2 - BORDER_HEIGHT;
526 		BltVideoObject(dst, border, SIDE_EDGE, x,         ly);
527 		BltVideoObject(dst, border, SIDE_EDGE, x + w - 2, ly);
528 	}
529 
530 	InvalidateRegion(x, y, x + w, y + h);
531 }
532 
533 
DrawBoxText(const PopUpBox * const box)534 static void DrawBoxText(const PopUpBox* const box)
535 {
536 	SGPFont const font = box->font;
537 	INT32 const tlx  = box->pos.x + box->uiLeftMargin;
538 	INT32 const tly  = box->pos.y + box->uiTopMargin;
539 	INT32 const brx  = box->pos.x + box->pos.w - box->uiRightMargin;
540 	INT32 const bry  = box->pos.y + box->pos.h - box->uiBottomMargin;
541 	INT32 const w    = box->pos.w - (box->uiRightMargin + box->uiLeftMargin + 2);
542 	INT32 const h    = GetFontHeight(font);
543 
544 	SetFont(font);
545 	SetFontDestBuffer(box->uiBuffer, tlx - 1, tly, brx, bry);
546 
547 	for (UINT32 i = 0; i < MAX_POPUP_BOX_STRING_COUNT; ++i)
548 	{
549 		// there is text in this line?
550 		const PopUpString* const text = box->Text[i];
551 		if (text)
552 		{
553 			// are we highlighting?...shading?..or neither
554 			if (text->fHighLightFlag)
555 			{
556 				SetFontForeground(text->ubHighLight);
557 			}
558 			else if (text->fSecondaryShadeFlag)
559 			{
560 				SetFontForeground(text->ubSecondaryShade);
561 			}
562 			else if (text->fShadeFlag)
563 			{
564 				SetFontForeground(text->ubShade);
565 			}
566 			else
567 			{
568 				SetFontForeground(text->ubForegroundColor);
569 			}
570 
571 			SetFontBackground(text->ubBackgroundColor);
572 
573 			const INT32 y = tly + i * (h + box->uiLineSpace);
574 			INT16 uX;
575 			INT16 uY;
576 			if (box->uiFlags & POPUP_BOX_FLAG_CENTER_TEXT)
577 			{
578 				FindFontCenterCoordinates(tlx, y, w, h, text->codepoints, font, &uX, &uY);
579 			}
580 			else
581 			{
582 				uX = tlx;
583 				uY = y;
584 			}
585 			MPrint(uX, uY, text->codepoints);
586 		}
587 
588 		// there is secondary text in this line?
589 		const PopUpString* const second = box->pSecondColumnString[i];
590 		if (second)
591 		{
592 			// are we highlighting?...shading?..or neither
593 			if (second->fHighLightFlag)
594 			{
595 				SetFontForeground(second->ubHighLight);
596 			}
597 			else if (second->fShadeFlag)
598 			{
599 				SetFontForeground(second->ubShade);
600 			}
601 			else
602 			{
603 				SetFontForeground(second->ubForegroundColor);
604 			}
605 
606 			SetFontBackground(second->ubBackgroundColor);
607 
608 			const INT32 y = tly + i * (h + box->uiLineSpace);
609 			INT16 uX;
610 			INT16 uY;
611 			if (box->uiFlags & POPUP_BOX_FLAG_CENTER_TEXT)
612 			{
613 				FindFontCenterCoordinates(tlx, y, w, h, second->codepoints, font, &uX, &uY);
614 			}
615 			else
616 			{
617 				uX = tlx + box->uiSecondColumnCurrentOffset;
618 				uY = y;
619 			}
620 			MPrint(uX, uY, second->codepoints);
621 		}
622 	}
623 
624 	if (box->uiBuffer != guiSAVEBUFFER)
625 	{
626 		InvalidateRegion(tlx - 1, tly, brx, bry);
627 	}
628 
629 	SetFontDestBuffer(FRAME_BUFFER);
630 }
631 
632 
ResizeBoxToText(PopUpBox * const box)633 void ResizeBoxToText(PopUpBox* const box)
634 {
635 	SGPFont const font = box->font;
636 	UINT32 max_lw = 0; // width of left  column
637 	UINT32 max_rw = 0; // width of right column
638 	UINT i;
639 	for (i = 0; i < MAX_POPUP_BOX_STRING_COUNT; ++i)
640 	{
641 		const PopUpString* const l = box->Text[i];
642 		if (l == NULL) break;
643 
644 		const UINT32 lw = StringPixLength(l->codepoints, font);
645 		if (lw > max_lw) max_lw = lw;
646 
647 		const PopUpString* const r = box->pSecondColumnString[i];
648 		if (r != NULL)
649 		{
650 			const UINT32 rw = StringPixLength(r->codepoints, font);
651 			if (rw > max_rw) max_rw = rw;
652 		}
653 	}
654 
655 	const UINT32 r_off = max_lw + box->uiSecondColumnMinimunOffset;
656 	box->uiSecondColumnCurrentOffset = r_off;
657 
658 	UINT32 w = box->uiLeftMargin + r_off + max_rw + box->uiRightMargin;
659 	if (w < box->uiBoxMinWidth) w = box->uiBoxMinWidth;
660 	box->pos.w = w;
661 
662 	box->pos.h = box->uiTopMargin + i * (GetFontHeight(font) + box->uiLineSpace) + box->uiBottomMargin;
663 }
664 
665 
IsBoxShown(const PopUpBox * const box)666 BOOLEAN IsBoxShown(const PopUpBox* const box)
667 {
668 	if (box == NULL) return FALSE;
669 	return box->fShowBox;
670 }
671 
672 
MarkAllBoxesAsAltered(void)673 void MarkAllBoxesAsAltered( void )
674 {
675 	FOR_EACH_POPUP_BOX(i)
676 	{
677 		ForceUpDateOfBox(*i);
678 	}
679 }
680 
681 
HideAllBoxes(void)682 void HideAllBoxes( void )
683 {
684 	FOR_EACH_POPUP_BOX(i)
685 	{
686 		HideBox(*i);
687 	}
688 }
689 
690 
RemoveBoxPrimaryText(PopUpBox * const Box,const INT32 hStringHandle)691 static void RemoveBoxPrimaryText(PopUpBox* const Box, const INT32 hStringHandle)
692 {
693 	Assert(Box != NULL);
694 	Assert( hStringHandle < MAX_POPUP_BOX_STRING_COUNT );
695 
696 	// remove & release primary text
697 	if (Box->Text[hStringHandle] != NULL)
698 	{
699 		delete Box->Text[hStringHandle];
700 		Box->Text[hStringHandle] = NULL;
701 	}
702 }
703 
704 
RemoveBoxSecondaryText(PopUpBox * const Box,const INT32 hStringHandle)705 static void RemoveBoxSecondaryText(PopUpBox* const Box, const INT32 hStringHandle)
706 {
707 	Assert(Box != NULL);
708 	Assert( hStringHandle < MAX_POPUP_BOX_STRING_COUNT );
709 
710 	// remove & release secondary strings
711 	if (Box->pSecondColumnString[hStringHandle] != NULL)
712 	{
713 		delete Box->pSecondColumnString[hStringHandle];
714 		Box->pSecondColumnString[hStringHandle] = NULL;
715 	}
716 }
717