Subversion Repositories psp

[/] [branches/] [smsplus_adhoc/] [psp/] [psplib/] [ui.c] - Blame information for rev 354

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 9 jack
/** PSP helper library ***************************************/
2
/**                                                         **/
3
/**                           ui.c                          **/
4
/**                                                         **/
5
/** This file contains a simple GUI rendering library       **/
6
/**                                                         **/
7
/** Copyright (C) Akop Karapetyan 2007                      **/
8
/**     You are not allowed to distribute this software     **/
9
/**     commercially. Please, notify me, if you make any    **/
10
/**     changes to this file.                               **/
11
/*************************************************************/
12
#include <malloc.h>
13
#include <math.h>
14
#include <stdio.h>
15
#include <string.h>
16
#include <pspkernel.h>
17
#include <psprtc.h>
18 64 jack
#include <psppower.h>
19 128 jack
#include <pspgu.h>
20 247 jack
#include <pspnet_adhocmatching.h>
21 9 jack
 
22
#include "psp.h"
23 247 jack
#include "file.h"
24 9 jack
#include "ctrl.h"
25
#include "ui.h"
26 109 jack
#include "font.h"
27 9 jack
 
28 109 jack
#define MAX_DIR_LEN 1024
29 9 jack
 
30 128 jack
#define UI_ANIM_FRAMES   8
31
#define UI_ANIM_FOG_STEP 0x0f
32
 
33 247 jack
#define ADHOC_INITIALIZING  "Initializing Ad-hoc networking. Please wait..."
34
#define ADHOC_AWAITING_JOIN "Waiting for someone to join..."
35
 
36 128 jack
#define CONTROL_BUTTON_MASK \
37 9 jack
  (PSP_CTRL_CIRCLE | PSP_CTRL_TRIANGLE | PSP_CTRL_CROSS | PSP_CTRL_SQUARE | \
38
   PSP_CTRL_LTRIGGER | PSP_CTRL_RTRIGGER | PSP_CTRL_SELECT | PSP_CTRL_START)
39
 
40
static const char
41
  *AlertDialogButtonTemplate   = "\026\001\020/\026\002\020 Close",
42
  *ConfirmDialogButtonTemplate = "\026\001\020 Confirm\t\026\002\020 Cancel",
43 109 jack
  *YesNoCancelDialogButtonTemplate =
44
    "\026\001\020 Yes\t\026"PSP_CHAR_SQUARE"\020 No\t\026\002\020 Cancel",
45 9 jack
 
46 106 jack
  *SelectorTemplate = "\026\001\020 Confirm\t\026\002\020 Cancel",
47
 
48 145 jack
  *BrowserTemplates[] = {
49
    "\026\002\020 Cancel\t\026\001\020 Open",
50
    "\026\002\020 Cancel\t\026\001\020 Enter directory",
51
    "\026\002\020 Cancel\t\026\001\020 Open\t\026"PSP_CHAR_TRIANGLE"\020 Parent directory",
52
    "\026\002\020 Cancel\t\026\001\020 Enter directory\t\026"PSP_CHAR_TRIANGLE"\020 Parent directory"
53
   },
54 9 jack
 
55 34 jack
  *SplashStatusBarTemplate  = "\026\255\020/\026\256\020 Switch tabs",
56
 
57 9 jack
  *OptionModeTemplate =
58
    "\026\245\020/\026\246\020 Select\t\026\247\020/\026\002\020 Cancel\t\026\250\020/\026\001\020 Confirm";
59
 
60 145 jack
enum
61
{
62
  BrowserTemplateOpenTop  = 0,
63
  BrowserTemplateEnterTop = 1,
64
  BrowserTemplateOpen     = 2,
65
  BrowserTemplateEnter    = 3,
66
};
67
 
68
#define BROWSER_TEMPLATE_COUNT 4
69
 
70 9 jack
struct UiPos
71
{
72
  int Index;
73
  int Offset;
74
  const PspMenuItem *Top;
75
};
76
 
77 247 jack
struct AdhocMatchEvent
78
{
79
  int NewEvent;
80
  int EventID;
81
  PspMAC EventMAC;
82
  PspMAC CurrentMAC;
83
  char OptData[512];
84
};
85
 
86
static struct AdhocMatchEvent _adhoc_match_event;
87
 
88
static void adhocMatchingCallback(int unk1,
89
                                  int event,
90
                                  unsigned char *mac2,
91
                                  int opt_len,
92
                                  void *opt_data);
93
 
94
#define ADHOC_PENDING     0
95
#define ADHOC_WAIT_CLI    1
96
#define ADHOC_WAIT_HOST   2
97
#define ADHOC_WAIT_EST    3
98
#define ADHOC_ESTABLISHED 4
99
#define ADHOC_EST_AS_CLI  5
100
 
101 145 jack
/* TODO: dynamically allocate ?? */
102
static unsigned int __attribute__((aligned(16))) call_list[524288];//262144];
103 9 jack
 
104 128 jack
/* Gets status string - containing current time and battery information */
105
static void GetStatusString(char *status, int length)
106 9 jack
{
107 128 jack
  static char main_str[128], batt_str[32];
108
  pspTime time;
109
 
110
  /* Get current time */
111
  sceRtcGetCurrentClockLocalTime(&time);
112
 
113
  /* Get the battery/power-related information */
114
  if (!scePowerIsBatteryExist()) sprintf(batt_str, PSP_CHAR_POWER);
115
  else
116
  {
117
    /* If the battery's online, display charging stats */
118
    int batt_time = scePowerGetBatteryLifeTime();
119
    int batt_percent = scePowerGetBatteryLifePercent();
120
    int i, charging = scePowerIsBatteryCharging();
121
 
122
    static int percentiles[] = { 60, 30, 12, 0 };
123
    for (i = 0; i < 4; i++)
124
      if (batt_percent >= percentiles[i])
125
        break;
126
 
127
    /* Fix for when battery switches state from AC to batt */
128
    batt_time = (batt_time >= 0) ? batt_time : 0;
129
 
130
    sprintf(batt_str, "%c%3i%% (%02i:%02i)",
131
      (charging) ? *PSP_CHAR_POWER : *PSP_CHAR_FULL_BATT + i,
132
      batt_percent, batt_time / 60, batt_time % 60);
133
  }
134
 
135
  /* Write the rest of the string */
136
  sprintf(main_str, "\270%2i/%2i %02i%c%02i %s ",
137
    time.month, time.day, time.hour, (time.microseconds > 500000) ? ':' : ' ',
138
    time.minutes, batt_str);
139
 
140
  strncpy(status, main_str, length);
141
  status[length - 1] = '\0';
142
}
143
 
144
static inline void RenderStatus()
145
{
146 145 jack
  static char status[128];
147
  GetStatusString(status, sizeof(status));
148
 
149
  int width = pspFontGetTextWidth(UiMetric.Font, status);
150 128 jack
  pspVideoPrint(UiMetric.Font, SCR_WIDTH - width, 0, status, PSP_COLOR_WHITE);
151 145 jack
}
152 128 jack
 
153
static void ReplaceIcons(char *string)
154
{
155 9 jack
  char *ch;
156
 
157
  for (ch = string; *ch; ch++)
158
  {
159
    switch(*ch)
160
    {
161
    case '\001': *ch = pspUiGetButtonIcon(UiMetric.OkButton); break;
162
    case '\002': *ch = pspUiGetButtonIcon(UiMetric.CancelButton); break;
163
    }
164
  }
165
}
166
 
167
char pspUiGetButtonIcon(u32 button_mask)
168
{
169
  switch (button_mask)
170
  {
171 67 jack
  case PSP_CTRL_CROSS:    return *PSP_CHAR_CROSS;
172
  case PSP_CTRL_CIRCLE:   return *PSP_CHAR_CIRCLE;
173
  case PSP_CTRL_TRIANGLE: return *PSP_CHAR_TRIANGLE;
174
  case PSP_CTRL_SQUARE:   return *PSP_CHAR_SQUARE;
175 9 jack
  default:                return '?';
176
  }
177
}
178
 
179
void pspUiAlert(const char *message)
180
{
181 128 jack
  PspImage *screen = NULL;
182 9 jack
  int sx, sy, dx, dy, th, fh, mw, cw, w, h;
183 128 jack
  int i, n = UI_ANIM_FRAMES;
184 9 jack
  char *instr = strdup(AlertDialogButtonTemplate);
185 128 jack
  ReplaceIcons(instr);
186 9 jack
 
187
  mw = pspFontGetTextWidth(UiMetric.Font, message);
188
  cw = pspFontGetTextWidth(UiMetric.Font, instr);
189
  fh = pspFontGetLineHeight(UiMetric.Font);
190
  th = pspFontGetTextHeight(UiMetric.Font, message);
191
 
192
  w = ((mw > cw) ? mw : cw) + 50;
193
  h = th + fh * 3;
194
  sx = SCR_WIDTH / 2 - w / 2;
195
  sy = SCR_HEIGHT / 2 - h / 2;
196
  dx = sx + w;
197
  dy = sy + h;
198
 
199 128 jack
  /* Intro animation */
200
  if (UiMetric.Animate)
201
  {
202
    /* Get copy of screen */
203
    screen = pspVideoGetVramBufferCopy();
204
 
205
    for (i = 0; i < n; i++)
206
    {
207
          pspVideoBegin();
208
 
209
          /* Clear screen */
210 140 jack
          pspVideoPutImage(screen, 0, 0, screen->Viewport.Width, screen->Height);
211 128 jack
 
212
          /* Apply fog and draw frame */
213
          pspVideoFillRect(0, 0, SCR_WIDTH, SCR_HEIGHT,
214
            COLOR(0,0,0,UI_ANIM_FOG_STEP*i));
215
          pspVideoFillRect(SCR_WIDTH/2-(((dx-sx)/n)*i)/2,
216
            SCR_HEIGHT/2-(((dy-sy)/n)*i)/2,
217
            SCR_WIDTH/2+(((dx-sx)/n)*i)/2, SCR_HEIGHT/2+(((dy-sy)/n)*i)/2,
218
            COLOR(RED_32(UiMetric.MenuOptionBoxBg),
219
              GREEN_32(UiMetric.MenuOptionBoxBg),
220
              BLUE_32(UiMetric.MenuOptionBoxBg),(0xff/n)*i));
221
 
222
          pspVideoEnd();
223
 
224
      /* Swap buffers */
225
      pspVideoWaitVSync();
226
      pspVideoSwapBuffers();
227
        }
228
 }
229
 
230 9 jack
  pspVideoBegin();
231
 
232 128 jack
  if (UiMetric.Animate)
233 140 jack
    pspVideoPutImage(screen, 0, 0, screen->Viewport.Width, screen->Height);
234 9 jack
 
235 128 jack
  pspVideoFillRect(0, 0, SCR_WIDTH, SCR_HEIGHT,
236
    COLOR(0,0,0,UI_ANIM_FOG_STEP*n));
237
  pspVideoFillRect(sx, sy, dx, dy, UiMetric.MenuOptionBoxBg);
238 9 jack
  pspVideoPrint(UiMetric.Font, SCR_WIDTH / 2 - mw / 2, sy + fh * 0.5, message,
239
    UiMetric.TextColor);
240
  pspVideoPrint(UiMetric.Font, SCR_WIDTH / 2 - cw / 2, dy - fh * 1.5, instr,
241
    UiMetric.TextColor);
242 147 jack
  pspVideoGlowRect(sx, sy, dx - 1, dy - 1,
243 128 jack
    COLOR(0xff,0xff,0xff,UI_ANIM_FOG_STEP*n), 2);
244 9 jack
 
245
  pspVideoEnd();
246
 
247
  /* Swap buffers */
248
  pspVideoWaitVSync();
249
  pspVideoSwapBuffers();
250
 
251
  SceCtrlData pad;
252
 
253
  /* Loop until X or O is pressed */
254
  while (!ExitPSP)
255
  {
256
    if (!pspCtrlPollControls(&pad))
257
      continue;
258
 
259
    if (pad.Buttons & UiMetric.OkButton || pad.Buttons & UiMetric.CancelButton)
260
      break;
261
  }
262 128 jack
 
263
  if (!ExitPSP && UiMetric.Animate)
264
  {
265
          /* Exit animation */
266
          for (i = n - 1; i >= 0; i--)
267
          {
268
                  pspVideoBegin();
269
 
270
                  /* Clear screen */
271 140 jack
                  pspVideoPutImage(screen, 0, 0, screen->Viewport.Width, screen->Height);
272 128 jack
 
273
                  /* Apply fog and draw frame */
274
          pspVideoFillRect(0, 0, SCR_WIDTH, SCR_HEIGHT,
275
            COLOR(0,0,0,UI_ANIM_FOG_STEP*i));
276
          pspVideoFillRect(SCR_WIDTH/2-(((dx-sx)/n)*i)/2,
277
            SCR_HEIGHT/2-(((dy-sy)/n)*i)/2,
278
            SCR_WIDTH/2+(((dx-sx)/n)*i)/2, SCR_HEIGHT/2+(((dy-sy)/n)*i)/2,
279
            COLOR(RED_32(UiMetric.MenuOptionBoxBg),
280
              GREEN_32(UiMetric.MenuOptionBoxBg),
281
              BLUE_32(UiMetric.MenuOptionBoxBg),(0xff/n)*i));
282
 
283
                  pspVideoEnd();
284
 
285
            /* Swap buffers */
286
            pspVideoWaitVSync();
287
            pspVideoSwapBuffers();
288
                }
289
        }
290
 
291
  if (screen) pspImageDestroy(screen);
292
  free(instr);
293 9 jack
}
294
 
