source: abuse/branches/lol/src/imlib/scroller.cpp @ 732

Last change on this file since 732 was 732, checked in by Sam Hocevar, 8 years ago

build: SDL2 compilation fixes.

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