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

Last change on this file since 655 was 655, checked in by Sam Hocevar, 12 years ago

imlib: refactor a few image methods so that they use vec2i.

File size: 18.4 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->x<=x2 && f->y<=y2 && f->x+f->l-1>=x1 && f->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->x, p->y, p->x + p->l, p->y + 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->x - k->x, j->y - k->y,
96                                  j->x + j->l - k->x, j->y + j->h - k->y);
97        k->m_surf->AddDirty(j->x - k->x, j->y - k->y,
98                              j->x + j->l - k->x, j->y + j->h - k->y);
99        k->next = j->next;
100    }
101    m_surf->AddDirty(j->x, j->y, j->x + j->l, j->y + 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(0, 0, 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.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 && 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.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 (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(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 (Jwindow *j = m_first; j; j = j->next)
216       j->m_surf->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    m_surf->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
224void Jwindow::resize(int L, int H)
225{
226  m_surf->SetSize(vec2i(L,H));
227  l=L; h=H;
228}
229
230void WindowManager::resize_window(Jwindow *j, int l, int h)
231{
232  Jwindow *p;
233  m_surf->AddDirty(j->x, j->y, j->x + j->l, j->y + j->h);
234  for (p=m_first; p!=j; p=p->next)
235    p->m_surf->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
241void WindowManager::move_window(Jwindow *j, int x, int y)
242{
243    m_surf->AddDirty(j->x, j->y, j->x + j->l, j->y + j->h);
244    for(Jwindow *p = m_first; p != j; p = p->next)
245        p->m_surf->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->m_surf->AddDirty(0, 0, j->l, j->h);
250}
251
252WindowManager::WindowManager(image *screen, palette *pal, int Hi,
253                             int Med, int Low, JCFont *Font)
254  : EventHandler(screen, pal)
255{
256    wm = this;
257    m_surf = screen;
258    hi = Hi; low = Low; med = Med; m_first = NULL; m_pal = pal; m_grab = NULL;
259    bk = pal->find_closest(0, 0, 0);
260    state = inputing; fnt = Font;  wframe_fnt = Font;
261    memset(key_state, 0, sizeof(key_state));
262    frame_suppress = 0;
263}
264
265WindowManager::~WindowManager()
266{
267    while(m_first)
268        close_window(m_first);
269    wm = NULL;
270}
271
272void WindowManager::add_window(Jwindow *win)
273{
274    if(!m_first)
275        m_first = win;
276    else
277    {
278        Jwindow *tmp = m_first;
279        while(tmp->next)
280            tmp = tmp->next;
281        tmp->next = win;
282        win->next = NULL;
283    }
284}
285
286void WindowManager::remove_window(Jwindow *win)
287{
288    if(m_grab == win)
289        m_grab = NULL;
290
291    // close the window we were dragging
292    if(state == dragging && win == drag_window)
293        state = inputing;
294
295    if(m_first == win)
296        m_first = m_first->next;
297    else
298    {
299        Jwindow * search;
300        for(search = m_first; search->next != win; search = search->next)
301            search->m_surf->AddDirty(win->x - search->x,
302                                       win->y - search->y,
303                                       win->x + win->l - search->x,
304                                       win->y + win->h - search->y);
305        search->m_surf->AddDirty(win->x - search->x, win->y - search->y,
306                                   win->x + win->l - search->x,
307                                   win->y + win->h - search->y);
308        search->next = win->next;
309    }
310
311    m_surf->AddDirty(win->x, win->y, win->x + win->l, win->y + win->h);
312}
313
314Jwindow * WindowManager::new_window(int x, int y, int l, int h,
315                                     ifield * fields, char const *name)
316{
317    if(x > m_surf->Size().x - 4)
318        x = m_surf->Size().x - 25;
319    if(y > m_surf->Size().y - 4)
320        y = m_surf->Size().y - 10;
321
322    Jwindow * j = new Jwindow (x, y, l, h, fields, name);
323    j->show();
324
325    return j;
326}
327
328void WindowManager::flush_screen()
329{
330    int mx = 0, my = 0;
331
332    if (has_mouse())
333    {
334        mx = (m_pos - m_center).x;
335        my = (m_pos - m_center).y;
336
337        m_sprite->save->PutPart(m_surf, 0, 0, mx, my,
338                                mx + m_sprite->visual->Size().x - 1,
339                                my + m_sprite->visual->Size().y - 1);
340        m_surf->PutImage(m_sprite->visual, vec2i(mx, my), 1);
341    }
342
343    for (Jwindow *p = m_first; p; p = p->next)
344        if (!p->is_hidden())
345            m_surf->delete_dirty(p->x, p->y, p->x + p->l, p->y + p->h);
346    update_dirty(m_surf);
347
348    if (has_mouse())
349        m_surf->PutImage(m_sprite->save, vec2i(mx, my));
350
351    for (Jwindow *p = m_first; p; p = p->next)
352    {
353        if (p->is_hidden())
354            continue;
355
356        if (has_mouse())
357        {
358            m_sprite->save->PutPart(p->m_surf, 0, 0, mx - p->x, my - p->y,
359                                    mx - p->x + m_sprite->visual->Size().x - 1,
360                                    my - p->y + m_sprite->visual->Size().y - 1);
361            p->m_surf->PutImage(m_sprite->visual,
362                                vec2i(mx - p->x, my - p->y), 1);
363        }
364
365//          m_surf->delete_dirty(p->x, p->y, p->x+p->l, p->y+p->h);
366        for (Jwindow *q = p->next; q; q = q->next)
367            if (!q->is_hidden())
368                p->m_surf->delete_dirty(q->x - p->x, q->y - p->y,
369                                        q->x + q->l - p->x,
370                                        q->y + q->h - p->y);
371        update_dirty(p->m_surf, p->x, p->y);
372        if (has_mouse())
373            p->m_surf->PutImage(m_sprite->save, vec2i(mx - p->x, my - p->y), 0);
374    }
375}
376
377Jwindow::Jwindow(char const *name)
378{
379    _x1 = left_border();
380    _y1 = jw_top + 5;
381    _x2 = _y2 = 0;
382
383    _hidden = true;
384    _moveable = true;
385    // property.flags = JWINDOW_NOAUTOHIDE_FLAG;
386
387    inm = new InputManager(this, NULL);
388    reconfigure();
389
390    m_surf = NULL;
391    next = NULL;
392
393    _name = NULL;
394    if(name)
395        _name = strdup(name);
396    wm->add_window(this);
397}
398
399Jwindow::Jwindow(int X, int Y, int L, int H, ifield *f, char const *name)
400{
401    l = 0;
402    h = 0;
403    _hidden = false;
404    _moveable = true;
405
406    _x1 = left_border();
407    _y1 = name ? top_border() : jw_top + 5;
408
409    m_surf = NULL;
410    inm = new InputManager(m_surf, f);
411    reconfigure(); /* FIXME: TODO */
412
413    l = L >= 0 ? L + left_border() : l - L;
414    h = H >= 0 ? H + top_border() : h - H;
415    y = Y >= 0 ? Y : yres - h + Y - top_border() - bottom_border() - 1;
416    x = X >= 0 ? X : xres - l + X - left_border() - right_border() - 1;
417
418    backg = wm->medium_color();
419
420    _x2 = l - 1;
421    _y2 = h - 1;
422    l += right_border();
423    h += bottom_border();
424
425    if(L == -1)
426        if(l < 15 + left_border() + right_border())
427            l = 15 + left_border() + right_border();
428    if(H == -1)
429        if(h < top_border() + bottom_border())
430            h = top_border() + bottom_border();
431    m_surf = new image(vec2i(l, h), NULL, 2);
432    m_surf->clear(backg);
433    // Keep this from getting destroyed when image list is cleared
434    image_list.unlink(m_surf);
435    inm->m_surf = m_surf;
436
437    next = NULL;
438
439    _name = NULL;
440    if(name)
441        _name = strdup(name);
442
443    wm->add_window(this);
444    if(!wm->frame_suppress)
445        redraw();
446}
447
448Jwindow::~Jwindow()
449{
450    wm->remove_window(this);
451    local_close();
452    delete m_surf;
453    delete inm;
454    if(_name)
455        free(_name);
456}
457
458void Jwindow::reconfigure()
459{
460    int x1, y1, x2, y2;
461    ifield *i;
462    l = 2;
463    h = 2;
464    for(i = inm->m_first; i; i = i->next)
465    {
466        i->set_owner(this);
467        i->area(x1, y1, x2, y2);
468        if ((int)y2 > (int)h)
469            h = y2;
470        if ((int)x2 > (int)l)
471            l = x2;
472    }
473}
474
475void Jwindow::local_close()
476{
477    ;
478}
479
480void Jwindow::redraw()
481{
482    int hi = wm->bright_color();
483    int med = wm->medium_color();
484    int low = wm->dark_color();
485    JCFont * fnt = wm->frame_font();
486
487    if(_name)
488    {
489        if (right_border() >= 1)
490        {
491            m_surf->WidgetBar(vec2i(0, 0), vec2i(l - 1, h - 1), hi, med, low);
492            if (right_border() >= 3)
493                m_surf->WidgetBar(vec2i(right_border() - 1, top_border() - 1),
494                                  vec2i(l - left_border(), h - bottom_border()),
495                                  low, med, hi);
496
497          else
498            m_surf->Line(vec2i(left_border() - 1, top_border() - 1),
499                         vec2i(right_border() - 1, top_border() - 1), low);
500        }
501      m_surf->Rectangle(vec2i(2, 2), vec2i(top_border() - 2, top_border() - 3),
502                        wm->black());
503      m_surf->WidgetBar(vec2i(3, 3), vec2i(top_border() - 3, top_border() - 4),
504                        hi, med, low); // draws the 'close' button
505    }
506
507  else
508    {
509      if (right_border() >= 1)
510        {
511          m_surf->WidgetBar(vec2i(0, 0), vec2i(l - 1, h - 1), hi, med, low);
512          if (right_border() >= 3)
513            m_surf->WidgetBar(vec2i(right_border() - 1, jw_top + 4),
514                              vec2i(l - left_border(), h - bottom_border()),
515                              low, med, hi);
516          else
517            m_surf->Line(vec2i(left_border() - 1, jw_top + 4),
518                         vec2i(right_border() - 1, jw_top + 4), low);
519        }
520      // Draw the 'close' button
521      m_surf->Rectangle(vec2i(1, 1), vec2i(4, 4), wm->black ());
522      m_surf->WidgetBar(vec2i(2, 2), vec2i(3, 3), hi, med, low);
523    }
524  if (_name && _name[0])
525    {
526      m_surf->Bar(vec2i(top_border(), 1),
527                  vec2i(top_border() + fnt->width() * strlen (_name) + 1,
528                        top_border() - 2),
529                  med);
530      fnt->put_string(m_surf, top_border() + 1, 1, _name, low);
531    }
532  // clear 'client' region
533  m_surf->Bar(vec2i(x1(), y1()), vec2i(x2(), y2()), backg);
534  inm->redraw ();
535}
536
537int Jwindow::left_border()
538{
539    return frame_left();
540}
541
542int Jwindow::right_border()
543{
544    return frame_right();
545}
546
547int Jwindow::top_border()
548{
549    return wm->font()->height() + frame_top();
550}
551
552int Jwindow::bottom_border()
553{
554    return frame_bottom();
555}
556
557
558ifield *InputManager::unlink(int id)     // unlinks ID from fields list and return the pointer to it
559{
560  for (ifield *i=m_first,*last=NULL; i; i=i->next)
561  {
562    if (i->id==id)
563    {
564      if (i==m_first)
565    m_first=m_first->next;
566      else
567        last->next=i->next;
568      if (m_active==i)
569        m_active=m_first;
570      return i;
571    }
572    ifield *x=i->unlink(id);
573    if (x) return x;
574    last=i;
575  }
576  return NULL;   // no such id
577}
578
579InputManager::~InputManager()
580{ ifield *i;
581  while (m_first)
582  { i=m_first;
583    m_first=m_first->next;
584    delete i;
585  }
586}
587
588void InputManager::clear_current()
589{
590    if(m_owner)
591        m_surf = m_owner->m_surf;
592    if(m_active)
593        m_active->draw(0, m_surf);
594    m_active = NULL;
595}
596
597void InputManager::handle_event(Event &ev, Jwindow *j)
598{
599  ifield *i,*in_area=NULL;
600  int x1,y1,x2,y2;
601
602  if(m_owner)
603      m_surf = m_owner->m_surf;
604
605  if (j)
606  {
607    ev.mouse_move.x-=j->x;
608    ev.mouse_move.y-=j->y;
609    m_cur=j;
610  }
611
612  if (!m_grab)
613  {
614    if ((ev.type==EV_MOUSE_BUTTON && ev.mouse_button==1) || ev.type==EV_MOUSE_MOVE)
615    {
616      for (i=m_first; i; i=i->next)
617      {
618    i->area(x1,y1,x2,y2);
619    if (ev.mouse_move.x>=x1 && ev.mouse_move.y>=y1 &&
620        ev.mouse_move.x<=x2 && ev.mouse_move.y<=y2)
621        in_area=i;
622      }
623      if (in_area!=m_active && (no_selections_allowed || (in_area && in_area->selectable())))
624      {
625    if (m_active)
626          m_active->draw(0,m_surf);
627
628    m_active=in_area;
629
630    if (m_active)
631      m_active->draw(1,m_surf);
632      }
633    }
634    if (ev.type==EV_KEY && ev.key==JK_TAB && m_active)
635    {
636      m_active->draw(0,m_surf);
637      do
638      {
639    m_active=m_active->next;
640    if (!m_active) m_active=m_first;
641      } while (m_active && !m_active->selectable());
642      m_active->draw(1,m_surf);
643    }
644  } else m_active=m_grab;
645
646  if (m_active)
647  {
648    if (ev.type!=EV_MOUSE_MOVE && ev.type!=EV_MOUSE_BUTTON)
649      m_active->handle_event(ev,m_surf,this);
650    else
651    {
652      m_active->area(x1,y1,x2,y2);
653      if (m_grab || (ev.mouse_move.x>=x1 && ev.mouse_move.y>=y1 &&
654          ev.mouse_move.x<=x2 && ev.mouse_move.y<=y2))
655      {
656    if (j)
657      m_active->handle_event(ev,m_surf,j->inm);
658    else m_active->handle_event(ev,m_surf,this);
659      }
660    }
661  }
662
663  if (j)
664  {
665    ev.mouse_move.x+=j->x;
666    ev.mouse_move.y+=j->y;
667  }
668}
669
670void InputManager::allow_no_selections()
671{
672    no_selections_allowed=1;
673}
674
675void InputManager::redraw()
676{
677    ifield *i;
678    if(m_owner)
679        m_surf = m_owner->m_surf;
680    for(i = m_first; i; i = i->next)
681        i->draw_first(m_surf);
682    if(m_active)
683        m_active->draw(1, m_surf);
684}
685
686InputManager::InputManager(image *screen, ifield *first)
687{
688    no_selections_allowed = 0;
689    m_cur = NULL;
690    m_grab = NULL;
691    m_owner = NULL;
692    m_surf = screen;
693    m_active = m_first = first;
694    while(m_active && !m_active->selectable())
695        m_active = m_active->next;
696    if(m_surf)
697        redraw();
698}
699
700InputManager::InputManager(Jwindow *owner, ifield *first)
701{
702    no_selections_allowed = 0;
703    m_cur = NULL;
704    m_grab = NULL;
705    m_owner = owner;
706    m_surf = NULL;
707    m_active = m_first = first;
708    while(m_active && !m_active->selectable())
709        m_active = m_active->next;
710}
711
712void InputManager::grab_focus(ifield *i)
713{
714    m_grab = i;
715    if (m_cur)
716        wm->grab_focus(m_cur);
717}
718
719void InputManager::release_focus()
720{
721    m_grab = NULL;
722    if (m_cur)
723        wm->release_focus();
724}
725
726void InputManager::remap(Filter *f)
727{
728    for (ifield *i = m_first; i; i = i->next)
729        i->remap(f);
730    redraw();
731}
732
733void InputManager::add(ifield *i)
734{ ifield *f=m_first;
735  if (i->selectable())
736  {
737    if (!f)
738      m_first=i;
739    else
740    {
741      while (f->next) f=f->next;
742      f->next=i;
743    }
744  }
745}
746
747ifield *InputManager::get(int id)
748{
749  ifield *f;
750  for (f=m_first; f; f=f->next)
751  {
752    ifield *ret=f->find(id);
753    if (ret) return ret;
754  }
755  return NULL;
756}
757
758ifield::ifield()
759{
760    owner = NULL;
761    x = 0;
762    y = 0;
763    next = NULL;
764    id = 0;
765}
766
767ifield::~ifield()
768{
769    ;
770}
771
772/* re-position the control with respect to the "client" area of the window */
773void ifield::set_owner(Jwindow * newowner)
774{
775    if(owner)
776        move(x - owner->x1(), y - owner->y1());
777    owner = newowner;
778    if(owner)
779        move(x + owner->x1(), y + owner->y1());
780}
781
Note: See TracBrowser for help on using the repository browser.