295 109 jack
int pspUiYesNoCancel(const char *message)
296
{
297 128 jack
  PspImage *screen = NULL;
298 109 jack
  int sx, sy, dx, dy, th, fh, mw, cw, w, h;
299 128 jack
  int i, n = UI_ANIM_FRAMES;
300 109 jack
  char *instr = strdup(YesNoCancelDialogButtonTemplate);
301 128 jack
  ReplaceIcons(instr);
302 109 jack
 
303
  mw = pspFontGetTextWidth(UiMetric.Font, message);
304
  cw = pspFontGetTextWidth(UiMetric.Font, instr);
305
  fh = pspFontGetLineHeight(UiMetric.Font);
306
  th = pspFontGetTextHeight(UiMetric.Font, message);
307
 
308
  w = ((mw > cw) ? mw : cw) + 50;
309
  h = th + fh * 3;
310
  sx = SCR_WIDTH / 2 - w / 2;
311
  sy = SCR_HEIGHT / 2 - h / 2;
312
  dx = sx + w;
313
  dy = sy + h;
314
 
315 128 jack
  /* Intro animation */
316
  if (UiMetric.Animate)
317
  {
318
    /* Get copy of screen */
319
    screen = pspVideoGetVramBufferCopy();
320
 
321
    for (i = 0; i < n; i++)
322
    {
323
          pspVideoBegin();
324
 
325
          /* Clear screen */
326 140 jack
          pspVideoPutImage(screen, 0, 0, screen->Viewport.Width, screen->Height);
327 128 jack
 
328
          /* Apply fog and draw frame */
329
          pspVideoFillRect(0, 0, SCR_WIDTH, SCR_HEIGHT,
330
            COLOR(0,0,0,UI_ANIM_FOG_STEP*i));
331
          pspVideoFillRect(SCR_WIDTH/2-(((dx-sx)/n)*i)/2,
332
            SCR_HEIGHT/2-(((dy-sy)/n)*i)/2,
333
            SCR_WIDTH/2+(((dx-sx)/n)*i)/2, SCR_HEIGHT/2+(((dy-sy)/n)*i)/2,
334
            COLOR(RED_32(UiMetric.MenuOptionBoxBg),
335
              GREEN_32(UiMetric.MenuOptionBoxBg),
336
              BLUE_32(UiMetric.MenuOptionBoxBg),(0xff/n)*i));
337
 
338
          pspVideoEnd();
339
 
340
      /* Swap buffers */
341
      pspVideoWaitVSync();
342
      pspVideoSwapBuffers();
343
        }
344
  }
345
 
346 109 jack
  pspVideoBegin();
347
 
348 128 jack
  if (UiMetric.Animate)
349 140 jack
    pspVideoPutImage(screen, 0, 0, screen->Viewport.Width, screen->Height);
350 128 jack
  pspVideoFillRect(0, 0, SCR_WIDTH, SCR_HEIGHT,
351
    COLOR(0,0,0,UI_ANIM_FOG_STEP*n));
352
  pspVideoFillRect(sx, sy, dx, dy, UiMetric.MenuOptionBoxBg);
353 109 jack
  pspVideoPrint(UiMetric.Font, SCR_WIDTH / 2 - mw / 2, sy + fh * 0.5, message,
354
    UiMetric.TextColor);
355
  pspVideoPrint(UiMetric.Font, SCR_WIDTH / 2 - cw / 2, dy - fh * 1.5, instr,
356
    UiMetric.TextColor);
357 147 jack
  pspVideoGlowRect(sx, sy, dx - 1, dy - 1,
358 128 jack
    COLOR(0xff,0xff,0xff,UI_ANIM_FOG_STEP*n), 2);
359 109 jack
 
360
  pspVideoEnd();
361
 
362
  /* Swap buffers */
363
  pspVideoWaitVSync();
364
  pspVideoSwapBuffers();
365
 
366
  SceCtrlData pad;
367
 
368
  /* Loop until X or O is pressed */
369
  while (!ExitPSP)
370
  {
371
    if (!pspCtrlPollControls(&pad))
372
      continue;
373
 
374
    if (pad.Buttons & UiMetric.OkButton || pad.Buttons & UiMetric.CancelButton
375
      || pad.Buttons & PSP_CTRL_SQUARE) break;
376
  }
377
 
378 128 jack
  if (!ExitPSP && UiMetric.Animate)
379
  {
380
          /* Exit animation */
381
          for (i = n - 1; i >= 0; i--)
382
          {
383
                  pspVideoBegin();
384
 
385
                  /* Clear screen */
386 140 jack
                  pspVideoPutImage(screen, 0, 0, screen->Viewport.Width, screen->Height);
387 128 jack
 
388
                  /* Apply fog and draw frame */
389
          pspVideoFillRect(0, 0, SCR_WIDTH, SCR_HEIGHT,
390
            COLOR(0,0,0,UI_ANIM_FOG_STEP*i));
391
          pspVideoFillRect(SCR_WIDTH/2-(((dx-sx)/n)*i)/2,
392
            SCR_HEIGHT/2-(((dy-sy)/n)*i)/2,
393
            SCR_WIDTH/2+(((dx-sx)/n)*i)/2, SCR_HEIGHT/2+(((dy-sy)/n)*i)/2,
394
            COLOR(RED_32(UiMetric.MenuOptionBoxBg),
395
              GREEN_32(UiMetric.MenuOptionBoxBg),
396
              BLUE_32(UiMetric.MenuOptionBoxBg),(0xff/n)*i));
397
 
398
                  pspVideoEnd();
399
 
400
            /* Swap buffers */
401
            pspVideoWaitVSync();
402
            pspVideoSwapBuffers();
403
                }
404
        }
405
 
406
  if (screen) pspImageDestroy(screen);
407
  free(instr);
408
 
409 109 jack
  if (pad.Buttons & UiMetric.CancelButton) return PSP_UI_CANCEL;
410
  else if (pad.Buttons & PSP_CTRL_SQUARE) return PSP_UI_NO;
411
  else return PSP_UI_YES;
412
}
413
 
414 9 jack
int pspUiConfirm(const char *message)
415
{
416 128 jack
  PspImage *screen = NULL;
417 106 jack
  int sx, sy, dx, dy, th, fh, mw, cw, w, h;
418 128 jack
  int i, n = UI_ANIM_FRAMES;
419 9 jack
  char *instr = strdup(ConfirmDialogButtonTemplate);
420 128 jack
  ReplaceIcons(instr);
421 9 jack
 
422
  mw = pspFontGetTextWidth(UiMetric.Font, message);
423
  cw = pspFontGetTextWidth(UiMetric.Font, instr);
424
  fh = pspFontGetLineHeight(UiMetric.Font);
425 106 jack
  th = pspFontGetTextHeight(UiMetric.Font, message);
426 9 jack
 
427
  w = ((mw > cw) ? mw : cw) + 50;
428 106 jack
  h = th + fh * 3;
429 9 jack
  sx = SCR_WIDTH / 2 - w / 2;
430
  sy = SCR_HEIGHT / 2 - h / 2;
431
  dx = sx + w;
432
  dy = sy + h;
433
 
434 128 jack
  if (UiMetric.Animate)
435
  {
436
    /* Get copy of screen */
437
    screen = pspVideoGetVramBufferCopy();
438
 
439
    /* Intro animation */
440
    for (i = 0; i < n; i++)
441
    {
442
          pspVideoBegin();
443
 
444
          /* Clear screen */
445 140 jack
          pspVideoPutImage(screen, 0, 0, screen->Viewport.Width, screen->Height);
446 128 jack
 
447
          /* Apply fog and draw frame */
448
          pspVideoFillRect(0, 0, SCR_WIDTH, SCR_HEIGHT,
449
            COLOR(0,0,0,UI_ANIM_FOG_STEP*i));
450
          pspVideoFillRect(SCR_WIDTH/2-(((dx-sx)/n)*i)/2,
451
            SCR_HEIGHT/2-(((dy-sy)/n)*i)/2,
452
            SCR_WIDTH/2+(((dx-sx)/n)*i)/2, SCR_HEIGHT/2+(((dy-sy)/n)*i)/2,
453
            COLOR(RED_32(UiMetric.MenuOptionBoxBg),
454
              GREEN_32(UiMetric.MenuOptionBoxBg),
455
              BLUE_32(UiMetric.MenuOptionBoxBg),(0xff/n)*i));
456
 
457
          pspVideoEnd();
458
 
459
      /* Swap buffers */
460
      pspVideoWaitVSync();
461
      pspVideoSwapBuffers();
462
        }
463
  }
464
 
465 9 jack
  pspVideoBegin();
466
 
467 128 jack
  if (UiMetric.Animate)
468 140 jack
    pspVideoPutImage(screen, 0, 0, screen->Viewport.Width, screen->Height);
469 128 jack
  pspVideoFillRect(0, 0, SCR_WIDTH, SCR_HEIGHT,
470
    COLOR(0,0,0,UI_ANIM_FOG_STEP*n));
471
  pspVideoFillRect(sx, sy, dx, dy, UiMetric.MenuOptionBoxBg);
472 106 jack
  pspVideoPrint(UiMetric.Font, SCR_WIDTH / 2 - mw / 2, sy + fh * 0.5, message,
473
    UiMetric.TextColor);
474
  pspVideoPrint(UiMetric.Font, SCR_WIDTH / 2 - cw / 2, dy - fh * 1.5, instr,
475
    UiMetric.TextColor);
476 147 jack
  pspVideoGlowRect(sx, sy, dx - 1, dy - 1,
477 128 jack
    COLOR(0xff,0xff,0xff,UI_ANIM_FOG_STEP*n), 2);
478 9 jack
 
479
  pspVideoEnd();
480
 
481
  /* Swap buffers */
482
  pspVideoWaitVSync();
483
  pspVideoSwapBuffers();
484
 
485
  SceCtrlData pad;
486
 
487
  /* Loop until X or O is pressed */
488
  while (!ExitPSP)
489
  {
490
    if (!pspCtrlPollControls(&pad))
491
      continue;
492
 
493
    if (pad.Buttons & UiMetric.OkButton || pad.Buttons & UiMetric.CancelButton)
494
      break;
495
  }
496
 
497 128 jack
  if (!ExitPSP && UiMetric.Animate)
498
  {
499
          /* Exit animation */
500
          for (i = n - 1; i >= 0; i--)
501
          {
502
                  pspVideoBegin();
503
 
504
                  /* Clear screen */
505 140 jack
                  pspVideoPutImage(screen, 0, 0, screen->Viewport.Width, screen->Height);
506 128 jack
 
507
                  /* Apply fog and draw frame */
508
          pspVideoFillRect(0, 0, SCR_WIDTH, SCR_HEIGHT,
509
            COLOR(0,0,0,UI_ANIM_FOG_STEP*i));
510
          pspVideoFillRect(SCR_WIDTH/2-(((dx-sx)/n)*i)/2,
511
            SCR_HEIGHT/2-(((dy-sy)/n)*i)/2,
512
            SCR_WIDTH/2+(((dx-sx)/n)*i)/2, SCR_HEIGHT/2+(((dy-sy)/n)*i)/2,
513
            COLOR(RED_32(UiMetric.MenuOptionBoxBg),
514
              GREEN_32(UiMetric.MenuOptionBoxBg),
515
              BLUE_32(UiMetric.MenuOptionBoxBg),(0xff/n)*i));
516
 
517
                  pspVideoEnd();
518
 
519
            /* Swap buffers */
520
            pspVideoWaitVSync();
521
            pspVideoSwapBuffers();
522
                }
523
        }
524
 
525
  if (screen) pspImageDestroy(screen);
526
  free(instr);
527
 
528 9 jack
  return pad.Buttons & UiMetric.OkButton;
529
}
530
 
531
void pspUiFlashMessage(const char *message)
532
{
533 128 jack
  PspImage *screen = NULL;
534 34 jack
  int sx, sy, dx, dy, fh, mw, mh, w, h;
535 128 jack
  int i, n = UI_ANIM_FRAMES;
536 9 jack
 
537
  mw = pspFontGetTextWidth(UiMetric.Font, message);
538
  fh = pspFontGetLineHeight(UiMetric.Font);
539 34 jack
  mh = pspFontGetTextHeight(UiMetric.Font, message);
540 9 jack
 
541
  w = mw + 50;
542 34 jack
  h = mh + fh * 2;
543 9 jack
  sx = SCR_WIDTH / 2 - w / 2;
544
  sy = SCR_HEIGHT / 2 - h / 2;
545
  dx = sx + w;
546
  dy = sy + h;
547
 
548 128 jack
  if (UiMetric.Animate)
549
  {
550
    /* Get copy of screen */
551
    screen = pspVideoGetVramBufferCopy();
552
 
553
    /* Intro animation */
554
    for (i = 0; i < n; i++)
555
    {
556
          pspVideoBegin();
557
 
558
          /* Clear screen */
559 140 jack
          pspVideoPutImage(screen, 0, 0, screen->Viewport.Width, screen->Height);
560 128 jack
 
561
          /* Apply fog and draw frame */
562
          pspVideoFillRect(0, 0, SCR_WIDTH, SCR_HEIGHT,
563
            COLOR(0,0,0,UI_ANIM_FOG_STEP*i));
564
          pspVideoFillRect(SCR_WIDTH/2-(((dx-sx)/n)*i)/2,
565
            SCR_HEIGHT/2-(((dy-sy)/n)*i)/2,
566
            SCR_WIDTH/2+(((dx-sx)/n)*i)/2, SCR_HEIGHT/2+(((dy-sy)/n)*i)/2,
567
            COLOR(RED_32(UiMetric.MenuOptionBoxBg),
568
              GREEN_32(UiMetric.MenuOptionBoxBg),
569
              BLUE_32(UiMetric.MenuOptionBoxBg),(0xff/n)*i));
570
 
571
          pspVideoEnd();
572
 
573
      /* Swap buffers */
574
      pspVideoWaitVSync();
575
      pspVideoSwapBuffers();
576
        }
577
  }
578
 
579 9 jack
  pspVideoBegin();
580
 
581 128 jack
  if (UiMetric.Animate)
582 140 jack
    pspVideoPutImage(screen, 0, 0, screen->Viewport.Width, screen->Height);
583 128 jack
  pspVideoFillRect(0, 0, SCR_WIDTH, SCR_HEIGHT,
584
    COLOR(0,0,0,UI_ANIM_FOG_STEP*n));
585
  pspVideoFillRect(sx, sy, dx, dy, UiMetric.MenuOptionBoxBg);
586 34 jack
  pspVideoPrintCenter(UiMetric.Font,
587
    sx, sy + fh, dx, message, UiMetric.TextColor);
588 147 jack
  pspVideoGlowRect(sx, sy, dx - 1, dy - 1,
589 128 jack
    COLOR(0xff,0xff,0xff,UI_ANIM_FOG_STEP*n), 2);
590 9 jack
 
591
  pspVideoEnd();
592
 
593
  /* Swap buffers */
594
  pspVideoWaitVSync();
595
  pspVideoSwapBuffers();
596 128 jack
 
597
  if (screen) pspImageDestroy(screen);
598 9 jack
}
599
 
