naev 0.12.6
gui_osd.c
1/*
2 * See Licensing and Copyright notice in naev.h
3 */
5#include <stdlib.h>
6
7#include "naev.h"
9
10#include "gui_osd.h"
11
12#include "array.h"
13#include "font.h"
14#include "log.h"
15#include "nstring.h"
16#include "ntracing.h"
17#include "opengl.h"
18
22typedef struct OSD_s {
23 unsigned int id;
25 int skip;
26 int hide;
28 char *title;
29 char **titlew;
30
31 char **msg;
32 char ***items;
33
34 unsigned int active;
35} OSD_t;
36
37/*
38 * OSD array.
39 */
40static unsigned int osd_idgen = 0;
41static OSD_t *osd_list = NULL;
42
43/*
44 * Dimensions.
45 */
46static int osd_x = 0;
47static int osd_y = 0;
48static int osd_w = 0;
49static int osd_h = 0;
50static int osd_lines = 0;
51static int osd_rh = 0;
52static int osd_tabLen = 0;
53static int osd_hyphenLen = 0;
54
55/*
56 * Prototypes.
57 */
58static OSD_t *osd_get( unsigned int osd );
59static int osd_free( OSD_t *osd );
60static void osd_calcDimensions( void );
61/* Sort. */
62static int osd_sortCompare( const void *arg1, const void *arg2 );
63static void osd_sort( void );
64static void osd_wordwrap( OSD_t *osd );
65
66static int osd_sortCompare( const void *arg1, const void *arg2 )
67{
68 const OSD_t *osd1, *osd2;
69 int ret, m;
70
71 osd1 = (OSD_t *)arg1;
72 osd2 = (OSD_t *)arg2;
73
74 /* Compare priority. */
75 if ( osd1->priority > osd2->priority )
76 return +1;
77 else if ( osd1->priority < osd2->priority )
78 return -1;
79
80 /* Compare name. */
81 ret = strcmp( osd1->title, osd2->title );
82 if ( ret != 0 )
83 return ret;
84
85 /* Compare items. */
86 m = MIN( array_size( osd1->items ), array_size( osd2->items ) );
87 for ( int i = 0; i < m; i++ ) {
88 ret = strcmp( osd1->msg[i], osd2->msg[i] );
89 if ( ret != 0 )
90 return ret;
91 }
92
93 /* Compare on length. */
94 if ( array_size( osd1->items ) > array_size( osd2->items ) )
95 return +1;
96 if ( array_size( osd1->items ) < array_size( osd2->items ) )
97 return -1;
98
99 /* Compare ID. */
100 if ( osd1->id > osd2->id )
101 return +1;
102 else if ( osd1->id < osd2->id )
103 return -1;
104 return 0;
105}
106
110static void osd_sort( void )
111{
112 qsort( osd_list, array_size( osd_list ), sizeof( OSD_t ), osd_sortCompare );
113}
114
123unsigned int osd_create( const char *title, int nitems, const char **items,
124 int priority, int hidden )
125{
126 int id;
127 OSD_t *osd;
128
129 /* Create. */
130 if ( osd_list == NULL )
131 osd_list = array_create( OSD_t );
132 osd = &array_grow( &osd_list );
133 memset( osd, 0, sizeof( OSD_t ) );
134 osd->id = id = ++osd_idgen;
135 osd->active = 0;
136
137 /* Copy text. */
138 osd->title = strdup( title );
139 osd->priority = priority;
140 osd->msg = array_create_size( char *, nitems );
141 osd->items = array_create_size( char **, nitems );
142 osd->titlew = array_create( char *);
143 osd->hide = hidden;
144 for ( int i = 0; i < nitems; i++ ) {
145 array_push_back( &osd->msg, strdup( items[i] ) );
146 array_push_back( &osd->items, array_create( char * ) );
147 }
148
149 osd_sort(); /* THIS INVALIDATES THE osd POINTER. */
150 osd_calcDimensions();
151
152 return id;
153}
154
158static void osd_wordwrap( OSD_t *osd )
159{
161 char title[STRMAX_SHORT]; /* Needs to be in the scope of the entire function
162 as it is used in gl_printLineIteratorNext
163 indirectly. */
164
165 /* Do title. */
166 for ( int i = 0; i < array_size( osd->titlew ); i++ )
167 free( osd->titlew[i] );
168 array_resize( &osd->titlew, 0 );
169
170 /* Handle the case same mission is repeated. */
171 if ( osd->duplicates > 0 ) {
172 snprintf( title, sizeof( title ), _( "%s #b(%dx)#0" ), osd->title,
173 osd->duplicates + 1 );
174 gl_printLineIteratorInit( &iter, &gl_smallFont, title, osd_w );
175 } else
176 gl_printLineIteratorInit( &iter, &gl_smallFont, osd->title, osd_w );
177
178 /* Figure out the length. */
179 while ( gl_printLineIteratorNext( &iter ) ) {
180 /* Copy text over. */
181 int chunk_len = iter.l_end - iter.l_begin + 1;
182 char *chunk = malloc( chunk_len );
183 snprintf( chunk, chunk_len, "%s", &iter.text[iter.l_begin] );
184 array_push_back( &osd->titlew, chunk );
185 }
186
187 /* Do items. */
188 for ( int i = 0; i < array_size( osd->items ); i++ ) {
189 int msg_len, w, has_tab;
190 const char *chunk_fmt;
191 for ( int l = 0; l < array_size( osd->items[i] ); l++ )
192 free( osd->items[i][l] );
193 array_resize( &osd->items[i], 0 );
194
195 msg_len = strlen( osd->msg[i] );
196 if ( msg_len == 0 )
197 continue;
198
199 /* Test if tabbed. */
200 has_tab = !!( osd->msg[i][0] == '\t' );
201 w = osd_w - ( has_tab ? osd_tabLen : osd_hyphenLen );
202 gl_printLineIteratorInit( &iter, &gl_smallFont, &osd->msg[i][has_tab],
203 w );
204 chunk_fmt = has_tab ? " %s" : "- %s";
205
206 while ( gl_printLineIteratorNext( &iter ) ) {
207 /* Copy text over. */
208 int chunk_len = iter.l_end - iter.l_begin + strlen( chunk_fmt ) - 1;
209 char *chunk = malloc( chunk_len );
210 snprintf( chunk, chunk_len, chunk_fmt, &iter.text[iter.l_begin] );
211 array_push_back( &osd->items[i], chunk );
212 chunk_fmt = has_tab ? " %s" : "%s";
213 iter.width = has_tab ? osd_w - osd_tabLen - osd_hyphenLen
214 : osd_w - osd_hyphenLen;
215 }
216 }
217}
218
224static OSD_t *osd_get( unsigned int osd )
225{
226 for ( int i = 0; i < array_size( osd_list ); i++ ) {
227 OSD_t *ll = &osd_list[i];
228 if ( ll->id == osd )
229 return ll;
230 }
231 WARN( _( "OSD '%d' not found." ), osd );
232 return NULL;
233}
234
238static int osd_free( OSD_t *osd )
239{
240 free( osd->title );
241 for ( int i = 0; i < array_size( osd->items ); i++ ) {
242 free( osd->msg[i] );
243 for ( int j = 0; j < array_size( osd->items[i] ); j++ )
244 free( osd->items[i][j] );
245 array_free( osd->items[i] );
246 }
247 array_free( osd->msg );
248 array_free( osd->items );
249 for ( int i = 0; i < array_size( osd->titlew ); i++ )
250 free( osd->titlew[i] );
251 array_free( osd->titlew );
252
253 return 0;
254}
255
261int osd_destroy( unsigned int osd )
262{
263 for ( int i = 0; i < array_size( osd_list ); i++ ) {
264 OSD_t *ll = &osd_list[i];
265 if ( ll->id != osd )
266 continue;
267
268 /* Clean up. */
269 osd_free( &osd_list[i] );
270
271 /* Remove. */
272 array_erase( &osd_list, &osd_list[i], &osd_list[i + 1] );
273
274 /* Recalculate dimensions. */
275 osd_calcDimensions();
276
277 /* Remove the OSD, if empty. */
278 if ( array_size( osd_list ) == 0 )
279 osd_exit();
280
281 /* Done here. */
282 return 0;
283 }
284
285 WARN( _( "OSD '%u' not found to destroy." ), osd );
286 return 0;
287}
288
296int osd_active( unsigned int osd, int msg )
297{
298 OSD_t *o = osd_get( osd );
299 if ( o == NULL )
300 return -1;
301
302 if ( ( msg < 0 ) || ( msg >= array_size( o->items ) ) ) {
303 WARN( _( "OSD '%s' only has %d items (requested %d)" ), o->title,
304 array_size( o->items ), msg );
305 return -1;
306 }
307
308 o->active = msg;
309 osd_calcDimensions();
310 return 0;
311}
312
319int osd_getActive( unsigned int osd )
320{
321 OSD_t *o = osd_get( osd );
322 if ( o == NULL )
323 return -1;
324
325 return o->active;
326}
327
336int osd_setup( int x, int y, int w, int h )
337{
338 /* Set offsets. */
339 osd_x = x;
340 osd_y = y;
341 osd_w = w;
342 osd_lines = h / ( gl_smallFont.h + 5 );
343 osd_h = h - h % ( gl_smallFont.h + 5 );
344
345 /* Calculate some font things. */
346 osd_tabLen = gl_printWidthRaw( &gl_smallFont, " " );
347 osd_hyphenLen = gl_printWidthRaw( &gl_smallFont, "- " );
348
349 osd_calcDimensions();
350
351 return 0;
352}
353
357void osd_exit( void )
358{
359 for ( int i = 0; i < array_size( osd_list ); i++ ) {
360 OSD_t *ll = &osd_list[i];
361 osd_free( ll );
362 }
363
364 array_free( osd_list );
365 osd_list = NULL;
366}
367
371void osd_render( void )
372{
373 double p;
374 int l;
375
376 /* Nothing to render. */
377 if ( osd_list == NULL )
378 return;
379
380 NTracingZone( _ctx, 1 );
381
382 /* Background. */
383 gl_renderRect( osd_x - 5., osd_y - ( osd_rh + 5. ), osd_w + 10., osd_rh + 10,
384 &cBlackHilight );
385
386 /* Render each thingy. */
387 p = osd_y - gl_smallFont.h;
388 l = 0;
389 for ( int k = 0; k < array_size( osd_list ); k++ ) {
390 int x, w;
391 OSD_t *ll = &osd_list[k];
392
393 if ( ll->skip )
394 continue;
395
396 x = osd_x;
397 w = osd_w;
398
399 /* Print title. */
400 for ( int i = 0; i < array_size( ll->titlew ); i++ ) {
401 gl_printMaxRaw( &gl_smallFont, w, x, p, NULL, -1., ll->titlew[i] );
402 p -= gl_smallFont.h + 5.;
403 l++;
404 }
405 if ( l >= osd_lines ) {
406 NTracingZoneEnd( _ctx );
407 return;
408 }
409
410 /* Print items. */
411 for ( int i = ll->active; i < array_size( ll->items ); i++ ) {
412 const glColour *c =
413 ( i == (int)ll->active ) ? &cFontWhite : &cFontGrey;
414 x = osd_x;
415 for ( int j = 0; j < array_size( ll->items[i] ); j++ ) {
416 gl_printRaw( &gl_smallFont, x, p, c, -1., ll->items[i][j] );
417 if ( j == 0 )
418 x = osd_x + osd_hyphenLen;
419 p -= gl_smallFont.h + 5.;
420 l++;
421 if ( l >= osd_lines ) {
422 NTracingZoneEnd( _ctx );
423 return;
424 }
425 }
426 }
427 }
428 NTracingZoneEnd( _ctx );
429}
430
434static void osd_calcDimensions( void )
435{
436 double len;
437
438 /* Nothing to render. */
439 if ( osd_list == NULL )
440 return;
441
442 /* Reset skips. */
443 for ( int k = 0; k < array_size( osd_list ); k++ ) {
444 OSD_t *ll = &osd_list[k];
445 ll->skip = ll->hide;
446 ll->duplicates = 0;
447 }
448
449 /* Get duplicates. */
450 for ( int k = 0; k < array_size( osd_list ); k++ ) {
451 int duplicates;
452 OSD_t *ll = &osd_list[k];
453
454 if ( ll->skip )
455 continue;
456
457 /* Check how many duplicates we have, mark duplicates for ignoring */
458 duplicates = 0;
459 for ( int m = k + 1; m < array_size( osd_list ); m++ ) {
460 OSD_t *lm = &osd_list[m];
461
462 if ( ( strcmp( lm->title, ll->title ) == 0 ) &&
463 ( array_size( lm->items ) == array_size( ll->items ) ) &&
464 ( lm->active == ll->active ) ) {
465 int is_duplicate = 1;
466 for ( int i = lm->active; i < array_size( lm->items ); i++ ) {
467 if ( array_size( lm->items[i] ) == array_size( ll->items[i] ) ) {
468 for ( int j = 0; j < array_size( lm->items[i] ); j++ ) {
469 if ( strcmp( lm->items[i][j], ll->items[i][j] ) != 0 ) {
470 is_duplicate = 0;
471 break;
472 }
473 }
474 } else {
475 is_duplicate = 0;
476 }
477 if ( !is_duplicate )
478 break;
479 }
480 if ( is_duplicate ) {
481 duplicates++;
482 lm->skip = 1;
483 }
484 }
485 }
486 ll->duplicates = duplicates;
487 }
488
489 /* Compute total length. */
490 len = 0;
491 for ( int k = 0; k < array_size( osd_list ); k++ ) {
492 OSD_t *ll = &osd_list[k];
493
494 if ( ll->skip )
495 continue;
496
497 /* Wordwrap. */
498 osd_wordwrap( ll );
499
500 /* Print title. */
501 for ( int i = 0; i < array_size( ll->titlew ); i++ )
502 len += gl_smallFont.h + 5.;
503
504 /* Print items. */
505 for ( int i = ll->active; i < array_size( ll->items ); i++ )
506 for ( int j = 0; j < array_size( ll->items[i] ); j++ )
507 len += gl_smallFont.h + 5.;
508 }
509 osd_rh = MIN( len, osd_h );
510}
511
518char *osd_getTitle( unsigned int osd )
519{
520 OSD_t *o = osd_get( osd );
521 if ( o == NULL )
522 return NULL;
523
524 return o->title;
525}
526
533char **osd_getItems( unsigned int osd )
534{
535 OSD_t *o = osd_get( osd );
536 if ( o == NULL )
537 return NULL;
538 return o->msg;
539}
540
547int osd_setHide( unsigned int osd, int state )
548{
549 OSD_t *o = osd_get( osd );
550 if ( o == NULL )
551 return -1;
552
553 o->hide = state;
554 osd_calcDimensions();
555 return 0;
556}
557
564int osd_getHide( unsigned int osd )
565{
566 OSD_t *o = osd_get( osd );
567 if ( o == NULL )
568 return -1;
569 return o->hide;
570}
571
578int osd_setPriority( unsigned int osd, int priority )
579{
580 OSD_t *o = osd_get( osd );
581 if ( o == NULL )
582 return -1;
583
584 o->priority = priority;
585 osd_sort();
586 osd_calcDimensions();
587 return 0;
588}
589
596int osd_getPriority( unsigned int osd )
597{
598 OSD_t *o = osd_get( osd );
599 if ( o == NULL )
600 return -1;
601 return o->priority;
602}
Provides macros to work with dynamic arrays.
#define array_free(ptr_array)
Frees memory allocated and sets array to NULL.
Definition array.h:170
#define array_resize(ptr_array, new_size)
Resizes the array to accomodate new_size elements.
Definition array.h:113
#define array_create_size(basic_type, capacity)
Creates a new dynamic array of ‘basic_type’ with an initial capacity.
Definition array.h:102
#define array_erase(ptr_array, first, last)
Erases elements in interval [first, last).
Definition array.h:148
static ALWAYS_INLINE int array_size(const void *array)
Returns number of elements in the array.
Definition array.h:179
#define array_grow(ptr_array)
Increases the number of elements by one and returns the last element.
Definition array.h:122
#define array_push_back(ptr_array, element)
Adds a new element at the end of the array.
Definition array.h:134
#define array_create(basic_type)
Creates a new dynamic array of ‘basic_type’.
Definition array.h:93
int gl_printLineIteratorNext(glPrintLineIterator *iter)
Updates iter with the next line's information.
Definition font.c:550
glFont gl_smallFont
Definition font.c:159
void gl_printRaw(const glFont *ft_font, double x, double y, const glColour *c, double outlineR, const char *text)
Prints text on screen.
Definition font.c:646
int gl_printWidthRaw(const glFont *ft_font, const char *text)
Gets the width that it would take to print some text.
Definition font.c:984
void gl_printLineIteratorInit(glPrintLineIterator *iter, const glFont *ft_font, const char *text, int width)
Initialize an iterator object for breaking text into lines.
Definition font.c:528
int gl_printMaxRaw(const glFont *ft_font, const int max, double x, double y, const glColour *c, double outlineR, const char *text)
Behaves like gl_printRaw but stops displaying text after a certain distance.
Definition font.c:753
Header file with generic functions and naev-specifics.
#define MIN(x, y)
Definition naev.h:39
void gl_renderRect(double x, double y, double w, double h, const glColour *c)
Renders a rectangle.
static const double c[]
Definition rng.c:256
On Screen Display element.
Definition gui_osd.c:22
char *** items
Definition gui_osd.c:32
unsigned int active
Definition gui_osd.c:34
char * title
Definition gui_osd.c:28
int priority
Definition gui_osd.c:24
char ** msg
Definition gui_osd.c:31
int hide
Definition gui_osd.c:26
int duplicates
Definition gui_osd.c:27
char ** titlew
Definition gui_osd.c:29
unsigned int id
Definition gui_osd.c:23
int skip
Definition gui_osd.c:25
The state of a line iteration. This matches the process of rendering text into an on-screen box: An e...
Definition font.h:44
const char * text
Definition font.h:45