root/window/event.cc

Revision 65:4416cfac86ae, 17.1 KB (checked in by Thibaut Girka <thib@…>, 18 months ago)
Convert EUC-JP files to UTF8
Line 
1/*
2 * Copyright (c) 2004-2006  Kazunori "jagarl" Ueno
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 * 3. The name of the author may not be used to endorse or promote products
14 *    derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28#include "SDL.h"
29#include "event.h"
30#include <vector>
31#include <list>
32#include <algorithm>
33#include <iostream>
34#include <sys/stat.h>
35
36using namespace std;
37
38bool save_req = false, load_req = false, grpdump_req = false; //  scn2k/scn2k_impl.cc: キヌボヌドからセヌブ・ロヌドできるように
39bool pressAreq=false,pressFreq=false,pressDreq=false;
40namespace Event {
41/* Impl: struct Event::Video */
42
43Video::Video(Container& container) : region(0, 0, 0, 0), z(0), parent(container) {
44        activated = false;
45        parent.Add(this);
46}
47Video::Video(Container& container, const Rect& init_rect) : region(init_rect), z(0), parent(container) {
48        activated = false;
49        parent.Add(this);
50}
51Video::Video(Container& container, const Rect& init_rect, int _z) : region(init_rect), z(_z), parent(container) {
52        activated = false;
53        parent.Add(this);
54}
55Video::~Video() {
56        parent.Delete(this);
57};
58void Video::SetRegion(const Rect& new_rect) {
59        region = new_rect;
60}
61void Video::SetZ(int new_z) {
62        z = new_z;
63}
64void Video::activate(void) {
65        activated = true;
66}
67void Video::deactivate(void) {
68        activated = false;
69}
70inline int Video::point_in(int x, int y) {
71        if (!activated) return -1;
72        if (region.point_in(x,y)) return z;
73        else return -1;
74}
75
76/* カヌ゜ルの動く順序䞊、巊の順に準䜍付け */
77bool operator <(const Video& pos1, const Video& pos2) {
78        if (pos1.region.ty < pos2.region.ty) return true;
79        if (pos1.region.ty == pos2.region.ty) return pos1.region.lx < pos2.region.lx;
80        if (pos1.region.by >= pos2.region.by) return pos1.region.lx <= pos2.region.lx;
81        return false;
82}
83
84
85/* Impl: struct Event::Time */
86Time::Time(Container& container) : wakeup_time(container.current_time), parent(container) {
87        parent.Add(this);
88}
89Time::~Time() {
90        parent.Delete(this);
91}
92/* Define: struct Event::ContainerImpl */
93
94struct ContainerImplTime_Item {
95        Time* instance;
96        bool valid;
97        bool operator ==(Time* const& to) const {
98                return to == instance;
99        }
100        ContainerImplTime_Item(Time* _time) :
101                instance(_time), valid(true) {
102        }
103};
104
105class ContainerImplTime : private vector<ContainerImplTime_Item> {
106public:
107        ContainerImplTime(void);
108        bool Exec(unsigned int current_time);
109        void Add(Time* new_event);
110        void Delete(Time* delete_event);
111private:
112        static vector<ContainerImplTime_Item> new_item;
113        unsigned int prev_execed_time;
114        static bool is_invalid(const_reference value) {
115                return !value.valid;
116        }
117};
118
119vector<ContainerImplTime_Item> ContainerImplTime::new_item;
120
121ContainerImplTime::ContainerImplTime(void) {
122        prev_execed_time = 0;
123}
124void ContainerImplTime::Add(Time* event) {
125        ContainerImplTime_Item item(event);
126        new_item.push_back(item);
127}
128void ContainerImplTime::Delete(Time* delete_event) {
129        iterator it = find(begin(), end(), delete_event);
130        if (it != end()) {
131                it->valid = false;
132                it->instance = NULL;
133                return;
134        }
135        it = find(new_item.begin(), new_item.end(), delete_event);
136        if (it != end()) {
137                it->valid = false;
138                it->instance = NULL;
139                return;
140        }
141}
142
143bool ContainerImplTime::Exec(unsigned int current_time) {
144        if (current_time == Time::NEVER_WAKE) return true;
145        // 呌び出したでに䜜補されたitemを远加
146        insert(end(), new_item.begin(), new_item.end());
147        new_item.clear();
148        if (empty()) return true;
149        if (current_time == Time::FRAME_UPDATE) { // ビデオフレヌムの曎新時
150                for (iterator it = begin(); it != end(); it++) {
151                        if (! it->valid) continue;
152                       
153                        unsigned tm = it->instance->Wakeup();
154                        if (tm == Time::FRAME_UPDATE) {
155                                it->instance->Elapsed(prev_execed_time);
156                        }
157                }
158        } else { // 時間倉化時
159                if (current_time < prev_execed_time) prev_execed_time = 0; /* 時間が䞀回りしおに戻ったずき */
160                for (iterator it = begin(); it != end(); it++) {
161                        if (! it->valid) continue;
162                        unsigned tm = it->instance->Wakeup();
163                        if (tm >= prev_execed_time && tm < current_time) {
164                                it->instance->Elapsed(current_time);
165                        }
166                }
167                prev_execed_time = current_time;
168        }
169        // 凊理䞭に削陀された item を実際に削陀
170        erase(remove_if(begin(), end(), is_invalid), end());
171        return true;
172}
173
174
175class ContainerImplVideo : private vector<Video*> {
176        public:
177                bool Exec(void);
178
179                ContainerImplVideo(void);
180                ~ContainerImplVideo();
181                void Add(Video* item);
182                void Delete(Video* item);
183                void RegisterGlobalMotionFunc(Container::motionfunc, void* pointer);
184                void DeleteGlobalMotionFunc(Container::motionfunc, void* pointer);
185                void RegisterGlobalPressFunc(Container::motionfunc, void* pointer);
186                void DeleteGlobalPressFunc(Container::motionfunc, void* pointer);
187        private:
188                struct Motionfunc {
189                        Container::motionfunc func;
190                        void* pointer;
191                        bool operator ==(const Motionfunc& m) const { return func == m.func && pointer == m.pointer;}
192                };
193                list<Motionfunc> motion_vec;
194                list<Motionfunc> press_vec;
195                typedef list<Motionfunc>::iterator MotionIterator;
196                bool is_sorted;
197        public:
198                int button_pressed;
199                int button_released;
200                int mouse_x, mouse_y;
201                int new_mouse_x, new_mouse_y;
202        private:
203                void SetChanged(void);
204                static bool SortLess(const Video* pos1, const Video* pos2) {
205                        return pos1 < pos2;
206                }
207                void Sort(void);
208                void Motion(int x, int y); // mouse motion
209                void Press(void);
210                void TakeScreenshot(void);
211                iterator cur_pos;
212                Video* cur_item; // 珟圚のフォヌカス䜍眮
213                int cur_pressed_x, cur_pressed_y;
214};
215
216void ContainerImplVideo::SetChanged(void) {
217        if (is_sorted) {
218                if (cur_item != NULL) {
219                        cur_pos = find(begin(), end(), cur_item);
220                        if (cur_pos == end()) cur_item = NULL;
221                }
222                is_sorted = false;
223        }
224}
225
226void ContainerImplVideo::Sort(void) {
227        sort(begin(), end(), SortLess);
228        if (cur_item != NULL) {
229                cur_pos = lower_bound(begin(), end(), cur_item, SortLess);
230        } else {
231                cur_pos = end();
232        }
233        is_sorted = true;
234}
235
236ContainerImplVideo::ContainerImplVideo(void) {
237        is_sorted = false;
238        button_pressed = 0;
239        button_released = 0;
240        cur_item = NULL;
241        mouse_x = 0; mouse_y = 0;
242        new_mouse_x = 0; new_mouse_y = 0;
243}
244
245ContainerImplVideo::~ContainerImplVideo(void) {
246};
247
248void ContainerImplVideo::Add(Video* event) {
249        push_back(event);
250        SetChanged();
251}
252
253void ContainerImplVideo::Delete(Video* delete_event) {
254        iterator it = find(begin(), end(), delete_event);
255        if (it != end()) {
256                erase(it);
257                SetChanged();
258        } else {
259                fprintf(stderr,"\nXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n");
260                fprintf(stderr,"X  ContainerImplVideo: Cannot delete node %p\n",delete_event);
261                fprintf(stderr,"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n\n");
262                fprintf(stderr,"vector from:\n");
263                for(it=begin(); it!=end(); it++) {
264                        fprintf(stderr,"%p, ",*it);
265                }
266                fprintf(stderr,"\n");
267        }
268        if (delete_event == cur_item) {
269                cur_pos = end();
270                cur_item = NULL;
271                Motion(mouse_x, mouse_y);
272        }
273}
274
275void ContainerImplVideo::RegisterGlobalMotionFunc(Container::motionfunc func, void* pointer) {
276        Motionfunc f;
277        f.func = func;
278        f.pointer = pointer;
279        if (find(motion_vec.begin(), motion_vec.end(), f) == motion_vec.end()) {
280                motion_vec.push_back(f);
281        }
282}
283
284void ContainerImplVideo::DeleteGlobalMotionFunc(Container::motionfunc func, void* pointer) {
285        Motionfunc f;
286        f.func = func;
287        f.pointer = pointer;
288        list<Motionfunc>::iterator it = find(motion_vec.begin(), motion_vec.end(), f);
289        if (it != motion_vec.end())
290                motion_vec.erase(it);
291}
292
293void ContainerImplVideo::RegisterGlobalPressFunc(Container::motionfunc func, void* pointer) {
294        Motionfunc f;
295        f.func = func;
296        f.pointer = pointer;
297        if (find(press_vec.begin(), press_vec.end(), f) == press_vec.end()) {
298                press_vec.push_back(f);
299        }
300}
301
302void ContainerImplVideo::DeleteGlobalPressFunc(Container::motionfunc func, void* pointer) {
303        Motionfunc f;
304        f.func = func;
305        f.pointer = pointer;
306        list<Motionfunc>::iterator it = find(press_vec.begin(), press_vec.end(), f);
307        if (it != press_vec.end())
308                press_vec.erase(it);
309}
310
311void ContainerImplVideo::Motion(int x, int y) {
312        mouse_x = x; mouse_y = y;
313        MotionIterator mit;
314        for (mit=motion_vec.begin(); mit != motion_vec.end();) {
315                MotionIterator mit_next = mit;
316                mit_next++;
317                if (!(*mit->func)(x, y, mit->pointer)) motion_vec.erase(mit);
318                mit = mit_next;
319       
320        }
321       
322        /* @@@ ドラッグ凊理ずマりスを抌す凊理のバッティングで「二回ボタンを抌さないず云々」関連のバグの可胜性あり */
323        if (button_pressed & (1<<MOUSE_LEFT)) {
324                if (cur_item) cur_item->Drag(cur_pressed_x, cur_pressed_y, x, y);
325                return;
326        }
327        if (cur_item != NULL) cur_item->Motion(x,y);
328        int z = -1; iterator z_it;
329        iterator it;
330        for (it = begin(); it != end(); it++) {
331                int new_z = (*it)->point_in(x, y);
332                if (z < new_z) {
333                        z = new_z;
334                        z_it = it;
335                }
336        }
337        if (z != -1) {
338                if (cur_item == *z_it) return;
339                if (cur_item) cur_item->Out();
340                cur_pos = z_it;
341                cur_item = *z_it;
342                cur_item->In();
343                return;
344        } else {
345                if (cur_item) cur_item->Out();
346                cur_pos = end();
347                cur_item = NULL;
348        }
349        return;
350}
351
352void ContainerImplVideo::Press(void) {
353        if (cur_item) {
354                cur_pressed_x = mouse_x;
355                cur_pressed_y = mouse_y;
356                cur_item->Press();
357                return;
358        }
359        MotionIterator mit;
360        for (mit=press_vec.begin(); mit != press_vec.end(); ) {
361                MotionIterator mit_next = mit;
362                mit_next++;
363                if (!(*mit->func)(mouse_x, mouse_y, mit->pointer)) {
364                        press_vec.erase(mit);
365                }
366                mit = mit_next;
367        }
368}
369
370void ContainerImplVideo::TakeScreenshot(void) {
371        int n=0;
372        char filename[1024];
373        struct stat buffer;
374        for(n=0; n<9999; n++) {
375                // XXX: put screenshots in a seperate dir?
376                sprintf(filename, "xclannad_%04i.bmp", n);
377                if(stat(filename, &buffer) == -1) break;
378        }
379        SDL_SaveBMP(SDL_GetVideoSurface(), filename);
380}
381
382bool ContainerImplVideo::Exec(void) {
383        bool is_mouse_motion = false;
384        int motion_x = 0, motion_y = 0;
385        SDL_Event event;
386        SDL_PumpEvents();
387        while(SDL_PeepEvents(&event, 1, SDL_GETEVENT, SDL_ALLEVENTS) == 1) {
388                switch(event.type) {
389                        case SDL_QUIT: return false; // @@@ なにかやらないず
390                        case SDL_ACTIVEEVENT: // なにもしない
391                                // cout<<"active : gain "<<int(event.active.gain)<<", state "<<int(event.active.state)<<endl;
392                                break;
393                        case SDL_KEYDOWN:
394                                if (!is_sorted) Sort();
395                                switch(event.key.keysym.sym) {
396                                        case SDLK_F12:
397                                        case SDLK_PRINT:
398                                        case SDLK_p:  // for Zaurus
399                                                TakeScreenshot();
400                                                break;
401                                        // Some window managers (eg enlightenment) use Alt-Enter for
402                                        // themselves, F11 is a good alternative
403                                        case SDLK_F11:
404                                                SDL_WM_ToggleFullScreen(SDL_GetVideoSurface());
405                                                break;
406                                        case SDLK_RETURN:
407                                                if (SDL_GetModState() & KMOD_ALT) {
408                                                        SDL_WM_ToggleFullScreen(SDL_GetVideoSurface());
409                                                        break;
410                                                }
411                                        case SDLK_SPACE:
412                                                Press();
413                                                break;
414                                        case SDLK_TAB: // move to next widget
415                                                if (cur_pos != end())  cur_pos++;
416                                                if (cur_pos == end()) cur_pos = begin();
417                                                if (cur_pos != end())  {
418                                                        cur_item = *cur_pos;
419                                                        cur_item->In();
420                                                } else {
421                                                        cur_item = NULL;
422                                                }
423                                                break;
424                                        case SDLK_LEFT: if (cur_pos != end()) (*cur_pos)->KeyLeft(); break;
425                                        case SDLK_RIGHT:if (cur_pos != end()) (*cur_pos)->KeyRight(); break;
426                                        case SDLK_LSHIFT: case SDLK_RSHIFT: button_pressed |= (1<<KEY_SHIFT); break;
427                                        case SDLK_ESCAPE: button_pressed |= (1<<MOUSE_RIGHT); break; /* for Zaurus */
428                                        case SDLK_s: save_req = true; break;
429                                        case SDLK_l: load_req = true; break;
430                                        case SDLK_g: grpdump_req = true; break;
431                                        case SDLK_a: pressAreq = true; break;
432                                        case SDLK_d: pressDreq = true; break;
433                                        case SDLK_f: pressFreq = true; break;
434                                }
435                                break;
436                        case SDL_KEYUP:
437                                // cout << "keyup which "<<int(event.key.which)<<", sym "<<int(event.key.keysym.sym)<<endl;
438                                switch(event.key.keysym.sym) {
439                                        case SDLK_RETURN: case SDLK_SPACE:
440                                                if (cur_item) cur_item->Release();
441                                        case SDLK_LSHIFT: case SDLK_RSHIFT: button_pressed &= ~(1<<KEY_SHIFT); button_released |= 1<<KEY_SHIFT; break;
442                                        case SDLK_ESCAPE: button_pressed &= ~(1<<MOUSE_RIGHT); button_released |= 1<<MOUSE_RIGHT; break; /* for Zaurus */
443                                }
444                                break;
445                        case  SDL_MOUSEMOTION:
446                                motion_x = event.motion.x;
447                                motion_y = event.motion.y;
448                                is_mouse_motion = true;
449                                // Motion(event.motion.x, event.motion.y);
450                                // cout<< "motion which "<<int(event.motion.which)<<
451                                //      "x "<<event.motion.x << "y "<<event.motion.y<<endl;
452                                break;
453                        case SDL_MOUSEBUTTONUP:
454                                if (event.button.button == 1) {
455                                        Motion(event.button.x, event.button.y);
456                                        is_mouse_motion = false;
457                                        if (cur_item) cur_item->Release();
458                                }
459                                switch(event.button.button) {
460                                        case 1:
461                                                button_pressed &= ~(1<<MOUSE_LEFT);
462                                                button_released |= 1<<MOUSE_LEFT;
463                                                break;
464                                        case 2:
465                                                button_pressed &= ~(1<<MOUSE_MIDDLE);
466                                                button_released |= 1<<MOUSE_MIDDLE;
467                                                break;
468                                        case 3:
469                                                button_pressed &= ~(1<<MOUSE_RIGHT);
470                                                button_released |= 1<<MOUSE_RIGHT;
471                                                break;
472                                        case 4:
473                                                button_pressed &= ~(1<<MOUSE_UP);
474                                                button_released |= 1<<MOUSE_UP;
475                                                break;
476                                        case 5:
477                                                button_pressed &= ~(1<<MOUSE_DOWN);
478                                                button_released |= 1<<MOUSE_DOWN;
479                                                break;
480                                }
481                                break;
482                        case SDL_MOUSEBUTTONDOWN:
483                                if (event.button.button == 1) {
484                                        Motion(event.button.x, event.button.y);
485                                        is_mouse_motion = false;
486                                        Press();
487                                }
488                                switch(event.button.button) {
489                                        case 1: button_pressed |= (1<<MOUSE_LEFT); break;
490                                        case 2: button_pressed |= (1<<MOUSE_MIDDLE); break;
491                                        case 3: button_pressed |= (1<<MOUSE_RIGHT); break;
492                                        case 4: button_pressed |= (1<<MOUSE_UP); break;
493                                        case 5: button_pressed |= (1<<MOUSE_DOWN); break;
494                                }
495                                // cout << "mouse which "<<int(event.button.which)<<"button "<<int(event.button.button)<<
496                                //      "state "<<int(event.button.state)<<"x "<<event.button.x << "y "<<event.button.y<<endl;
497                                break;
498                        case SDL_VIDEOEXPOSE: // redraw の必芁がある
499                                // cout<<"expose."<<endl;
500                                break;
501                }
502        }
503        // Motion 呌び出しは䞀回だけ
504        if (is_mouse_motion)
505                Motion(motion_x, motion_y);
506        return true;
507}
508
509/* Impl: struct Event::Container */
510Container::Container(void) {
511        pimpl_video = new ContainerImplVideo;
512        try {
513                pimpl_time = new ContainerImplTime;
514        } catch(...) {
515                delete pimpl_video;
516                throw;
517        }
518        button_pressed = 0;
519        current_time = 0;
520        int i;
521        for (i=0; i<BUTTON_MAX; i++) button_presscount[i] = 0;
522}
523
524Container::~Container(void) {
525        delete pimpl_video;
526        delete pimpl_time;
527}
528
529void Container::Add(Video* item) {
530        pimpl_video->Add(item);
531}
532
533void Container::Delete(Video* item) {
534        pimpl_video->Delete(item);
535}
536
537void Container::Add(Time* item) {
538        pimpl_time->Add(item);
539}
540
541void Container::Delete(Time* item) {
542        pimpl_time->Delete(item);
543}
544
545void Container::RegisterGlobalMotionFunc(Container::motionfunc f, void* pointer) {
546        pimpl_video->RegisterGlobalMotionFunc(f, pointer);
547}
548
549void Container::DeleteGlobalMotionFunc(Container::motionfunc f, void* pointer) {
550        pimpl_video->DeleteGlobalMotionFunc(f, pointer);
551}
552
553void Container::RegisterGlobalPressFunc(Container::motionfunc f, void* pointer) {
554        pimpl_video->RegisterGlobalPressFunc(f, pointer);
555}
556
557void Container::DeleteGlobalPressFunc(Container::motionfunc f, void* pointer) {
558        pimpl_video->DeleteGlobalPressFunc(f, pointer);
559}
560
561bool Container::Exec(unsigned int time) {
562        current_time = time;
563        bool ret = true;
564        ret = ret && pimpl_video->Exec();
565        ret = ret && pimpl_time->Exec(time);
566        int i; int mask = 1;
567
568        for (i=0; i<BUTTON_MAX; i++) {
569                if (pimpl_video->button_released&mask) {
570                        button_presscount[i]++;
571                }
572                mask <<= 1;
573        }
574        pimpl_video->button_released = 0;
575        button_pressed = pimpl_video->button_pressed;
576        return ret;
577}
578
579void Container::MousePos(int& x, int& y) {
580        x = pimpl_video->mouse_x;
581        y = pimpl_video->mouse_y;
582}
583
584bool Container::pressed(int mask) {
585        if (mask < 0 || mask >= BUTTON_MAX) return 0;
586        return (button_pressed & (1<<mask)) != 0;
587}
588
589bool Container::presscount(int mask) {
590        if (mask < 0 || mask >= BUTTON_MAX) return 0;
591        int count = button_presscount[mask];
592        button_presscount[mask] = 0;
593        return count;
594}
595
596} /* end of namespace Container */
597
598// 問題
599// z 軞ず xy 軞の盞互干枉高速化
600// 移動するりィゞット描画の高速化
601// キャッシュ
602// 文字列の䞀郚のみ曎新の高速化
603// 「階局 z で x なる領域無効化、y なる領域生成」で良いExpose
Note: See TracBrowser for help on using the browser.