600
void pspUiOpenBrowser(PspUiFileBrowser *browser, const char *start_path)
601
{
602
  PspMenu *menu;
603
  PspFile *file;
604
  PspFileList *list;
605 128 jack
  const PspMenuItem *sel, *last_sel;
606 106 jack
  PspMenuItem *item;
607 9 jack
  SceCtrlData pad;
608 145 jack
  char *instructions[BROWSER_TEMPLATE_COUNT];
609 9 jack
 
610 145 jack
  /* Initialize instruction strings */
611
  int i;
612
  for (i = 0; i < BROWSER_TEMPLATE_COUNT; i++)
613
  {
614
    instructions[i] = strdup(BrowserTemplates[i]);
615
    ReplaceIcons(instructions[i]);
616
  }
617
 
618 9 jack
  if (!start_path)
619
    start_path = pspGetAppDirectory();
620
 
621 247 jack
  char *cur_path = pspFileGetParentDirectory(start_path);
622
  const char *cur_file = pspFileGetFilename(start_path);
623 9 jack
  struct UiPos pos;
624 145 jack
  int lnmax, lnhalf;
625
  int sby, sbh, j, h, w, fh = pspFontGetLineHeight(UiMetric.Font);
626 9 jack
  int sx, sy, dx, dy;
627
  int hasparent, is_dir;
628
 
629
  sx = UiMetric.Left;
630
  sy = UiMetric.Top + fh + UiMetric.TitlePadding;
631
  dx = UiMetric.Right;
632
  dy = UiMetric.Bottom;
633
  w = dx - sx - UiMetric.ScrollbarWidth;
634
  h = dy - sy;
635
 
636
  menu = pspMenuCreate();
637
 
638 128 jack
  memset(call_list, 0, sizeof(call_list));
639
 
640
  int sel_top = 0, last_sel_top = 0, fast_scroll;
641
 
642 9 jack
  /* Begin browsing (outer) loop */
643
  while (!ExitPSP)
644
  {
645 128 jack
    sel = last_sel = NULL;
646 9 jack
    pos.Top = NULL;
647
    pspMenuClear(menu);
648
 
649
    /* Load list of files for the selected path */
650 247 jack
    if ((list = pspFileGetFileList(cur_path, browser->Filter)))
651 9 jack
    {
652
      /* Check for a parent path, prepend .. if necessary */
653 247 jack
      if ((hasparent =! pspFileIsRootDirectory(cur_path)))
654 106 jack
      {
655
        item = pspMenuAppendItem(menu, "..", 0);
656 247 jack
        item->Param = (void*)PSP_FILE_DIR;
657 106 jack
      }
658 9 jack
 
659
      /* Add a menu item for each file */
660
      for (file = list->First; file; file = file->Next)
661
      {
662
        /* Skip files that begin with '.' */
663
        if (file->Name && file->Name[0] == '.')
664
          continue;
665
 
666 106 jack
        item = pspMenuAppendItem(menu, file->Name, 0);
667
        item->Param = (void*)file->Attrs;
668
 
669 9 jack
        if (cur_file && strcmp(file->Name, cur_file) == 0)
670
          sel = item;
671
      }
672
 
673
      cur_file = NULL;
674
 
675
      /* Destroy the file list */
676 247 jack
      pspFileDestroyFileList(list);
677 9 jack
    }
678
    else
679
    {
680
      /* Check for a parent path, prepend .. if necessary */
681 247 jack
      if ((hasparent =! pspFileIsRootDirectory(cur_path)))
682 106 jack
      {
683
        item = pspMenuAppendItem(menu, "..", 0);
684 247 jack
        item->Param = (void*)PSP_FILE_DIR;
685 106 jack
      }
686 9 jack
    }
687
 
688
    /* Initialize variables */
689
    lnmax = (dy - sy) / fh;
690
    lnhalf = lnmax >> 1;
691
    sbh = (menu->Count > lnmax) ? (int)((float)h * ((float)lnmax / (float)menu->Count)) : 0;
692
 
693
    pos.Index = pos.Offset = 0;
694
 
695
    if (!sel)
696
    {
697
      /* Select the first file/dir in the directory */
698
      if (menu->First && menu->First->Next)
699
        sel=menu->First->Next;
700
      else if (menu->First)
701
        sel=menu->First;
702
    }
703
 
704
    /* Compute index and offset of selected file */
705
    if (sel)
706
    {
707 106 jack
      pos.Top = menu->First;
708
      for (item = menu->First; item != sel; item = item->Next)
709
      {
710
        if (pos.Index + 1 >= lnmax) { pos.Offset++; pos.Top=pos.Top->Next; }
711
        else pos.Index++;
712
      }
713 9 jack
    }
714
 
715
    pspVideoWaitVSync();
716
 
717
    /* Begin navigation (inner) loop */
718
    while (!ExitPSP)
719
    {
720
      if (!pspCtrlPollControls(&pad))
721
        continue;
722
 
723 128 jack
      fast_scroll = 0;
724
 
725 9 jack
      /* Check the directional buttons */
726
      if (sel)
727
      {
728
        if ((pad.Buttons & PSP_CTRL_DOWN || pad.Buttons & PSP_CTRL_ANALDOWN) && sel->Next)
729
        {
730
          if (pos.Index+1 >= lnmax) { pos.Offset++; pos.Top=pos.Top->Next; }
731
          else pos.Index++;
732
          sel=sel->Next;
733 128 jack
          fast_scroll = pad.Buttons & PSP_CTRL_ANALDOWN;
734 9 jack
        }
735
        else if ((pad.Buttons & PSP_CTRL_UP || pad.Buttons & PSP_CTRL_ANALUP) && sel->Prev)
736
        {
737
          if (pos.Index - 1 < 0) { pos.Offset--; pos.Top=pos.Top->Prev; }
738
          else pos.Index--;
739
          sel = sel->Prev;
740 128 jack
          fast_scroll = pad.Buttons & PSP_CTRL_ANALUP;
741 9 jack
        }
742
        else if (pad.Buttons & PSP_CTRL_LEFT)
743
        {
744
          for (i=0; sel->Prev && i < lnhalf; i++)
745
          {
746
            if (pos.Index-1 < 0) { pos.Offset--; pos.Top=pos.Top->Prev; }
747
            else pos.Index--;
748
            sel=sel->Prev;
749
          }
750
        }
751
        else if (pad.Buttons & PSP_CTRL_RIGHT)
752
        {
753
          for (i=0; sel->Next && i < lnhalf; i++)
754
          {
755
            if (pos.Index + 1 >= lnmax) { pos.Offset++; pos.Top=pos.Top->Next; }
756
            else pos.Index++;
757
            sel=sel->Next;
758
          }
759
        }
760
 
761
        /* File/dir selection */
762
        if (pad.Buttons & UiMetric.OkButton)
763
        {
764 247 jack
          if (((unsigned int)sel->Param & PSP_FILE_DIR))
765 9 jack
          {
766
            /* Selected a directory, descend */
767 247 jack
            pspFileEnterDirectory(&cur_path, sel->Caption);
768 9 jack
            break;
769
          }
770
          else
771
          {
772
            int exit = 1;
773
 
774
            /* Selected a file */
775
            if (browser->OnOk)
776
            {
777
              char *file = malloc((strlen(cur_path) + strlen(sel->Caption) + 1) * sizeof(char));
778
              sprintf(file, "%s%s", cur_path, sel->Caption);
779
              exit = browser->OnOk(browser, file);
780
              free(file);
781
            }
782
 
783
            if (exit) goto exit_browser;
784
            else continue;
785
          }
786
        }
787
      }
788
 
789
      if (pad.Buttons & PSP_CTRL_TRIANGLE)
790
      {
791 247 jack
        if (!pspFileIsRootDirectory(cur_path))
792 9 jack
        {
793 247 jack
          pspFileEnterDirectory(&cur_path, "..");
794 9 jack
          break;
795
        }
796
      }
797
      else if (pad.Buttons & UiMetric.CancelButton)
798
      {
799
        if (browser->OnCancel)
800
          browser->OnCancel(browser, cur_path);
801
        goto exit_browser;
802
      }
803
      else if ((pad.Buttons & CONTROL_BUTTON_MASK) && browser->OnButtonPress)
804
      {
805
        char *file = NULL;
806
        int exit;
807
 
808
        if (sel)
809
        {
810
          file = malloc((strlen(cur_path) + strlen(sel->Caption) + 1) * sizeof(char));
811
          sprintf(file, "%s%s", cur_path, sel->Caption);
812
        }
813
 
814
        exit = browser->OnButtonPress(browser,
815
          file, pad.Buttons & CONTROL_BUTTON_MASK);
816
 
817
        if (file) free(file);
818
        if (exit) goto exit_browser;
819
      }
820
 
821 247 jack
      is_dir = (unsigned int)sel->Param & PSP_FILE_DIR;
822 9 jack
 
823 128 jack
      sceGuStart(GU_CALL, call_list);
824 9 jack
 
825
      /* Draw current path */
826 145 jack
      pspVideoPrint(UiMetric.Font, sx, UiMetric.Top, cur_path,
827 9 jack
        UiMetric.TitleColor);
828
      pspVideoDrawLine(UiMetric.Left, UiMetric.Top + fh - 1, UiMetric.Left + w,
829
        UiMetric.Top + fh - 1, UiMetric.TitleColor);
830
 
831 145 jack
      const char *instruction;
832 9 jack
      if (hasparent)
833 145 jack
        instruction = instructions[(is_dir)
834
          ? BrowserTemplateEnter : BrowserTemplateOpen];
835
      else
836
        instruction = instructions[(is_dir)
837
          ? BrowserTemplateEnterTop : BrowserTemplateOpenTop];
838
 
839
      pspVideoPrintCenter(UiMetric.Font,
840
        sx, SCR_HEIGHT - fh, dx, instruction, UiMetric.StatusBarColor);
841 9 jack
 
842
      /* Draw scrollbar */
843
      if (sbh > 0)
844
      {
845 106 jack
        sby = sy + (int)((float)(h - sbh)
846
          * ((float)(pos.Offset + pos.Index) / (float)menu->Count));
847
        pspVideoFillRect(dx - UiMetric.ScrollbarWidth, sy, dx, dy,
848
          UiMetric.ScrollbarBgColor);
849
        pspVideoFillRect(dx - UiMetric.ScrollbarWidth, sby, dx, sby + sbh,
850
          UiMetric.ScrollbarColor);
851 9 jack
      }
852
 
853
      /* Render the files */
854 106 jack
      for (item = (PspMenuItem*)pos.Top, i = 0, j = sy;
855
        item && i < lnmax; item = item->Next, j += fh, i++)
856 9 jack
      {
857 128 jack
        if (item == sel) sel_top = j;
858 9 jack
 
859 106 jack
        pspVideoPrintClipped(UiMetric.Font, sx + 10, j, item->Caption, w - 10,
860 128 jack
          "...", (item == sel) ? UiMetric.SelectedColor
861 247 jack
            : ((unsigned int)item->Param & PSP_FILE_DIR)
862 128 jack
            ? UiMetric.BrowserDirectoryColor : UiMetric.BrowserFileColor);
863 145 jack
     }
864 9 jack
 
865 128 jack
      /* Render status information */
866
      RenderStatus();
867
 
868 9 jack
      /* Perform any custom drawing */
869
      if (browser->OnRender)
870
        browser->OnRender(browser, "not implemented");
871
 
872 128 jack
      sceGuFinish();
873
 
874 145 jack
      if (sel != last_sel && !fast_scroll && sel && last_sel
875 128 jack
        && UiMetric.Animate)
876
      {
877
        /* Move animation */
878
        int f, n = 4;
879
        for (f = 1; f <= n; f++)
880
        {
881
          pspVideoBegin();
882
 
883
          /* Clear screen */
884
          if (!UiMetric.Background) pspVideoClearScreen();
885
          else pspVideoPutImage(UiMetric.Background, 0, 0,
886 140 jack
            UiMetric.Background->Viewport.Width, UiMetric.Background->Height);
887 128 jack
 
888
          /* Selection box */
889
          int box_top = last_sel_top-((last_sel_top-sel_top)/n)*f;
890
          pspVideoFillRect(sx, box_top, sx+w, box_top+fh,
891
            UiMetric.SelectedBgColor);
892
 
893
          sceGuCallList(call_list);
894
 
895
          pspVideoEnd();
896
 
897
          pspVideoWaitVSync();
898
          pspVideoSwapBuffers();
899
        }
900
      }
901
 
902
      pspVideoBegin();
903
 
904
      /* Clear screen */
905
      if (UiMetric.Background)
906 140 jack
        pspVideoPutImage(UiMetric.Background, 0, 0,
907
          UiMetric.Background->Viewport.Width, UiMetric.Background->Height);
908 128 jack
      else pspVideoClearScreen();
909
 
910
      /* Render selection box */
911
      if (sel) pspVideoFillRect(sx, sel_top, sx+w, sel_top+fh,
912
        UiMetric.SelectedBgColor);
913
 
914
      sceGuCallList(call_list);
915
 
916 9 jack
      pspVideoEnd();
917
 
918
      /* Swap buffers */
919
      pspVideoWaitVSync();
920
      pspVideoSwapBuffers();
921 128 jack
 
922
      last_sel = sel;
923
      last_sel_top = sel_top;
924 9 jack
    }
925
  }
926
 
927
exit_browser:
928
 
929 145 jack
  /* Free instruction strings */
930
  for (i = 0; i < BROWSER_TEMPLATE_COUNT; i++)
931
    free(instructions[i]);
932
 
933 9 jack
  pspMenuDestroy(menu);
934
  free(cur_path);
935
}
936
 
