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

Last change on this file since 670 was 670, checked in by Sam Hocevar, 11 years ago

imlib: started refactoring the dirty rectangle system.

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