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

Last change on this file since 56 was 56, checked in by Sam Hocevar, 15 years ago
  • Add licensing terms to most C / C++ files (Ref #5).
File size: 15.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 "scroller.hpp"
13#define HS_ICON_W 10
14#define HS_ICON_H 8
15
16
17uint8_t hs_left_arrow[10*8]={
18    0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0,
19    0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0,
20    1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1,
21    1, 1, 1, 1, 2, 0, 1, 1, 2, 2, 2, 2, 2, 2, 2,
22    0, 0, 1, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1,
23    2, 0, 0, 0, 0};
24
25
26uint8_t hs_right_arrow[10*8]={
27    0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0,
28    0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0,
29    0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1,
30    1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 1, 1, 0,
31    0, 0, 0, 0, 0, 2, 1, 1, 0, 0, 0, 0, 0, 0, 2,
32    1, 1, 0, 0, 0};
33
34
35uint8_t vs_up_arrow[8*10]={
36    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 0,
37    0, 0, 0, 1, 1, 1, 1, 2, 0, 0, 1, 2, 1, 1, 2,
38    1, 2, 0, 0, 0, 1, 1, 2, 0, 0, 0, 0, 0, 1, 1,
39    2, 0, 0, 0, 0, 0, 1, 1, 2, 0, 0, 0, 0, 0, 1,
40    1, 2, 0, 0, 0, 0, 0, 1, 1, 2, 0, 0, 0, 0, 0,
41    0, 2, 2, 0, 0};
42
43
44uint8_t vs_down_arrow[8*10]={
45    0, 0, 0, 0, 2, 2, 0, 0, 0, 0, 0, 1, 1, 2, 0,
46    0, 0, 0, 0, 1, 1, 2, 0, 0, 0, 0, 0, 1, 1, 2,
47    0, 0, 0, 0, 0, 1, 1, 2, 0, 0, 0, 0, 0, 1, 1,
48    2, 0, 0, 0, 1, 2, 1, 1, 2, 1, 2, 0, 0, 1, 1,
49    1, 1, 2, 0, 0, 0, 0, 1, 1, 2, 0, 0, 0, 0, 0,
50    0, 0, 0, 0, 0};
51
52void show_icon(image *screen, window_manager *wm, int x, int y, int icw, int ich, uint8_t *buf)
53{
54  short cx1,cy1,cx2,cy2;
55  screen->get_clip(cx1,cy1,cx2,cy2);
56  uint8_t remap[3];
57  remap[0]=wm->medium_color();
58  remap[1]=wm->bright_color();
59  remap[2]=wm->dark_color();
60
61  for (int yc=ich;yc;yc--,y++)
62  {
63    if (y>=cy1 && y<=cy2)
64    {
65      uint8_t *sl=screen->scan_line(y)+x;
66      for (int xc=icw,xo=x;xc;xc--,xo++,sl++,buf++)
67      {
68        if (xo>=cx1 && xo<=cx2)
69          *sl=remap[*buf];
70      }
71    }
72  }
73  screen->add_dirty(x,y,x+icw-1,y+ich-1);
74}
75
76scroller::scroller(int X, int Y, int ID, int L, int H, int Vert, int Total_items, ifield *Next)
77{  x=X; y=Y; id=ID; next=Next;  l=L; h=H;  sx=0;  t=Total_items;  drag=-1; vert=Vert;
78}
79
80
81void scroller::area(int &x1, int &y1, int &x2, int &y2, window_manager *wm)
82
83  area_config(wm);
84  x1=x-1; y1=y-1; 
85  if (vert)
86  { x2=x+l+bw();  y2=y+h; }
87  else
88  { x2=x+l;  y2=y+h+bh(); }
89}
90
91void scroller::dragger_area(int &x1, int &y1, int &x2, int &y2)
92
93  if (vert)
94  { x1=x+l; y1=y+bh(); x2=x+l+bw()-1; y2=y+h-bh()-1; }
95  else { x1=x+bw(); y1=y+h; x2=x+l-bw(); y2=y+h+bh()-1; }
96}
97
98int scroller::bh() { if (vert) return 15; else return 13; }
99int scroller::bw() { if (vert) return 12; else return 14; }
100
101uint8_t *scroller::b1()
102{
103  if (vert) return vs_up_arrow;
104  else return hs_left_arrow;
105}
106
107uint8_t *scroller::b2()
108{
109  if (vert) return vs_down_arrow;
110  else return hs_right_arrow;
111}
112
113
114void scroller::draw_first(image *screen, window_manager *wm)
115{
116  if (sx>=t) sx=t-1;
117  draw(0,screen,wm);
118  screen->wiget_bar(b1x(),b1y(),b1x()+bw()-1,b1y()+bh()-1,
119                    wm->bright_color(),wm->medium_color(),wm->dark_color());
120  screen->wiget_bar(b2x(),b2y(),b2x()+bw()-1,b2y()+bh()-1,
121                    wm->bright_color(),wm->medium_color(),wm->dark_color());
122  show_icon(screen,wm,b1x()+2,b1y()+2,bw()-4,bh()-4,b1());
123  show_icon(screen,wm,b2x()+2,b2y()+2,bw()-4,bh()-4,b2());
124
125  int x1,y1,x2,y2;
126  dragger_area(x1,y1,x2,y2);
127  screen->bar(x1,y1,x2,y2,wm->black());
128  screen->bar(x1+1,y1+1,x2-1,y2-1,wm->medium_color());   
129  draw_wiget(screen,wm,0);
130  scroll_event(sx,screen,wm);
131}
132
133void scroller::wig_area(int &x1, int &y1, int &x2, int &y2)
134{
135  int sx1,sy1,sx2,sy2;
136  dragger_area(sx1,sy1,sx2,sy2);
137  if (vert)
138  {
139    x1=x+l+1;
140    if (t<2)
141      y1=y+bh()+1;
142    else
143      y1=y+bh()+1+sx*(sy2-sy1+1-bh())/(t-1);
144  } else
145  {
146    if (t<2) x1=x+bw()+1;
147    else x1=x+bw()+1+sx*(sx2-sx1+1-bw())/(t-1);
148    y1=y+h+1;
149  }
150  x2=x1+bw()-3;
151  y2=y1+bh()-3; 
152 
153}
154
155
156void scroller::draw_wiget(image *screen, window_manager *wm, int erase)
157{
158  int x1,y1,x2,y2;
159  wig_area(x1,y1,x2,y2);
160  if (erase)
161    screen->bar(x1,y1,x2,y2,wm->medium_color());
162  else
163    screen->wiget_bar(x1,y1,x2,y2,
164                      wm->bright_color(),wm->medium_color(),wm->dark_color());
165}
166
167void scroller::draw(int active, image *screen, window_manager *wm)
168{
169  int x1,y1,x2,y2;
170  area(x1,y1,x2,y2,wm);
171  screen->rectangle(x1,y1,x2,y2,active ? wm->bright_color() : wm->dark_color());
172}
173
174
175void scroller::handle_event(event &ev, image *screen, window_manager *wm, input_manager *inm)
176{
177  int mx=ev.mouse_move.x,my=ev.mouse_move.y;
178  switch (ev.type)
179  {
180    case EV_MOUSE_BUTTON :
181    {
182      if (ev.mouse_button && drag==-1)
183      {
184        if (mx>=b1x() && mx<b1x()+bw() && my>=b1y()-2 && my<b1y()+bh())
185        {
186          if (sx>0)
187          {
188            draw_wiget(screen,wm,1);
189            sx--;
190            draw_wiget(screen,wm,0);
191            scroll_event(sx,screen,wm);
192          }
193        } else if (mx>=b2x() && mx<b2x()+bw() && my>=b2y() && my<=b2y()+bh())
194        {
195          if (sx<t-1)
196          {
197            draw_wiget(screen,wm,1);
198            sx++;
199            draw_wiget(screen,wm,0);
200            scroll_event(sx,screen,wm);
201          }         
202        }
203        else
204        {
205          int dx1,dy1,dx2,dy2;
206          dragger_area(dx1,dy1,dx2,dy2);
207          if (mx>=dx1 && mx<=dx2 && my>=dy1 && my<=dy2)
208          {
209            int x1,y1,x2,y2;
210            wig_area(x1,y1,x2,y2);
211            if (mx>=x1 && mx<=x2 && my>=y1 && my<=y2)
212            {
213              drag=sx;
214              inm->grab_focus(this);
215            }         
216            else if (t>1)
217            {
218              int nx=mouse_to_drag(mx,my);
219              if (nx!=sx && nx>=0 && nx<t)
220              {
221                draw_wiget(screen,wm,1);
222                sx=nx;
223                draw_wiget(screen,wm,0);
224                scroll_event(sx,screen,wm);             
225              }         
226            }
227          } else handle_inside_event(ev,screen,wm,inm);
228        }
229      } else if (!ev.mouse_button && drag!=-1)
230      {
231        inm->release_focus();
232        drag=-1;
233      }
234    } break;
235
236    case EV_MOUSE_MOVE :
237    {
238      if (drag!=-1)
239      {
240        int nx=mouse_to_drag(mx,my);
241        if (nx<0) nx=0; else if (nx>=t) nx=t-1;
242        if (nx!=sx)
243        {
244          draw_wiget(screen,wm,1);
245          sx=nx;
246          draw_wiget(screen,wm,0);
247          scroll_event(sx,screen,wm);
248        }
249      } else if ( activate_on_mouse_move())
250      {
251        int x1,y1,x2,y2;
252        wig_area(x1,y1,x2,y2);
253        if (mx>=x && mx<=x+l-1 && my>=y && my<=y+h-1)
254          handle_inside_event(ev,screen,wm,inm);
255      }
256
257    } break;
258    case EV_KEY :
259    {
260      switch (ev.key)
261      {
262        case JK_LEFT :
263        { handle_left(screen,wm,inm); } break;
264        case JK_RIGHT :
265        { handle_right(screen,wm,inm); } break;
266        case JK_UP :
267        { handle_up(screen,wm,inm); } break;
268        case JK_DOWN :
269        { handle_down(screen,wm,inm); } break;
270
271        default :
272          handle_inside_event(ev,screen,wm,inm);
273      }
274    } break;
275  }
276}
277
278
279void scroller::handle_right(image *screen, window_manager *wm, input_manager *inm)
280{
281  if (!vert && sx<t-1)
282  {
283    draw_wiget(screen,wm,1);
284    sx++;
285    draw_wiget(screen,wm,0);
286    scroll_event(sx,screen,wm);     
287  }
288}
289
290void scroller::handle_left(image *screen, window_manager *wm, input_manager *inm)
291{
292  if (!vert && sx>1)
293  {
294    draw_wiget(screen,wm,1);
295    sx--;
296    draw_wiget(screen,wm,0);
297    scroll_event(sx,screen,wm);     
298  }
299}
300
301void scroller::handle_up(image *screen, window_manager *wm, input_manager *inm)
302{
303  if (vert && sx>1)
304  {
305    draw_wiget(screen,wm,1);
306    sx--;
307    draw_wiget(screen,wm,0);
308    scroll_event(sx,screen,wm);     
309  }
310}
311
312void scroller::handle_down(image *screen, window_manager *wm, input_manager *inm)
313{
314  if (vert && sx<t-1)
315  {
316    draw_wiget(screen,wm,1);
317    sx++;
318    draw_wiget(screen,wm,0);
319    scroll_event(sx,screen,wm);     
320  }
321}
322
323void scroller::set_x (int x, image *screen, window_manager *wm)
324{
325  if (x<0) x=0;
326  if (x>=t) x=t-1;
327  if (x!=sx)
328  {
329    draw_wiget(screen,wm,1);
330    sx=x;
331    draw_wiget(screen,wm,0);
332    scroll_event(sx,screen,wm);     
333  }
334}
335
336int scroller::mouse_to_drag(int mx,int my)
337{
338  int x1,y1,x2,y2;
339  dragger_area(x1,y1,x2,y2);
340 
341  if (vert)
342  {
343    int h=(y2-y1+1-bh());
344    if (h)
345      return (my-y-bh()-bh()/2)*(t-1)/h;
346    else return 0;
347  }
348  else
349  {
350    int w=(x2-x1+1-bw());
351    if (w)
352      return (mx-x-bw()-bw()/2)*(t-1)/w;
353    else return 0;
354  }
355}
356
357
358void scroller::scroll_event(int newx, image *screen, window_manager *wm)
359{
360  screen->bar(x,y,x+l-1,y+h-1,wm->black());
361  int xa,ya,xo=0,yo;
362  if (vert) { xa=0; ya=30; yo=x+5; yo=y+5; } else { xa=30; ya=0; xo=x+5; yo=y+5; }
363  for (int i=newx,c=0;c<30 && i<100;i++,c++)
364  {
365    char st[10];
366    sprintf(st,"%d",i);
367    wm->font()->put_string(screen,xo,yo,st,wm->bright_color());
368    xo+=xa; yo+=ya;
369  }
370}
371
372void pick_list::area_config(window_manager *wm)
373{
374  l=wid*wm->font()->width();
375  h=th*(wm->font()->height()+1); 
376}
377
378int lis_sort(void const *a, void const *b)
379{
380  pick_list_item *a1=(pick_list_item *)a;
381  pick_list_item *a2=(pick_list_item *)b;
382  return strcmp(a1->name,a2->name);
383}
384
385pick_list::pick_list(int X, int Y, int ID, int height,
386            char **List, int num_entries, int start_yoffset, ifield *Next, image *texture)
387     : scroller(X,Y,ID,2,2,1,0,Next)
388{
389  th=height;
390  tex=texture;
391  t=num_entries;
392  wid=0;
393  key_hist_total=0;
394  lis=(pick_list_item *)jmalloc(sizeof(pick_list_item)*num_entries,"pick list");
395  int i=0;
396  for (;i<num_entries;i++)
397  {
398    lis[i].name=List[i];
399    lis[i].number=i;
400  }
401  qsort((void *)lis,num_entries,sizeof(pick_list_item),lis_sort);
402
403  for (i=0;i<t;i++)
404    if ((int)strlen(List[i])>wid)
405      wid=strlen(List[i]);
406  cur_sel=sx=start_yoffset;
407}
408
409void pick_list::handle_inside_event(event &ev, image *screen, window_manager *wm, input_manager *inm)
410{
411  if (ev.type==EV_MOUSE_MOVE && activate_on_mouse_move())
412  {
413    int sel=last_sel+(ev.mouse_move.y-y)/(wm->font()->height()+1);
414    if (sel!=cur_sel && sel<t && sel>=0)
415    {
416      cur_sel=sel;
417      scroll_event(last_sel,screen,wm);
418    }   
419  }
420  else if (ev.type==EV_MOUSE_BUTTON)
421  { 
422    int sel=last_sel+(ev.mouse_move.y-y)/(wm->font()->height()+1);
423    if (sel<t && sel>=0)
424    {
425      if (sel==cur_sel)
426      wm->push_event(new event(id,(char *)this));
427      else
428      {
429        cur_sel=sel;
430        scroll_event(last_sel,screen,wm);
431      }     
432    }
433  } else if (ev.type==EV_KEY && ev.key==JK_ENTER) 
434    wm->push_event(new event(id,(char *)this));
435  else if (ev.type==EV_KEY)
436  {
437    int found=-1;
438    if (key_hist_total<20)
439      key_hist[(int)(key_hist_total++)]=ev.key;
440
441    for (int i=0;i<t && found==-1;i++)
442    {
443      if ((int)strlen(lis[i].name)>=key_hist_total && memcmp(lis[i].name,key_hist,key_hist_total)==0)
444        found=i;
445    }
446    if (found!=-1)
447    {
448      sx=found;
449      cur_sel=found;
450      scroll_event(sx,screen,wm);
451    } else key_hist_total=0;
452  }
453}
454
455void pick_list::handle_up(image *screen, window_manager *wm, input_manager *inm)
456{
457  if (cur_sel>0)
458    cur_sel--;
459  else return ;
460  if (cur_sel<sx)
461  {
462    draw_wiget(screen,wm,1);
463    sx=cur_sel;
464    draw_wiget(screen,wm,0);
465  }
466  scroll_event(sx,screen,wm);             
467}
468
469void pick_list::handle_down(image *screen, window_manager *wm, input_manager *inm)
470{
471  if (cur_sel<t-1)
472    cur_sel++;
473  else return ;
474  if (cur_sel>sx+th-1)
475  {
476    draw_wiget(screen,wm,1);
477    sx=cur_sel-th+1;
478    draw_wiget(screen,wm,0);
479  }
480  scroll_event(sx,screen,wm);             
481}
482
483void pick_list::scroll_event(int newx, image *screen, window_manager *wm)
484{
485  last_sel=newx;
486  if (tex)
487  {
488    short cx1,cy1,cx2,cy2;
489    screen->get_clip(cx1,cy1,cx2,cy2);
490    screen->set_clip(x,y,x+l-1,y+h-1);
491    int tw=(l+tex->width()-1)/tex->width();
492    int th=(h+tex->height()-1)/tex->height();
493    int dy=y;
494    for (int j=0;j<th;j++,dy+=tex->height())
495      for (int i=0,dx=x;i<tw;i++,dx+=tex->width())     
496        tex->put_image(screen,dx,dy);
497
498    screen->set_clip(cx1,cy1,cx2,cy2);
499  } else screen->bar(x,y,x+l-1,y+h-1,wm->black());
500
501  int dy=y;
502  for (int i=0;i<th;i++,dy+=wm->font()->height()+1)
503  {
504    if (i+newx==cur_sel)
505      screen->bar(x,dy,x+wid*wm->font()->width()-1,dy+wm->font()->height(),wm->dark_color());
506    if (i+newx<t)
507      wm->font()->put_string(screen,x,dy,lis[i+newx].name,wm->bright_color());
508  }
509}
510
511
512
513
514spicker::spicker(int X, int Y, int ID, int Rows, int Cols, int Vert, int MultiSelect,
515               ifield *Next)
516     : scroller(X,Y,ID,2,2,Vert,0,Next)
517{
518  l=-1;
519  last_click=-1;
520  r=Rows;
521  c=Cols;
522  m=MultiSelect;
523  select=NULL;
524}
525
526void spicker::set_select(int x, int on)
527{
528  if (m)
529  {
530    if (on)
531      select[x/8]|=1<<(x&7);
532    else
533      select[x/8]&=(0xff-(1<<(x&7)));
534  } else cur_sel=x; 
535}
536
537int spicker::get_select(int x)
538{
539  if (m)
540    return select[x/8]&(1<<(x&7));
541  else return (x==cur_sel);
542}
543
544int spicker::first_selected()
545{
546  if (m)
547  {
548    for (int i=0;i<t;i++)
549      if (get_select(i)) return i;
550    return -1;
551  } else return cur_sel;
552}
553
554void spicker::reconfigure()
555{
556  if (select)
557    jfree(select);
558  select=NULL;
559
560
561  t=total();
562  if (sx>t)
563    sx=t-1;
564  if (m)
565  {
566    select=(uint8_t *)jmalloc((t+7)/8,"selection bit array");
567    memset(select,0,(t+7)/8);
568  } else cur_sel=0;
569}
570
571void spicker::draw_background(window_manager *wm, image *screen)
572{
573  screen->bar(x,y,x+l-1,y+h-1,wm->dark_color());
574}
575
576
577void spicker::area_config(window_manager *wm)
578{
579  if (vert)
580    l=item_width(wm)+4;
581  else
582    l=item_width(wm)*c+4;
583
584  if (vert)
585    h=item_height(wm)*r+4;
586  else
587    h=item_height(wm)+4;
588
589}
590
591void spicker::set_x(int x, image *screen, window_manager *wm)
592{
593  cur_sel=x;
594  sx=x;
595  scroll_event(x,screen,wm);
596}
597
598
599void spicker::scroll_event(int newx, image *screen, window_manager *wm)
600{
601  last_sel=newx;
602  int xa,ya,xo,yo;
603  xo=x+2;
604  yo=y+2;
605  if (vert) { xa=0; ya=item_height(wm); }
606  else { xa=item_width(wm); ya=0; }
607  draw_background(wm,screen);
608
609  for (int i=newx;i<newx+vis();i++)
610  {
611    if (i<t)
612    {
613      if (m)     
614        draw_item(wm,screen,xo,yo,i,get_select(i));
615      else
616        draw_item(wm,screen,xo,yo,i,i==cur_sel);
617    }
618    xo+=xa; yo+=ya;
619  }
620}
621
622
623void spicker::handle_inside_event(event &ev, image *screen, window_manager *wm, input_manager *inm)
624{
625  switch (ev.type)
626  {
627    case EV_MOUSE_MOVE :
628    {
629      if (activate_on_mouse_move())
630      {
631        int me;     
632        if (vert)
633          me=last_sel+(ev.mouse_move.y-y)/item_height(wm);
634        else
635          me=last_sel+(ev.mouse_move.x-x)/item_width(wm);
636        if (me<t && me>=0)
637        {
638          if (cur_sel!=me)
639          {
640            cur_sel=me;
641            scroll_event(last_sel,screen,wm);
642            note_new_current(wm,screen,inm,me);
643          }
644        }
645      }
646    } break;
647    case EV_MOUSE_BUTTON :
648    {
649      int me;     
650      if (vert)
651        me=last_sel+(ev.mouse_move.y-y)/item_height(wm);
652      else
653        me=last_sel+(ev.mouse_move.x-x)/item_width(wm);
654      if (me<t && me>=0)
655      {
656        if (m)
657        {         
658          if (ev.mouse_button)
659          {
660            if (ok_to_select(me))
661            {
662              set_select(me,!get_select(me));
663              scroll_event(last_sel,screen,wm);
664              inm->grab_focus(this);
665            }
666          } else last_click=-1;
667
668        } else if (ok_to_select(me))
669        {
670          if (cur_sel==me)         
671            note_selection(wm,screen,inm,me);
672          else
673          {
674            cur_sel=me;
675            scroll_event(last_sel,screen,wm);
676            note_new_current(wm,screen,inm,me);
677          }
678        }
679      }
680    } break;
681  }
682}
683
684
685
686void spicker::handle_up(image *screen, window_manager *wm, input_manager *inm)
687{
688  if (vert && cur_sel>0)
689  {
690    cur_sel--;
691
692    if (cur_sel<sx)
693    {
694      draw_wiget(screen,wm,1);
695      last_sel=sx=cur_sel;
696      draw_wiget(screen,wm,0);
697    }
698    scroll_event(last_sel,screen,wm);
699    note_new_current(wm,screen,inm,cur_sel);   
700  }
701}
702
703void spicker::handle_down(image *screen, window_manager *wm, input_manager *inm)
704{
705  if (vert && cur_sel<t-1)
706    cur_sel++;
707  else return ;
708  if (cur_sel>sx+r-1)
709  {
710    draw_wiget(screen,wm,1);
711    last_sel=sx=cur_sel-r+1;
712    draw_wiget(screen,wm,0);
713  }
714  scroll_event(sx,screen,wm);
715  note_new_current(wm,screen,inm,cur_sel);   
716}
717
718void spicker::handle_left(image *screen, window_manager *wm, input_manager *inm)
719{
720}
721
722void spicker::handle_right(image *screen, window_manager *wm, input_manager *inm)
723{
724}
725
726
727
728
Note: See TracBrowser for help on using the repository browser.