937
void pspUiOpenGallery(const PspUiGallery *gallery, const char *title)
938
{
939
  PspMenu *menu = gallery->Menu;
940
  const PspMenuItem *top, *item;
941
  SceCtrlData pad;
942
  PspMenuItem *sel = menu->Selected;
943
 
944 128 jack
  int sx, sy, dx, dy,
945 9 jack
    orig_w = 272, orig_h = 228, // defaults
946
    fh, c, i, j,
947
    sbh, sby,
948
    w, h,
949
    icon_w, icon_h,
950
    grid_w, grid_h,
951
    icon_idx, icon_off,
952
    rows, vis_v, vis_s,
953
    icons;
954 128 jack
  const PspMenuItem *last_sel = NULL;
955 9 jack
 
956
  /* Find first icon and save its width/height */
957
  for (item = menu->First; item; item = item->Next)
958
  {
959
    if (item->Icon)
960
    {
961 140 jack
      orig_w = ((PspImage*)item->Icon)->Viewport.Width;
962 9 jack
      orig_h = ((PspImage*)item->Icon)->Height;
963
      break;
964
    }
965
  }
966
 
967
  fh = pspFontGetLineHeight(UiMetric.Font);
968
  sx = UiMetric.Left;
969
  sy = UiMetric.Top + ((title) ? fh + UiMetric.TitlePadding : 0);
970
  dx = UiMetric.Right;
971
  dy = UiMetric.Bottom;
972
  w = (dx - sx) - UiMetric.ScrollbarWidth; // visible width
973
  h = dy - sy; // visible height
974
  icon_w = (w - UiMetric.GalleryIconMarginWidth
975
    * (UiMetric.GalleryIconsPerRow - 1)) / UiMetric.GalleryIconsPerRow; // icon width
976
  icon_h = (int)((float)icon_w
977
    / ((float)orig_w / (float)orig_h)); // icon height
978
  grid_w = icon_w + UiMetric.GalleryIconMarginWidth; // width of the grid
979
  grid_h = icon_h + (fh * 2); // half-space for margin + 1 line of text 
980
  icons = menu->Count; // number of icons total
981
  rows = ceil((float)icons / (float)UiMetric.GalleryIconsPerRow); // number of rows total
982
  vis_v = h / grid_h; // number of rows visible at any time
983
  vis_s = UiMetric.GalleryIconsPerRow * vis_v; // max. number of icons visible on screen at any time
984 128 jack
  int max_w = ((float)icon_w * 1.5); /* Maximized width  */
985
  int max_h = ((float)icon_h * 1.5); /* Maximized height */
986 9 jack
 
987
  icon_idx = 0;
988
  icon_off = 0;
989
  top = menu->First;
990
 
991
  if (!sel)
992
  {
993
    /* Select the first icon */
994
    sel = menu->First;
995
  }
996
  else
997
  {
998
    /* Find the selected icon */
999
    for (item = menu->First; item; item = item->Next)
1000
    {
1001
      if (item == sel)
1002
        break;
1003
 
1004
      if (++icon_idx >= vis_s)
1005
      {
1006
        icon_idx=0;
1007
        icon_off += vis_s;
1008
        top = item;
1009
      }
1010
    }
1011
 
1012
    if (item != sel)
1013
    {
1014
      /* Icon not found; reset to first icon */
1015
      sel = menu->First;
1016
      top = menu->First;
1017
      icon_idx = 0;
1018
      icon_off = 0;
1019
    }
1020
  }
1021
 
1022
  /* Compute height of scrollbar */
1023
  sbh = ((float)vis_v / (float)(rows + (rows % vis_v))) * (float)h;
1024
 
1025
  /* Compute update frequency */
1026
  u32 ticks_per_sec, ticks_per_upd;
1027
  u64 current_tick, last_tick;
1028
 
1029
  ticks_per_sec = sceRtcGetTickResolution();
1030
  sceRtcGetCurrentTick(&last_tick);
1031
  ticks_per_upd = ticks_per_sec / UiMetric.MenuFps;
1032
 
1033 128 jack
  memset(call_list, 0, sizeof(call_list));
1034 247 jack
  int sel_left = 0 /*, max_left = 0 */;
1035
  int sel_top = 0 /*, max_top = 0 */;
1036 128 jack
 
1037
  pspVideoWaitVSync();
1038
 
1039 9 jack
  /* Begin navigation loop */
1040
  while (!ExitPSP)
1041
  {
1042
    if (!pspCtrlPollControls(&pad))
1043
      continue;
1044
 
1045
    /* Check the directional buttons */
1046
    if (sel)
1047
    {
1048
      if (pad.Buttons & PSP_CTRL_RIGHT && sel->Next)
1049
      {
1050
        sel = sel->Next;
1051
        if (++icon_idx >= vis_s)
1052
        {
1053
          icon_idx = 0;
1054
          icon_off += vis_s;
1055
          top = sel;
1056
        }
1057
      }
1058
      else if (pad.Buttons & PSP_CTRL_LEFT && sel->Prev)
1059
      {
1060
        sel = sel->Prev;
1061
        if (--icon_idx < 0)
1062
        {
1063
          icon_idx = vis_s-1;
1064
          icon_off -= vis_s;
1065
          for (i = 0; i < vis_s && top; i++) top = top->Prev;
1066
        }
1067
      }
1068
      else if (pad.Buttons & PSP_CTRL_DOWN)
1069
      {
1070
        for (i = 0; sel->Next && i < UiMetric.GalleryIconsPerRow; i++)
1071
        {
1072
          sel = sel->Next;
1073
          if (++icon_idx >= vis_s)
1074
          {
1075
            icon_idx = 0;
1076
            icon_off += vis_s;
1077
            top = sel;
1078
          }
1079
        }
1080
      }
1081
      else if (pad.Buttons & PSP_CTRL_UP)
1082
      {
1083
        for (i = 0; sel->Prev && i < UiMetric.GalleryIconsPerRow; i++)
1084
        {
1085
          sel = sel->Prev;
1086
          if (--icon_idx < 0)
1087
          {
1088
            icon_idx = vis_s-1;
1089
            icon_off -= vis_s;
1090
            for (j = 0; j < vis_s && top; j++) top = top->Prev;
1091
          }
1092
        }
1093
      }
1094
 
1095
      if (pad.Buttons & UiMetric.OkButton)
1096
      {
1097
        pad.Buttons &= ~UiMetric.OkButton;
1098
        if (!gallery->OnOk || gallery->OnOk(gallery, sel))
1099
          break;
1100
      }
1101
    }
1102
 
1103
    if (pad.Buttons & UiMetric.CancelButton)
1104
    {
1105
      pad.Buttons &= ~UiMetric.CancelButton;
1106
      if (gallery->OnCancel)
1107
        gallery->OnCancel(gallery, sel);
1108
      break;
1109
    }
1110
 
1111
    if ((pad.Buttons & CONTROL_BUTTON_MASK) && gallery->OnButtonPress)
1112
      if (gallery->OnButtonPress(gallery, sel, pad.Buttons & CONTROL_BUTTON_MASK))
1113
          break;
1114 128 jack
 
1115
    if (last_sel != sel && last_sel && sel && sel->Icon && UiMetric.Animate)
1116
    {
1117
      /* "Implode" animation */
1118
      int f = 1, n = 2;
1119
//      for (f = n - 1; f > 0; f--)
1120
//      {
1121
        pspVideoBegin();
1122
 
1123
        /* Clear screen */
1124
        if (!UiMetric.Background) pspVideoClearScreen();
1125
        else pspVideoPutImage(UiMetric.Background, 0, 0,
1126 140 jack
          UiMetric.Background->Viewport.Width, UiMetric.Background->Height);
1127 128 jack
 
1128
        sceGuCallList(call_list);
1129
 
1130 140 jack
        pspVideoEnd();
1131
 
1132 128 jack
        /* Render the menu items */
1133
        for (i = sy, item = top; item && i + grid_h < dy; i += grid_h)
1134
          for (j = sx, c = 0; item && c < UiMetric.GalleryIconsPerRow; j += grid_w, c++, item = item->Next)
1135
            if (item->Icon && item != last_sel)
1136
            {
1137 140 jack
              pspVideoBegin();
1138 128 jack
              pspVideoPutImage((PspImage*)item->Icon, j, i, icon_w, icon_h);
1139 140 jack
              pspVideoEnd();
1140 128 jack
            }
1141
 
1142 140 jack
        pspVideoBegin();
1143 128 jack
 
1144 140 jack
        pspVideoPutImage((PspImage*)last_sel->Icon,
1145
          sel_left-(icon_w+((max_w-icon_w)/n)*f)/2,
1146
          sel_top-(icon_h+((max_h-icon_h)/n)*f)/2,
1147
          icon_w+((max_w-icon_w)/n)*f,
1148
          icon_h+((max_h-icon_h)/n)*f);
1149
 
1150 128 jack
        pspVideoEnd();
1151
 
1152
        /* Swap buffers */
1153
        pspVideoWaitVSync();
1154
        pspVideoSwapBuffers();
1155
//      }
1156 9 jack
    }
1157
 
1158 128 jack
    sceGuStart(GU_CALL, call_list);
1159 9 jack
 
1160
    /* Draw title */
1161
    if (title)
1162
    {
1163
      pspVideoPrint(UiMetric.Font, UiMetric.Left, UiMetric.Top,
1164
        title, UiMetric.TitleColor);
1165
      pspVideoDrawLine(UiMetric.Left, UiMetric.Top + fh - 1, UiMetric.Left + w,
1166
        UiMetric.Top + fh - 1, UiMetric.TitleColor);
1167
    }
1168
 
1169
    /* Draw scrollbar */
1170
    if (sbh < h)
1171
    {
1172
      sby = sy + (((float)icon_off / (float)UiMetric.GalleryIconsPerRow)
1173
        / (float)(rows + (rows % vis_v))) * (float)h;
1174
      pspVideoFillRect(dx - UiMetric.ScrollbarWidth,
1175
        sy, dx, dy, UiMetric.ScrollbarBgColor);
1176
      pspVideoFillRect(dx - UiMetric.ScrollbarWidth,
1177
        sby, dx, sby+sbh, UiMetric.ScrollbarColor);
1178
    }
1179
 
1180
    /* Draw instructions */
1181
    if (sel && sel->HelpText)
1182
    {
1183
      static char help_copy[MAX_DIR_LEN];
1184
      strncpy(help_copy, sel->HelpText, MAX_DIR_LEN);
1185
      help_copy[MAX_DIR_LEN - 1] = '\0';
1186 128 jack
      ReplaceIcons(help_copy);
1187 9 jack
 
1188
      pspVideoPrintCenter(UiMetric.Font,
1189
        0, SCR_HEIGHT - fh, SCR_WIDTH, help_copy, UiMetric.StatusBarColor);
1190
    }
1191
 
1192 128 jack
    /* Render non-image components of each item */
1193 9 jack
    for (i = sy, item = top; item && i + grid_h < dy; i += grid_h)
1194
    {
1195
      for (j = sx, c = 0; item && c < UiMetric.GalleryIconsPerRow; j += grid_w, c++, item = item->Next)
1196
      {
1197 128 jack
        if (item != sel)
1198 9 jack
        {
1199 128 jack
          pspVideoShadowRect(j - 1, i - 1, j + icon_w, i + icon_h, PSP_COLOR_BLACK, 3);
1200
          pspVideoDrawRect(j - 1, i - 1, j + icon_w, i + icon_h, UiMetric.TextColor);
1201 9 jack
 
1202 128 jack
          if (item->Caption)
1203
          {
1204
            int cap_pos = j + icon_w / 2
1205
              - pspFontGetTextWidth(UiMetric.Font, item->Caption) / 2;
1206
            pspVideoPrint(UiMetric.Font, cap_pos,
1207
              i + icon_h + (fh / 2), item->Caption, UiMetric.TextColor);
1208
          }
1209 9 jack
        }
1210 128 jack
        else
1211 9 jack
        {
1212 128 jack
          sel_left = j + icon_w / 2;
1213
          sel_top = i + icon_h / 2;
1214 9 jack
 
1215 128 jack
          sel_left = (sel_left-max_w/2 < sx) ? sx+max_w/2 : sel_left;
1216
          sel_top = (sel_top-max_h/2 < UiMetric.Top)
1217
            ? UiMetric.Top+max_h/2 : sel_top;
1218
          sel_left = (sel_left+max_w/2 > dx) ? dx-max_w/2 : sel_left;
1219
          sel_top = (sel_top+max_h/2 > dy) ? dy-max_h/2 : sel_top;
1220 9 jack
        }
1221
      }
1222
    }
1223
 
1224 128 jack
    /* Render status information */
1225
    RenderStatus();
1226
 
1227 9 jack
    /* Perform any custom drawing */
1228
    if (gallery->OnRender)
1229
      gallery->OnRender(gallery, sel);
1230
 
1231 128 jack
    sceGuFinish();
1232
 
1233
    if (last_sel != sel && last_sel && sel && sel->Icon && UiMetric.Animate)
1234
    {
1235
      /* Popup animation */
1236
      int f = 1, n = 2;
1237
//      for (f = 1; f < n; f++)
1238
//      {
1239
        pspVideoBegin();
1240
 
1241
        /* Clear screen */
1242
        if (!UiMetric.Background) pspVideoClearScreen();
1243
        else pspVideoPutImage(UiMetric.Background, 0, 0,
1244 140 jack
          UiMetric.Background->Viewport.Width, UiMetric.Background->Height);
1245 128 jack
 
1246
        sceGuCallList(call_list);
1247
 
1248
        pspVideoEnd();
1249
 
1250
        /* Render the menu items */
1251
        for (i = sy, item = top; item && i + grid_h < dy; i += grid_h)
1252
          for (j = sx, c = 0; item && c < UiMetric.GalleryIconsPerRow; j += grid_w, c++, item = item->Next)
1253
            if (item->Icon && item != sel)
1254
            {
1255
              pspVideoBegin();
1256
              pspVideoPutImage((PspImage*)item->Icon, j, i, icon_w, icon_h);
1257
              pspVideoEnd();
1258
            }
1259
 
1260
        pspVideoBegin();
1261
 
1262 140 jack
        pspVideoPutImage((PspImage*)sel->Icon,
1263
          sel_left-(icon_w+((max_w-icon_w)/n)*f)/2,
1264
          sel_top-(icon_h+((max_h-icon_h)/n)*f)/2,
1265
          icon_w+((max_w-icon_w)/n)*f,
1266
          icon_h+((max_h-icon_h)/n)*f);
1267 128 jack
 
1268
        pspVideoEnd();
1269
 
1270
        /* Swap buffers */
1271
        pspVideoWaitVSync();
1272
        pspVideoSwapBuffers();
1273
//      }
1274
    }
1275
 
1276
    pspVideoBegin();
1277
 
1278
    /* Clear screen */
1279
    if (!UiMetric.Background) pspVideoClearScreen();
1280
    else pspVideoPutImage(UiMetric.Background, 0, 0,
1281 140 jack
      UiMetric.Background->Viewport.Width, UiMetric.Background->Height);
1282 128 jack
 
1283
    sceGuCallList(call_list);
1284
 
1285 9 jack
    pspVideoEnd();
1286
 
1287 128 jack
    /* Render the menu items */
1288
    for (i = sy, item = top; item && i + grid_h < dy; i += grid_h)
1289
      for (j = sx, c = 0; item && c < UiMetric.GalleryIconsPerRow; j += grid_w, c++, item = item->Next)
1290
        if (item->Icon && item != sel)
1291
        {
1292
          pspVideoBegin();
1293
          pspVideoPutImage((PspImage*)item->Icon, j, i, icon_w, icon_h);
1294
          pspVideoEnd();
1295
        }
1296
 
1297
    pspVideoBegin();
1298
 
1299
    if (sel && sel->Icon)
1300
    {
1301
      pspVideoPutImage((PspImage*)sel->Icon, sel_left-max_w/2, sel_top-max_h/2,
1302
        max_w, max_h);
1303
      pspVideoGlowRect(sel_left-max_w/2, sel_top-max_h/2,
1304 147 jack
        sel_left+max_w/2 - 1, sel_top+max_h/2 - 1,
1305 128 jack
        COLOR(0xff,0xff,0xff,UI_ANIM_FOG_STEP * UI_ANIM_FRAMES), 2);
1306
    }
1307
 
1308
    if (sel && sel->Caption)
1309
    {
1310
      int cap_left = sel_left
1311
        - pspFontGetTextWidth(UiMetric.Font, sel->Caption) / 2;
1312
      pspVideoPrint(UiMetric.Font, cap_left,
1313
        sel_top + max_h/2 - (fh + (fh - UiMetric.Font->Ascent)), sel->Caption,
1314
        UiMetric.TextColor);
1315
    }
1316
 
1317
    pspVideoEnd();
1318
 
1319
    last_sel = sel;
1320
 
1321 9 jack
    /* Wait if needed */
1322
    do { sceRtcGetCurrentTick(&current_tick); }
1323
    while (current_tick - last_tick < ticks_per_upd);
1324
    last_tick = current_tick;
1325
 
1326
    /* Swap buffers */
1327
    pspVideoWaitVSync();
1328
    pspVideoSwapBuffers();
1329
  }
1330
 
1331
  menu->Selected = sel;
1332
}
1333
 
