root/scn2k/scn2k_text.cc

Revision 66:d112357a0ec1, 51.7 KB (checked in by Thibaut Girka <thib@…>, 18 months ago)
Fix a bug with savegames introduced with changeset c7bcc0ec2267. Warning: savegames created since c7bcc0ec2267 are probably corrupted, you may have to start the game over. If you chose not to do so, you should replace all occurrences of 'TextWindow' by 'TextImplWindow', and 'Text Window' by 'TextImpl Window' in your save files.
Line 
1/*
2TODO:
3        日付のラベルが画面切り替え時に欠けるのを修正
4        画像効果 : 人間の入れ換わりなど
5        kcursor の操䜜を WidText クラスに任せる
6        WidText クラスには新たに以䞋の操䜜を加える
7                ・りェむト終了埌、クリアなしに新たなテキストを远加、新たにstart-waitする
8                ・文字の描画 (Start) ず Wait(カヌ゜ル衚瀺埅ち)の分離。
9                        Start するず文字を描画開始する。クリックで党描画。
10                        Flush するずバッファ内の文字をすべお描画する
11                        Wait するず党描画埌、クリックされるたでカヌ゜ルを衚瀺するたで埅぀
12                Text 偎の状態ずしおは Wait のみを持぀ (PREPAREに戻るのを埅぀)
13                ただし、Skip の暩利はどっちがも぀珟状は
14
15        GrpObj: NextObj ず GrpObj を分離。CreateObj は珟状通り、Visible=1 時に行う。
16                それぞれ num=0 (screen) の枝leaf ずしお実装。delete時は芪のdeleteのみを
17                行い、子はGrpObjの実䜓だけを削陀する
18                Visible 埌のhide は実際に hide ずする
19                ExecReservedCmd() はなくせるはず。Delete() もなくなる。
20        カノギReBlit() がうたくいかないせいで名前りィンドりが消えた時の背景がなくなる
21
22        くら回想衚瀺
23        SEL画像効果
24DONE:
25        ずもよのテキストりィンドり実装、ボタン実装
26        shake の画像効果
27        オブゞェクト内のテキスト色の実装
28        画像効果の改善
29*/
30
31/*
32 * Copyright (c) 2004-2006  Kazunori "jagarl" Ueno
33 * All rights reserved.
34 *
35 * Redistribution and use in source and binary forms, with or without
36 * modification, are permitted provided that the following conditions
37 * are met:
38 * 1. Redistributions of source code must retain the above copyright
39 *    notice, this list of conditions and the following disclaimer.
40 * 2. Redistributions in binary form must reproduce the above copyright
41 *    notice, this list of conditions and the following disclaimer in the
42 *    documentation and/or other materials provided with the distribution.
43 * 3. The name of the author may not be used to endorse or promote products
44 *    derived from this software without specific prior written permission.
45 *
46 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
47 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
48 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
49 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
50 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
51 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
52 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
53 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
54 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
55 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
56 */
57
58#include "scn2k_text.h"
59
60#include "system/file.h"
61#include "scn2k.h"
62
63#include <string>
64using namespace std;
65
66#include "window/render.h"
67
68/**************************************************************::
69**
70**      Text(implementation)
71*/
72Text::Text(Event::Container& _event, PicContainer& _parent) :
73        text(0),status(Text::NORMAL), status_saved(Text::NORMAL), status_mask(Text::NORMAL), ruby_text_flag(false),
74        old_time(0), text_window_number(0), text_parsing(false), skip_mode(SKIP_NO), save_selectcount(0), sel_widget(0),
75        backlog_widget(0), parent(_parent), event(_event),
76        kcursor(0), sel_bg1(0), sel_bg2(0), sel_bg_rect(0,0,0,0) {
77        config = AyuSysConfig::GetInstance();
78        int i;
79        for (i=0; i<32; i++) {
80                widgets[i] = 0;
81        }
82        text_stream.kanji_type = TextStream::sjis;
83        event.RegisterGlobalPressFunc(&PressFunc, (void*)this);
84
85        RegisterCommand(1, 33, 73, "grpOpenBg", (CmdImpl) &Text::impl_txtClear);
86        RegisterCommand(1, 33, 75, "grpMulti", (CmdImpl) &Text::impl_txtClear);
87        RegisterCommand(1, 33, 76, "grpOpen", (CmdImpl) &Text::impl_txtClear);
88
89        RegisterCommand(1, 23, 0, "koePlay", (CmdImpl) &Text::impl_logKoe);
90        RegisterCommand(1, 23, 8, "koeDoPlay", (CmdImpl) &Text::impl_logKoe);
91
92        RegisterCommand(0, 3, 151, "msgHide", (CmdImpl) &Text::impl_txtClear);
93        RegisterCommand(0, 3, 17, "pause", (CmdImpl) &Text::impl_pause);
94        RegisterCommand(0, 3, 3, "par", (CmdImpl) &Text::impl_br); //FIXME
95        RegisterCommand(0, 3, 201, "br", (CmdImpl) &Text::impl_br);
96        RegisterCommand(0, 3, 1000, "FaceOpen", (CmdImpl) &Text::impl_FaceOpen);
97        RegisterCommand(0, 3, 1001, "FaceClear", (CmdImpl) &Text::impl_FaceClear);
98        RegisterCommand(0, 3, 120, "__doruby", (CmdImpl) &Text::impl_doRuby); //FIXME: I don't know how it works
99        RegisterCommand(0, 3, 102, "TextWindow", (CmdImpl) &Text::impl_TextWindow);
100        RegisterCommand(0, 3, 103, "FastText", NULL);//FIXME: (CmdImpl) &Text::impl_FastText);
101        RegisterCommand(0, 3, 104, "NormalText", NULL);
102        RegisterCommand(0, 3, 152, "msgClear", (CmdImpl) &Text::impl_msgClear);
103
104        RegisterCommand(1, 4, 2600, "DefMessageSpeed", (CmdImpl) &Text::impl_GetDefConfig);
105        RegisterCommand(1, 4, 2601, "DefMessageNoWait", (CmdImpl) &Text::impl_GetDefConfig);
106        RegisterCommand(1, 4, 2604, "DefAutoMode", (CmdImpl) &Text::impl_GetDefConfig);
107        RegisterCommand(1, 4, 2605, "DefAutoCharTime", (CmdImpl) &Text::impl_GetDefConfig);
108        RegisterCommand(1, 4, 2606, "DefAutoBaseTime", (CmdImpl) &Text::impl_GetDefConfig);
109
110        RegisterCommand(1, 4, 2323, "MessageSpeed", (CmdImpl) &Text::impl_GetConfig);
111        RegisterCommand(1, 4, 2324, "MessageNoWait", (CmdImpl) &Text::impl_GetConfig);
112        RegisterCommand(1, 4, 2350, "AutoMode", (CmdImpl) &Text::impl_GetConfig);
113        RegisterCommand(1, 4, 2351, "AutoCharTime", (CmdImpl) &Text::impl_GetConfig);
114        RegisterCommand(1, 4, 2352, "AutoBaseTime", (CmdImpl) &Text::impl_GetConfig);
115
116        RegisterCommand(1, 4, 2223, "SetMessageSpeed", (CmdImpl) &Text::impl_SetConfig);
117        RegisterCommand(1, 4, 2224, "SetMessageNoWait", (CmdImpl) &Text::impl_SetConfig);
118        RegisterCommand(1, 4, 2250, "SetAutoMode", (CmdImpl) &Text::impl_SetConfig);
119        RegisterCommand(1, 4, 2251, "SetAutoCharTime", (CmdImpl) &Text::impl_SetConfig);
120        RegisterCommand(1, 4, 2252, "SetAutoBaseTime", (CmdImpl) &Text::impl_SetConfig);
121
122        RegisterCommand(1, 4, 1300, "GetName", (CmdImpl) &Text::impl_GetName);
123        RegisterCommand(1, 4, 1301, "SetName", (CmdImpl) &Text::impl_SetName);
124        RegisterCommand(1, 4, 1310, "GetLocalName", (CmdImpl) &Text::impl_GetLocalName);
125        RegisterCommand(1, 4, 1311, "SetLocalName", (CmdImpl) &Text::impl_SetLocalName);
126
127        RegisterCommand(0, 2, 1, "select", (CmdImpl) &Text::impl_createSelect);
128        RegisterCommand(0, 2, 3, "select2?", (CmdImpl) &Text::impl_createSelect); //FIXME: What difference with select?
129
130        RegisterCommand(0, 4, 1000, "ShowBackground", (CmdImpl) &Text::impl_ShowBackground);
131        RegisterCommand(0, 4, 1100, "SetSkipMode", (CmdImpl) &Text::impl_SetSkipMode);
132
133        RegisterCommand(1, 4, 2260, "SetWindowAttrR", (CmdImpl) &Text::impl_SetWindowAttr);
134        RegisterCommand(1, 4, 2261, "SetWindowAttrG", (CmdImpl) &Text::impl_SetWindowAttr);
135        RegisterCommand(1, 4, 2262, "SetWindowAttrB", (CmdImpl) &Text::impl_SetWindowAttr);
136        RegisterCommand(1, 4, 2263, "SetWindowAttrA", (CmdImpl) &Text::impl_SetWindowAttr);
137        RegisterCommand(1, 4, 2264, "SetWindowAttrF", (CmdImpl) &Text::impl_SetWindowAttr);
138        RegisterCommand(1, 4, 2267, "SetWindowAttr", (CmdImpl) &Text::impl_SetWindowAttr);
139        RegisterCommand(1, 4, 2367, "GetWindowAttr", (CmdImpl) &Text::impl_GetWindowAttr);
140        RegisterCommand(1, 4, 2617, "DefWindowAttr", (CmdImpl) &Text::impl_GetWindowAttr);
141
142        RegisterCommand(1, 4, 100, "wait", (CmdImpl) &Text::impl_Wait);
143        RegisterCommand(1, 4, 111, "time", (CmdImpl) &Text::impl_Wait);
144        RegisterCommand(1, 4, 121, "timeEx", (CmdImpl) &Text::impl_Wait);
145        RegisterCommand(1, 4, 101, "waitC", (CmdImpl) &Text::impl_Wait);
146        RegisterCommand(1, 4, 112, "timeC", (CmdImpl) &Text::impl_Wait);
147        RegisterCommand(1, 4, 131, "GetClick", (CmdImpl) &Text::impl_GetClick);
148
149        RegisterCommand(1, 4, 364, "PauseCursor", (CmdImpl) &Text::impl_PauseCursor);
150        RegisterCommand(1, 4, 3009, "load", (CmdImpl) &Text::impl_load);
151
152        RegisterCommand(1, 4, 500, "InitFrame", (CmdImpl) &Text::impl_InitFrame);
153        RegisterCommand(1, 4, 510, "ReadFrame", (CmdImpl) &Text::impl_ReadFrame);
154        RegisterCommand(1, 4, 620, "InitExFrames", (CmdImpl) &Text::impl_InitFrames);
155        RegisterCommand(1, 4, 624, "InitExFramesDecel", (CmdImpl) &Text::impl_InitFrames);
156        RegisterCommand(1, 4, 630, "ReadExFrames", (CmdImpl) &Text::impl_ReadFrames);
157
158        RegisterCommand(1, 4, 110, "ResetTimer", (CmdImpl) &Text::impl_ResetTimer);
159        RegisterCommand(1, 4, 120, "ResetExTimer", (CmdImpl) &Text::impl_ResetTimer);
160        RegisterCommand(1, 4, 114, "Timer", (CmdImpl) &Text::impl_Timer);
161
162        RegisterCommand(1, 4, 800, "index_series", (CmdImpl) &Text::impl_index_series);
163
164        RegisterCommand(1, 4, 1000, "rnd", (CmdImpl) &Text::impl_rnd);
165        RegisterCommand(1, 4, 1001, "pcnt", (CmdImpl) &Text::impl_pcnt);
166        RegisterCommand(1, 4, 1002, "abs", (CmdImpl) &Text::impl_abs);
167        RegisterCommand(1, 4, 1003, "power", (CmdImpl) &Text::impl_power);
168        RegisterCommand(1, 4, 1004, "sin", (CmdImpl) &Text::impl_sin);
169        RegisterCommand(1, 4, 1007, "min", (CmdImpl) &Text::impl_min);
170        RegisterCommand(1, 4, 1008, "max", (CmdImpl) &Text::impl_max);
171        RegisterCommand(1, 4, 1009, "constrain", (CmdImpl) &Text::impl_constrain);
172}
173
174Text::~Text() {
175        if (sel_widget != NULL)
176                delete sel_widget;
177        int i;
178        for (i=0; i<32; i++) {
179                if (widgets[i] != NULL)
180                        delete widgets[i];
181        }
182        if (backlog_widget != NULL)
183                delete backlog_widget;
184        if (sel_bg1 != NULL)
185                parent.Root().DeleteSurface(sel_bg1);
186        if (sel_bg2 != NULL)
187                parent.Root().DeleteSurface(sel_bg2);
188        event.DeleteGlobalPressFunc(&PressFunc, (void*)this);
189}
190
191bool Text::PressFunc(int x, int y, void* pointer) {
192        Text* t = (Text*)pointer;
193        if (t->status == WAIT_CLICK) {
194                t->status = WAIT_ABORT;
195        } else if (t->status == WAIT_CLICK_MOUSEPOS) {
196                t->status = WAIT_CLICK_MOUSEPOSEND_L;
197        } else if (t->status_mask & CLEARSCR_WAIT_MASK) {
198                t->status_mask = Status(t->status_mask & (~CLEARSCR_WAIT_MASK));
199                if (t->text) t->text->show();
200                if (t->kcursor) {
201                        if (t->status == WAIT_TEXT) t->kcursor->show();
202                }
203                if (t->sel_widget) t->sel_widget->show();
204                if (t->backlog_widget) t->backlog_widget->show();
205        } else if (t->status_mask & BACKLOG_WAIT_MASK) {
206                t->status_mask = Status(t->status_mask | BACKLOG_MASK_KOE);
207        } else if ( (t->skip_mode & SKIP_TEXT) && (!(t->skip_mode & SKIP_IN_MENU)) ) {
208                if (t->status == WAIT_SELECT_INBOX) ;
209                else if (t->status == WAIT_SELECT_OUTBOX) ;
210                else if (t->status == WAIT_SELECT_VALUE) ;
211                else t->status_mask = Status(t->status_mask | SKIPEND_MASK);
212        }
213        return true; // event not deleted
214}
215
216void Text::PressFuncButton(void* pointer, WidButton* from) {
217        Text* t = (Text*)pointer;
218        if (t->status != WAIT_SELECT_INBOX && t->status != WAIT_SELECT_OUTBOX) return;
219        vector<WidTextButton*>::iterator it;
220        int sel = 0;
221        for (it=t->selects.begin(); it != t->selects.end(); it++, sel++) {
222                if (from == *it) break;
223        }
224        if (it == t->selects.end()) {
225                fprintf(stderr,"Text::PressFuncButton: Cannot find select widget\n");
226                return;
227        }
228        t->status = Status(WAIT_SELECT_VALUE + sel);
229}
230
231void Text::SetSkipMode(SkipMode _mode) {
232        if ( (skip_mode & SKIP_IN_MENU) && (_mode & SKIP_IN_MENU) == 0) {
233                if (status_mask & BACKLOG_WAIT_MASK) { // backlog mode から埩垰
234                        status_mask = Status(status_mask & (~(BACKLOG_MASK|BACKLOG_MASK_FWD|BACKLOG_MASK_KOE|BACKLOG_WAIT_MASK)));
235                        text->wid->Clear();
236                        if (status == WAIT_TEXT && text != NULL) {
237                                text->StartText(text_stream);
238                                text->ShowFace(backlog_item.face.c_str());
239                                text->wid->Flush();
240                                if (kcursor) kcursor->show();
241                        }
242                        drawn_backlog_item.Clear();
243                }
244                if (text) text->wid->activate();
245                if (sel_widget) {
246                        sel_widget->show();
247                        if (kcursor) kcursor->hide();
248                }
249                if (backlog_widget) backlog_widget->show();
250                if (status_mask & STATSAVE_MASK) {
251                        status_mask = Status(status_mask & (~STATSAVE_MASK));
252                        status = status_saved;
253                }
254        } else if ( (skip_mode & SKIP_IN_MENU) == 0 && (_mode & SKIP_IN_MENU) ) {
255                if (text) text->wid->deactivate();
256                if (sel_widget) sel_widget->hide();
257                if (backlog_widget) backlog_widget->hide();
258        }
259        skip_mode = _mode;
260}
261
262void Text::InitWindow(void) {
263        int i;
264        int w;
265        std::string str;
266
267        for (w=0; w<32; w++) {
268                widgets[w] = new TextWindow(parent, event, w, (void*)this);
269                if (widgets[w]->wid == 0) {
270                        delete widgets[w];
271                        widgets[w] = NULL;
272                }
273        }
274        SetCursor(0);
275        for (i=0; i<26; i++) {
276                char buf[1024];
277                sprintf(buf, "#NAME.%c", i+'A');
278                const char* s = config->GetParaStr(buf);
279                if (s != NULL) replace_name[i] = s;
280        }
281        // replace_name2 : 初期蚭定
282        // 枚、秋生、枚 (CLANNAD)
283        char name_nagisa[3] = {'\x8f', '\x8d', '\0'};
284        char name_akio[5] = {'\x8f', '\x48', '\x90', '\xb6', '\0'};
285        replace_name2[0] = name_nagisa;
286        replace_name2[1] = name_akio;
287        replace_name2[2] = name_nagisa;
288        text = NULL;
289        /* テキスト速床の蚭定 */
290        int speed, mod, wait, auto_mod;
291        config->GetParam("#INIT_MESSAGE_SPEED", 1, &speed);
292        config->GetParam("#INIT_MESSAGE_SPEED_MOD", 1, &mod);
293        config->GetParam("#MESSAGE_KEY_WAIT_USE", 1, &auto_mod);
294        config->GetParam("#MESSAGE_KEY_WAIT_TIME", 1, &wait);
295        if (mod) speed = -1;
296        if (!auto_mod) wait = -1;
297        SetTextSpeed(speed);
298        SetTextWait(wait);
299}
300
301void Text::Save(string& str, bool rollback_save) {
302        char buf[1024];
303        str = "\n";
304        str += "[TextImpl Window]\n";
305        sprintf(buf, "TextImplWindow=%d\n", text_window_number);
306        str += buf;
307        if (rollback_save) {
308                ++save_selectcount;
309                BacklogItem save_item;
310                save_item.SetSavepos(save_selectcount);
311                backlog.push_back(save_item);
312        }
313        sprintf(buf, "SaveSelectCount=%d\n",save_selectcount);
314
315        str += buf;
316        int i;
317        for (i=0; i<26; i++) {
318                if (replace_name2[i].empty()) continue;
319                sprintf(buf, "RName.%c=%s\n",i+'A',replace_name2[i].c_str());
320                str += buf;
321        }
322        int cnt = 0;
323        vector<BacklogItem>::iterator it;
324        it = backlog.begin();
325        if (!rollback_save) {
326                SaveFaceHash face_log;
327                do {
328                        int cur_scn = -1; int cur_pos = -1;
329                        sprintf(buf, "Backlog.%d=",++cnt);
330                        str += buf;
331                        for (; it != backlog.end(); it++) {
332                                buf[0] = 0;
333                                int buflen = 0;
334                                if (it->scn == -1)
335                                        continue;
336                                if (it->pos == -1 && it->scn != 0)
337                                        continue;
338
339                                buf[buflen++] = ';';
340                                if (it->scn == 0 && it->pos == -1)
341                                        buflen += snprintf(buf+buflen, 1000-buflen, "\"%s\".", it->text.Save().c_str());
342                                else {
343                                        if (cur_scn != -1 && cur_scn != it->scn) break; // scn change
344                                        if (cur_pos != -1 && cur_pos/5000 != it->pos/5000) break; // pos exceeded
345                                        if (!it->text.container.empty()) {
346                                                buflen += snprintf(buf+buflen, 1000-buflen, "\"%s\"", it->text.Save().c_str());
347                                        }
348                                        if (cur_scn == -1) { // scene change
349                                                buflen += snprintf(buf+buflen, 1000-buflen, ":%d:%d",it->scn,it->pos);
350                                                cur_scn = it->scn;
351                                        }
352                                        else
353                                                buflen += snprintf(buf+buflen, 1000-buflen, "%d",it->pos);
354                                        cur_pos = it->pos;
355                                }
356                                if (it->koe != -1)
357                                        buflen += snprintf(buf+buflen, 1000-buflen, ",%d",it->koe);
358                                if (!it->face.empty()) {
359                                        if (it->koe == -1) buf[buflen++] = ',';
360                                        int face_num = face_log.Add(it->face);
361                                        if (face_num >= 0 && face_num < 20)
362                                                buflen += snprintf(buf+buflen, 1000-buflen, ",%c", 'A'+face_num);
363                                        else
364                                                buflen += snprintf(buf+buflen, 1000-buflen, ",\"%s\"", it->face.c_str());
365                                }
366                                buf[buflen++] = '\0';
367                                if (buflen >= 1000) { // 䞇が䞀、バックログアむテムの倧きさが 1000byte を越えるずき
368                                        fprintf(stderr,"Fatal : Cannot save backlog crrectly; Please send bug report to the author.\n");
369                                } else str += buf;
370                        }
371                        str += "\n";
372                } while(it != backlog.end());
373        }
374}
375
376void Text::Load(const char* str) {
377        if (text) text->wid->Clear();
378        hide();
379        text_window_number = 0;
380        save_selectcount = 0;
381        if (sel_widget != NULL) {
382                selects.clear();
383                sel_backlog_pos.clear();
384                delete sel_widget;
385                sel_widget = NULL;
386        }
387        if (backlog_widget != NULL) {
388                delete backlog_widget;
389                backlog_widget = NULL;
390        }
391        status = NORMAL;
392        status_mask = NORMAL;
393        status_saved = NORMAL;
394        text_parsing = false;
395        text_stream.Clear();
396        // backlog.clear();
397        vector<BacklogItem> new_backlog;
398        backlog_item.Clear();
399        cur_backlog_item.Clear();
400        drawn_backlog_item.Clear();
401
402        str = strstr(str, "\n[TextImpl Window]\n");
403
404        if (str) {
405                SaveFaceHash face_log;
406                str += strlen("\n[TextImpl Window]\n");
407                const char* strend = str;
408                do {
409                        str = strend;
410
411                        strend = strchr(str, '\n');
412                        if (strend == NULL) strend = str + strlen(str);
413                        else strend++;
414
415                        if (str[0] == '[') break; // next section
416                        if (strncmp(str, "TextImplWindow=",15) == 0) {
417                                str += 15;
418                                sscanf(str, "%d", &text_window_number);
419                        } else if (strncmp(str, "SaveSelectCount=",16) == 0) {
420                                str += 16;
421                                sscanf(str, "%d", &save_selectcount);
422                        } else if (strncmp(str, "RName.", 6) == 0) {
423                                int n = str[6]-'A';
424                                if (n >= 0 && n < 26 && str[7] == '=') {
425                                        const char* s = strchr(str, '\n');
426                                        int len = -1;
427                                        if (s) len = s-(str+8);
428                                        if (len > 0) {
429                                                replace_name2[n].assign(str+8, len);
430                                        }
431                                }
432                        } else if (strncmp(str, "Backlog.", 8) == 0) {
433                                int cur_scn = -1;
434                                int n = -1;
435                                sscanf(str+8, "%d", &n); /* not used */
436                                const char* next_str = strchr(str, ';');
437                                while(next_str != NULL && next_str < strend) {
438                                        str = next_str + 1;
439                                        next_str = strchr(str, ';');
440                                        if (next_str == NULL) next_str = strend;
441
442                                        BacklogItem item;
443                                        if (str[0] == '"') {
444                                                const char* send = strchr(str+1, '"');
445                                                if (send == NULL || send > next_str) continue;
446                                                string tmp_str; tmp_str.assign(str+1, send-str-1);
447                                                item.DeleteTextPos();
448                                                item.text.Load(tmp_str);
449                                                str = send + 1;
450                                        }
451                                        if (str[0] == '.') {
452                                                item.DeleteTextPos();
453                                                str++;
454                                        } else if (str[0] == ':') {
455                                                sscanf(str, ":%d:%d", &item.scn, &item.pos);
456                                                cur_scn = item.scn;
457                                               
458                                        } else {
459                                                item.scn = cur_scn;
460                                                sscanf(str, "%d", &item.pos);
461                                        }
462                                        str = strchr(str, ',');
463                                        if (str == NULL || str > next_str) goto backlog_store;
464                                        str++;
465                                        if (str[0] == ';' || str[0] == ',')
466                                                item.koe = -1;
467                                        else
468                                                sscanf(str, "%d", &item.koe);
469                                        str = strchr(str, ',');
470                                        if (str == NULL || str > next_str) goto backlog_store;
471                                        str++;
472                                        if (*str == '"') {
473                                                const char* send = strchr(str+1, '"');
474                                                if (send) {
475                                                        item.face.assign(str+1, send-str-1);
476                                                }
477                                        } else if (*str >= 'A' && *str <= 'Z') {
478                                                item.face = face_log.Get(*str - 'A');
479                                        }
480                                        face_log.Add(item.face);
481                                backlog_store:
482                                        new_backlog.push_back(item);
483                                }
484                        }
485                } while (*strend != 0);
486        }
487        if (new_backlog.empty() && (!backlog.empty())) { // empty なら save_selectcount たで backlog を巻き戻す
488                vector<BacklogItem>::iterator it = backlog.end();
489                do {
490                        it--;
491                        if (it->scn == BacklogItem::SaveSelect && it->pos == save_selectcount) {
492                                // Save 䜍眮を芋぀けたらそれ以降を erase
493                                backlog.erase(it, backlog.end());
494                                break;
495                        }
496                } while(it != backlog.begin());
497                --save_selectcount;
498        } else {
499                backlog.swap(new_backlog);
500        }
501        // backlog.clear();
502}
503
504void Text::hide(void) {
505        if (text) text->hide();
506        if (kcursor) kcursor->hide();
507        text = NULL;
508}
509void Text::show(int num) {
510        if (num != text_window_number) {
511                hide();
512                if (num >= 0 && num < 32 && widgets[num] != 0) {
513                        text_window_number = num;
514                }
515        }
516        text = widgets[text_window_number];
517        text->show();
518        if (kcursor) {
519                int kx, ky, d;
520                char key[1024];
521                sprintf(key, "#WINDOW.%03d.KEYCUR_MOD", text_window_number);
522                config->GetParam(key, 3, &d, &kx, &ky);
523                // 正しくない気がする
524                kx += text->wid->Pic()->PosX();
525                ky += text->wid->Pic()->PosY();
526                // 埮劙に䞋にする
527                ky += 8;
528                kcursor->Pic()->Move(kx, ky);
529        }
530}
531
532void Text::DrawBacklog(BacklogItem& item, Cmd& cmd) {
533        show();
534        text->wid->deactivate();
535        status_mask = Status(status_mask | BACKLOG_WAIT_MASK);
536        drawn_backlog_item = item;
537        if (item.text.container.empty()) {
538                // cmd から text 内容を再構成
539                TextStream saved_text = text_stream;
540                text_stream.Clear();
541                AddText(cmd.Str(cmd.args[0]));
542                item.text = text_stream;
543                text_stream = saved_text;
544        }
545        item.text.InsertColor(0, item.text.container.size(), 0xff,0xff,0);
546        text->StartText(item.text);
547        text->wid->Flush();
548        if (item.face.empty()) text->ResetFace();
549        else text->ShowFace(item.face.c_str());
550        if (kcursor) kcursor->hide();
551}
552
553void Text::CreateSelBG(void) {
554        if (sel_bg1 != NULL || sel_bg2 != NULL) return;
555
556        const char* btnfile1 = config->GetParaStr("#SELBTN.000.NAME");
557        const char* btnfile2 = config->GetParaStr("#SELBTN.000.BACK");
558        char path[1024];
559        strcpy(path, btnfile1);
560        sel_bg1 = parent.Root().NewSurface(path);
561        if (sel_bg1 == NULL) {
562                sprintf(path,"%s.g00",btnfile1);
563                sel_bg1 = parent.Root().NewSurface(path);
564        }
565        strcpy(path, btnfile2);
566        sel_bg2 = parent.Root().NewSurface(path);
567        if (sel_bg2 == NULL) {
568                sprintf(path,"%s.g00",btnfile2);
569                sel_bg2 = parent.Root().NewSurface(path);
570        }
571        sel_bg_rect = Rect(0,0,0,0);
572        if (sel_bg1) sel_bg_rect.join(Rect(*sel_bg1));
573        if (sel_bg2) sel_bg_rect.join(Rect(*sel_bg2));
574}
575
576void Text::CreateSelect(Cmd& cmd) {
577        char key[23];
578        sprintf(key, "#WINDOW.%03d.SELCOM_USE",text_window_number);
579        int sel_type = 0;
580        if (cmd.cmd3 == 1) config->GetParam(key, 1, &sel_type);
581        else if (cmd.cmd3 == 3) sel_type = 0;
582
583        int sel_size = cmd.args.size() / 2;
584        int i;
585        // cur_backlog_item に次にbacklogに入るべき内容を䜜成
586        // CreateSelect() 埌、SAVEPOINT なので珟圚のbacklogの内容(前のメッセヌゞ)が
587        // backlog に代入される。その埌、backlog_item に cur_backlog_item の内容がセットされる(Wait()内)
588        char backlog_sel_text[11] = {0x81,0x69,0x91,0x49,0x91,0xf0,0x8e,0x88,0x81,0x6a,0x00};
589        cur_backlog_item.Clear();
590        cur_backlog_item.AddTextPos(cmd);
591        cur_backlog_item.text.Add(backlog_sel_text);
592        cur_backlog_item.text.AddReturn();
593        sel_backlog_pos.clear();
594        for (i=0; i<sel_size; i++) {
595                sel_backlog_pos.push_back(cur_backlog_item.text.container.size());
596                cur_backlog_item.text.Add(cmd.Str(cmd.args[i*2]));
597                cur_backlog_item.text.AddReturn();
598        }
599        sel_backlog_pos.push_back(cur_backlog_item.text.container.size());
600
601        if (sel_type == 0) { // Princess Bride: 遞択りィンドりを別衚瀺
602External_select:
603                CreateSelBG();
604                hide(); // なので、テキストりィンドりは消去
605                int baseposx, baseposy, repposx, repposy, centerx, centery;
606                int mojisize, col1, col2;
607                config->GetParam("#SELBTN.000.CENTERING", 2, &centerx, &centery);
608                config->GetParam("#SELBTN.000.BASEPOS", 2, &baseposx, &baseposy);
609                config->GetParam("#SELBTN.000.REPPOS", 2, &repposx, &repposy);
610                config->GetParam("#SELBTN.000.MOJISIZE", 1, &mojisize);
611                config->GetParam("#SELBTN.000.MOJIDEFAULTCOL", 1, &col1);
612                config->GetParam("#SELBTN.000.MOJISELECTCOL", 1, &col2);
613                if (col1 == col2) col2 = 1; // CLANNAD でずりあえず。
614                int r, g, b;
615                sprintf(key, "#COLOR_TABLE.%03d", col1);
616                config->GetParam(key, 3, &r, &g, &b);
617                Color fore(r,g,b);
618                sprintf(key, "#COLOR_TABLE.%03d", col2);
619                config->GetParam(key, 3, &r, &g, &b);
620                Color seled(r,g,b);
621
622                /* りィゞット䜜成 */
623                /* りィンドり背景の倧きさを求める */
624                if (baseposx == 0 && sel_bg_rect.width() != 0)
625                        baseposx = (parent.Width()-sel_bg_rect.width()) / 2; // ボタン䜍眮をセンタリング
626                if (centerx)
627                        baseposx = (parent.Width()-sel_bg_rect.width()-sel_size*repposx) / 2;
628                if (centery)
629                        baseposy = (parent.Height()-sel_bg_rect.height()-sel_size*repposy) / 2;
630
631                sel_widget = parent.create_node( Rect(0, 0, parent.Width(), parent.Height()),0);
632
633                for (i=0; i<sel_size; i++) {
634                        PicBase* p;
635                        // 背景䜜成
636                        if (sel_bg2) {
637                                p = sel_widget->create_node(Rect(baseposx, baseposy, baseposx+sel_bg_rect.width(), baseposy+sel_bg_rect.height()),0);
638                                p->SetSurface(sel_bg2, 0, 0);
639                        }
640                        if (sel_bg1) {
641                                p = sel_widget->create_node(Rect(baseposx, baseposy, baseposx+sel_bg_rect.width(), baseposy+sel_bg_rect.height()),0);
642                                p->SetSurface(sel_bg1, 0, 0);
643                        }
644                        /* ボタン䜜成 */
645                        const char* str = cmd.Str(cmd.args[i*2]);
646                        int value = cmd.args[i*2+1].value;
647                        while(selects.size() <= value) selects.push_back(0); // vector の倧きさを広げる
648
649                        kconv( (const unsigned char*)str, (unsigned char*)key);
650                        selects[value] = new WidTextButton(event, sel_widget, key, mojisize, WidTextButton::CENTER,
651                                Rect(baseposx, baseposy, baseposx+sel_bg_rect.width(), baseposy+sel_bg_rect.height()), 1, fore, seled, Color(0,0,0,0));
652                        selects[value]->press_func = &PressFuncButton;
653                        selects[value]->press_pointer = (void*)this;
654
655                        baseposx += repposx;
656                        baseposy += repposy;
657                }
658                sel_widget->show_all();
659                status = WAIT_SELECT_OUTBOX;
660        } else { // CLANNAD: テキストりィンドり内に遞択肢衚瀺
661                int mojisize;
662                config->GetParam("#SELBTN.000.MOJISIZE", 1, &mojisize);
663                Color fore(0xff,0xff,0xff);
664                Color seled(0xff,0xff,0xff);
665
666                show();
667                if (text == NULL) goto External_select; // テキスト・りィンドりを衚瀺できなければ倖郚遞択肢にする
668                text->wid->Clear();
669                if (kcursor) kcursor->hide();
670                /* りィゞット䜜成  : テキスト衚瀺範囲ず同じ*/
671                int posx = text->wid->pictext->PosX();
672                int posy = text->wid->pictext->PosY();
673                int sel_w = text->wid->pictext->Width();
674                int sel_h = text->wid->pictext->Height();
675                sel_widget = text->wid->PicNode()->create_node(Rect(posx, posy, posx+sel_w, posy+sel_h), 0);
676
677                int sel_y = 0;
678                for (i=0; i<sel_size; i++) {
679                        /* ボタン䜜成 */
680                        const char* str = cmd.Str(cmd.args[i*2]);
681                        int value = cmd.args[i*2+1].value;
682                        while(selects.size() <= value) selects.push_back(0); // vector の倧きさを広げる
683
684                        kconv( (const unsigned char*)str, (unsigned char*)key);
685                        selects[value] = new WidTextButton(event, sel_widget, key, mojisize, WidTextButton::Attribute(WidTextButton::REVERSE | WidTextButton::NOPADDING),
686                                Rect(0, sel_y, sel_w, sel_y), 1, fore, seled, Color(0,0,0,0));
687                        selects[value]->press_func = &PressFuncButton;
688                        selects[value]->press_pointer = (void*)this;
689
690                        sel_y += selects[value]->Pic()->Height() + 1;
691                }
692                sel_widget->show_all();
693                status = WAIT_SELECT_INBOX;
694        }
695}
696
697void Text::AddText(const char* str_o) {
698        char str[10001];
699        if (text == NULL) return;
700        /* たず、replace string を倉換 */
701        int i;
702        int cnt = 0;
703        /*  = 81 96 A-Z = 0x82 [0x60-0x79] */
704        /*  = 81 93 A-Z = 0x82 [0x60-0x79] */
705        for (i=0; cnt<10000 && str_o[i] != 0; i++) {
706                if (str_o[i] < 0) {
707                        if ( (unsigned char)str_o[i] == 0x81 && (unsigned char)str_o[i+1] == 0x96 && (unsigned char)str_o[i+2] == 0x82) {
708                                int c = str_o[i+3];
709                                if (c >= 0x60 && c <= 0x79 && replace_name[c-0x60].length() != 0) { // 名前倉換
710                                        i += 3;
711                                        strcpy(str+cnt, replace_name[c-0x60].c_str());
712                                        cnt += replace_name[c-0x60].length();
713                                        continue;
714                                }
715                        } else if ( (unsigned char)str_o[i] == 0x81 && (unsigned char)str_o[i+1] == 0x93 && (unsigned char)str_o[i+2] == 0x82) {
716                                int c = str_o[i+3];
717                                if (c >= 0x60 && c <= 0x79 && replace_name2[c-0x60].length() != 0) { // 名前倉換
718                                        i += 3;
719                                        strcpy(str+cnt, replace_name2[c-0x60].c_str());
720                                        cnt += replace_name2[c-0x60].length();
721                                        continue;
722                                }
723                        }
724                        str[cnt++] = str_o[i++];
725                }
726                str[cnt++] = str_o[i];
727        }
728        str[cnt] = 0;
729        str[10000] = 0;
730        char* str_top = str;
731
732        for (char* s = str_top; *s != 0; s++) {
733                // if (*(unsigned char*)s == 0xa1 && *(unsigned char*)(s+1) == 0xda) { /* euc */
734                if (*(unsigned char*)s == 0x81 && *(unsigned char*)(s+1) == 0x79) { /* sjis */
735                        // 名前
736                        *s = 0;
737                        if (s != str_top) text_stream.Add(str_top);
738                        s += 2;
739                        char* name_top = s;
740                        for (; *s != 0; s++) {
741                                // if (*(unsigned char*)s == 0xa1 && *(unsigned char*)(s+1) == 0xdb) { /* euc */
742                                if (*(unsigned char*)s == 0x81 && *(unsigned char*)(s+1) == 0x7a) { /* sjis */
743                                        *s = 0;
744                                        s += 2;
745                                        text_stream.AddName(name_top);
746                                        break;
747                                }
748                                if (*s < 0 && s[1] != 0) s++; // 党角文字なら字飛ばす
749                        }
750                        str_top = s;
751                }
752                if (*s == 0x0a) {
753                        *s = 0;
754                        text_stream.Add(str_top);
755                        text_stream.AddReturn();
756                        str_top = s;
757                } else if (*s < 0 && s[1] != 0) s++;
758        }
759        text_stream.Add(str_top);
760}
761
762void Text::Exec(Cmd& cmd) {
763        if (cmd.cmd_type == CMD_TEXT) {
764                if (text == NULL) {
765                        show();
766                }
767                if (cmd.args.size() != 1) return;
768                if (ruby_text_flag) {
769                        ruby_text = cmd.Str(cmd.args[0]);
770                        ruby_text_flag = 0;
771                        cmd.clear();
772                        return;
773                }
774                cur_backlog_item.AddTextPos(cmd);
775                AddText(cmd.Str(cmd.args[0]));
776                char debug[1024];
777                kconv( (unsigned char*)cmd.Str(cmd.args[0]), (unsigned char*)debug);
778                eprintf("text: %s\n",debug);
779                if (text_parsing)
780                        cmd.clear();
781                else
782                        cmd.cmd_type = CMD_SAVEPOINT;
783                text_parsing = true; /* テキスト埅ち盎埌のテキスト䜍眮セヌブ䜍眮 */
784                return;
785        }
786
787        if (cmd.cmd_type != CMD_OTHER) return;
788
789        CommandHandler::Exec(cmd);
790}
791
792extern int print_blit;
793bool Text::Wait(unsigned int current_time, Cmd& cmd) {
794        if (current_time != Event::Time::NEVER_WAKE) old_time = current_time;
795/*
796if (event.presscount(MOUSE_UP)) {
797if (text) text->Pic()->ReBlit();
798}
799if (event.presscount(MOUSE_DOWN)) {
800print_blit^=1;
801}
802*/
803
804        if (status == NORMAL && status_mask == NORMAL) return false;
805
806        if (status_mask & WAIT_EXTRN_MASK) return true;
807        if (status_mask & (BACKLOG_MASK|BACKLOG_MASK_FWD) ) {
808                if (status_mask & BACKLOG_WAIT_MASK) ;
809                else {
810                        if ( (status == WAIT_TEXT && text != NULL) || status == WAIT_SELECT_INBOX || status == WAIT_SELECT_OUTBOX) {
811                                if(text && text->wid->status != WidText::PREPARE && text->wid->status != WidText::WAIT && text->wid->status != WidText::WAIT2) {
812                                        text->wid->Flush(); // 衚瀺を最埌の状態にする
813                                }
814                                if (status == WAIT_TEXT && text != NULL && kcursor != NULL) kcursor->show();
815                        }
816                }
817                if (status_mask & BACKLOG_MASK) {
818                        cmd.cmd_type = CMD_BACKLOGREQ;
819                } else {
820                        cmd.cmd_type = CMD_BACKLOGREQ_FWD;
821                }
822                status_mask = Status(status_mask & ~(BACKLOG_MASK|BACKLOG_MASK_FWD));
823                return false;
824        }
825        if ( (status_mask & BACKLOG_WAIT_MASK) && (status_mask & BACKLOG_MASK_KOE)) {
826                if (drawn_backlog_item.koe != -1) {
827                        cmd.cmd_type = CMD_OTHER;
828                        cmd.cmd1 = 1;
829                        cmd.cmd2 = 0x17;
830                        cmd.cmd3 = 0;
831                        cmd.cmd4 = 1;
832                        cmd.args.clear();
833                        cmd.args.push_back(VarInfo(drawn_backlog_item.koe));
834                        cmd.args.push_back(VarInfo(0));
835                }
836                status_mask = Status(status_mask & ~BACKLOG_MASK_KOE);
837                return false;
838        }
839        if (skip_mode & SKIP_IN_MENU) return false;
840        if (status_mask & SAVEMASK) {
841                cmd.cmd_type = CMD_SAVEREQ;
842                status_mask = Status(status_mask & ~SAVEMASK);
843                return false;
844        }
845        if (status_mask & LOADMASK) {
846                cmd.cmd_type = CMD_LOADREQ;
847                status_mask = Status(status_mask & ~LOADMASK);
848                return false;
849        }
850        if (status_mask & SKIPEND_MASK) {
851                if ( (skip_mode & SKIP_TEXT) && (skip_mode & SKIPEND_TEXT)) {
852                        if (skip_mode & SKIPEND_KEY) { // shift skip äž­
853                                SkipMode new_mode = SkipMode(skip_mode & (~SKIPEND_TEXT));
854                                if (new_mode & (SKIP_GRP_NOEFFEC || SKIP_GRP_NODRAW))
855                                        new_mode = SkipMode(new_mode & (~SKIP_GRP_FAST));
856                                cmd.SetSysvar(TYPE_SYS_SKIPMODE, new_mode);
857                        } else {
858                                cmd.SetSysvar(TYPE_SYS_SKIPMODE, SKIP_NO);
859                        }
860                }
861                status_mask = Status(status_mask & ~SKIPEND_MASK);
862        }
863        if (status_mask & SKIPMASK) {
864                if (skip_mode != SKIP_NO) {
865                        cmd.SetSysvar(TYPE_SYS_SKIPMODE, skip_mode | SKIPEND_TEXT);
866                } else {
867                        cmd.SetSysvar(TYPE_SYS_SKIPMODE, SKIP_TEXT | SKIP_GRP_FAST | SKIPEND_TEXT);
868                }
869                status_mask = Status(status_mask & ~SKIPMASK);
870                return false;
871        }
872        if (event.presscount(MOUSE_RIGHT)) {
873                if ( (status == WAIT_TEXT && text != NULL) || status == WAIT_SELECT_INBOX || status == WAIT_SELECT_OUTBOX) {
874                        if(text && text->wid->status != WidText::PREPARE && text->wid->status != WidText::WAIT && text->wid->status != WidText::WAIT2) {
875                                text->wid->Flush(); // 衚瀺を最埌の状態にする
876                        }
877                        cmd.cmd_type = CMD_MENUREQ;
878                        if (!(status_mask & STATSAVE_MASK)) {
879                                status_saved = status;
880                                status_mask = Status(status_mask | STATSAVE_MASK);
881                        }
882                        return false;
883                } else if (status == WAIT_CLICK_MOUSEPOS) {
884                        status = WAIT_CLICK_MOUSEPOSEND_R;
885                }
886        }
887        if (event.presscount(MOUSE_UP)) {
888                if ( (status == WAIT_TEXT && text != NULL) || status == WAIT_SELECT_INBOX || status == WAIT_SELECT_OUTBOX) {
889                        if(text && text->wid->status != WidText::PREPARE && text->wid->status != WidText::WAIT && text->wid->status != WidText::WAIT2) {
890                                text->wid->Flush(); // 衚瀺を最埌の状態にする
891                        }
892                        cmd.cmd_type = CMD_BACKLOGREQ;
893                        if (!(status_mask & STATSAVE_MASK)) {
894                                status_saved = status;
895                                status_mask = Status(status_mask | STATSAVE_MASK);
896                        }
897                        return false;
898                }
899        }
900        if (status_mask & CLEARSCR_MASK) {
901                if ( (status == WAIT_TEXT && text != NULL ) || status == WAIT_SELECT_INBOX || status == WAIT_SELECT_OUTBOX) {
902                        if (skip_mode) skip_mode = SKIP_NO;
903                        if (text && text->wid->status != WidText::PREPARE && text->wid->status != WidText::WAIT && text->wid->status != WidText::WAIT2) {
904                                text->wid->Flush(); // 衚瀺を最埌の状態にする
905                                return true;
906                        }
907                        status_mask = Status(status_mask & (~CLEARSCR_MASK) | CLEARSCR_WAIT_MASK);
908                        if (text != NULL) text->hide();
909                        if (kcursor != NULL) kcursor->hide();
910                        if (sel_widget != NULL) sel_widget->hide();
911                        if (backlog_widget != NULL) backlog_widget->hide();
912                        return true;
913                }
914                status_mask = Status(status_mask & (~CLEARSCR_MASK));
915                return false;
916        }
917        if (status_mask & CLEARSCR_WAIT_MASK) {
918                return true;
919        }
920        if (status == WAIT_TEXT) {
921                if (text == NULL) {
922                        status = NORMAL;
923                        return false;
924                }
925                if (skip_mode & SKIP_TEXT) {
926                } else if (text->wid->status != WidText::PREPARE) {
927                        return true;
928                }
929                if (kcursor != NULL) kcursor->hide();
930                text_stream.Clear();
931                status = NORMAL;
932                cmd.cmd_type = CMD_TEXTEND;
933                return false;
934        }
935        if (status == WAIT) {
936                if (skip_mode & SKIP_TEXT) ;
937                else if (wait_time > current_time) return true;
938                status = NORMAL;
939        } else if (status == WAIT_CLICK) {
940                if (skip_mode & SKIP_TEXT) ;
941                else if (wait_time > current_time) return true;
942                status = NORMAL;
943                cmd.SetSysvar(0);
944        } else if (status == WAIT_ABORT) {
945                cmd.SetSysvar(1);
946                status = NORMAL;
947        } else if (status == WAIT_CLICK_MOUSEPOS || status == WAIT_CLICK_MOUSEPOSEND_L || status == WAIT_CLICK_MOUSEPOSEND_R) {
948                if (status == WAIT_CLICK_MOUSEPOS && (skip_mode & SKIP_TEXT) == 0) return true; // keep wait
949                else {
950                        int x, y;
951                        event.MousePos(x,y);
952                        if (status == WAIT_CLICK_MOUSEPOS) x = y = 0; // skip mode
953                        cmd.clear();
954                        cmd.SetFlagvar(wait_savedvar[0], x);
955                        cmd.SetFlagvar(wait_savedvar[1], y);
956                        if (status == WAIT_CLICK_MOUSEPOSEND_R) cmd.SetSysvar(-1);
957                        else cmd.SetSysvar(0);
958                        status = NORMAL;
959                }
960        } else if (status == WAIT_SELECT_INBOX || status == WAIT_SELECT_OUTBOX) {
961                return true;
962        } else if ( int(status) >= WAIT_SELECT_VALUE) {
963                int sel_val = int(status) - WAIT_SELECT_VALUE;
964                cmd.SetSysvar(sel_val);
965                selects.clear();
966                delete sel_widget;
967                sel_widget = NULL;
968                status = NORMAL;
969                // CreateSelect() で䜜成された cur_backlog_item を backlog_item ぞ反映させる
970                cur_backlog_item.text.InsertColor(sel_backlog_pos[sel_val], sel_backlog_pos[sel_val+1], 0xff, 0, 0);
971                backlog_item = cur_backlog_item;
972                cur_backlog_item.Clear();
973        }
974        return false;
975}
976
977void clearbtn_press(void* pointer, WidButton* button) {
978        if (pointer == NULL) return;
979        Text* t = (Text*)pointer;
980        t->status_mask = Text::Status(t->status_mask | Text::CLEARSCR_MASK);
981}
982
983void Text::PressFuncSkip(void* pointer, WidButton* from) {
984        if (pointer == NULL) return;
985        Text* t = (Text*)pointer;
986        t->status_mask = Text::Status(t->status_mask | Text::SKIPMASK);
987        return;
988}
989void Text::PressFuncLoad(void* pointer, WidButton* from) {
990        if (pointer == NULL) return;
991        Text* t = (Text*)pointer;
992        t->status_mask = Text::Status(t->status_mask | Text::LOADMASK);
993}
994
995void Text::PressFuncSave(void* pointer, WidButton* from) {
996        if (pointer == NULL) return;
997        Text* t = (Text*)pointer;
998        t->status_mask = Text::Status(t->status_mask | Text::SAVEMASK);
999}
1000
1001void Text::PressFuncBacklog(void* pointer, WidButton* from) {
1002        if (pointer == NULL) return;
1003        Text* t = (Text*)pointer;
1004        t->status_mask = Text::Status(t->status_mask | Text::BACKLOG_MASK);
1005}
1006
1007void Text::PressFuncBacklogFwd(void* pointer, WidButton* from) {
1008        if (pointer == NULL) return;
1009        Text* t = (Text*)pointer;
1010        t->status_mask = Text::Status(t->status_mask | Text::BACKLOG_MASK_FWD);
1011}
1012
1013void movebtn_drag(int from_x, int from_y, int x, int y, void* pointer, WidButton* button) {
1014        if (pointer == NULL) return;
1015        fprintf(stderr,"drag.\n");
1016}
1017
1018#define BTNCNT 10
1019static const char* btnname[BTNCNT] = {
1020        "MOVE",
1021        "CLEAR",
1022        "READJUMP",
1023        "AUTOMODE",
1024        "MSGBK",
1025        "MSGBKLEFT",
1026        "MSGBKRIGHT",
1027        "EXBTN_000",
1028        "EXBTN_001",
1029        "EXBTN_002"
1030};
1031
1032static int btnpos[BTNCNT] = { // g00 ファむル内のボタン情報の䜍眮
1033//      0, 1, 13, 12, 2, 3, 4, 5, 6, 7 // princess bride?
1034        0, 1, 13, 14, 2, 3, 4, 5, 6, 7 // tomoyo after?
1035};
1036
1037static WidButton::PressFunc btnpress[BTNCNT] = {
1038        0, clearbtn_press, &Text::PressFuncSkip,0,&Text::PressFuncBacklogFwd,&Text::PressFuncBacklog,&Text::PressFuncBacklogFwd,&Text::PressFuncSave,&Text::PressFuncLoad,0
1039};
1040
1041static WidButton::DragFunc btndrag[BTNCNT] = {
1042        movebtn_drag, 0,0,0,0, 0,0,0,0, 0
1043};
1044
1045void Text::SetTextSpeed(int speed) {
1046        // 100 : 10char / sec
1047        // 10 : 100char / sec
1048        // text widget:
1049        if (speed <= 0) speed = -1;
1050        else if (speed > 1000) speed = 1;
1051        else speed = 1000 / speed;
1052        int i;
1053        for (i=0; i<32; i++)
1054                if (widgets[i]) widgets[i]->wid->SetSpeed(speed);
1055}
1056
1057void Text::SetTextWait(int wait) {
1058        int i;
1059        for (i=0; i<32; i++)
1060                if (widgets[i]) widgets[i]->wid->SetWait(wait);
1061}
1062
1063void Text::SetWindowColor(int r, int g, int b, int a, bool is_transparent) {
1064        char key[1024];
1065        int w;
1066
1067        for (w=0; w<32; w++) {
1068                if (widgets[w] == NULL) continue;
1069                sprintf(key, "#WAKU.%03d.000.BACK", w);
1070                const char* back = config->GetParaStr(key);
1071                if (back == NULL || back[0] == 0) continue;
1072                sprintf(key, "%s.g00", back);
1073                Surface* back_s = parent.Root().NewSurface(key);
1074                if (back_s == NULL) continue;
1075                Rect rect(*back_s);
1076                Surface* new_s = parent.Root().NewSurface(rect.width(), rect.height(), ALPHA_MASK);
1077                DSurfaceMove(back_s, rect, new_s, rect);
1078                DSurfaceFillA(new_s, rect, r, g, b, a);
1079                widgets[w]->wid->Pic()->SetSurface(new_s, 0, 0);
1080                widgets[w]->wid->Pic()->SetSurfaceFreeFlag(1);
1081                if (!is_transparent)
1082                        widgets[w]->wid->Pic()->SetSurfaceAttribute(PicBase::BLIT_MULTIPLY);
1083                parent.Root().DeleteSurface(back_s);
1084        }
1085}
1086
1087void Text::SetCursor(int cursor_no) {
1088        char key[1024];
1089        sprintf(key, "#CURSOR.%03d.NAME", cursor_no);
1090        string path = config->GetParaStr(key);
1091        if (path.length() == 0) return; // 名前なし
1092        path += ".pdt";
1093        int w,h,cont,speed;
1094        sprintf(key, "#CURSOR.%03d.SIZE", cursor_no);
1095        config->GetParam(key, 2, &w, &h);
1096        sprintf(key, "#CURSOR.%03d.CONT", cursor_no);
1097        config->GetParam(key, 1, &cont);
1098        sprintf(key, "#CURSOR.%03d.SPEED", cursor_no);
1099        config->GetParam(key, 1, &speed);
1100
1101        // speed で呚、cont 回倉化
1102        if (kcursor != NULL) delete kcursor;
1103
1104        kcursor = new WidTimeCursor(event, speed/cont, &parent, path.c_str(), 0, 0, w, 0, cont, Rect(0,0,w,h));
1105        int i;
1106        for (i=0; i<32; i++) {
1107                if (widgets[i]) widgets[i]->wid->SetCursor(kcursor);
1108        }
1109}
1110
1111void kconv(const unsigned char* src, unsigned char* dest) { //FIXME: code duplication?
1112        /* input : sjis output: euc */
1113        while(*src) {
1114                unsigned int high = *src++;
1115                if (high < 0x80) {
1116                        /* ASCII */
1117                        *dest++ = high; continue;
1118                } else if (high < 0xa0) {
1119                        /* SJIS */
1120                        high -= 0x71;
1121                } else if (high < 0xe0) {
1122                        /* hankaku KANA */
1123                        *dest++ = 0x8e; *dest++ = high;
1124                        continue;
1125                } else { /* high >= 0xe0 : SJIS */
1126                        high -= 0xb1;
1127                }
1128                /* SJIS convert */
1129                high = (high<<1) + 1;
1130
1131                unsigned int low = *src++;
1132                if (low == 0) break; /* incorrect code */
1133                if (low > 0x7f) low--;
1134                if (low >= 0x9e) {
1135                        low -= 0x7d;
1136                        high++;
1137                } else {
1138                        low -= 0x1f;
1139                }
1140                *dest++ = high | 0x80; *dest++ = low | 0x80;
1141        }
1142        *dest = 0;
1143}
1144
1145void kconv_rev(const unsigned char* src, unsigned char* dest) { //FIXME: code duplication?
1146        /* input : euc output: sjis */
1147        while(*src) {
1148                unsigned int high = *src++;
1149                if (high < 0x80) {
1150                        /* ASCII */
1151                        *dest++ = high; continue;
1152                } else if (high == 0x8e) { /* hankaku KANA */
1153                        high = *src;
1154                        if (high >= 0xa0 && high < 0xe0)
1155                                *dest++ = *src++;
1156                        continue;
1157                } else {
1158                        unsigned int low = *src++;
1159                        if (low == 0) break; /* incorrect code , EOS */
1160                        if (low < 0x80) continue; /* incorrect code */
1161                        /* convert */
1162                        low &= 0x7f; high &= 0x7f;
1163                        low += (high & 1) ? 0x1f : 0x7d;
1164                        high = (high-0x21)>>1;
1165                        high += (high > 0x1e) ? 0xc1 : 0x81;
1166                        *dest++ = high;
1167                        if (low > 0x7f) low++;
1168                        *dest++ = low;
1169                }
1170        }
1171        *dest = 0;
1172}
1173
1174string kconv(const string& s) {
1175        char* out = new char[s.length()*2+100];
1176        kconv((const unsigned char*)s.c_str(), (unsigned char*)out);
1177        string ret = out;
1178        delete[] out;
1179        return ret;
1180}
1181
1182string kconv_rev(const string& s) {
1183        char* out = new char[s.length()*2+100];
1184        kconv_rev((const unsigned char*)s.c_str(), (unsigned char*)out);
1185        string ret = out;
1186        delete[] out;
1187        return ret;
1188}
1189
1190/**************************************************************::
1191**
1192**      BacklogItem
1193*/
1194
1195BacklogItem::BacklogItem(void) {
1196        scn = -1;
1197        pos = -1;
1198        koe = -1;
1199        face = "";
1200        text.kanji_type = TextStream::sjis;
1201}
1202
1203void BacklogItem::Clear(void) {
1204        scn = -1;
1205        pos = -1;
1206        koe = -1;
1207        text.Clear();
1208}
1209
1210void BacklogItem::AddTextPos(Cmd& cmd) {
1211        if (scn == -1 && pos == -1) {
1212                scn = cmd.scn;
1213                pos = cmd.pos;
1214                return;
1215        }
1216        DeleteTextPos();
1217}
1218
1219void BacklogItem::DeleteTextPos(void) {
1220        scn = 0;
1221        pos = -1;
1222}
1223
1224BacklogItem& BacklogItem::operator =(const BacklogItem& p) {
1225        scn = p.scn;
1226        pos = p.pos;
1227        koe = p.koe;
1228        face = p.face;
1229        text = p.text;
1230}
1231
1232void BacklogItem::SetSavepos(int p) {
1233        Clear();
1234        scn = SaveSelect;
1235        pos = p;
1236}
1237
1238
1239/**************************************************************::
1240**
1241**      TextWindow
1242*/
1243
1244Rect TextWindow::WakuSize(PicContainer& pic, int waku_no) {
1245        char key[1024];
1246        sprintf(key, "#WAKU.%03d.000.NAME", waku_no);
1247        const char* name = AyuSysConfig::GetInstance()->GetParaStr(key);
1248        if (name == NULL) return Rect(0,0,0,0);
1249        std::string str = name; str += ".g00";
1250        Surface* s = pic.Root().NewSurface(str.c_str());
1251        if (s == NULL) return Rect(0,0,0,0);
1252        Rect r(*s);
1253        pic.Root().DeleteSurface(s);
1254        return r;
1255}
1256
1257void TextWindow::MakeWaku(PicContainer& pic, Event::Container& event, int waku_no, int window_no, bool* use_btn, void* callback) {
1258        AyuSysConfig *config = AyuSysConfig::GetInstance();
1259        char key[1024];
1260        std::string str;
1261        /* 枠を䜜成 */
1262        sprintf(key, "#WAKU.%03d.000.NAME", waku_no);
1263        const char* name = config->GetParaStr(key);
1264        if (name != NULL && name[0] == 0) name = NULL;
1265        sprintf(key, "#WAKU.%03d.000.BACK", waku_no);
1266        const char* back = config->GetParaStr(key);
1267        if (back != NULL && back[0] == 0) back = NULL;
1268        sprintf(key, "#WAKU.%03d.000.BTN", waku_no);
1269        const char* btn = config->GetParaStr(key);
1270        if (btn != NULL && btn[0] == 0) btn = NULL;
1271
1272        if (name == NULL && back == NULL && btn == NULL) return;
1273
1274        /* たず、テキスト背景を蚭定 */
1275        if (back != NULL) {
1276                str = back; str += ".g00";
1277                int rc, gc, bc, ac, flag;
1278                char key[1024];
1279                sprintf(key, "#WINDOW.%03d.ATTR", window_no);
1280                if (config->GetParam(key, 5, &rc, &gc, &bc, &ac, &flag) == -1) {
1281                        config->GetParam("#WINDOW_ATTR", 5, &rc, &gc, &bc, &ac, &flag);
1282                }
1283                Surface* back_s = pic.Root().NewSurface(str.c_str());
1284                if (back_s != NULL) {
1285                        Rect rect(*back_s);
1286                        Surface* s = pic.Root().NewSurface(rect.width(), rect.height(), ALPHA_MASK);
1287                        DSurfaceMove(back_s, rect, s, rect);
1288                        DSurfaceFillA(s, rect, rc, gc, bc, ac); // 透明床蚭定
1289                        pic.SetSurface(s, 0, 0);
1290                        pic.SetSurfaceFreeFlag(1);
1291                        if (flag == 0) wid->Pic()->SetSurfaceAttribute(PicBase::BLIT_MULTIPLY);
1292                        pic.Root().DeleteSurface(back_s);
1293                }
1294        }
1295        /* その前に枠食りを蚭定 */
1296        if (name != NULL) {
1297                str = name; str += ".g00";
1298                Surface* s = pic.Root().NewSurface(str.c_str());
1299                if (s) {
1300                        Rect rect(*s);
1301                        pic.Root().DeleteSurface(s);
1302                        PicBase* p = pic.create_leaf(Rect(0, 0, rect.width(), rect.height()),0);
1303                        p->SetSurface(str.c_str(), 0, 0);
1304                        p->ZMove(ZMOVE_BOTTOM);
1305                        p->show();
1306                }
1307        }
1308        if (btn == NULL) return;
1309        if (use_btn == NULL) return;
1310        // ボタンの䜜成
1311        // 䜿甚するボタンに぀いおは、必芁に応じお show() するこず
1312
1313        /* ボタンの䜍眮情報を求める */
1314        str = btn; str += ".g00";
1315        ARCINFO* info = FileSearcher::GetInstance()->Find(FileSearcher::PDT, str.c_str(), "g00");
1316        if (info == NULL) return; // cannot find file
1317        const char* data = info->Read();
1318        /* g00 ファむルのヘッダ郚分に䜍眮情報は入っおいる */
1319        /* 存圚しなければボタン画像ではない */
1320        if (data == NULL || *data != 2) {
1321                delete info;
1322                return;
1323        }
1324        int index_count = read_little_endian_int(data+5); // 0x70 == 112 ( 8 個ず぀グルヌプなので、14個のボタン ) が暙準
1325        int i;
1326        for (i=0; i<BTNCNT; i++) {
1327                if (!use_btn[i]) continue;
1328                if (btnpos[i]*8 >= index_count) {
1329                        continue; // ボタンが存圚しない
1330                }
1331                int x, y, w, h;
1332                sprintf(key, "#WAKU.%03d.000.%s_BOX", waku_no, btnname[i]);
1333                if (config->GetParam(key, 5, 0, &x, &y, &w, &h) == -1) continue;
1334                int sx, sy, sdx, sdy, cnt;
1335                const char* d = data + 9 + btnpos[i]*24*8;
1336                sx = read_little_endian_int(d);
1337                sy = read_little_endian_int(d+4);
1338                sdx = read_little_endian_int(d+24) - sx;
1339                sdy = read_little_endian_int(d+24 + 4) - sy;
1340                cnt = 2;
1341                if (sx+sdx*2 == read_little_endian_int(d+2*24) && sy+sdy*2 == read_little_endian_int(d+2*24+4)) cnt = 3;
1342                WidButton* wid = new WidButton(event, &pic, str.c_str(), sx, sy, sdx, sdy, cnt, Rect(x, y, x+w, y+h), 1);
1343                if (btnpress[i]) { wid->press_func = btnpress[i]; wid->press_pointer = callback;}
1344                if (btndrag[i]) { wid->drag_func = btndrag[i]; wid->drag_pointer = callback;}
1345        }
1346        delete info;
1347}
1348
1349TextWindow::TextWindow(PicContainer& parent, Event::Container& event, int win_no, void* callback) :
1350        wid(0), name_visible(true),name(0),name_container(0), face(0)
1351{
1352        AyuSysConfig *config = AyuSysConfig::GetInstance();
1353        int i;
1354        for (i=0; i<8; i++)
1355                face_pics[i]=0;
1356        char key[1024];
1357        bool use_btn[BTNCNT];
1358        int size, rep1, rep2, cntw, cnth, mposx, mposy, posd, posx, posy, minx, miny, waku_no, ruby;
1359        sprintf(key, "#WINDOW.%03d.MOJI_SIZE", win_no); if (config->GetParam(key, 1, &size) == -1) return;
1360        sprintf(key, "#WINDOW.%03d.MOJI_REP", win_no);  if (config->GetParam(key, 2, &rep1, &rep2) == -1) return;
1361        sprintf(key, "#WINDOW.%03d.MOJI_CNT", win_no);  if (config->GetParam(key, 2, &cntw, &cnth) == -1) return;
1362        sprintf(key, "#WINDOW.%03d.POS", win_no);       if (config->GetParam(key, 3, &posd, &posx, &posy) == -1) return;
1363        sprintf(key, "#WINDOW.%03d.MOJI_POS", win_no);  if (config->GetParam(key, 4, &mposy, NULL, &mposx, NULL) == -1) return;
1364        sprintf(key, "#WINDOW.%03d.MOJI_MIN", win_no);  if (config->GetParam(key, 2, &minx, &miny) == -1) return;
1365        sprintf(key, "#WINDOW.%03d.WAKU_SETNO", win_no);if (config->GetParam(key, 1, &waku_no) == -1) return;
1366        sprintf(key, "#WINDOW.%03d.LUBY_SIZE", win_no); if (config->GetParam(key, 1, &ruby) == -1) return;
1367
1368        /* テキストりィゞット画面の右䞋䞀杯たで䜿甚 */
1369        /* posd == 2 なら画面䞋にひっ぀くように配眮 */
1370        Rect r(0,0);
1371        if (posd == 2) {
1372                r = WakuSize(parent, waku_no);
1373                r = Rect(0, parent.Height()-r.height(), r.width(), parent.Height());
1374                posx = 0;
1375                posy = parent.Height()-r.height();
1376        } else /* posd == 0 ? */
1377                r = Rect(posx, posy, parent.Width(), parent.Height());
1378
1379        /* テキストりィンドりの䜜成 */
1380        int w = size*cntw; int h = (size+ruby+2)*cnth;
1381        wid = new WidText(event, &parent, r, Rect(mposx, mposy, mposx+w, mposy+h), size);
1382        wid->stream.kanji_type = TextStream::sjis;
1383        /* 顔りィンドりの䜜成 */
1384        for (i=0; i<8; i++) {
1385                int x,y;
1386                sprintf(key, "#WINDOW.%03d.FACE.%03d", win_no, i);
1387                if (config->GetParam(key, 2, &x, &y) == -1) continue;
1388                /* 顔りィンドりを䜜成する */
1389                if (x >= 0 && y >= 0) {
1390                        face_pics[i] = wid->PicNode()->create_leaf(Rect(x,y), PicBase::FIT_SURFACE);
1391                } else {
1392                        face_pics[i] = parent.create_leaf(Rect(x+posx,y+posy), PicBase::FIT_SURFACE);
1393                }
1394                face_pics[i]->show();
1395        }
1396        face = face_pics[0];
1397        // ボタンの蚭定
1398        for (i=0; i<BTNCNT; i++) {
1399                int num;
1400                sprintf(key, "#WINDOW.%03d.%s_USE", win_no, btnname[i]);
1401                config->GetParam(key, 1, &num);
1402                use_btn[i] = (num==0) ? false : true;
1403        }
1404        // make name window
1405        int shadow, name_mod, name_size, name_min, name_center, name_posx, name_posy, name_mposx, name_mposy;
1406        sprintf(key, "#WINDOW.%03d.MOJI_SHADOW", win_no);  config->GetParam(key, 1, &shadow);
1407        sprintf(key, "#WINDOW.%03d.NAME_MOD", win_no);  config->GetParam(key, 1, &name_mod);
1408        sprintf(key, "#WINDOW.%03d.NAME_MOJI_SIZE", win_no);  config->GetParam(key, 1, &name_size);
1409        sprintf(key, "#WINDOW.%03d.NAME_MOJI_MIN", win_no);  config->GetParam(key, 1, &name_min);
1410        sprintf(key, "#WINDOW.%03d.NAME_MOJI_POS", win_no);  config->GetParam(key, 2, &name_mposx, &name_mposy);
1411        sprintf(key, "#WINDOW.%03d.NAME_CENTERING", win_no);  config->GetParam(key, 1, &name_center);
1412        sprintf(key, "#WINDOW.%03d.NAME_POS", win_no);  config->GetParam(key, 2, &name_posx, &name_posy);
1413        // if name_mode==0 name is in the text window
1414        // if name_mode == 1 open name window
1415        // if name_mode == 2 name is not used
1416        if (name_mod) {
1417                if (name_mod == 1) {
1418                        int w = name_size*name_min; int h = name_size;
1419                        int name_waku;
1420                        sprintf(key, "#WINDOW.%03d.NAME_WAKU_SETNO", win_no);
1421                        if (config->GetParam(key, 1, &name_waku) != -1 && name_waku != -1) {
1422                                Rect waku_r = WakuSize(parent, name_waku);
1423                                waku_r.rmove(r.lx, r.ty); // テキストりィンドり䜍眮に動かす
1424                                waku_r.rmove(name_posx, name_posy-waku_r.height()); // NAME_POS ぞ䜍眮補正
1425                                name_container = parent.create_node(waku_r, 0);
1426                                MakeWaku(*name_container, event, name_waku, win_no, 0, callback);
1427                                Rect name_r(0,0,w,h);
1428                                name_r.rmove(name_mposx, name_mposy);
1429                                name = new WidLabel(name_container, name_r, true, 0, name_size);
1430                                name->show();
1431                        } else { // 名前専甚枠なし
1432                                Rect name_r(0, 0, w, h);
1433                                name_r.rmove(r.lx, r.ty);
1434                                name_r.rmove(name_posx, name_posy-name_size);
1435                                name_container = parent.create_node(name_r, 0);
1436                                name = new WidLabel(name_container, Rect(0, 0, w, h), true, 0, name_size);
1437                                name->show();
1438                                name_container->show();
1439                        }
1440                } else { // name_mod == 2 or 3
1441                        name_container = parent.create_node( Rect(0, 0, 1, 1), 0);
1442                }
1443        }
1444        MakeWaku(*wid->PicNode(), event,waku_no, win_no, use_btn, callback);
1445}
1446
1447TextWindow::~TextWindow()
1448{
1449        if (name_container != NULL) {
1450                delete name_container;
1451                name_container = NULL;
1452        }
1453        int i;
1454        for (i=0; i<8; i++) {
1455                if (face_pics[i] != NULL) {
1456                        delete face_pics[i];
1457                        face_pics[i] = NULL;
1458                }
1459        }
1460        if (wid != NULL) {
1461                delete wid;
1462                wid = NULL;
1463        }
1464}
1465
1466void TextWindow::show(void)
1467{
1468        wid->show();
1469        if (name_container != NULL && name_visible)
1470                name_container->show();
1471        if (face != NULL)
1472                face->show();
1473}
1474
1475void TextWindow::hide(void)
1476{
1477        wid->hide();
1478        if (name_container != NULL)
1479                name_container->hide();
1480        if (face != NULL)
1481                face->hide();
1482}
1483
1484void TextWindow::ShowFace(const char* path)
1485{
1486        if (face == NULL)
1487                return;
1488        face->SetSurface(path, 0, 0);
1489}
1490
1491void TextWindow::ResetFace(void) {
1492        if (face == NULL)
1493                return;
1494        face->SetSurface((Surface*) NULL, 0, 0);
1495}
1496
1497void TextWindow::StartText(const TextStream& _stream)
1498{
1499        wid->Clear();
1500        wid->stream = _stream;
1501        if (name_container != NULL) {
1502                char namestr[1024];
1503                namestr[0] = 0;
1504                wid->stream.RemoveName(namestr, 1024);
1505                if (namestr[0] == 0) {
1506                        name_container->hide();
1507                }
1508                else {
1509                        if (name != NULL) {
1510                                name_container->show_all();
1511                                name->SetText(namestr);
1512                        }
1513                }
1514        }
1515        wid->Start();
1516}
1517
1518void TextWindow::SetName(const char* n)
1519{
1520        if (name_container != NULL && name != NULL) {
1521                if (n[0]) {
1522                        name_container->show();
1523                        name->SetText(n);
1524                        name_visible = true;
1525                }
1526                else {
1527                        name_container->hide();
1528                        name_visible = false;
1529                }
1530        }
1531}
1532
1533/**************************************************************::
1534**
1535** SaveFaceHash
1536*/
1537
1538void SaveFaceHash::NewNode(string face, int face_id)
1539{
1540        facetonum[face] = face_id;
1541        container.push_front(Node(face, face_id));
1542        if (container.size() > size_max) {
1543                Node remove = container.back();
1544                container.pop_back();
1545                facetonum.erase(remove.first);
1546        }
1547}
1548
1549int SaveFaceHash::Add(string face)
1550{
1551        int id;
1552        int ret = -1;
1553        int i;
1554        List::iterator it;
1555        if (face.empty()) return -1;
1556        if (facetonum.find(face) == facetonum.end()) {
1557                id = ++id_max;
1558                NewNode(face, id);
1559                ret = -1;
1560        }
1561        else {
1562                id = facetonum[face];
1563                for (i=0, it=container.begin(); it != container.end(); i++, it++) {
1564                        if (it->second == id) {
1565                                ret = i;
1566                                Node n = *it;
1567                                container.erase(it);
1568                                container.push_front(n);
1569                                break;
1570                        }
1571                }
1572        }
1573        return ret;
1574}
1575
1576string SaveFaceHash::Get(int num) {
1577        if (num < 0) return "";
1578        List::iterator it = container.begin();
1579        for (; it != container.end(); it++) {
1580                if (num == 0) return it->first;
1581                num--;
1582        }
1583        return "";
1584}
1585
1586int SaveFaceHash::size_max = 20;
1587
Note: See TracBrowser for help on using the browser.