naev 0.12.5
news.c
Go to the documentation of this file.
1/*
2 * See Licensing and Copyright notice in naev.h
3 */
10#include <inttypes.h>
11#include <stdlib.h>
12
13#include "naev.h"
15
16#include "news.h"
17
18#include "array.h"
19#include "faction.h"
20#include "log.h"
21#include "nstring.h"
22#include "ntime.h"
23#include "nxml.h"
24#include "toolkit.h"
25
26#define NEWS_MAX_LENGTH 8192
27
28/*
29 * News stack.
30 */
32static int next_id = 0;
33
37static char buf[NEWS_MAX_LENGTH];
38static int len;
39
40static unsigned int news_tick = 0;
41static int news_drag = 0;
42static double news_pos = 0.;
44static char **news_lines = NULL;
46 NULL;
47static double textlength = 0.;
48
52static int largestID;
53
54/*
55 * Prototypes
56 */
57static void news_render( double bx, double by, double w, double h, void *data );
58static void news_focusLose( unsigned int wid, const char *wgtname );
59static int news_mouse( unsigned int wid, const SDL_Event *event, double mx,
60 double my, double w, double h, double rx, double ry,
61 void *data );
62static int news_parseArticle( xmlNodePtr parent );
63int news_saveArticles( xmlTextWriterPtr writer ); /* externed in save.c */
64int news_loadArticles( xmlNodePtr parent ); /* externed in load.c */
65static void clear_newslines( void );
66
67static int news_cmp( const void *p1, const void *p2 )
68{
69 const news_t *n1, *n2;
70 int diff;
71 n1 = (const news_t *)p1;
72 n2 = (const news_t *)p2;
73 diff = n1->priority - n2->priority;
74 if (diff != 0)
75 return diff;
76 if (n1->date < n2->date)
77 return +1;
78 else if (n1->date > n2->date)
79 return -1;
80 return n1->id - n2->id;
81}
82
94int news_add( const char *title, const char *content, const char *faction,
95 const char *tag, ntime_t date, ntime_t date_to_rm, int priority )
96{
97 news_t *n;
98 int id = ++next_id;
99
100 if (news_list == NULL)
102 n = &array_grow( &news_list );
103 memset( n, 0, sizeof( news_t ) );
104 n->id = id;
105 n->title = strdup( title );
106 n->desc = strdup( content );
107 n->faction = strdup( faction );
108 if (tag != NULL)
109 n->tag = strdup( tag );
110 n->date = date;
111 n->date_to_rm = date_to_rm;
112 n->priority = priority;
113
114 /* Sort it! */
115 qsort( news_list, array_size( news_list ), sizeof( news_t ), news_cmp );
116
117 return id;
118}
119
123int news_init( void )
124{
125 /* init news list with dummy article */
126 if (news_list != NULL)
127 news_exit();
128
130 news_lines = array_create( char * );
132
133 return 0;
134}
135
139void news_exit( void )
140{
141 if (news_list == NULL)
142 return;
143
144 for (int i = 0; i < array_size( news_list ); i++) {
145 news_t *n = &news_list[i];
146
147 free( n->faction );
148 free( n->title );
149 free( n->desc );
150 free( n->tag );
151 }
153 news_list = NULL;
154
155 for (int i = 0; i < array_size( news_lines ); i++)
156 free( news_lines[i] );
159 news_lines = NULL;
160 news_restores = NULL;
161 textlength = 0;
162
163 news_list = NULL;
164}
165
169news_t *news_get( int id )
170{
171 for (int i = 0; i < array_size( news_list ); i++) {
172 news_t *n = &news_list[i];
173 if (n->id == id)
174 return n;
175 }
176 return NULL;
177}
178
179void news_free( news_t *n )
180{
181 free( n->title );
182 free( n->desc );
183 free( n->faction );
184 free( n->tag );
185}
186
187void news_rm( int id )
188{
189 news_t *n = news_get( id );
190 if (n == NULL)
191 return;
192 news_free( n );
193 array_erase( &news_list, &n[0], &n[1] );
194}
195
202int *generate_news( int faction )
203{
204 const char *fname;
205 ntime_t curtime = ntime_get();
206 int p = 0;
207 const char *const *tags;
208
209 fname = ( faction >= 0 ) ? faction_name( faction ) : NULL;
210
211 /* First pass to remove old articles. */
212 for (int i = array_size( news_list ) - 1; i >= 0; i--) {
213 const news_t *n = &news_list[i];
214
215 /* if the article is due for removal */
216 if (n->date_to_rm <= curtime)
217 news_rm( n->id );
218 }
219
220 /* Put all acceptable news into buf */
221 tags = ( faction >= 0 ) ? faction_tags( faction ) : NULL;
222 for (int i = 0; i < array_size( news_list ); i++) {
223 news_t *n = &news_list[i];
224 int match_tag = 0;
225
226 /* Check to see if matches tag. */
227 if (tags != NULL) {
228 for (int j = 0; j < array_size( tags ); j++) {
229 if (strcasecmp( tags[j], n->faction ) == 0) {
230 match_tag = 1;
231 break;
232 }
233 }
234 }
235
236 /* if article is okay */
237 if (match_tag ||
238 ( ( fname != NULL ) && ( strcasecmp( n->faction, fname ) == 0 ) )) {
239 if (n->date != 0) {
240 char *article_time = ntime_pretty( n->date, 1 );
241 p += scnprintf( buf + p, NEWS_MAX_LENGTH - p,
242 " %s \n"
243 "%s: %s#0\n\n",
244 n->title, article_time, n->desc );
245 free( article_time );
246 } else {
247 p += scnprintf( buf + p, NEWS_MAX_LENGTH - p,
248 " %s \n"
249 "%s#0\n\n",
250 n->title, n->desc );
251 }
252 }
253 }
254
255 if (p == 0)
256 p = scnprintf( buf, NEWS_MAX_LENGTH, "\n\n%s\n\n\n",
257 _( "No news is available." ) );
258
259 len = MIN( p, NEWS_MAX_LENGTH );
260
261 return 0;
262}
263
273void news_widget( unsigned int wid, int x, int y, int w, int h )
274{
275 unsigned int *widptr;
277
278 /* Safe defaults. */
279 news_pos = h / 3.;
280 news_tick = SDL_GetTicks();
281
282 clear_newslines();
283
284 /* Now load up the text. */
285 gl_printLineIteratorInit( &iter, NULL, buf, w - 40 );
286
287 while (gl_printLineIteratorNext( &iter )) {
288 /* Copy the line. */
289 array_push_back( &news_lines, strndup( &buf[iter.l_begin],
290 iter.l_end - iter.l_begin ) );
291 if (array_size( news_restores ) == 0)
293 else {
295 gl_printStore( &restore, news_lines[array_size( news_lines ) - 2] );
296 array_push_back( &news_restores, restore );
297 }
298 }
299
300 /* Create the custom widget. */
301 widptr = malloc( sizeof( unsigned int ) );
302 *widptr = wid;
303 window_addCust( wid, x, y, w, h, "cstNews", 1, news_render, news_mouse, NULL,
304 news_focusLose, widptr );
305 window_custSetDynamic( wid, "cstNews", 1 );
306 window_canFocusWidget( wid, "cstNews", 0 );
307 window_custFreeDataFunc( wid, "cstNews", free );
308}
309
310/* clears newslines for bar text, for when taking off */
311void clear_newslines( void )
312{
313 for (int i = 0; i < array_size( news_lines ); i++)
314 free( news_lines[i] );
315
318}
319
323static void news_focusLose( unsigned int wid, const char *wgtname )
324{
325 (void)wid;
326 (void)wgtname;
327 news_drag = 0;
328}
329
343static int news_mouse( unsigned int wid, const SDL_Event *event, double mx,
344 double my, double w, double h, double rx, double ry,
345 void *data )
346{
347 (void)data;
348 (void)rx;
349
350 switch (event->type) {
351 case SDL_MOUSEWHEEL:
352 /* Must be in bounds. */
353 if (( mx < 0. ) || ( mx > w ) || ( my < 0. ) || ( my > h ))
354 return 0;
355
356 if (event->wheel.y > 0)
357 news_pos -= h / 3.;
358 else if (event->wheel.y < 0)
359 news_pos += h / 3.;
360 return 1;
361
362 case SDL_MOUSEBUTTONDOWN:
363 /* Must be in bounds. */
364 if (( mx < 0. ) || ( mx > w ) || ( my < 0. ) || ( my > h ))
365 return 0;
366 window_setFocus( wid, "cstNews" );
367
368 news_drag = 1;
369 return 1;
370
371 case SDL_MOUSEBUTTONUP:
372 news_drag = 0;
373 break;
374
375 case SDL_MOUSEMOTION:
376 if (news_drag)
377 news_pos -= ry;
378 break;
379 }
380
381 return 0;
382}
383
393static void news_render( double bx, double by, double w, double h, void *data )
394{
395 int s, m, p;
396 unsigned int t, *wid;
397 double y;
398
399 wid = data;
400 t = SDL_GetTicks();
401
402 /* Calculate offset. */
403 if (!news_drag && window_isTop( *wid )) {
404 double dt = (double)( t - news_tick ) / 1000.;
405 news_pos += dt * 25.;
406 }
407 news_tick = t;
408
409 /* Make sure user isn't silly and drags it to negative values. */
410 if (news_pos < 0.)
411 news_pos = 0.;
412
413 /* background */
414 gl_renderRect( bx, by, w, h, &cBlack );
415
416 /* Render the text. */
417 p = (int)ceil( news_pos / ( news_font->h + 5. ) );
418 m = (int)ceil( h / ( news_font->h + 5. ) );
419 if (p > array_size( news_lines ) + m + 1) {
420 news_pos = 0.;
421 return;
422 }
423
424 /* Get positions to make sure inbound. */
425 s = MAX( 0, p - m );
426 p = MIN( p + 1, array_size( news_lines ) - 1 );
427
428 /* Get start position. */
429 y = news_pos - s * ( news_font->h + 5. );
430
431 /* Draw loop. */
432 for (int i = s; i < p; i++) {
434 gl_printMidRaw( news_font, w - 40., bx + 10, by + y, &cFontGreen, -1.,
435 news_lines[i] );
436
437 /* Increment line and position. */
438 y -= news_font->h + 5.;
439 }
440}
441
442/*
443 * @brief saves all current articles
444 * @return 0 on success
445 */
446int news_saveArticles( xmlTextWriterPtr writer )
447{
448 xmlw_startElem( writer, "news" );
449
450 for (int i = 0; i < array_size( news_list ); i++) {
451 const char *ntitle, *ndesc;
452 news_t *n = &news_list[i];
453
454 if (n->title == NULL || n->desc == NULL || n->faction == NULL)
455 continue;
456
457 xmlw_startElem( writer, "article" );
458
459 ntitle = n->title;
460 ndesc = n->desc;
461
462 xmlw_attr( writer, "title", "%s", ntitle );
463 xmlw_attr( writer, "desc", "%s", ndesc );
464 xmlw_attr( writer, "faction", "%s", n->faction );
465 xmlw_attr( writer, "date", "%" PRIi64, n->date );
466 xmlw_attr( writer, "date_to_rm", "%" PRIi64, n->date_to_rm );
467 xmlw_attr( writer, "id", "%i", n->id );
468 xmlw_attr( writer, "priority", "%i", n->priority );
469
470 if (n->tag != NULL)
471 xmlw_attr( writer, "tag", "%s", n->tag );
472
473 xmlw_endElem( writer ); /* "article" */
474 }
475
476 xmlw_endElem( writer ); /* "news" */
477
478 return 0;
479}
480
487int news_loadArticles( xmlNodePtr parent )
488{
489 news_tick = 0;
490
491 xmlNodePtr node;
492
493 largestID = 0;
494
495 news_exit();
496 news_init();
497
498 /* Get and parse news/articles */
499 node = parent->xmlChildrenNode;
500 do {
501 if (xml_isNode( node, "news" ))
502 news_parseArticle( node );
503 } while (xml_nextNode( node ));
504
506
507 return 0;
508}
509
516static int news_parseArticle( xmlNodePtr parent )
517{
518 xmlNodePtr node;
519
520 node = parent->xmlChildrenNode;
521
522#define NEWS_READ( elem, s ) \
523 xmlr_attr_strd( node, s, elem ); \
524 if (elem == NULL) { \
525 WARN( _( "Event is missing '%s', skipping." ), s ); \
526 goto cleanup; \
527 }
528
529 do {
530 char *title, *desc, *faction, *tag, *buff;
531 int priority;
532 ntime_t date, date_to_rm;
533
534 if (!xml_isNode( node, "article" ))
535 continue;
536
537 /* Reset parameters. */
538 title = NULL;
539 desc = NULL;
540 faction = NULL;
541
542 NEWS_READ( title, "title" );
543 NEWS_READ( desc, "desc" );
544 NEWS_READ( faction, "faction" );
545
546 NEWS_READ( buff, "date" );
547 date = atoll( buff );
548 free( buff );
549
550 NEWS_READ( buff, "date_to_rm" );
551 date_to_rm = atoll( buff );
552 free( buff );
553
554 NEWS_READ( buff, "id" );
555 next_id = atoi( buff );
556 free( buff );
557
558 /* Older versions won't have priority. */
559 xmlr_attr_strd( node, "priority", buff );
560 priority = ( buff == NULL ) ? 5 : atoi( buff );
561 free( buff );
562
563 /* Read optional tag. */
564 tag = NULL;
565 xmlr_attr_strd( node, "tag", tag );
566
567 largestID = MAX( largestID, next_id + 1 );
568
569 /* make the article*/
570 news_add( title, desc, faction, tag, date, date_to_rm, priority );
571 free( tag );
572
573 cleanup:
574 free( title );
575 free( desc );
576 free( faction );
577 } while (xml_nextNode( node ));
578#undef NEWS_READ
579
580 return 0;
581}
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_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_back(ptr_array)
Returns the last element in the array.
Definition array.h:228
#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
const char *const * faction_tags(int f)
Gets the tags the faction has.
Definition faction.c:439
const char * faction_name(int f)
Gets a factions "real" (internal) name.
Definition faction.c:331
void gl_printRestoreInit(glFontRestore *restore)
Initializes a restore structure.
Definition font.c:416
int gl_printLineIteratorNext(glPrintLineIterator *iter)
Updates iter with the next line's information.
Definition font.c:550
glFont gl_defFont
Definition font.c:158
int gl_printMidRaw(const glFont *ft_font, int width, double x, double y, const glColour *c, double outlineR, const char *text)
Displays text centered in position and width.
Definition font.c:821
void gl_printRestore(const glFontRestore *restore)
Restores last colour from a restore structure.
Definition font.c:425
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
void gl_printStore(glFontRestore *restore, const char *text)
Stores the colour information from a piece of text.
Definition font.c:463
Header file with generic functions and naev-specifics.
#define MIN(x, y)
Definition naev.h:39
#define MAX(x, y)
Definition naev.h:37
static glFont * news_font
Definition news.c:43
news_t * news_list
Definition news.c:31
static int next_id
Definition news.c:32
static void news_focusLose(unsigned int wid, const char *wgtname)
Called when it's de-focused.
Definition news.c:323
static char ** news_lines
Definition news.c:44
int news_loadArticles(xmlNodePtr parent)
Loads the player's active articles from a save, initilizes news.
Definition news.c:487
int news_add(const char *title, const char *content, const char *faction, const char *tag, ntime_t date, ntime_t date_to_rm, int priority)
makes a new article and puts it into the list
Definition news.c:94
news_t * news_get(int id)
gets the article with id ID, else NULL
Definition news.c:169
static void news_render(double bx, double by, double w, double h, void *data)
Renders a news widget.
Definition news.c:393
static glFontRestore * news_restores
Definition news.c:45
static double news_pos
Definition news.c:42
static unsigned int news_tick
Definition news.c:40
void news_exit(void)
Kills the old news thread.
Definition news.c:139
int * generate_news(int faction)
Generates news from newslist from specific faction AND Generic news.
Definition news.c:202
#define NEWS_MAX_LENGTH
Definition news.c:26
static int news_mouse(unsigned int wid, const SDL_Event *event, double mx, double my, double w, double h, double rx, double ry, void *data)
News widget mouse event handler.
Definition news.c:343
static int largestID
Definition news.c:52
void news_widget(unsigned int wid, int x, int y, int w, int h)
Creates a news widget.
Definition news.c:273
int news_init(void)
Initiate news linked list with a stack.
Definition news.c:123
static int news_drag
Definition news.c:41
static int news_parseArticle(xmlNodePtr parent)
Parses articles.
Definition news.c:516
int scnprintf(char *text, size_t maxlen, const char *fmt,...)
Like snprintf(), but returns the number of characters ACTUALLY "printed" into the buffer....
Definition nstring.c:102
char * strndup(const char *s, size_t n)
Return a pointer to a new string, which is a duplicate of the string s (or, if necessary,...
Definition nstring.c:69
ntime_t ntime_get(void)
Gets the current time.
Definition ntime.c:113
char * ntime_pretty(ntime_t t, int d)
Gets the time in a pretty human readable format.
Definition ntime.c:178
void gl_renderRect(double x, double y, double w, double h, const glColour *c)
Renders a rectangle.
Evil hack to allow restoring, yes it makes me cry myself to sleep.
Definition font.h:28
Represents a font in memory.
Definition font.h:17
The state of a line iteration. This matches the process of rendering text into an on-screen box: An e...
Definition font.h:44
Represents a news article.
Definition news.h:15
char * faction
Definition news.h:22
ntime_t date_to_rm
Definition news.h:26
int priority
Definition news.h:17
char * title
Definition news.h:20
int id
Definition news.h:16
ntime_t date
Definition news.h:25
char * tag
Definition news.h:23
char * desc
Definition news.h:21
void window_setFocus(unsigned int wid, const char *wgtname)
Sets the focused widget in a window.
Definition toolkit.c:2488
void window_canFocusWidget(unsigned int wid, const char *name, int canfocus)
Allows or disallows focusing a widget.
Definition toolkit.c:517
int window_isTop(unsigned int wid)
Checks to see if a window is at the top.
Definition toolkit.c:544