1334
void pspUiOpenMenu(const PspUiMenu *uimenu, const char *title)
1335
{
1336
  struct UiPos pos;
1337
  PspMenu *menu = uimenu->Menu;
1338
  const PspMenuItem *item;
1339
  SceCtrlData pad;
1340
  const PspMenuOption *temp_option;
1341
  int lnmax;
1342
  int sby, sbh, i, j, k, h, w, fh = pspFontGetLineHeight(UiMetric.Font);
1343 128 jack
  int sx, sy, dx, dy, sel_top = 0, last_sel_top = 0;
1344 9 jack
  int max_item_w = 0, item_w;
1345
  int option_mode, max_option_w = 0;
1346
  int arrow_w = pspFontGetTextWidth(UiMetric.Font, "\272");
1347
  int anim_frame = 0, anim_incr = 1;
1348 128 jack
  PspMenuItem *sel = menu->Selected, *last_sel = NULL;
1349 9 jack
 
1350
  sx = UiMetric.Left;
1351
  sy = UiMetric.Top + ((title) ? (fh + UiMetric.TitlePadding) : 0);
1352
  dx = UiMetric.Right;
1353
  dy = UiMetric.Bottom;
1354
  w = dx - sx - UiMetric.ScrollbarWidth;
1355
  h = dy - sy;
1356
 
1357 128 jack
  memset(call_list, 0, sizeof(call_list));
1358
 
1359 9 jack
  /* Determine width of the longest caption */
1360
  for (item = menu->First; item; item = item->Next)
1361
  {
1362
    if (item->Caption)
1363
    {
1364
      item_w = pspFontGetTextWidth(UiMetric.Font, item->Caption);
1365
      if (item_w > max_item_w)
1366
        max_item_w = item_w;
1367
    }
1368
  }
1369
 
1370
  /* Initialize variables */
1371
  lnmax = (dy - sy) / fh;
1372
  sbh = (menu->Count > lnmax) ? (int)((float)h * ((float)lnmax / (float)menu->Count)) : 0;
1373
 
1374
  pos.Index = 0;
1375
  pos.Offset = 0;
1376
  pos.Top = NULL;
1377
  option_mode = 0;
1378
  temp_option = NULL;
1379
 
1380 128 jack
  int cur_x=0, min_x=0, max_x=0;
1381
  int cur_y=0, min_y=0, max_y=0;
1382
 
1383 9 jack
  /* Find first selectable item */
1384
  if (!sel)
1385
  {
1386
    for (sel = menu->First; sel; sel = sel->Next)
1387
      if (sel->Caption && sel->Caption[0] != '\t')
1388
        break;
1389
  }
1390
 
1391
  /* Compute index and offset of selected file */
1392
  pos.Top = menu->First;
1393
  for (item = menu->First; item != sel; item = item->Next)
1394
  {
1395
    if (pos.Index + 1 >= lnmax) { pos.Offset++; pos.Top = pos.Top->Next; }
1396
    else pos.Index++;
1397
  }
1398
 
1399
  pspVideoWaitVSync();
1400
  PspMenuItem *last;
1401
  struct UiPos last_valid;
1402
 
1403
  /* Compute update frequency */
1404
  u32 ticks_per_sec, ticks_per_upd;
1405
  u64 current_tick, last_tick;
1406
 
1407
  ticks_per_sec = sceRtcGetTickResolution();
1408
  sceRtcGetCurrentTick(&last_tick);
1409
  ticks_per_upd = ticks_per_sec / UiMetric.MenuFps;
1410
 
1411 128 jack
  int fast_scroll;
1412
 
1413 9 jack
  /* Begin navigation loop */
1414
  while (!ExitPSP)
1415
  {
1416
    if (!pspCtrlPollControls(&pad))
1417
      continue;
1418
 
1419 128 jack
    fast_scroll = 0;
1420
    anim_frame += (UiMetric.Animate) ? anim_incr : 0;
1421 9 jack
    if (anim_frame > 2 || anim_frame < 0)
1422
      anim_incr *= -1;
1423
 
1424
    /* Check the directional buttons */
1425
    if (sel)
1426
    {
1427
      if (pad.Buttons & PSP_CTRL_DOWN || pad.Buttons & PSP_CTRL_ANALDOWN)
1428
      {
1429 128 jack
        fast_scroll = pad.Buttons & PSP_CTRL_ANALDOWN;
1430
 
1431 9 jack
        if (option_mode)
1432
        {
1433
          if (temp_option->Next)
1434
            temp_option = temp_option->Next;
1435
        }
1436
        else
1437
        {
1438
          if (sel->Next)
1439
          {
1440
            last = sel;
1441
            last_valid = pos;
1442
 
1443
            for (;;)
1444
            {
1445
              if (pos.Index + 1 >= lnmax)
1446
              {
1447
                pos.Offset++;
1448
                pos.Top = pos.Top->Next;
1449
              }
1450
              else pos.Index++;
1451
 
1452
              sel = sel->Next;
1453
 
1454
              if (!sel)
1455
              {
1456
                sel = last;
1457
                pos = last_valid;
1458
                break;
1459
              }
1460
 
1461
              if (sel->Caption && sel->Caption[0] != '\t')
1462
                break;
1463
            }
1464
          }
1465
        }
1466
      }
1467
      else if (pad.Buttons & PSP_CTRL_UP || pad.Buttons & PSP_CTRL_ANALUP)
1468
      {
1469 128 jack
        fast_scroll = pad.Buttons & PSP_CTRL_ANALUP;
1470
 
1471 9 jack
        if (option_mode)
1472
        {
1473
          if (temp_option->Prev)
1474
            temp_option = temp_option->Prev;
1475
        }
1476
        else
1477
        {
1478
          if (sel->Prev)
1479
          {
1480
            last = sel;
1481
            last_valid = pos;
1482
 
1483
            for (;;)
1484
            {
1485
              if (pos.Index - 1 < 0)
1486
              {
1487
                pos.Offset--;
1488
                pos.Top = pos.Top->Prev;
1489
              }
1490
              else pos.Index--;
1491
 
1492
              sel = sel->Prev;
1493
 
1494
              if (!sel)
1495
              {
1496
                sel = last;
1497 177 jack
 
1498
                pos.Index = 0;
1499
                pos.Offset = 0;
1500
                pos.Top = menu->First;
1501
 
1502
                for (item = menu->First; item != sel; item = item->Next)
1503
                {
1504
                  if (pos.Index + 1 >= lnmax) { pos.Offset++; pos.Top = pos.Top->Next; }
1505
                  else pos.Index++;
1506
                }
1507
 
1508 9 jack
                break;
1509
              }
1510
 
1511
              if (sel->Caption && sel->Caption[0] != '\t')
1512
                break;
1513
            }
1514
          }
1515
        }
1516
      }
1517
 
1518 128 jack
      /* Recompute box bounds if scrolling in option mode */
1519
      if (option_mode && (pad.Buttons &
1520
        (PSP_CTRL_UP|PSP_CTRL_ANALUP|PSP_CTRL_DOWN|PSP_CTRL_ANALDOWN)))
1521
      {
1522
        cur_x = sx + max_item_w + UiMetric.MenuItemMargin + 10;
1523
        min_y = sy + pos.Index * fh;
1524
        cur_y = min_y + fh / 2;
1525
        max_y = sy + (pos.Index  + 1) * fh;
1526
        min_x = cur_x - UiMetric.MenuItemMargin;
1527
        max_x = cur_x + max_option_w + UiMetric.MenuItemMargin;
1528
        cur_x += pspFontGetTextWidth(UiMetric.Font, " >");
1529
        if (sel->Selected && sel->Selected->Text)
1530
          cur_x += pspFontGetTextWidth(UiMetric.Font, sel->Selected->Text);
1531
 
1532
        const PspMenuOption *option;
1533
        for (option = temp_option; option && min_y >= sy; option = option->Prev, min_y -= fh);
1534
        for (option = temp_option->Next; option && max_y < dy; option = option->Next, max_y += fh);
1535
        max_y += fh;
1536
      }
1537
 
1538 9 jack
      if (option_mode)
1539
      {
1540
        if (pad.Buttons & PSP_CTRL_RIGHT || pad.Buttons & UiMetric.OkButton)
1541
        {
1542
          option_mode = 0;
1543
 
1544
          /* If the callback function refuses the change, restore selection */
1545 128 jack
          if (!uimenu->OnItemChanged || uimenu->OnItemChanged(uimenu, sel, temp_option))
1546 9 jack
            sel->Selected = temp_option;
1547
        }
1548
        else if (pad.Buttons & PSP_CTRL_LEFT  || pad.Buttons & UiMetric.CancelButton)
1549
        {
1550
          option_mode = 0;
1551 128 jack
 
1552 9 jack
          if (pad.Buttons & UiMetric.CancelButton)
1553
            pad.Buttons &= ~UiMetric.CancelButton;
1554
        }
1555 128 jack
 
1556
        if (!option_mode)
1557
        {
1558
          if (UiMetric.Animate)
1559
          {
1560
            /* Deflation animation */
1561
            for (i = UI_ANIM_FRAMES - 1; i >= 0; i--)
1562
            {
1563
                  pspVideoBegin();
1564
              if (!UiMetric.Background) pspVideoClearScreen();
1565
                else pspVideoPutImage(UiMetric.Background, 0, 0,
1566 140 jack
                  UiMetric.Background->Viewport.Width, UiMetric.Background->Height);
1567 128 jack
 
1568
                  pspVideoCallList(call_list);
1569
 
1570
              /* Perform any custom drawing */
1571
              if (uimenu->OnRender)
1572
                uimenu->OnRender(uimenu, sel);
1573
 
1574
                  /* Clear screen */
1575
                  pspVideoFillRect(cur_x - ((cur_x - min_x) / UI_ANIM_FRAMES) * i,
1576
                    cur_y - ((cur_y - min_y) / UI_ANIM_FRAMES) * i,
1577
                    cur_x + ((max_x - cur_x) / UI_ANIM_FRAMES) * i,
1578
                    cur_y + ((max_y - cur_y) / UI_ANIM_FRAMES) * i,
1579
                UiMetric.MenuOptionBoxBg);
1580
 
1581
              /* Selected option for the item */
1582
              if (sel->Selected && sel->Selected->Text)
1583
              pspVideoPrint(UiMetric.Font,
1584
                sx + max_item_w + UiMetric.MenuItemMargin + 10,
1585
                sy + pos.Index * fh, sel->Selected->Text, UiMetric.SelectedColor);
1586
 
1587
                  pspVideoEnd();
1588
 
1589
              /* Swap buffers */
1590
              pspVideoWaitVSync();
1591
              pspVideoSwapBuffers();
1592
                }
1593
          }
1594
        }
1595 9 jack
      }
1596
      else
1597
      {
1598 128 jack
        if ((pad.Buttons & PSP_CTRL_RIGHT)
1599
          && sel->Options && sel->Options->Next)
1600 9 jack
        {
1601 128 jack
          option_mode = 1;
1602
          max_option_w = 0;
1603
          int width;
1604
          const PspMenuOption *option;
1605
 
1606
          /* Find the longest option caption */
1607
          for (option = sel->Options; option; option = option->Next)
1608
            if (option->Text && (width = pspFontGetTextWidth(UiMetric.Font, option->Text)) > max_option_w)
1609
              max_option_w = width;
1610
 
1611
          temp_option = (sel->Selected) ? sel->Selected : sel->Options;
1612
 
1613
          /* Determine bounds */
1614
          cur_x = sx + max_item_w + UiMetric.MenuItemMargin + 10;
1615
          min_y = sy + pos.Index * fh;
1616
          cur_y = min_y + fh / 2;
1617
          max_y = sy + (pos.Index  + 1) * fh;
1618
          min_x = cur_x - UiMetric.MenuItemMargin;
1619
          max_x = cur_x + max_option_w + UiMetric.MenuItemMargin;
1620
          cur_x += pspFontGetTextWidth(UiMetric.Font, " >");
1621
          if (sel->Selected && sel->Selected->Text)
1622
            cur_x += pspFontGetTextWidth(UiMetric.Font, sel->Selected->Text);
1623
 
1624
          for (option = temp_option; option && min_y >= sy; option = option->Prev, min_y -= fh);
1625
          for (option = temp_option->Next; option && max_y < dy; option = option->Next, max_y += fh);
1626
          max_y += fh;
1627
 
1628
          if (UiMetric.Animate)
1629 9 jack
          {
1630 128 jack
            /* Expansion animation */
1631
            for (i = 0; i <= UI_ANIM_FRAMES; i++)
1632
            {
1633
                  pspVideoBegin();
1634 9 jack
 
1635 128 jack
              if (!UiMetric.Background) pspVideoClearScreen();
1636
                else pspVideoPutImage(UiMetric.Background, 0, 0,
1637 140 jack
                  UiMetric.Background->Viewport.Width,
1638
                  UiMetric.Background->Height);
1639 247 jack
 
1640 128 jack
                  pspVideoCallList(call_list);
1641 9 jack
 
1642 128 jack
              /* Perform any custom drawing */
1643
              if (uimenu->OnRender)
1644
                uimenu->OnRender(uimenu, sel);
1645
 
1646
                  pspVideoFillRect(cur_x - ((cur_x - min_x) / UI_ANIM_FRAMES) * i,
1647
                    cur_y - ((cur_y - min_y) / UI_ANIM_FRAMES) * i,
1648
                    cur_x + ((max_x - cur_x) / UI_ANIM_FRAMES) * i,
1649
                    cur_y + ((max_y - cur_y) / UI_ANIM_FRAMES) * i,
1650
                UiMetric.MenuOptionBoxBg);
1651
 
1652
                  pspVideoEnd();
1653
 
1654
              /* Swap buffers */
1655
              pspVideoWaitVSync();
1656
              pspVideoSwapBuffers();
1657
                }
1658
                }
1659 9 jack
        }
1660
        else if (pad.Buttons & UiMetric.OkButton)
1661
        {
1662
          if (!uimenu->OnOk || uimenu->OnOk(uimenu, sel))
1663
            break;
1664
        }
1665
      }
1666
    }
1667
 
1668
    if (!option_mode)
1669
    {
1670
      if (pad.Buttons & UiMetric.CancelButton)
1671
      {
1672
        if (uimenu->OnCancel)
1673
          uimenu->OnCancel(uimenu, sel);
1674
        break;
1675
      }
1676
 
1677
      if ((pad.Buttons & CONTROL_BUTTON_MASK) && uimenu->OnButtonPress)
1678
      {
1679
        if (uimenu->OnButtonPress(uimenu, sel, pad.Buttons & CONTROL_BUTTON_MASK))
1680
            break;
1681
      }
1682
    }
1683
 
1684 128 jack
    /* Render to a call list */
1685
    sceGuStart(GU_CALL, call_list);
1686 9 jack
 
1687
    /* Draw instructions */
1688
    if (sel)
1689
    {
1690
      const char *dirs = NULL;
1691
 
1692
      if (!option_mode && sel->HelpText)
1693
      {
1694
        static char help_copy[MAX_DIR_LEN];
1695
        strncpy(help_copy, sel->HelpText, MAX_DIR_LEN);
1696
        help_copy[MAX_DIR_LEN - 1] = '\0';
1697 128 jack
        ReplaceIcons(help_copy);
1698 9 jack
 
1699
        dirs = help_copy;
1700
      }
1701
      else if (option_mode)
1702
      {
1703
        static char help_copy[MAX_DIR_LEN];
1704
        strncpy(help_copy, OptionModeTemplate, MAX_DIR_LEN);
1705
        help_copy[MAX_DIR_LEN - 1] = '\0';
1706 128 jack
        ReplaceIcons(help_copy);
1707 9 jack
 
1708
        dirs = help_copy;
1709
      }
1710
 
1711
      if (dirs)
1712
        pspVideoPrintCenter(UiMetric.Font,
1713
          0, SCR_HEIGHT - fh, SCR_WIDTH, dirs, UiMetric.StatusBarColor);
1714
    }
1715
 
1716
    /* Draw title */
1717
    if (title)
1718
    {
1719
      pspVideoPrint(UiMetric.Font, UiMetric.Left, UiMetric.Top,
1720
        title, UiMetric.TitleColor);
1721
      pspVideoDrawLine(UiMetric.Left, UiMetric.Top + fh - 1, UiMetric.Left + w,
1722
        UiMetric.Top + fh - 1, UiMetric.TitleColor);
1723
    }
1724
 
1725
    /* Render the menu items */
1726
    for (item = pos.Top, i = 0, j = sy; item && i < lnmax; item = item->Next, j += fh, i++)
1727
    {
1728
      if (item->Caption)
1729
      {
1730
            /* Section header */
1731
            if (item->Caption[0] == '\t')
1732
                {
1733
                  // if (i != 0) j += fh / 2;
1734
          pspVideoPrint(UiMetric.Font, sx, j, item->Caption + 1, UiMetric.TitleColor);
1735
          pspVideoDrawLine(sx, j + fh - 1, sx + w, j + fh - 1, UiMetric.TitleColor);
1736
                  continue;
1737
                }
1738
 
1739 128 jack
        if (item == sel) sel_top = j;
1740 9 jack
 
1741
        /* Item caption */
1742 128 jack
        pspVideoPrint(UiMetric.Font, sx + 10, j, item->Caption,
1743 9 jack
          (item == sel) ? UiMetric.SelectedColor : UiMetric.TextColor);
1744
 
1745 128 jack
        if (!option_mode || item != sel)
1746 9 jack
        {
1747 128 jack
          /* Selected option for the item */
1748
          if (item->Selected)
1749
          {
1750
            k = sx + max_item_w + UiMetric.MenuItemMargin + 10;
1751
            k += pspVideoPrint(UiMetric.Font, k, j, item->Selected->Text,
1752
              (item == sel) ? UiMetric.SelectedColor : UiMetric.TextColor);
1753 9 jack
 
1754 128 jack
            if (!option_mode && item == sel)
1755
              if (sel->Options && sel->Options->Next)
1756
                pspVideoPrint(UiMetric.Font, k + anim_frame, j, " >", UiMetric.MenuDecorColor);
1757 9 jack
          }
1758
        }
1759
      }
1760
    }
1761
 
1762 128 jack
    /* Render status information */
1763
    RenderStatus();
1764
 
1765
    /* Draw scrollbar */
1766
    if (sbh > 0)
1767
    {
1768
      sby = sy + (int)((float)(h - sbh) * ((float)(pos.Offset + pos.Index) / (float)menu->Count));
1769
      pspVideoFillRect(dx - UiMetric.ScrollbarWidth, sy, dx, dy, UiMetric.ScrollbarBgColor);
1770
      pspVideoFillRect(dx - UiMetric.ScrollbarWidth, sby, dx, sby + sbh, UiMetric.ScrollbarColor);
1771
    }
1772
 
1773
    /* End writing to call list */
1774
    sceGuFinish();
1775
 
1776
    if (!option_mode && !fast_scroll && sel && last_sel
1777
      && UiMetric.Animate && last_sel != sel)
1778
    {
1779
      /* Move animation */
1780
      int f, n = 4;
1781
      for (f = 1; f <= n; f++)
1782
      {
1783
        pspVideoBegin();
1784
 
1785
        /* Clear screen */
1786
        if (!UiMetric.Background) pspVideoClearScreen();
1787
        else pspVideoPutImage(UiMetric.Background, 0, 0,
1788 140 jack
          UiMetric.Background->Viewport.Width, UiMetric.Background->Height);
1789 128 jack
 
1790
        int box_top = last_sel_top-((last_sel_top-sel_top)/n)*f;
1791
        pspVideoFillRect(sx, box_top, sx+w, box_top+fh,
1792
          UiMetric.SelectedBgColor);
1793
 
1794
        sceGuCallList(call_list);
1795
 
1796
        /* Perform any custom drawing */
1797
        if (uimenu->OnRender)
1798
          uimenu->OnRender(uimenu, sel);
1799
 
1800
        pspVideoEnd();
1801
 
1802
        /* Swap buffers */
1803
        pspVideoWaitVSync();
1804
        pspVideoSwapBuffers();
1805
      }
1806
    }
1807
 
1808
    /* Begin direct rendering */
1809
    pspVideoBegin();
1810
 
1811
    /* Clear screen */
1812
    if (!UiMetric.Background) pspVideoClearScreen();
1813
    else pspVideoPutImage(UiMetric.Background, 0, 0,
1814 140 jack
      UiMetric.Background->Viewport.Width, UiMetric.Background->Height);
1815 128 jack
 
1816
    /* Draw the highlight for selected item */
1817
    if (!option_mode)
1818
      pspVideoFillRect(sx, sel_top, sx+w, sel_top+fh,
1819
        UiMetric.SelectedBgColor);
1820
 
1821
    pspVideoCallList(call_list);
1822
 
1823
    /* Perform any custom drawing */
1824
    if (uimenu->OnRender)
1825
      uimenu->OnRender(uimenu, sel);
1826
 
1827 9 jack
    /* Render menu options */
1828
    if (option_mode)
1829
    {
1830
      k = sx + max_item_w + UiMetric.MenuItemMargin + 10;
1831 128 jack
      int arrow_x = min_x + (UiMetric.MenuItemMargin / 2 - arrow_w / 2);
1832 9 jack
      const PspMenuOption *option;
1833
 
1834 128 jack
      /* Background */
1835
      pspVideoFillRect(min_x, min_y, max_x, max_y, UiMetric.MenuOptionBoxBg);
1836
      pspVideoFillRect(min_x, sy + pos.Index * fh, max_x,
1837
        sy + (pos.Index + 1) * fh, UiMetric.MenuSelOptionBg);
1838 147 jack
      pspVideoGlowRect(min_x, min_y, max_x - 1, max_y - 1,
1839 128 jack
        COLOR(0xff,0xff,0xff,UI_ANIM_FOG_STEP * UI_ANIM_FRAMES), 2);
1840
 
1841
      /* Render selected item + previous items */
1842
      i = sy + pos.Index * fh;
1843 9 jack
      for (option = temp_option; option && i >= sy; option = option->Prev, i -= fh)
1844 128 jack
        pspVideoPrint(UiMetric.Font, k, i, option->Text, (option == temp_option)
1845
          ? UiMetric.SelectedColor : UiMetric.MenuOptionBoxColor);
1846 9 jack
 
1847
      /* Up arrow */
1848 128 jack
      if (option) pspVideoPrint(UiMetric.Font, arrow_x,
1849 106 jack
          i + fh + anim_frame, PSP_CHAR_UP_ARROW, UiMetric.MenuDecorColor);
1850 9 jack
 
1851
      /* Render following items */
1852
      i = sy + (pos.Index  + 1) * fh;
1853
      for (option = temp_option->Next; option && i < dy; option = option->Next, i += fh)
1854 128 jack
        pspVideoPrint(UiMetric.Font, k, i, option->Text,
1855
          UiMetric.MenuOptionBoxColor);
1856 9 jack
 
1857
      /* Down arrow */
1858 128 jack
      if (option) pspVideoPrint(UiMetric.Font, arrow_x, i - fh - anim_frame,
1859 106 jack
          PSP_CHAR_DOWN_ARROW, UiMetric.MenuDecorColor);
1860 9 jack
    }
1861
 
1862
    pspVideoEnd();
1863
 
1864
    /* Wait if needed */
1865
    do { sceRtcGetCurrentTick(&current_tick); }
1866
    while (current_tick - last_tick < ticks_per_upd);
1867
    last_tick = current_tick;
1868
 
1869
    /* Swap buffers */
1870
    pspVideoWaitVSync();
1871
    pspVideoSwapBuffers();
1872 128 jack
 
1873
    last_sel = sel;
1874
    last_sel_top = sel_top;
1875 9 jack
  }
1876
 
1877
  menu->Selected = sel;
1878
}
1879
 
