source: abuse/branches/lol/src/imlib/input.cpp @ 724

Last change on this file since 724 was 724, checked in by Sam Hocevar, 9 years ago

build: merge all static libraries into a single one.

File size: 12.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 defined HAVE_CONFIG_H
12#   include "config.h"
13#endif
14
15#include <string.h>
16
17#include "common.h"
18
19#include "imlib/input.h"
20
21void AButton::remap(Filter *f)
22{
23    if (visual)
24    {
25        f->Apply(visual);
26        if (pressed)
27            f->Apply(pressed);
28    }
29}
30
31void AButtonBox::press_button(int id)      // if button box doesn't contain id, nothing happens
32{
33}
34
35void AButtonBox::remap(Filter *f)
36{
37    for (int i = 0; i < m_buttons.Count(); ++i)
38        m_buttons[i]->remap(f);
39}
40
41AWidget *AButtonBox::find(int id)
42{
43    if (id == m_id)
44        return this;
45
46    for (int i = 0; i < m_buttons.Count(); ++i)
47        if (id == m_buttons[i]->m_id)
48            return m_buttons[i];
49
50    return nullptr;
51}
52
53AButtonBox::AButtonBox(ivec2 pos, int id, int MaxDown, Array<AButton *> const &buttons)
54{
55    m_pos = pos;
56    m_id = id;
57    m_buttons = buttons;
58    maxdown = MaxDown;
59    if (m_buttons.Count() && maxdown)
60        m_buttons[0]->push();  // the first button is automatically selected!
61}
62
63AButtonBox::~AButtonBox()
64{
65    for (int i = 0; i < m_buttons.Count(); ++i)
66        delete m_buttons[i];
67}
68
69ibox2 AButtonBox::GetArea()
70{
71    ibox2 ret;
72    for (int i = 0; i < m_buttons.Count(); ++i)
73    {
74        ibox2 area = m_buttons[i]->GetArea();
75        if (i)
76        {
77            ret.A = lol::min(ret.A, area.A);
78            ret.B = lol::max(ret.B, area.B);
79        }
80        else
81            ret = area;
82    }
83    return ret;
84}
85
86void AButtonBox::draw_first(AImage *screen)
87{
88    for (int i = 0; i < m_buttons.Count(); ++i)
89        m_buttons[i]->draw_first(screen);
90}
91
92void AButtonBox::Draw(int active, AImage *screen)
93{
94    return;
95}
96
97void AButtonBox::Move(ivec2 pos)
98{
99    for (int i = 0; i < m_buttons.Count(); ++i)
100        m_buttons[i]->Move(pos + m_buttons[i]->m_pos);
101    m_pos = pos;
102}
103
104char const *AButtonBox::read()
105{
106    for (int i = 0; i < m_buttons.Count(); ++i)
107        if (*((int const *)m_buttons[i]->read()) == 0)
108            return (char const *)m_buttons[i];
109
110    return nullptr;
111}
112
113void AButtonBox::handle_event(Event &ev, AImage *screen, InputManager *im)
114{
115    switch (ev.type)
116    {
117    case EV_MOUSE_BUTTON:
118        // see if the user clicked on a button
119        for (int i = 0, found = 0; i < m_buttons.Count() && !found; ++i)
120        {
121            ibox2 area = m_buttons[i]->GetArea();
122            if (ev.mouse_move >= area.A && ev.mouse_move <= area.B)
123            {
124                m_buttons[i]->handle_event(ev, screen, im);
125
126                int total = 0;
127                for (int j = 0; j < m_buttons.Count(); ++j)
128                    if (*((int const *)m_buttons[j]->read()) == 0)
129                        total++;
130
131                if (*((int const *)m_buttons[i]->read()) == 0)  // did the user press or release the button
132                {
133                    for (int j = 0; j < m_buttons.Count() && total > maxdown; ++j)
134                        if ((i != j || maxdown == 0) && *((int const *)m_buttons[j]->read()) == 0)
135                        {
136                            total--;
137                            m_buttons[j]->push();
138                            m_buttons[j]->draw_first(screen);
139                        }
140                    m_buttons[i]->draw_first(screen);
141                }
142                else if (total == 0 && maxdown)
143                {
144                    // don't let the user de-press a button if non others are selected.
145                    m_buttons[i]->push();
146                }
147
148                found = 1; // don't look at anymore buttons
149
150            }
151        }
152        break;
153    }
154}
155
156void AButtonBox::add_button(AButton *b)
157{
158    m_buttons.Push(b);
159}
160
161void AButtonBox::arrange_left_right()
162{
163    ivec2 on = m_pos;
164    for (int i = 0; i < m_buttons.Count(); ++i)
165    {
166        ibox2 area = m_buttons[i]->GetArea();
167        m_buttons[i]->m_pos = on;
168        on.x += (area.B.x - area.A.x + 1) + 1;
169    }
170}
171
172void AButtonBox::arrange_up_down()
173{
174    ivec2 on = m_pos;
175    for (int i = 0; i < m_buttons.Count(); ++i)
176    {
177        ibox2 area = m_buttons[i]->GetArea();
178        m_buttons[i]->m_pos = on;
179        on.y += (area.B.y - area.A.y + 1) + 1;
180    }
181}
182
183void AButton::change_visual(AImage *new_visual)
184{
185    ASSERT(visual);
186    visual = new_visual;
187}
188
189ibox2 AButton::GetArea()
190{
191    if (pressed)
192        return ibox2(m_pos, m_pos + pressed->Size() - ivec2(1));
193
194    if (m_text.Count())
195        return ibox2(m_pos, m_pos + wm->font()->Size() * ivec2(m_text.Count(), 1) + ivec2(6));
196
197    return ibox2(m_pos, m_pos + visual->Size() + ivec2(6));
198}
199
200
201AButton::AButton(ivec2 pos, int id, char const *text)
202  : AWidget(pos, id),
203    m_text(text)
204{
205    act_id = -1;
206    up = 1;
207    act = 0;
208    visual = NULL;
209    pressed = NULL;
210}
211
212
213AButton::AButton(ivec2 pos, int id, AImage *vis)
214  : AWidget(pos, id)
215{
216    act_id = -1;
217    visual = vis; up = 1; act = 0;
218    pressed = NULL;
219}
220
221AButton::AButton(ivec2 pos, int id, AImage *Depressed, AImage *Pressed, AImage *active)
222  : AWidget(pos, id)
223{
224    act_id = -1;
225    visual = Depressed; up = 1; act = 0;
226    pressed = Pressed;
227    act_pict = active;
228}
229
230
231void ATextField::change_data(char const *new_data, int new_cursor, // cursor==-1, does not change it.
232                 int active, AImage *screen)
233{
234  if (strlen(format)<strlen(new_data))
235    data=(char *)realloc(data,strlen(new_data));
236
237  strcpy(data,new_data);
238  if (new_cursor!=-1)
239    cur=new_cursor;
240  draw_first(screen);
241  Draw(active, screen);
242}
243
244char const *ATextField::read()
245{
246    while (*data && data[strlen(data) - 1] == ' ')
247        data[strlen(data) - 1] = 0; /* Strip trailing spaces */
248    return data;
249}
250
251void ATextField::handle_event(Event &ev, AImage *screen, InputManager *im)
252{
253  int xx;
254  if (ev.type==EV_KEY)
255  {
256    switch (ev.key)
257    {
258      case JK_LEFT : if (cur) { draw_cur(wm->dark_color(),screen); cur--;
259                           draw_cur(wm->bright_color(),screen); } break;
260      case JK_RIGHT : if (cur<(int)strlen(format)-1) { draw_cur(wm->dark_color(),screen); cur++;
261                           draw_cur(wm->bright_color(),screen); } break;
262      case JK_END : if (cur!=last_spot())
263                          { draw_cur(wm->dark_color(),screen); cur=last_spot();
264                            if (cur==(int)strlen(format)-1) cur--;
265                           draw_cur(wm->bright_color(),screen); } break;
266      case JK_HOME : if (cur)
267                          { draw_cur(wm->dark_color(),screen); cur=0;
268                           draw_cur(wm->bright_color(),screen); } break;
269      case JK_BACKSPACE : if (cur)
270         { draw_cur(wm->dark_color(),screen); cur--;
271           for (xx=cur; xx<(int)strlen(format)-1; xx++)
272             data[xx]=data[xx+1];
273           data[strlen(format)-1]=' ';
274           draw_text(screen);
275           draw_cur(wm->bright_color(),screen);
276           wm->Push(Event(m_id, (char *)this));
277         } break;
278      default : if (ev.key>=' ' && ev.key<='~')
279         {
280           draw_cur(wm->dark_color(),screen);
281           for (xx=strlen(format)-1; xx>cur && xx>0; xx--)
282             data[xx]=data[xx-1];
283           data[cur]=ev.key;
284           if (cur<(int)strlen(format)-1)
285             cur++;
286       data[strlen(format)]=0;
287           draw_text(screen);
288           draw_cur(wm->bright_color(),screen);
289           wm->Push(Event(m_id, (char *)this));
290         } break;
291    }
292  }
293}
294
295void ATextField::Draw(int active, AImage *screen)
296{
297  if (active)
298  {
299    screen->Rectangle(ivec2(xstart(), m_pos.y), ivec2(xend(), yend()),
300                      wm->bright_color());
301    draw_cur(wm->bright_color(),screen);
302  }
303  else
304  {
305    screen->Rectangle(ivec2(xstart(), m_pos.y), ivec2(xend(), yend()),
306                      wm->dark_color());
307    draw_cur(wm->dark_color(),screen);
308  }
309}
310
311ibox2 ATextField::GetArea()
312{
313    return ibox2(m_pos, ivec2(xend(), yend()));
314}
315
316ATextField::ATextField(ivec2 pos, int id, char const *Prompt,
317                       char const *Format, char const *Data)
318  : AWidget(pos, id)
319{
320    int slen=(strlen(Format)>strlen(Data) ? strlen(Format) : strlen(Data));
321
322    prompt = strdup(Prompt);
323    format = strcpy((char *)malloc(slen+1),Format);
324    data = strcpy((char *)malloc(slen+1),Data);
325    cur = strlen(data);
326    while (cur && data[cur-1]==' ') cur--;
327}
328
329ATextField::ATextField(ivec2 pos, int id, char const *Prompt,
330                       char const *Format, double Data)
331  : AWidget(pos, id)
332{
333  char num[20];
334  sprintf(num,"%g",Data);
335  int slen=(strlen(Format)>strlen(num) ? strlen(Format) : strlen(num));
336  prompt = strdup(Prompt);
337  format=strcpy((char *)malloc(slen+1),Format);
338  data=strcpy((char *)malloc(slen+1),num);
339  cur=strlen(num);
340  while (cur && data[cur-1]==' ') cur--;
341}
342
343
344void AButton::push()
345{
346    up = !up;
347}
348
349void AButton::handle_event(Event &ev, AImage *screen, InputManager *im)
350{
351    if ((ev.type == EV_KEY && ev.key == 13)
352         || (ev.type == EV_MOUSE_BUTTON && ev.mouse_button))
353    {
354        GetArea(); /* FIXME: was this always a no-op? */
355        up = !up;
356        draw_first(screen);
357        Draw(act, screen);
358        wm->Push(Event(m_id, (char *)this));
359    }
360}
361
362void AButton::Draw(int active, AImage *screen)
363{
364    int color = active ? wm->bright_color() : wm->medium_color();
365    ibox2 area = GetArea();
366
367    if (active != act && act_id != -1 && active)
368        wm->Push(Event(act_id, nullptr));
369
370    if (!pressed)
371    {
372        screen->Rectangle(area.A + ivec2(2), area.B - ivec2(2), color);
373        act = active;
374    }
375    else if (!up)
376        screen->PutImage(act_pict, m_pos);
377    else if (!active)
378        screen->PutImage(visual, m_pos);
379    else
380        screen->PutImage(pressed, m_pos);
381}
382
383void AButton::draw_first(AImage *screen)
384{
385    if (pressed)
386    {
387        Draw(0, screen);
388        return;
389    }
390
391    ibox2 area = GetArea();
392
393    if (up)
394    {
395        screen->Rectangle(area.A, area.B, wm->black());
396//      screen->widget_bar(,wm->bright_color(),wm->medium_color(),wm->dark_color());
397        screen->WidgetBar(area.A + ivec2(1), area.B - ivec2(1),
398                          wm->bright_color(), wm->medium_color(), wm->dark_color());
399    }
400    else
401    {
402        screen->Line(area.A, ivec2(area.B.x, area.A.y), wm->dark_color());
403        screen->Line(area.A, ivec2(area.A.x, area.B.y), wm->dark_color());
404        screen->Line(ivec2(area.B.x, area.A.y + 1), area.B, wm->bright_color());
405        screen->Line(ivec2(area.A.x + 1, area.B.y), area.B, wm->bright_color());
406        screen->Bar(area.A + ivec2(1), area.B - ivec2(1), wm->medium_color());
407    }
408
409    if ((up && m_text.Count()) || (!up && !visual))
410    {
411        wm->font()->PutString(screen, m_pos + ivec2(4, 5), m_text, wm->black());
412        wm->font()->PutString(screen, m_pos + ivec2(3, 4), m_text);
413    }
414    else if (up)
415        screen->PutImage(visual, m_pos + ivec2(3), 1);
416    else
417        screen->PutImage(visual, area.A + ivec2(3), 1);
418}
419
420void ATextField::draw_first(AImage *screen)
421{
422  wm->font()->PutString(screen, m_pos + ivec2(0, 3), prompt);
423  screen->Bar(ivec2(xstart(), m_pos.y), ivec2(xend(), yend()), wm->dark_color());
424  wm->font()->PutString(screen, ivec2(xstart() + 1, m_pos.y + 3), data);
425}
426
427
428void ATextField::draw_cur(int color, AImage *screen)
429{
430    screen->Bar(ivec2(xstart() + cur * wm->font()->Size().x + 1, yend() - 2),
431                ivec2(xstart() + (cur + 1) * wm->font()->Size().x, yend() - 1),
432                color);
433}
434
435
436
437AInfoField::AInfoField(ivec2 pos, int id, char const *info)
438{
439    m_pos = pos;
440    m_text = info;
441    m_id = id;
442    w = -1;
443}
444
445
446ibox2 AInfoField::GetArea()
447{
448    if (w == -1)     // if we haven't calculated this yet
449    {
450        int fw = wm->font()->Size().x, fh = wm->font()->Size().y, maxw = 0;
451        int i = 0;
452        for (w = fw, h = fh + 1; m_text[i]; ++i)
453        {
454            maxw = lol::max(maxw, w);
455            if (m_text[i] == '\n')
456            {
457                h += fh + 1;
458                w = 1;
459            }
460            else
461                w += fw;
462        }
463        w = maxw;
464    }
465
466    return ibox2(m_pos, m_pos + ivec2(w, h));
467}
468
469void AInfoField::put_para(AImage *screen, char const *st, int dx, int dy,
470                          int xspace, int yspace, JCFont *font, int color)
471{
472  int ox=dx;
473  while (*st)
474  {
475    if (*st=='\n')
476    {
477      dx=ox;
478      dy+=yspace;
479    }
480    else
481    {
482      font->PutChar(screen, ivec2(dx, dy), *st, color);
483      dx+=xspace;
484    }
485    st++;
486  }
487}
488
489void AInfoField::draw_first(AImage *screen)
490{
491    put_para(screen, m_text.C(), m_pos.x+1, m_pos.y+1, wm->font()->Size().x,
492             wm->font()->Size().y, wm->font(), wm->black());
493    put_para(screen, m_text.C(), m_pos.x, m_pos.y, wm->font()->Size().x,
494             wm->font()->Size().y, wm->font(), wm->bright_color());
495}
496
Note: See TracBrowser for help on using the repository browser.