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