1880
void pspUiSplashScreen(PspUiSplash *splash)
1881
{
1882
  SceCtrlData pad;
1883
  int fh = pspFontGetLineHeight(UiMetric.Font);
1884
 
1885
  while (!ExitPSP)
1886
  {
1887
    if (!pspCtrlPollControls(&pad))
1888
      continue;
1889
 
1890
    if (pad.Buttons & UiMetric.CancelButton)
1891
    {
1892
      if (splash->OnCancel) splash->OnCancel(splash, NULL);
1893
      break;
1894
    }
1895
 
1896
    if ((pad.Buttons & CONTROL_BUTTON_MASK) && splash->OnButtonPress)
1897
    {
1898
      if (splash->OnButtonPress(splash, pad.Buttons & CONTROL_BUTTON_MASK))
1899
          break;
1900
    }
1901
 
1902
    pspVideoBegin();
1903
 
1904
    /* Clear screen */
1905
    if (UiMetric.Background)
1906
      pspVideoPutImage(UiMetric.Background, 0, 0,
1907 140 jack
        UiMetric.Background->Viewport.Width, UiMetric.Background->Height);
1908 9 jack
    else
1909
      pspVideoClearScreen();
1910
 
1911
    /* Draw instructions */
1912 34 jack
    const char *dirs = (splash->OnGetStatusBarText)
1913
      ? splash->OnGetStatusBarText(splash)
1914
      : SplashStatusBarTemplate;
1915
    pspVideoPrintCenter(UiMetric.Font, UiMetric.Left,
1916
      SCR_HEIGHT - fh, UiMetric.Right, dirs, UiMetric.StatusBarColor);
1917 9 jack
 
1918 128 jack
    /* Render status information */
1919
    RenderStatus();
1920
 
1921 9 jack
    /* Perform any custom drawing */
1922
    if (splash->OnRender)
1923
      splash->OnRender(splash, NULL);
1924
 
1925
    pspVideoEnd();
1926
 
1927
    /* Swap buffers */
1928
    pspVideoWaitVSync();
1929
    pspVideoSwapBuffers();
1930
  }
1931
}
1932 64 jack
 
1933 106 jack
const PspMenuItem* pspUiSelect(const char *title, const PspMenu *menu)
1934
{
1935 128 jack
  const PspMenuItem *sel, *item, *last_sel = NULL;
1936 106 jack
  struct UiPos pos;
1937
  int lnmax, lnhalf;
1938
  int i, j, h, w, fh = pspFontGetLineHeight(UiMetric.Font);
1939
  int sx, sy, dx, dy;
1940
  int anim_frame = 0, anim_incr = 1;
1941
  int arrow_w = pspFontGetTextWidth(UiMetric.Font, PSP_CHAR_DOWN_ARROW);
1942
  int widest = 100;
1943 128 jack
  int sel_top = 0, last_sel_top = 0;
1944 106 jack
  SceCtrlData pad;
1945
 
1946
  char *help_text = strdup(SelectorTemplate);
1947 128 jack
  ReplaceIcons(help_text);
1948 106 jack
 
1949 128 jack
  memset(call_list, 0, sizeof(call_list));
1950
 
1951 106 jack
  /* Determine width of the longest caption */
1952
  for (item = menu->First; item; item = item->Next)
1953
  {
1954
    if (item->Caption)
1955
    {
1956
      int item_w = pspFontGetTextWidth(UiMetric.Font, item->Caption);
1957
      if (item_w > widest)
1958
        widest = item_w;
1959
    }
1960
  }
1961
 
1962
  widest += UiMetric.MenuItemMargin * 2;
1963
 
1964
  sx = SCR_WIDTH - widest;
1965
  sy = UiMetric.Top;
1966
  dx = SCR_WIDTH;
1967
  dy = UiMetric.Bottom;
1968
  w = dx - sx;
1969
  h = dy - sy;
1970
 
1971
  u32 ticks_per_sec, ticks_per_upd;
1972
  u64 current_tick, last_tick;
1973
 
1974
  /* Initialize variables */
1975
  lnmax = (dy - sy) / fh;
1976
  lnhalf = lnmax >> 1;
1977
 
1978
  sel = menu->First;
1979
  pos.Top = menu->First;
1980
  pos.Index = pos.Offset = 0;
1981
 
1982
  pspVideoWaitVSync();
1983
 
1984
  /* Compute update frequency */
1985
  ticks_per_sec = sceRtcGetTickResolution();
1986
  sceRtcGetCurrentTick(&last_tick);
1987
  ticks_per_upd = ticks_per_sec / UiMetric.MenuFps;
1988
 
1989 128 jack
  /* Get copy of screen */
1990
  PspImage *screen = pspVideoGetVramBufferCopy();
1991
 
1992
  if (UiMetric.Animate)
1993
  {
1994
    /* Intro animation */
1995
    for (i = 0; i < UI_ANIM_FRAMES; i++)
1996
    {
1997
          pspVideoBegin();
1998
 
1999
          /* Clear screen */
2000 140 jack
          pspVideoPutImage(screen, 0, 0, screen->Viewport.Width, screen->Height);
2001 128 jack
 
2002
          /* Apply fog and draw right frame */
2003
          pspVideoFillRect(0, 0, SCR_WIDTH, SCR_HEIGHT,
2004
            COLOR(0, 0, 0, UI_ANIM_FOG_STEP * i));
2005
          pspVideoFillRect(SCR_WIDTH - (i * (widest / UI_ANIM_FRAMES)),
2006
        0, dx, SCR_HEIGHT, UiMetric.MenuOptionBoxBg);
2007
 
2008
          pspVideoEnd();
2009
 
2010
      /* Swap buffers */
2011
      pspVideoWaitVSync();
2012
      pspVideoSwapBuffers();
2013
        }
2014
  }
2015
 
2016
  int fast_scroll;
2017
 
2018 106 jack
  /* Begin navigation loop */
2019
  while (!ExitPSP)
2020
  {
2021
    if (!pspCtrlPollControls(&pad))
2022
      continue;
2023
 
2024 128 jack
    fast_scroll = 0;
2025
 
2026 106 jack
    /* Incr/decr animation frame */
2027 128 jack
    anim_frame += (UiMetric.Animate) ? anim_incr : 0;
2028 106 jack
    if (anim_frame > 2 || anim_frame < 0)
2029
      anim_incr *= -1;
2030
 
2031
    /* Check the directional buttons */
2032
    if (sel)
2033
    {
2034
      if ((pad.Buttons & PSP_CTRL_DOWN || pad.Buttons & PSP_CTRL_ANALDOWN)
2035
        && sel->Next)
2036
      {
2037 128 jack
        fast_scroll = pad.Buttons & PSP_CTRL_ANALDOWN;
2038 106 jack
        if (pos.Index + 1 >= lnmax) { pos.Offset++; pos.Top = pos.Top->Next; }
2039
        else pos.Index++;
2040
        sel = sel->Next;
2041
      }
2042
      else if ((pad.Buttons & PSP_CTRL_UP || pad.Buttons & PSP_CTRL_ANALUP)
2043
        && sel->Prev)
2044
      {
2045 128 jack
        fast_scroll = pad.Buttons & PSP_CTRL_ANALUP;
2046 106 jack
        if (pos.Index - 1 < 0) { pos.Offset--; pos.Top = pos.Top->Prev; }
2047
        else pos.Index--;
2048
        sel = sel->Prev;
2049
      }
2050
      else if (pad.Buttons & PSP_CTRL_LEFT)
2051
      {
2052
        for (i = 0; sel->Prev && i < lnhalf; i++)
2053
        {
2054
          if (pos.Index - 1 < 0) { pos.Offset--; pos.Top = pos.Top->Prev; }
2055
          else pos.Index--;
2056
          sel = sel->Prev;
2057
        }
2058
      }
2059
      else if (pad.Buttons & PSP_CTRL_RIGHT)
2060
      {
2061
        for (i = 0; sel->Next && i < lnhalf; i++)
2062
        {
2063
          if (pos.Index + 1 >= lnmax) { pos.Offset++; pos.Top = pos.Top->Next; }
2064
          else pos.Index++;
2065
          sel=sel->Next;
2066
        }
2067
      }
2068
 
2069
      if (pad.Buttons & UiMetric.OkButton) break;
2070
    }
2071
 
2072
    if (pad.Buttons & UiMetric.CancelButton) { sel = NULL; break; }
2073
 
2074 128 jack
    /* Render to a call list */
2075
    sceGuStart(GU_CALL, call_list);
2076 106 jack
 
2077 128 jack
    /* Apply fog and draw frame */
2078
    pspVideoFillRect(0, 0, SCR_WIDTH, SCR_HEIGHT,
2079
      COLOR(0, 0, 0, UI_ANIM_FOG_STEP * UI_ANIM_FRAMES));
2080 147 jack
    pspVideoGlowRect(sx, 0, dx - 1, SCR_HEIGHT - 1,
2081 128 jack
      COLOR(0xff,0xff,0xff,UI_ANIM_FOG_STEP * UI_ANIM_FRAMES), 2);
2082 106 jack
 
2083
    /* Title */
2084
    if (title)
2085
      pspVideoPrintCenter(UiMetric.Font, sx, 0, dx,
2086
        title, UiMetric.TitleColor);
2087
 
2088
    /* Render the items */
2089
    for (item = (PspMenuItem*)pos.Top, i = 0, j = sy;
2090
      item && i < lnmax; item = item->Next, j += fh, i++)
2091
    {
2092 128 jack
      if (item == sel) sel_top = j;
2093 106 jack
      pspVideoPrintClipped(UiMetric.Font, sx + 10, j, item->Caption, w - 10,
2094
        "...", (item == sel) ? UiMetric.SelectedColor : UiMetric.TextColor);
2095
    }
2096
 
2097
    /* Up arrow */
2098 247 jack
    if (pos.Top && pos.Top->Prev) pspVideoPrint(UiMetric.Font,
2099
      SCR_WIDTH - arrow_w * 2, sy + anim_frame,
2100
      PSP_CHAR_UP_ARROW, UiMetric.MenuDecorColor);
2101 106 jack
 
2102
    /* Down arrow */
2103 128 jack
    if (item) pspVideoPrint(UiMetric.Font, SCR_WIDTH - arrow_w * 2,
2104 106 jack
        dy - fh - anim_frame, PSP_CHAR_DOWN_ARROW, UiMetric.MenuDecorColor);
2105
 
2106
    /* Shortcuts */
2107
    pspVideoPrintCenter(UiMetric.Font, sx, SCR_HEIGHT - fh, dx,
2108
      help_text, UiMetric.StatusBarColor);
2109
 
2110 128 jack
    sceGuFinish();
2111
 
2112
    if (sel != last_sel && !fast_scroll && sel && last_sel
2113
      && UiMetric.Animate)
2114
    {
2115
      /* Move animation */
2116
      int f, n = 4;
2117
      for (f = 1; f <= n; f++)
2118
      {
2119
        pspVideoBegin();
2120
 
2121
        /* Clear screen */
2122 140 jack
        pspVideoPutImage(screen, 0, 0, screen->Viewport.Width, screen->Height);
2123 128 jack
        pspVideoFillRect(sx, 0, dx, SCR_HEIGHT, UiMetric.MenuOptionBoxBg);
2124
 
2125
        /* Selection box */
2126
        int box_top = last_sel_top-((last_sel_top-sel_top)/n)*f;
2127
        pspVideoFillRect(sx, box_top, sx + w, box_top + fh,
2128
          UiMetric.SelectedBgColor);
2129
 
2130
        sceGuCallList(call_list);
2131
 
2132
        pspVideoEnd();
2133
 
2134
        pspVideoWaitVSync();
2135
        pspVideoSwapBuffers();
2136
      }
2137
    }
2138
 
2139
    pspVideoBegin();
2140
 
2141
    /* Clear screen */
2142 140 jack
    pspVideoPutImage(screen, 0, 0, screen->Viewport.Width, screen->Height);
2143 128 jack
    pspVideoFillRect(sx, 0, dx, SCR_HEIGHT, UiMetric.MenuOptionBoxBg);
2144
 
2145
    if (sel) pspVideoFillRect(sx, sel_top, sx + w, sel_top + fh,
2146
      UiMetric.SelectedBgColor);
2147
 
2148
    sceGuCallList(call_list);
2149
 
2150 106 jack
    pspVideoEnd();
2151
 
2152
    /* Wait if needed */
2153
    do { sceRtcGetCurrentTick(&current_tick); }
2154
    while (current_tick - last_tick < ticks_per_upd);
2155
    last_tick = current_tick;
2156
 
2157
    /* Swap buffers */
2158
    pspVideoWaitVSync();
2159
    pspVideoSwapBuffers();
2160 128 jack
 
2161
    last_sel = sel;
2162
    last_sel_top = sel_top;
2163 106 jack
  }
2164
 
2165 128 jack
  if (UiMetric.Animate)
2166
  {
2167
    /* Exit animation */
2168
    for (i = UI_ANIM_FRAMES - 1; i >= 0; i--)
2169
    {
2170
          pspVideoBegin();
2171
 
2172
          /* Clear screen */
2173 140 jack
          pspVideoPutImage(screen, 0, 0, screen->Viewport.Width, screen->Height);
2174 128 jack
 
2175
          /* Apply fog and draw right frame */
2176
          pspVideoFillRect(0, 0, SCR_WIDTH, SCR_HEIGHT,
2177
            COLOR(0, 0, 0, UI_ANIM_FOG_STEP * i));
2178
          pspVideoFillRect(SCR_WIDTH - (i * (widest / UI_ANIM_FRAMES)),
2179
        0, dx, SCR_HEIGHT, UiMetric.MenuOptionBoxBg);
2180
 
2181
          pspVideoEnd();
2182
 
2183
      /* Swap buffers */
2184
      pspVideoWaitVSync();
2185
      pspVideoSwapBuffers();
2186
        }
2187
  }
2188
 
2189 106 jack
  free(help_text);
2190
  pspImageDestroy(screen);
2191
 
2192
  return sel;
2193
}
2194
 
