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 "video.h"
20 #include "image.h"
21 #include "input.h"
22 #include "event.h"
23 #include "filter.h"
24 #include "event.h"
25 #include "jwindow.h"
26 
27 static int jw_left = 3, jw_right = 3, jw_top = 2, jw_bottom = 3;
28 
frame_top()29 int frame_top() { return jw_top; }
frame_bottom()30 int frame_bottom() { return jw_bottom; }
frame_left()31 int frame_left() { return jw_left; }
frame_right()32 int frame_right() { return jw_right; }
33 
34 //
35 //  Sets the size of the border around each window
36 //
set_frame_size(int x)37 void set_frame_size(int x)
38 {
39     if(x < 1)
40         x = 1;
41     jw_left = x;
42     jw_right = x;
43     jw_top = 2;
44     jw_bottom = x;
45 }
46 
47  // true if a window lies in this area
window_in_area(int x1,int y1,int x2,int y2)48 int WindowManager::window_in_area(int x1, int y1, int x2, int y2)
49 {
50   for (Jwindow *f=first; f; f=f->next)
51     if (f->x<=x2 && f->y<=y2 && f->x+f->l-1>=x1 && f->y+f->h-1>=y1)
52       return 1;
53   return 0;
54 }
55 
grab_focus(Jwindow * j)56 void WindowManager::grab_focus(Jwindow *j)
57 { grab=j; }
58 
release_focus()59 void WindowManager::release_focus()
60 { grab=NULL; }
61 
62 
close_window(Jwindow * j)63 void WindowManager::close_window(Jwindow *j)
64 {
65     delete j;
66 }
67 
hide_windows()68 void WindowManager::hide_windows()
69 {
70     for (Jwindow *p = first; p; p = p->next)
71     {
72         if (!p->is_hidden())
73         {
74             p->hide();
75             screen->AddDirty(p->x, p->y, p->x + p->l, p->y + p->h);
76         }
77     }
78 }
79 
show_windows()80 void WindowManager::show_windows()
81 {
82   Jwindow *p;
83   for (p=first; p; p=p->next)
84     if (p->is_hidden())
85       show_window(p);
86 }
87 
hide_window(Jwindow * j)88 void WindowManager::hide_window(Jwindow *j)
89 {
90     if (j == first)
91         first = first->next;
92     else
93     {
94         Jwindow *k;
95         for (k = first; k->next != j; k = k->next)
96             k->screen->AddDirty(j->x - k->x, j->y - k->y,
97                                 j->x + j->l - k->x, j->y + j->h - k->y);
98         k->screen->AddDirty(j->x - k->x, j->y - k->y,
99                             j->x + j->l - k->x, j->y + j->h - k->y);
100         k->next = j->next;
101     }
102     screen->AddDirty(j->x, j->y, j->x + j->l, j->y + j->h);
103     j->hide();
104 }
105 
show_window(Jwindow * j)106 void WindowManager::show_window(Jwindow *j)
107 {
108     if (j->is_hidden())
109     {
110         j->show();
111         j->screen->AddDirty(0, 0, j->l, j->h);
112     }
113 }
114 
get_event(event & ev)115 void WindowManager::get_event(event &ev)
116 {
117   Jwindow *j;
118   eh->get_event(ev);
119   if (ev.type==EV_KEY)
120     key_state[ev.key]=1;
121   else if (ev.type==EV_KEYRELEASE)
122     key_state[ev.key]=0;
123 
124   if (state==inputing)
125   {
126     for (ev.window=NULL,j=first; j; j=j->next)
127       if (!j->is_hidden() && ev.mouse_move.x>=j->x && ev.mouse_move.y>=j->y &&
128           ev.mouse_move.x<j->x+j->l && ev.mouse_move.y<j->y+j->h)
129         ev.window=j;
130 
131     if (!ev.window && grab) ev.window=grab;
132 
133     if (ev.window)
134     {
135       int closew=0,movew=0;
136 
137       if ((ev.type==EV_MOUSE_BUTTON && ev.mouse_button==1 && ev.window &&
138        ev.mouse_move.x>=ev.window->x && ev.mouse_move.y>=ev.window->y &&
139        ev.mouse_move.x<ev.window->x+ev.window->l && ev.mouse_move.y<ev.window->y+ev.window->y1()))
140       {
141     if (ev.mouse_move.x-ev.window->x<11) closew=1;
142     else if (ev.window->is_moveable()) movew=1;
143       } else if (grab)
144         ev.window=grab;
145 
146       if (ev.type==EV_KEY && ev.key==JK_ESC)
147         closew=1;
148 
149 
150 
151       if (closew)
152         ev.type=EV_CLOSE_WINDOW;
153       else if (movew)
154       {
155     int red=0;
156     if (ev.window==first)       // see if we need to raise the window
157     {
158       first=first->next;
159       if (first)
160         red=1;
161     }
162     else
163     {
164       Jwindow *last=first;
165       for (; last->next!=ev.window; last=last->next);
166       if (ev.window->next)
167         red=1;
168       last->next=ev.window->next;
169     }
170     if (!first)
171       first=ev.window;
172     else
173     {
174       Jwindow *last=first;
175       for (; last->next; last=last->next);
176       last->next=ev.window;
177     }
178     ev.window->next=NULL;
179     if (red)
180     {
181       Jwindow *j=ev.window;
182 /*      screen->AddDirty(j->x,j->y,j->x+j->l,j->y+j->h);
183       for (p=first; p!=j; p=p->next)
184         p->screen->AddDirty(j->x-p->x,j->y-p->y,j->x+j->l-p->x,j->y+j->h-p->y); */
185       j->screen->AddDirty(0, 0, j->l, j->h);
186       flush_screen();
187     }
188 
189         state=dragging;
190         drag_window=ev.window;
191         drag_mousex=ev.window->x-ev.mouse_move.x;
192         drag_mousey=ev.window->y-ev.mouse_move.y;
193         ev.type=EV_SPURIOUS;
194       } else if (ev.window)
195         ev.window->inm->handle_event(ev,ev.window);
196     }
197   } else if (state==dragging)
198   {
199     ev.window=drag_window;
200     if (ev.type==EV_MOUSE_BUTTON && ev.mouse_button==0)  // user released the mouse
201     {
202       state=inputing;
203       ev.type=EV_SPURIOUS;
204     } else if (ev.type==EV_MOUSE_MOVE)
205     {
206        move_window(drag_window,ev.mouse_move.x+drag_mousex,ev.mouse_move.y+drag_mousey);
207        flush_screen();
208        ev.type=EV_DRAG_WINDOW;
209        ev.window_position.x=ev.mouse_move.x+drag_mousex;
210        ev.window_position.y=ev.mouse_move.y+drag_mousey;
211     }
212   }
213   if (ev.type == EV_REDRAW)
214   {
215     for (j=first; j; j=j->next)
216        j->screen->AddDirty(ev.redraw.x1 - j->x, ev.redraw.y1 - j->y,
217                            ev.redraw.x2 + 1 - j->x, ev.redraw.y2 + 1 - j->y);
218     screen->AddDirty(ev.redraw.x1, ev.redraw.y1, ev.redraw.x2 + 1, ev.redraw.y2 + 1);
219     flush_screen();
220     ev.type=EV_SPURIOUS;   // we took care of this one by ourselves.
221   }
222 }
223 
resize(int L,int H)224 void Jwindow::resize(int L, int H)
225 {
226   screen->SetSize(vec2i(L,H));
227   l=L; h=H;
228 }
229 
resize_window(Jwindow * j,int l,int h)230 void WindowManager::resize_window(Jwindow *j, int l, int h)
231 {
232   Jwindow *p;
233   screen->AddDirty(j->x, j->y, j->x + j->l, j->y + j->h);
234   for (p=first; p!=j; p=p->next)
235     p->screen->AddDirty(j->x - p->x, j->y - p->y, j->x + j->l - p->x, j->y + j->h - p->y);
236   j->resize(l,h);
237   if (!frame_suppress)
238   j->redraw();
239 }
240 
move_window(Jwindow * j,int x,int y)241 void WindowManager::move_window(Jwindow *j, int x, int y)
242 {
243     screen->AddDirty(j->x, j->y, j->x + j->l, j->y + j->h);
244     for(Jwindow *p = first; p != j; p = p->next)
245         p->screen->AddDirty(j->x - p->x, j->y - p->y,
246                             j->x + j->l - p->x, j->y + j->h - p->y);
247     j->x = x;
248     j->y = y;
249     j->screen->AddDirty(0, 0, j->l, j->h);
250 }
251 
WindowManager(image * Screen,palette * Pal,int Hi,int Med,int Low,JCFont * Font)252 WindowManager::WindowManager(image *Screen, palette *Pal, int Hi,
253                              int Med, int Low, JCFont *Font)
254 {
255     wm = this;
256     screen = Screen;
257     hi = Hi; low = Low; med = Med; first = NULL; pal = Pal; grab = NULL;
258     bk = pal->find_closest(0, 0, 0);
259     state = inputing; fnt = Font;  wframe_fnt = Font;
260     memset(key_state, 0, sizeof(key_state));
261     eh = new event_handler(screen, pal);
262     frame_suppress = 0;
263 }
264 
~WindowManager()265 WindowManager::~WindowManager()
266 {
267     delete eh;
268     while(first)
269         close_window(first);
270     wm = NULL;
271 }
272 
add_window(Jwindow * win)273 void WindowManager::add_window(Jwindow *win)
274 {
275     if(!first)
276         first = win;
277     else
278     {
279         Jwindow *tmp = first;
280         while(tmp->next)
281             tmp = tmp->next;
282         tmp->next = win;
283         win->next = NULL;
284     }
285 }
286 
remove_window(Jwindow * win)287 void WindowManager::remove_window(Jwindow *win)
288 {
289     if(grab == win)
290         grab = NULL;
291 
292     // close the window we were dragging
293     if(state == dragging && win == drag_window)
294         state = inputing;
295 
296     if(first == win)
297         first = first->next;
298     else
299     {
300         Jwindow * search;
301         for(search = first; search->next != win; search = search->next)
302             search->screen->AddDirty(win->x - search->x,
303                                      win->y - search->y,
304                                      win->x + win->l - search->x,
305                                      win->y + win->h - search->y);
306         search->screen->AddDirty(win->x - search->x, win->y - search->y,
307                                  win->x + win->l - search->x,
308                                  win->y + win->h - search->y);
309         search->next = win->next;
310     }
311 
312     screen->AddDirty(win->x, win->y, win->x + win->l, win->y + win->h);
313 }
314 
new_window(int x,int y,int l,int h,ifield * fields,char const * name)315 Jwindow * WindowManager::new_window(int x, int y, int l, int h,
316                                      ifield * fields, char const *name)
317 {
318     if(x > screen->Size().x - 4)
319         x = screen->Size().x - 25;
320     if(y > screen->Size().y - 4)
321         y = screen->Size().y - 10;
322 
323     Jwindow * j = new Jwindow (x, y, l, h, fields, name);
324     j->show();
325 
326     return j;
327 }
328 
flush_screen()329 void WindowManager::flush_screen()
330 {
331     Jwindow *p, *q;
332 
333     int mx = 0, my = 0;
334     image *mouse_pic = NULL, *mouse_save = NULL;
335 
336     if(has_mouse())
337     {
338         mouse_pic = eh->mouse_sprite()->visual;
339         mouse_save = eh->mouse_sprite()->save;
340         mx = eh->mouse->drawx();
341         my = eh->mouse->drawy();
342 
343         screen->put_part(mouse_save, 0, 0, mx, my,
344                          mx + mouse_pic->Size().x - 1,
345                          my + mouse_pic->Size().y - 1);
346         mouse_pic->put_image(screen, mx, my, 1);
347     }
348 
349     for(p = first; p; p = p->next)
350         if(!p->is_hidden())
351             screen->delete_dirty(p->x, p->y, p->x + p->l, p->y + p->h);
352     update_dirty(screen);
353 
354     if(has_mouse())
355         mouse_save->put_image(screen, mx, my);
356 
357     for(p = first; p; p = p->next)
358     {
359         if(p->is_hidden())
360             continue;
361 
362         if(has_mouse())
363         {
364             p->screen->put_part(mouse_save, 0, 0, mx - p->x, my - p->y,
365                                 mx - p->x + mouse_pic->Size().x - 1,
366                                 my - p->y + mouse_pic->Size().y - 1);
367             if(has_mouse())
368                 mouse_pic->put_image(p->screen, mx - p->x, my - p->y, 1);
369         }
370 
371 //          screen->delete_dirty(p->x, p->y, p->x+p->l, p->y+p->h);
372         for(q = p->next; q; q = q->next)
373             if(!q->is_hidden())
374                 p->screen->delete_dirty(q->x - p->x, q->y - p->y,
375                                         q->x + q->l - p->x, q->y + q->h - p->y);
376         update_dirty(p->screen, p->x, p->y);
377         if(has_mouse())
378             mouse_save->put_image(p->screen, mx - p->x, my - p->y, 0);
379     }
380 }
381 
Jwindow(char const * name)382 Jwindow::Jwindow(char const *name)
383 {
384     _x1 = left_border();
385     _y1 = jw_top + 5;
386     _x2 = _y2 = 0;
387 
388     _hidden = true;
389     _moveable = true;
390     // property.flags = JWINDOW_NOAUTOHIDE_FLAG;
391 
392     inm = new InputManager(this, NULL);
393     reconfigure();
394 
395     screen = NULL;
396     next = NULL;
397 
398     _name = NULL;
399     if(name)
400         _name = strdup(name);
401     wm->add_window(this);
402 }
403 
Jwindow(int X,int Y,int L,int H,ifield * f,char const * name)404 Jwindow::Jwindow(int X, int Y, int L, int H, ifield *f, char const *name)
405 {
406     l = 0;
407     h = 0;
408     _hidden = false;
409     _moveable = true;
410 
411     _x1 = left_border();
412     _y1 = name ? top_border() : jw_top + 5;
413 
414     screen = NULL;
415     inm = new InputManager(screen, f);
416     reconfigure(); /* FIXME: TODO */
417 
418     l = L >= 0 ? L + left_border() : l - L;
419     h = H >= 0 ? H + top_border() : h - H;
420     y = Y >= 0 ? Y : yres - h + Y - top_border() - bottom_border() - 1;
421     x = X >= 0 ? X : xres - l + X - left_border() - right_border() - 1;
422 
423     backg = wm->medium_color();
424 
425     _x2 = l - 1;
426     _y2 = h - 1;
427     l += right_border();
428     h += bottom_border();
429 
430     if(L == -1)
431         if(l < 15 + left_border() + right_border())
432             l = 15 + left_border() + right_border();
433     if(H == -1)
434         if(h < top_border() + bottom_border())
435             h = top_border() + bottom_border();
436     screen = new image(vec2i(l, h), NULL, 2);
437     screen->clear(backg);
438     // Keep this from getting destroyed when image list is cleared
439     image_list.unlink(screen);
440     inm->screen = screen;
441 
442     next = NULL;
443 
444     _name = NULL;
445     if(name)
446         _name = strdup(name);
447 
448     wm->add_window(this);
449     if(!wm->frame_suppress)
450         redraw();
451 }
452 
~Jwindow()453 Jwindow::~Jwindow()
454 {
455     wm->remove_window(this);
456     local_close();
457     if(screen)
458         delete screen;
459     delete inm;
460     if(_name)
461         free(_name);
462 }
463 
reconfigure()464 void Jwindow::reconfigure()
465 {
466     int x1, y1, x2, y2;
467     ifield *i;
468     l = 2;
469     h = 2;
470     for(i = inm->first; i; i = i->next)
471     {
472         i->set_owner(this);
473         i->area(x1, y1, x2, y2);
474         if ((int)y2 > (int)h)
475             h = y2;
476         if ((int)x2 > (int)l)
477             l = x2;
478     }
479 }
480 
local_close()481 void Jwindow::local_close()
482 {
483     ;
484 }
485 
redraw()486 void Jwindow::redraw()
487 {
488     int hi = wm->bright_color ();
489     int med = wm->medium_color ();
490     int low = wm->dark_color ();
491     JCFont * fnt = wm->frame_font ();
492 
493     if(_name)
494     {
495         if (right_border() >= 1)
496         {
497             screen->widget_bar (0, 0, l - 1, h - 1, hi, med, low);
498             if (right_border() >= 3)
499                 screen->widget_bar (right_border() - 1, top_border() - 1,
500                                 l - left_border(), h - bottom_border(), low,
501                                 med, hi);
502 
503           else
504             screen->line (left_border() - 1, top_border() - 1,
505                            right_border() - 1, top_border() - 1, low);
506         }
507       screen->rectangle (2, 2, top_border() - 2, top_border() - 3,
508                            wm->black ());
509       screen->widget_bar (3, 3, top_border() - 3, top_border() - 4, hi, med, low);     // draws the 'close' button
510     }
511 
512   else
513     {
514       if (right_border() >= 1)
515         {
516           screen->widget_bar (0, 0, l - 1, h - 1, hi, med, low);
517           if (right_border() >= 3)
518             screen->widget_bar (right_border() - 1, jw_top + 4,
519                                 l - left_border(), h - bottom_border(), low,
520                                 med, hi);
521 
522           else
523             screen->line (left_border() - 1, jw_top + 4, right_border() - 1,
524                            jw_top + 4, low);
525         }
526       screen->rectangle (1, 1, 4, 4, wm->black ());
527       screen->widget_bar (2, 2, 3, 3, hi, med, low);   // draws the 'close' button
528     }
529   if (_name && _name[0])
530     {
531       screen->bar (top_border(), 1,
532                     top_border() + fnt->width() * strlen (_name) + 1,
533                     top_border() - 2, med);
534       fnt->put_string (screen, top_border() + 1, 1, _name, low);
535     }
536   screen->bar (x1 (), y1 (), x2 (), y2 (), backg);  // clear 'client' region
537   inm->redraw ();
538 }
539 
left_border()540 int Jwindow::left_border()
541 {
542     return frame_left();
543 }
544 
right_border()545 int Jwindow::right_border()
546 {
547     return frame_right();
548 }
549 
top_border()550 int Jwindow::top_border()
551 {
552     return wm->font()->height() + frame_top();
553 }
554 
bottom_border()555 int Jwindow::bottom_border()
556 {
557     return frame_bottom();
558 }
559 
560 
unlink(int id)561 ifield *InputManager::unlink(int id)     // unlinks ID from fields list and return the pointer to it
562 {
563   for (ifield *i=first,*last=NULL; i; i=i->next)
564   {
565     if (i->id==id)
566     {
567       if (i==first)
568     first=first->next;
569       else
570         last->next=i->next;
571       if (active==i)
572         active=first;
573       return i;
574     }
575     ifield *x=i->unlink(id);
576     if (x) return x;
577     last=i;
578   }
579   return NULL;   // no such id
580 }
581 
~InputManager()582 InputManager::~InputManager()
583 { ifield *i;
584   while (first)
585   { i=first;
586     first=first->next;
587     delete i;
588   }
589 }
590 
clear_current()591 void InputManager::clear_current()
592 {
593     if(owner)
594         screen = owner->screen;
595     if(active)
596         active->draw(0, screen);
597     active = NULL;
598 }
599 
handle_event(event & ev,Jwindow * j)600 void InputManager::handle_event(event &ev, Jwindow *j)
601 {
602   ifield *i,*in_area=NULL;
603   int x1,y1,x2,y2;
604 
605   if(owner)
606       screen = owner->screen;
607 
608   if (j)
609   {
610     ev.mouse_move.x-=j->x;
611     ev.mouse_move.y-=j->y;
612     cur=j;
613   }
614 
615   if (!grab)
616   {
617     if ((ev.type==EV_MOUSE_BUTTON && ev.mouse_button==1) || ev.type==EV_MOUSE_MOVE)
618     {
619       for (i=first; i; i=i->next)
620       {
621     i->area(x1,y1,x2,y2);
622     if (ev.mouse_move.x>=x1 && ev.mouse_move.y>=y1 &&
623         ev.mouse_move.x<=x2 && ev.mouse_move.y<=y2)
624         in_area=i;
625       }
626       if (in_area!=active && (no_selections_allowed || (in_area && in_area->selectable())))
627       {
628     if (active)
629           active->draw(0,screen);
630 
631     active=in_area;
632 
633     if (active)
634       active->draw(1,screen);
635       }
636     }
637     if (ev.type==EV_KEY && ev.key==JK_TAB && active)
638     {
639       active->draw(0,screen);
640       do
641       {
642     active=active->next;
643     if (!active) active=first;
644       } while (active && !active->selectable());
645       active->draw(1,screen);
646     }
647   } else active=grab;
648 
649   if (active)
650   {
651     if (ev.type!=EV_MOUSE_MOVE && ev.type!=EV_MOUSE_BUTTON)
652       active->handle_event(ev,screen,this);
653     else
654     {
655       active->area(x1,y1,x2,y2);
656       if (grab || (ev.mouse_move.x>=x1 && ev.mouse_move.y>=y1 &&
657           ev.mouse_move.x<=x2 && ev.mouse_move.y<=y2))
658       {
659     if (j)
660       active->handle_event(ev,screen,j->inm);
661     else active->handle_event(ev,screen,this);
662       }
663     }
664   }
665 
666   if (j)
667   {
668     ev.mouse_move.x+=j->x;
669     ev.mouse_move.y+=j->y;
670   }
671 }
672 
allow_no_selections()673 void InputManager::allow_no_selections()
674 {
675   no_selections_allowed=1;
676 }
677 
redraw()678 void InputManager::redraw()
679 {
680     ifield *i;
681     if(owner)
682         screen = owner->screen;
683     for(i = first; i; i = i->next)
684         i->draw_first(screen);
685     if(active)
686         active->draw(1, screen);
687 }
688 
InputManager(image * Screen,ifield * First)689 InputManager::InputManager(image *Screen, ifield *First)
690 {
691     no_selections_allowed = 0;
692     cur = NULL;
693     grab = NULL;
694     owner = NULL;
695     screen = Screen;
696     active = first = First;
697     while(active && !active->selectable())
698         active = active->next;
699     if(screen)
700         redraw();
701 }
702 
InputManager(Jwindow * Owner,ifield * First)703 InputManager::InputManager(Jwindow *Owner, ifield *First)
704 {
705     no_selections_allowed = 0;
706     cur = NULL;
707     grab = NULL;
708     owner = Owner;
709     screen = NULL;
710     active = first = First;
711     while(active && !active->selectable())
712         active = active->next;
713 }
714 
grab_focus(ifield * i)715 void InputManager::grab_focus(ifield *i)
716 { grab=i;
717   if (cur)
718     wm->grab_focus(cur);
719 }
720 
release_focus()721 void InputManager::release_focus()
722 { grab=NULL;
723   if (cur)
724     wm->release_focus();
725 }
726 
remap(Filter * f)727 void InputManager::remap(Filter *f)
728 {
729   for (ifield *i=first; i; i=i->next)
730    i->remap(f);
731   redraw();
732 }
733 
add(ifield * i)734 void InputManager::add(ifield *i)
735 { ifield *f=first;
736   if (i->selectable())
737   {
738     if (!f)
739       first=i;
740     else
741     {
742       while (f->next) f=f->next;
743       f->next=i;
744     }
745   }
746 }
747 
get(int id)748 ifield *InputManager::get(int id)
749 {
750   ifield *f;
751   for (f=first; f; f=f->next)
752   {
753     ifield *ret=f->find(id);
754     if (ret) return ret;
755   }
756   return NULL;
757 }
758 
ifield()759 ifield::ifield()
760 {
761     owner = NULL;
762     x = 0;
763     y = 0;
764     next = NULL;
765     id = 0;
766 }
767 
~ifield()768 ifield::~ifield()
769 {
770     ;
771 }
772 
773 /* re-position the control with respect to the "client" area of the window */
set_owner(Jwindow * newowner)774 void ifield::set_owner(Jwindow * newowner)
775 {
776     if(owner)
777         move(x - owner->x1(), y - owner->y1());
778     owner = newowner;
779     if(owner)
780         move(x + owner->x1(), y + owner->y1());
781 }
782 
783