source: abuse/trunk/src/imlib/pmenu.cpp @ 521

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

imlib: refactor dirty_rect clipping coordiantes so that the upper
bound is no longer inclusive. It will make things easier in the future.

File size: 10.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 or
8 *  Jonathan Clark.
9 */
10
11#include "config.h"
12
13#include <string.h>
14
15#include "common.h"
16
17#include "pmenu.h"
18
19void pmenu::move(int new_x, int new_y)
20{
21  wm->move_window(bar,new_x,new_y);
22}
23
24pmenu::pmenu(int X, int Y, pmenu_item *first, image *screen)
25{
26  top=first;
27  active=NULL;
28
29  int cx1, cy1, cx2, cy2;
30  screen->GetClip(cx1, cy1, cx2, cy2);
31  if (cx1<X) cx1=X;
32  int w = cx2 - cx1 - Jwindow::left_border() - Jwindow::right_border();
33  int h = Jwindow::top_border() + Jwindow::bottom_border();
34
35  bar=wm->new_window(X, Y, w, 0, NULL);
36  bar->freeze();  // can't drag this window
37  bar->screen->widget_bar(0,0,w-1,h-1,wm->bright_color(),wm->medium_color(),
38            wm->dark_color());
39
40
41
42  int total=0,tx,tw;
43  pmenu_item *p=top;
44  for (; p; p=p->next) total++;
45
46  tw=w/(total+1);
47  tx=tw/2;
48
49  for (p=top; p; p=p->next,tx+=tw)
50    p->draw_self(bar,itemx(p),1,itemw(p),1,p==active);
51/*  }
52  else
53  {
54    for (p=top; p; p=p->next,tx+=tw)
55      p->draw(bar,itemx(p),1,itemw(p),1,p==active);
56  }*/
57
58}
59
60pmenu_item::pmenu_item(int ID, char const *Name, char const *on_off_flag, int Hotkey, pmenu_item *Next)
61{
62  xp=-1;
63  id=ID;
64  hotkey=Hotkey;
65  on_off=on_off_flag;
66  if (Name)
67    n = strdup(Name);
68  else n=NULL;
69  next=Next;
70  sub=NULL;
71}
72
73pmenu_item::pmenu_item(char const *Name, psub_menu *Sub, pmenu_item *Next, int xpos)
74{
75  xp=xpos;
76  id=0; hotkey=-1;
77  next=Next;
78  on_off=NULL;
79  CONDITION(Name,"Sub menu cannot have a NULL name");
80  n = strdup(Name);
81  sub=Sub;
82}
83
84pmenu_item *pmenu_item::find_id(int search_id)
85{
86  if (id==search_id) return this;
87  else if (sub) return sub->find_id(search_id);
88  else return NULL;
89}
90
91pmenu_item *pmenu_item::find_key(int key)
92{
93  if (key==hotkey && hotkey!=-1) return this;
94  else if (sub) return sub->find_key(key);
95  else return NULL;
96}
97
98pmenu::~pmenu()
99{
100  while (top)
101  {
102    pmenu_item *p=top;
103    top=top->next;
104    delete p;
105  }
106  if (bar) wm->close_window(bar);
107}
108
109psub_menu::~psub_menu()
110{
111  if (win)
112    wm->close_window(win);
113
114  while (first)
115  {
116    pmenu_item *tmp=first;
117    first=first->next;
118    delete tmp;
119  }
120}
121
122pmenu_item *psub_menu::find_id(int search_id)
123{
124  for (pmenu_item *f=first; f; f=f->next)
125  {
126    pmenu_item *ret=f->find_id(search_id);
127    if (ret) return ret;
128  }
129  return NULL;
130}
131
132pmenu_item *psub_menu::find_key(int key)
133{
134  for (pmenu_item *f=first; f; f=f->next)
135  {
136    pmenu_item *ret=f->find_key(key);
137    if (ret) return ret;
138  }
139  return NULL;
140}
141
142
143void psub_menu::hide(Jwindow *parent, int x, int y)
144{
145  int w,h;
146  calc_size(w,h);
147  int cx1, cy1, cx2, cy2;
148  screen->GetClip(cx1, cy1, cx2, cy2);
149  // FIXME: is this correct? it looks like it used to be incorrect
150  // before the GetClip refactoring...
151  if (w+x>cx2-1)
152    x=cx2-1-w;
153
154  if (win)
155  {
156    if (active!=-1)
157    {
158      int w,h;
159      calc_size(w,h);
160      item_num(active)->draw(win,x+3,y+3+active*(wm->font()->height()+1),w-6,0,0);
161    }
162    wm->close_window(win);
163    win=NULL;
164  }
165}
166
167void psub_menu::calc_size(int &w, int &h)
168{
169  int tw=wm->font()->width(),th=wm->font()->height();
170  w=h=0;
171  for (pmenu_item *p=first; p; p=p->next)
172  {
173    if (p->name())
174    {
175      int l=strlen(p->name())*tw+8;
176      if (p->on_off) l+=tw*4;
177      if (l>w) w=l;
178    }
179    h++;
180  }
181  h=h*(th+1)+8;
182}
183
184void psub_menu::draw(Jwindow *parent, int x, int y)
185{
186  if (win) wm->close_window(win);
187
188  int w,h,i=0;
189  calc_size(w,h);
190  int cx1, cy1, cx2, cy2;
191  screen->GetClip(cx1, cy1, cx2, cy2);
192  if (parent->x+w+x>=cx2)
193    x=cx2-1-w-parent->x;
194  if (h+y+parent->y>=cy2)
195  {
196    if (parent->y+parent->h+wm->font()->height()>=cy2)
197      y=-h;
198    else y=y-h+wm->font()->height()+5;
199  }
200
201
202  win=wm->new_window(parent->x+x,parent->y+y,
203             w - Jwindow::left_border() - Jwindow::right_border(),
204             h - Jwindow::top_border() - Jwindow::bottom_border(),
205                     NULL);
206  win->freeze();
207  win->screen->widget_bar(0,0,w-1,h-1,wm->bright_color(),wm->medium_color(),wm->dark_color());
208
209  int has_flags=0;
210  pmenu_item *p=first;
211  for (; p; p=p->next) if (p->on_off) has_flags=1;
212  x=has_flags ? 3+wm->font()->width() : 3;
213  y=3;
214
215  for (p=first; p; p=p->next,i++,y+=wm->font()->height()+1)
216    p->draw(win,x,y,w-6,0,i==active);
217
218}
219
220void pmenu_item::draw_self(Jwindow *parent, int x, int y, int w, int top, int active)
221{
222  int bx=x;
223  if (on_off) bx=x-wm->font()->width();
224
225  if (!n)
226  {
227    int h=wm->font()->height();
228    parent->screen->widget_bar(x,y+h/2-1,x+w-1,y+h/2,wm->dark_color(),wm->medium_color(),wm->bright_color());
229  } else
230  {
231    if (active)
232    {
233      if (xp!=-1)
234        parent->screen->xor_bar(bx,y,x+w-1,y+wm->font()->height()+1,wm->dark_color());
235      else
236      {
237    parent->screen->bar(bx,y,x+w-1,y+wm->font()->height()+1,wm->dark_color());
238    wm->font()->put_string(parent->screen,x+1,y+1,n,wm->medium_color());
239    if (on_off && *on_off) wm->font()->put_string(parent->screen,bx+1,y+1,"*",wm->medium_color());
240      }
241    } else
242    {
243      if (xp!=-1)
244        parent->screen->xor_bar(bx,y,x+w-1,y+wm->font()->height()+1,wm->dark_color());
245      else
246      {
247    parent->screen->bar(bx,y,x+w-1,y+wm->font()->height()+1,wm->medium_color());
248    wm->font()->put_string(parent->screen,x+1,y+1,n,wm->bright_color());
249    if (on_off && *on_off) wm->font()->put_string(parent->screen,bx+1,y+1,"*",wm->bright_color());
250      }
251    }
252  }
253}
254
255void pmenu_item::draw(Jwindow *parent, int x, int y, int w, int top,
256              int active)
257{
258  if (n)
259  {
260    if (active)
261    {
262      draw_self(parent,x,y,w,top,active);
263      if (sub)
264      {
265    if (top)
266          sub->draw(parent,x,y+wm->font()->height()+2);
267    else
268      sub->draw(parent,x+w,y);
269      }
270    }
271    else
272    {
273      if (sub)
274      {
275    if (top)
276          sub->hide(parent,x,y+wm->font()->height()+2);
277    else
278      sub->hide(parent,x+w,y);
279      }
280      draw_self(parent,x,y,w,top,active);
281
282    }
283
284  } else draw_self(parent,x,y,w,top,active);
285}
286
287int pmenu::itemx(pmenu_item *p)
288{
289  if (p->xp!=-1) return p->xp;
290  int w=bar->screen->Size().x;
291
292
293  int total=0,tw,i=0,x=0;
294  for (pmenu_item *pp=top; pp; pp=pp->next,i++)
295  { if (pp==p) x=i;
296    total++;
297  }
298
299
300  tw=w/(total+1);
301  return tw/2+x*tw;
302}
303
304
305void pmenu::draw(image *screen, int top_only)
306{
307
308}
309
310
311int psub_menu::handle_event(Jwindow *parent, int x, int y, event &ev)
312{
313  int w,h;
314  calc_size(w,h);
315  int cx1, cy1, cx2, cy2;
316  screen->GetClip(cx1, cy1, cx2, cy2);
317
318  x=win->x;
319  y=win->y;
320
321  int has_flags=0,dx=3;
322  for (pmenu_item *p=first; p; p=p->next) if (p->on_off) has_flags=1;
323  if (has_flags) dx+=wm->font()->width();
324
325  int th=wm->font()->height();
326  if (ev.mouse_move.x>=x && ev.mouse_move.y>=y && ev.mouse_move.x<x+w && ev.mouse_move.y<y+h)
327  {
328    int new_active=(ev.mouse_move.y-y-3)/(th+1);
329    if (item_num(new_active)==NULL) new_active=-1;
330
331    if (new_active!=active)
332    {
333      if (active!=-1)
334        item_num(active)->draw(win,dx,3+active*(th+1),w-6,0,0);
335      active=new_active;
336      if (active!=-1)
337        item_num(active)->draw(win,dx,3+active*(th+1),w-6,0,1);
338    }
339    if (ev.type==EV_MOUSE_BUTTON)
340    {
341      if (active!=-1)
342        return item_num(active)->handle_event(win,dx,3+active*(th+1),w-6,0,ev);
343      else return 0;
344    } else return 1;
345  } else if (active!=-1)
346    return item_num(active)->handle_event(win,win->x+dx,win->y+3+active*(th+1),w-6,0,ev);
347  else return 0;
348
349
350}
351
352int pmenu_item::handle_event(Jwindow *parent, int x, int y, int w, int top,
353                 event &ev)
354{
355  x+=parent->x;
356  y+=parent->y;
357  if (ev.mouse_move.x>=x && ev.mouse_move.y>=y && ev.mouse_move.x<x+w &&
358      ev.mouse_move.y<y+wm->font()->height()+2)
359  {
360    if (sub) return 1;
361    else
362    {
363      if (ev.type==EV_MOUSE_BUTTON &&n)
364        wm->push_event(new event(id,(char *)this));
365      return 1;
366    }
367  } else if (sub)
368  {
369    if (top)
370      return sub->handle_event(parent,x,y+wm->font()->height()+2,ev);
371    else return sub->handle_event(parent,x+w,y,ev);
372  } else return 0;
373}
374
375pmenu_item *pmenu::inarea(int mx, int my, image *screen)
376{
377  int cx1, cy1, cx2, cy2;
378  screen->GetClip(cx1, cy1, cx2, cy2);
379  mx-=bar->x;
380  my-=bar->y;
381  if (mx<0 || my<0 || mx>=bar->screen->Size().x || my>=bar->screen->Size().y) return NULL;
382  else
383  {
384    for (pmenu_item *p=top; p; p=p->next)
385    {
386      if (!p->next) return p;
387      else if (itemx(p->next)>mx) return p;
388    }
389    return NULL;
390  }
391}
392
393int psub_menu::own_event(event &ev)
394{
395  if (win && ev.window==win) return 1; else
396    for (pmenu_item *p=first; p; p=p->next)
397      if (p->own_event(ev))
398        return 1;
399  return 0;
400}
401
402int pmenu_item::own_event(event &ev)
403{
404  if (sub)
405    return sub->own_event(ev);
406  else return 0;
407}
408
409pmenu_item::~pmenu_item()
410{ if (n) free(n); if (sub) delete sub;
411}
412
413int pmenu::handle_event(event &ev, image *screen)
414{
415  if (!active && ev.window!=bar) return 0;
416/*
417    int yes=0;
418    if (ev.window==bar) yes=1;    // event in top bar?
419    else
420    {
421      for (pmenu_item *p=top; p && !yes; p=p->next)  // event in submenu?
422      if (p->own_event(ev)) yes=1;
423    }
424    if (!yes) return 0;        // event is not for us...
425  }*/
426
427  switch (ev.type)
428  {
429    case EV_KEY :
430    {
431      for (pmenu_item *p=top; p; p=p->next)
432      {
433    pmenu_item *r=p->find_key(ev.key);
434    if (r)
435    {
436      wm->push_event(new event(r->id,(char *)r));
437      return 1;
438    }
439      }
440      return 0;
441    } break;
442    case EV_MOUSE_MOVE :
443    {
444      pmenu_item *new_selection=inarea(ev.mouse_move.x,ev.mouse_move.y,screen);
445      if (!new_selection && active &&
446      active->handle_event(bar,itemx(active),1,itemw(active),1,ev))
447    return 1;
448      else if (active!=new_selection)
449      {
450    if (active)
451      active->draw(bar,itemx(active),1,itemw(active),1,0);
452    active=new_selection;
453    if (active)
454      active->draw(bar,itemx(active),1,itemw(active),1,1);
455      }
456      if (active) return 1;
457      else return 0;
458    } break;
459    case EV_MOUSE_BUTTON :
460    {
461      if (active)
462      {
463        if (active->handle_event(bar,itemx(active),1,itemw(active),1,ev))
464    {
465      active->draw(bar,itemx(active),1,itemw(active),1,0);
466      active=NULL;
467      return 1;
468    } else return 0;
469      }
470      else return 0;
471    } break;
472  }
473  return 0;
474}
475
476
Note: See TracBrowser for help on using the repository browser.