source: abuse/trunk/src/imlib/jwindow.cpp @ 129

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