00001
00026
00027
00028
00029
00030
00031
00032 #include <julius.h>
00033
00034 #ifdef VISUALIZE
00035
00036 #include <gtk/gtk.h>
00037
00038
00039 #define WINTITLE "Julius word trellis viewer"
00040 #define DEFAULT_WINDOW_WIDTH 800
00041 #define DEFAULT_WINDOW_HEIGHT 600
00042 #define CANVAS_MARGIN 16
00043 #define WAVE_HEIGHT 48
00044 #define WAVE_MARGIN 6
00045 #define RESULT_HEIGHT 0
00046 #define FONTSET "-*-fixed-medium-r-normal--10-*-*-*-*-*-*-*"
00047
00048
00049 static GdkFont *fontset;
00050 static GdkPixmap *pixmap = NULL;
00051 static gint canvas_width;
00052 static gint canvas_height;
00053
00054
00055
00056
00057
00058 static boolean sw_wid_axis = TRUE;
00059 static boolean sw_score_beam = FALSE;
00060 static boolean sw_text = TRUE;
00061 static boolean sw_line = TRUE;
00062 static boolean sw_level_thres = FALSE;
00063 static boolean sw_hypo = FALSE;
00064
00065
00066
00067
00068
00069 static BACKTRELLIS *btlocal = NULL;
00070
00071 static POPNODE *popped = NULL;
00072 static int pnum;
00073 static POPNODE *lastpop = NULL;
00074
00075
00076
00077
00078
00079
00080 #define NCOLS 15
00081 static GdkColor cols[NCOLS] = {
00082 {0, 63000, 63000, 63000},
00083 {0, 0, 0, 40000},
00084 {0, 50000, 20000, 0},
00085 {0, 0, 0, 65535},
00086 {0, 60000, 60000, 0},
00087 {0, 24000, 32000, 24000},
00088 {0, 10000, 10000, 40000},
00089 {0, 50000, 54000, 50000},
00090 {0, 50000, 30000, 0},
00091 {0, 55535, 0, 0},
00092 {0, 50000, 30000, 0},
00093 {0, 12000, 20000, 12000},
00094 {0, 50000, 50000, 12000},
00095 {0, 50000, 0, 0},
00096 {0, 0, 0, 0}
00097 };
00098 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;
00099
00100 static GdkGC *dgc = NULL;
00101
00110 static void
00111 color_init()
00112 {
00113 GdkColormap *defcolmap;
00114 gboolean success[NCOLS];
00115
00116 defcolmap = gdk_colormap_get_system();
00117 if (gdk_colormap_alloc_colors(defcolmap, cols, NCOLS, FALSE, TRUE, success) > 0) {
00118 j_printerr("Warning: some colors are not allocated\n");
00119 }
00120
00121 }
00122
00123
00124
00125
00126
00127
00128 static LOGPROB *ftop = NULL;
00129 static LOGPROB *fbottom = NULL;
00130 static LOGPROB lowest;
00131 static LOGPROB maxrange;
00132 static LOGPROB maxrange2;
00133
00146 static void
00147 get_max_frame_score(BACKTRELLIS *bt)
00148 {
00149 int t, i;
00150 TRELLIS_ATOM *tre;
00151 LOGPROB x,y;
00152
00153
00154 if (ftop != NULL) free(ftop);
00155 ftop = mymalloc(sizeof(LOGPROB) * bt->framelen);
00156 if (fbottom != NULL) free(fbottom);
00157 fbottom = mymalloc(sizeof(LOGPROB) * bt->framelen);
00158
00159
00160 maxrange = 0.0;
00161 for (t=0;t<bt->framelen;t++) {
00162 x = LOG_ZERO;
00163 y = 0.0;
00164 for (i=0;i<bt->num[t];i++) {
00165 tre = bt->rw[t][i];
00166 if (x < tre->backscore) x = tre->backscore;
00167 if (y > tre->backscore) y = tre->backscore;
00168 }
00169 ftop[t] = x;
00170 fbottom[t] = y;
00171 if (maxrange < x - y) maxrange = x - y;
00172 }
00173
00174
00175 lowest = 0.0;
00176 for (t=0;t<bt->framelen;t++) {
00177 if (lowest > fbottom[t]) lowest = fbottom[t];
00178 }
00179 maxrange2 = 0.0;
00180 for (t=0;t<bt->framelen;t++) {
00181 x = lowest * (float)t / (float)bt->framelen;
00182 if (ftop[t] == LOG_ZERO) continue;
00183 if (maxrange2 < abs(ftop[t] - x)) maxrange2 = abs(ftop[t] - x);
00184 if (maxrange2 < abs(fbottom[t] - x)) maxrange2 = abs(fbottom[t] - x);
00185 }
00186 }
00187
00204 static gint
00205 scale_x(int t)
00206 {
00207 return(t * (canvas_width - CANVAS_MARGIN * 2) / btlocal->framelen + CANVAS_MARGIN);
00208 }
00209
00228 static gint
00229 scale_y(LOGPROB s, int t)
00230 {
00231 gint y;
00232 LOGPROB top, bottom;
00233 gint yoffset, height;
00234
00235 if (sw_score_beam) {
00236
00237 top = ftop[t];
00238 if (top == LOG_ZERO) {
00239 bottom = top;
00240 } else {
00241 bottom = ftop[t] - maxrange;
00242 }
00243 } else {
00244
00245 top = lowest * (float)t / (float)btlocal->framelen + maxrange2;
00246 bottom = lowest * (float)t / (float)btlocal->framelen - maxrange2;
00247 }
00248
00249 yoffset = CANVAS_MARGIN + RESULT_HEIGHT + (speechlen != 0 ? (WAVE_MARGIN + WAVE_HEIGHT): 0);
00250 height = canvas_height - yoffset - CANVAS_MARGIN;
00251 if (top <= bottom) {
00252 y = yoffset;
00253 } else {
00254 y = (top - s) * height / (top - bottom) + yoffset;
00255 }
00256 return(y);
00257 }
00258
00275 static gint
00276 scale_y_wid(WORD_ID wid)
00277 {
00278 gint y;
00279 gint yoffset, height;
00280
00281 yoffset = CANVAS_MARGIN + RESULT_HEIGHT + (speechlen != 0 ? (WAVE_MARGIN + WAVE_HEIGHT) : 0);
00282 height = canvas_height - yoffset - CANVAS_MARGIN;
00283 if (wid == WORD_INVALID) {
00284 y = yoffset;
00285 } else {
00286 y = wid * height / winfo->num + yoffset;
00287 }
00288 return(y);
00289 }
00290
00291
00292
00293
00294
00295 static SP16 max_level;
00296
00313 static gint
00314 scale_x_wave(int t)
00315 {
00316 return(t * (canvas_width - CANVAS_MARGIN * 2) / speechlen + CANVAS_MARGIN);
00317 }
00318
00335 static gint
00336 scale_y_wave(SP16 x)
00337 {
00338 return(WAVE_HEIGHT / 2 + WAVE_MARGIN - (x * WAVE_HEIGHT / (max_level * 2)));
00339 }
00340
00351 static void
00352 get_max_waveform_level()
00353 {
00354 int t;
00355 SP16 maxl;
00356
00357 if (speechlen == 0) return;
00358
00359 maxl = 0;
00360 for(t=0;t<speechlen;t++) {
00361 if (maxl < abs(speech[t])) {
00362 maxl = abs(speech[t]);
00363 }
00364 }
00365
00366 max_level = maxl;
00367 if (max_level < 3000) max_level = 3000;
00368 }
00369
00382 static void
00383 draw_waveform(GtkWidget *widget)
00384 {
00385 int t;
00386 gint text_width;
00387 static char buf[20];
00388
00389 if (speechlen == 0) return;
00390
00391
00392 if (dgc == NULL) {
00393 dgc = gdk_gc_new(widget->window);
00394 gdk_gc_copy(dgc, widget->style->fg_gc[GTK_STATE_NORMAL]);
00395 }
00396
00397
00398
00399 gdk_gc_set_foreground(dgc, &(cols[C_WAVEFORM]));
00400 gdk_draw_rectangle(pixmap, dgc, FALSE,
00401 scale_x_wave(0), scale_y_wave(max_level),
00402 scale_x_wave(speechlen-1) - scale_x_wave(0),
00403 scale_y_wave(-max_level) - scale_y_wave(max_level));
00404
00405 if (sw_level_thres) {
00406
00407 gdk_gc_set_foreground(dgc, &(cols[C_LEVELTHRES]));
00408 gdk_draw_line(pixmap, dgc,
00409 scale_x_wave(0), scale_y_wave(level_thres),
00410 scale_x_wave(speechlen-1), scale_y_wave(level_thres));
00411 gdk_draw_line(pixmap, dgc,
00412 scale_x_wave(0), scale_y_wave(-level_thres),
00413 scale_x_wave(speechlen-1), scale_y_wave(-level_thres));
00414 snprintf(buf, 20, "-lv %d", level_thres);
00415 text_width = gdk_string_width(fontset, buf) + 1;
00416 gdk_draw_string(pixmap, fontset, dgc,
00417 canvas_width - CANVAS_MARGIN - text_width - 2,
00418 scale_y_wave(-max_level) - 2,
00419 buf);
00420 }
00421
00422
00423 snprintf(buf, 20, "max: %d", max_level);
00424 text_width = gdk_string_width(fontset, buf) + 1;
00425 gdk_gc_set_foreground(dgc, &(cols[C_WAVEFORM]));
00426 gdk_draw_string(pixmap, fontset, dgc,
00427 canvas_width - CANVAS_MARGIN - text_width - 2,
00428 scale_y_wave(max_level) + 12,
00429 buf);
00430
00431
00432 for(t=1;t<speechlen;t++) {
00433 gdk_gc_set_line_attributes(dgc, 1, GDK_LINE_SOLID, GDK_CAP_BUTT, GDK_JOIN_MITER);
00434 gdk_draw_line(pixmap, dgc,
00435 scale_x_wave(t-1), scale_y_wave(speech[t-1]),
00436 scale_x_wave(t), scale_y_wave(speech[t]));
00437 }
00438 }
00439
00440
00441
00442
00443
00444
00467 static void
00468 mygdk_draw_arc(GtkWidget *widget, int x1, int y1, int x2, int y2, int sw)
00469 {
00470 int width;
00471 UserColors c;
00472
00473
00474 if (dgc == NULL) {
00475 dgc = gdk_gc_new(widget->window);
00476 gdk_gc_copy(dgc, widget->style->fg_gc[GTK_STATE_NORMAL]);
00477 }
00478
00479
00480 switch(sw) {
00481 case 0: c = C_LINE_FAINT; width = 1; break;
00482 case 1: c = C_LINE; width = 1; break;
00483 case 2: c = C_LINE_BEST; width = 3; break;
00484 case 3: c = C_PASS2_NEXT; width = 1; break;
00485 case 4: c = C_PASS2; width = 1; break;
00486 case 5: c = C_PASS2_NEXT; width = 2; break;
00487 case 6: c = C_PASS2_BEST; width = 3; break;
00488 default: c = C_LINE; width = 1; break;
00489 }
00490
00491
00492 if (sw_line) {
00493 gdk_gc_set_line_attributes(dgc, width, GDK_LINE_SOLID, GDK_CAP_BUTT, GDK_JOIN_MITER);
00494 gdk_gc_set_foreground(dgc, &(cols[c]));
00495 gdk_draw_line(pixmap, dgc, x1, y1, x2, y2);
00496 gdk_gc_set_line_attributes(dgc, 1, GDK_LINE_SOLID, GDK_CAP_BUTT, GDK_JOIN_MITER);
00497 }
00498
00499
00500 if (sw != 0 && sw != 5) {
00501
00502 gdk_gc_set_foreground(dgc, &(cols[C_SHADOW]));
00503 gdk_draw_rectangle(pixmap, dgc,
00504 TRUE,
00505 x1 - width/2 - 2,
00506 y1 - width/2 -2,
00507 width+4,
00508 width+4);
00509 gdk_draw_rectangle(pixmap, dgc,
00510 TRUE,
00511 x2 - width/2 - 2,
00512 y2 - width/2 -2,
00513 width+4,
00514 width+4);
00515 }
00516 gdk_gc_set_foreground(dgc, &(cols[C_BGN]));
00517 gdk_draw_rectangle(pixmap, dgc,
00518 TRUE,
00519 x1 - width/2 - 1,
00520 y1 - width/2 -1,
00521 width+2,
00522 width+2);
00523 if (c == C_LINE_BEST || c == C_PASS2_BEST) {
00524 gdk_gc_set_foreground(dgc, &(cols[C_END_BEST]));
00525 } else {
00526 gdk_gc_set_foreground(dgc, &(cols[C_END]));
00527 }
00528 gdk_draw_rectangle(pixmap, dgc,
00529 TRUE,
00530 x2 - width/2 - 1,
00531 y2 - width/2 - 1,
00532 width+2,
00533 width+2);
00534
00535 }
00536
00555 static void
00556 draw_atom_sub(GtkWidget *widget, TRELLIS_ATOM *tre, TRELLIS_ATOM *last_tre, int sw)
00557 {
00558 int from_t;
00559 LOGPROB from_s;
00560 int from_w;
00561
00562
00563 if (sw_wid_axis) {
00564 if (tre->begintime <= 0) {
00565 from_t = 0;
00566 from_w = WORD_INVALID;
00567 } else {
00568 from_t = last_tre->endtime;
00569 from_w = last_tre->wid;
00570 }
00571 mygdk_draw_arc(widget,
00572 scale_x(from_t),
00573 scale_y_wid(from_w),
00574 scale_x(tre->endtime),
00575 scale_y_wid(tre->wid),
00576 sw);
00577 } else {
00578 if (tre->begintime <= 0) {
00579 from_t = 0;
00580 from_s = 0.0;
00581 } else {
00582 from_t = last_tre->endtime;
00583 from_s = last_tre->backscore;
00584 }
00585 mygdk_draw_arc(widget,
00586 scale_x(from_t),
00587 scale_y(from_s, from_t),
00588 scale_x(tre->endtime),
00589 scale_y(tre->backscore, tre->endtime),
00590 sw);
00591 }
00592 }
00593
00610 static void
00611 draw_atom(GtkWidget *widget, TRELLIS_ATOM *tre, int sw)
00612 {
00613 draw_atom_sub(widget, tre, tre->last_tre, sw);
00614 }
00615
00616
00633 static void
00634 draw_atom_text(GtkWidget *widget, TRELLIS_ATOM *tre, int sw)
00635 {
00636 gint text_width;
00637 UserColors c;
00638 int style;
00639 int dx, dy, x, y;
00640
00641 if (winfo->woutput[tre->wid] != NULL && strlen(winfo->woutput[tre->wid]) > 0) {
00642 switch(sw) {
00643 case 0: style = -1; break;
00644 case 1: c = C_TEXT; style = 0; break;
00645 case 2: c = C_TEXT_BEST; style = 1; break;
00646 case 3: c = C_PASS2_NEXT; style = 0; break;
00647 case 4: c = C_PASS2; style = 0; break;
00648 case 5: c = C_PASS2; style = 1; break;
00649 case 6: c = C_PASS2_BEST; style = 1; break;
00650 default: c = C_TEXT; style = 0; break;
00651 }
00652 if (style == -1) return;
00653
00654 text_width = gdk_string_width(fontset, winfo->woutput[tre->wid]) + 1;
00655 x = scale_x(tre->endtime) - text_width;
00656 if (sw_wid_axis) {
00657 y = scale_y_wid(tre->wid) - 4;
00658 } else {
00659 y = scale_y(tre->backscore, tre->endtime) - 4;
00660 }
00661
00662 if (style == 1) {
00663 gdk_gc_set_foreground(dgc, &cols[C_SHADOW]);
00664 for (dx = -1; dx <= 1; dx++) {
00665 for (dy = -1; dy <= 1; dy++) {
00666 if (dx == 0 && dy == 0) continue;
00667 gdk_draw_string(pixmap, fontset, dgc, x + dx, y + dy,
00668 winfo->woutput[tre->wid]);
00669 }
00670 }
00671 }
00672 gdk_gc_set_foreground(dgc, &cols[c]);
00673 gdk_draw_string(pixmap, fontset, dgc, x, y,
00674 winfo->woutput[tre->wid]);
00675 }
00676 }
00677
00678
00679
00680
00681
00682 static WORD_ID *wordlist = NULL;
00683 static WORD_ID wordlistnum = 0;
00684
00701 static boolean
00702 wordlist_find(WORD_ID wid)
00703 {
00704 int left, right, mid;
00705
00706 if (wordlistnum == 0) return FALSE;
00707
00708 left = 0;
00709 right = wordlistnum - 1;
00710 while (left < right) {
00711 mid = (left + right) / 2;
00712 if (wordlist[mid] < wid) {
00713 left = mid + 1;
00714 } else {
00715 right = mid;
00716 }
00717 }
00718 if (wordlist[left] == wid) return TRUE;
00719 return FALSE;
00720 }
00721
00722
00723
00724
00725
00726
00727
00744 static void
00745 draw_atom_top(GtkWidget *widget, TRELLIS_ATOM *tre, int sw)
00746 {
00747 if (wordlistnum == 0 || wordlist_find(tre->wid)) {
00748 draw_atom(widget, tre, sw);
00749 }
00750 }
00751
00770 static void
00771 draw_atom_text_top(GtkWidget *widget, TRELLIS_ATOM *tre, int sw)
00772 {
00773 if (wordlistnum == 0 || wordlist_find(tre->wid)) {
00774 draw_atom_text(widget, tre, sw);
00775 }
00776 }
00777
00778
00779
00780
00781
00782
00795 static void
00796 draw_all_atom(GtkWidget *widget)
00797 {
00798 int t, i;
00799 TRELLIS_ATOM *tre;
00800
00801 for (t=0;t<btlocal->framelen;t++) {
00802 for (i=0;i<btlocal->num[t];i++) {
00803 tre = btlocal->rw[t][i];
00804 draw_atom_top(widget, tre, 0);
00805 }
00806 }
00807 if (sw_text) {
00808 for (t=0;t<btlocal->framelen;t++) {
00809 for (i=0;i<btlocal->num[t];i++) {
00810 tre = btlocal->rw[t][i];
00811 draw_atom_text_top(widget, tre, 0);
00812 }
00813 }
00814 }
00815 }
00816
00829 static void
00830 draw_context_valid_atom(GtkWidget *widget)
00831 {
00832 int t, i;
00833 TRELLIS_ATOM *tre;
00834
00835 for (t=0;t<btlocal->framelen;t++) {
00836 for (i=0;i<btlocal->num[t];i++) {
00837 tre = btlocal->rw[t][i];
00838 if (tre->last_tre != NULL && tre->last_tre->wid != WORD_INVALID) {
00839 draw_atom_top(widget, tre->last_tre, 1);
00840 }
00841 }
00842 }
00843 if (sw_text) {
00844 for (t=0;t<btlocal->framelen;t++) {
00845 for (i=0;i<btlocal->num[t];i++) {
00846 tre = btlocal->rw[t][i];
00847 if (tre->last_tre != NULL && tre->last_tre->wid != WORD_INVALID) {
00848 draw_atom_text_top(widget, tre->last_tre, 1);
00849 }
00850 }
00851 }
00852 }
00853 }
00854
00855 #ifdef WORD_GRAPH
00856
00868 static void
00869 draw_word_graph(GtkWidget *widget)
00870 {
00871 int t, i;
00872 TRELLIS_ATOM *tre;
00873
00874
00875
00876 for (t=0;t<btlocal->framelen;t++) {
00877 for (i=0;i<btlocal->num[t];i++) {
00878 tre = btlocal->rw[t][i];
00879 if (tre->within_wordgraph) {
00880 draw_atom_top(widget, tre, 1);
00881 }
00882 }
00883 }
00884 if (sw_text) {
00885 for (t=0;t<btlocal->framelen;t++) {
00886 for (i=0;i<btlocal->num[t];i++) {
00887 tre = btlocal->rw[t][i];
00888 if (tre->within_wordgraph) {
00889 draw_atom_text_top(widget, tre, 1);
00890 }
00891 }
00892 }
00893 }
00894
00895 }
00896 #endif
00897
00910 static void
00911 draw_best_path(GtkWidget *widget)
00912 {
00913 int last_time;
00914 LOGPROB maxscore;
00915 TRELLIS_ATOM *tre, *last_tre;
00916 int i;
00917
00918
00919 for (last_time = btlocal->framelen - 1; last_time >= 0; last_time--) {
00920 #ifdef USE_NGRAM
00921
00922 last_tre = bt_binsearch_atom(btlocal, last_time, winfo->tail_silwid);
00923 if (last_tre != NULL) break;
00924 #else
00925
00926 maxscore = LOG_ZERO;
00927 for (i=0;i<btlocal->num[last_time];i++) {
00928 tre = btlocal->rw[last_time][i];
00929
00930 if (maxscore < tre->backscore) {
00931 maxscore = tre->backscore;
00932 last_tre = tre;
00933 }
00934
00935 }
00936 if (maxscore != LOG_ZERO) break;
00937 #endif
00938 }
00939 if (last_time < 0) return;
00940
00941
00942 draw_atom_top(widget, last_tre, 2);
00943 tre = last_tre;
00944 while (tre->begintime > 0) {
00945 tre = tre->last_tre;
00946 draw_atom_top(widget, tre, 2);
00947 }
00948 if (sw_text) {
00949 draw_atom_text_top(widget, last_tre, 2);
00950 tre = last_tre;
00951 while (tre->begintime > 0) {
00952 tre = tre->last_tre;
00953 draw_atom_text_top(widget, tre, 2);
00954 }
00955 }
00956 }
00957
00958
00959
00960
00961
00962
00963
00964
00977 void
00978 visual2_init(int maxhypo)
00979 {
00980 POPNODE *p, *ptmp;
00981 int i;
00982
00983 if (popped == NULL) {
00984 popped = (POPNODE *)mymalloc(sizeof(POPNODE) * (maxhypo + 1));
00985 } else {
00986 for(i=0;i<pnum;i++) {
00987 p = popped[i].next;
00988 while(p) {
00989 ptmp = p->next;
00990 free(p);
00991 p = ptmp;
00992 }
00993 }
00994 }
00995 pnum = 1;
00996
00997 popped[0].tre = NULL;
00998 popped[0].score = LOG_ZERO;
00999 popped[0].last = NULL;
01000 popped[0].next = NULL;
01001
01002
01003 p = lastpop;
01004 while(p) {
01005 ptmp = p->next;
01006 free(p);
01007 p = ptmp;
01008 }
01009 lastpop = NULL;
01010 }
01011
01026 void
01027 visual2_popped(NODE *n, int popctr)
01028 {
01029 if (pnum < popctr + 1) pnum = popctr + 1;
01030
01031 popped[popctr].tre = n->popnode->tre;
01032 popped[popctr].score = n->popnode->score;
01033 popped[popctr].last = n->popnode->last;
01034 popped[popctr].next = NULL;
01035
01036 n->popnode = &(popped[popctr]);
01037 }
01038
01055 void
01056 visual2_next_word(NODE *next, NODE *prev, int popctr)
01057 {
01058 POPNODE *new;
01059
01060
01061 new = (POPNODE *)mymalloc(sizeof(POPNODE));
01062 new->tre = next->tre;
01063 new->score = next->score;
01064
01065 new->last = (prev) ? prev->popnode : NULL;
01066 next->popnode = new;
01067
01068 new->next = popped[popctr].next;
01069 popped[popctr].next = new;
01070 }
01071
01086 void
01087 visual2_best(NODE *now, WORD_INFO *winfo)
01088 {
01089 POPNODE *new;
01090
01091 new = (POPNODE *)mymalloc(sizeof(POPNODE));
01092 new->tre = now->popnode->tre;
01093 new->score = now->popnode->score;
01094 new->last = now->popnode->last;
01095 new->next = lastpop;
01096 lastpop = new;
01097 }
01098
01099
01100
01101
01102
01103
01116 static void
01117 draw_final_results(GtkWidget *widget)
01118 {
01119 POPNODE *firstp, *lastp, *p;
01120
01121 for(firstp = lastpop; firstp; firstp = firstp->next) {
01122 if (firstp->tre != NULL) {
01123 draw_atom(widget, firstp->tre, 6);
01124 }
01125 lastp = firstp;
01126 for(p = firstp->last; p; p = p->last) {
01127 if (p->tre != NULL) {
01128 draw_atom_sub(widget, p->tre, lastp->tre, 6);
01129 draw_atom_text_top(widget, p->tre, 6);
01130 }
01131 lastp = p;
01132 }
01133 }
01134 }
01135
01136 static LOGPROB maxscore;
01137 static LOGPROB minscore;
01138
01148 static void
01149 get_max_hypo_score()
01150 {
01151 POPNODE *p;
01152 int i;
01153
01154 maxscore = LOG_ZERO;
01155 minscore = 0.0;
01156 for(i=1;i<pnum;i++) {
01157 if (maxscore < popped[i].score) maxscore = popped[i].score;
01158 if (minscore > popped[i].score) minscore = popped[i].score;
01159 }
01160 }
01161
01178 static gint
01179 scale_hypo_y(LOGPROB s)
01180 {
01181 gint y;
01182 gint yoffset, height;
01183
01184 yoffset = CANVAS_MARGIN + RESULT_HEIGHT + (speechlen != 0 ? (WAVE_MARGIN + WAVE_HEIGHT) : 0);
01185 height = canvas_height - yoffset - CANVAS_MARGIN;
01186 y = (maxscore - s) * height / (maxscore - minscore) + yoffset;
01187 return(y);
01188 }
01189
01190
01211 static void
01212 draw_popped(GtkWidget *widget, POPNODE *p, UserColors c, int width, int style)
01213 {
01214 int text_width;
01215 gint x, y;
01216
01217 if (p->tre == NULL) return;
01218
01219 if (p->last != NULL && p->last->tre != NULL) {
01220 gdk_gc_set_line_attributes(dgc, width, GDK_LINE_SOLID, GDK_CAP_BUTT, GDK_JOIN_MITER);
01221 gdk_gc_set_foreground(dgc, &(cols[c]));
01222 gdk_draw_line(pixmap, dgc,
01223 scale_x(p->last->tre->endtime),
01224 scale_hypo_y(p->last->score),
01225 scale_x(p->tre->endtime),
01226 scale_hypo_y(p->score));
01227 gdk_gc_set_line_attributes(dgc, 1, GDK_LINE_SOLID, GDK_CAP_BUTT, GDK_JOIN_MITER);
01228 }
01229
01230 if (p->tre != NULL) {
01231 x = scale_x(p->tre->endtime);
01232 y = scale_hypo_y(p->score);
01233 if (style == 1) {
01234 gdk_gc_set_foreground(dgc, &(cols[C_SHADOW]));
01235 gdk_draw_rectangle(pixmap, dgc,
01236 TRUE,
01237 x - 3,
01238 y - 3,
01239 7,
01240 7);
01241 } else if (style == 2) {
01242 gdk_gc_set_foreground(dgc, &(cols[c]));
01243 gdk_draw_rectangle(pixmap, dgc,
01244 TRUE,
01245 x - 3,
01246 y - 3,
01247 7,
01248 7);
01249 }
01250 gdk_gc_set_foreground(dgc, &(cols[c]));
01251 gdk_draw_rectangle(pixmap, dgc,
01252 TRUE,
01253 x - 2,
01254 y - 2,
01255 5,
01256 5);
01257 if (p->tre->wid != WORD_INVALID) {
01258 text_width = gdk_string_width(fontset, winfo->woutput[p->tre->wid]) + 1;
01259 gdk_draw_string(pixmap, fontset, dgc, x - text_width-1, y - 5,
01260 winfo->woutput[p->tre->wid]);
01261 }
01262 }
01263
01264
01265 }
01266
01267
01268
01269 static int old_popctr;
01270
01285 static void
01286 draw_popnodes(GtkWidget *widget, int popctr)
01287 {
01288 POPNODE *p, *porg;
01289
01290 if (popctr < 0 || popctr >= pnum) {
01291 j_printerr("invalid popctr (%d > %d)!\n", popctr, pnum);
01292 return;
01293 }
01294
01295 porg = &(popped[popctr]);
01296
01297
01298 for(p = porg->next; p; p = p->next) {
01299 draw_popped(widget, p, C_LINE_BEST, 1, 0);
01300 }
01301
01302
01303 for(p = porg->last; p; p = p->last) {
01304 draw_popped(widget, p, C_PASS2_BEST, 2, 0);
01305 }
01306 draw_popped(widget, porg, C_PASS2_BEST, 3, 1);
01307
01308 old_popctr = popctr;
01309 }
01322 static void
01323 draw_popnodes_old(GtkWidget *widget)
01324 {
01325 POPNODE *p, *porg;
01326
01327 porg = &(popped[old_popctr]);
01328
01329
01330 for(p = porg->next; p; p = p->next) {
01331 draw_popped(widget, p, C_LINE_FAINT, 1, 0);
01332 }
01333
01334
01335 for(p = porg->last; p; p = p->last) {
01336 draw_popped(widget, p, C_PASS2, 2, 0);
01337 }
01338 draw_popped(widget, porg, C_PASS2, 3, 2);
01339 }
01340
01341
01342
01343
01344
01345 static boolean fitscreen = TRUE;
01346
01359 static void
01360 draw_background(GtkWidget *widget)
01361 {
01362 static char buf[MAX_HMMNAME_LEN];
01363
01364
01365 if (dgc == NULL) {
01366 dgc = gdk_gc_new(widget->window);
01367 gdk_gc_copy(dgc, widget->style->fg_gc[GTK_STATE_NORMAL]);
01368 }
01369
01370 gdk_gc_set_foreground(dgc, &(cols[C_BG]));
01371 gdk_draw_rectangle(pixmap, dgc, TRUE,
01372 0,0,canvas_width,canvas_height);
01373
01374
01375 gdk_gc_set_foreground(dgc, &(cols[C_TEXT]));
01376 if (sw_hypo) {
01377 gdk_draw_string(pixmap, fontset, dgc, 0, canvas_height - 16,
01378 "Hypothesis score (2nd pass)");
01379 } else {
01380 gdk_draw_string(pixmap, fontset, dgc, 0, canvas_height - 16,
01381 sw_wid_axis ? "Word ID" : (sw_score_beam ? "Beam score" : "Accumulated score (normalized by time)"));
01382 }
01383 snprintf(buf, 50, "x%3.1f", (float)canvas_width / (float)btlocal->framelen);
01384 gdk_draw_string(pixmap, fontset, dgc, 0, canvas_height - 3, buf);
01385 }
01386
01399 static void
01400 drawarea_draw(GtkWidget *widget)
01401 {
01402
01403 if (pixmap) {
01404 gdk_pixmap_unref(pixmap);
01405 }
01406 pixmap = gdk_pixmap_new(widget->window, canvas_width, canvas_height, -1);
01407
01408
01409 draw_background(widget);
01410
01411 if (speechlen != 0) {
01412 draw_waveform(widget);
01413 }
01414
01415 if (!sw_hypo) {
01416 if (btlocal != NULL) {
01417
01418 draw_all_atom(widget);
01419 #ifdef WORD_GRAPH
01420 draw_word_graph(widget);
01421 #else
01422 draw_context_valid_atom(widget);
01423 #endif
01424 draw_best_path(widget);
01425 }
01426 if (popped != NULL) {
01427
01428 draw_final_results(widget);
01429 }
01430 }
01431 }
01432
01445 static void
01446 drawarea_expose(GtkWidget *widget)
01447 {
01448 GdkRectangle r;
01449
01450 r.x = 0;
01451 r.y = 0;
01452 r.width = canvas_width;
01453 r.height = canvas_height;
01454 gtk_widget_draw(widget, &r);
01455 }
01456
01477 static gboolean
01478 event_drawarea_expose(GtkWidget *widget, GdkEventExpose *event, gpointer user_data)
01479 {
01480 if (pixmap != NULL) {
01481 gdk_draw_pixmap(widget->window,
01482 widget->style->fg_gc[GTK_STATE_NORMAL],
01483 pixmap,
01484 event->area.x, event->area.y,
01485 event->area.x, event->area.y,
01486 event->area.width, event->area.height);
01487 }
01488 }
01489
01510 static gboolean
01511 event_drawarea_configure(GtkWidget *widget, GdkEventExpose *event, gpointer user_data)
01512 {
01513 if (fitscreen) {
01514 canvas_width = widget->allocation.width;
01515 }
01516
01517 canvas_height = widget->allocation.height;
01518
01519
01520 drawarea_draw(widget);
01521 }
01522
01523
01524
01525
01526
01527
01542 static void
01543 action_toggle_thres(GtkWidget *widget)
01544 {
01545
01546 if (speechlen == 0) return;
01547
01548 if (sw_level_thres) sw_level_thres = FALSE;
01549 else sw_level_thres = TRUE;
01550
01551
01552 drawarea_draw(widget);
01553
01554
01555 drawarea_expose(widget);
01556 }
01557
01558 #ifdef PLAYCOMMAND
01559
01571 static void
01572 action_play_waveform(GtkWidget *widget)
01573 {
01574 char buf[80];
01575 static char command[250];
01576 int fd;
01577
01578 if (speechlen == 0) return;
01579
01580
01581 snprintf(buf, 250, "/var/tmp/julius_visual_play.%d", getpid());
01582 if ((fd = open(buf, O_CREAT | O_TRUNC | O_WRONLY, 0644)) < 0) {
01583 j_printerr("cannot open %s for writing\n", buf);
01584 return;
01585 }
01586 if (wrsamp(fd, speech, speechlen) < 0) {
01587 j_printerr("failed to write to %s for playing\n", buf);
01588 return;
01589 }
01590 close(fd);
01591
01592 snprintf(command, 250, PLAYCOMMAND, para.smp_freq, buf);
01593 j_printf("play: [%s]\n", command);
01594 system(command);
01595
01596 unlink(buf);
01597 }
01598 #endif
01599
01614 static void
01615 action_view_wid(GtkWidget *button, GtkWidget *widget)
01616 {
01617 if (GTK_TOGGLE_BUTTON(button)->active) {
01618
01619 sw_wid_axis = TRUE;
01620 sw_hypo = FALSE;
01621
01622 drawarea_draw(widget);
01623
01624 drawarea_expose(widget);
01625 } else {
01626 sw_wid_axis = FALSE;
01627 }
01628 }
01629
01644 static void
01645 action_view_score(GtkWidget *button, GtkWidget *widget)
01646 {
01647 if (GTK_TOGGLE_BUTTON(button)->active) {
01648
01649 sw_score_beam = FALSE;
01650 sw_hypo = FALSE;
01651
01652 drawarea_draw(widget);
01653
01654 drawarea_expose(widget);
01655 }
01656 }
01657
01674 static void
01675 action_view_beam(GtkWidget *button, GtkWidget *widget)
01676 {
01677 if (GTK_TOGGLE_BUTTON(button)->active) {
01678
01679 sw_score_beam = TRUE;
01680 sw_hypo = FALSE;
01681
01682 drawarea_draw(widget);
01683
01684 drawarea_expose(widget);
01685 }
01686 }
01687
01704 static void
01705 action_toggle_arc(GtkWidget *button, GtkWidget *widget)
01706 {
01707 if (GTK_TOGGLE_BUTTON(button)->active) {
01708 sw_text = TRUE;
01709 sw_line = TRUE;
01710 } else {
01711 sw_text = FALSE;
01712 sw_line = FALSE;
01713 }
01714
01715 drawarea_draw(widget);
01716
01717 drawarea_expose(widget);
01718 }
01719
01736 static void
01737 action_set_wid(GtkWidget *widget, GtkWidget *draw)
01738 {
01739 gchar *entry_text;
01740 WORD_ID i;
01741
01742 entry_text = gtk_entry_get_text(GTK_ENTRY(widget));
01743
01744
01745 if (wordlist == NULL) {
01746 wordlist = mymalloc(sizeof(WORD_ID) * winfo->num);
01747 }
01748 wordlistnum = 0;
01749
01750
01751 if (strlen(entry_text) == 0) {
01752 wordlistnum = 0;
01753 } else {
01754 for (i=0;i<winfo->num;i++) {
01755 if (strmatch(entry_text, winfo->woutput[i])) {
01756 wordlist[wordlistnum] = i;
01757 wordlistnum++;
01758 }
01759 }
01760 if (wordlistnum == 0) {
01761 j_printerr("word \"%s\" not found, show all\n", entry_text);
01762 } else {
01763 j_printerr("%d words found for \"%s\"\n", wordlistnum, entry_text);
01764 }
01765 }
01766
01767
01768 drawarea_draw(draw);
01769
01770 drawarea_expose(draw);
01771 }
01772
01787 static void
01788 action_zoom(GtkWidget *widget)
01789 {
01790 fitscreen = FALSE;
01791 if (btlocal != NULL) {
01792 canvas_width = btlocal->framelen * 2;
01793 gtk_drawing_area_size(GTK_DRAWING_AREA(widget), canvas_width, canvas_height);
01794
01795 }
01796 drawarea_draw(widget);
01797 drawarea_expose(widget);
01798 }
01799
01814 static void
01815 action_zoom_4(GtkWidget *widget)
01816 {
01817 fitscreen = FALSE;
01818 if (btlocal != NULL) {
01819 canvas_width = btlocal->framelen * 4;
01820 gtk_drawing_area_size(GTK_DRAWING_AREA(widget), canvas_width, canvas_height);
01821 }
01822
01823 drawarea_draw(widget);
01824 drawarea_expose(widget);
01825 }
01826
01841 static void
01842 action_zoom_8(GtkWidget *widget)
01843 {
01844 fitscreen = FALSE;
01845 if (btlocal != NULL) {
01846 canvas_width = btlocal->framelen * 8;
01847 gtk_drawing_area_size(GTK_DRAWING_AREA(widget), canvas_width, canvas_height);
01848 }
01849
01850 drawarea_draw(widget);
01851 drawarea_expose(widget);
01852 }
01853
01868 static void
01869 action_fit_screen(GtkWidget *widget)
01870 {
01871 fitscreen = TRUE;
01872 canvas_width = widget->parent->allocation.width;
01873 gtk_drawing_area_size(GTK_DRAWING_AREA(widget), canvas_width, canvas_height);
01874
01875 drawarea_draw(widget);
01876 drawarea_expose(widget);
01877 }
01878
01894 static void
01895 action_toggle_popctr(GtkWidget *button, GtkWidget *widget)
01896 {
01897 if (GTK_TOGGLE_BUTTON(button)->active) {
01898 sw_hypo = TRUE;
01899 } else {
01900 sw_hypo = FALSE;
01901 }
01902 drawarea_draw(widget);
01903 drawarea_expose(widget);
01904 }
01905
01923 static void
01924 action_change_popctr(GtkAdjustment *adj, GtkWidget *widget)
01925 {
01926 int popctr;
01927
01928 if (sw_hypo) {
01929 popctr = adj->value;
01930 draw_popnodes_old(widget);
01931 draw_popnodes(widget, popctr);
01932 drawarea_expose(widget);
01933 }
01934 }
01935
01936
01937
01938
01939
01960 static gint
01961 delete_event(GtkWidget *widget, GdkEvent *event, gpointer data)
01962 {
01963 return (FALSE);
01964 }
01965
01980 static void
01981 destroy(GtkWidget *widget, gpointer data)
01982 {
01983 gtk_main_quit();
01984 }
01985
01986
01987
01988
01989
01998 void
01999 visual_init()
02000 {
02001 POPNODE *p;
02002
02003
02004 btlocal = NULL;
02005
02006
02007
02008
02009 gtk_init(NULL, NULL);
02010
02011
02012 gtk_set_locale();
02013
02014
02015 fontset = gdk_fontset_load(FONTSET);
02016 if (fontset == NULL) {
02017 j_error("cannot load X font \"%s\" for visualize\n", FONTSET);
02018 }
02019
02020
02021 color_init();
02022
02023 j_printerr("GTK initialized\n");
02024
02025 }
02026
02039 void
02040 visual_show(BACKTRELLIS *bt)
02041 {
02042 GtkWidget *window, *button, *draw, *entry, *scrolled_window, *scale;
02043 GtkWidget *box1, *box2, *label, *frame, *box3;
02044 GtkObject *adj;
02045 GSList *group;
02046 GList *glist;
02047
02048
02049 j_printerr("*** Showing word trellis view (close window to proceed)\n");
02050
02051
02052 btlocal = bt;
02053
02054
02055 get_max_frame_score(bt);
02056
02057
02058 get_max_hypo_score();
02059
02060
02061 if (speechlen != 0) get_max_waveform_level();
02062
02063
02064 sw_hypo = FALSE;
02065
02066
02067 fitscreen = TRUE;
02068 if (dgc != NULL) {
02069 gdk_gc_unref(dgc);
02070 dgc = NULL;
02071 }
02072
02073
02074 window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
02075 gtk_widget_set_usize(GTK_WIDGET(window), DEFAULT_WINDOW_WIDTH, DEFAULT_WINDOW_HEIGHT);
02076 gtk_window_set_title(GTK_WINDOW(window), WINTITLE);
02077 gtk_signal_connect(GTK_OBJECT(window), "delete_event",
02078 GTK_SIGNAL_FUNC(delete_event), NULL);
02079 gtk_signal_connect(GTK_OBJECT(window), "destroy",
02080 GTK_SIGNAL_FUNC(destroy), NULL);
02081 gtk_container_border_width(GTK_CONTAINER(window), 10);
02082
02083
02084 box1 = gtk_hbox_new(FALSE, 5);
02085 gtk_container_add(GTK_CONTAINER(window), box1);
02086
02087
02088 scrolled_window = gtk_scrolled_window_new(NULL, NULL);
02089 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window), GTK_POLICY_ALWAYS,GTK_POLICY_AUTOMATIC);
02090
02091
02092 draw = gtk_drawing_area_new();
02093
02094 gtk_signal_connect(GTK_OBJECT(draw), "expose-event", GTK_SIGNAL_FUNC(event_drawarea_expose), NULL);
02095 gtk_signal_connect(GTK_OBJECT(draw), "configure-event", GTK_SIGNAL_FUNC(event_drawarea_configure), NULL);
02096 gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(scrolled_window), draw);
02097 gtk_box_pack_start(GTK_BOX(box1), scrolled_window, TRUE, TRUE, 0);
02098
02099
02100 box2 = gtk_vbox_new(FALSE, 5);
02101 gtk_box_pack_start(GTK_BOX(box1), box2, FALSE, TRUE, 0);
02102
02103 if (speechlen != 0) {
02104
02105 frame = gtk_frame_new("waveform");
02106 gtk_box_pack_start(GTK_BOX(box2), frame, FALSE, FALSE, 0);
02107 box3 = gtk_hbox_new(FALSE, 5);
02108 gtk_container_set_border_width(GTK_CONTAINER(box3), 5);
02109 gtk_container_add(GTK_CONTAINER(frame), box3);
02110
02111
02112 #ifdef PLAYCOMMAND
02113 button = gtk_button_new_with_label("play");
02114 gtk_signal_connect_object(GTK_OBJECT(button), "clicked",
02115 GTK_SIGNAL_FUNC(action_play_waveform), GTK_OBJECT(draw));
02116 gtk_box_pack_start(GTK_BOX(box3), button, FALSE, FALSE, 0);
02117 #endif
02118
02119
02120 button = gtk_button_new_with_label("thres");
02121 gtk_signal_connect_object(GTK_OBJECT(button), "clicked",
02122 GTK_SIGNAL_FUNC(action_toggle_thres), GTK_OBJECT(draw));
02123 gtk_box_pack_start(GTK_BOX(box3), button, FALSE, FALSE, 0);
02124 }
02125
02126
02127 frame = gtk_frame_new("change view");
02128 gtk_box_pack_start(GTK_BOX(box2), frame, FALSE, FALSE, 0);
02129 box3 = gtk_hbox_new(FALSE, 5);
02130 gtk_container_set_border_width(GTK_CONTAINER(box3), 5);
02131 gtk_container_add(GTK_CONTAINER(frame), box3);
02132
02133
02134 button = gtk_radio_button_new_with_label(NULL, "word");
02135 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), TRUE);
02136 gtk_signal_connect(GTK_OBJECT(button), "toggled",
02137 GTK_SIGNAL_FUNC(action_view_wid), GTK_OBJECT(draw));
02138 gtk_box_pack_start(GTK_BOX(box3), button, FALSE, FALSE, 0);
02139
02140
02141 group = gtk_radio_button_group(GTK_RADIO_BUTTON(button));
02142 button = gtk_radio_button_new_with_label(group, "score");
02143 gtk_signal_connect(GTK_OBJECT(button), "toggled",
02144 GTK_SIGNAL_FUNC(action_view_score), GTK_OBJECT(draw));
02145 gtk_box_pack_start(GTK_BOX(box3), button, FALSE, FALSE, 0);
02146
02147
02148 group = gtk_radio_button_group(GTK_RADIO_BUTTON(button));
02149 button = gtk_radio_button_new_with_label(group, "beam");
02150 gtk_signal_connect(GTK_OBJECT(button), "toggled",
02151 GTK_SIGNAL_FUNC(action_view_beam), GTK_OBJECT(draw));
02152 gtk_box_pack_start(GTK_BOX(box3), button, FALSE, FALSE, 0);
02153
02154
02155 frame = gtk_frame_new("show/hide");
02156 gtk_box_pack_start(GTK_BOX(box2), frame, FALSE, FALSE, 0);
02157 box3 = gtk_vbox_new(FALSE, 5);
02158 gtk_container_set_border_width(GTK_CONTAINER(box3), 5);
02159 gtk_container_add(GTK_CONTAINER(frame), box3);
02160
02161
02162 button = gtk_toggle_button_new_with_label("arcs");
02163 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), TRUE);
02164 gtk_signal_connect(GTK_OBJECT(button), "toggled",
02165 GTK_SIGNAL_FUNC(action_toggle_arc), GTK_OBJECT(draw));
02166 gtk_box_pack_start(GTK_BOX(box3), button, FALSE, FALSE, 0);
02167
02168
02169 frame = gtk_frame_new("view words");
02170 gtk_box_pack_start(GTK_BOX(box2), frame, FALSE, FALSE, 0);
02171 box3 = gtk_vbox_new(FALSE, 5);
02172 gtk_container_set_border_width(GTK_CONTAINER(box3), 5);
02173 gtk_container_add(GTK_CONTAINER(frame), box3);
02174
02175
02176 entry = gtk_entry_new_with_max_length(16);
02177 gtk_signal_connect(GTK_OBJECT(entry), "activate",
02178 GTK_SIGNAL_FUNC(action_set_wid), GTK_OBJECT(draw));
02179 gtk_box_pack_start(GTK_BOX(box3), entry, FALSE, FALSE, 0);
02180
02181
02182 frame = gtk_frame_new("zoom");
02183 gtk_box_pack_start(GTK_BOX(box2), frame, FALSE, FALSE, 0);
02184 box3 = gtk_hbox_new(FALSE, 5);
02185 gtk_container_set_border_width(GTK_CONTAINER(box3), 5);
02186 gtk_container_add(GTK_CONTAINER(frame), box3);
02187
02188
02189 button = gtk_button_new_with_label("x2");
02190 gtk_signal_connect_object(GTK_OBJECT(button), "clicked",
02191 GTK_SIGNAL_FUNC(action_zoom), GTK_OBJECT(draw));
02192 gtk_box_pack_start(GTK_BOX(box3), button, FALSE, FALSE, 0);
02193
02194
02195 button = gtk_button_new_with_label("x4");
02196 gtk_signal_connect_object(GTK_OBJECT(button), "clicked",
02197 GTK_SIGNAL_FUNC(action_zoom_4), GTK_OBJECT(draw));
02198 gtk_box_pack_start(GTK_BOX(box3), button, FALSE, FALSE, 0);
02199
02200
02201 button = gtk_button_new_with_label("x8");
02202 gtk_signal_connect_object(GTK_OBJECT(button), "clicked",
02203 GTK_SIGNAL_FUNC(action_zoom_8), GTK_OBJECT(draw));
02204 gtk_box_pack_start(GTK_BOX(box3), button, FALSE, FALSE, 0);
02205
02206
02207 button = gtk_button_new_with_label("fit");
02208 gtk_signal_connect_object(GTK_OBJECT(button), "clicked",
02209 GTK_SIGNAL_FUNC(action_fit_screen), GTK_OBJECT(draw));
02210 gtk_box_pack_start(GTK_BOX(box3), button, FALSE, FALSE, 0);
02211
02212
02213 frame = gtk_frame_new("pass2 replay");
02214 gtk_box_pack_start(GTK_BOX(box2), frame, FALSE, FALSE, 0);
02215 box3 = gtk_vbox_new(FALSE, 5);
02216 gtk_container_set_border_width(GTK_CONTAINER(box3), 5);
02217 gtk_container_add(GTK_CONTAINER(frame), box3);
02218
02219 adj = gtk_adjustment_new(0.0, 0.0, (pnum-1) + 5, 1.0, 1.0, 5.0);
02220 gtk_signal_connect(GTK_OBJECT(adj), "value_changed",
02221 GTK_SIGNAL_FUNC(action_change_popctr), GTK_OBJECT(draw));
02222
02223
02224 button = gtk_toggle_button_new_with_label("start");
02225 gtk_signal_connect(GTK_OBJECT(button), "toggled",
02226 GTK_SIGNAL_FUNC(action_toggle_popctr), GTK_OBJECT(draw));
02227 gtk_box_pack_start(GTK_BOX(box3), button, FALSE, FALSE, 0);
02228
02229
02230 scale = gtk_hscale_new(GTK_ADJUSTMENT(adj));
02231 gtk_scale_set_digits(GTK_SCALE(scale), 0);
02232 gtk_box_pack_start(GTK_BOX(box3), scale, FALSE, FALSE, 0);
02233
02234
02235 button = gtk_button_new_with_label("close");
02236
02237 gtk_signal_connect_object(GTK_OBJECT(button), "clicked",
02238 GTK_SIGNAL_FUNC(gtk_widget_destroy),
02239 GTK_OBJECT(window));
02240
02241 gtk_box_pack_start(GTK_BOX(box2), button, FALSE, FALSE, 0);
02242
02243
02244 gtk_widget_show_all(window);
02245
02246
02247 gtk_main();
02248 }
02249
02250 #endif