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