2195 247 jack
static void adhocMatchingCallback(int unk1,
2196
                                  int event,
2197
                                  unsigned char *mac2,
2198
                                  int opt_len,
2199
                                  void *opt_data)
2200
{
2201
  _adhoc_match_event.NewEvent = 1;
2202
  _adhoc_match_event.EventID = event;
2203
  memcpy(_adhoc_match_event.EventMAC, mac2,
2204
    sizeof(unsigned char) * 6);
2205
  strncpy(_adhoc_match_event.OptData, opt_data, sizeof(char) * opt_len);
2206
  _adhoc_match_event.OptData[opt_len] = '\0';
2207
}
2208
 
2209
int pspUiAdhocHost(const char *name, PspMAC mac)
2210
{
2211
  /* Check the wlan switch */
2212
  if (!pspAdhocIsWLANEnabled())
2213
  {
2214
    pspUiAlert("Error: WLAN switch is turned off");
2215
    return 0;
2216
  }
2217
 
2218
  pspUiFlashMessage(ADHOC_INITIALIZING);
2219
  _adhoc_match_event.NewEvent = 0;
2220
 
2221
  /* Initialize ad-hoc networking */
2222
  if (!pspAdhocInit("ULUS99999", adhocMatchingCallback))
2223
  {
2224
    pspUiAlert("Ad-hoc networking initialization failed");
2225
    return 0;
2226
  }
2227
 
2228
  /* Wait for someone to join */
2229
  pspUiFlashMessage(ADHOC_AWAITING_JOIN);
2230
 
2231
  int state = ADHOC_WAIT_CLI;
2232
  PspMAC selected;
2233
 
2234
  /* Loop until someone joins or host cancels */
2235
  while (!ExitPSP)
2236
  {
2237
    SceCtrlData pad;
2238
 
2239
    if (!pspCtrlPollControls(&pad))
2240
      continue;
2241
 
2242
    if (pad.Buttons & UiMetric.CancelButton)
2243
      break;
2244
 
2245
    if (_adhoc_match_event.NewEvent)
2246
    {
2247
      _adhoc_match_event.NewEvent = 0;
2248
 
2249
      switch(_adhoc_match_event.EventID)
2250
      {
2251 353 jack
      case PSP_ADHOC_MATCHING_EVENT_HELLO:
2252 247 jack
        break;
2253 353 jack
      case PSP_ADHOC_MATCHING_EVENT_DISCONNECT:
2254
      case PSP_ADHOC_MATCHING_EVENT_CANCEL:
2255 247 jack
        if (pspAdhocIsMACEqual(selected, _adhoc_match_event.EventMAC))
2256
          state = ADHOC_WAIT_CLI;
2257
        break;
2258 353 jack
      case PSP_ADHOC_MATCHING_EVENT_JOIN:
2259 247 jack
        if (state == ADHOC_WAIT_CLI)
2260
        {
2261
          memcpy(selected, _adhoc_match_event.EventMAC,
2262
            sizeof(unsigned char) * 6);
2263
          sceKernelDelayThread(1000000/60);
2264
          pspAdhocSelectTarget(selected);
2265
          state = ADHOC_WAIT_EST;
2266
        }
2267
        break;
2268 353 jack
      case PSP_ADHOC_MATCHING_EVENT_COMPLETE:
2269 247 jack
        if (state == ADHOC_WAIT_EST)
2270
        {
2271
          if (pspAdhocIsMACEqual(selected, _adhoc_match_event.EventMAC))
2272
          {
2273
            state = ADHOC_ESTABLISHED;
2274
            goto established;
2275
          }
2276
        }
2277
        break;
2278
      }
2279
    }
2280
 
2281
    /* Wait if needed */
2282
    sceKernelDelayThread(1000000/60);
2283
  }
2284
 
2285
established:
2286
 
2287
  if (state == ADHOC_ESTABLISHED)
2288
  {
2289
    sceKernelDelayThread(1000000);
2290
 
2291
    PspMAC my_mac;
2292
    pspAdhocGetOwnMAC(my_mac);
2293
    memcpy(mac, selected, sizeof(unsigned char) * 6);
2294
 
2295
    if (!pspAdhocConnect(my_mac))
2296
      return 0;
2297
 
2298
    return 1;
2299
  }
2300
 
2301
  /* Shutdown ad-hoc networking */
2302
  pspAdhocShutdown();
2303
  return 0;
2304
}
2305
 
2306
int pspUiAdhocJoin(PspMAC mac)
2307
{
2308
  /* Check the wlan switch */
2309
  if (!pspAdhocIsWLANEnabled())
2310
  {
2311
    pspUiAlert("Error: WLAN switch is turned off");
2312
    return 0;
2313
  }
2314
 
2315
  char *title = "Select host";
2316
 
2317
  /* Get copy of screen */
2318
  PspImage *screen = pspVideoGetVramBufferCopy();
2319
 
2320
  pspUiFlashMessage(ADHOC_INITIALIZING);
2321
  _adhoc_match_event.NewEvent = 0;
2322
 
2323
  /* Initialize ad-hoc networking */
2324
  if (!pspAdhocInit("ULUS99999", adhocMatchingCallback))
2325
  {
2326
    pspUiAlert("Ad-hoc networking initialization failed");
2327
    pspImageDestroy(screen);
2328
    return 0;
2329
  }
2330
 
2331
  /* Initialize menu */
2332
  PspMenu *menu = pspMenuCreate();
2333
 
2334
  int state = ADHOC_PENDING;
2335
  const PspMenuItem *sel, *item, *last_sel = NULL;
2336
  struct UiPos pos;
2337
  int lnmax, lnhalf;
2338
  int i, j, h, w, fh = pspFontGetLineHeight(UiMetric.Font);
2339
  int sx, sy, dx, dy;
2340
  int anim_frame = 0, anim_incr = 1;
2341
  int arrow_w = pspFontGetTextWidth(UiMetric.Font, PSP_CHAR_DOWN_ARROW);
2342
  int widest = 100;
2343
  int sel_top = 0, last_sel_top = 0;
2344
  SceCtrlData pad;
2345
  PspMAC selected;
2346
 
2347
  char *help_text = strdup(SelectorTemplate);
2348
  ReplaceIcons(help_text);
2349
 
2350
  memset(call_list, 0, sizeof(call_list));
2351
 
2352
  /* Determine width of the longest caption */
2353
  for (item = menu->First; item; item = item->Next)
2354
  {
2355
    if (item->Caption)
2356
    {
2357
      int item_w = pspFontGetTextWidth(UiMetric.Font, item->Caption);
2358
      if (item_w > widest)
2359
        widest = item_w;
2360
    }
2361
  }
2362
 
2363
  widest += UiMetric.MenuItemMargin * 2;
2364
 
2365
  sx = SCR_WIDTH - widest;
2366
  sy = UiMetric.Top;
2367
  dx = SCR_WIDTH;
2368
  dy = UiMetric.Bottom;
2369
  w = dx - sx;
2370
  h = dy - sy;
2371
 
2372
  u32 ticks_per_sec, ticks_per_upd;
2373
  u64 current_tick, last_tick;
2374
 
2375
  /* Initialize variables */
2376
  lnmax = (dy - sy) / fh;
2377
  lnhalf = lnmax >> 1;
2378
 
2379
  sel = menu->First;
2380
  pos.Top = menu->First;
2381
  pos.Index = pos.Offset = 0;
2382
 
2383
  pspVideoWaitVSync();
2384
 
2385
  /* Compute update frequency */
2386
  ticks_per_sec = sceRtcGetTickResolution();
2387
  sceRtcGetCurrentTick(&last_tick);
2388
  ticks_per_upd = ticks_per_sec / UiMetric.MenuFps;
2389
 
2390
  if (UiMetric.Animate)
2391
  {
2392
    /* Intro animation */
2393
    for (i = 0; i < UI_ANIM_FRAMES; i++)
2394
    {
2395
      pspVideoBegin();
2396
 
2397
      /* Clear screen */
2398
      pspVideoPutImage(screen, 0, 0, screen->Viewport.Width, screen->Height);
2399
 
2400
      /* Apply fog and draw right frame */
2401
      pspVideoFillRect(0, 0, SCR_WIDTH, SCR_HEIGHT,
2402
        COLOR(0, 0, 0, UI_ANIM_FOG_STEP * i));
2403
      pspVideoFillRect(SCR_WIDTH - (i * (widest / UI_ANIM_FRAMES)),
2404
        0, dx, SCR_HEIGHT, UiMetric.MenuOptionBoxBg);
2405
 
2406
      pspVideoEnd();
2407
 
2408
      /* Swap buffers */
2409
      pspVideoWaitVSync();
2410
      pspVideoSwapBuffers();
2411
    }
2412
  }
2413
 
2414
  int fast_scroll, found_psp;
2415
 
2416
  /* Begin navigation loop */
2417
  while (!ExitPSP)
2418
  {
2419
    if (_adhoc_match_event.NewEvent)
2420
    {
2421
      found_psp = 0;
2422
      PspMenuItem *adhoc_item;
2423
      _adhoc_match_event.NewEvent = 0;
2424
 
2425 353 jack
      if (_adhoc_match_event.EventID == PSP_ADHOC_MATCHING_EVENT_HELLO)
2426 247 jack
      {
2427
        /* Make sure the machine isn't already on the list */
2428
        for (adhoc_item = menu->First; adhoc_item; adhoc_item = adhoc_item->Next)
2429
          if (adhoc_item->Param && pspAdhocIsMACEqual((unsigned char*)adhoc_item->Param,
2430
            _adhoc_match_event.EventMAC))
2431
          {
2432
            found_psp = 1;
2433
            break;
2434
          }
2435
 
2436
        if (!found_psp)
2437
        {
2438
          /* Create item */
2439
          adhoc_item = pspMenuAppendItem(menu, _adhoc_match_event.OptData, 0);
2440
 
2441
          /* Add MAC */
2442
          unsigned char *opp_mac = (unsigned char*)malloc(6 * sizeof(unsigned char));
2443
          memcpy(opp_mac, _adhoc_match_event.EventMAC, sizeof(unsigned char) * 6);
2444
          adhoc_item->Param = opp_mac;
2445
 
2446
          if (!pos.Top)
2447
            sel = pos.Top = menu->First;
2448
        }
2449
      }
2450 353 jack
      else if (_adhoc_match_event.EventID == PSP_ADHOC_MATCHING_EVENT_DISCONNECT)
2451 247 jack
      {
2452
        /* Make sure the machine IS on the list */
2453
        for (adhoc_item = menu->First; adhoc_item; adhoc_item = adhoc_item->Next)
2454
          if (adhoc_item->Param && pspAdhocIsMACEqual((unsigned char*)adhoc_item->Param,
2455
            _adhoc_match_event.EventMAC))
2456
          {
2457
            found_psp = 1;
2458
            break;
2459
          }
2460
 
2461
        if (found_psp)
2462
        {
2463
          /* Free MAC & destroy item */
2464
          free((void*)adhoc_item->Param);
2465
          pspMenuDestroyItem(menu, adhoc_item);
2466
 
2467
          /* Reset items */
2468
          sel = pos.Top = menu->First;
2469
          pos.Index = pos.Offset = 0;
2470
        }
2471
      }
2472 353 jack
      else if (_adhoc_match_event.EventID == PSP_ADHOC_MATCHING_EVENT_REJECT)
2473 247 jack
      {
2474
        /* Host rejected connection */
2475
        if (state == ADHOC_WAIT_HOST)
2476
        {
2477
          state = ADHOC_PENDING;
2478
        }
2479
      }
2480 353 jack
      else if (_adhoc_match_event.EventID == PSP_ADHOC_MATCHING_EVENT_COMPLETE)
2481 247 jack
      {
2482
        if (state == ADHOC_WAIT_HOST)
2483
        {
2484
          state = ADHOC_EST_AS_CLI;
2485
          break;
2486
        }
2487
      }
2488
    }
2489
 
2490
    /* Delay */
2491
    sceKernelDelayThread(1000000/60);
2492
 
2493
    if (!pspCtrlPollControls(&pad))
2494
      continue;
2495
 
2496
    fast_scroll = 0;
2497
 
2498
    /* Incr/decr animation frame */
2499
    anim_frame += (UiMetric.Animate) ? anim_incr : 0;
2500
    if (anim_frame > 2 || anim_frame < 0)
2501
      anim_incr *= -1;
2502
 
2503
    /* Check the directional buttons */
2504
    if (sel)
2505
    {
2506
      if ((pad.Buttons & PSP_CTRL_DOWN || pad.Buttons & PSP_CTRL_ANALDOWN)
2507
        && sel->Next)
2508
      {
2509
        fast_scroll = pad.Buttons & PSP_CTRL_ANALDOWN;
2510
        if (pos.Index + 1 >= lnmax) { pos.Offset++; pos.Top = pos.Top->Next; }
2511
        else pos.Index++;
2512
        sel = sel->Next;
2513
      }
2514
      else if ((pad.Buttons & PSP_CTRL_UP || pad.Buttons & PSP_CTRL_ANALUP)
2515
        && sel->Prev)
2516
      {
2517
        fast_scroll = pad.Buttons & PSP_CTRL_ANALUP;
2518
        if (pos.Index - 1 < 0) { pos.Offset--; pos.Top = pos.Top->Prev; }
2519
        else pos.Index--;
2520
        sel = sel->Prev;
2521
      }
2522
      else if (pad.Buttons & PSP_CTRL_LEFT)
2523
      {
2524
        for (i = 0; sel->Prev && i < lnhalf; i++)
2525
        {
2526
          if (pos.Index - 1 < 0) { pos.Offset--; pos.Top = pos.Top->Prev; }
2527
          else pos.Index--;
2528
          sel = sel->Prev;
2529
        }
2530
      }
2531
      else if (pad.Buttons & PSP_CTRL_RIGHT)
2532
      {
2533
        for (i = 0; sel->Next && i < lnhalf; i++)
2534
        {
2535
          if (pos.Index + 1 >= lnmax) { pos.Offset++; pos.Top = pos.Top->Next; }
2536
          else pos.Index++;
2537
          sel=sel->Next;
2538
        }
2539
      }
2540
 
2541
      if (pad.Buttons & UiMetric.OkButton)
2542
      {
2543
        if (state == ADHOC_PENDING)
2544
        {
2545
          state = ADHOC_WAIT_HOST;
2546
          memcpy(selected, sel->Param, sizeof(unsigned char) * 6);
2547
          pspAdhocSelectTarget(selected);
2548
        }
2549
      }
2550
    }
2551
 
2552
    if (pad.Buttons & UiMetric.CancelButton) { sel = NULL; break; }
2553
 
2554
    /* Render to a call list */
2555
    sceGuStart(GU_CALL, call_list);
2556
 
2557
    /* Apply fog and draw frame */
2558
    pspVideoFillRect(0, 0, SCR_WIDTH, SCR_HEIGHT,
2559
      COLOR(0, 0, 0, UI_ANIM_FOG_STEP * UI_ANIM_FRAMES));
2560
    pspVideoGlowRect(sx, 0, dx - 1, SCR_HEIGHT - 1,
2561
      COLOR(0xff,0xff,0xff,UI_ANIM_FOG_STEP * UI_ANIM_FRAMES), 2);
2562
 
2563
    /* Title */
2564
    if (title)
2565
      pspVideoPrintCenter(UiMetric.Font, sx, 0, dx,
2566
        title, UiMetric.TitleColor);
2567
 
2568
    /* Render the items */
2569
    for (item = (PspMenuItem*)pos.Top, i = 0, j = sy;
2570
      item && i < lnmax; item = item->Next, j += fh, i++)
2571
    {
2572
      if (item == sel) sel_top = j;
2573
      pspVideoPrintClipped(UiMetric.Font, sx + 10, j, item->Caption, w - 10,
2574
        "...", (item == sel) ? UiMetric.SelectedColor : UiMetric.TextColor);
2575
    }
2576
 
2577
    /* Up arrow */
2578
    if (pos.Top && pos.Top->Prev) pspVideoPrint(UiMetric.Font,
2579
      SCR_WIDTH - arrow_w * 2, sy + anim_frame,
2580
      PSP_CHAR_UP_ARROW, UiMetric.MenuDecorColor);
2581
 
2582
    /* Down arrow */
2583
    if (item) pspVideoPrint(UiMetric.Font, SCR_WIDTH - arrow_w * 2,
2584
        dy - fh - anim_frame, PSP_CHAR_DOWN_ARROW, UiMetric.MenuDecorColor);
2585
 
2586
    /* Shortcuts */
2587
    pspVideoPrintCenter(UiMetric.Font, sx, SCR_HEIGHT - fh, dx,
2588
      help_text, UiMetric.StatusBarColor);
2589
 
2590
    sceGuFinish();
2591
 
2592
    if (sel != last_sel && !fast_scroll && sel && last_sel
2593
      && UiMetric.Animate)
2594
    {
2595
      /* Move animation */
2596
      int f, n = 4;
2597
      for (f = 1; f <= n; f++)
2598
      {
2599
        pspVideoBegin();
2600
 
2601
        /* Clear screen */
2602
        pspVideoPutImage(screen, 0, 0, screen->Viewport.Width, screen->Height);
2603
        pspVideoFillRect(sx, 0, dx, SCR_HEIGHT, UiMetric.MenuOptionBoxBg);
2604
 
2605
        /* Selection box */
2606
        int box_top = last_sel_top-((last_sel_top-sel_top)/n)*f;
2607
        pspVideoFillRect(sx, box_top, sx + w, box_top + fh,
2608
          UiMetric.SelectedBgColor);
2609
 
2610
        sceGuCallList(call_list);
2611
 
2612
        pspVideoEnd();
2613
 
2614
        pspVideoWaitVSync();
2615
        pspVideoSwapBuffers();
2616
      }
2617
    }
2618
 
2619
    pspVideoBegin();
2620
 
2621
    /* Clear screen */
2622
    pspVideoPutImage(screen, 0, 0, screen->Viewport.Width, screen->Height);
2623
    pspVideoFillRect(sx, 0, dx, SCR_HEIGHT, UiMetric.MenuOptionBoxBg);
2624
 
2625
    if (sel) pspVideoFillRect(sx, sel_top, sx + w, sel_top + fh,
2626
      UiMetric.SelectedBgColor);
2627
 
2628
    sceGuCallList(call_list);
2629
 
2630
    pspVideoEnd();
2631
 
2632
    /* Wait if needed */
2633
    do { sceRtcGetCurrentTick(&current_tick); }
2634
    while (current_tick - last_tick < ticks_per_upd);
2635
    last_tick = current_tick;
2636
 
2637
    /* Swap buffers */
2638
    pspVideoWaitVSync();
2639
    pspVideoSwapBuffers();
2640
 
2641
    last_sel = sel;
2642
    last_sel_top = sel_top;
2643
  }
2644
 
2645
  if (UiMetric.Animate)
2646
  {
2647
    /* Exit animation */
2648
    for (i = UI_ANIM_FRAMES - 1; i >= 0; i--)
2649
    {
2650
      pspVideoBegin();
2651
 
2652
      /* Clear screen */
2653
      pspVideoPutImage(screen, 0, 0, screen->Viewport.Width, screen->Height);
2654
 
2655
      /* Apply fog and draw right frame */
2656
      pspVideoFillRect(0, 0, SCR_WIDTH, SCR_HEIGHT,
2657
        COLOR(0, 0, 0, UI_ANIM_FOG_STEP * i));
2658
      pspVideoFillRect(SCR_WIDTH - (i * (widest / UI_ANIM_FRAMES)),
2659
        0, dx, SCR_HEIGHT, UiMetric.MenuOptionBoxBg);
2660
 
2661
      pspVideoEnd();
2662
 
2663
      /* Swap buffers */
2664
      pspVideoWaitVSync();
2665
      pspVideoSwapBuffers();
2666
    }
2667
  }
2668
 
2669
  free(help_text);
2670
  pspImageDestroy(screen);
2671
 
2672
  /* Free memory used for MACs; menu resources */
2673
  for (item = menu->First; item; item=item->Next)
2674
    if (item->Param) free((void*)item->Param);
2675
  pspMenuDestroy(menu);
2676
 
2677
  if (state == ADHOC_EST_AS_CLI)
2678
  {
2679
    memcpy(mac, selected, sizeof(unsigned char) * 6);
2680
 
2681
    if (!pspAdhocConnect(selected))
2682
      return 0;
2683
 
2684
    return 1;
2685
  }
2686
 
2687
  /* Shut down ad-hoc networking */
2688
  pspAdhocShutdown();
2689
  return 0;
2690
}
2691
 
