00001
00027
00028
00029
00030
00031
00032
00033 #include <libmain.h>
00034 #include "app.h"
00035
00036 #ifdef VISUALIZE
00037
00038 #include <gtk/gtk.h>
00039
00040
00041 #define WINTITLE "Julius word trellis viewer"
00042 #define DEFAULT_WINDOW_WIDTH 800
00043 #define DEFAULT_WINDOW_HEIGHT 600
00044 #define CANVAS_MARGIN 16
00045 #define WAVE_HEIGHT 48
00046 #define WAVE_MARGIN 6
00047 #define RESULT_HEIGHT 0
00048 #define FONTSET "-*-fixed-medium-r-normal--10-*-*-*-*-*-*-*"
00049
00050
00051 static GdkFont *fontset;
00052 static GdkPixmap *pixmap = NULL;
00053 static gint canvas_width;
00054 static gint canvas_height;
00055
00056
00057
00058
00059
00060 static boolean sw_wid_axis = TRUE;
00061 static boolean sw_score_beam = FALSE;
00062 static boolean sw_text = TRUE;
00063 static boolean sw_line = TRUE;
00064 static boolean sw_level_thres = FALSE;
00065 static boolean sw_hypo = FALSE;
00066
00067
00068
00069
00070 static Recog *re;
00071
00072 static BACKTRELLIS *btlocal = NULL;
00073
00074 static POPNODE *popped = NULL;
00075 static int pnum;
00076 static POPNODE *lastpop = NULL;
00077
00078
00079
00080
00081
00082
00083 #define NCOLS 15
00084 static GdkColor cols[NCOLS] = {
00085 {0, 63000, 63000, 63000},
00086 {0, 0, 0, 40000},
00087 {0, 50000, 20000, 0},
00088 {0, 0, 0, 65535},
00089 {0, 60000, 60000, 0},
00090 {0, 24000, 32000, 24000},
00091 {0, 10000, 10000, 40000},
00092 {0, 50000, 54000, 50000},
00093 {0, 50000, 30000, 0},
00094 {0, 55535, 0, 0},
00095 {0, 50000, 30000, 0},
00096 {0, 12000, 20000, 12000},
00097 {0, 50000, 50000, 12000},
00098 {0, 50000, 0, 0},
00099 {0, 0, 0, 0}
00100 };
00101 typedef enum {C_BG, C_WAVEFORM, C_LEVELTHRES, C_BGN, C_END, C_LINE, C_TEXT, C_LINE_FAINT, C_LINE_BEST, C_END_BEST, C_TEXT_BEST, C_PASS2_NEXT, C_PASS2, C_PASS2_BEST, C_SHADOW} UserColors;
00102
00103 static GdkGC *dgc = NULL;
00104
00113 static void
00114 color_init()
00115 {
00116 GdkColormap *defcolmap;
00117 gboolean success[NCOLS];
00118
00119 defcolmap = gdk_colormap_get_system();
00120 if (gdk_colormap_alloc_colors(defcolmap, cols, NCOLS, FALSE, TRUE, success) > 0) {
00121 fprintf(stderr, "Warning: some colors are not allocated\n");
00122 }
00123
00124 }
00125
00126
00127
00128
00129
00130
00131 static LOGPROB *ftop = NULL;
00132 static LOGPROB *fbottom = NULL;
00133 static LOGPROB lowest;
00134 static LOGPROB maxrange;
00135 static LOGPROB maxrange2;
00136
00149 static void
00150 get_max_frame_score(BACKTRELLIS *bt)
00151 {
00152 int t, i;
00153 TRELLIS_ATOM *tre;
00154 LOGPROB x,y;
00155
00156
00157 if (ftop != NULL) free(ftop);
00158 ftop = mymalloc(sizeof(LOGPROB) * bt->framelen);
00159 if (fbottom != NULL) free(fbottom);
00160 fbottom = mymalloc(sizeof(LOGPROB) * bt->framelen);
00161
00162
00163 maxrange = 0.0;
00164 for (t=0;t<bt->framelen;t++) {
00165 x = LOG_ZERO;
00166 y = 0.0;
00167 for (i=0;i<bt->num[t];i++) {
00168 tre = bt->rw[t][i];
00169 if (x < tre->backscore) x = tre->backscore;
00170 if (y > tre->backscore) y = tre->backscore;
00171 }
00172 ftop[t] = x;
00173 fbottom[t] = y;
00174 if (maxrange < x - y) maxrange = x - y;
00175 }
00176
00177
00178 lowest = 0.0;
00179 for (t=0;t<bt->framelen;t++) {
00180 if (lowest > fbottom[t]) lowest = fbottom[t];
00181 }
00182 maxrange2 = 0.0;
00183 for (t=0;t<bt->framelen;t++) {
00184 x = lowest * (float)t / (float)bt->framelen;
00185 if (ftop[t] == LOG_ZERO) continue;
00186 if (maxrange2 < abs(ftop[t] - x)) maxrange2 = abs(ftop[t] - x);
00187 if (maxrange2 < abs(fbottom[t] - x)) maxrange2 = abs(fbottom[t] - x);
00188 }
00189 }
00190
00207 static gint
00208 scale_x(int t)
00209 {
00210 return(t * (canvas_width - CANVAS_MARGIN * 2) / btlocal->framelen + CANVAS_MARGIN);
00211 }
00212
00231 static gint
00232 scale_y(LOGPROB s, int t)
00233 {
00234 gint y;
00235 LOGPROB top, bottom;
00236 gint yoffset, height;
00237
00238 if (sw_score_beam) {
00239
00240 top = ftop[t];
00241 if (top == LOG_ZERO) {
00242 bottom = top;
00243 } else {
00244 bottom = ftop[t] - maxrange;
00245 }
00246 } else {
00247
00248 top = lowest * (float)t / (float)btlocal->framelen + maxrange2;
00249 bottom = lowest * (float)t / (float)btlocal->framelen - maxrange2;
00250 }
00251
00252 yoffset = CANVAS_MARGIN + RESULT_HEIGHT + (re->speechlen != 0 ? (WAVE_MARGIN + WAVE_HEIGHT): 0);
00253 height = canvas_height - yoffset - CANVAS_MARGIN;
00254 if (top <= bottom) {
00255 y = yoffset;
00256 } else {
00257 y = (top - s) * height / (top - bottom) + yoffset;
00258 }
00259 return(y);
00260 }
00261
00278 static gint
00279 scale_y_wid(WORD_ID wid)
00280 {
00281 gint y;
00282 gint yoffset, height;
00283
00284 yoffset = CANVAS_MARGIN + RESULT_HEIGHT + (re->speechlen != 0 ? (WAVE_MARGIN + WAVE_HEIGHT) : 0);
00285 height = canvas_height - yoffset - CANVAS_MARGIN;
00286 if (wid == WORD_INVALID) {
00287 y = yoffset;
00288 } else {
00289 y = wid * height / re->model->winfo->num + yoffset;
00290 }
00291 return(y);
00292 }
00293
00294
00295
00296
00297
00298 static SP16 max_level;
00299
00316 static gint
00317 scale_x_wave(int t)
00318 {
00319 return(t * (canvas_width - CANVAS_MARGIN * 2) / re->speechlen + CANVAS_MARGIN);
00320 }
00321
00338 static gint
00339 scale_y_wave(SP16 x)
00340 {
00341 return(WAVE_HEIGHT / 2 + WAVE_MARGIN - (x * WAVE_HEIGHT / (max_level * 2)));
00342 }
00343
00354 static void
00355 get_max_waveform_level()
00356 {
00357 int t;
00358 SP16 maxl;
00359
00360 if (re->speechlen == 0) return;
00361
00362 maxl = 0;
00363 for(t=0;t<re->speechlen;t++) {
00364 if (maxl < abs(re->speech[t])) {
00365 maxl = abs(re->speech[t]);
00366 }
00367 }
00368
00369 max_level = maxl;
00370 if (max_level < 3000) max_level = 3000;
00371 }
00372
00385 static void
00386 draw_waveform(GtkWidget *widget)
00387 {
00388 int t;
00389 gint text_width;
00390 static char buf[20];
00391
00392 if (re->speechlen == 0) return;
00393
00394
00395 if (dgc == NULL) {
00396 dgc = gdk_gc_new(widget->window);
00397 gdk_gc_copy(dgc, widget->style->fg_gc[GTK_STATE_NORMAL]);
00398 }
00399
00400
00401
00402 gdk_gc_set_foreground(dgc, &(cols[C_WAVEFORM]));
00403 gdk_draw_rectangle(pixmap, dgc, FALSE,
00404 scale_x_wave(0), scale_y_wave(max_level),
00405 scale_x_wave(re->speechlen-1) - scale_x_wave(0),
00406 scale_y_wave(-max_level) - scale_y_wave(max_level));
00407
00408 if (sw_level_thres) {
00409
00410 gdk_gc_set_foreground(dgc, &(cols[C_LEVELTHRES]));
00411 gdk_draw_line(pixmap, dgc,
00412 scale_x_wave(0), scale_y_wave(re->jconf->detect.level_thres),
00413 scale_x_wave(re->speechlen-1), scale_y_wave(re->jconf->detect.level_thres));
00414 gdk_draw_line(pixmap, dgc,
00415 scale_x_wave(0), scale_y_wave(- re->jconf->detect.level_thres),
00416 scale_x_wave(re->speechlen-1), scale_y_wave(- re->jconf->detect.level_thres));
00417 snprintf(buf, 20, "-lv %d", re->jconf->detect.level_thres);
00418 text_width = gdk_string_width(fontset, buf) + 1;
00419 gdk_draw_string(pixmap, fontset, dgc,
00420 canvas_width - CANVAS_MARGIN - text_width - 2,
00421 scale_y_wave(-max_level) - 2,
00422 buf);
00423 }
00424
00425
00426 snprintf(buf, 20, "max: %d", max_level);
00427 text_width = gdk_string_width(fontset, buf) + 1;
00428 gdk_gc_set_foreground(dgc, &(cols[C_WAVEFORM]));
00429 gdk_draw_string(pixmap, fontset, dgc,
00430 canvas_width - CANVAS_MARGIN - text_width - 2,
00431 scale_y_wave(max_level) + 12,
00432 buf);
00433
00434
00435 for(t=1;t<re->speechlen;t++) {
00436 gdk_gc_set_line_attributes(dgc, 1, GDK_LINE_SOLID, GDK_CAP_BUTT, GDK_JOIN_MITER);
00437 gdk_draw_line(pixmap, dgc,
00438 scale_x_wave(t-1), scale_y_wave(re->speech[t-1]),
00439 scale_x_wave(t), scale_y_wave(re->speech[t]));
00440 }
00441 }
00442
00443
00444
00445
00446
00447
00470 static void
00471 mygdk_draw_arc(GtkWidget *widget, int x1, int y1, int x2, int y2, int sw)
00472 {
00473 int width;
00474 UserColors c;
00475
00476
00477 if (dgc == NULL) {
00478 dgc = gdk_gc_new(widget->window);
00479 gdk_gc_copy(dgc, widget->style->fg_gc[GTK_STATE_NORMAL]);
00480 }
00481
00482
00483 switch(sw) {
00484 case 0: c = C_LINE_FAINT; width = 1; break;
00485 case 1: c = C_LINE; width = 1; break;
00486 case 2: c = C_LINE_BEST; width = 3; break;
00487 case 3: c = C_PASS2_NEXT; width = 1; break;
00488 case 4: c = C_PASS2; width = 1; break;
00489 case 5: c = C_PASS2_NEXT; width = 2; break;
00490 case 6: c = C_PASS2_BEST; width = 3; break;
00491 default: c = C_LINE; width = 1; break;
00492 }
00493
00494
00495 if (sw_line) {
00496 gdk_gc_set_line_attributes(dgc, width, GDK_LINE_SOLID, GDK_CAP_BUTT, GDK_JOIN_MITER);
00497 gdk_gc_set_foreground(dgc, &(cols[c]));
00498 gdk_draw_line(pixmap, dgc, x1, y1, x2, y2);
00499 gdk_gc_set_line_attributes(dgc, 1, GDK_LINE_SOLID, GDK_CAP_BUTT, GDK_JOIN_MITER);
00500 }
00501
00502
00503 if (sw != 0 && sw != 5) {
00504
00505 gdk_gc_set_foreground(dgc, &(cols[C_SHADOW]));
00506 gdk_draw_rectangle(pixmap, dgc,
00507 TRUE,
00508 x1 - width/2 - 2,
00509 y1 - width/2 -2,
00510 width+4,
00511 width+4);
00512 gdk_draw_rectangle(pixmap, dgc,
00513 TRUE,
00514 x2 - width/2 - 2,
00515 y2 - width/2 -2,
00516 width+4,
00517 width+4);
00518 }
00519 gdk_gc_set_foreground(dgc, &(cols[C_BGN]));
00520 gdk_draw_rectangle(pixmap, dgc,
00521 TRUE,
00522 x1 - width/2 - 1,
00523 y1 - width/2 -1,
00524 width+2,
00525 width+2);
00526 if (c == C_LINE_BEST || c == C_PASS2_BEST) {
00527 gdk_gc_set_foreground(dgc, &(cols[C_END_BEST]));
00528 } else {
00529 gdk_gc_set_foreground(dgc, &(cols[C_END]));
00530 }
00531 gdk_draw_rectangle(pixmap, dgc,
00532 TRUE,
00533 x2 - width/2 - 1,
00534 y2 - width/2 - 1,
00535 width+2,
00536 width+2);
00537
00538 }
00539
00558 static void
00559 draw_atom_sub(GtkWidget *widget, TRELLIS_ATOM *tre, TRELLIS_ATOM *last_tre, int sw)
00560 {
00561 int from_t;
00562 LOGPROB from_s;
00563 int from_w;
00564
00565
00566 if (sw_wid_axis) {
00567 if (tre->begintime <= 0) {
00568 from_t = 0;
00569 from_w = WORD_INVALID;
00570 } else {
00571 from_t = last_tre->endtime;
00572 from_w = last_tre->wid;
00573 }
00574 mygdk_draw_arc(widget,
00575 scale_x(from_t),
00576 scale_y_wid(from_w),
00577 scale_x(tre->endtime),
00578 scale_y_wid(tre->wid),
00579 sw);
00580 } else {
00581 if (tre->begintime <= 0) {
00582 from_t = 0;
00583 from_s = 0.0;
00584 } else {
00585 from_t = last_tre->endtime;
00586 from_s = last_tre->backscore;
00587 }
00588 mygdk_draw_arc(widget,
00589 scale_x(from_t),
00590 scale_y(from_s, from_t),
00591 scale_x(tre->endtime),
00592 scale_y(tre->backscore, tre->endtime),
00593 sw);
00594 }
00595 }
00596
00613 static void
00614 draw_atom(GtkWidget *widget, TRELLIS_ATOM *tre, int sw)
00615 {
00616 draw_atom_sub(widget, tre, tre->last_tre, sw);
00617 }
00618
00619
00636 static void
00637 draw_atom_text(GtkWidget *widget, TRELLIS_ATOM *tre, int sw)
00638 {
00639 gint text_width;
00640 UserColors c;
00641 int style;
00642 int dx, dy, x, y;
00643 WORD_INFO *winfo;
00644
00645 winfo = re->model->winfo;
00646
00647 if (winfo->woutput[tre->wid] != NULL && strlen(winfo->woutput[tre->wid]) > 0) {
00648 switch(sw) {
00649 case 0: style = -1; break;
00650 case 1: c = C_TEXT; style = 0; break;
00651 case 2: c = C_TEXT_BEST; style = 1; break;
00652 case 3: c = C_PASS2_NEXT; style = 0; break;
00653 case 4: c = C_PASS2; style = 0; break;
00654 case 5: c = C_PASS2; style = 1; break;
00655 case 6: c = C_PASS2_BEST; style = 1; break;
00656 default: c = C_TEXT; style = 0; break;
00657 }
00658 if (style == -1) return;
00659
00660 text_width = gdk_string_width(fontset, winfo->woutput[tre->wid]) + 1;
00661 x = scale_x(tre->endtime) - text_width;
00662 if (sw_wid_axis) {
00663 y = scale_y_wid(tre->wid) - 4;
00664 } else {
00665 y = scale_y(tre->backscore, tre->endtime) - 4;
00666 }
00667
00668 if (style == 1) {
00669 gdk_gc_set_foreground(dgc, &cols[C_SHADOW]);
00670 for (dx = -1; dx <= 1; dx++) {
00671 for (dy = -1; dy <= 1; dy++) {
00672 if (dx == 0 && dy == 0) continue;
00673 gdk_draw_string(pixmap, fontset, dgc, x + dx, y + dy,
00674 winfo->woutput[tre->wid]);
00675 }
00676 }
00677 }
00678 gdk_gc_set_foreground(dgc, &cols[c]);
00679 gdk_draw_string(pixmap, fontset, dgc, x, y,
00680 winfo->woutput[tre->wid]);
00681 }
00682 }
00683
00684
00685
00686
00687
00688 static WORD_ID *wordlist = NULL;
00689 static WORD_ID wordlistnum = 0;
00690
00707 static boolean
00708 wordlist_find(WORD_ID wid)
00709 {
00710 int left, right, mid;
00711
00712 if (wordlistnum == 0) return FALSE;
00713
00714 left = 0;
00715 right = wordlistnum - 1;
00716 while (left < right) {
00717 mid = (left + right) / 2;
00718 if (wordlist[mid] < wid) {
00719 left = mid + 1;
00720 } else {
00721 right = mid;
00722 }
00723 }
00724 if (wordlist[left] == wid) return TRUE;
00725 return FALSE;
00726 }
00727
00728
00729
00730
00731
00732
00733
00750 static void
00751 draw_atom_top(GtkWidget *widget, TRELLIS_ATOM *tre, int sw)
00752 {
00753 if (wordlistnum == 0 || wordlist_find(tre->wid)) {
00754 draw_atom(widget, tre, sw);
00755 }
00756 }
00757
00776 static void
00777 draw_atom_text_top(GtkWidget *widget, TRELLIS_ATOM *tre, int sw)
00778 {
00779 if (wordlistnum == 0 || wordlist_find(tre->wid)) {
00780 draw_atom_text(widget, tre, sw);
00781 }
00782 }
00783
00784
00785
00786
00787
00788
00801 static void
00802 draw_all_atom(GtkWidget *widget)
00803 {
00804 int t, i;
00805 TRELLIS_ATOM *tre;
00806
00807 for (t=0;t<btlocal->framelen;t++) {
00808 for (i=0;i<btlocal->num[t];i++) {
00809 tre = btlocal->rw[t][i];
00810 draw_atom_top(widget, tre, 0);
00811 }
00812 }
00813 if (sw_text) {
00814 for (t=0;t<btlocal->framelen;t++) {
00815 for (i=0;i<btlocal->num[t];i++) {
00816 tre = btlocal->rw[t][i];
00817 draw_atom_text_top(widget, tre, 0);
00818 }
00819 }
00820 }
00821 }
00822
00835 static void
00836 draw_context_valid_atom(GtkWidget *widget)
00837 {
00838 int t, i;
00839 TRELLIS_ATOM *tre;
00840
00841 for (t=0;t<btlocal->framelen;t++) {
00842 for (i=0;i<btlocal->num[t];i++) {
00843 tre = btlocal->rw[t][i];
00844 if (tre->last_tre != NULL && tre->last_tre->wid != WORD_INVALID) {
00845 draw_atom_top(widget, tre->last_tre, 1);
00846 }
00847 }
00848 }
00849 if (sw_text) {
00850 for (t=0;t<btlocal->framelen;t++) {
00851 for (i=0;i<btlocal->num[t];i++) {
00852 tre = btlocal->rw[t][i];
00853 if (tre->last_tre != NULL && tre->last_tre->wid != WORD_INVALID) {
00854 draw_atom_text_top(widget, tre->last_tre, 1);
00855 }
00856 }
00857 }
00858 }
00859 }
00860
00861 #ifdef WORD_GRAPH
00862
00874 static void
00875 draw_word_graph(GtkWidget *widget)
00876 {
00877 int t, i;
00878 TRELLIS_ATOM *tre;
00879
00880
00881
00882 for (t=0;t<btlocal->framelen;t++) {
00883 for (i=0;i<btlocal->num[t];i++) {
00884 tre = btlocal->rw[t][i];
00885 if (tre->within_wordgraph) {
00886 draw_atom_top(widget, tre, 1);
00887 }
00888 }
00889 }
00890 if (sw_text) {
00891 for (t=0;t<btlocal->framelen;t++) {
00892 for (i=0;i<btlocal->num[t];i++) {
00893 tre = btlocal->rw[t][i];
00894 if (tre->within_wordgraph) {
00895 draw_atom_text_top(widget, tre, 1);
00896 }
00897 }
00898 }
00899 }
00900
00901 }
00902 #endif
00903
00916 static void
00917 draw_best_path(GtkWidget *widget)
00918 {
00919 int last_time;
00920 LOGPROB maxscore;
00921 TRELLIS_ATOM *tre, *last_tre;
00922 int i;
00923
00924
00925 for (last_time = btlocal->framelen - 1; last_time >= 0; last_time--) {
00926 #ifdef USE_NGRAM
00927
00928 last_tre = bt_binsearch_atom(btlocal, last_time, re->model->winfo->tail_silwid);
00929 if (last_tre != NULL) break;
00930 #else
00931
00932 maxscore = LOG_ZERO;
00933 for (i=0;i<btlocal->num[last_time];i++) {
00934 tre = btlocal->rw[last_time][i];
00935
00936 if (maxscore < tre->backscore) {
00937 maxscore = tre->backscore;
00938 last_tre = tre;
00939 }
00940
00941 }
00942 if (maxscore != LOG_ZERO) break;
00943 #endif
00944 }
00945 if (last_time < 0) return;
00946
00947
00948 draw_atom_top(widget, last_tre, 2);
00949 tre = last_tre;
00950 while (tre->begintime > 0) {
00951 tre = tre->last_tre;
00952 draw_atom_top(widget, tre, 2);
00953 }
00954 if (sw_text) {
00955 draw_atom_text_top(widget, last_tre, 2);
00956 tre = last_tre;
00957 while (tre->begintime > 0) {
00958 tre = tre->last_tre;
00959 draw_atom_text_top(widget, tre, 2);
00960 }
00961 }
00962 }
00963
00964
00965
00966
00967
00968
00969
00970
00983 void
00984 visual2_init(int maxhypo)
00985 {
00986 POPNODE *p, *ptmp;
00987 int i;
00988
00989 if (popped == NULL) {
00990 popped = (POPNODE *)mymalloc(sizeof(POPNODE) * (maxhypo + 1));
00991 } else {
00992 for(i=0;i<pnum;i++) {
00993 p = popped[i].next;
00994 while(p) {
00995 ptmp = p->next;
00996 free(p);
00997 p = ptmp;
00998 }
00999 }
01000 }
01001 pnum = 1;
01002
01003 popped[0].tre = NULL;
01004 popped[0].score = LOG_ZERO;
01005 popped[0].last = NULL;
01006 popped[0].next = NULL;
01007
01008
01009 p = lastpop;
01010 while(p) {
01011 ptmp = p->next;
01012 free(p);
01013 p = ptmp;
01014 }
01015 lastpop = NULL;
01016 }
01017
01032 void
01033 visual2_popped(NODE *n, int popctr)
01034 {
01035 if (pnum < popctr + 1) pnum = popctr + 1;
01036
01037 popped[popctr].tre = n->popnode->tre;
01038 popped[popctr].score = n->popnode->score;
01039 popped[popctr].last = n->popnode->last;
01040 popped[popctr].next = NULL;
01041
01042 n->popnode = &(popped[popctr]);
01043 }
01044
01061 void
01062 visual2_next_word(NODE *next, NODE *prev, int popctr)
01063 {
01064 POPNODE *new;
01065
01066
01067 new = (POPNODE *)mymalloc(sizeof(POPNODE));
01068 new->tre = next->tre;
01069 new->score = next->score;
01070
01071 new->last = (prev) ? prev->popnode : NULL;
01072 next->popnode = new;
01073
01074 new->next = popped[popctr].next;
01075 popped[popctr].next = new;
01076 }
01077
01092 void
01093 visual2_best(NODE *now, WORD_INFO *winfo)
01094 {
01095 POPNODE *new;
01096
01097 new = (POPNODE *)mymalloc(sizeof(POPNODE));
01098 new->tre = now->popnode->tre;
01099 new->score = now->popnode->score;
01100 new->last = now->popnode->last;
01101 new->next = lastpop;
01102 lastpop = new;
01103 }
01104
01105
01106
01107
01108
01109
01122 static void
01123 draw_final_results(GtkWidget *widget)
01124 {
01125 POPNODE *firstp, *lastp, *p;
01126
01127 for(firstp = lastpop; firstp; firstp = firstp->next) {
01128 if (firstp->tre != NULL) {
01129 draw_atom(widget, firstp->tre, 6);
01130 }
01131 lastp = firstp;
01132 for(p = firstp->last; p; p = p->last) {
01133 if (p->tre != NULL) {
01134 draw_atom_sub(widget, p->tre, lastp->tre, 6);
01135 draw_atom_text_top(widget, p->tre, 6);
01136 }
01137 lastp = p;
01138 }
01139 }
01140 }
01141
01142 static LOGPROB maxscore;
01143 static LOGPROB minscore;
01144
01154 static void
01155 get_max_hypo_score()
01156 {
01157 POPNODE *p;
01158 int i;
01159
01160 maxscore = LOG_ZERO;
01161 minscore = 0.0;
01162 for(i=1;i<pnum;i++) {
01163 if (maxscore < popped[i].score) maxscore = popped[i].score;
01164 if (minscore > popped[i].score) minscore = popped[i].score;
01165 }
01166 }
01167
01184 static gint
01185 scale_hypo_y(LOGPROB s)
01186 {
01187 gint y;
01188 gint yoffset, height;
01189
01190 yoffset = CANVAS_MARGIN + RESULT_HEIGHT + (re->speechlen != 0 ? (WAVE_MARGIN + WAVE_HEIGHT) : 0);
01191 height = canvas_height - yoffset - CANVAS_MARGIN;
01192 y = (maxscore - s) * height / (maxscore - minscore) + yoffset;
01193 return(y);
01194 }
01195
01196
01217 static void
01218 draw_popped(GtkWidget *widget, POPNODE *p, UserColors c, int width, int style)
01219 {
01220 int text_width;
01221 gint x, y;
01222
01223 if (p->tre == NULL) return;
01224
01225 if (p->last != NULL && p->last->tre != NULL) {
01226 gdk_gc_set_line_attributes(dgc, width, GDK_LINE_SOLID, GDK_CAP_BUTT, GDK_JOIN_MITER);
01227 gdk_gc_set_foreground(dgc, &(cols[c]));
01228 gdk_draw_line(pixmap, dgc,
01229 scale_x(p->last->tre->endtime),
01230 scale_hypo_y(p->last->score),
01231 scale_x(p->tre->endtime),
01232 scale_hypo_y(p->score));
01233 gdk_gc_set_line_attributes(dgc, 1, GDK_LINE_SOLID, GDK_CAP_BUTT, GDK_JOIN_MITER);
01234 }
01235
01236 if (p->tre != NULL) {
01237 x = scale_x(p->tre->endtime);
01238 y = scale_hypo_y(p->score);
01239 if (style == 1) {
01240 gdk_gc_set_foreground(dgc, &(cols[C_SHADOW]));
01241 gdk_draw_rectangle(pixmap, dgc,
01242 TRUE,
01243 x - 3,
01244 y - 3,
01245 7,
01246 7);
01247 } else if (style == 2) {
01248 gdk_gc_set_foreground(dgc, &(cols[c]));
01249 gdk_draw_rectangle(pixmap, dgc,
01250 TRUE,
01251 x - 3,
01252 y - 3,
01253 7,
01254 7);
01255 }
01256 gdk_gc_set_foreground(dgc, &(cols[c]));
01257 gdk_draw_rectangle(pixmap, dgc,
01258 TRUE,
01259 x - 2,
01260 y - 2,
01261 5,
01262 5);
01263 if (p->tre->wid != WORD_INVALID) {
01264 text_width = gdk_string_width(fontset, re->model->winfo->woutput[p->tre->wid]) + 1;
01265 gdk_draw_string(pixmap, fontset, dgc, x - text_width-1, y - 5,
01266 re->model->winfo->woutput[p->tre->wid]);
01267 }
01268 }
01269
01270
01271 }
01272
01273
01274
01275 static int old_popctr;
01276
01291 static void
01292 draw_popnodes(GtkWidget *widget, int popctr)
01293 {
01294 POPNODE *p, *porg;
01295
01296 if (popctr < 0 || popctr >= pnum) {
01297 fprintf(stderr, "invalid popctr (%d > %d)!\n", popctr, pnum);
01298 return;
01299 }
01300
01301 porg = &(popped[popctr]);
01302
01303
01304 for(p = porg->next; p; p = p->next) {
01305 draw_popped(widget, p, C_LINE_BEST, 1, 0);
01306 }
01307
01308
01309 for(p = porg->last; p; p = p->last) {
01310 draw_popped(widget, p, C_PASS2_BEST, 2, 0);
01311 }
01312 draw_popped(widget, porg, C_PASS2_BEST, 3, 1);
01313
01314 old_popctr = popctr;
01315 }
01328 static void
01329 draw_popnodes_old(GtkWidget *widget)
01330 {
01331 POPNODE *p, *porg;
01332
01333 porg = &(popped[old_popctr]);
01334
01335
01336 for(p = porg->next; p; p = p->next) {
01337 draw_popped(widget, p, C_LINE_FAINT, 1, 0);
01338 }
01339
01340
01341 for(p = porg->last; p; p = p->last) {
01342 draw_popped(widget, p, C_PASS2, 2, 0);
01343 }
01344 draw_popped(widget, porg, C_PASS2, 3, 2);
01345 }
01346
01347
01348
01349
01350
01351 static boolean fitscreen = TRUE;
01352
01365 static void
01366 draw_background(GtkWidget *widget)
01367 {
01368 static char buf[MAX_HMMNAME_LEN];
01369
01370
01371 if (dgc == NULL) {
01372 dgc = gdk_gc_new(widget->window);
01373 gdk_gc_copy(dgc, widget->style->fg_gc[GTK_STATE_NORMAL]);
01374 }
01375
01376 gdk_gc_set_foreground(dgc, &(cols[C_BG]));
01377 gdk_draw_rectangle(pixmap, dgc, TRUE,
01378 0,0,canvas_width,canvas_height);
01379
01380
01381 gdk_gc_set_foreground(dgc, &(cols[C_TEXT]));
01382 if (sw_hypo) {
01383 gdk_draw_string(pixmap, fontset, dgc, 0, canvas_height - 16,
01384 "Hypothesis score (2nd pass)");
01385 } else {
01386 gdk_draw_string(pixmap, fontset, dgc, 0, canvas_height - 16,
01387 sw_wid_axis ? "Word ID" : (sw_score_beam ? "Beam score" : "Accumulated score (normalized by time)"));
01388 }
01389 snprintf(buf, 50, "x%3.1f", (float)canvas_width / (float)btlocal->framelen);
01390 gdk_draw_string(pixmap, fontset, dgc, 0, canvas_height - 3, buf);
01391 }
01392
01405 static void
01406 drawarea_draw(GtkWidget *widget)
01407 {
01408
01409 if (pixmap) {
01410 gdk_pixmap_unref(pixmap);
01411 }
01412 pixmap = gdk_pixmap_new(widget->window, canvas_width, canvas_height, -1);
01413
01414
01415 draw_background(widget);
01416
01417 if (re->speechlen != 0) {
01418 draw_waveform(widget);
01419 }
01420
01421 if (!sw_hypo) {
01422 if (btlocal != NULL) {
01423
01424 draw_all_atom(widget);
01425 #ifdef WORD_GRAPH
01426 draw_word_graph(widget);
01427 #else
01428 draw_context_valid_atom(widget);
01429 #endif
01430 draw_best_path(widget);
01431 }
01432 if (popped != NULL) {
01433
01434 draw_final_results(widget);
01435 }
01436 }
01437 }
01438
01451 static void
01452 drawarea_expose(GtkWidget *widget)
01453 {
01454 GdkRectangle r;
01455
01456 r.x = 0;
01457 r.y = 0;
01458 r.width = canvas_width;
01459 r.height = canvas_height;
01460 gtk_widget_draw(widget, &r);
01461 }
01462
01483 static gboolean
01484 event_drawarea_expose(GtkWidget *widget, GdkEventExpose *event, gpointer user_data)
01485 {
01486 if (pixmap != NULL) {
01487 gdk_draw_pixmap(widget->window,
01488 widget->style->fg_gc[GTK_STATE_NORMAL],
01489 pixmap,
01490 event->area.x, event->area.y,
01491 event->area.x, event->area.y,
01492 event->area.width, event->area.height);
01493 }
01494 }
01495
01516 static gboolean
01517 event_drawarea_configure(GtkWidget *widget, GdkEventExpose *event, gpointer user_data)
01518 {
01519 if (fitscreen) {
01520 canvas_width = widget->allocation.width;
01521 }
01522
01523 canvas_height = widget->allocation.height;
01524
01525
01526 drawarea_draw(widget);
01527 }
01528
01529
01530
01531
01532
01533
01548 static void
01549 action_toggle_thres(GtkWidget *widget)
01550 {
01551
01552 if (re->speechlen == 0) return;
01553
01554 if (sw_level_thres) sw_level_thres = FALSE;
01555 else sw_level_thres = TRUE;
01556
01557
01558 drawarea_draw(widget);
01559
01560
01561 drawarea_expose(widget);
01562 }
01563
01564 #ifdef PLAYCOMMAND
01565
01577 static void
01578 action_play_waveform(GtkWidget *widget)
01579 {
01580 char buf[80];
01581 static char command[250];
01582 int fd;
01583
01584 if (re->speechlen == 0) return;
01585
01586
01587 snprintf(buf, 250, "/var/tmp/julius_visual_play.%d", getpid());
01588 if ((fd = open(buf, O_CREAT | O_TRUNC | O_WRONLY, 0644)) < 0) {
01589 fprintf(stderr, "cannot open %s for writing\n", buf);
01590 return;
01591 }
01592 if (wrsamp(fd, re->speech, re->speechlen) < 0) {
01593 fprintf(stderr, "failed to write to %s for playing\n", buf);
01594 return;
01595 }
01596 close(fd);
01597
01598 snprintf(command, 250, PLAYCOMMAND, re->jconf->analysis.para.smp_freq, buf);
01599 printf("play: [%s]\n", command);
01600 system(command);
01601
01602 unlink(buf);
01603 }
01604 #endif
01605
01620 static void
01621 action_view_wid(GtkWidget *button, GtkWidget *widget)
01622 {
01623 if (GTK_TOGGLE_BUTTON(button)->active) {
01624
01625 sw_wid_axis = TRUE;
01626 sw_hypo = FALSE;
01627
01628 drawarea_draw(widget);
01629
01630 drawarea_expose(widget);
01631 } else {
01632 sw_wid_axis = FALSE;
01633 }
01634 }
01635
01650 static void
01651 action_view_score(GtkWidget *button, GtkWidget *widget)
01652 {
01653 if (GTK_TOGGLE_BUTTON(button)->active) {
01654
01655 sw_score_beam = FALSE;
01656 sw_hypo = FALSE;
01657
01658 drawarea_draw(widget);
01659
01660 drawarea_expose(widget);
01661 }
01662 }
01663
01680 static void
01681 action_view_beam(GtkWidget *button, GtkWidget *widget)
01682 {
01683 if (GTK_TOGGLE_BUTTON(button)->active) {
01684
01685 sw_score_beam = TRUE;
01686 sw_hypo = FALSE;
01687
01688 drawarea_draw(widget);
01689
01690 drawarea_expose(widget);
01691 }
01692 }
01693
01710 static void
01711 action_toggle_arc(GtkWidget *button, GtkWidget *widget)
01712 {
01713 if (GTK_TOGGLE_BUTTON(button)->active) {
01714 sw_text = TRUE;
01715 sw_line = TRUE;
01716 } else {
01717 sw_text = FALSE;
01718 sw_line = FALSE;
01719 }
01720
01721 drawarea_draw(widget);
01722
01723 drawarea_expose(widget);
01724 }
01725
01742 static void
01743 action_set_wid(GtkWidget *widget, GtkWidget *draw)
01744 {
01745 gchar *entry_text;
01746 WORD_ID i;
01747
01748 entry_text = gtk_entry_get_text(GTK_ENTRY(widget));
01749
01750
01751 if (wordlist == NULL) {
01752 wordlist = mymalloc(sizeof(WORD_ID) * re->model->winfo->num);
01753 }
01754 wordlistnum = 0;
01755
01756
01757 if (strlen(entry_text) == 0) {
01758 wordlistnum = 0;
01759 } else {
01760 for (i=0;i<re->model->winfo->num;i++) {
01761 if (strmatch(entry_text, re->model->winfo->woutput[i])) {
01762 wordlist[wordlistnum] = i;
01763 wordlistnum++;
01764 }
01765 }
01766 if (wordlistnum == 0) {
01767 fprintf(stderr, "word \"%s\" not found, show all\n", entry_text);
01768 } else {
01769 fprintf(stderr, "%d words found for \"%s\"\n", wordlistnum, entry_text);
01770 }
01771 }
01772
01773
01774 drawarea_draw(draw);
01775
01776 drawarea_expose(draw);
01777 }
01778
01793 static void
01794 action_zoom(GtkWidget *widget)
01795 {
01796 fitscreen = FALSE;
01797 if (btlocal != NULL) {
01798 canvas_width = btlocal->framelen * 2;
01799 gtk_drawing_area_size(GTK_DRAWING_AREA(widget), canvas_width, canvas_height);
01800
01801 }
01802 drawarea_draw(widget);
01803 drawarea_expose(widget);
01804 }
01805
01820 static void
01821 action_zoom_4(GtkWidget *widget)
01822 {
01823 fitscreen = FALSE;
01824 if (btlocal != NULL) {
01825 canvas_width = btlocal->framelen * 4;
01826 gtk_drawing_area_size(GTK_DRAWING_AREA(widget), canvas_width, canvas_height);
01827 }
01828
01829 drawarea_draw(widget);
01830 drawarea_expose(widget);
01831 }
01832
01847 static void
01848 action_zoom_8(GtkWidget *widget)
01849 {
01850 fitscreen = FALSE;
01851 if (btlocal != NULL) {
01852 canvas_width = btlocal->framelen * 8;
01853 gtk_drawing_area_size(GTK_DRAWING_AREA(widget), canvas_width, canvas_height);
01854 }
01855
01856 drawarea_draw(widget);
01857 drawarea_expose(widget);
01858 }
01859
01874 static void
01875 action_fit_screen(GtkWidget *widget)
01876 {
01877 fitscreen = TRUE;
01878 canvas_width = widget->parent->allocation.width;
01879 gtk_drawing_area_size(GTK_DRAWING_AREA(widget), canvas_width, canvas_height);
01880
01881 drawarea_draw(widget);
01882 drawarea_expose(widget);
01883 }
01884
01900 static void
01901 action_toggle_popctr(GtkWidget *button, GtkWidget *widget)
01902 {
01903 if (GTK_TOGGLE_BUTTON(button)->active) {
01904 sw_hypo = TRUE;
01905 } else {
01906 sw_hypo = FALSE;
01907 }
01908 drawarea_draw(widget);
01909 drawarea_expose(widget);
01910 }
01911
01929 static void
01930 action_change_popctr(GtkAdjustment *adj, GtkWidget *widget)
01931 {
01932 int popctr;
01933
01934 if (sw_hypo) {
01935 popctr = adj->value;
01936 draw_popnodes_old(widget);
01937 draw_popnodes(widget, popctr);
01938 drawarea_expose(widget);
01939 }
01940 }
01941
01942
01943
01944
01945
01966 static gint
01967 delete_event(GtkWidget *widget, GdkEvent *event, gpointer data)
01968 {
01969 return (FALSE);
01970 }
01971
01986 static void
01987 destroy(GtkWidget *widget, gpointer data)
01988 {
01989 gtk_main_quit();
01990 }
01991
01992
01993
01994
01995
02004 void
02005 visual_init(Recog *recog)
02006 {
02007 POPNODE *p;
02008
02009
02010 re = recog;
02011
02012
02013 btlocal = NULL;
02014
02015
02016
02017
02018 gtk_init(NULL, NULL);
02019
02020
02021 gtk_set_locale();
02022
02023
02024 fontset = gdk_fontset_load(FONTSET);
02025 if (fontset == NULL) {
02026 fprintf(stderr, "cannot load X font \"%s\" for visualize\n", FONTSET); exit(-1);
02027 }
02028
02029
02030 color_init();
02031
02032 fprintf(stderr, "GTK initialized\n");
02033
02034 }
02035
02048 void
02049 visual_show(BACKTRELLIS *bt)
02050 {
02051 GtkWidget *window, *button, *draw, *entry, *scrolled_window, *scale;
02052 GtkWidget *box1, *box2, *label, *frame, *box3;
02053 GtkObject *adj;
02054 GSList *group;
02055 GList *glist;
02056
02057
02058 fprintf(stderr, "*** Showing word trellis view (close window to proceed)\n");
02059
02060
02061 btlocal = bt;
02062
02063
02064 get_max_frame_score(bt);
02065
02066
02067 get_max_hypo_score();
02068
02069
02070 if (re->speechlen != 0) get_max_waveform_level();
02071
02072
02073 sw_hypo = FALSE;
02074
02075
02076 fitscreen = TRUE;
02077 if (dgc != NULL) {
02078 gdk_gc_unref(dgc);
02079 dgc = NULL;
02080 }
02081
02082
02083 window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
02084 gtk_widget_set_usize(GTK_WIDGET(window), DEFAULT_WINDOW_WIDTH, DEFAULT_WINDOW_HEIGHT);
02085 gtk_window_set_title(GTK_WINDOW(window), WINTITLE);
02086 gtk_signal_connect(GTK_OBJECT(window), "delete_event",
02087 GTK_SIGNAL_FUNC(delete_event), NULL);
02088 gtk_signal_connect(GTK_OBJECT(window), "destroy",
02089 GTK_SIGNAL_FUNC(destroy), NULL);
02090 gtk_container_border_width(GTK_CONTAINER(window), 10);
02091
02092
02093 box1 = gtk_hbox_new(FALSE, 5);
02094 gtk_container_add(GTK_CONTAINER(window), box1);
02095
02096
02097 scrolled_window = gtk_scrolled_window_new(NULL, NULL);
02098 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window), GTK_POLICY_ALWAYS,GTK_POLICY_AUTOMATIC);
02099
02100
02101 draw = gtk_drawing_area_new();
02102
02103 gtk_signal_connect(GTK_OBJECT(draw), "expose-event", GTK_SIGNAL_FUNC(event_drawarea_expose), NULL);
02104 gtk_signal_connect(GTK_OBJECT(draw), "configure-event", GTK_SIGNAL_FUNC(event_drawarea_configure), NULL);
02105 gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(scrolled_window), draw);
02106 gtk_box_pack_start(GTK_BOX(box1), scrolled_window, TRUE, TRUE, 0);
02107
02108
02109 box2 = gtk_vbox_new(FALSE, 5);
02110 gtk_box_pack_start(GTK_BOX(box1), box2, FALSE, TRUE, 0);
02111
02112 if (re->speechlen != 0) {
02113
02114 frame = gtk_frame_new("waveform");
02115 gtk_box_pack_start(GTK_BOX(box2), frame, FALSE, FALSE, 0);
02116 box3 = gtk_hbox_new(FALSE, 5);
02117 gtk_container_set_border_width(GTK_CONTAINER(box3), 5);
02118 gtk_container_add(GTK_CONTAINER(frame), box3);
02119
02120
02121 #ifdef PLAYCOMMAND
02122 button = gtk_button_new_with_label("play");
02123 gtk_signal_connect_object(GTK_OBJECT(button), "clicked",
02124 GTK_SIGNAL_FUNC(action_play_waveform), GTK_OBJECT(draw));
02125 gtk_box_pack_start(GTK_BOX(box3), button, FALSE, FALSE, 0);
02126 #endif
02127
02128
02129 button = gtk_button_new_with_label("thres");
02130 gtk_signal_connect_object(GTK_OBJECT(button), "clicked",
02131 GTK_SIGNAL_FUNC(action_toggle_thres), GTK_OBJECT(draw));
02132 gtk_box_pack_start(GTK_BOX(box3), button, FALSE, FALSE, 0);
02133 }
02134
02135
02136 frame = gtk_frame_new("change view");
02137 gtk_box_pack_start(GTK_BOX(box2), frame, FALSE, FALSE, 0);
02138 box3 = gtk_hbox_new(FALSE, 5);
02139 gtk_container_set_border_width(GTK_CONTAINER(box3), 5);
02140 gtk_container_add(GTK_CONTAINER(frame), box3);
02141
02142
02143 button = gtk_radio_button_new_with_label(NULL, "word");
02144 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), TRUE);
02145 gtk_signal_connect(GTK_OBJECT(button), "toggled",
02146 GTK_SIGNAL_FUNC(action_view_wid), GTK_OBJECT(draw));
02147 gtk_box_pack_start(GTK_BOX(box3), button, FALSE, FALSE, 0);
02148
02149
02150 group = gtk_radio_button_group(GTK_RADIO_BUTTON(button));
02151 button = gtk_radio_button_new_with_label(group, "score");
02152 gtk_signal_connect(GTK_OBJECT(button), "toggled",
02153 GTK_SIGNAL_FUNC(action_view_score), GTK_OBJECT(draw));
02154 gtk_box_pack_start(GTK_BOX(box3), button, FALSE, FALSE, 0);
02155
02156
02157 group = gtk_radio_button_group(GTK_RADIO_BUTTON(button));
02158 button = gtk_radio_button_new_with_label(group, "beam");
02159 gtk_signal_connect(GTK_OBJECT(button), "toggled",
02160 GTK_SIGNAL_FUNC(action_view_beam), GTK_OBJECT(draw));
02161 gtk_box_pack_start(GTK_BOX(box3), button, FALSE, FALSE, 0);
02162
02163
02164 frame = gtk_frame_new("show/hide");
02165 gtk_box_pack_start(GTK_BOX(box2), frame, FALSE, FALSE, 0);
02166 box3 = gtk_vbox_new(FALSE, 5);
02167 gtk_container_set_border_width(GTK_CONTAINER(box3), 5);
02168 gtk_container_add(GTK_CONTAINER(frame), box3);
02169
02170
02171 button = gtk_toggle_button_new_with_label("arcs");
02172 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), TRUE);
02173 gtk_signal_connect(GTK_OBJECT(button), "toggled",
02174 GTK_SIGNAL_FUNC(action_toggle_arc), GTK_OBJECT(draw));
02175 gtk_box_pack_start(GTK_BOX(box3), button, FALSE, FALSE, 0);
02176
02177
02178 frame = gtk_frame_new("view words");
02179 gtk_box_pack_start(GTK_BOX(box2), frame, FALSE, FALSE, 0);
02180 box3 = gtk_vbox_new(FALSE, 5);
02181 gtk_container_set_border_width(GTK_CONTAINER(box3), 5);
02182 gtk_container_add(GTK_CONTAINER(frame), box3);
02183
02184
02185 entry = gtk_entry_new_with_max_length(16);
02186 gtk_signal_connect(GTK_OBJECT(entry), "activate",
02187 GTK_SIGNAL_FUNC(action_set_wid), GTK_OBJECT(draw));
02188 gtk_box_pack_start(GTK_BOX(box3), entry, FALSE, FALSE, 0);
02189
02190
02191 frame = gtk_frame_new("zoom");
02192 gtk_box_pack_start(GTK_BOX(box2), frame, FALSE, FALSE, 0);
02193 box3 = gtk_hbox_new(FALSE, 5);
02194 gtk_container_set_border_width(GTK_CONTAINER(box3), 5);
02195 gtk_container_add(GTK_CONTAINER(frame), box3);
02196
02197
02198 button = gtk_button_new_with_label("x2");
02199 gtk_signal_connect_object(GTK_OBJECT(button), "clicked",
02200 GTK_SIGNAL_FUNC(action_zoom), GTK_OBJECT(draw));
02201 gtk_box_pack_start(GTK_BOX(box3), button, FALSE, FALSE, 0);
02202
02203
02204 button = gtk_button_new_with_label("x4");
02205 gtk_signal_connect_object(GTK_OBJECT(button), "clicked",
02206 GTK_SIGNAL_FUNC(action_zoom_4), GTK_OBJECT(draw));
02207 gtk_box_pack_start(GTK_BOX(box3), button, FALSE, FALSE, 0);
02208
02209
02210 button = gtk_button_new_with_label("x8");
02211 gtk_signal_connect_object(GTK_OBJECT(button), "clicked",
02212 GTK_SIGNAL_FUNC(action_zoom_8), GTK_OBJECT(draw));
02213 gtk_box_pack_start(GTK_BOX(box3), button, FALSE, FALSE, 0);
02214
02215
02216 button = gtk_button_new_with_label("fit");
02217 gtk_signal_connect_object(GTK_OBJECT(button), "clicked",
02218 GTK_SIGNAL_FUNC(action_fit_screen), GTK_OBJECT(draw));
02219 gtk_box_pack_start(GTK_BOX(box3), button, FALSE, FALSE, 0);
02220
02221
02222 frame = gtk_frame_new("pass2 replay");
02223 gtk_box_pack_start(GTK_BOX(box2), frame, FALSE, FALSE, 0);
02224 box3 = gtk_vbox_new(FALSE, 5);
02225 gtk_container_set_border_width(GTK_CONTAINER(box3), 5);
02226 gtk_container_add(GTK_CONTAINER(frame), box3);
02227
02228 adj = gtk_adjustment_new(0.0, 0.0, (pnum-1) + 5, 1.0, 1.0, 5.0);
02229 gtk_signal_connect(GTK_OBJECT(adj), "value_changed",
02230 GTK_SIGNAL_FUNC(action_change_popctr), GTK_OBJECT(draw));
02231
02232
02233 button = gtk_toggle_button_new_with_label("start");
02234 gtk_signal_connect(GTK_OBJECT(button), "toggled",
02235 GTK_SIGNAL_FUNC(action_toggle_popctr), GTK_OBJECT(draw));
02236 gtk_box_pack_start(GTK_BOX(box3), button, FALSE, FALSE, 0);
02237
02238
02239 scale = gtk_hscale_new(GTK_ADJUSTMENT(adj));
02240 gtk_scale_set_digits(GTK_SCALE(scale), 0);
02241 gtk_box_pack_start(GTK_BOX(box3), scale, FALSE, FALSE, 0);
02242
02243
02244 button = gtk_button_new_with_label("close");
02245
02246 gtk_signal_connect_object(GTK_OBJECT(button), "clicked",
02247 GTK_SIGNAL_FUNC(gtk_widget_destroy),
02248 GTK_OBJECT(window));
02249
02250 gtk_box_pack_start(GTK_BOX(box2), button, FALSE, FALSE, 0);
02251
02252
02253 gtk_widget_show_all(window);
02254
02255
02256 gtk_main();
02257 }
02258
02259 #endif