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

Last change on this file since 512 was 512, checked in by Sam Hocevar, 7 years ago

imlib: use vec2i for image::size and unroll all necessary changes
everywhere else in the code.

File size: 10.1 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  short cx1,cy1,cx2,cy2;
30  screen->get_clip(cx1,cy1,cx2,cy2);
31  if (cx1<X) cx1=X;
32  int w = cx2 - cx1 - Jwindow::left_border() - Jwindow::right_border() + 1;
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  short cx1,cy1,cx2,cy2;
148  screen->get_clip(cx1,cy1,cx2,cy2);
149  if (w+x>cx2)
150    x=cx2-w;
151
152
153  if (win)
154  {
155    if (active!=-1)
156    {
157      int w,h;
158      calc_size(w,h);
159      item_num(active)->draw(win,x+3,y+3+active*(wm->font()->height()+1),w-6,0,0);
160    }
161    wm->close_window(win);
162    win=NULL;
163  }
164}
165
166void psub_menu::calc_size(int &w, int &h)
167{
168  int tw=wm->font()->width(),th=wm->font()->height();
169  w=h=0;
170  for (pmenu_item *p=first; p; p=p->next)
171  {
172    if (p->name())
173    {
174      int l=strlen(p->name())*tw+8;
175      if (p->on_off) l+=tw*4;
176      if (l>w) w=l;
177    }
178    h++;
179  }
180  h=h*(th+1)+8;
181}
182
183void psub_menu::draw(Jwindow *parent, int x, int y)
184{
185  if (win) wm->close_window(win);
186
187  int w,h,i=0;
188  calc_size(w,h);
189  short cx1,cy1,cx2,cy2;
190  screen->get_clip(cx1,cy1,cx2,cy2);
191  if (parent->x+w+x>cx2)
192    x=cx2-w-parent->x;
193  if (h+y+parent->y>cy2)
194  {
195    if (parent->y+parent->h+wm->font()->height()>cy2)
196      y=-h;
197    else y=y-h+wm->font()->height()+5;
198  }
199
200
201  win=wm->new_window(parent->x+x,parent->y+y,
202             w - Jwindow::left_border() - Jwindow::right_border(),
203             h - Jwindow::top_border() - Jwindow::bottom_border(),
204                     NULL);
205  win->freeze();
206  win->screen->widget_bar(0,0,w-1,h-1,wm->bright_color(),wm->medium_color(),wm->dark_color());
207
208  int has_flags=0;
209  pmenu_item *p=first;
210  for (; p; p=p->next) if (p->on_off) has_flags=1;
211  x=has_flags ? 3+wm->font()->width() : 3;
212  y=3;
213
214  for (p=first; p; p=p->next,i++,y+=wm->font()->height()+1)
215    p->draw(win,x,y,w-6,0,i==active);
216
217}
218
219void pmenu_item::draw_self(Jwindow *parent, int x, int y, int w, int top, int active)
220{
221  int bx=x;
222  if (on_off) bx=x-wm->font()->width();
223
224  if (!n)
225  {
226    int h=wm->font()->height();
227    parent->screen->widget_bar(x,y+h/2-1,x+w-1,y+h/2,wm->dark_color(),wm->medium_color(),wm->bright_color());
228  } else
229  {
230    if (active)
231    {
232      if (xp!=-1)
233        parent->screen->xor_bar(bx,y,x+w-1,y+wm->font()->height()+1,wm->dark_color());
234      else
235      {
236    parent->screen->bar(bx,y,x+w-1,y+wm->font()->height()+1,wm->dark_color());
237    wm->font()->put_string(parent->screen,x+1,y+1,n,wm->medium_color());
238    if (on_off && *on_off) wm->font()->put_string(parent->screen,bx+1,y+1,"*",wm->medium_color());
239      }
240    } else
241    {
242      if (xp!=-1)
243        parent->screen->xor_bar(bx,y,x+w-1,y+wm->font()->height()+1,wm->dark_color());
244      else
245      {
246    parent->screen->bar(bx,y,x+w-1,y+wm->font()->height()+1,wm->medium_color());
247    wm->font()->put_string(parent->screen,x+1,y+1,n,wm->bright_color());
248    if (on_off && *on_off) wm->font()->put_string(parent->screen,bx+1,y+1,"*",wm->bright_color());
249      }
250    }
251  }
252}
253
254void pmenu_item::draw(Jwindow *parent, int x, int y, int w, int top,
255              int active)
256{
257  if (n)
258  {
259    if (active)
260    {
261      draw_self(parent,x,y,w,top,active);
262      if (sub)
263      {
264    if (top)
265          sub->draw(parent,x,y+wm->font()->height()+2);
266    else
267      sub->draw(parent,x+w,y);
268      }
269    }
270    else
271    {
272      if (sub)
273      {
274    if (top)
275          sub->hide(parent,x,y+wm->font()->height()+2);
276    else
277      sub->hide(parent,x+w,y);
278      }
279      draw_self(parent,x,y,w,top,active);
280
281    }
282
283  } else draw_self(parent,x,y,w,top,active);
284}
285
286int pmenu::itemx(pmenu_item *p)
287{
288  if (p->xp!=-1) return p->xp;
289  int w=bar->screen->Size().x;
290
291
292  int total=0,tw,i=0,x=0;
293  for (pmenu_item *pp=top; pp; pp=pp->next,i++)
294  { if (pp==p) x=i;
295    total++;
296  }
297
298
299  tw=w/(total+1);
300  return tw/2+x*tw;
301}
302
303
304void pmenu::draw(image *screen, int top_only)
305{
306
307}
308
309
310int psub_menu::handle_event(Jwindow *parent, int x, int y, event &ev)
311{
312  int w,h;
313  calc_size(w,h);
314  short cx1,cy1,cx2,cy2;
315  screen->get_clip(cx1,cy1,cx2,cy2);
316
317  x=win->x;
318  y=win->y;
319
320  int has_flags=0,dx=3;
321  for (pmenu_item *p=first; p; p=p->next) if (p->on_off) has_flags=1;
322  if (has_flags) dx+=wm->font()->width();
323
324  int th=wm->font()->height();
325  if (ev.mouse_move.x>=x && ev.mouse_move.y>=y && ev.mouse_move.x<x+w && ev.mouse_move.y<y+h)
326  {
327    int new_active=(ev.mouse_move.y-y-3)/(th+1);
328    if (item_num(new_active)==NULL) new_active=-1;
329
330    if (new_active!=active)
331    {
332      if (active!=-1)
333        item_num(active)->draw(win,dx,3+active*(th+1),w-6,0,0);
334      active=new_active;
335      if (active!=-1)
336        item_num(active)->draw(win,dx,3+active*(th+1),w-6,0,1);
337    }
338    if (ev.type==EV_MOUSE_BUTTON)
339    {
340      if (active!=-1)
341        return item_num(active)->handle_event(win,dx,3+active*(th+1),w-6,0,ev);
342      else return 0;
343    } else return 1;
344  } else if (active!=-1)
345    return item_num(active)->handle_event(win,win->x+dx,win->y+3+active*(th+1),w-6,0,ev);
346  else return 0;
347
348
349}
350
351int pmenu_item::handle_event(Jwindow *parent, int x, int y, int w, int top,
352                 event &ev)
353{
354  x+=parent->x;
355  y+=parent->y;
356  if (ev.mouse_move.x>=x && ev.mouse_move.y>=y && ev.mouse_move.x<x+w &&
357      ev.mouse_move.y<y+wm->font()->height()+2)
358  {
359    if (sub) return 1;
360    else
361    {
362      if (ev.type==EV_MOUSE_BUTTON &&n)
363        wm->push_event(new event(id,(char *)this));
364      return 1;
365    }
366  } else if (sub)
367  {
368    if (top)
369      return sub->handle_event(parent,x,y+wm->font()->height()+2,ev);
370    else return sub->handle_event(parent,x+w,y,ev);
371  } else return 0;
372}
373
374pmenu_item *pmenu::inarea(int mx, int my, image *screen)
375{
376  short cx1,cy1,cx2,cy2;
377  screen->get_clip(cx1,cy1,cx2,cy2);
378  mx-=bar->x;
379  my-=bar->y;
380  if (mx<0 || my<0 || mx>=bar->screen->Size().x || my>=bar->screen->Size().y) return NULL;
381  else
382  {
383    for (pmenu_item *p=top; p; p=p->next)
384    {
385      if (!p->next) return p;
386      else if (itemx(p->next)>mx) return p;
387    }
388    return NULL;
389  }
390}
391
392int psub_menu::own_event(event &ev)
393{
394  if (win && ev.window==win) return 1; else
395    for (pmenu_item *p=first; p; p=p->next)
396      if (p->own_event(ev))
397        return 1;
398  return 0;
399}
400
401int pmenu_item::own_event(event &ev)
402{
403  if (sub)
404    return sub->own_event(ev);
405  else return 0;
406}
407
408pmenu_item::~pmenu_item()
409{ if (n) free(n); if (sub) delete sub;
410}
411
412int pmenu::handle_event(event &ev, image *screen)
413{
414  if (!active && ev.window!=bar) return 0;
415/*
416    int yes=0;
417    if (ev.window==bar) yes=1;    // event in top bar?
418    else
419    {
420      for (pmenu_item *p=top; p && !yes; p=p->next)  // event in submenu?
421      if (p->own_event(ev)) yes=1;
422    }
423    if (!yes) return 0;        // event is not for us...
424  }*/
425
426  switch (ev.type)
427  {
428    case EV_KEY :
429    {
430      for (pmenu_item *p=top; p; p=p->next)
431      {
432    pmenu_item *r=p->find_key(ev.key);
433    if (r)
434    {
435      wm->push_event(new event(r->id,(char *)r));
436      return 1;
437    }
438      }
439      return 0;
440    } break;
441    case EV_MOUSE_MOVE :
442    {
443      pmenu_item *new_selection=inarea(ev.mouse_move.x,ev.mouse_move.y,screen);
444      if (!new_selection && active &&
445      active->handle_event(bar,itemx(active),1,itemw(active),1,ev))
446    return 1;
447      else if (active!=new_selection)
448      {
449    if (active)
450      active->draw(bar,itemx(active),1,itemw(active),1,0);
451    active=new_selection;
452    if (active)
453      active->draw(bar,itemx(active),1,itemw(active),1,1);
454      }
455      if (active) return 1;
456      else return 0;
457    } break;
458    case EV_MOUSE_BUTTON :
459    {
460      if (active)
461      {
462        if (active->handle_event(bar,itemx(active),1,itemw(active),1,ev))
463    {
464      active->draw(bar,itemx(active),1,itemw(active),1,0);
465      active=NULL;
466      return 1;
467    } else return 0;
468      }
469      else return 0;
470    } break;
471  }
472  return 0;
473}
474
475
Note: See TracBrowser for help on using the repository browser.