2692 128 jack
void pspUiFadeout()
2693
{
2694
  /* Get copy of screen */
2695
  PspImage *screen = pspVideoGetVramBufferCopy();
2696
 
2697
  /* Exit animation */
2698
  int i, alpha;
2699
  for (i = 0; i < UI_ANIM_FRAMES; i++)
2700
  {
2701
          pspVideoBegin();
2702
 
2703
          /* Clear screen */
2704 140 jack
          pspVideoPutImage(screen, 0, 0, screen->Viewport.Width, screen->Height);
2705 128 jack
 
2706
          /* Apply fog */
2707
          alpha = (0x100/UI_ANIM_FRAMES)*i-1;
2708
          if (alpha > 0)
2709
            pspVideoFillRect(0, 0, SCR_WIDTH, SCR_HEIGHT, COLOR(0,0,0,alpha));
2710
 
2711
          pspVideoEnd();
2712
 
2713
    /* Swap buffers */
2714
    pspVideoWaitVSync();
2715
    pspVideoSwapBuffers();
2716
        }
2717
 
2718
  pspImageDestroy(screen);
2719
}
2720 354 jack
 
2721
int pspUiBETA(PspMAC mac, int host)
2722
{
2723
  const char *message = "Waiting for the other party to resume ...";
2724
  PspImage *screen = NULL;
2725
  int sx, sy, dx, dy, th, fh, mw, cw, w, h;
2726
  int i, n = UI_ANIM_FRAMES;
2727
  char *instr = strdup("\026"PSP_CHAR_SQUARE"\020 Disconnect\t\026\002\020 Cancel");
2728
  ReplaceIcons(instr);
2729
 
2730
  mw = pspFontGetTextWidth(UiMetric.Font, message);
2731
  cw = pspFontGetTextWidth(UiMetric.Font, instr);
2732
  fh = pspFontGetLineHeight(UiMetric.Font);
2733
  th = pspFontGetTextHeight(UiMetric.Font, message);
2734
 
2735
  w = ((mw > cw) ? mw : cw) + 50;
2736
  h = th + fh * 3;
2737
  sx = SCR_WIDTH / 2 - w / 2;
2738
  sy = SCR_HEIGHT / 2 - h / 2;
2739
  dx = sx + w;
2740
  dy = sy + h;
2741
 
2742
  /* Intro animation */
2743
  if (UiMetric.Animate)
2744
  {
2745
    /* Get copy of screen */
2746
    screen = pspVideoGetVramBufferCopy();
2747
 
2748
    for (i = 0; i < n; i++)
2749
    {
2750
          pspVideoBegin();
2751
 
2752
          /* Clear screen */
2753
          pspVideoPutImage(screen, 0, 0, screen->Viewport.Width, screen->Height);
2754
 
2755
          /* Apply fog and draw frame */
2756
          pspVideoFillRect(0, 0, SCR_WIDTH, SCR_HEIGHT,
2757
            COLOR(0,0,0,UI_ANIM_FOG_STEP*i));
2758
          pspVideoFillRect(SCR_WIDTH/2-(((dx-sx)/n)*i)/2,
2759
            SCR_HEIGHT/2-(((dy-sy)/n)*i)/2,
2760
            SCR_WIDTH/2+(((dx-sx)/n)*i)/2, SCR_HEIGHT/2+(((dy-sy)/n)*i)/2,
2761
            COLOR(RED_32(UiMetric.MenuOptionBoxBg),
2762
              GREEN_32(UiMetric.MenuOptionBoxBg),
2763
              BLUE_32(UiMetric.MenuOptionBoxBg),(0xff/n)*i));
2764
 
2765
          pspVideoEnd();
2766
 
2767
      /* Swap buffers */
2768
      pspVideoWaitVSync();
2769
      pspVideoSwapBuffers();
2770
        }
2771
  }
2772
 
2773
  pspVideoBegin();
2774
 
2775
  if (UiMetric.Animate)
2776
    pspVideoPutImage(screen, 0, 0, screen->Viewport.Width, screen->Height);
2777
  pspVideoFillRect(0, 0, SCR_WIDTH, SCR_HEIGHT,
2778
    COLOR(0,0,0,UI_ANIM_FOG_STEP*n));
2779
  pspVideoFillRect(sx, sy, dx, dy, UiMetric.MenuOptionBoxBg);
2780
  pspVideoPrint(UiMetric.Font, SCR_WIDTH / 2 - mw / 2, sy + fh * 0.5, message,
2781
    UiMetric.TextColor);
2782
  pspVideoPrint(UiMetric.Font, SCR_WIDTH / 2 - cw / 2, dy - fh * 1.5, instr,
2783
    UiMetric.TextColor);
2784
  pspVideoGlowRect(sx, sy, dx - 1, dy - 1,
2785
    COLOR(0xff,0xff,0xff,UI_ANIM_FOG_STEP*n), 2);
2786
 
2787
  pspVideoEnd();
2788
 
2789
  /* Swap buffers */
2790
  pspVideoWaitVSync();
2791
  pspVideoSwapBuffers();
2792
 
2793
  SceCtrlData pad;
2794
  unsigned int confirm = 0xDEADBEEF;
2795
 
2796
  /* Loop until X or O is pressed */
2797
  while (!ExitPSP)
2798
  {
2799
    if (!pspCtrlPollControls(&pad))
2800
      continue;
2801
 
2802
    if (host)
2803
      pspAdhocSend(mac, &confirm, sizeof(confirm));
2804
    else
2805
    {
2806
      unsigned int recvd = 0;
2807
      pspAdhocRecv(&recvd, sizeof(recvd));
2808
 
2809
      if (recvd == confirm)
2810
        break;
2811
    }
2812
 
2813
    sceKernelDelayThread(1000000);
2814
 
2815
    if (pad.Buttons & UiMetric.CancelButton
2816
      || pad.Buttons & PSP_CTRL_SQUARE) break;
2817
  }
2818
 
2819
  if (!ExitPSP && UiMetric.Animate)
2820
  {
2821
          /* Exit animation */
2822
          for (i = n - 1; i >= 0; i--)
2823
          {
2824
                  pspVideoBegin();
2825
 
2826
                  /* Clear screen */
2827
                  pspVideoPutImage(screen, 0, 0, screen->Viewport.Width, screen->Height);
2828
 
2829
                  /* Apply fog and draw frame */
2830
          pspVideoFillRect(0, 0, SCR_WIDTH, SCR_HEIGHT,
2831
            COLOR(0,0,0,UI_ANIM_FOG_STEP*i));
2832
          pspVideoFillRect(SCR_WIDTH/2-(((dx-sx)/n)*i)/2,
2833
            SCR_HEIGHT/2-(((dy-sy)/n)*i)/2,
2834
            SCR_WIDTH/2+(((dx-sx)/n)*i)/2, SCR_HEIGHT/2+(((dy-sy)/n)*i)/2,
2835
            COLOR(RED_32(UiMetric.MenuOptionBoxBg),
2836
              GREEN_32(UiMetric.MenuOptionBoxBg),
2837
              BLUE_32(UiMetric.MenuOptionBoxBg),(0xff/n)*i));
2838
 
2839
                  pspVideoEnd();
2840
 
2841
            /* Swap buffers */
2842
            pspVideoWaitVSync();
2843
            pspVideoSwapBuffers();
2844
                }
2845
        }
2846
 
2847
  if (screen) pspImageDestroy(screen);
2848
  free(instr);
2849
 
2850
  if (pad.Buttons & UiMetric.CancelButton) return PSP_UI_CANCEL;
2851
  else if (pad.Buttons & PSP_CTRL_SQUARE) return PSP_UI_NO;
2852
  else return PSP_UI_YES;
2853
}
2854
 
2855