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

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

imlib: make some Image methods use vec2i.

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