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

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