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