1 /*
2  *  Abuse - dark 2D side-scrolling platform game
3  *  Copyright (c) 1995 Crack dot Com
4  *  Copyright (c) 2005-2011 Sam Hocevar <sam@hocevar.net>
5  *
6  *  This software was released into the Public Domain. As with most public
7  *  domain software, no warranty is made or implied by Crack dot Com, by
8  *  Jonathan Clark, or by Sam Hocevar.
9  */
10 
11 #if defined HAVE_CONFIG_H
12 #   include "config.h"
13 #endif
14 
15 #include <string.h>
16 
17 #include "common.h"
18 
19 #include "input.h"
20 
remap(Filter * f)21 void button::remap(Filter *f)
22 {
23   if (visual)
24   {
25     f->Apply(visual);
26     if (pressed)
27       f->Apply(pressed);
28   }
29 }
30 
press_button(int id)31 void button_box::press_button(int id)      // if button box doesn't contain id, nothing happens
32 {
33 }
34 
remap(Filter * f)35 void button_box::remap(Filter *f)
36 {
37   for (button *b=buttons; b; b=(button *)b->next)
38     b->remap(f);
39 }
40 
find(int search_id)41 ifield *button_box::find(int search_id)
42 {
43   if (search_id==id) return this;
44   for (ifield *i=(ifield *)buttons; i; i=i->next)
45     if (search_id==i->id) return i;
46   return NULL;
47 }
48 
button_box(int X,int Y,int ID,int MaxDown,button * Buttons,ifield * Next)49 button_box::button_box(int X, int Y, int ID, int MaxDown, button *Buttons, ifield *Next)
50 {
51   x=X; y=Y; id=ID; next=Next;
52   buttons=Buttons;
53   maxdown=MaxDown;
54   if (buttons && maxdown) buttons->push();  // the first button is automatically selected!
55 }
56 
~button_box()57 button_box::~button_box()
58 {
59   while (buttons)
60   {
61     button *b=buttons;
62     buttons=(button *)buttons->next;
63     delete b;
64   }
65 }
66 
area(int & x1,int & y1,int & x2,int & y2)67 void button_box::area(int &x1, int &y1, int &x2, int &y2)
68 {
69   button *b=buttons;
70   if (!b) return ;
71   else
72   {
73     b->area(x1,y1,x2,y2);
74     int xp1,yp1,xp2,yp2;
75     for (b=(button *)b->next; b; b=(button *)b->next)
76     {
77       b->area(xp1,yp1,xp2,yp2);
78       if (xp1<x1) x1=xp1;
79       if (xp2>x2) x2=xp2;
80       if (yp1<y1) y1=yp1;
81       if (yp2>y2) y2=yp2;
82     }
83   }
84 }
85 
draw_first(image * screen)86 void button_box::draw_first(image *screen)
87 {
88   for (button *b=buttons; b; b=(button *)b->next)
89     b->draw_first(screen);
90 }
91 
draw(int active,image * screen)92 void button_box::draw(int active, image *screen)
93 {
94   return ;
95 }
96 
move(int newx,int newy)97 void button_box::move(int newx, int newy)
98 {
99     for(button * b = buttons; b; b = (button *)b->next)
100         b->move(newx + b->x, newy + b->y);
101     x = newx;
102     y = newy;
103 }
104 
read()105 char *button_box::read()
106 {
107   for (button *b=buttons; b; b=(button *)b->next)
108   {
109     if (*((int *)b->read())==0)
110       return (char *)b;
111   }
112   return NULL;
113 }
114 
handle_event(event & ev,image * screen,InputManager * im)115 void button_box::handle_event(event &ev, image *screen, InputManager *im)
116 {
117   switch (ev.type)
118   {
119     case EV_MOUSE_BUTTON :
120     {
121       int x1,y1,x2,y2;
122       int found=0;
123       for (button *b=buttons; !found && b; b=(button *)b->next)  // see if the user clicked on a button
124       {
125     b->area(x1,y1,x2,y2);
126     if (ev.mouse_move.x>=x1 && ev.mouse_move.x<=x2 &&
127         ev.mouse_move.y>=y1 && ev.mouse_move.y<=y2)
128     {
129       b->handle_event(ev,screen,im);
130 
131       int total=0;
132       button *b2=buttons;
133       for (; b2; b2=(button *)b2->next)
134         if (*((int *)b2->read())==0)
135           total++;
136 
137       if (*((int *)b->read())==0)  // did the user press or release the button
138       {
139         if (total>maxdown)
140         {
141           for (b2=buttons; total>maxdown && b2; b2=(button *)b2->next)
142             if ((b!=b2 || maxdown==0) && *((int *)b2->read())==0)
143         {
144           total--;
145           b2->push();
146           b2->draw_first(screen);
147         }
148         }
149         b->draw_first(screen);
150       } else if (total==0 && maxdown)
151         b->push();    // don't let the user de-press a button if non others are selected.
152 
153       found=1; // don't look at anymore buttons
154 
155     }
156       }
157     } break;
158   }
159 }
160 
161 
add_button(button * b)162 void button_box::add_button(button *b)
163 {
164   b->next=buttons;
165   buttons=b;
166 }
167 
168 
arrange_left_right()169 void button_box::arrange_left_right()
170 {
171   button *b=buttons;
172   int x_on=x,x1,y1,x2,y2;
173   for (; b; b=(button *)b->next)
174   {
175     b->area(x1,y1,x2,y2);
176     b->x=x_on;
177     b->y=y;
178     x_on+=(x2-x1+1)+1;
179   }
180 }
181 
arrange_up_down()182 void button_box::arrange_up_down()
183 {
184   button *b=buttons;
185   int y_on=y,x1,y1,x2,y2;
186   for (; b; b=(button *)b->next)
187   {
188     b->area(x1,y1,x2,y2);
189     b->y=y_on;
190     b->x=x;
191     y_on+=(y2-y1+1)+1;
192   }
193 }
194 
change_visual(image * new_visual)195 void button::change_visual(image *new_visual)
196 {
197   CHECK(visual);
198   visual=new_visual;
199 }
200 
area(int & x1,int & y1,int & x2,int & y2)201 void button::area(int &x1, int &y1, int &x2, int &y2)
202 {
203   x1=x; y1=y;
204   if (pressed)
205   {
206     x2=x+pressed->Size().x-1;
207     y2=y+pressed->Size().y-1;
208   }
209   else
210   {
211     if (text)
212     {
213       x2=x+wm->font()->width()*strlen(text)+6;
214       y2=y+wm->font()->height()+6;
215     } else
216     {
217       x2=x+6+visual->Size().x;
218       y2=y+6+visual->Size().y;
219     }
220   }
221 }
222 
223 
button(int X,int Y,int ID,char const * Text,ifield * Next)224 button::button(int X, int Y, int ID, char const *Text, ifield *Next)
225 {
226   x=X; y=Y; id=ID;
227   act_id=-1;
228   text = strdup(Text);
229   up=1; next=Next; act=0;
230   visual=NULL;
231   pressed=NULL;
232 }
233 
234 
button(int X,int Y,int ID,image * vis,ifield * Next)235 button::button(int X, int Y, int ID, image *vis, ifield *Next)
236 { x=X; y=Y; id=ID; text=NULL;
237   act_id=-1;
238   visual=vis; up=1; next=Next; act=0;
239   pressed=NULL;
240 }
241 
button(int X,int Y,int ID,image * Depressed,image * Pressed,image * active,ifield * Next)242 button::button(int X, int Y, int ID, image *Depressed, image *Pressed, image *active, ifield *Next)
243 { x=X; y=Y; id=ID; text=NULL;
244   act_id=-1;
245   visual=Depressed; up=1; next=Next; act=0;
246   pressed=Pressed;
247   act_pict=active;
248 }
249 
250 
change_data(char const * new_data,int new_cursor,int active,image * screen)251 void text_field::change_data(char const *new_data, int new_cursor, // cursor==-1, does not change it.
252                  int active, image *screen)
253 {
254   if (strlen(format)<strlen(new_data))
255     data=(char *)realloc(data,strlen(new_data));
256 
257   strcpy(data,new_data);
258   if (new_cursor!=-1)
259     cur=new_cursor;
260   draw_first(screen);
261   draw(active,screen);
262 }
263 
read()264 char *text_field::read()
265 {
266   while (*data && data[strlen(data)-1]==' ') data[strlen(data)-1]=0;
267   return data;
268 }
269 
handle_event(event & ev,image * screen,InputManager * im)270 void text_field::handle_event(event &ev, image *screen, InputManager *im)
271 {
272   int xx;
273   if (ev.type==EV_KEY)
274   {
275     switch (ev.key)
276     {
277       case JK_LEFT : if (cur) { draw_cur(wm->dark_color(),screen); cur--;
278                            draw_cur(wm->bright_color(),screen); } break;
279       case JK_RIGHT : if (cur<(int)strlen(format)-1) { draw_cur(wm->dark_color(),screen); cur++;
280                            draw_cur(wm->bright_color(),screen); } break;
281       case JK_END : if (cur!=last_spot())
282                           { draw_cur(wm->dark_color(),screen); cur=last_spot();
283                             if (cur==(int)strlen(format)-1) cur--;
284                            draw_cur(wm->bright_color(),screen); } break;
285       case JK_HOME : if (cur)
286                           { draw_cur(wm->dark_color(),screen); cur=0;
287                            draw_cur(wm->bright_color(),screen); } break;
288       case JK_BACKSPACE : if (cur)
289          { draw_cur(wm->dark_color(),screen); cur--;
290            for (xx=cur; xx<(int)strlen(format)-1; xx++)
291              data[xx]=data[xx+1];
292            data[strlen(format)-1]=' ';
293            draw_text(screen);
294            draw_cur(wm->bright_color(),screen);
295            wm->push_event(new event(id,(char *)this));
296          } break;
297       default : if (ev.key>=' ' && ev.key<='~')
298          {
299            draw_cur(wm->dark_color(),screen);
300            for (xx=strlen(format)-1; xx>cur && xx>0; xx--)
301              data[xx]=data[xx-1];
302            data[cur]=ev.key;
303            if (cur<(int)strlen(format)-1)
304              cur++;
305        data[strlen(format)]=0;
306            draw_text(screen);
307            draw_cur(wm->bright_color(),screen);
308            wm->push_event(new event(id,(char *)this));
309          } break;
310     }
311   }
312 }
313 
draw(int active,image * screen)314 void text_field::draw(int active, image *screen)
315 {
316   if (active)
317   {
318     screen->rectangle(xstart(),y,xend(),yend(),wm->bright_color());
319     draw_cur(wm->bright_color(),screen);
320   }
321   else
322   {
323     screen->rectangle(xstart(),y,xend(),yend(),wm->dark_color());
324     draw_cur(wm->dark_color(),screen);
325   }
326 }
327 
area(int & x1,int & y1,int & x2,int & y2)328 void text_field::area(int &x1, int &y1, int &x2, int &y2)
329 {
330   x1=x; y1=y;
331   x2=xend();
332   y2=yend();
333 }
334 
text_field(int X,int Y,int ID,char const * Prompt,char const * Format,char const * Data,ifield * Next)335 text_field::text_field(int X, int Y, int ID, char const *Prompt,
336                        char const *Format, char const *Data, ifield *Next)
337 {
338   int slen=(strlen(Format)>strlen(Data) ? strlen(Format) : strlen(Data));
339 
340   x=X; y=Y; id=ID;
341   prompt = strdup(Prompt);
342   format=strcpy((char *)malloc(slen+1),Format);
343   data=strcpy((char *)malloc(slen+1),Data);
344   cur=strlen(data);
345   while (cur && data[cur-1]==' ') cur--;
346   next=Next;
347 }
348 
text_field(int X,int Y,int ID,char const * Prompt,char const * Format,double Data,ifield * Next)349 text_field::text_field(int X, int Y, int ID, char const *Prompt,
350                        char const *Format, double Data, ifield *Next)
351 {
352   char num[20];
353   sprintf(num,"%g",Data);
354   int slen=(strlen(Format)>strlen(num) ? strlen(Format) : strlen(num));
355   x=X; y=Y; id=ID;
356   prompt = strdup(Prompt);
357   format=strcpy((char *)malloc(slen+1),Format);
358   data=strcpy((char *)malloc(slen+1),num);
359   cur=strlen(num);
360   while (cur && data[cur-1]==' ') cur--;
361   next=Next;
362 }
363 
364 
push()365 void button::push()
366 { up=!up; }
367 
handle_event(event & ev,image * screen,InputManager * im)368 void button::handle_event(event &ev, image *screen, InputManager *im)
369 {
370   if ((ev.type==EV_KEY && ev.key==13) || (ev.type==EV_MOUSE_BUTTON &&
371                                          ev.mouse_button))
372   {
373     int  x1,y1,x2,y2;
374     area(x1,y1,x2,y2);
375     up=!up;
376     draw_first(screen);
377     draw(act,screen);
378     wm->push_event(new event(id,(char *)this));
379   }
380 }
381 
draw(int active,image * screen)382 void button::draw(int active, image *screen)
383 {
384   int x1,y1,x2,y2,color=(active ? wm->bright_color() : wm->medium_color());
385   area(x1,y1,x2,y2);
386   if (active!=act  && act_id!=-1 && active)
387     wm->push_event(new event(act_id,NULL));
388 
389   if (pressed)
390   {
391     if (up)
392     {
393       if (!active)
394         visual->put_image(screen,x,y);
395       else
396         pressed->put_image(screen,x,y);
397     } else act_pict->put_image(screen,x,y);
398   }
399   else
400   {
401     screen->rectangle(x1+2,y1+2,x2-2,y2-2,color);
402     act=active;
403   }
404 }
405 
draw_first(image * screen)406 void button::draw_first(image *screen)
407 {
408   if (pressed)
409     draw(0,screen);
410   else
411   {
412 
413     int x1,y1,x2,y2;
414     area(x1,y1,x2,y2);
415 
416 
417     if (up)
418     {
419       screen->rectangle(x1,y1,x2,y2,wm->black());
420 //      screen->widget_bar(,wm->bright_color(),wm->medium_color(),wm->dark_color());
421       screen->widget_bar(x1+1,y1+1,x2-1,y2-1,wm->bright_color(),wm->medium_color(),wm->dark_color());
422       if (text)
423       {
424         wm->font()->put_string(screen,x+4,y+5,text,wm->black());
425         wm->font()->put_string(screen,x+3,y+4,text);
426       }
427       else visual->put_image(screen,x+3,y+3,1);
428     } else
429     {
430       screen->line(x1,y1,x2,y1,wm->dark_color());
431       screen->line(x1,y1,x1,y2,wm->dark_color());
432       screen->line(x2,y1+1,x2,y2,wm->bright_color());
433       screen->line(x1+1,y2,x2,y2,wm->bright_color());
434       screen->bar(x1+1,y1+1,x2-1,y2-1,wm->medium_color());
435       if (visual)
436         visual->put_image(screen,x1+3,y1+3,1);
437       else
438       {
439         wm->font()->put_string(screen,x+4,y+5,text,wm->black());
440         wm->font()->put_string(screen,x+3,y+4,text);
441       }
442     }
443   }
444 }
445 
draw_first(image * screen)446 void text_field::draw_first(image *screen)
447 {
448   wm->font()->put_string(screen,x,y+3,prompt);
449   screen->bar(xstart(),y,xend(),yend(),wm->dark_color());
450   wm->font()->put_string(screen,xstart()+1,y+3,data);
451 }
452 
453 
draw_cur(int color,image * screen)454 void text_field::draw_cur(int color, image *screen)
455 {
456   screen->bar(xstart()+cur*wm->font()->width()+1,
457                       yend()-2,
458                       xstart()+(cur+1)*wm->font()->width(),
459                       yend()-1,color);
460 }
461 
462 
463 
info_field(int X,int Y,int ID,char const * info,ifield * Next)464 info_field::info_field(int X, int Y, int ID, char const *info, ifield *Next)
465 {
466   x = X; y = Y; id = ID; next = Next;
467   text = strdup(info);
468   w = -1;
469 }
470 
471 
area(int & x1,int & y1,int & x2,int & y2)472 void info_field::area(int &x1, int &y1, int &x2, int &y2)
473 {
474   if (w==-1)     // if we haven't calculated this yet
475   {
476     int fw=wm->font()->width(),fh=wm->font()->height(),maxw=0;
477     char *info=text;
478     for (w=fw,h=fh+1; *info; info++)
479     {
480       if (w>maxw) maxw=w;
481       if (*info=='\n')
482       {
483     h+=fh+1;
484     w=1;
485       }
486       else w+=fw;
487     }
488     w=maxw;
489   }
490   x1=x;
491   y1=y;
492   x2=x+w;
493   y2=y+h;
494 }
495 
put_para(image * screen,char const * st,int dx,int dy,int xspace,int yspace,JCFont * font,int color)496 void info_field::put_para(image *screen, char const *st, int dx, int dy,
497               int xspace, int yspace, JCFont *font, int color)
498 {
499   int ox=dx;
500   while (*st)
501   {
502     if (*st=='\n')
503     {
504       dx=ox;
505       dy+=yspace;
506     }
507     else
508     {
509       font->put_char(screen,dx,dy,*st,color);
510       dx+=xspace;
511     }
512     st++;
513   }
514 }
515 
draw_first(image * screen)516 void info_field::draw_first(image *screen)
517 {
518   put_para(screen,text,x+1,y+1,wm->font()->width(),wm->font()->height(),wm->font(),wm->black());
519   put_para(screen,text,x,y,wm->font()->width(),wm->font()->height(),wm->font(),wm->bright_color());
520 }
521 
522 
523 
524 
525