#include "snd.h" #include #include #include #if __GNUC__ #ifdef LESSTIF_VERSION /* moved the warning here so it only is displayed once */ #warning You appear to be using Lesstif: this is not recommended! Expect bugs... #endif #if (XmVERSION == 1) #warning Motif 1 is no longer supported -- this has little chance of working... #endif #endif /* In case of X error that simply exits without any stack trace, first * * XSynchronize(dpy, true); * XSync(dpy, true); * * around line 30817 (where ss->mainapp gets set) * then if still trouble, make an X error handler: * * static XErrorHandler old_handler = (XErrorHandler) 0; * static int ApplicationErrorHandler(Display *display, XErrorEvent *theEvent) * { * (void) fprintf(stderr, "Xlib error: error code %d request code %d\n", theEvent->error_code, theEvent->request_code); * abort(); * return 0; * } * * and at the same point as before * * old_handler = XSetErrorHandler(ApplicationErrorHandler); * * code 8 seems to mean a newly created window is unhappy (tooltip for example) */ static XmRenderTable get_xm_font(XFontStruct *ignore, const char *font, const char *tag) { XmRendition tmp; XmRenderTable tabl; int n; Arg args[12]; n = 0; XtSetArg(args[n], XmNfontName, font); n++; XtSetArg(args[n], XmNfontType, XmFONT_IS_FONT); n++; XtSetArg(args[n], XmNloadModel, XmLOAD_IMMEDIATE); n++; tmp = XmRenditionCreate(main_shell(ss), (char *)tag, args, n); tabl = XmRenderTableAddRenditions(NULL, &tmp, 1, XmMERGE_NEW); /* XmRenditionFree(tmp); */ /* valgrind thinks this is a bad idea */ return(tabl); } /* to see all fonts: (format #f "~{~A~%~}" (XListFonts (XtDisplay (cadr (main-widgets))) "*" 10000)) */ bool set_tiny_font(const char *font) { XFontStruct *fs = NULL; fs = XLoadQueryFont(main_display(ss), font); if (fs) { /* it's not clear to me whether this is safe -- what if two fontstructs are pointing to the same font? */ if (TINY_FONT(ss)) XFreeFont(main_display(ss), TINY_FONT(ss)); if (tiny_font(ss)) free(tiny_font(ss)); in_set_tiny_font(mus_strdup(font)); TINY_FONT(ss) = fs; if (ss->tiny_fontlist) XM_FONT_FREE(ss->tiny_fontlist); ss->tiny_fontlist = get_xm_font(TINY_FONT(ss), font, "tiny_font"); return(true); } return(false); } bool set_listener_font(const char *font) { XFontStruct *fs = NULL; fs = XLoadQueryFont(main_display(ss), font); if (fs) { if (LISTENER_FONT(ss)) XFreeFont(main_display(ss), LISTENER_FONT(ss)); if (listener_font(ss)) free(listener_font(ss)); in_set_listener_font(mus_strdup(font)); LISTENER_FONT(ss) = fs; if (ss->listener_fontlist) XM_FONT_FREE(ss->listener_fontlist); ss->listener_fontlist = get_xm_font(LISTENER_FONT(ss), font, "listener_font"); set_listener_text_font(); return(true); } return(false); } bool set_peaks_font(const char *font) { XFontStruct *fs = NULL; fs = XLoadQueryFont(main_display(ss), font); if (fs) { if (PEAKS_FONT(ss)) XFreeFont(main_display(ss), PEAKS_FONT(ss)); if (peaks_font(ss)) free(peaks_font(ss)); in_set_peaks_font(mus_strdup(font)); PEAKS_FONT(ss) = fs; if (ss->peaks_fontlist) XM_FONT_FREE(ss->peaks_fontlist); ss->peaks_fontlist = get_xm_font(PEAKS_FONT(ss), font, "peaks_font"); return(true); } return(false); } bool set_bold_peaks_font(const char *font) { XFontStruct *fs = NULL; fs = XLoadQueryFont(main_display(ss), font); if (fs) { if (BOLD_PEAKS_FONT(ss)) XFreeFont(main_display(ss), BOLD_PEAKS_FONT(ss)); if (bold_peaks_font(ss)) free(bold_peaks_font(ss)); in_set_bold_peaks_font(mus_strdup(font)); BOLD_PEAKS_FONT(ss) = fs; if (ss->bold_peaks_fontlist) XM_FONT_FREE(ss->bold_peaks_fontlist); ss->bold_peaks_fontlist = get_xm_font(BOLD_PEAKS_FONT(ss), font, "bold_peaks_font"); return(true); } return(false); } bool set_axis_label_font(const char *font) { XFontStruct *fs = NULL; fs = XLoadQueryFont(main_display(ss), font); if (fs) { if (AXIS_LABEL_FONT(ss)) XFreeFont(main_display(ss), AXIS_LABEL_FONT(ss)); if (axis_label_font(ss)) free(axis_label_font(ss)); in_set_axis_label_font(mus_strdup(font)); AXIS_LABEL_FONT(ss) = fs; #if HAVE_GL reload_label_font(); #endif return(true); } return(false); } bool set_axis_numbers_font(const char *font) { XFontStruct *fs = NULL; fs = XLoadQueryFont(main_display(ss), font); if (fs) { if (AXIS_NUMBERS_FONT(ss)) XFreeFont(main_display(ss), AXIS_NUMBERS_FONT(ss)); if (axis_numbers_font(ss)) free(axis_numbers_font(ss)); in_set_axis_numbers_font(mus_strdup(font)); AXIS_NUMBERS_FONT(ss) = fs; #if HAVE_GL reload_number_font(); #endif return(true); } return(false); } int mark_name_width(const char *txt) { if (txt) return(XTextWidth(PEAKS_FONT(ss), txt, strlen(txt))); return(0); } int label_width(const char *txt, bool use_tiny_font) { if (txt) return(XTextWidth((use_tiny_font) ? TINY_FONT(ss) : AXIS_LABEL_FONT(ss), txt, strlen(txt))); else return(0); } int number_width(const char *num, bool use_tiny_font) { if (num) return(XTextWidth((use_tiny_font) ? TINY_FONT(ss) : AXIS_NUMBERS_FONT(ss), num, strlen(num))); return(0); } int number_height(XFontStruct *numbers_font) { return(numbers_font->ascent); } int label_height(bool use_tiny_font) { XFontStruct *label_font; if (use_tiny_font) label_font = TINY_FONT(ss); else label_font = AXIS_LABEL_FONT(ss); return(label_font->ascent + label_font->descent); } void clear_window(graphics_context *ax) { if ((ax) && (ax->dp) && (ax->wn)) XClearWindow(ax->dp, ax->wn); } static void map_over_children(Widget w, void (*func)(Widget uw)) { /* apply func to each child in entire tree beneath top widget */ /* taken from Douglas Young, "Motif Debugging and Performance Tuning" Prentice-Hall 1995 */ /* used mostly to get colors right in environments with "convenience" widgets */ if (w) { uint32_t i; (*func)(w); if (XtIsComposite(w)) { CompositeWidget cw = (CompositeWidget)w; for (i = 0; i < cw->composite.num_children; i++) map_over_children(cw->composite.children[i], func); } if (XtIsWidget(w)) for (i = 0; i < w->core.num_popups; i++) map_over_children(w->core.popup_list[i], func); } } void map_over_children_with_color(Widget w, void (*func)(Widget uw, color_t color), color_t color) { if (w) { uint32_t i; (*func)(w, color); if (XtIsComposite(w)) { CompositeWidget cw = (CompositeWidget)w; for (i = 0; i < cw->composite.num_children; i++) map_over_children_with_color(cw->composite.children[i], func, color); } if (XtIsWidget(w)) for (i = 0; i < w->core.num_popups; i++) map_over_children_with_color(w->core.popup_list[i], func, color); } } static void raise_dialog(Widget w) { /* since we're using non-transient message dialogs, the dialog window can become completely * hidden behind other windows, with no easy way to raise it back to the top, so... */ if ((w) && (XtIsManaged(w))) { Widget parent; parent = XtParent(w); if ((parent) && (XtIsSubclass(parent, xmDialogShellWidgetClass))) XtPopup(parent, XtGrabNone); /* XtGrabNone means don't lock out events to rest of App (i.e. modeless dialog) */ } } static void set_main_color_of_widget(Widget w) { if (XtIsWidget(w)) { if (XmIsScrollBar(w)) XmChangeColor(w, (Pixel)ss->position_color); else { Pixel cur_color; XtVaGetValues(w, XmNbackground, &cur_color, NULL); if ((cur_color != ss->highlight_color) && (cur_color != ss->white)) XmChangeColor(w, (Pixel)ss->basic_color); } } } void set_label(Widget label, const char *str) { XmString s1; s1 = XmStringCreateLocalized((char *)str); XtVaSetValues(label, XmNlabelString, s1, NULL); XmStringFree(s1); } static char *get_label(Widget label) { char *text; XmString str = NULL; XtVaGetValues(label, XmNlabelString, &str, NULL); if (XmStringEmpty(str)) return(NULL); text = (char *)XmStringUnparse(str, NULL, XmCHARSET_TEXT, XmCHARSET_TEXT, NULL, 0, XmOUTPUT_ALL); XmStringFree(str); return(text); } void set_button_label(Widget label, const char *str) { set_label(label, str); } void set_title(const char *title) { XtVaSetValues(main_shell(ss), XmNtitle, (char *)title, NULL); } void goto_window(Widget text) { if (XmIsTraversable(text)) XmProcessTraversal(text, XmTRAVERSE_CURRENT); } static XtCallbackList make_callback_list(XtCallbackProc callback, XtPointer closure) { XtCallbackList nlist; nlist = (XtCallbackList)calloc(2, sizeof(XtCallbackRec)); nlist[0].callback = callback; nlist[0].closure = closure; nlist[1].callback = NULL; nlist[1].closure = NULL; return(nlist); } #include static void color_sashes(Widget w) { if ((XtIsWidget(w)) && (XtIsSubclass(w, xmSashWidgetClass))) XmChangeColor(w, (Pixel)ss->sash_color); } void check_for_event(void) { /* this is needed to force label updates and provide interrupts from long computations */ XEvent event; XtInputMask msk = 0; XtAppContext app; if (ss->checking_explicitly) return; ss->checking_explicitly = true; app = main_app(ss); while (true) { msk = XtAppPending(app); /* if (msk & (XtIMXEvent | XtIMAlternateInput)) */ /* if (msk & XtIMXEvent) */ /* was also tracking alternate input events, but these are problematic if libfam is in use (even with check) * but libfam is now long-since forgotten; new form below is thanks to Tito Latini */ if ((msk & (XtIMXEvent | XtIMAlternateInput)) == XtIMXEvent) { XtAppNextEvent(app, &event); XtDispatchEvent(&event); /* widget = XtWindowToWidget(event.xany.display, event.xany.window); */ } else break; } ss->checking_explicitly = false; } void color_cursor(Pixel color) { ss->cursor_color = color; #if HAVE_SCHEME s7_symbol_set_value(s7, ss->cursor_color_symbol, Xen_wrap_pixel(color)); #endif XSetForeground(main_display(ss), ss->cursor_gc, (Pixel)(XOR(color, ss->graph_color))); XSetForeground(main_display(ss), ss->selected_cursor_gc, (Pixel)(XOR(color, ss->selected_graph_color))); } void color_marks(Pixel color) { ss->mark_color = color; #if HAVE_SCHEME s7_symbol_set_value(s7, ss->mark_color_symbol, Xen_wrap_pixel(color)); #endif XSetForeground(main_display(ss), ss->mark_gc, (Pixel)(XOR(color, ss->graph_color))); XSetForeground(main_display(ss), ss->selected_mark_gc, (Pixel)(XOR(color, ss->selected_graph_color))); } void color_selection(Pixel color) { ss->selection_color = color; #if HAVE_SCHEME s7_symbol_set_value(s7, ss->selection_color_symbol, Xen_wrap_pixel(color)); #endif XSetForeground(main_display(ss), ss->selection_gc, (Pixel)(XOR(color, ss->graph_color))); XSetForeground(main_display(ss), ss->selected_selection_gc, (Pixel)(XOR(color, ss->selected_graph_color))); } void color_graph(Pixel color) { Display *dpy; dpy = main_display(ss); XSetBackground(dpy, ss->basic_gc, color); XSetForeground(dpy, ss->erase_gc, color); XSetForeground(dpy, ss->selection_gc, (Pixel)(XOR(ss->selection_color, color))); XSetForeground(dpy, ss->cursor_gc, (Pixel)(XOR(ss->cursor_color, color))); XSetForeground(dpy, ss->mark_gc, (Pixel)(XOR(ss->mark_color, color))); } void color_selected_graph(Pixel color) { Display *dpy; dpy = main_display(ss); XSetBackground(dpy, ss->selected_basic_gc, color); XSetForeground(dpy, ss->selected_erase_gc, color); XSetForeground(dpy, ss->selected_selection_gc, (Pixel)(XOR(ss->selection_color, color))); XSetForeground(dpy, ss->selected_cursor_gc, (Pixel)(XOR(ss->cursor_color, color))); XSetForeground(dpy, ss->selected_mark_gc, (Pixel)(XOR(ss->mark_color, color))); } void color_data(Pixel color) { Display *dpy; dpy = main_display(ss); XSetForeground(dpy, ss->basic_gc, color); XSetBackground(dpy, ss->erase_gc, color); } void color_selected_data(Pixel color) { Display *dpy; dpy = main_display(ss); XSetForeground(dpy, ss->selected_basic_gc, color); XSetBackground(dpy, ss->selected_erase_gc, color); } void recolor_graph(chan_info *cp, bool selected) { XtVaSetValues(channel_graph(cp), XmNbackground, (selected) ? ss->selected_graph_color : ss->graph_color, NULL); } void set_mix_color(Pixel color) { Display *dpy; dpy = main_display(ss); ss->mix_color = color; #if HAVE_SCHEME s7_symbol_set_value(s7, ss->mix_color_symbol, Xen_wrap_pixel(color)); #endif XSetForeground(dpy, ss->mix_gc, color); } void set_sensitive(Widget wid, bool val) { if (wid) XtSetSensitive(wid, val); } void set_toggle_button(Widget wid, bool val, bool passed, void *ignore) { XmToggleButtonSetState(wid, (Boolean)val, (Boolean)passed); } Dimension widget_height(Widget w) { Dimension height; XtVaGetValues(w, XmNheight, &height, NULL); return(height); } Dimension widget_width(Widget w) { Dimension width; XtVaGetValues(w, XmNwidth, &width, NULL); return(width); } void set_widget_height(Widget w, Dimension height) { XtVaSetValues(w, XmNheight, height, NULL); } void set_widget_width(Widget w, Dimension width) { XtVaSetValues(w, XmNwidth, width, NULL); } void set_widget_size(Widget w, Dimension width, Dimension height) { XtVaSetValues(w, XmNwidth, width, XmNheight, height, NULL); } Position widget_x(Widget w) { Position x; XtVaGetValues(w, XmNx, &x, NULL); return(x); } Position widget_y(Widget w) { Position y; XtVaGetValues(w, XmNy, &y, NULL); return(y); } void set_widget_x(Widget w, Position x) { XtVaSetValues(w, XmNx, x, NULL); } void set_widget_y(Widget w, Position y) { XtVaSetValues(w, XmNy, y, NULL); } void set_widget_position(Widget w, Position x, Position y) { XtVaSetValues(w, XmNx, x, XmNy, y, NULL); } idle_t add_work_proc(XtWorkProc func, XtPointer data) { /* during auto-testing I need to force the background procs to run to completion */ if (with_background_processes(ss)) return(XtAppAddWorkProc(main_app(ss), func, data)); else { while (((*func)(data)) == BACKGROUND_CONTINUE) ; return((idle_t)0); } } static int attach_all_sides(Arg *args, int n) { XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++; return(n); } static void widget_int_to_text(Widget w, int val) { char *str; str = (char *)calloc(16, sizeof(char)); snprintf(str, 16, "%d", val); XmTextFieldSetString(w, str); free(str); } static void widget_mus_long_t_to_text(Widget w, mus_long_t val) { char *str; str = (char *)calloc(32, sizeof(char)); snprintf(str, 32, "%" print_mus_long, val); XmTextFieldSetString(w, str); free(str); } static Pixmap rotate_text(Widget w, const char *str, XFontStruct *font, mus_float_t angle_in_degrees, int *nw, int *nh, Pixel bg, Pixel fg, GC d_gc) { /* rotate clockwise by angle_in_degrees degrees (i.e. 45 points text south-east), * new bounding box (text centered in it) returned in nw and nh * bg = background color, fg = foreground (text) color) */ mus_float_t matrix[4]; mus_float_t angle_in_radians; XImage *before, *after; Pixmap pix, rotpix; uint32_t width, height, depth, nwidth, nheight, x, y, nx, ny, tx, ty, depth_bytes; char *data; unsigned long px; Display *dp; Drawable wn; Visual *vis; int scr; int bx0 = 0, bx1 = 0, by0 = 0, by1 = 0, b; if (!str) return(BadPixmap); angle_in_radians = mus_degrees_to_radians(angle_in_degrees); matrix[0] = cos(angle_in_radians); matrix[1] = sin(angle_in_radians); matrix[2] = -sin(angle_in_radians); matrix[3] = cos(angle_in_radians); dp = XtDisplay(w); wn = XtWindow(w); scr = DefaultScreen(dp); vis = DefaultVisual(dp, scr); XtVaGetValues(w, XmNdepth, &depth, NULL); depth_bytes = (depth >> 3); if (depth_bytes == 0) depth_bytes = 1; /* unsigned so can't be negative */ /* find extent of original text, expand out to byte boundaries */ XSetFont(dp, d_gc, font->fid); width = XTextWidth(font, str, strlen(str)) + 8; height = (font->ascent + font->descent) + 8; if (width % 8) width = 8 * (1 + (int)(width / 8)); if (height % 8) height = 8 * (1 + (int)(height / 8)); /* get bounding box of rotated text (this could be simplfied -- used to involve scaling) */ b = (int)(width * matrix[0]); if (b < 0) bx0 = b; else bx1 = b; b = (int)(height * matrix[2]); if (b < 0) bx0 += b; else bx1 += b; b = (int)(width * matrix[1]); if (b < 0) by0 = b; else by1 = b; b = (int)(height * matrix[3]); if (b < 0) by0 += b; else by1 += b; /* set translation vector so we're centered in the resultant pixmap */ if (bx0 < 0) tx = -bx0; else tx = 0; if (by0 < 0) ty = -by0; else ty = 0; nx = bx1 - bx0; ny = by1 - by0; /* expand result bounds to byte boundaries */ if (nx % 8) nwidth = 8 * (1 + (int)(nx / 8)); else nwidth = nx; if (ny % 8) nheight = 8 * (1 + (int)(ny / 8)); else nheight = ny; (*nw) = nwidth; (*nh) = nheight; XSetBackground(dp, d_gc, bg); XSetForeground(dp, d_gc, bg); /* create pixmaps, fill with background color, write string to pix */ pix = XCreatePixmap(dp, wn, width, height, depth); rotpix= XCreatePixmap(dp, wn, nwidth, nheight, depth); XFillRectangle(dp, pix, d_gc, 0, 0, width, height); XFillRectangle(dp, rotpix, d_gc, 0, 0, nwidth, nheight); #if HAVE_SUN XSync(dp, 0); /* needed to get the numbers drawn at all */ #endif XSetForeground(dp, d_gc, fg); XDrawImageString(dp, pix, d_gc, 4, height - 4, str, strlen(str)); /* dump pixmap bits into an image; image data will be freed automatically later */ data = (char *)calloc((width + 1) * (height + 1) * depth_bytes, sizeof(char)); /* not calloc since X will free this */ before = XCreateImage(dp, vis, depth, XYPixmap, 0, data, width, height, 8, 0); XGetSubImage(dp, pix, 0, 0, width, height, AllPlanes, XYPixmap, before, 0, 0); data = (char *)calloc((nwidth + 1) * (nheight + 1) * depth_bytes, sizeof(char)); after = XCreateImage(dp, vis, depth, XYPixmap, 0, data, nwidth, nheight, 8, 0); /* clear background of result image */ for (x = 0; x < nwidth; x++) for (y = 0; y < nheight; y++) XPutPixel(after, x, y, bg); /* write rotated pixels to result image */ for (x = 0; x < width; x++) for (y = 0; y < height; y++) { px = XGetPixel(before, x, y); if (px != bg) XPutPixel(after, mus_iclamp(0, (int)snd_round(tx + x * matrix[0] + y * matrix[2]), nwidth - 1), mus_iclamp(0, (int)snd_round(ty + x * matrix[1] + y * matrix[3]), nheight - 1), px); } /* dump image into result pixmap (needed for later display) */ XPutImage(dp, rotpix, d_gc, after, 0, 0, 0, 0, nwidth, nheight); /* cleanup */ XDestroyImage(before); /* frees data as well */ XDestroyImage(after); XFreePixmap(dp, pix); return(rotpix); } void draw_rotated_axis_label(chan_info *cp, graphics_context *ax, const char *text, int x0, int y0) { Pixmap pix; int h = 0, w = 0; XGCValues gv; Display *dp; Widget widget; if ((cp->chan > 0) && (cp->sound->channel_style == CHANNELS_COMBINED)) widget = channel_graph(cp->sound->chans[0]); else widget = channel_graph(cp); dp = XtDisplay(widget); XGetGCValues(main_display(ss), ax->gc, GCForeground | GCBackground, &gv); pix = rotate_text(widget, text, AXIS_LABEL_FONT(ss), -90.0, &w, &h, gv.background, gv.foreground, ax->gc); XCopyArea(dp, pix, XtWindow(widget), ax->gc, 0, 0, w, h, x0, y0); /* XtWindow?? */ XFreePixmap(dp, pix); } static void ensure_list_row_visible(widget_t list, int pos) { if (pos >= 0) { int top, visible, num_rows; XtVaGetValues(list, XmNtopItemPosition, &top, XmNvisibleItemCount, &visible, XmNitemCount, &num_rows, NULL); if (pos <= top) XmListSetPos(list, pos); /* was pos+1?? (new file dialog sample type list off by 1 in that case) */ else { if (pos >= (top + visible)) { if ((pos + visible) > num_rows) XmListSetBottomPos(list, num_rows); else XmListSetPos(list, pos); } } } } static void ensure_scrolled_window_row_visible(widget_t list, int row, int num_rows) { int minimum, maximum, value, size, new_value, increment, page_increment; Widget scrollbar, work_window; XtVaGetValues(list, XmNverticalScrollBar, &scrollbar, XmNworkWindow, &work_window, NULL); XtVaGetValues(scrollbar, XmNminimum, &minimum, XmNmaximum, &maximum, XmNvalue, &value, XmNsliderSize, &size, XmNincrement, &increment, /* needed for XmScrollBarSetValues which is needed to force list display update */ XmNpageIncrement, &page_increment, NULL); maximum -= size; if (row == 0) new_value = 0; else { if (row >= (num_rows - 1)) new_value = maximum; else new_value = (int)((row + 0.5) * ((double)(maximum - minimum) / (double)(num_rows - 1))); } XmScrollBarSetValues(scrollbar, new_value, size, increment, page_increment, true); } static XmString multi_line_label(const char *s, int *lines) { /* taken from the Motif FAQ */ XmString xms1, xms2, line, separator; char *p, *tmp; (*lines) = 1; tmp = mus_strdup(s); separator = XmStringSeparatorCreate(); p = strtok(tmp, "\n"); xms1 = XmStringCreateLocalized(p); p = strtok(NULL, "\n"); while (p) { (*lines)++; line = XmStringCreateLocalized(p); xms2 = XmStringConcat(xms1, separator); XmStringFree(xms1); xms1 = XmStringConcat(xms2, line); XmStringFree(xms2); XmStringFree(line); p = strtok(NULL, "\n"); } XmStringFree(separator); free(tmp); return(xms1); } #include /* needed to set the scale title background */ void draw_line(graphics_context *ax, int x0, int y0, int x1, int y1) { XDrawLine(ax->dp, ax->wn, ax->gc, x0, y0, x1, y1); } void fill_rectangle(graphics_context *ax, int x0, int y0, int width, int height) { XFillRectangle(ax->dp, ax->wn, ax->gc, x0, y0, width, height); } void erase_rectangle(chan_info *cp, graphics_context *ax, int x0, int y0, int width, int height) { XFillRectangle(ax->dp, ax->wn, erase_GC(cp), x0, y0, width, height); } void draw_string(graphics_context *ax, int x0, int y0, const char *str, int len) { if ((str) && (*str)) XDrawString(ax->dp, ax->wn, ax->gc, x0, y0, str, len); } void gtk_style_draw_string(graphics_context *ax, int x0, int y0, const char *str, int len) { /* for callers of Scheme-level draw-string, the Motif and Gtk versions should agree on where "y0" is */ XGCValues gv; static XFontStruct *fs = NULL; XGetGCValues(main_display(ss), ax->gc, GCFont, &gv); /* now gv.font is the default font */ if (fs) XFree(fs); /* this doesn't free all the space */ /* but this: */ /* if (fs) XFreeFont(main_display(ss), fs); */ /* gets: X Error of failed request: BadFont (invalid Font parameter) Major opcode of failed request: 56 (X_ChangeGC) Resource id in failed request: 0x4e0035c Serial number of failed request: 8479111 Current serial number in output stream: 8479240 */ fs = XQueryFont(main_display(ss), gv.font); if (fs) XDrawString(ax->dp, ax->wn, ax->gc, x0, y0 + fs->ascent, str, len); else XDrawString(ax->dp, ax->wn, ax->gc, x0, y0, str, len); /* not sure why this happens... */ /* XFreeFont here is trouble, but handling it as above seems ok -- Font.c in xlib does allocate new space */ } static void draw_polygon_va(graphics_context *ax, bool filled, int points, va_list ap) { int i; XPoint *pts; pts = (XPoint *)calloc(points, sizeof(XPoint)); for (i = 0; i < points; i++) { pts[i].x = va_arg(ap, int); pts[i].y = va_arg(ap, int); } if (filled) XFillPolygon(ax->dp, ax->wn, ax->gc, pts, points, Convex, CoordModeOrigin); else XDrawLines(ax->dp, ax->wn, ax->gc, pts, points, CoordModeOrigin); free(pts); } void fill_polygon(graphics_context *ax, int points, ...) { /* currently used only in snd-marks.c */ va_list ap; if (points == 0) return; va_start(ap, points); draw_polygon_va(ax, true, points, ap); va_end(ap); } #if 0 void draw_polygon(graphics_context *ax, int points, ...) { va_list ap; if (points == 0) return; va_start(ap, points); draw_polygon_va(ax, false, points, ap); va_end(ap); } #endif void draw_lines(graphics_context *ax, point_t *points, int num) { if (num == 0) return; XDrawLines(ax->dp, ax->wn, ax->gc, points, num, CoordModeOrigin); } void draw_points(graphics_context *ax, point_t *points, int num, int size) { if (num == 0) return; if (size == 1) XDrawPoints(ax->dp, ax->wn, ax->gc, points, num, CoordModeOrigin); else { int i, size2; XArc *rs; /* create squares or whatever centered on each point */ size2 = size / 2; rs = (XArc *)calloc(num, sizeof(XArc)); for (i = 0; i < num; i++) { rs[i].x = points[i].x - size2; rs[i].y = points[i].y - size2; rs[i].angle1 = 0; rs[i].angle2 = 360 * 64; rs[i].width = size; rs[i].height = size; } XFillArcs(ax->dp, ax->wn, ax->gc, rs, num); free(rs); } } #if 0 void draw_point(graphics_context *ax, point_t point, int size) { if (size == 1) XDrawPoint(ax->dp, ax->wn, ax->gc, point.x, point.y); else XFillArc(ax->dp, ax->wn, ax->gc, point.x - size / 2, point.y - size / 2, size, size, 0, 360 * 64); } #endif void draw_dot(graphics_context *ax, int x, int y, int size) { XFillArc(ax->dp, ax->wn, ax->gc, x - size / 2, y - size / 2, size, size, 0, 360 * 64); } void fill_polygons(graphics_context *ax, point_t *points, int num, int y0) { XPoint polypts[4]; int i; for (i = 1; i < num; i++) { polypts[0].x = points[i - 1].x; polypts[0].y = points[i - 1].y; polypts[1].x = points[i].x; polypts[1].y = points[i].y; polypts[2].x = polypts[1].x; polypts[2].y = y0; polypts[3].x = points[i - 1].x; polypts[3].y = y0; XFillPolygon(ax->dp, ax->wn, ax->gc, polypts, 4, Convex, CoordModeOrigin); } } void fill_two_sided_polygons(graphics_context *ax, point_t *points, point_t *points1, int num) { XPoint polypts[4]; int i; for (i = 1; i < num; i++) { polypts[0].x = points[i - 1].x; polypts[0].y = points[i - 1].y; polypts[1].x = points[i].x; polypts[1].y = points[i].y; polypts[2].x = points1[i].x; polypts[2].y = points1[i].y; polypts[3].x = points1[i - 1].x; polypts[3].y = points1[i - 1].y; XFillPolygon(ax->dp, ax->wn, ax->gc, polypts, 4, Convex, CoordModeOrigin); } } void setup_graphics_context(chan_info *cp, graphics_context *ax) { Widget w; w = channel_to_widget(cp); ax->dp = XtDisplay(w); ax->gc = copy_GC(cp); ax->wn = XtWindow(w); } /* colormaps */ static int sono_bins = 0; /* tracks total_bins -- each sono_data[i] is an array of total_bins rectangles */ static Pixel *current_colors = NULL; static int current_colors_size = 0; static int current_colormap = BLACK_AND_WHITE_COLORMAP; static XRectangle **sono_data = NULL; /* each entry in sono_data is an array of colormap_size arrays: sono_data[colormap_size][total_bins] */ static int sono_colors = 0; /* tracks colormap_size */ static GC colormap_GC; void check_colormap_sizes(int colors) { int i, old_size; if (current_colors_size > 0) { if (current_colormap != BLACK_AND_WHITE_COLORMAP) { int scr; Colormap cmap; Display *dpy; dpy = XtDisplay(main_shell(ss)); scr = DefaultScreen(dpy); cmap = DefaultColormap(dpy, scr); XFreeColors(dpy, cmap, current_colors, current_colors_size, 0); current_colormap = BLACK_AND_WHITE_COLORMAP; } if ((current_colors) && (current_colors_size < colors)) { old_size = current_colors_size; current_colors_size = colors; current_colors = (Pixel *)realloc(current_colors, current_colors_size * sizeof(Pixel)); for (i = old_size; i < current_colors_size; i++) current_colors[i] = 0; } } if ((sono_data) && (sono_colors < colors) && (sono_bins > 0)) { old_size = sono_colors; sono_colors = colors; sono_data = (XRectangle **)realloc(sono_data, sono_colors * sizeof(XRectangle *)); for (i = old_size; i < sono_colors; i++) sono_data[i] = (XRectangle *)calloc(sono_bins, sizeof(XRectangle)); } } static void initialize_colormap(void) { XGCValues gv; gv.background = ss->white; gv.foreground = ss->data_color; colormap_GC = XCreateGC(main_display(ss), XtWindow(main_shell(ss)), GCForeground | GCBackground, &gv); sono_colors = color_map_size(ss); sono_data = (XRectangle **)calloc(sono_colors, sizeof(XRectangle *)); current_colors_size = color_map_size(ss); current_colors = (Pixel *)calloc(current_colors_size, sizeof(Pixel)); } void draw_spectro_line(graphics_context *ax, int color, int x0, int y0, int x1, int y1) { XSetForeground(ax->dp, colormap_GC, current_colors[color]); XDrawLine(ax->dp, ax->wn, colormap_GC, x0, y0, x1, y1); } void draw_sono_rectangles(graphics_context *ax, int color, int jmax) { XSetForeground(ax->dp, colormap_GC, current_colors[color]); XFillRectangles(ax->dp, ax->wn, colormap_GC, sono_data[color], jmax); } void set_sono_rectangle(int j, int color, int x, int y, int width, int height) { XRectangle *r; r = sono_data[color]; r[j].x = x; r[j].y = y; r[j].width = width; r[j].height = height; } void allocate_sono_rects(int bins) { if (bins != sono_bins) { int i; for (i = 0; i < sono_colors; i++) { if ((sono_bins > 0) && (sono_data[i])) free(sono_data[i]); /* each is array of XRectangle structs, but it's the wrong size */ sono_data[i] = (XRectangle *)calloc(bins, sizeof(XRectangle)); } sono_bins = bins; } } void allocate_color_map(int colormap) { static bool warned_color = false; if (current_colormap != colormap) { int i; Colormap cmap; XColor tmp_color; Display *dpy; int scr; tmp_color.flags = DoRed | DoGreen | DoBlue; dpy = XtDisplay(main_shell(ss)); scr = DefaultScreen(dpy); cmap = DefaultColormap(dpy, scr); /* 8-bit color displays can't handle all these colors, apparently, so we have to check status */ if (current_colormap != BLACK_AND_WHITE_COLORMAP) XFreeColors(dpy, cmap, current_colors, current_colors_size, 0); for (i = 0; i < current_colors_size; i++) { get_current_color(colormap, i, &(tmp_color.red), &(tmp_color.green), &(tmp_color.blue)); if ((XAllocColor(dpy, cmap, &tmp_color)) == 0) /* 0 = failure -- try black as a fallback */ { tmp_color.red = 0; tmp_color.green = 0; tmp_color.blue = 0; if ((XAllocColor(dpy, cmap, &tmp_color)) == 0) { if (!warned_color) snd_error_without_format("can't even allocate black?!?"); warned_color = true; } } current_colors[i] = tmp_color.pixel; } current_colormap = colormap; } } void draw_colored_lines(chan_info *cp, graphics_context *ax, point_t *points, int num, int *colors, int axis_y0, color_t default_color) { int i, x0, y0, y2 = 0, y00 = -1, cur, prev; color_t old_color; if (num <= 0) return; old_color = get_foreground_color(ax); x0 = points[0].x; y0 = points[0].y; if (abs(y0 - axis_y0) < 5) prev = -1; else prev = colors[0]; set_foreground_color(ax, (prev == -1) ? default_color : current_colors[prev]); for (i = 1; i < num; i++) { int x1, y1; x1 = points[i].x; y1 = points[i].y; if (i < num - 1) y2 = points[i + 1].y; else y2 = y1; if ((abs(y0 - axis_y0) < 5) && (abs(y1 - axis_y0) < 5)) cur = -1; else { if ((y00 > y0) && (y00 > y1) && (i > 1)) cur = colors[i - 2]; else { if ((y2 > y1) && (y2 > y0)) cur = colors[i + 1]; else { if (y0 > y1) cur = colors[i]; else cur = colors[i - 1]; /* coords are upside down */ } } } if (cur != prev) { set_foreground_color(ax, (cur == -1) ? default_color : current_colors[cur]); prev = cur; } if (cp->transform_graph_style == GRAPH_DOTS) draw_dot(ax, x0, y0, cp->dot_size); else draw_line(ax, x0, y0, x1, y1); y00 = y0; x0 = x1; y0 = y1; } set_foreground_color(ax, old_color); } /* -------- color/orientation browser -------- */ static Xen color_hook; static void check_color_hook(void) { if (Xen_hook_has_list(color_hook)) run_hook(color_hook, Xen_empty_list, S_color_hook); } static Widget ccd_dialog = NULL, ccd_list, ccd_scale, ccd_invert, ccd_cutoff; static void update_graph_setting_fft_changed(chan_info *cp) { cp->fft_changed = FFT_CHANGE_LOCKED; update_graph(cp); } static void invert_color_callback(Widget w, XtPointer context, XtPointer info) { XmToggleButtonCallbackStruct *cb = (XmToggleButtonCallbackStruct *)info; in_set_color_inverted(cb->set); check_color_hook(); for_each_chan(update_graph_setting_fft_changed); } void set_color_inverted(bool val) { in_set_color_inverted(val); if (ccd_dialog) XmToggleButtonSetState(ccd_invert, (Boolean)val, false); check_color_hook(); if (!(ss->graph_hook_active)) for_each_chan(update_graph_setting_fft_changed); } static void scale_color_callback(Widget w, XtPointer context, XtPointer info) { mus_float_t val; int scale_val; XmScaleCallbackStruct *cbs = (XmScaleCallbackStruct *)info; scale_val = cbs->value; if (scale_val <= 50) val = (mus_float_t)(scale_val + 1) / 51.0; else val = 1.0 + (mus_float_t)((scale_val - 50) * (scale_val - 50)) / 12.5; in_set_color_scale(val); check_color_hook(); for_each_chan(update_graph_setting_fft_changed); } static void reflect_color_scale(mus_float_t val) { if (val < 0.02) XmScaleSetValue(ccd_scale, 0); else { if (val <= 1.0) XmScaleSetValue(ccd_scale, mus_iclamp(0, (int)(val * 51.0 - 1), 100)); else XmScaleSetValue(ccd_scale, mus_iclamp(0, 50 + (int)sqrt((val - 1.0) * 12.5), 100)); } } void set_color_scale(mus_float_t val) { in_set_color_scale(val); if (ccd_dialog) reflect_color_scale(color_scale(ss)); if (!(ss->graph_hook_active)) for_each_chan(update_graph_setting_fft_changed); } static void list_color_callback(Widget w, XtPointer context, XtPointer info) { XmListCallbackStruct *cbs = (XmListCallbackStruct *)info; if (is_colormap(cbs->item_position - 1)) { in_set_color_map(cbs->item_position - 1); check_color_hook(); for_each_chan(update_graph_setting_fft_changed); } } void set_color_map(int val) { in_set_color_map(val); if ((ccd_dialog) && (val >= 0)) XmListSelectPos(ccd_list, val + 1, false); check_color_hook(); if (!(ss->graph_hook_active)) for_each_chan(update_graph_setting_fft_changed); } static XmString fscale_label(const char *orig_label, mus_float_t value) { XmString x; char *lab; lab = mus_format("%s: %.3f", orig_label, value); x = XmStringCreateLocalized(lab); free(lab); return(x); } static void fscale_set_label(const char *orig_label, Widget w, mus_float_t value) { XmString x; char *lab; lab = mus_format("%s: %.3f", orig_label, value); x = XmStringCreateLocalized(lab); XtVaSetValues(w, XmNtitleString, x, NULL); free(lab); XmStringFree(x); } static void cutoff_color_callback(Widget w, XtPointer context, XtPointer info) /* cutoff point */ { /* cutoff point for color chooser */ XmScaleCallbackStruct *cbs = (XmScaleCallbackStruct *)info; in_set_color_cutoff((mus_float_t)(cbs->value) / 1000.0); fscale_set_label("data cutoff", w, color_cutoff(ss)); check_color_hook(); for_each_chan(update_graph_setting_fft_changed); } void set_color_cutoff(mus_float_t val) { in_set_color_cutoff(val); if (ccd_dialog) XmScaleSetValue(ccd_cutoff, (int)(val * 1000.0)); if (!(ss->graph_hook_active)) for_each_chan(update_graph_setting_fft_changed); } static void dismiss_color_orientation_callback(Widget w, XtPointer context, XtPointer info) { XtUnmanageChild(ccd_dialog); } static void help_color_orientation_callback(Widget w, XtPointer context, XtPointer info) { color_orientation_dialog_help(); } void reflect_color_list(bool setup_time) { if ((ccd_dialog) && (ccd_list)) { int i, size; XmString *cmaps; size = num_colormaps(); cmaps = (XmString *)calloc(size, sizeof(XmString)); for (i = 0; i < size; i++) cmaps[i] = XmStringCreateLocalized(colormap_name(i)); XtVaSetValues(ccd_list, XmNitems, cmaps, XmNitemCount, size, NULL); if (setup_time) XtVaSetValues(ccd_list, XmNvisibleItemCount, 6, NULL); for (i = 0; i < size; i++) XmStringFree(cmaps[i]); free(cmaps); } } static Xen orientation_hook; static void check_orientation_hook(void) { if (Xen_hook_has_list(orientation_hook)) run_hook(orientation_hook, Xen_empty_list, S_orientation_hook); } static Widget oid_ax, oid_ay, oid_az, oid_sx, oid_sy, oid_sz, oid_hop; #if HAVE_GL static Widget oid_glbutton; #endif #define HOP_MAX 20 static XmString scale_label(const char *orig_label, int value, bool dec) { XmString x; char *lab; if (!dec) lab = mus_format("%s: %d", orig_label, value); else lab = mus_format("%s: %.2f", orig_label, value * 0.01); x = XmStringCreateLocalized(lab); free(lab); return(x); } static void scale_set_label(const char *orig_label, Widget w, int value, bool dec) { /* in new motif (after version 2.1), showValue not XmNONE (= 0) clobbers XmScale title! * also XmNEAR_BORDER has no effect -- same as XmNEAR_SLIDER * so... * we create the full label by hand here. */ XmString x; char *lab; if (!dec) lab = mus_format("%s: %d", orig_label, value); else lab = mus_format("%s: %.2f", orig_label, value * 0.01); x = XmStringCreateLocalized(lab); XtVaSetValues(w, XmNtitleString, x, NULL); free(lab); XmStringFree(x); } static void ax_orientation_callback(Widget w, XtPointer context, XtPointer info) { XmScaleCallbackStruct *cbs = (XmScaleCallbackStruct *)info; scale_set_label("x angle", w, cbs->value, false); in_set_spectro_x_angle((mus_float_t)(cbs->value)); chans_field(FCP_X_ANGLE, (mus_float_t)(cbs->value)); check_orientation_hook(); for_each_chan(update_graph); } void set_spectro_x_angle(mus_float_t val) { if (val < 0.0) val += 360.0; else if (val >= 360.0) val = fmod(val, 360.0); in_set_spectro_x_angle(val); if (ccd_dialog) { XmScaleSetValue(oid_ax, (int)val); scale_set_label("x angle", oid_ax, (int)val, false); } chans_field(FCP_X_ANGLE, val); check_orientation_hook(); if (!(ss->graph_hook_active)) for_each_chan(update_graph); } static void ay_orientation_callback(Widget w, XtPointer context, XtPointer info) { XmScaleCallbackStruct *cbs = (XmScaleCallbackStruct *)info; scale_set_label("y angle", w, cbs->value, false); in_set_spectro_y_angle((mus_float_t)(cbs->value)); chans_field(FCP_Y_ANGLE, (mus_float_t)(cbs->value)); check_orientation_hook(); for_each_chan(update_graph); } void set_spectro_y_angle(mus_float_t val) { if (val < 0.0) val += 360.0; else if (val >= 360.0) val = fmod(val, 360.0); in_set_spectro_y_angle(val); if (ccd_dialog) { XmScaleSetValue(oid_ay, (int)val); scale_set_label("y angle", oid_ay, (int)val, false); } chans_field(FCP_Y_ANGLE, val); check_orientation_hook(); if (!(ss->graph_hook_active)) for_each_chan(update_graph); } static void az_orientation_callback(Widget w, XtPointer context, XtPointer info) { XmScaleCallbackStruct *cbs = (XmScaleCallbackStruct *)info; scale_set_label("z angle", w, cbs->value, false); in_set_spectro_z_angle((mus_float_t)(cbs->value)); chans_field(FCP_Z_ANGLE, (mus_float_t)(cbs->value)); check_orientation_hook(); for_each_chan(update_graph); } void set_spectro_z_angle(mus_float_t val) { if (val < 0.0) val += 360.0; else if (val >= 360.0) val = fmod(val, 360.0); in_set_spectro_z_angle(val); if (ccd_dialog) { XmScaleSetValue(oid_az, (int)val); scale_set_label("z angle", oid_az, (int)val, false); } chans_field(FCP_Z_ANGLE, val); check_orientation_hook(); if (!(ss->graph_hook_active)) for_each_chan(update_graph); } static void sx_orientation_callback(Widget w, XtPointer context, XtPointer info) { XmScaleCallbackStruct *cbs = (XmScaleCallbackStruct *)info; scale_set_label("x scale", w, cbs->value, true); in_set_spectro_x_scale((mus_float_t)(cbs->value) * 0.01); chans_field(FCP_X_SCALE, (mus_float_t)(cbs->value) * 0.01); check_orientation_hook(); for_each_chan(update_graph); } void set_spectro_x_scale(mus_float_t val) { in_set_spectro_x_scale(val); if (ccd_dialog) { int value; value = mus_iclamp(0, (int)(val * 100), (int)(100 * SPECTRO_X_SCALE_MAX)); XmScaleSetValue(oid_sx, value); scale_set_label("x scale", oid_sx, value, true); } chans_field(FCP_X_SCALE, val); check_orientation_hook(); if (!(ss->graph_hook_active)) for_each_chan(update_graph); } static void sy_orientation_callback(Widget w, XtPointer context, XtPointer info) { XmScaleCallbackStruct *cbs = (XmScaleCallbackStruct *)info; scale_set_label("y scale", w, cbs->value, true); in_set_spectro_y_scale((mus_float_t)(cbs->value) * 0.01); chans_field(FCP_Y_SCALE, (mus_float_t)(cbs->value) * 0.01); check_orientation_hook(); for_each_chan(update_graph); } void set_spectro_y_scale(mus_float_t val) { in_set_spectro_y_scale(val); if (ccd_dialog) { int value; value = mus_iclamp(0, (int)(val * 100), (int)(100 * SPECTRO_Y_SCALE_MAX)); XmScaleSetValue(oid_sy, value); scale_set_label("y scale", oid_sy, value, true); } chans_field(FCP_Y_SCALE, val); check_orientation_hook(); if (!(ss->graph_hook_active)) for_each_chan(update_graph); } static void sz_orientation_callback(Widget w, XtPointer context, XtPointer info) { XmScaleCallbackStruct *cbs = (XmScaleCallbackStruct *)info; scale_set_label("z scale", w, cbs->value, true); in_set_spectro_z_scale((mus_float_t)(cbs->value) * 0.01); chans_field(FCP_Z_SCALE, (mus_float_t)(cbs->value) * 0.01); check_orientation_hook(); for_each_chan(update_graph); } void set_spectro_z_scale(mus_float_t val) { in_set_spectro_z_scale(val); if (ccd_dialog) { int value; value = mus_iclamp(0, (int)(val * 100), (int)(100 * SPECTRO_Z_SCALE_MAX)); XmScaleSetValue(oid_sz, value); scale_set_label("z scale", oid_sz, value, true); } chans_field(FCP_Z_SCALE, val); check_orientation_hook(); if (!(ss->graph_hook_active)) for_each_chan(update_graph); } static void chans_spectro_hop(chan_info *cp, int value) { cp->spectro_hop = value; } static void hop_orientation_callback(Widget w, XtPointer context, XtPointer info) { int val; XmScaleCallbackStruct *cbs = (XmScaleCallbackStruct *)info; scale_set_label("hop", w, cbs->value, false); val = mus_iclamp(1, cbs->value, HOP_MAX); in_set_spectro_hop(val); for_each_chan_with_int(chans_spectro_hop,val); check_orientation_hook(); for_each_chan(update_graph); } void set_spectro_hop(int val) { if (val > 0) { in_set_spectro_hop(val); if (ccd_dialog) { int value; value = mus_iclamp(1, val, HOP_MAX); XmScaleSetValue(oid_hop, value); scale_set_label("hop", oid_hop, value, false); } for_each_chan_with_int(chans_spectro_hop, val); check_orientation_hook(); if (!(ss->graph_hook_active)) for_each_chan(update_graph); } } static int fixup_angle(mus_float_t ang) { int na; na = (int)ang; if (na < 0) na += 360; na = na % 360; return(na); } void reflect_spectro(void) { /* set color/orientaton widget values */ if (ccd_dialog) { XmToggleButtonSetState(ccd_invert, (Boolean)(color_inverted(ss)), false); XtVaSetValues(ccd_cutoff, XmNvalue, (int)((color_cutoff(ss)) * 1000), NULL); reflect_color_scale(color_scale(ss)); XtVaSetValues(oid_ax, XmNvalue, fixup_angle(spectro_x_angle(ss)), NULL); XtVaSetValues(oid_ay, XmNvalue, fixup_angle(spectro_y_angle(ss)), NULL); XtVaSetValues(oid_az, XmNvalue, fixup_angle(spectro_z_angle(ss)), NULL); XtVaSetValues(oid_sx, XmNvalue, mus_iclamp(0, (int)(spectro_x_scale(ss) * 100), 100), NULL); XtVaSetValues(oid_sy, XmNvalue, mus_iclamp(0, (int)(spectro_y_scale(ss) * 100), 100), NULL); XtVaSetValues(oid_sz, XmNvalue, mus_iclamp(0, (int)(spectro_z_scale(ss) * 100), 100), NULL); XtVaSetValues(oid_hop, XmNvalue, mus_iclamp(1, spectro_hop(ss), HOP_MAX), NULL); check_orientation_hook(); } } void set_with_gl(bool val, bool with_dialogs) { #if HAVE_GL sgl_save_currents(); #endif in_set_with_gl(val); #if HAVE_GL sgl_set_currents(with_dialogs); if ((ccd_dialog) && (with_dialogs)) XmToggleButtonSetState(oid_glbutton, val, false); #endif } #if HAVE_GL static void with_gl_callback(Widget w, XtPointer context, XtPointer info) { XmToggleButtonCallbackStruct *cb = (XmToggleButtonCallbackStruct *)info; sgl_save_currents(); in_set_with_gl(cb->set); sgl_set_currents(true); /* this only sets the slider positions -- it doesn't update the labels! */ /* and reflect_spectro() doesn't help! */ if (ccd_dialog) { scale_set_label("x angle", oid_ax, spectro_x_angle(ss), false); scale_set_label("y angle", oid_ay, spectro_y_angle(ss), false); scale_set_label("z angle", oid_az, spectro_z_angle(ss), false); scale_set_label("x scale", oid_sx, spectro_x_scale(ss), false); scale_set_label("y scale", oid_sy, spectro_y_scale(ss), false); scale_set_label("z scale", oid_sz, spectro_z_scale(ss), false); } for_each_chan(update_graph); } #endif static void reset_color_orientation_callback(Widget w, XtPointer context, XtPointer info) { /* put everything back the way it was at the start. * this sets everything to the startup defaults -- should they be the dialog startup values instead? */ set_color_cutoff(DEFAULT_COLOR_CUTOFF); set_color_inverted(DEFAULT_COLOR_INVERTED); set_color_scale(DEFAULT_COLOR_SCALE); set_color_map(DEFAULT_COLOR_MAP); reset_spectro(); reflect_spectro(); for_each_chan(update_graph); } /* I tried a scrolled window with each colormap name in an appropriate color, but it looked kinda dumb */ Widget make_color_orientation_dialog(bool managed) { if (!ccd_dialog) { Arg args[32]; int n, initial_value; XmString xhelp, xdismiss, xinvert, titlestr, xreset, xstr; Widget mainform, light_label, lsep, rsep, sep1, tsep, color_frame, orientation_frame, color_form, orientation_form; Widget color_title, orientation_title; #if HAVE_GL XmString glstr; #endif xdismiss = XmStringCreateLocalized((char *)I_GO_AWAY); /* needed by template dialog */ xhelp = XmStringCreateLocalized((char *)I_HELP); xreset = XmStringCreateLocalized((char *)"Reset"); titlestr = XmStringCreateLocalized((char *)"Color and Orientation"); n = 0; XtSetArg(args[n], XmNbackground, ss->basic_color); n++; XtSetArg(args[n], XmNcancelLabelString, xdismiss); n++; XtSetArg(args[n], XmNhelpLabelString, xhelp); n++; XtSetArg(args[n], XmNokLabelString, xreset); n++; XtSetArg(args[n], XmNautoUnmanage, false); n++; XtSetArg(args[n], XmNdialogTitle, titlestr); n++; XtSetArg(args[n], XmNresizePolicy, XmRESIZE_GROW); n++; XtSetArg(args[n], XmNnoResize, false); n++; XtSetArg(args[n], XmNtransient, false); n++; ccd_dialog = XmCreateTemplateDialog(main_shell(ss), (char *)"Color and Orientation", args, n); XtAddCallback(ccd_dialog, XmNcancelCallback, dismiss_color_orientation_callback, NULL); XtAddCallback(ccd_dialog, XmNhelpCallback, help_color_orientation_callback, NULL); XtAddCallback(ccd_dialog, XmNokCallback, reset_color_orientation_callback, NULL); XmStringFree(xhelp); XmStringFree(xdismiss); XmStringFree(titlestr); XmStringFree(xreset); XtVaSetValues(XmMessageBoxGetChild(ccd_dialog, XmDIALOG_CANCEL_BUTTON), XmNarmColor, ss->selection_color, NULL); XtVaSetValues(XmMessageBoxGetChild(ccd_dialog, XmDIALOG_HELP_BUTTON), XmNarmColor, ss->selection_color, NULL); XtVaSetValues(XmMessageBoxGetChild(ccd_dialog, XmDIALOG_CANCEL_BUTTON), XmNbackground, ss->highlight_color, NULL); XtVaSetValues(XmMessageBoxGetChild(ccd_dialog, XmDIALOG_HELP_BUTTON), XmNbackground, ss->highlight_color, NULL); XtVaSetValues(XmMessageBoxGetChild(ccd_dialog, XmDIALOG_OK_BUTTON), XmNarmColor, ss->selection_color, NULL); XtVaSetValues(XmMessageBoxGetChild(ccd_dialog, XmDIALOG_OK_BUTTON), XmNbackground, ss->highlight_color, NULL); n = 0; XtSetArg(args[n], XmNbackground, ss->basic_color); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNbottomWidget, XmMessageBoxGetChild(ccd_dialog, XmDIALOG_SEPARATOR)); n++; mainform = XtCreateManagedWidget("formd", xmFormWidgetClass, ccd_dialog, args, n); /* color section */ n = 0; XtSetArg(args[n], XmNbackground, ss->basic_color); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNborderWidth, 10); n++; XtSetArg(args[n], XmNborderColor, ss->basic_color); n++; color_frame = XtCreateManagedWidget("color", xmFrameWidgetClass, mainform, args, n); n = 0; XtSetArg(args[n], XmNbackground, ss->basic_color); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++; color_form = XtCreateManagedWidget("cform", xmFormWidgetClass, color_frame, args, n); n = 0; XtSetArg(args[n], XmNbackground, ss->highlight_color); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNalignment, XmALIGNMENT_CENTER); n++; color_title = XtCreateManagedWidget("colors", xmLabelWidgetClass, color_form, args, n); n = 0; XtSetArg(args[n], XmNbackground, ss->basic_color); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_POSITION); n++; XtSetArg(args[n], XmNleftPosition, 60); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNtopWidget, color_title); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNlistMarginWidth, 3); n++; ccd_list = XmCreateScrolledList(color_form, (char *)"colormap-list", args, n); XtVaSetValues(ccd_list, XmNbackground, ss->white, XmNforeground, ss->black, NULL); reflect_color_list(true); XtAddCallback(ccd_list, XmNbrowseSelectionCallback, list_color_callback, NULL); XtManageChild(ccd_list); XmListSelectPos(ccd_list, color_map(ss) + 1, false); n = 0; XtSetArg(args[n], XmNbackground, ss->basic_color); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNtopWidget, color_title); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNseparatorType, XmNO_LINE); n++; XtSetArg(args[n], XmNorientation, XmVERTICAL); n++; XtSetArg(args[n], XmNwidth, 10); n++; lsep = XtCreateManagedWidget("sep", xmSeparatorWidgetClass, color_form, args, n); n = 0; XtSetArg(args[n], XmNbackground, ss->basic_color); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNrightWidget, ccd_list); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNtopWidget, color_title); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNseparatorType, XmNO_LINE); n++; XtSetArg(args[n], XmNorientation, XmVERTICAL); n++; XtSetArg(args[n], XmNwidth, 10); n++; rsep = XtCreateManagedWidget("sep", xmSeparatorWidgetClass, color_form, args, n); /* this horizontal separator exists solely to keep the "light" label from clobbering the "dark" label! */ n = 0; XtSetArg(args[n], XmNbackground, ss->basic_color); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNleftWidget, lsep); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNrightWidget, rsep); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNtopWidget, color_title); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNseparatorType, XmNO_LINE); n++; XtSetArg(args[n], XmNorientation, XmHORIZONTAL); n++; XtSetArg(args[n], XmNwidth, 250); n++; XtSetArg(args[n], XmNheight, 10); n++; sep1 = XtCreateManagedWidget("sep1", xmSeparatorWidgetClass, color_form, args, n); n = 0; XtSetArg(args[n], XmNbackground, ss->basic_color); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNleftWidget, lsep); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNrightWidget, rsep); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNtopWidget, sep1); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNorientation, XmHORIZONTAL); n++; XtSetArg(args[n], XmNshowValue, XmNEAR_SLIDER); n++; XtSetArg(args[n], XmNvalue, 50); n++; ccd_scale = XtCreateManagedWidget("ccdscl", xmScaleWidgetClass, color_form, args, n); XtAddCallback(ccd_scale, XmNvalueChangedCallback, scale_color_callback, NULL); XtAddCallback(ccd_scale, XmNdragCallback, scale_color_callback, NULL); n = 0; XtSetArg(args[n], XmNbackground, ss->basic_color); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNleftWidget, lsep); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNtopWidget, ccd_scale); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++; light_label = XtCreateManagedWidget("light", xmLabelWidgetClass, color_form, args, n); n = 0; XtSetArg(args[n], XmNbackground, ss->basic_color); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNrightWidget, rsep); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNtopWidget, ccd_scale); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++; XtCreateManagedWidget("dark", xmLabelWidgetClass, color_form, args, n); n = 0; XtSetArg(args[n], XmNbackground, ss->basic_color); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNleftWidget, lsep); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNrightWidget, rsep); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNtopWidget, light_label); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNseparatorType, XmNO_LINE); n++; XtSetArg(args[n], XmNorientation, XmHORIZONTAL); n++; XtSetArg(args[n], XmNwidth, 250); n++; XtSetArg(args[n], XmNheight, 10); n++; tsep = XtCreateManagedWidget("tsep", xmSeparatorWidgetClass, color_form, args, n); n = 0; xstr = fscale_label("data cutoff", color_cutoff(ss)); XtSetArg(args[n], XmNbackground, ss->basic_color); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNleftWidget, lsep); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNrightWidget, rsep); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNtopWidget, tsep); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNorientation, XmHORIZONTAL); n++; XtSetArg(args[n], XmNshowValue, XmNONE); n++; XtSetArg(args[n], XmNmaximum, 250); n++; XtSetArg(args[n], XmNdecimalPoints, 3); n++; XtSetArg(args[n], XmNtitleString, xstr); n++; XtSetArg(args[n], XmNvalue, (int)(color_cutoff(ss) * 1000)); n++; ccd_cutoff = XtCreateManagedWidget("cutoff", xmScaleWidgetClass, color_form, args, n); XtAddCallback(ccd_cutoff, XmNvalueChangedCallback, cutoff_color_callback, NULL); XtAddCallback(ccd_cutoff, XmNdragCallback, cutoff_color_callback, NULL); XmStringFree(xstr); XtVaSetValues(((XmScaleWidget)ccd_cutoff)->composite.children[0], XmNbackground, ss->basic_color, NULL); n = 0; XtSetArg(args[n], XmNbackground, ss->basic_color); n++; XtSetArg(args[n], XmNselectColor, ss->selection_color); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNleftWidget, lsep); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNtopWidget, ccd_cutoff); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNset, color_inverted(ss)); n++; xinvert = XmStringCreateLocalized((char *)"invert"); XtSetArg(args[n], XmNlabelString, xinvert); n++; ccd_invert = make_togglebutton_widget("invert", color_form, args, n); XtAddCallback(ccd_invert, XmNvalueChangedCallback, invert_color_callback, NULL); XmStringFree(xinvert); /* orientation section */ n = 0; XtSetArg(args[n], XmNbackground, ss->basic_color); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNtopWidget, color_frame); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNborderWidth, 10); n++; XtSetArg(args[n], XmNborderColor, ss->basic_color); n++; orientation_frame = XtCreateManagedWidget("color", xmFrameWidgetClass, mainform, args, n); n = 0; XtSetArg(args[n], XmNbackground, ss->basic_color); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++; orientation_form = XtCreateManagedWidget("oform", xmFormWidgetClass, orientation_frame, args, n); n = 0; XtSetArg(args[n], XmNbackground, ss->highlight_color); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNalignment, XmALIGNMENT_CENTER); n++; orientation_title = XtCreateManagedWidget("orientation", xmLabelWidgetClass, orientation_form, args, n); #define SCALE_BORDER_WIDTH 6 n = 0; initial_value = fixup_angle(spectro_x_angle(ss)); xstr = scale_label("x angle", initial_value, false); XtSetArg(args[n], XmNbackground, ss->basic_color); n++; XtSetArg(args[n], XmNorientation, XmHORIZONTAL); n++; XtSetArg(args[n], XmNshowValue, XmNONE); n++; XtSetArg(args[n], XmNvalue, initial_value); n++; XtSetArg(args[n], XmNmaximum, 360); n++; XtSetArg(args[n], XmNtitleString, xstr); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_POSITION); n++; XtSetArg(args[n], XmNrightPosition, 48); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNtopWidget, orientation_title); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNborderWidth, SCALE_BORDER_WIDTH); n++; XtSetArg(args[n], XmNborderColor, ss->basic_color); n++; oid_ax = XtCreateManagedWidget("ax", xmScaleWidgetClass, orientation_form, args, n); XtAddCallback(oid_ax, XmNvalueChangedCallback, ax_orientation_callback, NULL); XtAddCallback(oid_ax, XmNdragCallback, ax_orientation_callback, NULL); XmStringFree(xstr); XtVaSetValues(((XmScaleWidget)oid_ax)->composite.children[0], XmNbackground, ss->basic_color, NULL); n = 0; initial_value = mus_iclamp(0, (int)(spectro_x_scale(ss) * 100), (int)(100 * SPECTRO_X_SCALE_MAX)); xstr = scale_label("x scale", initial_value, true); XtSetArg(args[n], XmNbackground, ss->basic_color); n++; XtSetArg(args[n], XmNorientation, XmHORIZONTAL); n++; XtSetArg(args[n], XmNshowValue, XmNONE); n++; XtSetArg(args[n], XmNmaximum, (int)(100 * SPECTRO_X_SCALE_MAX)); n++; XtSetArg(args[n], XmNvalue, initial_value); n++; XtSetArg(args[n], XmNtitleString, xstr); n++; XtSetArg(args[n], XmNdecimalPoints, 2); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_POSITION); n++; XtSetArg(args[n], XmNleftPosition, 52); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_OPPOSITE_WIDGET); n++; XtSetArg(args[n], XmNtopWidget, oid_ax); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNborderWidth, SCALE_BORDER_WIDTH); n++; XtSetArg(args[n], XmNborderColor, ss->basic_color); n++; oid_sx = XtCreateManagedWidget("xs", xmScaleWidgetClass, orientation_form, args, n); XtAddCallback(oid_sx, XmNvalueChangedCallback, sx_orientation_callback, NULL); XtAddCallback(oid_sx, XmNdragCallback, sx_orientation_callback, NULL); XmStringFree(xstr); XtVaSetValues(((XmScaleWidget)oid_sx)->composite.children[0], XmNbackground, ss->basic_color, NULL); n = 0; initial_value = fixup_angle(spectro_y_angle(ss)); xstr = scale_label("y angle", initial_value, false); XtSetArg(args[n], XmNbackground, ss->basic_color); n++; XtSetArg(args[n], XmNorientation, XmHORIZONTAL); n++; XtSetArg(args[n], XmNshowValue, XmNONE); n++; XtSetArg(args[n], XmNvalue, initial_value); n++; XtSetArg(args[n], XmNmaximum, 360); n++; XtSetArg(args[n], XmNtitleString, xstr); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_POSITION); n++; XtSetArg(args[n], XmNrightPosition, 48); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNtopWidget, oid_ax); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNborderWidth, SCALE_BORDER_WIDTH); n++; XtSetArg(args[n], XmNborderColor, ss->basic_color); n++; oid_ay = XtCreateManagedWidget("ay", xmScaleWidgetClass, orientation_form, args, n); XtAddCallback(oid_ay, XmNvalueChangedCallback, ay_orientation_callback, NULL); XtAddCallback(oid_ay, XmNdragCallback, ay_orientation_callback, NULL); XmStringFree(xstr); XtVaSetValues(((XmScaleWidget)oid_ay)->composite.children[0], XmNbackground, ss->basic_color, NULL); n = 0; initial_value = mus_iclamp(0, (int)(spectro_y_scale(ss) * 100), (int)(100 * SPECTRO_Y_SCALE_MAX)); xstr = scale_label("y scale", initial_value, true); XtSetArg(args[n], XmNbackground, ss->basic_color); n++; XtSetArg(args[n], XmNorientation, XmHORIZONTAL); n++; XtSetArg(args[n], XmNshowValue, XmNONE); n++; XtSetArg(args[n], XmNmaximum, (int)(100 * SPECTRO_Y_SCALE_MAX)); n++; XtSetArg(args[n], XmNvalue, initial_value); n++; XtSetArg(args[n], XmNtitleString, xstr); n++; XtSetArg(args[n], XmNdecimalPoints, 2); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_POSITION); n++; XtSetArg(args[n], XmNleftPosition, 52); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNtopWidget, oid_sx); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNborderWidth, SCALE_BORDER_WIDTH); n++; XtSetArg(args[n], XmNborderColor, ss->basic_color); n++; oid_sy = XtCreateManagedWidget("ys", xmScaleWidgetClass, orientation_form, args, n); XtAddCallback(oid_sy, XmNvalueChangedCallback, sy_orientation_callback, NULL); XtAddCallback(oid_sy, XmNdragCallback, sy_orientation_callback, NULL); XmStringFree(xstr); XtVaSetValues(((XmScaleWidget)oid_sy)->composite.children[0], XmNbackground, ss->basic_color, NULL); n = 0; initial_value = fixup_angle(spectro_z_angle(ss)); xstr = scale_label("z angle", initial_value, false); XtSetArg(args[n], XmNbackground, ss->basic_color); n++; XtSetArg(args[n], XmNorientation, XmHORIZONTAL); n++; XtSetArg(args[n], XmNtitleString, xstr); n++; XtSetArg(args[n], XmNshowValue, XmNONE); n++; XtSetArg(args[n], XmNvalue, initial_value); n++; XtSetArg(args[n], XmNmaximum, 360); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_POSITION); n++; XtSetArg(args[n], XmNrightPosition, 48); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNtopWidget, oid_ay); n++; XtSetArg(args[n], XmNborderWidth, SCALE_BORDER_WIDTH); n++; XtSetArg(args[n], XmNborderColor, ss->basic_color); n++; oid_az = XtCreateManagedWidget("az", xmScaleWidgetClass, orientation_form, args, n); XtAddCallback(oid_az, XmNvalueChangedCallback, az_orientation_callback, NULL); XtAddCallback(oid_az, XmNdragCallback, az_orientation_callback, NULL); XmStringFree(xstr); XtVaSetValues(((XmScaleWidget)oid_az)->composite.children[0], XmNbackground, ss->basic_color, NULL); n = 0; initial_value = mus_iclamp(0, (int)(spectro_z_scale(ss) * 100), (int)(100 * SPECTRO_Z_SCALE_MAX)); xstr = scale_label("z scale", initial_value, true); XtSetArg(args[n], XmNbackground, ss->basic_color); n++; XtSetArg(args[n], XmNorientation, XmHORIZONTAL); n++; XtSetArg(args[n], XmNshowValue, XmNONE); n++; XtSetArg(args[n], XmNdecimalPoints, 2); n++; XtSetArg(args[n], XmNmaximum, (int)(100 * SPECTRO_Z_SCALE_MAX)); n++; XtSetArg(args[n], XmNvalue, initial_value); n++; XtSetArg(args[n], XmNtitleString, xstr); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_POSITION); n++; XtSetArg(args[n], XmNleftPosition, 52); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNtopWidget, oid_sy); n++; XtSetArg(args[n], XmNborderWidth, SCALE_BORDER_WIDTH); n++; XtSetArg(args[n], XmNborderColor, ss->basic_color); n++; oid_sz = XtCreateManagedWidget("zs", xmScaleWidgetClass, orientation_form, args, n); XtAddCallback(oid_sz, XmNvalueChangedCallback, sz_orientation_callback, NULL); XtAddCallback(oid_sz, XmNdragCallback, sz_orientation_callback, NULL); XmStringFree(xstr); XtVaSetValues(((XmScaleWidget)oid_sz)->composite.children[0], XmNbackground, ss->basic_color, NULL); n = 0; initial_value = mus_iclamp(1, spectro_hop(ss), HOP_MAX); xstr = scale_label("hop", initial_value, false); XtSetArg(args[n], XmNbackground, ss->basic_color); n++; XtSetArg(args[n], XmNorientation, XmHORIZONTAL); n++; XtSetArg(args[n], XmNshowValue, XmNONE); n++; XtSetArg(args[n], XmNvalue, initial_value); n++; XtSetArg(args[n], XmNmaximum, HOP_MAX); n++; XtSetArg(args[n], XmNtitleString, xstr); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_POSITION); n++; XtSetArg(args[n], XmNrightPosition, 48); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNtopWidget, oid_az); n++; #if HAVE_GL XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++; #else XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++; #endif XtSetArg(args[n], XmNborderWidth, SCALE_BORDER_WIDTH); n++; XtSetArg(args[n], XmNborderColor, ss->basic_color); n++; oid_hop = XtCreateManagedWidget("hop", xmScaleWidgetClass, orientation_form, args, n); XtAddCallback(oid_hop, XmNvalueChangedCallback, hop_orientation_callback, NULL); XtAddCallback(oid_hop, XmNdragCallback, hop_orientation_callback, NULL); XmStringFree(xstr); XtVaSetValues(((XmScaleWidget)oid_hop)->composite.children[0], XmNbackground, ss->basic_color, NULL); #if HAVE_GL n = 0; XtSetArg(args[n], XmNbackground, ss->basic_color); n++; XtSetArg(args[n], XmNselectColor, ss->selection_color); n++; XtSetArg(args[n], XmNset, with_gl(ss)); n++; glstr = XmStringCreateLocalized((char *)"use OpenGL"); XtSetArg(args[n], XmNlabelString, glstr); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNtopWidget, oid_hop); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++; oid_glbutton = make_togglebutton_widget("use OpenGL", orientation_form, args, n); XtAddCallback(oid_glbutton, XmNvalueChangedCallback, with_gl_callback, NULL); XmStringFree(glstr); #endif if (color_scale(ss) != 1.0) reflect_color_scale(color_scale(ss)); map_over_children(ccd_dialog, set_main_color_of_widget); set_dialog_widget(COLOR_ORIENTATION_DIALOG, ccd_dialog); if (managed) XtManageChild(ccd_dialog); } else { if (managed) { if (!XtIsManaged(ccd_dialog)) XtManageChild(ccd_dialog); raise_dialog(ccd_dialog); } } return(ccd_dialog); } static void view_color_orientation_callback(Widget w, XtPointer context, XtPointer info) { make_color_orientation_dialog(true); } bool color_orientation_dialog_is_active(void) { return((ccd_dialog) && (XtIsManaged(ccd_dialog))); } #define HELP_ROWS 10 #define HELP_XREFS 8 #define HELP_COLUMNS 72 /* these set the initial size of the help dialog text area */ static Widget help_dialog = NULL; static Widget help_text = NULL; static char *original_help_text = NULL; static with_word_wrap_t outer_with_wrap = WITHOUT_WORD_WRAP; static const char **help_urls = NULL; /* shouldn't this be static char* const char*? */ static int old_help_text_width = 0; static void help_expose(Widget w, XtPointer context, XEvent *event, Boolean *cont) { int curwid; curwid = widget_width(help_text); if (old_help_text_width == 0) old_help_text_width = curwid; else { if ((outer_with_wrap == WITH_WORD_WRAP) && (abs(curwid - old_help_text_width) > 10)) { char *cur_help_str, *new_help_str = NULL; cur_help_str = XmTextGetString(help_text); new_help_str = word_wrap(original_help_text, curwid); XmTextSetString(help_text, new_help_str); if (new_help_str) free(new_help_str); if (cur_help_str) XtFree(cur_help_str); old_help_text_width = curwid; } } } static XmString parse_crossref(const char *xref) { XmString xs = NULL, tmp; int i, len, start = 0, j, k; char *str; /* crossref has text for scrolled list entry, but url is in '{}'. It is displayed via the texts rendition */ len = strlen(xref); for (i = 0; i < len; i++) { if (xref[i] == '{') { if (i > 0) { str = (char *)calloc(i - start + 1, sizeof(char)); for (k = 0, j = start; j < i; k++, j++) str[k] = xref[j]; tmp = XmStringGenerate(str, NULL, XmCHARSET_TEXT, (char *)"normal_text"); free(str); if (xs) xs = XmStringConcatAndFree(xs, tmp); else xs = tmp; } start = i + 1; } else { if (xref[i] == '}') { str = (char *)calloc(i - start + 1, sizeof(char)); for (k = 0, j = start; j < i; k++, j++) str[k] = xref[j]; if (xs) xs = XmStringConcatAndFree(xs, XmStringGenerate(str, NULL, XmCHARSET_TEXT, (char *)"url_text")); else xs = XmStringGenerate(str, NULL, XmCHARSET_TEXT, (char *)"url_text"); free(str); start = i + 1; } } } if (start < len) { str = (char *)calloc(len - start + 1, sizeof(char)); for (k = 0, j = start; j < len; k++, j++) str[k] = xref[j]; if (xs) xs = XmStringConcatAndFree(xs, XmStringGenerate(str, NULL, XmCHARSET_TEXT, (char *)"normal_text")); else xs = XmStringGenerate(str, NULL, XmCHARSET_TEXT, (char *)"normal_text"); free(str); } return(xs); } static char *find_highlighted_text(XmString xs) { /* search xs for text in "url_text" rendition, returning first such portion */ XtPointer text; bool in_red_text = false; uint32_t len; char *result; XmStringComponentType type; XmStringContext ctx; XmStringInitContext(&ctx, xs); while ((type = XmStringGetNextTriple(ctx, &len, &text)) != XmSTRING_COMPONENT_END) { switch (type) { case XmSTRING_COMPONENT_RENDITION_BEGIN: in_red_text = mus_strcmp((char *)text, "url_text"); break; case XmSTRING_COMPONENT_RENDITION_END: in_red_text = false; break; case XmSTRING_COMPONENT_TEXT: if (in_red_text) { result = mus_strdup((char *)text); XtFree((char *)text); XmStringFreeContext(ctx); return(result); } } /* this from the Motif docs, though it looks odd to me */ if (text) XtFree((char *)text); text = NULL; } XmStringFreeContext(ctx); return(NULL); } static Widget related_items = NULL; static char *help_completer(widget_t w, const char *text, void *data) { return(expression_completer(w, text, data)); /* might want to look at help topics too */ } static bool new_help(const char *pattern, bool complain) { const char *url = NULL; const char **xrefs; url = snd_url(pattern); if (url) { /* given name, find doc string, if any */ Xen xstr; xstr = g_snd_help(C_string_to_Xen_string(pattern), 0); if (Xen_is_string(xstr)) { int gc_loc; gc_loc = snd_protect(xstr); xrefs = help_name_to_xrefs(pattern); snd_help_with_xrefs(pattern, Xen_string_to_C_string(xstr), WITH_WORD_WRAP, xrefs, NULL); snd_unprotect_at(gc_loc); if (xrefs) free(xrefs); return(true); } url_to_html_viewer(url); return(true); } if ((!(snd_topic_help(pattern))) && (complain)) { xrefs = help_name_to_xrefs(pattern); if (xrefs) { snd_help_with_xrefs(pattern, "(no help found)", WITH_WORD_WRAP, xrefs, NULL); free(xrefs); return(true); } else snd_help_with_xrefs(pattern, "(no help found)", WITH_WORD_WRAP, NULL, NULL); } return(false); } static void help_browse_callback(Widget w, XtPointer context, XtPointer info) { /* single-click to select item in "related items" list */ XmListCallbackStruct *cbs = (XmListCallbackStruct *)info; if ((help_urls) && (help_urls[cbs->item_position - 1])) url_to_html_viewer(help_urls[cbs->item_position - 1]); else { char *red_text; red_text = find_highlighted_text(cbs->item); if (red_text) { name_to_html_viewer(red_text); free(red_text); } else { red_text = (char *)XmStringUnparse(cbs->item, NULL, XmCHARSET_TEXT, XmCHARSET_TEXT, NULL, 0, XmOUTPUT_ALL); if (red_text) { new_help(red_text, true); XtFree(red_text); } } } } static void help_double_click_callback(Widget w, XtPointer context, XtPointer info) { /* double-click item in "related items" list */ XmListCallbackStruct *cbs = (XmListCallbackStruct *)info; if ((help_urls) && (help_urls[cbs->item_position - 1])) url_to_html_viewer(help_urls[cbs->item_position - 1]); else { char *red_text; red_text = find_highlighted_text(cbs->selected_items[0]); if (red_text) { name_to_html_viewer(red_text); free(red_text); } else { red_text = (char *)XmStringUnparse(cbs->selected_items[0], NULL, XmCHARSET_TEXT, XmCHARSET_TEXT, NULL, 0, XmOUTPUT_ALL); if (red_text) { name_to_html_viewer(red_text); XtFree(red_text); } } } } static Widget help_search = NULL; static void help_quit_callback(Widget w, XtPointer context, XtPointer info) { /* this focus widget check is actually needed! */ if (XmGetFocusWidget(help_dialog) == XmMessageBoxGetChild(help_dialog, XmDIALOG_CANCEL_BUTTON)) XtUnmanageChild(help_dialog); } static void text_release_callback(Widget w, XtPointer context, XEvent *event, Boolean *flag) { char *help_str; help_str = XmTextGetSelection(w); if (help_str) { int i, len; bool one_word = true; len = mus_strlen(help_str); for (i = 0; i < len; i++) if (isspace(help_str[i])) { one_word = false; break; } if (one_word) new_help(help_str, false); XtFree(help_str); } } static void help_search_callback(Widget w, XtPointer context, XtPointer info) { char *pattern = NULL; pattern = XmTextFieldGetString(w); if (new_help(pattern, true)) XmTextFieldSetString(w, (char *)""); if (pattern) XtFree(pattern); } static XmRendition texts[2]; static void create_help_monolog(void) { /* create scrollable but not editable text window */ Arg args[20]; int n; XmString titlestr, go_away; Widget holder, xref_label; /* documentation says this isn't needed, but it is */ Widget frame, label, inner_holder, sep, parent; XmRenderTable rs = NULL; titlestr = XmStringCreateLocalized((char *)I_HELP); go_away = XmStringCreateLocalized((char *)I_GO_AWAY); n = 0; XtSetArg(args[n], XmNbackground, ss->basic_color); n++; XtSetArg(args[n], XmNdialogTitle, titlestr); n++; /* this window should be resizable by the user (i.e. have the resize bars), but not resize itself */ XtSetArg(args[n], XmNautoUnmanage, false); n++; XtSetArg(args[n], XmNresizePolicy, XmRESIZE_GROW); n++; XtSetArg(args[n], XmNnoResize, false); n++; XtSetArg(args[n], XmNtransient, false); n++; XtSetArg(args[n], XmNcancelLabelString, go_away); n++; help_dialog = XmCreateMessageDialog(main_pane(ss), (char *)"snd-help", args, n); XtAddEventHandler(help_dialog, ExposureMask, false, help_expose, NULL); XtAddCallback(help_dialog, XmNcancelCallback, help_quit_callback, NULL); XtUnmanageChild(XmMessageBoxGetChild(help_dialog, XmDIALOG_OK_BUTTON)); XtUnmanageChild(XmMessageBoxGetChild(help_dialog, XmDIALOG_HELP_BUTTON)); XtUnmanageChild(XmMessageBoxGetChild(help_dialog, XmDIALOG_SYMBOL_LABEL)); XtVaSetValues(XmMessageBoxGetChild(help_dialog, XmDIALOG_MESSAGE_LABEL), XmNbackground, ss->highlight_color, NULL); XmStringFree(titlestr); holder = XtCreateManagedWidget("holder", xmFormWidgetClass, help_dialog, NULL, 0); n = 0; XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNeditMode, XmMULTI_LINE_EDIT); n++; XtSetArg(args[n], XmNeditable, false); n++; XtSetArg(args[n], XmNcolumns, HELP_COLUMNS); n++; XtSetArg(args[n], XmNrows, HELP_ROWS); n++; XtSetArg(args[n], XmNforeground, ss->black); n++; /* needed if color allocation fails completely */ XtSetArg(args[n], XmNbackground, ss->white); n++; help_text = XmCreateScrolledText(holder, (char *)"help-text", args, n); XtAddEventHandler(help_text, ButtonReleaseMask, false, text_release_callback, NULL); XtManageChild(help_text); /* to display the url-related portion of the text in red, we need a rendition for it in the rendertable */ /* try to find the current default render table. */ parent = help_text; while ((parent) && (!rs)) { XtVaGetValues(parent, XmNrenderTable, &rs, NULL); parent = XtParent(parent); } n = 0; if (!rs) { /* failed to find a rendertable to specialize, so we need an explicit font */ XtSetArg(args[n], XmNfontName, listener_font(ss)); n++; XtSetArg(args[n], XmNfontType, XmFONT_IS_FONT); n++; XtSetArg(args[n], XmNloadModel, XmLOAD_IMMEDIATE); n++; } XtSetArg(args[n], XmNrenditionBackground, ss->white); n++; XtSetArg(args[n], XmNrenditionForeground, ss->red); n++; texts[0] = XmRenditionCreate(help_text, (char *)"url_text", args, n); XtSetArg(args[n - 1], XmNrenditionForeground, ss->black); texts[1] = XmRenditionCreate(help_text, (char *)"normal_text", args, n); rs = XmRenderTableCopy(XmRenderTableAddRenditions(rs, texts, 2, XmMERGE_NEW), NULL, 0); /* * valgrind says this data is used later * XmRenditionFree(texts[0]); * XmRenditionFree(texts[1]); */ n = 0; XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNtopWidget, XtParent(help_text)); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNheight, 6); n++; XtSetArg(args[n], XmNorientation, XmHORIZONTAL); n++; XtSetArg(args[n], XmNseparatorType, XmNO_LINE); n++; sep = XtCreateManagedWidget("sep", xmSeparatorWidgetClass, holder, args, n); n = 0; XtSetArg(args[n], XmNbackground, ss->highlight_color); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNheight, 24); n++; /* XtSetArg(args[n], XmNalignment, XmALIGNMENT_BEGINNING); n++; */ label = XtCreateManagedWidget("help topic:", xmLabelWidgetClass, holder, args, n); n = 0; XtSetArg(args[n], XmNtopAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNleftWidget, label); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++; help_search = make_textfield_widget("help-search", holder, args, n, ACTIVATABLE, add_completer_func(help_completer, NULL)); XtAddCallback(help_search, XmNactivateCallback, help_search_callback, NULL); n = 0; XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNtopWidget, sep); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNbottomWidget, help_search); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNshadowThickness, 4); n++; frame = XtCreateManagedWidget("frame", xmFrameWidgetClass, holder, args, n); inner_holder = XtCreateManagedWidget("inner-holder", xmFormWidgetClass, frame, NULL, 0); n = 0; XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNalignment, XmALIGNMENT_BEGINNING); n++; xref_label = XtCreateManagedWidget("related topics:", xmLabelWidgetClass, inner_holder, args, n); n = 0; XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNtopWidget, xref_label); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++; /* in operton-based solaris 10 this (next) line causes an X server error (with no stack...): * complaint is X_ChangeGC got an invalid font. * Do I need a configure test program for this? Is there some other way to force the render table to take effect? */ #if (!HAVE_SUN) || (!MUS_LITTLE_ENDIAN) XtSetArg(args[n], XmNfontList, 0); n++; /* needed or new rendertable doesn't take effect! */ /* also, 0, not NULL so types match */ XtSetArg(args[n], XmNrenderTable, rs); n++; #endif XtSetArg(args[n], XmNvisibleItemCount, HELP_XREFS); n++; /* appears to be a no-op */ XtSetArg(args[n], XmNheight, 150); n++; XtSetArg(args[n], XmNscrollBarDisplayPolicy, XmAS_NEEDED); n++; related_items = XmCreateScrolledList(inner_holder, (char *)"help-list", args, n); XtManageChild(related_items); XtAddCallback(related_items, XmNbrowseSelectionCallback, help_browse_callback, NULL); XtAddCallback(related_items, XmNdefaultActionCallback, help_double_click_callback, NULL); XtManageChild(help_dialog); map_over_children(help_dialog, set_main_color_of_widget); XtVaSetValues(help_text, XmNbackground, ss->white, XmNforeground, ss->black, NULL); XtVaSetValues(related_items, XmNbackground, ss->highlight_color, XmNforeground, ss->black, NULL); XtVaSetValues(xref_label, XmNbackground, ss->highlight_color, XmNforeground, ss->black, NULL); XtVaSetValues(XmMessageBoxGetChild(help_dialog, XmDIALOG_CANCEL_BUTTON), XmNarmColor, ss->selection_color, NULL); XtVaSetValues(XmMessageBoxGetChild(help_dialog, XmDIALOG_CANCEL_BUTTON), XmNbackground, ss->highlight_color, NULL); set_dialog_widget(HELP_DIALOG, help_dialog); } int help_text_width(const char *txt, int start, int end) { #if 0 /* this is full of problems... -- adding renditions below makes everything else flakey */ if ((help_text) && (end > start)) { char *msg; int i, j; XmString s1; Dimension text_wid = 0; XmFontList fonts; XtVaGetValues(help_text, XmNfontList, &fonts, NULL); msg = (char *)calloc(end - start + 1, sizeof(char)); for (i = start, j = 0; i < end; i++, j++) msg[j] = txt[i]; s1 = XmStringCreateLocalized(msg); text_wid = XmStringWidth(fonts, s1); XmStringFree(s1); free(msg); return((int)text_wid); } #endif return((end - start) * 8); } Widget snd_help(const char *subject, const char *helpstr, with_word_wrap_t with_wrap) { /* place help string in scrollable help window */ /* if window is already active, add this help at the top and reposition */ XmString xstr1; outer_with_wrap = with_wrap; if (!(help_dialog)) create_help_monolog(); else raise_dialog(help_dialog); xstr1 = XmStringCreateLocalized((char *)subject); XtVaSetValues(help_dialog, XmNmessageString, xstr1, NULL); original_help_text = (char *)helpstr; if (with_wrap == WITH_WORD_WRAP) { char *new_help_str = NULL; new_help_str = word_wrap(helpstr, widget_width(help_text)); XmTextSetString(help_text, new_help_str); if (new_help_str) free(new_help_str); } else XmTextSetString(help_text, (char *)helpstr); if (!XtIsManaged(help_dialog)) XtManageChild(help_dialog); XmStringFree(xstr1); XtVaSetValues(related_items, XmNitems, NULL, XmNitemCount, 0, NULL); return(help_dialog); } Widget snd_help_with_xrefs(const char *subject, const char *helpstr, with_word_wrap_t with_wrap, const char **xrefs, const char **urls) { Widget w; w = snd_help(subject, helpstr, with_wrap); help_urls = urls; /* can't associate the url with the help item in any "natural" way in Motif (no user-data per item) */ if (xrefs) { int i, len; for (i = 0; ; i++) if (!xrefs[i]) { len = i; break; } if (len > 0) { XmString *strs; strs = (XmString *)calloc(len, sizeof(XmString)); for (i = 0; i < len; i++) strs[i] = parse_crossref((const char *)(xrefs[i])); XtVaSetValues(related_items, XmNitems, strs, XmNitemCount, len, NULL); for (i = 0; i < len; i++) XmStringFree(strs[i]); free(strs); } } return(w); } void snd_help_append(const char *text) { if (help_text) XmTextInsert(help_text, XmTextGetLastPosition(help_text), (char *)text); } void snd_help_back_to_top(void) { if (help_text) XmTextShowPosition(help_text, 0); } static Widget edit_find_dialog, edit_find_text, cancelB, edit_find_label, previousB; static Widget find_error_frame = NULL, find_error_label = NULL; static chan_info *find_channel = NULL; /* sigh */ static void clear_find_error(void); static void edit_find_modify_callback(Widget w, XtPointer context, XtPointer info) { clear_find_error(); } static void clear_find_error(void) { if ((find_error_frame) && (XtIsManaged(find_error_frame))) XtUnmanageChild(find_error_frame); XtRemoveCallback(edit_find_text, XmNmodifyVerifyCallback, edit_find_modify_callback, NULL); /* squeezing out the error label room here moves the text widget, which is irritating since it * means the text we're typing gets lost */ } void find_dialog_stop_label(bool show_stop) { XmString s1; if (show_stop) s1 = XmStringCreateLocalized((char *)I_STOP); else s1 = XmStringCreateLocalized((char *)I_GO_AWAY); XtVaSetValues(cancelB, XmNlabelString, s1, NULL); XmStringFree(s1); } void errors_to_find_text(const char *msg, void *data) { Dimension find_height = 0; int lines = 0; XmString label; find_dialog_set_label("error"); label = multi_line_label(msg, &lines); XtVaSetValues(find_error_label, XmNlabelString, label, XmNheight, lines * 20, NULL); XtVaSetValues(find_error_frame, XmNheight, lines * 20, NULL); XtVaGetValues(edit_find_dialog, XmNheight, &find_height, NULL); if (find_height < (lines * 20 + 140)) { XtUnmanageChild(edit_find_dialog); XtVaSetValues(edit_find_dialog, XmNheight, 140 + 20 * lines, NULL); XtManageChild(edit_find_dialog); } XmStringFree(label); XtManageChild(find_error_frame); XtAddCallback(edit_find_text, XmNmodifyVerifyCallback, edit_find_modify_callback, NULL); } void stop_search_if_error(const char *msg, void *data) { errors_to_find_text(msg, data); ss->stopped_explicitly = true; /* should be noticed in global_search in snd-find.c */ } static void edit_find_help_callback(Widget w, XtPointer context, XtPointer info) { find_dialog_help(); } static void edit_find_ok_callback(read_direction_t direction, Widget w, XtPointer context, XtPointer info) { char *str; str = XmTextGetString(edit_find_text); #if HAVE_EXTENSION_LANGUAGE find_dialog_find(str, direction, find_channel); #endif if (str) free(str); } void find_dialog_set_label(const char *str) { if (edit_find_label) set_label(edit_find_label, str); } static void edit_find_next_callback(Widget w, XtPointer context, XtPointer info) { edit_find_ok_callback(READ_FORWARD, w, context, info); } static void edit_find_previous_callback(Widget w, XtPointer context, XtPointer info) { edit_find_ok_callback(READ_BACKWARD, w, context, info); } static void find_dialog_close(Widget w, XtPointer context, XtPointer info) { clear_find_error(); } static void edit_find_cancel_callback(Widget w, XtPointer context, XtPointer info) { if (ss->checking_explicitly) ss->stopped_explicitly = true; else { XtUnmanageChild(edit_find_dialog); clear_find_error(); } } static void make_edit_find_dialog(bool managed, chan_info *cp) { find_channel = cp; if (!edit_find_dialog) { Widget dl, rc; Arg args[20]; int n; XmString go_away, next; n = 0; XtSetArg(args[n], XmNbackground, ss->basic_color); n++; go_away = XmStringCreateLocalized((char *)I_GO_AWAY); next = XmStringCreateLocalized((char *)I_NEXT); XtSetArg(args[n], XmNokLabelString, next); n++; XtSetArg(args[n], XmNcancelLabelString, go_away); n++; XtSetArg(args[n], XmNautoUnmanage, false); n++; XtSetArg(args[n], XmNresizePolicy, XmRESIZE_GROW); n++; XtSetArg(args[n], XmNnoResize, false); n++; XtSetArg(args[n], XmNtransient, false); n++; edit_find_dialog = XmCreateMessageDialog(main_shell(ss), (char *)I_FIND, args, n); XmStringFree(go_away); XmStringFree(next); XtUnmanageChild(XmMessageBoxGetChild(edit_find_dialog, XmDIALOG_SYMBOL_LABEL)); XtUnmanageChild(XmMessageBoxGetChild(edit_find_dialog, XmDIALOG_MESSAGE_LABEL)); XtAddCallback(edit_find_dialog, XmNhelpCallback, edit_find_help_callback, NULL); XtAddCallback(edit_find_dialog, XmNcancelCallback, edit_find_cancel_callback, NULL); XtAddCallback(edit_find_dialog, XmNokCallback, edit_find_next_callback, NULL); n = 0; XtSetArg(args[n], XmNbackground, ss->highlight_color); n++; XtSetArg(args[n], XmNarmColor, ss->selection_color); n++; previousB = XtCreateManagedWidget(I_PREVIOUS, xmPushButtonGadgetClass, edit_find_dialog, args, n); XtAddCallback(previousB, XmNactivateCallback, edit_find_previous_callback, NULL); rc = XtCreateManagedWidget("row", xmFormWidgetClass, edit_find_dialog, NULL, 0); n = 0; XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_NONE); n++; dl = XtCreateManagedWidget(I_find, xmLabelWidgetClass, rc, args, n); n = 0; XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNleftWidget, dl); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++; edit_find_text = make_textfield_widget("text", rc, args, n, ACTIVATABLE, add_completer_func(expression_completer, NULL)); n = 0; XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNtopWidget, edit_find_text); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNmarginHeight, 10); n++; edit_find_label = XtCreateManagedWidget(" ", xmLabelWidgetClass, rc, args, n); n = 0; XtSetArg(args[n], XmNbackground, ss->basic_color); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNtopWidget, edit_find_label); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNallowResize, true); n++; XtSetArg(args[n], XmNshadowType, XmSHADOW_ETCHED_IN); n++; XtSetArg(args[n], XmNshadowThickness, 2); n++; find_error_frame = XtCreateManagedWidget("find-error-frame", xmFrameWidgetClass, rc, args, n); n = 0; XtSetArg(args[n], XmNbackground, ss->highlight_color); n++; find_error_label = XtCreateManagedWidget("", xmLabelWidgetClass, find_error_frame, args, n); map_over_children(edit_find_dialog, set_main_color_of_widget); XtVaSetValues(XmMessageBoxGetChild(edit_find_dialog, XmDIALOG_OK_BUTTON), XmNarmColor, ss->selection_color, NULL); XtVaSetValues(XmMessageBoxGetChild(edit_find_dialog, XmDIALOG_CANCEL_BUTTON), XmNarmColor, ss->selection_color, NULL); XtVaSetValues(XmMessageBoxGetChild(edit_find_dialog, XmDIALOG_HELP_BUTTON), XmNarmColor, ss->selection_color, NULL); XtVaSetValues(XmMessageBoxGetChild(edit_find_dialog, XmDIALOG_OK_BUTTON), XmNbackground, ss->highlight_color, NULL); XtVaSetValues(XmMessageBoxGetChild(edit_find_dialog, XmDIALOG_CANCEL_BUTTON), XmNbackground, ss->highlight_color, NULL); XtVaSetValues(XmMessageBoxGetChild(edit_find_dialog, XmDIALOG_HELP_BUTTON), XmNbackground, ss->highlight_color, NULL); cancelB = XmMessageBoxGetChild(edit_find_dialog, XmDIALOG_CANCEL_BUTTON); set_dialog_widget(FIND_DIALOG, edit_find_dialog); XtUnmanageChild(find_error_frame); if (managed) XtManageChild(edit_find_dialog); { Atom wm_delete_window; wm_delete_window = XmInternAtom(main_display(ss), (char *)"WM_DELETE_WINDOW", false); XmAddWMProtocolCallback(XtParent(edit_find_dialog), wm_delete_window, find_dialog_close, NULL); } } else { if (managed) { if (!XtIsManaged(edit_find_dialog)) XtManageChild(edit_find_dialog); raise_dialog(edit_find_dialog); } } { XmString titlestr; if (cp) titlestr = XmStringCreateLocalized(mus_format("%s in %s channel %d", (char *)I_FIND, cp->sound->short_filename, cp->chan)); else titlestr = XmStringCreateLocalized((char *)I_FIND); XtVaSetValues(edit_find_dialog, XmNdialogTitle, titlestr, NULL); XmStringFree(titlestr); } } static void edit_find_callback(Widget w, XtPointer context, XtPointer info) { make_edit_find_dialog(true, NULL); } void find_dialog(chan_info *cp) { make_edit_find_dialog(true, cp); } bool find_dialog_is_active(void) { return((edit_find_dialog) && (XtIsManaged(edit_find_dialog))); } void save_find_dialog_state(FILE *fd) { if (find_dialog_is_active()) { char *text = NULL; text = XmTextGetString(edit_find_text); if ((text) && (*text)) { #if HAVE_SCHEME fprintf(fd, "(%s #t \"%s\")\n", S_find_dialog, text); #endif #if HAVE_RUBY fprintf(fd, "%s(true, \"%s\")\n", to_proc_name(S_find_dialog), text); #endif #if HAVE_FORTH fprintf(fd, "#t \"%s\" %s drop\n", text, S_find_dialog); #endif XtFree(text); } else { #if HAVE_SCHEME if (ss->search_expr) fprintf(fd, "(%s #t \"%s\")\n", S_find_dialog, ss->search_expr); else fprintf(fd, "(%s #t)\n", S_find_dialog); #endif #if HAVE_RUBY if (ss->search_expr) fprintf(fd, "%s(true, \"%s\")\n", to_proc_name(S_find_dialog), ss->search_expr); else fprintf(fd, "%s(true)\n", to_proc_name(S_find_dialog)); #endif #if HAVE_FORTH if (ss->search_expr) fprintf(fd, "#t \"%s\" %s drop\n", ss->search_expr, S_find_dialog); else fprintf(fd, "#t %s drop\n", S_find_dialog); #endif } } } static Xen g_find_dialog(Xen managed, Xen text) { #define H_find_dialog "(" S_find_dialog " :optional managed text): create and activate the Edit:Find dialog, return the dialog widget. \ If 'text' is included, it is preloaded into the find dialog text widget." Xen_check_type(Xen_is_boolean_or_unbound(managed), managed, 1, S_find_dialog, "a boolean"); Xen_check_type(Xen_is_string_or_unbound(text), text, 2, S_find_dialog, "a string"); make_edit_find_dialog(Xen_boolean_to_C_bool(managed), NULL); if ((edit_find_text) && (Xen_is_string(text))) XmTextSetString(edit_find_text, (char *)Xen_string_to_C_string(text)); return(Xen_wrap_widget(edit_find_dialog)); } static Xen g_find_dialog_widgets(void) { if (edit_find_dialog) return(Xen_cons(Xen_wrap_widget(edit_find_dialog), Xen_cons(Xen_wrap_widget(edit_find_text), Xen_cons(Xen_wrap_widget(XmMessageBoxGetChild(edit_find_dialog, XmDIALOG_OK_BUTTON)), /* find next */ Xen_cons(Xen_wrap_widget(previousB), /* find previous */ Xen_cons(Xen_wrap_widget(XmMessageBoxGetChild(edit_find_dialog, XmDIALOG_CANCEL_BUTTON)), /* go away */ Xen_empty_list)))))); return(Xen_empty_list); } #define NAME_COLUMNS 8 /* ---------------- mix dialog ---------------- */ static Widget mix_dialog = NULL; static int mix_dialog_id = INVALID_MIX_ID, old_mix_dialog_id = INVALID_MIX_ID; static env *dialog_env = NULL; static bool dragging = false; static int edpos_before_drag; static with_hook_t hookable_before_drag; static mus_long_t drag_beg = 0, drag_end = 0; static void start_dragging(int mix_id) { chan_info *cp; cp = mix_chan_info_from_id(mix_id); edpos_before_drag = cp->edit_ctr; hookable_before_drag = cp->hookable; cp->hookable = WITHOUT_HOOK; dragging = true; drag_beg = mix_position_from_id(mix_id); drag_end = drag_beg + mix_length_from_id(mix_id); start_dragging_syncd_mixes(mix_id); } static void keep_dragging(int mix_id) { chan_info *cp; cp = mix_chan_info_from_id(mix_id); cp->edit_ctr = edpos_before_drag; keep_dragging_syncd_mixes(mix_id); } static void stop_dragging(int mix_id) { chan_info *cp; cp = mix_chan_info_from_id(mix_id); undo_edit(cp, 1); cp->hookable = hookable_before_drag; dragging = false; stop_dragging_syncd_mixes(mix_id); } /* -------- speed -------- */ static Widget w_speed_number, w_speed_label, w_speed; static speed_style_t xmix_speed_control_style = SPEED_CONTROL_AS_FLOAT; static int speed_to_scrollbar(mus_float_t minval, mus_float_t val, mus_float_t maxval) { if (val <= minval) return(0); if (val >= maxval) return((int)(0.9 * SCROLLBAR_MAX)); return(snd_round(0.9 * SCROLLBAR_MAX * ((log(val) - log(minval)) / (log(maxval) - log(minval))))); } static mus_float_t set_speed_label(Widget speed_number, int ival) { char speed_number_buffer[6]; mus_float_t speed; speed = speed_changed(exp((ival * (log(speed_control_max(ss)) - log(speed_control_min(ss))) / (0.9 * SCROLLBAR_MAX)) + log(speed_control_min(ss))), speed_number_buffer, xmix_speed_control_style, speed_control_tones(ss), 6); set_label(speed_number, speed_number_buffer); return(speed); } static void mix_speed_click_callback(Widget w, XtPointer context, XtPointer info) { char speed_number_buffer[6]; mus_float_t speed; if (!(mix_is_active(mix_dialog_id))) return; speed = speed_changed(1.0, speed_number_buffer, xmix_speed_control_style, speed_control_tones(ss), 6); drag_beg = mix_position_from_id(mix_dialog_id); drag_end = drag_beg + mix_length_from_id(mix_dialog_id); mix_set_speed_edit(mix_dialog_id, speed); syncd_mix_set_speed(mix_dialog_id, speed); after_mix_edit(mix_dialog_id); set_label(w_speed_number, speed_number_buffer); XtVaSetValues(w_speed, XmNvalue, speed_to_scrollbar(speed_control_min(ss), 1.0, speed_control_max(ss)), NULL); } static void mix_speed_label_click_callback(Widget w, XtPointer context, XtPointer info) { char speed_number_buffer[6]; if (!(mix_is_active(mix_dialog_id))) return; switch (xmix_speed_control_style) { default: case SPEED_CONTROL_AS_FLOAT: xmix_speed_control_style = SPEED_CONTROL_AS_RATIO; break; case SPEED_CONTROL_AS_RATIO: xmix_speed_control_style = SPEED_CONTROL_AS_SEMITONE; break; case SPEED_CONTROL_AS_SEMITONE: xmix_speed_control_style = SPEED_CONTROL_AS_FLOAT; break; } speed_changed(mix_speed_from_id(mix_dialog_id), speed_number_buffer, xmix_speed_control_style, speed_control_tones(ss), 6); set_label(w_speed_number, speed_number_buffer); } static void mix_speed_drag_callback(Widget w, XtPointer context, XtPointer info) { int ival; mus_float_t speed; mus_long_t beg, end; if (!(mix_is_active(mix_dialog_id))) return; ival = ((XmScrollBarCallbackStruct *)info)->value; if (!dragging) start_dragging(mix_dialog_id); else keep_dragging(mix_dialog_id); speed = set_speed_label(w_speed_number, ival); mix_set_speed_edit(mix_dialog_id, speed); beg = mix_position_from_id(mix_dialog_id); end = beg + mix_length_from_id(mix_dialog_id); if (drag_beg > beg) drag_beg = beg; if (drag_end < end) drag_end = end; mix_display_during_drag(mix_dialog_id, drag_beg, drag_end); syncd_mix_set_speed(mix_dialog_id, speed); } static void mix_speed_valuechanged_callback(Widget w, XtPointer context, XtPointer info) { XmScrollBarCallbackStruct *cb = (XmScrollBarCallbackStruct *)info; mus_float_t speed; if (!(mix_is_active(mix_dialog_id))) return; if (dragging) stop_dragging(mix_dialog_id); speed = set_speed_label(w_speed_number, cb->value); mix_set_speed_edit(mix_dialog_id, speed); syncd_mix_set_speed(mix_dialog_id, speed); after_mix_edit(mix_dialog_id); after_syncd_mix_edit(mix_dialog_id); } /* -------- amp -------- */ static Widget w_amp_number, w_amp_label, w_amp; static mus_float_t scrollbar_to_amp(int val) { if (val <= 0) return(amp_control_min(ss)); if (val >= (0.9 * SCROLLBAR_MAX)) return(amp_control_max(ss)); if (val > (0.5 * 0.9 * SCROLLBAR_MAX)) return((((val / (0.5 * 0.9 * SCROLLBAR_MAX)) - 1.0) * (amp_control_max(ss) - 1.0)) + 1.0); else return((val * (1.0 - amp_control_min(ss)) / (0.5 * 0.9 * SCROLLBAR_MAX)) + amp_control_min(ss)); } static int amp_to_scrollbar(Widget amp_number, mus_float_t amp) { char sfs[6]; snprintf(sfs, 6, "%.2f", amp); set_label(amp_number, sfs); return(amp_to_scroll(amp_control_min(ss), amp, amp_control_max(ss))); } static void change_mix_amp(int mix_id, mus_float_t val) { char sfs[6]; mix_set_amp_edit(mix_id, val); syncd_mix_set_amp(mix_id, val); snprintf(sfs, 6, "%.2f", val); set_label(w_amp_number, sfs); } static void mix_amp_click_callback(Widget w, XtPointer context, XtPointer info) { if (!(mix_is_active(mix_dialog_id))) return; change_mix_amp(mix_dialog_id, 1.0); after_mix_edit(mix_dialog_id); XtVaSetValues(w_amp, XmNvalue, amp_to_scroll(amp_control_min(ss), 1.0, amp_control_max(ss)), NULL); } static void mix_amp_drag_callback(Widget w, XtPointer context, XtPointer info) { int ival; if (!(mix_is_active(mix_dialog_id))) return; ival = ((XmScrollBarCallbackStruct *)info)->value; if (!dragging) start_dragging(mix_dialog_id); else keep_dragging(mix_dialog_id); change_mix_amp(mix_dialog_id, scrollbar_to_amp(ival)); mix_display_during_drag(mix_dialog_id, drag_beg, drag_end); } static void mix_amp_valuechanged_callback(Widget w, XtPointer context, XtPointer info) { int ival; if (!(mix_is_active(mix_dialog_id))) return; ival = ((XmScrollBarCallbackStruct *)info)->value; if (dragging) stop_dragging(mix_dialog_id); change_mix_amp(mix_dialog_id, scrollbar_to_amp(ival)); after_mix_edit(mix_dialog_id); after_syncd_mix_edit(mix_dialog_id); } /* -------- amp-env -------- */ static Widget w_env_frame, w_env; static graphics_context *ax = NULL; static GC cur_gc; static env_editor *spf = NULL; static bool with_mix_background_wave = false; static void show_mix_background_wave(int mix_id) { int pts; bool two_sided = false; if (!spf) return; pts = prepare_mix_dialog_waveform(mix_id, spf->axis, &two_sided); if (pts > 0) { XSetForeground(main_display(ss), ax->gc, ss->enved_waveform_color); if (two_sided) draw_both_grf_points(1, ax, pts, GRAPH_LINES); else draw_grf_points(1, ax, pts, spf->axis, ungrf_y(spf->axis, 0.0), GRAPH_LINES); XSetForeground(main_display(ss), ax->gc, ss->black); } } static void mix_amp_env_resize(Widget w, XtPointer context, XtPointer info) { env *cur_env; if (!(mix_is_active(mix_dialog_id))) return; if (!ax) { XGCValues gv; gv.function = GXcopy; XtVaGetValues(w_env, XmNbackground, &gv.background, XmNforeground, &gv.foreground, NULL); cur_gc = XtGetGC(w_env, GCForeground | GCFunction, &gv); ax = (graphics_context *)calloc(1, sizeof(graphics_context)); ax->wn = XtWindow(w_env); ax->dp = XtDisplay(w_env); ax->gc = cur_gc; } else clear_window(ax); cur_env = dialog_env; spf->with_dots = true; env_editor_display_env(spf, cur_env, ax, "mix env", 0, 0, widget_width(w), widget_height(w), NOT_PRINTING); if (with_mix_background_wave) show_mix_background_wave(mix_dialog_id); } #ifdef __APPLE__ static int press_x, press_y; #endif static void mix_drawer_button_motion(Widget w, XtPointer context, XEvent *event, Boolean *cont) { XMotionEvent *ev = (XMotionEvent *)event; if (!(mix_is_active(mix_dialog_id))) return; #ifdef __APPLE__ if ((press_x == ev->x) && (press_y == ev->y)) return; #endif env_editor_button_motion(spf, ev->x, ev->y, ev->time, dialog_env); mix_amp_env_resize(w, NULL, NULL); } static void mix_drawer_button_press(Widget w, XtPointer context, XEvent *event, Boolean *cont) { XButtonEvent *ev = (XButtonEvent *)event; if (!(mix_is_active(mix_dialog_id))) return; #ifdef __APPLE__ press_x = ev->x; press_y = ev->y; #endif if (env_editor_button_press(spf, ev->x, ev->y, ev->time, dialog_env)) mix_amp_env_resize(w, NULL, NULL); } static void mix_drawer_button_release(Widget w, XtPointer context, XEvent *event, Boolean *cont) { if (!(mix_is_active(mix_dialog_id))) return; env_editor_button_release(spf, dialog_env); mix_amp_env_resize(w, NULL, NULL); } static Widget w_id = NULL, w_beg = NULL; #if WITH_AUDIO static Widget mix_play = NULL; #endif static Widget error_frame = NULL, error_label = NULL; static void clear_mix_error(void) { if ((error_frame) && (XtIsManaged(error_frame))) XtUnmanageChild(error_frame); } static void unpost_mix_error(XtPointer data, XtIntervalId *id) { clear_mix_error(); } static void errors_to_mix_text(const char *msg, void *data) { int lines = 0; XmString label; label = multi_line_label(msg, &lines); XtVaSetValues(error_label, XmNlabelString, label, XmNheight, lines * 20, NULL); XtVaSetValues(error_frame, XmNheight, lines * 20, NULL); XmStringFree(label); XtManageChild(error_frame); /* since the offending text is automatically overwritten, we can't depend on subsequent text modify callbacks * to clear things, so we'll just use a timer */ XtAppAddTimeOut(main_app(ss), 5000, (XtTimerCallbackProc)unpost_mix_error, NULL); } static void widget_mix_to_text(Widget w, int id) { if (mix_name(id)) XmTextFieldSetString(w, (char *)mix_name(id)); else widget_int_to_text(w, id); } static bool id_changed = false; static void id_activated(void) { char *val; id_changed = false; val = XmTextGetString(w_id); if (val) { int id; /* look for a mix name first, then a number */ id = mix_name_to_id(val); if (id < 0) { redirect_errors_to(errors_to_mix_text, NULL); id = string_to_int(val, 0, "id"); redirect_errors_to(NULL, NULL); } if (mix_is_active(id)) { mix_dialog_id = id; reflect_mix_change(id); } XtFree(val); } } static void id_modify_callback(Widget w, XtPointer context, XtPointer info) { id_changed = true; } static void id_check_callback(Widget w, XtPointer context, XtPointer info) { if (id_changed) id_activated(); } static void beg_activated(void) { char *val; if (!(mix_is_active(mix_dialog_id))) return; val = XmTextGetString(w_beg); if (val) { chan_info *cp; char *up_to_colon; mus_float_t beg; cp = mix_chan_info_from_id(mix_dialog_id); up_to_colon = string_to_colon(val); redirect_errors_to(errors_to_mix_text, NULL); beg = string_to_mus_float_t(up_to_colon, 0.0, "begin time"); redirect_errors_to(NULL, NULL); if (beg >= 0.0) { mus_long_t pos, old_pos; old_pos = mix_position_from_id(mix_dialog_id); pos = (mus_long_t)(beg * snd_srate(cp->sound)); mix_set_position_edit(mix_dialog_id, pos); syncd_mix_change_position(mix_dialog_id, pos - old_pos); } after_mix_edit(mix_dialog_id); free(up_to_colon); XtFree(val); } } static void apply_mix_dialog_callback(Widget w, XtPointer context, XtPointer info) { if (!(mix_is_active(mix_dialog_id))) return; if ((dialog_env) && (!(is_default_env(dialog_env)))) { mix_set_amp_env_edit(mix_dialog_id, dialog_env); syncd_mix_set_amp_env(mix_dialog_id, dialog_env); } else { mix_set_amp_env_edit(mix_dialog_id, NULL); syncd_mix_set_amp_env(mix_dialog_id, NULL); } mix_amp_env_resize(w_env, NULL, NULL); after_mix_edit(mix_dialog_id); } static void copy_mix_dialog_callback(Widget w, XtPointer context, XtPointer info) { Widget active_widget; active_widget = XmGetFocusWidget(mix_dialog); if (active_widget == XmMessageBoxGetChild(mix_dialog, XmDIALOG_OK_BUTTON)) { copy_mix(mix_dialog_id); after_mix_edit(mix_dialog_id); } else { if (active_widget == w_id) id_activated(); else { if (active_widget == w_beg) beg_activated(); } } } static void quit_mix_dialog_callback(Widget w, XtPointer context, XtPointer info) { clear_mix_error(); XtUnmanageChild(mix_dialog); } static void help_mix_dialog_callback(Widget w, XtPointer context, XtPointer info) { mix_dialog_help(); } /* -------- play -------- */ #if WITH_AUDIO static bool mix_playing = false; #endif void reflect_mix_play_stop(void) { #if WITH_AUDIO if (mix_play) XmChangeColor(mix_play, ss->basic_color); mix_playing = false; #endif } #if WITH_AUDIO static void mix_dialog_play_callback(Widget w, XtPointer context, XtPointer info) { if (mix_playing) reflect_mix_play_stop(); else { if (!(mix_exists(mix_dialog_id))) return; if (mix_play) XmChangeColor(mix_play, ss->selection_color); /* this needs to happen before trying to play */ syncd_mix_play(mix_dialog_id); mix_playing = true; /* don't use the return value here */ play_mix_from_id(mix_dialog_id); } } #endif /* -------- dB -------- */ static void mix_dB_callback(Widget w, XtPointer context, XtPointer info) { XmToggleButtonCallbackStruct *cb = (XmToggleButtonCallbackStruct *)info; spf->in_dB = cb->set; mix_amp_env_resize(w_env, NULL, NULL); } /* -------- sync -------- */ static void mix_sync_callback(Widget w, XtPointer context, XtPointer info) { XmToggleButtonCallbackStruct *cb = (XmToggleButtonCallbackStruct *)info; if ((cb->set) && (mix_sync_from_id(mix_dialog_id) == 0)) { mix_set_sync_from_id(mix_dialog_id, GET_ORIGINAL_SYNC); /* choose a new sync val or return to previous */ /* check for resync */ syncd_mix_set_color(mix_dialog_id, ss->red); } else { if ((!(cb->set)) && (mix_sync_from_id(mix_dialog_id) != 0)) { syncd_mix_unset_color(mix_dialog_id); /* unset colors of any syncd mixes */ mix_set_sync_from_id(mix_dialog_id, 0); } } for_each_normal_chan(display_channel_mixes); } /* -------- clip -------- */ static void mix_clip_callback(Widget w, XtPointer context, XtPointer info) { XmToggleButtonCallbackStruct *cb = (XmToggleButtonCallbackStruct *)info; spf->clipping = cb->set; mix_amp_env_resize(w_env, NULL, NULL); } /* -------- wave -------- */ static void mix_wave_callback(Widget w, XtPointer context, XtPointer info) { XmToggleButtonCallbackStruct *cb = (XmToggleButtonCallbackStruct *)info; with_mix_background_wave = cb->set; mix_amp_env_resize(w_env, NULL, NULL); } /* -------- next/previous -------- */ static Widget mix_next_button, mix_previous_button; static void mix_next_callback(Widget w, XtPointer context, XtPointer info) { int id; clear_mix_error(); id = next_mix_id(mix_dialog_id); if (id != INVALID_MIX_ID) { mix_dialog_id = id; reflect_mix_change(id); if (next_mix_id(id) == INVALID_MIX_ID) set_sensitive(mix_next_button, false); } } static void mix_previous_callback(Widget w, XtPointer context, XtPointer info) { int id; clear_mix_error(); id = previous_mix_id(mix_dialog_id); if (id != INVALID_MIX_ID) { mix_dialog_id = id; reflect_mix_change(id); if (previous_mix_id(id) == INVALID_MIX_ID) set_sensitive(mix_previous_button, false); } } static Pixmap make_pixmap(unsigned char *bits, int width, int height, int depth, GC gc) { Pixmap rb, nr; rb = XCreateBitmapFromData(main_display(ss), RootWindowOfScreen(XtScreen(main_pane(ss))), (const char *)bits, width, height); nr = XCreatePixmap(main_display(ss), RootWindowOfScreen(XtScreen(main_pane(ss))), width, height, depth); XCopyPlane(main_display(ss), rb, nr, gc, 0, 0, width, height, 0, 0, 1); XFreePixmap(main_display(ss), rb); return(nr); } #define p_speaker_width 12 #define p_speaker_height 12 static unsigned char p_speaker_bits[] = { 0x00, 0x07, 0xc0, 0x04, 0x30, 0x04, 0x0e, 0x04, 0x06, 0x04, 0x06, 0x04, 0x06, 0x04, 0x06, 0x04, 0x0e, 0x04, 0x30, 0x04, 0xc0, 0x04, 0x00, 0x07}; static int mixer_depth; static GC gc; static Pixmap speaker_r; void make_mixer_icons_transparent_again(Pixel old_color, Pixel new_color) { if (mix_dialog) { XFreePixmap(XtDisplay(mix_dialog), speaker_r); XSetBackground(XtDisplay(mix_dialog), gc, new_color); speaker_r = make_pixmap(p_speaker_bits, p_speaker_width, p_speaker_height, mixer_depth, gc); #if WITH_AUDIO XtVaSetValues(mix_play, XmNlabelPixmap, speaker_r, NULL); #endif } } static Widget w_sync; Widget make_mix_dialog(void) { if (!mix_dialog) { Widget mainform, mix_row, mix_frame, sep, w_sep1; Widget w_dB_frame, w_dB, w_clip, w_wave, w_dB_row, env_button, copy_button; XmString xgo_away, xhelp, xtitle, s1, xcopy; int n; Arg args[20]; XtCallbackList n1, n2; XGCValues v; char amplab[LABEL_BUFFER_SIZE]; xmix_speed_control_style = speed_control_style(ss); mix_dialog_id = any_mix_id(); xgo_away = XmStringCreateLocalized((char *)I_GO_AWAY); xcopy = XmStringCreateLocalized((char *)"Copy mix"); xhelp = XmStringCreateLocalized((char *)I_HELP); xtitle = XmStringCreateLocalized((char *)"Mixes"); n = 0; XtSetArg(args[n], XmNbackground, ss->basic_color); n++; XtSetArg(args[n], XmNokLabelString, xcopy); n++; XtSetArg(args[n], XmNcancelLabelString, xgo_away); n++; XtSetArg(args[n], XmNhelpLabelString, xhelp); n++; XtSetArg(args[n], XmNautoUnmanage, false); n++; XtSetArg(args[n], XmNdialogTitle, xtitle); n++; XtSetArg(args[n], XmNresizePolicy, XmRESIZE_GROW); n++; XtSetArg(args[n], XmNnoResize, false); n++; XtSetArg(args[n], XmNtransient, false); n++; mix_dialog = XmCreateTemplateDialog(main_shell(ss), (char *)"Mixes", args, n); copy_button = XmMessageBoxGetChild(mix_dialog, XmDIALOG_OK_BUTTON); /* XtAddCallback(mix_dialog, XmNokCallback, copy_mix_dialog_callback, NULL); */ XtAddCallback(copy_button, XmNactivateCallback, copy_mix_dialog_callback, NULL); XtAddCallback(mix_dialog, XmNcancelCallback, quit_mix_dialog_callback, NULL); XtAddCallback(mix_dialog, XmNhelpCallback, help_mix_dialog_callback, NULL); XmStringFree(xhelp); XmStringFree(xcopy); XmStringFree(xgo_away); XmStringFree(xtitle); XtVaSetValues(XmMessageBoxGetChild(mix_dialog, XmDIALOG_CANCEL_BUTTON), XmNarmColor, ss->selection_color, NULL); XtVaSetValues(XmMessageBoxGetChild(mix_dialog, XmDIALOG_OK_BUTTON), XmNarmColor, ss->selection_color, NULL); XtVaSetValues(XmMessageBoxGetChild(mix_dialog, XmDIALOG_HELP_BUTTON), XmNarmColor, ss->selection_color, NULL); XtVaSetValues(XmMessageBoxGetChild(mix_dialog, XmDIALOG_CANCEL_BUTTON), XmNbackground, ss->highlight_color, NULL); XtVaSetValues(XmMessageBoxGetChild(mix_dialog, XmDIALOG_OK_BUTTON), XmNbackground, ss->highlight_color, NULL); XtVaSetValues(XmMessageBoxGetChild(mix_dialog, XmDIALOG_HELP_BUTTON), XmNbackground, ss->highlight_color, NULL); n = 0; XtSetArg(args[n], XmNbackground, ss->highlight_color); n++; XtSetArg(args[n], XmNarmColor, ss->selection_color); n++; env_button = XtCreateManagedWidget("Apply env", xmPushButtonGadgetClass, mix_dialog, args, n); XtAddCallback(env_button, XmNactivateCallback, apply_mix_dialog_callback, NULL); n = 0; XtSetArg(args[n], XmNbackground, ss->basic_color); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNbottomWidget, XmMessageBoxGetChild(mix_dialog, XmDIALOG_SEPARATOR)); n++; mainform = XtCreateManagedWidget("formd", xmFormWidgetClass, mix_dialog, args, n); n = 0; XtSetArg(args[n], XmNbackground, ss->basic_color); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNallowResize, true); n++; XtSetArg(args[n], XmNshadowType, XmSHADOW_ETCHED_IN); n++; XtSetArg(args[n], XmNshadowThickness, 2); n++; mix_frame = XtCreateManagedWidget("mix-frame", xmFrameWidgetClass, mainform, args, n); n = 0; XtSetArg(args[n], XmNbackground, ss->highlight_color); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNorientation, XmHORIZONTAL); n++; mix_row = XtCreateManagedWidget("mix-dialog-row", xmRowColumnWidgetClass, mix_frame, args, n); n = 0; XtSetArg(args[n], XmNbackground, ss->highlight_color); n++; XtCreateManagedWidget("mix:", xmLabelWidgetClass, mix_row, args, n); n = 0; XtSetArg(args[n], XmNbackground, ss->basic_color); n++; XtSetArg(args[n], XmNresizeWidth, false); n++; XtSetArg(args[n], XmNcolumns, NAME_COLUMNS); n++; XtSetArg(args[n], XmNrecomputeSize, false); n++; w_id = make_textfield_widget("mix-id", mix_row, args, n, ACTIVATABLE, NO_COMPLETER); XtAddCallback(w_id, XmNlosingFocusCallback, id_check_callback, NULL); XtAddCallback(w_id, XmNmodifyVerifyCallback, id_modify_callback, NULL); XmTextSetString(w_id, (char *)"0"); n = 0; XtSetArg(args[n], XmNbackground, ss->basic_color); n++; w_beg = make_textfield_widget("mix-times", mix_row, args, n, ACTIVATABLE, NO_COMPLETER); XmTextSetString(w_beg, (char *)"0.000 : 1.000"); XtVaGetValues(mix_row, XmNforeground, &v.foreground, XmNbackground, &v.background, XmNdepth, &mixer_depth, NULL); gc = XtGetGC(mix_row, GCForeground | GCBackground, &v); speaker_r = make_pixmap(p_speaker_bits, p_speaker_width, p_speaker_height, mixer_depth, gc); #if WITH_AUDIO n = 0; XtSetArg(args[n], XmNbackground, ss->highlight_color); n++; XtSetArg(args[n], XmNlabelType, XmPIXMAP); n++; XtSetArg(args[n], XmNlabelPixmap, speaker_r); n++; XtSetArg(args[n], XmNarmColor, ss->selection_color); n++; mix_play = XtCreateManagedWidget("mix-play", xmPushButtonWidgetClass, mix_row, args, n); XtAddCallback(mix_play, XmNactivateCallback, mix_dialog_play_callback, NULL); #endif n = 0; XtSetArg(args[n], XmNbackground, ss->highlight_color); n++; XtSetArg(args[n], XmNarmColor, ss->selection_color); n++; mix_previous_button = XtCreateManagedWidget(I_PREVIOUS, xmPushButtonWidgetClass, mix_row, args, n); if (previous_mix_id(mix_dialog_id) == INVALID_MIX_ID) set_sensitive(mix_previous_button, false); XtAddCallback(mix_previous_button, XmNactivateCallback, mix_previous_callback, NULL); n = 0; XtSetArg(args[n], XmNbackground, ss->highlight_color); n++; XtSetArg(args[n], XmNarmColor, ss->selection_color); n++; mix_next_button = XtCreateManagedWidget(I_NEXT, xmPushButtonWidgetClass, mix_row, args, n); if (next_mix_id(mix_dialog_id) == INVALID_MIX_ID) set_sensitive(mix_next_button, false); XtAddCallback(mix_next_button, XmNactivateCallback, mix_next_callback, NULL); /* separator before sliders */ n = 0; XtSetArg(args[n], XmNbackground, ss->basic_color); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNtopWidget, mix_row); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNorientation, XmHORIZONTAL); n++; XtSetArg(args[n], XmNheight, 10); n++; XtSetArg(args[n], XmNseparatorType, XmNO_LINE); n++; sep = XtCreateManagedWidget("mix-dialog-sep", xmSeparatorWidgetClass, mainform, args, n); /* SPEED */ n = 0; s1 = XmStringCreateLocalized((char *)"speed:"); XtSetArg(args[n], XmNbackground, ss->basic_color); n++; XtSetArg(args[n], XmNalignment, XmALIGNMENT_BEGINNING); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNtopWidget, sep); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNlabelString, s1); n++; XtSetArg(args[n], XmNrecomputeSize, false); n++; XtSetArg(args[n], XmNshadowThickness, 0); n++; XtSetArg(args[n], XmNhighlightThickness, 0); n++; XtSetArg(args[n], XmNfillOnArm, false); n++; w_speed_label = make_pushbutton_widget("mix-speed-label", mainform, args, n); XtAddCallback(w_speed_label, XmNactivateCallback, mix_speed_click_callback, NULL); XmStringFree(s1); n = 0; s1 = initial_speed_label(xmix_speed_control_style); XtSetArg(args[n], XmNbackground, ss->basic_color); n++; XtSetArg(args[n], XmNalignment, XmALIGNMENT_BEGINNING); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_OPPOSITE_WIDGET); n++; XtSetArg(args[n], XmNtopWidget, w_speed_label); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNleftWidget, w_speed_label); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNlabelString, s1); n++; XtSetArg(args[n], XmNrecomputeSize, false); n++; XtSetArg(args[n], XmNshadowThickness, 0); n++; XtSetArg(args[n], XmNhighlightThickness, 0); n++; XtSetArg(args[n], XmNfillOnArm, false); n++; w_speed_number = make_pushbutton_widget("mix-speed-number", mainform, args, n); XtAddCallback(w_speed_number, XmNactivateCallback, mix_speed_label_click_callback, NULL); XmStringFree(s1); n = 0; XtSetArg(args[n], XmNbackground, ss->position_color); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_OPPOSITE_WIDGET); n++; XtSetArg(args[n], XmNtopWidget, w_speed_number); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNleftWidget, w_speed_number); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNorientation, XmHORIZONTAL); n++; XtSetArg(args[n], XmNmaximum, SCROLLBAR_MAX); n++; XtSetArg(args[n], XmNvalue, speed_to_scrollbar(speed_control_min(ss), 1.0, speed_control_max(ss))); n++; XtSetArg(args[n], XmNheight, 16); n++; XtSetArg(args[n], XmNdragCallback, n1 = make_callback_list(mix_speed_drag_callback, NULL)); n++; XtSetArg(args[n], XmNvalueChangedCallback, n2 = make_callback_list(mix_speed_valuechanged_callback, NULL)); n++; w_speed = XtCreateManagedWidget("mix-speed", xmScrollBarWidgetClass, mainform, args, n); free(n1); free(n2); n = 0; snprintf(amplab, LABEL_BUFFER_SIZE, "%s", "amp:"); s1 = XmStringCreateLocalized(amplab); XtSetArg(args[n], XmNbackground, ss->basic_color); n++; XtSetArg(args[n], XmNalignment, XmALIGNMENT_BEGINNING); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNtopWidget, w_speed_label); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNlabelString, s1); n++; XtSetArg(args[n], XmNrecomputeSize, false); n++; XtSetArg(args[n], XmNshadowThickness, 0); n++; XtSetArg(args[n], XmNhighlightThickness, 0); n++; XtSetArg(args[n], XmNfillOnArm, false); n++; w_amp_label = make_pushbutton_widget("mix-amp-label", mainform, args, n); XtAddCallback(w_amp_label, XmNactivateCallback, mix_amp_click_callback, NULL); XmStringFree(s1); n = 0; s1 = XmStringCreateLocalized((char *)"1.00"); XtSetArg(args[n], XmNbackground, ss->basic_color); n++; XtSetArg(args[n], XmNalignment, XmALIGNMENT_BEGINNING); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNtopWidget, w_speed_number); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNleftWidget, w_amp_label); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNlabelString, s1); n++; XtSetArg(args[n], XmNrecomputeSize, false); n++; w_amp_number = XtCreateManagedWidget("mix-amp-number", xmLabelWidgetClass, mainform, args, n); XmStringFree(s1); n = 0; XtSetArg(args[n], XmNbackground, ss->position_color); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_OPPOSITE_WIDGET); n++; XtSetArg(args[n], XmNtopWidget, w_amp_number); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNleftWidget, w_amp_number); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNorientation, XmHORIZONTAL); n++; XtSetArg(args[n], XmNmaximum, SCROLLBAR_MAX); n++; XtSetArg(args[n], XmNvalue, 0); n++; XtSetArg(args[n], XmNdragCallback, n1 = make_callback_list(mix_amp_drag_callback, NULL)); n++; XtSetArg(args[n], XmNvalueChangedCallback, n2 = make_callback_list(mix_amp_valuechanged_callback, NULL)); n++; w_amp = XtCreateManagedWidget("mix-amp", xmScrollBarWidgetClass, mainform, args, n); free(n1); free(n2); /* separator before envelopes */ n = 0; XtSetArg(args[n], XmNbackground, ss->basic_color); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNtopWidget, w_amp_label); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNorientation, XmHORIZONTAL); n++; XtSetArg(args[n], XmNheight, 8); n++; XtSetArg(args[n], XmNseparatorType, XmNO_LINE); n++; w_sep1 = XtCreateManagedWidget("mix-dialog-sep1", xmSeparatorWidgetClass, mainform, args, n); /* button box for dB clip wave sync */ n = 0; XtSetArg(args[n], XmNbackground, ss->basic_color); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNtopWidget, w_sep1); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNshadowType, XmSHADOW_ETCHED_IN); n++; XtSetArg(args[n], XmNshadowThickness, 4); n++; w_dB_frame = XtCreateManagedWidget("mix-dB-frame", xmFrameWidgetClass, mainform, args, n); n = 0; XtSetArg(args[n], XmNbackground, ss->highlight_color); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++; w_dB_row = XtCreateManagedWidget("mix-dB-row", xmRowColumnWidgetClass, w_dB_frame, args, n); n = 0; XtSetArg(args[n], XmNbackground, ss->highlight_color); n++; XtSetArg(args[n], XmNselectColor, ss->selection_color); n++; if (ss->toggle_size > 0) {XtSetArg(args[n], XmNindicatorSize, ss->toggle_size); n++;} w_clip = make_togglebutton_widget("clip", w_dB_row, args, n); XtAddCallback(w_clip, XmNvalueChangedCallback, mix_clip_callback, NULL); XmToggleButtonSetState(w_clip, true, false); w_wave = make_togglebutton_widget("wave", w_dB_row, args, n); XtAddCallback(w_wave, XmNvalueChangedCallback, mix_wave_callback, NULL); w_dB = make_togglebutton_widget("dB", w_dB_row, args, n); XtAddCallback(w_dB, XmNvalueChangedCallback, mix_dB_callback, NULL); if (mix_sync_from_id(mix_dialog_id) != 0) {XtSetArg(args[n], XmNset, true); n++;} w_sync = make_togglebutton_widget("sync", w_dB_row, args, n); XtAddCallback(w_sync, XmNvalueChangedCallback, mix_sync_callback, NULL); n = 0; XtSetArg(args[n], XmNbackground, ss->basic_color); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNallowResize, true); n++; XtSetArg(args[n], XmNshadowType, XmSHADOW_ETCHED_IN); n++; XtSetArg(args[n], XmNshadowThickness, 2); n++; error_frame = XtCreateManagedWidget("error-frame", xmFrameWidgetClass, mainform, args, n); n = 0; XtSetArg(args[n], XmNbackground, ss->highlight_color); n++; error_label = XtCreateManagedWidget("", xmLabelWidgetClass, error_frame, args, n); /* amp env */ n = 0; XtSetArg(args[n], XmNbackground, ss->basic_color); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNtopWidget, w_sep1); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_POSITION); n++; XtSetArg(args[n], XmNleftPosition, 4); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNrightWidget, w_dB_frame); n++; XtSetArg(args[n], XmNallowResize, true); n++; XtSetArg(args[n], XmNshadowType, XmSHADOW_ETCHED_IN); n++; XtSetArg(args[n], XmNshadowThickness, 4); n++; w_env_frame = XtCreateManagedWidget("mix-amp-env-frame", xmFrameWidgetClass, mainform, args, n); n = 0; XtSetArg(args[n], XmNbackground, ss->highlight_color); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNallowResize, true); n++; w_env = XtCreateManagedWidget("mix-amp-env-window", xmDrawingAreaWidgetClass, w_env_frame, args, n); XtManageChild(mix_dialog); XtAddCallback(w_env, XmNresizeCallback, mix_amp_env_resize, NULL); XtAddCallback(w_env, XmNexposeCallback, mix_amp_env_resize, NULL); spf = new_env_editor(); XtAddEventHandler(w_env, ButtonPressMask, false, mix_drawer_button_press, NULL); XtAddEventHandler(w_env, ButtonMotionMask, false, mix_drawer_button_motion, NULL); XtAddEventHandler(w_env, ButtonReleaseMask, false, mix_drawer_button_release, NULL); set_dialog_widget(MIX_DIALOG, mix_dialog); XtUnmanageChild(error_frame); } else { if (!(XtIsManaged(mix_dialog))) XtManageChild(mix_dialog); raise_dialog(mix_dialog); } reflect_mix_change(mix_dialog_id); return(mix_dialog); } void reflect_mix_change(int mix_id) { if ((mix_dialog) && (XtIsManaged(mix_dialog))) { if (mix_id != ANY_MIX_ID) mix_dialog_id = mix_id; if (!(mix_exists(mix_dialog_id))) { mix_dialog_id = any_mix_id(); mix_id = mix_dialog_id; } if ((mix_id == mix_dialog_id) || (mix_id == ANY_MIX_ID)) { mus_float_t val; set_sensitive(mix_next_button, (next_mix_id(mix_dialog_id) != INVALID_MIX_ID)); set_sensitive(mix_previous_button, (previous_mix_id(mix_dialog_id) != INVALID_MIX_ID)); /* now reflect current mix state in mix dialog controls */ if (mix_exists(mix_dialog_id)) { chan_info *cp = NULL; mus_long_t beg, len; char lab[LABEL_BUFFER_SIZE]; /* syncd mixes have the same color (red) reverting to old color when sync changes */ cp = mix_chan_info_from_id(mix_dialog_id); if (old_mix_dialog_id != INVALID_MIX_ID) { mix_unset_color_from_id(old_mix_dialog_id); syncd_mix_unset_color(old_mix_dialog_id); } old_mix_dialog_id = mix_dialog_id; mix_set_color_from_id(mix_dialog_id, ss->red); syncd_mix_set_color(mix_dialog_id, ss->red); for_each_normal_chan(display_channel_mixes); if (!dragging) { val = mix_speed_from_id(mix_dialog_id); XtVaSetValues(w_speed, XmNvalue, speed_to_scrollbar(speed_control_min(ss), val, speed_control_max(ss)), NULL); speed_changed(val, lab, xmix_speed_control_style, speed_control_tones(ss), 6); set_label(w_speed_number, lab); } widget_mix_to_text(w_id, mix_dialog_id); beg = mix_position_from_id(mix_dialog_id); len = mix_length_from_id(mix_dialog_id); snprintf(lab, LABEL_BUFFER_SIZE, "%.3f : %.3f%s", ((double)beg / (double)snd_srate(cp->sound)), ((double)(beg + len) / (double)snd_srate(cp->sound)), (mix_is_active(mix_dialog_id)) ? "" : " (locked)"); XmTextSetString(w_beg, lab); set_sensitive(XmMessageBoxGetChild(mix_dialog, XmDIALOG_OK_BUTTON), true); } else { XmTextSetString(w_id, (char *)"-1"); XmTextSetString(w_beg, (char *)"no active mixes"); set_sensitive(XmMessageBoxGetChild(mix_dialog, XmDIALOG_OK_BUTTON), false); } if (!dragging) { if (mix_is_active(mix_dialog_id)) val = mix_amp_from_id(mix_dialog_id); else val = 1.0; XtVaSetValues(w_amp, XmNvalue, amp_to_scrollbar(w_amp_number, val), NULL); } if (mix_amp_env_from_id(mix_dialog_id)) { if (dialog_env) free_env(dialog_env); dialog_env = copy_env(mix_amp_env_from_id(mix_dialog_id)); } /* copy here else we're editing it directly afterwards (and we free old in mix_set_amp_env_edit) */ if (!dialog_env) dialog_env = default_env(1.0, 1.0); mix_amp_env_resize(w_env, NULL, NULL); set_toggle_button(w_sync, (mix_sync_from_id(mix_dialog_id) != 0), false, NULL); } } } int mix_dialog_mix(void) { return(mix_dialog_id); } void mix_dialog_set_mix(int id) { mix_dialog_id = id; reflect_mix_change(mix_dialog_id); } /* envelope editor and viewer */ static Widget enved_dialog = NULL; static Widget apply_button, apply2_button, cancel_button, drawer, show_button, save_button, revert_button, undo_button, redo_button; static Widget brkptL, graph_button, flt_button, amp_button, src_button, clip_button; static Widget nameL, textL, screnvlst, dB_button, orderL, reset_button, fir_button = NULL; static Widget baseScale, baseValue, selection_button; static GC gc1, rgc, ggc; static const char *env_names[3] = {"amp env:", "flt env:", "src env:"}; static bool showing_all_envs = false; /* edit one env (0), or view all currently defined envs (1) */ static bool apply_to_selection = false, we_turned_selection_off = false; static int env_window_width = 0; static int env_window_height = 0; static chan_info *active_channel = NULL, *last_active_channel = NULL; static env* selected_env = NULL; /* if during view, one env is clicked, it is "selected" and can be pasted elsewhere */ static env* active_env = NULL; /* env currently being edited */ static axis_info *axis = NULL; static axis_info *gray_ap = NULL; static bool is_FIR = true; static bool old_clipping = false; static bool ignore_button_release = false; static bool cancelling = true; static void fixup_graphics_context(graphics_context *ax, Widget w, GC gc) { ax->dp = XtDisplay(w); ax->wn = XtWindow(w); if (gc) ax->gc = gc; } axis_info *enved_make_axis(const char *name, graphics_context *ax, int ex0, int ey0, int width, int height, mus_float_t xmin, mus_float_t xmax, mus_float_t ymin, mus_float_t ymax, printing_t printing) { /* conjure up minimal context for axis drawer in snd-axis.c */ if (!axis) { axis = (axis_info *)calloc(1, sizeof(axis_info)); axis->ax = (graphics_context *)calloc(1, sizeof(graphics_context)); fixup_graphics_context(axis->ax, drawer, ax->gc); } if (!gray_ap) { gray_ap = (axis_info *)calloc(1, sizeof(axis_info)); gray_ap->ax = (graphics_context *)calloc(1, sizeof(graphics_context)); gray_ap->graph_active = true; fixup_graphics_context(gray_ap->ax, drawer, ggc); } init_env_axes(axis, name, ex0, ey0, width, height, xmin, xmax, ymin, ymax, printing); return(axis); } static void display_env(env *e, const char *name, GC cur_gc, int x0, int y0, int width, int height, bool dots, printing_t printing) { graphics_context *ax = NULL; ax = (graphics_context *)calloc(1, sizeof(graphics_context)); ax->wn = XtWindow(drawer); if (!(ax->wn)) {free(ax); return;} ax->dp = XtDisplay(drawer); ax->gc = cur_gc; ss->enved->with_dots = dots; env_editor_display_env(ss->enved, e, ax, name, x0, y0, width, height, printing); free(ax); } void display_enved_env_with_selection(env *e, const char *name, int x0, int y0, int width, int height, bool dots, printing_t printing) { display_env(e, name, (selected_env == e) ? rgc : gc1, x0, y0, width, height, dots, printing); } static void reflect_segment_state(void) { if ((enved_dialog) && (active_env) && (!(showing_all_envs))) env_redisplay(); } static void prepare_env_edit(env *new_env) { prepare_enved_edit(new_env); if (new_env->base == 1.0) set_enved_style(ENVELOPE_LINEAR); else { set_enved_base(new_env->base); set_enved_style(ENVELOPE_EXPONENTIAL); } reflect_segment_state(); } void set_enved_redo_sensitive(bool val) {set_sensitive(redo_button, val);} void set_enved_revert_sensitive(bool val) {set_sensitive(revert_button, val);} void set_enved_undo_sensitive(bool val) {set_sensitive(undo_button, val);} void set_enved_save_sensitive(bool val) {set_sensitive(save_button, val);} void set_enved_show_sensitive(bool val) {set_sensitive(show_button, val);} static bool use_listener_font = false; void make_scrolled_env_list(void) { XmString *strs; int n, size; size = enved_all_envs_top(); XtVaSetValues(screnvlst, XmNbackground, ss->highlight_color, NULL); strs = (XmString *)calloc(size, sizeof(XmString)); for (n = 0; n < size; n++) strs[n] = XmStringCreate(enved_all_names(n), (char *)((use_listener_font) ? "listener_font" : XmFONTLIST_DEFAULT_TAG)); XtVaSetValues(screnvlst, XmNitems, strs, XmNitemCount, size, NULL); for (n = 0; n < size; n++) XmStringFree(strs[n]); free(strs); } void enved_reflect_peak_env_completion(snd_info *sp) { if ((enved_dialog) && (active_channel) && (enved_with_wave(ss))) if (active_channel->sound == sp) env_redisplay(); } void new_active_channel_alert(void) { if (enved_dialog) { /* if showing current active channel in gray, update */ active_channel = current_channel(); env_redisplay(); } } static void dismiss_enved_callback(Widget w, XtPointer context, XtPointer info) { if (!cancelling) { if (ss->checking_explicitly) ss->stopped_explicitly = true; } else XtUnmanageChild(enved_dialog); } static void help_enved_callback(Widget w, XtPointer context, XtPointer info) { envelope_editor_dialog_help(); } static bool within_selection_src = false; static void apply_enved(void) { if (active_env) { active_channel = current_channel(); if (active_channel) { int i, j; char *origin = NULL, *estr = NULL; env *max_env = NULL; set_sensitive(apply_button, false); set_sensitive(apply2_button, false); set_button_label(cancel_button, I_STOP); cancelling = false; check_for_event(); switch (enved_target(ss)) { case ENVED_AMPLITUDE: #if HAVE_FORTH origin = mus_format("%s%s %s drop", estr = env_to_string(active_env), (apply_to_selection) ? "" : " 0 " PROC_FALSE, (apply_to_selection) ? S_env_selection : S_env_channel); #else origin = mus_format("%s" PROC_OPEN "%s%s", to_proc_name((apply_to_selection) ? S_env_selection : S_env_channel), estr = env_to_string(active_env), (apply_to_selection) ? "" : PROC_SEP "0" PROC_SEP PROC_FALSE); #endif apply_env(active_channel, active_env, 0, current_samples(active_channel), apply_to_selection, origin, NULL, C_int_to_Xen_integer(AT_CURRENT_EDIT_POSITION), 0); /* calls update_graph, I think, but in short files that doesn't update the amp-env */ if (estr) free(estr); if (origin) free(origin); break; case ENVED_SPECTRUM: #if HAVE_FORTH origin = mus_format("%s %d%s %s drop", estr = env_to_string(active_env), enved_filter_order(ss), (apply_to_selection) ? "" : " 0 " PROC_FALSE, (apply_to_selection) ? S_filter_selection : S_filter_channel); #else origin = mus_format("%s" PROC_OPEN "%s" PROC_SEP "%d%s", to_proc_name((apply_to_selection) ? S_filter_selection : S_filter_channel), estr = env_to_string(active_env), enved_filter_order(ss), (apply_to_selection) ? "" : PROC_SEP "0" PROC_SEP PROC_FALSE); #endif apply_filter(active_channel, (is_FIR) ? enved_filter_order(ss) : 0, active_env, origin, NULL, apply_to_selection, NULL, NULL, C_int_to_Xen_integer(AT_CURRENT_EDIT_POSITION), 0, false); if (estr) free(estr); if (origin) free(origin); break; case ENVED_SRATE: /* mus_src no longer protects against 0 srate */ max_env = copy_env(active_env); for (i = 0, j = 1; i < max_env->pts; i++, j += 2) if (max_env->data[j] < .01) max_env->data[j] = .01; within_selection_src = true; src_env_or_num(active_channel, max_env, 0.0, false, "Enved: src", apply_to_selection, NULL, C_int_to_Xen_integer(AT_CURRENT_EDIT_POSITION), 0); within_selection_src = false; max_env = free_env(max_env); break; } if (enved_with_wave(ss)) env_redisplay(); set_sensitive(apply_button, true); set_sensitive(apply2_button, true); set_button_label(cancel_button, I_GO_AWAY); cancelling = true; } } } static void env_redisplay_1(printing_t printing) { if (enved_dialog_is_active()) { XClearWindow(XtDisplay(drawer), XtWindow(drawer)); if (showing_all_envs) view_envs(env_window_width, env_window_height, printing); else { char *name = NULL; name = XmTextGetString(textL); if (!name) name = mus_strdup("noname"); /* active_env can be null here if just showing axes (empty initial graph) */ if ((enved_with_wave(ss)) && (active_channel) && (!(active_channel->squelch_update))) { if ((enved_target(ss) == ENVED_SPECTRUM) && (active_env) && (is_FIR) && (printing == NOT_PRINTING)) display_frequency_response(active_env, axis, gray_ap->ax, enved_filter_order(ss), enved_in_dB(ss)); enved_show_background_waveform(axis, gray_ap, apply_to_selection, (enved_target(ss) == ENVED_SPECTRUM), printing); } display_env(active_env, name, gc1, 0, 0, env_window_width, env_window_height, true, printing); if (name) XtFree(name); } } } void env_redisplay(void) { env_redisplay_1(NOT_PRINTING); } void env_redisplay_with_print(void) { env_redisplay_1(PRINTING); } void update_enved_background_waveform(chan_info *cp) { if ((enved_dialog_is_active()) && (enved_with_wave(ss)) && (enved_target(ss) == ENVED_AMPLITUDE) && (cp == active_channel) && ((!apply_to_selection) || (selection_is_active_in_channel(cp)))) env_redisplay(); } static void enved_reset(void) { set_enved_clipping(DEFAULT_ENVED_CLIPPING); set_enved_style(ENVELOPE_LINEAR); set_enved_power(DEFAULT_ENVED_POWER); set_enved_base(DEFAULT_ENVED_BASE); set_enved_target(DEFAULT_ENVED_TARGET); set_enved_with_wave(DEFAULT_ENVED_WITH_WAVE); set_enved_in_dB(DEFAULT_ENVED_IN_DB); XmTextSetString(textL, NULL); set_enved_filter_order(DEFAULT_ENVED_FILTER_ORDER); if (active_env) active_env = free_env(active_env); #if HAVE_SCHEME active_env = string_to_env("'(0 0 1 0)"); #endif #if HAVE_FORTH active_env = string_to_env("'( 0 0 1 0 )"); #endif #if HAVE_RUBY active_env = string_to_env("[0, 0, 1, 0]"); #endif set_enved_env_list_top(0); prepare_env_edit(active_env); set_sensitive(save_button, true); reflect_enved_style(); env_redisplay(); } static void clear_point_label(void); static void clear_xenv_error(void) { if (brkptL) clear_point_label(); } static void unpost_xenv_error(XtPointer data, XtIntervalId *id) { clear_xenv_error(); } static void errors_to_xenv_text(const char *msg, void *data) { set_button_label(brkptL, msg); XtAppAddTimeOut(main_app(ss), 5000, (XtTimerCallbackProc)unpost_xenv_error, NULL); } static void order_field_activated(void) { /* return in order text field */ char *str = NULL; str = XmTextGetString(orderL); if ((str) && (*str)) { int order; redirect_errors_to(errors_to_xenv_text, NULL); order = string_to_int(str, 1, "order"); redirect_errors_to(NULL, NULL); if (order & 1) order++; if ((order > 0) && (order < 2000)) set_enved_filter_order(order); else widget_int_to_text(orderL, enved_filter_order(ss)); } if (str) XtFree(str); } static void text_field_activated(void) { /* might be breakpoints to load or an envelope name ( in enved text field) */ char *name = NULL; name = XmTextGetString(textL); if ((name) && (*name)) { char *str; env *e = NULL; str = name; while (isspace((int)(*str))) str++; e = name_to_env(str); if (!e) { if (isalpha((int)(str[0]))) { alert_envelope_editor(str, copy_env(active_env)); add_or_edit_symbol(str, active_env); set_sensitive(save_button, false); env_redisplay(); /* updates label */ /* e is null here */ } else { redirect_errors_to(errors_to_xenv_text, NULL); e = string_to_env(str); redirect_errors_to(NULL, NULL); } } if (e) { if (active_env) { #define ENVED_TEMP_NAME "enved-backup" /* save current under a temp name! -- user might have mistakenly reused a name */ alert_envelope_editor((char *)ENVED_TEMP_NAME, copy_env(active_env)); add_or_edit_symbol(ENVED_TEMP_NAME, active_env); active_env = free_env(active_env); } active_env = copy_env(e); set_enved_env_list_top(0); prepare_env_edit(active_env); set_sensitive(save_button, true); set_sensitive(undo_button, false); set_sensitive(revert_button, false); env_redisplay(); e = free_env(e); } } if (name) XtFree(name); } static void enved_text_activate_callback(Widget w, XtPointer context, XtPointer info) { text_field_activated(); } static void order_activate_callback(Widget w, XtPointer context, XtPointer info) { order_field_activated(); } static void save_button_pressed(Widget w, XtPointer context, XtPointer info) { char *name = NULL; if (!active_env) return; name = XmTextGetString(textL); if ((!name) || (!(*name))) name = mus_strdup("unnamed"); alert_envelope_editor(name, copy_env(active_env)); add_or_edit_symbol(name, active_env); set_sensitive(save_button, false); env_redisplay(); if (name) XtFree(name); } static void apply_enved_callback(Widget w, XtPointer context, XtPointer info) { /* apply current envs to currently sync'd channels */ Widget active_widget; active_widget = XmGetFocusWidget(enved_dialog); if (active_widget == XmMessageBoxGetChild(enved_dialog, XmDIALOG_OK_BUTTON)) { apply_enved(); last_active_channel = active_channel; } } static void undo_and_apply_enved_callback(Widget w, XtPointer context, XtPointer info) { /* undo previous amp env, then apply */ /* this blindly undoes the previous edit (assumed to be an envelope) -- if the user made some other change in the meantime, too bad */ if ((active_channel) && (active_channel == last_active_channel)) { active_channel->squelch_update = true; undo_edit_with_sync(active_channel, 1); active_channel->squelch_update = false; clear_status_area(active_channel->sound); } apply_enved(); last_active_channel = active_channel; } static void select_or_edit_env(int pos) { if (showing_all_envs) { showing_all_envs = false; set_button_label(show_button, "view envs"); } if (active_env) active_env = free_env(active_env); selected_env = position_to_env(pos); if (!selected_env) return; active_env = selected_env; XmTextSetString(textL, enved_all_names(pos)); set_enved_env_list_top(0); prepare_env_edit(active_env); set_sensitive(undo_button, false); set_sensitive(revert_button, false); set_sensitive(save_button, false); env_redisplay(); } static void clear_point_label(void) { XtVaSetValues(brkptL, XmNlabelType, XmSTRING, XmNlabelString, NULL, NULL); } static void enved_display_point_label(mus_float_t x, mus_float_t y) { char brkpt_buf[LABEL_BUFFER_SIZE]; if ((enved_in_dB(ss)) && (min_dB(ss) < -60)) snprintf(brkpt_buf, LABEL_BUFFER_SIZE, "%.3f : %.5f", x, y); else snprintf(brkpt_buf, LABEL_BUFFER_SIZE, "%.3f : %.3f", x, y); set_button_label(brkptL, brkpt_buf); } static void drawer_button_motion(Widget w, XtPointer context, XEvent *event, Boolean *cont) { XMotionEvent *ev = (XMotionEvent *)event; ignore_button_release = false; if (!showing_all_envs) { mus_float_t x, y; #ifdef __APPLE__ if ((ev->x == press_x) && (ev->y == press_y)) return; #endif env_editor_button_motion_with_xy(ss->enved, ev->x, ev->y, ev->time, active_env, &x, &y); enved_display_point_label(x, y); env_redisplay(); } } static void drawer_button_press(Widget w, XtPointer context, XEvent *event, Boolean *cont) { XButtonEvent *ev = (XButtonEvent *)event; #ifdef __APPLE__ press_x = ev->x; press_y = ev->y; #endif ss->enved->down_time = ev->time; ss->enved->env_dragged = false; if (showing_all_envs) { int pos; pos = hit_env(ev->x, ev->y, env_window_width, env_window_height); XmListSelectPos(screnvlst, pos + 1, false); if ((pos >= 0) && (pos < enved_all_envs_top())) { select_or_edit_env(pos); ignore_button_release = true; } } else { if (!active_env) { active_env = default_env(1.0, 0.0); active_env->base = enved_base(ss); env_redisplay(); /* needed to get current_xs set up correctly */ } if (env_editor_button_press(ss->enved, ev->x, ev->y, ev->time, active_env)) env_redisplay(); enved_display_point_label(ungrf_x(ss->enved->axis, ev->x), env_editor_ungrf_y_dB(ss->enved, ev->y)); set_sensitive(save_button, true); set_sensitive(undo_button, true); set_sensitive(revert_button, true); } } static void drawer_button_release(Widget w, XtPointer context, XEvent *event, Boolean *cont) { if (ignore_button_release) ignore_button_release = false; else { if ((active_env) && (!showing_all_envs)) { env_editor_button_release(ss->enved, active_env); env_redisplay(); clear_point_label(); } } } static void drawer_resize(Widget w, XtPointer context, XtPointer info) { /* update display, can be either view of all envs or sequence of current envs */ env_window_width = widget_width(w); env_window_height = widget_height(w); env_redisplay(); } static void show_button_pressed(Widget w, XtPointer context, XtPointer info) { /* if show all (as opposed to show current), loop through loaded LV_LISTs */ showing_all_envs = (!showing_all_envs); set_button_label(show_button, (showing_all_envs) ? "edit env" : "view envs"); env_redisplay(); } static void selection_button_pressed(Widget s, XtPointer context, XtPointer info) { we_turned_selection_off = false; apply_to_selection = (!apply_to_selection); XmChangeColor(selection_button, (apply_to_selection) ? ((Pixel)ss->yellow) : ((Pixel)ss->highlight_color)); set_sensitive(apply2_button, true); if ((enved_with_wave(ss)) && (!showing_all_envs)) env_redisplay(); } static void revert_button_pressed(Widget w, XtPointer context, XtPointer info) { revert_env_edit(); if (active_env) active_env = free_env(active_env); active_env = enved_next_env(); if (!active_env) text_field_activated(); env_redisplay(); } static void undo_button_pressed(Widget w, XtPointer context, XtPointer info) { undo_env_edit(); if (active_env) active_env = free_env(active_env); active_env = enved_next_env(); env_redisplay(); } static void redo_button_pressed(Widget w, XtPointer context, XtPointer info) { redo_env_edit(); if (active_env) active_env = free_env(active_env); active_env = enved_next_env(); env_redisplay(); } static void reflect_apply_state(void) { set_label(nameL, env_names[enved_target(ss)]); XmChangeColor(amp_button, (enved_target(ss) == ENVED_AMPLITUDE) ? ((Pixel)ss->yellow) : ((Pixel)ss->highlight_color)); XmChangeColor(flt_button, (enved_target(ss) == ENVED_SPECTRUM) ? ((Pixel)ss->yellow) : ((Pixel)ss->highlight_color)); XmChangeColor(src_button, (enved_target(ss) == ENVED_SRATE) ? ((Pixel)ss->yellow) : ((Pixel)ss->highlight_color)); if ((!showing_all_envs) && (enved_with_wave(ss))) env_redisplay(); } static void freq_button_callback(Widget w, XtPointer context, XtPointer info) { in_set_enved_target(ENVED_SPECTRUM); old_clipping = enved_clipping(ss); set_enved_clipping(true); reflect_apply_state(); } static void amp_button_callback(Widget w, XtPointer context, XtPointer info) { if (enved_target(ss) == ENVED_SPECTRUM) set_enved_clipping(old_clipping); in_set_enved_target(ENVED_AMPLITUDE); reflect_apply_state(); } static void src_button_callback(Widget w, XtPointer context, XtPointer info) { if (enved_target(ss) == ENVED_SPECTRUM) set_enved_clipping(old_clipping); in_set_enved_target(ENVED_SRATE); reflect_apply_state(); } static void reset_button_callback(Widget w, XtPointer context, XtPointer info) { enved_reset(); } static void enved_print(char *name) { print_enved(name, env_window_height); } static void env_browse_callback(Widget w, XtPointer context, XtPointer info) { XmListCallbackStruct *cb = (XmListCallbackStruct *)info; select_or_edit_env(cb->item_position - 1); } static void graph_button_callback(Widget w, XtPointer context, XtPointer info) { XmToggleButtonCallbackStruct *cb = (XmToggleButtonCallbackStruct *)info; in_set_enved_with_wave(cb->set); env_redisplay(); } static void dB_button_callback(Widget w, XtPointer context, XtPointer info) { XmToggleButtonCallbackStruct *cb = (XmToggleButtonCallbackStruct *)info; in_set_enved_in_dB(cb->set); env_redisplay(); } static void clip_button_callback(Widget w, XtPointer context, XtPointer info) { XmToggleButtonCallbackStruct *cb = (XmToggleButtonCallbackStruct *)info; in_set_enved_clipping(cb->set); } #define BASE_MAX 400 #define BASE_MID 200 /* these two just set the granularity of the scale widget, not the user-visible bounds */ static void make_base_label(mus_float_t bval) { char *sfs, *buf; int i, len, scale_len; len = (int)(enved_power(ss) * 4); if (len < 32) len = 32; sfs = (char *)calloc(len, sizeof(char)); snprintf(sfs, len, "%.3f", bval); scale_len = (int)(enved_power(ss) + 3); if (scale_len < 32) scale_len = 32; buf = (char *)calloc(scale_len, sizeof(char)); for (i = 0; i < scale_len - 1; i++) buf[i] = sfs[i]; set_button_label(baseValue, buf); free(sfs); free(buf); in_set_enved_base(bval); if ((active_env) && (!(showing_all_envs))) { active_env->base = enved_base(ss); if (active_env->base == 1.0) set_enved_style(ENVELOPE_LINEAR); else set_enved_style(ENVELOPE_EXPONENTIAL); env_redisplay(); } } static void base_changed(int val) { mus_float_t bval; if (val == 0) bval = 0.0; else { if (val == BASE_MID) bval = 1.0; else { if (val > BASE_MID) bval = pow(1.0 + (10.0 * ((mus_float_t)(val - BASE_MID) / (mus_float_t)BASE_MID)), enved_power(ss)); else bval = pow(((mus_float_t)val / (mus_float_t)BASE_MID), enved_power(ss) - 1.0); } } make_base_label(bval); if (active_env) set_sensitive(save_button, true); /* what about undo/redo here? */ } static void reflect_changed_base(mus_float_t val) { int ival; if (val <= 0.0) ival = 0; else { if (val == 1.0) ival = BASE_MID; else { if (val <= 1.0) ival = (int)(pow(val, 1.0 / (enved_power(ss) - 1.0)) * BASE_MID); else ival = (int)(BASE_MID + ((BASE_MID * (pow(val, (1.0 / (enved_power(ss)))) - 1)) / 10.0)); } } XtVaSetValues(baseScale, XmNvalue, mus_iclamp(0, ival, (int)(BASE_MAX * .9)), NULL); make_base_label(val); } static void base_drag_callback(Widget w, XtPointer context, XtPointer info) { XmScrollBarCallbackStruct *sb = (XmScrollBarCallbackStruct *)info; base_changed(sb->value); } static int base_last_value = BASE_MID; static void base_valuechanged_callback(Widget w, XtPointer context, XtPointer info) { XmScrollBarCallbackStruct *sb = (XmScrollBarCallbackStruct *)info; base_last_value = sb->value; base_changed(sb->value); } static void base_click_callback(Widget w, XtPointer context, XtPointer info) { XmPushButtonCallbackStruct *cb = (XmPushButtonCallbackStruct *)info; XButtonEvent *ev; int val; ev = (XButtonEvent *)(cb->event); if (ev->state & (snd_ControlMask | snd_MetaMask)) val = base_last_value; else val = BASE_MID; /* this is supposedly 1.0 */ base_changed(val); XtVaSetValues(baseScale, XmNvalue, val, NULL); } static void FIR_click_callback(Widget w, XtPointer context, XtPointer info) { is_FIR = (!is_FIR); set_label(w, (is_FIR) ? "fir" : "fft"); if (enved_with_wave(ss)) env_redisplay(); } static void reflect_sound_state(void) { bool file_on; file_on = (bool)(any_selected_sound()); set_sensitive(apply_button, file_on); set_sensitive(apply2_button, file_on); } static Xen reflect_file_in_enved(Xen hook_or_reason) { if (enved_dialog) reflect_sound_state(); return(Xen_false); } static void add_reflect_enved_hook(void); Widget create_envelope_editor(void) { if (!enved_dialog) { int n; Arg args[32]; Widget colE, colD, colB, colF; Widget spacer, spacer1, aform, mainform, screnvname, baseSep, baseLabel; XmString xhelp, xdismiss, xapply, titlestr, s1; XGCValues gv; XtCallbackList n1, n2; char str[LABEL_BUFFER_SIZE]; /* -------- DIALOG -------- */ xdismiss = XmStringCreateLocalized((char *)I_GO_AWAY); xhelp = XmStringCreateLocalized((char *)I_HELP); titlestr = XmStringCreateLocalized((char *)"Edit Envelope"); xapply = XmStringCreateLocalized((char *)"Apply"); n = 0; XtSetArg(args[n], XmNbackground, ss->basic_color); n++; XtSetArg(args[n], XmNautoUnmanage, false); n++; XtSetArg(args[n], XmNcancelLabelString, xdismiss); n++; XtSetArg(args[n], XmNhelpLabelString, xhelp); n++; XtSetArg(args[n], XmNokLabelString, xapply); n++; XtSetArg(args[n], XmNdialogTitle, titlestr); n++; XtSetArg(args[n], XmNresizePolicy, XmRESIZE_GROW); n++; XtSetArg(args[n], XmNnoResize, false); n++; XtSetArg(args[n], XmNtransient, false); n++; enved_dialog = XmCreateTemplateDialog(main_shell(ss), (char *)"envelope editor", args, n); XtAddCallback(enved_dialog, XmNcancelCallback, dismiss_enved_callback, NULL); XtAddCallback(enved_dialog, XmNhelpCallback, help_enved_callback, NULL); XtAddCallback(enved_dialog, XmNokCallback, apply_enved_callback, NULL); XmStringFree(xhelp); XmStringFree(xdismiss); XmStringFree(titlestr); XmStringFree(xapply); XtVaSetValues(XmMessageBoxGetChild(enved_dialog, XmDIALOG_CANCEL_BUTTON), XmNarmColor, ss->selection_color, NULL); XtVaSetValues(XmMessageBoxGetChild(enved_dialog, XmDIALOG_HELP_BUTTON), XmNarmColor, ss->selection_color, NULL); XtVaSetValues(XmMessageBoxGetChild(enved_dialog, XmDIALOG_OK_BUTTON), XmNarmColor, ss->selection_color, NULL); XtVaSetValues(XmMessageBoxGetChild(enved_dialog, XmDIALOG_CANCEL_BUTTON), XmNbackground, ss->highlight_color, NULL); XtVaSetValues(XmMessageBoxGetChild(enved_dialog, XmDIALOG_HELP_BUTTON), XmNbackground, ss->highlight_color, NULL); XtVaSetValues(XmMessageBoxGetChild(enved_dialog, XmDIALOG_OK_BUTTON), XmNbackground, ss->highlight_color, NULL); n = 0; XtSetArg(args[n], XmNbackground, ss->highlight_color); n++; XtSetArg(args[n], XmNarmColor, ss->selection_color); n++; apply2_button = XtCreateManagedWidget("Undo&Apply", xmPushButtonGadgetClass, enved_dialog, args, n); XtAddCallback(apply2_button, XmNactivateCallback, undo_and_apply_enved_callback, NULL); n = 0; XtSetArg(args[n], XmNbackground, ss->highlight_color); n++; XtSetArg(args[n], XmNforeground, ss->black); n++; XtSetArg(args[n], XmNarmColor, ss->selection_color); n++; reset_button = XtCreateManagedWidget("Clear graph", xmPushButtonGadgetClass, enved_dialog, args, n); XtAddCallback(reset_button, XmNactivateCallback, reset_button_callback, NULL); /* -------- MAIN WIDGET -------- */ n = 0; XtSetArg(args[n], XmNbackground, ss->basic_color); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNbottomWidget, XmMessageBoxGetChild(enved_dialog, XmDIALOG_SEPARATOR)); n++; mainform = XtCreateManagedWidget("formd", xmFormWidgetClass, enved_dialog, args, n); /* the order in which widgets are defined matters a lot here: * we need to build from the bottom up so that the graph portion expands * when the window is resized (if top-down, the slider at the bottom expands!) */ /* -------- EXP SLIDER AT BOTTOM -------- */ n = 0; XtSetArg(args[n], XmNbackground, ss->basic_color); n++; XtSetArg(args[n], XmNalignment, XmALIGNMENT_BEGINNING); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNrecomputeSize, false); n++; XtSetArg(args[n], XmNshadowThickness, 0); n++; XtSetArg(args[n], XmNhighlightThickness, 0); n++; XtSetArg(args[n], XmNfillOnArm, false); n++; baseLabel = make_pushbutton_widget("exp:", mainform, args, n); XtAddCallback(baseLabel, XmNactivateCallback, base_click_callback, NULL); n = 0; XtSetArg(args[n], XmNbackground, ss->basic_color); n++; s1 = XmStringCreateLocalized((char *)"1.000"); XtSetArg(args[n], XmNalignment, XmALIGNMENT_BEGINNING); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_OPPOSITE_WIDGET); n++; XtSetArg(args[n], XmNtopWidget, baseLabel); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNleftWidget, baseLabel); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_NONE); n++; /* XtSetArg(args[n], XmNrecomputeSize, false); n++; */ XtSetArg(args[n], XmNlabelString, s1); n++; baseValue = XtCreateManagedWidget("base-label", xmLabelWidgetClass, mainform, args, n); XmStringFree(s1); /* -------- filter order -------- */ n = 0; XtSetArg(args[n], XmNbackground, ss->basic_color); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNcolumns, 3); n++; XtSetArg(args[n], XmNrecomputeSize, false); n++; XtSetArg(args[n], XmNheight, 24); n++; XtSetArg(args[n], XmNresizeWidth, false); n++; XtSetArg(args[n], XmNalignment, XmALIGNMENT_BEGINNING); n++; XtSetArg(args[n], XmNmarginHeight, 0); n++; XtSetArg(args[n], XmNmarginBottom, 0); n++; snprintf(str, LABEL_BUFFER_SIZE, "%d", enved_filter_order(ss)); XtSetArg(args[n], XmNvalue, str); n++; orderL = make_textfield_widget("orderL", mainform, args, n, ACTIVATABLE, NO_COMPLETER); XtAddCallback(orderL, XmNactivateCallback, order_activate_callback, NULL); /* -------- fft/fir choice -------- */ n = 0; XtSetArg(args[n], XmNbackground, ss->basic_color); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNrightWidget, orderL); n++; XtSetArg(args[n], XmNrecomputeSize, false); n++; XtSetArg(args[n], XmNshadowThickness, 0); n++; XtSetArg(args[n], XmNhighlightThickness, 0); n++; XtSetArg(args[n], XmNfillOnArm, false); n++; fir_button = make_pushbutton_widget((char *)((is_FIR) ? "fir" : "fft"), mainform, args, n); XtAddCallback(fir_button, XmNactivateCallback, FIR_click_callback, NULL); /* -------- exp base scale -------- */ n = 0; XtSetArg(args[n], XmNbackground, ss->position_color); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_OPPOSITE_WIDGET); n++; XtSetArg(args[n], XmNtopWidget, baseLabel); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNleftWidget, baseValue); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNrightWidget, fir_button); n++; XtSetArg(args[n], XmNorientation, XmHORIZONTAL); n++; XtSetArg(args[n], XmNmaximum, BASE_MAX); n++; XtSetArg(args[n], XmNvalue, BASE_MID); n++; XtSetArg(args[n], XmNincrement, 1); n++; XtSetArg(args[n], XmNpageIncrement, 1); n++; XtSetArg(args[n], XmNdragCallback, n1 = make_callback_list(base_drag_callback, NULL)); n++; XtSetArg(args[n], XmNvalueChangedCallback, n2 = make_callback_list(base_valuechanged_callback, NULL)); n++; baseScale = XtCreateManagedWidget("expscl", xmScrollBarWidgetClass, mainform, args, n); n = 0; XtSetArg(args[n], XmNbackground, ss->basic_color); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNbottomWidget, baseScale); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNmargin, LINE_MARGIN); n++; XtSetArg(args[n], XmNheight, LINE_MARGIN); n++; XtSetArg(args[n], XmNorientation, XmHORIZONTAL); n++; XtSetArg(args[n], XmNseparatorType, XmNO_LINE); n++; XtSetArg(args[n], XmNheight, 5); n++; baseSep = XtCreateManagedWidget("snd-rec-sep", xmSeparatorWidgetClass, mainform, args, n); /* -------- AMP ENV NAME -------- */ n = 0; s1 = XmStringCreateLocalized((char *)"amp env:"); XtSetArg(args[n], XmNbackground, ss->basic_color); n++; XtSetArg(args[n], XmNalignment, XmALIGNMENT_BEGINNING); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNbottomWidget, baseSep); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNlabelString, s1); n++; XtSetArg(args[n], XmNshadowThickness, 0); n++; XtSetArg(args[n], XmNhighlightThickness, 0); n++; nameL = XtCreateManagedWidget("nameL", xmLabelWidgetClass, mainform, args, n); XmStringFree(s1); n = 0; XtSetArg(args[n], XmNbackground, ss->basic_color); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNbottomWidget, baseSep); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNleftWidget, nameL); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_NONE); n++; textL = make_textfield_widget("textL", mainform, args, n, ACTIVATABLE, add_completer_func(env_name_completer, NULL)); XtAddCallback(textL, XmNactivateCallback, enved_text_activate_callback, NULL); /* -------- dB, GRAPH ('wave') AND CLIP BUTTONS -------- */ n = 0; XtSetArg(args[n], XmNbackground, ss->basic_color); n++; XtSetArg(args[n], XmNselectColor, ss->selection_color); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNbottomWidget, baseSep); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++; if (ss->toggle_size > 0) {XtSetArg(args[n], XmNindicatorSize, ss->toggle_size); n++;} dB_button = make_togglebutton_widget("dB", mainform, args, n); XtAddCallback(dB_button, XmNvalueChangedCallback, dB_button_callback, NULL); n = 0; XtSetArg(args[n], XmNbackground, ss->basic_color); n++; XtSetArg(args[n], XmNselectColor, ss->selection_color); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNbottomWidget, baseSep); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNrightWidget, dB_button); n++; if (ss->toggle_size > 0) {XtSetArg(args[n], XmNindicatorSize, ss->toggle_size); n++;} graph_button = make_togglebutton_widget("wave", mainform, args, n); XtAddCallback(graph_button, XmNvalueChangedCallback, graph_button_callback, NULL); n = 0; XtSetArg(args[n], XmNbackground, ss->basic_color); n++; XtSetArg(args[n], XmNselectColor, ss->selection_color); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNbottomWidget, baseSep); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNrightWidget, graph_button); n++; if (ss->toggle_size > 0) {XtSetArg(args[n], XmNindicatorSize, ss->toggle_size); n++;} clip_button = make_togglebutton_widget("clip", mainform, args, n); XtAddCallback(clip_button, XmNvalueChangedCallback, clip_button_callback, NULL); /* -------- BREAKPOINT DATA DISPLAY LABEL -------- */ n = 0; XtSetArg(args[n], XmNbackground, ss->basic_color); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNbottomWidget, baseSep); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNleftWidget, textL); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNrightWidget, clip_button); n++; XtSetArg(args[n], XmNrecomputeSize, false); n++; XtSetArg(args[n], XmNlabelType, XmSTRING); n++; brkptL = XtCreateManagedWidget(" ", xmLabelWidgetClass, mainform, args, n); /* -------- SPACERS TO DIVIDE WINDOW IN TWO -------- */ n = 0; XtSetArg(args[n], XmNbackground, ss->basic_color); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNbottomWidget, textL); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNorientation, XmHORIZONTAL); n++; XtSetArg(args[n], XmNheight, 4); n++; XtSetArg(args[n], XmNseparatorType, XmNO_LINE); n++; spacer = XtCreateManagedWidget("spacer", xmSeparatorWidgetClass, mainform, args, n); n = 0; XtSetArg(args[n], XmNbackground, ss->basic_color); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNbottomWidget, spacer); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNorientation, XmHORIZONTAL); n++; XtSetArg(args[n], XmNseparatorType, XmSHADOW_ETCHED_IN); n++; spacer1 = XtCreateManagedWidget("spacer1", xmSeparatorWidgetClass, mainform, args, n); /* second separator needed because marginTop seems to be broken or non-existent for these widgets */ /* -------- WINDOW LEFT WIDGET HOLDER -------- */ n = 0; XtSetArg(args[n], XmNbackground, ss->basic_color); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNbottomWidget, spacer1); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_NONE); n++; aform = XtCreateManagedWidget("aform", xmFormWidgetClass, mainform, args, n); /* -------- BUTTON BOX AT TOP LEFT -------- */ n = 0; XtSetArg(args[n], XmNbackground, ss->zoom_color); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNshadowThickness, 4); n++; XtSetArg(args[n], XmNshadowType, XmSHADOW_ETCHED_IN); n++; colF = XtCreateManagedWidget("env-button-frame", xmFrameWidgetClass, aform, args, n); n = 0; XtSetArg(args[n], XmNbackground, ss->lighter_blue); n++; colB = XtCreateManagedWidget("env-button-holder", xmFormWidgetClass, colF, args, n); /* VIEW ENVS */ n = 0; XtSetArg(args[n], XmNbackground, ss->highlight_color); n++; XtSetArg(args[n], XmNarmColor, ss->selection_color); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNalignment, XmALIGNMENT_CENTER); n++; show_button = XtCreateManagedWidget("view envs", xmPushButtonWidgetClass, colB, args, n); XtAddCallback(show_button, XmNactivateCallback, show_button_pressed, NULL); /* SAVE PRINT */ n = 0; XtSetArg(args[n], XmNbackground, ss->highlight_color); n++; XtSetArg(args[n], XmNarmColor, ss->selection_color); n++; XtSetArg(args[n], XmNalignment, XmALIGNMENT_CENTER); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNtopWidget, show_button); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++; save_button = XtCreateManagedWidget("define it", xmPushButtonWidgetClass, colB, args, n); XtAddCallback(save_button, XmNactivateCallback, save_button_pressed, NULL); /* REVERT */ n = 0; XtSetArg(args[n], XmNbackground, ss->highlight_color); n++; XtSetArg(args[n], XmNarmColor, ss->selection_color); n++; XtSetArg(args[n], XmNalignment, XmALIGNMENT_CENTER); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNtopWidget, save_button); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++; revert_button = XtCreateManagedWidget("revert", xmPushButtonWidgetClass, colB, args, n); XtAddCallback(revert_button, XmNactivateCallback, revert_button_pressed, NULL); /* UNDO REDO */ n = 0; XtSetArg(args[n], XmNbackground, ss->highlight_color); n++; XtSetArg(args[n], XmNarmColor, ss->selection_color); n++; XtSetArg(args[n], XmNalignment, XmALIGNMENT_CENTER); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNtopWidget, revert_button); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_POSITION); n++; XtSetArg(args[n], XmNrightPosition, 50); n++; undo_button = XtCreateManagedWidget("undo", xmPushButtonWidgetClass, colB, args, n); n = 0; XtSetArg(args[n], XmNbackground, ss->highlight_color); n++; XtSetArg(args[n], XmNarmColor, ss->selection_color); n++; XtSetArg(args[n], XmNalignment, XmALIGNMENT_CENTER); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_OPPOSITE_WIDGET); n++; XtSetArg(args[n], XmNtopWidget, undo_button); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNleftWidget, undo_button); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++; redo_button = XtCreateManagedWidget("redo", xmPushButtonWidgetClass, colB, args, n); XtAddCallback(undo_button, XmNactivateCallback, undo_button_pressed, NULL); XtAddCallback(redo_button, XmNactivateCallback, redo_button_pressed, NULL); /* AMP FLT SRC */ /* enved_function (target) choice (a row of three push buttons that acts like a "radio box") */ n = 0; XtSetArg(args[n], XmNbackground, ss->highlight_color); n++; XtSetArg(args[n], XmNarmColor, ss->yellow); n++; XtSetArg(args[n], XmNalignment, XmALIGNMENT_CENTER); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNtopWidget, undo_button); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_POSITION); n++; XtSetArg(args[n], XmNrightPosition, 33); n++; amp_button = XtCreateManagedWidget("amp", xmPushButtonWidgetClass, colB, args, n); n = 0; XtSetArg(args[n], XmNbackground, ss->highlight_color); n++; XtSetArg(args[n], XmNarmColor, ss->yellow); n++; XtSetArg(args[n], XmNalignment, XmALIGNMENT_CENTER); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_OPPOSITE_WIDGET); n++; XtSetArg(args[n], XmNtopWidget, amp_button); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNleftWidget, amp_button); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_POSITION); n++; XtSetArg(args[n], XmNrightPosition, 67); n++; flt_button = XtCreateManagedWidget("flt", xmPushButtonWidgetClass, colB, args, n); n = 0; XtSetArg(args[n], XmNbackground, ss->highlight_color); n++; XtSetArg(args[n], XmNarmColor, ss->yellow); n++; XtSetArg(args[n], XmNalignment, XmALIGNMENT_CENTER); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_OPPOSITE_WIDGET); n++; XtSetArg(args[n], XmNtopWidget, flt_button); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNleftWidget, flt_button); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++; src_button = XtCreateManagedWidget("src", xmPushButtonWidgetClass, colB, args, n); XtAddCallback(flt_button, XmNactivateCallback, freq_button_callback, NULL); XtAddCallback(amp_button, XmNactivateCallback, amp_button_callback, NULL); XtAddCallback(src_button, XmNactivateCallback, src_button_callback, NULL); /* SELECTION */ n = 0; XtSetArg(args[n], XmNbackground, ss->highlight_color); n++; XtSetArg(args[n], XmNarmColor, ss->selection_color); n++; XtSetArg(args[n], XmNalignment, XmALIGNMENT_CENTER); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNtopWidget, amp_button); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++; selection_button = make_pushbutton_widget("selection", colB, args, n); XtAddCallback(selection_button, XmNactivateCallback, selection_button_pressed, NULL); /* -------- ENV LIST AT LEFT UNDER BUTTONS -------- */ n = 0; XtSetArg(args[n], XmNbackground, ss->highlight_color); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNtopWidget, colF); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNshadowThickness, 4); n++; XtSetArg(args[n], XmNshadowType, XmSHADOW_ETCHED_IN); n++; colE = XtCreateManagedWidget("env-list-frame", xmFrameWidgetClass, aform, args, n); n = 0; XtSetArg(args[n], XmNbackground, ss->highlight_color); n++; colD = XtCreateManagedWidget("env-list-holder", xmFormWidgetClass, colE, args, n); n = 0; XtSetArg(args[n], XmNbackground, ss->basic_color); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++; screnvname = XtCreateManagedWidget("envs:", xmLabelWidgetClass, colD, args, n); n = 0; XtSetArg(args[n], XmNbackground, ss->basic_color); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNtopWidget, screnvname); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++; if (ss->listener_fontlist) { XtSetArg(args[n], XmNfontList, 0); n++; XtSetArg(args[n], XM_FONT_RESOURCE, ss->listener_fontlist); n++; use_listener_font = true; } screnvlst = XmCreateScrolledList(colD, (char *)"scrolled-env-list", args, n); XtManageChild(screnvlst); XtAddCallback(screnvlst, XmNbrowseSelectionCallback, env_browse_callback, NULL); map_over_children(screnvlst, set_main_color_of_widget); if (enved_all_envs_top() > 0) make_scrolled_env_list(); /* -------- MAIN GRAPH -------- */ n = 0; XtSetArg(args[n], XmNbackground, ss->graph_color); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNbottomWidget, spacer1 /* textL */); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNleftWidget, aform); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNheight, 350); n++; XtSetArg(args[n], XmNallowResize, true); n++; drawer = XtCreateManagedWidget("drawer", xmDrawingAreaWidgetClass, mainform, args, n); gv.function = GXcopy; XtVaGetValues(drawer, XmNbackground, &gv.background, XmNforeground, &gv.foreground, NULL); gc1 = XtGetGC(drawer, GCForeground | GCFunction, &gv); gv.foreground = ss->red; rgc = XtGetGC(drawer, GCBackground | GCForeground | GCFunction, &gv); gv.foreground = ss->enved_waveform_color; ggc = XtGetGC(drawer, GCBackground | GCForeground | GCFunction, &gv); XtManageChild(enved_dialog); /* needed so that window is valid when resize callback is invoked */ apply_button = XmMessageBoxGetChild(enved_dialog, XmDIALOG_OK_BUTTON); cancel_button = XmMessageBoxGetChild(enved_dialog, XmDIALOG_CANCEL_BUTTON); cancelling = true; XtAddCallback(drawer, XmNresizeCallback, drawer_resize, NULL); XtAddCallback(drawer, XmNexposeCallback, drawer_resize, NULL); XtAddEventHandler(drawer, ButtonPressMask, false, drawer_button_press, NULL); XtAddEventHandler(drawer, ButtonMotionMask, false, drawer_button_motion, NULL); XtAddEventHandler(drawer, ButtonReleaseMask, false, drawer_button_release, NULL); if (enved_all_envs_top() == 0) set_sensitive(show_button, false); set_sensitive(revert_button, false); set_sensitive(undo_button, false); set_sensitive(redo_button, false); set_sensitive(save_button, false); if (!(selection_is_active())) set_sensitive(selection_button, false); XmToggleButtonSetState(clip_button, (Boolean)(enved_clipping(ss)), false); XmToggleButtonSetState(graph_button, (Boolean)(enved_with_wave(ss)), false); XmToggleButtonSetState(dB_button, (Boolean)(enved_in_dB(ss)), false); free(n1); free(n2); reflect_apply_state(); reflect_segment_state(); reflect_sound_state(); set_dialog_widget(ENVED_DIALOG, enved_dialog); add_reflect_enved_hook(); } else raise_dialog(enved_dialog); if (!XtIsManaged(enved_dialog)) XtManageChild(enved_dialog); active_channel = current_channel(); return(enved_dialog); } void set_enved_clipping(bool val) { in_set_enved_clipping(val); if (enved_dialog) XmToggleButtonSetState(clip_button, (Boolean)val, false); } void reflect_enved_style(void) { reflect_segment_state(); } void set_enved_target(enved_target_t val) { in_set_enved_target(val); if (enved_dialog) reflect_apply_state(); } void set_enved_with_wave(bool val) { in_set_enved_with_wave(val); if (enved_dialog) XmToggleButtonSetState(graph_button, (Boolean)val, false); } void set_enved_in_dB(bool val) { in_set_enved_in_dB(val); if (enved_dialog) XmToggleButtonSetState(dB_button, (Boolean)val, false); } void set_enved_base(mus_float_t val) { in_set_enved_base(val); if (enved_dialog) reflect_changed_base(val); } bool enved_dialog_is_active(void) { return((enved_dialog) && (XtIsManaged(enved_dialog))); } void set_enved_filter_order(int order) { if ((order > 0) && (order < 2000)) { if (order & 1) {in_set_enved_filter_order(order + 1);} else {in_set_enved_filter_order(order);} if (enved_dialog) { widget_int_to_text(orderL, enved_filter_order(ss)); if ((enved_dialog) && (enved_target(ss) == ENVED_SPECTRUM) && (enved_with_wave(ss)) && (!showing_all_envs)) env_redisplay(); } } } void enved_reflect_selection(bool on) { if ((enved_dialog) && (!within_selection_src)) { set_sensitive(selection_button, on); if ((apply_to_selection) && (!on)) { apply_to_selection = false; we_turned_selection_off = true; } if ((on) && (we_turned_selection_off)) { apply_to_selection = true; } XmChangeColor(selection_button, (apply_to_selection) ? ((Pixel)ss->yellow) : ((Pixel)ss->highlight_color)); if ((enved_target(ss) != ENVED_SPECTRUM) && (enved_with_wave(ss)) && (!showing_all_envs)) env_redisplay(); } } void color_enved_waveform(Pixel pix) { if (enved_dialog) { XSetForeground(main_display(ss), ggc, pix); if ((enved_with_wave(ss)) && (enved_dialog)) env_redisplay(); } } static Xen g_enved_envelope(void) { #define H_enved_envelope "(" S_enved_envelope "): current envelope editor displayed (active) envelope" return(env_to_xen(active_env)); } static Xen g_set_enved_envelope(Xen e) { Xen_check_type(Xen_is_list(e) || Xen_is_string(e) || Xen_is_symbol(e), e, 1, S_set S_enved_envelope, "a list, symbol, or string"); if (active_env) active_env = free_env(active_env); if ((Xen_is_string(e)) || (Xen_is_symbol(e))) active_env = name_to_env((Xen_is_string(e)) ? Xen_string_to_C_string(e) : Xen_symbol_to_C_string(e)); /* xen_to_env in name_to_env, so no copy */ else active_env = xen_to_env(e); if ((!active_env) && (!(Xen_is_list(e)))) Xen_error(Xen_make_error_type("no-such-envelope"), Xen_list_2(C_string_to_Xen_string(S_set S_enved_envelope ": bad envelope arg: ~A"), e)); if (enved_dialog) env_redisplay(); return(e); } static Xen g_enved_filter(void) { #define H_enved_filter "(" S_enved_filter "): envelope editor FIR/FFT filter choice (" PROC_TRUE ": FIR)" return(C_bool_to_Xen_boolean(is_FIR)); } static Xen g_set_enved_filter(Xen type) { Xen_check_type(Xen_is_boolean(type), type, 1, S_set S_enved_filter, "boolean"); is_FIR = Xen_boolean_to_C_bool(type); if (fir_button) set_label(fir_button, (is_FIR) ? "fir" : "fft"); return(type); } /* Transform settings dialog */ static Widget transform_dialog = NULL; /* main dialog shell */ static Widget type_list, size_list, wavelet_list, window_list; static Widget beta_scale, alpha_scale, start_scale, end_scale, alpha_number, beta_number, start_number, end_number; static Widget db_button, peaks_button, logfreq_button, sono_button, spectro_button, normo_button, normalize_button, selection_button1, phases_button; static Widget graph_label, graph_drawer; static Widget peak_txt, db_txt, freq_base_txt; static Widget error_frame1, error_label1; #define NUM_TRANSFORM_SIZES 15 static const char *transform_size_names[NUM_TRANSFORM_SIZES] = {"32", "64", "128", "256", "512", "1024", "2048", "4096", "8192", "16384", "65536", "262144", "1048576", "4194304 ", "16777216"}; static mus_long_t transform_sizes[NUM_TRANSFORM_SIZES] = {32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384, 65536, 262144, 1048576, 4194304, 16777216}; /* ---------------- fft window graph ---------------- */ static GC gc2, fgc; #define GRAPH_SIZE 128 static mus_float_t graph_data[GRAPH_SIZE]; /* fft window graph in transform options dialog */ static mus_float_t graph_fftr[GRAPH_SIZE * 2]; static mus_float_t graph_ffti[GRAPH_SIZE * 2]; /* I goofed around with making the graph size dependent on the drawer's width, but there's really nothing gained */ /* also tried linear/db+min-dB distinction, but linear looks dumb and min-dB is a bother */ static mus_float_t fp_dB(mus_float_t py) { return((py <= ss->lin_dB) ? 0.0 : (1.0 - (20.0 * log10(py) / min_dB(ss)))); } static int local_grf_x(double val, axis_info *ap) { if (val >= ap->x1) return(ap->x_axis_x1); if (val <= ap->x0) return(ap->x_axis_x0); return((int)(ap->x_base + val * ap->x_scale)); } static int local_grf_y(mus_float_t val, axis_info *ap) { if (val >= ap->y1) return(ap->y_axis_y1); if (val <= ap->y0) return(ap->y_axis_y0); return((int)(ap->y_base + val * ap->y_scale)); } static axis_info *axis_ap = NULL; static void graph_redisplay(void) { /* fft_window(ss) is the current choice */ int ix0, iy0, ix1, iy1, i; mus_float_t xincr, x; graphics_context *ax; if (!axis_ap) { axis_ap = (axis_info *)calloc(1, sizeof(axis_info)); ax = (graphics_context *)calloc(1, sizeof(graphics_context)); axis_ap->ax = ax; ax->dp = XtDisplay(graph_drawer); ax->wn = XtWindow(graph_drawer); } else ax = axis_ap->ax; axis_ap->xmin = 0.0; axis_ap->xmax = 1.0; axis_ap->x_ambit = 1.0; axis_ap->x0 = 0.0; axis_ap->x1 = 1.0; if (axis_ap->xlabel) free(axis_ap->xlabel); if (fft_beta_max(fft_window(ss)) != 1.0) axis_ap->xlabel = mus_format("(%d, beta: %.2f)", GRAPH_SIZE, fft_beta_max(fft_window(ss)) * fft_window_beta(ss)); else axis_ap->xlabel = mus_format("(%d)", GRAPH_SIZE); if (fft_window(ss) == MUS_FLAT_TOP_WINDOW) { axis_ap->ymin = -0.1; axis_ap->ymax = 1.0; axis_ap->y_ambit = 1.1; axis_ap->y0 = -0.1; axis_ap->y1 = 1.0; } else { axis_ap->ymin = 0.0; axis_ap->ymax = 1.0; axis_ap->y_ambit = 1.0; axis_ap->y0 = 0.0; axis_ap->y1 = 1.0; } axis_ap->width = widget_width(graph_drawer); axis_ap->window_width = axis_ap->width; axis_ap->y_offset = 0; axis_ap->height = widget_height(graph_drawer); axis_ap->graph_x0 = 0; clear_window(ax); ax->gc = gc2; make_axes_1(axis_ap, X_AXIS_IN_SECONDS, 1 /* "srate" */, SHOW_ALL_AXES, NOT_PRINTING, WITH_X_AXIS, NO_GRID, WITH_LINEAR_AXES, grid_density(ss)); ix1 = local_grf_x(0.0, axis_ap); iy1 = local_grf_y(graph_data[0], axis_ap); xincr = 1.0 / (mus_float_t)GRAPH_SIZE; for (i = 1, x = xincr; i < GRAPH_SIZE; i++, x += xincr) { ix0 = ix1; iy0 = iy1; ix1 = local_grf_x(x, axis_ap); iy1 = local_grf_y(graph_data[i], axis_ap); XDrawLine(ax->dp, ax->wn, gc2, ix0, iy0, ix1, iy1); } ax->gc = fgc; ix1 = local_grf_x(0.0, axis_ap); iy1 = local_grf_y(graph_fftr[0], axis_ap); xincr = 1.0 / (mus_float_t)GRAPH_SIZE; for (i = 1, x = xincr; i < GRAPH_SIZE; i++, x += xincr) { ix0 = ix1; iy0 = iy1; ix1 = local_grf_x(x, axis_ap); if (fft_log_magnitude(ss)) iy1 = local_grf_y(fp_dB(graph_fftr[i]), axis_ap); else iy1 = local_grf_y(graph_fftr[i], axis_ap); XDrawLine(ax->dp, ax->wn, fgc, ix0, iy0, ix1, iy1); } } static void get_fft_window_data(void) { int i; mus_make_fft_window_with_window(fft_window(ss), GRAPH_SIZE, fft_window_beta(ss) * fft_beta_max(fft_window(ss)), fft_window_alpha(ss), graph_data); mus_clear_floats(graph_fftr, GRAPH_SIZE * 2); mus_clear_floats(graph_ffti, GRAPH_SIZE * 2); mus_copy_floats(graph_fftr, graph_data, GRAPH_SIZE); mus_spectrum(graph_fftr, graph_ffti, NULL, GRAPH_SIZE * 2, MUS_SPECTRUM_IN_DB); for (i = 0; i < GRAPH_SIZE; i++) graph_fftr[i] = (graph_fftr[i] + 80.0) / 80.0; /* min dB here is -80 */ } static void widget_float_to_text(Widget w, mus_float_t val) { char *str; str = (char *)calloc(16, sizeof(char)); snprintf(str, 16, "%.2f", val); XmTextFieldSetString(w, str); free(str); } /* ---------------- errors ---------------- */ static void clear_fft_error(void) { if ((error_frame1) && (XtIsManaged(error_frame1))) XtUnmanageChild(error_frame1); } static void unpost_fft_error(XtPointer data, XtIntervalId *id) { clear_fft_error(); } static void errors_to_fft_text(const char *msg, void *data) { int lines = 0; XmString label; label = multi_line_label(msg, &lines); XtVaSetValues(error_label1, XmNlabelString, label, XmNheight, lines * 20, NULL); XtVaSetValues(error_frame1, XmNheight, lines * 20, NULL); XmStringFree(label); XtManageChild(error_frame1); /* since the offending text is automatically overwritten, we can't depend on subsequent text modify callbacks * to clear things, so we'll just use a timer */ XtAppAddTimeOut(main_app(ss), 5000, (XtTimerCallbackProc)unpost_fft_error, NULL); } /* ---------------- transform size ---------------- */ static void chans_transform_size(chan_info *cp, mus_long_t size) { cp->transform_size = size; if (cp->fft) cp->fft->size = size; } void set_transform_size(mus_long_t val) { for_each_chan(force_fft_clear); in_set_transform_size(val); for_each_chan_with_mus_long_t(chans_transform_size, val); if (transform_dialog) { int i; for (i = 0; i < NUM_TRANSFORM_SIZES; i++) if (transform_sizes[i] == val) { XmListSelectPos(size_list, i + 1, false); break; } } if (!(ss->graph_hook_active)) for_each_chan(calculate_fft); } static void size_browse_callback(Widget w, XtPointer context, XtPointer info) { XmListCallbackStruct *cbs = (XmListCallbackStruct *)info; for_each_chan(force_fft_clear); in_set_transform_size(transform_sizes[cbs->item_position - 1]); for_each_chan_with_mus_long_t(chans_transform_size, transform_size(ss)); for_each_chan(calculate_fft); set_label(graph_label, mus_fft_window_name(fft_window(ss))); } /* ---------------- wavelet choice ---------------- */ static void chans_wavelet_type(chan_info *cp, int value) { cp->wavelet_type = value; } void set_wavelet_type(int val) { if (transform_dialog) XmListSelectPos(wavelet_list, val, false); in_set_wavelet_type(val); for_each_chan_with_int(chans_wavelet_type, val); if ((transform_type(ss) == WAVELET) && (!(ss->graph_hook_active))) for_each_chan(calculate_fft); } static void wavelet_browse_callback(Widget w, XtPointer context, XtPointer info) { int val; XmListCallbackStruct *cbs = (XmListCallbackStruct *)info; in_set_wavelet_type(val = (cbs->item_position - 1)); /* make these numbers 0-based as in mus.lisp */ for_each_chan_with_int(chans_wavelet_type, val); if (transform_type(ss) == WAVELET) for_each_chan(calculate_fft); } /* ---------------- fft window choice ---------------- */ static void highlight_alpha_beta_scales(mus_fft_window_t val) { if (fft_window_beta_in_use(val)) { XtVaSetValues(beta_scale, XmNbackground, ss->highlight_color, NULL); XtVaSetValues(beta_number, XmNbackground, ss->highlight_color, NULL); } else { XtVaSetValues(beta_scale, XmNbackground, ss->basic_color, NULL); XtVaSetValues(beta_number, XmNbackground, ss->basic_color, NULL); } if (fft_window_alpha_in_use(val)) { XtVaSetValues(alpha_scale, XmNbackground, ss->highlight_color, NULL); XtVaSetValues(alpha_number, XmNbackground, ss->highlight_color, NULL); } else { XtVaSetValues(alpha_scale, XmNbackground, ss->basic_color, NULL); XtVaSetValues(alpha_number, XmNbackground, ss->basic_color, NULL); } } void set_fft_window(mus_fft_window_t val) { in_set_fft_window(val); if (!(ss->graph_hook_active)) for_each_chan(calculate_fft); if (transform_dialog) { XmListSelectPos(window_list, (int)val + 1, false); set_label(graph_label, mus_fft_window_name(val)); get_fft_window_data(); if (XtIsManaged(transform_dialog)) graph_redisplay(); highlight_alpha_beta_scales(val); } } static void window_browse_callback(Widget w, XtPointer context, XtPointer info) { XmListCallbackStruct *cbs = (XmListCallbackStruct *)info; mus_fft_window_t fft_window_choice; fft_window_choice = (mus_fft_window_t)(cbs->item_position - 1); /* make these numbers 0-based as in mus.lisp */ in_set_fft_window(fft_window_choice); for_each_chan(calculate_fft); set_label(graph_label, mus_fft_window_name(fft_window(ss))); get_fft_window_data(); graph_redisplay(); highlight_alpha_beta_scales(fft_window_choice); } /* ---------------- transform choice ---------------- */ static void chans_transform_type(chan_info *cp, int value) { cp->transform_type = value; } void set_transform_type(int val) { if (is_transform(val)) { if (!(ss->graph_hook_active)) for_each_chan(force_fft_clear); in_set_transform_type(val); for_each_chan_with_int(chans_transform_type, val); if (!(ss->graph_hook_active)) for_each_chan(calculate_fft); if (transform_dialog) XmListSelectPos(type_list, transform_type_to_position(val) + 1, false); } } static void transform_type_browse_callback(Widget w, XtPointer context, XtPointer info) { int type; XmListCallbackStruct *cbs = (XmListCallbackStruct *)info; type = transform_position_to_type(cbs->item_position - 1); for_each_chan(force_fft_clear); in_set_transform_type(type); for_each_chan_with_int(chans_transform_type, type); for_each_chan(calculate_fft); } void make_transform_type_list(void) { int num; num = max_transform_type(); if (transform_dialog) { XmString *types; int i, j; types = (XmString *)calloc(num, sizeof(XmString)); for (i = 0, j = 0; i < num; i++) if (is_transform(i)) { set_transform_position(i, j); types[j++] = XmStringCreateLocalized((char *)transform_name(i)); } XtVaSetValues(type_list, XmNitems, types, XmNitemCount, j, XmNvisibleItemCount, 6, NULL); for (i = 0; i < j; i++) XmStringFree(types[i]); free(types); } } /* ---------------- transform "graph type" (i.e. sonogram etc) ---------------- */ void set_transform_graph_type(graph_type_t val) { in_set_transform_graph_type(val); if (transform_dialog) switch (val) { case GRAPH_ONCE: XmToggleButtonSetState(normo_button, true, false); XmToggleButtonSetState(spectro_button, false, false); XmToggleButtonSetState(sono_button, false, false); break; case GRAPH_AS_SONOGRAM: XmToggleButtonSetState(normo_button, false, false); XmToggleButtonSetState(spectro_button, false, false); XmToggleButtonSetState(sono_button, true, false); break; case GRAPH_AS_SPECTROGRAM: XmToggleButtonSetState(normo_button, false, false); XmToggleButtonSetState(spectro_button, true, false); XmToggleButtonSetState(sono_button, false, false); break; case GRAPH_AS_WAVOGRAM: break; } if (!(ss->graph_hook_active)) for_each_chan(calculate_fft); } static void graph_transform_once_callback(Widget w, XtPointer context, XtPointer info) { graph_type_t old_type; old_type = transform_graph_type(ss); XmToggleButtonSetState(normo_button, true, false); XmToggleButtonSetState(sono_button, false, false); XmToggleButtonSetState(spectro_button, false, false); in_set_transform_graph_type(GRAPH_ONCE); if (old_type != GRAPH_ONCE) for_each_chan(calculate_fft); } static void sonogram_callback(Widget w, XtPointer context, XtPointer info) { graph_type_t old_type; old_type = transform_graph_type(ss); XmToggleButtonSetState(sono_button, true, false); XmToggleButtonSetState(normo_button, false, false); XmToggleButtonSetState(spectro_button, false, false); in_set_transform_graph_type(GRAPH_AS_SONOGRAM); if (old_type != GRAPH_AS_SONOGRAM) for_each_chan(calculate_fft); } static void spectrogram_callback(Widget w, XtPointer context, XtPointer info) { graph_type_t old_type; old_type = transform_graph_type(ss); XmToggleButtonSetState(spectro_button, true, false); XmToggleButtonSetState(normo_button, false, false); XmToggleButtonSetState(sono_button, false, false); in_set_transform_graph_type(GRAPH_AS_SPECTROGRAM); if (old_type != GRAPH_AS_SPECTROGRAM) for_each_chan(calculate_fft); } /* ---------------- show peaks ---------------- */ static void map_show_transform_peaks(chan_info *cp, bool value) { cp->show_transform_peaks = value; } static void peaks_callback(Widget w, XtPointer context, XtPointer info) { bool val; XmToggleButtonCallbackStruct *cb = (XmToggleButtonCallbackStruct *)info; val = (cb->set); in_set_show_transform_peaks(val); for_each_chan_with_bool(map_show_transform_peaks, val); for_each_chan(calculate_fft); } void set_show_transform_peaks(bool val) { in_set_show_transform_peaks(val); for_each_chan_with_bool(map_show_transform_peaks, val); if (transform_dialog) set_toggle_button(peaks_button, val, false, NULL); if (!(ss->graph_hook_active)) for_each_chan(calculate_fft); } void reflect_peaks_in_transform_dialog(void) { if (transform_dialog) widget_int_to_text(peak_txt, max_transform_peaks(ss)); } static void peaks_activate_callback(Widget w, XtPointer context, XtPointer info) { char *str; str = XmTextFieldGetString(w); if ((str) && (*str)) { int new_peaks; redirect_errors_to(errors_to_fft_text, NULL); new_peaks = string_to_int(str, 1, "peaks"); redirect_errors_to(NULL, NULL); if (new_peaks >= 1) { set_max_transform_peaks(new_peaks); for_each_chan(calculate_fft); } else widget_int_to_text(w, max_transform_peaks(ss)); XtFree(str); } } /* ---------------- log magnitude ---------------- */ static void chans_fft_log_magnitude(chan_info *cp, bool value) { cp->fft_log_magnitude = value; cp->fft_changed = FFT_CHANGE_LOCKED; } void set_fft_log_magnitude(bool val) { in_set_fft_log_magnitude(val); for_each_chan_with_bool(chans_fft_log_magnitude, val); if (transform_dialog) set_toggle_button(db_button, val, false, NULL); if (!(ss->graph_hook_active)) for_each_chan(calculate_fft); } /* ---------------- dB ---------------- */ static void fft_db_callback(Widget w, XtPointer context, XtPointer info) { bool val; XmToggleButtonCallbackStruct *cb = (XmToggleButtonCallbackStruct *)info; val = cb->set; in_set_fft_log_magnitude(val); graph_redisplay(); for_each_chan_with_bool(chans_fft_log_magnitude, val); for_each_chan(calculate_fft); } void reflect_min_db_in_transform_dialog(void) { if (transform_dialog) widget_float_to_text(db_txt, min_dB(ss)); } static void min_db_activate_callback(Widget w, XtPointer context, XtPointer info) { char *str; str = XmTextFieldGetString(w); if ((str) && (*str)) { mus_float_t new_db; redirect_errors_to(errors_to_fft_text, NULL); new_db = string_to_mus_float_t(str, -10000.0, "dB"); redirect_errors_to(NULL, NULL); if (new_db < 0.0) set_min_db(new_db); else widget_float_to_text(w, min_dB(ss)); XtFree(str); } } /* ---------------- log frequency ---------------- */ static void chans_fft_log_frequency(chan_info *cp, bool value) { cp->fft_log_frequency = value; cp->fft_changed = FFT_CHANGE_LOCKED; } static void logfreq_callback(Widget w, XtPointer context, XtPointer info) { bool val; XmToggleButtonCallbackStruct *cb = (XmToggleButtonCallbackStruct *)info; val = cb->set; in_set_fft_log_frequency(val); for_each_chan_with_bool(chans_fft_log_frequency, val); for_each_chan(calculate_fft); } void set_fft_log_frequency(bool val) { in_set_fft_log_frequency(val); for_each_chan_with_bool(chans_fft_log_frequency, val); if (transform_dialog) set_toggle_button(logfreq_button, val, false, NULL); if (!(ss->graph_hook_active)) for_each_chan(calculate_fft); } void reflect_log_freq_start_in_transform_dialog(void) { if (transform_dialog) widget_float_to_text(freq_base_txt, log_freq_start(ss)); } static void log_freq_start_activate_callback(Widget w, XtPointer context, XtPointer info) { char *str; str = XmTextFieldGetString(w); if ((str) && (*str)) { mus_float_t new_lfb; redirect_errors_to(errors_to_fft_text, NULL); new_lfb = string_to_mus_float_t(str, 0.0, "log freq start"); redirect_errors_to(NULL, NULL); if (new_lfb > 0.0) set_log_freq_start(new_lfb); else widget_float_to_text(w, log_freq_start(ss)); XtFree(str); } } /* ---------------- normalization choice ---------------- */ static void chans_transform_normalization(chan_info *cp, int value) { cp->transform_normalization = (fft_normalize_t)value; cp->fft_changed = FFT_CHANGE_LOCKED; } static void normalize_callback(Widget w, XtPointer context, XtPointer info) { fft_normalize_t choice; XmToggleButtonCallbackStruct *cb = (XmToggleButtonCallbackStruct *)info; choice = (cb->set) ? NORMALIZE_BY_CHANNEL : DONT_NORMALIZE; in_set_transform_normalization(choice); for_each_chan_with_int(chans_transform_normalization, (int)choice); for_each_chan(calculate_fft); } void set_transform_normalization(fft_normalize_t val) { in_set_transform_normalization(val); for_each_chan_with_int(chans_transform_normalization, (int)val); if (transform_dialog) set_toggle_button(normalize_button, (val != DONT_NORMALIZE), false, NULL); if (!(ss->graph_hook_active)) for_each_chan(calculate_fft); } /* ---------------- show selection transform ---------------- */ static void selection_callback(Widget w, XtPointer context, XtPointer info) { XmToggleButtonCallbackStruct *cb = (XmToggleButtonCallbackStruct *)info; in_set_show_selection_transform(cb->set); for_each_chan(calculate_fft); } void set_show_selection_transform(bool show) { in_set_show_selection_transform(show); if (transform_dialog) set_toggle_button(selection_button1, show, false, NULL); if (!(ss->graph_hook_active)) for_each_chan(calculate_fft); } /* ---------------- show phases (via color) ---------------- */ static void chans_fft_with_phases(chan_info *cp, bool value) { cp->fft_with_phases = value; cp->fft_changed = FFT_CHANGE_LOCKED; } static void phases_callback(Widget w, XtPointer context, XtPointer info) { bool val; XmToggleButtonCallbackStruct *cb = (XmToggleButtonCallbackStruct *)info; val = cb->set; in_set_fft_with_phases(val); graph_redisplay(); for_each_chan_with_bool(chans_fft_with_phases, val); for_each_chan(calculate_fft); } void set_fft_with_phases(bool val) { in_set_fft_with_phases(val); for_each_chan_with_bool(chans_fft_with_phases, val); if (!(ss->graph_hook_active)) for_each_chan(calculate_fft); } /* ---------------- window alpha parameter ---------------- */ static void alpha_drag_callback(Widget w, XtPointer context, XtPointer info) { char alpha_number_buffer[512]; /* 11 before gcc 7.1 */ mus_float_t alpha; alpha = (((XmScrollBarCallbackStruct *)info)->value) / 90.0; in_set_fft_window_alpha(alpha); chans_field(FCP_ALPHA, alpha); snprintf(alpha_number_buffer, 512, "alpha:%.3f", alpha); set_label(alpha_number, alpha_number_buffer); if (fft_window_alpha_in_use(fft_window(ss))) { get_fft_window_data(); graph_redisplay(); if (transform_type(ss) == FOURIER) for_each_chan(calculate_fft); } } static void set_alpha_scale(mus_float_t val) { char alpha_number_buffer[512]; XtVaSetValues(alpha_scale, XmNvalue, (int)(val * 90), NULL); snprintf(alpha_number_buffer, 512, "alpha:%.3f", val); set_label(alpha_number, alpha_number_buffer); } void set_fft_window_alpha(mus_float_t val) { in_set_fft_window_alpha(val); chans_field(FCP_ALPHA, val); if (transform_dialog) { set_alpha_scale(val); get_fft_window_data(); if (XtIsManaged(transform_dialog)) graph_redisplay(); } if (!(ss->graph_hook_active)) for_each_chan(calculate_fft); } /* ---------------- window beta parameter ---------------- */ static void beta_drag_callback(Widget w, XtPointer context, XtPointer info) { char beta_number_buffer[12]; mus_float_t beta; beta = (((XmScrollBarCallbackStruct *)info)->value) / 90.0; in_set_fft_window_beta(beta); chans_field(FCP_BETA, beta); snprintf(beta_number_buffer, 12, "beta: %.3f", beta); set_label(beta_number, beta_number_buffer); if (fft_window_beta_in_use(fft_window(ss))) { get_fft_window_data(); graph_redisplay(); if (transform_type(ss) == FOURIER) for_each_chan(calculate_fft); } } static void set_beta_scale(mus_float_t val) { char beta_number_buffer[12]; XtVaSetValues(beta_scale, XmNvalue, (int)(val * 90), NULL); snprintf(beta_number_buffer, 12, "beta: %.3f", val); set_label(beta_number, beta_number_buffer); } void set_fft_window_beta(mus_float_t val) { in_set_fft_window_beta(val); chans_field(FCP_BETA, val); if (transform_dialog) { set_beta_scale(val); get_fft_window_data(); if (XtIsManaged(transform_dialog)) graph_redisplay(); } if (!(ss->graph_hook_active)) for_each_chan(calculate_fft); } /* ---------------- spectrum start/end ---------------- */ static void chans_spectrum_changed(chan_info *cp) { cp->fft_changed = FFT_CHANGE_LOCKED; update_graph(cp); } static void set_spectrum_start_scale(mus_float_t val) { char start_number_buffer[12]; XtVaSetValues(start_scale, XmNvalue, (int)(val * 90), NULL); snprintf(start_number_buffer, 12, "start:%.3f", val); set_label(start_number, start_number_buffer); } static void check_spectrum_start(mus_float_t end) { /* don't display chans, but do reset if necessary */ if (spectrum_start(ss) > end) { in_set_spectrum_start(end); if (transform_dialog) set_spectrum_start_scale(end); chans_field(FCP_SPECTRUM_START, end); } } static void check_spectrum_end(mus_float_t start); void set_spectrum_start(mus_float_t val) { if (transform_dialog) set_spectrum_start_scale(val); in_set_spectrum_start(val); check_spectrum_end(val); chans_field(FCP_SPECTRUM_START, val); for_each_chan(chans_spectrum_changed); } static void start_drag_callback(Widget w, XtPointer context, XtPointer info) { char start_number_buffer[12]; mus_float_t start; start = (((XmScrollBarCallbackStruct *)info)->value) / 90.0; snprintf(start_number_buffer, 12, "start:%.3f", start); set_label(start_number, start_number_buffer); in_set_spectrum_start(start); check_spectrum_end(start); chans_field(FCP_SPECTRUM_START, start); for_each_chan(chans_spectrum_changed); } static void set_spectrum_end_scale(mus_float_t val) { char end_number_buffer[12]; XtVaSetValues(end_scale, XmNvalue, (int)(val * 90), NULL); snprintf(end_number_buffer, 12, "end: %.3f", val); set_label(end_number, end_number_buffer); } static void check_spectrum_end(mus_float_t start) { /* don't display chans, but do reset if necessary */ if (spectrum_end(ss) < start) { in_set_spectrum_end(start); if (transform_dialog) set_spectrum_end_scale(start); chans_field(FCP_SPECTRUM_END, start); } } void set_spectrum_end(mus_float_t val) { if (transform_dialog) set_spectrum_end_scale(val); in_set_spectrum_end(val); check_spectrum_start(val); chans_field(FCP_SPECTRUM_END, val); for_each_chan(chans_spectrum_changed); } static void end_drag_callback(Widget w, XtPointer context, XtPointer info) { char end_number_buffer[12]; mus_float_t end; end = (((XmScrollBarCallbackStruct *)info)->value) / 90.0; snprintf(end_number_buffer, 12, "end: %.3f", end); set_label(end_number, end_number_buffer); in_set_spectrum_end(end); check_spectrum_start(end); chans_field(FCP_SPECTRUM_END, end); for_each_chan(chans_spectrum_changed); } /* ---------------- dialog buttons etc ---------------- */ static void graph_resize_callback(Widget w, XtPointer context, XtPointer info) { graph_redisplay(); } static void dismiss_transform_callback(Widget w, XtPointer context, XtPointer info) { if (XmGetFocusWidget(transform_dialog) == XmMessageBoxGetChild(transform_dialog, XmDIALOG_CANCEL_BUTTON)) XtUnmanageChild(transform_dialog); } static void color_orientation_callback(Widget w, XtPointer context, XtPointer info) { make_color_orientation_dialog(true); } static void help_transform_callback(Widget w, XtPointer context, XtPointer info) { transform_dialog_help(); } static void fft_blue_textfield_unfocus_callback(Widget w, XtPointer context, XtPointer info) { XtVaSetValues(w, XmNbackground, ss->lighter_blue, NULL); XtVaSetValues(w, XmNcursorPositionVisible, false, NULL); } static void fft_blue_mouse_leave_text_callback(Widget w, XtPointer context, XEvent *event, Boolean *flag) { XtVaSetValues(w, XmNbackground, ss->lighter_blue, NULL); XtVaSetValues(w, XmNcursorPositionVisible, false, NULL); } static void fft_white_mouse_enter_text_callback(Widget w, XtPointer context, XEvent *event, Boolean *flag) { XtVaSetValues(w, XmNbackground, ss->text_focus_color, NULL); XtVaSetValues(w, XmNcursorPositionVisible, true, NULL); } /* ---------------- transform options dialog ---------------- */ #define FRAME_BORDER_WIDTH 6 static bool need_callback = true; Widget make_transform_dialog(bool managed) { if (!transform_dialog) { Widget mainform, type_frame, type_form, type_label, size_frame, size_form, size_label, display_frame, display_form, display_label; Widget window_frame, window_form, window_label, wavelet_frame, wavelet_form, wavelet_label, graph_frame, graph_form, gsep; Widget ab_form, ab_frame, ab_title, ab_sep; Widget se_form, se_frame, se_title, se_sep, ok_button; XmString s1; XmString xhelp, xgo_away, xtitle, bstr, xorient; Arg args[32]; XmString sizes[NUM_TRANSFORM_SIZES]; XmString wavelets[NUM_WAVELETS]; XmString windows[MUS_NUM_FFT_WINDOWS]; XGCValues gv; XtCallbackList n1, n2, n3, n4; int size_pos = 1; int n, i; for (i = 0; i < NUM_TRANSFORM_SIZES; i++) if (transform_sizes[i] == transform_size(ss)) { size_pos = i + 1; break; } xgo_away = XmStringCreateLocalized((char *)I_GO_AWAY); /* needed by template dialog */ xhelp = XmStringCreateLocalized((char *)I_HELP); xtitle = XmStringCreateLocalized((char *)"Transform Options"); xorient = XmStringCreateLocalized((char *)"Color/Orientation"); n = 0; XtSetArg(args[n], XmNbackground, ss->basic_color); n++; XtSetArg(args[n], XmNcancelLabelString, xgo_away); n++; XtSetArg(args[n], XmNokLabelString, xorient); n++; XtSetArg(args[n], XmNhelpLabelString, xhelp); n++; XtSetArg(args[n], XmNautoUnmanage, false); n++; XtSetArg(args[n], XmNdialogTitle, xtitle); n++; XtSetArg(args[n], XmNresizePolicy, XmRESIZE_GROW); n++; XtSetArg(args[n], XmNnoResize, false); n++; XtSetArg(args[n], XmNtransient, false); n++; transform_dialog = XmCreateTemplateDialog(main_shell(ss), (char *)"Transform Options", args, n); ok_button = XmMessageBoxGetChild(transform_dialog, XmDIALOG_OK_BUTTON); XtAddCallback(transform_dialog, XmNcancelCallback, dismiss_transform_callback, NULL); /* XtAddCallback(transform_dialog, XmNokCallback, color_orientation_callback, NULL); */ /* in dialog calls this! */ XtAddCallback(ok_button, XmNactivateCallback, color_orientation_callback, NULL); XtAddCallback(transform_dialog, XmNhelpCallback, help_transform_callback, NULL); XmStringFree(xhelp); XmStringFree(xgo_away); XmStringFree(xtitle); XmStringFree(xorient); XtVaSetValues(XmMessageBoxGetChild(transform_dialog, XmDIALOG_CANCEL_BUTTON), XmNarmColor, ss->selection_color, NULL); XtVaSetValues(XmMessageBoxGetChild(transform_dialog, XmDIALOG_HELP_BUTTON), XmNarmColor, ss->selection_color, NULL); XtVaSetValues(XmMessageBoxGetChild(transform_dialog, XmDIALOG_OK_BUTTON), XmNarmColor, ss->selection_color, NULL); XtVaSetValues(XmMessageBoxGetChild(transform_dialog, XmDIALOG_CANCEL_BUTTON), XmNbackground, ss->highlight_color, NULL); XtVaSetValues(XmMessageBoxGetChild(transform_dialog, XmDIALOG_HELP_BUTTON), XmNbackground, ss->highlight_color, NULL); XtVaSetValues(XmMessageBoxGetChild(transform_dialog, XmDIALOG_OK_BUTTON), XmNbackground, ss->highlight_color, NULL); n = 0; XtSetArg(args[n], XmNbackground, ss->basic_color); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNbottomWidget, XmMessageBoxGetChild(transform_dialog, XmDIALOG_SEPARATOR)); n++; mainform = XtCreateManagedWidget("mainform", xmFormWidgetClass, transform_dialog, args, n); n = 0; XtSetArg(args[n], XmNbackground, ss->basic_color); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNallowResize, true); n++; XtSetArg(args[n], XmNshadowType, XmSHADOW_ETCHED_IN); n++; XtSetArg(args[n], XmNshadowThickness, 2); n++; error_frame1 = XtCreateManagedWidget("error-frame", xmFrameWidgetClass, mainform, args, n); n = 0; XtSetArg(args[n], XmNbackground, ss->highlight_color); n++; error_label1 = XtCreateManagedWidget("", xmLabelWidgetClass, error_frame1, args, n); /* now 7 or 8 boxes within the main box: type (list) | size (list) | display (button column) wavelet (list) | window (list) | graph (fft?) of current window alpha/beta ------------------------ | start/end ------------------------- | each box has a frame, label, and contents */ /* -------- SPECTRUM START/END -------- */ n = 0; XtSetArg(args[n], XmNbackground, ss->basic_color); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_POSITION); n++; XtSetArg(args[n], XmNrightPosition, 60); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNborderWidth, FRAME_BORDER_WIDTH); n++; XtSetArg(args[n], XmNborderColor, ss->basic_color); n++; se_frame = XtCreateManagedWidget("se-frame", xmFrameWidgetClass, mainform, args, n); n = 0; XtSetArg(args[n], XmNbackground, ss->basic_color); n++; n = attach_all_sides(args, n); se_form = XtCreateManagedWidget("se-form", xmFormWidgetClass, se_frame, args, n); /* needed because XmFrame only accepts one child */ n = 0; XtSetArg(args[n], XmNbackground, ss->highlight_color); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNalignment, XmALIGNMENT_CENTER); n++; se_title = XtCreateManagedWidget("spectrum start/end", xmLabelWidgetClass, se_form, args, n); n = 0; XtSetArg(args[n], XmNbackground, ss->basic_color); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNtopWidget, se_title); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNseparatorType, XmSHADOW_ETCHED_IN); n++; XtSetArg(args[n], XmNorientation, XmHORIZONTAL); n++; se_sep = XtCreateManagedWidget("se_sep", xmSeparatorWidgetClass, se_form, args, n); n = 0; s1 = XmStringCreateLocalized((char *)"start:0.0 "); XtSetArg(args[n], XmNbackground, ss->basic_color); n++; XtSetArg(args[n], XmNalignment, XmALIGNMENT_BEGINNING); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNtopWidget, se_sep); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNlabelString, s1); n++; XtSetArg(args[n], XmNrecomputeSize, false); n++; XtSetArg(args[n], XmNshadowThickness, 0); n++; XtSetArg(args[n], XmNhighlightThickness, 0); n++; start_number = XtCreateManagedWidget("start-number", xmLabelWidgetClass, se_form, args, n); XmStringFree(s1); n = 0; XtSetArg(args[n], XmNbackground, ss->basic_color); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_OPPOSITE_WIDGET); n++; XtSetArg(args[n], XmNtopWidget, start_number); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNleftWidget, start_number); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNorientation, XmHORIZONTAL); n++; XtSetArg(args[n], XmNmaximum, 100); n++; XtSetArg(args[n], XmNvalue, 0); n++; XtSetArg(args[n], XmNheight, 16); n++; XtSetArg(args[n], XmNdragCallback, n3 = make_callback_list(start_drag_callback, NULL)); n++; XtSetArg(args[n], XmNvalueChangedCallback, n3); n++; start_scale = XtCreateManagedWidget("start-scale", xmScrollBarWidgetClass, se_form, args, n); n = 0; s1 = XmStringCreateLocalized((char *)"end: 1.0 "); XtSetArg(args[n], XmNbackground, ss->basic_color); n++; XtSetArg(args[n], XmNalignment, XmALIGNMENT_BEGINNING); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNtopWidget, start_number); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNlabelString, s1); n++; XtSetArg(args[n], XmNrecomputeSize, false); n++; XtSetArg(args[n], XmNshadowThickness, 0); n++; XtSetArg(args[n], XmNhighlightThickness, 0); n++; end_number = XtCreateManagedWidget("end-number", xmLabelWidgetClass, se_form, args, n); XmStringFree(s1); n = 0; XtSetArg(args[n], XmNbackground, ss->basic_color); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_OPPOSITE_WIDGET); n++; XtSetArg(args[n], XmNtopWidget, end_number); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNleftWidget, end_number); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNorientation, XmHORIZONTAL); n++; XtSetArg(args[n], XmNmaximum, 100); n++; XtSetArg(args[n], XmNvalue, 90); n++; XtSetArg(args[n], XmNheight, 16); n++; XtSetArg(args[n], XmNdragCallback, n4 = make_callback_list(end_drag_callback, NULL)); n++; XtSetArg(args[n], XmNvalueChangedCallback, n4); n++; end_scale = XtCreateManagedWidget("end-scale", xmScrollBarWidgetClass, se_form, args, n); /* -------- WINDOW ALPHA/BETA -------- */ n = 0; XtSetArg(args[n], XmNbackground, ss->basic_color); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_POSITION); n++; XtSetArg(args[n], XmNrightPosition, 60); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNbottomWidget, se_frame); n++; XtSetArg(args[n], XmNborderWidth, FRAME_BORDER_WIDTH); n++; XtSetArg(args[n], XmNborderColor, ss->basic_color); n++; ab_frame = XtCreateManagedWidget("ab-frame", xmFrameWidgetClass, mainform, args, n); n = 0; XtSetArg(args[n], XmNbackground, ss->basic_color); n++; n = attach_all_sides(args, n); ab_form = XtCreateManagedWidget("ab-form", xmFormWidgetClass, ab_frame, args, n); /* needed because XmFrame only accepts one child */ n = 0; XtSetArg(args[n], XmNbackground, ss->highlight_color); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNalignment, XmALIGNMENT_CENTER); n++; ab_title = XtCreateManagedWidget("window parameter", xmLabelWidgetClass, ab_form, args, n); n = 0; XtSetArg(args[n], XmNbackground, ss->basic_color); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNtopWidget, ab_title); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNseparatorType, XmSHADOW_ETCHED_IN); n++; XtSetArg(args[n], XmNorientation, XmHORIZONTAL); n++; ab_sep = XtCreateManagedWidget("ab_sep", xmSeparatorWidgetClass, ab_form, args, n); n = 0; s1 = XmStringCreateLocalized((char *)"alpha:0.0 "); XtSetArg(args[n], XmNbackground, ss->basic_color); n++; XtSetArg(args[n], XmNalignment, XmALIGNMENT_BEGINNING); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNtopWidget, ab_sep); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNlabelString, s1); n++; XtSetArg(args[n], XmNrecomputeSize, false); n++; XtSetArg(args[n], XmNshadowThickness, 0); n++; XtSetArg(args[n], XmNhighlightThickness, 0); n++; alpha_number = XtCreateManagedWidget("alpha-number", xmLabelWidgetClass, ab_form, args, n); XmStringFree(s1); n = 0; XtSetArg(args[n], XmNbackground, ss->basic_color); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_OPPOSITE_WIDGET); n++; XtSetArg(args[n], XmNtopWidget, alpha_number); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNleftWidget, alpha_number); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNorientation, XmHORIZONTAL); n++; XtSetArg(args[n], XmNmaximum, 100); n++; XtSetArg(args[n], XmNvalue, 0); n++; XtSetArg(args[n], XmNheight, 16); n++; XtSetArg(args[n], XmNdragCallback, n1 = make_callback_list(alpha_drag_callback, NULL)); n++; XtSetArg(args[n], XmNvalueChangedCallback, n1); n++; alpha_scale = XtCreateManagedWidget("alpha-scale", xmScrollBarWidgetClass, ab_form, args, n); n = 0; s1 = XmStringCreateLocalized((char *)"beta: 0.0 "); XtSetArg(args[n], XmNbackground, ss->basic_color); n++; XtSetArg(args[n], XmNalignment, XmALIGNMENT_BEGINNING); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNtopWidget, alpha_number); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNlabelString, s1); n++; XtSetArg(args[n], XmNrecomputeSize, false); n++; XtSetArg(args[n], XmNshadowThickness, 0); n++; XtSetArg(args[n], XmNhighlightThickness, 0); n++; beta_number = XtCreateManagedWidget("beta-number", xmLabelWidgetClass, ab_form, args, n); XmStringFree(s1); n = 0; XtSetArg(args[n], XmNbackground, ss->basic_color); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_OPPOSITE_WIDGET); n++; XtSetArg(args[n], XmNtopWidget, beta_number); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNleftWidget, beta_number); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNorientation, XmHORIZONTAL); n++; XtSetArg(args[n], XmNmaximum, 100); n++; XtSetArg(args[n], XmNvalue, 0); n++; XtSetArg(args[n], XmNheight, 16); n++; XtSetArg(args[n], XmNdragCallback, n2 = make_callback_list(beta_drag_callback, NULL)); n++; XtSetArg(args[n], XmNvalueChangedCallback, n2); n++; beta_scale = XtCreateManagedWidget("beta-scale", xmScrollBarWidgetClass, ab_form, args, n); /* -------- WINDOW -------- */ n = 0; XtSetArg(args[n], XmNbackground, ss->basic_color); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_POSITION); n++; XtSetArg(args[n], XmNrightPosition, 30); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_POSITION); n++; XtSetArg(args[n], XmNtopPosition, 35); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNbottomWidget, ab_frame); n++; XtSetArg(args[n], XmNborderWidth, FRAME_BORDER_WIDTH); n++; XtSetArg(args[n], XmNborderColor, ss->basic_color); n++; window_frame = XtCreateManagedWidget("window-frame", xmFrameWidgetClass, mainform, args, n); n = 0; XtSetArg(args[n], XmNbackground, ss->basic_color); n++; n = attach_all_sides(args, n); window_form = XtCreateManagedWidget("window-form", xmFormWidgetClass, window_frame, args, n); n = 0; XtSetArg(args[n], XmNbackground, ss->highlight_color); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNalignment, XmALIGNMENT_CENTER); n++; window_label = XtCreateManagedWidget("window", xmLabelWidgetClass, window_form, args, n); n = 0; XtSetArg(args[n], XmNbackground, ss->basic_color); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNbottomWidget, XmATTACH_FORM); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNtopWidget, window_label); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNtopItemPosition, ((int)fft_window(ss) > 2) ? ((int)fft_window(ss) - 1) : ((int)fft_window(ss) + 1)); n++; window_list = XmCreateScrolledList(window_form, (char *)"window-list", args, n); XtVaSetValues(window_list, XmNbackground, ss->white, XmNforeground, ss->black, NULL); for (i = 0; i < MUS_NUM_FFT_WINDOWS; i++) windows[i] = XmStringCreateLocalized((char *)mus_fft_window_name((mus_fft_window_t)i)); XtVaSetValues(window_list, XmNitems, windows, XmNitemCount, MUS_NUM_FFT_WINDOWS, XmNvisibleItemCount, 8, NULL); for (i = 0; i < MUS_NUM_FFT_WINDOWS; i++) XmStringFree(windows[i]); XtManageChild(window_list); XtAddCallback(window_list, XmNbrowseSelectionCallback, window_browse_callback, NULL); /* -------- WAVELET -------- */ n = 0; XtSetArg(args[n], XmNbackground, ss->basic_color); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNleftWidget, window_frame); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_POSITION); n++; XtSetArg(args[n], XmNrightPosition, 60); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_POSITION); n++; XtSetArg(args[n], XmNtopPosition, 35); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNbottomWidget, ab_frame); n++; XtSetArg(args[n], XmNborderWidth, FRAME_BORDER_WIDTH); n++; XtSetArg(args[n], XmNborderColor, ss->basic_color); n++; wavelet_frame = XtCreateManagedWidget("wavelet-frame", xmFrameWidgetClass, mainform, args, n); n = 0; XtSetArg(args[n], XmNbackground, ss->basic_color); n++; n = attach_all_sides(args, n); wavelet_form = XtCreateManagedWidget("wavelet-form", xmFormWidgetClass, wavelet_frame, args, n); n = 0; XtSetArg(args[n], XmNbackground, ss->highlight_color); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNalignment, XmALIGNMENT_CENTER); n++; wavelet_label = XtCreateManagedWidget("wavelet", xmLabelWidgetClass, wavelet_form, args, n); n = 0; XtSetArg(args[n], XmNbackground, ss->basic_color); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNbottomWidget, XmATTACH_FORM); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNtopWidget, wavelet_label); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++; wavelet_list = XmCreateScrolledList(wavelet_form, (char *)"wavelet-list", args, n); XtVaSetValues(wavelet_list, XmNbackground, ss->white, XmNforeground, ss->black, NULL); for (i = 0; i < NUM_WAVELETS; i++) wavelets[i] = XmStringCreateLocalized((char *)wavelet_name(i)); XtVaSetValues(wavelet_list, XmNitems, wavelets, XmNitemCount, NUM_WAVELETS, XmNvisibleItemCount, 8, NULL); for (i = 0; i < NUM_WAVELETS; i++) XmStringFree(wavelets[i]); XtManageChild(wavelet_list); XtAddCallback(wavelet_list, XmNbrowseSelectionCallback, wavelet_browse_callback, NULL); /* -------- TRANSFORM TYPE -------- */ n = 0; XtSetArg(args[n], XmNbackground, ss->basic_color); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_POSITION); n++; XtSetArg(args[n], XmNrightPosition, 30); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_POSITION); n++; XtSetArg(args[n], XmNbottomPosition, 35); n++; XtSetArg(args[n], XmNborderWidth, FRAME_BORDER_WIDTH); n++; XtSetArg(args[n], XmNborderColor, ss->basic_color); n++; type_frame = XtCreateManagedWidget("type-frame", xmFrameWidgetClass, mainform, args, n); n = 0; XtSetArg(args[n], XmNbackground, ss->basic_color); n++; n = attach_all_sides(args, n); type_form = XtCreateManagedWidget("type-form", xmFormWidgetClass, type_frame, args, n); /* needed because XmFrame only accepts one child */ n = 0; XtSetArg(args[n], XmNbackground, ss->highlight_color); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNalignment, XmALIGNMENT_CENTER); n++; type_label = XtCreateManagedWidget("type", xmLabelWidgetClass, type_form, args, n); n = 0; XtSetArg(args[n], XmNbackground, ss->basic_color); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNtopWidget, type_label); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++; type_list = XmCreateScrolledList(type_form, (char *)"type-list", args, n); XtVaSetValues(type_list, XmNbackground, ss->white, XmNforeground, ss->black, NULL); make_transform_type_list(); XtManageChild(type_list); XtAddCallback(type_list, XmNbrowseSelectionCallback, transform_type_browse_callback, NULL); /* -------- SIZE -------- */ n = 0; XtSetArg(args[n], XmNbackground, ss->basic_color); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNleftWidget, type_frame); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_POSITION); n++; XtSetArg(args[n], XmNrightPosition, 60); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_OPPOSITE_WIDGET); n++; XtSetArg(args[n], XmNbottomWidget, type_frame); n++; XtSetArg(args[n], XmNborderWidth, FRAME_BORDER_WIDTH); n++; XtSetArg(args[n], XmNborderColor, ss->basic_color); n++; size_frame = XtCreateManagedWidget("size-frame", xmFrameWidgetClass, mainform, args, n); n = 0; XtSetArg(args[n], XmNbackground, ss->basic_color); n++; n = attach_all_sides(args, n); size_form = XtCreateManagedWidget("size-form", xmFormWidgetClass, size_frame, args, n); n = 0; XtSetArg(args[n], XmNbackground, ss->highlight_color); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNalignment, XmALIGNMENT_CENTER); n++; size_label = XtCreateManagedWidget("size", xmLabelWidgetClass, size_form, args, n); n = 0; XtSetArg(args[n], XmNbackground, ss->basic_color); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNtopWidget, size_label); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNtopItemPosition, (size_pos > 2) ? (size_pos - 2) : size_pos); n++; size_list = XmCreateScrolledList(size_form, (char *)"size-list", args, n); XtVaSetValues(size_list, XmNbackground, ss->white, XmNforeground, ss->black, NULL); for (i = 0; i < NUM_TRANSFORM_SIZES; i++) sizes[i] = XmStringCreateLocalized((char *)transform_size_names[i]); XtVaSetValues(size_list, XmNitems, sizes, XmNitemCount, NUM_TRANSFORM_SIZES, XmNvisibleItemCount, 6, NULL); for (i = 0; i < NUM_TRANSFORM_SIZES; i++) XmStringFree(sizes[i]); XtManageChild(size_list); XtAddCallback(size_list, XmNbrowseSelectionCallback, size_browse_callback, NULL); /* -------- DISPLAY BOX BUTTONS -------- */ n = 0; XtSetArg(args[n], XmNbackground, ss->basic_color); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNleftWidget, size_frame); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNborderWidth, FRAME_BORDER_WIDTH); n++; XtSetArg(args[n], XmNborderColor, ss->basic_color); n++; display_frame = XtCreateManagedWidget("display-frame", xmFrameWidgetClass, mainform, args, n); n = 0; XtSetArg(args[n], XmNbackground, ss->zoom_color); n++; n = attach_all_sides(args, n); display_form = XtCreateManagedWidget("display-form", xmFormWidgetClass, display_frame, args, n); n = 0; XtSetArg(args[n], XmNbackground, ss->highlight_color); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNalignment, XmALIGNMENT_CENTER); n++; display_label = XtCreateManagedWidget("display", xmLabelWidgetClass, display_form, args, n); n = 0; XtSetArg(args[n], XmNbackground, ss->lighter_blue); n++; XtSetArg(args[n], XmNselectColor, ss->red); n++; bstr = XmStringCreateLocalized((char *)"single transform"); XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNtopWidget, display_label); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNlabelString, bstr); n++; XtSetArg(args[n], XmNalignment, XmALIGNMENT_BEGINNING); n++; XtSetArg(args[n], XmNindicatorType, XmONE_OF_MANY); n++; normo_button = make_togglebutton_widget("normo-button", display_form, args, n); XtAddCallback(normo_button, XmNdisarmCallback, graph_transform_once_callback, NULL); XmStringFree(bstr); n = 0; XtSetArg(args[n], XmNbackground, ss->lighter_blue); n++; XtSetArg(args[n], XmNselectColor, ss->red); n++; bstr = XmStringCreateLocalized((char *)"sonogram"); XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNtopWidget, normo_button); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNlabelString, bstr); n++; XtSetArg(args[n], XmNalignment, XmALIGNMENT_BEGINNING); n++; XtSetArg(args[n], XmNindicatorType, XmONE_OF_MANY); n++; sono_button = make_togglebutton_widget("sono-button", display_form, args, n); XtAddCallback(sono_button, XmNdisarmCallback, sonogram_callback, NULL); XmStringFree(bstr); n = 0; XtSetArg(args[n], XmNbackground, ss->lighter_blue); n++; XtSetArg(args[n], XmNselectColor, ss->red); n++; bstr = XmStringCreateLocalized((char *)"spectrogram"); XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNtopWidget, sono_button); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNlabelString, bstr); n++; XtSetArg(args[n], XmNalignment, XmALIGNMENT_BEGINNING); n++; XtSetArg(args[n], XmNindicatorType, XmONE_OF_MANY); n++; spectro_button = make_togglebutton_widget("spectro-button", display_form, args, n); XtAddCallback(spectro_button, XmNdisarmCallback, spectrogram_callback, NULL); XmStringFree(bstr); n = 0; XtSetArg(args[n], XmNbackground, ss->lighter_blue); n++; XtSetArg(args[n], XmNselectColor, ss->red); n++; bstr = XmStringCreateLocalized((char *)"peaks"); XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_POSITION); n++; XtSetArg(args[n], XmNrightPosition, 67); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNtopWidget, spectro_button); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNlabelString, bstr); n++; XtSetArg(args[n], XmNalignment, XmALIGNMENT_BEGINNING); n++; peaks_button = make_togglebutton_widget("peaks-button", display_form, args, n); XtAddCallback(peaks_button, XmNvalueChangedCallback, peaks_callback, NULL); XmStringFree(bstr); n = 0; XtSetArg(args[n], XmNbackground, ss->lighter_blue); n++; XtSetArg(args[n], XmNresizeWidth, false); n++; XtSetArg(args[n], XmNcolumns, 6); n++; XtSetArg(args[n], XmNrecomputeSize, false); n++; /* XtSetArg(args[n], XmNmarginHeight, 1); n++; */ XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNleftWidget, peaks_button); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_OPPOSITE_WIDGET); n++; XtSetArg(args[n], XmNtopWidget, peaks_button); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_OPPOSITE_WIDGET); n++; XtSetArg(args[n], XmNbottomWidget, peaks_button); n++; XtSetArg(args[n], XmNborderWidth, 0); n++; XtSetArg(args[n], XmNshadowThickness, 0); n++; peak_txt = make_textfield_widget("max-peaks", display_form, args, n, ACTIVATABLE, NO_COMPLETER); XtRemoveCallback(peak_txt, XmNlosingFocusCallback, textfield_unfocus_callback, NULL); XtAddCallback(peak_txt, XmNlosingFocusCallback, fft_blue_textfield_unfocus_callback, NULL); XtAddEventHandler(peak_txt, LeaveWindowMask, false, fft_blue_mouse_leave_text_callback, NULL); XtAddEventHandler(peak_txt, EnterWindowMask, false, fft_white_mouse_enter_text_callback, NULL); widget_int_to_text(peak_txt, max_transform_peaks(ss)); XtAddCallback(peak_txt, XmNactivateCallback, peaks_activate_callback, NULL); n = 0; XtSetArg(args[n], XmNbackground, ss->lighter_blue); n++; XtSetArg(args[n], XmNselectColor, ss->red); n++; bstr = XmStringCreateLocalized((char *)"dB"); XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_POSITION); n++; XtSetArg(args[n], XmNrightPosition, 67); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNtopWidget, peaks_button); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNlabelString, bstr); n++; XtSetArg(args[n], XmNalignment, XmALIGNMENT_BEGINNING); n++; db_button = make_togglebutton_widget("db-button", display_form, args, n); XtAddCallback(db_button, XmNvalueChangedCallback, fft_db_callback, NULL); XmStringFree(bstr); n = 0; XtSetArg(args[n], XmNbackground, ss->lighter_blue); n++; XtSetArg(args[n], XmNresizeWidth, false); n++; XtSetArg(args[n], XmNcolumns, 6); n++; XtSetArg(args[n], XmNrecomputeSize, false); n++; /* XtSetArg(args[n], XmNmarginHeight, 1); n++; */ XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNleftWidget, db_button); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_OPPOSITE_WIDGET); n++; XtSetArg(args[n], XmNtopWidget, db_button); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_OPPOSITE_WIDGET); n++; XtSetArg(args[n], XmNbottomWidget, db_button); n++; XtSetArg(args[n], XmNborderWidth, 0); n++; XtSetArg(args[n], XmNshadowThickness, 0); n++; db_txt = make_textfield_widget("db", display_form, args, n, ACTIVATABLE, NO_COMPLETER); XtRemoveCallback(db_txt, XmNlosingFocusCallback, textfield_unfocus_callback, NULL); XtAddCallback(db_txt, XmNlosingFocusCallback, fft_blue_textfield_unfocus_callback, NULL); XtAddEventHandler(db_txt, LeaveWindowMask, false, fft_blue_mouse_leave_text_callback, NULL); XtAddEventHandler(db_txt, EnterWindowMask, false, fft_white_mouse_enter_text_callback, NULL); widget_float_to_text(db_txt, min_dB(ss)); XtAddCallback(db_txt, XmNactivateCallback, min_db_activate_callback, NULL); n = 0; XtSetArg(args[n], XmNbackground, ss->lighter_blue); n++; XtSetArg(args[n], XmNselectColor, ss->red); n++; bstr = XmStringCreateLocalized((char *)"log freq"); XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_POSITION); n++; XtSetArg(args[n], XmNrightPosition, 67); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNtopWidget, db_button); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNlabelString, bstr); n++; XtSetArg(args[n], XmNalignment, XmALIGNMENT_BEGINNING); n++; logfreq_button = make_togglebutton_widget("logfreq-button", display_form, args, n); XtAddCallback(logfreq_button, XmNvalueChangedCallback, logfreq_callback, NULL); XmStringFree(bstr); n = 0; XtSetArg(args[n], XmNbackground, ss->lighter_blue); n++; XtSetArg(args[n], XmNresizeWidth, false); n++; XtSetArg(args[n], XmNcolumns, 6); n++; XtSetArg(args[n], XmNrecomputeSize, false); n++; /* XtSetArg(args[n], XmNmarginHeight, 1); n++; */ XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNleftWidget, logfreq_button); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_OPPOSITE_WIDGET); n++; XtSetArg(args[n], XmNtopWidget, logfreq_button); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_OPPOSITE_WIDGET); n++; XtSetArg(args[n], XmNbottomWidget, logfreq_button); n++; XtSetArg(args[n], XmNborderWidth, 0); n++; XtSetArg(args[n], XmNshadowThickness, 0); n++; freq_base_txt = make_textfield_widget("lfb", display_form, args, n, ACTIVATABLE, NO_COMPLETER); XtRemoveCallback(freq_base_txt, XmNlosingFocusCallback, textfield_unfocus_callback, NULL); XtAddCallback(freq_base_txt, XmNlosingFocusCallback, fft_blue_textfield_unfocus_callback, NULL); XtAddEventHandler(freq_base_txt, LeaveWindowMask, false, fft_blue_mouse_leave_text_callback, NULL); XtAddEventHandler(freq_base_txt, EnterWindowMask, false, fft_white_mouse_enter_text_callback, NULL); widget_float_to_text(freq_base_txt, log_freq_start(ss)); XtAddCallback(freq_base_txt, XmNactivateCallback, log_freq_start_activate_callback, NULL); n = 0; XtSetArg(args[n], XmNbackground, ss->lighter_blue); n++; XtSetArg(args[n], XmNselectColor, ss->red); n++; bstr = XmStringCreateLocalized((char *)"normalize"); XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNtopWidget, logfreq_button); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNlabelString, bstr); n++; XtSetArg(args[n], XmNalignment, XmALIGNMENT_BEGINNING); n++; normalize_button = make_togglebutton_widget("normalize-button", display_form, args, n); XtAddCallback(normalize_button, XmNvalueChangedCallback, normalize_callback, NULL); XmStringFree(bstr); n = 0; XtSetArg(args[n], XmNbackground, ss->lighter_blue); n++; XtSetArg(args[n], XmNselectColor, ss->red); n++; bstr = XmStringCreateLocalized((char *)"selection"); XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNtopWidget, normalize_button); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNlabelString, bstr); n++; XtSetArg(args[n], XmNalignment, XmALIGNMENT_BEGINNING); n++; selection_button1 = make_togglebutton_widget("selection-button", display_form, args, n); XtAddCallback(selection_button1, XmNvalueChangedCallback, selection_callback, NULL); XmStringFree(bstr); n = 0; XtSetArg(args[n], XmNbackground, ss->lighter_blue); n++; XtSetArg(args[n], XmNselectColor, ss->red); n++; bstr = XmStringCreateLocalized((char *)"with phases"); XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNtopWidget, selection_button1); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNlabelString, bstr); n++; XtSetArg(args[n], XmNalignment, XmALIGNMENT_BEGINNING); n++; phases_button = make_togglebutton_widget("phases-button", display_form, args, n); XtAddCallback(phases_button, XmNvalueChangedCallback, phases_callback, NULL); XmStringFree(bstr); /* -------- GRAPH -------- */ n = 0; XtSetArg(args[n], XmNbackground, ss->basic_color); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNleftWidget, wavelet_frame); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNtopWidget, display_frame); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNborderWidth, FRAME_BORDER_WIDTH); n++; XtSetArg(args[n], XmNborderColor, ss->basic_color); n++; graph_frame = XtCreateManagedWidget("graph-frame", xmFrameWidgetClass, mainform, args, n); n = 0; XtSetArg(args[n], XmNbackground, ss->basic_color); n++; n = attach_all_sides(args, n); graph_form = XtCreateManagedWidget("graph-form", xmFormWidgetClass, graph_frame, args, n); n = 0; XtSetArg(args[n], XmNbackground, ss->highlight_color); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNalignment, XmALIGNMENT_CENTER); n++; graph_label = XtCreateManagedWidget("window", xmLabelWidgetClass, graph_form, args, n); /* label should change according to what is being displayed */ n = 0; XtSetArg(args[n], XmNbackground, ss->basic_color); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNtopWidget, graph_label); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNseparatorType, XmSHADOW_ETCHED_IN); n++; XtSetArg(args[n], XmNorientation, XmHORIZONTAL); n++; gsep = XtCreateManagedWidget("gsep", xmSeparatorWidgetClass, graph_form, args, n); n = 0; XtSetArg(args[n], XmNbackground, ss->graph_color); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNtopWidget, gsep); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNallowResize, true); n++; graph_drawer = XtCreateManagedWidget("graph-drawer", xmDrawingAreaWidgetClass, graph_form, args, n); gv.function = GXcopy; XtVaGetValues(graph_drawer, XmNbackground, &gv.background, XmNforeground, &gv.foreground, NULL); gc2 = XtGetGC(graph_drawer, GCForeground | GCFunction, &gv); gv.foreground = ss->enved_waveform_color; fgc = XtGetGC(graph_drawer, GCForeground | GCFunction, &gv); XmToggleButtonSetState(normo_button, (Boolean)(transform_graph_type(ss) == GRAPH_ONCE), false); XmToggleButtonSetState(sono_button, (Boolean)(transform_graph_type(ss) == GRAPH_AS_SONOGRAM), false); XmToggleButtonSetState(spectro_button, (Boolean)(transform_graph_type(ss) == GRAPH_AS_SPECTROGRAM), false); XmToggleButtonSetState(peaks_button, (Boolean)(show_transform_peaks(ss)), false); XmToggleButtonSetState(db_button, (Boolean)(fft_log_magnitude(ss)), false); XmToggleButtonSetState(logfreq_button, (Boolean)(fft_log_frequency(ss)), false); XmToggleButtonSetState(normalize_button, (Boolean)(transform_normalization(ss) != DONT_NORMALIZE), false); XmToggleButtonSetState(selection_button1, (Boolean)(show_selection_transform(ss)), false); XmToggleButtonSetState(phases_button, (Boolean)(fft_with_phases(ss)), false); /* select current list choices */ /* display current windowing choice unless wavelet in force */ XmListSelectPos(type_list, transform_type_to_position(transform_type(ss)) + 1, false); XmListSelectPos(wavelet_list, wavelet_type(ss) + 1, false); XmListSelectPos(size_list, size_pos, false); XmListSelectPos(window_list, (int)fft_window(ss) + 1, false); if (spectrum_start(ss) != 0.0) set_spectrum_start_scale(spectrum_start(ss)); if (spectrum_end(ss) != 1.0) set_spectrum_end_scale(spectrum_end(ss)); if (fft_window_alpha(ss) != 0.0) set_alpha_scale(fft_window_alpha(ss)); if (fft_window_beta(ss) != 0.0) set_beta_scale(fft_window_beta(ss)); highlight_alpha_beta_scales(fft_window(ss)); free(n1); free(n2); free(n3); free(n4); set_dialog_widget(TRANSFORM_DIALOG, transform_dialog); XtUnmanageChild(error_frame1); } else { if (managed) raise_dialog(transform_dialog); } if (managed) { if (!XtIsManaged(transform_dialog)) XtManageChild(transform_dialog); } else XtUnmanageChild(transform_dialog); if ((need_callback) && (XtIsManaged(transform_dialog))) { set_label(graph_label, mus_fft_window_name(fft_window(ss))); get_fft_window_data(); XtAddCallback(graph_drawer, XmNresizeCallback, graph_resize_callback, NULL); XtAddCallback(graph_drawer, XmNexposeCallback, graph_resize_callback, NULL); need_callback = false; } return(transform_dialog); } bool transform_dialog_is_active(void) { return((transform_dialog) && (XtIsManaged(transform_dialog))); } /* -------- region browser -------- */ typedef struct { Widget rw, nm, pl; int pos; } regrow; static Widget region_dialog = NULL, region_list, region_grf; static regrow **region_rows = NULL; static int region_rows_size = 0; static snd_info *rsp = NULL; static int current_region = -1; static Widget reg_srtxt, reg_lentxt, reg_chntxt, reg_maxtxt; static Widget region_ww = NULL; static Widget mix_button = NULL, save_as_button = NULL, insert_button = NULL; static regrow *region_row(int n); static void set_current_region(int rg) { bool reg_ok = false; current_region = rg; reflect_region_in_save_as_dialog(); if (rg >= 0) reg_ok = region_ok(region_list_position_to_id(rg)); if (save_as_button) XtSetSensitive(save_as_button, reg_ok); if (mix_button) XtSetSensitive(mix_button, reg_ok); if (insert_button) XtSetSensitive(insert_button, reg_ok); } void reflect_regions_in_region_browser(void) { if (rsp) { uint32_t i; rsp->active = true; if (rsp->chans) for (i = 0; i < rsp->nchans; i++) rsp->chans[i]->active = CHANNEL_HAS_AXES; } } void reflect_no_regions_in_region_browser(void) { if (rsp) { uint32_t i; rsp->active = false; if (rsp->chans) for (i = 0; i < rsp->nchans; i++) rsp->chans[i]->active = CHANNEL_INACTIVE; } } static void region_update_graph(chan_info *cp) { if (current_region == -1) return; rsp->nchans = region_chans(region_list_position_to_id(current_region)); if (rsp->nchans == 0) return; update_graph(cp); rsp->nchans = 1; } void reflect_region_graph_style(void) { if (current_region == -1) return; if ((rsp) && (rsp->chans) && (rsp->chans[0]) && (region_dialog_is_active())) { rsp->chans[0]->time_graph_style = region_graph_style(ss); rsp->chans[0]->dot_size = dot_size(ss); /* update_graph(rsp->chans[0]); */ update_region_browser(true); } } static void unhighlight_region(void) { if (current_region != -1) { regrow *oldr; oldr = region_row(current_region); XtVaSetValues(oldr->rw, XmNbackground, ss->highlight_color, NULL); XtVaSetValues(oldr->nm, XmNbackground, ss->highlight_color, NULL); } } static void highlight_region(void) { if (current_region != -1) { regrow *oldr; oldr = region_row(current_region); XtVaSetValues(oldr->rw, XmNbackground, ss->zoom_color, NULL); XtVaSetValues(oldr->nm, XmNbackground, ss->zoom_color, NULL); } } static void make_region_labels(file_info *hdr) { char *str; if (!hdr) return; str = (char *)calloc(PRINT_BUFFER_SIZE, sizeof(char)); snprintf(str, PRINT_BUFFER_SIZE, "srate: %d", hdr->srate); set_label(reg_srtxt, str); snprintf(str, PRINT_BUFFER_SIZE, "chans: %d", hdr->chans); set_label(reg_chntxt, str); snprintf(str, PRINT_BUFFER_SIZE, "length: %.3f", ((double)(hdr->samples) / (double)(hdr->chans * hdr->srate))); set_label(reg_lentxt, str); snprintf(str, PRINT_BUFFER_SIZE, "maxamp: %.3f", region_maxamp(region_list_position_to_id(current_region))); set_label(reg_maxtxt, str); free(str); } int update_region_browser(bool grf_too) { int i, len; region_state *rs; rs = region_report(); len = rs->len; for (i = 0; i < len; i++) { regrow *r; r = region_row(i); set_button_label(r->nm, rs->name[i]); #if WITH_AUDIO XmToggleButtonSetState(r->pl, false, false); #endif XtManageChild(r->rw); } for (i = len; i < max_regions(ss); i++) if (region_rows[i]) XtUnmanageChild(region_rows[i]->rw); free_region_state(rs); if (len == 0) return(0); XtManageChild(region_list); if (grf_too) { chan_info *cp; unhighlight_region(); set_current_region(0); highlight_region(); goto_window(region_rows[0]->nm); cp = rsp->chans[0]; if (cp) { cp->sound = rsp; cp->chan = 0; set_sensitive(channel_f(cp), false); set_sensitive(channel_w(cp), (region_chans(region_list_position_to_id(0)) > 1)); rsp->hdr = fixup_region_data(cp, 0, 0); make_region_labels(rsp->hdr); region_update_graph(cp); } } return(len); } static void region_quit_callback(Widget w, XtPointer context, XtPointer info) { XtUnmanageChild(region_dialog); } bool region_browser_is_active(void) { return((region_dialog) && (XtIsRealized(region_dialog))); } static void region_resize_callback(Widget w, XtPointer context, XtPointer info) { region_update_graph((chan_info *)context); } void delete_region_and_update_browser(int pos) { int act; unhighlight_region(); act = remove_region_from_list(pos); if (act == INVALID_REGION) return; if (region_dialog) { if (act != NO_REGIONS) { set_current_region(0); highlight_region(); goto_window(region_rows[0]->nm); } else set_current_region(-1); update_region_browser(1); } } static void region_help_callback(Widget w, XtPointer context, XtPointer info) { region_dialog_help(); } static void region_insert_callback(Widget w, XtPointer context, XtPointer info) { if ((current_region != -1) && (selected_channel())) paste_region(region_list_position_to_id(current_region), selected_channel()); } static void region_mix_callback(Widget w, XtPointer context, XtPointer info) { if ((current_region != -1) && (selected_channel())) add_region(region_list_position_to_id(current_region), selected_channel()); } static void region_save_callback(Widget w, XtPointer context, XtPointer info) { if ((current_region != -1) && (XmGetFocusWidget(region_dialog) == XmMessageBoxGetChild(region_dialog, XmDIALOG_OK_BUTTON))) make_region_save_as_dialog(true); } static void region_up_arrow_callback(Widget w, XtPointer context, XtPointer info) { chan_info *cp; cp = rsp->chans[0]; cp->sound = rsp; if (cp->chan > 0) { cp->chan--; set_sensitive(channel_f(cp), (cp->chan > 0)); set_sensitive(channel_w(cp), true); fixup_region_data(cp, cp->chan, current_region); region_update_graph(cp); } } static void region_down_arrow_callback(Widget w, XtPointer context, XtPointer info) { chan_info *cp; cp = rsp->chans[0]; cp->sound = rsp; if ((cp->chan + 1) < region_chans(region_list_position_to_id(current_region))) { cp->chan++; set_sensitive(channel_f(cp), true); set_sensitive(channel_w(cp), (region_chans(region_list_position_to_id(current_region)) > (cp->chan + 1))); fixup_region_data(cp, cp->chan, current_region); region_update_graph(cp); } } static void region_focus_callback(Widget w, XtPointer context, XtPointer info) { static oclock_t mouse_down_time = 0; XmPushButtonCallbackStruct *cb = (XmPushButtonCallbackStruct *)info; XButtonEvent *ev; chan_info *cp; regrow *r = (regrow *)context; ev = (XButtonEvent *)(cb->event); if (mouse_down_time != 0) { if ((ev->time - mouse_down_time) < ss->click_time) /* edit region if double clicked */ { mouse_down_time = ev->time; if (current_region != -1) region_edit(current_region); return; } } mouse_down_time = ev->time; unhighlight_region(); if (region_list_position_to_id(r->pos) == INVALID_REGION) return; /* needed by auto-tester */ set_current_region(r->pos); cp = rsp->chans[0]; cp->sound = rsp; cp->chan = 0; highlight_region(); set_sensitive(channel_f(cp), false); set_sensitive(channel_w(cp), (region_chans(region_list_position_to_id(current_region)) > 1)); rsp->hdr = fixup_region_data(cp, 0, current_region); if (!rsp->hdr) return; make_region_labels(rsp->hdr); region_update_graph(cp); } void reflect_play_region_stop(int n) { #if WITH_AUDIO if (region_rows) { regrow *rg; rg = region_row(region_id_to_list_position(n)); if (rg) XmToggleButtonSetState(rg->pl, false, false); } #endif } static void region_play_callback(Widget w, XtPointer context, XtPointer info) { #if WITH_AUDIO regrow *r = (regrow *)context; if (XmToggleButtonGetState(r->pl)) play_region(region_list_position_to_id(r->pos), IN_BACKGROUND); else stop_playing_region(region_list_position_to_id(r->pos), PLAY_BUTTON_UNSET); #endif } static Xen reflect_file_in_region_browser(Xen hook_or_reason) { if (region_dialog) { bool file_on; file_on = (bool)(any_selected_sound()); set_sensitive(mix_button, file_on); set_sensitive(insert_button, file_on); } return(Xen_false); } static char *regrow_get_label(void *ur) { regrow *r = (regrow *)ur; return(get_label(r->nm)); } static int regrow_get_pos(void *ur) { regrow *r = (regrow *)ur; return(r->pos); } static void regrow_mouse_enter_label(Widget w, XtPointer context, XEvent *event, Boolean *flag) { mouse_enter_label(context, REGION_VIEWER); } static void regrow_mouse_leave_label(Widget w, XtPointer context, XEvent *event, Boolean *flag) { mouse_leave_label(context, REGION_VIEWER); } static regrow *make_regrow(Widget ww, Widget last_row, XtCallbackProc play_callback, XtCallbackProc name_callback) { int n; Arg args[32]; regrow *r; XmString s1; #if WITH_AUDIO XtCallbackList n1; #endif XtCallbackList n3; s1 = XmStringCreateLocalized((char *)""); r = (regrow *)calloc(1, sizeof(regrow)); n = 0; XtSetArg(args[n], XmNbackground, ss->highlight_color); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNtopAttachment, (last_row) ? XmATTACH_WIDGET : XmATTACH_FORM); n++; if (last_row) {XtSetArg(args[n], XmNtopWidget, last_row); n++;} XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNheight, 18); n++; r->rw = XtCreateWidget("rw", xmFormWidgetClass, ww, args, n); #if WITH_AUDIO n = 0; XtSetArg(args[n], XmNbackground, ss->highlight_color); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNselectColor, ss->selection_color); n++; XtSetArg(args[n], XmNlabelString, s1); n++; XtSetArg(args[n], XmNvalueChangedCallback, n1 = make_callback_list(play_callback, (XtPointer)r)); n++; if (ss->toggle_size > 0) {XtSetArg(args[n], XmNindicatorSize, ss->toggle_size); n++;} XtSetArg(args[n], XmNmarginWidth, 8); n++; r->pl = make_togglebutton_widget("pl", r->rw, args, n); #endif n = 0; XtSetArg(args[n], XmNbackground, ss->highlight_color); n++; #if WITH_AUDIO XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNleftWidget, r->pl); n++; #else XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++; #endif XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNshadowThickness, 0); n++; XtSetArg(args[n], XmNhighlightThickness, 0); n++; XtSetArg(args[n], XmNalignment, XmALIGNMENT_BEGINNING); n++; XtSetArg(args[n], XmNfillOnArm, false); n++; XtSetArg(args[n], XmNrecomputeSize, false); n++; XtSetArg(args[n], XmNwidth, 300); n++; XtSetArg(args[n], XmNactivateCallback, n3 = make_callback_list(name_callback, (XtPointer)r)); n++; r->nm = XtCreateManagedWidget("nm", xmPushButtonWidgetClass, r->rw, args, n); XmStringFree(s1); XtAddEventHandler(r->nm, EnterWindowMask, false, regrow_mouse_enter_label, (XtPointer)r); XtAddEventHandler(r->nm, LeaveWindowMask, false, regrow_mouse_leave_label, (XtPointer)r); #if WITH_AUDIO free(n1); #endif free(n3); return(r); } static void add_reflect_region_hook(void); static void make_region_dialog(void) { int n, i, id; Arg args[32]; Widget formw, last_row, infosep; Widget panes, toppane, sep1 = NULL, sep2; #if WITH_AUDIO Widget plw; #endif XmString xgo_away, xhelp, titlestr, xsave_as; regrow *r; chan_info *cp; xgo_away = XmStringCreateLocalized((char *)I_GO_AWAY); xhelp = XmStringCreateLocalized((char *)I_HELP); titlestr = XmStringCreateLocalized((char *)"Regions"); xsave_as = XmStringCreateLocalized((char *)"Save as"); n = 0; XtSetArg(args[n], XmNbackground, ss->basic_color); n++; XtSetArg(args[n], XmNcancelLabelString, xgo_away); n++; XtSetArg(args[n], XmNhelpLabelString, xhelp); n++; XtSetArg(args[n], XmNokLabelString, xsave_as); n++; XtSetArg(args[n], XmNautoUnmanage, false); n++; XtSetArg(args[n], XmNdialogTitle, titlestr); n++; XtSetArg(args[n], XmNresizePolicy, XmRESIZE_GROW); n++; XtSetArg(args[n], XmNnoResize, false); n++; XtSetArg(args[n], XmNtransient, false); n++; region_dialog = XmCreateTemplateDialog(main_shell(ss), (char *)"Regions", args, n); save_as_button = XmMessageBoxGetChild(region_dialog, XmDIALOG_OK_BUTTON); n = 0; XtSetArg(args[n], XmNbackground, ss->highlight_color); n++; XtSetArg(args[n], XmNarmColor, ss->selection_color); n++; insert_button = XtCreateManagedWidget("Insert", xmPushButtonGadgetClass, region_dialog, args, n); n = 0; XtSetArg(args[n], XmNbackground, ss->highlight_color); n++; XtSetArg(args[n], XmNarmColor, ss->selection_color); n++; mix_button = XtCreateManagedWidget("Mix", xmPushButtonGadgetClass, region_dialog, args, n); /* XtAddCallback(region_dialog, XmNokCallback, region_save_callback, NULL); */ XtAddCallback(save_as_button, XmNactivateCallback, region_save_callback, NULL); XtAddCallback(region_dialog, XmNcancelCallback, region_quit_callback, NULL); XtAddCallback(region_dialog, XmNhelpCallback, region_help_callback, NULL); XtAddCallback(mix_button, XmNactivateCallback, region_mix_callback, NULL); XtAddCallback(insert_button, XmNactivateCallback, region_insert_callback, NULL); XmStringFree(xhelp); XmStringFree(xgo_away); XmStringFree(xsave_as); XmStringFree(titlestr); XtVaSetValues(XmMessageBoxGetChild(region_dialog, XmDIALOG_OK_BUTTON), XmNarmColor, ss->selection_color, NULL); XtVaSetValues(XmMessageBoxGetChild(region_dialog, XmDIALOG_CANCEL_BUTTON), XmNarmColor, ss->selection_color, NULL); XtVaSetValues(XmMessageBoxGetChild(region_dialog, XmDIALOG_HELP_BUTTON), XmNarmColor, ss->selection_color, NULL); XtVaSetValues(XmMessageBoxGetChild(region_dialog, XmDIALOG_OK_BUTTON), XmNbackground, ss->highlight_color, NULL); XtVaSetValues(XmMessageBoxGetChild(region_dialog, XmDIALOG_CANCEL_BUTTON), XmNbackground, ss->highlight_color, NULL); XtVaSetValues(XmMessageBoxGetChild(region_dialog, XmDIALOG_HELP_BUTTON), XmNbackground, ss->highlight_color, NULL); insert_button = XmMessageBoxGetChild(region_dialog, XmDIALOG_CANCEL_BUTTON); n = 0; XtSetArg(args[n], XmNbackground, ss->basic_color); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNbottomWidget, XmMessageBoxGetChild(region_dialog, XmDIALOG_SEPARATOR)); n++; formw = XtCreateManagedWidget("formw", xmFormWidgetClass, region_dialog, args, n); n = 0; XtSetArg(args[n], XmNbackground, ss->basic_color); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNtopWidget, sep1); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNallowResize, true); n++; XtSetArg(args[n], XmNpaneMaximum, LOTSA_PIXELS); n++; panes = XtCreateManagedWidget("panes", xmPanedWindowWidgetClass, formw, args, n); n = 0; XtSetArg(args[n], XmNbackground, ss->basic_color); n++; n = attach_all_sides(args, n); XtSetArg(args[n], XmNpaneMinimum, 40); n++; toppane = XtCreateManagedWidget("toppane", xmFormWidgetClass, panes, args, n); #if WITH_AUDIO n = 0; XtSetArg(args[n], XmNbackground, ss->basic_color); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNalignment, XmALIGNMENT_BEGINNING); n++; plw = XtCreateManagedWidget("play", xmLabelWidgetClass, toppane, args, n); #endif n = 0; XtSetArg(args[n], XmNbackground, ss->basic_color); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNorientation, XmHORIZONTAL); n++; XtSetArg(args[n], XmNseparatorType, XmNO_LINE); n++; XtSetArg(args[n], XmNheight, 8); n++; sep2 = XtCreateManagedWidget("sep2", xmSeparatorWidgetClass, toppane, args, n); n = 0; XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_POSITION); n++; XtSetArg(args[n], XmNrightPosition, 70); n++; #if WITH_AUDIO XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNtopWidget, plw); n++; #else XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++; #endif XtSetArg(args[n], XmNbottomAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNbottomWidget, sep2); n++; XtSetArg(args[n], XmNscrollingPolicy, XmAUTOMATIC); n++; XtSetArg(args[n], XmNscrollBarDisplayPolicy, XmSTATIC); n++; region_list = XmCreateScrolledWindow(toppane, (char *)"reglist", args, n); n = attach_all_sides(args, 0); region_ww = XtCreateManagedWidget("ww", xmFormWidgetClass, region_list, args, n); XtVaSetValues(region_list, XmNworkWindow, region_ww, NULL); map_over_children(region_list, set_main_color_of_widget); last_row = NULL; region_rows = (regrow **)calloc(max_regions(ss), sizeof(regrow *)); region_rows_size = max_regions(ss); for (i = 0; i < max_regions(ss); i++) { r = make_regrow(region_ww, last_row, region_play_callback, region_focus_callback); region_rows[i] = r; r->pos = i; last_row = r->rw; } update_region_browser(0); n = 0; XtSetArg(args[n], XmNbackground, ss->basic_color); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNleftWidget, region_list); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_NONE); n++; #if WITH_AUDIO XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNtopWidget, plw); n++; #else XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++; #endif XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNorientation, XmVERTICAL); n++; XtSetArg(args[n], XmNseparatorType, XmNO_LINE); n++; XtSetArg(args[n], XmNwidth, 8); n++; infosep = XtCreateManagedWidget("infosep", xmSeparatorWidgetClass, toppane, args, n); n = 0; XtSetArg(args[n], XmNbackground, ss->highlight_color); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNleftWidget, infosep); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++; #if WITH_AUDIO XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNtopWidget, plw); n++; #else XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++; #endif XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNalignment, XmALIGNMENT_BEGINNING); n++; reg_srtxt = XtCreateManagedWidget("srate:", xmLabelWidgetClass, toppane, args, n); n = 0; XtSetArg(args[n], XmNbackground, ss->highlight_color); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNleftWidget, infosep); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNtopWidget, reg_srtxt); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNalignment, XmALIGNMENT_BEGINNING); n++; reg_chntxt = XtCreateManagedWidget("chans:", xmLabelWidgetClass, toppane, args, n); n = 0; XtSetArg(args[n], XmNbackground, ss->highlight_color); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNleftWidget, infosep); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNtopWidget, reg_chntxt); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNalignment, XmALIGNMENT_BEGINNING); n++; reg_lentxt = XtCreateManagedWidget("length:", xmLabelWidgetClass, toppane, args, n); n = 0; XtSetArg(args[n], XmNbackground, ss->highlight_color); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNleftWidget, infosep); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNtopWidget, reg_lentxt); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNalignment, XmALIGNMENT_BEGINNING); n++; reg_maxtxt = XtCreateManagedWidget("maxamp:", xmLabelWidgetClass, toppane, args, n); n = 0; XtSetArg(args[n], XmNbackground, ss->white); n++; n = attach_all_sides(args, n); XtSetArg(args[n], XmNpaneMinimum, 150); n++; region_grf = XtCreateManagedWidget("grf", xmFormWidgetClass, panes, args, n); XtManageChild(region_dialog); if (widget_width(region_dialog) < 400) set_widget_width(region_dialog, 400); id = region_list_position_to_id(0); rsp = make_simple_channel_display(region_srate(id), region_len(id), WITH_ARROWS, region_graph_style(ss), region_grf, WITHOUT_EVENTS); rsp->inuse = SOUND_REGION; set_current_region(0); cp = rsp->chans[0]; XtVaSetValues(region_rows[0]->nm, XmNbackground, ss->white, XmNforeground, ss->black, NULL); map_over_children(panes, color_sashes); XtVaSetValues(toppane, XmNpaneMinimum, 1, NULL); XtVaSetValues(region_grf, XmNpaneMinimum, 1, NULL); XtAddCallback(channel_graph(cp), XmNresizeCallback, region_resize_callback, (XtPointer)cp); XtAddCallback(channel_graph(cp), XmNexposeCallback, region_resize_callback, (XtPointer)cp); /* channel_f is up arrow, channel_w is down arrow */ XtAddCallback(channel_f(cp), XmNactivateCallback, region_up_arrow_callback, NULL); XtAddCallback(channel_w(cp), XmNactivateCallback, region_down_arrow_callback, NULL); set_sensitive(channel_f(cp), false); set_sensitive(channel_w(cp), (region_chans(region_list_position_to_id(0)) > 1)); cp->chan = 0; rsp->hdr = fixup_region_data(cp, 0, 0); make_region_labels(rsp->hdr); highlight_region(); region_update_graph(cp); add_reflect_region_hook(); set_dialog_widget(REGION_DIALOG, region_dialog); } static void view_region_callback(Widget w, XtPointer context, XtPointer info) { /* put up scrollable dialog describing/playing/editing the region list */ if (!region_dialog) make_region_dialog(); else raise_dialog(region_dialog); if (!XtIsManaged(region_dialog)) { set_current_region(0); XtManageChild(region_dialog); } } bool region_dialog_is_active(void) { return((region_dialog) && (XtIsManaged(region_dialog))); } void allocate_region_rows(int n) { if ((region_dialog) && (n > region_rows_size)) { int i; region_rows = (regrow **)realloc(region_rows, n * sizeof(regrow *)); for (i = region_rows_size; i < n; i++) region_rows[i] = NULL; region_rows_size = n; } } static regrow *region_row(int n) { if (n < region_rows_size) { regrow *r; if (!region_rows[n]) { r = make_regrow(region_ww, (n > 0) ? (region_rows[n - 1]->rw) : NULL, region_play_callback, region_focus_callback); region_rows[n] = r; r->pos = n; } return(region_rows[n]); } return(NULL); } static int region_dialog_region(void) { return(region_list_position_to_id(current_region)); } static Xen g_view_regions_dialog(void) { #define H_view_regions_dialog "(" S_view_regions_dialog "): start the region dialog" if (snd_regions() > 0) view_region_callback(main_pane(ss), NULL, NULL); return(Xen_wrap_widget(region_dialog)); } #include "snd-file.h" /* various file-related dialogs: File|Edit:Save-as File:Open|View File|Edit:Mix File:Insert File:Edit-Header File:New Info and Raw View:Files */ static void snd_sort(int sorter, sort_info **data, int len); /* -------------------------------- sorters -------------------------------- */ static mus_long_t file_bytes(const char *filename) { #ifndef _MSC_VER struct stat statbuf; if (stat(filename, &statbuf) >= 0) return(statbuf.st_size); return(0); #else int chan; mus_long_t bytes; chan = mus_file_open_read(filename); if (chan == -1) return(0); bytes = lseek(chan, 0L, SEEK_END); snd_close(chan, filename); return(bytes); #endif } /* sort files list by name (aphabetical), or some number (date written, size), or by xen proc */ static int sort_a_to_z(const void *a, const void *b) { sort_info *d1 = *(sort_info **)a; sort_info *d2 = *(sort_info **)b; return(strcmp(d1->filename, d2->filename)); } static int sort_z_to_a(const void *a, const void *b) { return(-sort_a_to_z(a, b)); } static int sort_small_to_big(const void *a, const void *b) { sort_info *d1 = *(sort_info **)a; sort_info *d2 = *(sort_info **)b; if (d1->samps > d2->samps) return(1); else { if (d1->samps == d2->samps) return(0); else return(-1); } } static int sort_big_to_small(const void *a, const void *b) { return(-sort_small_to_big(a, b)); } static int sort_new_to_old(const void *a, const void *b) { sort_info *d1 = *(sort_info **)a; sort_info *d2 = *(sort_info **)b; if (d1->time < d2->time) return(1); else { if (d1->time == d2->time) return(0); else return(-1); } } static int sort_old_to_new(const void *a, const void *b) { return(-sort_new_to_old(a, b)); } static Xen sorter_func; static int sort_xen(const void *a, const void *b) { /* sorter function gets two names, returns -1, 0, or 1 just like the other comparators */ sort_info *d1 = *(sort_info **)a; sort_info *d2 = *(sort_info **)b; return(Xen_integer_to_C_int(Xen_call_with_2_args(sorter_func, C_string_to_Xen_string(d1->full_filename), C_string_to_Xen_string(d2->full_filename), "sort func"))); } static void snd_sort(int sorter, sort_info **data, int len) { int i, sorter_pos; switch (sorter) { case SORT_A_TO_Z: qsort((void *)data, len, sizeof(sort_info *), sort_a_to_z); break; case SORT_Z_TO_A: qsort((void *)data, len, sizeof(sort_info *), sort_z_to_a); break; case SORT_NEW_TO_OLD: for (i = 0; i < len; i++) data[i]->time = file_write_date(data[i]->full_filename); qsort((void *)data, len, sizeof(sort_info *), sort_new_to_old); break; case SORT_OLD_TO_NEW: for (i = 0; i < len; i++) data[i]->time = file_write_date(data[i]->full_filename); qsort((void *)data, len, sizeof(sort_info *), sort_old_to_new); break; case SORT_SMALL_TO_BIG: for (i = 0; i < len; i++) data[i]->samps = file_bytes(data[i]->full_filename); qsort((void *)data, len, sizeof(sort_info *), sort_small_to_big); break; case SORT_BIG_TO_SMALL: for (i = 0; i < len; i++) data[i]->samps = file_bytes(data[i]->full_filename); qsort((void *)data, len, sizeof(sort_info *), sort_big_to_small); break; default: case SORT_XEN: /* sorter is SORT_XEN + index into file_sorters list */ /* that list is a vector of pairs (name proc) */ sorter_pos = sorter - SORT_XEN; if ((sorter_pos >= 0) && (sorter_pos < ss->file_sorters_size)) { if (Xen_is_list(Xen_vector_ref(ss->file_sorters, sorter_pos))) { sorter_func = Xen_cadr(Xen_vector_ref(ss->file_sorters, sorter_pos)); qsort((void *)data, len, sizeof(sort_info *), sort_xen); return; } } snd_warning("no such file-sorter (%d)", sorter_pos); break; } } static void dialog_set_title(widget_t dialog, const char *titlestr) { XmString title; title = XmStringCreateLocalized((char *)titlestr); XtVaSetValues(dialog, XmNdialogTitle, title, NULL); XmStringFree(title); } void cleanup_file_monitor(void) {} static bool initialize_file_monitor(void) {return(false);} void *unmonitor_file(void *watcher) {return(NULL);} void monitor_sound(snd_info *sp) {} /* -------------------------------------------------------------------------------- */ #define FSB_BOX(Dialog, Child) XmFileSelectionBoxGetChild(Dialog, Child) #define MSG_BOX(Dialog, Child) XmMessageBoxGetChild(Dialog, Child) /* ---------------- open/mix/insert/save-as dialogs ---------------- */ static void color_file_selection_box(Widget w) { /* overwrite most Motif-default colors */ Widget wtmp; map_over_children(w, set_main_color_of_widget); XtVaSetValues(FSB_BOX(w, XmDIALOG_DIR_LIST), XmNbackground, ss->white, XmNforeground, ss->black, NULL); XtVaSetValues(FSB_BOX(w, XmDIALOG_LIST), XmNbackground, ss->white, XmNforeground, ss->black, NULL); XtVaSetValues(FSB_BOX(w, XmDIALOG_CANCEL_BUTTON), XmNarmColor, ss->selection_color, NULL); XtVaSetValues(FSB_BOX(w, XmDIALOG_HELP_BUTTON), XmNarmColor, ss->selection_color, NULL); XtVaSetValues(FSB_BOX(w, XmDIALOG_OK_BUTTON), XmNarmColor, ss->selection_color, NULL); XtVaSetValues(FSB_BOX(w, XmDIALOG_CANCEL_BUTTON), XmNbackground, ss->highlight_color, NULL); XtVaSetValues(FSB_BOX(w, XmDIALOG_HELP_BUTTON), XmNbackground, ss->highlight_color, NULL); XtVaSetValues(FSB_BOX(w, XmDIALOG_OK_BUTTON), XmNbackground, ss->highlight_color, NULL); wtmp = FSB_BOX(w, XmDIALOG_TEXT); if (wtmp) { XtVaSetValues(wtmp, XmNhighlightThickness, 1, NULL); XtAddCallback(wtmp, XmNfocusCallback, textfield_focus_callback, NULL); XtAddCallback(wtmp, XmNlosingFocusCallback, textfield_unfocus_callback, NULL); XtAddEventHandler(wtmp, EnterWindowMask, false, mouse_enter_text_callback, NULL); XtAddEventHandler(wtmp, LeaveWindowMask, false, mouse_leave_text_callback, NULL); } wtmp = FSB_BOX(w, XmDIALOG_FILTER_TEXT); if (wtmp) { XtVaSetValues(wtmp, XmNhighlightThickness, 1, NULL); XtAddCallback(wtmp, XmNfocusCallback, textfield_focus_callback, NULL); XtAddCallback(wtmp, XmNlosingFocusCallback, textfield_unfocus_callback, NULL); XtAddEventHandler(wtmp, EnterWindowMask, false, mouse_enter_text_callback, NULL); XtAddEventHandler(wtmp, LeaveWindowMask, false, mouse_leave_text_callback, NULL); } } static void force_directory_reread(Widget dialog) { /* force update, but make sure the filename is not reset to its (dumb) default */ XmString dirmask; Widget name_field; char *filename = NULL; name_field = FSB_BOX(dialog, XmDIALOG_TEXT); filename = XmTextGetString(name_field); XtVaGetValues(dialog, XmNdirMask, &dirmask, NULL); XmFileSelectionDoSearch(dialog, dirmask); XmStringFree(dirmask); XmTextSetString(name_field, filename); if (filename) { XmTextSetCursorPosition(name_field, mus_strlen(filename)); XtFree(filename); } } static void force_directory_reread_and_let_filename_change(Widget dialog) { XmString dirmask; XtVaGetValues(dialog, XmNdirMask, &dirmask, NULL); XmFileSelectionDoSearch(dialog, dirmask); XmStringFree(dirmask); } /* -------------------------------- file list positioning -------------------------------- */ typedef struct { char *directory_name; position_t list_top; } dirpos_info; typedef struct { dirpos_info **dirs; int size, top; } dirpos_list; void dirpos_update(dirpos_list *dl, const char *dir, position_t pos); position_t dirpos_list_top(dirpos_list *dl, const char *dirname); dirpos_list *make_dirpos_list(void); static dirpos_info *make_dirpos_info(const char *dir, position_t pos) { dirpos_info *dp; dp = (dirpos_info *)calloc(1, sizeof(dirpos_info)); dp->directory_name = mus_strdup(dir); dp->list_top = pos; return(dp); } dirpos_list *make_dirpos_list(void) { dirpos_list *dl; dl = (dirpos_list *)calloc(1, sizeof(dirpos_list)); dl->size = 8; dl->top = 0; dl->dirs = (dirpos_info **)calloc(dl->size, sizeof(dirpos_info *)); return(dl); } void dirpos_update(dirpos_list *dl, const char *dir, position_t pos) { int i; if (!dl) return; for (i = 0; i < dl->top; i++) { if ((dl->dirs[i]) && (mus_strcmp(dir, dl->dirs[i]->directory_name))) { dirpos_info *dp; dp = dl->dirs[i]; dp->list_top = pos; return; } } if (dl->top >= dl->size) { int old_size; old_size = dl->size; dl->size += 8; dl->dirs = (dirpos_info **)realloc(dl->dirs, dl->size * sizeof(dirpos_info *)); for (i = old_size; i < dl->size; i++) dl->dirs[i] = NULL; } dl->dirs[dl->top++] = make_dirpos_info(dir, pos); } position_t dirpos_list_top(dirpos_list *dl, const char *dirname) { int i; if (dl) for (i = 0; i < dl->top; i++) if ((dl->dirs[i]) && (mus_strcmp(dirname, dl->dirs[i]->directory_name))) return(dl->dirs[i]->list_top); return(POSITION_UNKNOWN); } /* -------- popups -------- */ /* I think there is no way to get a key action to popup one of these menus -- Xm/RowColumn.c * appears to insist on a button event, and any change to that via XmNmenuPost gets an * error. Perhaps we should notice the POPUP_BUTTON setting however? */ typedef struct file_pattern_info { /* just-sounds file lists */ bool reread_directory; bool in_just_sounds_update; Widget dialog, just_sounds_button; char *last_dir; dir_info *current_files; void *directory_watcher; int filter_choice, sorter_choice; dirpos_list *dir_list; } file_pattern_info; /* popups: * text: history of previous choices, * list: sort and filter choices * dir: higher level dir choices * filter: history of previous choices */ typedef struct file_popup_info { Widget dialog; Widget file_text_popup, file_list_popup, file_dir_popup, file_filter_popup; Widget file_text_popup_label, file_filter_popup_label, file_dir_popup_label, file_list_popup_label; /* file_filter here refers to the dialog filter field, not file-filters */ char **file_text_names, **file_filter_names; /* history of choices as array of strings */ Widget *file_text_items, *file_filter_items, *file_dir_items, *file_list_items; /* menu items */ int file_list_items_size; file_pattern_info *fp; } file_popup_info; /* file popup */ static void file_text_item_activate_callback(Widget w, XtPointer context, XtPointer info) { file_popup_info *fd = (file_popup_info *)context; char *filename; snd_info *sp; filename = get_label(w); XmTextFieldSetString(FSB_BOX(fd->dialog, XmDIALOG_TEXT), filename); ss->open_requestor = FROM_OPEN_DIALOG_POPUP; ss->open_requestor_data = NULL; sp = snd_open_file(filename, FILE_READ_WRITE); if (sp) select_channel(sp, 0); XtUnmanageChild(fd->dialog); if (filename) XtFree(filename); } #define FILE_TEXT_POPUP_LABEL "previous files" static void file_text_popup_callback(Widget w, XtPointer context, XtPointer info) { file_popup_info *fd = (file_popup_info *)context; XmPopupHandlerCallbackStruct *cb = (XmPopupHandlerCallbackStruct *)info; XEvent *e; e = cb->event; if (e->type == ButtonPress) { /* position menu to match current text widget, show previous choices, if any else "[no previous choices]" */ /* XmMenuPosition(popup_menu, event) happens automatically */ char *current_filename; int i, filenames_to_display = 0; if (!fd->file_text_items) { int n = 0; Arg args[12]; fd->file_text_items = (Widget *)calloc(FILENAME_LIST_SIZE, sizeof(Widget)); XtSetArg(args[n], XmNbackground, ss->lighter_blue); n++; for (i = 0; i < FILENAME_LIST_SIZE; i++) { fd->file_text_items[i] = XtCreateWidget("", xmPushButtonWidgetClass, fd->file_text_popup, args, n); XtAddCallback(fd->file_text_items[i], XmNactivateCallback, file_text_item_activate_callback, (void *)fd); } } current_filename = XmTextFieldGetString(FSB_BOX(fd->dialog, XmDIALOG_TEXT)); /* w is probably ok here (assumes only text triggers this) */ for (i = 0; i < FILENAME_LIST_SIZE; i++) if ((fd->file_text_names[i]) && (mus_file_probe(fd->file_text_names[i])) && (!(mus_strcmp(fd->file_text_names[i], current_filename)))) { set_label(fd->file_text_items[filenames_to_display], fd->file_text_names[i]); XtManageChild(fd->file_text_items[filenames_to_display]); filenames_to_display++; } for (i = filenames_to_display; i < FILENAME_LIST_SIZE; i++) if ((fd->file_text_items[i]) && (XtIsManaged(fd->file_text_items[i]))) XtUnmanageChild(fd->file_text_items[i]); XtFree(current_filename); /* why was this commented out? */ if (filenames_to_display == 0) set_label(fd->file_text_popup_label, "no " FILE_TEXT_POPUP_LABEL); else set_label(fd->file_text_popup_label, FILE_TEXT_POPUP_LABEL); cb->menuToPost = fd->file_text_popup; } } /* filter popup */ static void file_filter_text_activate_callback(Widget w, XtPointer context, XtPointer info) { file_popup_info *fd = (file_popup_info *)context; char *filter; filter = XmTextFieldGetString(w); if (filter) { remember_filename(filter, fd->file_filter_names); XtFree(filter); force_directory_reread_and_let_filename_change(fd->dialog); } } static void file_filter_item_activate_callback(Widget w, XtPointer context, XtPointer info) { file_popup_info *fd = (file_popup_info *)context; Widget text; char *filtername; filtername = get_label(w); text = FSB_BOX(fd->dialog, XmDIALOG_FILTER_TEXT); XmTextFieldSetString(text, filtername); force_directory_reread(fd->dialog); if (filtername) XtFree(filtername); } #define FILE_FILTER_POPUP_LABEL "previous filters" static void file_filter_popup_callback(Widget w, XtPointer context, XtPointer info) { file_popup_info *fd = (file_popup_info *)context; XmPopupHandlerCallbackStruct *cb = (XmPopupHandlerCallbackStruct *)info; XEvent *e; e = cb->event; if (e->type == ButtonPress) { char *current_filtername; int i, filternames_to_display = 0; if (!fd->file_filter_items) { int n = 0; Arg args[12]; fd->file_filter_items = (Widget *)calloc(FILENAME_LIST_SIZE, sizeof(Widget)); XtSetArg(args[n], XmNbackground, ss->lighter_blue); n++; for (i = 0; i < FILENAME_LIST_SIZE; i++) { fd->file_filter_items[i] = XtCreateWidget("", xmPushButtonWidgetClass, fd->file_filter_popup, args, n); XtAddCallback(fd->file_filter_items[i], XmNactivateCallback, file_filter_item_activate_callback, (void *)fd); } } current_filtername = XmTextFieldGetString(FSB_BOX(fd->dialog, XmDIALOG_FILTER_TEXT)); for (i = 0; i < FILENAME_LIST_SIZE; i++) if ((fd->file_filter_names[i]) && (!(mus_strcmp(fd->file_filter_names[i], current_filtername)))) { set_label(fd->file_filter_items[filternames_to_display], fd->file_filter_names[i]); XtManageChild(fd->file_filter_items[filternames_to_display]); filternames_to_display++; } for (i = filternames_to_display; i < FILENAME_LIST_SIZE; i++) if ((fd->file_filter_items[i]) && (XtIsManaged(fd->file_filter_items[i]))) XtUnmanageChild(fd->file_filter_items[i]); XtFree(current_filtername); /* if (filternames_to_display == 0) set_label(fd->file_filter_popup_label, "no " FILE_FILTER_POPUP_LABEL); else set_label(fd->file_filter_popup_label, FILE_FILTER_POPUP_LABEL); */ cb->menuToPost = fd->file_filter_popup; } } /* dir list popup */ static void update_dir_list(Widget dialog, char *filter) { Widget text; text = FSB_BOX(dialog, XmDIALOG_FILTER_TEXT); XmTextFieldSetString(text, filter); force_directory_reread(dialog); } static void file_dir_item_activate_callback(Widget w, XtPointer context, XtPointer info) { file_popup_info *fd = (file_popup_info *)context; char *name, *filter; name = get_label(w); filter = mus_format("%s/*", name); update_dir_list(fd->dialog, filter); if (name) XtFree(name); free(filter); } #define FILE_DIR_POPUP_LABEL "dirs" /* dir_items, but strs generated on the fly, current in filter text */ static void file_dir_popup_callback(Widget w, XtPointer context, XtPointer info) { file_popup_info *fd = (file_popup_info *)context; XmPopupHandlerCallbackStruct *cb = (XmPopupHandlerCallbackStruct *)info; XEvent *e; e = cb->event; if (e->type == ButtonPress) { char *current_filename = NULL; int i, dirs_to_display = 0; if (!fd->file_dir_items) { int n = 0; Arg args[12]; fd->file_dir_items = (Widget *)calloc(FILENAME_LIST_SIZE, sizeof(Widget)); XtSetArg(args[n], XmNbackground, ss->lighter_blue); n++; for (i = 0; i < FILENAME_LIST_SIZE; i++) { fd->file_dir_items[i] = XtCreateWidget("", xmPushButtonWidgetClass, fd->file_dir_popup, args, n); XtAddCallback(fd->file_dir_items[i], XmNactivateCallback, file_dir_item_activate_callback, (void *)fd); } } { XmStringTable items; int num_dirs; XtVaGetValues(fd->dialog, XmNdirListItems, &items, XmNdirListItemCount, &num_dirs, NULL); if (num_dirs > 0) current_filename = (char *)XmStringUnparse(items[0], NULL, XmCHARSET_TEXT, XmCHARSET_TEXT, NULL, 0, XmOUTPUT_ALL); } if (!current_filename) { current_filename = XmTextFieldGetString(FSB_BOX(fd->dialog, XmDIALOG_FILTER_TEXT)); if (!current_filename) current_filename = XmTextFieldGetString(FSB_BOX(fd->dialog, XmDIALOG_TEXT)); } if (current_filename) { int len; len = strlen(current_filename); for (i = 0; i < len; i++) if (current_filename[i] == '/') dirs_to_display++; if (dirs_to_display > FILENAME_LIST_SIZE) dirs_to_display = FILENAME_LIST_SIZE; if (dirs_to_display > 0) { char **dirs; int j = 1; dirs = (char **)calloc(dirs_to_display, sizeof(char *)); dirs[0] = mus_strdup("/"); for (i = 1; i < len; i++) if (current_filename[i] == '/') { dirs[j] = (char *)calloc(i + 1, sizeof(char)); memcpy(dirs[j], (const char *)current_filename, i); j++; } for (i = 0; i < dirs_to_display; i++) { set_label(fd->file_dir_items[i], dirs[i]); XtManageChild(fd->file_dir_items[i]); free(dirs[i]); } free(dirs); } } for (i = dirs_to_display; i < FILENAME_LIST_SIZE; i++) if ((fd->file_dir_items[i]) && (XtIsManaged(fd->file_dir_items[i]))) XtUnmanageChild(fd->file_dir_items[i]); XtFree(current_filename); cb->menuToPost = fd->file_dir_popup; } } #define FILE_LIST_POPUP_LABEL "sort/filter" #define NO_FILTER_LABEL "no filter" #define FILE_FILTER_OFFSET 1024 #define NO_FILE_FILTER_OFFSET 2048 static void sort_files_and_redisplay(file_pattern_info *fp); static void file_list_item_activate_callback(Widget w, XtPointer context, XtPointer info) { file_popup_info *fd = (file_popup_info *)context; intptr_t data; int choice; XtVaGetValues(w, XmNuserData, &data, NULL); choice = (int)data; if (choice >= FILE_FILTER_OFFSET) { XmToggleButtonSetState(fd->fp->just_sounds_button, false, false); if (choice == NO_FILE_FILTER_OFFSET) fd->fp->filter_choice = NO_FILE_FILTER; else fd->fp->filter_choice = choice - FILE_FILTER_OFFSET + 2; fd->fp->in_just_sounds_update = true; force_directory_reread(fd->fp->dialog); fd->fp->in_just_sounds_update = false; } else { fd->fp->sorter_choice = choice; sort_files_and_redisplay(fd->fp); } } static Widget make_file_list_item(file_popup_info *fd, int choice) { int n; Arg args[12]; const char *item_label; Widget w; n = 0; XtSetArg(args[n], XmNbackground, ss->lighter_blue); n++; switch (choice) { case 0: item_label = "a..z"; break; case 1: item_label = "z..a"; break; case 2: item_label = "new..old"; break; case 3: item_label = "old..new"; break; case 4: item_label = "small..big"; break; case 5: item_label = "big..small"; break; default: item_label = "unused"; break; } XtSetArg(args[n], XmNuserData, choice); /* userData is index into sorters list */ w = XtCreateManagedWidget(item_label, xmPushButtonWidgetClass, fd->file_list_popup, args, n + 1); XtAddCallback(w, XmNactivateCallback, file_list_item_activate_callback, (void *)fd); return(w); } static void file_list_popup_callback(Widget w, XtPointer context, XtPointer info) { file_popup_info *fd = (file_popup_info *)context; XmPopupHandlerCallbackStruct *cb = (XmPopupHandlerCallbackStruct *)info; XEvent *e; e = cb->event; if (e->type == ButtonPress) { int i; if (!fd->file_list_items) { /* set up the default menu items */ fd->file_list_items = (Widget *)calloc(SORT_XEN, sizeof(Widget)); fd->file_list_items_size = SORT_XEN; for (i = 0; i < SORT_XEN; i++) fd->file_list_items[i] = make_file_list_item(fd, i); } /* clear any trailers just in case */ if (fd->file_list_items_size > SORT_XEN) for (i = SORT_XEN; i < fd->file_list_items_size; i++) XtUnmanageChild(fd->file_list_items[i]); /* check for added sort and filter functions (allocate more items if needed) */ { int extra_sorters = 0, extra_filters = 0, items_len; for (i = 0; i < ss->file_sorters_size; i++) if (!(Xen_is_false(Xen_vector_ref(ss->file_sorters, i)))) extra_sorters++; for (i = 0; i < ss->file_filters_size; i++) if (!(Xen_is_false(Xen_vector_ref(ss->file_filters, i)))) extra_filters++; items_len = SORT_XEN + extra_sorters + extra_filters; if (fd->fp->filter_choice != NO_FILE_FILTER) items_len++; if (items_len > fd->file_list_items_size) { fd->file_list_items = (Widget *)realloc(fd->file_list_items, items_len * sizeof(Widget)); for (i = fd->file_list_items_size; i < items_len; i++) fd->file_list_items[i] = make_file_list_item(fd, i); fd->file_list_items_size = items_len; } } /* make sure all the added sorter labels are correct, bg blue, and items active */ if (fd->file_list_items_size > SORT_XEN) { int k = SORT_XEN; /* sorters */ for (i = 0; i < ss->file_sorters_size; i++) { if (!(Xen_is_false(Xen_vector_ref(ss->file_sorters, i)))) { set_label(fd->file_list_items[k], Xen_string_to_C_string(Xen_car(Xen_vector_ref(ss->file_sorters, i)))); XtVaSetValues(fd->file_list_items[k], XmNbackground, ss->lighter_blue, XmNuserData, SORT_XEN + i, NULL); if (!(XtIsManaged(fd->file_list_items[k]))) XtManageChild(fd->file_list_items[k]); k++; } } for (i = 0; i < ss->file_filters_size; i++) { if (!(Xen_is_false(Xen_vector_ref(ss->file_filters, i)))) { set_label(fd->file_list_items[k], Xen_string_to_C_string(Xen_car(Xen_vector_ref(ss->file_filters, i)))); XtVaSetValues(fd->file_list_items[k], XmNbackground, ss->light_blue, XmNuserData, i + FILE_FILTER_OFFSET, NULL); if (!(XtIsManaged(fd->file_list_items[k]))) XtManageChild(fd->file_list_items[k]); k++; } } /* add "no filter" item if currently filtered */ if (fd->fp->filter_choice != NO_FILE_FILTER) { set_label(fd->file_list_items[k], NO_FILTER_LABEL); XtVaSetValues(fd->file_list_items[k], XmNbackground, ss->light_blue, XmNuserData, NO_FILE_FILTER_OFFSET, NULL); if (!(XtIsManaged(fd->file_list_items[k]))) XtManageChild(fd->file_list_items[k]); } } cb->menuToPost = fd->file_list_popup; } } static void add_file_popups(file_popup_info *fd) { int n; Arg args[20]; /* from lib/Xm.RCPopup.c: * When a user creates a new popup menu then we will install a particular * event handler on the menu's widget parent. Along with this we install * a grab on the button specified in XmNmenuPost or XmNwhichButton. [XmNmenuPost is a string = translation table syntax, is default] * [XmNwhichButton is obsolete] * The posting algorithm is as follows: * * 1. On receipt of a posting event, the handler will search the child * list for a candidate widget or gadget, and track the most specific * popup menu available (these can be found in the popup list). The * criteria for a match includes matching the XmNmenuPost information. * * 2. Matching criteria include: * * * The menu must have XmNpopupEnabled set to either * XmPOPUP_AUTOMATIC or XmPOPUP_AUTOMATIC_RECURSIVE. * * * The popup menu is chosen according to creation order. If there is * more than one, the first correct match is chosen. * * * If the popup menu is found in a parent of the target widget, and * the popup menu must also have XmNpopupEnabled set to * XmPOPUP_AUTOMATIC_RECURSIVE to match. [sigh -- no one actually reads comments...] * * 3. Once a selection is made, if the menu's parent widget has a * popupHandlerCallback, it is invoked. The callback allows the user to * determine if a more specific menu is necessary, such as would be the * case in a graphical manipulation environment, and includes all the * necessary information. * */ n = 0; XtSetArg(args[n], XmNbackground, ss->highlight_color); n++; XtSetArg(args[n], XmNpopupEnabled, XmPOPUP_AUTOMATIC); n++; /* file text */ XtAddCallback(FSB_BOX(fd->dialog, XmDIALOG_TEXT), XmNpopupHandlerCallback, file_text_popup_callback, (void *)fd); fd->file_text_popup = XmCreatePopupMenu(FSB_BOX(fd->dialog, XmDIALOG_TEXT), (char *)"file-text-popup", args, n); fd->file_text_names = make_filename_list(); fd->file_text_popup_label = XtCreateManagedWidget(FILE_TEXT_POPUP_LABEL, xmLabelWidgetClass, fd->file_text_popup, args, n); XtCreateManagedWidget("sep", xmSeparatorWidgetClass, fd->file_text_popup, args, n); /* filter text */ XtAddCallback(FSB_BOX(fd->dialog, XmDIALOG_FILTER_TEXT), XmNpopupHandlerCallback, file_filter_popup_callback, (void *)fd); fd->file_filter_popup = XmCreatePopupMenu(FSB_BOX(fd->dialog, XmDIALOG_FILTER_TEXT), (char *)"file-filter-popup", args, n); fd->file_filter_names = make_filename_list(); fd->file_filter_popup_label = XtCreateManagedWidget(FILE_FILTER_POPUP_LABEL, xmLabelWidgetClass, fd->file_filter_popup, args, n); XtCreateManagedWidget("sep", xmSeparatorWidgetClass, fd->file_filter_popup, args, n); { char *startup_filter; startup_filter = XmTextFieldGetString(FSB_BOX(fd->dialog, XmDIALOG_FILTER_TEXT)); if (startup_filter) { remember_filename(startup_filter, fd->file_filter_names); XtFree(startup_filter); } } XtAddCallback(FSB_BOX(fd->dialog, XmDIALOG_FILTER_TEXT), XmNactivateCallback, file_filter_text_activate_callback, (void *)fd); /* file directory */ XtAddCallback(FSB_BOX(fd->dialog, XmDIALOG_DIR_LIST), XmNpopupHandlerCallback, file_dir_popup_callback, (void *)fd); fd->file_dir_popup = XmCreatePopupMenu(FSB_BOX(fd->dialog, XmDIALOG_DIR_LIST), (char *)"file-dir-popup", args, n); fd->file_dir_popup_label = XtCreateManagedWidget(FILE_DIR_POPUP_LABEL, xmLabelWidgetClass, fd->file_dir_popup, args, n); XtCreateManagedWidget("sep", xmSeparatorWidgetClass, fd->file_dir_popup, args, n); /* file list */ XtAddCallback(FSB_BOX(fd->dialog, XmDIALOG_LIST), XmNpopupHandlerCallback, file_list_popup_callback, (void *)fd); fd->file_list_popup = XmCreatePopupMenu(FSB_BOX(fd->dialog, XmDIALOG_LIST), (char *)"file-list-popup", args, n); fd->file_list_popup_label = XtCreateManagedWidget(FILE_LIST_POPUP_LABEL, xmLabelWidgetClass, fd->file_list_popup, args, n); XtCreateManagedWidget("sep", xmSeparatorWidgetClass, fd->file_list_popup, args, n); } /* ---------------- just-sounds (file-filters) ---------------- */ static void file_change_directory_callback(Widget w, XtPointer context, XtPointer info) { /* click in directory list */ file_pattern_info *fp = (file_pattern_info *)context; char *leaving_dir; { /* save current directory list position */ position_t position = 0; XmString *strs = NULL; XtVaGetValues(w, XmNtopItemPosition, &position, XmNselectedItems, &strs, NULL); if ((strs) && (position > 1)) /* 1 = .. */ { char *filename = NULL; filename = (char *)XmStringUnparse(strs[0], NULL, XmCHARSET_TEXT, XmCHARSET_TEXT, NULL, 0, XmOUTPUT_ALL); dirpos_update(fp->dir_list, filename, position); XtFree(filename); } } leaving_dir = mus_strdup(fp->last_dir); if ((leaving_dir) && (leaving_dir[strlen(leaving_dir) - 1] == '/')) leaving_dir[strlen(leaving_dir) - 1] = 0; fp->reread_directory = true; force_directory_reread_and_let_filename_change(fp->dialog); fp->reread_directory = false; if (leaving_dir) { position_t pos; pos = dirpos_list_top(fp->dir_list, leaving_dir); if (pos != POSITION_UNKNOWN) XmListSetPos(w, pos); free(leaving_dir); } } static void sort_files_and_redisplay(file_pattern_info *fp) { /* if just sorting, no need to read the directory */ dir_info *cur_dir; cur_dir = fp->current_files; if (cur_dir->len > 0) { XmString *names; int i, new_selected_position = -1; char *selected_filename = NULL; { XmString *strs = NULL; int selections = 0; XtVaGetValues(XmFileSelectionBoxGetChild(fp->dialog, XmDIALOG_LIST), XmNselectedItems, &strs, XmNselectedItemCount, &selections, NULL); if ((selections > 0) && (strs) && (strs[0])) selected_filename = (char *)XmStringUnparse(strs[0], NULL, XmCHARSET_TEXT, XmCHARSET_TEXT, NULL, 0, XmOUTPUT_ALL); } snd_sort(fp->sorter_choice, cur_dir->files, cur_dir->len); /* here we could use colored text to mark sound files, perhaps different colors for * different chans (as in install-searcher-with-colors), but I would rather have * used different background colors (less intrusive I think). As far as I can tell, * this is impossible given the current XmList widget -- each item is an internal * "Element", not a label widget or whatever, and the selection color, for example, * is done by hand. */ names = (XmString *)calloc(cur_dir->len, sizeof(XmString)); for (i = 0; i < cur_dir->len; i++) { names[i] = XmStringCreateLocalized(cur_dir->files[i]->full_filename); if ((new_selected_position == -1) && (mus_strcmp(selected_filename, cur_dir->files[i]->full_filename))) new_selected_position = i; } XtVaSetValues(fp->dialog, XmNfileListItems, names, XmNfileListItemCount, cur_dir->len, XmNlistUpdated, true, NULL); if (new_selected_position >= 0) ensure_list_row_visible(XmFileSelectionBoxGetChild(fp->dialog, XmDIALOG_LIST), new_selected_position); for (i = 0; i < cur_dir->len; i++) if (names[i]) XmStringFree(names[i]); free(names); } else { /* nothing to sort, but make sure the files list is actually empty */ XtVaSetValues(fp->dialog, XmNfileListItems, NULL, XmNfileListItemCount, 0, XmNlistUpdated, true, NULL); } } static void snd_directory_reader(Widget dialog, XmFileSelectionBoxCallbackStruct *info) { /* replaces the FSB searchProc */ file_pattern_info *fp; dir_info *cur_dir = NULL; char *pattern = NULL, *our_dir = NULL; XtVaGetValues(dialog, XmNuserData, &fp, NULL); if (!(fp->dialog)) fp->dialog = dialog; /* can be null at initialization */ pattern = (char *)XmStringUnparse(info->pattern, NULL, XmCHARSET_TEXT, XmCHARSET_TEXT, NULL, 0, XmOUTPUT_ALL); our_dir = (char *)XmStringUnparse(info->dir, NULL, XmCHARSET_TEXT, XmCHARSET_TEXT, NULL, 0, XmOUTPUT_ALL); /* get current directory contents, given filter and pattern */ if (mus_strcmp(pattern, "*")) { if (fp->filter_choice == NO_FILE_FILTER) cur_dir = find_files_in_dir(our_dir); else cur_dir = find_filtered_files_in_dir(our_dir, fp->filter_choice); } else cur_dir = find_filtered_files_in_dir_with_pattern(our_dir, fp->filter_choice, pattern); if (fp->current_files) free_dir_info(fp->current_files); fp->current_files = cur_dir; if (pattern) XtFree(pattern); /* set file_pattern_info->selected_filename list_slider_position from history */ { position_t list_pos; Widget file_list; file_list = XmFileSelectionBoxGetChild(dialog, XmDIALOG_LIST); list_pos = dirpos_list_top(fp->dir_list, our_dir); /* post the sorted list in the dialog -- alphabetize by default */ sort_files_and_redisplay(fp); if (list_pos != POSITION_UNKNOWN) XmListSetPos(file_list, list_pos); } if ((!fp->last_dir) || (!mus_strcmp(our_dir, fp->last_dir))) { if (fp->directory_watcher) unmonitor_file(fp->directory_watcher); fp->directory_watcher = NULL; if (fp->last_dir) free(fp->last_dir); fp->last_dir = mus_strdup(our_dir); fp->reread_directory = false; } if (our_dir) XtFree(our_dir); } static void just_sounds_callback(Widget w, XtPointer context, XtPointer info) { XmToggleButtonCallbackStruct *cb = (XmToggleButtonCallbackStruct *)info; file_pattern_info *fp = (file_pattern_info *)context; if (cb->set) fp->filter_choice = JUST_SOUNDS_FILTER; else fp->filter_choice = NO_FILE_FILTER; fp->in_just_sounds_update = true; force_directory_reread(fp->dialog); fp->in_just_sounds_update = false; } /* -------- play selected file handlers -------- */ typedef struct { Widget dialog, play_button; snd_info *player; } dialog_play_info; static void file_dialog_stop_playing(dialog_play_info *dp) { #if WITH_AUDIO if ((dp->player) && (dp->player->playing)) { stop_playing_sound(dp->player, PLAY_BUTTON_UNSET); dp->player = NULL; } #endif } void clear_deleted_snd_info(void *udp) { dialog_play_info *dp = (dialog_play_info *)udp; #if WITH_AUDIO dp->player = NULL; #endif } #if WITH_AUDIO static void play_selected_callback(Widget w, XtPointer context, XtPointer info) { XmToggleButtonCallbackStruct *cb = (XmToggleButtonCallbackStruct *)info; dialog_play_info *dp = (dialog_play_info *)context; if (cb->set) { Widget wtmp; char *filename = NULL; if ((dp->player) && (dp->player->playing)) stop_playing_sound(dp->player, PLAY_BUTTON_UNSET); wtmp = FSB_BOX(dp->dialog, XmDIALOG_TEXT); filename = XmTextGetString(wtmp); if (filename) { if (mus_file_probe(filename)) { dp->player = make_sound_readable(filename, false); dp->player->delete_me = (void *)dp; if (dp->player) play_sound(dp->player, 0, NO_END_SPECIFIED); } XtFree(filename); } } else file_dialog_stop_playing(dp); } #endif static void add_play_and_just_sounds_buttons(Widget dialog, Widget parent, file_pattern_info *fp, dialog_play_info *dp) { Widget rc; int n; Arg args[12]; n = 0; XtSetArg(args[n], XmNorientation, XmHORIZONTAL); n++; rc = XtCreateManagedWidget("filebuttons-rc", xmRowColumnWidgetClass, parent, args, n); n = 0; XtSetArg(args[n], XmNset, just_sounds(ss)); n++; XtSetArg(args[n], XmNalignment, XmALIGNMENT_BEGINNING); n++; fp->just_sounds_button = XtCreateManagedWidget("sound files only", xmToggleButtonWidgetClass, rc, args, n); XtAddCallback(fp->just_sounds_button, XmNvalueChangedCallback, just_sounds_callback, (XtPointer)fp); #if WITH_AUDIO n = 0; XtSetArg(args[n], XmNorientation, XmVERTICAL); n++; XtSetArg(args[n], XmNwidth, 20); n++; XtSetArg(args[n], XmNseparatorType, XmNO_LINE); n++; XtCreateManagedWidget("sep1", xmSeparatorWidgetClass, rc, args, n); n = 0; /* XmNmarginLeft here refers to the space between the button and its label! */ XtSetArg(args[n], XmNalignment, XmALIGNMENT_END); n++; dp->play_button = XtCreateWidget("play selected sound", xmToggleButtonWidgetClass, rc, args, n); XtAddCallback(dp->play_button, XmNvalueChangedCallback, play_selected_callback, (XtPointer)dp); #endif } /* -------- File Open/View/Mix Dialogs -------- */ typedef struct file_dialog_info { read_only_t file_dialog_read_only; Widget dialog; Widget info_frame, info1, info2; /* labels giving info on selected file, or an error message */ file_pattern_info *fp; dialog_play_info *dp; void *unsound_directory_watcher; /* started if file doesn't exist, not a sound file, bogus header, etc (clears error msg if problem changed) */ void *info_filename_watcher; /* watch for change in selected file and repost info */ char *unsound_dirname, *unsound_filename; char *info_filename; file_popup_info *fpop; } file_dialog_info; static void open_file_help_callback(Widget w, XtPointer context, XtPointer info) { open_file_dialog_help(); } static void file_cancel_callback(Widget w, XtPointer context, XtPointer info) { file_dialog_stop_playing((dialog_play_info *)context); XtUnmanageChild (w); } static void file_wm_delete_callback(Widget w, XtPointer context, XtPointer info) { file_dialog_stop_playing((dialog_play_info *)context); } static void post_sound_info(Widget info1, Widget info2, const char *filename, bool with_filename) { /* filename is known[strongly believed] to be a sound file, etc */ XmString label; char *buf; buf = (char *)calloc(LABEL_BUFFER_SIZE, sizeof(char)); snprintf(buf, LABEL_BUFFER_SIZE, "%s%s%d chan%s, %d Hz, %.3f secs", (with_filename) ? filename_without_directory(filename) : "", (with_filename) ? ": " : "", mus_sound_chans(filename), (mus_sound_chans(filename) > 1) ? "s" : "", mus_sound_srate(filename), (double)mus_sound_duration(filename)); label = XmStringCreateLocalized(buf); XtVaSetValues(info1, XmNlabelString, label, NULL); XmStringFree(label); snprintf(buf, LABEL_BUFFER_SIZE, "%s, %s%s", mus_header_type_name(mus_sound_header_type(filename)), short_sample_type_name(mus_sound_sample_type(filename), filename), snd_strftime(", %d-%b-%Y", mus_sound_write_date(filename))); label = XmStringCreateLocalized(buf); XtVaSetValues(info2, XmNlabelString, label, NULL); XmStringFree(label); free(buf); } static void post_file_info(file_dialog_info *fd, const char *filename) { #if WITH_AUDIO XtManageChild(fd->dp->play_button); #endif post_sound_info(fd->info1, fd->info2, filename, true); if (!(XtIsManaged(fd->info1))) XtManageChild(fd->info1); if (!(XtIsManaged(fd->info2))) XtManageChild(fd->info2); if (!(XtIsManaged(fd->info_frame))) XtManageChild(fd->info_frame); } static void unpost_file_info(file_dialog_info *fd) { #if WITH_AUDIO if (XtIsManaged(fd->dp->play_button)) XtUnmanageChild(fd->dp->play_button); #endif if (XtIsManaged(fd->info_frame)) XtUnmanageChild(fd->info_frame); if (fd->info_filename_watcher) { fd->info_filename_watcher = unmonitor_file(fd->info_filename_watcher); if (fd->info_filename) {free(fd->info_filename); fd->info_filename = NULL;} } } static bool is_empty_file(const char *filename) { #ifndef _MSC_VER struct stat statbuf; if (stat(filename, &statbuf) >= 0) return(statbuf.st_size == (mus_long_t)0); #endif return(false); } static int local_error = MUS_NO_ERROR; static char *local_error_msg = NULL; static mus_error_handler_t *old_error_handler; static void local_error2snd(int type, char *msg) { local_error = type; if (local_error_msg) free(local_error_msg); if (msg) local_error_msg = mus_strdup(msg); else local_error_msg = NULL; } static bool is_plausible_sound_file(const char *name) { int err = MUS_NO_ERROR; if (is_empty_file(name)) return(false); old_error_handler = mus_error_set_handler(local_error2snd); err = mus_header_read(name); mus_error_set_handler(old_error_handler); return((err == MUS_NO_ERROR) && (mus_header_type() != MUS_RAW)); } static void file_dialog_select_callback(Widget w, XtPointer context, XtPointer info) { file_dialog_info *fd = (file_dialog_info *)context; XmString *strs = NULL; XtVaGetValues(w, XmNselectedItems, &strs, NULL); if (strs) /* can be null if click in empty space */ { char *filename; position_t position = 0; filename = (char *)XmStringUnparse(strs[0], NULL, XmCHARSET_TEXT, XmCHARSET_TEXT, NULL, 0, XmOUTPUT_ALL); if (filename) { if (is_plausible_sound_file(filename)) /* forces header read to avoid later unwanted error possibility */ post_file_info(fd, filename); XtFree(filename); } else unpost_file_info(fd); /* save current list position */ XtVaGetValues(w, XmNtopItemPosition, &position, NULL); dirpos_update(fd->fp->dir_list, fd->fp->current_files->dir_name, position); } } static void unpost_if_filter_changed(Widget w, XtPointer context, XtPointer info) { unpost_file_info((file_dialog_info *)context); } static void watch_filename_change(Widget w, XtPointer context, XtPointer info) { /* try to move file list to show possible matches, * if a sound file, show info */ file_dialog_info *fd = (file_dialog_info *)context; char *filename = NULL; filename = XmTextGetString(w); if ((filename) && (*filename)) { XmStringTable files; Widget file_list; int num_files = 0, pos = -1, l, u; file_list = FSB_BOX(fd->dialog, XmDIALOG_LIST); XtVaGetValues(fd->dialog, XmNfileListItemCount, &num_files, XmNfileListItems, &files, /* do not free */ NULL); l = 0; /* hooray for Knuth... */ u = num_files - 1; while (true) { int i, comp; char *file_list_file = NULL; if (u < l) break; i = (l + u) / 2; file_list_file = (char *)XmStringUnparse(files[i], NULL, XmCHARSET_TEXT, XmCHARSET_TEXT, NULL, 0, XmOUTPUT_ALL); /* p453 */ comp = strcmp(file_list_file, filename); XtFree(file_list_file); pos = i + 1; if (comp == 0) break; if (comp < 0) /* files[i] less than filename */ l = i + 1; else u = i - 1; } if (pos > 0) ensure_list_row_visible(file_list, pos); if ((mus_file_probe(filename)) && (!is_directory(filename))) { if (is_sound_file(filename)) post_file_info(fd, filename); } } if (filename) XtFree(filename); } static void focus_filename_text_callback(Widget w, XtPointer context, XtPointer info) { XtAddCallback(w, XmNvalueChangedCallback, watch_filename_change, context); } static void unfocus_filename_text_callback(Widget w, XtPointer context, XtPointer info) { XtRemoveCallback(w, XmNvalueChangedCallback, watch_filename_change, context); } static bool file_is_directory(Widget dialog) { char *filename = NULL; bool is_dir = false; filename = XmTextGetString(FSB_BOX(dialog, XmDIALOG_TEXT)); if (filename) { is_dir = is_directory(filename); XtFree(filename); } return(is_dir); } static bool file_is_nonexistent_directory(Widget dialog) { char *filename = NULL; bool is_nonexistent_dir = false; filename = XmTextGetString(FSB_BOX(dialog, XmDIALOG_TEXT)); if (filename) { int len; len = strlen(filename); if ((!mus_file_probe(filename)) && (filename[len - 1] == '/')) { int i; /* check that there's some hope of making this directory */ for (i = len - 2; i > 0; i--) if (filename[i] == '/') { filename[i] = '\0'; is_nonexistent_dir = is_directory(filename); break; } } XtFree(filename); } return(is_nonexistent_dir); } static void reflect_text_in_open_button(Widget w, XtPointer context, XtPointer info) { file_dialog_info *fd = (file_dialog_info *)context; /* w here is the text widget, not the button */ XtSetSensitive(FSB_BOX(fd->dialog, XmDIALOG_OK_BUTTON), (!(file_is_directory(fd->dialog)))); } static void multifile_completer(widget_t w, void *data) { watch_filename_change(w, (XtPointer)data, NULL); } #define FILE_DIALOG_WIDTH 500 #define FILE_DIALOG_HEIGHT 500 static file_dialog_info *make_file_dialog(read_only_t read_only, char *title, char *select_title, XtCallbackProc file_ok_proc, XtCallbackProc file_help_proc) { /* file selection dialog box with added "Just Sound Files" and "Play selected" toggle buttons and info area, * popups, and so on. This applies to the Open, Mix, and Insert dialogs. The save-as * dialogs are handled by make_save_as_dialog below */ Widget w; file_dialog_info *fd; Arg args[32]; int n; XmString s1, s2, ok_label, filter_list_label, cancel_label; Widget wtmp = NULL, rc1, rc2; fd = (file_dialog_info *)calloc(1, sizeof(file_dialog_info)); fd->fp = (file_pattern_info *)calloc(1, sizeof(file_pattern_info)); fd->fp->in_just_sounds_update = false; if (just_sounds(ss)) fd->fp->filter_choice = JUST_SOUNDS_FILTER; else fd->fp->filter_choice = NO_FILE_FILTER; fd->dp = (dialog_play_info *)calloc(1, sizeof(dialog_play_info)); fd->file_dialog_read_only = read_only; fd->fpop = (file_popup_info *)calloc(1, sizeof(file_popup_info)); fd->fpop->fp = fd->fp; fd->fp->dir_list = make_dirpos_list(); w = main_shell(ss); s1 = XmStringCreateLocalized(select_title); s2 = XmStringCreateLocalized(title); ok_label = XmStringCreateLocalized(title); filter_list_label = XmStringCreateLocalized((char *)"files listed:"); cancel_label = XmStringCreateLocalized((char *)I_GO_AWAY); n = 0; if (open_file_dialog_directory(ss)) { XmString dirstr; dirstr = XmStringCreateLocalized(open_file_dialog_directory(ss)); XtSetArg(args[n], XmNdirectory, dirstr); n++; } XtSetArg(args[n], XmNbackground, ss->basic_color); n++; XtSetArg(args[n], XmNokLabelString, ok_label); n++; XtSetArg(args[n], XmNselectionLabelString, s1); n++; /* "open", "mix", "insert", "open read-only:" */ XtSetArg(args[n], XmNdialogTitle, s2); n++; XtSetArg(args[n], XmNfilterLabelString, filter_list_label); n++; /* default label 'Filter' is confusing in this context */ XtSetArg(args[n], XmNfileFilterStyle, XmFILTER_HIDDEN_FILES); n++; /* the dot files mostly just get in the way */ XtSetArg(args[n], XmNcancelLabelString, cancel_label); n++; XtSetArg(args[n], XmNuserData, (XtPointer)(fd->fp)); n++; XtSetArg(args[n], XmNfileSearchProc, snd_directory_reader); n++; /* over-ride Motif's directory reader altogether */ XtSetArg(args[n], XmNwidth, FILE_DIALOG_WIDTH); n++; XtSetArg(args[n], XmNheight, FILE_DIALOG_HEIGHT); n++; XtSetArg(args[n], XmNresizePolicy, XmRESIZE_GROW); n++; XtSetArg(args[n], XmNnoResize, false); n++; fd->dialog = XmCreateFileSelectionDialog(w, title, args, n); fd->fp->dialog = fd->dialog; fd->dp->dialog = fd->dialog; fd->fpop->dialog = fd->dialog; XtUnmanageChild(FSB_BOX(fd->dialog, XmDIALOG_DIR_LIST_LABEL)); /* these are obvious */ XtUnmanageChild(FSB_BOX(fd->dialog, XmDIALOG_LIST_LABEL)); XtUnmanageChild(FSB_BOX(fd->dialog, XmDIALOG_APPLY_BUTTON)); /* "Filter" button is useless */ XtVaSetValues(FSB_BOX(fd->dialog, XmDIALOG_FILTER_LABEL), XmNbackground, ss->basic_color, NULL); XtVaSetValues(FSB_BOX(fd->dialog, XmDIALOG_SELECTION_LABEL), XmNbackground, ss->basic_color, NULL); XmStringFree(s1); XmStringFree(s2); XmStringFree(ok_label); XmStringFree(filter_list_label); XmStringFree(cancel_label); /* -------- play and just-sounds buttons and info area */ rc1 = XtVaCreateManagedWidget("filebuttons-rc1", xmRowColumnWidgetClass, fd->dialog, XmNorientation, XmVERTICAL, NULL); add_play_and_just_sounds_buttons(fd->dialog, rc1, fd->fp, fd->dp); fd->info_frame = XtVaCreateWidget("", xmFrameWidgetClass, rc1, NULL); rc2 = XtVaCreateManagedWidget("info-rc2", xmRowColumnWidgetClass, fd->info_frame, XmNorientation, XmVERTICAL, XmNbackground, ss->highlight_color, NULL); fd->info1 = XtVaCreateManagedWidget("", xmLabelWidgetClass, rc2, XmNbackground, ss->highlight_color, NULL); fd->info2 = XtVaCreateManagedWidget("", xmLabelWidgetClass, rc2, XmNbackground, ss->highlight_color, NULL); /* -------- Snd-like color schemes */ color_file_selection_box(fd->dialog); XtVaSetValues(fd->fp->just_sounds_button, XmNselectColor, ss->selection_color, NULL); #if WITH_AUDIO XtVaSetValues(fd->dp->play_button, XmNselectColor, ss->selection_color, NULL); #endif /* -------- completions */ wtmp = FSB_BOX(fd->dialog, XmDIALOG_TEXT); add_completer_to_builtin_textfield(wtmp, add_completer_func_with_multicompleter(sound_filename_completer, (void *)fd, multifile_completer)); XtAddCallback(wtmp, XmNfocusCallback, focus_filename_text_callback, (XtPointer)fd); XtAddCallback(wtmp, XmNlosingFocusCallback, unfocus_filename_text_callback, (XtPointer)fd); wtmp = FSB_BOX(fd->dialog, XmDIALOG_FILTER_TEXT); add_completer_to_builtin_textfield(wtmp, add_completer_func(filename_completer, NULL)); XtAddCallback(wtmp, XmNvalueChangedCallback, unpost_if_filter_changed, (XtPointer)fd); /* -------- base button callbacks */ XtAddCallback(fd->dialog, XmNokCallback, file_ok_proc, (XtPointer)fd); XtAddCallback(fd->dialog, XmNcancelCallback, file_cancel_callback, (XtPointer)(fd->dp)); XtAddCallback(fd->dialog, XmNhelpCallback, file_help_proc, NULL); XtAddCallback(FSB_BOX(fd->dialog, XmDIALOG_LIST), XmNbrowseSelectionCallback, file_dialog_select_callback, (XtPointer)fd); /* -------- single click in directory list */ XtAddCallback(FSB_BOX(fd->dialog, XmDIALOG_DIR_LIST), XmNbrowseSelectionCallback, file_change_directory_callback, (XtPointer)(fd->fp)); /* -------- the WM 'close' button */ { Atom wm_delete_window; wm_delete_window = XmInternAtom(main_display(ss), (char *)"WM_DELETE_WINDOW", false); XmAddWMProtocolCallback(XtParent(fd->dialog), wm_delete_window, file_wm_delete_callback, (XtPointer)(fd->dp)); } /* -------- special popups */ add_file_popups(fd->fpop); XtSetSensitive(FSB_BOX(fd->dialog, XmDIALOG_OK_BUTTON), (!(file_is_directory(fd->dialog)))); XtAddCallback(FSB_BOX(fd->dialog, XmDIALOG_TEXT), XmNvalueChangedCallback, reflect_text_in_open_button, (void *)fd); return(fd); } /* -------- File:Open/View dialogs -------- */ static void file_open_error(const char *error_msg, file_dialog_info *fd) { XmString msg; msg = XmStringCreateLocalized((char *)error_msg); XtVaSetValues(fd->info1, XmNlabelString, msg, NULL); XmStringFree(msg); if (XtIsManaged(fd->info2)) XtUnmanageChild(fd->info2); if (!(XtIsManaged(fd->info_frame))) XtManageChild(fd->info_frame); } static void redirect_file_open_error(const char *error_msg, void *ufd) { /* called from snd_error, redirecting error handling to the dialog */ file_open_error(error_msg, (file_dialog_info *)ufd); } static void open_modify_callback(Widget w, XtPointer context, XtPointer info); static void unpost_open_modify_error(file_dialog_info *fd) { Widget dialog_filename_text; if (XtIsManaged(fd->info_frame)) XtUnmanageChild(fd->info_frame); dialog_filename_text = FSB_BOX(fd->dialog, XmDIALOG_TEXT); if (dialog_filename_text) XtRemoveCallback(dialog_filename_text, XmNmodifyVerifyCallback, open_modify_callback, (XtPointer)fd); if (fd->unsound_directory_watcher) { fd->unsound_directory_watcher = unmonitor_file(fd->unsound_directory_watcher); if (fd->unsound_dirname) {free(fd->unsound_dirname); fd->unsound_dirname = NULL;} if (fd->unsound_filename) {free(fd->unsound_filename); fd->unsound_filename = NULL;} } } static void open_modify_callback(Widget w, XtPointer context, XtPointer info) { file_dialog_info *fd = (file_dialog_info *)context; XmTextVerifyCallbackStruct *cbs = (XmTextVerifyCallbackStruct *)info; if (!(fd->fp->in_just_sounds_update)) /* auto trigger from just_sounds button -- unwanted! */ unpost_open_modify_error(fd); cbs->doit = true; /* fixup filename elsewhere -- returning false here makes the thing beep! */ } static void clear_error_if_open_changes(Widget dialog, file_dialog_info *data) { Widget dialog_filename_text; dialog_filename_text = FSB_BOX(dialog, XmDIALOG_TEXT); if (dialog_filename_text) XtAddCallback(dialog_filename_text, XmNmodifyVerifyCallback, open_modify_callback, (XtPointer)data); } static void file_open_ok_callback(Widget w, XtPointer context, XtPointer info) { file_dialog_info *fd = (file_dialog_info *)context; XmFileSelectionBoxCallbackStruct *cbs = (XmFileSelectionBoxCallbackStruct *)info; char *filename = NULL; if (XmGetFocusWidget(fd->dialog) == FSB_BOX(fd->dialog, XmDIALOG_FILTER_TEXT)) return; filename = (char *)XmStringUnparse(cbs->value, NULL, XmCHARSET_TEXT, XmCHARSET_TEXT, NULL, 0, XmOUTPUT_ALL); if ((!filename) || (!(*filename))) { file_open_error("no filename given", fd); clear_error_if_open_changes(fd->dialog, fd); } else { file_dialog_stop_playing(fd->dp); if (!(is_directory(filename))) /* this can be a directory name if the user clicked 'ok' when he meant 'cancel' */ { snd_info *sp; redirect_snd_error_to(redirect_file_open_error, (void *)fd); ss->requestor_dialog = w; ss->open_requestor = FROM_OPEN_DIALOG; ss->open_requestor_data = NULL; sp = snd_open_file(filename, fd->file_dialog_read_only); redirect_snd_error_to(NULL, NULL); if (sp) { XtUnmanageChild(w); remember_filename(filename, fd->fpop->file_text_names); select_channel(sp, 0); } else { if (ss->open_requestor != FROM_RAW_DATA_DIALOG) { clear_error_if_open_changes(fd->dialog, fd); /* whatever the error was, I think it is correct here to unpost the error * if the underlying file is either changed or created. */ } } if (filename) XtFree(filename); } else { char *str; str = mus_format("%s is a directory", filename); file_open_error(str, fd); clear_error_if_open_changes(fd->dialog, fd); free(str); } } } static file_dialog_info *odat = NULL; widget_t make_open_file_dialog(read_only_t read_only, bool managed) { char *title, *select_title; if (read_only == FILE_READ_ONLY) { title = (char *)"View"; select_title = (char *)"open read-only:"; } else { title = (char *)"Open"; select_title = (char *)"open:"; } if (!odat) { XmString cancel_label; odat = make_file_dialog(read_only, title, select_title, file_open_ok_callback, open_file_help_callback); set_dialog_widget(FILE_OPEN_DIALOG, odat->dialog); /* now preload last n files opened before this point */ preload_filenames(odat->fpop->file_text_names); cancel_label = XmStringCreateLocalized((char *)I_GO_AWAY); XtVaSetValues(odat->dialog, XmNcancelLabelString, cancel_label, NULL); XmStringFree(cancel_label); } else { if (odat->file_dialog_read_only != read_only) { XmString s1, s2; s1 = XmStringCreateLocalized(select_title); s2 = XmStringCreateLocalized(title); XtVaSetValues(odat->dialog, XmNselectionLabelString, s1, XmNdialogTitle, s2, XmNokLabelString, s2, /* "ok" button label can be either "View" or "Open" */ NULL); XmStringFree(s1); XmStringFree(s2); } odat->file_dialog_read_only = read_only; if (odat->fp->reread_directory) { force_directory_reread(odat->dialog); odat->fp->reread_directory = false; } } if ((managed) && (!(XtIsManaged(odat->dialog)))) XtManageChild(odat->dialog); return(odat->dialog); } /* -------- File:Mix dialog -------- */ static void file_mix_ok_callback(Widget w, XtPointer context, XtPointer info) { XmFileSelectionBoxCallbackStruct *cbs = (XmFileSelectionBoxCallbackStruct *)info; file_dialog_info *fd = (file_dialog_info *)context; char *filename = NULL; filename = (char *)XmStringUnparse(cbs->value, NULL, XmCHARSET_TEXT, XmCHARSET_TEXT, NULL, 0, XmOUTPUT_ALL); if ((!filename) || (!(*filename))) { file_open_error("no filename given", fd); clear_error_if_open_changes(fd->dialog, fd); } else { file_dialog_stop_playing(fd->dp); if (!(is_directory(filename))) /* this can be a directory name if the user clicked 'ok' when he meant 'cancel' */ { int id_or_error; snd_info *sp; sp = any_selected_sound(); redirect_snd_error_to(redirect_file_open_error, (void *)fd); ss->requestor_dialog = w; ss->open_requestor = FROM_MIX_DIALOG; ss->open_requestor_data = NULL; id_or_error = mix_complete_file_at_cursor(sp, filename); /* "id_or_error" here is either one of the mix id's or an error indication such as MIX_FILE_NO_MIX */ /* the possible error conditions have been checked already, or go through snd_error */ redirect_snd_error_to(NULL, NULL); if (id_or_error < 0) /* actually -1 .. -3 */ { if (ss->open_requestor != FROM_RAW_DATA_DIALOG) { clear_error_if_open_changes(fd->dialog, fd); } } else { status_report(sp, "%s mixed in at cursor", filename); remember_filename(filename, fd->fpop->file_text_names); } if (filename) XtFree(filename); } else { char *str; str = mus_format("%s is a directory", filename); file_open_error(str, fd); clear_error_if_open_changes(fd->dialog, fd); free(str); } } } static void mix_file_help_callback(Widget w, XtPointer context, XtPointer info) { mix_file_dialog_help(); } static file_dialog_info *mdat = NULL; static Xen mix_open_file_watcher(Xen hook_or_reason) { if ((mdat->dialog) && (XtIsManaged(mdat->dialog))) set_sensitive(FSB_BOX(mdat->dialog, XmDIALOG_OK_BUTTON), (bool)any_selected_sound()); return(Xen_false); } static void add_reflect_mix_hook(void); widget_t make_mix_file_dialog(bool managed) { /* called from the menu */ if (!mdat) { mdat = make_file_dialog(FILE_READ_ONLY, (char *)"Mix Sound", (char *)"mix in:", file_mix_ok_callback, mix_file_help_callback); set_dialog_widget(FILE_MIX_DIALOG, mdat->dialog); add_reflect_mix_hook(); } else { if (mdat->fp->reread_directory) { force_directory_reread(mdat->dialog); mdat->fp->reread_directory = false; } } if ((managed) && (!XtIsManaged(mdat->dialog))) XtManageChild(mdat->dialog); return(mdat->dialog); } /* -------- File:Insert dialog -------- */ static void file_insert_ok_callback(Widget w, XtPointer context, XtPointer info) { XmFileSelectionBoxCallbackStruct *cbs = (XmFileSelectionBoxCallbackStruct *)info; file_dialog_info *fd = (file_dialog_info *)context; char *filename = NULL; filename = (char *)XmStringUnparse(cbs->value, NULL, XmCHARSET_TEXT, XmCHARSET_TEXT, NULL, 0, XmOUTPUT_ALL); if ((!filename) || (!(*filename))) { file_open_error("no filename given", fd); clear_error_if_open_changes(fd->dialog, fd); } else { file_dialog_stop_playing(fd->dp); if (!(is_directory(filename))) /* this can be a directory name if the user clicked 'ok' when he meant 'cancel' */ { bool ok; snd_info *sp; sp = any_selected_sound(); ss->requestor_dialog = w; ss->open_requestor = FROM_INSERT_DIALOG; ss->open_requestor_data = NULL; redirect_snd_error_to(redirect_file_open_error, (void *)fd); ok = insert_complete_file_at_cursor(sp, filename); redirect_snd_error_to(NULL, NULL); if (!ok) { if (ss->open_requestor != FROM_RAW_DATA_DIALOG) { clear_error_if_open_changes(fd->dialog, fd); /* ideally insert_complete_file would return an indication of what the error was... */ } } else { status_report(sp, "%s inserted at cursor", filename); remember_filename(filename, fd->fpop->file_text_names); } if (filename) XtFree(filename); } else { char *str; str = mus_format("%s is a directory", filename); file_open_error(str, fd); clear_error_if_open_changes(fd->dialog, fd); free(str); } } } static void insert_file_help_callback(Widget w, XtPointer context, XtPointer info) { insert_file_dialog_help(); } static file_dialog_info *idat = NULL; static Xen insert_open_file_watcher(Xen hook_or_reason) { if ((idat->dialog) && (XtIsManaged(idat->dialog))) set_sensitive(FSB_BOX(idat->dialog, XmDIALOG_OK_BUTTON), (bool)any_selected_sound()); return(Xen_false); } static void add_reflect_insert_hook(void); widget_t make_insert_file_dialog(bool managed) { if (!idat) { idat = make_file_dialog(FILE_READ_ONLY, (char *)"Insert Sound", (char *)"insert:", file_insert_ok_callback, insert_file_help_callback); set_dialog_widget(FILE_INSERT_DIALOG, idat->dialog); add_reflect_insert_hook(); } else { if (idat->fp->reread_directory) { force_directory_reread(idat->dialog); idat->fp->reread_directory = false; } } if ((managed) && (!XtIsManaged(idat->dialog))) XtManageChild(idat->dialog); return(idat->dialog); } /* -------- reflect outside changes -------- */ void set_open_file_play_button(bool val) { #if WITH_AUDIO if ((odat) && (odat->dp->play_button)) XmToggleButtonSetState(odat->dp->play_button, (Boolean)val, false); if ((mdat) && (mdat->dp->play_button)) XmToggleButtonSetState(mdat->dp->play_button, (Boolean)val, false); if ((idat) && (idat->dp->play_button)) XmToggleButtonSetState(idat->dp->play_button, (Boolean)val, false); #endif } void alert_new_file(void) { if (ss->file_monitor_ok) return; /* ideally this would include the save-as dialogs */ if (odat) { odat->fp->reread_directory = true; if (XtIsManaged(odat->dialog)) { force_directory_reread(odat->dialog); odat->fp->reread_directory = false; } } if (mdat) { mdat->fp->reread_directory = true; if (XtIsManaged(mdat->dialog)) { force_directory_reread(mdat->dialog); mdat->fp->reread_directory = false; } } if (idat) { idat->fp->reread_directory = true; if (XtIsManaged(idat->dialog)) { force_directory_reread(idat->dialog); idat->fp->reread_directory = false; } } } void reflect_just_sounds(void) { if ((odat) && (odat->fp->just_sounds_button)) XmToggleButtonSetState(odat->fp->just_sounds_button, just_sounds(ss), true); if ((mdat) && (mdat->fp->just_sounds_button)) XmToggleButtonSetState(mdat->fp->just_sounds_button, just_sounds(ss), true); if ((idat) && (idat->fp->just_sounds_button)) XmToggleButtonSetState(idat->fp->just_sounds_button, just_sounds(ss), true); } /* ---------------- file data panel ---------------- */ #define NUM_VISIBLE_HEADERS 5 char *get_file_dialog_sound_attributes(file_data *fdat, int *srate, int *chans, mus_header_t *header_type, mus_sample_t *sample_type, mus_long_t *location, mus_long_t *samples, int min_chan) { char *str; int n; int res; int *ns = NULL; fdat->error_widget = NOT_A_SCANF_WIDGET; fdat->scanf_widget = NOT_A_SCANF_WIDGET; if ((srate) && (fdat->srate_text)) { str = XmTextGetString(fdat->srate_text); fdat->scanf_widget = SRATE_WIDGET; if ((str) && (*str)) { (*srate) = string_to_int(str, 1, "srate"); XtFree(str); } else snd_error_without_format("no srate?"); } if ((chans) && (fdat->chans_text)) { str = XmTextGetString(fdat->chans_text); fdat->scanf_widget = CHANS_WIDGET; if ((str) && (*str)) { (*chans) = string_to_int(str, min_chan, "chans"); XtFree(str); } else { if (min_chan > 0) snd_error_without_format("no chans?"); } } if ((location) && (fdat->location_text)) { str = XmTextGetString(fdat->location_text); fdat->scanf_widget = DATA_LOCATION_WIDGET; if ((str) && (*str)) { (*location) = string_to_mus_long_t(str, 0, "data location"); XtFree(str); } else snd_error_without_format("no data location?"); } if ((samples) && (fdat->samples_text)) { str = XmTextGetString(fdat->samples_text); fdat->scanf_widget = SAMPLES_WIDGET; if ((str) && (*str)) { (*samples) = string_to_mus_long_t(str, 0, "samples"); XtFree(str); } else snd_error_without_format("no samples?"); } fdat->scanf_widget = SAMPLES_WIDGET; if ((header_type) && (fdat->header_type_list)) { res = XmListGetSelectedPos(fdat->header_type_list, &ns, &n); if (res) { (*header_type) = position_to_header_type(ns[0] - 1); fdat->current_header_type = (*header_type); free(ns); ns = NULL; } } if ((sample_type) && (fdat->sample_type_list)) { res = XmListGetSelectedPos(fdat->sample_type_list, &ns, &n); if (res) { (*sample_type) = position_to_sample_type(fdat->current_header_type, ns[0] - 1); fdat->current_sample_type = (*sample_type); free(ns); ns = NULL; } } if (fdat->comment_text) { char *comment = NULL; comment = XmTextGetString(fdat->comment_text); if (comment) { str = mus_strdup(comment); XtFree(comment); return(str); } } return(NULL); } #define IGNORE_DATA_LOCATION -1 #define IGNORE_SAMPLES MUS_UNKNOWN_SAMPLE #define IGNORE_CHANS -1 #define IGNORE_SRATE -1 #define IGNORE_HEADER_TYPE MUS_UNKNOWN_HEADER static void set_file_dialog_sound_attributes(file_data *fdat, mus_header_t header_type, mus_sample_t sample_type, int srate, int chans, mus_long_t location, mus_long_t samples, char *comment) { int i; const char **fl = NULL; XmString *strs; if (header_type != IGNORE_HEADER_TYPE) fdat->current_header_type = header_type; else fdat->current_header_type = MUS_RAW; fdat->current_sample_type = sample_type; fl = header_type_and_sample_type_to_position(fdat, fdat->current_header_type, fdat->current_sample_type); if (!fl) return; if ((header_type != IGNORE_HEADER_TYPE) && (fdat->header_type_list)) { XmListSelectPos(fdat->header_type_list, fdat->header_type_pos + 1, false); ensure_list_row_visible(fdat->header_type_list, fdat->header_type_pos + 1); } strs = (XmString *)malloc(fdat->sample_types * sizeof(XmString)); for (i = 0; i < fdat->sample_types; i++) strs[i] = XmStringCreateLocalized((char *)fl[i]); XtVaSetValues(fdat->sample_type_list, XmNitems, strs, XmNitemCount, fdat->sample_types, NULL); for (i = 0; i < fdat->sample_types; i++) XmStringFree(strs[i]); free(strs); XmListSelectPos(fdat->sample_type_list, fdat->sample_type_pos + 1, false); ensure_list_row_visible(fdat->sample_type_list, fdat->sample_type_pos + 1); if ((srate != IGNORE_SRATE) && (fdat->srate_text)) widget_int_to_text(fdat->srate_text, srate); if ((chans != IGNORE_CHANS) && (fdat->chans_text)) widget_int_to_text(fdat->chans_text, chans); if (fdat->comment_text) XmTextSetString(fdat->comment_text, comment); if ((location != IGNORE_DATA_LOCATION) && (fdat->location_text)) widget_mus_long_t_to_text(fdat->location_text, location); if ((samples != IGNORE_SAMPLES) && (fdat->samples_text)) widget_mus_long_t_to_text(fdat->samples_text, samples); } /* -------- error handling -------- */ /* if an error occurs, a callback is added to the offending text widget, and an error is * posted in the error_text label. When the user modifies the bad entry, the callback * erases the error message, and removes itself from the text widget. */ static void clear_dialog_error(file_data *fd) { if (XtIsManaged(fd->error_text)) { XtUnmanageChild(fd->error_text); if (fd->comment_text) { XtVaSetValues(fd->comment_text, XmNbottomAttachment, XmATTACH_FORM, NULL); } } } static void show_dialog_error(file_data *fd) { if (!(XtIsManaged(fd->error_text))) { if (fd->comment_text) { XtVaSetValues(fd->comment_text, XmNbottomAttachment, XmATTACH_WIDGET, XmNbottomWidget, fd->error_text, NULL); } XtManageChild(fd->error_text); } } static void post_file_dialog_error(const char *error_msg, file_data *fd) { XmString msg; msg = XmStringCreateLocalized((char *)error_msg); XtVaSetValues(fd->error_text, XmNbackground, ss->yellow, XmNlabelString, msg, NULL); XmStringFree(msg); show_dialog_error(fd); } static void redirect_post_file_dialog_error(const char *error_msg, void *ufd) { post_file_dialog_error(error_msg, (file_data *)ufd); } static void filename_modify_callback(Widget w, XtPointer context, XtPointer info) { file_data *fd = (file_data *)context; XmTextVerifyCallbackStruct *cbs = (XmTextVerifyCallbackStruct *)info; Widget dialog_filename_text; clear_dialog_error(fd); dialog_filename_text = FSB_BOX(fd->dialog, XmDIALOG_TEXT); if (dialog_filename_text) XtRemoveCallback(dialog_filename_text, XmNmodifyVerifyCallback, filename_modify_callback, context); cbs->doit = true; } static void clear_error_if_filename_changes(Widget dialog, file_data *data) { Widget dialog_filename_text; dialog_filename_text = FSB_BOX(dialog, XmDIALOG_TEXT); if (dialog_filename_text) XtAddCallback(dialog_filename_text, XmNmodifyVerifyCallback, filename_modify_callback, (XtPointer)data); } static void chans_modify_callback(Widget w, XtPointer context, XtPointer info) { file_data *fd = (file_data *)context; XmTextVerifyCallbackStruct *cbs = (XmTextVerifyCallbackStruct *)info; clear_dialog_error(fd); XtRemoveCallback(fd->chans_text, XmNmodifyVerifyCallback, chans_modify_callback, context); cbs->doit = true; } static void clear_error_if_chans_changes(Widget dialog, file_data *fd) { if (fd->chans_text) XtAddCallback(fd->chans_text, XmNmodifyVerifyCallback, chans_modify_callback, (XtPointer)fd); } static void panel_modify_callback(Widget w, XtPointer context, XtPointer info) { file_data *fd = (file_data *)context; XmTextVerifyCallbackStruct *cbs = (XmTextVerifyCallbackStruct *)info; clear_dialog_error(fd); XtRemoveCallback(w, XmNmodifyVerifyCallback, panel_modify_callback, context); cbs->doit = true; } static void clear_error_if_panel_changes(Widget dialog, file_data *fd) { Widget baddy; switch (fd->error_widget) { case SRATE_WIDGET: baddy = fd->srate_text; break; case DATA_LOCATION_WIDGET: baddy = fd->location_text; break; case SAMPLES_WIDGET: baddy = fd->samples_text; break; default: baddy = fd->chans_text; break; } if (baddy) XtAddCallback(baddy, XmNmodifyVerifyCallback, panel_modify_callback, (XtPointer)fd); } static void post_file_panel_error(const char *error_msg, void *ufd) { file_data *fd = (file_data *)ufd; fd->error_widget = fd->scanf_widget; post_file_dialog_error(error_msg, fd); } static void file_data_type_callback(Widget w, XtPointer context, XtPointer info) { int pos; XmListCallbackStruct *cbs = (XmListCallbackStruct *)info; file_data *fd; XtVaGetValues(w, XmNuserData, &fd, NULL); pos = cbs->item_position - 1; if (position_to_header_type(pos) != fd->current_header_type) { position_to_header_type_and_sample_type(fd, pos); set_file_dialog_sound_attributes(fd, fd->current_header_type, fd->current_sample_type, IGNORE_SRATE, IGNORE_CHANS, IGNORE_DATA_LOCATION, IGNORE_SAMPLES, NULL); } } static void file_sample_type_callback(Widget w, XtPointer context, XtPointer info) { XmListCallbackStruct *cbs = (XmListCallbackStruct *)info; file_data *fd; XtVaGetValues(w, XmNuserData, &fd, NULL); fd->current_sample_type = position_to_sample_type(fd->current_header_type, cbs->item_position - 1); } static void file_data_src_callback(Widget w, XtPointer context, XtPointer info) { file_data *fd = (file_data *)context; XmToggleButtonCallbackStruct *cb = (XmToggleButtonCallbackStruct *)info; fd->src = cb->set; } static void file_data_auto_comment_callback(Widget w, XtPointer context, XtPointer info) { file_data *fd = (file_data *)context; XmToggleButtonCallbackStruct *cb = (XmToggleButtonCallbackStruct *)info; fd->auto_comment = cb->set; } /* ---------------- File Data Panel ---------------- */ #define PANEL_COMMENT_SPACE 16 #define WITHOUT_AUTO_COMMENT false #define WITH_SRATE true #define WITHOUT_SRATE false static file_data *make_file_data_panel(Widget parent, const char *name, Arg *in_args, int in_n, dialog_channels_t with_chan, mus_header_t header_type, mus_sample_t sample_type, dialog_data_location_t with_loc, dialog_samples_t with_samples, dialog_header_type_t with_header_type, dialog_comment_t with_comment, header_choice_t header_choice, bool with_src, bool with_auto_comment) { Widget form, header_label, data_label, srate_label, chans_label, sep1, sep2 = NULL, sep3, sep4; Widget comment_label = NULL, location_label, samples_label; file_data *fdat; Arg args[32]; int i, n; XmString *strs; int nsample_types = 0, nheaders = 0; const char **sample_types = NULL, **header_types = NULL; switch (header_choice) { case WITH_READABLE_HEADERS: header_types = short_readable_headers(&nheaders); break; case WITH_WRITABLE_HEADERS: header_types = short_writable_headers(&nheaders); break; case WITH_BUILTIN_HEADERS: header_types = short_builtin_headers(&nheaders); break; } fdat = (file_data *)calloc(1, sizeof(file_data)); fdat->src = save_as_dialog_src(ss); fdat->auto_comment = save_as_dialog_auto_comment(ss); fdat->saved_comment = NULL; fdat->current_header_type = header_type; fdat->current_sample_type = sample_type; sample_types = header_type_and_sample_type_to_position(fdat, header_type, sample_type); nsample_types = fdat->sample_types; /* pick up all args from caller -- args here are attachment points */ form = XtCreateManagedWidget(name, xmFormWidgetClass, parent, in_args, in_n); if (with_header_type == WITH_HEADER_TYPE_FIELD) { n = 0; XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNorientation, XmVERTICAL); n++; XtSetArg(args[n], XmNwidth, 5); n++; XtSetArg(args[n], XmNseparatorType, XmNO_LINE); n++; sep1 = XtCreateManagedWidget("sep1", xmSeparatorWidgetClass, form, args, n); n = 0; XtSetArg(args[n], XmNbackground, ss->highlight_color); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNleftWidget, sep1); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_NONE); n++; header_label = XtCreateManagedWidget("header", xmLabelWidgetClass, form, args, n); /* what is selected depends on current type */ strs = (XmString *)calloc(nheaders, sizeof(XmString)); for (i = 0; i < nheaders; i++) strs[i] = XmStringCreateLocalized((char *)header_types[i]); n = 0; XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNtopWidget, header_label); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNleftWidget, sep1); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNlistMarginWidth, 1); n++; XtSetArg(args[n], XmNuserData, (XtPointer)fdat); n++; XtSetArg(args[n], XmNitems, strs); n++; XtSetArg(args[n], XmNitemCount, nheaders); n++; XtSetArg(args[n], XmNvisibleItemCount, NUM_VISIBLE_HEADERS); n++; fdat->header_type_list = XmCreateScrolledList(form, (char *)"header-type", args, n); XtManageChild(fdat->header_type_list); for (i = 0; i < nheaders; i++) XmStringFree(strs[i]); free(strs); XmListSelectPos(fdat->header_type_list, fdat->header_type_pos + 1, false); XtAddCallback(fdat->header_type_list, XmNbrowseSelectionCallback, file_data_type_callback, NULL); n = 0; XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNleftWidget, fdat->header_type_list); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNorientation, XmVERTICAL); n++; XtSetArg(args[n], XmNwidth, 15); n++; XtSetArg(args[n], XmNseparatorType, XmNO_LINE); n++; sep2 = XtCreateManagedWidget("sep2", xmSeparatorWidgetClass, form, args, n); } n = 0; XtSetArg(args[n], XmNbackground, ss->highlight_color); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++; if (with_header_type == WITH_HEADER_TYPE_FIELD) { XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNleftWidget, sep2); n++; } else { XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++; } XtSetArg(args[n], XmNrightAttachment, XmATTACH_NONE); n++; data_label = XtCreateManagedWidget("data", xmLabelWidgetClass, form, args, n); n = 0; XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNtopWidget, data_label); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++; if (with_header_type == WITH_HEADER_TYPE_FIELD) { XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNleftWidget, sep2); n++; } else { XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++; } XtSetArg(args[n], XmNrightAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNuserData, (XtPointer)fdat); n++; fdat->sample_type_list = XmCreateScrolledList(form, (char *)"sample-type", args, n); strs = (XmString *)calloc(nsample_types, sizeof(XmString)); for (i = 0; i < nsample_types; i++) strs[i] = XmStringCreateLocalized((char *)sample_types[i]); XtVaSetValues(fdat->sample_type_list, XmNitems, strs, XmNitemCount, nsample_types, NULL); for (i = 0; i < nsample_types; i++) XmStringFree(strs[i]); free(strs); XmListSelectPos(fdat->sample_type_list, fdat->sample_type_pos + 1, false); XtManageChild(fdat->sample_type_list); XtAddCallback(fdat->sample_type_list, XmNbrowseSelectionCallback, file_sample_type_callback, NULL); n = 0; XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNleftWidget, fdat->sample_type_list); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNorientation, XmVERTICAL); n++; XtSetArg(args[n], XmNwidth, 15); n++; XtSetArg(args[n], XmNseparatorType, XmNO_LINE); n++; sep3 = XtCreateManagedWidget("sep3", xmSeparatorWidgetClass, form, args, n); /* srate */ n = 0; XtSetArg(args[n], XmNbackground, ss->highlight_color); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNleftWidget, sep3); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_NONE); n++; srate_label = XtCreateManagedWidget("srate", xmLabelWidgetClass, form, args, n); n = 0; XtSetArg(args[n], XmNcolumns, 8); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNtopWidget, srate_label); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNleftWidget, sep3); n++; if (with_src) { XtSetArg(args[n], XmNrightAttachment, XmATTACH_NONE); n++; } else { XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++; } XtSetArg(args[n], XmNalignment, XmALIGNMENT_BEGINNING); n++; fdat->srate_text = make_textfield_widget("srate-text", form, args, n, NOT_ACTIVATABLE, add_completer_func(srate_completer, NULL)); if (with_src) { n = 0; XtSetArg(args[n], XmNbackground, ss->basic_color); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNtopWidget, srate_label); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNleftWidget, fdat->srate_text); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNselectColor, ss->selection_color); n++; /* this is probably clobbered by color_file_selection_box */ fdat->src_button = make_togglebutton_widget("src", form, args, n); XtAddCallback(fdat->src_button, XmNvalueChangedCallback, file_data_src_callback, (XtPointer)fdat); XmToggleButtonSetState(fdat->src_button, fdat->src, false); } if (with_chan != WITHOUT_CHANNELS_FIELD) { /* chans */ n = 0; XtSetArg(args[n], XmNbackground, ss->highlight_color); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNtopWidget, fdat->srate_text); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNleftWidget, sep3); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_NONE); n++; chans_label = XtCreateManagedWidget((char *)((with_chan == WITH_CHANNELS_FIELD) ? "channels" : "extract channel"), xmLabelWidgetClass, form, args, n); n = 0; XtSetArg(args[n], XmNcolumns, 6); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNtopWidget, chans_label); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNleftWidget, sep3); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNalignment, XmALIGNMENT_BEGINNING); n++; fdat->chans_text = make_textfield_widget("chans-text", form, args, n, NOT_ACTIVATABLE, NO_COMPLETER); XmTextFieldSetString(fdat->chans_text, (char *)"0"); if (with_loc == WITH_DATA_LOCATION_FIELD) { n = 0; XtSetArg(args[n], XmNbackground, ss->highlight_color); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNtopWidget, fdat->chans_text); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNleftWidget, sep3); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_NONE); n++; location_label = XtCreateManagedWidget("data location", xmLabelWidgetClass, form, args, n); n = 0; XtSetArg(args[n], XmNcolumns, 6); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNtopWidget, location_label); n++; XtSetArg(args[n], XmNbottomAttachment, (with_samples == WITHOUT_SAMPLES_FIELD) ? XmATTACH_FORM : XmATTACH_NONE); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNleftWidget, sep3); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNalignment, XmALIGNMENT_BEGINNING); n++; fdat->location_text = make_textfield_widget("location-text", form, args, n, NOT_ACTIVATABLE, NO_COMPLETER); } } if (with_samples == WITH_SAMPLES_FIELD) { n = 0; XtSetArg(args[n], XmNbackground, ss->highlight_color); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNtopWidget, ((fdat->location_text) ? fdat->location_text : ((fdat->chans_text) ? fdat->chans_text : fdat->srate_text))); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNleftWidget, sep3); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_NONE); n++; samples_label = XtCreateManagedWidget("samples", xmLabelWidgetClass, form, args, n); n = 0; XtSetArg(args[n], XmNcolumns, 8); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNtopWidget, samples_label); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNleftWidget, sep3); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNalignment, XmALIGNMENT_BEGINNING); n++; fdat->samples_text = make_textfield_widget("samples-text", form, args, n, NOT_ACTIVATABLE, NO_COMPLETER); } n = 0; XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNtopWidget, form); n++; /* form is the internal XmForm widget holding the lists etc */ XtSetArg(args[n], XmNbottomAttachment, (with_comment != WITHOUT_COMMENT_FIELD) ? XmATTACH_NONE : XmATTACH_FORM); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNorientation, XmHORIZONTAL); n++; XtSetArg(args[n], XmNheight, (with_comment != WITHOUT_COMMENT_FIELD) ? PANEL_COMMENT_SPACE : 2); n++; XtSetArg(args[n], XmNseparatorType, XmNO_LINE); n++; sep4 = XtCreateManagedWidget("sep4", xmSeparatorWidgetClass, parent, args, n); /* try to make the comment field the one that grows */ n = 0; if (with_comment == WITHOUT_COMMENT_FIELD) { XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNtopWidget, sep4); n++; } else { XtSetArg(args[n], XmNtopAttachment, XmATTACH_NONE); n++; } XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNbackground, ss->highlight_color); n++; /* overridden later -> yellow */ XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNborderColor, ss->black); n++; XtSetArg(args[n], XmNborderWidth, 2); n++; XtSetArg(args[n], XmNmarginWidth, 10); n++; XtSetArg(args[n], XmNmarginHeight, 10); n++; fdat->error_text = XtCreateWidget("", xmLabelWidgetClass, parent, args, n); /* XtUnmanageChild(fdat->error_text); */ if (with_comment != WITHOUT_COMMENT_FIELD) { n = 0; XtSetArg(args[n], XmNbackground, ss->highlight_color); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNtopWidget, sep4); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_NONE); n++; comment_label = XtCreateManagedWidget("comment", xmLabelWidgetClass, parent, args, n); if (with_auto_comment) { n = 0; XtSetArg(args[n], XmNbackground, ss->basic_color); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNtopWidget, sep4); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNselectColor, ss->selection_color); n++; fdat->auto_comment_button = make_togglebutton_widget("auto", parent, args, n); XtAddCallback(fdat->auto_comment_button, XmNvalueChangedCallback, file_data_auto_comment_callback, (XtPointer)fdat); XmToggleButtonSetState(fdat->auto_comment_button, fdat->auto_comment, false); } n = 0; XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++; if (with_auto_comment) { XtSetArg(args[n], XmNtopWidget, fdat->auto_comment_button); n++; } else { XtSetArg(args[n], XmNtopWidget, comment_label); n++; } XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNrows, 4); n++; /* XtSetArg(args[n], XmNcolumns, 16); n++; */ /* this sets the lower size, so we don't want it too big */ fdat->comment_text = make_text_widget("comment-text", parent, args, n); } else fdat->comment_text = NULL; return(fdat); } static void reflect_file_data_panel_change(file_data *fd, void *data, void (*change_action)(Widget w, XtPointer context, XtPointer info)) { if (fd->srate_text) XtAddCallback(fd->srate_text, XmNvalueChangedCallback, change_action, (XtPointer)data); if (fd->chans_text) XtAddCallback(fd->chans_text, XmNvalueChangedCallback, change_action, (XtPointer)data); if (fd->samples_text) XtAddCallback(fd->samples_text, XmNvalueChangedCallback, change_action, (XtPointer)data); if (fd->location_text) XtAddCallback(fd->location_text, XmNvalueChangedCallback, change_action, (XtPointer)data); if (fd->comment_text) XtAddCallback(fd->comment_text, XmNvalueChangedCallback, change_action, (XtPointer)data); if (fd->sample_type_list) XtAddCallback(fd->sample_type_list, XmNbrowseSelectionCallback, change_action, (XtPointer)data); if (fd->header_type_list) XtAddCallback(fd->header_type_list, XmNbrowseSelectionCallback, change_action, (XtPointer)data); } static void unreflect_file_data_panel_change(file_data *fd, void *data, void (*change_action)(Widget w, XtPointer context, XtPointer info)) { if (fd->srate_text) XtRemoveCallback(fd->srate_text, XmNvalueChangedCallback, change_action, (XtPointer)data); if (fd->chans_text) XtRemoveCallback(fd->chans_text, XmNvalueChangedCallback, change_action, (XtPointer)data); if (fd->samples_text) XtRemoveCallback(fd->samples_text, XmNvalueChangedCallback, change_action, (XtPointer)data); if (fd->location_text) XtRemoveCallback(fd->location_text, XmNvalueChangedCallback, change_action, (XtPointer)data); if (fd->comment_text) XtRemoveCallback(fd->comment_text, XmNvalueChangedCallback, change_action, (XtPointer)data); if (fd->sample_type_list) XtRemoveCallback(fd->sample_type_list, XmNbrowseSelectionCallback, change_action, (XtPointer)data); if (fd->header_type_list) XtRemoveCallback(fd->header_type_list, XmNbrowseSelectionCallback, change_action, (XtPointer)data); } /* -------- save as dialog (file and edit menus) -------- */ typedef struct { file_data *panel_data; Widget dialog, filename_widget, extractB, mkdirB; char *filename; /* output name (?) */ save_dialog_t type; file_pattern_info *fp; dialog_play_info *dp; void *file_watcher; file_popup_info *fpop; const char *original_filename; } save_as_dialog_info; static save_as_dialog_info *save_sound_as = NULL, *save_selection_as = NULL, *save_region_as = NULL; static save_as_dialog_info *new_save_as_dialog_info(save_dialog_t type) { save_as_dialog_info *sd; sd = (save_as_dialog_info *)calloc(1, sizeof(save_as_dialog_info)); sd->type = type; return(sd); } static void make_auto_comment(save_as_dialog_info *sd) { if ((sd == save_sound_as) && (XtIsManaged(sd->dialog))) { file_data *fd; fd = sd->panel_data; if (!(fd->auto_comment)) { /* don't erase typed-in comment, if any */ XmTextSetString(fd->comment_text, fd->saved_comment); } else { snd_info *sp; bool edits = false; int i; char *original_sound_comment, *comment, *orig_comment = NULL; sp = any_selected_sound(); original_sound_comment = mus_sound_comment(sp->filename); if (original_sound_comment) { if (*original_sound_comment) orig_comment = mus_format("\n%s comment:\n%s\n", sp->short_filename, original_sound_comment); free(original_sound_comment); original_sound_comment = NULL; } if (fd->saved_comment) XtFree(fd->saved_comment); fd->saved_comment = XmTextGetString(fd->comment_text); if ((fd->saved_comment) && (!(*(fd->saved_comment)))) { /* this is the norm in Motif */ XtFree(fd->saved_comment); fd->saved_comment = NULL; } for (i = 0; i < (int)sp->nchans; i++) if (sp->chans[i]->edit_ctr != 0) { edits = true; break; } if (!edits) comment = mus_format("%s%ssaved %s from %s (no edits)\n%s", (fd->saved_comment) ? fd->saved_comment : "", (fd->saved_comment) ? "\n" : "", snd_local_time(), sp->filename, (orig_comment) ? orig_comment : ""); else { int len; char **edit_strs; char *time; time = snd_local_time(); len = 2 * mus_strlen(sp->filename) + mus_strlen(time) + 32 * sp->nchans + mus_strlen(fd->saved_comment) + mus_strlen(original_sound_comment); edit_strs = (char **)malloc(sp->nchans * sizeof(char *)); for (i = 0; i < (int)sp->nchans; i++) { edit_strs[i] = edit_list_to_function(sp->chans[i], 1, sp->chans[i]->edit_ctr); len += mus_strlen(edit_strs[i]); } comment = (char *)calloc(len, sizeof(char)); snprintf(comment, len, "%s%ssaved %s from %s with edits:\n", (fd->saved_comment) ? fd->saved_comment : "", (fd->saved_comment) ? "\n" : "", snd_local_time(), sp->filename); for (i = 0; i < (int)sp->nchans; i++) { if (sp->nchans > 1) { char buf[64]; snprintf(buf, 64, "\n-------- channel %d --------\n", i); strcat(comment, buf); } strcat(comment, edit_strs[i]); } if (orig_comment) strcat(comment, orig_comment); free(edit_strs); } XmTextSetString(fd->comment_text, comment); if (comment) free(comment); if (orig_comment) free(orig_comment); } } } static void auto_comment_callback(Widget w, XtPointer context, XtPointer info) { save_as_dialog_info *sd = (save_as_dialog_info *)context; XmToggleButtonCallbackStruct *cb = (XmToggleButtonCallbackStruct *)info; sd->panel_data->auto_comment = (cb->set); make_auto_comment(sd); } void reflect_save_as_src(bool val) { if (save_sound_as) XmToggleButtonSetState(save_sound_as->panel_data->src_button, val, true); if (save_selection_as) XmToggleButtonSetState(save_selection_as->panel_data->src_button, val, true); if (save_region_as) XmToggleButtonSetState(save_region_as->panel_data->src_button, val, true); } void reflect_save_as_auto_comment(bool val) { if (save_sound_as) XmToggleButtonSetState(save_sound_as->panel_data->auto_comment_button, val, true); } void reflect_save_as_sound_selection(const char *sound_name) { if ((save_sound_as) && (XtIsManaged(save_sound_as->dialog))) { XmString xmstr2; char *file_string; file_string = (char *)calloc(PRINT_BUFFER_SIZE, sizeof(char)); if (sound_name) snprintf(file_string, PRINT_BUFFER_SIZE, "save %s", sound_name); else { snd_info *sp; sp = any_selected_sound(); if (sp) snprintf(file_string, PRINT_BUFFER_SIZE, "save %s", sp->short_filename); else snprintf(file_string, PRINT_BUFFER_SIZE, "nothing to save!"); } xmstr2 = XmStringCreateLocalized(file_string); XtVaSetValues(save_sound_as->dialog, XmNdialogTitle, xmstr2, NULL); XmStringFree(xmstr2); free(file_string); } } void reflect_selection_in_save_as_dialog(bool on) { if ((on) && (save_selection_as) && (save_selection_as->panel_data)) clear_dialog_error(save_selection_as->panel_data); } void reflect_region_in_save_as_dialog(void) { if ((save_region_as) && (save_region_as->dialog) && (XtIsManaged(save_region_as->dialog)) && (region_ok(region_dialog_region()))) clear_dialog_error(save_region_as->panel_data); } static void save_as_filename_modify_callback(Widget w, XtPointer context, XtPointer info); static void save_as_undoit(save_as_dialog_info *sd) { XmString ok_label; ok_label = XmStringCreateLocalized((char *)"Save"); XtVaSetValues(sd->dialog, XmNokLabelString, ok_label, NULL); XmStringFree(ok_label); clear_dialog_error(sd->panel_data); XtRemoveCallback(sd->filename_widget, XmNmodifyVerifyCallback, save_as_filename_modify_callback, (XtPointer)(sd->panel_data)); sd->file_watcher = unmonitor_file(sd->file_watcher); } static void save_as_filename_modify_callback(Widget w, XtPointer context, XtPointer info) { XmTextVerifyCallbackStruct *cbs = (XmTextVerifyCallbackStruct *)info; save_as_undoit((save_as_dialog_info *)context); cbs->doit = true; } static void clear_error_if_save_as_filename_changes(Widget dialog, save_as_dialog_info *sd) { XtAddCallback(sd->filename_widget, XmNmodifyVerifyCallback, save_as_filename_modify_callback, (XtPointer)sd); } static bool srates_differ(int srate, save_as_dialog_info *sd) { switch (sd->type) { case SOUND_SAVE_AS: return(snd_srate(any_selected_sound()) != srate); case SELECTION_SAVE_AS: return(selection_srate() != srate); case REGION_SAVE_AS: return(region_srate(region_dialog_region()) != srate); } return(false); } static double srate_ratio(int srate, save_as_dialog_info *sd) { switch (sd->type) { case SOUND_SAVE_AS: return((double)(snd_srate(any_selected_sound())) / (double)srate); case SELECTION_SAVE_AS: return((double)selection_srate() / (double)srate); case REGION_SAVE_AS: return((double)region_srate(region_dialog_region()) / (double)srate); } return(1.0); } static void save_or_extract(save_as_dialog_info *sd, bool saving) { char *str = NULL, *comment = NULL, *msg = NULL, *fullname = NULL, *tmpfile = NULL; snd_info *sp = NULL; mus_header_t header_type = MUS_NEXT, output_type; mus_sample_t sample_type = DEFAULT_OUTPUT_SAMPLE_TYPE; int srate = DEFAULT_OUTPUT_SRATE; int chan = 0, extractable_chans = 0; bool file_exists = false; io_error_t io_err = IO_NO_ERROR; clear_dialog_error(sd->panel_data); if ((sd->type == SELECTION_SAVE_AS) && (!(selection_is_active()))) { if (saving) msg = (char *)"no selection to save"; else msg = (char *)"can't extract: no selection"; post_file_dialog_error((const char *)msg, sd->panel_data); return; } if ((sd->type == REGION_SAVE_AS) && (!(region_ok(region_dialog_region())))) { post_file_dialog_error("no region to save", sd->panel_data); return; } sp = any_selected_sound(); if ((!sp) && (sd->type != REGION_SAVE_AS)) { if (saving) msg = (char *)"nothing to save"; else msg = (char *)"nothing to extract"; post_file_dialog_error((const char *)msg, sd->panel_data); clear_error_if_filename_changes(sd->dialog, sd->panel_data); return; } /* get output filename */ str = XmTextGetString(sd->filename_widget); if ((!str) || (!*str)) { if (saving) msg = (char *)"can't save: no file name given"; else msg = (char *)"can't extract: no file name given"; post_file_dialog_error((const char *)msg, sd->panel_data); clear_error_if_filename_changes(sd->dialog, sd->panel_data); return; } /* get output file attributes */ redirect_snd_error_to(post_file_panel_error, (void *)(sd->panel_data)); { mus_long_t location = 28, samples = 0; int chans = 1; if (saving) comment = get_file_dialog_sound_attributes(sd->panel_data, &srate, &chans, &header_type, &sample_type, &location, &samples, 0); else comment = get_file_dialog_sound_attributes(sd->panel_data, &srate, &chan, &header_type, &sample_type, &location, &samples, 0); } output_type = header_type; redirect_snd_error_to(NULL, NULL); if (sd->panel_data->error_widget != NOT_A_SCANF_WIDGET) { clear_error_if_panel_changes(sd->dialog, sd->panel_data); if (comment) free(comment); XtFree(str); return; } switch (sd->type) { case SOUND_SAVE_AS: clear_status_area(sp); if (!saving) extractable_chans = sp->nchans; break; case SELECTION_SAVE_AS: if (!saving) extractable_chans = selection_chans(); break; default: break; } if (!saving) { if ((chan > extractable_chans) || (((extractable_chans > 1) && (chan == extractable_chans)) || (chan < 0))) { if (chan > extractable_chans) msg = mus_format("can't extract chan %d (%s has %d chan%s)", chan, (sd->type == SOUND_SAVE_AS) ? "sound" : "selection", extractable_chans, (extractable_chans > 1) ? "s" : ""); else msg = mus_format("can't extract chan %d (first chan is numbered 0)", chan); post_file_dialog_error((const char *)msg, sd->panel_data); clear_error_if_chans_changes(sd->dialog, sd->panel_data); free(msg); if (comment) free(comment); XtFree(str); return; } } fullname = mus_expand_filename(str); if (run_before_save_as_hook(sp, fullname, sd->type != SOUND_SAVE_AS, srate, sample_type, header_type, comment)) { msg = mus_format("%s cancelled by %s", (saving) ? "save" : "extract", S_before_save_as_hook); post_file_dialog_error((const char *)msg, sd->panel_data); clear_error_if_filename_changes(sd->dialog, sd->panel_data); free(msg); free(fullname); if (comment) free(comment); XtFree(str); return; } file_exists = mus_file_probe(fullname); if ((sd->type == SOUND_SAVE_AS) && (mus_strcmp(fullname, sp->filename))) { /* save-as here is the same as save */ if ((sp->user_read_only == FILE_READ_ONLY) || (sp->file_read_only == FILE_READ_ONLY)) { msg = mus_format("can't overwrite %s (it is write-protected)", sp->short_filename); post_file_dialog_error((const char *)msg, sd->panel_data); clear_error_if_filename_changes(sd->dialog, sd->panel_data); free(msg); free(fullname); if (comment) free(comment); XtFree(str); return; } } else { if (!(sd->file_watcher)) { /* check for overwrites that are questionable -- DoIt click will return here with sd->file_watcher active */ snd_info *parlous_sp = NULL; if ((file_exists) && ((ask_before_overwrite(ss)) || ((sd->type == SOUND_SAVE_AS) && (parlous_sp = file_is_open_elsewhere_and_has_unsaved_edits(sp, fullname))))) { XmString ok_label; msg = mus_format("%s exists%s. To overwrite it, click 'DoIt'", str, (parlous_sp) ? ", and has unsaved edits" : ""); post_file_dialog_error((const char *)msg, sd->panel_data); clear_error_if_save_as_filename_changes(sd->dialog, sd); ok_label = XmStringCreateLocalized((char *)"DoIt"); XtVaSetValues(sd->dialog, XmNokLabelString, ok_label, NULL); XmUpdateDisplay(FSB_BOX(sd->dialog, XmDIALOG_OK_BUTTON)); XmStringFree(ok_label); free(msg); free(fullname); if (comment) free(comment); XtFree(str); return; } } } /* try to save... if it exists already, first write as temp, then move */ if (sd->file_watcher) save_as_undoit(sd); ss->local_errno = 0; if (header_is_encoded(header_type)) { output_type = header_type; sample_type = MUS_LSHORT; header_type = MUS_RIFF; tmpfile = snd_tempnam(); } else { tmpfile = fullname; } redirect_snd_error_to(redirect_post_file_dialog_error, (void *)(sd->panel_data)); switch (sd->type) { case SOUND_SAVE_AS: if (saving) io_err = save_edits_without_display(sp, tmpfile, header_type, sample_type, srate, comment, AT_CURRENT_EDIT_POSITION); else io_err = save_channel_edits(sp->chans[chan], tmpfile, AT_CURRENT_EDIT_POSITION); /* protects if same name */ break; case SELECTION_SAVE_AS: { char *ofile; if (file_exists) /* file won't exist if we're encoding, so this isn't as wasteful as it looks */ ofile = snd_tempnam(); else ofile = mus_strdup(tmpfile); io_err = save_selection(ofile, srate, sample_type, header_type, comment, (saving) ? SAVE_ALL_CHANS : chan); if (io_err == IO_NO_ERROR) io_err = move_file(ofile, fullname); free(ofile); } break; case REGION_SAVE_AS: { if (region_ok(region_dialog_region())) { char *ofile; if (file_exists) ofile = snd_tempnam(); else ofile = mus_strdup(tmpfile); io_err = save_region(region_dialog_region(), ofile, sample_type, header_type, comment); if (io_err == IO_NO_ERROR) io_err = move_file(ofile, fullname); free(ofile); } } break; } redirect_snd_error_to(NULL, NULL); /* check for possible srate conversion */ if ((sd->panel_data->src) && (srates_differ(srate, sd))) { /* if src, and srates differ, do the sampling rate conversion. * this needs to happen before the snd_encode (->OGG etc) below * if we do it before the save-as above, then undo it later, it messes up the user's edit history list * so do it here to tmpfile (tmpfile is fullname unless we're doing a translation to something like OGG) */ src_file(tmpfile, srate_ratio(srate, sd)); } if (io_err == IO_NO_ERROR) { if (header_is_encoded(output_type)) { snd_encode(output_type, tmpfile, fullname); snd_remove(tmpfile, REMOVE_FROM_CACHE); free(tmpfile); } remember_filename(fullname, sd->fpop->file_text_names); if (!file_exists) force_directory_reread(sd->dialog); if (saving) { if (sd->type == SOUND_SAVE_AS) status_report(sp, "%s saved as %s", sp->short_filename, str); else status_report(sp, "%s saved as %s", (sd->type == SELECTION_SAVE_AS) ? "selection" : "region", str); } else { if (sd->type == SOUND_SAVE_AS) status_report(sp, "%s chan %d saved as %s", sp->short_filename, chan, str); else status_report(sp, "selection chan %d saved as %s", chan, str); } run_after_save_as_hook(sp, str, true); /* true => from dialog */ XtUnmanageChild(sd->dialog); } else { msg = mus_format("%s as %s: %s (%s)", (saving) ? "save" : "extract chan", str, io_error_name(io_err), snd_io_strerror()); post_file_dialog_error((const char *)msg, sd->panel_data); clear_error_if_filename_changes(sd->dialog, sd->panel_data); free(msg); } free(fullname); XtFree(str); if (comment) free(comment); } static void save_as_ok_callback(Widget w, XtPointer context, XtPointer info) { save_or_extract((save_as_dialog_info *)context, true); } static void save_as_extract_callback(Widget w, XtPointer context, XtPointer info) { save_or_extract((save_as_dialog_info *)context, false); } static void save_as_dialog_select_callback(Widget w, XtPointer context, XtPointer info) { #if WITH_AUDIO dialog_play_info *dp = (dialog_play_info *)context; XmString *strs = NULL; XtVaGetValues(w, XmNselectedItems, &strs, NULL); if (strs) { char *filename; filename = (char *)XmStringUnparse(strs[0], NULL, XmCHARSET_TEXT, XmCHARSET_TEXT, NULL, 0, XmOUTPUT_ALL); if ((filename) && (is_sound_file(filename))) XtManageChild(dp->play_button); else { if (XtIsManaged(dp->play_button)) XtUnmanageChild(dp->play_button); } if (filename) XtFree(filename); } #endif } static void save_as_cancel_callback(Widget w, XtPointer context, XtPointer info) { save_as_dialog_info *sd = (save_as_dialog_info *)context; XtUnmanageChild(sd->dialog); } static void save_as_help_callback(Widget w, XtPointer context, XtPointer info) { save_as_dialog_help(); } static bool directory_exists(char *name) { char temp; bool result; int i, len, last_slash = -1; len = strlen(name); for (i = 0; i < len; i++) if (name[i] == '/') last_slash = i; if (last_slash <= 0) return(true); if (last_slash >= len - 1) /* can't be > */ return(is_directory(name)); temp = name[last_slash + 1]; name[last_slash + 1] = '\0'; result = is_directory(name); name[last_slash + 1] = temp; return(result); } static void save_as_file_exists_check(Widget w, XtPointer context, XtPointer info) { Widget dialog = (Widget)context; char *filename = NULL; XmString s1; filename = XmTextGetString(w); if ((filename) && (*filename)) { if ((mus_file_probe(filename)) && (!is_directory(filename))) { #ifndef _MSC_VER if (access(filename, W_OK) < 0) s1 = XmStringCreateLocalized((char *)"save as (file write-protected?):"); else #endif s1 = XmStringCreateLocalized((char *)"save as (overwriting):"); } else { if (!(directory_exists(filename))) s1 = XmStringCreateLocalized((char *)"save as (no such directory?):"); else s1 = XmStringCreateLocalized((char *)"save as:"); } } else s1 = XmStringCreateLocalized((char *)"save as:"); XtVaSetValues(dialog, XmNselectionLabelString, s1, NULL); if (filename) XtFree(filename); } static int snd_mkdir(const char *filename) { #ifdef __MINGW32__ return(mkdir(filename)); #else return(mkdir(filename, 0777)); #endif } static void save_as_mkdir_callback(Widget w, XtPointer context, XtPointer info) { save_as_dialog_info *sd = (save_as_dialog_info *)context; char *filename = NULL; filename = XmTextGetString(FSB_BOX(sd->dialog, XmDIALOG_TEXT)); if (snd_mkdir(filename) < 0) { /* could not make the directory */ char *str; str = mus_format("can't make %s: %s", filename, strerror(errno)); post_file_dialog_error((const char *)str, sd->panel_data); clear_error_if_filename_changes(sd->dialog, sd->panel_data); free(str); } else { /* set FSB to new dir and force update */ char *filter; filter = mus_format("%s*", filename); /* already has the "/" at the end */ update_dir_list(sd->dialog, filter); free(filter); XtSetSensitive(w, false); } XtFree(filename); } static void reflect_text_in_save_button(Widget w, XtPointer context, XtPointer info) { save_as_dialog_info *sd = (save_as_dialog_info *)context; /* w here is text widget, not button */ XtSetSensitive(FSB_BOX(sd->dialog, XmDIALOG_OK_BUTTON), (!(file_is_directory(sd->dialog)))); if (sd->mkdirB) XtSetSensitive(sd->mkdirB, file_is_nonexistent_directory(sd->dialog)); } static void reflect_text_in_extract_button(Widget w, XtPointer context, XtPointer info) { save_as_dialog_info *sd = (save_as_dialog_info *)context; /* w here is text widget, not button */ XtSetSensitive(sd->extractB, (!(file_is_directory(sd->dialog)))); } static void save_as_filter_text_activate_callback(Widget w, XtPointer context, XtPointer info) { save_as_dialog_info *sd = (save_as_dialog_info *)context; force_directory_reread_and_let_filename_change(sd->dialog); } static void make_save_as_dialog(save_as_dialog_info *sd, char *sound_name, mus_header_t header_type, mus_sample_t sample_type) { char *file_string; sd->original_filename = sound_name; if (!(sd->dialog)) { Arg args[32]; int n; XmString xmstr1, xmstr2, s1; XmString filter_list_label, cancel_label; Widget extractB, mainform; n = 0; XtSetArg(args[n], XmNbackground, ss->basic_color); n++; s1 = XmStringCreateLocalized((char *)"save as:"); XtSetArg(args[n], XmNselectionLabelString, s1); n++; xmstr1 = XmStringCreateLocalized((char *)"Save"); XtSetArg(args[n], XmNokLabelString, xmstr1); n++; file_string = (char *)calloc(PRINT_BUFFER_SIZE, sizeof(char)); snprintf(file_string, PRINT_BUFFER_SIZE, "save %s", sound_name); xmstr2 = XmStringCreateLocalized(file_string); XtSetArg(args[n], XmNdialogTitle, xmstr2); n++; filter_list_label = XmStringCreateLocalized((char *)"files listed:"); XtSetArg(args[n], XmNfilterLabelString, filter_list_label); n++; cancel_label = XmStringCreateLocalized((char *)I_GO_AWAY); XtSetArg(args[n], XmNcancelLabelString, cancel_label); n++; sd->fp = (file_pattern_info *)calloc(1, sizeof(file_pattern_info)); sd->fp->in_just_sounds_update = false; if (just_sounds(ss)) sd->fp->filter_choice = JUST_SOUNDS_FILTER; else sd->fp->filter_choice = NO_FILE_FILTER; sd->dp = (dialog_play_info *)calloc(1, sizeof(dialog_play_info)); sd->fpop = (file_popup_info *)calloc(1, sizeof(file_popup_info)); sd->fpop->fp = sd->fp; XtSetArg(args[n], XmNresizePolicy, XmRESIZE_GROW); n++; XtSetArg(args[n], XmNnoResize, false); n++; XtSetArg(args[n], XmNautoUnmanage, false); n++; XtSetArg(args[n], XmNchildPlacement, XmPLACE_ABOVE_SELECTION); n++; XtSetArg(args[n], XmNallowOverlap, false); n++; XtSetArg(args[n], XmNheight, 600); n++; XtSetArg(args[n], XmNuserData, (XtPointer)sd->fp); n++; XtSetArg(args[n], XmNfileFilterStyle, XmFILTER_HIDDEN_FILES); n++; XtSetArg(args[n], XmNfileSearchProc, snd_directory_reader); n++; /* over-ride Motif's directory reader altogether */ sd->dialog = XmCreateFileSelectionDialog(main_shell(ss), (char *)"save-as", args, n); sd->fp->dialog = sd->dialog; sd->dp->dialog = sd->dialog; sd->fpop->dialog = sd->dialog; free(file_string); XtUnmanageChild(FSB_BOX(sd->dialog, XmDIALOG_DIR_LIST_LABEL)); XtUnmanageChild(FSB_BOX(sd->dialog, XmDIALOG_LIST_LABEL)); XtUnmanageChild(FSB_BOX(sd->dialog, XmDIALOG_APPLY_BUTTON)); XtVaSetValues(FSB_BOX(sd->dialog, XmDIALOG_FILTER_LABEL), XmNbackground, ss->basic_color, NULL); XtVaSetValues(FSB_BOX(sd->dialog, XmDIALOG_SELECTION_LABEL), XmNbackground, ss->basic_color, NULL); XmStringFree(s1); XmStringFree(xmstr1); XmStringFree(xmstr2); XmStringFree(filter_list_label); XmStringFree(cancel_label); sd->filename_widget = FSB_BOX(sd->dialog, XmDIALOG_TEXT); XtAddCallback(sd->dialog, XmNhelpCallback, save_as_help_callback, (XtPointer)sd); XtAddCallback(sd->dialog, XmNcancelCallback, save_as_cancel_callback, (XtPointer)sd); XtAddCallback(sd->dialog, XmNokCallback, save_as_ok_callback, (XtPointer)sd); mainform = XtVaCreateManagedWidget("filebuttons-mainform", xmFormWidgetClass, sd->dialog, NULL); add_play_and_just_sounds_buttons(sd->dialog, mainform, sd->fp, sd->dp); n = 0; XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNtopWidget, sd->fp->just_sounds_button); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++; sd->panel_data = make_file_data_panel(mainform, "data-form", args, n, (sd->type == REGION_SAVE_AS) ? WITHOUT_CHANNELS_FIELD : WITH_EXTRACT_CHANNELS_FIELD, header_type, sample_type, WITHOUT_DATA_LOCATION_FIELD, WITHOUT_SAMPLES_FIELD, WITH_HEADER_TYPE_FIELD, WITH_COMMENT_FIELD, WITH_WRITABLE_HEADERS, WITH_SRATE, sd->type == SOUND_SAVE_AS); /* auto comment */ sd->panel_data->dialog = sd->dialog; color_file_selection_box(sd->dialog); XtVaSetValues(sd->panel_data->sample_type_list, XmNbackground, ss->white, XmNforeground, ss->black, NULL); XtVaSetValues(sd->panel_data->header_type_list, XmNbackground, ss->white, XmNforeground, ss->black, NULL); XtVaSetValues(sd->fp->just_sounds_button, XmNselectColor, ss->selection_color, NULL); #if WITH_AUDIO XtVaSetValues(sd->dp->play_button, XmNselectColor, ss->selection_color, NULL); #endif XtVaSetValues(sd->panel_data->src_button, XmNselectColor, ss->selection_color, NULL); if (sd->type == SOUND_SAVE_AS) { XtVaSetValues(sd->panel_data->auto_comment_button, XmNselectColor, ss->selection_color, NULL); XtAddCallback(sd->panel_data->auto_comment_button, XmNvalueChangedCallback, auto_comment_callback, (XtPointer)sd); } XtAddCallback(FSB_BOX(sd->dialog, XmDIALOG_LIST), XmNbrowseSelectionCallback, save_as_dialog_select_callback, (XtPointer)(sd->dp)); XtAddCallback(sd->filename_widget, XmNvalueChangedCallback, save_as_file_exists_check, (XtPointer)(sd->dialog)); XtAddCallback(FSB_BOX(sd->dialog, XmDIALOG_FILTER_TEXT), XmNactivateCallback, save_as_filter_text_activate_callback, (void *)sd); { Widget wtmp; wtmp = FSB_BOX(sd->dialog, XmDIALOG_DIR_LIST); if (wtmp) XtAddCallback(wtmp, XmNbrowseSelectionCallback, file_change_directory_callback, (XtPointer)(sd->fp)); } add_file_popups(sd->fpop); /* this must come after the file data panel so that Motif puts it in the button box, not the main work area */ if (sd->type != REGION_SAVE_AS) { /* add "Extract" button */ n = 0; XtSetArg(args[n], XmNbackground, ss->highlight_color); n++; XtSetArg(args[n], XmNarmColor, ss->selection_color); n++; extractB = XtCreateManagedWidget("Extract", xmPushButtonGadgetClass, sd->dialog, args, n); XtAddCallback(extractB, XmNactivateCallback, save_as_extract_callback, (XtPointer)sd); sd->extractB = extractB; XtSetSensitive(extractB, (!(file_is_directory(sd->dialog)))); XtAddCallback(FSB_BOX(sd->dialog, XmDIALOG_TEXT), XmNvalueChangedCallback, reflect_text_in_extract_button, (void *)sd); } /* add "Mkdir" button */ n = 0; XtSetArg(args[n], XmNbackground, ss->highlight_color); n++; XtSetArg(args[n], XmNarmColor, ss->selection_color); n++; sd->mkdirB = XtCreateManagedWidget("Mkdir", xmPushButtonGadgetClass, sd->dialog, args, n); XtAddCallback(sd->mkdirB, XmNactivateCallback, save_as_mkdir_callback, (XtPointer)sd); XtSetSensitive(sd->mkdirB, false); XtSetSensitive(FSB_BOX(sd->dialog, XmDIALOG_OK_BUTTON), (!(file_is_directory(sd->dialog)))); XtAddCallback(FSB_BOX(sd->dialog, XmDIALOG_TEXT), XmNvalueChangedCallback, reflect_text_in_save_button, (void *)sd); XtManageChild(sd->dialog); switch (sd->type) { case SOUND_SAVE_AS: set_dialog_widget(SOUND_SAVE_AS_DIALOG, sd->dialog); break; case SELECTION_SAVE_AS: set_dialog_widget(SELECTION_SAVE_AS_DIALOG, sd->dialog); break; case REGION_SAVE_AS: set_dialog_widget(REGION_SAVE_AS_DIALOG, sd->dialog); break; default: snd_error("internal screw up"); break; } } else { XmString xmstr2; file_string = (char *)calloc(PRINT_BUFFER_SIZE, sizeof(char)); snprintf(file_string, PRINT_BUFFER_SIZE, "save %s", sound_name); xmstr2 = XmStringCreateLocalized(file_string); XtVaSetValues(sd->dialog, XmNdialogTitle, xmstr2, NULL); XmStringFree(xmstr2); free(file_string); } } static save_as_dialog_info *make_sound_save_as_dialog_1(bool managed, int chan) { /* should the save-as dialog, at least in the file case, reflect the current file attributes/comment? * or should we have a save-as-hook that can set up the dialog fields? */ snd_info *sp = NULL; char *com = NULL; file_info *hdr = NULL; save_as_dialog_info *sd; if (!save_sound_as) save_sound_as = new_save_as_dialog_info(SOUND_SAVE_AS); sd = save_sound_as; sp = any_selected_sound(); if (sp) hdr = sp->hdr; make_save_as_dialog(sd, (char *)((sp) ? sp->short_filename : ""), default_output_header_type(ss), default_output_sample_type(ss)); set_file_dialog_sound_attributes(sd->panel_data, sd->panel_data->current_header_type, sd->panel_data->current_sample_type, (hdr) ? hdr->srate : selection_srate(), IGNORE_CHANS, IGNORE_DATA_LOCATION, IGNORE_SAMPLES, com = output_comment(hdr)); if (com) free(com); if (chan >= 0) { char *chan_str; chan_str = (char *)calloc(16, sizeof(char)); snprintf(chan_str, 16, "%d", chan); XmTextFieldSetString(sd->panel_data->chans_text, chan_str); free(chan_str); } if (sd->fp->reread_directory) { force_directory_reread(sd->dialog); sd->fp->reread_directory = false; } if ((managed) && (!XtIsManaged(sd->dialog))) XtManageChild(sd->dialog); make_auto_comment(sd); return(sd); } widget_t make_sound_save_as_dialog(bool managed) { save_as_dialog_info *sd; sd = make_sound_save_as_dialog_1(managed, -1); return(sd->dialog); } void make_channel_extract_dialog(int chan) { make_sound_save_as_dialog_1(true, chan); } widget_t make_selection_save_as_dialog(bool managed) { save_as_dialog_info *sd; if (!save_selection_as) save_selection_as = new_save_as_dialog_info(SELECTION_SAVE_AS); sd = save_selection_as; make_save_as_dialog(sd, (char *)"current selection", default_output_header_type(ss), default_output_sample_type(ss)); set_file_dialog_sound_attributes(sd->panel_data, sd->panel_data->current_header_type, sd->panel_data->current_sample_type, selection_srate(), IGNORE_CHANS, IGNORE_DATA_LOCATION, IGNORE_SAMPLES, NULL); if (sd->fp->reread_directory) { force_directory_reread(sd->dialog); sd->fp->reread_directory = false; } if ((managed) && (!XtIsManaged(sd->dialog))) XtManageChild(sd->dialog); return(sd->dialog); } widget_t make_region_save_as_dialog(bool managed) { save_as_dialog_info *sd; char *comment = NULL; if (!save_region_as) save_region_as = new_save_as_dialog_info(REGION_SAVE_AS); sd = save_region_as; make_save_as_dialog(sd, (char *)"selected region", default_output_header_type(ss), default_output_sample_type(ss)); comment = region_description(region_dialog_region()); set_file_dialog_sound_attributes(sd->panel_data, sd->panel_data->current_header_type, sd->panel_data->current_sample_type, region_srate(region_dialog_region()), IGNORE_CHANS, IGNORE_DATA_LOCATION, IGNORE_SAMPLES, comment); if (sd->fp->reread_directory) { force_directory_reread(sd->dialog); sd->fp->reread_directory = false; } if ((managed) && (!XtIsManaged(sd->dialog))) XtManageChild(sd->dialog); if (comment) free(comment); return(sd->dialog); } /* -------- save/restore for all these dialogs -------- */ void save_file_dialog_state(FILE *fd) { if ((odat) && (XtIsManaged(odat->dialog))) { /* odat->file_dialog_read_only -> "view-sound" dialog -- this distinction currently ignored */ #if HAVE_SCHEME fprintf(fd, "(%s #t)\n", S_open_file_dialog); #endif #if HAVE_RUBY fprintf(fd, "%s(true)\n", to_proc_name(S_open_file_dialog)); #endif #if HAVE_FORTH fprintf(fd, "#t %s drop\n", S_open_file_dialog); #endif } if ((mdat) && (XtIsManaged(mdat->dialog))) { #if HAVE_SCHEME fprintf(fd, "(%s #t)\n", S_mix_file_dialog); #endif #if HAVE_RUBY fprintf(fd, "%s(true)\n", to_proc_name(S_mix_file_dialog)); #endif #if HAVE_FORTH fprintf(fd, "#t %s drop\n", S_mix_file_dialog); #endif } if ((idat) && (XtIsManaged(idat->dialog))) { #if HAVE_SCHEME fprintf(fd, "(%s #t)\n", S_insert_file_dialog); #endif #if HAVE_RUBY fprintf(fd, "%s(true)\n", to_proc_name(S_insert_file_dialog)); #endif #if HAVE_FORTH fprintf(fd, "#t %s drop\n", S_insert_file_dialog); #endif } if ((save_sound_as) && (XtIsManaged(save_sound_as->dialog))) { #if HAVE_SCHEME fprintf(fd, "(%s #t)\n", S_save_sound_dialog); #endif #if HAVE_RUBY fprintf(fd, "%s(true)\n", to_proc_name(S_save_sound_dialog)); #endif #if HAVE_FORTH fprintf(fd, "#t %s drop\n", S_save_sound_dialog); #endif } if ((save_selection_as) && (XtIsManaged(save_selection_as->dialog))) { #if HAVE_SCHEME fprintf(fd, "(%s #t)\n", S_save_selection_dialog); #endif #if HAVE_RUBY fprintf(fd, "%s(true)\n", to_proc_name(S_save_selection_dialog)); #endif #if HAVE_FORTH fprintf(fd, "#t %s drop\n", S_save_selection_dialog); #endif } if ((save_region_as) && (XtIsManaged(save_region_as->dialog))) { #if HAVE_SCHEME fprintf(fd, "(%s #t)\n", S_save_region_dialog); #endif #if HAVE_RUBY fprintf(fd, "%s(true)\n", to_proc_name(S_save_region_dialog)); #endif #if HAVE_FORTH fprintf(fd, "#t %s drop\n", S_save_region_dialog); #endif } } /* -------------------------------- New File -------------------------------- */ static Widget new_file_dialog = NULL; static file_data *ndat = NULL; static mus_long_t initial_samples = 1; static Widget new_file_text = NULL; static char *new_file_filename = NULL; static void *new_file_watcher = NULL; static void new_filename_modify_callback(Widget w, XtPointer context, XtPointer info); static void new_file_undoit(void) { XmString ok_label; ok_label = XmStringCreateLocalized((char *)"Ok"); XtVaSetValues(new_file_dialog, XmNokLabelString, ok_label, NULL); XmStringFree(ok_label); clear_dialog_error(ndat); XtRemoveCallback(new_file_text, XmNmodifyVerifyCallback, new_filename_modify_callback, NULL); new_file_watcher = unmonitor_file(new_file_watcher); } static void new_filename_modify_callback(Widget w, XtPointer context, XtPointer info) { XmTextVerifyCallbackStruct *cbs = (XmTextVerifyCallbackStruct *)info; new_file_undoit(); cbs->doit = true; } static void clear_error_if_new_filename_changes(Widget dialog) { XtAddCallback(new_file_text, XmNmodifyVerifyCallback, new_filename_modify_callback, NULL); } static void new_file_ok_callback(Widget w, XtPointer context, XtPointer info) { mus_long_t loc; char *newer_name = NULL, *msg; mus_header_t header_type; mus_sample_t sample_type; int srate, chans; newer_name = XmTextGetString(new_file_text); if ((!newer_name) || (!(*newer_name))) { msg = (char *)"new sound needs a file name ('New file:' field is empty)"; post_file_dialog_error((const char *)msg, ndat); clear_error_if_new_filename_changes(new_file_dialog); } else { char *comment; redirect_snd_error_to(post_file_panel_error, (void *)ndat); comment = get_file_dialog_sound_attributes(ndat, &srate, &chans, &header_type, &sample_type, &loc, &initial_samples, 1); redirect_snd_error_to(NULL, NULL); if (ndat->error_widget != NOT_A_SCANF_WIDGET) { clear_error_if_panel_changes(new_file_dialog, ndat); } else { /* handle the overwrite hook directly */ if (new_file_filename) free(new_file_filename); new_file_filename = mus_expand_filename(newer_name); if ((!new_file_watcher) && (ask_before_overwrite(ss)) && (mus_file_probe(new_file_filename))) { XmString ok_label; msg = mus_format("%s exists. If you want to overwrite it, click 'DoIt'", newer_name); post_file_dialog_error((const char *)msg, ndat); clear_error_if_new_filename_changes(new_file_dialog); ok_label = XmStringCreateLocalized((char *)"DoIt"); XtVaSetValues(new_file_dialog, XmNokLabelString, ok_label, NULL); XmUpdateDisplay(MSG_BOX(new_file_dialog, XmDIALOG_OK_BUTTON)); XmStringFree(ok_label); free(msg); } else { snd_info *sp; if (new_file_watcher) new_file_undoit(); ss->local_errno = 0; redirect_snd_error_to(redirect_post_file_dialog_error, (void *)ndat); sp = snd_new_file(new_file_filename, chans, srate, sample_type, header_type, comment, initial_samples); redirect_snd_error_to(NULL, NULL); if (!sp) { clear_error_if_new_filename_changes(new_file_dialog); } else { XtUnmanageChild(new_file_dialog); } } } XtFree(newer_name); if (comment) free(comment); } } static char *new_file_dialog_filename(mus_header_t header_type) { static int new_file_dialog_file_ctr = 1; char *filename = NULL; const char *extension = NULL; filename = (char *)calloc(64, sizeof(char)); switch (header_type) { case MUS_AIFC: extension = "aiff"; break; case MUS_AIFF: extension = "aiff"; break; case MUS_RIFF: extension = "wav"; break; case MUS_RF64: extension = "wav"; break; case MUS_CAFF: extension = "caf"; break; default: extension = "snd"; break; } snprintf(filename, 64, "new-%d.%s", new_file_dialog_file_ctr++, extension); return(filename); } static void load_new_file_defaults(char *newname) { char *new_comment = NULL; mus_header_t header_type; mus_sample_t sample_type; int chans, srate; header_type = default_output_header_type(ss); chans = default_output_chans(ss); sample_type = default_output_sample_type(ss); srate = default_output_srate(ss); new_comment = output_comment(NULL); if ((!newname) || (!(*newname))) newname = new_file_dialog_filename(header_type); mus_sound_forget(newname); set_file_dialog_sound_attributes(ndat, header_type, sample_type, srate, chans, IGNORE_DATA_LOCATION, initial_samples, new_comment); if (new_comment) free(new_comment); } static void new_file_reset_callback(Widget w, XtPointer context, XtPointer info) { char *current_name; current_name = XmTextGetString(new_file_text); load_new_file_defaults(current_name); if (current_name) XtFree(current_name); if (new_file_watcher) new_file_undoit(); } static void new_file_cancel_callback(Widget w, XtPointer context, XtPointer info) { XtUnmanageChild(w); } static void new_file_help_callback(Widget w, XtPointer context, XtPointer info) { new_file_dialog_help(); } widget_t make_new_file_dialog(bool managed) { if (!new_file_dialog) { Arg args[20]; int n; XmString xok, xcancel, xhelp; Widget name_label, form; XmString titlestr; Widget sep, reset_button; titlestr = XmStringCreateLocalized((char *)"New file"); xhelp = XmStringCreateLocalized((char *)I_HELP); xcancel = XmStringCreateLocalized((char *)I_GO_AWAY); xok = XmStringCreateLocalized((char *)"Ok"); n = 0; XtSetArg(args[n], XmNbackground, ss->basic_color); n++; XtSetArg(args[n], XmNresizePolicy, XmRESIZE_GROW); n++; XtSetArg(args[n], XmNcancelLabelString, xcancel); n++; XtSetArg(args[n], XmNhelpLabelString, xhelp); n++; XtSetArg(args[n], XmNokLabelString, xok); n++; XtSetArg(args[n], XmNdialogTitle, titlestr); n++; XtSetArg(args[n], XmNnoResize, false); n++; XtSetArg(args[n], XmNautoUnmanage, false); n++; new_file_dialog = XmCreateTemplateDialog(main_shell(ss), (char *)"new", args, n); XmStringFree(titlestr); XmStringFree(xok); XmStringFree(xcancel); XmStringFree(xhelp); XtAddCallback(new_file_dialog, XmNhelpCallback, new_file_help_callback, NULL); XtAddCallback(new_file_dialog, XmNcancelCallback, new_file_cancel_callback, NULL); XtAddCallback(new_file_dialog, XmNokCallback, new_file_ok_callback, NULL); n = 0; XtSetArg(args[n], XmNbackground, ss->highlight_color); n++; XtSetArg(args[n], XmNarmColor, ss->selection_color); n++; reset_button = XtCreateManagedWidget("Reset", xmPushButtonGadgetClass, new_file_dialog, args, n); XtAddCallback(reset_button, XmNactivateCallback, new_file_reset_callback, NULL); n = 0; form = XtCreateManagedWidget("newfile", xmFormWidgetClass, new_file_dialog, args, n); n = 0; XtSetArg(args[n], XmNbackground, ss->highlight_color); n++; XtSetArg(args[n], XmNforeground, ss->black); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_NONE); n++; name_label = XtCreateManagedWidget("New file:", xmLabelWidgetClass, form, args, n); n = 0; XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNleftWidget, name_label); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++; new_file_text = make_textfield_widget("newtext", form, args, n, ACTIVATABLE, add_completer_func(filename_completer, NULL)); n = 0; XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNtopWidget, new_file_text); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNorientation, XmHORIZONTAL); n++; XtSetArg(args[n], XmNheight, 8); n++; XtSetArg(args[n], XmNseparatorType, XmNO_LINE); n++; sep = XtCreateManagedWidget("sep", xmSeparatorWidgetClass, form, args, n); n = 0; XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNtopWidget, sep); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++; ndat = make_file_data_panel(form, "data-form", args, n, WITH_CHANNELS_FIELD, default_output_header_type(ss), default_output_sample_type(ss), WITHOUT_DATA_LOCATION_FIELD, WITH_SAMPLES_FIELD, WITH_HEADER_TYPE_FIELD, WITH_COMMENT_FIELD, WITH_BUILTIN_HEADERS, WITHOUT_SRATE, WITHOUT_AUTO_COMMENT); ndat->dialog = new_file_dialog; XtManageChild(ndat->error_text); XtManageChild(new_file_dialog); map_over_children(new_file_dialog, set_main_color_of_widget); XtVaSetValues(ndat->sample_type_list, XmNbackground, ss->white, XmNforeground, ss->black, NULL); XtVaSetValues(ndat->header_type_list, XmNbackground, ss->white, XmNforeground, ss->black, NULL); XtVaSetValues(MSG_BOX(new_file_dialog, XmDIALOG_OK_BUTTON), XmNarmColor, ss->selection_color, NULL); XtVaSetValues(MSG_BOX(new_file_dialog, XmDIALOG_CANCEL_BUTTON), XmNarmColor, ss->selection_color, NULL); XtVaSetValues(MSG_BOX(new_file_dialog, XmDIALOG_HELP_BUTTON), XmNarmColor, ss->selection_color, NULL); XtVaSetValues(MSG_BOX(new_file_dialog, XmDIALOG_OK_BUTTON), XmNbackground, ss->highlight_color, NULL); XtVaSetValues(MSG_BOX(new_file_dialog, XmDIALOG_CANCEL_BUTTON), XmNbackground, ss->highlight_color, NULL); XtVaSetValues(MSG_BOX(new_file_dialog, XmDIALOG_HELP_BUTTON), XmNbackground, ss->highlight_color, NULL); set_dialog_widget(NEW_FILE_DIALOG, new_file_dialog); XtUnmanageChild(ndat->error_text); load_new_file_defaults(NULL); } else { char *new_name; new_name = XmTextGetString(new_file_text); if (new_file_watcher) { /* if overwrite question pends, but file has been deleted in the meantime, go back to normal state */ if ((!new_name) || (!(*new_name)) || (!(mus_file_probe(new_name)))) new_file_undoit(); } if (strncmp(new_name, "new-", 4) == 0) { /* if file is open with currently posted new-file dialog name, and it's our name (new-%d), then tick the counter */ snd_info *sp; sp = find_sound(new_name, 0); if (sp) { char *filename; filename = new_file_dialog_filename(default_output_header_type(ss)); XmTextSetString(new_file_text, filename); mus_sound_forget(filename); free(filename); } } if (new_name) XtFree(new_name); } if ((managed) && (!(XtIsManaged(new_file_dialog)))) XtManageChild(new_file_dialog); return(new_file_dialog); } /* ---------------- Edit Header ---------------- */ typedef struct edhead_info { Widget dialog; file_data *edat; snd_info *sp; bool panel_changed; void *file_ro_watcher; int sp_ro_watcher_loc; } edhead_info; static int edhead_info_size = 0; static edhead_info **edhead_infos = NULL; static edhead_info *new_edhead_dialog(void) { int loc = -1; if (edhead_info_size == 0) { loc = 0; edhead_info_size = 4; edhead_infos = (edhead_info **)calloc(edhead_info_size, sizeof(edhead_info *)); } else { int i; for (i = 0; i < edhead_info_size; i++) if ((!edhead_infos[i]) || (!(XtIsManaged(edhead_infos[i]->dialog)))) { loc = i; break; } if (loc == -1) { loc = edhead_info_size; edhead_info_size += 4; edhead_infos = (edhead_info **)realloc(edhead_infos, edhead_info_size * sizeof(edhead_info *)); for (i = loc; i < edhead_info_size; i++) edhead_infos[i] = NULL; } } if (!edhead_infos[loc]) { edhead_infos[loc] = (edhead_info *)calloc(1, sizeof(edhead_info)); edhead_infos[loc]->dialog = NULL; edhead_infos[loc]->panel_changed = false; } edhead_infos[loc]->sp = NULL; edhead_infos[loc]->file_ro_watcher = NULL; return(edhead_infos[loc]); } static XmString make_header_dialog_title(edhead_info *ep, snd_info *sp) { /* dialog may not yet exist */ char *str; XmString xstr; str = (char *)calloc(PRINT_BUFFER_SIZE, sizeof(char)); if ((sp->user_read_only == FILE_READ_ONLY) || (sp->file_read_only == FILE_READ_ONLY)) { if (sp->hdr->type == MUS_RAW) snprintf(str, PRINT_BUFFER_SIZE, "Add header to (write-protected) %s", sp->short_filename); else snprintf(str, PRINT_BUFFER_SIZE, "Edit header of (write-protected) %s", sp->short_filename); if (ep->dialog) set_sensitive(MSG_BOX(ep->dialog, XmDIALOG_OK_BUTTON), (sp->hdr->type == MUS_RAW)); } else { if (sp->hdr->type == MUS_RAW) snprintf(str, PRINT_BUFFER_SIZE, "Add header to %s", sp->short_filename); else snprintf(str, PRINT_BUFFER_SIZE, "Edit header of %s", sp->short_filename); if (ep->dialog) set_sensitive(MSG_BOX(ep->dialog, XmDIALOG_OK_BUTTON), ep->panel_changed); } xstr = XmStringCreateLocalized(str); free(str); return(xstr); } static void edit_header_help_callback(Widget w, XtPointer context, XtPointer info) { edit_header_dialog_help(); } static void edit_header_set_ok_sensitive(Widget w, XtPointer context, XtPointer info) { edhead_info *ep = (edhead_info *)context; if (ep->sp->file_read_only == FILE_READ_WRITE) set_sensitive(MSG_BOX(ep->dialog, XmDIALOG_OK_BUTTON), true); ep->panel_changed = true; } static void eh_cancel(edhead_info *ep) { unreflect_file_data_panel_change(ep->edat, (void *)ep, edit_header_set_ok_sensitive); ep->panel_changed = false; if ((ep->file_ro_watcher) && (ep->sp) && (ep->sp->active) && (ep->sp->filename)) ep->file_ro_watcher = unmonitor_file(ep->file_ro_watcher); } static void edit_header_cancel_callback(Widget w, XtPointer context, XtPointer info) { edhead_info *ep = (edhead_info *)context; XtUnmanageChild(ep->dialog); eh_cancel(ep); } static void edit_header_wm_delete_callback(Widget w, XtPointer context, XtPointer info) { eh_cancel((edhead_info *)context); } static void edit_header_ok_callback(Widget w, XtPointer context, XtPointer info) { edhead_info *ep = (edhead_info *)context; if ((ep->sp) && (ep->sp->active)) { if (XmGetFocusWidget(ep->dialog) == MSG_BOX(ep->dialog, XmDIALOG_OK_BUTTON)) { bool ok; redirect_snd_error_to(redirect_post_file_dialog_error, (void *)(ep->edat)); ok = edit_header_callback(ep->sp, ep->edat, redirect_post_file_dialog_error, post_file_panel_error); /* edit_header_callback, if all goes well, writes the header, recopies the data, * then calls snd_update which closes the sound and reopens it, to force the * new_header to take effect. The read-only watcher is disabled during that * process to keep it from getting a SOUND_IS_CLOSING message from close. */ redirect_snd_error_to(NULL, NULL); if (ep->edat->error_widget != NOT_A_SCANF_WIDGET) { clear_error_if_panel_changes(ep->dialog, ep->edat); return; } else { if (!ok) { set_sensitive(MSG_BOX(ep->dialog, XmDIALOG_OK_BUTTON), false); return; } } ep->file_ro_watcher = unmonitor_file(ep->file_ro_watcher); XtUnmanageChild(ep->dialog); unreflect_file_data_panel_change(ep->edat, (void *)ep, edit_header_set_ok_sensitive); } } } Widget edit_header(snd_info *sp) { file_info *hdr; XmString xstr4; Widget main_w; edhead_info *ep = NULL; if (!sp) return(NULL); /* look for a dialog already editing this sound, raise if found, else make a new one */ if (edhead_info_size > 0) { int i; for (i = 0; i < edhead_info_size; i++) if ((edhead_infos[i]) && ((edhead_infos[i]->sp == sp) || ((edhead_infos[i]->sp) && /* maybe same sound open twice -- only one edit header dialog for it */ (edhead_infos[i]->sp->inuse == SOUND_NORMAL) && (mus_strcmp(sp->filename, edhead_infos[i]->sp->filename))))) { ep = edhead_infos[i]; break; } } if (!ep) ep = new_edhead_dialog(); ep->sp = sp; hdr = sp->hdr; ep->panel_changed = (hdr->type == MUS_RAW); xstr4 = make_header_dialog_title(ep, sp); if (!ep->dialog) { int n; Arg args[20]; XmString xstr1, xstr2, xstr3, titlestr; n = 0; xstr1 = XmStringCreateLocalized((char *)I_GO_AWAY); /* needed by template dialog */ xstr2 = XmStringCreateLocalized((char *)I_HELP); xstr3 = XmStringCreateLocalized((char *)"Save"); titlestr = XmStringCreateLocalized((char *)"Edit Header"); XtSetArg(args[n], XmNbackground, ss->basic_color); n++; XtSetArg(args[n], XmNcancelLabelString, xstr1); n++; XtSetArg(args[n], XmNhelpLabelString, xstr2); n++; XtSetArg(args[n], XmNokLabelString, xstr3); n++; XtSetArg(args[n], XmNmessageString, xstr4); n++; XtSetArg(args[n], XmNdialogTitle, titlestr); n++; XtSetArg(args[n], XmNautoUnmanage, false); n++; XtSetArg(args[n], XmNresizePolicy, XmRESIZE_GROW); n++; XtSetArg(args[n], XmNnoResize, false); n++; XtSetArg(args[n], XmNtransient, false); n++; ep->dialog = XmCreateTemplateDialog(main_shell(ss), (char *)"Edit Header", args, n); XtAddCallback(ep->dialog, XmNcancelCallback, edit_header_cancel_callback, (XtPointer)ep); XtAddCallback(ep->dialog, XmNhelpCallback, edit_header_help_callback, (XtPointer)ep); XtAddCallback(ep->dialog, XmNokCallback, edit_header_ok_callback, (XtPointer)ep); XmStringFree(xstr1); XmStringFree(xstr2); XmStringFree(xstr3); XmStringFree(titlestr); n = 0; main_w = XtCreateManagedWidget("eh-main", xmFormWidgetClass, ep->dialog, args, n); n = 0; XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++; ep->edat = make_file_data_panel(main_w, "Edit Header", args, n, WITH_CHANNELS_FIELD, hdr->type, hdr->sample_type, WITH_DATA_LOCATION_FIELD, WITH_SAMPLES_FIELD, WITH_HEADER_TYPE_FIELD, WITH_COMMENT_FIELD, WITH_BUILTIN_HEADERS, WITHOUT_SRATE, WITHOUT_AUTO_COMMENT); ep->edat->dialog = ep->dialog; if (hdr->type == MUS_RAW) set_file_dialog_sound_attributes(ep->edat, default_output_header_type(ss), hdr->sample_type, hdr->srate, hdr->chans, hdr->data_location, hdr->samples, hdr->comment); else set_file_dialog_sound_attributes(ep->edat, hdr->type, hdr->sample_type, hdr->srate, hdr->chans, hdr->data_location, hdr->samples, hdr->comment); XtManageChild(ep->edat->error_text); XtManageChild(ep->dialog); map_over_children(ep->dialog, set_main_color_of_widget); XtVaSetValues(MSG_BOX(ep->dialog, XmDIALOG_OK_BUTTON), XmNarmColor, ss->selection_color, NULL); XtVaSetValues(MSG_BOX(ep->dialog, XmDIALOG_CANCEL_BUTTON), XmNarmColor, ss->selection_color, NULL); XtVaSetValues(MSG_BOX(ep->dialog, XmDIALOG_HELP_BUTTON), XmNarmColor, ss->selection_color, NULL); XtVaSetValues(MSG_BOX(ep->dialog, XmDIALOG_OK_BUTTON), XmNbackground, ss->highlight_color, NULL); XtVaSetValues(MSG_BOX(ep->dialog, XmDIALOG_CANCEL_BUTTON), XmNbackground, ss->highlight_color, NULL); XtVaSetValues(MSG_BOX(ep->dialog, XmDIALOG_HELP_BUTTON), XmNbackground, ss->highlight_color, NULL); XtVaSetValues(ep->edat->header_type_list, XmNbackground, ss->white, XmNforeground, ss->black, NULL); XtVaSetValues(ep->edat->sample_type_list, XmNbackground, ss->white, XmNforeground, ss->black, NULL); XtVaSetValues(MSG_BOX(ep->dialog, XmDIALOG_MESSAGE_LABEL), XmNbackground, ss->basic_color, NULL); set_dialog_widget(EDIT_HEADER_DIALOG, ep->dialog); { Atom wm_delete_window; wm_delete_window = XmInternAtom(main_display(ss), (char *)"WM_DELETE_WINDOW", false); XmAddWMProtocolCallback(XtParent(ep->dialog), wm_delete_window, edit_header_wm_delete_callback, (XtPointer)ep); } XtUnmanageChild(ep->edat->error_text); } else { XtVaSetValues(ep->dialog, XmNmessageString, xstr4, NULL); if (hdr->type == MUS_RAW) set_file_dialog_sound_attributes(ep->edat, default_output_header_type(ss), hdr->sample_type, hdr->srate, hdr->chans, hdr->data_location, hdr->samples, hdr->comment); else set_file_dialog_sound_attributes(ep->edat, hdr->type, hdr->sample_type, hdr->srate, hdr->chans, hdr->data_location, hdr->samples, hdr->comment); raise_dialog(ep->dialog); clear_dialog_error(ep->edat); } set_sensitive(MSG_BOX(ep->dialog, XmDIALOG_OK_BUTTON), (hdr->type == MUS_RAW)); /* nothing needs to be saved when we start */ XmStringFree(xstr4); if (!(XtIsManaged(ep->dialog))) XtManageChild(ep->dialog); reflect_file_data_panel_change(ep->edat, (void *)ep, edit_header_set_ok_sensitive); return(ep->dialog); } void save_edit_header_dialog_state(FILE *fd) { int i; for (i = 0; i < edhead_info_size; i++) if (edhead_infos[i]) { edhead_info *ep; ep = edhead_infos[i]; if ((ep->dialog) && (XtIsManaged(ep->dialog)) && (snd_ok(ep->sp))) { #if HAVE_SCHEME fprintf(fd, "(%s (%s \"%s\"))\n", S_edit_header_dialog, S_find_sound, ep->sp->short_filename); #endif #if HAVE_RUBY fprintf(fd, "%s(%s(\"%s\"))\n", to_proc_name(S_edit_header_dialog), to_proc_name(S_find_sound), ep->sp->short_filename); #endif #if HAVE_FORTH fprintf(fd, "\"%s\" %s %s drop\n", ep->sp->short_filename, S_find_sound, S_edit_header_dialog); #endif break; } } } typedef enum {VF_AT_CURSOR, VF_AT_END, VF_AT_BEGINNING, VF_AT_MARK, VF_AT_SAMPLE} vf_location_t; typedef struct { widget_t rw; widget_t nm; #if WITH_AUDIO widget_t pl; #endif int pos; void *vdat; } vf_row; typedef struct { vf_row **file_list_entries; int index, size; char **names; char **full_names; int end; int sorter; int *selected_files; int selected_files_size; int currently_selected_files; mus_float_t amp; vf_location_t location_choice; mus_float_t speed; graphics_context *env_ax; env_editor *spf; env *amp_env; bool has_error; int sort_items_size; speed_style_t speed_style; mus_long_t beg; int dirs_size; void *dirs; char **dir_names; bool need_update; widget_t dialog; widget_t file_list; widget_t file_list_holder; widget_t left_title; widget_t info1; widget_t info2; widget_t mixB; widget_t insertB; widget_t at_cursor_button; widget_t at_end_button; widget_t at_beginning_button; widget_t at_mark_button; widget_t at_sample_button; widget_t at_sample_text; widget_t at_mark_text; widget_t amp_number; widget_t amp_scrollbar; widget_t speed_number; widget_t speed_scrollbar; widget_t env_drawer; widget_t a_to_z; widget_t z_to_a; widget_t new_to_old; widget_t old_to_new; widget_t small_to_big; widget_t big_to_small; widget_t smenu; widget_t current_play_button; widget_t amp_event; widget_t speed_event; widget_t speed_label_event; widget_t add_text; widget_t* sort_items; GC env_gc; } view_files_info; static void vf_unhighlight_row(widget_t nm, widget_t rw); static void vf_highlight_row(widget_t nm, widget_t rw); static void vf_post_info(view_files_info *vdat, int pos); static void vf_unpost_info(view_files_info *vdat); static mus_long_t vf_location(view_files_info *vdat); static void vf_post_error(const char *error_msg, view_files_info *data); static void redirect_vf_post_error(const char *error_msg, void *data); static void redirect_vf_post_location_error(const char *error_msg, void *data); static void vf_post_add_error(const char *error_msg, view_files_info *data); static widget_t make_view_files_dialog_1(view_files_info *vdat, bool managed); static void vf_post_selected_files_list(view_files_info *vdat); static void view_files_add_file_or_directory(view_files_info *vdat, const char *file_or_dir); static void vf_reflect_sort_choice_in_menu(view_files_info *vdat); static vf_row *view_files_make_row(view_files_info *vdat, widget_t last_row); static void vf_flash_row(vf_row *r); static void vf_set_amp(view_files_info *vdat, mus_float_t val); static void vf_set_speed(view_files_info *vdat, mus_float_t val); static void vf_set_amp_env(view_files_info *vdat, env *new_e); static void vf_clear_error(view_files_info *vdat); static void vf_mix_insert_buttons_set_sensitive(view_files_info *vdat, bool sensitive); static int vf_mix(view_files_info *vdat); static bool vf_insert(view_files_info *vdat); static void view_files_display_list(view_files_info *vdat); static void view_files_unmonitor_directories(view_files_info *vdat) {} static void view_files_monitor_directory(view_files_info *vdat, const char *dirname) {} /* -------------------------------- Raw Data Dialog -------------------------------- */ /* we keep an array of raw data dialogs so that any number can be active at once */ typedef struct raw_info { Widget dialog; mus_long_t location; file_data *rdat; read_only_t read_only; bool selected; char *filename; char *help; open_requestor_t requestor; void *requestor_data; Widget requestor_dialog; } raw_info; static int raw_info_size = 0; static raw_info **raw_infos = NULL; static raw_info *new_raw_dialog(void) { int loc = -1; if (raw_info_size == 0) { loc = 0; raw_info_size = 4; raw_infos = (raw_info **)calloc(raw_info_size, sizeof(raw_info *)); } else { int i; for (i = 0; i < raw_info_size; i++) if ((!raw_infos[i]) || (!(XtIsManaged(raw_infos[i]->dialog)))) { loc = i; break; } if (loc == -1) { loc = raw_info_size; raw_info_size += 4; raw_infos = (raw_info **)realloc(raw_infos, raw_info_size * sizeof(raw_info *)); for (i = loc; i < raw_info_size; i++) raw_infos[i] = NULL; } } if (!raw_infos[loc]) { raw_infos[loc] = (raw_info *)calloc(1, sizeof(raw_info)); raw_infos[loc]->dialog = NULL; raw_infos[loc]->filename = NULL; raw_infos[loc]->help = NULL; } raw_infos[loc]->requestor = NO_REQUESTOR; raw_infos[loc]->requestor_data = NULL; raw_infos[loc]->location = 0; return(raw_infos[loc]); } static void raw_data_ok_callback(Widget w, XtPointer context, XtPointer info) { raw_info *rp = (raw_info *)context; int raw_srate = 0, raw_chans = 0; mus_sample_t raw_sample_type = MUS_UNKNOWN_SAMPLE; redirect_snd_error_to(post_file_panel_error, (void *)(rp->rdat)); get_file_dialog_sound_attributes(rp->rdat, &raw_srate, &raw_chans, NULL, &raw_sample_type, &(rp->location), NULL, 1); redirect_snd_error_to(NULL, NULL); if (rp->rdat->error_widget != NOT_A_SCANF_WIDGET) { clear_error_if_panel_changes(rp->dialog, rp->rdat); } else { mus_header_set_raw_defaults(raw_srate, raw_chans, raw_sample_type); mus_sound_override_header(rp->filename, raw_srate, raw_chans, raw_sample_type, MUS_RAW, rp->location, mus_bytes_to_samples(raw_sample_type, mus_sound_length(rp->filename) - rp->location)); /* choose action based on how we got here */ if ((rp->requestor_dialog) && ((rp->requestor == FROM_MIX_DIALOG) || (rp->requestor == FROM_INSERT_DIALOG) || (rp->requestor == FROM_VIEW_FILES_MIX_DIALOG) || (rp->requestor == FROM_VIEW_FILES_INSERT_DIALOG))) { ss->reloading_updated_file = true; /* don't reread lack-of-header! */ /* redirection may be still set here, but I'll make it obvious */ switch (rp->requestor) { case FROM_MIX_DIALOG: redirect_snd_error_to(redirect_file_open_error, (void *)mdat); mix_complete_file_at_cursor(any_selected_sound(), rp->filename); break; case FROM_INSERT_DIALOG: redirect_snd_error_to(redirect_file_open_error, (void *)idat); insert_complete_file_at_cursor(any_selected_sound(), rp->filename); break; case FROM_VIEW_FILES_MIX_DIALOG: { view_files_info *vdat = (view_files_info *)(rp->requestor_data); redirect_snd_error_to(redirect_vf_post_error, rp->requestor_data); vf_mix(vdat); } break; case FROM_VIEW_FILES_INSERT_DIALOG: { view_files_info *vdat = (view_files_info *)(rp->requestor_data); redirect_snd_error_to(redirect_vf_post_error, rp->requestor_data); vf_insert(vdat); } break; default: snd_error("wrong requestor type in raw data dialog? %d\n", (int)(rp->requestor)); break; } redirect_snd_error_to(NULL, NULL); ss->reloading_updated_file = false; } else { /* FROM_OPEN_DIALOG (has requestor_dialog) * FROM_KEYBOARD (has sp = requestor_data) * FROM_DRAG_AND_DROP (just open, no needed side effects) * FROM_VIEW_FILES (ditto) * FROM_VIEW_FILES_MIX_DIALOG or INSERT -- requestor_data contains needed info to complete the action */ file_info *hdr; hdr = (file_info *)calloc(1, sizeof(file_info)); hdr->name = mus_strdup(rp->filename); hdr->type = MUS_RAW; hdr->srate = raw_srate; hdr->chans = raw_chans; hdr->sample_type = raw_sample_type; hdr->samples = mus_bytes_to_samples(raw_sample_type, mus_sound_length(rp->filename) - rp->location); hdr->data_location = rp->location; hdr->comment = NULL; if (rp->requestor == FROM_KEYBOARD) { clear_status_area((snd_info *)(rp->requestor_data)); rp->selected = true; } finish_opening_sound(add_sound_window(rp->filename, rp->read_only, hdr), rp->selected); } XtUnmanageChild(rp->dialog); } } static void raw_data_cancel_callback(Widget w, XtPointer context, XtPointer info) { raw_info *rp = (raw_info *)context; XtUnmanageChild(rp->dialog); if ((rp->requestor_dialog) && ((rp->requestor == FROM_OPEN_DIALOG) || (rp->requestor == FROM_MIX_DIALOG))) XtManageChild(rp->requestor_dialog); } static void raw_data_reset_callback(Widget w, XtPointer context, XtPointer info) { raw_info *rp = (raw_info *)context; int raw_srate, raw_chans; mus_sample_t raw_sample_type; rp->location = 0; mus_header_raw_defaults(&raw_srate, &raw_chans, &raw_sample_type); /* pick up defaults */ set_file_dialog_sound_attributes(rp->rdat, IGNORE_HEADER_TYPE, raw_sample_type, raw_srate, raw_chans, rp->location, IGNORE_SAMPLES, NULL); if (XtIsManaged(rp->rdat->error_text)) XtUnmanageChild(rp->rdat->error_text); } static void raw_data_help_callback(Widget w, XtPointer context, XtPointer info) { raw_info *rp = (raw_info *)context; raw_data_dialog_help(rp->help); } static void make_raw_data_dialog(raw_info *rp, const char *title) { XmString go_away, xhelp, xok, xtitle, titlestr; int n; int raw_srate, raw_chans; mus_sample_t raw_sample_type; Arg args[20]; Widget reset_button, main_w; go_away = XmStringCreateLocalized((char *)I_GO_AWAY); /* needed by template dialog */ xhelp = XmStringCreateLocalized((char *)I_HELP); xok = XmStringCreateLocalized((char *)"Ok"); if (!title) titlestr = XmStringCreateLocalized((char *)"No header on file"); else titlestr = XmStringCreateLocalized((char *)title); xtitle = XmStringCreateLocalized((char *)title); n = 0; XtSetArg(args[n], XmNbackground, ss->basic_color); n++; XtSetArg(args[n], XmNcancelLabelString, go_away); n++; XtSetArg(args[n], XmNhelpLabelString, xhelp); n++; XtSetArg(args[n], XmNokLabelString, xok); n++; XtSetArg(args[n], XmNmessageString, xtitle); n++; XtSetArg(args[n], XmNdialogTitle, titlestr); n++; XtSetArg(args[n], XmNresizePolicy, XmRESIZE_GROW); n++; XtSetArg(args[n], XmNallowShellResize, true); n++; XtSetArg(args[n], XmNnoResize, false); n++; XtSetArg(args[n], XmNautoUnmanage, false); n++; /* not transient -- we want this window to remain visible if possible */ rp->dialog = XmCreateWarningDialog(main_shell(ss), (char *)"raw data", args, n); XtAddCallback(rp->dialog, XmNcancelCallback, raw_data_cancel_callback, (XtPointer)rp); XtAddCallback(rp->dialog, XmNhelpCallback, raw_data_help_callback, (XtPointer)rp); XtAddCallback(rp->dialog, XmNokCallback, raw_data_ok_callback, (XtPointer)rp); XmStringFree(go_away); XmStringFree(xhelp); XmStringFree(xok); XmStringFree(xtitle); XmStringFree(titlestr); n = 0; XtSetArg(args[n], XmNbackground, ss->highlight_color); n++; XtSetArg(args[n], XmNarmColor, ss->selection_color); n++; reset_button = XtCreateManagedWidget("Reset", xmPushButtonGadgetClass, rp->dialog, args, n); XtAddCallback(reset_button, XmNactivateCallback, raw_data_reset_callback, (XtPointer)rp); mus_header_raw_defaults(&raw_srate, &raw_chans, &raw_sample_type); /* pick up defaults */ n = 0; XtSetArg(args[n], XmNallowResize, true); n++; XtSetArg(args[n], XmNresizePolicy, XmRESIZE_NONE); n++; main_w = XtCreateManagedWidget("raw-main", xmFormWidgetClass, rp->dialog, args, n); n = 0; XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++; rp->rdat = make_file_data_panel(main_w, "data-form", args, n, WITH_CHANNELS_FIELD, MUS_RAW, raw_sample_type, WITH_DATA_LOCATION_FIELD, WITHOUT_SAMPLES_FIELD, WITHOUT_HEADER_TYPE_FIELD, WITHOUT_COMMENT_FIELD, WITH_READABLE_HEADERS, WITHOUT_SRATE, WITHOUT_AUTO_COMMENT); rp->rdat->dialog = rp->dialog; set_file_dialog_sound_attributes(rp->rdat, IGNORE_HEADER_TYPE, raw_sample_type, raw_srate, raw_chans, rp->location, IGNORE_SAMPLES, NULL); map_over_children(rp->dialog, set_main_color_of_widget); XtVaSetValues(MSG_BOX(rp->dialog, XmDIALOG_OK_BUTTON), XmNarmColor, ss->selection_color, NULL); XtVaSetValues(MSG_BOX(rp->dialog, XmDIALOG_CANCEL_BUTTON), XmNarmColor, ss->selection_color, NULL); XtVaSetValues(MSG_BOX(rp->dialog, XmDIALOG_HELP_BUTTON), XmNarmColor, ss->selection_color, NULL); XtVaSetValues(MSG_BOX(rp->dialog, XmDIALOG_OK_BUTTON), XmNbackground, ss->highlight_color, NULL); XtVaSetValues(MSG_BOX(rp->dialog, XmDIALOG_CANCEL_BUTTON), XmNbackground, ss->highlight_color, NULL); XtVaSetValues(MSG_BOX(rp->dialog, XmDIALOG_HELP_BUTTON), XmNbackground, ss->highlight_color, NULL); XtVaSetValues(reset_button, XmNselectColor, ss->selection_color, NULL); XtVaSetValues(rp->rdat->sample_type_list, XmNbackground, ss->white, XmNforeground, ss->black, NULL); /* * this line makes the dialog take up all vertical space on the screen * XtManageChild(rp->rdat->error_text); */ XtVaSetValues(MSG_BOX(rp->dialog, XmDIALOG_MESSAGE_LABEL), XmNbackground, ss->basic_color, NULL); XtManageChild(rp->dialog); XtUnmanageChild(rp->rdat->error_text); set_dialog_widget(RAW_DATA_DIALOG, rp->dialog); } void raw_data_dialog_to_file_info(const char *filename, char *title, char *info, read_only_t read_only, bool selected) { /* put up dialog for srate, chans, sample type */ raw_info *rp; rp = new_raw_dialog(); rp->read_only = read_only; rp->selected = selected; if (rp->filename) free(rp->filename); rp->filename = mus_strdup(filename); rp->requestor = ss->open_requestor; rp->requestor_data = ss->open_requestor_data; rp->requestor_dialog = ss->requestor_dialog; ss->open_requestor = NO_REQUESTOR; ss->requestor_dialog = NULL; ss->open_requestor_data = NULL; if ((rp->requestor_dialog) && ((rp->requestor == FROM_OPEN_DIALOG) || (rp->requestor == FROM_MIX_DIALOG))) XtUnmanageChild(rp->requestor_dialog); if (!title) title = mus_format("no header found on %s\n", filename); if (!(rp->dialog)) make_raw_data_dialog(rp, title); else { XmString xstr4; xstr4 = XmStringCreateLocalized(title); XtVaSetValues(rp->dialog, XmNmessageString, xstr4, NULL); XmStringFree(xstr4); } free(title); if (rp->help) free(rp->help); if (info) { XtVaSetValues(MSG_BOX(rp->dialog, XmDIALOG_HELP_BUTTON), XmNbackground, ss->green, NULL); rp->help = mus_strdup(info); free(info); } else { XtVaSetValues(MSG_BOX(rp->dialog, XmDIALOG_HELP_BUTTON), XmNbackground, ss->highlight_color, NULL); rp->help = NULL; } raise_dialog(rp->dialog); if (!XtIsManaged(rp->dialog)) XtManageChild(rp->dialog); } /* ---------------- INFO MONOLOG ---------------- */ #define POST_IT_ROWS 12 #define POST_IT_COLUMNS 56 static Widget post_it_dialog = NULL; static Widget post_it_text = NULL; static void create_post_it_monolog(void) { /* create scrollable but not editable text window; used for fft peaks, sp info, and raw data help displays */ Arg args[20]; int n; n = 0; XtSetArg(args[n], XmNbackground, ss->basic_color); n++; XtSetArg(args[n], XmNresizePolicy, XmRESIZE_GROW); n++; XtSetArg(args[n], XmNnoResize, false); n++; XtSetArg(args[n], XmNtransient, false); n++; post_it_dialog = XmCreateMessageDialog(main_pane(ss), (char *)"info", args, n); XtUnmanageChild(MSG_BOX(post_it_dialog, XmDIALOG_CANCEL_BUTTON)); XtUnmanageChild(MSG_BOX(post_it_dialog, XmDIALOG_HELP_BUTTON)); XtUnmanageChild(MSG_BOX(post_it_dialog, XmDIALOG_SYMBOL_LABEL)); XtVaSetValues(MSG_BOX(post_it_dialog, XmDIALOG_MESSAGE_LABEL), XmNbackground, ss->highlight_color, NULL); n = 0; XtSetArg(args[n], XmNeditMode, XmMULTI_LINE_EDIT); n++; XtSetArg(args[n], XmNeditable, false); n++; XtSetArg(args[n], XmNcolumns, POST_IT_COLUMNS); n++; XtSetArg(args[n], XmNrows, POST_IT_ROWS); n++; XtSetArg(args[n], XmNforeground, ss->black); n++; /* needed if color allocation fails completely */ XtSetArg(args[n], XmNbackground, ss->white); n++; post_it_text = XmCreateScrolledText(post_it_dialog, (char *)"post-it-text", args, n); XtManageChild(post_it_text); XtManageChild(post_it_dialog); map_over_children(post_it_dialog, set_main_color_of_widget); XtVaSetValues(post_it_text, XmNbackground, ss->white, XmNforeground, ss->black, NULL); XtVaSetValues(MSG_BOX(post_it_dialog, XmDIALOG_OK_BUTTON), XmNarmColor, ss->selection_color, NULL); XtVaSetValues(MSG_BOX(post_it_dialog, XmDIALOG_OK_BUTTON), XmNbackground, ss->highlight_color, NULL); set_dialog_widget(POST_IT_DIALOG, post_it_dialog); } widget_t post_it(const char *subject, const char *str) { /* place string in scrollable help window */ XmString xstr1, xstr2; if (!ss) return(NULL); /* an attempt to call this before X/Motif is ready */ if (!(post_it_dialog)) create_post_it_monolog(); else raise_dialog(post_it_dialog); xstr1 = XmStringCreateLocalized((char *)subject); xstr2 = XmStringCreateLocalized((char *)subject); XtVaSetValues(post_it_dialog, XmNmessageString, xstr1, XmNdialogTitle, xstr2, NULL); XmTextSetString(post_it_text, (char *)str); if (!XtIsManaged(post_it_dialog)) XtManageChild(post_it_dialog); XmStringFree(xstr1); XmStringFree(xstr2); return(post_it_dialog); } void post_it_append(const char *str) { if (post_it_dialog) XmTextInsert(post_it_text, XmTextGetLastPosition(post_it_text), (char *)str); } void save_post_it_dialog_state(FILE *fd) { if ((post_it_dialog) && (XtIsManaged(post_it_dialog))) { char *subject = NULL, *text = NULL; subject = dialog_get_title(post_it_dialog); text = XmTextGetString(post_it_text); #if HAVE_SCHEME fprintf(fd, "(%s \"%s\" \"%s\")\n", S_info_dialog, subject, text); #endif #if HAVE_RUBY fprintf(fd, "%s(\"%s\", \"%s\")\n", to_proc_name(S_info_dialog), subject, text); #endif #if HAVE_FORTH fprintf(fd, "\"%s\" \"%s\" %s drop\n", subject, text, S_info_dialog); #endif if (subject) free(subject); if (text) XtFree(text); } } /* ---------------- unsaved edits dialog ---------------- */ static int num_unsaved_edits_dialogs = 0; static Widget *unsaved_edits_dialogs = NULL; static snd_info **unsaved_edits_sounds = NULL; static Widget unsaved_edits_dialog(snd_info *sp) { int i; /* are there any such dialogs? */ if (num_unsaved_edits_dialogs == 0) return(NULL); /* now see if we've already prompted about this sound */ for (i = 0; i < num_unsaved_edits_dialogs; i++) if (unsaved_edits_sounds[i] == sp) return(unsaved_edits_dialogs[i]); /* try to find a free unmanaged dialog */ for (i = 0; i < num_unsaved_edits_dialogs; i++) if ((unsaved_edits_dialogs[i]) && (!XtIsManaged(unsaved_edits_dialogs[i]))) return(unsaved_edits_dialogs[i]); return(NULL); } static void save_unsaved_edits_dialog(Widget d, snd_info *sp) { if (num_unsaved_edits_dialogs == 0) { unsaved_edits_dialogs = (Widget *)calloc(1, sizeof(Widget)); unsaved_edits_sounds = (snd_info **)calloc(1, sizeof(snd_info *)); } else { unsaved_edits_dialogs = (Widget *)realloc(unsaved_edits_dialogs, (num_unsaved_edits_dialogs + 1) * sizeof(Widget)); unsaved_edits_sounds = (snd_info **)realloc(unsaved_edits_sounds, (num_unsaved_edits_dialogs + 1) * sizeof(snd_info *)); } unsaved_edits_dialogs[num_unsaved_edits_dialogs] = d; unsaved_edits_sounds[num_unsaved_edits_dialogs] = sp; num_unsaved_edits_dialogs++; } void unpost_unsaved_edits_if_any(snd_info *sp) { int i; for (i = 0; i < num_unsaved_edits_dialogs; i++) if (((unsaved_edits_sounds[i] == sp) || (!snd_ok(unsaved_edits_sounds[i]))) && (XtIsManaged(unsaved_edits_dialogs[i]))) XtUnmanageChild(unsaved_edits_dialogs[i]); } static void zero_edits(chan_info *cp) { cp->edit_ctr = 0; } static void unsaved_edits_no_callback(Widget w, XtPointer context, XtPointer info) { snd_info *sp = (snd_info *)context; for_each_sound_chan(sp, zero_edits); snd_close_file(sp); } static void unsaved_edits_yes_callback(Widget w, XtPointer context, XtPointer info) { snd_info *sp = (snd_info *)context; save_edits(sp); snd_close_file(sp); } static void unsaved_edits_help_callback(Widget w, XtPointer context, XtPointer info) { snd_help("save edits?", "You have set " S_ask_about_unsaved_edits " to " PROC_TRUE ", so you will be asked whether you want \ to save edits if you try to close a sound that has unsaved edits.", WITH_WORD_WRAP); } void save_edits_now(snd_info *sp) { char *question; XmString q; Widget dialog; question = mus_format("%s has unsaved edits. Save them?", sp->short_filename); q = XmStringCreateLocalized(question); dialog = unsaved_edits_dialog(sp); if (!dialog) { Arg args[20]; int n; XmString yes, no; yes = XmStringCreateLocalized((char *)"yes"); no = XmStringCreateLocalized((char *)"no"); n = 0; XtSetArg(args[n], XmNbackground, ss->basic_color); n++; XtSetArg(args[n], XmNokLabelString, yes); n++; XtSetArg(args[n], XmNcancelLabelString, no); n++; XtSetArg(args[n], XmNmessageString, q); n++; dialog = XmCreateQuestionDialog(main_pane(ss), sp->filename, args, n); save_unsaved_edits_dialog(dialog, sp); XtAddCallback(dialog, XmNhelpCallback, unsaved_edits_help_callback, (XtPointer)sp); XtAddCallback(dialog, XmNokCallback, unsaved_edits_yes_callback, (XtPointer)sp); XtAddCallback(dialog, XmNcancelCallback, unsaved_edits_no_callback, (XtPointer)sp); XmStringFree(yes); XmStringFree(no); map_over_children(dialog, set_main_color_of_widget); XtVaSetValues(MSG_BOX(dialog, XmDIALOG_OK_BUTTON), XmNarmColor, ss->selection_color, NULL); XtVaSetValues(MSG_BOX(dialog, XmDIALOG_OK_BUTTON), XmNbackground, ss->highlight_color, NULL); XtVaSetValues(MSG_BOX(dialog, XmDIALOG_CANCEL_BUTTON), XmNarmColor, ss->selection_color, NULL); XtVaSetValues(MSG_BOX(dialog, XmDIALOG_CANCEL_BUTTON), XmNbackground, ss->highlight_color, NULL); XtVaSetValues(MSG_BOX(dialog, XmDIALOG_HELP_BUTTON), XmNarmColor, ss->selection_color, NULL); XtVaSetValues(MSG_BOX(dialog, XmDIALOG_HELP_BUTTON), XmNbackground, ss->highlight_color, NULL); } else { XtVaSetValues(dialog, XmNmessageString, q, NULL); } XmStringFree(q); free(question); XtManageChild(dialog); } /* ---------------- file has changed dialog ---------------- */ static int num_file_has_changed_dialogs = 0; static Widget *file_has_changed_dialogs = NULL; static snd_info **file_has_changed_sounds = NULL; static Widget file_has_changed_dialog(snd_info *sp) { int i; /* are there any such dialogs? */ if (num_file_has_changed_dialogs == 0) return(NULL); /* now see if we've already prompted about this sound */ for (i = 0; i < num_file_has_changed_dialogs; i++) if (file_has_changed_sounds[i] == sp) return(file_has_changed_dialogs[i]); /* try to find a free unmanaged dialog */ for (i = 0; i < num_file_has_changed_dialogs; i++) if ((file_has_changed_dialogs[i]) && (!XtIsManaged(file_has_changed_dialogs[i]))) return(file_has_changed_dialogs[i]); return(NULL); } static void save_file_has_changed_dialog(Widget d, snd_info *sp) { if (num_file_has_changed_dialogs == 0) { file_has_changed_dialogs = (Widget *)calloc(1, sizeof(Widget)); file_has_changed_sounds = (snd_info **)calloc(1, sizeof(snd_info *)); } else { file_has_changed_dialogs = (Widget *)realloc(file_has_changed_dialogs, (num_file_has_changed_dialogs + 1) * sizeof(Widget)); file_has_changed_sounds = (snd_info **)realloc(file_has_changed_sounds, (num_file_has_changed_dialogs + 1) * sizeof(snd_info *)); } file_has_changed_dialogs[num_file_has_changed_dialogs] = d; file_has_changed_sounds[num_file_has_changed_dialogs] = sp; num_file_has_changed_dialogs++; } void unpost_file_has_changed_if_any(snd_info *sp) { int i; for (i = 0; i < num_file_has_changed_dialogs; i++) if (((file_has_changed_sounds[i] == sp) || (!snd_ok(file_has_changed_sounds[i]))) && (XtIsManaged(file_has_changed_dialogs[i]))) XtUnmanageChild(file_has_changed_dialogs[i]); } static void file_has_changed_no_callback(Widget w, XtPointer context, XtPointer info) { } static void file_has_changed_yes_callback(Widget w, XtPointer context, XtPointer info) { snd_info *sp = (snd_info *)context; save_edits_without_asking(sp); sp->need_update = false; stop_bomb(sp); /* in case Snd already noticed the problem */ clear_status_area(sp); } static void file_has_changed_help_callback(Widget w, XtPointer context, XtPointer info) { snd_help("save edits?", "The file has changed unexpectedly, so in most cases, saving the current edits can't do anything useful. But you can try anyway!", WITH_WORD_WRAP); } void changed_file_dialog(snd_info *sp) { char *question; XmString q; Widget dialog; question = mus_format("%s has changed! Save edits anyway?", sp->short_filename); q = XmStringCreateLocalized(question); dialog = file_has_changed_dialog(sp); if (!dialog) { Arg args[20]; int n; XmString yes, no; yes = XmStringCreateLocalized((char *)"yes"); no = XmStringCreateLocalized((char *)"no"); n = 0; XtSetArg(args[n], XmNbackground, ss->basic_color); n++; XtSetArg(args[n], XmNokLabelString, yes); n++; XtSetArg(args[n], XmNcancelLabelString, no); n++; XtSetArg(args[n], XmNmessageString, q); n++; dialog = XmCreateQuestionDialog(main_pane(ss), sp->filename, args, n); save_file_has_changed_dialog(dialog, sp); XtAddCallback(dialog, XmNhelpCallback, file_has_changed_help_callback, (XtPointer)sp); XtAddCallback(dialog, XmNokCallback, file_has_changed_yes_callback, (XtPointer)sp); XtAddCallback(dialog, XmNcancelCallback, file_has_changed_no_callback, (XtPointer)sp); XmStringFree(yes); XmStringFree(no); map_over_children(dialog, set_main_color_of_widget); XtVaSetValues(MSG_BOX(dialog, XmDIALOG_OK_BUTTON), XmNarmColor, ss->selection_color, NULL); XtVaSetValues(MSG_BOX(dialog, XmDIALOG_OK_BUTTON), XmNbackground, ss->highlight_color, NULL); XtVaSetValues(MSG_BOX(dialog, XmDIALOG_CANCEL_BUTTON), XmNarmColor, ss->selection_color, NULL); XtVaSetValues(MSG_BOX(dialog, XmDIALOG_CANCEL_BUTTON), XmNbackground, ss->highlight_color, NULL); XtVaSetValues(MSG_BOX(dialog, XmDIALOG_HELP_BUTTON), XmNarmColor, ss->selection_color, NULL); XtVaSetValues(MSG_BOX(dialog, XmDIALOG_HELP_BUTTON), XmNbackground, ss->highlight_color, NULL); } else { XtVaSetValues(dialog, XmNmessageString, q, NULL); } XmStringFree(q); free(question); XtManageChild(dialog); } /* ---------------- view files dialog ---------------- */ /* -------- view files shared code -------- */ static void view_files_clear_selected_files(view_files_info *vdat); static int view_files_add_selected_file(view_files_info *vdat, vf_row *r); static int view_files_find_row(view_files_info *vdat, const char *name); static int view_files_info_size = 0; static view_files_info **view_files_infos = NULL; static Xen vf_open_file_watcher(Xen hook_or_reason) { int k; /* reasons are FILE_OPENED|CLOSED, but it's not worth the trouble of splitting them out here */ /* loop through all vf dialogs ... */ for (k = 0; k < view_files_info_size; k++) if ((view_files_infos[k]) && (view_files_infos[k]->dialog) && (widget_is_active(view_files_infos[k]->dialog))) { view_files_info *vdat; vdat = view_files_infos[k]; vf_mix_insert_buttons_set_sensitive(vdat, ((vdat->currently_selected_files > 0) && (any_selected_sound()))); } return(Xen_false); } int view_files_dialog_list_length(void) { int i, n = 0; for (i = 0; i < view_files_info_size; i++) if ((view_files_infos[i]) && (view_files_infos[i]->dialog)) n++; return(n); } char **view_files_dialog_titles(void) { int n; n = view_files_dialog_list_length(); if (n > 0) { char **titles; int i, j = 0; titles = (char **)calloc(n + 1, sizeof(char *)); for (i = 0; i < view_files_info_size; i++) if ((view_files_infos[i]) && (view_files_infos[i]->dialog)) titles[j++] = dialog_get_title(view_files_infos[i]->dialog); return(titles); } return(NULL); } void view_files_start_dialog_with_title(const char *title) { int i; for (i = 0; i < view_files_info_size; i++) if ((view_files_infos[i]) && (view_files_infos[i]->dialog)) { char *dialog_title = NULL; dialog_title = dialog_get_title(view_files_infos[i]->dialog); if (mus_strcmp(title, dialog_title)) /* this includes NULL == NULL */ { if (dialog_title) free(dialog_title); make_view_files_dialog_1(view_files_infos[i], true); return; } if (dialog_title) free(dialog_title); } } static view_files_info *new_view_files_dialog(void) { /* always returns a new (empty) file viewer -- changed 8-Jan-08 */ int loc = -1; view_files_info *vdat; if (view_files_info_size == 0) { loc = 0; view_files_info_size = 4; view_files_infos = (view_files_info **)calloc(view_files_info_size, sizeof(view_files_info *)); } else { int i; for (i = 0; i < view_files_info_size; i++) if (!view_files_infos[i]) { loc = i; break; } if (loc == -1) { loc = view_files_info_size; view_files_info_size += 4; view_files_infos = (view_files_info **)realloc(view_files_infos, view_files_info_size * sizeof(view_files_info *)); for (i = loc; i < view_files_info_size; i++) view_files_infos[i] = NULL; } } view_files_infos[loc] = (view_files_info *)calloc(1, sizeof(view_files_info)); vdat = view_files_infos[loc]; vdat->index = loc; vdat->dialog = NULL_WIDGET; vdat->file_list = NULL_WIDGET; vdat->file_list_holder = NULL_WIDGET; vdat->file_list_entries = NULL; vdat->size = 0; vdat->end = -1; vdat->names = NULL; vdat->full_names = NULL; vdat->selected_files = NULL; vdat->selected_files_size = 0; vdat->location_choice = VF_AT_CURSOR; vdat->has_error = false; vdat->need_update = false; vdat->dirs_size = 0; vdat->dirs = NULL; vdat->dir_names = NULL; vdat->amp = 1.0; vdat->speed = 1.0; vdat->amp_env = default_env(1.0, 1.0); vdat->sort_items_size = 0; vdat->sort_items = NULL; vdat->speed_style = speed_control_style(ss); /* don't clear at this point! */ view_files_infos[loc]->currently_selected_files = 0; view_files_infos[loc]->sorter = view_files_sort(ss); return(view_files_infos[loc]); } static int vf_dialog_to_index(widget_t dialog) { int i; if ((!dialog) && (view_files_infos[0]) && (view_files_infos[0]->dialog)) return(0); for (i = 0; i < view_files_info_size; i++) if ((view_files_infos[i]) && (view_files_infos[i]->dialog == dialog)) return(i); return(-1); } static view_files_info *vf_dialog_to_info(widget_t dialog) { int index; index = vf_dialog_to_index(dialog); if (index >= 0) return(view_files_infos[index]); return(NULL); } static char **vf_selected_files(view_files_info *vdat) { int len; char **files = NULL; len = vdat->currently_selected_files; if (len > 0) { int i; files = (char **)calloc(len, sizeof(char *)); for (i = 0; i < len; i++) files[i] = mus_strdup(vdat->full_names[vdat->selected_files[i]]); } return(files); } static char **view_files_selected_files(widget_t dialog, int *len) { /* free result */ view_files_info *vdat; vdat = vf_dialog_to_info(dialog); if (vdat) { (*len) = vdat->currently_selected_files; return(vf_selected_files(vdat)); } (*len) = 0; return(NULL); } static void view_files_run_select_hook(widget_t dialog, const char *selected_file); static char **view_files_set_selected_files(widget_t dialog, char **files, int len) { view_files_info *vdat; vdat = vf_dialog_to_info(dialog); if (vdat) { int i; view_files_clear_selected_files(vdat); for (i = 0; i < len; i++) if (files[i]) { int loc; loc = view_files_find_row(vdat, (const char *)(files[i])); if (loc >= 0) { view_files_add_selected_file(vdat, vdat->file_list_entries[loc]); view_files_run_select_hook(vdat->dialog, (const char *)(files[i])); } } vf_mix_insert_buttons_set_sensitive(vdat, ((vdat->currently_selected_files > 0) && (any_selected_sound()))); } return(files); } static char **view_files_files(widget_t dialog, int *len) { /* don't free result! */ view_files_info *vdat; vdat = vf_dialog_to_info(dialog); if (vdat) { (*len) = vdat->end + 1; return(vdat->full_names); } (*len) = 0; return(NULL); } static void view_files_clear_list(view_files_info *vdat); static char **view_files_set_files(widget_t dialog, char **files, int len) { view_files_info *vdat; vdat = vf_dialog_to_info(dialog); if (vdat) { view_files_clear_selected_files(vdat); view_files_clear_list(vdat); if (len > 0) { int i; for (i = 0; i < len; i++) if (files[i]) view_files_add_file_or_directory(vdat, (const char *)(files[i])); } view_files_display_list(vdat); } return(files); } static void vf_mix_insert_buttons_set_sensitive(view_files_info *vdat, bool sensitive) { if (vdat->mixB) { set_sensitive(vdat->mixB, sensitive); set_sensitive(vdat->insertB, sensitive); } } static void view_files_clear_selected_files(view_files_info *vdat) { int len; len = vdat->currently_selected_files; if (len > 0) { int i; for (i = 0; i < len; i++) { vf_row *r; r = vdat->file_list_entries[vdat->selected_files[i]]; if (r) vf_unhighlight_row(r->nm, r->rw); } } vdat->currently_selected_files = 0; vf_mix_insert_buttons_set_sensitive(vdat, false); } static void view_files_unselect_file(view_files_info *vdat, vf_row *r) { vf_unhighlight_row(r->nm, r->rw); if (vdat->currently_selected_files > 1) { /* need to fixup selected_files list */ int i, new_loc = 0; for (i = 0; i < vdat->currently_selected_files; i++) if (vdat->selected_files[i] != r->pos) vdat->selected_files[new_loc++] = vdat->selected_files[i]; } vdat->currently_selected_files--; if (vdat->currently_selected_files < 0) vdat->currently_selected_files = 0; if (vdat->currently_selected_files == 0) { vf_mix_insert_buttons_set_sensitive(vdat, false); vf_unpost_info(vdat); } } static int view_files_add_selected_file(view_files_info *vdat, vf_row *r) { /* returns how many are now selected (counting new) */ if (vdat->selected_files_size == 0) { vdat->selected_files_size = 4; vdat->selected_files = (int *)calloc(vdat->selected_files_size, sizeof(int)); vdat->selected_files[0] = r->pos; vdat->currently_selected_files = 1; } else { if (vdat->currently_selected_files >= vdat->selected_files_size) { vdat->selected_files_size += 4; vdat->selected_files = (int *)realloc(vdat->selected_files, vdat->selected_files_size * sizeof(int)); vdat->selected_files[vdat->currently_selected_files++] = r->pos; } else { vdat->selected_files[vdat->currently_selected_files++] = r->pos; } } vf_highlight_row(r->nm, r->rw); return(vdat->currently_selected_files); } static void vf_fixup_selected_files(view_files_info *vdat, char **saved_selected_files, int len) { /* various things change the order or contents of the files list, so the selected locs list needs to reflect that */ int i, newly_selected = 0; for (i = 0; i < len; i++) { int j; for (j = 0; j <= vdat->end; j++) if ((vdat->full_names[j]) && (mus_strcmp(vdat->full_names[j], saved_selected_files[i]))) { vf_row *old_r, *new_r; /* fprintf(stderr,"old %d at %d -> %d at %d\n", vdat->selected_files[i], i, j, newly_selected); */ old_r = vdat->file_list_entries[vdat->selected_files[i]]; vdat->selected_files[newly_selected++] = j; new_r = vdat->file_list_entries[j]; if (new_r != old_r) { vf_highlight_row(new_r->nm, new_r->rw); vf_unhighlight_row(old_r->nm, old_r->rw); } break; } } vdat->currently_selected_files = newly_selected; } static int view_files_find_row(view_files_info *vdat, const char *name) { int i; if (vdat->names) for (i = 0; i <= vdat->end; i++) if ((vdat->names[i]) && (mus_strcmp(vdat->names[i], name))) return(i); if (vdat->full_names) for (i = 0; i <= vdat->end; i++) if ((vdat->full_names[i]) && (mus_strcmp(vdat->full_names[i], name))) return(i); return(-1); } static void view_files_select(vf_row *r, bool add_to_selected) { view_files_info *vdat = (view_files_info *)(r->vdat); int i, curloc = -1; for (i = 0; i < vdat->currently_selected_files; i++) if (vdat->selected_files[i] == r->pos) { curloc = r->pos; break; } if (curloc == -1) { /* file not currently selected */ if (!add_to_selected) /* not shift click, so remove all currently selected files first */ view_files_clear_selected_files(vdat); view_files_add_selected_file(vdat, r); view_files_run_select_hook(vdat->dialog, vdat->full_names[r->pos]); } else { /* file already selected, so remove from selected files list */ view_files_unselect_file(vdat, r); } if ((vdat->currently_selected_files == 0) || ((vdat->currently_selected_files == 1) && (!(is_plausible_sound_file(vdat->full_names[vdat->selected_files[0]]))))) vf_unpost_info(vdat); else { if (vdat->currently_selected_files == 1) vf_post_info(vdat, vdat->selected_files[0]); else vf_post_selected_files_list(vdat); } vf_mix_insert_buttons_set_sensitive(vdat, ((vdat->currently_selected_files > 0) && (any_selected_sound()))); } static bool view_files_play(view_files_info *vdat, int pos, bool play) { static snd_info *play_sp; if (play) { if (play_sp) { if (play_sp->playing) return(true); /* can't play two of these at once */ if ((!vdat->names[pos]) || (!mus_strcmp(play_sp->short_filename, vdat->names[pos]))) { completely_free_snd_info(play_sp); play_sp = NULL; } } if ((!play_sp) && (vdat->full_names[pos])) play_sp = make_sound_readable(vdat->full_names[pos], false); if (play_sp) { play_sp->short_filename = vdat->names[pos]; play_sp->filename = NULL; /* pass view files dialog settings to play */ play_sp->speed_control = vdat->speed; play_sp->amp_control = vdat->amp; play_sound(play_sp, 0, NO_END_SPECIFIED); } else return(true); /* can't find or setup file */ } else { /* play toggled off */ if ((play_sp) && (play_sp->playing)) { stop_playing_sound(play_sp, PLAY_BUTTON_UNSET); vdat->current_play_button = NULL_WIDGET; } } return(false); } void view_files_unplay(void) { int k; for (k = 0; k < view_files_info_size; k++) if ((view_files_infos[k]) && (view_files_infos[k]->dialog) && (widget_is_active(view_files_infos[k]->dialog))) { view_files_info *vdat; vdat = view_files_infos[k]; if ((vdat->current_play_button) && (XmToggleButtonGetState(vdat->current_play_button) != XmUNSET)) { set_toggle_button(vdat->current_play_button, false, true, (void *)vdat); vdat->current_play_button = NULL_WIDGET; } } } static void view_files_reflect_sort_items(void) { int i; view_files_info *vdat; int j = 0, k; if (view_files_info_size == 0) return; for (i = 0; i < ss->file_sorters_size; i++) { Xen ref; ref = Xen_vector_ref(ss->file_sorters, i); if (Xen_is_pair(ref)) { XmString s1; s1 = XmStringCreateLocalized((char *)Xen_string_to_C_string(Xen_car(ref))); for (k = 0; k < view_files_info_size; k++) if ((view_files_infos[k]) && (view_files_infos[k]->dialog)) { vdat = view_files_infos[k]; if (j >= vdat->sort_items_size) { int n = 0, k, old_size; Arg args[20]; old_size = vdat->sort_items_size; XtSetArg(args[n], XmNbackground, ss->basic_color); n++; vdat->sort_items_size += 4; vdat->sort_items = (Widget *)realloc(vdat->sort_items, vdat->sort_items_size * sizeof(Widget)); for (k = old_size; k < vdat->sort_items_size; k++) vdat->sort_items[k] = XtCreateWidget("unused", xmPushButtonWidgetClass, vdat->smenu, args, n); } XtVaSetValues(vdat->sort_items[j], XmNlabelString, s1, XmNuserData, i + SORT_XEN, /* this is an index into the file_sorters list, not the widget list */ NULL); XtManageChild(vdat->sort_items[j]); } j++; XmStringFree(s1); } } } /* (add-file-sorter "duration" (lambda (lst) (sort lst (lambda (a b) (> (mus-sound-duration a) (mus-sound-duration b)))))) */ static void vf_add_file(view_files_info *vdat, const char *filename, const char *fullname) { vdat->end++; if (vdat->end >= vdat->size) { int new_size; new_size = vdat->size + 32; if (vdat->size == 0) { vdat->names = (char **)calloc(new_size, sizeof(char *)); vdat->full_names = (char **)calloc(new_size, sizeof(char *)); } else { int i; vdat->names = (char **)realloc(vdat->names, new_size * sizeof(char *)); vdat->full_names = (char **)realloc(vdat->full_names, new_size * sizeof(char *)); for (i = vdat->size; i < new_size; i++) { vdat->names[i] = NULL; vdat->full_names[i] = NULL; } } if (!vdat->file_list_entries) vdat->file_list_entries = (vf_row **)calloc(new_size, sizeof(vf_row *)); else { int i; vdat->file_list_entries = (vf_row **)realloc(vdat->file_list_entries, new_size * sizeof(vf_row *)); for (i = vdat->size; i < new_size; i++) vdat->file_list_entries[i] = NULL; } vdat->size = new_size; } vdat->names[vdat->end] = mus_strdup(filename); vdat->full_names[vdat->end] = mus_strdup(fullname); } static void add_file_to_view_files_list(view_files_info *vdat, const char *filename, const char *fullname) { int row; row = view_files_find_row(vdat, filename); if (row != -1) { if ((vdat->dialog) && (widget_is_active(vdat->dialog)) && (vdat->file_list_entries[row])) { ensure_scrolled_window_row_visible(vdat->file_list, row, vdat->end + 1); vf_flash_row(vdat->file_list_entries[row]); } return; } errno = 0; if (!(mus_file_probe(fullname))) { if ((vdat->dialog) && (widget_is_active(vdat->dialog))) { char *msg; if (errno != 0) msg = mus_format("%s: %s", filename, strerror(errno)); else msg = mus_format("%s does not exist", filename); vf_post_add_error(msg, vdat); free(msg); } return; } vf_add_file(vdat, filename, fullname); } /* what about temps coming and going -- should we just add a need-update switch for later remanage? */ /* remanagement only through make_view_files_dialog -- this file */ /* perhaps ss->making|deleting_temp_file -> ignore this fam event? */ static void add_directory_to_view_files_list(view_files_info *vdat, const char *dirname) { /* I think all directory additions come through here */ if ((dirname) && (dirname[strlen(dirname) - 1] != '/')) { char *add_slash; add_slash = mus_format("%s/", dirname); add_directory_to_view_files_list(vdat, add_slash); free(add_slash); } else { dir_info *sound_files = NULL; #if (!USE_NO_GUI) view_files_monitor_directory(vdat, dirname); #endif sound_files = find_sound_files_in_dir(dirname); if ((sound_files) && (sound_files->len > 0)) { int i, dirs = 0, len = 16; for (i = 0; i < sound_files->len; i++) add_file_to_view_files_list(vdat, sound_files->files[i]->filename, sound_files->files[i]->full_filename); sound_files = free_dir_info(sound_files); /* fixup title */ for (i = 0; i < vdat->dirs_size; i++) if (vdat->dir_names[i]) { dirs++; len += mus_strlen(just_filename(vdat->dir_names[i])); } if ((dirs < 4) && (len < 512)) { int cur_dir = 0; char *titlestr = NULL, *dirstr; titlestr = (char *)calloc(len + dirs * 8, sizeof(char)); strcat(titlestr, "Files: "); for (i = 0; i < vdat->dirs_size; i++) if (vdat->dir_names[i]) { dirstr = just_filename(vdat->dir_names[i]); strcat(titlestr, dirstr); free(dirstr); cur_dir++; if (cur_dir < dirs) strcat(titlestr, ", "); } dialog_set_title(vdat->dialog, titlestr); free(titlestr); } } } } static void view_files_sort_list(view_files_info *vdat) { if (vdat->end >= 0) { sort_info **data; int i, len; len = vdat->end + 1; data = (sort_info **)calloc(len, sizeof(sort_info *)); for (i = 0; i < len; i++) { data[i] = (sort_info *)calloc(1, sizeof(sort_info)); data[i]->filename = vdat->names[i]; data[i]->full_filename = vdat->full_names[i]; } snd_sort(vdat->sorter, data, len); for (i = 0; i < len; i++) { vdat->names[i] = data[i]->filename; vdat->full_names[i] = data[i]->full_filename; free(data[i]); } free(data); } } static void view_files_display_list(view_files_info *vdat) { int i; vf_row *r; if (!vdat) return; if (!(vdat->dialog)) return; if (vdat->end >= 0) { int i, old_len; char **old_names = NULL; widget_t last_row = NULL_WIDGET; /* ignored in gtk version */ old_len = vdat->currently_selected_files; if (old_len > 0) old_names = vf_selected_files(vdat); view_files_sort_list(vdat); for (i = 0; i <= vdat->end; i++) { r = vdat->file_list_entries[i]; if (!r) { r = view_files_make_row(vdat, last_row); vdat->file_list_entries[i] = r; r->pos = i; } set_button_label(r->nm, vdat->names[r->pos]); #if WITH_AUDIO set_toggle_button(r->pl, false, false, (void *)vdat); #endif if (!(widget_is_active(r->rw))) activate_widget(r->rw); last_row = r->rw; } if (old_names) { vf_fixup_selected_files(vdat, old_names, old_len); for (i = 0; i < old_len; i++) free(old_names[i]); free(old_names); } } for (i = vdat->end + 1; i < vdat->size; i++) { r = vdat->file_list_entries[i]; if (r) { if (widget_is_active(r->rw)) deactivate_widget(r->rw); } } if (!(widget_is_active(vdat->file_list))) activate_widget(vdat->file_list); } static void view_files_clear_list(view_files_info *vdat) { #if (!USE_NO_GUI) view_files_unmonitor_directories(vdat); #endif if (vdat->names) { int i; for (i = 0; i < vdat->size; i++) if (vdat->names[i]) { free(vdat->names[i]); vdat->names[i] = NULL; free(vdat->full_names[i]); vdat->full_names[i] = NULL; } vdat->end = -1; vdat->currently_selected_files = 0; } } #if 0 static void view_files_update_list(view_files_info *vdat) { /* here we need the file's full name */ int i, old_len; char **old_names = NULL; old_len = vdat->currently_selected_files; if (old_len > 0) old_names = vf_selected_files(vdat); if (vdat->names) { int i, j; for (i = 0; i <= vdat->end; i++) if (vdat->names[i]) { if (!(mus_file_probe(vdat->full_names[i]))) { free(vdat->names[i]); vdat->names[i] = NULL; free(vdat->full_names[i]); vdat->full_names[i] = NULL; } } for (i = 0, j = 0; i <= vdat->end; i++) if (vdat->names[i]) { if (i != j) { vdat->names[j] = vdat->names[i]; vdat->names[i] = NULL; vdat->full_names[j] = vdat->full_names[i]; vdat->full_names[i] = NULL; } j++; } vdat->end = j - 1; } if (old_names) { vf_fixup_selected_files(vdat, old_names, old_len); for (i = 0; i < old_len; i++) free(old_names[i]); free(old_names); } } #endif static void vf_clear_error(view_files_info *vdat) { if (vdat->currently_selected_files == 1) vf_post_info(vdat, vdat->selected_files[0]); else { if (vdat->currently_selected_files == 0) vf_unpost_info(vdat); else vf_post_selected_files_list(vdat); } vdat->has_error = false; } static int vf_mix(view_files_info *vdat) { int len, id_or_error = 0; snd_info *sp; sp = any_selected_sound(); len = vdat->currently_selected_files; if ((len == 1) && (snd_feq(vdat->amp, 1.0)) && (snd_feq(vdat->speed, 1.0)) && (is_default_env(vdat->amp_env))) id_or_error = mix_complete_file(sp, vdat->beg, vdat->full_names[vdat->selected_files[0]], with_mix_tags(ss), DONT_DELETE_ME, MIX_SETS_SYNC_LOCALLY, NULL); else { int i; bool err = false; char *tempfile; char **selected_files; selected_files = vf_selected_files(vdat); tempfile = scale_and_src(selected_files, len, sp->nchans, vdat->amp, vdat->speed, vdat->amp_env, &err); if (err) { vf_post_error(tempfile, vdat); id_or_error = MIX_FILE_NO_TEMP_FILE; } else { if (sp->nchans > 1) remember_temp(tempfile, sp->nchans); id_or_error = mix_complete_file(sp, vdat->beg, tempfile, with_mix_tags(ss), (sp->nchans > 1) ? MULTICHANNEL_DELETION : DELETE_ME, MIX_SETS_SYNC_LOCALLY, NULL); } free(tempfile); for (i = 0; i < len; i++) free(selected_files[i]); free(selected_files); } return(id_or_error); } static void view_files_mix_selected_files(widget_t w, view_files_info *vdat) { vdat->has_error = false; redirect_snd_error_to(redirect_vf_post_location_error, (void *)vdat); vdat->beg = vf_location(vdat); redirect_snd_error_to(NULL, NULL); if (!(vdat->has_error)) { int id_or_error = 0; redirect_snd_error_to(redirect_vf_post_error, (void *)vdat); ss->requestor_dialog = w; ss->open_requestor_data = (void *)vdat; ss->open_requestor = FROM_VIEW_FILES_MIX_DIALOG; id_or_error = vf_mix(vdat); /* "id_or_error" here is either one of the mix id's or an error indication such as MIX_FILE_NO_MIX */ /* the possible error conditions have been checked already, or go through snd_error */ redirect_snd_error_to(NULL, NULL); if (id_or_error >= 0) { char *msg; if (vdat->currently_selected_files == 1) msg = mus_format("%s mixed in at %" print_mus_long, vdat->names[vdat->selected_files[0]], vdat->beg); else msg = mus_format("selected files mixed in at %" print_mus_long, vdat->beg); vf_post_error(msg, vdat); vdat->has_error = false; free(msg); } } } static bool vf_insert(view_files_info *vdat) { int len; bool ok = false; snd_info *sp; sp = any_selected_sound(); len = vdat->currently_selected_files; if ((len == 1) && (snd_feq(vdat->amp, 1.0)) && (snd_feq(vdat->speed, 1.0)) && (is_default_env(vdat->amp_env))) ok = insert_complete_file(sp, vdat->full_names[vdat->selected_files[0]], vdat->beg, DONT_DELETE_ME); else { int i; bool err = false; char *tempfile; char **selected_files; selected_files = vf_selected_files(vdat); tempfile = scale_and_src(selected_files, len, sp->nchans, vdat->amp, vdat->speed, vdat->amp_env, &err); if (err) { vf_post_error(tempfile, vdat); ok = false; } else { vf_clear_error(vdat); if (sp->nchans > 1) remember_temp(tempfile, sp->nchans); ok = insert_complete_file(sp, tempfile, vdat->beg, (sp->nchans > 1) ? MULTICHANNEL_DELETION : DELETE_ME); } free(tempfile); for (i = 0; i < len; i++) free(selected_files[i]); free(selected_files); } return(ok); } static void view_files_insert_selected_files(widget_t w, view_files_info *vdat) { vdat->has_error = false; redirect_snd_error_to(redirect_vf_post_location_error, (void *)vdat); vdat->beg = vf_location(vdat); redirect_snd_error_to(NULL, NULL); if (!(vdat->has_error)) { bool ok; redirect_snd_error_to(redirect_vf_post_error, (void *)vdat); redirect_snd_warning_to(redirect_vf_post_error, (void *)vdat); ss->requestor_dialog = w; ss->open_requestor = FROM_VIEW_FILES_INSERT_DIALOG; ss->open_requestor_data = (void *)vdat; ok = vf_insert(vdat); redirect_snd_error_to(NULL, NULL); redirect_snd_warning_to(NULL, NULL); if (ok) { char *msg; if (vdat->currently_selected_files == 1) msg = mus_format("%s inserted at %" print_mus_long, vdat->names[vdat->selected_files[0]], vdat->beg); else msg = mus_format("selected files inserted at %" print_mus_long, vdat->beg); vf_post_error(msg, vdat); vdat->has_error = false; free(msg); } /* else we've already posted whatever went wrong (make_file_info etc) */ } } static mus_float_t view_files_amp(widget_t dialog) { view_files_info *vdat; vdat = vf_dialog_to_info(dialog); if (vdat) return(vdat->amp); return(0.0); } static mus_float_t view_files_set_amp(widget_t dialog, mus_float_t new_amp) { view_files_info *vdat; vdat = vf_dialog_to_info(dialog); if (vdat) vf_set_amp(vdat, new_amp); return(new_amp); } static mus_float_t view_files_speed(widget_t dialog) { view_files_info *vdat; vdat = vf_dialog_to_info(dialog); if (vdat) return(vdat->speed); return(1.0); } static mus_float_t view_files_set_speed(widget_t dialog, mus_float_t new_speed) { view_files_info *vdat; vdat = vf_dialog_to_info(dialog); if (vdat) vf_set_speed(vdat, new_speed); return(new_speed); } static speed_style_t view_files_speed_style(widget_t dialog) { view_files_info *vdat; vdat = vf_dialog_to_info(dialog); if (vdat) return(vdat->speed_style); return(SPEED_CONTROL_AS_FLOAT); } static speed_style_t view_files_set_speed_style(widget_t dialog, speed_style_t speed_style) { view_files_info *vdat; vdat = vf_dialog_to_info(dialog); if (vdat) { vdat->speed_style = speed_style; vf_set_speed(vdat, vdat->speed); /* update label etc */ } return(speed_style); } static env *view_files_amp_env(widget_t dialog) { view_files_info *vdat; vdat = vf_dialog_to_info(dialog); if (vdat) return(vdat->amp_env); return(NULL); } static void view_files_set_amp_env(widget_t dialog, env *new_e) { vf_set_amp_env(vf_dialog_to_info(dialog), new_e); } static int view_files_local_sort(widget_t dialog) { view_files_info *vdat; vdat = vf_dialog_to_info(dialog); if (vdat) return(vdat->sorter); return(-1); } static int view_files_set_local_sort(widget_t dialog, int sort_choice) { view_files_info *vdat; vdat = vf_dialog_to_info(dialog); if (vdat) { vdat->sorter = sort_choice; view_files_display_list(vdat); vf_reflect_sort_choice_in_menu(vdat); } return(sort_choice); } static view_files_info *view_files_find_dialog(widget_t dialog) { int i; for (i = 0; i < view_files_info_size; i++) if ((view_files_infos[i]) && (view_files_infos[i]->dialog == dialog)) return(view_files_infos[i]); return(NULL); } widget_t make_view_files_dialog(bool managed, bool make_new) { int i; view_files_info *vdat = NULL; if (make_new) return(make_view_files_dialog_1(new_view_files_dialog(), managed)); for (i = 0; i < view_files_info_size; i++) if ((view_files_infos[i]) && (view_files_infos[i]->dialog)) { vdat = view_files_infos[i]; if (widget_is_active(vdat->dialog)) break; } if (vdat) return(make_view_files_dialog_1(vdat, managed)); return(make_view_files_dialog_1(new_view_files_dialog(), managed)); } void save_view_files_dialogs(FILE *fd) { #if HAVE_EXTENSION_LANGUAGE int i; view_files_info *vdat; for (i = 0; i < view_files_info_size; i++) if ((view_files_infos[i]) && (view_files_infos[i]->dialog) && (widget_is_active(view_files_infos[i]->dialog))) { vdat = view_files_infos[i]; #if HAVE_SCHEME fprintf(fd, "(let ((vf (" S_view_files_dialog " #t #t)))\n"); if (vdat->full_names) { int k; fprintf(fd, " (set! (" S_view_files_files " vf) (list"); for (k = 0; k <= vdat->end; k++) fprintf(fd, " \"%s\"", vdat->full_names[k]); fprintf(fd, "))\n"); if (vdat->currently_selected_files > 0) { fprintf(fd, " (set! (" S_view_files_selected_files " vf) (list"); for (k = 0; k < vdat->currently_selected_files; k++) fprintf(fd, " \"%s\"", vdat->full_names[vdat->selected_files[k]]); fprintf(fd, "))\n"); } } if (!(snd_feq(vdat->amp, 1.0))) fprintf(fd, " (set! (" S_view_files_amp " vf) %.3f)\n", vdat->amp); if (!(snd_feq(vdat->speed, 1.0))) fprintf(fd, " (set! (" S_view_files_speed " vf) %.3f)\n", vdat->speed); if (!(is_default_env(vdat->amp_env))) fprintf(fd, " (set! (" S_view_files_amp_env " vf) %s)\n", env_to_string(vdat->amp_env)); /* assume file-sorters are set up already */ fprintf(fd, " (set! (" S_view_files_sort " vf) %d)\n", vdat->sorter); fprintf(fd, ")\n"); #endif #if HAVE_RUBY fprintf(fd, "vf = view_files_dialog(true, true)\n"); if (vdat->full_names) { int k; fprintf(fd, " set_view_files_files(vf, ["); for (k = 0; k < vdat->end; k++) fprintf(fd, "\"%s\", ", vdat->full_names[k]); fprintf(fd, "\"%s\"])\n", vdat->full_names[vdat->end]); if (vdat->currently_selected_files > 0) { fprintf(fd, " set_view_files_selected_files(vf, ["); for (k = 0; k < vdat->currently_selected_files - 1; k++) fprintf(fd, "\"%s\", ", vdat->full_names[vdat->selected_files[k]]); fprintf(fd, "\"%s\"])\n", vdat->full_names[vdat->selected_files[vdat->currently_selected_files]]); } } if (!(snd_feq(vdat->amp, 1.0))) fprintf(fd, " set_view_files_amp(vf, %.3f)\n", vdat->amp); if (!(snd_feq(vdat->speed, 1.0))) fprintf(fd, " set_view_files_speed(vf, %.3f)\n", vdat->speed); if (!(is_default_env(vdat->amp_env))) fprintf(fd, " set_view_files_amp_env(vf, %s)\n", env_to_string(vdat->amp_env)); /* assume file-sorters are set up already */ fprintf(fd, " set_view_files_sort(vf, %d)\n", vdat->sorter); fprintf(fd, "\n"); #endif #if HAVE_FORTH fprintf(fd, "#t #t view-files-dialog value vf\n"); if (vdat->full_names) { int k; fprintf(fd, " vf '("); for (k = 0; k <= vdat->end; k++) fprintf(fd, " \"%s\"", vdat->full_names[k]); fprintf(fd, " ) set-view-files-files drop\n"); if (vdat->currently_selected_files > 0) { fprintf(fd, " vf '("); for (k = 0; k <= vdat->currently_selected_files; k++) fprintf(fd, " \"%s\"", vdat->full_names[vdat->selected_files[k]]); fprintf(fd, " ) set-view-files-selected-files drop\n"); } } if (!(snd_feq(vdat->amp, 1.0))) fprintf(fd, " vf %.3f set-view-files-amp drop\n", vdat->amp); if (!(snd_feq(vdat->speed, 1.0))) fprintf(fd, " vf %.3f set-view-files-speed drop\n", vdat->speed); if (!(is_default_env(vdat->amp_env))) fprintf(fd, " vf %s set-view-files-amp-env drop\n", env_to_string(vdat->amp_env)); /* assume file-sorters are set up already */ fprintf(fd, " vf %d set-view-files-sort drop\n\n", vdat->sorter); #endif } #endif } void view_files_add_directory(widget_t dialog, const char *dirname) { view_files_info *vdat = NULL; if (dialog) vdat = view_files_find_dialog(dialog); else { if (view_files_info_size > 0) vdat = view_files_infos[0]; else { vdat = new_view_files_dialog(); make_view_files_dialog_1(vdat, false); } } if (vdat) { char *full_filename; full_filename = mus_expand_filename((const char *)dirname); if (!(mus_file_probe(full_filename))) { if ((vdat->dialog) && (widget_is_active(vdat->dialog))) { char *msg; if (errno != 0) msg = mus_format("%s: %s", full_filename, strerror(errno)); else msg = mus_format("%s does not exist", full_filename); vf_post_add_error(msg, vdat); free(msg); } } else { add_directory_to_view_files_list(vdat, full_filename); } free(full_filename); } } static void view_files_add_file(widget_t dialog, const char *filename) { view_files_info *vdat = NULL; if (dialog) vdat = view_files_find_dialog(dialog); else { if (view_files_info_size > 0) vdat = view_files_infos[0]; else { vdat = new_view_files_dialog(); make_view_files_dialog_1(vdat, false); } } if (vdat) { char *full_filename; full_filename = mus_expand_filename((const char *)filename); add_file_to_view_files_list(vdat, filename, full_filename); free(full_filename); } } static void view_files_open_selected_files(view_files_info *vdat) { ss->open_requestor = FROM_VIEW_FILES; if (vdat->currently_selected_files > 0) { int i; snd_info *sp = NULL; for (i = 0; i < vdat->currently_selected_files; i++) sp = snd_open_file(vdat->full_names[vdat->selected_files[i]], FILE_READ_WRITE); if (sp) select_channel(sp, 0); } } char *view_files_find_any_directory(void) { /* find any active directory in any vf dialog */ if (view_files_info_size > 0) { int j; for (j = 0; j < view_files_info_size; j++) { view_files_info *vdat; vdat = view_files_infos[j]; if ((vdat) && (vdat->dir_names)) { int i; for (i = 0; i < vdat->dirs_size; i++) if (vdat->dir_names[i]) return(vdat->dir_names[i]); } } } return(NULL); } static Xen mouse_enter_label_hook; static Xen mouse_leave_label_hook; static char *vf_row_get_label(void *ur) { vf_row *r = (vf_row *)ur; return(((view_files_info *)(r->vdat))->full_names[r->pos]); } static int vf_row_get_pos(void *ur) { vf_row *r = (vf_row *)ur; return(r->pos); } static void mouse_enter_or_leave_label(void *r, int type, Xen hook, const char *caller) { if ((r) && (Xen_hook_has_list(hook))) { char *label = NULL; bool need_free = false; if (type == FILE_VIEWER) label = vf_row_get_label(r); else { label = regrow_get_label(r); if (label) need_free = true; } if (label) run_hook(hook, Xen_list_3(C_int_to_Xen_integer(type), C_int_to_Xen_integer((type == FILE_VIEWER) ? (vf_row_get_pos(r)) : (regrow_get_pos(r))), C_string_to_Xen_string(label)), caller); if (need_free) XtFree(label); } } void mouse_leave_label(void *r, int type) { mouse_enter_or_leave_label(r, type, mouse_leave_label_hook, S_mouse_leave_label_hook); } void mouse_enter_label(void *r, int type) { mouse_enter_or_leave_label(r, type, mouse_enter_label_hook, S_mouse_enter_label_hook); } static void vf_mouse_enter_label(Widget w, XtPointer context, XEvent *event, Boolean *flag) { mouse_enter_label(context, FILE_VIEWER); } static void vf_mouse_leave_label(Widget w, XtPointer context, XEvent *event, Boolean *flag) { mouse_leave_label(context, FILE_VIEWER); } static vf_row *make_vf_row(view_files_info *vdat, Widget last_row, XtCallbackProc play_callback, XtCallbackProc name_callback) { int n; Arg args[32]; vf_row *r; XmString s1; #if WITH_AUDIO XtCallbackList n1; #endif XtCallbackList n3; s1 = XmStringCreateLocalized((char *)""); r = (vf_row *)calloc(1, sizeof(vf_row)); r->vdat = (void *)vdat; n = 0; XtSetArg(args[n], XmNbackground, ss->highlight_color); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNtopAttachment, (last_row) ? XmATTACH_WIDGET : XmATTACH_FORM); n++; if (last_row) {XtSetArg(args[n], XmNtopWidget, last_row); n++;} XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNheight, 18); n++; r->rw = XtCreateWidget("rw", xmFormWidgetClass, vdat->file_list_holder, args, n); #if WITH_AUDIO n = 0; XtSetArg(args[n], XmNbackground, ss->highlight_color); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNselectColor, ss->selection_color); n++; XtSetArg(args[n], XmNlabelString, s1); n++; XtSetArg(args[n], XmNvalueChangedCallback, n1 = make_callback_list(play_callback, (XtPointer)r)); n++; if (ss->toggle_size > 0) {XtSetArg(args[n], XmNindicatorSize, ss->toggle_size); n++;} XtSetArg(args[n], XmNmarginWidth, 8); n++; r->pl = make_togglebutton_widget("pl", r->rw, args, n); #endif n = 0; XtSetArg(args[n], XmNbackground, ss->highlight_color); n++; #if WITH_AUDIO XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNleftWidget, r->pl); n++; #else XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++; #endif XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNshadowThickness, 0); n++; XtSetArg(args[n], XmNhighlightThickness, 0); n++; XtSetArg(args[n], XmNalignment, XmALIGNMENT_BEGINNING); n++; XtSetArg(args[n], XmNfillOnArm, false); n++; XtSetArg(args[n], XmNrecomputeSize, false); n++; XtSetArg(args[n], XmNwidth, 500); n++; /* this sets the max name length indirectly -- was 300 which truncates some long file names (29-Oct-07) */ XtSetArg(args[n], XmNactivateCallback, n3 = make_callback_list(name_callback, (XtPointer)r)); n++; r->nm = XtCreateManagedWidget("nm", xmPushButtonWidgetClass, r->rw, args, n); XmStringFree(s1); XtAddEventHandler(r->nm, EnterWindowMask, false, vf_mouse_enter_label, (XtPointer)r); XtAddEventHandler(r->nm, LeaveWindowMask, false, vf_mouse_leave_label, (XtPointer)r); #if WITH_AUDIO free(n1); #endif free(n3); return(r); } static void vf_unhighlight_row(widget_t nm, widget_t rw) { XtVaSetValues(rw, XmNbackground, ss->highlight_color, NULL); XtVaSetValues(nm, XmNbackground, ss->highlight_color, NULL); } static void vf_highlight_row(widget_t nm, widget_t rw) { XtVaSetValues(rw, XmNbackground, ss->zoom_color, NULL); XtVaSetValues(nm, XmNbackground, ss->zoom_color, NULL); } typedef struct { vf_row *r; color_t old_color; } vf_flash_data; static void vf_unflash_row(XtPointer data, XtIntervalId *id) { vf_flash_data *v = (vf_flash_data *)data; XtVaSetValues(v->r->rw, XmNbackground, v->old_color, NULL); XtVaSetValues(v->r->nm, XmNbackground, v->old_color, NULL); free(v); } static void vf_flash_row(vf_row *r) { vf_flash_data *v; v = (vf_flash_data *)calloc(1, sizeof(vf_flash_data)); v->r = r; XtVaGetValues(r->rw, XmNbackground, &(v->old_color), NULL); XtVaSetValues(r->rw, XmNbackground, ss->light_blue, NULL); XtVaSetValues(r->nm, XmNbackground, ss->light_blue, NULL); XtAppAddTimeOut(main_app(ss), 500, (XtTimerCallbackProc)vf_unflash_row, (void *)v); } static void vf_post_info(view_files_info *vdat, int pos) { char *title; XmString s3; title = mus_format("%s:", vdat->names[pos]); s3 = XmStringCreateLocalized(title); XtVaSetValues(vdat->left_title, XmNlabelString, s3, NULL); XmStringFree(s3); free(title); post_sound_info(vdat->info1, vdat->info2, vdat->full_names[pos], false); } static void vf_post_selected_files_list(view_files_info *vdat) { int len; char *msg1 = NULL, *msg2 = NULL, *title; XmString s1, s2, s3; len = vdat->currently_selected_files; title = mus_strdup("selected files:"); s3 = XmStringCreateLocalized(title); XtVaSetValues(vdat->left_title, XmNlabelString, s3, NULL); XmStringFree(s3); free(title); if (len == 2) { msg1 = mus_strdup(vdat->names[vdat->selected_files[0]]); msg2 = mus_strdup(vdat->names[vdat->selected_files[1]]); } else { if (len == 3) { msg1 = mus_format("%s, %s", vdat->names[vdat->selected_files[0]], vdat->names[vdat->selected_files[1]]); msg2 = mus_strdup(vdat->names[vdat->selected_files[2]]); } else { msg1 = mus_format("%s, %s", vdat->names[vdat->selected_files[0]], vdat->names[vdat->selected_files[1]]); msg2 = mus_format("%s, %s%s", vdat->names[vdat->selected_files[2]], vdat->names[vdat->selected_files[3]], (len == 4) ? "" : "..."); } } s1 = XmStringCreateLocalized(msg1); s2 = XmStringCreateLocalized(msg2); XtVaSetValues(vdat->info1, XmNlabelString, s1, NULL); XtVaSetValues(vdat->info2, XmNlabelString, s2, NULL); XmStringFree(s1); XmStringFree(s2); free(msg1); free(msg2); } static void vf_unpost_info(view_files_info *vdat) { XmString s1, s2, s3; char *title; title = mus_strdup("(no files selected)"); s3 = XmStringCreateLocalized(title); XtVaSetValues(vdat->left_title, XmNlabelString, s3, NULL); XmStringFree(s3); free(title); s1 = XmStringCreateLocalized((char *)"|"); s2 = XmStringCreateLocalized((char *)"|"); XtVaSetValues(vdat->info1, XmNlabelString, s1, NULL); XtVaSetValues(vdat->info2, XmNlabelString, s2, NULL); XmStringFree(s1); XmStringFree(s2); } static void view_files_select_callback(Widget w, XtPointer context, XtPointer info) { static oclock_t mouse_down_time = 0; XmPushButtonCallbackStruct *cb = (XmPushButtonCallbackStruct *)info; XButtonEvent *ev; ev = (XButtonEvent *)(cb->event); /* cb->click_count is always 1 so we can't detect a double-click that way * ss->click_time has the (very short!) multiclick time */ if (mouse_down_time != 0) { if ((ev->time - mouse_down_time) < ss->click_time) /* open file if double clicked */ { mouse_down_time = ev->time; view_files_open_selected_files((view_files_info *)(((vf_row *)context)->vdat)); return; } } mouse_down_time = ev->time; view_files_select((vf_row *)context, ev->state & snd_ShiftMask); } static void view_files_play_callback(Widget w, XtPointer context, XtPointer info) { #if WITH_AUDIO /* open and play -- close at end or when button off toggled */ vf_row *r = (vf_row *)context; view_files_info *vdat; XmToggleButtonCallbackStruct *cb = (XmToggleButtonCallbackStruct *)info; vdat = (view_files_info *)(r->vdat); if (view_files_play(vdat, r->pos, cb->set)) XmToggleButtonSetState(w, false, false); else vdat->current_play_button = w; #endif } static vf_row *view_files_make_row(view_files_info *vdat, widget_t last_row) { return(make_vf_row(vdat, last_row, view_files_play_callback, view_files_select_callback)); } static void view_files_help_callback(Widget w, XtPointer context, XtPointer info) { view_files_dialog_help(); } static void view_files_quit_callback(Widget w, XtPointer context, XtPointer info) { view_files_info *vdat = (view_files_info *)context; XtUnmanageChild(vdat->dialog); } static void view_files_new_viewer_callback(Widget w, XtPointer context, XtPointer info) { view_files_info *vdat = (view_files_info *)context; if ((vdat) && (vdat->dialog) && (XtIsManaged(vdat->dialog)) && (XmGetFocusWidget(vdat->dialog) == XmMessageBoxGetChild(vdat->dialog, XmDIALOG_OK_BUTTON))) { Position x = 0, y = 0; /* jog the current one over a bit -- otherwise the new one lands exactly on top of the old! */ XtVaGetValues(vdat->dialog, XmNx, &x, XmNy, &y, NULL); XtVaSetValues(vdat->dialog, XmNx, x + 30, XmNy, y - 30, NULL); vdat = new_view_files_dialog(); make_view_files_dialog_1(vdat, true); } } static void sort_vf(view_files_info *vdat, int sort_choice) { vdat->sorter = sort_choice; vf_reflect_sort_choice_in_menu(vdat); view_files_display_list(vdat); } static void sort_view_files_a_to_z(Widget w, XtPointer context, XtPointer info) { sort_vf((view_files_info *)context, SORT_A_TO_Z); } static void sort_view_files_z_to_a(Widget w, XtPointer context, XtPointer info) { sort_vf((view_files_info *)context, SORT_Z_TO_A); } static void sort_view_files_new_to_old(Widget w, XtPointer context, XtPointer info) { sort_vf((view_files_info *)context, SORT_NEW_TO_OLD); } static void sort_view_files_old_to_new(Widget w, XtPointer context, XtPointer info) { sort_vf((view_files_info *)context, SORT_OLD_TO_NEW); } static void sort_view_files_big_to_small(Widget w, XtPointer context, XtPointer info) { sort_vf((view_files_info *)context, SORT_BIG_TO_SMALL); } static void sort_view_files_small_to_big(Widget w, XtPointer context, XtPointer info) { sort_vf((view_files_info *)context, SORT_SMALL_TO_BIG); } static void sort_view_files_xen(Widget w, XtPointer context, XtPointer info) { intptr_t index; XtVaGetValues(w, XmNuserData, &index, NULL); /* index is location in list of file-sorters */ sort_vf((view_files_info *)context, (int)index); } static void vf_reflect_sort_choice_in_menu(view_files_info *vdat) { int i; set_sensitive(vdat->a_to_z, vdat->sorter != SORT_A_TO_Z); set_sensitive(vdat->z_to_a, vdat->sorter != SORT_Z_TO_A); set_sensitive(vdat->new_to_old, vdat->sorter != SORT_NEW_TO_OLD); set_sensitive(vdat->old_to_new, vdat->sorter != SORT_OLD_TO_NEW); set_sensitive(vdat->small_to_big, vdat->sorter != SORT_SMALL_TO_BIG); set_sensitive(vdat->big_to_small, vdat->sorter != SORT_BIG_TO_SMALL); for (i = 0; i < vdat->sort_items_size; i++) if (XtIsManaged(vdat->sort_items[i])) set_sensitive(vdat->sort_items[i], vdat->sorter != (SORT_XEN + i)); } static void view_files_add_file_or_directory(view_files_info *vdat, const char *file_or_dir) { char *filename; filename = mus_expand_filename((const char *)file_or_dir); if (filename) { int len; len = strlen(filename); if (filename[len - 1] == '*') filename[len - 1] = 0; if (is_directory(filename)) add_directory_to_view_files_list(vdat, (const char *)filename); else add_file_to_view_files_list(vdat, file_or_dir, filename); free(filename); } } static void view_files_add_files(Widget w, XtPointer context, XtPointer info) { view_files_info *vdat = (view_files_info *)context; char *file_or_dir; file_or_dir = XmTextFieldGetString(w); if ((file_or_dir) && (*file_or_dir)) { view_files_add_file_or_directory(vdat, (const char *)file_or_dir); XtFree(file_or_dir); view_files_display_list(vdat); } } static void view_files_drop_watcher(Widget w, const char *str, Position x, Position y, void *context) { view_files_info *vdat = (view_files_info *)context; /* incoming str is a single filename (drop watcher code splits the possible list and calls us on each one) */ view_files_add_file_or_directory(vdat, str); view_files_display_list(vdat); } static void view_files_drag_watcher(Widget w, const char *str, Position x, Position y, drag_style_t dtype, void *context) { view_files_info *vdat = (view_files_info *)context; switch (dtype) { case DRAG_ENTER: XmChangeColor(vdat->file_list, ss->selection_color); break; case DRAG_LEAVE: XmChangeColor(vdat->file_list, ss->basic_color); break; default: break; } } static mus_long_t vf_location(view_files_info *vdat) { mus_long_t pos = 0; snd_info *sp; chan_info *cp; char *str; switch (vdat->location_choice) { case VF_AT_CURSOR: sp = any_selected_sound(); if (sp) { cp = any_selected_channel(sp); return(cursor_sample(cp)); } break; case VF_AT_END: sp = any_selected_sound(); if (sp) { cp = any_selected_channel(sp); return(current_samples(cp)); } break; case VF_AT_BEGINNING: return(0); break; case VF_AT_MARK: str = XmTextGetString(vdat->at_mark_text); if ((str) && (*str)) { pos = mark_id_to_sample(string_to_int(str, 0, "mark")); XtFree(str); if (pos < 0) snd_error_without_format("no such mark"); } else snd_error_without_format("no mark?"); break; case VF_AT_SAMPLE: str = XmTextGetString(vdat->at_sample_text); if ((str) && (*str)) { pos = string_to_mus_long_t(str, 0, "sample"); XtFree(str); /* pos already checked for lower bound */ } else snd_error_without_format("no sample number?"); break; } return(pos); } static void vf_clear_sample(view_files_info *vdat); static void vf_sample_button_modify_callback(Widget w, XtPointer context, XtPointer info) { vf_clear_sample((view_files_info *)context); } static void vf_sample_text_modify_callback(Widget w, XtPointer context, XtPointer info) { XmTextVerifyCallbackStruct *cbs = (XmTextVerifyCallbackStruct *)info; vf_clear_sample((view_files_info *)context); cbs->doit = true; } static void vf_clear_sample(view_files_info *vdat) { vf_clear_error(vdat); XtRemoveCallback(vdat->at_sample_text, XmNmodifyVerifyCallback, vf_sample_text_modify_callback, (XtPointer)vdat); XtRemoveCallback(vdat->at_sample_button, XmNvalueChangedCallback, vf_sample_button_modify_callback, (XtPointer)vdat); } static void vf_clear_mark(view_files_info *vdat); static void vf_mark_button_modify_callback(Widget w, XtPointer context, XtPointer info) { vf_clear_mark((view_files_info *)context); } static void vf_mark_text_modify_callback(Widget w, XtPointer context, XtPointer info) { XmTextVerifyCallbackStruct *cbs = (XmTextVerifyCallbackStruct *)info; vf_clear_mark((view_files_info *)context); cbs->doit = true; } static void vf_clear_mark(view_files_info *vdat) { vf_clear_error(vdat); XtRemoveCallback(vdat->at_mark_text, XmNmodifyVerifyCallback, vf_mark_text_modify_callback, (XtPointer)vdat); XtRemoveCallback(vdat->at_mark_button, XmNvalueChangedCallback, vf_mark_button_modify_callback, (XtPointer)vdat); } static void vf_add_text_modify_callback(Widget w, XtPointer context, XtPointer info); static void remove_all_pending_clear_callbacks(view_files_info *vdat) { /* docs say this is a no-op if the indicated callback does not exist (i.e. not an error or segfault) */ XtRemoveCallback(vdat->at_mark_text, XmNmodifyVerifyCallback, vf_mark_text_modify_callback, (XtPointer)vdat); XtRemoveCallback(vdat->at_mark_button, XmNvalueChangedCallback, vf_mark_button_modify_callback, (XtPointer)vdat); XtRemoveCallback(vdat->at_sample_text, XmNmodifyVerifyCallback, vf_sample_text_modify_callback, (XtPointer)vdat); XtRemoveCallback(vdat->at_sample_button, XmNvalueChangedCallback, vf_sample_button_modify_callback, (XtPointer)vdat); XtRemoveCallback(vdat->add_text, XmNmodifyVerifyCallback, vf_add_text_modify_callback, (XtPointer)vdat); } static void vf_post_error(const char *error_msg, view_files_info *vdat) { XmString msg; remove_all_pending_clear_callbacks(vdat); vdat->has_error = true; msg = XmStringCreateLocalized((char *)error_msg); XtVaSetValues(vdat->info1, XmNlabelString, msg, NULL); XmStringFree(msg); msg = XmStringCreateLocalized((char *)""); XtVaSetValues(vdat->info2, XmNlabelString, msg, NULL); XmStringFree(msg); } static void redirect_vf_post_error(const char *error_msg, void *vdat) { vf_post_error(error_msg, (view_files_info *)vdat); } static void redirect_vf_post_location_error(const char *error_msg, void *data) { view_files_info *vdat = (view_files_info *)data; vf_post_error(error_msg, vdat); if (vdat->location_choice == VF_AT_SAMPLE) { /* watch at_sample_text or button (undo) */ XtAddCallback(vdat->at_sample_text, XmNmodifyVerifyCallback, vf_sample_text_modify_callback, (XtPointer)vdat); XtAddCallback(vdat->at_sample_button, XmNvalueChangedCallback, vf_sample_button_modify_callback, (XtPointer)vdat); } else { /* watch at_mark_text or button */ XtAddCallback(vdat->at_mark_text, XmNmodifyVerifyCallback, vf_mark_text_modify_callback, (XtPointer)vdat); XtAddCallback(vdat->at_mark_button, XmNvalueChangedCallback, vf_mark_button_modify_callback, (XtPointer)vdat); } } static void vf_add_text_modify_callback(Widget w, XtPointer context, XtPointer info) { XmTextVerifyCallbackStruct *cbs = (XmTextVerifyCallbackStruct *)info; view_files_info *vdat = (view_files_info *)context; vf_clear_error(vdat); XtRemoveCallback(vdat->add_text, XmNmodifyVerifyCallback, vf_add_text_modify_callback, (XtPointer)vdat); cbs->doit = true; } static void vf_post_add_error(const char *error_msg, view_files_info *vdat) { vf_post_error(error_msg, vdat); XtAddCallback(vdat->add_text, XmNmodifyVerifyCallback, vf_add_text_modify_callback, (XtPointer)vdat); /* what about other clearing actions? */ } static void view_files_mix_selected_callback(Widget w, XtPointer context, XtPointer info) { view_files_mix_selected_files(w, (view_files_info *)context); } static void view_files_insert_selected_callback(Widget w, XtPointer context, XtPointer info) { view_files_insert_selected_files(w, (view_files_info *)context); } static void view_files_at_cursor_callback(Widget w, XtPointer context, XtPointer info) { view_files_info *vdat = (view_files_info *)context; if (vdat->has_error) { if (vdat->location_choice == VF_AT_SAMPLE) vf_clear_sample(vdat); else vf_clear_mark(vdat); } XmToggleButtonSetState(vdat->at_cursor_button, true, false); XmToggleButtonSetState(vdat->at_end_button, false, false); XmToggleButtonSetState(vdat->at_beginning_button, false, false); XmToggleButtonSetState(vdat->at_mark_button, false, false); XmToggleButtonSetState(vdat->at_sample_button, false, false); vdat->location_choice = VF_AT_CURSOR; } static void view_files_at_end_callback(Widget w, XtPointer context, XtPointer info) { view_files_info *vdat = (view_files_info *)context; if (vdat->has_error) { if (vdat->location_choice == VF_AT_SAMPLE) vf_clear_sample(vdat); else vf_clear_mark(vdat); } XmToggleButtonSetState(vdat->at_cursor_button, false, false); XmToggleButtonSetState(vdat->at_end_button, true, false); XmToggleButtonSetState(vdat->at_beginning_button, false, false); XmToggleButtonSetState(vdat->at_mark_button, false, false); XmToggleButtonSetState(vdat->at_sample_button, false, false); vdat->location_choice = VF_AT_END; } static void view_files_at_beginning_callback(Widget w, XtPointer context, XtPointer info) { view_files_info *vdat = (view_files_info *)context; if (vdat->has_error) { if (vdat->location_choice == VF_AT_SAMPLE) vf_clear_sample(vdat); else vf_clear_mark(vdat); } XmToggleButtonSetState(vdat->at_cursor_button, false, false); XmToggleButtonSetState(vdat->at_end_button, false, false); XmToggleButtonSetState(vdat->at_beginning_button, true, false); XmToggleButtonSetState(vdat->at_mark_button, false, false); XmToggleButtonSetState(vdat->at_sample_button, false, false); vdat->location_choice = VF_AT_BEGINNING; } static void view_files_at_sample_callback(Widget w, XtPointer context, XtPointer info) { view_files_info *vdat = (view_files_info *)context; if ((vdat->has_error) && (vdat->location_choice == VF_AT_MARK)) vf_clear_mark(vdat); XmToggleButtonSetState(vdat->at_cursor_button, false, false); XmToggleButtonSetState(vdat->at_end_button, false, false); XmToggleButtonSetState(vdat->at_beginning_button, false, false); XmToggleButtonSetState(vdat->at_mark_button, false, false); XmToggleButtonSetState(vdat->at_sample_button, true, false); vdat->location_choice = VF_AT_SAMPLE; } static void view_files_at_mark_callback(Widget w, XtPointer context, XtPointer info) { view_files_info *vdat = (view_files_info *)context; if ((vdat->has_error) && (vdat->location_choice == VF_AT_SAMPLE)) vf_clear_sample(vdat); XmToggleButtonSetState(vdat->at_cursor_button, false, false); XmToggleButtonSetState(vdat->at_end_button, false, false); XmToggleButtonSetState(vdat->at_beginning_button, false, false); XmToggleButtonSetState(vdat->at_mark_button, true, false); XmToggleButtonSetState(vdat->at_sample_button, false, false); vdat->location_choice = VF_AT_MARK; } /* -------- speed -------- */ static int vf_speed_to_scroll(mus_float_t minval, mus_float_t val, mus_float_t maxval) { if (val <= minval) return(0); if (val >= maxval) return((int)(0.9 * SCROLLBAR_MAX)); return(snd_round(0.9 * SCROLLBAR_MAX * ((log(val) - log(minval)) / (log(maxval) - log(minval))))); } static void vf_set_speed(view_files_info *vdat, mus_float_t val) { char speed_number_buffer[6]; vdat->speed = speed_changed(val, speed_number_buffer, vdat->speed_style, speed_control_tones(ss), 6); set_label(vdat->speed_number, speed_number_buffer); XtVaSetValues(vdat->speed_scrollbar, XmNvalue, vf_speed_to_scroll(speed_control_min(ss), val, speed_control_max(ss)), NULL); } static void vf_speed_click_callback(Widget w, XtPointer context, XtPointer info) { view_files_info *vdat = (view_files_info *)context; vf_set_speed(vdat, 1.0); XtVaSetValues(vdat->speed_scrollbar, XmNvalue, vf_speed_to_scroll(speed_control_min(ss), 1.0, speed_control_max(ss)), NULL); } static void vf_speed_label_click_callback(Widget w, XtPointer context, XtPointer info) { char speed_number_buffer[6]; view_files_info *vdat = (view_files_info *)context; switch (vdat->speed_style) { default: case SPEED_CONTROL_AS_FLOAT: vdat->speed_style = SPEED_CONTROL_AS_RATIO; break; case SPEED_CONTROL_AS_RATIO: vdat->speed_style = SPEED_CONTROL_AS_SEMITONE; break; case SPEED_CONTROL_AS_SEMITONE: vdat->speed_style = SPEED_CONTROL_AS_FLOAT; break; } speed_changed(vdat->speed, speed_number_buffer, vdat->speed_style, speed_control_tones(ss), 6); set_label(vdat->speed_number, speed_number_buffer); } static void vf_speed_valuechanged_callback(Widget w, XtPointer context, XtPointer info) { view_files_info *vdat = (view_files_info *)context; XmScrollBarCallbackStruct *cb = (XmScrollBarCallbackStruct *)info; vf_set_speed(vdat, exp((cb->value * (log(speed_control_max(ss)) - log(speed_control_min(ss))) / (0.9 * SCROLLBAR_MAX)) + log(speed_control_min(ss)))); } static void vf_speed_drag_callback(Widget w, XtPointer context, XtPointer info) { view_files_info *vdat = (view_files_info *)context; XmScrollBarCallbackStruct *cb = (XmScrollBarCallbackStruct *)info; vf_set_speed(vdat, exp((cb->value * (log(speed_control_max(ss)) - log(speed_control_min(ss))) / (0.9 * SCROLLBAR_MAX)) + log(speed_control_min(ss)))); } /* -------- amp -------- */ static mus_float_t vf_scroll_to_amp(int val) { if (val <= 0) return(amp_control_min(ss)); if (val >= (0.9 * SCROLLBAR_MAX)) return(amp_control_max(ss)); if (val > (0.5 * 0.9 * SCROLLBAR_MAX)) return((((val / (0.5 * 0.9 * SCROLLBAR_MAX)) - 1.0) * (amp_control_max(ss) - 1.0)) + 1.0); else return((val * (1.0 - amp_control_min(ss)) / (0.5 * 0.9 * SCROLLBAR_MAX)) + amp_control_min(ss)); } static int vf_amp_to_scroll(mus_float_t amp) { return(amp_to_scroll(amp_control_min(ss), amp, amp_control_max(ss))); } static void vf_set_amp(view_files_info *vdat, mus_float_t val) { char sfs[6]; vdat->amp = val; snprintf(sfs, 6, "%.2f", val); set_label(vdat->amp_number, sfs); XtVaSetValues(vdat->amp_scrollbar, XmNvalue, amp_to_scroll(amp_control_min(ss), val, amp_control_max(ss)), NULL); } static void vf_amp_click_callback(Widget w, XtPointer context, XtPointer info) { vf_set_amp((view_files_info *)context, 1.0); } static void vf_amp_valuechanged_callback(Widget w, XtPointer context, XtPointer info) { vf_set_amp((view_files_info *)context, vf_scroll_to_amp(((XmScrollBarCallbackStruct *)info)->value)); } static void vf_amp_drag_callback(Widget w, XtPointer context, XtPointer info) { vf_set_amp((view_files_info *)context, vf_scroll_to_amp(((XmScrollBarCallbackStruct *)info)->value)); } /* -------- amp-envs -------- */ static void vf_amp_env_resize(Widget w, XtPointer context, XtPointer info) { view_files_info *vdat = (view_files_info *)context; if (!vdat->env_ax) { XGCValues gv; gv.function = GXcopy; XtVaGetValues(vdat->env_drawer, XmNbackground, &gv.background, XmNforeground, &gv.foreground, NULL); vdat->env_gc = XtGetGC(vdat->env_drawer, GCForeground | GCFunction, &gv); vdat->env_ax = (graphics_context *)calloc(1, sizeof(graphics_context)); vdat->env_ax->wn = XtWindow(vdat->env_drawer); vdat->env_ax->dp = XtDisplay(vdat->env_drawer); vdat->env_ax->gc = vdat->env_gc; if (!(vdat->env_ax->wn)) return; } else { if (!(vdat->env_ax->wn)) { vdat->env_ax->wn = XtWindow(vdat->env_drawer); /* sometimes the dialog window is not ready when display_env gets called */ if (!(vdat->env_ax->wn)) return; } clear_window(vdat->env_ax); } vdat->spf->with_dots = true; env_editor_display_env(vdat->spf, vdat->amp_env, vdat->env_ax, "amp env", 0, 0, widget_width(w), widget_height(w), NOT_PRINTING); /* it might be nice to show the sound data in the background, but there are * complications involving multichannel and multiselection cases, also * how to get the "peak-func" and how to call g_channel_amp_envs. * Too many problems... * but perhaps something like the region browser display would work: * label saying file+chan and up/down arrows to see the rest + off button */ } static void vf_amp_env_redraw(Widget w, view_files_info *vdat) { vf_amp_env_resize(w, (void *)vdat, NULL); } static void vf_drawer_button_motion(Widget w, XtPointer context, XEvent *event, Boolean *cont) { view_files_info *vdat = (view_files_info *)context; XMotionEvent *ev = (XMotionEvent *)event; /* mus_float_t pos; */ #ifdef __APPLE__ if ((press_x == ev->x) && (press_y == ev->y)) return; #endif /* pos = (mus_float_t)(ev->x) / (mus_float_t)widget_width(w); */ env_editor_button_motion(vdat->spf, ev->x, ev->y, ev->time, vdat->amp_env); vf_amp_env_resize(w, context, NULL); } static void vf_drawer_button_press(Widget w, XtPointer context, XEvent *event, Boolean *cont) { view_files_info *vdat = (view_files_info *)context; XButtonEvent *ev = (XButtonEvent *)event; /* mus_float_t pos; */ #ifdef __APPLE__ press_x = ev->x; press_y = ev->y; #endif /* pos = (mus_float_t)(ev->x) / (mus_float_t)widget_width(w); */ if (env_editor_button_press(vdat->spf, ev->x, ev->y, ev->time, vdat->amp_env)) vf_amp_env_resize(w, context, NULL); } static void vf_drawer_button_release(Widget w, XtPointer context, XEvent *event, Boolean *cont) { view_files_info *vdat = (view_files_info *)context; /* XButtonEvent *ev = (XButtonEvent *)event; */ /* mus_float_t pos; */ /* pos = (mus_float_t)(ev->x) / (mus_float_t)widget_width(w); */ env_editor_button_release(vdat->spf, vdat->amp_env); vf_amp_env_resize(w, context, NULL); } static void vf_set_amp_env(view_files_info *vdat, env *new_e) { if (!vdat) return; if (vdat->amp_env) free_env(vdat->amp_env); vdat->amp_env = copy_env(new_e); if ((vdat->dialog) && (widget_is_active(vdat->dialog))) vf_amp_env_redraw(vdat->env_drawer, vdat); } static void blue_textfield_unfocus_callback(Widget w, XtPointer context, XtPointer info) { XtVaSetValues(w, XmNbackground, ss->lighter_blue, NULL); XtVaSetValues(w, XmNcursorPositionVisible, false, NULL); } static void blue_mouse_leave_text_callback(Widget w, XtPointer context, XEvent *event, Boolean *flag) { XtVaSetValues(w, XmNbackground, ss->lighter_blue, NULL); XtVaSetValues(w, XmNcursorPositionVisible, false, NULL); } static void white_mouse_enter_text_callback(Widget w, XtPointer context, XEvent *event, Boolean *flag) { XtVaSetValues(w, XmNbackground, ss->text_focus_color, NULL); XtVaSetValues(w, XmNcursorPositionVisible, true, NULL); } static void view_files_reset_callback(Widget w, XtPointer context, XtPointer info) { view_files_info *vdat = (view_files_info *)context; env *e; vf_set_amp(vdat, 1.0); vf_set_speed(vdat, 1.0); vf_set_amp_env(vdat, e = default_env(1.0, 1.0)); /* vf_set_amp_env copies the envelope */ free_env(e); sort_vf(vdat, view_files_sort(ss)); } static widget_t make_view_files_dialog_1(view_files_info *vdat, bool managed) { if (!(vdat->dialog)) { int i, n; Arg args[20]; XmString go_away, xhelp, titlestr, new_viewer_str, s1, bstr; Widget mainform, viewform, leftform, reset_button, new_viewer_button; Widget left_title_sep, add_label, sep1, sep3, sep4, sep6, sep7; #if WITH_AUDIO Widget plw; #endif Widget rlw, sbar; XtCallbackList n1, n2, n3, n4; Widget amp_label, speed_label, env_frame; Widget bframe, bform; go_away = XmStringCreateLocalized((char *)I_GO_AWAY); xhelp = XmStringCreateLocalized((char *)I_HELP); new_viewer_str = XmStringCreateLocalized((char *)"New Viewer"); { char *filestr = NULL; filestr = mus_format("%s %d", "Files", vdat->index + 1); titlestr = XmStringCreateLocalized(filestr); free(filestr); } n = 0; XtSetArg(args[n], XmNbackground, ss->basic_color); n++; XtSetArg(args[n], XmNhelpLabelString, xhelp); n++; XtSetArg(args[n], XmNokLabelString, new_viewer_str); n++; XtSetArg(args[n], XmNcancelLabelString, go_away); n++; XtSetArg(args[n], XmNautoUnmanage, false); n++; XtSetArg(args[n], XmNdialogTitle, titlestr); n++; XtSetArg(args[n], XmNresizePolicy, XmRESIZE_GROW); n++; XtSetArg(args[n], XmNnoResize, false); n++; XtSetArg(args[n], XmNtransient, false); n++; vdat->dialog = XmCreateTemplateDialog(main_shell(ss), (char *)"Files", args, n); new_viewer_button = MSG_BOX(vdat->dialog, XmDIALOG_OK_BUTTON); XtAddCallback(vdat->dialog, XmNhelpCallback, view_files_help_callback, (XtPointer)vdat); /* XtAddCallback(vdat->dialog, XmNokCallback, view_files_new_viewer_callback, (XtPointer)vdat); */ XtAddCallback(new_viewer_button, XmNactivateCallback, view_files_new_viewer_callback, (XtPointer)vdat); XtAddCallback(vdat->dialog, XmNcancelCallback, view_files_quit_callback, (XtPointer)vdat); n = 0; XtSetArg(args[n], XmNbackground, ss->highlight_color); n++; XtSetArg(args[n], XmNarmColor, ss->selection_color); n++; reset_button = XtCreateManagedWidget("Reset", xmPushButtonGadgetClass, vdat->dialog, args, n); XtAddCallback(reset_button, XmNactivateCallback, view_files_reset_callback, (XtPointer)vdat); XmStringFree(xhelp); XmStringFree(go_away); XmStringFree(titlestr); XmStringFree(new_viewer_str); XtVaSetValues(MSG_BOX(vdat->dialog, XmDIALOG_OK_BUTTON), XmNarmColor, ss->selection_color, NULL); XtVaSetValues(MSG_BOX(vdat->dialog, XmDIALOG_HELP_BUTTON), XmNarmColor, ss->selection_color, NULL); XtVaSetValues(MSG_BOX(vdat->dialog, XmDIALOG_CANCEL_BUTTON), XmNarmColor, ss->selection_color, NULL); XtVaSetValues(MSG_BOX(vdat->dialog, XmDIALOG_OK_BUTTON), XmNbackground, ss->highlight_color, NULL); XtVaSetValues(MSG_BOX(vdat->dialog, XmDIALOG_HELP_BUTTON), XmNbackground, ss->highlight_color, NULL); XtVaSetValues(MSG_BOX(vdat->dialog, XmDIALOG_CANCEL_BUTTON), XmNbackground, ss->highlight_color, NULL); n = 0; XtSetArg(args[n], XmNbackground, ss->basic_color); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNbottomWidget, MSG_BOX(vdat->dialog, XmDIALOG_SEPARATOR)); n++; XtSetArg(args[n], XmNsashIndent, 2); n++; XtSetArg(args[n], XmNorientation, XmHORIZONTAL); n++; XtSetArg(args[n], XmNspacing, 24); n++; XtSetArg(args[n], XmNpaneMaximum, LOTSA_PIXELS); n++; mainform = XtCreateManagedWidget("formd", xmPanedWindowWidgetClass, vdat->dialog, args, n); /* -------- left side controls -------- */ n = 0; XtSetArg(args[n], XmNbackground, ss->basic_color); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++; leftform = XtCreateManagedWidget("leftform", xmFormWidgetClass, mainform, args, n); n = 0; XtSetArg(args[n], XmNbackground, ss->highlight_color); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNalignment, XmALIGNMENT_CENTER); n++; vdat->left_title = XtCreateManagedWidget("(no files selected)", xmLabelWidgetClass, leftform, args, n); n = 0; XtSetArg(args[n], XmNbackground, ss->white); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNtopWidget, vdat->left_title); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNorientation, XmHORIZONTAL); n++; XtSetArg(args[n], XmNseparatorType, XmDOUBLE_LINE); n++; left_title_sep = XtCreateManagedWidget("sep", xmSeparatorWidgetClass, leftform, args, n); n = 0; XtSetArg(args[n], XmNbackground, ss->highlight_color); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNtopWidget, left_title_sep); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++; vdat->info1 = XtCreateManagedWidget("|", xmLabelWidgetClass, leftform, args, n); n = 0; XtSetArg(args[n], XmNbackground, ss->highlight_color); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNtopWidget, vdat->info1); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++; vdat->info2 = XtCreateManagedWidget("|", xmLabelWidgetClass, leftform, args, n); n = 0; XtSetArg(args[n], XmNbackground, ss->basic_color); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNtopWidget, vdat->info2); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNorientation, XmHORIZONTAL); n++; XtSetArg(args[n], XmNheight, 8); n++; XtSetArg(args[n], XmNseparatorType, XmNO_LINE); n++; sep6 = XtCreateManagedWidget("dialog-sep1", xmSeparatorWidgetClass, leftform, args, n); n = 0; XtSetArg(args[n], XmNbackground, ss->zoom_color); n++; XtSetArg(args[n], XmNborderColor, ss->zoom_color); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNtopWidget, sep6); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNborderWidth, 2); n++; bframe = XtCreateManagedWidget("bframe", xmFrameWidgetClass, leftform, args, n); n = 0; XtSetArg(args[n], XmNbackground, ss->position_color); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++; bform = XtCreateManagedWidget("bform", xmFormWidgetClass, bframe, args, n); n = 0; XtSetArg(args[n], XmNbackground, ss->highlight_color); n++; XtSetArg(args[n], XmNmarginTop, 0); n++; XtSetArg(args[n], XmNmarginBottom, 0); n++; XtSetArg(args[n], XmNshadowThickness, 1); n++; XtSetArg(args[n], XmNhighlightThickness, 1); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_POSITION); n++; XtSetArg(args[n], XmNrightPosition, 50); n++; vdat->mixB = XtCreateManagedWidget("Mix", xmPushButtonWidgetClass, bform, args, n); XtAddCallback(vdat->mixB, XmNactivateCallback, view_files_mix_selected_callback, (XtPointer)vdat); n = 0; XtSetArg(args[n], XmNbackground, ss->highlight_color); n++; XtSetArg(args[n], XmNmarginTop, 0); n++; XtSetArg(args[n], XmNmarginBottom, 0); n++; XtSetArg(args[n], XmNshadowThickness, 1); n++; XtSetArg(args[n], XmNhighlightThickness, 1); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNleftWidget, vdat->mixB); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++; vdat->insertB = XtCreateManagedWidget("Insert", xmPushButtonWidgetClass, bform, args, n); XtAddCallback(vdat->insertB, XmNactivateCallback, view_files_insert_selected_callback, (XtPointer)vdat); n = 0; XtSetArg(args[n], XmNbackground, ss->lighter_blue); n++; XtSetArg(args[n], XmNselectColor, ss->red); n++; bstr = XmStringCreateLocalized((char *)"at cursor"); XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNtopWidget, vdat->mixB); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNlabelString, bstr); n++; XtSetArg(args[n], XmNalignment, XmALIGNMENT_BEGINNING); n++; XtSetArg(args[n], XmNindicatorType, XmONE_OF_MANY); n++; XtSetArg(args[n], XmNset, XmSET); n++; vdat->at_cursor_button = make_togglebutton_widget("at-cursor-button", bform, args, n); XtAddCallback(vdat->at_cursor_button, XmNdisarmCallback, view_files_at_cursor_callback, (XtPointer)vdat); XmStringFree(bstr); n = 0; XtSetArg(args[n], XmNbackground, ss->lighter_blue); n++; XtSetArg(args[n], XmNselectColor, ss->red); n++; bstr = XmStringCreateLocalized((char *)"at end"); XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNtopWidget, vdat->at_cursor_button); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNlabelString, bstr); n++; XtSetArg(args[n], XmNalignment, XmALIGNMENT_BEGINNING); n++; XtSetArg(args[n], XmNindicatorType, XmONE_OF_MANY); n++; vdat->at_end_button = make_togglebutton_widget("at-end-button", bform, args, n); XtAddCallback(vdat->at_end_button, XmNdisarmCallback, view_files_at_end_callback, (XtPointer)vdat); XmStringFree(bstr); n = 0; XtSetArg(args[n], XmNbackground, ss->lighter_blue); n++; XtSetArg(args[n], XmNselectColor, ss->red); n++; bstr = XmStringCreateLocalized((char *)"at beginning"); XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNtopWidget, vdat->at_end_button); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNlabelString, bstr); n++; XtSetArg(args[n], XmNalignment, XmALIGNMENT_BEGINNING); n++; XtSetArg(args[n], XmNindicatorType, XmONE_OF_MANY); n++; vdat->at_beginning_button = make_togglebutton_widget("at-beginning-button", bform, args, n); XtAddCallback(vdat->at_beginning_button, XmNdisarmCallback, view_files_at_beginning_callback, (XtPointer)vdat); XmStringFree(bstr); n = 0; XtSetArg(args[n], XmNbackground, ss->lighter_blue); n++; XtSetArg(args[n], XmNselectColor, ss->red); n++; bstr = XmStringCreateLocalized((char *)"at sample"); XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_POSITION); n++; XtSetArg(args[n], XmNrightPosition, 50); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNtopWidget, vdat->at_beginning_button); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNlabelString, bstr); n++; XtSetArg(args[n], XmNalignment, XmALIGNMENT_BEGINNING); n++; XtSetArg(args[n], XmNindicatorType, XmONE_OF_MANY); n++; vdat->at_sample_button = make_togglebutton_widget("at-sample-button", bform, args, n); XtAddCallback(vdat->at_sample_button, XmNdisarmCallback, view_files_at_sample_callback, (XtPointer)vdat); XmStringFree(bstr); n = 0; XtSetArg(args[n], XmNbackground, ss->lighter_blue); n++; XtSetArg(args[n], XmNborderWidth, 0); n++; XtSetArg(args[n], XmNshadowThickness, 0); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNtopWidget, vdat->at_beginning_button); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_OPPOSITE_WIDGET); n++; XtSetArg(args[n], XmNbottomWidget, vdat->at_sample_button); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNleftWidget, vdat->at_sample_button); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++; vdat->at_sample_text = make_textfield_widget("at-sample-text", bform, args, n, NOT_ACTIVATABLE, NO_COMPLETER); XtRemoveCallback(vdat->at_sample_text, XmNlosingFocusCallback, textfield_unfocus_callback, NULL); XtAddCallback(vdat->at_sample_text, XmNlosingFocusCallback, blue_textfield_unfocus_callback, NULL); XtAddEventHandler(vdat->at_sample_text, LeaveWindowMask, false, blue_mouse_leave_text_callback, NULL); XtAddEventHandler(vdat->at_sample_text, EnterWindowMask, false, white_mouse_enter_text_callback, NULL); n = 0; XtSetArg(args[n], XmNbackground, ss->lighter_blue); n++; XtSetArg(args[n], XmNselectColor, ss->red); n++; bstr = XmStringCreateLocalized((char *)"at mark"); XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_POSITION); n++; XtSetArg(args[n], XmNrightPosition, 50); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNtopWidget, vdat->at_sample_button); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNlabelString, bstr); n++; XtSetArg(args[n], XmNalignment, XmALIGNMENT_BEGINNING); n++; XtSetArg(args[n], XmNindicatorType, XmONE_OF_MANY); n++; vdat->at_mark_button = make_togglebutton_widget("at-mark-button", bform, args, n); XtAddCallback(vdat->at_mark_button, XmNdisarmCallback, view_files_at_mark_callback, (XtPointer)vdat); XmStringFree(bstr); n = 0; XtSetArg(args[n], XmNbackground, ss->lighter_blue); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNtopWidget, vdat->at_sample_text); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNleftWidget, vdat->at_mark_button); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNborderWidth, 0); n++; XtSetArg(args[n], XmNshadowThickness, 0); n++; vdat->at_mark_text = make_textfield_widget("at-mark-text", bform, args, n, NOT_ACTIVATABLE, NO_COMPLETER); XtRemoveCallback(vdat->at_mark_text, XmNlosingFocusCallback, textfield_unfocus_callback, NULL); XtAddCallback(vdat->at_mark_text, XmNlosingFocusCallback, blue_textfield_unfocus_callback, NULL); XtAddEventHandler(vdat->at_mark_text, LeaveWindowMask, false, blue_mouse_leave_text_callback, NULL); XtAddEventHandler(vdat->at_mark_text, EnterWindowMask, false, white_mouse_enter_text_callback, NULL); n = 0; XtSetArg(args[n], XmNbackground, ss->basic_color); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNtopWidget, bframe); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNorientation, XmHORIZONTAL); n++; XtSetArg(args[n], XmNseparatorType, XmNO_LINE); n++; XtSetArg(args[n], XmNheight, 8); n++; sep4 = XtCreateManagedWidget("sep4", xmSeparatorWidgetClass, leftform, args, n); n = 0; /* AMP */ s1 = XmStringCreateLocalized((char *)"amp:"); XtSetArg(args[n], XmNbackground, ss->basic_color); n++; XtSetArg(args[n], XmNalignment, XmALIGNMENT_BEGINNING); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNtopWidget, sep4); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNlabelString, s1); n++; /* XtSetArg(args[n], XmNmarginHeight, CONTROLS_MARGIN); n++; */ XtSetArg(args[n], XmNrecomputeSize, false); n++; XtSetArg(args[n], XmNshadowThickness, 0); n++; XtSetArg(args[n], XmNhighlightThickness, 0); n++; XtSetArg(args[n], XmNfillOnArm, false); n++; amp_label = make_pushbutton_widget("amp-label", leftform, args, n); XtAddCallback(amp_label, XmNactivateCallback, vf_amp_click_callback, (XtPointer)vdat); XmStringFree(s1); n = 0; s1 = XmStringCreateLocalized((char *)"1.0 "); XtSetArg(args[n], XmNbackground, ss->basic_color); n++; XtSetArg(args[n], XmNalignment, XmALIGNMENT_BEGINNING); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNtopWidget, sep4); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNleftWidget, amp_label); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_NONE); n++; /* XtSetArg(args[n], XmNmarginHeight, CONTROLS_MARGIN); n++; */ XtSetArg(args[n], XmNrecomputeSize, false); n++; XtSetArg(args[n], XmNlabelString, s1); n++; /* XtSetArg(args[n], XmNmarginRight, 3); n++; */ vdat->amp_number = XtCreateManagedWidget("amp-number", xmLabelWidgetClass, leftform, args, n); XmStringFree(s1); n = 0; XtSetArg(args[n], XmNbackground, ss->position_color); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNtopWidget, sep4); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNheight, 16); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNleftWidget, vdat->amp_number); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNorientation, XmHORIZONTAL); n++; XtSetArg(args[n], XmNmaximum, SCROLLBAR_MAX); n++; XtSetArg(args[n], XmNvalue, vf_amp_to_scroll(1.0)); n++; XtSetArg(args[n], XmNvalueChangedCallback, n2 = make_callback_list(vf_amp_valuechanged_callback, (XtPointer)vdat)); n++; XtSetArg(args[n], XmNdragCallback, n3 = make_callback_list(vf_amp_drag_callback, (XtPointer)vdat)); n++; vdat->amp_scrollbar = XtCreateManagedWidget("amp-scroll", xmScrollBarWidgetClass, leftform, args, n); n = 0; /* SPEED */ s1 = XmStringCreateLocalized((char *)"speed:"); XtSetArg(args[n], XmNbackground, ss->basic_color); n++; XtSetArg(args[n], XmNalignment, XmALIGNMENT_BEGINNING); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNtopWidget, amp_label); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNlabelString, s1); n++; /* XtSetArg(args[n], XmNmarginHeight, CONTROLS_MARGIN); n++; */ XtSetArg(args[n], XmNrecomputeSize, false); n++; XtSetArg(args[n], XmNshadowThickness, 0); n++; XtSetArg(args[n], XmNhighlightThickness, 0); n++; XtSetArg(args[n], XmNfillOnArm, false); n++; speed_label = make_pushbutton_widget("speed-label", leftform, args, n); XtAddCallback(speed_label, XmNactivateCallback, vf_speed_click_callback, (XtPointer)vdat); XmStringFree(s1); n = 0; s1 = initial_speed_label(speed_control_style(ss)); XtSetArg(args[n], XmNbackground, ss->basic_color); n++; XtSetArg(args[n], XmNalignment, XmALIGNMENT_BEGINNING); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_OPPOSITE_WIDGET); n++; XtSetArg(args[n], XmNtopWidget, speed_label); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNleftWidget, speed_label); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNlabelString, s1); n++; /* XtSetArg(args[n], XmNmarginHeight, CONTROLS_MARGIN); n++; */ XtSetArg(args[n], XmNrecomputeSize, false); n++; /* XtSetArg(args[n], XmNmarginRight, 3); n++; */ XtSetArg(args[n], XmNshadowThickness, 0); n++; XtSetArg(args[n], XmNhighlightThickness, 0); n++; XtSetArg(args[n], XmNfillOnArm, false); n++; vdat->speed_number = make_pushbutton_widget("speed-number", leftform, args, n); XtAddCallback(vdat->speed_number, XmNactivateCallback, vf_speed_label_click_callback, (XtPointer)vdat); XmStringFree(s1); n = 0; XtSetArg(args[n], XmNbackground, ss->position_color); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_OPPOSITE_WIDGET); n++; XtSetArg(args[n], XmNtopWidget, vdat->speed_number); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNleftWidget, vdat->speed_number); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNorientation, XmHORIZONTAL); n++; XtSetArg(args[n], XmNmaximum, SCROLLBAR_MAX); n++; XtSetArg(args[n], XmNvalue, vf_speed_to_scroll(speed_control_min(ss), 1.0, speed_control_max(ss))); n++; XtSetArg(args[n], XmNheight, 16); n++; XtSetArg(args[n], XmNvalueChangedCallback, n4 = make_callback_list(vf_speed_valuechanged_callback, (XtPointer)vdat)); n++; XtSetArg(args[n], XmNdragCallback, n1 = make_callback_list(vf_speed_drag_callback, (XtPointer)vdat)); n++; vdat->speed_scrollbar = XtCreateManagedWidget("speed-scroll", xmScrollBarWidgetClass, leftform, args, n); /* separator before envelope */ n = 0; XtSetArg(args[n], XmNbackground, ss->basic_color); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNtopWidget, speed_label); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNorientation, XmHORIZONTAL); n++; XtSetArg(args[n], XmNheight, 8); n++; XtSetArg(args[n], XmNseparatorType, XmNO_LINE); n++; sep7 = XtCreateManagedWidget("dialog-sep1", xmSeparatorWidgetClass, leftform, args, n); /* amp env */ n = 0; XtSetArg(args[n], XmNbackground, ss->basic_color); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNtopWidget, sep7); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_POSITION); n++; XtSetArg(args[n], XmNleftPosition, 4); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_POSITION); n++; XtSetArg(args[n], XmNrightPosition, 98); n++; XtSetArg(args[n], XmNheight, 100); n++; XtSetArg(args[n], XmNallowResize, true); n++; XtSetArg(args[n], XmNshadowType, XmSHADOW_ETCHED_IN); n++; XtSetArg(args[n], XmNshadowThickness, 4); n++; env_frame = XtCreateManagedWidget("amp-env-frame", xmFrameWidgetClass, leftform, args, n); n = 0; XtSetArg(args[n], XmNbackground, ss->highlight_color); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNallowResize, true); n++; XtSetArg(args[n], XmNheight, 100); n++; vdat->env_drawer = XtCreateManagedWidget("amp-env-window", xmDrawingAreaWidgetClass, env_frame, args, n); /* right side */ n = 0; XtSetArg(args[n], XmNbackground, ss->basic_color); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++; viewform = XtCreateManagedWidget("viewform", xmFormWidgetClass, mainform, args, n); /* Add dir/file text entry at bottom */ n = 0; s1 = XmStringCreateLocalized((char *)"add:"); XtSetArg(args[n], XmNbackground, ss->basic_color); n++; XtSetArg(args[n], XmNalignment, XmALIGNMENT_BEGINNING); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNlabelString, s1); n++; XtSetArg(args[n], XmNshadowThickness, 0); n++; XtSetArg(args[n], XmNhighlightThickness, 0); n++; add_label = XtCreateManagedWidget("add", xmLabelWidgetClass, viewform, args, n); XmStringFree(s1); n = 0; XtSetArg(args[n], XmNbackground, ss->basic_color); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNleftWidget, add_label); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++; vdat->add_text = make_textfield_widget("add-text", viewform, args, n, ACTIVATABLE, add_completer_func(filename_completer, NULL)); XtAddCallback(vdat->add_text, XmNactivateCallback, view_files_add_files, (XtPointer)vdat); n = 0; XtSetArg(args[n], XmNbackground, ss->basic_color); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNbottomWidget, vdat->add_text); n++; XtSetArg(args[n], XmNorientation, XmHORIZONTAL); n++; XtSetArg(args[n], XmNseparatorType, XmNO_LINE); n++; XtSetArg(args[n], XmNheight, 4); n++; sep3 = XtCreateManagedWidget("sep3", xmSeparatorWidgetClass, viewform, args, n); n = 0; XtSetArg(args[n], XmNbackground, ss->highlight_color); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNalignment, XmALIGNMENT_CENTER); n++; rlw = XtCreateManagedWidget("files", xmLabelWidgetClass, viewform, args, n); n = 0; XtSetArg(args[n], XmNbackground, ss->white); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNtopWidget, rlw); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNorientation, XmHORIZONTAL); n++; XtSetArg(args[n], XmNseparatorType, XmDOUBLE_LINE); n++; sep1 = XtCreateManagedWidget("sep1", xmSeparatorWidgetClass, viewform, args, n); #if WITH_AUDIO n = 0; XtSetArg(args[n], XmNbackground, ss->basic_color); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_POSITION); n++; XtSetArg(args[n], XmNleftPosition, 5); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNtopWidget, sep1); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++; plw = XtCreateManagedWidget("play", xmLabelWidgetClass, viewform, args, n); #endif n = 0; XtSetArg(args[n], XmNbackground, ss->basic_color); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNtopWidget, sep1); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNshadowThickness, 0); n++; XtSetArg(args[n], XmNhighlightThickness, 0); n++; XtSetArg(args[n], XmNmarginHeight, 0); n++; sbar = XmCreateMenuBar(viewform, (char *)"menuBar", args, n); n = 0; XtSetArg(args[n], XmNbackground, ss->basic_color); n++; vdat->smenu = XmCreatePulldownMenu(sbar, (char *)"sort-menu", args, n); n = 0; XtSetArg(args[n], XmNbackground, ss->basic_color); n++; XtSetArg(args[n], XmNsubMenuId, vdat->smenu); n++; XtSetArg(args[n], XmNshadowThickness, 0); n++; XtSetArg(args[n], XmNhighlightThickness, 0); n++; XtSetArg(args[n], XmNmarginHeight, 1); n++; XtCreateManagedWidget("sort", xmCascadeButtonWidgetClass, sbar, args, n); n = 0; XtSetArg(args[n], XmNbackground, ss->basic_color); n++; vdat->a_to_z = XtCreateManagedWidget("a..z", xmPushButtonWidgetClass, vdat->smenu, args, n); vdat->z_to_a = XtCreateManagedWidget("z..a", xmPushButtonWidgetClass, vdat->smenu, args, n); vdat->new_to_old = XtCreateManagedWidget("new..old", xmPushButtonWidgetClass, vdat->smenu, args, n); vdat->old_to_new = XtCreateManagedWidget("old..new", xmPushButtonWidgetClass, vdat->smenu, args, n); vdat->small_to_big = XtCreateManagedWidget("small..big", xmPushButtonWidgetClass, vdat->smenu, args, n); vdat->big_to_small = XtCreateManagedWidget("big..small", xmPushButtonWidgetClass, vdat->smenu, args, n); vdat->sort_items_size = 4; vdat->sort_items = (Widget *)calloc(vdat->sort_items_size, sizeof(Widget)); for (i = 0; i < vdat->sort_items_size; i++) vdat->sort_items[i] = XtCreateWidget("unused", xmPushButtonWidgetClass, vdat->smenu, args, n); XtManageChild(sbar); n = 0; XtSetArg(args[n], XmNleftAttachment, XmATTACH_POSITION); n++; XtSetArg(args[n], XmNleftPosition, 5); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++; #if WITH_AUDIO XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNtopWidget, plw); n++; #else XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNtopWidget, sep1); n++; #endif XtSetArg(args[n], XmNbottomAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNbottomWidget, sep3); n++; XtSetArg(args[n], XmNscrollingPolicy, XmAUTOMATIC); n++; XtSetArg(args[n], XmNscrollBarDisplayPolicy, XmSTATIC); n++; vdat->file_list = XmCreateScrolledWindow(viewform, (char *)"file_list", args, n); n = attach_all_sides(args, 0); vdat->file_list_holder = XtCreateManagedWidget("file_list_holder", xmRowColumnWidgetClass, vdat->file_list, args, n); XtVaSetValues(vdat->file_list, XmNworkWindow, vdat->file_list_holder, NULL); add_drag_and_drop(vdat->file_list, view_files_drop_watcher, view_files_drag_watcher, (void *)vdat); if (managed) view_files_display_list(vdat); XtAddCallback(vdat->a_to_z, XmNactivateCallback, sort_view_files_a_to_z, (XtPointer)vdat); XtAddCallback(vdat->z_to_a, XmNactivateCallback, sort_view_files_z_to_a, (XtPointer)vdat); XtAddCallback(vdat->new_to_old, XmNactivateCallback, sort_view_files_new_to_old, (XtPointer)vdat); XtAddCallback(vdat->old_to_new, XmNactivateCallback, sort_view_files_old_to_new, (XtPointer)vdat); XtAddCallback(vdat->small_to_big, XmNactivateCallback, sort_view_files_small_to_big, (XtPointer)vdat); XtAddCallback(vdat->big_to_small, XmNactivateCallback, sort_view_files_big_to_small, (XtPointer)vdat); vf_reflect_sort_choice_in_menu(vdat); { int i; for (i = 0; i < vdat->sort_items_size; i++) XtAddCallback(vdat->sort_items[i], XmNactivateCallback, sort_view_files_xen, (XtPointer)vdat); } map_over_children(vdat->file_list, set_main_color_of_widget); set_dialog_widget(VIEW_FILES_DIALOG, vdat->dialog); if (managed) XtManageChild(vdat->dialog); XtAddCallback(vdat->env_drawer, XmNresizeCallback, vf_amp_env_resize, (XtPointer)vdat); XtAddCallback(vdat->env_drawer, XmNexposeCallback, vf_amp_env_resize, (XtPointer)vdat); vdat->spf = new_env_editor(); /* one global amp env */ XtAddEventHandler(vdat->env_drawer, ButtonPressMask, false, vf_drawer_button_press, (XtPointer)vdat); XtAddEventHandler(vdat->env_drawer, ButtonMotionMask, false, vf_drawer_button_motion, (XtPointer)vdat); XtAddEventHandler(vdat->env_drawer, ButtonReleaseMask, false, vf_drawer_button_release, (XtPointer)vdat); free(n1); free(n2); free(n3); free(n4); vf_mix_insert_buttons_set_sensitive(vdat, false); } else { if (managed) { if (!XtIsManaged(vdat->dialog)) XtManageChild(vdat->dialog); raise_dialog(vdat->dialog); view_files_display_list(vdat); } } if (managed) { vf_amp_env_resize(vdat->env_drawer, (XtPointer)vdat, NULL); view_files_reflect_sort_items(); } return(vdat->dialog); } /* -------- view-files variables -------- */ static Xen g_view_files_dialog(Xen managed, Xen make_new) { #define H_view_files_dialog "(" S_view_files_dialog " :optional managed create-new-dialog): start the View Files dialog" Xen_check_type(Xen_is_boolean_or_unbound(managed), managed, 1, S_view_files_dialog, "a boolean"); return(Xen_wrap_widget(make_view_files_dialog(Xen_boolean_to_C_bool(managed), Xen_is_true(make_new)))); } static Xen g_add_directory_to_view_files_list(Xen directory, Xen dialog) { #define H_add_directory_to_view_files_list "(" S_add_directory_to_view_files_list " dir :optional w): adds any sound files in 'dir' to the View:Files dialog" Xen_check_type(Xen_is_string(directory), directory, 1, S_add_directory_to_view_files_list, "a string"); Xen_check_type(Xen_is_widget(dialog) || !Xen_is_bound(dialog), dialog, 2, S_add_directory_to_view_files_list, "a view-files dialog widget"); if (!Xen_is_bound(dialog)) view_files_add_directory(NULL_WIDGET, Xen_string_to_C_string(directory)); else view_files_add_directory((widget_t)(Xen_unwrap_widget(dialog)), Xen_string_to_C_string(directory)); return(directory); } static Xen g_add_file_to_view_files_list(Xen file, Xen dialog) { #define H_add_file_to_view_files_list "(" S_add_file_to_view_files_list " file :optional w): adds file to the View:Files dialog's list" char *name = NULL; Xen_check_type(Xen_is_string(file), file, 1, S_add_file_to_view_files_list, "a string"); Xen_check_type(Xen_is_widget(dialog) || !Xen_is_bound(dialog), dialog, 2, S_add_file_to_view_files_list, "a view-files dialog widget"); name = mus_expand_filename(Xen_string_to_C_string(file)); if (mus_file_probe(name)) { if (!Xen_is_bound(dialog)) view_files_add_file(NULL_WIDGET, name); else view_files_add_file((widget_t)(Xen_unwrap_widget(dialog)), name); } if (name) free(name); return(file); } static Xen g_view_files_sort(Xen dialog) { #define H_view_files_sort "(" S_view_files_sort " :optional dialog): sort choice in View:files dialog." if (Xen_is_bound(dialog)) { Xen_check_type(Xen_is_widget(dialog), dialog, 1, S_view_files_sort, "a view-files dialog widget"); return(C_int_to_Xen_integer(view_files_local_sort((widget_t)(Xen_unwrap_widget(dialog))))); } return(C_int_to_Xen_integer(view_files_sort(ss))); } static Xen g_set_view_files_sort(Xen dialog, Xen val) { int choice; Xen sort_choice; if (Xen_is_bound(val)) sort_choice = val; else sort_choice = dialog; Xen_check_type(Xen_is_integer(sort_choice), sort_choice, 1, S_set S_view_files_sort, "an integer"); choice = Xen_integer_to_C_int(sort_choice); if ((choice < 0) || (choice >= (ss->file_sorters_size + SORT_XEN))) Xen_out_of_range_error(S_set S_view_files_sort, 2, sort_choice, "must be a valid file-sorter index"); if (Xen_is_bound(val)) { widget_t w; Xen_check_type(Xen_is_widget(dialog), dialog, 1, S_set S_view_files_sort, "a view-files dialog widget"); w = (widget_t)(Xen_unwrap_widget(dialog)); view_files_set_local_sort(w, choice); return(C_int_to_Xen_integer((int)view_files_sort(ss))); } /* else set global (default) sort choice */ set_view_files_sort(choice); return(C_int_to_Xen_integer((int)view_files_sort(ss))); } static Xen g_view_files_amp(Xen dialog) { #define H_view_files_amp "(" S_view_files_amp " dialog): amp setting in the given View:Files dialog" Xen_check_type(Xen_is_widget(dialog), dialog, 1, S_view_files_amp, "a view-files dialog widget"); return(C_double_to_Xen_real(view_files_amp((widget_t)(Xen_unwrap_widget(dialog))))); } static Xen g_view_files_set_amp(Xen dialog, Xen amp) { Xen_check_type(Xen_is_widget(dialog), dialog, 1, S_set S_view_files_amp, "a view-files dialog widget"); Xen_check_type(Xen_is_number(amp), amp, 2, S_set S_view_files_amp, "a number"); view_files_set_amp((widget_t)(Xen_unwrap_widget(dialog)), Xen_real_to_C_double(amp)); return(amp); } static Xen g_view_files_speed(Xen dialog) { #define H_view_files_speed "(" S_view_files_speed " dialog): speed setting in the given View:Files dialog" Xen_check_type(Xen_is_widget(dialog), dialog, 1, S_view_files_speed, "a view-files dialog widget"); return(C_double_to_Xen_real(view_files_speed((widget_t)(Xen_unwrap_widget(dialog))))); } static Xen g_view_files_set_speed(Xen dialog, Xen speed) { Xen_check_type(Xen_is_widget(dialog), dialog, 1, S_set S_view_files_speed, "a view-files dialog widget"); Xen_check_type(Xen_is_number(speed), speed, 2, S_set S_view_files_speed, "a number"); view_files_set_speed((widget_t)(Xen_unwrap_widget(dialog)), Xen_real_to_C_double(speed)); return(speed); } static Xen g_view_files_amp_env(Xen dialog) { #define H_view_files_amp_env "(" S_view_files_amp_env " dialog): amp env breakpoints in the given View:Files dialog" Xen_check_type(Xen_is_widget(dialog), dialog, 1, S_view_files_amp_env, "a view-files dialog widget"); return(env_to_xen(view_files_amp_env((widget_t)(Xen_unwrap_widget(dialog))))); } static Xen g_view_files_set_amp_env(Xen dialog, Xen amp_env) { Xen_check_type(Xen_is_widget(dialog), dialog, 1, S_set S_view_files_amp_env, "a view-files dialog widget"); Xen_check_type(Xen_is_list(amp_env), amp_env, 2, S_set S_view_files_amp_env, "an envelope"); view_files_set_amp_env((widget_t)(Xen_unwrap_widget(dialog)), xen_to_env(amp_env)); return(amp_env); } static Xen g_view_files_speed_style(Xen dialog) { #define H_view_files_speed_style "(" S_view_files_speed_style " dialog): speed_style in use in the given View:Files dialog" Xen_check_type(Xen_is_widget(dialog), dialog, 1, S_view_files_speed_style, "a view-files dialog widget"); return(C_int_to_Xen_integer((int)(view_files_speed_style((widget_t)(Xen_unwrap_widget(dialog)))))); } static Xen g_view_files_set_speed_style(Xen dialog, Xen speed_style) { Xen_check_type(Xen_is_widget(dialog), dialog, 1, S_set S_view_files_speed_style, "a view-files dialog widget"); Xen_check_type(Xen_is_integer(speed_style), speed_style, 2, S_set S_view_files_speed_style, "an int"); view_files_set_speed_style((widget_t)(Xen_unwrap_widget(dialog)), (speed_style_t)(Xen_integer_to_C_int(speed_style))); return(speed_style); } static Xen g_view_files_selected_files(Xen dialog) { #define H_view_files_selected_files "(" S_view_files_selected_files " dialog): list of files currently selected in the given View:Files dialog" Xen result = Xen_empty_list; char **selected_files; int len = 0; Xen_check_type(Xen_is_widget(dialog), dialog, 1, S_view_files_selected_files, "a view-files dialog widget"); selected_files = view_files_selected_files((widget_t)(Xen_unwrap_widget(dialog)), &len); if ((selected_files) && (len > 0)) { int i; for (i = 0; i < len; i++) { result = Xen_cons(C_string_to_Xen_string(selected_files[i]), result); free(selected_files[i]); } free(selected_files); } return(result); } static Xen g_view_files_set_selected_files(Xen dialog, Xen files) { int len; Xen_check_type(Xen_is_widget(dialog), dialog, 1, S_set S_view_files_selected_files, "a view-files dialog widget"); Xen_check_type(Xen_is_list(files), files, 2, S_set S_view_files_selected_files, "a list of files or directories"); len = Xen_list_length(files); if (len > 0) { char **cfiles = NULL; int i; for (i = 0; i < len; i++) if (!(Xen_is_string(Xen_list_ref(files, i)))) { Xen_check_type(false, Xen_list_ref(files, i), i, S_set S_view_files_selected_files, "a filename (string)"); return(Xen_false); } cfiles = (char **)calloc(len, sizeof(char *)); for (i = 0; i < len; i++) cfiles[i] = (char *)Xen_string_to_C_string(Xen_list_ref(files, i)); view_files_set_selected_files((widget_t)(Xen_unwrap_widget(dialog)), cfiles, len); free(cfiles); } return(files); } static Xen g_view_files_files(Xen dialog) { #define H_view_files_files "(" S_view_files_files " dialog): list of files currently available in the given View:Files dialog" Xen result = Xen_empty_list; char **files; int i, len = 0; Xen_check_type(Xen_is_widget(dialog), dialog, 1, S_view_files_files, "a view-files dialog widget"); files = view_files_files((widget_t)(Xen_unwrap_widget(dialog)), &len); if ((files) && (len > 0)) for (i = 0; i < len; i++) result = Xen_cons(C_string_to_Xen_string(files[i]), result); return(result); } static Xen g_view_files_set_files(Xen dialog, Xen files) { int len = 0; char **cfiles = NULL; Xen_check_type(Xen_is_widget(dialog), dialog, 1, S_set S_view_files_files, "a view-files dialog widget"); Xen_check_type(Xen_is_list(files), files, 2, S_set S_view_files_files, "a list of files or directories"); len = Xen_list_length(files); if (len > 0) { int i; for (i = 0; i < len; i++) if (!(Xen_is_string(Xen_list_ref(files, i)))) { Xen_check_type(false, Xen_list_ref(files, i), i, S_set S_view_files_files, "a filename (string)"); return(Xen_false); } cfiles = (char **)calloc(len, sizeof(char *)); for (i = 0; i < len; i++) cfiles[i] = (char *)Xen_string_to_C_string(Xen_list_ref(files, i)); } view_files_set_files((widget_t)(Xen_unwrap_widget(dialog)), cfiles, len); if (cfiles) free(cfiles); return(files); } static Xen view_files_select_hook; static void view_files_run_select_hook(widget_t dialog, const char *selected_file) { if (Xen_hook_has_list(view_files_select_hook)) run_hook(view_files_select_hook, Xen_list_2(Xen_wrap_widget(dialog), C_string_to_Xen_string(selected_file)), S_view_files_select_hook); } /* -------- file-filters and file-sorters -------- */ #define INITIAL_FILE_SORTERS_SIZE 4 static bool file_sorter_ok(Xen name, Xen proc, const char *caller) { char *errmsg; Xen_check_type(Xen_is_string(name), name, 1, caller, "a string"); Xen_check_type(Xen_is_procedure(proc), proc, 2, caller, "a procedure of 2 args (file1 and file2)"); errmsg = procedure_ok(proc, 2, caller, "file sort", 2); if (errmsg) { Xen errstr; errstr = C_string_to_Xen_string(errmsg); free(errmsg); snd_bad_arity_error(caller, errstr, proc); return(false); } return(true); } static Xen g_add_file_sorter(Xen name, Xen proc) { #define H_add_file_sorter "(" S_add_file_sorter " name proc) -- add proc with identifier name to file sorter list, returns its index" int choice = -1; /* type checks are redundant here */ if (file_sorter_ok(name, proc, S_add_file_sorter)) { int i, len; len = ss->file_sorters_size; for (i = 0; i < len; i++) { if (Xen_is_false(Xen_vector_ref(ss->file_sorters, i))) { Xen_vector_set(ss->file_sorters, i, Xen_list_2(name, proc)); choice = i; break; } } if (choice == -1) { ss->file_sorters_size = len * 2; ss->file_sorters = g_expand_vector(ss->file_sorters, ss->file_sorters_size); Xen_vector_set(ss->file_sorters, len, Xen_list_2(name, proc)); choice = len; } view_files_reflect_sort_items(); } return(C_int_to_Xen_integer(choice + SORT_XEN)); } static Xen g_delete_file_sorter(Xen index) { #define H_delete_file_sorter "(" S_delete_file_sorter " index) -- delete proc with identifier name from file sorter list" int pos; Xen_check_type(Xen_is_integer(index), index, 1, S_delete_file_sorter, "a file-sorter index"); pos = Xen_integer_to_C_int(index); if ((pos >= SORT_XEN) && ((pos - SORT_XEN) < ss->file_sorters_size)) Xen_vector_set(ss->file_sorters, pos - SORT_XEN, Xen_false); view_files_reflect_sort_items(); return(index); } /* -------- drop watcher lists -------- */ /* the rigamarole for dealing with a drop is so messed up that I think it's * worth the trouble of setting up a separate callback list -- hence the * drop watchers */ typedef struct { void (*drop_watcher)(Widget w, const char *message, Position x, Position y, void *data); void (*drag_watcher)(Widget w, const char *message, Position x, Position y, drag_style_t dtype, void *data); Widget caller; void *context; } drop_watcher_t; static drop_watcher_t **drop_watchers = NULL; static int drop_watchers_size = 0; #define DROP_WATCHER_SIZE_INCREMENT 2 static int add_drop_watcher(Widget w, void (*drop_watcher)(Widget w, const char *message, Position x, Position y, void *data), void (*drag_watcher)(Widget w, const char *message, Position x, Position y, drag_style_t dtype, void *data), void *context) { int loc = -1; if (!(drop_watchers)) { loc = 0; drop_watchers_size = DROP_WATCHER_SIZE_INCREMENT; drop_watchers = (drop_watcher_t **)calloc(drop_watchers_size, sizeof(drop_watcher_t *)); } else { int i; for (i = 0; i < drop_watchers_size; i++) if (!(drop_watchers[i])) { loc = i; break; } if (loc == -1) { loc = drop_watchers_size; drop_watchers_size += DROP_WATCHER_SIZE_INCREMENT; drop_watchers = (drop_watcher_t **)realloc(drop_watchers, drop_watchers_size * sizeof(drop_watcher_t *)); for (i = loc; i < drop_watchers_size; i++) drop_watchers[i] = NULL; } } drop_watchers[loc] = (drop_watcher_t *)calloc(1, sizeof(drop_watcher_t)); drop_watchers[loc]->drop_watcher = drop_watcher; drop_watchers[loc]->drag_watcher = drag_watcher; drop_watchers[loc]->context = context; drop_watchers[loc]->caller = w; return(loc); } #if 0 static bool remove_drop_watcher(int loc) { if ((drop_watchers) && (loc < drop_watchers_size) && (loc >= 0) && (drop_watchers[loc])) { free(drop_watchers[loc]); drop_watchers[loc] = NULL; return(true); } return(false); } #endif static drop_watcher_t *find_drop_watcher(Widget caller) { if (drop_watchers) { int i; for (i = 0; i < drop_watchers_size; i++) { if (drop_watchers[i]) { drop_watcher_t *d; d = drop_watchers[i]; if (d->caller == caller) return(d); } } } return(NULL); } /* can't move axes if icon dragged to end of graph because the entire system freezes! */ static Atom FILE_NAME; /* Sun uses this, SGI uses STRING */ static Atom COMPOUND_TEXT; /* various Motif widgets use this and the next */ static Atom _MOTIF_COMPOUND_STRING; static Atom text_plain; /* gtk uses this -- apparently a url */ static Atom uri_list; /* rox uses this -- looks just like text/plain to me */ static Atom TEXT; /* ditto */ static Xen drop_hook; static char *atom_to_string(Atom type, XtPointer value, unsigned long length) { char *str = NULL; if ((type == XA_STRING) || (type == FILE_NAME) || (type == text_plain) || (type == uri_list) || (type == TEXT)) { unsigned long i; str = (char *)calloc(length + 1, sizeof(char)); for (i = 0; i < length; i++) str[i] = ((char *)value)[i]; } else { if ((type == COMPOUND_TEXT) || (type == _MOTIF_COMPOUND_STRING)) { char *temp; XmString cvt, tmp; XmParseTable parser = (XmParseTable)XtCalloc(1, sizeof(XmParseMapping)); int n; Arg args[12]; /* create parse table to catch separator in XmString and insert "\n" in output */ /* multiple file names are passed this way in Motif */ tmp = XmStringSeparatorCreate(); n = 0; XtSetArg(args[n], XmNincludeStatus, XmINSERT); n++; XtSetArg(args[n], XmNsubstitute, tmp); n++; XtSetArg(args[n], XmNpattern, "\n"); n++; parser[0] = XmParseMappingCreate(args, n); if (type == _MOTIF_COMPOUND_STRING) cvt = XmCvtByteStreamToXmString((unsigned char *)value); else cvt = XmCvtCTToXmString((char *)value); temp = (char *)XmStringUnparse(cvt, NULL, XmCHARSET_TEXT, XmCHARSET_TEXT, parser, 1, XmOUTPUT_ALL); XmParseTableFree(parser, 1); XmStringFree(cvt); str = mus_strdup(temp); XtFree(temp); } } return(str); } static Position mx, my; static void massage_selection(Widget w, XtPointer context, Atom *selection, Atom *type, XtPointer value, unsigned long *length, int *format) { char *str = NULL; str = atom_to_string(*type, value, *length); /* str can contain more than one name (separated by cr) */ if (str) { if ((!(Xen_hook_has_list(drop_hook))) || (!(Xen_is_true(run_or_hook(drop_hook, Xen_list_1(C_string_to_Xen_string(str)), S_drop_hook))))) { Widget caller; /* "w" above is the transfer control widget, not the drop-receiver */ drop_watcher_t *d; caller = (Widget)((XmDropTransferEntry)context)->client_data; d = find_drop_watcher(caller); if (d) { /* loop through possible list of filenames, calling watcher on each */ char *filename; int len = 0, i, j = 0; len = mus_strlen(str); filename = (char *)calloc(len, sizeof(char)); for (i = 0; i < len; i++) { if ((str[i] == '\n') || (str[i] == '\r')) /* apparently the only space chars here are \n and \r? */ { if (j > 0) { filename[j] = '\0'; if (strncmp(filename, "file://", 7) == 0) { char *tmp; tmp = (char *)(filename + 7); (*(d->drop_watcher))(caller, (const char *)tmp, mx, my, d->context); } else (*(d->drop_watcher))(caller, (const char *)filename, mx, my, d->context); j = 0; } /* else ignore extra white space chars */ } else { filename[j++] = str[i]; } } free(filename); } } free(str); } } static void handle_drop(Widget w, XtPointer context, XtPointer info) { XmDropProcCallbackStruct *cb = (XmDropProcCallbackStruct *)info; Arg args[12]; int n, i, num_targets, k; Atom *targets; XmDropTransferEntryRec entries[2]; if ((cb->dropAction != XmDROP) || ((cb->operation != XmDROP_COPY) && (cb->operation != XmDROP_LINK))) { cb->dropSiteStatus = XmINVALID_DROP_SITE; return; } k = -1; XtVaGetValues(cb->dragContext, XmNexportTargets, &targets, XmNnumExportTargets, &num_targets, NULL); for (i = 0; i < num_targets; i++) if ((targets[i] == XA_STRING) || (targets[i] == FILE_NAME) || (targets[i] == COMPOUND_TEXT) || (targets[i] == _MOTIF_COMPOUND_STRING) || (targets[i] == TEXT) || (targets[i] == text_plain) || (targets[i] == uri_list)) { k = i; break; } if (k == -1) { #if 0 fprintf(stderr, "failed drop attempt:\n"); for (i = 0; i < num_targets; i++) fprintf(stderr, " target %d = %s\n", i, XGetAtomName(main_display(ss), targets[i])); #endif cb->dropSiteStatus = XmINVALID_DROP_SITE; cb->operation = XmDROP_NOOP; n = 0; XtSetArg(args[n], XmNnumDropTransfers, 0); n++; XtSetArg(args[n], XmNtransferStatus, XmTRANSFER_FAILURE); n++; XmDropTransferStart(cb->dragContext, args, n); return; } mx = cb->x; my = cb->y; entries[0].target = targets[k]; entries[0].client_data = (XtPointer)w; n = 0; XtSetArg(args[n], XmNdropTransfers, entries); n++; XtSetArg(args[n], XmNnumDropTransfers, 1); n++; XtSetArg(args[n], XmNtransferProc, massage_selection); n++; /* cb->operation = XmDROP_COPY; */ XmDropTransferStart(cb->dragContext, args, n); } static void handle_drag(Widget w, XtPointer context, XtPointer info) { XmDragProcCallbackStruct *cb = (XmDragProcCallbackStruct *)info; drop_watcher_t *d; d = find_drop_watcher(w); if ((d) && (d->drag_watcher)) { switch (cb->reason) { case XmCR_DROP_SITE_MOTION_MESSAGE: (*(d->drag_watcher))(w, NULL, cb->x, cb->y, DRAG_MOTION, d->context); break; case XmCR_DROP_SITE_ENTER_MESSAGE: (*(d->drag_watcher))(w, NULL, cb->x, cb->y, DRAG_ENTER, d->context); break; case XmCR_DROP_SITE_LEAVE_MESSAGE: (*(d->drag_watcher))(w, NULL, cb->x, cb->y, DRAG_LEAVE, d->context); break; } } } #define NUM_TARGETS 7 void add_drag_and_drop(Widget w, void (*drop_watcher)(Widget w, const char *message, Position x, Position y, void *data), void (*drag_watcher)(Widget w, const char *message, Position x, Position y, drag_style_t dtype, void *data), void *context) { Display *dpy; int n; Atom targets[NUM_TARGETS]; Arg args[12]; dpy = main_display(ss); targets[0] = XA_STRING; FILE_NAME = XInternAtom(dpy, "FILE_NAME", false); targets[1] = FILE_NAME; COMPOUND_TEXT = XInternAtom(dpy, "COMPOUND_TEXT", false); targets[2] = COMPOUND_TEXT; _MOTIF_COMPOUND_STRING = XInternAtom(dpy, "_MOTIF_COMPOUND_STRING", false); targets[3] = _MOTIF_COMPOUND_STRING; text_plain = XInternAtom(dpy, "text/plain", false); targets[4] = text_plain; TEXT = XInternAtom(dpy, "TEXT", false); targets[5] = TEXT; uri_list = XInternAtom(dpy, "text/uri-list", false); targets[6] = uri_list; n = 0; XtSetArg(args[n], XmNdropSiteOperations, XmDROP_COPY | XmDROP_LINK); n++; XtSetArg(args[n], XmNimportTargets, targets); n++; XtSetArg(args[n], XmNnumImportTargets, NUM_TARGETS); n++; XtSetArg(args[n], XmNdropProc, handle_drop); n++; XtSetArg(args[n], XmNdragProc, handle_drag); n++; XmDropSiteRegister(w, args, n); add_drop_watcher(w, drop_watcher, drag_watcher, context); } /* -------------------------------------------------------------------------------- */ #include "sndlib-strings.h" /* preferences dialog; layout design taken from webmail */ static Widget preferences_dialog = NULL, load_path_text_widget = NULL; static bool prefs_unsaved = false; static char *prefs_saved_filename = NULL; static char *include_load_path = NULL; #define MID_POSITION 50 #define PREFS_COLOR_POSITION 62 /* COLOR_POSITION is slider_choice_t in snd-0.h */ #define FIRST_COLOR_POSITION 6 #define SECOND_COLOR_POSITION 30 #define THIRD_COLOR_POSITION 55 #define MID_SPACE 16 #define INTER_TOPIC_SPACE 3 #define INTER_VARIABLE_SPACE 2 #define POWER_WAIT_TIME 100 #define POWER_INITIAL_WAIT_TIME 500 /* "power" is an old-timey name for auto-repeat */ #define ERROR_WAIT_TIME 5000 #define STARTUP_WIDTH 925 #define STARTUP_HEIGHT 800 typedef struct prefs_info { Widget label, text, arrow_up, arrow_down, arrow_right, error, toggle, scale, toggle2, toggle3; Widget color, rscl, gscl, bscl, rtxt, gtxt, btxt, list_menu, radio_button; Widget *radio_buttons; bool got_error; timeout_result_t power_id; const char *var_name, *saved_label; int num_buttons; mus_float_t scale_max; void (*toggle_func)(struct prefs_info *prf); void (*toggle2_func)(struct prefs_info *prf); void (*scale_func)(struct prefs_info *prf); void (*arrow_up_func)(struct prefs_info *prf); void (*arrow_down_func)(struct prefs_info *prf); void (*text_func)(struct prefs_info *prf); void (*list_func)(struct prefs_info *prf, char *value); void (*color_func)(struct prefs_info *prf, double r, double g, double b); void (*reflect_func)(struct prefs_info *prf); void (*save_func)(struct prefs_info *prf, FILE *fd); const char *(*help_func)(struct prefs_info *prf); void (*clear_func)(struct prefs_info *prf); void (*revert_func)(struct prefs_info *prf); } prefs_info; static void prefs_set_dialog_title(const char *filename); static void reflect_key(prefs_info *prf, const char *key_name); static void save_key(prefs_info *prf, FILE *fd, char *(*binder)(char *key, bool c, bool m, bool x)); static void key_bind(prefs_info *prf, char *(*binder)(char *key, bool c, bool m, bool x)); static void clear_prefs_dialog_error(void); static void scale_set_color(prefs_info *prf, color_t pixel); static color_t rgb_to_color(mus_float_t r, mus_float_t g, mus_float_t b); static void post_prefs_error(const char *msg, prefs_info *data); #ifdef __GNUC__ static void va_post_prefs_error(const char *msg, prefs_info *data, ...) __attribute__ ((format (printf, 1, 0))); #else static void va_post_prefs_error(const char *msg, prefs_info *data, ...); #endif /* used in snd-prefs */ #define GET_TOGGLE(Toggle) (XmToggleButtonGetState(Toggle) == XmSET) #define SET_TOGGLE(Toggle, Value) XmToggleButtonSetState(Toggle, Value, false) #define GET_TEXT(Text) XmTextFieldGetString(Text) #define SET_TEXT(Text, Val) XmTextFieldSetString(Text, (char *)Val) #define free_TEXT(Val) XtFree(Val) #define SET_SCALE(Value) XmScaleSetValue(prf->scale, (int)(100 * Value)) #define SET_SENSITIVE(Wid, Val) XtSetSensitive(Wid, Val) #define black_text(Prf) XtVaSetValues(Prf->label, XmNforeground, ss->black, NULL) #define red_text(Prf) XtVaSetValues(Prf->label, XmNforeground, ss->red, NULL) #define TIMEOUT(Func) XtAppAddTimeOut(main_app(ss), ERROR_WAIT_TIME, Func, (XtPointer)prf) static int get_scale_1(Widget scale) { int val = 0; XmScaleGetValue(scale, &val); return(val); } #define GET_SCALE() (get_scale_1(prf->scale) * 0.01) static void set_radio_button(prefs_info *prf, int which) { if ((which >= 0) && (which < prf->num_buttons)) { int i; for (i = 0; i < prf->num_buttons; i++) { if ((prf->radio_buttons[i]) && (XmIsToggleButton(prf->radio_buttons[i]))) XmToggleButtonSetState(prf->radio_buttons[i], (i == which), false); } prf->radio_button = prf->radio_buttons[which]; } } static int which_radio_button(prefs_info *prf) { intptr_t which = 0; XtVaGetValues(prf->radio_button, XmNuserData, &which, NULL); return(which); } #include "snd-prefs.c" static bool prefs_dialog_error_is_posted = false; static void post_prefs_dialog_error(const char *message, void *data) { XmString title; title = XmStringCreateLocalized((char *)message); XtVaSetValues(preferences_dialog, XmNmessageString, title, NULL); XmStringFree(title); prefs_dialog_error_is_posted = (bool)message; } static void clear_prefs_dialog_error(void) { if (prefs_dialog_error_is_posted) { prefs_dialog_error_is_posted = false; post_prefs_dialog_error(NULL, NULL); } } static void prefs_change_callback(Widget w, XtPointer context, XtPointer info) { prefs_unsaved = true; prefs_set_dialog_title(NULL); clear_prefs_dialog_error(); } /* ---------------- row (main) label widget ---------------- */ static Widget make_row_label(prefs_info *prf, const char *label, Widget box, Widget top_widget) { Widget w; Arg args[20]; int n; n = 0; XtSetArg(args[n], XmNbackground, ss->white); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNtopWidget, top_widget); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_POSITION); n++; XtSetArg(args[n], XmNrightPosition, MID_POSITION); n++; XtSetArg(args[n], XmNalignment, XmALIGNMENT_END); n++; w = XtCreateManagedWidget(label, xmLabelWidgetClass, box, args, n); prf->saved_label = label; return(w); } /* ---------------- row inner label widget ---------------- */ static Widget make_row_inner_label(prefs_info *prf, const char *label, Widget left_widget, Widget box, Widget top_widget) { Widget w; Arg args[20]; int n; n = 0; XtSetArg(args[n], XmNbackground, ss->white); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNtopWidget, top_widget); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNleftWidget, left_widget); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_NONE); n++; w = XtCreateManagedWidget(label, xmLabelWidgetClass, box, args, n); return(w); } /* ---------------- row middle separator widget ---------------- */ static Widget make_row_middle_separator(Widget label, Widget box, Widget top_widget) { Arg args[20]; int n; n = 0; XtSetArg(args[n], XmNbackground, ss->white); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNtopWidget, top_widget); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_OPPOSITE_WIDGET); n++; XtSetArg(args[n], XmNbottomWidget, label); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNleftWidget, label); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNorientation, XmVERTICAL); n++; XtSetArg(args[n], XmNwidth, MID_SPACE); n++; XtSetArg(args[n], XmNseparatorType, XmSHADOW_ETCHED_OUT); n++; return(XtCreateManagedWidget("sep", xmSeparatorWidgetClass, box, args, n)); } /* ---------------- row inner separator widget ---------------- */ static Widget make_row_inner_separator(int width, Widget left_widget, Widget box, Widget top_widget) { Arg args[20]; int n; n = 0; XtSetArg(args[n], XmNbackground, ss->white); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNtopWidget, top_widget); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNleftWidget, left_widget); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNorientation, XmHORIZONTAL); n++; XtSetArg(args[n], XmNwidth, width); n++; XtSetArg(args[n], XmNseparatorType, XmNO_LINE); n++; return(XtCreateManagedWidget("sep1", xmSeparatorWidgetClass, box, args, n)); } static Widget make_row_error(prefs_info *prf, Widget box, Widget left_widget, Widget top_widget) { Arg args[20]; int n; Widget w; n = 0; XtSetArg(args[n], XmNbackground, ss->white); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNtopWidget, top_widget); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_OPPOSITE_WIDGET); n++; XtSetArg(args[n], XmNbottomWidget, left_widget); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNleftWidget, left_widget); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNalignment, XmALIGNMENT_END); n++; w = XtCreateManagedWidget("", xmLabelWidgetClass, box, args, n); return(w); } /* ---------------- row toggle widget ---------------- */ static Widget make_row_toggle_with_label(prefs_info *prf, bool current_value, Widget left_widget, Widget box, Widget top_widget, const char *label) { Widget w; Arg args[20]; int n; n = 0; XtSetArg(args[n], XmNbackground, ss->white); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNtopWidget, top_widget); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNleftWidget, left_widget); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNset, (current_value) ? XmSET : XmUNSET); n++; XtSetArg(args[n], XmNborderWidth, 0); n++; XtSetArg(args[n], XmNborderColor, ss->white); n++; XtSetArg(args[n], XmNmarginHeight, 0); n++; XtSetArg(args[n], XmNindicatorOn, XmINDICATOR_FILL); n++; XtSetArg(args[n], XmNindicatorSize, 14); n++; w = XtCreateManagedWidget(label, xmToggleButtonWidgetClass, box, args, n); return(w); } static Widget make_row_toggle(prefs_info *prf, bool current_value, Widget left_widget, Widget box, Widget top_widget) { return(make_row_toggle_with_label(prf, current_value, left_widget, box, top_widget, " ")); } /* ---------------- row arrows ---------------- */ static void remove_arrow_func(Widget w, XtPointer context, XtPointer info) { prefs_info *prf = (prefs_info *)context; if (prf->power_id != 0) { XtRemoveTimeOut(prf->power_id); prf->power_id = 0; } } static void arrow_func_up(XtPointer context, XtIntervalId *id) { prefs_info *prf = (prefs_info *)context; if (XtIsSensitive(prf->arrow_up)) { if ((prf) && (prf->arrow_up_func)) { (*(prf->arrow_up_func))(prf); prf->power_id = XtAppAddTimeOut(main_app(ss), POWER_WAIT_TIME, arrow_func_up, (XtPointer)prf); } else prf->power_id = 0; } } static void arrow_func_down(XtPointer context, XtIntervalId *id) { prefs_info *prf = (prefs_info *)context; if (XtIsSensitive(prf->arrow_down)) { if ((prf) && (prf->arrow_down_func)) { (*(prf->arrow_down_func))(prf); prf->power_id = XtAppAddTimeOut(main_app(ss), POWER_WAIT_TIME, arrow_func_down, (XtPointer)prf); } else prf->power_id = 0; } } static void call_arrow_down_press(Widget w, XtPointer context, XtPointer info) { prefs_info *prf = (prefs_info *)context; if ((prf) && (prf->arrow_down_func)) { (*(prf->arrow_down_func))(prf); if (XtIsSensitive(w)) prf->power_id = XtAppAddTimeOut(main_app(ss), POWER_INITIAL_WAIT_TIME, arrow_func_down, (XtPointer)prf); else prf->power_id = 0; } } static void call_arrow_up_press(Widget w, XtPointer context, XtPointer info) { prefs_info *prf = (prefs_info *)context; if ((prf) && (prf->arrow_up_func)) { (*(prf->arrow_up_func))(prf); if (XtIsSensitive(w)) prf->power_id = XtAppAddTimeOut(main_app(ss), POWER_INITIAL_WAIT_TIME, arrow_func_up, (XtPointer)prf); else prf->power_id = 0; } } static Widget make_row_arrows(prefs_info *prf, Widget box, Widget left_widget, Widget top_widget) { Arg args[20]; int n; n = 0; XtSetArg(args[n], XmNbackground, ss->white); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNtopWidget, top_widget); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNleftWidget, left_widget); n++; XtSetArg(args[n], XmNarrowDirection, XmARROW_DOWN); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_NONE); n++; prf->arrow_down = XtCreateManagedWidget("arrow-down", xmArrowButtonWidgetClass, box, args, n); n = 0; XtSetArg(args[n], XmNbackground, ss->white); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNtopWidget, top_widget); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNleftWidget, prf->arrow_down); n++; XtSetArg(args[n], XmNarrowDirection, XmARROW_UP); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_NONE); n++; prf->arrow_up = XtCreateManagedWidget("arrow-up", xmArrowButtonWidgetClass, box, args, n); XtAddCallback(prf->arrow_down, XmNarmCallback, call_arrow_down_press, (XtPointer)prf); XtAddCallback(prf->arrow_down, XmNdisarmCallback, remove_arrow_func, (XtPointer)prf); XtAddCallback(prf->arrow_up, XmNarmCallback, call_arrow_up_press, (XtPointer)prf); XtAddCallback(prf->arrow_up, XmNdisarmCallback, remove_arrow_func, (XtPointer)prf); XtAddCallback(prf->arrow_up, XmNactivateCallback, prefs_change_callback, NULL); XtAddCallback(prf->arrow_down, XmNactivateCallback, prefs_change_callback, NULL); return(prf->arrow_up); } /* ---------------- bool row ---------------- */ static void call_toggle_func(Widget w, XtPointer context, XtPointer info) { prefs_info *prf = (prefs_info *)context; if ((prf) && (prf->toggle_func)) (*(prf->toggle_func))(prf); } static prefs_info *prefs_row_with_toggle(const char *label, const char *varname, bool current_value, Widget box, Widget top_widget, void (*toggle_func)(prefs_info *prf)) { prefs_info *prf = NULL; Widget sep; prf = (prefs_info *)calloc(1, sizeof(prefs_info)); prf->var_name = varname; prf->toggle_func = toggle_func; prf->label = make_row_label(prf, label, box, top_widget); sep = make_row_middle_separator(prf->label, box, top_widget); prf->toggle = make_row_toggle(prf, current_value, sep, box, top_widget); XtAddCallback(prf->toggle, XmNvalueChangedCallback, call_toggle_func, (XtPointer)prf); return(prf); } /* ---------------- two toggles ---------------- */ static void call_toggle2_func(Widget w, XtPointer context, XtPointer info) { prefs_info *prf = (prefs_info *)context; if ((prf) && (prf->toggle2_func)) (*(prf->toggle2_func))(prf); } static prefs_info *prefs_row_with_two_toggles(const char *label, const char *varname, const char *label1, bool value1, const char *label2, bool value2, Widget box, Widget top_widget, void (*toggle_func)(prefs_info *prf), void (*toggle2_func)(prefs_info *prf)) { prefs_info *prf = NULL; Widget sep, sep1; prf = (prefs_info *)calloc(1, sizeof(prefs_info)); prf->var_name = varname; prf->toggle_func = toggle_func; prf->toggle2_func = toggle2_func; prf->label = make_row_label(prf, label, box, top_widget); sep = make_row_middle_separator(prf->label, box, top_widget); prf->toggle = make_row_toggle_with_label(prf, value1, sep, box, top_widget, label1); sep1 = make_row_inner_separator(20, prf->toggle, box, top_widget); prf->toggle2 = make_row_toggle_with_label(prf, value2, sep1, box, top_widget, label2); XtAddCallback(prf->toggle, XmNvalueChangedCallback, call_toggle_func, (XtPointer)prf); XtAddCallback(prf->toggle2, XmNvalueChangedCallback, call_toggle2_func, (XtPointer)prf); return(prf); } /* ---------------- toggle with text ---------------- */ static void call_text_func(Widget w, XtPointer context, XtPointer info) { prefs_info *prf = (prefs_info *)context; if ((prf) && (prf->text_func)) (*(prf->text_func))(prf); } /* earlier versions of this dialog assumed the user would type to save a new value * typed in a text widget, but no one does that anymore, so now, to catch these changes * but not be confused by automatic changes (such as in a scale widget's label), * we'll use XmNfocusCallback to set a text_focussed flag, XmNlosingFocusCallback to * unset it, XmNvalueChangedCallback to set a text_changed flag, XmNactivateCallback * to clear text_changed, and if XmNlosingFocusCallback sees that flag set, it * calls the activate function and unsets the flag. */ typedef struct { bool text_focussed, text_changed; prefs_info *prf; } text_info; static void text_change_callback(Widget w, XtPointer context, XtPointer info) { text_info *data = (text_info *)context; if (data->text_focussed) /* try to omit non-user actions that change the value */ data->text_changed = true; } static void text_activate_callback(Widget w, XtPointer context, XtPointer info) { text_info *data = (text_info *)context; data->text_changed = false; } static void text_grab_focus_callback(Widget w, XtPointer context, XtPointer info) { text_info *data = (text_info *)context; data->text_focussed = true; } static void text_lose_focus_callback(Widget w, XtPointer context, XtPointer info) { text_info *data = (text_info *)context; if ((data->text_focussed) && (data->text_changed) && (data->prf) && (data->prf->text_func)) { (*(data->prf->text_func))(data->prf); data->text_changed = false; } } static Widget make_row_text(prefs_info *prf, const char *text_value, int cols, Widget left_widget, Widget box, Widget top_widget) { Widget w; int n; Arg args[30]; text_info *info; n = 0; XtSetArg(args[n], XmNbackground, ss->white); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNtopWidget, top_widget); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNleftWidget, left_widget); n++; if (cols != 0) { XtSetArg(args[n], XmNrightAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNcolumns, cols); n++; } else { XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++; } if (text_value) { XtSetArg(args[n], XmNvalue, text_value); n++; } XtSetArg(args[n], XmNmarginHeight, 1); n++; XtSetArg(args[n], XmNborderWidth, 0); n++; XtSetArg(args[n], XmNborderColor, ss->white); n++; XtSetArg(args[n], XmNbottomShadowColor, ss->white); n++; XtSetArg(args[n], XmNshadowThickness, 0); n++; XtSetArg(args[n], XmNtopShadowColor, ss->white); n++; w = make_textfield_widget("text", box, args, n, ACTIVATABLE_BUT_NOT_FOCUSED, NO_COMPLETER); XtAddCallback(w, XmNactivateCallback, prefs_change_callback, NULL); info = (text_info *)calloc(1, sizeof(text_info)); info->prf = prf; XtAddCallback(w, XmNactivateCallback, text_activate_callback, (XtPointer)info); XtAddCallback(w, XmNvalueChangedCallback, text_change_callback, (XtPointer)info); XtAddCallback(w, XmNfocusCallback, text_grab_focus_callback, (XtPointer)info); XtAddCallback(w, XmNlosingFocusCallback, text_lose_focus_callback, (XtPointer)info); return(w); } static prefs_info *prefs_row_with_toggle_with_text(const char *label, const char *varname, bool current_value, const char *text_label, const char *text_value, int cols, Widget box, Widget top_widget, void (*toggle_func)(prefs_info *prf), void (*text_func)(prefs_info *prf)) { prefs_info *prf = NULL; Widget sep, sep1, lab1; prf = (prefs_info *)calloc(1, sizeof(prefs_info)); prf->var_name = varname; prf->toggle_func = toggle_func; prf->text_func = text_func; prf->label = make_row_label(prf, label, box, top_widget); sep = make_row_middle_separator(prf->label, box, top_widget); prf->toggle = make_row_toggle(prf, current_value, sep, box, top_widget); sep1 = make_row_inner_separator(16, prf->toggle, box, top_widget); lab1 = make_row_inner_label(prf, text_label, sep1, box, top_widget); prf->text = make_row_text(prf, text_value, cols, lab1, box, top_widget); XtAddCallback(prf->toggle, XmNvalueChangedCallback, call_toggle_func, (XtPointer)prf); XtAddCallback(prf->text, XmNactivateCallback, call_text_func, (XtPointer)prf); return(prf); } static prefs_info *prefs_row_with_toggle_with_two_texts(const char *label, const char *varname, bool current_value, const char *label1, const char *text1, const char *label2, const char *text2, int cols, Widget box, Widget top_widget, void (*toggle_func)(prefs_info *prf), void (*text_func)(prefs_info *prf)) { prefs_info *prf = NULL; Widget sep, lab1, lab2, sep1; prf = (prefs_info *)calloc(1, sizeof(prefs_info)); prf->var_name = varname; prf->toggle_func = toggle_func; prf->text_func = text_func; prf->label = make_row_label(prf, label, box, top_widget); sep = make_row_middle_separator(prf->label, box, top_widget); prf->toggle = make_row_toggle(prf, current_value, sep, box, top_widget); sep1 = make_row_inner_separator(16, prf->toggle, box, top_widget); lab1 = make_row_inner_label(prf, label1, sep1, box, top_widget); prf->text = make_row_text(prf, text1, cols, lab1, box, top_widget); lab2 = make_row_inner_label(prf, label2, prf->text, box, top_widget); prf->rtxt = make_row_text(prf, text2, cols, lab2, box, top_widget); XtAddCallback(prf->toggle, XmNvalueChangedCallback, call_toggle_func, (XtPointer)prf); XtAddCallback(prf->text, XmNactivateCallback, call_text_func, (XtPointer)prf); XtAddCallback(prf->rtxt, XmNactivateCallback, call_text_func, (XtPointer)prf); return(prf); } /* ---------------- text with toggle ---------------- */ static prefs_info *prefs_row_with_text_with_toggle(const char *label, const char *varname, bool current_value, const char *toggle_label, const char *text_value, int cols, Widget box, Widget top_widget, void (*toggle_func)(prefs_info *prf), void (*text_func)(prefs_info *prf)) { prefs_info *prf = NULL; Widget sep, sep1, lab1; prf = (prefs_info *)calloc(1, sizeof(prefs_info)); prf->var_name = varname; prf->toggle_func = toggle_func; prf->text_func = text_func; prf->label = make_row_label(prf, label, box, top_widget); sep = make_row_middle_separator(prf->label, box, top_widget); prf->text = make_row_text(prf, text_value, cols, sep, box, top_widget); sep1 = make_row_inner_separator(8, prf->text, box, top_widget); lab1 = make_row_inner_label(prf, toggle_label, sep1, box, top_widget); prf->toggle = make_row_toggle(prf, current_value, lab1, box, top_widget); XtAddCallback(prf->toggle, XmNvalueChangedCallback, call_toggle_func, (XtPointer)prf); XtAddCallback(prf->text, XmNactivateCallback, call_text_func, (XtPointer)prf); return(prf); } /* ---------------- text with toggle ---------------- */ static prefs_info *prefs_row_with_text_and_three_toggles(const char *label, const char *varname, const char *text_label, int cols, const char *toggle1_label, const char *toggle2_label, const char *toggle3_label, const char *text_value, bool toggle1_value, bool toggle2_value, bool toggle3_value, Widget box, Widget top_widget, void (*text_func)(prefs_info *prf)) { prefs_info *prf = NULL; Widget sep, sep1, lab1, sep2, lab2, lab3, sep3, lab4; prf = (prefs_info *)calloc(1, sizeof(prefs_info)); prf->var_name = varname; prf->text_func = text_func; prf->label = make_row_label(prf, label, box, top_widget); sep = make_row_middle_separator(prf->label, box, top_widget); lab3 = make_row_inner_label(prf, text_label, sep, box, top_widget); prf->text = make_row_text(prf, text_value, cols, lab3, box, top_widget); sep1 = make_row_inner_separator(12, prf->text, box, top_widget); lab1 = make_row_inner_label(prf, toggle1_label, sep1, box, top_widget); prf->toggle = make_row_toggle(prf, toggle1_value, lab1, box, top_widget); sep2 = make_row_inner_separator(4, prf->toggle, box, top_widget); lab2 = make_row_inner_label(prf, toggle2_label, sep2, box, top_widget); prf->toggle2 = make_row_toggle(prf, toggle2_value, lab2, box, top_widget); sep3 = make_row_inner_separator(4, prf->toggle2, box, top_widget); lab4 = make_row_inner_label(prf, toggle3_label, sep3, box, top_widget); prf->toggle3 = make_row_toggle(prf, toggle3_value, lab4, box, top_widget); XtAddCallback(prf->text, XmNactivateCallback, call_text_func, (XtPointer)prf); return(prf); } /* ---------------- radio row ---------------- */ static void call_radio_func(Widget w, XtPointer context, XtPointer info) { prefs_info *prf = (prefs_info *)context; if ((prf) && (prf->toggle_func)) { prf->radio_button = w; (*(prf->toggle_func))(prf); } } static Widget make_row_radio_box(prefs_info *prf, const char **labels, int num_labels, int current_value, Widget box, Widget left_widget, Widget top_widget) { Arg args[20]; int i, n; Widget w; prf->radio_buttons = (Widget *)calloc(num_labels, sizeof(Widget)); prf->num_buttons = num_labels; n = 0; XtSetArg(args[n], XmNbackground, ss->white); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNtopWidget, top_widget); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNleftWidget, left_widget); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNborderWidth, 0); n++; XtSetArg(args[n], XmNborderColor, ss->white); n++; XtSetArg(args[n], XmNmarginHeight, 0); n++; XtSetArg(args[n], XmNorientation, XmHORIZONTAL); n++; XtSetArg(args[n], XmNpacking, XmPACK_TIGHT); n++; w = XmCreateRadioBox(box, (char *)"radio-box", args, n); XtManageChild(w); for (i = 0; i < num_labels; i++) { Widget button; n = 0; XtSetArg(args[n], XmNbackground, ss->white); n++; XtSetArg(args[n], XmNset, (i == current_value) ? XmSET : XmUNSET); n++; XtSetArg(args[n], XmNborderWidth, 0); n++; XtSetArg(args[n], XmNborderColor, ss->white); n++; XtSetArg(args[n], XmNmarginHeight, 0); n++; XtSetArg(args[n], XmNindicatorOn, XmINDICATOR_FILL); n++; XtSetArg(args[n], XmNindicatorSize, 14); n++; XtSetArg(args[n], XmNselectColor, ss->green); n++; XtSetArg(args[n], XmNuserData, i); n++; button = XtCreateManagedWidget(labels[i], xmToggleButtonWidgetClass, w, args, n); prf->radio_buttons[i] = button; XtAddCallback(button, XmNvalueChangedCallback, call_radio_func, (XtPointer)prf); XtAddCallback(button, XmNvalueChangedCallback, prefs_change_callback, NULL); } return(w); } static prefs_info *prefs_row_with_radio_box(const char *label, const char *varname, const char **labels, int num_labels, int current_value, Widget box, Widget top_widget, void (*toggle_func)(prefs_info *prf)) { prefs_info *prf = NULL; Widget sep; prf = (prefs_info *)calloc(1, sizeof(prefs_info)); prf->var_name = varname; prf->toggle_func = toggle_func; prf->label = make_row_label(prf, label, box, top_widget); sep = make_row_middle_separator(prf->label, box, top_widget); prf->toggle = make_row_radio_box(prf, labels, num_labels, current_value, box, sep, top_widget); return(prf); } /* ---------------- radio box + number ---------------- */ static prefs_info *prefs_row_with_radio_box_and_number(const char *label, const char *varname, const char **labels, int num_labels, int current_value, const char *text_value, int text_cols, Widget box, Widget top_widget, void (*toggle_func)(prefs_info *prf), void (*arrow_up_func)(prefs_info *prf), void (*arrow_down_func)(prefs_info *prf), void (*text_func)(prefs_info *prf)) { prefs_info *prf = NULL; Widget sep; prf = (prefs_info *)calloc(1, sizeof(prefs_info)); prf->var_name = varname; prf->toggle_func = toggle_func; prf->text_func = text_func; prf->arrow_up_func = arrow_up_func; prf->arrow_down_func = arrow_down_func; prf->label = make_row_label(prf, label, box, top_widget); sep = make_row_middle_separator(prf->label, box, top_widget); prf->toggle = make_row_radio_box(prf, labels, num_labels, current_value, box, sep, top_widget); prf->text = make_row_text(prf, text_value, text_cols, prf->toggle, box, top_widget); prf->arrow_up = make_row_arrows(prf, box, prf->text, top_widget); XtAddCallback(prf->text, XmNactivateCallback, call_text_func, (XtPointer)prf); return(prf); } /* ---------------- scale row ---------------- */ static void call_scale_func(Widget w, XtPointer context, XtPointer info) { prefs_info *prf = (prefs_info *)context; if ((prf) && (prf->scale_func)) (*(prf->scale_func))(prf); } static void call_scale_text_func(Widget w, XtPointer context, XtPointer info) { prefs_info *prf = (prefs_info *)context; if ((prf) && (prf->text_func)) (*(prf->text_func))(prf); } static void prefs_scale_callback(Widget w, XtPointer context, XtPointer info) { prefs_info *prf = (prefs_info *)context; XmScaleCallbackStruct *cb = (XmScaleCallbackStruct *)info; float_to_textfield(prf->text, (cb->value * prf->scale_max) / 100.0); } static prefs_info *prefs_row_with_scale(const char *label, const char *varname, mus_float_t max_val, mus_float_t current_value, Widget box, Widget top_widget, void (*scale_func)(prefs_info *prf), void (*text_func)(prefs_info *prf)) { Arg args[20]; int n; prefs_info *prf = NULL; Widget sep; XtCallbackList n1, n2; char *str; prf = (prefs_info *)calloc(1, sizeof(prefs_info)); prf->var_name = varname; prf->scale_max = max_val; prf->label = make_row_label(prf, label, box, top_widget); sep = make_row_middle_separator(prf->label, box, top_widget); str = (char *)calloc(12, sizeof(char)); snprintf(str, 12, "%.3f", current_value); prf->text = make_row_text(prf, str, 6, sep, box, top_widget); free(str); n = 0; XtSetArg(args[n], XmNbackground, ss->white); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNtopWidget, top_widget); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNleftWidget, prf->text); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNborderWidth, 0); n++; XtSetArg(args[n], XmNborderColor, ss->white); n++; XtSetArg(args[n], XmNmarginHeight, 0); n++; XtSetArg(args[n], XmNorientation, XmHORIZONTAL); n++; XtSetArg(args[n], XmNshowValue, XmNONE); n++; XtSetArg(args[n], XmNvalue, (int)(100 * current_value / max_val)); n++; XtSetArg(args[n], XmNdragCallback, n1 = make_callback_list(prefs_scale_callback, (XtPointer)prf)); n++; XtSetArg(args[n], XmNvalueChangedCallback, n2 = make_callback_list(prefs_scale_callback, (XtPointer)prf)); n++; prf->scale = XtCreateManagedWidget("", xmScaleWidgetClass, box, args, n); prf->scale_func = scale_func; prf->text_func = text_func; XtAddCallback(prf->scale, XmNvalueChangedCallback, call_scale_func, (XtPointer)prf); XtAddCallback(prf->text, XmNactivateCallback, call_scale_text_func, (XtPointer)prf); XtAddCallback(prf->scale, XmNvalueChangedCallback, prefs_change_callback, NULL); free(n1); free(n2); return(prf); } /* ---------------- text row ---------------- */ static prefs_info *prefs_row_with_text(const char *label, const char *varname, const char *value, Widget box, Widget top_widget, void (*text_func)(prefs_info *prf)) { prefs_info *prf = NULL; Widget sep; prf = (prefs_info *)calloc(1, sizeof(prefs_info)); prf->var_name = varname; prf->label = make_row_label(prf, label, box, top_widget); sep = make_row_middle_separator(prf->label, box, top_widget); prf->text = make_row_text(prf, value, 0, sep, box, top_widget); prf->text_func = text_func; XtAddCallback(prf->text, XmNactivateCallback, call_text_func, (XtPointer)prf); return(prf); } /* ---------------- two texts in a row ---------------- */ static prefs_info *prefs_row_with_two_texts(const char *label, const char *varname, const char *label1, const char *text1, const char *label2, const char *text2, int cols, Widget box, Widget top_widget, void (*text_func)(prefs_info *prf)) { prefs_info *prf = NULL; Widget sep, lab1, lab2; prf = (prefs_info *)calloc(1, sizeof(prefs_info)); prf->var_name = varname; prf->label = make_row_label(prf, label, box, top_widget); sep = make_row_middle_separator(prf->label, box, top_widget); lab1 = make_row_inner_label(prf, label1, sep, box, top_widget); prf->text = make_row_text(prf, text1, cols, lab1, box, top_widget); lab2 = make_row_inner_label(prf, label2, prf->text, box, top_widget); prf->rtxt = make_row_text(prf, text2, cols, lab2, box, top_widget); prf->text_func = text_func; XtAddCallback(prf->text, XmNactivateCallback, call_text_func, (XtPointer)prf); XtAddCallback(prf->rtxt, XmNactivateCallback, call_text_func, (XtPointer)prf); return(prf); } /* ---------------- number row ---------------- */ static prefs_info *prefs_row_with_number(const char *label, const char *varname, const char *value, int cols, Widget box, Widget top_widget, void (*arrow_up_func)(prefs_info *prf), void (*arrow_down_func)(prefs_info *prf), void (*text_func)(prefs_info *prf)) { prefs_info *prf = NULL; Widget sep; prf = (prefs_info *)calloc(1, sizeof(prefs_info)); prf->var_name = varname; prf->label = make_row_label(prf, label, box, top_widget); sep = make_row_middle_separator(prf->label, box, top_widget); prf->text = make_row_text(prf, value, cols, sep, box, top_widget); prf->arrow_up = make_row_arrows(prf, box, prf->text, top_widget); prf->error = make_row_error(prf, box, prf->arrow_up, top_widget); prf->text_func = text_func; prf->arrow_up_func = arrow_up_func; prf->arrow_down_func = arrow_down_func; XtAddCallback(prf->text, XmNactivateCallback, call_text_func, (XtPointer)prf); return(prf); } /* ---------------- list row ---------------- */ typedef struct { prefs_info *prf; char *value; } list_entry; static list_entry *make_list_entry(prefs_info *prf, const char *value) { list_entry *le; le = (list_entry *)calloc(1, sizeof(list_entry)); le->prf = prf; le->value = (char *)value; return(le); } static void prefs_list_callback(Widget w, XtPointer context, XtPointer info) { list_entry *le = (list_entry *)context; if ((le) && (le->prf->list_func)) (*(le->prf->list_func))(le->prf, le->value); } static prefs_info *prefs_row_with_list(const char *label, const char *varname, const char *value, const char **values, int num_values, Widget box, Widget top_widget, void (*text_func)(prefs_info *prf), char *(*completion_func)(widget_t w, const char *text, void *context), void *completion_context, void (*list_func)(prefs_info *prf, char *value)) { Arg args[20]; int n, i, cols = 0; prefs_info *prf = NULL; Widget sep, sbar; prf = (prefs_info *)calloc(1, sizeof(prefs_info)); prf->var_name = varname; prf->label = make_row_label(prf, label, box, top_widget); sep = make_row_middle_separator(prf->label, box, top_widget); /* get text widget size */ for (i = 0; i < num_values; i++) if (values[i]) { int len; len = strlen(values[i]); if (len > cols) cols = len; } n = 0; XtSetArg(args[n], XmNbackground, ss->white); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNtopWidget, top_widget); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNleftWidget, sep); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNcolumns, cols + 1); n++; XtSetArg(args[n], XmNvalue, value); n++; XtSetArg(args[n], XmNmarginHeight, 1); n++; XtSetArg(args[n], XmNborderWidth, 0); n++; XtSetArg(args[n], XmNborderColor, ss->white); n++; XtSetArg(args[n], XmNbottomShadowColor, ss->white); n++; XtSetArg(args[n], XmNshadowThickness, 0); n++; XtSetArg(args[n], XmNtopShadowColor, ss->white); n++; if (completion_func) prf->text = make_textfield_widget("text", box, args, n, ACTIVATABLE_BUT_NOT_FOCUSED, add_completer_func(completion_func, completion_context)); else prf->text = make_textfield_widget("text", box, args, n, ACTIVATABLE_BUT_NOT_FOCUSED, NO_COMPLETER); n = 0; XtSetArg(args[n], XmNbackground, ss->basic_color); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNleftWidget, prf->text); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNtopWidget, top_widget); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNshadowThickness, 0); n++; XtSetArg(args[n], XmNhighlightThickness, 0); n++; XtSetArg(args[n], XmNmarginHeight, 0); n++; sbar = XmCreateMenuBar(box, (char *)"menuBar", args, n); XtManageChild(sbar); n = 0; XtSetArg(args[n], XmNbackground, ss->basic_color); n++; prf->list_menu = XmCreatePulldownMenu(sbar, (char *)"sort-menu", args, n); n = 0; XtSetArg(args[n], XmNbackground, ss->basic_color); n++; XtSetArg(args[n], XmNsubMenuId, prf->list_menu); n++; XtSetArg(args[n], XmNshadowThickness, 0); n++; XtSetArg(args[n], XmNhighlightThickness, 0); n++; XtSetArg(args[n], XmNmarginHeight, 1); n++; XtSetArg(args[n], XmNbackground, ss->white); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNtopWidget, top_widget); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNleftWidget, prf->text); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_NONE); n++; prf->arrow_right = XtCreateManagedWidget(">", xmCascadeButtonWidgetClass, sbar, args, n); n = 0; XtSetArg(args[n], XmNbackground, ss->white); n++; for (i = 0; i < num_values; i++) if (values[i]) { Widget tmp; tmp = XtCreateManagedWidget(values[i], xmPushButtonWidgetClass, prf->list_menu, args, n); XtAddCallback(tmp, XmNactivateCallback, prefs_list_callback, make_list_entry(prf, values[i])); XtAddCallback(tmp, XmNactivateCallback, prefs_change_callback, NULL); } prf->error = make_row_error(prf, box, prf->arrow_right, top_widget); prf->text_func = text_func; XtAddCallback(prf->text, XmNactivateCallback, call_text_func, (XtPointer)prf); XtAddCallback(prf->text, XmNactivateCallback, prefs_change_callback, NULL); XtAddCallback(prf->arrow_right, XmNactivateCallback, prefs_change_callback, NULL); prf->list_func = list_func; return(prf); } /* ---------------- color selector row(s) ---------------- */ static XColor *rgb_to_color_1(mus_float_t r, mus_float_t g, mus_float_t b) { Display *dpy; XColor *new_color; new_color = (XColor *)calloc(1, sizeof(XColor)); new_color->flags = DoRed | DoGreen | DoBlue; new_color->red = float_to_rgb(r); new_color->green = float_to_rgb(g); new_color->blue = float_to_rgb(b); dpy = main_display(ss); XAllocColor(dpy, DefaultColormap(dpy, DefaultScreen(dpy)), new_color); return(new_color); } #define COLOR_MAX 90 #define COLOR_MAXF 90.0 #define COLOR_MARGIN 1 static color_t rgb_to_color(mus_float_t r, mus_float_t g, mus_float_t b) { color_t temp; XColor *color; color = rgb_to_color_1(r, g, b); temp = color->pixel; free(color); return(temp); } static void pixel_to_rgb(Pixel pix, double *r, double *g, double *b) { XColor tmp_color; Display *dpy; dpy = XtDisplay(main_shell(ss)); tmp_color.flags = DoRed | DoGreen | DoBlue; tmp_color.pixel = pix; XQueryColor(dpy, DefaultColormap(dpy, DefaultScreen(dpy)), &tmp_color); (*r) = rgb_to_float(tmp_color.red); (*g) = rgb_to_float(tmp_color.green); (*b) = rgb_to_float(tmp_color.blue); } static void XmScrollBarGetValue(Widget w, int *val) { XtVaGetValues(w, XmNvalue, val, NULL); } static void XmScrollBarSetValue(Widget w, int val) { XtVaSetValues(w, XmNvalue, val, NULL); } static void reflect_color(prefs_info *prf) { int ir = 0, ig = 0, ib = 0; mus_float_t r, g, b; XColor *current_color; Pixel pixel; XmScrollBarGetValue(prf->rscl, &ir); XmScrollBarGetValue(prf->gscl, &ig); XmScrollBarGetValue(prf->bscl, &ib); current_color = rgb_to_color_1(ir / COLOR_MAXF, ig / COLOR_MAXF, ib / COLOR_MAXF); r = rgb_to_float(current_color->red); g = rgb_to_float(current_color->green); b = rgb_to_float(current_color->blue); pixel = current_color->pixel; free(current_color); current_color = NULL; XtVaSetValues(prf->color, XmNbackground, pixel, NULL); float_to_textfield(prf->rtxt, r); float_to_textfield(prf->gtxt, g); float_to_textfield(prf->btxt, b); } static void prefs_color_callback(Widget w, XtPointer context, XtPointer info) { reflect_color((prefs_info *)context); } static void unpost_color_error(XtPointer data, XtIntervalId *id) { prefs_info *prf = (prefs_info *)data; reflect_color(prf); prf->got_error = false; black_text(prf); set_label(prf->label, prf->saved_label); } static void errors_to_color_text(const char *msg, void *data) { prefs_info *prf = (prefs_info *)data; prf->got_error = true; red_text(prf); set_label(prf->label, msg); XtAppAddTimeOut(main_app(ss), ERROR_WAIT_TIME, (XtTimerCallbackProc)unpost_color_error, data); } static void prefs_r_callback(Widget w, XtPointer context, XtPointer info) { prefs_info *prf = (prefs_info *)context; char *str; double r; str = XmTextFieldGetString(w); redirect_errors_to(errors_to_color_text, (void *)prf); r = (double)string_to_mus_float_t(str, 0.0, "red amount"); redirect_errors_to(NULL, NULL); XmScrollBarSetValue(prf->rscl, mus_iclamp(0, (int)(COLOR_MAX * r), COLOR_MAX)); if (!(prf->got_error)) reflect_color(prf); if (str) XtFree(str); } static void prefs_g_callback(Widget w, XtPointer context, XtPointer info) { prefs_info *prf = (prefs_info *)context; char *str; double r; str = XmTextFieldGetString(w); redirect_errors_to(errors_to_color_text, (void *)prf); r = (double)string_to_mus_float_t(str, 0.0, "green amount"); redirect_errors_to(NULL, NULL); XmScrollBarSetValue(prf->gscl, mus_iclamp(0, (int)(COLOR_MAX * r), COLOR_MAX)); if (!(prf->got_error)) reflect_color(prf); if (str) XtFree(str); } static void prefs_b_callback(Widget w, XtPointer context, XtPointer info) { prefs_info *prf = (prefs_info *)context; char *str; double r; str = XmTextFieldGetString(w); redirect_errors_to(errors_to_color_text, (void *)prf); r = (double)string_to_mus_float_t(str, 0.0, "blue amount"); redirect_errors_to(NULL, NULL); XmScrollBarSetValue(prf->bscl, mus_iclamp(0, (int)(COLOR_MAX * r), COLOR_MAX)); if (!(prf->got_error)) reflect_color(prf); if (str) XtFree(str); } static void prefs_call_color_func_callback(Widget w, XtPointer context, XtPointer info) { prefs_info *prf = (prefs_info *)context; if ((prf) && (prf->color_func)) { int ir = 0, ig = 0, ib = 0; XmScrollBarGetValue(prf->rscl, &ir); XmScrollBarGetValue(prf->gscl, &ig); XmScrollBarGetValue(prf->bscl, &ib); (*(prf->color_func))(prf, (double)ir / COLOR_MAXF, (double)ig / COLOR_MAXF, (double)ib / COLOR_MAXF); } } static void scale_set_color(prefs_info *prf, color_t pixel) { double r = 0.0, g = 0.0, b = 0.0; pixel_to_rgb(pixel, &r, &g, &b); float_to_textfield(prf->rtxt, r); XmScrollBarSetValue(prf->rscl, (int)(COLOR_MAX * r)); float_to_textfield(prf->gtxt, g); XmScrollBarSetValue(prf->gscl, (int)(COLOR_MAX * g)); float_to_textfield(prf->btxt, b); XmScrollBarSetValue(prf->bscl, (int)(COLOR_MAX * b)); XtVaSetValues(prf->color, XmNbackground, pixel, NULL); } static Pixel red, green, blue; static prefs_info *prefs_color_selector_row(const char *label, const char *varname, Pixel current_pixel, Widget box, Widget top_widget, void (*color_func)(prefs_info *prf, double r, double g, double b)) { Arg args[20]; int n; prefs_info *prf = NULL; Widget sep, sep1, frame; XtCallbackList n1; double r = 0.0, g = 0.0, b = 0.0; prf = (prefs_info *)calloc(1, sizeof(prefs_info)); prf->var_name = varname; pixel_to_rgb(current_pixel, &r, &g, &b); prf->label = make_row_label(prf, label, box, top_widget); sep = make_row_middle_separator(prf->label, box, top_widget); n = 0; XtSetArg(args[n], XmNbackground, current_pixel); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNtopWidget, top_widget); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_OPPOSITE_WIDGET); n++; XtSetArg(args[n], XmNbottomWidget, sep); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNleftWidget, sep); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_POSITION); n++; XtSetArg(args[n], XmNrightPosition, PREFS_COLOR_POSITION); n++; XtSetArg(args[n], XmNshadowType, XmSHADOW_ETCHED_IN); n++; frame = XtCreateManagedWidget("frame", xmFrameWidgetClass, box, args, n); n = 0; XtSetArg(args[n], XmNbackground, current_pixel); n++; prf->color = XtCreateManagedWidget("", xmLabelWidgetClass, frame, args, n); sep1 = make_row_inner_separator(8, prf->color, box, top_widget); prf->rtxt = make_row_text(prf, NULL, 6, sep1, box, top_widget); float_to_textfield(prf->rtxt, r); prf->gtxt = make_row_text(prf, NULL, 6, prf->rtxt, box, top_widget); float_to_textfield(prf->gtxt, g); prf->btxt = make_row_text(prf, NULL, 6, prf->gtxt, box, top_widget); float_to_textfield(prf->btxt, b); /* second row = 3 scales */ n1 = make_callback_list(prefs_color_callback, (XtPointer)prf); n = 0; XtSetArg(args[n], XmNbackground, ss->white); n++; XtSetArg(args[n], XmNforeground, red); n++; XtSetArg(args[n], XmNsliderVisual, XmFOREGROUND_COLOR); n++; XtSetArg(args[n], XmNsliderMark, XmTHUMB_MARK); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNtopWidget, prf->label); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++; if (FIRST_COLOR_POSITION == 0) { XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++; } else { XtSetArg(args[n], XmNleftAttachment, XmATTACH_POSITION); n++; XtSetArg(args[n], XmNleftPosition, FIRST_COLOR_POSITION); n++; } XtSetArg(args[n], XmNrightAttachment, XmATTACH_POSITION); n++; XtSetArg(args[n], XmNrightPosition, SECOND_COLOR_POSITION - COLOR_MARGIN); n++; XtSetArg(args[n], XmNmarginHeight, 0); n++; /* scale widget borders are messed up in some Motifs -- they aren't erased correctly in a scrolled window * so, try to use a scrollbar instead. */ XtSetArg(args[n], XmNmaximum, 100); n++; XtSetArg(args[n], XmNheight, 16); n++; XtSetArg(args[n], XmNorientation, XmHORIZONTAL); n++; XtSetArg(args[n], XmNshowArrows, XmNONE); n++; XtSetArg(args[n], XmNvalue, (int)(COLOR_MAX * r)); n++; XtSetArg(args[n], XmNdragCallback, n1); n++; XtSetArg(args[n], XmNvalueChangedCallback, n1); n++; prf->rscl = XtCreateManagedWidget("", xmScrollBarWidgetClass, box, args, n); n = 0; XtSetArg(args[n], XmNbackground, ss->white); n++; XtSetArg(args[n], XmNforeground, green); n++; XtSetArg(args[n], XmNsliderVisual, XmFOREGROUND_COLOR); n++; XtSetArg(args[n], XmNsliderMark, XmTHUMB_MARK); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNtopWidget, prf->label); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_POSITION); n++; XtSetArg(args[n], XmNleftPosition, SECOND_COLOR_POSITION + COLOR_MARGIN); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_POSITION); n++; XtSetArg(args[n], XmNrightPosition, THIRD_COLOR_POSITION - COLOR_MARGIN); n++; XtSetArg(args[n], XmNmarginHeight, 0); n++; XtSetArg(args[n], XmNmaximum, 100); n++; XtSetArg(args[n], XmNheight, 16); n++; XtSetArg(args[n], XmNorientation, XmHORIZONTAL); n++; XtSetArg(args[n], XmNshowArrows, XmNONE); n++; XtSetArg(args[n], XmNvalue, (int)(COLOR_MAX * g)); n++; XtSetArg(args[n], XmNdragCallback, n1); n++; XtSetArg(args[n], XmNvalueChangedCallback, n1); n++; prf->gscl = XtCreateManagedWidget("", xmScrollBarWidgetClass, box, args, n); n = 0; XtSetArg(args[n], XmNbackground, ss->white); n++; XtSetArg(args[n], XmNforeground, blue); n++; XtSetArg(args[n], XmNsliderVisual, XmFOREGROUND_COLOR); n++; XtSetArg(args[n], XmNsliderMark, XmTHUMB_MARK); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNtopWidget, prf->label); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_POSITION); n++; XtSetArg(args[n], XmNleftPosition, THIRD_COLOR_POSITION + COLOR_MARGIN); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_POSITION); n++; XtSetArg(args[n], XmNrightPosition, 80); n++; XtSetArg(args[n], XmNmarginHeight, 0); n++; XtSetArg(args[n], XmNmaximum, 100); n++; XtSetArg(args[n], XmNheight, 16); n++; XtSetArg(args[n], XmNorientation, XmHORIZONTAL); n++; XtSetArg(args[n], XmNshowArrows, XmNONE); n++; XtSetArg(args[n], XmNvalue, (int)(COLOR_MAX * b)); n++; XtSetArg(args[n], XmNdragCallback, n1); n++; XtSetArg(args[n], XmNvalueChangedCallback, n1); n++; prf->bscl = XtCreateManagedWidget("", xmScrollBarWidgetClass, box, args, n); XtAddCallback(prf->rtxt, XmNactivateCallback, prefs_r_callback, (XtPointer)prf); XtAddCallback(prf->gtxt, XmNactivateCallback, prefs_g_callback, (XtPointer)prf); XtAddCallback(prf->btxt, XmNactivateCallback, prefs_b_callback, (XtPointer)prf); XtAddCallback(prf->rscl, XmNvalueChangedCallback, prefs_call_color_func_callback, (XtPointer)prf); XtAddCallback(prf->gscl, XmNvalueChangedCallback, prefs_call_color_func_callback, (XtPointer)prf); XtAddCallback(prf->bscl, XmNvalueChangedCallback, prefs_call_color_func_callback, (XtPointer)prf); XtAddCallback(prf->rscl, XmNvalueChangedCallback, prefs_change_callback, NULL); XtAddCallback(prf->gscl, XmNvalueChangedCallback, prefs_change_callback, NULL); XtAddCallback(prf->bscl, XmNvalueChangedCallback, prefs_change_callback, NULL); prf->color_func = color_func; free(n1); return(prf); } /* ---------------- topic separator ---------------- */ static Widget make_inter_topic_separator(Widget topics) { int n; Arg args[20]; n = 0; XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNorientation, XmHORIZONTAL); n++; XtSetArg(args[n], XmNheight, INTER_TOPIC_SPACE); n++; XtSetArg(args[n], XmNseparatorType, XmNO_LINE); n++; return(XtCreateManagedWidget("sep", xmSeparatorWidgetClass, topics, args, n)); } /* ---------------- variable separator ---------------- */ static Widget make_inter_variable_separator(Widget topics, Widget top_widget) { int n; Arg args[20]; n = 0; XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNtopWidget, top_widget); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNorientation, XmHORIZONTAL); n++; XtSetArg(args[n], XmNheight, INTER_VARIABLE_SPACE); n++; XtSetArg(args[n], XmNseparatorType, XmNO_LINE); n++; return(XtCreateManagedWidget("sep", xmSeparatorWidgetClass, topics, args, n)); } /* ---------------- top-level contents label ---------------- */ static Widget make_top_level_label(const char *label, Widget parent) { int n; Arg args[20]; n = 0; XtSetArg(args[n], XmNbackground, ss->light_blue); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNalignment, XmALIGNMENT_BEGINNING); n++; XtSetArg(args[n], XmNheight, 32); n++; return(XtCreateManagedWidget(label, xmLabelWidgetClass, parent, args, n)); } static Widget make_top_level_box(Widget topics) { Widget frame; int n; Arg args[20]; n = 0; XtSetArg(args[n], XmNbackground, ss->white); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++; frame = XtCreateManagedWidget("pref-frame", xmFrameWidgetClass, topics, args, n); n = 0; XtSetArg(args[n], XmNbackground, ss->white); n++; return(XtCreateManagedWidget("pref-box", xmFormWidgetClass, frame, args, n)); } static Widget make_inner_label(const char *label, Widget parent, Widget top_widget) { int n; Arg args[20]; n = 0; XtSetArg(args[n], XmNbackground, ss->basic_color); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNtopWidget, top_widget); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNalignment, XmALIGNMENT_BEGINNING); n++; XtSetArg(args[n], XmNheight, 32); n++; return(XtCreateManagedWidget(label, xmLabelWidgetClass, parent, args, n)); } /* ---------------- base buttons ---------------- */ static void wm_delete_callback(Widget w, XtPointer context, XtPointer info) { clear_prefs_dialog_error(); } static void preferences_help_callback(Widget w, XtPointer context, XtPointer info) { snd_help("preferences", "This dialog sets various global variables. 'Save' then writes the new values \ to ~/.snd_prefs_ruby|forth|s7 so that they take effect the next time you start Snd. 'Revert' resets each variable either to \ its value when the Preferences dialog was started, or to the last saved value. 'Clear' resets each variable to its default value (its \ value when Snd starts, before loading initialization files). 'Help' starts this dialog, and as long as it's active, it will post helpful \ information if the mouse lingers over some variable -- sort of a tooltip that stays out of your way. \ You can also request help on a given topic by clicking the variable name on the far right.", WITH_WORD_WRAP); } static void preferences_quit_callback(Widget w, XtPointer context, XtPointer info) { clear_prefs_dialog_error(); if (XmGetFocusWidget(preferences_dialog) == XmMessageBoxGetChild(preferences_dialog, XmDIALOG_CANCEL_BUTTON)) XtUnmanageChild(preferences_dialog); } static void prefs_set_dialog_title(const char *filename) { XmString title; char *str; if (filename) { if (prefs_saved_filename) free(prefs_saved_filename); prefs_saved_filename = mus_strdup(filename); } if (prefs_saved_filename) str = mus_format("Preferences%s (saved in %s)\n", (prefs_unsaved) ? "*" : "", prefs_saved_filename); else str = mus_format("Preferences%s", (prefs_unsaved) ? "*" : ""); title = XmStringCreateLocalized(str); free(str); XtVaSetValues(preferences_dialog, XmNdialogTitle, title, NULL); XmStringFree(title); } static void preferences_revert_callback(Widget w, XtPointer context, XtPointer info) { preferences_revert_or_clear(true); } static void preferences_clear_callback(Widget w, XtPointer context, XtPointer info) { preferences_revert_or_clear(false); } #if HAVE_EXTENSION_LANGUAGE static void preferences_save_callback(Widget w, XtPointer context, XtPointer info) { clear_prefs_dialog_error(); redirect_snd_error_to(post_prefs_dialog_error, NULL); redirect_snd_warning_to(post_prefs_dialog_error, NULL); save_prefs(); redirect_snd_error_to(NULL, NULL); redirect_snd_warning_to(NULL, NULL); } #endif /* ---------------- errors ---------------- */ static void clear_prefs_error(Widget w, XtPointer context, XtPointer info) { prefs_info *prf = (prefs_info *)context; XtRemoveCallback(prf->text, XmNvalueChangedCallback, clear_prefs_error, context); set_label(prf->error, ""); } static void post_prefs_error(const char *msg, prefs_info *prf) { prf->got_error = true; set_label(prf->error, msg); XtAddCallback(prf->text, XmNvalueChangedCallback, clear_prefs_error, (XtPointer)prf); } static void va_post_prefs_error(const char *msg, prefs_info *data, ...) { char *buf; va_list ap; va_start(ap, data); buf = vstr(msg, ap); va_end(ap); post_prefs_error(buf, data); free(buf); } /* ---------------- preferences dialog ---------------- */ widget_t make_preferences_dialog(void) { Arg args[20]; Widget scroller, topics, current_sep; char *str; prefs_info *prf; if (preferences_dialog) { /* I don't think this should reflect current state except when it is created */ if (!(XtIsManaged(preferences_dialog))) XtManageChild(preferences_dialog); else raise_dialog(preferences_dialog); return(preferences_dialog); } /* -------- base buttons -------- */ { int n; XmString title, help, revert, clear, save, go_away; Widget clear_button, revert_button; #if HAVE_EXTENSION_LANGUAGE Widget save_button; save = XmStringCreateLocalized((char *)"Save"); #endif title = XmStringCreateLocalized((char *)"Preferences"); help = XmStringCreateLocalized((char *)I_HELP); revert = XmStringCreateLocalized((char *)"Revert"); clear = XmStringCreateLocalized((char *)"Clear"); go_away = XmStringCreateLocalized((char *)I_GO_AWAY); n = 0; XtSetArg(args[n], XmNbackground, ss->basic_color); n++; XtSetArg(args[n], XmNresizePolicy, XmRESIZE_GROW); n++; XtSetArg(args[n], XmNnoResize, false); n++; XtSetArg(args[n], XmNtransient, false); n++; XtSetArg(args[n], XmNcancelLabelString, go_away); n++; XtSetArg(args[n], XmNhelpLabelString, help); n++; XtSetArg(args[n], XmNokLabelString, revert); n++; XtSetArg(args[n], XmNdialogTitle, title); n++; XtSetArg(args[n], XmNallowShellResize, true); n++; XtSetArg(args[n], XmNautoUnmanage, false); n++; { Dimension width, height; width = XDisplayWidth(main_display(ss), DefaultScreen(main_display(ss))); height = XDisplayHeight(main_display(ss), DefaultScreen(main_display(ss))); XtSetArg(args[n], XmNwidth, (STARTUP_WIDTH < width) ? (Dimension)STARTUP_WIDTH : ((Dimension)(width - 50))); n++; XtSetArg(args[n], XmNheight, (STARTUP_HEIGHT < height) ? (Dimension)STARTUP_HEIGHT : ((Dimension)(height - 50))); n++; } preferences_dialog = XmCreateTemplateDialog(main_pane(ss), (char *)"preferences", args, n); revert_button = XmMessageBoxGetChild(preferences_dialog, XmDIALOG_OK_BUTTON); n = 0; XtSetArg(args[n], XmNbackground, ss->highlight_color); n++; XtSetArg(args[n], XmNarmColor, ss->selection_color); n++; clear_button = XtCreateManagedWidget("Clear", xmPushButtonGadgetClass, preferences_dialog, args, n); #if HAVE_EXTENSION_LANGUAGE n = 0; XtSetArg(args[n], XmNbackground, ss->highlight_color); n++; XtSetArg(args[n], XmNarmColor, ss->selection_color); n++; save_button = XtCreateManagedWidget("Save", xmPushButtonGadgetClass, preferences_dialog, args, n); XtAddCallback(save_button, XmNactivateCallback, preferences_save_callback, NULL); #endif XtAddCallback(preferences_dialog, XmNcancelCallback, preferences_quit_callback, NULL); XtAddCallback(preferences_dialog, XmNhelpCallback, preferences_help_callback, NULL); /* XtAddCallback(preferences_dialog, XmNokCallback, preferences_revert_callback, NULL); */ XtAddCallback(revert_button, XmNactivateCallback, preferences_revert_callback, NULL); XtAddCallback(clear_button, XmNactivateCallback, preferences_clear_callback, NULL); XmStringFree(title); XmStringFree(help); #if HAVE_EXTENSION_LANGUAGE XmStringFree(save); #endif XmStringFree(go_away); XmStringFree(revert); XmStringFree(clear); map_over_children(preferences_dialog, set_main_color_of_widget); #if HAVE_EXTENSION_LANGUAGE XtVaSetValues(XmMessageBoxGetChild(preferences_dialog, XmDIALOG_CANCEL_BUTTON), XmNarmColor, ss->selection_color, NULL); XtVaSetValues(XmMessageBoxGetChild(preferences_dialog, XmDIALOG_CANCEL_BUTTON), XmNbackground, ss->highlight_color, NULL); #endif XtVaSetValues(XmMessageBoxGetChild(preferences_dialog, XmDIALOG_OK_BUTTON), XmNarmColor, ss->selection_color, NULL); XtVaSetValues(XmMessageBoxGetChild(preferences_dialog, XmDIALOG_HELP_BUTTON), XmNarmColor, ss->selection_color, NULL); XtVaSetValues(XmMessageBoxGetChild(preferences_dialog, XmDIALOG_OK_BUTTON), XmNbackground, ss->highlight_color, NULL); XtVaSetValues(XmMessageBoxGetChild(preferences_dialog, XmDIALOG_HELP_BUTTON), XmNbackground, ss->highlight_color, NULL); n = 0; XtSetArg(args[n], XmNbackground, ss->white); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNbottomWidget, XmMessageBoxGetChild(preferences_dialog, XmDIALOG_SEPARATOR)); n++; XtSetArg(args[n], XmNscrollingPolicy, XmAUTOMATIC); n++; XtSetArg(args[n], XmNscrollBarDisplayPolicy, XmSTATIC); n++; scroller = XmCreateScrolledWindow(preferences_dialog, (char *)"pref-scroller", args, n); XtManageChild(scroller); n = attach_all_sides(args, 0); XtSetArg(args[n], XmNbackground, ss->white); n++; XtSetArg(args[n], XmNorientation, XmVERTICAL); n++; topics = XtCreateManagedWidget("pref-topics", xmRowColumnWidgetClass, scroller, args, n); XtVaSetValues(scroller, XmNworkWindow, topics, NULL); } red = rgb_to_color(1.0, 0.0, 0.0); green = rgb_to_color(0.0, 1.0, 0.0); blue = rgb_to_color(0.0, 0.0, 1.0); /* ---------------- overall behavior ---------------- */ { Widget dpy_box, dpy_label, file_label, cursor_label, key_label; char *str1, *str2; /* ---------------- overall behavior ----------------*/ dpy_box = make_top_level_box(topics); dpy_label = make_top_level_label("overall behavior choices", dpy_box); current_sep = dpy_label; str1 = mus_format("%d", ss->init_window_width); str2 = mus_format("%d", ss->init_window_height); rts_init_window_width = ss->init_window_width; rts_init_window_height = ss->init_window_height; prf = prefs_row_with_two_texts("start up size", S_window_width, "width:", str1, "height:", str2, 6, dpy_box, current_sep, startup_size_text); remember_pref(prf, reflect_init_window_size, save_init_window_size, help_init_window_size, clear_init_window_size, revert_init_window_size); free(str2); free(str1); current_sep = make_inter_variable_separator(dpy_box, prf->label); prf = prefs_row_with_toggle("ask before overwriting anything", S_ask_before_overwrite, rts_ask_before_overwrite = ask_before_overwrite(ss), dpy_box, current_sep, overwrite_toggle); remember_pref(prf, reflect_ask_before_overwrite, save_ask_before_overwrite, help_ask_before_overwrite, NULL, revert_ask_before_overwrite); current_sep = make_inter_variable_separator(dpy_box, prf->label); prf = prefs_row_with_toggle("ask about unsaved edits before exiting", S_ask_about_unsaved_edits, rts_unsaved_edits = ask_about_unsaved_edits(ss), dpy_box, current_sep, unsaved_edits_toggle); remember_pref(prf, reflect_unsaved_edits, save_unsaved_edits, help_unsaved_edits, clear_unsaved_edits, revert_unsaved_edits); current_sep = make_inter_variable_separator(dpy_box, prf->label); prf = prefs_row_with_toggle("include thumbnail graph in upper right corner", S_with_inset_graph, rts_with_inset_graph = with_inset_graph(ss), dpy_box, current_sep, with_inset_graph_toggle); remember_pref(prf, reflect_with_inset_graph, save_with_inset_graph, help_inset_graph, clear_with_inset_graph, revert_with_inset_graph); current_sep = make_inter_variable_separator(dpy_box, prf->label); prf = prefs_row_with_toggle("resize main window as sounds open and close", S_auto_resize, rts_auto_resize = auto_resize(ss), dpy_box, current_sep, resize_toggle); remember_pref(prf, reflect_auto_resize, save_auto_resize, help_auto_resize, NULL, revert_auto_resize); current_sep = make_inter_variable_separator(dpy_box, prf->label); prf = prefs_row_with_toggle("pointer focus", S_with_pointer_focus, rts_with_pointer_focus = with_pointer_focus(ss), dpy_box, current_sep, with_pointer_focus_toggle); remember_pref(prf, reflect_with_pointer_focus, save_with_pointer_focus, help_pointer_focus, clear_with_pointer_focus, revert_with_pointer_focus); current_sep = make_inter_variable_separator(dpy_box, prf->label); rts_sync_style = sync_style(ss); prf = prefs_row_with_two_toggles("operate on all channels together", S_sync, "within each sound", rts_sync_style == SYNC_BY_SOUND, "across all sounds", rts_sync_style == SYNC_ALL, dpy_box, current_sep, sync1_choice, sync2_choice); remember_pref(prf, reflect_sync_style, save_sync_style, help_sync_style, clear_sync_style, revert_sync_style); current_sep = make_inter_variable_separator(dpy_box, prf->label); rts_remember_sound_state = remember_sound_state(ss); prf = prefs_row_with_toggle("restore a sound's state if reopened later", S_remember_sound_state, rts_remember_sound_state, dpy_box, current_sep, toggle_remember_sound_state); remember_pref(prf, reflect_remember_sound_state, save_remember_sound_state, help_remember_sound_state, clear_remember_sound_state, revert_remember_sound_state); current_sep = make_inter_variable_separator(dpy_box, prf->label); prf = prefs_row_with_toggle("show the control panel upon opening a sound", S_show_controls, rts_show_controls = in_show_controls(ss), dpy_box, current_sep, controls_toggle); remember_pref(prf, reflect_show_controls, save_show_controls, help_show_controls, NULL, revert_show_controls); current_sep = make_inter_variable_separator(dpy_box, prf->label); include_peak_env_directory = mus_strdup(peak_env_dir(ss)); rts_peak_env_directory = mus_strdup(include_peak_env_directory); include_peak_envs = find_peak_envs(); rts_peak_envs = include_peak_envs; prf = prefs_row_with_toggle_with_text("save peak envs to speed up initial display", S_peak_env_dir, include_peak_envs, "directory:", include_peak_env_directory, 25, dpy_box, current_sep, peak_envs_toggle, peak_envs_text); remember_pref(prf, reflect_peak_envs, save_peak_envs, help_peak_envs, clear_peak_envs, revert_peak_envs); current_sep = make_inter_variable_separator(dpy_box, prf->label); str = mus_format("%d", rts_max_regions = max_regions(ss)); prf = prefs_row_with_toggle_with_text("selection creates an associated region", S_selection_creates_region, rts_selection_creates_region = selection_creates_region(ss), "max regions:", str, 5, dpy_box, current_sep, selection_creates_region_toggle, max_regions_text); remember_pref(prf, reflect_selection_creates_region, save_selection_creates_region, help_selection_creates_region, NULL, revert_selection_creates_region); free(str); current_sep = make_inter_variable_separator(dpy_box, prf->label); rts_with_toolbar = with_toolbar(ss); prf = prefs_row_with_toggle("include a toolbar", S_with_toolbar, rts_with_toolbar, dpy_box, current_sep, toggle_with_toolbar); remember_pref(prf, reflect_with_toolbar, save_with_toolbar, help_with_toolbar, clear_with_toolbar, revert_with_toolbar); current_sep = make_inter_variable_separator(dpy_box, prf->label); rts_with_tooltips = with_tooltips(ss); prf = prefs_row_with_toggle("enable tooltips", S_with_tooltips, rts_with_tooltips, dpy_box, current_sep, toggle_with_tooltips); remember_pref(prf, reflect_with_tooltips, save_with_tooltips, help_with_tooltips, clear_with_tooltips, revert_with_tooltips); /* ---------------- file options ---------------- */ current_sep = make_inter_variable_separator(dpy_box, prf->label); file_label = make_inner_label(" file options", dpy_box, current_sep); rts_load_path = find_sources(); prf = prefs_row_with_text("directory containing Snd's " Xen_language " files", "load path", rts_load_path, dpy_box, file_label, load_path_text); remember_pref(prf, reflect_load_path, NULL, help_load_path, clear_load_path, revert_load_path); load_path_text_widget = prf->text; current_sep = make_inter_variable_separator(dpy_box, prf->label); prf = prefs_row_with_toggle("display only sound files in various file lists", S_just_sounds, rts_just_sounds = just_sounds(ss), dpy_box, current_sep, just_sounds_toggle); remember_pref(prf, prefs_reflect_just_sounds, save_just_sounds, help_just_sounds, NULL, revert_just_sounds); current_sep = make_inter_variable_separator(dpy_box, prf->label); rts_temp_dir = mus_strdup(temp_dir(ss)); prf = prefs_row_with_text("directory for temporary files", S_temp_dir, temp_dir(ss), dpy_box, current_sep, temp_dir_text); remember_pref(prf, reflect_temp_dir, save_temp_dir, help_temp_dir, NULL, revert_temp_dir); current_sep = make_inter_variable_separator(dpy_box, prf->label); rts_save_dir = mus_strdup(save_dir(ss)); prf = prefs_row_with_text("directory for save-state files", S_save_dir, save_dir(ss), dpy_box, current_sep, save_dir_text); remember_pref(prf, reflect_save_dir, save_save_dir, help_save_dir, NULL, revert_save_dir); current_sep = make_inter_variable_separator(dpy_box, prf->label); rts_save_state_file = mus_strdup(save_state_file(ss)); prf = prefs_row_with_text("default save-state filename", S_save_state_file, save_state_file(ss), dpy_box, current_sep, save_state_file_text); remember_pref(prf, reflect_save_state_file, save_save_state_file, help_save_state_file, NULL, revert_save_state_file); #if HAVE_LADSPA current_sep = make_inter_variable_separator(dpy_box, prf->label); rts_ladspa_dir = mus_strdup(ladspa_dir(ss)); prf = prefs_row_with_text("directory for ladspa plugins", S_ladspa_dir, ladspa_dir(ss), dpy_box, current_sep, ladspa_dir_text); remember_pref(prf, reflect_ladspa_dir, save_ladspa_dir, help_ladspa_dir, NULL, revert_ladspa_dir); #endif current_sep = make_inter_variable_separator(dpy_box, prf->label); rts_vf_directory = mus_strdup(view_files_find_any_directory()); prf = prefs_row_with_text("directory for view-files dialog", S_add_directory_to_view_files_list, rts_vf_directory, dpy_box, current_sep, view_files_directory_text); remember_pref(prf, reflect_view_files_directory, save_view_files_directory, help_view_files_directory, NULL, revert_view_files_directory); current_sep = make_inter_variable_separator(dpy_box, prf->label); rts_html_program = mus_strdup(html_program(ss)); prf = prefs_row_with_text("external program to read HTML files via snd-help", S_html_program, html_program(ss), dpy_box, current_sep, html_program_text); remember_pref(prf, reflect_html_program, save_html_program, help_html_program, NULL, revert_html_program); current_sep = make_inter_variable_separator(dpy_box, prf->label); rts_default_output_chans = default_output_chans(ss); prf = prefs_row_with_radio_box("default new sound attributes: chans", S_default_output_chans, output_chan_choices, NUM_OUTPUT_CHAN_CHOICES, -1, dpy_box, current_sep, default_output_chans_choice); remember_pref(prf, reflect_default_output_chans, save_default_output_chans, help_default_output_chans, NULL, revert_default_output_chans); reflect_default_output_chans(prf); rts_default_output_srate = default_output_srate(ss); prf = prefs_row_with_radio_box("srate", S_default_output_srate, output_srate_choices, NUM_OUTPUT_SRATE_CHOICES, -1, dpy_box, prf->label, default_output_srate_choice); remember_pref(prf, reflect_default_output_srate, save_default_output_srate, help_default_output_srate, NULL, revert_default_output_srate); reflect_default_output_srate(prf); rts_default_output_header_type = default_output_header_type(ss); prf = prefs_row_with_radio_box("header type", S_default_output_header_type, output_header_type_choices, NUM_OUTPUT_HEADER_TYPE_CHOICES, -1, dpy_box, prf->label, default_output_header_type_choice); output_header_type_prf = prf; remember_pref(prf, reflect_default_output_header_type, save_default_output_header_type, help_default_output_header_type, NULL, revert_default_output_header_type); rts_default_output_sample_type = default_output_sample_type(ss); prf = prefs_row_with_radio_box("sample type", S_default_output_sample_type, output_sample_type_choices, NUM_OUTPUT_SAMPLE_TYPE_CHOICES, -1, dpy_box, prf->label, default_output_sample_type_choice); output_sample_type_prf = prf; remember_pref(prf, reflect_default_output_sample_type, save_default_output_sample_type, help_default_output_sample_type, NULL, revert_default_output_sample_type); reflect_default_output_header_type(output_header_type_prf); reflect_default_output_sample_type(output_sample_type_prf); current_sep = make_inter_variable_separator(dpy_box, prf->label); { int i, srate = 0, chans = 0; mus_sample_t sample_type = MUS_UNKNOWN_SAMPLE; mus_header_raw_defaults(&srate, &chans, &sample_type); rts_raw_chans = chans; rts_raw_srate = srate; rts_raw_sample_type = sample_type; str = mus_format("%d", chans); str1 = mus_format("%d", srate); raw_sample_type_choices = (char **)calloc(MUS_NUM_SAMPLES - 1, sizeof(char *)); for (i = 1; i < MUS_NUM_SAMPLES; i++) raw_sample_type_choices[i - 1] = raw_sample_type_to_string((mus_sample_t)i); /* skip MUS_UNKNOWN_SAMPLE = 0 */ prf = prefs_row_with_text("default raw sound attributes: chans", S_mus_header_raw_defaults, str, dpy_box, current_sep, raw_chans_choice); remember_pref(prf, reflect_raw_chans, save_raw_chans, help_raw_chans, NULL, revert_raw_chans); prf = prefs_row_with_text("srate", S_mus_header_raw_defaults, str1, dpy_box, prf->label, raw_srate_choice); remember_pref(prf, reflect_raw_srate, save_raw_srate, help_raw_srate, NULL, revert_raw_srate); prf = prefs_row_with_list("sample type", S_mus_header_raw_defaults, raw_sample_type_choices[sample_type - 1], (const char **)raw_sample_type_choices, MUS_NUM_SAMPLES - 1, dpy_box, prf->label, raw_sample_type_from_text, NULL, NULL, raw_sample_type_from_menu); remember_pref(prf, reflect_raw_sample_type, save_raw_sample_type, help_raw_sample_type, NULL, revert_raw_sample_type); free(str); free(str1); } /* ---------------- additional keys ---------------- */ current_sep = make_inter_variable_separator(dpy_box, prf->label); key_label = make_inner_label(" additional keys", dpy_box, current_sep); { key_info *ki; ki = find_prefs_key("play-from-cursor"); prf = prefs_row_with_text_and_three_toggles("play all chans from cursor", S_play, "key:", 8, "ctrl:", "meta:", "C-x:", ki->key, ki->c, ki->m, ki->x, dpy_box, key_label, bind_play_from_cursor); remember_pref(prf, reflect_play_from_cursor, save_pfc, help_play_from_cursor, clear_play_from_cursor, NULL); free(ki); current_sep = make_inter_variable_separator(dpy_box, prf->label); ki = find_prefs_key("show-all"); prf = prefs_row_with_text_and_three_toggles("show entire sound", S_x_bounds, "key:", 8, "ctrl:", "meta:", "C-x:", ki->key, ki->c, ki->m, ki->x, dpy_box, current_sep, bind_show_all); remember_pref(prf, reflect_show_all, save_show_all, help_show_all, clear_show_all, NULL); free(ki); current_sep = make_inter_variable_separator(dpy_box, prf->label); ki = find_prefs_key("select-all"); prf = prefs_row_with_text_and_three_toggles("select entire sound", S_select_all, "key:", 8, "ctrl:", "meta:", "C-x:", ki->key, ki->c, ki->m, ki->x, dpy_box, current_sep, bind_select_all); remember_pref(prf, reflect_select_all, save_select_all, help_select_all, clear_select_all, NULL); free(ki); current_sep = make_inter_variable_separator(dpy_box, prf->label); ki = find_prefs_key("show-selection"); prf = prefs_row_with_text_and_three_toggles("show current selection", "show-selection", "key:", 8, "ctrl:", "meta:", "C-x:", ki->key, ki->c, ki->m, ki->x, dpy_box, current_sep, bind_show_selection); remember_pref(prf, reflect_show_selection, save_show_selection, help_show_selection, clear_show_selection, NULL); free(ki); current_sep = make_inter_variable_separator(dpy_box, prf->label); ki = find_prefs_key("revert-sound"); prf = prefs_row_with_text_and_three_toggles("undo all edits (revert)", S_revert_sound, "key:", 8, "ctrl:", "meta:", "C-x:", ki->key, ki->c, ki->m, ki->x, dpy_box, current_sep, bind_revert); remember_pref(prf, reflect_revert, save_revert, help_revert, clear_revert_sound, NULL); free(ki); current_sep = make_inter_variable_separator(dpy_box, prf->label); ki = find_prefs_key("exit"); prf = prefs_row_with_text_and_three_toggles("exit from Snd", S_exit, "key:", 8, "ctrl:", "meta:", "C-x:", ki->key, ki->c, ki->m, ki->x, dpy_box, current_sep, bind_exit); remember_pref(prf, reflect_exit, save_exit, help_exit, clear_exit, NULL); free(ki); current_sep = make_inter_variable_separator(dpy_box, prf->label); ki = find_prefs_key("goto-maxamp"); prf = prefs_row_with_text_and_three_toggles("move cursor to channel's maximum sample", S_maxamp_position, "key:", 8, "ctrl:", "meta:", "C-x:", ki->key, ki->c, ki->m, ki->x, dpy_box, current_sep, bind_goto_maxamp); remember_pref(prf, reflect_goto_maxamp, save_goto_maxamp, help_goto_maxamp, clear_goto_maxamp, NULL); free(ki); } /* ---------------- cursor options ---------------- */ current_sep = make_inter_variable_separator(dpy_box, prf->label); cursor_label = make_inner_label(" cursor options", dpy_box, current_sep); prf = prefs_row_with_toggle("report cursor location as it moves", S_with_verbose_cursor, rts_with_verbose_cursor = with_verbose_cursor(ss), dpy_box, cursor_label, with_verbose_cursor_toggle); remember_pref(prf, reflect_with_verbose_cursor, save_with_verbose_cursor, help_with_verbose_cursor, NULL, revert_with_verbose_cursor); current_sep = make_inter_variable_separator(dpy_box, prf->label); { char *str1; str = mus_format("%.2f", rts_cursor_update_interval = cursor_update_interval(ss)); str1 = mus_format("%d", rts_cursor_location_offset = cursor_location_offset(ss)); prf = prefs_row_with_toggle_with_two_texts("track current location while playing", S_with_tracking_cursor, (rts_with_tracking_cursor = with_tracking_cursor(ss)), "update:", str, "offset:", str1, 8, dpy_box, current_sep, with_tracking_cursor_toggle, cursor_location_text); remember_pref(prf, reflect_with_tracking_cursor, save_with_tracking_cursor, help_with_tracking_cursor, NULL, revert_with_tracking_cursor); free(str); free(str1); } current_sep = make_inter_variable_separator(dpy_box, prf->label); str = mus_format("%d", rts_cursor_size = cursor_size(ss)); prf = prefs_row_with_number("size", S_cursor_size, str, 4, dpy_box, current_sep, cursor_size_up, cursor_size_down, cursor_size_from_text); remember_pref(prf, reflect_cursor_size, save_cursor_size, help_cursor_size, NULL, revert_cursor_size); free(str); if (cursor_size(ss) <= 0) XtSetSensitive(prf->arrow_down, false); current_sep = make_inter_variable_separator(dpy_box, prf->label); prf = prefs_row_with_radio_box("shape", S_cursor_style, cursor_styles, NUM_CURSOR_STYLES, rts_cursor_style = cursor_style(ss), dpy_box, current_sep, cursor_style_choice); remember_pref(prf, reflect_cursor_style, save_cursor_style, help_cursor_style, NULL, revert_cursor_style); current_sep = make_inter_variable_separator(dpy_box, prf->label); prf = prefs_row_with_radio_box("tracking cursor shape", S_tracking_cursor_style, cursor_styles, NUM_CURSOR_STYLES, rts_tracking_cursor_style = tracking_cursor_style(ss), dpy_box, current_sep, tracking_cursor_style_choice); remember_pref(prf, reflect_tracking_cursor_style, save_tracking_cursor_style, help_tracking_cursor_style, NULL, revert_tracking_cursor_style); current_sep = make_inter_variable_separator(dpy_box, prf->label); saved_cursor_color = ss->cursor_color; prf = prefs_color_selector_row("color", S_cursor_color, ss->cursor_color, dpy_box, current_sep, cursor_color_func); remember_pref(prf, NULL, save_cursor_color, help_cursor_color, clear_cursor_color, revert_cursor_color); /* ---------------- (overall) colors ---------------- */ current_sep = make_inter_variable_separator(dpy_box, prf->rscl); cursor_label = make_inner_label(" colors", dpy_box, current_sep); saved_basic_color = ss->basic_color; prf = prefs_color_selector_row("main background color", S_basic_color, ss->basic_color, dpy_box, cursor_label, basic_color_func); remember_pref(prf, NULL, save_basic_color, help_basic_color, clear_basic_color, revert_basic_color); current_sep = make_inter_variable_separator(dpy_box, prf->rscl); saved_highlight_color = ss->highlight_color; prf = prefs_color_selector_row("main highlight color", S_highlight_color, ss->highlight_color, dpy_box, current_sep, highlight_color_func); remember_pref(prf, NULL, save_highlight_color, help_highlight_color, clear_highlight_color, revert_highlight_color); current_sep = make_inter_variable_separator(dpy_box, prf->rscl); saved_position_color = ss->position_color; prf = prefs_color_selector_row("second highlight color", S_position_color, ss->position_color, dpy_box, current_sep, position_color_func); remember_pref(prf, NULL, save_position_color, help_position_color, clear_position_color, revert_position_color); current_sep = make_inter_variable_separator(dpy_box, prf->rscl); saved_zoom_color = ss->zoom_color; prf = prefs_color_selector_row("third highlight color", S_zoom_color, ss->zoom_color, dpy_box, current_sep, zoom_color_func); remember_pref(prf, NULL, save_zoom_color, help_zoom_color, clear_zoom_color, revert_zoom_color); } current_sep = make_inter_topic_separator(topics); /* -------- graphs -------- */ { Widget grf_box, grf_label, colgrf_label; /* ---------------- graph options ---------------- */ grf_box = make_top_level_box(topics); grf_label = make_top_level_label("graph options", grf_box); prf = prefs_row_with_radio_box("how to connect the dots", S_graph_style, graph_styles, NUM_GRAPH_STYLES, rts_graph_style = graph_style(ss), grf_box, grf_label, graph_style_choice); remember_pref(prf, reflect_graph_style, save_graph_style, help_graph_style, NULL, revert_graph_style); current_sep = make_inter_variable_separator(grf_box, prf->label); str = mus_format("%d", rts_dot_size = dot_size(ss)); prf = prefs_row_with_number("dot size", S_dot_size, str, 4, grf_box, current_sep, dot_size_up, dot_size_down, dot_size_from_text); remember_pref(prf, reflect_dot_size, save_dot_size, help_dot_size, NULL, revert_dot_size); free(str); if (dot_size(ss) <= 0) XtSetSensitive(prf->arrow_down, false); current_sep = make_inter_variable_separator(grf_box, prf->label); rts_initial_beg = initial_beg(ss); rts_initial_dur = initial_dur(ss); str = mus_format("%.2f : %.2f", rts_initial_beg, rts_initial_dur); prf = prefs_row_with_text_with_toggle("initial graph x bounds", S_initial_graph_hook, (rts_full_duration = show_full_duration(ss)), "show full duration", str, 16, grf_box, current_sep, initial_bounds_toggle, initial_bounds_text); free(str); remember_pref(prf, reflect_initial_bounds, save_initial_bounds, help_initial_bounds, clear_initial_bounds, revert_initial_bounds); current_sep = make_inter_variable_separator(grf_box, prf->label); prf = prefs_row_with_radio_box("how to layout multichannel graphs", S_channel_style, channel_styles, NUM_CHANNEL_STYLES, rts_channel_style = channel_style(ss), grf_box, current_sep, channel_style_choice); remember_pref(prf, reflect_channel_style, save_channel_style, help_channel_style, NULL, revert_channel_style); current_sep = make_inter_variable_separator(grf_box, prf->label); prf = prefs_row_with_toggle("layout wave and fft graphs horizontally", S_graphs_horizontal, rts_graphs_horizontal = graphs_horizontal(ss), grf_box, current_sep, graphs_horizontal_toggle); remember_pref(prf, reflect_graphs_horizontal, save_graphs_horizontal, help_graphs_horizontal, NULL, revert_graphs_horizontal); current_sep = make_inter_variable_separator(grf_box, prf->label); prf = prefs_row_with_toggle("include y=0 line in sound graphs", S_show_y_zero, rts_show_y_zero = show_y_zero(ss), grf_box, current_sep, y_zero_toggle); remember_pref(prf, reflect_show_y_zero, save_show_y_zero, help_show_y_zero, NULL, revert_show_y_zero); current_sep = make_inter_variable_separator(grf_box, prf->label); rts_show_grid = show_grid(ss); prf = prefs_row_with_toggle("include a grid in sound graphs", S_show_grid, rts_show_grid == WITH_GRID, grf_box, current_sep, grid_toggle); remember_pref(prf, reflect_show_grid, save_show_grid, help_show_grid, NULL, revert_show_grid); current_sep = make_inter_variable_separator(grf_box, prf->label); prf = prefs_row_with_scale("grid density", S_grid_density, 2.0, rts_grid_density = grid_density(ss), grf_box, current_sep, grid_density_scale_callback, grid_density_text_callback); remember_pref(prf, reflect_grid_density, save_grid_density, help_grid_density, NULL, revert_grid_density); current_sep = make_inter_variable_separator(grf_box, prf->label); rts_show_axes = show_axes(ss); prf = prefs_row_with_list("what axes to display", S_show_axes, show_axes_choices[(int)rts_show_axes], show_axes_choices, NUM_SHOW_AXES, grf_box, current_sep, show_axes_from_text, NULL, NULL, show_axes_from_menu); remember_pref(prf, reflect_show_axes, save_show_axes, help_show_axes, clear_show_axes, revert_show_axes); current_sep = make_inter_variable_separator(grf_box, prf->label); rts_x_axis_style = x_axis_style(ss); prf = prefs_row_with_list("time division", S_x_axis_style, x_axis_styles[(int)rts_x_axis_style], x_axis_styles, NUM_X_AXIS_STYLES, grf_box, current_sep, x_axis_style_from_text, NULL, NULL, x_axis_style_from_menu); remember_pref(prf, reflect_x_axis_style, save_x_axis_style, help_x_axis_style, clear_x_axis_style, revert_x_axis_style); current_sep = make_inter_variable_separator(grf_box, prf->label); prf = prefs_row_with_toggle("include smpte info", "show-smpte-label", rts_with_smpte_label = with_smpte_label(ss), grf_box, current_sep, smpte_toggle); remember_pref(prf, reflect_smpte, save_smpte, help_smpte, clear_smpte, revert_smpte); /* ---------------- (graph) colors ---------------- */ current_sep = make_inter_variable_separator(grf_box, prf->label); colgrf_label = make_inner_label(" colors", grf_box, current_sep); saved_data_color = ss->data_color; prf = prefs_color_selector_row("unselected data (waveform) color", S_data_color, ss->data_color, grf_box, colgrf_label, data_color_func); remember_pref(prf, NULL, save_data_color, help_data_color, clear_data_color, revert_data_color); current_sep = make_inter_variable_separator(grf_box, prf->rscl); saved_graph_color = ss->graph_color; prf = prefs_color_selector_row("unselected graph (background) color", S_graph_color, ss->graph_color, grf_box, current_sep, graph_color_func); remember_pref(prf, NULL, save_graph_color, help_graph_color, clear_graph_color, revert_graph_color); current_sep = make_inter_variable_separator(grf_box, prf->rscl); saved_selected_data_color = ss->selected_data_color; prf = prefs_color_selector_row("selected channel data (waveform) color", S_selected_data_color, ss->selected_data_color, grf_box, current_sep, selected_data_color_func); remember_pref(prf, NULL, save_selected_data_color, help_selected_data_color, clear_selected_data_color, revert_selected_data_color); current_sep = make_inter_variable_separator(grf_box, prf->rscl); saved_selected_graph_color = ss->selected_graph_color; prf = prefs_color_selector_row("selected channel graph (background) color", S_selected_graph_color, ss->selected_graph_color, grf_box, current_sep, selected_graph_color_func); remember_pref(prf, NULL, save_selected_graph_color, help_selected_graph_color, clear_selected_graph_color, revert_selected_graph_color); current_sep = make_inter_variable_separator(grf_box, prf->rscl); saved_selection_color = ss->selection_color; prf = prefs_color_selector_row("selection color", S_selection_color, ss->selection_color, grf_box, current_sep, selection_color_func); remember_pref(prf, NULL, save_selection_color, help_selection_color, clear_selection_color, revert_selection_color); /* ---------------- (graph) fonts ---------------- */ current_sep = make_inter_variable_separator(grf_box, prf->rscl); colgrf_label = make_inner_label(" fonts", grf_box, current_sep); rts_axis_label_font = mus_strdup(axis_label_font(ss)); prf = prefs_row_with_text("axis label font", S_axis_label_font, axis_label_font(ss), grf_box, colgrf_label, axis_label_font_text); remember_pref(prf, reflect_axis_label_font, save_axis_label_font, help_axis_label_font, clear_axis_label_font, revert_axis_label_font); current_sep = make_inter_variable_separator(grf_box, prf->label); rts_axis_numbers_font = mus_strdup(axis_numbers_font(ss)); prf = prefs_row_with_text("axis number font", S_axis_numbers_font, axis_numbers_font(ss), grf_box, current_sep, axis_numbers_font_text); remember_pref(prf, reflect_axis_numbers_font, save_axis_numbers_font, help_axis_numbers_font, clear_axis_numbers_font, revert_axis_numbers_font); current_sep = make_inter_variable_separator(grf_box, prf->label); rts_peaks_font = mus_strdup(peaks_font(ss)); prf = prefs_row_with_text("fft peaks font", S_peaks_font, peaks_font(ss), grf_box, current_sep, peaks_font_text); remember_pref(prf, reflect_peaks_font, save_peaks_font, help_peaks_font, clear_peaks_font, revert_peaks_font); current_sep = make_inter_variable_separator(grf_box, prf->label); rts_bold_peaks_font = mus_strdup(bold_peaks_font(ss)); prf = prefs_row_with_text("fft peaks bold font (for main peaks)", S_bold_peaks_font, bold_peaks_font(ss), grf_box, current_sep, bold_peaks_font_text); remember_pref(prf, reflect_bold_peaks_font, save_bold_peaks_font, help_bold_peaks_font, clear_bold_peaks_font, revert_bold_peaks_font); current_sep = make_inter_variable_separator(grf_box, prf->label); rts_tiny_font = mus_strdup(tiny_font(ss)); prf = prefs_row_with_text("tiny font (for various annotations)", S_peaks_font, tiny_font(ss), grf_box, current_sep, tiny_font_text); remember_pref(prf, reflect_tiny_font, save_tiny_font, help_tiny_font, clear_tiny_font, revert_tiny_font); } current_sep = make_inter_topic_separator(topics); /* -------- transform -------- */ { Widget fft_box, fft_label; /* ---------------- transform options ---------------- */ fft_box = make_top_level_box(topics); fft_label = make_top_level_label("transform options", fft_box); rts_fft_size = transform_size(ss); str = mus_format("%" print_mus_long, rts_fft_size); prf = prefs_row_with_number("size", S_transform_size, str, 12, fft_box, fft_label, fft_size_up, fft_size_down, fft_size_from_text); remember_pref(prf, reflect_fft_size, save_fft_size, help_fft_size, NULL, revert_fft_size); free(str); if (transform_size(ss) <= 2) XtSetSensitive(prf->arrow_down, false); current_sep = make_inter_variable_separator(fft_box, prf->label); prf = prefs_row_with_radio_box("transform graph choice", S_transform_graph_type, transform_graph_types, NUM_TRANSFORM_GRAPH_TYPES, rts_transform_graph_type = transform_graph_type(ss), fft_box, current_sep, transform_graph_type_choice); remember_pref(prf, reflect_transform_graph_type, save_transform_graph_type, help_transform_graph_type, NULL, revert_transform_graph_type); current_sep = make_inter_variable_separator(fft_box, prf->label); rts_transform_type = transform_type(ss); prf = prefs_row_with_list("transform", S_transform_type, transform_types[rts_transform_type], transform_types, NUM_BUILTIN_TRANSFORM_TYPES, fft_box, current_sep, transform_type_from_text, transform_type_completer, NULL, transform_type_from_menu); remember_pref(prf, reflect_transform_type, save_transform_type, help_transform_type, clear_transform_type, revert_transform_type); current_sep = make_inter_variable_separator(fft_box, prf->label); rts_fft_window = fft_window(ss); prf = prefs_row_with_list("data window", S_fft_window, mus_fft_window_name(rts_fft_window), mus_fft_window_names(), MUS_NUM_FFT_WINDOWS, fft_box, current_sep, fft_window_from_text, fft_window_completer, NULL, fft_window_from_menu); remember_pref(prf, reflect_fft_window, save_fft_window, help_fft_window, clear_fft_window, revert_fft_window); current_sep = make_inter_variable_separator(fft_box, prf->label); prf = prefs_row_with_scale("data window family parameter", S_fft_window_beta, 1.0, rts_fft_window_beta = fft_window_beta(ss), fft_box, current_sep, fft_window_beta_scale_callback, fft_window_beta_text_callback); remember_pref(prf, reflect_fft_window_beta, save_fft_window_beta, help_fft_window_beta, NULL, revert_fft_window_beta); current_sep = make_inter_variable_separator(fft_box, prf->label); str = mus_format("%d", rts_max_transform_peaks = max_transform_peaks(ss)); prf = prefs_row_with_toggle_with_text("show fft peak data", S_show_transform_peaks, rts_show_transform_peaks = show_transform_peaks(ss), "max peaks:", str, 5, fft_box, current_sep, transform_peaks_toggle, max_peaks_text); remember_pref(prf, reflect_transform_peaks, save_transform_peaks, help_transform_peaks, NULL, revert_transform_peaks); free(str); current_sep = make_inter_variable_separator(fft_box, prf->label); { const char **cmaps; int i, len; len = num_colormaps(); cmaps = (const char **)calloc(len, sizeof(const char *)); for (i = 0; i < len; i++) cmaps[i] = (const char *)colormap_name(i); rts_colormap = color_map(ss); prf = prefs_row_with_list("sonogram colormap", S_colormap, cmaps[rts_colormap], cmaps, len, fft_box, current_sep, colormap_from_text, colormap_completer, NULL, colormap_from_menu); remember_pref(prf, reflect_colormap, save_colormap, help_colormap, clear_colormap, revert_colormap); free(cmaps); } current_sep = make_inter_variable_separator(fft_box, prf->label); prf = prefs_row_with_toggle("y axis as log magnitude (dB)", S_fft_log_magnitude, rts_fft_log_magnitude = fft_log_magnitude(ss), fft_box, current_sep, log_magnitude_toggle); remember_pref(prf, reflect_fft_log_magnitude, save_fft_log_magnitude, help_fft_log_magnitude, NULL, revert_fft_log_magnitude); current_sep = make_inter_variable_separator(fft_box, prf->label); str = mus_format("%.1f", rts_min_dB = min_dB(ss)); prf = prefs_row_with_text("minimum y-axis dB value", S_min_dB, str, fft_box, current_sep, min_dB_text); remember_pref(prf, reflect_min_dB, save_min_dB, help_min_dB, NULL, revert_min_dB); free(str); current_sep = make_inter_variable_separator(fft_box, prf->label); prf = prefs_row_with_toggle("x axis as log freq", S_fft_log_frequency, rts_fft_log_frequency = fft_log_frequency(ss), fft_box, current_sep, log_frequency_toggle); remember_pref(prf, reflect_fft_log_frequency, save_fft_log_frequency, help_fft_log_frequency, NULL, revert_fft_log_frequency); current_sep = make_inter_variable_separator(fft_box, prf->label); prf = prefs_row_with_radio_box("normalization", S_transform_normalization, transform_normalizations, NUM_TRANSFORM_NORMALIZATIONS, rts_transform_normalization = transform_normalization(ss), fft_box, current_sep, transform_normalization_choice); remember_pref(prf, reflect_transform_normalization, save_transform_normalization, help_transform_normalization, NULL, revert_transform_normalization); } current_sep = make_inter_topic_separator(topics); /* -------- marks, mixes, and regions -------- */ { Widget mmr_box, mmr_label; char *str1, *str2; /* ---------------- marks and mixes ---------------- */ mmr_box = make_top_level_box(topics); mmr_label = make_top_level_label("marks and mixes", mmr_box); saved_mark_color = ss->mark_color; prf = prefs_color_selector_row("mark and mix tag color", S_mark_color, ss->mark_color, mmr_box, mmr_label, mark_color_func); remember_pref(prf, NULL, save_mark_color, help_mark_color, clear_mark_color, revert_mark_color); current_sep = make_inter_variable_separator(mmr_box, prf->rscl); str1 = mus_format("%d", rts_mark_tag_width = mark_tag_width(ss)); str2 = mus_format("%d", rts_mark_tag_height = mark_tag_height(ss)); prf = prefs_row_with_two_texts("mark tag size", S_mark_tag_width, "width:", str1, "height:", str2, 4, mmr_box, current_sep, mark_tag_size_text); remember_pref(prf, reflect_mark_tag_size, save_mark_tag_size, help_mark_tag_size, NULL, revert_mark_tag_size); free(str2); free(str1); current_sep = make_inter_variable_separator(mmr_box, prf->label); str1 = mus_format("%d", rts_mix_tag_width = mix_tag_width(ss)); str2 = mus_format("%d", rts_mix_tag_height = mix_tag_height(ss)); prf = prefs_row_with_two_texts("mix tag size", S_mix_tag_width, "width:", str1, "height:", str2, 4, mmr_box, current_sep, mix_tag_size_text); remember_pref(prf, reflect_mix_tag_size, save_mix_tag_size, help_mix_tag_size, NULL, revert_mix_tag_size); free(str2); free(str1); current_sep = make_inter_variable_separator(mmr_box, prf->label); saved_mix_color = ss->mix_color; prf = prefs_color_selector_row("mix waveform color", S_mix_color, ss->mix_color, mmr_box, current_sep, mix_color_func); remember_pref(prf, NULL, save_mix_color, help_mix_color, clear_mix_color, revert_mix_color); current_sep = make_inter_variable_separator(mmr_box, prf->rscl); str = mus_format("%d", rts_mix_waveform_height = mix_waveform_height(ss)); prf = prefs_row_with_toggle_with_text("show mix waveforms (attached to the mix tag)", S_show_mix_waveforms, rts_show_mix_waveforms = show_mix_waveforms(ss), "max waveform height:", str, 5, mmr_box, current_sep, show_mix_waveforms_toggle, mix_waveform_height_text); remember_pref(prf, reflect_mix_waveforms, save_mix_waveforms, help_mix_waveforms, NULL, revert_mix_waveforms); free(str); } current_sep = make_inter_topic_separator(topics); /* -------- clm -------- */ { Widget clm_box, clm_label; /* ---------------- clm options ---------------- */ clm_box = make_top_level_box(topics); clm_label = make_top_level_label("clm", clm_box); rts_speed_control_style = speed_control_style(ss); str = mus_format("%d", rts_speed_control_tones = speed_control_tones(ss)); prf = prefs_row_with_radio_box_and_number("speed control choice", S_speed_control_style, speed_control_styles, NUM_SPEED_CONTROL_STYLES, (int)speed_control_style(ss), str, 6, clm_box, clm_label, speed_control_choice, speed_control_up, speed_control_down, speed_control_text); XtSetSensitive(prf->arrow_down, (speed_control_tones(ss) > MIN_SPEED_CONTROL_SEMITONES)); remember_pref(prf, reflect_speed_control, save_speed_control, help_speed_control, NULL, revert_speed_control); free(str); current_sep = make_inter_variable_separator(clm_box, prf->label); str = mus_format("%d", rts_sinc_width = sinc_width(ss)); prf = prefs_row_with_text("sinc interpolation width in srate converter", S_sinc_width, str, clm_box, current_sep, sinc_width_text); remember_pref(prf, reflect_sinc_width, save_sinc_width, help_sinc_width, NULL, revert_sinc_width); free(str); } current_sep = make_inter_topic_separator(topics); /* -------- programming -------- */ { Widget prg_box, prg_label; /* ---------------- listener options ---------------- */ prg_box = make_top_level_box(topics); prg_label = make_top_level_label("listener options", prg_box); prf = prefs_row_with_toggle("show listener at start up", S_show_listener, rts_show_listener = listener_is_visible(), prg_box, prg_label, show_listener_toggle); remember_pref(prf, reflect_show_listener, save_show_listener, help_show_listener, clear_show_listener, revert_show_listener); current_sep = make_inter_variable_separator(prg_box, prf->label); rts_listener_prompt = mus_strdup(listener_prompt(ss)); prf = prefs_row_with_text("prompt", S_listener_prompt, listener_prompt(ss), prg_box, current_sep, listener_prompt_text); remember_pref(prf, reflect_listener_prompt, save_listener_prompt, help_listener_prompt, NULL, revert_listener_prompt); current_sep = make_inter_variable_separator(prg_box, prf->label); str = mus_format("%d", rts_print_length = print_length(ss)); prf = prefs_row_with_text("number of vector elements to display", S_print_length, str, prg_box, current_sep, print_length_text); remember_pref(prf, reflect_print_length, save_print_length, help_print_length, NULL, revert_print_length); free(str); current_sep = make_inter_variable_separator(prg_box, prf->label); rts_listener_font = mus_strdup(listener_font(ss)); prf = prefs_row_with_text("font", S_listener_font, listener_font(ss), prg_box, current_sep, listener_font_text); remember_pref(prf, reflect_listener_font, save_listener_font, help_listener_font, clear_listener_font, revert_listener_font); current_sep = make_inter_variable_separator(prg_box, prf->label); saved_listener_color = ss->listener_color; prf = prefs_color_selector_row("background color", S_listener_color, ss->listener_color, prg_box, current_sep, listener_color_func); remember_pref(prf, NULL, save_listener_color, help_listener_color, clear_listener_color, revert_listener_color); current_sep = make_inter_variable_separator(prg_box, prf->rscl); saved_listener_text_color = ss->listener_text_color; prf = prefs_color_selector_row("text color", S_listener_text_color, ss->listener_text_color, prg_box, current_sep, listener_text_color_func); remember_pref(prf, NULL, save_listener_text_color, help_listener_text_color, clear_listener_text_color, revert_listener_text_color); } current_sep = make_inter_topic_separator(topics); /* -------- audio -------- */ { Widget aud_box, aud_label; /* ---------------- audio options ---------------- */ aud_box = make_top_level_box(topics); aud_label = make_top_level_label("audio options", aud_box); str = mus_format("%d", rts_dac_size = dac_size(ss)); prf = prefs_row_with_text("dac buffer size", S_dac_size, str, aud_box, aud_label, dac_size_text); remember_pref(prf, reflect_dac_size, save_dac_size, help_dac_size, NULL, revert_dac_size); free(str); current_sep = make_inter_variable_separator(aud_box, prf->label); prf = prefs_row_with_toggle("fold in otherwise unplayable channels", S_dac_combines_channels, rts_dac_combines_channels = dac_combines_channels(ss), aud_box, current_sep, dac_combines_channels_toggle); remember_pref(prf, reflect_dac_combines_channels, save_dac_combines_channels, help_dac_combines_channels, NULL, revert_dac_combines_channels); } { Atom wm_delete_window; wm_delete_window = XmInternAtom(main_display(ss), (char *)"WM_DELETE_WINDOW", false); XmAddWMProtocolCallback(XtParent(preferences_dialog), wm_delete_window, wm_delete_callback, NULL); } XtManageChild(preferences_dialog); set_dialog_widget(PREFERENCES_DIALOG, preferences_dialog); return(preferences_dialog); } #include "snd-menu.h" #include /* X side of file print */ static Widget print_dialog = NULL; static Widget print_name = NULL; static Widget print_eps_or_lpr = NULL; static char print_string[PRINT_BUFFER_SIZE]; static Widget error_info_box, error_info_frame, error_info; static void print_help_callback(Widget w, XtPointer context, XtPointer info) { print_dialog_help(); } static void clear_print_error(void); static void print_cancel_callback(Widget w, XtPointer context, XtPointer info) { if (XmGetFocusWidget(print_dialog) == XmMessageBoxGetChild(print_dialog, XmDIALOG_CANCEL_BUTTON)) { ss->print_choice = PRINT_SND; clear_print_error(); XtUnmanageChild(print_dialog); } /* else it's the from the text widget probably */ } static int lpr(char *name) { /* make some desultory effort to print the file */ snprintf(print_string, PRINT_BUFFER_SIZE, "lpr %s", name); return(system(print_string)); } static void watch_print(Widget w, XtPointer context, XtPointer info) { clear_print_error(); } static Widget rc; static bool print_watching = false, print_error = false; static void clear_print_error(void) { XtUnmanageChild(rc); XtUnmanageChild(error_info_box); XtVaSetValues(print_eps_or_lpr, XmNbottomAttachment, XmATTACH_FORM, NULL); XtManageChild(rc); print_error = false; if (print_watching) { print_watching = false; XtRemoveCallback(print_name, XmNvalueChangedCallback, watch_print, NULL); XtRemoveCallback(print_eps_or_lpr, XmNvalueChangedCallback, watch_print, NULL); } } static void report_in_error_info(const char *msg, void *ignore) { XmString s1; if ((!msg) || (!(*msg))) return; print_error = true; s1 = XmStringCreateLocalized((char *)msg); XtVaSetValues(error_info, XmNlabelString, s1, NULL); if (!(XtIsManaged(error_info_box))) { Dimension text_wid = 0, dialog_wid = 0; XmFontList fonts; XtVaGetValues(error_info, XmNfontList, &fonts, NULL); XtVaGetValues(print_dialog, XmNwidth, &dialog_wid, NULL); text_wid = XmStringWidth(fonts, s1); XtUnmanageChild(rc); XtVaSetValues(print_eps_or_lpr, XmNbottomAttachment, XmATTACH_NONE, NULL); if (text_wid > dialog_wid) { XtUnmanageChild(print_dialog); XtVaSetValues(print_dialog, XmNwidth, text_wid + 40, NULL); XtManageChild(print_dialog); } XtManageChild(error_info_box); XtManageChild(rc); print_watching = true; XtAddCallback(print_name, XmNvalueChangedCallback, watch_print, NULL); XtAddCallback(print_eps_or_lpr, XmNvalueChangedCallback, watch_print, NULL); } XmStringFree(s1); } static printing_t printing = NOT_PRINTING; static void print_ok_callback(Widget w, XtPointer context, XtPointer info) { bool quit = false; XmString plab, slab; snd_info *nsp = NULL; if (printing) ss->stopped_explicitly = true; else { bool print_it; clear_print_error(); if (ss->print_choice == PRINT_SND) { plab = XmStringCreateLocalized((char *)I_STOP); nsp = any_selected_sound(); snprintf(print_string, PRINT_BUFFER_SIZE, "printing %s", nsp->short_filename); slab = XmStringCreateLocalized(print_string); XtVaSetValues(print_dialog, XmNokLabelString, plab, XmNmessageString, slab, NULL); XmStringFree(plab); XmStringFree(slab); } printing = PRINTING; print_it = (bool)XmToggleButtonGetState(print_eps_or_lpr); quit = (ss->print_choice == PRINT_ENV); if (print_it) { char *name; name = snd_tempnam(); redirect_snd_error_to(report_in_error_info, NULL); switch (ss->print_choice) { case PRINT_SND: snd_print(name); break; case PRINT_ENV: enved_print(name); break; } redirect_snd_error_to(NULL, NULL); if (!print_error) { int err; err = lpr(name); /* lpr apparently insists on printing to stderr? */ if (err != 0) report_in_error_info("can't print!", NULL); snd_remove(name, IGNORE_CACHE); } free(name); } else { char *str = NULL; redirect_snd_error_to(report_in_error_info, NULL); str = XmTextGetString(print_name); switch (ss->print_choice) { case PRINT_SND: if (snd_print(str)) status_report(nsp, "printed current view to %s", str); break; case PRINT_ENV: enved_print(str); break; } redirect_snd_error_to(NULL, NULL); if (str) XtFree(str); } } printing = NOT_PRINTING; if (ss->print_choice == PRINT_SND) { plab = XmStringCreateLocalized((char *)"Print"); snprintf(print_string, PRINT_BUFFER_SIZE, "print %s", nsp->short_filename); slab = XmStringCreateLocalized(print_string); XtVaSetValues(print_dialog, XmNokLabelString, plab, XmNmessageString, slab, NULL); XmStringFree(plab); XmStringFree(slab); } ss->print_choice = PRINT_SND; if (quit) XtUnmanageChild(print_dialog); } static void start_print_dialog(XmString xmstr4, bool managed) { if (!print_dialog) { Widget dl; XmString xmstr1, xmstr2, xmstr3, titlestr; Arg args[20]; int n; n = 0; XtSetArg(args[n], XmNbackground, ss->basic_color); n++; xmstr1 = XmStringCreateLocalized((char *)"Print"); /* "ok" here is confusing -- might mean, ok I'm done */ xmstr2 = XmStringCreateLocalized((char *)I_HELP); xmstr3 = XmStringCreateLocalized((char *)I_GO_AWAY); titlestr = XmStringCreateLocalized((char *)"Print"); XtSetArg(args[n], XmNmessageString, xmstr4); n++; XtSetArg(args[n], XmNokLabelString, xmstr1); n++; XtSetArg(args[n], XmNhelpLabelString, xmstr2); n++; XtSetArg(args[n], XmNcancelLabelString, xmstr3); n++; XtSetArg(args[n], XmNautoUnmanage, false); n++; XtSetArg(args[n], XmNdialogTitle, titlestr); n++; XtSetArg(args[n], XmNresizePolicy, XmRESIZE_GROW); n++; XtSetArg(args[n], XmNallowResize, true); n++; XtSetArg(args[n], XmNnoResize, false); n++; XtSetArg(args[n], XmNtransient, false); n++; /* this gives us the resize handles */ print_dialog = XmCreateMessageDialog(main_pane(ss), (char *)"eps file:", args, n); XtVaSetValues(XmMessageBoxGetChild(print_dialog, XmDIALOG_MESSAGE_LABEL), XmNbackground, ss->basic_color, NULL); XmStringFree(xmstr1); XmStringFree(xmstr2); XmStringFree(xmstr3); XmStringFree(titlestr); XtUnmanageChild(XmMessageBoxGetChild(print_dialog, XmDIALOG_SYMBOL_LABEL)); XtAddCallback(print_dialog, XmNhelpCallback, print_help_callback, NULL); XtAddCallback(print_dialog, XmNcancelCallback, print_cancel_callback, NULL); XtAddCallback(print_dialog, XmNokCallback, print_ok_callback, NULL); n = 0; rc = XtCreateManagedWidget("form", xmFormWidgetClass, print_dialog, args, n); n = 0; XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_NONE); n++; dl = XtCreateManagedWidget("eps file:", xmLabelWidgetClass, rc, args, n); n = 0; XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNleftWidget, dl); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNvalue, eps_file(ss)); n++; print_name = make_textfield_widget("text", rc, args, n, ACTIVATABLE, NO_COMPLETER); n = 0; XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNtopWidget, print_name); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_NONE); n++; print_eps_or_lpr = make_togglebutton_widget("direct to printer", rc, args, n); /* error display */ n = 0; XtSetArg(args[n], XmNbackground, ss->highlight_color); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNtopWidget, print_eps_or_lpr); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNallowResize, true); n++; XtSetArg(args[n], XmNmargin, 0); n++; error_info_box = XtCreateWidget("error-box", xmRowColumnWidgetClass, rc, args, n); n = 0; XtSetArg(args[n], XmNbackground, ss->highlight_color); n++; XtSetArg(args[n], XmNmarginHeight, 4); n++; error_info_frame = XtCreateManagedWidget("error-frame", xmFrameWidgetClass, error_info_box, args, n); n = 0; XtSetArg(args[n], XmNbackground, ss->highlight_color); n++; XtSetArg(args[n], XmNalignment, XmALIGNMENT_BEGINNING); n++; error_info = XtCreateManagedWidget("error-info", xmLabelWidgetClass, error_info_frame, args, n); XtVaSetValues(print_eps_or_lpr, XmNbottomAttachment, XmATTACH_FORM, NULL); if (managed) XtManageChild(print_dialog); map_over_children(print_dialog, set_main_color_of_widget); XtVaSetValues(XmMessageBoxGetChild(print_dialog, XmDIALOG_OK_BUTTON), XmNarmColor, ss->selection_color, NULL); XtVaSetValues(XmMessageBoxGetChild(print_dialog, XmDIALOG_CANCEL_BUTTON), XmNarmColor, ss->selection_color, NULL); XtVaSetValues(XmMessageBoxGetChild(print_dialog, XmDIALOG_HELP_BUTTON), XmNarmColor, ss->selection_color, NULL); XtVaSetValues(XmMessageBoxGetChild(print_dialog, XmDIALOG_OK_BUTTON), XmNbackground, ss->highlight_color, NULL); XtVaSetValues(XmMessageBoxGetChild(print_dialog, XmDIALOG_CANCEL_BUTTON), XmNbackground, ss->highlight_color, NULL); XtVaSetValues(XmMessageBoxGetChild(print_dialog, XmDIALOG_HELP_BUTTON), XmNbackground, ss->highlight_color, NULL); XtVaSetValues(print_eps_or_lpr, XmNselectColor, ss->selection_color, NULL); set_dialog_widget(PRINT_DIALOG, print_dialog); } else { XtVaSetValues(print_dialog, XmNmessageString, xmstr4, NULL); if (managed) { if (!XtIsManaged(print_dialog)) XtManageChild(print_dialog); raise_dialog(print_dialog); /* a no-op unless already managed */ } } } widget_t make_file_print_dialog(bool managed, bool direct_to_printer) { XmString xmstr4; xmstr4 = XmStringCreateLocalized((char *)"print"); start_print_dialog(xmstr4, managed); XmStringFree(xmstr4); XmToggleButtonSetState(print_eps_or_lpr, direct_to_printer, false); return(print_dialog); } static void file_print_callback(Widget w, XtPointer context, XtPointer info) { XmString xmstr4; if (ss->print_choice == PRINT_SND) { snd_info *nsp; nsp = any_selected_sound(); if (!nsp) return; snprintf(print_string, PRINT_BUFFER_SIZE, "print %s", nsp->short_filename); xmstr4 = XmStringCreateLocalized(print_string); } else xmstr4 = XmStringCreateLocalized((char *)"print env"); start_print_dialog(xmstr4, true); XmStringFree(xmstr4); } void save_print_dialog_state(FILE *fd) { if ((print_dialog) && (XtIsManaged(print_dialog))) { #if HAVE_SCHEME fprintf(fd, "(%s #t %s)\n", S_print_dialog, ((bool)(XmToggleButtonGetState(print_eps_or_lpr))) ? "#t" : "#f"); #endif #if HAVE_RUBY fprintf(fd, "%s(true, %s)\n", to_proc_name(S_print_dialog), ((bool)(XmToggleButtonGetState(print_eps_or_lpr))) ? "true" : "false"); #endif #if HAVE_FORTH fprintf(fd, "#t %s %s drop\n", ((bool)(XmToggleButtonGetState(print_eps_or_lpr))) ? "#t" : "#f", S_print_dialog); #endif } } void set_menu_label(Widget w, const char *label) {if (w) set_button_label(w, label);} /* -------------------------------- FILE MENU -------------------------------- */ static Widget *recent_file_items = NULL; static int recent_file_items_size = 0; static void open_recent_file_callback(Widget w, XtPointer context, XtPointer info) { char *filename; snd_info *sp; filename = get_label(w); ss->open_requestor = FROM_OPEN_RECENT_MENU; ss->open_requestor_data = NULL; sp = snd_open_file(filename, FILE_READ_WRITE); if (sp) select_channel(sp, 0); } static void file_open_recent_callback(Widget w, XtPointer info, XtPointer context) { int size; size = recent_files_size(); if (size > 0) { int i; char **recent_file_names; if (size > recent_file_items_size) { if (recent_file_items_size == 0) recent_file_items = (Widget *)calloc(size, sizeof(Widget)); else { recent_file_items = (Widget *)realloc(recent_file_items, size * sizeof(Widget)); for (i = recent_file_items_size; i < size; i++) recent_file_items[i] = NULL; } recent_file_items_size = size; } recent_file_names = recent_files(); for (i = 0; i < size; i++) { if (!recent_file_items[i]) { int n = 0; Arg args[6]; XtSetArg(args[n], XmNbackground, ss->basic_color); n++; recent_file_items[i] = XtCreateManagedWidget(recent_file_names[i], xmPushButtonWidgetClass, file_open_recent_menu, args, n); XtAddCallback(recent_file_items[i], XmNactivateCallback, open_recent_file_callback, NULL); } else { set_label(recent_file_items[i], recent_file_names[i]); XtManageChild(recent_file_items[i]); } } for (i = size; i < recent_file_items_size; i++) /* maybe previous file was deleted */ if ((recent_file_items[i]) && (XtIsManaged(recent_file_items[i]))) XtUnmanageChild(recent_file_items[i]); } } static void make_open_recent_menu(void) { int n = 0; Arg args[6]; XtSetArg(args[n], XmNbackground, ss->basic_color); n++; XtSetArg(args[n], XmNpositionIndex, 1); n++; /* just after "Open" menu */ file_open_recent_menu = XmCreatePulldownMenu(file_menu, (char *)"open-recent", args, n); XtSetArg(args[n], XmNsubMenuId, file_open_recent_menu); n++; file_open_recent_cascade_menu = XtCreateManagedWidget("Open recent", xmCascadeButtonWidgetClass, file_menu, args, n); XtAddCallback(file_open_recent_cascade_menu, XmNcascadingCallback, file_open_recent_callback, NULL); } static void file_menu_update_1(Widget w, XtPointer info, XtPointer context) { if (recent_files_size() > 0) { if (!file_open_recent_menu) make_open_recent_menu(); else set_sensitive(file_open_recent_cascade_menu, true); } else { if (file_open_recent_menu) set_sensitive(file_open_recent_cascade_menu, false); } file_menu_update(); } static void file_open_callback(Widget w, XtPointer info, XtPointer context) {make_open_file_dialog(FILE_READ_WRITE, true);} static void file_view_callback(Widget w, XtPointer info, XtPointer context) {make_open_file_dialog(FILE_READ_ONLY, true);} static void file_new_callback(Widget w, XtPointer info, XtPointer context) {make_new_file_dialog(true);} static void file_close_callback(Widget w, XtPointer info, XtPointer context) {if (any_selected_sound()) snd_close_file(any_selected_sound());} static void file_close_all_callback(Widget w, XtPointer info, XtPointer context) {for_each_sound(snd_close_file);} static void file_save_callback(Widget w, XtPointer info, XtPointer context) {if (any_selected_sound()) save_edits_from_kbd(any_selected_sound());} static void file_update_callback(Widget w, XtPointer info, XtPointer context) {update_file_from_menu();} static void file_save_as_callback(Widget w, XtPointer info, XtPointer context) {make_sound_save_as_dialog(true);} static void file_revert_callback(Widget w, XtPointer info, XtPointer context) {revert_file_from_menu();} static void file_exit_callback(Widget w, XtPointer info, XtPointer context) {if (snd_exit_cleanly(EXIT_NOT_FORCED)) snd_exit(1);} static void file_mix_callback_1(Widget w, XtPointer info, XtPointer context) {make_mix_file_dialog(true);} static void file_insert_callback_1(Widget w, XtPointer info, XtPointer context) {make_insert_file_dialog(true);} static void file_print_callback_1(Widget w, XtPointer info, XtPointer context) {file_print_callback(w, info, context);} /* -------------------------------- EDIT MENU -------------------------------- */ static void edit_mix_callback(Widget w, XtPointer info, XtPointer context) {add_selection_or_region(0, selected_channel());} static void edit_envelope_callback(Widget w, XtPointer info, XtPointer context) {create_envelope_editor();} static void edit_cut_callback(Widget w, XtPointer info, XtPointer context) {delete_selection(UPDATE_DISPLAY);} static void edit_paste_callback(Widget w, XtPointer info, XtPointer context) {insert_selection_from_menu();} static void edit_save_as_callback(Widget w, XtPointer info, XtPointer context) {make_selection_save_as_dialog(true);} static void edit_select_all_callback(Widget w, XtPointer info, XtPointer context) {select_all(current_channel());} static void edit_unselect_callback(Widget w, XtPointer info, XtPointer context) {deactivate_selection();} static void edit_undo_callback(Widget w, XtPointer info, XtPointer context) {undo_edit_with_sync(current_channel(), 1);} static void edit_redo_callback(Widget w, XtPointer info, XtPointer context) {redo_edit_with_sync(current_channel(), 1);} static void edit_menu_update_1(Widget w, XtPointer info, XtPointer context) {edit_menu_update();} #if WITH_AUDIO static void edit_play_callback(Widget w, XtPointer info, XtPointer context) { if (ss->selection_play_stop) { stop_playing_all_sounds(PLAY_BUTTON_UNSET); reflect_play_selection_stop(); /* if there was an error, stop_playing might not remember to clear this */ } else { set_menu_label(edit_play_menu, I_STOP); ss->selection_play_stop = true; play_selection(IN_BACKGROUND); } } void reflect_play_selection_stop(void) { set_menu_label(edit_play_menu, "Play Selection"); ss->selection_play_stop = false; } #else void reflect_play_selection_stop(void) { } #endif static void edit_header_callback_1(Widget w, XtPointer info, XtPointer context) { snd_info *sp; sp = any_selected_sound(); if (sp) edit_header(sp); } #if HAVE_EXTENSION_LANGUAGE static void edit_find_callback_1(Widget w, XtPointer info, XtPointer context) { edit_find_callback(w, info, context); } #endif /* -------------------------------- VIEW MENU -------------------------------- */ static Widget *view_files_items = NULL; static Widget view_files_cascade_menu = NULL; static int view_files_items_size = 0; static void view_files_item_callback(Widget w, XtPointer context, XtPointer info) { view_files_start_dialog_with_title(get_label(w)); } static void view_files_callback(Widget w, XtPointer info, XtPointer context) { int size; size = view_files_dialog_list_length(); if (size == 0) make_view_files_dialog(true, true); /* managed and empty (brand-new) */ else { if (size == 1) make_view_files_dialog(true, false); /* raise current */ else { int i; char **view_files_names; if ((XmIsPushButton(view_files_menu)) && /* autotest check */ (!view_files_cascade_menu)) return; view_files_names = view_files_dialog_titles(); if (size > view_files_items_size) { if (view_files_items_size == 0) view_files_items = (Widget *)calloc(size, sizeof(Widget)); else { view_files_items = (Widget *)realloc(view_files_items, size * sizeof(Widget)); for (i = view_files_items_size; i < size; i++) view_files_items[i] = NULL; } view_files_items_size = size; } for (i = 0; i < size; i++) { if (!view_files_items[i]) { int n = 0; Arg args[6]; XtSetArg(args[n], XmNbackground, ss->basic_color); n++; view_files_items[i] = XtCreateManagedWidget(view_files_names[i], xmPushButtonWidgetClass, view_files_menu, args, n); XtAddCallback(view_files_items[i], XmNactivateCallback, view_files_item_callback, NULL); } else { set_label(view_files_items[i], view_files_names[i]); XtManageChild(view_files_items[i]); } free(view_files_names[i]); } free(view_files_names); } } } static void make_view_files_list_menu(void) { int n = 0, pos = 2; Arg args[6]; if ((view_files_menu) && (XmIsPushButton(view_files_menu))) { XtVaGetValues(view_files_menu, XmNpositionIndex, &pos, NULL); XtUnmanageChild(view_files_menu); } XtSetArg(args[n], XmNbackground, ss->basic_color); n++; XtSetArg(args[n], XmNpositionIndex, pos); n++; view_files_menu = XmCreatePulldownMenu(view_menu, (char *)"view-files", args, n); XtSetArg(args[n], XmNsubMenuId, view_files_menu); n++; view_files_cascade_menu = XtCreateManagedWidget("Files", xmCascadeButtonWidgetClass, view_menu, args, n); XtAddCallback(view_files_cascade_menu, XmNcascadingCallback, view_files_callback, NULL); } static void view_menu_update_1(Widget w, XtPointer info, XtPointer context) { if ((view_files_dialog_list_length() > 1) && (!view_files_cascade_menu)) make_view_files_list_menu(); view_menu_update(); } static void view_separate_callback(Widget w, XtPointer info, XtPointer context) {set_channel_style(CHANNELS_SEPARATE);} static void view_combined_callback(Widget w, XtPointer info, XtPointer context) {set_channel_style(CHANNELS_COMBINED);} static void view_superimposed_callback(Widget w, XtPointer info, XtPointer context) {set_channel_style(CHANNELS_SUPERIMPOSED);} static void view_dots_callback(Widget w, XtPointer info, XtPointer context) {set_graph_style(GRAPH_DOTS);} static void view_lines_callback(Widget w, XtPointer info, XtPointer context) {set_graph_style(GRAPH_LINES);} static void view_filled_callback(Widget w, XtPointer info, XtPointer context) {set_graph_style(GRAPH_FILLED);} static void view_dots_and_lines_callback(Widget w, XtPointer info, XtPointer context) {set_graph_style(GRAPH_DOTS_AND_LINES);} static void view_lollipops_callback(Widget w, XtPointer info, XtPointer context) {set_graph_style(GRAPH_LOLLIPOPS);} #if HAVE_EXTENSION_LANGUAGE static void view_listener_callback(Widget w, XtPointer info, XtPointer context) {handle_listener(!(listener_is_visible()));} #endif static void view_mix_dialog_callback(Widget w, XtPointer info, XtPointer context) {make_mix_dialog();} static void view_zero_callback(Widget w, XtPointer info, XtPointer context){set_show_y_zero((!(show_y_zero(ss))));} static void view_cursor_callback(Widget w, XtPointer info, XtPointer context){set_with_verbose_cursor((!(with_verbose_cursor(ss))));} #if HAVE_EXTENSION_LANGUAGE static void view_inset_callback(Widget w, XtPointer info, XtPointer context) { set_with_inset_graph((!(with_inset_graph(ss)))); for_each_chan(update_graph); } #endif static void view_controls_callback(Widget w, XtPointer info, XtPointer context) {set_show_controls(!in_show_controls(ss));} static void view_region_callback_1(Widget w, XtPointer info, XtPointer context) {view_region_callback(w, info, context);} static void view_color_orientation_callback_1(Widget w, XtPointer info, XtPointer context) {view_color_orientation_callback(w, info, context);} static void view_x_axis_seconds_callback(Widget w, XtPointer info, XtPointer context) {set_x_axis_style(X_AXIS_IN_SECONDS);} static void view_x_axis_clock_callback(Widget w, XtPointer info, XtPointer context) {set_x_axis_style(X_AXIS_AS_CLOCK);} static void view_x_axis_beats_callback(Widget w, XtPointer info, XtPointer context) {set_x_axis_style(X_AXIS_IN_BEATS);} static void view_x_axis_measures_callback(Widget w, XtPointer info, XtPointer context) {set_x_axis_style(X_AXIS_IN_MEASURES);} static void view_x_axis_samples_callback(Widget w, XtPointer info, XtPointer context) {set_x_axis_style(X_AXIS_IN_SAMPLES);} static void view_x_axis_percentage_callback(Widget w, XtPointer info, XtPointer context) {set_x_axis_style(X_AXIS_AS_PERCENTAGE);} static void view_no_axes_callback(Widget w, XtPointer info, XtPointer context) {set_show_axes(SHOW_NO_AXES);} static void view_all_axes_callback(Widget w, XtPointer info, XtPointer context) {set_show_axes(SHOW_ALL_AXES);} static void view_just_x_axis_callback(Widget w, XtPointer info, XtPointer context) {set_show_axes(SHOW_X_AXIS);} static void view_all_axes_unlabelled_callback(Widget w, XtPointer info, XtPointer context) {set_show_axes(SHOW_ALL_AXES_UNLABELLED);} static void view_just_x_axis_unlabelled_callback(Widget w, XtPointer info, XtPointer context) {set_show_axes(SHOW_X_AXIS_UNLABELLED);} static void view_bare_x_axis_callback(Widget w, XtPointer info, XtPointer context) {set_show_axes(SHOW_BARE_X_AXIS);} static void view_focus_right_callback(Widget w, XtPointer info, XtPointer context) {set_zoom_focus_style(ZOOM_FOCUS_RIGHT);} static void view_focus_left_callback(Widget w, XtPointer info, XtPointer context) {set_zoom_focus_style(ZOOM_FOCUS_LEFT);} static void view_focus_middle_callback(Widget w, XtPointer info, XtPointer context) {set_zoom_focus_style(ZOOM_FOCUS_MIDDLE);} static void view_focus_active_callback(Widget w, XtPointer info, XtPointer context) {set_zoom_focus_style(ZOOM_FOCUS_ACTIVE);} static void view_grid_callback(Widget w, XtPointer info, XtPointer context) { if (show_grid(ss) == NO_GRID) set_show_grid(WITH_GRID); else set_show_grid(NO_GRID); } /* -------------------------------- OPTIONS MENU -------------------------------- */ static void options_transform_callback(Widget w, XtPointer info, XtPointer context) {make_transform_dialog(true);} static void options_controls_callback(Widget w, XtPointer info, XtPointer context) {make_controls_dialog();} #if HAVE_EXTENSION_LANGUAGE static void options_save_state_callback(Widget w, XtPointer info, XtPointer context) {save_state_from_menu();} #endif static void options_preferences_callback(Widget w, XtPointer info, XtPointer context) {make_preferences_dialog();} /* -------------------------------- HELP MENU -------------------------------- */ static void help_about_snd_callback(Widget w, XtPointer info, XtPointer context) {about_snd_help();} static void help_fft_callback(Widget w, XtPointer info, XtPointer context) {fft_help();} #if HAVE_EXTENSION_LANGUAGE static void help_find_callback(Widget w, XtPointer info, XtPointer context) {find_help();} static void help_init_file_callback(Widget w, XtPointer info, XtPointer context) {init_file_help();} #endif static void help_undo_callback(Widget w, XtPointer info, XtPointer context) {undo_help();} static void help_sync_callback(Widget w, XtPointer info, XtPointer context) {sync_help();} static void help_debug_callback(Widget w, XtPointer info, XtPointer context) {debug_help();} static void help_controls_callback(Widget w, XtPointer info, XtPointer context) {controls_help();} static void help_env_callback(Widget w, XtPointer info, XtPointer context) {env_help();} static void help_marks_callback(Widget w, XtPointer info, XtPointer context) {marks_help();} static void help_mix_callback(Widget w, XtPointer info, XtPointer context) {mix_help();} static void help_sound_files_callback(Widget w, XtPointer info, XtPointer context) {sound_files_help();} static void help_keys_callback(Widget w, XtPointer info, XtPointer context) {key_help();} static void help_play_callback(Widget w, XtPointer info, XtPointer context) {play_help();} static void help_filter_callback(Widget w, XtPointer info, XtPointer context) {filter_help();} static void help_save_callback(Widget w, XtPointer info, XtPointer context) {save_help();} static void help_reverb_callback(Widget w, XtPointer info, XtPointer context) {reverb_help();} static void help_resample_callback(Widget w, XtPointer info, XtPointer context) {resample_help();} static void help_insert_callback(Widget w, XtPointer info, XtPointer context) {insert_help();} static void help_delete_callback(Widget w, XtPointer info, XtPointer context) {delete_help();} static void help_region_callback(Widget w, XtPointer info, XtPointer context) {region_help();} static void help_selection_callback(Widget w, XtPointer info, XtPointer context) {selection_help();} static void help_colors_callback(Widget w, XtPointer info, XtPointer context) {colors_help();} void check_menu_labels(int key, int state, bool extended) { /* user has redefined key, so erase old key binding info from the menu label */ if (extended) { if (state == snd_ControlMask) { if (key == snd_K_f) set_label(file_open_menu, "Open"); else if (key == snd_K_s) set_label(file_save_menu, "Save"); else if (key == snd_K_q) set_label(file_mix_menu, "Mix"); else if (key == snd_K_i) set_label(file_insert_menu, "Insert"); else if (key == snd_K_u) set_label(edit_undo_menu, "Undo"); else if (key == snd_K_r) set_label(edit_redo_menu, "Redo"); } else { if (key == snd_K_k) set_label(file_close_menu, "Close"); else if (key == snd_K_i) set_label(edit_paste_menu, "Insert Selection"); else if (key == snd_K_q) set_label(edit_mix_menu, "Mix Selection"); else #if WITH_AUDIO if (key == snd_K_p) set_label(edit_play_menu, "Play Selection"); else #endif if (key == snd_K_w) set_label(edit_save_as_menu, "Save Selection"); } } #if HAVE_EXTENSION_LANGUAGE else { if ((key == snd_K_s) && (state == snd_ControlMask)) set_label(edit_find_menu, I_FIND); } #endif } /* -------------------------------- MAIN MENU -------------------------------- */ static void menu_drag_watcher(Widget w, const char *str, Position x, Position y, drag_style_t dtype, void *data) { char *new_title; switch (dtype) { case DRAG_ENTER: new_title = mus_format("%s: drop to open file", ss->startup_title); XtVaSetValues(main_shell(ss), XmNtitle, (char *)new_title, NULL); XmChangeColor(w, ss->selection_color); free(new_title); break; case DRAG_LEAVE: reflect_file_change_in_title(); XmChangeColor(w, ss->highlight_color); break; default: break; } } static void menu_drop_watcher(Widget w, const char *str, Position x, Position y, void *data) { snd_info *sp = NULL; ss->open_requestor = FROM_DRAG_AND_DROP; sp = snd_open_file(str, FILE_READ_WRITE); if (sp) select_channel(sp, 0); } void add_menu_drop(void) { add_drag_and_drop(main_menu, menu_drop_watcher, menu_drag_watcher, NULL); } Widget add_menu(void) { static Arg main_args[12]; static Arg in_args[12]; static Arg high_args[12]; Arg sep_args[12]; int in_n = 0, n, high_n = 0, main_n = 0, start_high_n, k, j; ss->mw = (Widget *)calloc(NUM_MENU_WIDGETS, sizeof(Widget)); XtSetArg(main_args[main_n], XmNbackground, ss->basic_color); main_n++; XtSetArg(high_args[high_n], XmNbackground, ss->highlight_color); high_n++; XtSetArg(in_args[in_n], XmNbackground, ss->basic_color); in_n++; start_high_n = high_n; XtSetArg(in_args[in_n], XmNsensitive, false); in_n++; n = high_n; XtSetArg(high_args[n], XmNtopAttachment, XmATTACH_FORM); n++; XtSetArg(high_args[n], XmNbottomAttachment, XmATTACH_NONE); n++; XtSetArg(high_args[n], XmNleftAttachment, XmATTACH_FORM); n++; XtSetArg(high_args[n], XmNrightAttachment, XmATTACH_FORM); n++; main_menu = XmCreateMenuBar(main_pane(ss), (char *)"menuBar", high_args, n); /* FILE MENU */ XtSetArg(main_args[main_n], XmNuserData, (XtPointer)0); file_menu = XmCreatePulldownMenu(main_menu, (char *)"File", main_args, main_n + 1); high_n = start_high_n; XtSetArg(high_args[high_n], XmNsubMenuId, file_menu); high_n++; XtSetArg(high_args[high_n], XmNmnemonic, 'F'); high_n++; XtSetArg(high_args[high_n], XmNuserData, (XtPointer)0); high_n++; file_cascade_menu = XtCreateManagedWidget("File", xmCascadeButtonWidgetClass, main_menu, high_args, high_n); file_open_menu = XtCreateManagedWidget("Open", xmPushButtonWidgetClass, file_menu, main_args, main_n); XtAddCallback(file_open_menu, XmNactivateCallback, file_open_callback, NULL); XtVaSetValues(file_open_menu, XmNmnemonic, 'O', NULL); file_close_menu = XtCreateManagedWidget("Close", xmPushButtonWidgetClass, file_menu, in_args, in_n); XtAddCallback(file_close_menu, XmNactivateCallback, file_close_callback, NULL); XtVaSetValues(file_close_menu, XmNmnemonic, 'C', NULL); file_close_all_menu = XtCreateWidget("Close all", xmPushButtonWidgetClass, file_menu, main_args, main_n); XtAddCallback(file_close_all_menu, XmNactivateCallback, file_close_all_callback, NULL); file_save_menu = XtCreateManagedWidget("Save", xmPushButtonWidgetClass, file_menu, in_args, in_n); XtAddCallback(file_save_menu, XmNactivateCallback, file_save_callback, NULL); XtVaSetValues(file_save_menu, XmNmnemonic, 'S', NULL); file_save_as_menu = XtCreateManagedWidget("Save as", xmPushButtonWidgetClass, file_menu, in_args, in_n); XtAddCallback(file_save_as_menu, XmNactivateCallback, file_save_as_callback, NULL); XtVaSetValues(file_save_as_menu, XmNmnemonic, 'a', NULL); file_revert_menu = XtCreateManagedWidget("Revert", xmPushButtonWidgetClass, file_menu, in_args, in_n); XtAddCallback(file_revert_menu, XmNactivateCallback, file_revert_callback, NULL); XtVaSetValues(file_revert_menu, XmNmnemonic, 'R', NULL); file_mix_menu = XtCreateManagedWidget("Mix", xmPushButtonWidgetClass, file_menu, in_args, in_n); XtAddCallback(file_mix_menu, XmNactivateCallback, file_mix_callback_1, NULL); XtVaSetValues(file_mix_menu, XmNmnemonic, 'M', NULL); file_insert_menu = XtCreateManagedWidget("Insert", xmPushButtonWidgetClass, file_menu, in_args, in_n); XtAddCallback(file_insert_menu, XmNactivateCallback, file_insert_callback_1, NULL); XtVaSetValues(file_insert_menu, XmNmnemonic, 'I', NULL); file_update_menu = XtCreateManagedWidget("Update", xmPushButtonWidgetClass, file_menu, in_args, in_n); XtAddCallback(file_update_menu, XmNactivateCallback, file_update_callback, NULL); XtVaSetValues(file_update_menu, XmNmnemonic, 'U', NULL); file_new_menu = XtCreateManagedWidget("New", xmPushButtonWidgetClass, file_menu, main_args, main_n); XtAddCallback(file_new_menu, XmNactivateCallback, file_new_callback, NULL); XtVaSetValues(file_new_menu, XmNmnemonic, 'N', NULL); file_view_menu = XtCreateManagedWidget("View", xmPushButtonWidgetClass, file_menu, main_args, main_n); XtAddCallback(file_view_menu, XmNactivateCallback, file_view_callback, NULL); XtVaSetValues(file_view_menu, XmNmnemonic, 'V', NULL); file_print_menu = XtCreateManagedWidget("Print", xmPushButtonWidgetClass, file_menu, in_args, in_n); XtAddCallback(file_print_menu, XmNactivateCallback, file_print_callback_1, NULL); XtVaSetValues(file_print_menu, XmNmnemonic, 'P', NULL); j = 0; XtSetArg(sep_args[j], XmNbackground, ss->basic_color); j++; XtSetArg(sep_args[j], XmNseparatorType, XmSHADOW_ETCHED_IN); j++; file_sep_menu = XtCreateManagedWidget("", xmSeparatorWidgetClass, file_menu, sep_args, j); file_exit_menu = XtCreateManagedWidget("Exit", xmPushButtonWidgetClass, file_menu, main_args, main_n); XtAddCallback(file_exit_menu, XmNactivateCallback, file_exit_callback, NULL); XtVaSetValues(file_exit_menu, XmNmnemonic, 'E', NULL); /* EDIT MENU */ XtSetArg(main_args[main_n], XmNuserData, (XtPointer)1); edit_menu = XmCreatePulldownMenu(main_menu, (char *)"Edit", main_args, main_n + 1); high_n = start_high_n; XtSetArg(high_args[high_n], XmNsubMenuId, edit_menu); high_n++; XtSetArg(high_args[high_n], XmNmnemonic, 'E'); high_n++; XtSetArg(high_args[high_n], XmNuserData, (XtPointer)1); high_n++; edit_cascade_menu = XtCreateManagedWidget("Edit", xmCascadeButtonWidgetClass, main_menu, high_args, high_n); edit_undo_menu = XtCreateManagedWidget("Undo", xmPushButtonWidgetClass, edit_menu, in_args, in_n); XtAddCallback(edit_undo_menu, XmNactivateCallback, edit_undo_callback, NULL); XtVaSetValues(edit_undo_menu, XmNmnemonic, 'U', NULL); edit_redo_menu = XtCreateManagedWidget("Redo", xmPushButtonWidgetClass, edit_menu, in_args, in_n); XtAddCallback(edit_redo_menu, XmNactivateCallback, edit_redo_callback, NULL); XtVaSetValues(edit_redo_menu, XmNmnemonic, 'R', NULL); #if HAVE_EXTENSION_LANGUAGE edit_find_menu = XtCreateManagedWidget(I_FIND, xmPushButtonWidgetClass, edit_menu, in_args, in_n); XtAddCallback(edit_find_menu, XmNactivateCallback, edit_find_callback_1, NULL); XtVaSetValues(edit_find_menu, XmNmnemonic, 'F', NULL); #endif edit_select_sep_menu = XtCreateManagedWidget("", xmSeparatorWidgetClass, edit_menu, sep_args, j); edit_cut_menu = XtCreateManagedWidget("Delete selection", xmPushButtonWidgetClass, edit_menu, in_args, in_n); XtAddCallback(edit_cut_menu, XmNactivateCallback, edit_cut_callback, NULL); XtVaSetValues(edit_cut_menu, XmNmnemonic, 'C', NULL); edit_paste_menu = XtCreateManagedWidget("Insert selection", xmPushButtonWidgetClass, edit_menu, in_args, in_n); XtAddCallback(edit_paste_menu, XmNactivateCallback, edit_paste_callback, NULL); XtVaSetValues(edit_paste_menu, XmNmnemonic, 'P', NULL); edit_mix_menu = XtCreateManagedWidget("Mix selection", xmPushButtonWidgetClass, edit_menu, in_args, in_n); XtAddCallback(edit_mix_menu, XmNactivateCallback, edit_mix_callback, NULL); XtVaSetValues(edit_mix_menu, XmNmnemonic, 'M', NULL); #if WITH_AUDIO edit_play_menu = XtCreateManagedWidget("Play selection", xmPushButtonWidgetClass, edit_menu, in_args, in_n); XtAddCallback(edit_play_menu, XmNactivateCallback, edit_play_callback, NULL); XtVaSetValues(edit_play_menu, XmNmnemonic, 'P', NULL); #endif edit_save_as_menu = XtCreateManagedWidget("Save selection", xmPushButtonWidgetClass, edit_menu, in_args, in_n); XtAddCallback(edit_save_as_menu, XmNactivateCallback, edit_save_as_callback, NULL); XtVaSetValues(edit_save_as_menu, XmNmnemonic, 'S', NULL); edit_select_all_menu = XtCreateManagedWidget("Select all", xmPushButtonWidgetClass, edit_menu, in_args, in_n); XtAddCallback(edit_select_all_menu, XmNactivateCallback, edit_select_all_callback, NULL); edit_unselect_menu = XtCreateManagedWidget("Unselect all", xmPushButtonWidgetClass, edit_menu, in_args, in_n); XtAddCallback(edit_unselect_menu, XmNactivateCallback, edit_unselect_callback, NULL); edit_edit_sep_menu = XtCreateManagedWidget("", xmSeparatorWidgetClass, edit_menu, sep_args, j); edit_env_menu = XtCreateManagedWidget("Edit envelope", xmPushButtonWidgetClass, edit_menu, main_args, main_n); XtAddCallback(edit_env_menu, XmNactivateCallback, edit_envelope_callback, NULL); XtVaSetValues(edit_env_menu, XmNmnemonic, 'E', NULL); edit_header_menu = XtCreateManagedWidget("Edit header", xmPushButtonWidgetClass, edit_menu, in_args, in_n); XtAddCallback(edit_header_menu, XmNactivateCallback, edit_header_callback_1, NULL); XtVaSetValues(edit_header_menu, XmNmnemonic, 'H', NULL); /* VIEW MENU */ XtSetArg(main_args[main_n], XmNuserData, (XtPointer)2); view_menu = XmCreatePulldownMenu(main_menu, (char *)"View", main_args, main_n + 1); high_n = start_high_n; XtSetArg(high_args[high_n], XmNsubMenuId, view_menu); high_n++; XtSetArg(high_args[high_n], XmNmnemonic, 'V'); high_n++; XtSetArg(high_args[high_n], XmNuserData, (XtPointer)2); high_n++; view_cascade_menu = XtCreateManagedWidget("View", xmCascadeButtonWidgetClass, main_menu, high_args, high_n); #if HAVE_EXTENSION_LANGUAGE view_listener_menu = XtCreateManagedWidget("Open listener", xmPushButtonWidgetClass, view_menu, main_args, main_n); XtAddCallback(view_listener_menu, XmNactivateCallback, view_listener_callback, NULL); XtVaSetValues(view_listener_menu, XmNmnemonic, 'L', NULL); #endif view_files_menu = XtCreateManagedWidget("Files", xmPushButtonWidgetClass, view_menu, main_args, main_n); XtAddCallback(view_files_menu, XmNactivateCallback, view_files_callback, NULL); XtVaSetValues(view_files_menu, XmNmnemonic, 'F', NULL); view_mix_dialog_menu = XtCreateManagedWidget("Mixes", xmPushButtonWidgetClass, view_menu, main_args, main_n); XtAddCallback(view_mix_dialog_menu, XmNactivateCallback, view_mix_dialog_callback, NULL); view_region_menu = XtCreateManagedWidget("Regions", xmPushButtonWidgetClass, view_menu, in_args, in_n); XtAddCallback(view_region_menu, XmNactivateCallback, view_region_callback_1, NULL); XtVaSetValues(view_region_menu, XmNmnemonic, 'R', NULL); view_color_orientation_menu = XtCreateManagedWidget("Color/Orientation", xmPushButtonWidgetClass, view_menu, main_args, main_n); XtAddCallback(view_color_orientation_menu, XmNactivateCallback, view_color_orientation_callback_1, NULL); view_controls_menu = XtCreateManagedWidget("Show controls", xmPushButtonWidgetClass, view_menu, main_args, main_n); XtAddCallback(view_controls_menu, XmNactivateCallback, view_controls_callback, NULL); XtVaSetValues(view_controls_menu, XmNmnemonic, 'S', NULL); view_sep2_menu = XtCreateManagedWidget("", xmSeparatorWidgetClass, view_menu, sep_args, j); view_graph_style_menu = XmCreatePulldownMenu(view_menu, (char *)"graph-style", main_args, main_n); k = main_n; XtSetArg(main_args[k], XmNsubMenuId, view_graph_style_menu); k++; view_graph_style_cascade_menu = XtCreateManagedWidget(I_LINES_OR_DOTS, xmCascadeButtonWidgetClass, view_menu, main_args, k); view_lines_menu = XtCreateManagedWidget("lines", xmPushButtonWidgetClass, view_graph_style_menu, main_args, main_n); XtAddCallback(view_lines_menu, XmNactivateCallback, view_lines_callback, NULL); if (graph_style(ss) == GRAPH_LINES) set_sensitive(view_lines_menu, false); view_dots_menu = XtCreateManagedWidget("dots", xmPushButtonWidgetClass, view_graph_style_menu, main_args, main_n); XtAddCallback(view_dots_menu, XmNactivateCallback, view_dots_callback, NULL); if (graph_style(ss) == GRAPH_DOTS) set_sensitive(view_dots_menu, false); view_filled_menu = XtCreateManagedWidget("filled", xmPushButtonWidgetClass, view_graph_style_menu, main_args, main_n); XtAddCallback(view_filled_menu, XmNactivateCallback, view_filled_callback, NULL); if (graph_style(ss) == GRAPH_FILLED) set_sensitive(view_filled_menu, false); view_dots_and_lines_menu = XtCreateManagedWidget("dots and lines", xmPushButtonWidgetClass, view_graph_style_menu, main_args, main_n); XtAddCallback(view_dots_and_lines_menu, XmNactivateCallback, view_dots_and_lines_callback, NULL); if (graph_style(ss) == GRAPH_DOTS_AND_LINES) set_sensitive(view_dots_and_lines_menu, false); view_lollipops_menu = XtCreateManagedWidget("lollipops", xmPushButtonWidgetClass, view_graph_style_menu, main_args, main_n); XtAddCallback(view_lollipops_menu, XmNactivateCallback, view_lollipops_callback, NULL); if (graph_style(ss) == GRAPH_LOLLIPOPS) set_sensitive(view_lollipops_menu, false); view_cursor_menu = XtCreateManagedWidget("Verbose cursor", xmPushButtonWidgetClass, view_menu, main_args, main_n); XtAddCallback(view_cursor_menu, XmNactivateCallback, view_cursor_callback, NULL); #if HAVE_EXTENSION_LANGUAGE view_inset_menu = XtCreateManagedWidget("With inset graph", xmPushButtonWidgetClass, view_menu, main_args, main_n); XtAddCallback(view_inset_menu, XmNactivateCallback, view_inset_callback, NULL); #endif view_combine_menu = XmCreatePulldownMenu(view_menu, (char *)"combine", main_args, main_n); k = main_n; XtSetArg(main_args[k], XmNsubMenuId, view_combine_menu); k++; view_combine_cascade_menu = XtCreateManagedWidget(I_CHANNEL_LAYOUT, xmCascadeButtonWidgetClass, view_menu, main_args, k); view_combine_separate_menu = XtCreateManagedWidget("separate", xmPushButtonWidgetClass, view_combine_menu, main_args, main_n); XtAddCallback(view_combine_separate_menu, XmNactivateCallback, view_separate_callback, NULL); if (channel_style(ss) == CHANNELS_SEPARATE) set_sensitive(view_combine_separate_menu, false); view_combine_combined_menu = XtCreateManagedWidget("combined", xmPushButtonWidgetClass, view_combine_menu, main_args, main_n); XtAddCallback(view_combine_combined_menu, XmNactivateCallback, view_combined_callback, NULL); if (channel_style(ss) == CHANNELS_COMBINED) set_sensitive(view_combine_combined_menu, false); view_combine_superimposed_menu = XtCreateManagedWidget("superimposed", xmPushButtonWidgetClass, view_combine_menu, main_args, main_n); XtAddCallback(view_combine_superimposed_menu, XmNactivateCallback, view_superimposed_callback, NULL); if (channel_style(ss) == CHANNELS_SUPERIMPOSED) set_sensitive(view_combine_superimposed_menu, false); view_zero_menu = XtCreateManagedWidget("Show y = 0", xmPushButtonWidgetClass, view_menu, main_args, main_n); XtAddCallback(view_zero_menu, XmNactivateCallback, view_zero_callback, NULL); XtVaSetValues(view_zero_menu, XmNmnemonic, 'y', NULL); view_x_axis_menu = XmCreatePulldownMenu(view_menu, (char *)"xaxis", main_args, main_n); k = main_n; XtSetArg(main_args[k], XmNsubMenuId, view_x_axis_menu); k++; view_x_axis_cascade_menu = XtCreateManagedWidget("X axis units", xmCascadeButtonWidgetClass, view_menu, main_args, k); view_x_axis_seconds_menu = XtCreateManagedWidget("seconds", xmPushButtonWidgetClass, view_x_axis_menu, main_args, main_n); XtAddCallback(view_x_axis_seconds_menu, XmNactivateCallback, view_x_axis_seconds_callback, NULL); set_sensitive(view_x_axis_seconds_menu, false); view_x_axis_samples_menu = XtCreateManagedWidget("samples", xmPushButtonWidgetClass, view_x_axis_menu, main_args, main_n); XtAddCallback(view_x_axis_samples_menu, XmNactivateCallback, view_x_axis_samples_callback, NULL); view_x_axis_clock_menu = XtCreateManagedWidget("clock", xmPushButtonWidgetClass, view_x_axis_menu, main_args, main_n); XtAddCallback(view_x_axis_clock_menu, XmNactivateCallback, view_x_axis_clock_callback, NULL); view_x_axis_percentage_menu = XtCreateManagedWidget("percentage", xmPushButtonWidgetClass, view_x_axis_menu, main_args, main_n); XtAddCallback(view_x_axis_percentage_menu, XmNactivateCallback, view_x_axis_percentage_callback, NULL); view_x_axis_beats_menu = XtCreateManagedWidget("beats", xmPushButtonWidgetClass, view_x_axis_menu, main_args, main_n); XtAddCallback(view_x_axis_beats_menu, XmNactivateCallback, view_x_axis_beats_callback, NULL); view_x_axis_measures_menu = XtCreateManagedWidget("measures", xmPushButtonWidgetClass, view_x_axis_menu, main_args, main_n); XtAddCallback(view_x_axis_measures_menu, XmNactivateCallback, view_x_axis_measures_callback, NULL); view_axes_menu = XmCreatePulldownMenu(view_menu, (char *)"axes", main_args, main_n); k = main_n; XtSetArg(main_args[k], XmNsubMenuId, view_axes_menu); k++; view_axes_cascade_menu = XtCreateManagedWidget(I_AXIS_LAYOUT, xmCascadeButtonWidgetClass, view_menu, main_args, k); view_no_axes_menu = XtCreateManagedWidget("no axes", xmPushButtonWidgetClass, view_axes_menu, main_args, main_n); XtAddCallback(view_no_axes_menu, XmNactivateCallback, view_no_axes_callback, NULL); if (show_axes(ss) == SHOW_NO_AXES) set_sensitive(view_no_axes_menu, false); /* false because it is already chosen */ view_all_axes_menu = XtCreateManagedWidget("both axes", xmPushButtonWidgetClass, view_axes_menu, main_args, main_n); XtAddCallback(view_all_axes_menu, XmNactivateCallback, view_all_axes_callback, NULL); if (show_axes(ss) == SHOW_ALL_AXES) set_sensitive(view_all_axes_menu, false); view_just_x_axis_menu = XtCreateManagedWidget("just x axis", xmPushButtonWidgetClass, view_axes_menu, main_args, main_n); XtAddCallback(view_just_x_axis_menu, XmNactivateCallback, view_just_x_axis_callback, NULL); if (show_axes(ss) == SHOW_X_AXIS) set_sensitive(view_just_x_axis_menu, false); view_all_axes_unlabelled_menu = XtCreateManagedWidget("both axes, no labels", xmPushButtonWidgetClass, view_axes_menu, main_args, main_n); XtAddCallback(view_all_axes_unlabelled_menu, XmNactivateCallback, view_all_axes_unlabelled_callback, NULL); if (show_axes(ss) == SHOW_ALL_AXES_UNLABELLED) set_sensitive(view_all_axes_unlabelled_menu, false); view_just_x_axis_unlabelled_menu = XtCreateManagedWidget("just x axis, no label", xmPushButtonWidgetClass, view_axes_menu, main_args, main_n); XtAddCallback(view_just_x_axis_unlabelled_menu, XmNactivateCallback, view_just_x_axis_unlabelled_callback, NULL); if (show_axes(ss) == SHOW_X_AXIS_UNLABELLED) set_sensitive(view_just_x_axis_unlabelled_menu, false); view_bare_x_axis_menu = XtCreateManagedWidget("bare x axis", xmPushButtonWidgetClass, view_axes_menu, main_args, main_n); XtAddCallback(view_bare_x_axis_menu, XmNactivateCallback, view_bare_x_axis_callback, NULL); if (show_axes(ss) == SHOW_BARE_X_AXIS) set_sensitive(view_bare_x_axis_menu, false); view_focus_style_menu = XmCreatePulldownMenu(view_menu, (char *)"focusstyle", main_args, main_n); k = main_n; XtSetArg(main_args[k], XmNsubMenuId, view_focus_style_menu); k++; view_focus_cascade_menu = XtCreateManagedWidget(I_ZOOM_CENTERS_ON, xmCascadeButtonWidgetClass, view_menu, main_args, k); view_focus_left_menu = XtCreateManagedWidget("window left edge", xmPushButtonWidgetClass, view_focus_style_menu, main_args, main_n); XtAddCallback(view_focus_left_menu, XmNactivateCallback, view_focus_left_callback, NULL); view_focus_right_menu = XtCreateManagedWidget("window right edge", xmPushButtonWidgetClass, view_focus_style_menu, main_args, main_n); XtAddCallback(view_focus_right_menu, XmNactivateCallback, view_focus_right_callback, NULL); view_focus_middle_menu = XtCreateManagedWidget("window midpoint", xmPushButtonWidgetClass, view_focus_style_menu, main_args, main_n); XtAddCallback(view_focus_middle_menu, XmNactivateCallback, view_focus_middle_callback, NULL); view_focus_active_menu = XtCreateManagedWidget("cursor or selection", xmPushButtonWidgetClass, view_focus_style_menu, main_args, main_n); XtAddCallback(view_focus_active_menu, XmNactivateCallback, view_focus_active_callback, NULL); view_grid_menu = XtCreateManagedWidget("With grid", xmPushButtonWidgetClass, view_menu, main_args, main_n); XtAddCallback(view_grid_menu, XmNactivateCallback, view_grid_callback, NULL); /* OPTIONS MENU */ XtSetArg(main_args[main_n], XmNuserData, (XtPointer)3); options_menu = XmCreatePulldownMenu(main_menu, (char *)"Option", main_args, main_n + 1); high_n = start_high_n; XtSetArg(high_args[high_n], XmNsubMenuId, options_menu); high_n++; XtSetArg(high_args[high_n], XmNmnemonic, 'O'); high_n++; XtSetArg(high_args[high_n], XmNuserData, (XtPointer)3); high_n++; options_cascade_menu = XtCreateManagedWidget("Options", xmCascadeButtonWidgetClass, main_menu, high_args, high_n); options_transform_menu = XtCreateManagedWidget("Transform options", xmPushButtonWidgetClass, options_menu, main_args, main_n); XtAddCallback(options_transform_menu, XmNactivateCallback, options_transform_callback, NULL); XtVaSetValues(options_transform_menu, XmNmnemonic, 't', NULL); options_controls_menu = XtCreateManagedWidget("Control panel options", xmPushButtonWidgetClass, options_menu, main_args, main_n); XtAddCallback(options_controls_menu, XmNactivateCallback, options_controls_callback, NULL); XtVaSetValues(options_controls_menu, XmNmnemonic, 'c', NULL); #if HAVE_EXTENSION_LANGUAGE options_save_state_menu = XtCreateManagedWidget("Save session", xmPushButtonWidgetClass, options_menu, main_args, main_n); XtAddCallback(options_save_state_menu, XmNactivateCallback, options_save_state_callback, NULL); #endif options_sep_menu = XtCreateManagedWidget("", xmSeparatorWidgetClass, options_menu, sep_args, j); options_preferences_menu = XtCreateManagedWidget("Preferences", xmPushButtonWidgetClass, options_menu, main_args, main_n); XtAddCallback(options_preferences_menu, XmNactivateCallback, options_preferences_callback, NULL); /* HELP MENU */ XtSetArg(main_args[main_n], XmNuserData, (XtPointer)4); help_menu = XmCreatePulldownMenu(main_menu, (char *)I_HELP, main_args, main_n + 1); high_n = start_high_n; XtSetArg(high_args[high_n], XmNsubMenuId, help_menu); high_n++; XtSetArg(high_args[high_n], XmNmnemonic, 'H'); high_n++; XtSetArg(high_args[high_n], XmNuserData, (XtPointer)4); high_n++; help_cascade_menu = XtCreateManagedWidget(I_HELP, xmCascadeButtonWidgetClass, main_menu, high_args, high_n); help_about_snd_menu = XtCreateManagedWidget("About Snd", xmPushButtonWidgetClass, help_menu, main_args, main_n); XtAddCallback(help_about_snd_menu, XmNactivateCallback, help_about_snd_callback, NULL); XtVaSetValues(help_about_snd_menu, XmNmnemonic, 'O', NULL); #if HAVE_EXTENSION_LANGUAGE help_init_file_menu = XtCreateManagedWidget("Customization", xmPushButtonWidgetClass, help_menu, main_args, main_n); XtAddCallback(help_init_file_menu, XmNactivateCallback, help_init_file_callback, NULL); #endif help_controls_menu = XtCreateManagedWidget("Control panel", xmPushButtonWidgetClass, help_menu, main_args, main_n); XtAddCallback(help_controls_menu, XmNactivateCallback, help_controls_callback, NULL); help_keys_menu = XtCreateManagedWidget("Key bindings", xmPushButtonWidgetClass, help_menu, main_args, main_n); XtAddCallback(help_keys_menu, XmNactivateCallback, help_keys_callback, NULL); help_play_menu = XtCreateManagedWidget("Play", xmPushButtonWidgetClass, help_menu, main_args, main_n); XtAddCallback(help_play_menu, XmNactivateCallback, help_play_callback, NULL); help_save_menu = XtCreateManagedWidget("Save", xmPushButtonWidgetClass, help_menu, main_args, main_n); XtAddCallback(help_save_menu, XmNactivateCallback, help_save_callback, NULL); help_mix_menu = XtCreateManagedWidget("Mix", xmPushButtonWidgetClass, help_menu, main_args, main_n); XtAddCallback(help_mix_menu, XmNactivateCallback, help_mix_callback, NULL); help_resample_menu = XtCreateManagedWidget("Resample", xmPushButtonWidgetClass, help_menu, main_args, main_n); XtAddCallback(help_resample_menu, XmNactivateCallback, help_resample_callback, NULL); help_fft_menu = XtCreateManagedWidget("FFT", xmPushButtonWidgetClass, help_menu, main_args, main_n); XtAddCallback(help_fft_menu, XmNactivateCallback, help_fft_callback, NULL); help_filter_menu = XtCreateManagedWidget("Filter", xmPushButtonWidgetClass, help_menu, main_args, main_n); XtAddCallback(help_filter_menu, XmNactivateCallback, help_filter_callback, NULL); help_reverb_menu = XtCreateManagedWidget("Reverb", xmPushButtonWidgetClass, help_menu, main_args, main_n); XtAddCallback(help_reverb_menu, XmNactivateCallback, help_reverb_callback, NULL); help_env_menu = XtCreateManagedWidget("Envelope", xmPushButtonWidgetClass, help_menu, main_args, main_n); XtAddCallback(help_env_menu, XmNactivateCallback, help_env_callback, NULL); help_marks_menu = XtCreateManagedWidget("Mark", xmPushButtonWidgetClass, help_menu, main_args, main_n); XtAddCallback(help_marks_menu, XmNactivateCallback, help_marks_callback, NULL); help_insert_menu = XtCreateManagedWidget("Insert", xmPushButtonWidgetClass, help_menu, main_args, main_n); XtAddCallback(help_insert_menu, XmNactivateCallback, help_insert_callback, NULL); help_delete_menu = XtCreateManagedWidget("Delete", xmPushButtonWidgetClass, help_menu, main_args, main_n); XtAddCallback(help_delete_menu, XmNactivateCallback, help_delete_callback, NULL); help_undo_menu = XtCreateManagedWidget("Undo and redo", xmPushButtonWidgetClass, help_menu, main_args, main_n); XtAddCallback(help_undo_menu, XmNactivateCallback, help_undo_callback, NULL); #if HAVE_EXTENSION_LANGUAGE help_find_menu = XtCreateManagedWidget("Search", xmPushButtonWidgetClass, help_menu, main_args, main_n); XtAddCallback(help_find_menu, XmNactivateCallback, help_find_callback, NULL); #endif help_sync_menu = XtCreateManagedWidget("Sync and unite", xmPushButtonWidgetClass, help_menu, main_args, main_n); XtAddCallback(help_sync_menu, XmNactivateCallback, help_sync_callback, NULL); help_sound_files_menu = XtCreateManagedWidget("Headers and data", xmPushButtonWidgetClass, help_menu, main_args, main_n); XtAddCallback(help_sound_files_menu, XmNactivateCallback, help_sound_files_callback, NULL); help_debug_menu = XtCreateManagedWidget("Debugging", xmPushButtonWidgetClass, help_menu, main_args, main_n); XtAddCallback(help_debug_menu, XmNactivateCallback, help_debug_callback, NULL); help_region_menu = XtCreateManagedWidget("Regions", xmPushButtonWidgetClass, help_menu, main_args, main_n); XtAddCallback(help_region_menu, XmNactivateCallback, help_region_callback, NULL); help_selection_menu = XtCreateManagedWidget("Selections", xmPushButtonWidgetClass, help_menu, main_args, main_n); XtAddCallback(help_selection_menu, XmNactivateCallback, help_selection_callback, NULL); help_colors_menu = XtCreateManagedWidget("Colors", xmPushButtonWidgetClass, help_menu, main_args, main_n); XtAddCallback(help_colors_menu, XmNactivateCallback, help_colors_callback, NULL); XtVaSetValues(main_menu, XmNmenuHelpWidget, help_cascade_menu, NULL); XtAddCallback(file_cascade_menu, XmNcascadingCallback, file_menu_update_1, NULL); XtAddCallback(edit_cascade_menu, XmNcascadingCallback, edit_menu_update_1, NULL); XtAddCallback(view_cascade_menu, XmNcascadingCallback, view_menu_update_1, NULL); XtManageChild(main_menu); return(main_menu); } /* -------------------------------- POPUP MENU -------------------------------- */ static Widget basic_popup_menu = NULL, selection_popup_menu = NULL, fft_popup_menu = NULL; static Widget add_menu_item(Widget menu, const char *label, void (*callback)(Widget w, XtPointer info, XtPointer context)) { Arg args[20]; int n; Widget w; n = 0; XtSetArg(args[n], XmNbackground, ss->highlight_color); n++; w = XtCreateManagedWidget(label, xmPushButtonWidgetClass, menu, args, n); XtAddCallback(w, XmNactivateCallback, callback, NULL); return(w); } static void popup_info_callback(Widget w, XtPointer info, XtPointer context) { snd_info *sp; sp = any_selected_sound(); if (sp) display_info(sp); } static void popup_normalize_callback(Widget w, XtPointer info, XtPointer context) { mus_float_t scl[1]; scl[0] = 1.0; scale_to(any_selected_sound(), current_channel(), scl, 1, OVER_SOUND); } static void popup_reverse_callback(Widget w, XtPointer info, XtPointer context) { reverse_sound(current_channel(), OVER_SOUND, C_int_to_Xen_integer(AT_CURRENT_EDIT_POSITION), 0); } static void stop_everything_callback(Widget w, XtPointer info, XtPointer context) { control_g(any_selected_sound()); } static void play_channel_callback(Widget w, XtPointer info, XtPointer context) { chan_info *cp; cp = current_channel(); play_channel(cp, 0, current_samples(cp)); } static Widget popup_play; void post_basic_popup_menu(void *e) { XButtonPressedEvent *event = (XButtonPressedEvent *)e; snd_info *sp; if (!basic_popup_menu) { Arg args[20]; int n; n = 0; XtSetArg(args[n], XmNbackground, ss->highlight_color); n++; XtSetArg(args[n], XmNpopupEnabled, false); n++; /* this was XmPOPUP_AUTOMATIC_RECURSIVE */ basic_popup_menu = XmCreatePopupMenu(main_pane(ss), (char *)"basic-popup-menu", args, n); add_menu_item(basic_popup_menu, "Info", popup_info_callback); add_menu_item(basic_popup_menu, "Select all", edit_select_all_callback); popup_play = add_menu_item(basic_popup_menu, "Play channel", play_channel_callback); add_menu_item(basic_popup_menu, "Stop!", stop_everything_callback); add_menu_item(basic_popup_menu, "-> 1.0", popup_normalize_callback); add_menu_item(basic_popup_menu, "Reverse", popup_reverse_callback); } XmMenuPosition(basic_popup_menu, event); sp = any_selected_sound(); if ((!sp) || (sp->nchans == 1)) XtUnmanageChild(popup_play); else XtManageChild(popup_play); XtManageChild(basic_popup_menu); } /* -------- selection popup -------- */ static void popup_show_selection_callback(Widget w, XtPointer info, XtPointer context) { show_selection(); } static void popup_zero_selection_callback(Widget w, XtPointer info, XtPointer context) { mus_float_t scl[1]; scl[0] = 0.0; scale_by(NULL, scl, 1, OVER_SELECTION); } static void popup_normalize_selection_callback(Widget w, XtPointer info, XtPointer context) { mus_float_t scl[1]; scl[0] = 1.0; scale_to(NULL, NULL, scl, 1, OVER_SELECTION); } static void popup_error_handler(const char *msg, void *data) { redirect_snd_error_to(NULL, NULL); redirect_snd_warning_to(NULL, NULL); status_report(any_selected_sound(), "%s: %s", (char *)data, msg); } static void popup_cut_to_new_callback_1(bool cut) { char *temp_file; io_error_t io_err; temp_file = snd_tempnam(); io_err = save_selection(temp_file, selection_srate(), default_output_sample_type(ss), default_output_header_type(ss), NULL, SAVE_ALL_CHANS); if (io_err == IO_NO_ERROR) { if (cut) delete_selection(UPDATE_DISPLAY); ss->open_requestor = FROM_POPUP_CUT_TO_NEW; redirect_snd_error_to(popup_error_handler, (void *)"popup cut->new"); snd_open_file(temp_file, FILE_READ_WRITE); redirect_snd_error_to(NULL, NULL); free(temp_file); } } static void popup_cut_to_new_callback(Widget w, XtPointer info, XtPointer context) {popup_cut_to_new_callback_1(true);} static void popup_copy_to_new_callback(Widget w, XtPointer info, XtPointer context) {popup_cut_to_new_callback_1(false);} static void crop(chan_info *cp) { if (selection_is_active_in_channel(cp)) { mus_long_t beg, end, framples; framples = current_samples(cp); beg = selection_beg(cp); end = selection_end(cp); if (beg > 0) delete_samples(0, beg, cp, cp->edit_ctr); if (end < (framples - 1)) delete_samples(end + 1, framples - end, cp, cp->edit_ctr); } } static void popup_crop_callback(Widget w, XtPointer info, XtPointer context) { for_each_chan(crop); } static void popup_cut_and_smooth_callback(Widget w, XtPointer info, XtPointer context) { for_each_chan(cut_and_smooth); } static void mark_selection(chan_info *cp) { if (selection_is_active_in_channel(cp)) { add_mark(selection_beg(cp), NULL, cp); add_mark(selection_end(cp), NULL, cp); } } static void popup_mark_selection_callback(Widget w, XtPointer info, XtPointer context) { for_each_chan(mark_selection); } static void popup_reverse_selection_callback(Widget w, XtPointer info, XtPointer context) { reverse_sound(current_channel(), OVER_SELECTION, C_int_to_Xen_integer(AT_CURRENT_EDIT_POSITION), 0); } static mus_float_t selection_max = 0.0; static void selection_info(chan_info *cp) { if ((selection_is_active_in_channel(cp)) && (selection_maxamp(cp) > selection_max)) selection_max = selection_maxamp(cp); } static void popup_selection_info_callback(Widget w, XtPointer info, XtPointer context) { selection_max = 0.0; for_each_chan(selection_info); status_report(any_selected_sound(), "selection max: %f", selection_max); } #if WITH_AUDIO static void popup_loop_play_callback(Widget w, XtPointer info, XtPointer context) { if (ss->selection_play_stop) { stop_playing_all_sounds(PLAY_BUTTON_UNSET); reflect_play_selection_stop(); } else { set_menu_label(edit_play_menu, I_STOP); ss->selection_play_stop = true; loop_play_selection(); } } #endif void post_selection_popup_menu(void *e) { XButtonPressedEvent *event = (XButtonPressedEvent *)e; if (!selection_popup_menu) { Arg args[20]; int n; n = 0; XtSetArg(args[n], XmNbackground, ss->highlight_color); n++; XtSetArg(args[n], XmNpopupEnabled, false); n++; /* this was XmPOPUP_AUTOMATIC_RECURSIVE */ selection_popup_menu = XmCreatePopupMenu(main_pane(ss), (char *)"selection-popup-menu", args, n); add_menu_item(selection_popup_menu, "Fill window", popup_show_selection_callback); add_menu_item(selection_popup_menu, "Cut", edit_cut_callback); add_menu_item(selection_popup_menu, "Cut and smooth", popup_cut_and_smooth_callback); add_menu_item(selection_popup_menu, "Cut -> new", popup_cut_to_new_callback); add_menu_item(selection_popup_menu, "Save as", edit_save_as_callback); #if WITH_AUDIO add_menu_item(selection_popup_menu, "Play", edit_play_callback); add_menu_item(selection_popup_menu, "Play looping", popup_loop_play_callback); #endif add_menu_item(selection_popup_menu, "Crop", popup_crop_callback); add_menu_item(selection_popup_menu, "Unselect all", edit_unselect_callback); add_menu_item(selection_popup_menu, "-> 0.0", popup_zero_selection_callback); add_menu_item(selection_popup_menu, "-> 1.0", popup_normalize_selection_callback); add_menu_item(selection_popup_menu, "Copy -> new", popup_copy_to_new_callback); add_menu_item(selection_popup_menu, "Paste", edit_paste_callback); add_menu_item(selection_popup_menu, "Mix", edit_mix_callback); add_menu_item(selection_popup_menu, "Mark", popup_mark_selection_callback); add_menu_item(selection_popup_menu, "Reverse", popup_reverse_selection_callback); add_menu_item(selection_popup_menu, "Info", popup_selection_info_callback); } XmMenuPosition(selection_popup_menu, event); XtManageChild(selection_popup_menu); } /* -------- fft popup -------- */ static void popup_peaks_callback(Widget w, XtPointer info, XtPointer context) { FILE *peaks_fd; peaks_fd = FOPEN("fft.txt", "w"); if (peaks_fd) { write_transform_peaks(peaks_fd, current_channel()); /* follows sync */ fclose(peaks_fd); } } static void fft_size_16_callback(Widget w, XtPointer info, XtPointer context) {set_transform_size(16);} static void fft_size_64_callback(Widget w, XtPointer info, XtPointer context) {set_transform_size(64);} static void fft_size_256_callback(Widget w, XtPointer info, XtPointer context) {set_transform_size(256);} static void fft_size_1024_callback(Widget w, XtPointer info, XtPointer context) {set_transform_size(1024);} static void fft_size_4096_callback(Widget w, XtPointer info, XtPointer context) {set_transform_size(4096);} static void fft_size_16384_callback(Widget w, XtPointer info, XtPointer context) {set_transform_size(16384);} static void fft_size_65536_callback(Widget w, XtPointer info, XtPointer context) {set_transform_size(65536);} static void fft_size_262144_callback(Widget w, XtPointer info, XtPointer context) {set_transform_size(262144);} static void fft_size_1048576_callback(Widget w, XtPointer info, XtPointer context) {set_transform_size(1048576);} static void fft_window_rectangular_callback(Widget w, XtPointer info, XtPointer context) {set_fft_window(MUS_RECTANGULAR_WINDOW);} static void fft_window_hann_callback(Widget w, XtPointer info, XtPointer context) {set_fft_window(MUS_HANN_WINDOW);} static void fft_window_welch_callback(Widget w, XtPointer info, XtPointer context) {set_fft_window(MUS_WELCH_WINDOW);} static void fft_window_parzen_callback(Widget w, XtPointer info, XtPointer context) {set_fft_window(MUS_PARZEN_WINDOW);} static void fft_window_bartlett_callback(Widget w, XtPointer info, XtPointer context) {set_fft_window(MUS_BARTLETT_WINDOW);} static void fft_window_blackman2_callback(Widget w, XtPointer info, XtPointer context) {set_fft_window(MUS_BLACKMAN2_WINDOW);} static void fft_window_blackman3_callback(Widget w, XtPointer info, XtPointer context) {set_fft_window(MUS_BLACKMAN3_WINDOW);} static void fft_window_blackman4_callback(Widget w, XtPointer info, XtPointer context) {set_fft_window(MUS_BLACKMAN4_WINDOW);} static void fft_window_hamming_callback(Widget w, XtPointer info, XtPointer context) {set_fft_window(MUS_HAMMING_WINDOW);} static void fft_window_exponential_callback(Widget w, XtPointer info, XtPointer context) {set_fft_window(MUS_EXPONENTIAL_WINDOW);} static void fft_window_riemann_callback(Widget w, XtPointer info, XtPointer context) {set_fft_window(MUS_RIEMANN_WINDOW);} static void fft_window_kaiser_callback(Widget w, XtPointer info, XtPointer context) {set_fft_window(MUS_KAISER_WINDOW);} static void fft_window_cauchy_callback(Widget w, XtPointer info, XtPointer context) {set_fft_window(MUS_CAUCHY_WINDOW);} static void fft_window_poisson_callback(Widget w, XtPointer info, XtPointer context) {set_fft_window(MUS_POISSON_WINDOW);} static void fft_window_gaussian_callback(Widget w, XtPointer info, XtPointer context) {set_fft_window(MUS_GAUSSIAN_WINDOW);} static void fft_window_tukey_callback(Widget w, XtPointer info, XtPointer context) {set_fft_window(MUS_TUKEY_WINDOW);} static void fft_window_dolph_chebyshev_callback(Widget w, XtPointer info, XtPointer context) {set_fft_window(MUS_DOLPH_CHEBYSHEV_WINDOW);} static void fft_window_blackman6_callback(Widget w, XtPointer info, XtPointer context) {set_fft_window(MUS_BLACKMAN6_WINDOW);} static void fft_window_blackman8_callback(Widget w, XtPointer info, XtPointer context) {set_fft_window(MUS_BLACKMAN8_WINDOW);} static void fft_window_blackman10_callback(Widget w, XtPointer info, XtPointer context) {set_fft_window(MUS_BLACKMAN10_WINDOW);} static void fft_type_fourier_callback(Widget w, XtPointer info, XtPointer context) {set_transform_type(FOURIER);} static void fft_type_wavelet_callback(Widget w, XtPointer info, XtPointer context) {set_transform_type(WAVELET);} static void fft_type_autocorrelation_callback(Widget w, XtPointer info, XtPointer context) {set_transform_type(AUTOCORRELATION);} static void fft_type_cepstrum_callback(Widget w, XtPointer info, XtPointer context) {set_transform_type(CEPSTRUM);} static void fft_graph_once_callback(Widget w, XtPointer info, XtPointer context) {set_transform_graph_type(GRAPH_ONCE);} static void fft_graph_sonogram_callback(Widget w, XtPointer info, XtPointer context) {set_transform_graph_type(GRAPH_AS_SONOGRAM);} static void fft_graph_spectrogram_callback(Widget w, XtPointer info, XtPointer context) {set_transform_graph_type(GRAPH_AS_SPECTROGRAM);} static void fft_gray_callback(Widget w, XtPointer info, XtPointer context) {set_color_map(GRAY_COLORMAP);} static void fft_hot_callback(Widget w, XtPointer info, XtPointer context) {set_color_map(HOT_COLORMAP);} static void fft_cool_callback(Widget w, XtPointer info, XtPointer context) {set_color_map(COOL_COLORMAP);} static void fft_bone_callback(Widget w, XtPointer info, XtPointer context) {set_color_map(BONE_COLORMAP);} static void fft_copper_callback(Widget w, XtPointer info, XtPointer context) {set_color_map(COPPER_COLORMAP);} static void fft_pink_callback(Widget w, XtPointer info, XtPointer context) {set_color_map(PINK_COLORMAP);} static void fft_jet_callback(Widget w, XtPointer info, XtPointer context) {set_color_map(JET_COLORMAP);} static void fft_prism_callback(Widget w, XtPointer info, XtPointer context) {set_color_map(PRISM_COLORMAP);} static void fft_autumn_callback(Widget w, XtPointer info, XtPointer context) {set_color_map(AUTUMN_COLORMAP);} static void fft_winter_callback(Widget w, XtPointer info, XtPointer context) {set_color_map(WINTER_COLORMAP);} static void fft_spring_callback(Widget w, XtPointer info, XtPointer context) {set_color_map(SPRING_COLORMAP);} static void fft_summer_callback(Widget w, XtPointer info, XtPointer context) {set_color_map(SUMMER_COLORMAP);} static void fft_rainbow_callback(Widget w, XtPointer info, XtPointer context) {set_color_map(RAINBOW_COLORMAP);} static void fft_flag_callback(Widget w, XtPointer info, XtPointer context) {set_color_map(FLAG_COLORMAP);} static void fft_phases_callback(Widget w, XtPointer info, XtPointer context) {set_color_map(PHASES_COLORMAP);} static void fft_black_and_white_callback(Widget w, XtPointer info, XtPointer context) {set_color_map(BLACK_AND_WHITE_COLORMAP);} void post_fft_popup_menu(void *e) { XButtonPressedEvent *event = (XButtonPressedEvent *)e; if (!fft_popup_menu) { Widget outer_menu; Arg args[20]; int n; n = 0; XtSetArg(args[n], XmNbackground, ss->highlight_color); n++; XtSetArg(args[n], XmNpopupEnabled, false); n++; /* this was XmPOPUP_AUTOMATIC_RECURSIVE */ fft_popup_menu = XmCreatePopupMenu(main_pane(ss), (char *)"fft-popup-menu", args, n); n = 0; XtSetArg(args[n], XmNbackground, ss->highlight_color); n++; outer_menu = XmCreatePulldownMenu(fft_popup_menu, (char *)"Size", args, n); n = 0; XtSetArg(args[n], XmNbackground, ss->highlight_color); n++; XtSetArg(args[n], XmNsubMenuId, outer_menu); n++; XtCreateManagedWidget("Size", xmCascadeButtonWidgetClass, fft_popup_menu, args, n); add_menu_item(outer_menu, "16", fft_size_16_callback); add_menu_item(outer_menu, "64", fft_size_64_callback); add_menu_item(outer_menu, "256", fft_size_256_callback); add_menu_item(outer_menu, "1024", fft_size_1024_callback); add_menu_item(outer_menu, "4096", fft_size_4096_callback); add_menu_item(outer_menu, "16384", fft_size_16384_callback); add_menu_item(outer_menu, "65536", fft_size_65536_callback); add_menu_item(outer_menu, "262144", fft_size_262144_callback); add_menu_item(outer_menu, "1048576", fft_size_1048576_callback); n = 0; XtSetArg(args[n], XmNbackground, ss->highlight_color); n++; outer_menu = XmCreatePulldownMenu(fft_popup_menu, (char *)"Window", args, n); n = 0; XtSetArg(args[n], XmNbackground, ss->highlight_color); n++; XtSetArg(args[n], XmNsubMenuId, outer_menu); n++; XtCreateManagedWidget("Window", xmCascadeButtonWidgetClass, fft_popup_menu, args, n); add_menu_item(outer_menu, "rectangular", fft_window_rectangular_callback); add_menu_item(outer_menu, "hann", fft_window_hann_callback); add_menu_item(outer_menu, "welch", fft_window_welch_callback); add_menu_item(outer_menu, "parzen", fft_window_parzen_callback); add_menu_item(outer_menu, "bartlett", fft_window_bartlett_callback); add_menu_item(outer_menu, "hamming", fft_window_hamming_callback); add_menu_item(outer_menu, "blackman2", fft_window_blackman2_callback); add_menu_item(outer_menu, "blackman3", fft_window_blackman3_callback); add_menu_item(outer_menu, "blackman4", fft_window_blackman4_callback); add_menu_item(outer_menu, "exponential", fft_window_exponential_callback); add_menu_item(outer_menu, "riemann", fft_window_riemann_callback); add_menu_item(outer_menu, "kaiser", fft_window_kaiser_callback); add_menu_item(outer_menu, "cauchy", fft_window_cauchy_callback); add_menu_item(outer_menu, "poisson", fft_window_poisson_callback); add_menu_item(outer_menu, "gaussian", fft_window_gaussian_callback); add_menu_item(outer_menu, "tukey", fft_window_tukey_callback); add_menu_item(outer_menu, "dolph-chebyshev", fft_window_dolph_chebyshev_callback); add_menu_item(outer_menu, "blackman6", fft_window_blackman6_callback); add_menu_item(outer_menu, "blackman8", fft_window_blackman8_callback); add_menu_item(outer_menu, "blackman10" , fft_window_blackman10_callback); n = 0; XtSetArg(args[n], XmNbackground, ss->highlight_color); n++; outer_menu = XmCreatePulldownMenu(fft_popup_menu, (char *)"Graph type", args, n); n = 0; XtSetArg(args[n], XmNbackground, ss->highlight_color); n++; XtSetArg(args[n], XmNsubMenuId, outer_menu); n++; XtCreateManagedWidget("Graph type", xmCascadeButtonWidgetClass, fft_popup_menu, args, n); add_menu_item(outer_menu, "one fft", fft_graph_once_callback); add_menu_item(outer_menu, "sonogram", fft_graph_sonogram_callback); add_menu_item(outer_menu, "spectrogram", fft_graph_spectrogram_callback); n = 0; XtSetArg(args[n], XmNbackground, ss->highlight_color); n++; outer_menu = XmCreatePulldownMenu(fft_popup_menu, (char *)"Transform type", args, n); n = 0; XtSetArg(args[n], XmNbackground, ss->highlight_color); n++; XtSetArg(args[n], XmNsubMenuId, outer_menu); n++; XtCreateManagedWidget("Transform type", xmCascadeButtonWidgetClass, fft_popup_menu, args, n); add_menu_item(outer_menu, "fourier", fft_type_fourier_callback); add_menu_item(outer_menu, "wavelet", fft_type_wavelet_callback); add_menu_item(outer_menu, "autocorrelation", fft_type_autocorrelation_callback); add_menu_item(outer_menu, "cepstrum", fft_type_cepstrum_callback); n = 0; XtSetArg(args[n], XmNbackground, ss->highlight_color); n++; outer_menu = XmCreatePulldownMenu(fft_popup_menu, (char *)"Colormap", args, n); n = 0; XtSetArg(args[n], XmNbackground, ss->highlight_color); n++; XtSetArg(args[n], XmNsubMenuId, outer_menu); n++; XtCreateManagedWidget("Colormap", xmCascadeButtonWidgetClass, fft_popup_menu, args, n); add_menu_item(outer_menu, "gray", fft_gray_callback); add_menu_item(outer_menu, "autumn", fft_autumn_callback); add_menu_item(outer_menu, "spring", fft_spring_callback); add_menu_item(outer_menu, "winter", fft_winter_callback); add_menu_item(outer_menu, "summer", fft_summer_callback); add_menu_item(outer_menu, "cool", fft_cool_callback); add_menu_item(outer_menu, "copper", fft_copper_callback); add_menu_item(outer_menu, "flag", fft_flag_callback); add_menu_item(outer_menu, "prism", fft_prism_callback); add_menu_item(outer_menu, "bone", fft_bone_callback); add_menu_item(outer_menu, "hot", fft_hot_callback); add_menu_item(outer_menu, "jet", fft_jet_callback); add_menu_item(outer_menu, "pink", fft_pink_callback); add_menu_item(outer_menu, "rainbow", fft_rainbow_callback); add_menu_item(outer_menu, "phases", fft_phases_callback); add_menu_item(outer_menu, "black and white", fft_black_and_white_callback); add_menu_item(fft_popup_menu, "Peaks->fft.txt", popup_peaks_callback); } XmMenuPosition(fft_popup_menu, event); XtManageChild(fft_popup_menu); } void post_lisp_popup_menu(void *e) {} /* ---------------- tooltips ---------------- */ static Widget tooltip_shell = NULL; #if (!HAVE_GL) static Widget tooltip_label = NULL; #endif static timeout_result_t tool_proc = 0, quit_proc = 0; static Time tool_last_time = 0; static Position tool_x, tool_y; static Widget tool_w; #if (!HAVE_GL) static void leave_tooltip(XtPointer tooltip, XtIntervalId *id) { XtUnmanageChild(tooltip_shell); quit_proc = 0; } #endif static void handle_tooltip(XtPointer tooltip, XtIntervalId *id) { #if (!HAVE_GL) /* if GL, we get a segfault here -- I don't know why */ char *tip = (char *)tooltip; Position rx, ry; XmString str; int lines = 0; if (!tooltip_shell) { tooltip_shell = XtVaCreatePopupShell(tip, overrideShellWidgetClass, main_shell(ss), XmNallowShellResize, true, NULL); tooltip_label = XtVaCreateManagedWidget("tooltip", xmLabelWidgetClass, tooltip_shell, XmNrecomputeSize, true, XmNbackground, ss->lighter_blue, NULL); } str = multi_line_label(tip, &lines); XtVaSetValues(tooltip_label, XmNlabelString, str, NULL); XmStringFree(str); XtTranslateCoords(tool_w, tool_x, tool_y, &rx, &ry); XtVaSetValues(tooltip_shell, XmNx, rx, XmNy, ry, NULL); XtManageChild(tooltip_shell); quit_proc = XtAppAddTimeOut(main_app(ss), (unsigned long)10000, (XtTimerCallbackProc)leave_tooltip, NULL); #endif } static void tool_starter(Widget w, XtPointer context, XEvent *event, Boolean *cont) { XEnterWindowEvent *ev = (XEnterWindowEvent *)event; char *tip = (char *)context; if ((with_tooltips(ss)) && ((ev->time - tool_last_time) > 2)) { tool_x = ev->x; tool_y = ev->y; tool_w = w; tool_last_time = ev->time; tool_proc = XtAppAddTimeOut(main_app(ss), (unsigned long)300, (XtTimerCallbackProc)handle_tooltip, (XtPointer)tip); } } static void tool_stopper(Widget w, XtPointer context, XEvent *event, Boolean *cont) { XLeaveWindowEvent *ev = (XLeaveWindowEvent *)event; tool_last_time = ev->time; if (tool_proc != 0) { XtRemoveTimeOut(tool_proc); tool_proc = 0; } if (quit_proc != 0) { XtRemoveTimeOut(quit_proc); quit_proc = 0; } if ((tooltip_shell) && (XtIsManaged(tooltip_shell))) XtUnmanageChild(tooltip_shell); } void add_tooltip(Widget w, const char *tip) { XtAddEventHandler(w, EnterWindowMask, false, tool_starter, (XtPointer)tip); XtAddEventHandler(w, LeaveWindowMask, false, tool_stopper, NULL); } /* ---------------- toolbar ---------------- */ static void add_to_toolbar(Widget bar, Pixmap icon, const char *tip, void (*callback)(Widget w, XtPointer info, XtPointer context)) { Widget w; w = XtVaCreateManagedWidget("icon", xmPushButtonWidgetClass, bar, XmNlabelPixmap, icon, XmNlabelType, XmPIXMAP, XmNwidth, 24, XmNheight, 24, XmNshadowThickness, 0, XmNhighlightThickness, 0, /* XmNmarginHeight, 0, */ XmNbackground, ss->basic_color, NULL); XtAddCallback(w, XmNactivateCallback, callback, NULL); add_tooltip(w, tip); } static void add_separator_to_toolbar(Widget bar) { XtVaCreateManagedWidget("icon", xmPushButtonWidgetClass, bar, XmNlabelPixmap, toolbar_icon(SND_XPM_SEPARATOR), XmNlabelType, XmPIXMAP, XmNwidth, 8, XmNheight, 24, XmNshadowThickness, 0, XmNhighlightThickness, 0, XmNbackground, ss->basic_color, NULL); } #if WITH_AUDIO static void play_from_start_callback(Widget w, XtPointer info, XtPointer context) { snd_info *sp; sp = any_selected_sound(); if (sp) play_sound(sp, 0, NO_END_SPECIFIED); } static void play_from_cursor_callback(Widget w, XtPointer info, XtPointer context) { snd_info *sp; sp = any_selected_sound(); if (sp) { chan_info *cp; cp = any_selected_channel(sp); if (cp) play_sound(sp, cursor_sample(cp), NO_END_SPECIFIED); } } static void stop_playing_callback(Widget w, XtPointer info, XtPointer context) { stop_playing_all_sounds(PLAY_C_G); reflect_play_selection_stop(); /* this sets ss->selection_play_stop = false; */ } #endif static void full_dur_callback(Widget w, XtPointer info, XtPointer context) { snd_info *sp; sp = any_selected_sound(); if (sp) { uint32_t i; for (i = 0; i < sp->nchans; i++) set_x_axis_x0x1(sp->chans[i], 0.0, sp->chans[i]->axis->xmax); } } static void zoom_out_callback(Widget w, XtPointer info, XtPointer context) { snd_info *sp; sp = any_selected_sound(); if (sp) { uint32_t i; for (i = 0; i < sp->nchans; i++) zx_incremented(sp->chans[i], 2.0); } } static void zoom_in_callback(Widget w, XtPointer info, XtPointer context) { snd_info *sp; sp = any_selected_sound(); if (sp) { uint32_t i; for (i = 0; i < sp->nchans; i++) zx_incremented(sp->chans[i], 0.5); } } static void goto_start_callback(Widget w, XtPointer info, XtPointer context) { snd_info *sp; sp = any_selected_sound(); if (sp) { uint32_t i; for (i = 0; i < sp->nchans; i++) set_x_axis_x0x1(sp->chans[i], 0.0, sp->chans[i]->axis->x1 - sp->chans[i]->axis->x0); } } static void go_back_callback(Widget w, XtPointer info, XtPointer context) { snd_info *sp; sp = any_selected_sound(); if (sp) { uint32_t i; for (i = 0; i < sp->nchans; i++) sx_incremented(sp->chans[i], -1.0); } } static void go_forward_callback(Widget w, XtPointer info, XtPointer context) { snd_info *sp; sp = any_selected_sound(); if (sp) { uint32_t i; for (i = 0; i < sp->nchans; i++) sx_incremented(sp->chans[i], 1.0); } } static void goto_end_callback(Widget w, XtPointer info, XtPointer context) { snd_info *sp; sp = any_selected_sound(); if (sp) { uint32_t i; for (i = 0; i < sp->nchans; i++) set_x_axis_x0x1(sp->chans[i], sp->chans[i]->axis->xmax - sp->chans[i]->axis->x1 + sp->chans[i]->axis->x0, sp->chans[i]->axis->xmax); } } static Widget toolbar = NULL; void show_toolbar(void) { if (!toolbar) { #define ICON_HEIGHT 28 Arg args[32]; int n; XtVaSetValues(main_shell(ss), XmNallowShellResize, false, NULL); n = attach_all_sides(args, 0); XtSetArg(args[n], XmNbackground, ss->basic_color); n++; XtSetArg(args[n], XmNheight, ICON_HEIGHT); n++; XtSetArg(args[n], XmNpaneMaximum, ICON_HEIGHT); n++; /* Xm/Paned initializes each pane max to 1000 apparently! */ XtSetArg(args[n], XmNpositionIndex, 0); n++; XtSetArg(args[n], XmNshadowThickness, 0); n++; XtSetArg(args[n], XmNhighlightThickness, 0); n++; XtSetArg(args[n], XmNmarginHeight, 0); n++; if ((sound_style(ss) == SOUNDS_IN_NOTEBOOK) || (sound_style(ss) == SOUNDS_HORIZONTAL)) toolbar = XtCreateManagedWidget("toolbar", xmRowColumnWidgetClass, sound_pane_box(ss), args, n); else toolbar = XtCreateManagedWidget("toolbar", xmRowColumnWidgetClass, sound_pane(ss), args, n); ss->toolbar = toolbar; if (auto_resize(ss)) XtVaSetValues(main_shell(ss), XmNallowShellResize, true, NULL); make_toolbar_icons(main_shell(ss)); add_to_toolbar(toolbar, toolbar_icon(SND_XPM_NEW), "new sound", file_new_callback); add_to_toolbar(toolbar, toolbar_icon(SND_XPM_OPEN), "open sound", file_open_callback); add_to_toolbar(toolbar, toolbar_icon(SND_XPM_SAVE), "save current sound, overwriting it", file_save_callback); add_to_toolbar(toolbar, toolbar_icon(SND_XPM_SAVE_AS), "save current sound in a new file", file_save_as_callback); add_to_toolbar(toolbar, toolbar_icon(SND_XPM_REVERT), "revert to saved", file_revert_callback); add_to_toolbar(toolbar, toolbar_icon(SND_XPM_UNDO), "undo edit", edit_undo_callback); add_to_toolbar(toolbar, toolbar_icon(SND_XPM_REDO), "redo last (undone) edit", edit_redo_callback); add_to_toolbar(toolbar, toolbar_icon(SND_XPM_CLOSE), "close selected sound", file_close_callback); add_separator_to_toolbar(toolbar); #if WITH_AUDIO add_to_toolbar(toolbar, toolbar_icon(SND_XPM_PLAY), "play from the start", play_from_start_callback); add_to_toolbar(toolbar, toolbar_icon(SND_XPM_CURSOR_PLAY), "play from the cursor", play_from_cursor_callback); add_to_toolbar(toolbar, toolbar_icon(SND_XPM_STOP_PLAY), "stop playing", stop_playing_callback); add_separator_to_toolbar(toolbar); #endif add_to_toolbar(toolbar, toolbar_icon(SND_XPM_UP), "show full sound", full_dur_callback); add_to_toolbar(toolbar, toolbar_icon(SND_XPM_ZOOM_OUT), "zoom out", zoom_out_callback); add_to_toolbar(toolbar, toolbar_icon(SND_XPM_ZOOM_IN), "zoom in", zoom_in_callback); add_to_toolbar(toolbar, toolbar_icon(SND_XPM_BACK_ARROW), "go to start of sound", goto_start_callback); add_to_toolbar(toolbar, toolbar_icon(SND_XPM_BACK), "go back a window", go_back_callback); add_to_toolbar(toolbar, toolbar_icon(SND_XPM_NEXT), "go forward a window", go_forward_callback); add_to_toolbar(toolbar, toolbar_icon(SND_XPM_FORWARD_ARROW), "go to end of sound", goto_end_callback); add_separator_to_toolbar(toolbar); add_to_toolbar(toolbar, toolbar_icon(SND_XPM_CUT), "delete selection", edit_cut_callback); add_to_toolbar(toolbar, toolbar_icon(SND_XPM_PASTE), "insert selection at cursor", edit_paste_callback); add_to_toolbar(toolbar, toolbar_icon(SND_XPM_PREFERENCES), "open preferences dialog", options_preferences_callback); add_to_toolbar(toolbar, toolbar_icon(SND_XPM_STOP), "stop the current operation", stop_everything_callback); add_to_toolbar(toolbar, toolbar_icon(SND_XPM_EXIT), "exit Snd", file_exit_callback); } else { XtVaSetValues(main_shell(ss), XmNallowShellResize, false, NULL); XtManageChild(toolbar); if (auto_resize(ss)) XtVaSetValues(main_shell(ss), XmNallowShellResize, true, NULL); } } void hide_toolbar(void) { if (toolbar) { XtVaSetValues(main_shell(ss), XmNallowShellResize, false, NULL); XtUnmanageChild(toolbar); if (auto_resize(ss)) XtVaSetValues(main_shell(ss), XmNallowShellResize, true, NULL); } } /* ---------------- ext lang tie-ins ---------------- */ #define INVALID_MENU -1 #define call_index(Data) (Data >> 16) #define pack_menu_data(Slot, Menu) ((Slot << 16) | (Menu)) static void menu_callback(Widget w, XtPointer info, XtPointer context) { intptr_t callb; XtVaGetValues(w, XmNuserData, &callb, NULL); g_menu_callback(call_index(callb)); /* menu option activate callback */ } static void GHC_callback(Widget w, XtPointer info, XtPointer context) { intptr_t slot; XtVaGetValues(w, XmNuserData, &slot, NULL); g_menu_callback(call_index(slot)); /* main menu cascading callback */ } static Widget *main_menus = NULL; static int main_menus_size = 0; /* fancy code here looping through the main menus children hangs or segfaults in 86_64 unoptimized cases! */ Widget menu_widget(int which_menu) { switch (which_menu) { case 0: return(file_menu); break; case 1: return(edit_menu); break; case 2: return(view_menu); break; case 3: return(options_menu); break; case 4: return(help_menu); break; default: if (which_menu < main_menus_size) return(main_menus[which_menu]); break; } return(NULL); } static bool or_over_children(Widget w, bool (*func)(Widget uw, const char *ustr), const char *str) { if (w) { if ((*func)(w, str)) return(true); if (XtIsComposite(w)) { uint32_t i; CompositeWidget cw = (CompositeWidget)w; for (i = 0; i < cw->composite.num_children; i++) if (or_over_children(cw->composite.children[i], func, str)) return(true); } } return(false); } static bool clobber_menu(Widget w, const char *name) { char *wname; wname = XtName(w); if ((wname) && (mus_strcmp(name, wname)) && (XtIsManaged(w))) { intptr_t slot; XtVaGetValues(w, XmNuserData, &slot, NULL); unprotect_callback(call_index(slot)); XtUnmanageChild(w); } return(true); /* in any case, don't try to recurse into the children */ } int g_remove_from_menu(int which_menu, const char *label) { Widget top_menu; top_menu = menu_widget(which_menu); if (top_menu) { or_over_children(top_menu, clobber_menu, label); return(0); } return(INVALID_MENU); } static void set_widget_name(Widget w, const char *new_name) { /* based on XtName in Xt/Intrinsic.c, Xt/Create.c, and Xt/ResourceI.h */ w->core.xrm_name = XrmStringToName(new_name); } static int new_menu = 5; int g_add_to_main_menu(const char *label, int slot) { static Arg args[12]; Widget m, cas; int n; if (auto_resize(ss)) XtVaSetValues(main_shell(ss), XmNallowShellResize, false, NULL); new_menu++; n = 0; XtSetArg(args[n], XmNbackground, ss->basic_color); n++; XtSetArg(args[n], XmNuserData, pack_menu_data(slot, new_menu)); n++; m = XmCreatePulldownMenu(main_menu, (char *)label, args, n); n = 0; XtSetArg(args[n], XmNbackground, ss->highlight_color); n++; XtSetArg(args[n], XmNsubMenuId, m); n++; XtSetArg(args[n], XmNuserData, pack_menu_data(slot, new_menu)); n++; cas = XtCreateManagedWidget(label, xmCascadeButtonWidgetClass, main_menu, args, n); if (slot >= 0) XtAddCallback(cas, XmNcascadingCallback, GHC_callback, NULL); if (auto_resize(ss)) XtVaSetValues(main_shell(ss), XmNallowShellResize, true, NULL); if (main_menus_size == 0) { main_menus_size = 8; main_menus = (Widget *)calloc(main_menus_size, sizeof(Widget)); } else { if (new_menu >= main_menus_size) { main_menus_size = new_menu + 8; main_menus = (Widget *)realloc(main_menus, main_menus_size * sizeof(Widget)); } } main_menus[new_menu] = m; return(new_menu); } Widget g_add_to_menu(int which_menu, const char *label, int callb, int position) { Widget m, menw; Arg args[12]; int n = 0; menw = menu_widget(which_menu); if (!menw) return(NULL); if (label) { uint32_t i; /* look for currently unused widget first */ /* but close-all and open-recent should be left alone! */ CompositeWidget cw = (CompositeWidget)menw; for (i = 0; i < cw->composite.num_children; i++) { m = cw->composite.children[i]; if ((m) && (!(XtIsManaged(m))) && (m != file_close_all_menu) && (m != file_open_recent_menu) && (m != file_open_recent_cascade_menu)) { if (!(mus_strcmp(XtName(m), label))) { set_widget_name(m, label); set_button_label(m, label); } if (position >= 0) XtVaSetValues(m, XmNpositionIndex, position, NULL); XtVaSetValues(m, XmNuserData, pack_menu_data(callb, which_menu), NULL); XtManageChild(m); return(m); } } XtSetArg(args[n], XmNbackground, ss->basic_color); n++; if (position >= 0) {XtSetArg(args[n], XmNpositionIndex, position); n++;} XtSetArg(args[n], XmNuserData, pack_menu_data(callb, which_menu)); n++; m = XtCreateManagedWidget(label, xmPushButtonWidgetClass, menw, args, n); XtAddCallback(m, XmNactivateCallback, menu_callback, NULL); } else { XtSetArg(args[n], XmNbackground, ss->basic_color); n++; if (position >= 0) {XtSetArg(args[n], XmNpositionIndex, position); n++;} m = XtCreateManagedWidget("sep", xmSeparatorWidgetClass, menw, args, n); } return(m); } static Xen g_menu_widgets(void) { #define H_menu_widgets "(" S_menu_widgets "): a list of top level menu widgets: ((0)main (1)file (2)edit (3)view (4)options (5)help)" return(Xen_cons(Xen_wrap_widget(main_menu), Xen_cons(Xen_wrap_widget(file_cascade_menu), Xen_cons(Xen_wrap_widget(edit_cascade_menu), Xen_cons(Xen_wrap_widget(view_cascade_menu), Xen_cons(Xen_wrap_widget(options_cascade_menu), Xen_cons(Xen_wrap_widget(help_cascade_menu), Xen_empty_list))))))); } /* Motif bug: the button backgrounds remain in the original highlight color? but the widget (if it is one) is not the child of any obvious widget */ /* motif case needs prompt length fixups, listener if no panes, minibuffer as label not text entry */ /* ---------------- listener text history ---------------- */ static char **listener_strings = NULL; static int listener_strings_size = 0, listener_strings_pos = 0; static bool listener_first_time = true; static void remember_listener_string(const char *str) { int i, top; if (!str) return; if (listener_strings_size == 0) { listener_strings_size = 8; listener_strings = (char **)calloc(listener_strings_size, sizeof(char *)); } listener_strings_pos = 0; listener_first_time = true; /* if str matches current history top entry, ignore it (as in tcsh) */ if ((listener_strings[0]) && (mus_strcmp(str, listener_strings[0]))) return; top = listener_strings_size - 1; if (listener_strings[top]) free(listener_strings[top]); for (i = top; i > 0; i--) listener_strings[i] = listener_strings[i - 1]; listener_strings[0] = mus_strdup(str); } static void restore_listener_string(bool back) { if (listener_strings) { char *str; if (!(listener_first_time)) { if (back) listener_strings_pos++; else listener_strings_pos--; } listener_first_time = false; if (listener_strings_pos < 0) listener_strings_pos = 0; if (listener_strings_pos > (listener_strings_size - 1)) listener_strings_pos = listener_strings_size - 1; str = listener_strings[listener_strings_pos]; if (str) append_listener_text(-1, str); } } static bool is_prompt(const char *str, int beg) { int i, j; /* fprintf(stderr, "check %s %s for %d at %d\n", str, ss->Listener_Prompt, ss->listener_prompt_length, beg); */ for (i = beg, j = ss->listener_prompt_length - 1; (i >= 0) && (j >= 0); i--, j--) if (str[i] != ss->Listener_Prompt[j]) { /* fprintf(stderr, "%c != %c at %d\n", str[i], ss->Listener_Prompt[j], j); */ return(false); } if (j != -1) { /* fprintf(stderr, "j: %d\n", j); */ return(false); } if ((i == -1) || (str[i] == '\n')) { /* fprintf(stderr, "found prompt!\n"); */ return(true); } /* fprintf(stderr, "i: %d, str[i]: %c\n", i, str[i]); */ return(false); } static void listener_help_at_cursor(char *buf, int name_curpos, int len, int prompt_pos) { int i, name_start, name_end; if (isspace(buf[name_curpos])) { for (i = name_curpos - 1; i >= 0; i--) if ((!isspace(buf[i])) && (buf[i] != '(') && (buf[i] != ')')) break; if (i > 0) name_curpos = i; } for (i = name_curpos; i >= 0; i--) if ((isspace(buf[i])) || (buf[i] == '(') || (buf[i] == ')')) break; name_start = i + 1; for (i = name_curpos + 1; i < len; i++) if ((isspace(buf[i])) || (buf[i] == '(') || (buf[i] == ')')) break; name_end = i - 1; if (name_end > name_start) { char *new_text; buf[name_end + 1] = '\0'; new_text = direct_completions((char *)(buf + name_start)); if (new_text) { int matches; matches = get_possible_completions_size(); if (matches == 1) { Xen help; help = g_snd_help(C_string_to_Xen_string(new_text), 0); if (Xen_is_string(help)) snd_help((char *)(buf + name_start), Xen_string_to_C_string(help), WITH_WORD_WRAP); } else { if (matches > 1) { char **buffer; char *help_str; int match_len = 0; buffer = get_possible_completions(); for (i = 0; i < matches; i++) match_len += mus_strlen(buffer[i]); help_str = (char *)calloc(match_len + matches * 8, sizeof(char)); for (i = 0; i < matches; i++) { strcat(help_str, buffer[i]); strcat(help_str, "\n"); } snd_help((char *)(buf + name_start), help_str, WITHOUT_WORD_WRAP); free(help_str); } } free(new_text); } } } static bool within_prompt(const char *str, int beg, int end) { /* search backwards up to prompt length for cr (or 0), check for prompt */ int i, lim; if ((beg + 1 == end) && (str[beg] == '\n')) return(false); /* end-of-page cr within double quotes probably */ lim = beg - ss->listener_prompt_length; if (lim < 0) return(true); for (i = beg; i >= lim; i--) if ((str[i] == '\n') || (i == 0)) { int j, k; for (j = 0, k = i + 1; (j < ss->listener_prompt_length) && (k < end); j++, k++) if (str[k] != ss->Listener_Prompt[j]) return(false); return(true); } return(false); } static char *trim(char *orig) { int i, j, start = -1, end = -1, len; char *str; len = mus_strlen(orig); if (len == 0) return(NULL); for (start = 0; start < len; start++) if ((!isspace(orig[start])) && (orig[start] != '(') && (orig[start] != ')')) break; if (start >= len) return(NULL); for (end = len - 1; end > start; end--) if ((!isspace(orig[end])) && (orig[end] != '(') && (orig[end] != ')')) break; if (start == end) return(NULL); len = end - start + 1; str = (char *)calloc(len + 1, sizeof(char)); for (i = start, j = 0; i <= end; i++, j++) str[j] = orig[i]; return(str); } static int find_matching_paren(const char *str, int parens, int pos, int *highlight_pos) { int i, j; bool quoting = false; int up_comment = -1; for (i = pos - 1; i > 0;) { if (is_prompt(str, i)) break; if (str[i] == '\"') { /* there could be any number of slashified slashes before this quote. */ int k, slashes = 0; for (k = i - 1; k >= 0; k--) { if (str[k] == '\\') slashes++; else break; } if ((slashes & 1) == 0) quoting = !quoting; } if (!quoting) { if ((i <= 1) || (str[i - 1] != '\\') || (str[i - 2] != '#')) { if (str[i] == ')') parens++; else if (str[i] == '(') parens--; else if (str[i] == '\n') { /* check for comment on next line up */ bool up_quoting = false; int quote_comment = -1; for (j = i - 1; j > 0; j--) { if (str[j] == '\n') break; if ((str[j] == '\"') && (str[j - 1] != '\\')) up_quoting = !up_quoting; if ((str[j] == ';') && ((j <= 1) || (str[j - 1] != '\\') || (str[j - 2] != '#'))) { if (!up_quoting) up_comment = j; else quote_comment = j; } } if (up_comment < i) { if (up_comment > 0) i = up_comment; else { if ((up_quoting) && (quote_comment > 0)) i = quote_comment; } } } } } if (parens == 0) { (*highlight_pos) = i; break; } i--; } return(parens); } #if (!HAVE_RUBY) && (!HAVE_FORTH) static bool highlight_unbalanced_paren(void); static int check_balance(const char *expr, int start, int end, bool in_listener) { int i; bool not_whitespace = false; int paren_count = 0; bool prev_separator = true; bool quote_wait = false; i = start; while (i < end) { switch (expr[i]) { case ';' : /* skip till newline. */ do { i++; } while ((expr[i] != '\n') && (i < end)); break; case ' ': case '\n': case '\t': case '\r': if ((not_whitespace) && (paren_count == 0) && (!quote_wait)) return(i); else { prev_separator = true; i++; } break; case '\"' : if ((not_whitespace) && (paren_count == 0) && (!quote_wait)) return(i); else { /* skip past ", ignoring \", some cases: * "\"\"" '("\"\"") "\\" "#\\(" "'(\"#\\\")" */ while (i < end) { i++; if (expr[i] == '\\') i++; else { if (expr[i] == '\"') break; } } i++; if (paren_count == 0) { if (i < end) return(i); else return(0); } else { prev_separator = true; not_whitespace = true; quote_wait = false; } } break; case '#': if ((i < end - 1) && (expr[i + 1] == '|')) { /* (+ #| a comment |# 2 1) */ i++; do { i++; } while (((expr[i] != '|') || (expr[i + 1] != '#')) && (i < end)); i++; break; } else { /* (set! *#readers* (cons (cons #\c (lambda (str) (apply make-rectangular (read)))) *#readers*)) */ if ((not_whitespace) && (paren_count == 0) && (!quote_wait)) return(i); else { bool found_it = false; if (prev_separator) { int k, incr = 0; for (k = i + 1; k < end; k++) { if (expr[k] == '(') { /* should we look at the readers here? I want to support #c(1 2) for example */ not_whitespace = false; prev_separator = false; incr = k - i; break; } else { if ((!isdigit(expr[k])) && /* #2d(...)? */ (!isalpha(expr[k])) && /* #c(1 2)? */ (expr[k] != 'D') && (expr[k] != 'd') && (expr[k] != '=') && /* what is this for? */ (expr[k] != '#')) /* perhaps #1d(#(1 2) 3) ? */ break; } } if (incr > 0) { i += incr; found_it = true; } } if (!found_it) { if ((i + 2 < end) && (expr[i + 1] == '\\') && ((expr[i + 2] == ')') || (expr[i + 2] == ';') || (expr[i + 2] == '\"') || (expr[i + 2] == '('))) i += 3; else { prev_separator = false; quote_wait = false; not_whitespace = true; i++; } } } } break; case '(' : if ((not_whitespace) && (paren_count == 0) && (!quote_wait)) return(i - 1); /* 'a(...) -- ignore the (...) */ else { i++; paren_count++; not_whitespace = true; prev_separator = true; quote_wait = false; } break; case ')' : paren_count--; if ((not_whitespace) && (paren_count == 0)) return(i + 1); else { i++; not_whitespace = true; prev_separator = true; quote_wait = false; } break; case '\'' : case '`' : /* `(1 2) */ if (prev_separator) quote_wait = true; not_whitespace = true; i++; break; case ',': /* `,(+ 1 2) */ case '@': /* `,@(list 1 2) */ prev_separator = false; not_whitespace = true; i++; break; default: prev_separator = false; quote_wait = false; not_whitespace = true; i++; break; } } if ((in_listener) && (!(highlight_unbalanced_paren()))) return(-1); return(0); } #endif static char listener_prompt_buffer[LABEL_BUFFER_SIZE]; static char *listener_prompt_with_cr(void) { snprintf(listener_prompt_buffer, LABEL_BUFFER_SIZE, "\n%s", listener_prompt(ss)); return(listener_prompt_buffer); } #define GUI_TEXT_END(w) XmTextGetLastPosition(w) #define GUI_TEXT_POSITION_TYPE XmTextPosition #define GUI_TEXT(w) XmTextGetString(w) #define GUI_TEXT_INSERTION_POSITION(w) XmTextGetInsertionPosition(w) #define GUI_TEXT_SET_INSERTION_POSITION(w, pos) XmTextSetInsertionPosition(w, pos) #define GUI_LISTENER_TEXT_INSERT(w, pos, text) XmTextInsert(w, pos, text) #define GUI_FREE(w) XtFree(w) #define GUI_SET_CURSOR(w, cursor) XUndefineCursor(XtDisplay(w), XtWindow(w)); XDefineCursor(XtDisplay(w), XtWindow(w), cursor) #define GUI_UNSET_CURSOR(w, cursor) XUndefineCursor(XtDisplay(w), XtWindow(w)); XDefineCursor(XtDisplay(w), XtWindow(w), None) #define GUI_UPDATE(w) XmUpdateDisplay(w) #define GUI_TEXT_GOTO(w, pos) XmTextShowPosition(w, pos) static int current_listener_position = -1, listener_positions_size = 0; static int *listener_positions = NULL; static void add_listener_position(int pos) { if (listener_positions_size == 0) { listener_positions_size = 32; listener_positions = (int *)calloc(listener_positions_size, sizeof(int)); current_listener_position = 0; } else { int i; if (pos > listener_positions[current_listener_position]) { current_listener_position++; if (current_listener_position >= listener_positions_size) { listener_positions_size += 32; listener_positions = (int *)realloc(listener_positions, listener_positions_size * sizeof(int)); for (i = current_listener_position + 1; i < listener_positions_size; i++) listener_positions[i] = 0; } } else { for (i = current_listener_position - 1; i >= 0; i--) if (listener_positions[i] < pos) break; current_listener_position = i + 1; } } listener_positions[current_listener_position] = pos; } static void backup_listener_to_previous_expression(void) { if (current_listener_position > 0) { current_listener_position--; listener_delete_text(listener_positions[current_listener_position]); } } #if HAVE_SCHEME static s7_pointer top_level_let = NULL; static s7_pointer g_top_level_let(s7_scheme *sc, s7_pointer args) { return(top_level_let); } static s7_pointer g_set_top_level_let(s7_scheme *sc, s7_pointer args) { top_level_let = s7_car(args); return(top_level_let); } #endif static void listener_return(widget_t w, int last_prompt) { #if (!USE_NO_GUI) /* try to find complete form either enclosing current cursor, or just before it */ GUI_TEXT_POSITION_TYPE cmd_eot = 0; char *str = NULL, *full_str = NULL; int i, j; Xen form = Xen_undefined; GUI_TEXT_POSITION_TYPE last_position = 0, current_position = 0; #if (!HAVE_RUBY && !HAVE_FORTH) GUI_TEXT_POSITION_TYPE end_of_text = 0, start_of_text = 0; int parens; #if USE_MOTIF GUI_TEXT_POSITION_TYPE new_eot = 0; #endif #endif full_str = GUI_TEXT(w); current_position = GUI_TEXT_INSERTION_POSITION(w); #if (!HAVE_RUBY && !HAVE_FORTH) start_of_text = current_position; end_of_text = current_position; #endif last_position = GUI_TEXT_END(w); add_listener_position(last_position); #if (!HAVE_SCHEME) if (have_read_hook()) { Xen result; int len; len = last_position - last_prompt; if (len > 0) { str = (char *)calloc(len + 1, sizeof(char)); for (i = last_prompt, j = 0; i < last_position; i++, j++) str[j] = full_str[i]; result = run_read_hook(str); free(str); if (Xen_is_true(result)) { if (full_str) GUI_FREE(full_str); return; } } } #endif /* prompt = listener_prompt(ss); */ /* first look for a form just before the current mouse location, * independent of everything (i.e. user may have made changes * in a form included in a comment, then typed return, expecting * us to use the new version, but the check_balance procedure * tries to ignore comments). */ str = NULL; #if HAVE_RUBY || HAVE_FORTH { int k, len, start, full_len; for (i = current_position - 1; i >= 0; i--) if (is_prompt(full_str, i)) { full_len = strlen(full_str); for (k = current_position - 1; k < full_len; k++) if (full_str[k] == '\n') break; start = i + 1; len = (k - start + 1); str = (char *)calloc(len, sizeof(char)); for (k = 0; k < len - 1; k++) str[k] = full_str[k + start]; break; } } #else if (last_position > end_of_text) { end_of_text = last_position; /* added 12-Nov-07 for first form */ for (i = current_position; i < last_position; i++) if (is_prompt(full_str, i + 1)) { /* fprintf(stderr, "set end to %d (%d)\n", i - ss->listener_prompt_length + 1, i); */ end_of_text = i - ss->listener_prompt_length + 1; break; } } if (start_of_text > 0) { for (i = end_of_text; i >= 0; i--) if (is_prompt(full_str, i)) { /* fprintf(stderr, "set start to %d\n", i + 1); */ start_of_text = i + 1; break; } } /* fprintf(stderr, "found %d %d\n", start_of_text, end_of_text); */ if (end_of_text > start_of_text) { int slen; parens = 0; slen = end_of_text - start_of_text + 2; str = (char *)calloc(slen, sizeof(char)); for (i = start_of_text, j = 0; i <= end_of_text; j++, i++) { str[j] = full_str[i]; if (str[j] == '(') parens++; } str[end_of_text - start_of_text + 1] = 0; end_of_text = mus_strlen(str); if (parens) { end_of_text = check_balance(str, 0, (int)end_of_text, true); /* last-arg->we are in the listener */ if ((end_of_text > 0) && (end_of_text < slen)) { if (end_of_text < (slen - 1)) str[end_of_text + 1] = 0; else str[end_of_text] = 0; if (str[end_of_text] == '\n') str[end_of_text] = 0; } else { free(str); str = NULL; if (end_of_text < 0) listener_append_and_prompt(NULL); else { #if USE_MOTIF new_eot = GUI_TEXT_END(w); GUI_LISTENER_TEXT_INSERT(w, new_eot, (char *)"\n"); #else GUI_LISTENER_TEXT_INSERT(w, 0, (char *)"\n"); #endif } if (full_str) GUI_FREE(full_str); return; } } else { /* no parens -- pick up closest entity */ int loc, k, len; char *tmp; loc = current_position - start_of_text - 1; for (i = loc; i >= 0; i--) if ((str[i] == '\n') || (i == 0)) { len = mus_strlen(str); tmp = (char *)calloc(len + 1, sizeof(char)); if (i != 0) i++; for (k = 0; i < len; i++, k++) if ((i > loc) && ((str[i] == '\n') || (str[i] == ' '))) break; else tmp[k] = str[i]; free(str); str = tmp; break; } } } #endif if (full_str) GUI_FREE(full_str); { bool need_eval = false; int i, len; /* fprintf(stderr, "return: %s\n", str); */ len = mus_strlen(str); for (i = 0; i < len; i++) if ((str[i] != ' ') && (str[i] != '\n') && (str[i] != '\r') && (str[i] != '\t')) { need_eval = true; break; } if (!need_eval) append_listener_text(-1, "\n"); else { if (str) { char *errmsg = NULL; if (current_position < (last_position - 2)) GUI_LISTENER_TEXT_INSERT(w, GUI_TEXT_END(w), str); GUI_SET_CURSOR(w, ss->wait_cursor); GUI_UPDATE(w); /* not sure about this... */ if ((mus_strlen(str) > 1) || (str[0] != '\n')) remember_listener_string(str); #if HAVE_RUBY || HAVE_FORTH form = Xen_eval_C_string(str); #endif #if HAVE_SCHEME /* very tricky -- we need the interface running to see C-g, and in ordinary (not-hung, but very slow-to-compute) code * we need to let other interface stuff run. We can't look at each event and flush all but the C-g we're waiting * for because that confuses the rest of the GUI, and some such interactions are expected. But if interface actions * are tied to scheme code, the check_for_event lets that code be evaluated, even though we're actually running * the evaluator already in a separate thread. If we block on the thread ID (pthread_self), bad stuff still gets * through somehow. * * s7 threads here only solves the s7 side of the problem. To make the Gtk calls thread-safe, * we have to use gdk threads, and that means either wrapping every gtk section thoughout Snd in * gdk_thread_enter/leave, or expecting the caller to do that in every expression he types in the listener. * * Using clone_s7 code in s7 for CL-like stack-groups is much trickier * than I thought -- it's basically importing all the pthread GC and alloc stuff into the main s7. * * So... set begin_hook to a func that calls gtk_main_iteration or check_for_event; * if C-g, the begin_hook func returns true, and s7 calls s7_quit, and C_g_typed is true here. * Otherwise, I think anything is safe because we're only looking at the block start, and * we're protected there by a stack barrier. * * But this polling at block starts is expensive, mainly because XtAppPending and gtk_events_pending * are very slow. So with_interrupts can turn off this check. */ if (s7_begin_hook(s7)) return; /* s7 is already running (user typed during computation) */ if ((mus_strlen(str) > 1) || (str[0] != '\n')) { s7_int gc_loc; s7_pointer old_port; old_port = s7_set_current_error_port(s7, s7_open_output_string(s7)); gc_loc = s7_gc_protect(s7, old_port); if (with_interrupts(ss)) s7_set_begin_hook(s7, listener_begin_hook); if (have_read_hook()) form = run_read_hook(str); else form = s7_eval_c_string_with_environment(s7, str, top_level_let); s7_set_begin_hook(s7, NULL); if (ss->C_g_typed) { errmsg = mus_strdup("\nSnd interrupted!"); ss->C_g_typed = false; } else errmsg = mus_strdup(s7_get_output_string(s7, s7_current_error_port(s7))); s7_close_output_port(s7, s7_current_error_port(s7)); s7_set_current_error_port(s7, old_port); s7_gc_unprotect_at(s7, gc_loc); } #endif if (errmsg) { if (*errmsg) snd_display_result(errmsg, NULL); free(errmsg); } else snd_report_listener_result(form); /* used to check for unbound form here, but that's no good in Ruby */ free(str); str = NULL; GUI_UNSET_CURSOR(w, ss->arrow_cursor); } else { listener_append_and_prompt(NULL); } } } cmd_eot = GUI_TEXT_END(w); add_listener_position(cmd_eot); GUI_TEXT_GOTO(w, cmd_eot - 1); GUI_TEXT_SET_INSERTION_POSITION(w, cmd_eot + 1); #endif } /* -------------------------------------------------------------------------------- */ #define OVERRIDE_TOGGLE 1 /* Motif 2.0 defines control-button1 to be "take focus" -- this is not a good idea!! */ static void Tab_completion(Widget w, XEvent *event, char **str, Cardinal *num) { int completer; intptr_t data; XtVaGetValues(w, XmNuserData, &data, NULL); completer = (int)data; if (completer >= 0) { int matches; char *old_text, *new_text; old_text = XmTextGetString(w); if (mus_strlen(old_text) == 0) return; /* C-x C-f TAB in kbd??, for example */ new_text = complete_text(w, old_text, completer); if (mus_strlen(new_text) == 0) return; /* can this happen? */ XmTextSetString(w, new_text); XmTextSetCursorPosition(w, XmTextGetLastPosition(w)); matches = get_completion_matches(); if ((mus_strcmp(old_text, new_text)) && (matches != -1)) { Pixel old_color; XtVaGetValues(w, XmNforeground, &old_color, NULL); if (matches > 1) XtVaSetValues(w, XmNforeground, ss->green, NULL); else if (matches == 0) XtVaSetValues(w, XmNforeground, ss->red, NULL); if (matches != 1) { XmUpdateDisplay(w); sleep(1); XtVaSetValues(w, XmNforeground, old_color, NULL); XmUpdateDisplay(w); } if (matches > 1) /* there are several possible completions -- let the widget decide how to handle it */ handle_completions(w, completer); } if (old_text) XtFree(old_text); if (new_text) free(new_text); } } /* listener completions */ static Widget listener_text = NULL; static Widget listener_pane = NULL; /* form widget that hold the listener scrolled text widget */ static Widget completions_list = NULL; static Widget completions_pane = NULL; static void perform_completion(XmString selection) { int i, j, old_len, new_len; char *text = NULL, *old_text = NULL; text = (char *)XmStringUnparse(selection, NULL, XmCHARSET_TEXT, XmCHARSET_TEXT, NULL, 0, XmOUTPUT_ALL); save_completion_choice(text); old_text = XmTextGetString(listener_text); old_len = mus_strlen(old_text); new_len = mus_strlen(text); for (i = old_len - 1, j = new_len - 1; j >= 0; j--) { if (old_text[i] != text[j]) { i = old_len - 1; if (old_text[i] == text[j]) i--; /* this added 15-Apr-02 for case like map-chan(nel) */ /* probably should go back new_len and scan forwards instead */ } else i--; } append_listener_text(XmTextGetLastPosition(listener_text), (char *)(text - 1 + old_len - i)); if (text) XtFree(text); if (old_text) XtFree(old_text); } static void listener_completions_browse_callback(Widget w, XtPointer context, XtPointer info) { XmListCallbackStruct *cbs = (XmListCallbackStruct *)info; /* choice = cbs->item_position - 1; */ perform_completion(cbs->item); XtUnmanageChild(completions_pane); } static int alphabetize(const void *a, const void *b) { return(strcmp(*((const char **)a), (*(const char **)b))); } static int find_prompt(Widget w, XmTextPosition start) { Boolean found_prompt = false, found_newline; XmTextPosition loc = 0; if (start == 0) /* try to avoid strlen null in motif */ return(0); /* the prompt defaults to ">", so a naive backwards search for the prompt is easily confused. * (bugfix thanks to Tito Latini). */ while (!found_prompt) { found_newline = XmTextFindString(w, start, (char *)"\n", XmTEXT_BACKWARD, &loc); start = found_newline ? loc : 0; found_prompt = XmTextFindString(w, start, listener_prompt(ss), XmTEXT_FORWARD, &loc); if ((found_prompt && loc <= (start + 1)) || (start == 0)) break; start--; } if (!found_prompt) return(0); else return((int)loc + mus_strlen(listener_prompt(ss))); } static void motif_listener_completion(Widget w, XEvent *event, char **str, Cardinal *num) /* change name because emacs is confused */ { /* used only by the listener widget -- needs to be smart about text since overall string can be enormous * and we don't want to back up past the last prompt * also if at start of line (or all white-space to previous \n), indent */ int beg, end, replace_end, len; char *old_text; if ((completions_pane) && (XtIsManaged(completions_pane))) { XmString *strs = NULL; XtVaGetValues(completions_list, XmNselectedItems, &strs, NULL); if (strs) { perform_completion(strs[0]); XtUnmanageChild(completions_pane); return; } } end = XmTextGetInsertionPosition(w); replace_end = end; beg = find_prompt(w, (XmTextPosition)end); len = end - beg + 1; old_text = (char *)calloc(len + 1, sizeof(char)); XmTextGetSubstring(w, beg, len, len + 1, old_text); /* now old_text is the stuff typed since the last prompt */ if (old_text[len - 1] == '\n') { old_text[len - 1] = 0; end--; } if (old_text) { int matches = 0; char *new_text = NULL, *file_text = NULL; bool try_completion = true; new_text = complete_listener_text(old_text, end, &try_completion, &file_text); if (!try_completion) { free(old_text); return; } if (mus_strcmp(old_text, new_text)) matches = get_completion_matches(); else XmTextReplace(w, beg, replace_end, new_text); if (new_text) { free(new_text); new_text = NULL; } if (matches > 1) { int num; clear_possible_completions(); set_save_completions(true); if (file_text) new_text = filename_completer(w, file_text, NULL); else new_text = expression_completer(w, old_text, NULL); if (new_text) { free(new_text); new_text = NULL; } num = get_possible_completions_size(); if (num > 0) { int i; XmString *match; char **buffer; if (!completions_list) { Arg args[20]; int n = 0; XtSetArg(args[n], XmNleftAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNscrollBarPlacement, XmBOTTOM_LEFT); n++; XtSetArg(args[n], XmNbackground, ss->white); n++; XtSetArg(args[n], XmNforeground, ss->black); n++; XtSetArg(args[n], XmNselectColor, ss->selection_color); n++; completions_list = XmCreateScrolledList(listener_pane, (char *)"completion-help-text", args, n); completions_pane = XtParent(completions_list); XtAddCallback(completions_list, XmNbrowseSelectionCallback, listener_completions_browse_callback, NULL); XtManageChild(completions_list); } buffer = get_possible_completions(); qsort((void *)buffer, num, sizeof(char *), alphabetize); match = (XmString *)calloc(num, sizeof(XmString)); for (i = 0; i < num; i++) match[i] = XmStringCreateLocalized(buffer[i]); XtVaSetValues(completions_list, XmNitems, match, XmNitemCount, num, XmNvisibleItemCount, mus_iclamp(1, num, 20), NULL); if (!(XtIsManaged(completions_pane))) XtManageChild(completions_pane); /* look at previous completions list first for a match, then * look back from "beg" for any member of the match list previously typed */ { int row; row = find_best_completion(buffer, num); XmListSelectPos(completions_list, row, false); ensure_list_row_visible(completions_list, row); } for (i = 0; i < num; i++) XmStringFree(match[i]); free(match); } set_save_completions(false); } if (file_text) free(file_text); if (old_text) free(old_text); } } /* ---------------- text widget specializations ---------------- */ void textfield_focus_callback(Widget w, XtPointer context, XtPointer info) { XtVaSetValues(w, XmNbackground, ss->text_focus_color, NULL); XtVaSetValues(w, XmNcursorPositionVisible, true, NULL); } void textfield_unfocus_callback(Widget w, XtPointer context, XtPointer info) { XtVaSetValues(w, XmNbackground, ss->basic_color, NULL); XtVaSetValues(w, XmNcursorPositionVisible, false, NULL); } static void textfield_no_color_focus_callback(Widget w, XtPointer context, XtPointer info) { XtVaSetValues(w, XmNcursorPositionVisible, true, NULL); } static void textfield_no_color_unfocus_callback(Widget w, XtPointer context, XtPointer info) { XtVaSetValues(w, XmNcursorPositionVisible, false, NULL); } /* -------- specialized action procs -------- */ static bool actions_loaded = false; #define CONTROL_KEY 4 static void No_op(Widget w, XEvent *ev, char **str, Cardinal *num) { /* return does not cause widget activation in many textfield cases -- it is a true no-op */ } #define snd_K_u XK_u #define snd_K_x XK_x static void Activate_keyboard(Widget w, XEvent *ev, char **str, Cardinal *num) { /* make the current channel active preloading kbd cmd with str[0]+ctrl bit */ chan_info *cp; cp = current_channel(); if (cp) { goto_graph(cp); keyboard_command(cp, (str[0][0] == 'u') ? snd_K_u : snd_K_x, CONTROL_KEY); } } static char *listener_selection = NULL; static void Kill_line(Widget w, XEvent *ev, char **str, Cardinal *num) { /* C-k with storage of killed text */ XmTextPosition curpos, loc; Boolean found; curpos = XmTextGetCursorPosition(w); found = XmTextFindString(w, curpos, (char *)"\n", XmTEXT_FORWARD, &loc); if (!found) loc = XmTextGetLastPosition(w); if (loc > curpos) { if (listener_selection) {XtFree(listener_selection); listener_selection = NULL;} XmTextSetSelection(w, curpos, loc, CurrentTime); listener_selection = XmTextGetSelection(w); /* xm manual p329 sez storage is allocated here */ XmTextCut(w, CurrentTime); } } static void Yank(Widget w, XEvent *ev, char **str, Cardinal *num) { /* copy current selection at current cursor position */ if (listener_selection) { XmTextPosition curpos; curpos = XmTextGetCursorPosition(w); XmTextInsert(w, curpos, listener_selection); curpos += strlen(listener_selection); XmTextShowPosition(w, curpos); XmTextSetCursorPosition(w, curpos); XmTextClearSelection(w, ev->xkey.time); /* so C-y + edit doesn't forbid the edit */ } } static void Begin_of_line(Widget w, XEvent *ev, char **ustr, Cardinal *num) { /* don't back up before listener prompt */ XmTextPosition curpos, loc; Boolean found; curpos = XmTextGetCursorPosition(w) - 1; found = XmTextFindString(w, curpos, (char *)"\n", XmTEXT_BACKWARD, &loc); if (curpos >= ss->listener_prompt_length - 1) { char *str = NULL; str = (char *)calloc(ss->listener_prompt_length + 3, sizeof(char)); loc = found ? loc + 1 : 0; XmTextGetSubstring(w, loc, ss->listener_prompt_length, ss->listener_prompt_length + 2, str); if (strncmp(listener_prompt(ss), str, ss->listener_prompt_length) == 0) XmTextSetCursorPosition(w, loc + ss->listener_prompt_length); else XmTextSetCursorPosition(w, loc); free(str); } else XmTextSetCursorPosition(w, 0); } static void Delete_region(Widget w, XEvent *ev, char **str, Cardinal *num) { XmTextCut(w, CurrentTime); } static XmTextPosition down_pos, last_pos; static Xen listener_click_hook; static void B1_press(Widget w, XEvent *event, char **str, Cardinal *num) { XmTextPosition pos; XButtonEvent *ev = (XButtonEvent *)event; XmProcessTraversal(w, XmTRAVERSE_CURRENT); /* we're replacing the built-in take_focus action here, so do it by hand, but leave listener blue, so to speak */ if (w != listener_text) XtVaSetValues(w, XmNbackground, ss->white, NULL); else XmTextClearSelection(listener_text, CurrentTime); /* should this happen in other windows as well? */ pos = XmTextXYToPos(w, (Position)(ev->x), (Position)(ev->y)); XmTextSetCursorPosition(w, pos); down_pos = pos; last_pos = pos; if (Xen_hook_has_list(listener_click_hook)) run_hook(listener_click_hook, Xen_list_1(C_int_to_Xen_integer((int)pos)), S_listener_click_hook); } static void B1_move(Widget w, XEvent *event, char **str, Cardinal *num) { XmTextPosition pos; XButtonEvent *ev = (XButtonEvent *)event; pos = XmTextXYToPos(w, (Position)(ev->x), (Position)(ev->y)); if (last_pos > pos) /* must have backed up the cursor */ XmTextSetHighlight(w, pos, last_pos, XmHIGHLIGHT_NORMAL); if (down_pos != pos) XmTextSetHighlight(w, down_pos, pos, XmHIGHLIGHT_SELECTED); last_pos = pos; } static void B1_release(Widget w, XEvent *event, char **str, Cardinal *num) { XmTextPosition pos; XButtonEvent *ev = (XButtonEvent *)event; pos = XmTextXYToPos(w, (Position)(ev->x), (Position)(ev->y)); XmTextSetCursorPosition(w, pos); if (down_pos != pos) { XmTextSetHighlight(w, down_pos, pos, XmHIGHLIGHT_SELECTED); if (listener_selection) {XtFree(listener_selection); listener_selection = NULL;} XmTextSetSelection(w, down_pos, pos, CurrentTime); listener_selection = XmTextGetSelection(w); } } static void Text_transpose(Widget w, XEvent *event, char **str, Cardinal *num) { XmTextPosition curpos; curpos = XmTextGetCursorPosition(w); if (curpos > 1) { char buf[3]; /* needs room for null */ char tmp; XmTextGetSubstring(w, (XmTextPosition)(curpos - 1), 2, 3, buf); tmp = buf[0]; buf[0] = buf[1]; buf[1] = tmp; XmTextReplace(w, curpos - 1, curpos + 1, buf); XmTextSetCursorPosition(w, curpos + 1); } } static void Complain(Widget w, XEvent *event, char **str, Cardinal *num) { char *old_text, *new_text; XmTextPosition curpos; int len; curpos = XmTextGetCursorPosition(w); old_text = XmTextGetString(w); len = mus_strlen(old_text) + 5; new_text = (char *)calloc(len, sizeof(char)); snprintf(new_text, len, "%s C-%c", (old_text) ? old_text : "", str[0][0]); XmTextSetString(w, new_text); XmTextSetCursorPosition(w, curpos); if (old_text) XtFree(old_text); free(new_text); } static void text_at_cursor(Widget w) { XmTextPosition curpos, endpos, start, end; int len, prompt_pos; char *buf; curpos = XmTextGetCursorPosition(w); if (curpos <= 1) curpos = XmTextGetInsertionPosition(w); if (curpos <= 1) { snd_help("Listener", "This is the 'listener', a text widget in which you can interact with Snd's extension language. See extsnd.html.", WITH_WORD_WRAP); return; } prompt_pos = find_prompt(w, curpos); if (curpos > 40) start = curpos - 40; else start = 0; if (start < prompt_pos) start = prompt_pos; endpos = XmTextGetLastPosition(w); if ((endpos - curpos) > 40) end = curpos + 40; else end = endpos; len = end - start + 1; buf = (char *)calloc(len + 1, sizeof(char)); XmTextGetSubstring(w, start, len, len + 1, buf); listener_help_at_cursor(buf, curpos - start - 1, len, prompt_pos); free(buf); } static void Help_At_Cursor(Widget w, XEvent *ev, char **str, Cardinal *num) { text_at_cursor(w); } static void Word_upper(Widget w, XEvent *event, char **str, Cardinal *num) { bool up, cap; XmTextPosition curpos, endpos; up = (str[0][0] == 'u'); cap = (str[0][0] == 'c'); curpos = XmTextGetCursorPosition(w); endpos = XmTextGetLastPosition(w); if (curpos < endpos) { int i, length, wstart, wend; char *buf = NULL; length = endpos - curpos; buf = (char *)calloc(length + 1, sizeof(char)); XmTextGetSubstring(w, curpos, length, length + 1, buf); wstart = 0; wend = length; for (i = 0; i < length; i++) if (!isspace((int)(buf[i]))) { wstart = i; break; } for (i = wstart + 1; i < length; i++) if (isspace((int)(buf[i]))) { wend = i; break; } if (cap) { buf[0] = toupper(buf[wstart]); buf[1] = '\0'; XmTextReplace(w, curpos + wstart, curpos + wstart + 1, buf); } else { int j; for (i = wstart, j = 0; i < wend; i++, j++) if (up) buf[j] = toupper(buf[i]); else buf[j] = tolower(buf[i]); buf[j] = '\0'; XmTextReplace(w, curpos + wstart, curpos + wend, buf); } XmTextSetCursorPosition(w, curpos + wend); if (buf) free(buf); } } void append_listener_text(int end, const char *msg) { if (listener_text) { if (end == -1) end = XmTextGetLastPosition(listener_text); XmTextInsert(listener_text, end, (char *)msg); XmTextSetCursorPosition(listener_text, XmTextGetLastPosition(listener_text)); } } static bool dont_check_motion = false; void listener_delete_text(int new_end) { int old_end; old_end = XmTextGetLastPosition(listener_text); if (old_end > new_end) { dont_check_motion = true; XmTextSetSelection(listener_text, new_end, old_end, CurrentTime); XmTextRemove(listener_text); dont_check_motion = false; } } static void Listener_Meta_P(Widget w, XEvent *event, char **str, Cardinal *num) { listener_delete_text(find_prompt(w, XmTextGetInsertionPosition(w))); restore_listener_string(true); } static void Listener_Meta_N(Widget w, XEvent *event, char **str, Cardinal *num) { listener_delete_text(find_prompt(w, XmTextGetInsertionPosition(w))); restore_listener_string(false); } int save_listener_text(FILE *fp) { /* return -1 if fwrite problem */ if (listener_text) { char *str = NULL; str = XmTextGetString(listener_text); if (str) { size_t bytes; bytes = fwrite((void *)str, sizeof(char), mus_strlen(str), fp); XtFree(str); if (bytes == 0) return(-1); } } return(0); } static void Listener_clear(Widget w, XEvent *event, char **str, Cardinal *num) { clear_listener(); } static void Listener_g(Widget w, XEvent *event, char **str, Cardinal *num) { ss->C_g_typed = true; control_g(any_selected_sound()); } static void Listener_Backup(Widget w, XEvent *event, char **str, Cardinal *num) { backup_listener_to_previous_expression(); } static void Listener_Arrow_Up(Widget w, XEvent *event, char **str, Cardinal *num) { if ((completions_pane) && (XtIsManaged(completions_pane))) { int *ns; int n; XmListGetSelectedPos(completions_list, &ns, &n); if (ns[0] > 1) XmListSelectPos(completions_list, ns[0] - 1, false); free(ns); } else XtCallActionProc(w, "previous-line", event, str, *num); } static void Listener_Arrow_Down(Widget w, XEvent *event, char **str, Cardinal *num) { if ((completions_pane) && (XtIsManaged(completions_pane))) { int *ns; int n; XmListGetSelectedPos(completions_list, &ns, &n); XmListSelectPos(completions_list, ns[0] + 1, false); free(ns); } else XtCallActionProc(w, "next-line", event, str, *num); } static void Listener_Return(Widget w, XEvent *event, char **str, Cardinal *num) { if ((completions_pane) && (XtIsManaged(completions_pane))) { XmString *strs = NULL; XtVaGetValues(completions_list, XmNselectedItems, &strs, NULL); if (strs) { perform_completion(strs[0]); XtUnmanageChild(completions_pane); } } else XtCallActionProc(w, "activate", event, str, *num); } #define NUM_ACTS 24 static XtActionsRec acts[NUM_ACTS] = { {(char *)"no-op", No_op}, {(char *)"activate-keyboard", Activate_keyboard}, {(char *)"yank", Yank}, {(char *)"delete-region", Delete_region}, {(char *)"kill-line", Kill_line}, {(char *)"begin-of-line", Begin_of_line}, {(char *)"b1-press", B1_press}, {(char *)"b1-move", B1_move}, {(char *)"b1-release", B1_release}, {(char *)"text-transpose", Text_transpose}, {(char *)"word-upper", Word_upper}, {(char *)"tab-completion", Tab_completion}, {(char *)"listener-completion", motif_listener_completion}, {(char *)"listener-clear", Listener_clear}, {(char *)"listener-g", Listener_g}, {(char *)"listener-meta-p", Listener_Meta_P}, {(char *)"listener-meta-n", Listener_Meta_N}, {(char *)"listener-next-line", Listener_Arrow_Down}, {(char *)"listener-previous-line", Listener_Arrow_Up}, {(char *)"listener-return", Listener_Return}, {(char *)"delete-to-previous-command", Listener_Backup}, {(char *)"complain", Complain}, {(char *)"help-at-cursor", Help_At_Cursor}, }; /* translation tables for emacs compatibility and better inter-widget communication */ /* these values are listed in lib/Xm/Transltns.c */ /* for textfield (single-line) widgets */ static char TextTrans2[] = "Ctrl a: beginning-of-line()\n\ Ctrl b: backward-character()\n\ Mod1 b: backward-word()\n\ Mod1 c: word-upper(c)\n\ Ctrl c: complain(c)\n\ Ctrl d: delete-next-character()\n\ Mod1 d: delete-next-word()\n\ Ctrl e: end-of-line()\n\ Ctrl f: forward-character()\n\ Mod1 f: forward-word()\n\ Ctrl g: activate()\n\ Ctrl h: delete-previous-character()\n\ Ctrl i: complain(i)\n\ Ctrl j: complain(j)\n\ Ctrl k: delete-to-end-of-line()\n\ Mod1 l: word-upper(l)\n\ Ctrl m: complain(m)\n\ Ctrl n: complain(n)\n\ Mod1 n: activate()\n\ Ctrl o: complain(o)\n\ Mod1 p: activate()\n\ Ctrl p: complain(p)\n\ Ctrl q: complain(q)\n\ Ctrl r: activate()\n\ Ctrl s: activate()\n\ Ctrl t: text-transpose()\n\ Mod1 u: word-upper(u)\n\ Ctrl u: complain(u)\n\ Ctrl v: complain(v)\n\ Ctrl w: complain(w)\n\ Ctrl x: activate-keyboard(x)\n\ Ctrl y: complain(y)\n\ Ctrl z: complain(z)\n\ Mod1 <: beginning-of-line()\n\ Mod1 >: end-of-line()\n\ Delete: delete-previous-character()\n\ Mod1 Delete: delete-to-start-of-line()\n\ Tab: tab-completion()\n\ Return: activate()\n"; static XtTranslations transTable2 = NULL; /* same (but not activatable), try to avoid causing the currently active pushbutton widget to appear to be activated by in the text widget */ static char TextTrans6[] = "Ctrl a: beginning-of-line()\n\ Ctrl b: backward-character()\n\ Mod1 b: backward-word()\n\ Mod1 c: word-upper(c)\n\ Ctrl d: delete-next-character()\n\ Mod1 d: delete-next-word()\n\ Ctrl e: end-of-line()\n\ Ctrl f: forward-character()\n\ Mod1 f: forward-word()\n\ Ctrl g: no-op()\n\ Ctrl h: delete-previous-character()\n\ Ctrl k: delete-to-end-of-line()\n\ Mod1 l: word-upper(l)\n\ Ctrl t: text-transpose()\n\ Mod1 u: word-upper(u)\n\ Mod1 <: beginning-of-line()\n\ Mod1 >: end-of-line()\n\ Delete: delete-previous-character()\n\ Mod1 Delete: delete-to-start-of-line()\n\ Tab: tab-completion()\n\ Return: no-op()\n"; static XtTranslations transTable6 = NULL; /* for text (multi-line) widgets */ static char TextTrans3[] = "Ctrl a: beginning-of-line()\n\ Ctrl b: backward-character()\n\ Mod1 b: backward-word()\n\ Mod1 c: word-upper(c)\n\ Ctrl d: delete-next-character()\n\ Mod1 d: delete-next-word()\n\ Ctrl e: end-of-line()\n\ Ctrl f: forward-character()\n\ Mod1 f: forward-word()\n\ Ctrl g: activate()\n\ Ctrl h: delete-previous-character()\n\ Ctrl j: newline-and-indent()\n\ Ctrl k: kill-line()\n\ Mod1 l: word-upper(l)\n\ Ctrl n: next-line()\n\ Ctrl o: newline-and-backup()\n\ Ctrl p: previous-line()\n\ Ctrl t: text-transpose()\n\ Mod1 u: word-upper(u)\n\ Ctrl v: next-page()\n\ Mod1 v: previous-page()\n\ Ctrl w: delete-region()\n\ Ctrl y: yank()\n\ Ctrl z: activate()\n\ Mod1 [: backward-paragraph()\n\ Mod1 ]: forward-paragraph()\n\ Mod1 <: beginning-of-file()\n\ Mod1 >: end-of-file()\n\ Delete: delete-previous-character()\n\ Mod1 Delete: delete-to-start-of-line()\n\ Ctrl osfLeft: page-left()\n\ Ctrl osfRight: page-right()\n\ Ctrl osfDown: next-page()\n\ Ctrl osfUp: previous-page()\n\ Ctrl space: set-anchor()\n\ : b1-press()\n\ : b1-release()\n\ : b1-move()\n\ Return: newline()\n"; static XtTranslations transTable3 = NULL; /* for lisp listener */ static char TextTrans4[] = "Ctrl a: begin-of-line()\n\ Ctrl b: backward-character()\n\ Mod1 b: backward-word()\n\ Mod1 c: word-upper(c)\n\ Ctrl d: delete-next-character()\n\ Mod1 d: delete-next-word()\n\ Ctrl e: end-of-line()\n\ Ctrl f: forward-character()\n\ Mod1 f: forward-word()\n\ Ctrl Meta g: listener-clear()\n\ Ctrl g: listener-g()\n\ Ctrl h: delete-previous-character()\n\ Ctrl j: newline-and-indent()\n\ Ctrl k: kill-line()\n\ Ctrl l: redraw-display()\n\ Mod1 l: word-upper(l)\n\ Ctrl n: next-line()\n\ Mod1 n: listener-meta-n()\n\ Ctrl o: newline-and-backup()\n\ Ctrl p: previous-line()\n\ Mod1 p: listener-meta-p()\n\ Ctrl t: text-transpose()\n\ Ctrl u: activate-keyboard(u)\n\ Mod1 u: word-upper(u)\n\ Ctrl v: next-page()\n\ Mod1 v: previous-page()\n\ Ctrl w: delete-region()\n\ Ctrl x: activate-keyboard(x)\n\ Ctrl y: yank()\n\ Ctrl z: activate()\n\ Ctrl ?: help-at-cursor()\n\ Mod1 .: help-at-cursor()\n\ Mod1 [: backward-paragraph()\n\ Mod1 ]: forward-paragraph()\n\ Mod1 <: beginning-of-file()\n\ Mod1 >: end-of-file()\n\ Shift Ctrl -: delete-to-previous-command()\n\ Delete: delete-previous-character()\n\ Mod1 Delete: delete-to-start-of-line()\n\ Ctrl osfLeft: page-left()\n\ Ctrl osfRight: page-right()\n\ Ctrl osfDown: next-page()\n\ Ctrl osfUp: previous-page()\n\ osfDown: listener-next-line()\n\ osfUp: listener-previous-line()\n\ Ctrl space: set-anchor()\n\ : b1-press()\n\ : b1-release()\n\ : b1-move()\n\ Tab: listener-completion()\n\ Return: listener-return()\n"; static XtTranslations transTable4 = NULL; void add_completer_to_builtin_textfield(Widget w, int completer) { /* used to make file selection dialog's file and filter text widgets act like other text field widgets */ if (!actions_loaded) { XtAppAddActions(main_app(ss), acts, NUM_ACTS); actions_loaded = true; } if (!transTable2) transTable2 = XtParseTranslationTable(TextTrans2); XtOverrideTranslations(w, transTable2); XtVaSetValues(w, XmNuserData, completer, NULL); } /* -------- text related widgets -------- */ static Xen mouse_enter_text_hook; static Xen mouse_leave_text_hook; void mouse_enter_text_callback(Widget w, XtPointer context, XEvent *event, Boolean *flag) { if (with_pointer_focus(ss)) goto_window(w); if (Xen_hook_has_list(mouse_enter_text_hook)) run_hook(mouse_enter_text_hook, Xen_list_1(Xen_wrap_widget(w)), S_mouse_enter_text_hook); } void mouse_leave_text_callback(Widget w, XtPointer context, XEvent *event, Boolean *flag) { if (Xen_hook_has_list(mouse_leave_text_hook)) run_hook(mouse_leave_text_hook, Xen_list_1(Xen_wrap_widget(w)), S_mouse_leave_text_hook); } Widget make_textfield_widget(const char *name, Widget parent, Arg *args, int n, text_cr_t activatable, int completer) { /* white background when active, emacs translations */ Widget df; if (!actions_loaded) { XtAppAddActions(main_app(ss), acts, NUM_ACTS); actions_loaded = true; } XtSetArg(args[n], XmNuserData, completer); n++; XtSetArg(args[n], XmNhighlightThickness, 1); n++; XtSetArg(args[n], XmNcursorPositionVisible, false); n++; df = XtCreateManagedWidget(name, xmTextFieldWidgetClass, parent, args, n); if (activatable != ACTIVATABLE_BUT_NOT_FOCUSED) { XtAddCallback(df, XmNfocusCallback, textfield_focus_callback, NULL); XtAddCallback(df, XmNlosingFocusCallback, textfield_unfocus_callback, NULL); } else { XtAddCallback(df, XmNfocusCallback, textfield_no_color_focus_callback, NULL); XtAddCallback(df, XmNlosingFocusCallback, textfield_no_color_unfocus_callback, NULL); } XtAddEventHandler(df, EnterWindowMask, false, mouse_enter_text_callback, NULL); XtAddEventHandler(df, LeaveWindowMask, false, mouse_leave_text_callback, NULL); if ((activatable == ACTIVATABLE) || (activatable == ACTIVATABLE_BUT_NOT_FOCUSED)) { if (!transTable2) transTable2 = XtParseTranslationTable(TextTrans2); XtOverrideTranslations(df, transTable2); } else { if (!transTable6) transTable6 = XtParseTranslationTable(TextTrans6); XtOverrideTranslations(df, transTable6); } return(df); } Widget make_text_widget(const char *name, Widget parent, Arg *args, int n) { /* white background when active, emacs translations */ /* used only for comment widget in file data box (snd-xfile.c), but needs to be in this file to pick up actions etc */ Widget df; if (!actions_loaded) { XtAppAddActions(main_app(ss), acts, NUM_ACTS); actions_loaded = true; } XtSetArg(args[n], XmNeditMode, XmMULTI_LINE_EDIT); n++; /* XmNblinkRate 0 turns off the cursor blink */ XtSetArg(args[n], XmNcursorPositionVisible, false); n++; XtSetArg(args[n], XmNhighlightThickness, 1); n++; df = XmCreateScrolledText(parent, (char *)name, args, n); XtManageChild(df); XtAddCallback(df, XmNfocusCallback, textfield_focus_callback, NULL); XtAddCallback(df, XmNlosingFocusCallback, textfield_unfocus_callback, NULL); XtAddEventHandler(df, EnterWindowMask, false, mouse_enter_text_callback, NULL); XtAddEventHandler(df, LeaveWindowMask, false, mouse_leave_text_callback, NULL); if (!transTable3) transTable3 = XtParseTranslationTable(TextTrans3); XtOverrideTranslations(df, transTable3); return(df); } /* ---------------- listener widget ---------------- */ static Widget lisp_window = NULL; void listener_append(const char *msg) { if (listener_text) XmTextInsert(listener_text, XmTextGetLastPosition(listener_text), (char *)msg); } void listener_append_and_prompt(const char *msg) { if (listener_text) { XmTextPosition cmd_eot; if (msg) XmTextInsert(listener_text, XmTextGetLastPosition(listener_text), (char *)msg); cmd_eot = XmTextGetLastPosition(listener_text); XmTextInsert(listener_text, cmd_eot, listener_prompt_with_cr()); cmd_eot = XmTextGetLastPosition(listener_text); XmTextShowPosition(listener_text, cmd_eot - 1); } } static void listener_return_callback(Widget w, XtPointer context, XtPointer info) { listener_return(w, find_prompt(w, XmTextGetInsertionPosition(w))); /* prompt loc (last prompt pos) used only by read hook */ } #if (!HAVE_FORTH) && (!HAVE_RUBY) static int flashes = 0; static int paren_pos = -1; #define FLASH_TIME 150 static void flash_unbalanced_paren(XtPointer context, XtIntervalId *id) { flashes--; XmTextSetHighlight(listener_text, paren_pos, paren_pos + 1, (flashes & 1) ? XmHIGHLIGHT_NORMAL : XmHIGHLIGHT_SELECTED); if (flashes > 0) XtAppAddTimeOut(main_app(ss), (unsigned long)FLASH_TIME, (XtTimerCallbackProc)flash_unbalanced_paren, NULL); else { XmTextSetHighlight(listener_text, paren_pos, paren_pos + 1, XmHIGHLIGHT_NORMAL); paren_pos = -1; } } static bool highlight_unbalanced_paren(void) { /* if cursor is positioned at close paren, try to find reason for unbalanced expr and highlight it */ int pos; bool success = true; pos = XmTextGetInsertionPosition(listener_text); if (pos > 2) { char *str; str = XmTextGetString(listener_text); if ((str[pos - 1] == ')') && ((str[pos - 2] != '\\') || (str[pos - 3] != '#'))) { int parens; parens = find_matching_paren(str, 2, pos - 1, &paren_pos); if (parens == 0) { XmTextSetHighlight(listener_text, paren_pos, paren_pos + 1, XmHIGHLIGHT_SELECTED); flashes = 4; XtAppAddTimeOut(main_app(ss), (unsigned long)FLASH_TIME, (XtTimerCallbackProc)flash_unbalanced_paren, NULL); } else success = false; } if (str) XtFree(str); } return(success); } #endif static int last_highlight_position = -1; static void listener_motion_callback(Widget w, XtPointer context, XtPointer info) { XmTextVerifyCallbackStruct *cbs = (XmTextVerifyCallbackStruct *)info; int pos; cbs->doit = true; if (dont_check_motion) return; if (last_highlight_position != -1) { XmTextSetHighlight(w, last_highlight_position, last_highlight_position + 1, XmHIGHLIGHT_NORMAL); last_highlight_position = -1; } pos = cbs->newInsert - 1; if (pos > 0) { char *str = NULL; str = XmTextGetString(w); if ((str[pos] == ')') && ((pos <= 1) || (str[pos - 1] != '\\') || (str[pos - 2] != '#'))) { int parens; parens = find_matching_paren(str, 1, pos, &last_highlight_position); if (parens == 0) XmTextSetHighlight(w, last_highlight_position, last_highlight_position + 1, XmHIGHLIGHT_SECONDARY_SELECTED); } if (str) XtFree(str); } } static void listener_modify_callback(Widget w, XtPointer context, XtPointer info) { XmTextVerifyCallbackStruct *cbs = (XmTextVerifyCallbackStruct *)info; /* pure motion stuff (arrow keys) does not trigger this callback */ if ((completions_pane) && (XtIsManaged(completions_pane))) XtUnmanageChild(completions_pane); if (((cbs->text)->length > 0) || (dont_check_motion)) cbs->doit = true; else { char *str = NULL; int len; str = XmTextGetString(w); len = XmTextGetLastPosition(w); if (within_prompt(str, cbs->startPos, len)) cbs->doit = false; else cbs->doit = true; if (str) XtFree(str); } } static Xen mouse_enter_listener_hook; static Xen mouse_leave_listener_hook; static void listener_focus_callback(Widget w, XtPointer context, XEvent *event, Boolean *flag) { if (with_pointer_focus(ss)) goto_window(listener_text); if (Xen_hook_has_list(mouse_enter_listener_hook)) run_hook(mouse_enter_listener_hook, Xen_list_1(Xen_wrap_widget(listener_text)), /* not w */ S_mouse_enter_listener_hook); } static void listener_unfocus_callback(Widget w, XtPointer context, XEvent *event, Boolean *flag) { if (Xen_hook_has_list(mouse_leave_listener_hook)) run_hook(mouse_leave_listener_hook, Xen_list_1(Xen_wrap_widget(listener_text)), /* not w */ S_mouse_leave_listener_hook); } /* ---------------- popup callbacks ---------------- */ static Widget listener_popup = NULL; static void listener_help_callback(Widget w, XtPointer context, XtPointer info) { char *txt; txt = XmTextGetSelection(listener_text); if (txt) { char *trim_txt; trim_txt = trim(txt); if (trim_txt) { snd_help(trim_txt, Xen_string_to_C_string(g_snd_help(C_string_to_Xen_string(trim_txt), 0)), WITH_WORD_WRAP); free(trim_txt); } XtFree(txt); } else text_at_cursor(listener_text); } static void listener_save_callback(Widget w, XtPointer context, XtPointer info) { FILE *fp = NULL; fp = FOPEN("listener.txt", "w"); if (fp) { save_listener_text(fp); snd_fclose(fp, "listener.txt"); } } static void listener_clear_callback(Widget w, XtPointer context, XtPointer info) { clear_listener(); } #if HAVE_SCHEME static void listener_stacktrace_callback(Widget w, XtPointer context, XtPointer info) { s7_pointer str; str = s7_eval_c_string(s7, "(stacktrace)"); if (s7_string_length(str) == 0) str = s7_eval_c_string(s7, "(object->string (owlet))"); snd_display_result(s7_string(str), NULL); } #endif static void listener_stop_callback(Widget w, XtPointer context, XtPointer info) { control_g(any_selected_sound()); } #if HAVE_SCHEME static Widget stacktrace_popup_menu = NULL; #endif static void listener_popup_callback(Widget w, XtPointer context, XtPointer info) { XmPopupHandlerCallbackStruct *cb = (XmPopupHandlerCallbackStruct *)info; XEvent *e; e = cb->event; if (e->type == ButtonPress) { #if HAVE_SCHEME if (stacktrace_popup_menu) set_menu_label(stacktrace_popup_menu, (s7_is_null(s7, s7_curlet(s7))) ? "Error info" : "Stacktrace"); #endif cb->menuToPost = listener_popup; } } static void make_listener_widget(int height) { if (!listener_text) { Arg args[32]; Widget wv, wh, w; int n; if (!actions_loaded) {XtAppAddActions(main_app(ss), acts, NUM_ACTS); actions_loaded = true;} n = attach_all_sides(args, 0); XtSetArg(args[n], XmNheight, height); n++; XtSetArg(args[n], XmNpaneMaximum, LOTSA_PIXELS); n++; /* Xm/Paned initializes each pane max to 1000 apparently! */ if ((sound_style(ss) == SOUNDS_IN_NOTEBOOK) || (sound_style(ss) == SOUNDS_HORIZONTAL)) listener_pane = XtCreateManagedWidget("frm", xmFormWidgetClass, sound_pane_box(ss), args, n); else listener_pane = XtCreateManagedWidget("frm", xmFormWidgetClass, sound_pane(ss), args, n); /* this widget is not redundant at least in Metroworks Motif */ n = 0; XtSetArg(args[n], XmNbackground, ss->listener_color); n++; XtSetArg(args[n], XmNforeground, ss->listener_text_color); n++; if (ss->listener_fontlist) {XtSetArg(args[n], XM_FONT_RESOURCE, ss->listener_fontlist); n++;} n = attach_all_sides(args, n); XtSetArg(args[n], XmNeditMode, XmMULTI_LINE_EDIT); n++; XtSetArg(args[n], XmNskipAdjust, true); n++; XtSetArg(args[n], XmNvalue, listener_prompt(ss)); n++; XtSetArg(args[n], XmNpendingDelete, false); n++; /* don't cut selection upon paste */ XtSetArg(args[n], XmNpositionIndex, XmLAST_POSITION); n++; XtSetArg(args[n], XmNhighlightThickness, 1); n++; listener_text = XmCreateScrolledText(listener_pane, (char *)"lisp-listener", args, n); ss->listener_pane = listener_text; n = 0; XtSetArg(args[n], XmNbackground, ss->highlight_color); n++; XtSetArg(args[n], XmNpopupEnabled, XmPOPUP_AUTOMATIC); n++; listener_popup = XmCreatePopupMenu(listener_text, (char *)"listener-popup", args, n); w = XtCreateManagedWidget(I_STOP, xmPushButtonWidgetClass, listener_popup, args, n); XtAddCallback(w, XmNactivateCallback, listener_stop_callback, NULL); #if HAVE_SCHEME w = XtCreateManagedWidget("Stacktrace", xmPushButtonWidgetClass, listener_popup, args, n); XtAddCallback(w, XmNactivateCallback, listener_stacktrace_callback, NULL); stacktrace_popup_menu = w; #endif w = XtCreateManagedWidget(I_HELP, xmPushButtonWidgetClass, listener_popup, args, n); XtAddCallback(w, XmNactivateCallback, listener_help_callback, NULL); w = XtCreateManagedWidget("Clear", xmPushButtonWidgetClass, listener_popup, args, n); XtAddCallback(w, XmNactivateCallback, listener_clear_callback, NULL); w = XtCreateManagedWidget("Save", xmPushButtonWidgetClass, listener_popup, args, n); XtAddCallback(w, XmNactivateCallback, listener_save_callback, NULL); XtVaSetValues(main_shell(ss), XmNallowShellResize, false, NULL); XtManageChild(listener_text); XmTextSetCursorPosition(listener_text, ss->listener_prompt_length); if (!transTable4) transTable4 = XtParseTranslationTable(TextTrans4); XtOverrideTranslations(listener_text, transTable4); XtAddCallback(listener_text, XmNactivateCallback, listener_return_callback, NULL); XtAddCallback(listener_text, XmNmodifyVerifyCallback, listener_modify_callback, NULL); XtAddCallback(listener_text, XmNmotionVerifyCallback, listener_motion_callback, NULL); lisp_window = XtParent(listener_text); XtAddEventHandler(lisp_window, EnterWindowMask, false, listener_focus_callback, NULL); XtAddEventHandler(lisp_window, LeaveWindowMask, false, listener_unfocus_callback, NULL); XtAddCallback(listener_text, XmNpopupHandlerCallback, listener_popup_callback, NULL); XmChangeColor(lisp_window, ss->basic_color); XtVaGetValues(lisp_window, XmNverticalScrollBar, &wv, XmNhorizontalScrollBar, &wh, NULL); XmChangeColor(wv, ss->basic_color); XmChangeColor(wh, ss->basic_color); map_over_children(sound_pane(ss), color_sashes); if (auto_resize(ss)) XtVaSetValues(main_shell(ss), XmNallowShellResize, true, NULL); } } void goto_listener(void) { goto_window(listener_text); XmTextSetCursorPosition(listener_text, XmTextGetLastPosition(listener_text) + 1); XmTextSetInsertionPosition(listener_text, XmTextGetLastPosition(listener_text) + 1); } void color_listener(Pixel pix) { ss->listener_color = pix; #if HAVE_SCHEME s7_symbol_set_value(s7, ss->listener_color_symbol, Xen_wrap_pixel(pix)); #endif if (listener_text) XmChangeColor(listener_text, pix); } void color_listener_text(Pixel pix) { ss->listener_text_color = pix; #if HAVE_SCHEME s7_symbol_set_value(s7, ss->listener_text_color_symbol, Xen_wrap_pixel(pix)); #endif if (listener_text) XtVaSetValues(listener_text, XmNforeground, pix, NULL); } void handle_listener(bool open) { if (open) { if (!listener_text) make_listener_widget(100); else { XtManageChild(listener_pane); if (!(listener_is_visible())) { XtUnmanageChild(listener_pane); XtVaSetValues(listener_pane, XmNpaneMinimum, 100, XmNpaneMaximum, LOTSA_PIXELS, NULL); XtManageChild(listener_pane); XtVaSetValues(listener_pane, XmNpaneMinimum, 1, NULL); } } } else XtUnmanageChild(listener_pane); } bool listener_exists(void) { return((bool)listener_text); } int listener_height(void) { if ((listener_text) && (XtIsManaged(listener_pane))) return(widget_height(listener_text)); else return(0); } int listener_width(void) { if ((listener_text) && (XtIsManaged(listener_pane))) return(widget_width(listener_text)); else return(0); } #if OVERRIDE_TOGGLE static char ToggleTrans2[] = "c: ArmAndActivate()\n"; static XtTranslations toggleTable2 = NULL; static void override_toggle_translation(Widget w) { if (!toggleTable2) toggleTable2 = XtParseTranslationTable(ToggleTrans2); XtOverrideTranslations(w, toggleTable2); } #endif Widget make_togglebutton_widget(const char *name, Widget parent, Arg *args, int n) { Widget w; w = XtCreateManagedWidget(name, xmToggleButtonWidgetClass, parent, args, n); #if OVERRIDE_TOGGLE override_toggle_translation(w); #endif return(w); } Widget make_pushbutton_widget(const char *name, Widget parent, Arg *args, int n) { Widget w; w = XtCreateManagedWidget(name, xmPushButtonWidgetClass, parent, args, n); #if OVERRIDE_TOGGLE override_toggle_translation(w); /* ??? activate here (rather than armandactivate) fails? */ #endif return(w); } static Xen g_listener_selection(void) { #define H_listener_selection "(" S_listener_selection "): currently selected text in listener or " PROC_FALSE Xen res = Xen_false; if (listener_text) { char *txt; txt = XmTextGetSelection(listener_text); if (txt) { res = C_string_to_Xen_string(txt); XtFree(txt); } } return(res); } static Xen g_reset_listener_cursor(void) { #define H_reset_listener_cursor "(" S_reset_listener_cursor "): reset listener cursor to the default pointer" if (listener_text) XUndefineCursor(XtDisplay(listener_text), XtWindow(listener_text)); return(Xen_false); } void clear_listener(void) { if (listener_text) /* this can be called even when there is no listener */ { dont_check_motion = true; XmTextSetSelection(listener_text, 0, XmTextGetCursorPosition(listener_text), CurrentTime); XmTextRemove(listener_text); XmTextInsert(listener_text, 0, listener_prompt(ss)); XmTextShowPosition(listener_text, ss->listener_prompt_length); dont_check_motion = false; } } void set_listener_text_font(void) { if (listener_text) XtVaSetValues(listener_text, XM_FONT_RESOURCE, ss->listener_fontlist, NULL); } static Xen g_goto_listener_end(void) { #define H_goto_listener_end "(" S_goto_listener_end "): move cursor and scroll to bottom of listener pane" if (listener_text) { XmTextPosition eot; eot = XmTextGetLastPosition(listener_text); XmTextShowPosition(listener_text, eot); XmTextSetInsertionPosition(listener_text, eot); return(C_int_to_Xen_integer(eot)); } return(Xen_false); } #include enum {W_top, W_form, W_main_window, W_edhist, W_wf_buttons, W_f, W_w, W_left_scrollers, W_zy, W_sy, W_bottom_scrollers, W_sx, W_zx, W_graph, W_gzy, W_gsy, CP_NUM_WIDGETS }; #if ((XmVERSION >= 2) && (XmREVISION >= 3)) #define DEFAULT_EDIT_HISTORY_WIDTH 2 #else #define DEFAULT_EDIT_HISTORY_WIDTH 1 #endif Widget channel_main_pane(chan_info *cp) { if (cp) return(cp->widgets[W_form]); return(NULL); } Widget channel_graph(chan_info *cp) {return(cp->widgets[W_graph]);} static Widget channel_sx(chan_info *cp) {return(cp->widgets[W_sx]);} static Widget channel_sy(chan_info *cp) {return(cp->widgets[W_sy]);} static Widget channel_zx(chan_info *cp) {return(cp->widgets[W_zx]);} static Widget channel_zy(chan_info *cp) {return(cp->widgets[W_zy]);} static Widget channel_gsy(chan_info *cp) {return(cp->widgets[W_gsy]);} static Widget channel_gzy(chan_info *cp) {return(cp->widgets[W_gzy]);} Widget channel_w(chan_info *cp) {return(cp->widgets[W_w]);} Widget channel_f(chan_info *cp) {return(cp->widgets[W_f]);} bool channel_graph_is_visible(chan_info *cp) { return((cp) && (cp->widgets) && (channel_graph(cp)) && (XtIsManaged(channel_graph(cp))) && (cp->sound) && /* here we may have a sound wrapper for variable display in which case the sound widgets are not implemented */ (((cp->sound->inuse == SOUND_WRAPPER) || (cp->sound->inuse == SOUND_REGION)) || ((cp->sound->inuse == SOUND_NORMAL) && /* other choice: SOUND_IDLE -> no display */ (w_snd_pane(cp->sound)) && (XtIsManaged(w_snd_pane(cp->sound)))))); } #define EDIT_HISTORY_LIST(Cp) (Cp)->widgets[W_edhist] static mus_float_t sqr(mus_float_t a) {return(a * a);} static mus_float_t cube(mus_float_t a) {return(a * a * a);} static mus_float_t get_scrollbar(Widget w, int val, int scrollbar_max) { int size; if (val == 0) return(0.0); XtVaGetValues(w, XmNsliderSize, &size, NULL); return((mus_float_t)val / (mus_float_t)(scrollbar_max - size)); } static void sy_changed(int value, chan_info *cp) { axis_info *ap; mus_float_t low; ap = cp->axis; low = get_scrollbar(channel_sy(cp), value, SCROLLBAR_MAX); ap->sy = (1.0 - ap->zy) * low; apply_y_axis_change(cp); } static void sx_changed(int value, chan_info *cp) { /* treat as centered with non-slider trough as defining current bounds */ axis_info *ap; double low; ap = cp->axis; low = get_scrollbar(channel_sx(cp), value, SCROLLBAR_MAX); ap->sx = low * (1.0 - ap->zx); apply_x_axis_change(cp); } static void zy_changed(int value, chan_info *cp) { axis_info *ap; mus_float_t old_zy; ap = cp->axis; if (value < 1) value = 1; old_zy = ap->zy; ap->zy = sqr(get_scrollbar(channel_zy(cp), value, SCROLLBAR_MAX)); if (ap->zy < 1e-5) ap->zy = 1e-5; /* if this goes to 0, X can hang */ ap->sy += (.5 * (old_zy - ap->zy)); /* try to keep wave centered */ if (ap->sy < 0) ap->sy = 0; apply_y_axis_change(cp); resize_sy(cp); } #define X_RANGE_CHANGEOVER 20.0 static void zx_changed(int value, chan_info *cp) { /* scrollbar change */ axis_info *ap; static int old_zx_value = -1; #define ZX_MIN 20 if (value < ZX_MIN) value = ZX_MIN; /* less than this causes underflow in snd-axis describe_ticks */ /* snd-gchn uses .01 -- its equivalent here would be 100 */ /* perhaps the definition should be ((int)(0.002 * MAX_SCROLLBAR)) */ if (old_zx_value == value) return; /* try to keep click on slider from moving the window! */ old_zx_value = value; ap = cp->axis; if (ap->xmax == 0.0) return; if (ap->xmax <= ap->xmin) { ap->xmax = ap->xmin + .001; ap->x_ambit = .001; } if (ap->x_ambit < X_RANGE_CHANGEOVER) ap->zx = sqr(get_scrollbar(channel_zx(cp), value, SCROLLBAR_MAX)); else ap->zx = cube(get_scrollbar(channel_zx(cp), value, SCROLLBAR_MAX)); /* if cursor visible, focus on that, else selection, else mark, else left side */ focus_x_axis_change(cp, zoom_focus_style(ss)); resize_sx(cp); } static void set_scrollbar(Widget w, mus_float_t position, mus_float_t range, int scrollbar_max) /* position and range 0 to 1.0 */ { int size, val; size = (int)(scrollbar_max * range); if (size > scrollbar_max) size = scrollbar_max; /* this can't happen!?! */ if (size < 1) size = 1; val = (int)(scrollbar_max * position); if ((val + size) > scrollbar_max) val = scrollbar_max - size; if (val < 0) val = 0; XtVaSetValues(w, XmNsliderSize, size, XmNvalue, val, NULL); } static void change_gzy_1(mus_float_t val, chan_info *cp) { mus_float_t chan_frac, new_gsy, new_size; cp->gzy = val; chan_frac = 1.0 / ((mus_float_t)(((snd_info *)(cp->sound))->nchans)); new_size = chan_frac + ((1.0 - chan_frac) * cp->gzy); if ((cp->gsy + new_size) > 1.0) new_gsy = 1.0 - new_size; else new_gsy = cp->gsy; if (new_gsy < 0.0) new_gsy = 0.0; set_scrollbar(channel_gsy(cp), new_gsy, new_size, SCROLLBAR_MAX); } static void gzy_changed(int value, chan_info *cp) { change_gzy_1(get_scrollbar(channel_gzy(cp), value, SCROLLBAR_MAX), cp); for_each_sound_chan(cp->sound, update_graph_or_warn); } void change_gzy(mus_float_t val, chan_info *cp) { change_gzy_1(val, cp); set_scrollbar(channel_gzy(cp), val, 1.0 / (mus_float_t)(cp->sound->nchans), SCROLLBAR_MAX); } static void gsy_changed(int value, chan_info *cp) { mus_float_t low; low = get_scrollbar(channel_gsy(cp), value, SCROLLBAR_MAX); cp->gsy = (1.0 - cp->gzy) * low; for_each_sound_chan(cp->sound, update_graph_or_warn); } mus_float_t gsy_value(chan_info *cp) { Widget wcp; int ival; wcp = channel_gsy(cp); XtVaGetValues(wcp, XmNvalue, &ival, NULL); return((mus_float_t)ival / (mus_float_t)(SCROLLBAR_MAX)); } mus_float_t gsy_size(chan_info *cp) { Widget wcp; int ival; wcp = channel_gsy(cp); XtVaGetValues(wcp, XmNsliderSize, &ival, NULL); return((mus_float_t)ival / (mus_float_t)(SCROLLBAR_MAX)); } static void set_zx_scrollbar(chan_info *cp, axis_info *ap) { if (ap->x_ambit < X_RANGE_CHANGEOVER) set_scrollbar(channel_zx(cp), sqrt(ap->zx), .1, SCROLLBAR_MAX); /* assume size is 10% of scrollbar length */ else set_scrollbar(channel_zx(cp), pow(ap->zx, .333), .1, SCROLLBAR_MAX); } void set_z_scrollbars(chan_info *cp, axis_info *ap) { set_zx_scrollbar(cp, ap); set_scrollbar(channel_zy(cp), sqrt(ap->zy), .1, SCROLLBAR_MAX); } void initialize_scrollbars(chan_info *cp) { axis_info *ap; snd_info *sp; cp->gzy = 1.0; cp->gsy = 1.0; ap = cp->axis; sp = cp->sound; set_scrollbar(channel_sx(cp), ap->sx, ap->zx, SCROLLBAR_MAX); set_scrollbar(channel_sy(cp), ap->sy, ap->zy, SCROLLBAR_MAX); set_z_scrollbars(cp, ap); if ((sp->nchans > 1) && (cp->chan == 0) && (channel_gsy(cp))) { set_scrollbar(channel_gsy(cp), 1.0, 1.0, SCROLLBAR_MAX); set_scrollbar(channel_gzy(cp), 1.0, 1.0 / (mus_float_t)(sp->nchans), SCROLLBAR_MAX); } } void resize_sy(chan_info *cp) { /* something changed the y axis view, so the scale scroller needs to reflect that change (in size and position) */ axis_info *ap; ap = cp->axis; if (ap->y_ambit != 0.0) set_scrollbar(channel_sy(cp), (ap->y0 - ap->ymin) / ap->y_ambit, (ap->y1 - ap->y0) / ap->y_ambit, SCROLLBAR_MAX); } void resize_sy_and_zy(chan_info *cp) { resize_sy(cp); set_scrollbar(channel_zy(cp), sqrt(cp->axis->zy), .1, SCROLLBAR_MAX); } void resize_sx(chan_info *cp) { axis_info *ap; ap = cp->axis; if (ap->x_ambit != 0.0) set_scrollbar(channel_sx(cp), (ap->x0 - ap->xmin) / ap->x_ambit, (ap->x1 - ap->x0) / ap->x_ambit, SCROLLBAR_MAX); } void resize_sx_and_zx(chan_info *cp) { resize_sx(cp); /* change zx position (not its size) */ set_zx_scrollbar(cp, cp->axis); } void channel_open_pane(chan_info *cp) { XtManageChild(channel_main_pane(cp)); } void channel_unlock_pane(chan_info *cp) { XtVaSetValues(channel_main_pane(cp), XmNpaneMinimum, 5, XmNpaneMaximum, LOTSA_PIXELS, NULL); } static void channel_lock_pane(chan_info *cp, int val) { if (val < 6) val = 6; XtUnmanageChild(channel_main_pane(cp)); XtVaSetValues(channel_main_pane(cp), XmNpaneMinimum, val - 5, XmNpaneMaximum, val + 5, NULL); } static void sy_drag_callback(Widget w, XtPointer context, XtPointer info) { chan_info *cp = (chan_info *)(context); if (cp->active == CHANNEL_HAS_AXES) sy_changed(((XmScrollBarCallbackStruct *)info)->value, cp); } static void sy_valuechanged_callback(Widget w, XtPointer context, XtPointer info) { chan_info *cp = (chan_info *)(context); if (cp->active == CHANNEL_HAS_AXES) sy_changed(((XmScrollBarCallbackStruct *)info)->value, cp); } static void sx_drag_callback(Widget w, XtPointer context, XtPointer info) { chan_info *cp = (chan_info *)(context); if (cp->active == CHANNEL_HAS_AXES) sx_changed(((XmScrollBarCallbackStruct *)info)->value, cp); } static void sx_valuechanged_callback(Widget w, XtPointer context, XtPointer info) { chan_info *cp = (chan_info *)(context); if (cp->active == CHANNEL_HAS_AXES) sx_changed(((XmScrollBarCallbackStruct *)info)->value, cp); } static void sx_increment_callback(Widget w, XtPointer context, XtPointer info) { /* problem here is that in large files these increments, if determined via scrollbar values, are huge */ /* so, move ahead one-tenth window on each tick */ chan_info *cp = (chan_info *)(context); if (cp->active == CHANNEL_HAS_AXES) sx_incremented(cp, 0.1); } static void sx_decrement_callback(Widget w, XtPointer context, XtPointer info) { chan_info *cp = (chan_info *)(context); if (cp->active == CHANNEL_HAS_AXES) sx_incremented(cp, -0.1); } static void zy_drag_callback(Widget w, XtPointer context, XtPointer info) { chan_info *cp = (chan_info *)(context); if (cp->active == CHANNEL_HAS_AXES) zy_changed(((XmScrollBarCallbackStruct *)info)->value, cp); } static void zy_valuechanged_callback(Widget w, XtPointer context, XtPointer info) { chan_info *cp = (chan_info *)(context); if (cp->active == CHANNEL_HAS_AXES) zy_changed(((XmScrollBarCallbackStruct *)info)->value, cp); } static void zx_drag_callback(Widget w, XtPointer context, XtPointer info) { chan_info *cp = (chan_info *)(context); if (cp->active == CHANNEL_HAS_AXES) zx_changed(((XmScrollBarCallbackStruct *)info)->value, cp); } /* can't use value changed callback in scrollbars because they are called upon mouse release * even when nothing changed, and the value passed appears to be the right edge of the * slider -- this is too unpredictable, and the result is the window moves when the user * did not want it to. */ static void gzy_drag_callback(Widget w, XtPointer context, XtPointer info) { chan_info *cp = (chan_info *)(context); if (cp->active == CHANNEL_HAS_AXES) gzy_changed(((XmScrollBarCallbackStruct *)info)->value, cp); } static void gsy_drag_callback(Widget w, XtPointer context, XtPointer info) { chan_info *cp = (chan_info *)(context); if (cp->active == CHANNEL_HAS_AXES) gsy_changed(((XmScrollBarCallbackStruct *)info)->value, cp); } static void gsy_valuechanged_callback(Widget w, XtPointer context, XtPointer info) { chan_info *cp = (chan_info *)(context); if (cp->active == CHANNEL_HAS_AXES) gsy_changed(((XmScrollBarCallbackStruct *)info)->value, cp); } /* anything special for increment? XmNincrementCallback sx_increment_callback */ static void f_toggle_callback(Widget w, XtPointer context, XtPointer info) { XmToggleButtonCallbackStruct *cb = (XmToggleButtonCallbackStruct *)info; XButtonEvent *ev; ev = (XButtonEvent *)(cb->event); f_button_callback((chan_info *)context, cb->set, (ev->state & snd_ControlMask)); } static void w_toggle_callback(Widget w, XtPointer context, XtPointer info) { XmToggleButtonCallbackStruct *cb = (XmToggleButtonCallbackStruct *)info; XButtonEvent *ev; ev = (XButtonEvent *)(cb->event); w_button_callback((chan_info *)context, cb->set, (ev->state & snd_ControlMask)); } static void channel_expose_callback(Widget w, XtPointer context, XtPointer info) { static oclock_t last_expose_event_time = 0; static chan_info *last_cp = NULL; chan_info *cp = (chan_info *)context; XmDrawingAreaCallbackStruct *cb = (XmDrawingAreaCallbackStruct *)info; XExposeEvent *ev; oclock_t curtime; if ((!cp) || (cp->active < CHANNEL_HAS_AXES) || (!cp->sound)) return; ev = (XExposeEvent *)(cb->event); /* if multiple channels/sounds displayed, each gets an expose event, but the earlier ones * have count>0, and the last can get more than 1, causing our notion of last_cp to * be useless, and we'll drop the earlier ones anyway, so if cp != last_cp, expose * last_cp if last_count>0 or times equal (not sure which is safest). */ curtime = XtLastTimestampProcessed(main_display(ss)); if ((ev->count == 0) || (last_expose_event_time != curtime) || (cp != last_cp)) { snd_info *sp; sp = cp->sound; if (sp->channel_style != CHANNELS_SEPARATE) { if ((cp->chan == 0) && (ev->width > 10) && (ev->height > 10)) for_each_sound_chan(sp, update_graph_or_warn); } else update_graph_or_warn(cp); } last_cp = cp; last_expose_event_time = curtime; } static void channel_resize_callback(Widget w, XtPointer context, XtPointer info) { channel_resize((chan_info *)context); } static Xen mouse_enter_graph_hook; static Xen mouse_leave_graph_hook; static void graph_mouse_enter(Widget w, XtPointer context, XEvent *event, Boolean *flag) { intptr_t data; XEnterWindowEvent *ev = (XEnterWindowEvent *)event; if (with_pointer_focus(ss)) goto_window(w); XtVaGetValues(w, XmNuserData, &data, NULL); if (Xen_hook_has_list(mouse_enter_graph_hook)) run_hook(mouse_enter_graph_hook, Xen_list_2(C_int_to_Xen_sound(unpack_sound(data)), C_int_to_Xen_integer(unpack_channel(data))), S_mouse_enter_graph_hook); check_cursor_shape((chan_info *)context, ev->x, ev->y); } static void graph_mouse_leave(Widget w, XtPointer context, XEvent *event, Boolean *flag) { intptr_t data; XLeaveWindowEvent *ev = (XLeaveWindowEvent *)event; XtVaGetValues(w, XmNuserData, &data, NULL); if (Xen_hook_has_list(mouse_leave_graph_hook)) run_hook(mouse_leave_graph_hook, Xen_list_2(C_int_to_Xen_sound(unpack_sound(data)), C_int_to_Xen_integer(unpack_channel(data))), S_mouse_leave_graph_hook); /* XUndefineCursor(XtDisplay(w), XtWindow(w)); */ check_cursor_shape((chan_info *)context, ev->x, ev->y); } static void graph_button_press(Widget w, XtPointer context, XEvent *event, Boolean *cont) { XButtonEvent *ev = (XButtonEvent *)event; graph_button_press_callback((chan_info *)context, (void *)ev, ev->x, ev->y, ev->state, ev->button, ev->time); } static void graph_button_release(Widget w, XtPointer context, XEvent *event, Boolean *cont) /* cont = "continue to dispatch" */ { XButtonEvent *ev = (XButtonEvent *)event; graph_button_release_callback((chan_info *)context, ev->x, ev->y, ev->state, ev->button); } #if 0 static void graph_button_motion(Widget w, XtPointer context, XEvent *event, Boolean *cont) { /* mouse drag */ XMotionEvent *ev = (XMotionEvent *)event; graph_button_motion_callback((chan_info *)context, ev->x, ev->y, ev->time); } #endif static void graph_mouse_motion(Widget w, XtPointer context, XEvent *event, Boolean *cont) { /* mouse movement */ XMotionEvent *ev = (XMotionEvent *)event; if ((ev->state & Button1Mask) == 0) check_cursor_shape((chan_info *)context, ev->x, ev->y); else graph_button_motion_callback((chan_info *)context, ev->x, ev->y, ev->time); } static int no_padding(Arg *args, int n) { XtSetArg(args[n], XmNmarginHeight, 0); n++; XtSetArg(args[n], XmNmarginWidth, 0); n++; XtSetArg(args[n], XmNmarginTop, 0); n++; XtSetArg(args[n], XmNmarginBottom, 0); n++; XtSetArg(args[n], XmNmarginLeft, 0); n++; XtSetArg(args[n], XmNmarginRight, 0); n++; return(n); } static void hide_gz_scrollbars(snd_info *sp) { Widget w; w = channel_gsy(sp->chans[0]); if ((w) && (XtIsManaged(w))) XtUnmanageChild(w); w = channel_gzy(sp->chans[0]); if ((w) && (XtIsManaged(w))) XtUnmanageChild(w); } static void show_gz_scrollbars(snd_info *sp) { Widget w; w = channel_gsy(sp->chans[0]); if ((w) && (!XtIsManaged(w))) XtManageChild(w); w = channel_gzy(sp->chans[0]); if ((w) && (!XtIsManaged(w))) XtManageChild(w); } /* edit history support */ static void history_select_callback(Widget w, XtPointer context, XtPointer info) { /* undo/redo to reach selected position */ XmListCallbackStruct *cbs = (XmListCallbackStruct *)info; edit_history_select((chan_info *)context, cbs->item_position - 1); } #if WITH_RELATIVE_PANES /* using undocumented callback here, as in snd-xsnd.c */ static void remake_edit_history(Widget lst, chan_info *cp, int from_graph) { snd_info *sp; int i, eds; XmString *edits; if (cp->squelch_update) return; XmListDeleteAllItems(lst); sp = cp->sound; if (sp->channel_style != CHANNELS_SEPARATE) { chan_info *ncp; uint32_t k; int all_eds = 0, ed, filelen; char *title; for (k = 0; k < sp->nchans; k++) { ncp = sp->chans[k]; eds = ncp->edit_ctr; while ((eds < (ncp->edit_size - 1)) && (ncp->edits[eds + 1])) eds++; all_eds += eds; } all_eds += 3 * sp->nchans; edits = (XmString *)calloc(all_eds, sizeof(XmString)); filelen = 16 + strlen(sp->filename); title = (char *)calloc(filelen, sizeof(char)); for (k = 0, ed = 0; k < sp->nchans; k++) { ncp = sp->chans[k]; ncp->edhist_base = ed; snprintf(title, filelen, "chan %d: %s", k + 1, sp->filename); edits[ed++] = XmStringCreateLocalized(title); eds = ncp->edit_ctr; while ((eds < (ncp->edit_size - 1)) && (ncp->edits[eds + 1])) eds++; for (i = 1; i <= eds; i++) { char *temp; temp = edit_to_string(ncp, i); edits[ed++] = XmStringCreateLocalized(temp); free(temp); } if (k < sp->nchans - 1) edits[ed++] = XmStringCreateLocalized((char *)"______________________________"); } free(title); XtVaSetValues(lst, XmNitems, edits, XmNitemCount, ed, NULL); for (i = 0; i < ed; i++) XmStringFree(edits[i]); free(edits); XmListSelectPos(lst, cp->edhist_base + cp->edit_ctr + 1, false); if (from_graph) goto_graph(cp); } else { int items = 0; eds = cp->edit_ctr; while ((eds < (cp->edit_size - 1)) && (cp->edits[eds + 1])) eds++; edits = (XmString *)calloc(eds + 1, sizeof(XmString)); edits[0] = XmStringCreateLocalized(sp->filename); for (i = 1; i <= eds; i++) { char *temp; temp = edit_to_string(cp, i); edits[i] = XmStringCreateLocalized(temp); free(temp); } XtVaSetValues(lst, XmNitems, edits, XmNitemCount, eds + 1, NULL); for (i = 0; i <= eds; i++) XmStringFree(edits[i]); free(edits); XmListSelectPos(lst, cp->edit_ctr + 1, false); XtVaGetValues(lst, XmNvisibleItemCount, &items, NULL); if (items <= eds) XtVaSetValues(lst, XmNtopItemPosition, eds - items + 2, NULL); if (from_graph) goto_graph(cp); } } static void watch_edit_history_sash(Widget w, XtPointer closure, XtPointer info) { SashCallData call_data = (SashCallData)info; /* call_data->params[0]: Commit, Move, Key, Start (as strings) */ if ((call_data->params) && (mus_strcmp(call_data->params[0], "Start"))) { chan_info *cp = (chan_info *)closure; Widget edhist; if ((cp) && (cp->widgets)) { edhist = EDIT_HISTORY_LIST(cp); if (edhist) remake_edit_history(edhist, cp, false); } } } #endif void reflect_edit_history_change(chan_info *cp) { /* new edit so it is added, and any trailing lines removed */ snd_info *sp; Widget lst; if (cp->squelch_update) return; if (cp->in_as_one_edit > 0) return; sp = cp->sound; lst = EDIT_HISTORY_LIST(cp); #if WITH_RELATIVE_PANES if ((lst) && (widget_width(lst) > 1)) remake_edit_history(lst, cp, true); else { if ((cp->chan > 0) && (sp->channel_style != CHANNELS_SEPARATE)) { lst = EDIT_HISTORY_LIST(sp->chans[0]); if ((lst) && (widget_width(lst) > 1)) remake_edit_history(lst, sp->chans[0], true); } } #else /* old form */ if (lst) { int i, eds, items = 0; XmString *edits; eds = cp->edit_ctr; while ((eds < (cp->edit_size - 1)) && (cp->edits[eds + 1])) eds++; if (eds >= 0) { if ((eds == cp->edit_ctr) && (eds > 1)) /* need to force 0 (1) case to start list with sound file name */ { XmString edit; /* special common case -- we're appending a new edit description */ XtVaGetValues(lst, XmNitemCount, &items, NULL); if (items > eds ) XmListDeleteItemsPos(lst, cp->edit_size, eds + 1); /* cp->edit_size is too large, but the manual says this is the way to delete to the end */ { char *temp; temp = edit_to_string(cp, eds); edit = XmStringCreateLocalized(temp); free(temp); } XmListAddItemUnselected(lst, edit, eds + 1); XmStringFree(edit); } else { edits = (XmString *)calloc(eds + 1, sizeof(XmString)); edits[0] = XmStringCreateLocalized(sp->filename); for (i = 1; i <= eds; i++) { char *temp; temp = edit_to_string(cp, i); edits[i] = XmStringCreateLocalized(temp); free(temp); } XtVaSetValues(lst, XmNitems, edits, XmNitemCount, eds + 1, NULL); for (i = 0; i <= eds; i++) XmStringFree(edits[i]); free(edits); } XmListSelectPos(lst, cp->edit_ctr + 1, false); XtVaGetValues(lst, XmNvisibleItemCount, &items, NULL); if (items <= eds) XtVaSetValues(lst, XmNtopItemPosition, eds - items + 2, NULL); goto_graph(cp); } } #endif } void reflect_edit_counter_change(chan_info *cp) { /* undo/redo/revert -- change which line is highlighted */ Widget lst; if (cp->squelch_update) return; lst = EDIT_HISTORY_LIST(cp); if ((lst) && (widget_width(lst) > 1)) { int len, top; XmListSelectPos(lst, cp->edit_ctr + 1, false); XtVaGetValues(lst, XmNvisibleItemCount, &len, XmNtopItemPosition, &top, NULL); if ((cp->edit_ctr + 1) < top) XtVaSetValues(lst, XmNtopItemPosition, cp->edit_ctr + 1, NULL); else if ((cp->edit_ctr + 1) >= (top + len)) XtVaSetValues(lst, XmNtopItemPosition, cp->edit_ctr, NULL); goto_graph(cp); } } /* for combined cases, the incoming chan_info pointer is always chan[0], * but the actual channel depends on placement if mouse oriented. * virtual_selected_channel(cp) (snd-chn.c) retains the current selected channel */ void graph_key_press(Widget w, XtPointer context, XEvent *event, Boolean *cont) { XKeyEvent *ev = (XKeyEvent *)event; KeySym keysym; int key_state; snd_info *sp = (snd_info *)context; key_state = ev->state; keysym = XkbKeycodeToKeysym(XtDisplay(w), (int)(ev->keycode), 0, (key_state & snd_ShiftMask) ? 1 : 0); key_press_callback(any_selected_channel(sp), ev->x, ev->y, ev->state, keysym); } static void cp_graph_key_press(Widget w, XtPointer context, XEvent *event, Boolean *cont) { /* called by every key-intercepting widget in the entire sound pane */ XKeyEvent *ev = (XKeyEvent *)event; KeySym keysym; int key_state; chan_info *cp = (chan_info *)context; if ((!cp) || (!cp->sound)) return; /* can't happen */ key_state = ev->state; keysym = XkbKeycodeToKeysym(XtDisplay(w), (int)(ev->keycode), 0, (key_state & snd_ShiftMask) ? 1 : 0); key_press_callback(cp, ev->x, ev->y, ev->state, keysym); } static void channel_drop_watcher(Widget w, const char *str, Position x, Position y, void *context) { intptr_t data; data = (intptr_t)context; drag_and_drop_mix_at_x_y((int)data, str, x, y); } static void channel_drag_watcher(Widget w, const char *str, Position x, Position y, drag_style_t dtype, void *context) { int snd, chn; intptr_t data; snd_info *sp; XtVaGetValues(w, XmNuserData, &data, NULL); chn = unpack_channel(data); snd = unpack_sound(data); sp = ss->sounds[snd]; if (snd_ok(sp)) { mus_float_t seconds; chan_info *cp; switch (dtype) { case DRAG_ENTER: case DRAG_MOTION: cp = sp->chans[chn]; if ((sp->nchans > 1) && (sp->channel_style == CHANNELS_COMBINED)) cp = which_channel(sp, y); seconds = ungrf_x(cp->axis, x); if (seconds < 0.0) seconds = 0.0; if (sp->nchans > 1) status_report(sp, "drop to mix file in chan %d at %.4f", cp->chan + 1, seconds); else status_report(sp, "drop to mix file at %.4f", seconds); break; case DRAG_LEAVE: set_status(sp, " ", false); /* not clear_status_area here! => segfault */ break; } } } int add_channel_window(snd_info *sp, int channel, int chan_y, int insertion, Widget main, fw_button_t button_style, bool with_events) { bool need_extra_scrollbars; Widget *cw; chan_info *cp; graphics_context *cax; bool make_widgets; /* if ((main) && ((!(XmIsForm(main))) || (!(XtWindow(main))))) return(-1); */ /* new gcc complains about the XmIsForm for some reason */ if ((main) && (!(XtWindow(main)))) return(-1); /* can this happen? */ make_widgets = (!sp->chans[channel]); sp->chans[channel] = make_chan_info(sp->chans[channel], channel, sp); cp = sp->chans[channel]; if (!cp->widgets) cp->widgets = (Widget *)calloc(CP_NUM_WIDGETS, sizeof(Widget)); cw = cp->widgets; need_extra_scrollbars = ((!main) && (channel == 0)); if (make_widgets) { XtCallbackList n1, n2, n3, n4, n5, n6, n7, n8, n9, n10, n11, n12, n13, n14, n15; int n; Arg args[32]; /* allocate the entire widget apparatus for this channel of this sound */ if (!main) { n = 0; XtSetArg(args[n], XmNbackground, ss->basic_color); n++; if (insertion) {XtSetArg(args[n], XmNpositionIndex, (short)channel); n++;} XtSetArg(args[n], XmNpaneMinimum, chan_y); n++; cw[W_form] = XtCreateManagedWidget("chn-form", xmFormWidgetClass, w_snd_pane(sp), args, n); if ((sp->channel_style == CHANNELS_COMBINED) && (channel > 0)) XtUnmanageChild(cw[W_form]); n = 0; XtSetArg(args[n], XmNbackground, ss->basic_color); n++; /* n = no_padding(args, n); */ n = attach_all_sides(args, n); XtSetArg(args[n], XmNsashIndent, 2); n++; XtSetArg(args[n], XmNorientation, XmHORIZONTAL); n++; XtSetArg(args[n], XmNpaneMaximum, LOTSA_PIXELS); n++; cw[W_top] = XtCreateManagedWidget("chn-top", xmPanedWindowWidgetClass, cw[W_form], args, n); XtAddEventHandler(cw[W_top], KeyPressMask, false, graph_key_press, (XtPointer)sp); n = 0; XtSetArg(args[n], XmNbackground, ss->white); n++; XtSetArg(args[n], XmNpaneMaximum, DEFAULT_EDIT_HISTORY_WIDTH); n++; XtSetArg(args[n], XmNlistSizePolicy, XmCONSTANT); n++; cw[W_edhist] = XmCreateScrolledList(cw[W_top], (char *)"chn-edhist", args, n); XtManageChild(cw[W_edhist]); XtAddCallback(cw[W_edhist], XmNbrowseSelectionCallback, history_select_callback, cp); XtAddEventHandler(cw[W_edhist], KeyPressMask, false, graph_key_press, (XtPointer)sp); XtAddEventHandler(XtParent(cw[W_edhist]), KeyPressMask, false, graph_key_press, (XtPointer)sp); n = 0; XtSetArg(args[n], XmNbackground, ss->basic_color); n++; XtSetArg(args[n], XmNpaneMaximum, LOTSA_PIXELS); n++; cw[W_main_window] = XtCreateManagedWidget("chn-main-window", xmFormWidgetClass, cw[W_top], args, n); XtAddEventHandler(cw[W_main_window], KeyPressMask, false, graph_key_press, (XtPointer)sp); #if WITH_RELATIVE_PANES { int k; Widget child; CompositeWidget w = (CompositeWidget)(cw[W_top]); for (k = w->composite.num_children - 1; k >= 0; k--) { child = w->composite.children[k]; if ((XtIsWidget(child)) && (XtIsSubclass(child, xmSashWidgetClass))) { XtAddCallback(child, XmNcallback, watch_edit_history_sash, (XtPointer)cp); break; /* there seems to be more than 1?? */ } } } #endif } else cw[W_main_window] = main; n = 0; XtSetArg(args[n], XmNbackground, ss->basic_color); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_NONE); n++; n = no_padding(args, n); XtSetArg(args[n], XmNpacking, XmPACK_COLUMN); n++; XtSetArg(args[n], XmNnumColumns, 1); n++; XtSetArg(args[n], XmNorientation, XmVERTICAL); n++; cw[W_wf_buttons] = XtCreateManagedWidget("chn-buttons", xmRowColumnWidgetClass, cw[W_main_window], args, n); if (button_style == WITH_FW_BUTTONS) { n = 0; XtSetArg(args[n], XmNbackground, ss->basic_color); n++; XtSetArg(args[n], XmNspacing, 1); n++; XtSetArg(args[n], XmNselectColor, ss->selection_color); n++; cw[W_f] = make_togglebutton_widget("f", cw[W_wf_buttons], args, n); XtAddCallback(cw[W_f], XmNvalueChangedCallback, f_toggle_callback, cp); XtAddEventHandler(cw[W_f], KeyPressMask, false, graph_key_press, (XtPointer)sp); XtSetArg(args[n], XmNset, true); n++; cw[W_w] = make_togglebutton_widget("w", cw[W_wf_buttons], args, n); XtAddCallback(cw[W_w], XmNvalueChangedCallback, w_toggle_callback, cp); XtAddEventHandler(cw[W_w], KeyPressMask, false, graph_key_press, (XtPointer)sp); } else { n = 0; XtSetArg(args[n], XmNbackground, ss->basic_color); n++; XtSetArg(args[n], XmNarrowDirection, XmARROW_UP); n++; XtSetArg(args[n], XmNsensitive, false); n++; cw[W_f] = XtCreateManagedWidget("up", xmArrowButtonWidgetClass, cw[W_wf_buttons], args, n); n = 0; XtSetArg(args[n], XmNbackground, ss->basic_color); n++; XtSetArg(args[n], XmNarrowDirection, XmARROW_DOWN); n++; XtSetArg(args[n], XmNsensitive, false); n++; cw[W_w] = XtCreateManagedWidget("down", xmArrowButtonWidgetClass, cw[W_wf_buttons], args, n); } n = 0; XtSetArg(args[n], XmNbackground, ss->basic_color); n++; XtSetArg(args[n], XmNorientation, XmHORIZONTAL); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNbottomWidget, cw[W_wf_buttons]); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNspacing, 0); n++; cw[W_left_scrollers] = XtCreateManagedWidget("chn-left", xmRowColumnWidgetClass, cw[W_main_window], args, n); XtAddEventHandler(cw[W_left_scrollers], KeyPressMask, false, graph_key_press, (XtPointer)sp); n = 0; XtSetArg(args[n], XmNbackground, ss->zoom_color); n++; XtSetArg(args[n], XmNwidth, ss->position_slider_width); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNorientation, XmVERTICAL); n++; XtSetArg(args[n], XmNmaximum, SCROLLBAR_MAX); n++; XtSetArg(args[n], XmNincrement, 1); n++; XtSetArg(args[n], XmNprocessingDirection, XmMAX_ON_TOP); n++; XtSetArg(args[n], XmNdragCallback, n1 = make_callback_list(zy_drag_callback, (XtPointer)cp)); n++; XtSetArg(args[n], XmNvalueChangedCallback, n2 = make_callback_list(zy_valuechanged_callback, (XtPointer)cp)); n++; cw[W_zy] = XtCreateManagedWidget("chn-zy", xmScrollBarWidgetClass, cw[W_left_scrollers], args, n); XtAddEventHandler(cw[W_zy], KeyPressMask, false, graph_key_press, (XtPointer)sp); n = 0; XtSetArg(args[n], XmNbackground, ss->position_color); n++; XtSetArg(args[n], XmNwidth, ss->zoom_slider_width); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNleftWidget, cw[W_zy]); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNorientation, XmVERTICAL); n++; XtSetArg(args[n], XmNmaximum, SCROLLBAR_MAX); n++; XtSetArg(args[n], XmNincrement, 1); n++; XtSetArg(args[n], XmNprocessingDirection, XmMAX_ON_TOP); n++; XtSetArg(args[n], XmNdragCallback, n3 = make_callback_list(sy_drag_callback, (XtPointer)cp)); n++; XtSetArg(args[n], XmNvalueChangedCallback, n4 = make_callback_list(sy_valuechanged_callback, (XtPointer)cp)); n++; cw[W_sy] = XtCreateManagedWidget("chn-sy", xmScrollBarWidgetClass, cw[W_left_scrollers], args, n); XtAddEventHandler(cw[W_sy], KeyPressMask, false, graph_key_press, (XtPointer)sp); n = 0; XtSetArg(args[n], XmNbackground, ss->basic_color); n++; XtSetArg(args[n], XmNorientation, XmVERTICAL); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNleftWidget, cw[W_wf_buttons]); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNspacing, 0); n++; cw[W_bottom_scrollers] = XtCreateManagedWidget("chn-bottom", xmRowColumnWidgetClass, cw[W_main_window], args, n); XtAddEventHandler(cw[W_bottom_scrollers], KeyPressMask, false, graph_key_press, (XtPointer)sp); n = 0; XtSetArg(args[n], XmNbackground, ss->position_color); n++; XtSetArg(args[n], XmNheight, ss->position_slider_width); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNorientation, XmHORIZONTAL); n++; XtSetArg(args[n], XmNmaximum, SCROLLBAR_MAX); n++; XtSetArg(args[n], XmNincrement, 1); n++; XtSetArg(args[n], XmNdragCallback, n5 = make_callback_list(sx_drag_callback, (XtPointer)cp)); n++; XtSetArg(args[n], XmNincrementCallback, n6 = make_callback_list(sx_increment_callback, (XtPointer)cp)); n++; XtSetArg(args[n], XmNdecrementCallback, n7 = make_callback_list(sx_decrement_callback, (XtPointer)cp)); n++; XtSetArg(args[n], XmNvalueChangedCallback, n8 = make_callback_list(sx_valuechanged_callback, (XtPointer)cp)); n++; cw[W_sx] = XtCreateManagedWidget("chn-sx", xmScrollBarWidgetClass, cw[W_bottom_scrollers], args, n); XtAddEventHandler(cw[W_sx], KeyPressMask, false, graph_key_press, (XtPointer)sp); n = 0; XtSetArg(args[n], XmNbackground, ss->zoom_color); n++; XtSetArg(args[n], XmNheight, ss->zoom_slider_width + 2); n++; XtSetArg(args[n], XmNorientation, XmHORIZONTAL); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNbottomWidget, cw[W_sx]); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNmaximum, SCROLLBAR_MAX); n++; XtSetArg(args[n], XmNincrement, 1); n++; XtSetArg(args[n], XmNdragCallback, n9 = make_callback_list(zx_drag_callback, (XtPointer)cp)); n++; XtSetArg(args[n], XmNincrementCallback, n10 = make_callback_list(zx_drag_callback, (XtPointer)cp)); n++; XtSetArg(args[n], XmNdecrementCallback, n11 = make_callback_list(zx_drag_callback, (XtPointer)cp)); n++; XtSetArg(args[n], XmNpageIncrementCallback, n12 = make_callback_list(zx_drag_callback, (XtPointer)cp)); n++; XtSetArg(args[n], XmNpageDecrementCallback, n13 = make_callback_list(zx_drag_callback, (XtPointer)cp)); n++; XtSetArg(args[n], XmNtoTopCallback, n14 = make_callback_list(zx_drag_callback, (XtPointer)cp)); n++; XtSetArg(args[n], XmNtoBottomCallback, n15 = make_callback_list(zx_drag_callback, (XtPointer)cp)); n++; cw[W_zx] = XtCreateManagedWidget("chn-zx", xmScrollBarWidgetClass, cw[W_bottom_scrollers], args, n); XtAddEventHandler(cw[W_zx], KeyPressMask, false, graph_key_press, (XtPointer)sp); n = 0; XtSetArg(args[n], XmNbackground, ss->graph_color); n++; XtSetArg(args[n], XmNforeground, ss->data_color); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNbottomWidget, cw[W_bottom_scrollers]); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNleftWidget, cw[W_left_scrollers]); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNuserData, pack_sound_and_channel(sp->index, cp->chan)); n++; /* this collides with W_gzy below, but a consistent version came up with half a window blank */ XtSetArg(args[n], XmNnavigationType, XmNONE); n++; cw[W_graph] = XtCreateManagedWidget("chn-graph", xmDrawingAreaWidgetClass, cw[W_main_window], args, n); if (with_events) { /* region regraph sets up its own callbacks */ XtAddCallback(cw[W_graph], XmNresizeCallback, channel_resize_callback, (XtPointer)cp); XtAddCallback(cw[W_graph], XmNexposeCallback, channel_expose_callback, (XtPointer)cp); } /* allow cursor in all cases (zoom to cursor in region window for example, or fft axis drag in variable display) */ XtAddEventHandler(cw[W_graph], ButtonPressMask, false, graph_button_press, (XtPointer)cp); XtAddEventHandler(cw[W_graph], ButtonReleaseMask, false, graph_button_release, (XtPointer)cp); /* XtAddEventHandler(cw[W_graph], ButtonMotionMask, false, graph_button_motion, (XtPointer)cp); */ XtAddEventHandler(cw[W_graph], PointerMotionMask, false, graph_mouse_motion, (XtPointer)cp); if (!main) { intptr_t data; XtAddEventHandler(cw[W_graph], EnterWindowMask, false, graph_mouse_enter, (XtPointer)cp); XtAddEventHandler(cw[W_graph], LeaveWindowMask, false, graph_mouse_leave, (XtPointer)cp); XtAddEventHandler(cw[W_graph], KeyPressMask, false, cp_graph_key_press, (XtPointer)cp); data = (intptr_t)pack_sound_and_channel(sp->index, cp->chan); add_drag_and_drop(cw[W_graph], channel_drop_watcher, channel_drag_watcher, (void *)data); } free(n1); free(n2); free(n3); free(n4); free(n5); free(n6); free(n7); free(n8); free(n9); free(n10); free(n11); free(n12); free(n13); free(n14); free(n15); if (need_extra_scrollbars) { /* that is: not region browser chan, might need combined graph, channel 0 is the controller in that case */ /* this is independent of sp->nchans because these structs are re-used and added to as needed */ n = 0; XtSetArg(args[n], XmNbackground, ss->zoom_color); n++; XtSetArg(args[n], XmNwidth, ss->position_slider_width); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNbottomWidget, cw[W_bottom_scrollers]); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNorientation, XmVERTICAL); n++; XtSetArg(args[n], XmNmaximum, SCROLLBAR_MAX); n++; XtSetArg(args[n], XmNincrement, 1); n++; XtSetArg(args[n], XmNprocessingDirection, XmMAX_ON_TOP); n++; XtSetArg(args[n], XmNincrementCallback, n1 = make_callback_list(gzy_drag_callback, (XtPointer)cp)); n++; XtSetArg(args[n], XmNdecrementCallback, n2 = make_callback_list(gzy_drag_callback, (XtPointer)cp)); n++; XtSetArg(args[n], XmNpageIncrementCallback, n3 = make_callback_list(gzy_drag_callback, (XtPointer)cp)); n++; XtSetArg(args[n], XmNpageDecrementCallback, n4 = make_callback_list(gzy_drag_callback, (XtPointer)cp)); n++; XtSetArg(args[n], XmNtoTopCallback, n5 = make_callback_list(gzy_drag_callback, (XtPointer)cp)); n++; XtSetArg(args[n], XmNtoBottomCallback, n6 = make_callback_list(gzy_drag_callback, (XtPointer)cp)); n++; XtSetArg(args[n], XmNdragCallback, n7 = make_callback_list(gzy_drag_callback, (XtPointer)cp)); n++; cw[W_gzy] = XtCreateManagedWidget("chn-gzy", xmScrollBarWidgetClass, cw[W_main_window], args, n); XtAddEventHandler(cw[W_gzy], KeyPressMask, false, graph_key_press, (XtPointer)sp); n = 0; XtSetArg(args[n], XmNbackground, ss->position_color); n++; XtSetArg(args[n], XmNwidth, ss->position_slider_width); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNbottomWidget, cw[W_bottom_scrollers]); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNrightWidget, cw[W_gzy]); n++; XtSetArg(args[n], XmNorientation, XmVERTICAL); n++; XtSetArg(args[n], XmNmaximum, SCROLLBAR_MAX); n++; XtSetArg(args[n], XmNincrement, 1); n++; XtSetArg(args[n], XmNprocessingDirection, XmMAX_ON_TOP); n++; XtSetArg(args[n], XmNdragCallback, n8 = make_callback_list(gsy_drag_callback, (XtPointer)cp)); n++; XtSetArg(args[n], XmNvalueChangedCallback, n9 = make_callback_list(gsy_valuechanged_callback, (XtPointer)cp)); n++; cw[W_gsy] = XtCreateManagedWidget("chn-gsy", xmScrollBarWidgetClass, cw[W_main_window], args, n); XtAddEventHandler(cw[W_gsy], KeyPressMask, false, graph_key_press, (XtPointer)sp); free(n1); free(n2); free(n3); free(n4); free(n5); free(n6); free(n7); free(n8); free(n9); } else { cw[W_gsy] = NULL; cw[W_gzy] = NULL; } run_new_widget_hook(cw[W_main_window]); /* also position of current graph in overall sound as window */ } /* end alloc new chan */ else { int i; /* re-manage currently inactive chan */ XtVaSetValues(cw[W_main_window], XmNpaneMinimum, chan_y, NULL); if (cw[W_edhist]) XtVaSetValues(XtParent(cw[W_edhist]), XmNpaneMaximum, 1, NULL); if ((sp->channel_style != CHANNELS_COMBINED) || (channel == 0)) for (i = 0; i < CP_NUM_WIDGETS - 1; i++) if ((cw[i]) && (!XtIsManaged(cw[i]))) XtManageChild(cw[i]); recolor_graph(cp, false); /* in case selection color left over from previous use */ } if (cw[W_edhist]) XtVaSetValues(XtParent(cw[W_edhist]), XmNpaneMaximum, LOTSA_PIXELS, NULL); if ((need_extra_scrollbars) && (sp->channel_style != CHANNELS_COMBINED)) hide_gz_scrollbars(sp); /* default is on in this case */ cax = cp->ax; cax->wn = XtWindow(cw[W_graph]); cax->dp = XtDisplay(cw[W_graph]); cax->gc = ss->basic_gc; return(0); } static void set_graph_font(chan_info *cp, graphics_context *ax, XFontStruct *bf) { if (!ax) return; ax->current_font = bf->fid; XSetFont(XtDisplay(channel_to_widget(cp)), copy_GC(cp), bf->fid); } void set_peak_numbers_font(chan_info *cp, graphics_context *ax) {set_graph_font(cp, ax, PEAKS_FONT(ss));} void set_tiny_numbers_font(chan_info *cp, graphics_context *ax) {set_graph_font(cp, ax, TINY_FONT(ss));} void set_bold_peak_numbers_font(chan_info *cp, graphics_context *ax) {set_graph_font(cp, ax, BOLD_PEAKS_FONT(ss));} color_t get_foreground_color(graphics_context *ax) { XGCValues gv; XGetGCValues(main_display(ss), ax->gc, GCForeground, &gv); return(gv.foreground); } void set_foreground_color(graphics_context *ax, Pixel color) { XSetForeground(main_display(ss), ax->gc, color); } GC copy_GC(chan_info *cp) { if (cp->selected) return(ss->selected_basic_gc); return(ss->basic_gc); } GC erase_GC(chan_info *cp) { /* used only to clear partial bgs in chan graphs */ snd_info *sp; sp = cp->sound; if ((cp->selected) || ((sp) && (sp->channel_style == CHANNELS_SUPERIMPOSED) && (sp->index == ss->selected_sound))) return(ss->selected_erase_gc); return(ss->erase_gc); } void free_fft_pix(chan_info *cp) { if ((cp->fft_pix != None) && (channel_graph(cp))) XFreePixmap(XtDisplay(channel_graph(cp)), cp->fft_pix); cp->fft_pix = None; cp->fft_pix_ready = false; } bool restore_fft_pix(chan_info *cp, graphics_context *ax) { XCopyArea(ax->dp, cp->fft_pix, ax->wn, copy_GC(cp), 0, 0, /* source x y */ cp->fft_pix_width, cp->fft_pix_height, cp->fft_pix_x0, cp->fft_pix_y0); return(true); } void save_fft_pix(chan_info *cp, graphics_context *ax, int fwidth, int fheight, int x0, int y1) { if ((fwidth == 0) || (fheight == 0)) return; if (cp->fft_pix == None) { /* make new pixmap */ cp->fft_pix_width = fwidth; cp->fft_pix_height = fheight; cp->fft_pix_x0 = x0; cp->fft_pix_y0 = y1; cp->fft_pix_cutoff = cp->spectrum_end; cp->fft_pix = XCreatePixmap(ax->dp, RootWindowOfScreen(XtScreen(channel_graph(cp))), fwidth, fheight, DefaultDepthOfScreen(XtScreen(channel_graph(cp)))); } XCopyArea(ax->dp, ax->wn, cp->fft_pix, copy_GC(cp), cp->fft_pix_x0, cp->fft_pix_y0, cp->fft_pix_width, cp->fft_pix_height, 0, 0); cp->fft_pix_ready = true; } void cleanup_cw(chan_info *cp) { if (cp) { Widget *cw; free_fft_pix(cp); cp->selected = false; cw = cp->widgets; if (cw) { if (cw[W_w]) { XtVaSetValues(cw[W_w], XmNset, true, NULL); XtVaSetValues(cw[W_f], XmNset, false, NULL); } if (channel_main_pane(cp)) XtUnmanageChild(channel_main_pane(cp)); } } } void change_channel_style(snd_info *sp, channel_style_t new_style) { if ((sp) && (sp->nchans > 1)) { channel_style_t old_style; chan_info *selected_cp; selected_cp = any_selected_channel(sp); /* chan 0 is none is selected */ old_style = sp->channel_style; sp->channel_style = new_style; if (new_style != old_style) { uint32_t i, height; #if WITH_RELATIVE_PANES if ((new_style == CHANNELS_SEPARATE) || (old_style == CHANNELS_SEPARATE)) { Widget lst; lst = EDIT_HISTORY_LIST(sp->chans[0]); if ((lst) && (widget_width(lst) > 1)) remake_edit_history(lst, sp->chans[0], true); } #endif if (old_style == CHANNELS_COMBINED) { hide_gz_scrollbars(sp); for (i = 1; i < sp->nchans; i++) channel_set_mix_tags_erased(sp->chans[i]); } else { if (new_style == CHANNELS_COMBINED) { show_gz_scrollbars(sp); for (i = 1; i < sp->nchans; i++) channel_set_mix_tags_erased(sp->chans[i]); } } if (old_style == CHANNELS_SUPERIMPOSED) { syncb(sp, sp->previous_sync); XtVaSetValues(unite_button(sp), XmNselectColor, ss->selection_color, NULL); } else { if (new_style == CHANNELS_SUPERIMPOSED) { sp->previous_sync = sp->sync; if (sp->sync == 0) syncb(sp, 1); XtVaSetValues(unite_button(sp), XmNselectColor, ss->green, NULL); apply_y_axis_change(selected_cp); apply_x_axis_change(selected_cp); for (i = 0; i < sp->nchans; i++) { if ((int)i != selected_cp->chan) { chan_info *ncp; ncp = sp->chans[i]; cursor_sample(ncp) = cursor_sample(selected_cp); if (selected_cp->graph_transform_on != ncp->graph_transform_on) { ncp->graph_transform_on = selected_cp->graph_transform_on; set_toggle_button(channel_f(ncp), selected_cp->graph_transform_on, false, (void *)ncp); } if (selected_cp->graph_time_on != ncp->graph_time_on) { ncp->graph_time_on = selected_cp->graph_time_on; set_toggle_button(channel_w(ncp), selected_cp->graph_time_on, false, (void *)ncp); } } } } } height = widget_height(w_snd_pane(sp)) - control_panel_height(sp); if (old_style == CHANNELS_SEPARATE) { axis_info *ap; ap = selected_cp->axis; channel_lock_pane(sp->chans[0], height); for (i = 0; i < sp->nchans; i++) { if ((int)i != selected_cp->chan) set_axes(sp->chans[i], ap->x0, ap->x1, ap->y0, ap->y1); if (i > 0) cleanup_cw(sp->chans[i]); } channel_open_pane(sp->chans[0]); channel_unlock_pane(sp->chans[0]); XmToggleButtonSetState(unite_button(sp), true, false); } else { if (new_style == CHANNELS_SEPARATE) { /* height = total space available */ height /= sp->nchans; for_each_sound_chan_with_int(sp, channel_lock_pane, height); for_each_sound_chan(sp, channel_open_pane); for_each_sound_chan(sp, channel_unlock_pane); for (i = 1; i < sp->nchans; i++) { Widget *cw; chan_info *cp; int j; cp = sp->chans[i]; cw = cp->widgets; for (j = 0; j < CP_NUM_WIDGETS - 1; j++) if ((cw[j]) && (!XtIsManaged(cw[j]))) XtManageChild(cw[j]); XmToggleButtonSetState(cw[W_f], (Boolean)(cp->graph_transform_on), false); XmToggleButtonSetState(cw[W_w], (Boolean)(cp->graph_time_on), false); /* these can get out of sync if changes are made in the unseparated case */ } XmToggleButtonSetState(unite_button(sp), false, false); if (sp->selected_channel > 0) color_selected_channel(sp); } } if ((new_style == CHANNELS_COMBINED) && (sp->selected_channel > 0)) color_selected_channel(sp); } } } static Xen g_channel_widgets(Xen snd, Xen chn) { #define H_channel_widgets "(" S_channel_widgets " :optional snd chn): a list of widgets: ((0)graph (1)w (2)f (3)sx (4)sy (5)zx (6)zy (7)edhist)" chan_info *cp; Snd_assert_channel(S_channel_widgets, snd, chn, 1); cp = get_cp(snd, chn, S_channel_widgets); if (!cp) return(Xen_false); return(Xen_cons(Xen_wrap_widget(channel_graph(cp)), Xen_cons(Xen_wrap_widget(channel_w(cp)), Xen_cons(Xen_wrap_widget(channel_f(cp)), Xen_cons(Xen_wrap_widget(channel_sx(cp)), Xen_cons(Xen_wrap_widget(channel_sy(cp)), Xen_cons(Xen_wrap_widget(channel_zx(cp)), Xen_cons(Xen_wrap_widget(channel_zy(cp)), Xen_cons(Xen_wrap_widget(EDIT_HISTORY_LIST(cp)), Xen_cons(Xen_wrap_widget(channel_gsy(cp)), Xen_cons(Xen_wrap_widget(channel_gzy(cp)), Xen_cons(Xen_wrap_widget(channel_main_pane(cp)), Xen_empty_list)))))))))))); } /* previous snd-xxen.c contents) */ static void timed_eval(XtPointer in_code, XtIntervalId *id) { #if HAVE_EXTENSION_LANGUAGE Xen lst = (XEN)in_code; Xen_call_with_no_args(Xen_cadr(lst), "timed callback func"); snd_unprotect_at(Xen_integer_to_C_int(Xen_car(lst))); #endif } static Xen g_in(Xen ms, Xen code) { #define H_in "(" S_in " msecs thunk): invoke thunk in msecs milliseconds (named call_in in Ruby)" #if HAVE_EXTENSION_LANGUAGE Xen_check_type(Xen_is_number(ms), ms, 1, S_in, "a number"); Xen_check_type(Xen_is_procedure(code), code, 2, S_in, "a procedure"); if (Xen_is_aritable(code, 0)) { int secs; Xen_check_type(Xen_is_integer(ms), ms, 3, S_in, "an integer"); secs = Xen_integer_to_C_int(ms); if (secs < 0) Xen_out_of_range_error(S_in, 1, ms, "a positive integer"); else { Xen lst; lst = Xen_list_2(Xen_false, code); Xen_list_set(lst, 0, C_int_to_Xen_integer(snd_protect(lst))); XtAppAddTimeOut(main_app(ss), (unsigned long)secs, (XtTimerCallbackProc)timed_eval, (XtPointer)lst); } } else Xen_bad_arity_error(S_in, 2, code, "should take no args"); #endif return(ms); } void color_unselected_graphs(color_t color) { int i; for (i = 0; i < ss->max_sounds; i++) { snd_info *sp; int j; sp = ss->sounds[i]; if ((sp) && (sp->inuse != SOUND_WRAPPER)) for (j = 0; j < sp->allocated_chans; j++) { chan_info *cp; cp = sp->chans[j]; if ((cp) && ((i != ss->selected_sound) || (j != sp->selected_channel))) XtVaSetValues(channel_graph(cp), XmNbackground, color, NULL); } } } void color_chan_components(color_t color, slider_choice_t which_component) { int i; for (i = 0; i < ss->max_sounds; i++) { snd_info *sp; int j; sp = ss->sounds[i]; if ((sp) && (sp->inuse != SOUND_WRAPPER)) for (j = 0; j < sp->allocated_chans; j++) { chan_info *cp; cp = sp->chans[j]; if (cp) { if (which_component == COLOR_POSITION) { XtVaSetValues(channel_sx(cp), XmNbackground, color, NULL); XtVaSetValues(channel_sy(cp), XmNbackground, color, NULL); } else { XtVaSetValues(channel_zy(cp), XmNbackground, color, NULL); XtVaSetValues(channel_zx(cp), XmNbackground, color, NULL); } } } } } static Xen g_graph_cursor(void) { #define H_graph_cursor "(" S_graph_cursor "): current graph cursor shape" return(C_int_to_Xen_integer(in_graph_cursor(ss))); } static Xen g_set_graph_cursor(Xen curs) { int val; Xen_check_type(Xen_is_integer(curs), curs, 1, S_set S_graph_cursor, "an integer"); /* X11/cursorfont.h has various even-numbered glyphs, but the odd numbers are ok, and XC_num_glyphs is a lie */ /* if you use too high a number here, X dies */ val = Xen_integer_to_C_int(curs); if ((val >= 0) && (val <= XC_xterm)) { ss->Graph_Cursor = val; ss->graph_cursor = XCreateFontCursor(XtDisplay(main_shell(ss)), in_graph_cursor(ss)); } else Xen_out_of_range_error(S_set S_graph_cursor, 1, curs, "invalid cursor"); return(curs); } #include #define sound_env_editor(Sp) ((env_editor *)(sp->flt)) #define TOGGLE_MARGIN 0 enum {W_pane, W_name_form, W_amp_form, W_amp, W_amp_label, W_amp_number, W_speed, W_speed_label, W_speed_number, W_speed_arrow, W_expand, W_expand_label, W_expand_number, W_expand_button, W_contrast, W_contrast_label, W_contrast_number, W_contrast_button, W_revscl, W_revscl_label, W_revscl_number, W_revlen, W_revlen_label, W_revlen_number, W_reverb_button, W_filter_label, W_filter_order, W_filter_env, W_filter, W_filter_button, W_filter_dB, W_filter_hz, W_filter_frame, W_filter_order_down, W_filter_order_up, W_name, W_lock_or_bomb, W_stop_icon, W_info, W_play, W_sync, W_unite, W_close, SP_NUM_WIDGETS }; Widget unite_button(snd_info *sp) {return(sp->widgets[W_unite]);} Widget w_snd_pane(snd_info *sp) {return(sp->widgets[W_pane]);} #define SND_PANE(Sp) Sp->widgets[W_pane] #define SND_NAME(Sp) Sp->widgets[W_name] #define NAME_BOX(Sp) Sp->widgets[W_name_form] #define LOCK_OR_BOMB(Sp) Sp->widgets[W_lock_or_bomb] #define STOP_ICON(Sp) Sp->widgets[W_stop_icon] #define NAME_LABEL(Sp) Sp->widgets[W_name] #define STATUS_AREA(Sp) Sp->widgets[W_info] #define SYNC_BUTTON(Sp) Sp->widgets[W_sync] #define PLAY_BUTTON(Sp) Sp->widgets[W_play] #define UNITE_BUTTON(Sp) Sp->widgets[W_unite] #define CLOSE_BUTTON(Sp) Sp->widgets[W_close] #define CONTROLS(Sp) Sp->widgets[W_amp_form] #define AMP_SCROLLBAR(Sp) Sp->widgets[W_amp] #define AMP_LABEL(Sp) Sp->widgets[W_amp_number] #define AMP_BUTTON(Sp) Sp->widgets[W_amp_label] #define SPEED_SCROLLBAR(Sp) Sp->widgets[W_speed] #define SPEED_ARROW(Sp) Sp->widgets[W_speed_arrow] #define SPEED_LABEL(Sp) Sp->widgets[W_speed_number] #define SPEED_BUTTON(Sp) Sp->widgets[W_speed_label] #define EXPAND_SCROLLBAR(Sp) Sp->widgets[W_expand] #define EXPAND_LABEL(Sp) Sp->widgets[W_expand_number] #define EXPAND_RIGHT_BUTTON(Sp) Sp->widgets[W_expand_button] #define EXPAND_LEFT_BUTTON(Sp) Sp->widgets[W_expand_label] #define CONTRAST_SCROLLBAR(Sp) Sp->widgets[W_contrast] #define CONTRAST_LABEL(Sp) Sp->widgets[W_contrast_number] #define CONTRAST_RIGHT_BUTTON(Sp) Sp->widgets[W_contrast_button] #define CONTRAST_LEFT_BUTTON(Sp) Sp->widgets[W_contrast_label] #define REVSCL_SCROLLBAR(Sp) Sp->widgets[W_revscl] #define REVLEN_SCROLLBAR(Sp) Sp->widgets[W_revlen] #define REVSCL_LABEL(Sp) Sp->widgets[W_revscl_number] #define REVLEN_LABEL(Sp) Sp->widgets[W_revlen_number] #define REVSCL_BUTTON(Sp) Sp->widgets[W_revscl_label] #define REVLEN_BUTTON(Sp) Sp->widgets[W_revlen_label] #define REVERB_BUTTON(Sp) Sp->widgets[W_reverb_button] #define FILTER_ORDER_TEXT(Sp) Sp->widgets[W_filter_order] #define FILTER_COEFFS_TEXT(Sp) Sp->widgets[W_filter] #define FILTER_BUTTON(Sp) Sp->widgets[W_filter_button] #define FILTER_DB_BUTTON(Sp) Sp->widgets[W_filter_dB] #define FILTER_HZ_BUTTON(Sp) Sp->widgets[W_filter_hz] #define FILTER_LABEL(Sp) Sp->widgets[W_filter_label] #define FILTER_GRAPH(Sp) Sp->widgets[W_filter_env] #define FILTER_ORDER_UP(Sp) Sp->widgets[W_filter_order_up] #define FILTER_ORDER_DOWN(Sp) Sp->widgets[W_filter_order_down] #define FILTER_FRAME(Sp) Sp->widgets[W_filter_frame] #define PROGRESS_ICON(Cp) (Cp)->sound->progress_widgets[(Cp)->chan] int snd_pane_height(snd_info *sp) { Dimension height; XtVaGetValues(SND_PANE(sp), XmNheight, &height, NULL); return((int)height); } void set_status(snd_info *sp, const char *str, bool update) { if ((sp->inuse != SOUND_NORMAL) || (!has_widgets(sp))) return; XmTextSetString(STATUS_AREA(sp), (char *)str); /* updating clears the entire graph widget and triggers an expose event -- this is evil if we're currently displaying! */ /* there's also a bug in libxcb (fixed, but not propagated yet) that causes a segfault here if more than * one thread is affected by this global X queue flush. */ if (update) XmUpdateDisplay(STATUS_AREA(sp)); } static void name_click_callback(Widget w, XtPointer context, XtPointer info) { char *str; snd_info *sp = (snd_info *)context; str = sp_name_click(sp); if (str) { status_report(sp, "%s", str); free(str); } } static void stop_sign_click_callback(Widget w, XtPointer context, XtPointer info) { snd_info *sp = (snd_info *)context; if ((ss->checking_explicitly) || (play_in_progress())) ss->stopped_explicitly = true; stop_playing_all_sounds(PLAY_C_G); if (sp->applying) stop_applying(sp); for_each_sound_chan(sp, stop_fft_in_progress); } /* The 0.9 * SCROLLBAR_MAX reflects the fact that the slider is 10% of the trough, and the left edge of the slider is the readback value */ /* ---------------- AMP-CONTROL ---------------- */ int amp_to_scroll(mus_float_t minval, mus_float_t val, mus_float_t maxval) { if (val <= minval) return(0); if (val >= maxval) return((int)(0.9 * SCROLLBAR_MAX)); if (val >= 1.0) return(snd_round(0.9 * 0.5 * SCROLLBAR_MAX * (1.0 + (val - 1.0) / (maxval - 1.0)))); return(snd_round(0.9 * 0.5 * SCROLLBAR_MAX * ((val - minval) / (1.0 - minval)))); } static int scroll_to_amp(snd_info *sp, int val) { char amp_number_buffer[6]; if (val <= 0) sp->amp_control = sp->amp_control_min; else { if (val >= (0.9 * SCROLLBAR_MAX)) sp->amp_control = sp->amp_control_max; else { if (val > (0.5 * 0.9 * SCROLLBAR_MAX)) sp->amp_control = (((val / (0.5 * 0.9 * SCROLLBAR_MAX)) - 1.0) * (sp->amp_control_max - 1.0)) + 1.0; else sp->amp_control = (val * (1.0 - sp->amp_control_min) / (0.5 * 0.9 * SCROLLBAR_MAX)) + sp->amp_control_min; } } snprintf(amp_number_buffer, 6, "%.3f", sp->amp_control); set_label(AMP_LABEL(sp), amp_number_buffer); return(val); } void set_amp(snd_info *sp, mus_float_t val) { if (!has_widgets(sp)) sp->amp_control = val; else XtVaSetValues(AMP_SCROLLBAR(sp), XmNvalue, scroll_to_amp(sp, amp_to_scroll(sp->amp_control_min, val, sp->amp_control_max)), NULL); } static void amp_click_callback(Widget w, XtPointer context, XtPointer info) { XmPushButtonCallbackStruct *cb = (XmPushButtonCallbackStruct *)info; snd_info *sp = (snd_info *)context; XButtonEvent *ev; ev = (XButtonEvent *)(cb->event); if (ev->state & (snd_ControlMask | snd_MetaMask)) set_amp(sp, sp->last_amp_control); else set_amp(sp, 1.0); } static void amp_drag_callback(Widget w, XtPointer context, XtPointer info) { scroll_to_amp((snd_info *)context, ((XmScrollBarCallbackStruct *)info)->value); } static void amp_valuechanged_callback(Widget w, XtPointer context, XtPointer info) { XmScrollBarCallbackStruct *cb = (XmScrollBarCallbackStruct *)info; snd_info *sp = (snd_info *)context; scroll_to_amp(sp, cb->value); sp->last_amp_control = sp->saved_amp_control; sp->saved_amp_control = sp->amp_control; } /* ---------------- SPEED-CONTROL ---------------- */ XmString initial_speed_label(speed_style_t style) { /* used also in snd-xmix.c */ switch (style) { case SPEED_CONTROL_AS_RATIO: return(XmStringCreateLocalized((char *)" 1/1")); break; case SPEED_CONTROL_AS_SEMITONE: return(XmStringCreateLocalized((char *)" 0")); break; default: return(XmStringCreateLocalized((char *)" 1.00")); break; } } static int speed_to_scroll(mus_float_t minval, mus_float_t val, mus_float_t maxval) { if (val <= minval) return(0); if (val >= maxval) return((int)(0.9 * SCROLLBAR_MAX)); return(snd_round(0.9 * SCROLLBAR_MAX * ((log(val) - log(minval)) / (log(maxval) - log(minval))))); } static int scroll_to_speed(snd_info *sp, int ival) { char speed_number_buffer[6]; sp->speed_control = speed_changed(exp((ival * (log(sp->speed_control_max) - log(sp->speed_control_min)) / (0.9 * SCROLLBAR_MAX)) + log(sp->speed_control_min)), speed_number_buffer, sp->speed_control_style, sp->speed_control_tones, 6); set_label(SPEED_LABEL(sp), speed_number_buffer); /* set_label works with buttons or labels */ return(ival); } void set_speed(snd_info *sp, mus_float_t val) { if (!has_widgets(sp)) sp->speed_control = val; else XtVaSetValues(SPEED_SCROLLBAR(sp), XmNvalue, scroll_to_speed(sp, speed_to_scroll(sp->speed_control_min, val, sp->speed_control_max)), NULL); } static void speed_click_callback(Widget w, XtPointer context, XtPointer info) { XmPushButtonCallbackStruct *cb = (XmPushButtonCallbackStruct *)info; snd_info *sp = (snd_info *)context; XButtonEvent *ev; ev = (XButtonEvent *)(cb->event); if (ev->state & (snd_ControlMask | snd_MetaMask)) set_speed(sp, sp->last_speed_control); else set_speed(sp, 1.0); #if XEN_HAVE_RATIOS if (sp->speed_control_style == SPEED_CONTROL_AS_RATIO) snd_rationalize(sp->speed_control, &(sp->speed_control_numerator), &(sp->speed_control_denominator)); #endif } static void speed_label_click_callback(Widget w, XtPointer context, XtPointer info) { snd_info *sp = (snd_info *)context; switch (sp->speed_control_style) { default: case SPEED_CONTROL_AS_FLOAT: sp->speed_control_style = SPEED_CONTROL_AS_RATIO; break; case SPEED_CONTROL_AS_RATIO: sp->speed_control_style = SPEED_CONTROL_AS_SEMITONE; break; case SPEED_CONTROL_AS_SEMITONE: sp->speed_control_style = SPEED_CONTROL_AS_FLOAT; break; } set_speed(sp, sp->speed_control); /* remake label */ } static void speed_drag_callback(Widget w, XtPointer context, XtPointer info) { snd_info *sp = (snd_info *)context; scroll_to_speed(sp, ((XmScrollBarCallbackStruct *)info)->value); #if XEN_HAVE_RATIOS if (sp->speed_control_style == SPEED_CONTROL_AS_RATIO) snd_rationalize(sp->speed_control, &(sp->speed_control_numerator), &(sp->speed_control_denominator)); #endif } static void speed_valuechanged_callback(Widget w, XtPointer context, XtPointer info) { XmScrollBarCallbackStruct *cb = (XmScrollBarCallbackStruct *)info; snd_info *sp = (snd_info *)context; scroll_to_speed(sp, cb->value); #if XEN_HAVE_RATIOS if (sp->speed_control_style == SPEED_CONTROL_AS_RATIO) snd_rationalize(sp->speed_control, &(sp->speed_control_numerator), &(sp->speed_control_denominator)); #endif sp->last_speed_control = sp->saved_speed_control; sp->saved_speed_control = sp->speed_control; } void toggle_direction_arrow(snd_info *sp, bool state) { if (!has_widgets(sp)) sp->speed_control_direction = ((state) ? -1 : 1); else XmToggleButtonSetState(SPEED_ARROW(sp), (Boolean)state, true); } /* ---------------- EXPAND-CONTROL ---------------- */ static int expand_to_scroll(mus_float_t minval, mus_float_t val, mus_float_t maxval) { if (val <= minval) return(0); if (val >= maxval) return((int)(0.9 * SCROLLBAR_MAX)); return(snd_round(0.9 * SCROLLBAR_MAX * ((log(val) - log(minval)) / (log(maxval) - log(minval))))); } static int scroll_to_expand(snd_info *sp, int val) { char expand_number_buffer[6]; if (val <= 0) sp->expand_control = sp->expand_control_min; else { if (val >= (0.9 * SCROLLBAR_MAX)) sp->expand_control = sp->expand_control_max; else sp->expand_control = exp((val * (log(sp->expand_control_max) - log(sp->expand_control_min)) / (0.9 * SCROLLBAR_MAX)) + log(sp->expand_control_min)); } if (sp->playing) dac_set_expand(sp, sp->expand_control); snprintf(expand_number_buffer, 6, "%.3f", sp->expand_control); set_label(EXPAND_LABEL(sp), expand_number_buffer); return(val); } void set_expand(snd_info *sp, mus_float_t val) { if (!has_widgets(sp)) sp->expand_control = val; else XtVaSetValues(EXPAND_SCROLLBAR(sp), XmNvalue, scroll_to_expand(sp, expand_to_scroll(sp->expand_control_min, val, sp->expand_control_max)), NULL); } static void expand_click_callback(Widget w, XtPointer context, XtPointer info) { XmPushButtonCallbackStruct *cb = (XmPushButtonCallbackStruct *)info; snd_info *sp = (snd_info *)context; XButtonEvent *ev; ev = (XButtonEvent *)(cb->event); if (ev->state & (snd_ControlMask | snd_MetaMask)) set_expand(sp, sp->last_expand_control); else set_expand(sp, 1.0); } static void expand_drag_callback(Widget w, XtPointer context, XtPointer info) { scroll_to_expand((snd_info *)context, ((XmScrollBarCallbackStruct *)info)->value); } static void expand_valuechanged_callback(Widget w, XtPointer context, XtPointer info) { XmScrollBarCallbackStruct *cb = (XmScrollBarCallbackStruct *)info; snd_info *sp = (snd_info *)context; scroll_to_expand(sp, cb->value); sp->last_expand_control = sp->saved_expand_control; sp->saved_expand_control = sp->expand_control; } static void expand_button_callback(Widget w, XtPointer context, XtPointer info) { XmToggleButtonCallbackStruct *cb = (XmToggleButtonCallbackStruct *)info; snd_info *sp = (snd_info *)context; sp->expand_control_on = cb->set; XmChangeColor(EXPAND_SCROLLBAR(sp), (Pixel)((sp->expand_control_on) ? (ss->position_color) : (ss->basic_color))); } void toggle_expand_button(snd_info *sp, bool state) { if (!has_widgets(sp)) sp->expand_control_on = state; else XmToggleButtonSetState(EXPAND_RIGHT_BUTTON(sp), (Boolean)state, true); } /* ---------------- CONTRAST-CONTROL ---------------- */ static int contrast_to_scroll(mus_float_t minval, mus_float_t val, mus_float_t maxval) { if (val <= minval) return(0); if (val >= maxval) return((int)(0.9 * SCROLLBAR_MAX)); return(snd_round((val - minval) / (maxval - minval) * 0.9 * SCROLLBAR_MAX)); } static int scroll_to_contrast(snd_info *sp, int val) { char contrast_number_buffer[6]; sp->contrast_control = sp->contrast_control_min + val * (sp->contrast_control_max - sp->contrast_control_min) / (0.9 * SCROLLBAR_MAX); snprintf(contrast_number_buffer, 6, "%.3f", sp->contrast_control); set_label(CONTRAST_LABEL(sp), contrast_number_buffer); return(val); } void set_contrast(snd_info *sp, mus_float_t val) { if (!has_widgets(sp)) sp->contrast_control = val; else XtVaSetValues(CONTRAST_SCROLLBAR(sp), XmNvalue, scroll_to_contrast(sp, contrast_to_scroll(sp->contrast_control_min, val, sp->contrast_control_max)), NULL); } static void contrast_click_callback(Widget w, XtPointer context, XtPointer info) { XmPushButtonCallbackStruct *cb = (XmPushButtonCallbackStruct *)info; snd_info *sp = (snd_info *)context; XButtonEvent *ev; ev = (XButtonEvent *)(cb->event); if (ev->state & (snd_ControlMask | snd_MetaMask)) set_contrast(sp, sp->last_contrast_control); else set_contrast(sp, 0.0); } static void contrast_drag_callback(Widget w, XtPointer context, XtPointer info) { scroll_to_contrast((snd_info *)context, ((XmScrollBarCallbackStruct *)info)->value); } static void contrast_valuechanged_callback(Widget w, XtPointer context, XtPointer info) { XmScrollBarCallbackStruct *cb = (XmScrollBarCallbackStruct *)info; snd_info *sp = (snd_info *)context; scroll_to_contrast(sp, cb->value); sp->last_contrast_control = sp->saved_contrast_control; sp->saved_contrast_control = sp->contrast_control; } static void contrast_button_callback(Widget w, XtPointer context, XtPointer info) { snd_info *sp = (snd_info *)context; XmToggleButtonCallbackStruct *cb = (XmToggleButtonCallbackStruct *)info; sp->contrast_control_on = cb->set; XmChangeColor(CONTRAST_SCROLLBAR(sp), (Pixel)((sp->contrast_control_on) ? (ss->position_color) : (ss->basic_color))); } void toggle_contrast_button(snd_info *sp, bool state) { if (!has_widgets(sp)) sp->contrast_control_on = state; else XmToggleButtonSetState(CONTRAST_RIGHT_BUTTON(sp), (Boolean)state, true); } /* ---------------- REVERB-CONTROL-SCALE ---------------- */ static int revscl_to_scroll(mus_float_t minval, mus_float_t val, mus_float_t maxval) { if (val <= minval) return(0); if (val >= maxval) return((int)(0.9 * SCROLLBAR_MAX)); return(snd_round(0.9 * SCROLLBAR_MAX * (pow(val, 0.333) - pow(minval, 0.333)) / (pow(maxval, 0.333) - pow(minval, 0.333)))); } /* static mus_float_t cube(mus_float_t a) {return(a*a*a);} */ static int scroll_to_revscl(snd_info *sp, int val) { char revscl_number_buffer[7]; if (val <= 0) sp->reverb_control_scale = sp->reverb_control_scale_min; else { if (val >= (0.9 * SCROLLBAR_MAX)) sp->reverb_control_scale = sp->reverb_control_scale_max; else sp->reverb_control_scale = cube((val * (pow(sp->reverb_control_scale_max, 0.333) - pow(sp->reverb_control_scale_min, 0.333)) / (0.9 * SCROLLBAR_MAX)) + pow(sp->reverb_control_scale_min, 0.333)); } snprintf(revscl_number_buffer, 7, "%.4f", sp->reverb_control_scale); set_label(REVSCL_LABEL(sp), revscl_number_buffer); return(val); } void set_revscl(snd_info *sp, mus_float_t val) { if (!has_widgets(sp)) sp->reverb_control_scale = val; else XtVaSetValues(REVSCL_SCROLLBAR(sp), XmNvalue, scroll_to_revscl(sp, revscl_to_scroll(sp->reverb_control_scale_min, val, sp->reverb_control_scale_max)), NULL); } static void revscl_click_callback(Widget w, XtPointer context, XtPointer info) { XmPushButtonCallbackStruct *cb = (XmPushButtonCallbackStruct *)info; snd_info *sp = (snd_info *)context; XButtonEvent *ev; ev = (XButtonEvent *)(cb->event); if (ev->state & (snd_ControlMask | snd_MetaMask)) set_revscl(sp, sp->last_reverb_control_scale); else set_revscl(sp, 0.0); } static void revscl_drag_callback(Widget w, XtPointer context, XtPointer info) { scroll_to_revscl((snd_info *)context, ((XmScrollBarCallbackStruct *)info)->value); } static void revscl_valuechanged_callback(Widget w, XtPointer context, XtPointer info) { XmScrollBarCallbackStruct *cb = (XmScrollBarCallbackStruct *)info; snd_info *sp = (snd_info *)context; scroll_to_revscl(sp, cb->value); sp->last_reverb_control_scale = sp->saved_reverb_control_scale; sp->saved_reverb_control_scale = sp->reverb_control_scale; } /* ---------------- REVERB-CONTROL-LENGTH ---------------- */ static int revlen_to_scroll(mus_float_t minval, mus_float_t val, mus_float_t maxval) { if (val <= minval) return(0); if (val >= maxval) return((int)(0.9 * SCROLLBAR_MAX)); return(snd_round((val - minval) / (maxval - minval) * 0.9 * SCROLLBAR_MAX)); } static int scroll_to_revlen(snd_info *sp, int val) { char revlen_number_buffer[5]; sp->reverb_control_length = sp->reverb_control_length_min + (sp->reverb_control_length_max - sp->reverb_control_length_min) * (mus_float_t)val / (0.9 * SCROLLBAR_MAX); snprintf(revlen_number_buffer, 5, "%.2f", sp->reverb_control_length); set_label(REVLEN_LABEL(sp), revlen_number_buffer); return(val); } void set_revlen(snd_info *sp, mus_float_t val) { if (!has_widgets(sp)) sp->reverb_control_length = val; else XtVaSetValues(REVLEN_SCROLLBAR(sp), XmNvalue, scroll_to_revlen(sp, revlen_to_scroll(sp->reverb_control_length_min, val, sp->reverb_control_length_max)), NULL); } static void revlen_click_callback(Widget w, XtPointer context, XtPointer info) { XmPushButtonCallbackStruct *cb = (XmPushButtonCallbackStruct *)info; snd_info *sp = (snd_info *)context; XButtonEvent *ev; ev = (XButtonEvent *)(cb->event); if (ev->state & (snd_ControlMask | snd_MetaMask)) set_revlen(sp, sp->last_reverb_control_length); else set_revlen(sp, 1.0); } static void revlen_drag_callback(Widget w, XtPointer context, XtPointer info) { scroll_to_revlen((snd_info *)context, ((XmScrollBarCallbackStruct *)info)->value); } static void revlen_valuechanged_callback(Widget w, XtPointer context, XtPointer info) { XmScrollBarCallbackStruct *cb = (XmScrollBarCallbackStruct *)info; snd_info *sp = (snd_info *)context; scroll_to_revlen(sp, cb->value); sp->last_reverb_control_length = sp->saved_reverb_control_length; sp->saved_reverb_control_length = sp->reverb_control_length; } static void reverb_button_callback(Widget w, XtPointer context, XtPointer info) { snd_info *sp = (snd_info *)context; XmToggleButtonCallbackStruct *cb = (XmToggleButtonCallbackStruct *)info; sp->reverb_control_on = cb->set; XmChangeColor(REVLEN_SCROLLBAR(sp), (Pixel)((sp->reverb_control_on) ? (ss->position_color) : (ss->basic_color))); XmChangeColor(REVSCL_SCROLLBAR(sp), (Pixel)((sp->reverb_control_on) ? (ss->position_color) : (ss->basic_color))); } void toggle_reverb_button(snd_info *sp, bool state) { if (!has_widgets(sp)) sp->reverb_control_on = state; else XmToggleButtonSetState(REVERB_BUTTON(sp), (Boolean)state, true); } /* ---------------- FILTER_CONTROL ---------------- */ static void filter_button_callback(Widget w, XtPointer context, XtPointer info) { snd_info *sp = (snd_info *)context; XmToggleButtonCallbackStruct *cb = (XmToggleButtonCallbackStruct *)info; sp->filter_control_on = cb->set; } void toggle_filter_button(snd_info *sp, bool state) { if (!has_widgets(sp)) sp->filter_control_on = state; else XmToggleButtonSetState(FILTER_BUTTON(sp), (Boolean)state, true); } static void filter_textfield_deactivate(snd_info *sp) { chan_info *active_chan; active_chan = any_selected_channel(sp); if (active_chan) goto_window(channel_graph(active_chan)); } #define MIN_FILTER_GRAPH_HEIGHT 20 void display_filter_env(snd_info *sp) { graphics_context *ax; int height, width; Widget drawer; env_editor *edp; if (!(snd_ok(sp))) return; /* autotest close + lagging X updates */ edp = sp->flt; drawer = FILTER_GRAPH(sp); height = widget_height(drawer); if (height < MIN_FILTER_GRAPH_HEIGHT) return; width = widget_width(drawer); ax = (graphics_context *)calloc(1, sizeof(graphics_context)); ax->gc = ss->fltenv_basic_gc; ax->wn = XtWindow(drawer); ax->dp = XtDisplay(drawer); XClearWindow(ax->dp, ax->wn); edp->in_dB = sp->filter_control_in_dB; edp->with_dots = true; if (sp->filter_control_in_hz) sp->filter_control_xmax = (mus_float_t)(snd_srate(sp) / 2); else sp->filter_control_xmax = 1.0; if (!sp->filter_control_envelope) sp->filter_control_envelope = default_env(sp->filter_control_xmax, 1.0); env_editor_display_env(edp, sp->filter_control_envelope, ax, "frequency response", 0, 0, width, height, NOT_PRINTING); if (edp->edited) { ax->gc = ss->fltenv_data_gc; display_frequency_response(sp->filter_control_envelope, (sound_env_editor(sp))->axis, ax, sp->filter_control_order, sp->filter_control_in_dB); } free(ax); } void set_filter_text(snd_info *sp, const char *str) { if (has_widgets(sp)) XmTextSetString(FILTER_COEFFS_TEXT(sp), (char *)str); } static void filter_drawer_button_motion(Widget w, XtPointer context, XEvent *event, Boolean *cont) { snd_info *sp = (snd_info *)context; XMotionEvent *ev = (XMotionEvent *)event; env_editor *edp; #ifdef __APPLE__ if ((press_x == ev->x) && (press_y == ev->y)) return; #endif edp = sp->flt; edp->in_dB = sp->filter_control_in_dB; env_editor_button_motion(edp, ev->x, ev->y, ev->time, sp->filter_control_envelope); display_filter_env(sp); sp->filter_control_changed = true; } static void filter_drawer_button_press(Widget w, XtPointer context, XEvent *event, Boolean *cont) { snd_info *sp = (snd_info *)context; XButtonEvent *ev = (XButtonEvent *)event; env_editor *edp; if (!(sp->filter_control_envelope)) return; #ifdef __APPLE__ press_x = ev->x; press_y = ev->y; #endif edp = sp->flt; edp->in_dB = sp->filter_control_in_dB; if (env_editor_button_press(edp, ev->x, ev->y, ev->time, sp->filter_control_envelope)) display_filter_env(sp); } static void filter_drawer_button_release(Widget w, XtPointer context, XEvent *event, Boolean *cont) { char *tmpstr = NULL; snd_info *sp = (snd_info *)context; env_editor_button_release(sound_env_editor(sp), sp->filter_control_envelope); display_filter_env(sp); set_filter_text(sp, tmpstr = env_to_string(sp->filter_control_envelope)); if (tmpstr) free(tmpstr); sp->filter_control_changed = true; } static void filter_drawer_resize(Widget w, XtPointer context, XtPointer info) { snd_info *sp = (snd_info *)context; display_filter_env(sp); } static void filter_dB_callback(Widget w, XtPointer context, XtPointer info) { snd_info *sp = (snd_info *)context; XmToggleButtonCallbackStruct *cb = (XmToggleButtonCallbackStruct *)info; sp->filter_control_in_dB = (cb->set); display_filter_env(sp); } void set_filter_in_dB(snd_info *sp, bool val) { sp->filter_control_in_dB = val; if (has_widgets(sp)) { XmToggleButtonSetState(FILTER_DB_BUTTON(sp), (Boolean)val, false); display_filter_env(sp); } } static void new_in_hz(snd_info *sp, bool val) { sp->filter_control_in_hz = val; if (val) sp->filter_control_xmax = (mus_float_t)(snd_srate(sp) / 2); else sp->filter_control_xmax = 1.0; if (sp->filter_control_envelope) free_env(sp->filter_control_envelope); sp->filter_control_envelope = default_env(sp->filter_control_xmax, 1.0); } static void filter_hz_callback(Widget w, XtPointer context, XtPointer info) { snd_info *sp = (snd_info *)context; XmToggleButtonCallbackStruct *cb = (XmToggleButtonCallbackStruct *)info; new_in_hz(sp, cb->set); display_filter_env(sp); } void set_filter_in_hz(snd_info *sp, bool val) { new_in_hz(sp, val); if (has_widgets(sp)) { XmToggleButtonSetState(FILTER_HZ_BUTTON(sp), (Boolean)val, false); display_filter_env(sp); } } void set_filter_order(snd_info *sp, int order) { if (order & 1) order++; if (order <= 0) order = 2; sp->filter_control_order = order; if (has_widgets(sp)) { widget_int_to_text(FILTER_ORDER_TEXT(sp), order); display_filter_env(sp); } sp->filter_control_changed = true; } static void filter_order_up_callback(Widget w, XtPointer context, XtPointer info) { snd_info *sp = (snd_info *)context; set_filter_order(sp, sp->filter_control_order + 2); } static void filter_order_down_callback(Widget w, XtPointer context, XtPointer info) { snd_info *sp = (snd_info *)context; if (sp->filter_control_order > 2) set_filter_order(sp, sp->filter_control_order - 2); } static void get_filter_order(snd_info *sp, char *str) { int order; redirect_errors_to(errors_to_status_area, (void *)sp); order = string_to_int(str, 1, "filter order"); redirect_errors_to(NULL, NULL); if (order & 1) order++; if (order <= 0) order = 2; sp->filter_control_order = order; } static void filter_activate_callback(Widget w, XtPointer context, XtPointer info) { /* make an envelope out of the data */ snd_info *sp = (snd_info *)context; char *str = NULL; str = XmTextGetString(w); if (sp->filter_control_envelope) sp->filter_control_envelope = free_env(sp->filter_control_envelope); redirect_errors_to(errors_to_status_area, (void *)sp); sp->filter_control_envelope = string_to_env((const char *)str); redirect_errors_to(NULL, NULL); if (str) XtFree(str); if (!(sp->filter_control_envelope)) /* maybe user cleared text field? */ sp->filter_control_envelope = default_env(sp->filter_control_xmax, 1.0); str = XmTextGetString(FILTER_ORDER_TEXT(sp)); if ((str) && (*str)) { get_filter_order(sp, str); XtFree(str); } (sound_env_editor(sp))->edited = true; display_filter_env(sp); filter_textfield_deactivate(sp); sp->filter_control_changed = true; } static void filter_order_activate_callback(Widget w, XtPointer context, XtPointer info) { char *str; snd_info *sp = (snd_info *)context; str = XmTextGetString(w); if ((str) && (*str)) { get_filter_order(sp, str); sp->filter_control_changed = true; display_filter_env(sp); XtFree(str); } filter_textfield_deactivate(sp); } void filter_env_changed(snd_info *sp, env *e) { /* turn e back into a string for textfield widget */ if (has_widgets(sp)) { char *tmpstr = NULL; XmTextSetString(FILTER_COEFFS_TEXT(sp), tmpstr = env_to_string(e)); if (tmpstr) free(tmpstr); (sound_env_editor(sp))->edited = true; display_filter_env(sp); } sp->filter_control_changed = true; } /* ---------------- PLAY BUTTON ---------------- */ void set_play_button(snd_info *sp, bool val) { #if WITH_AUDIO if (has_widgets(sp)) XmToggleButtonSetState(PLAY_BUTTON(sp), (Boolean)val, false); set_open_file_play_button(val); #endif } #if WITH_AUDIO static void play_button_callback(Widget w, XtPointer context, XtPointer info) { snd_info *sp = (snd_info *)context; chan_info *cp; XmToggleButtonCallbackStruct *cb = (XmToggleButtonCallbackStruct *)info; XButtonEvent *ev; ev = (XButtonEvent *)(cb->event); if (sp->playing) stop_playing_sound(sp, PLAY_BUTTON_UNSET); ss->tracking = ((with_tracking_cursor(ss) != DONT_TRACK) || ((cb->set) && (ev->state & (snd_ControlMask | snd_MetaMask)))); cp = any_selected_channel(sp); goto_graph(cp); if (cb->set) { XtVaSetValues(w, XmNselectColor, (ss->tracking) ? ss->green : ss->selection_color, NULL); play_sound(sp, 0, NO_END_SPECIFIED); } } #endif typedef struct {bool pausing; } pause_data; #if WITH_AUDIO static void set_play_button_pause(snd_info *sp, void *ptr) { if ((sp->playing) && (has_widgets(sp))) { pause_data *pd = (pause_data *)ptr; Widget w; w = PLAY_BUTTON(sp); if (pd->pausing) XtVaSetValues(w, XmNselectColor, ss->red, NULL); else XtVaSetValues(w, XmNselectColor, (ss->tracking) ? ss->green : ss->selection_color, NULL); } } #endif void play_button_pause(bool pausing) { #if WITH_AUDIO pause_data *pd; pd = (pause_data *)calloc(1, sizeof(pause_data)); pd->pausing = pausing; for_each_sound_with_void(set_play_button_pause, (void *)pd); free(pd); #endif } void set_control_panel_play_button(snd_info *sp) { #if WITH_AUDIO if (has_widgets(sp)) { set_toggle_button(PLAY_BUTTON(sp), false, false, sp); XtVaSetValues(PLAY_BUTTON(sp), XmNselectColor, ss->selection_color, NULL); } #endif } static void play_arrow_callback(Widget w, XtPointer context, XtPointer info) { #if WITH_AUDIO snd_info *sp = (snd_info *)context; XmToggleButtonCallbackStruct *cb = (XmToggleButtonCallbackStruct *)info; bool dir; dir = (bool)(cb->set); if (dir) sp->speed_control_direction = -1; else sp->speed_control_direction = 1; #endif } /* ---------------- SYNC BUTTON ---------------- */ static void set_sync_color(snd_info *sp) { Widget syb; syb = SYNC_BUTTON(sp); switch (sp->sync) { case 1: case 0: XtVaSetValues(syb, XmNselectColor, ss->selection_color, NULL); break; case 2: XtVaSetValues(syb, XmNselectColor, ss->green, NULL); break; case 3: XtVaSetValues(syb, XmNselectColor, ss->yellow, NULL); break; case 4: XtVaSetValues(syb, XmNselectColor, ss->red, NULL); break; default: XtVaSetValues(syb, XmNselectColor, ss->black, NULL); break; } } void syncb(snd_info *sp, int on) { sp->sync = on; if (on > ss->sound_sync_max) ss->sound_sync_max = on; if (has_widgets(sp)) { set_sync_color(sp); XmToggleButtonSetState(SYNC_BUTTON(sp), (on != 0), false); /* need actual bool here, not a cast! */ } } static void sync_button_callback(Widget w, XtPointer context, XtPointer info) { snd_info *sp = (snd_info *)context; XmToggleButtonCallbackStruct *cb = (XmToggleButtonCallbackStruct *)info; XButtonEvent *ev; ev = (XButtonEvent *)(cb->event); if (cb->set) if (ev->state & snd_ControlMask) if (ev->state & snd_MetaMask) if (ev->state & snd_ShiftMask) sp->sync = 4; else sp->sync = 3; else sp->sync = 2; else sp->sync = 1; else sp->sync = 0; set_sync_color(sp); if (sp->sync != 0) { chan_info *cp; if (sp->sync > ss->sound_sync_max) ss->sound_sync_max = sp->sync; cp = sp->lacp; if (!cp) cp = any_selected_channel(sp); goto_graph(cp); if (cp->cursor_on) sync_cursors(cp, cursor_sample(cp)); apply_x_axis_change(cp); } } /* ---------------- UNITE BUTTON ---------------- */ static void unite_button_callback(Widget w, XtPointer context, XtPointer info) { /* click if set unsets, click if unset->combine, ctrl-click->superimpose */ snd_info *sp = (snd_info *)context; XmToggleButtonCallbackStruct *cb = (XmToggleButtonCallbackStruct *)info; XButtonEvent *ev; channel_style_t val; ev = (XButtonEvent *)(cb->event); if (cb->set) { if (ev->state & (snd_ControlMask | snd_MetaMask)) val = CHANNELS_SUPERIMPOSED; else val = CHANNELS_COMBINED; } else val = CHANNELS_SEPARATE; set_sound_channel_style(sp, val); } /* ---------------- CLOSE BUTTON ---------------- */ static void close_button_callback(Widget w, XtPointer context, XtPointer info) { snd_close_file((snd_info *)context); } /* apply is only safe if the DAC is currently inactive and remains safe only * if all other apply buttons are locked out (and play). */ /* relative panes needs to notice overall window resize, but there's no way to do so in Motif, as far as I can tell */ #if WITH_RELATIVE_PANES /* It would be nice if we could set a paned window to keep its children relative * amounts the same upon outside resize, but the Paned Window widget doesn't * have a resize callback, and no obvious way to advise the resize mechanism. * An attempt to get the same effect by wrapping w_pane in a drawingarea widget * ran into other troubles (the thing is seriously confused about its size). * You'd naively think the Actions "Start" and "Commit" could be used, since * XtActions are said to be a list of XtActionProcs, but I can't find a way to add * my action without deactivating the built-in action of the same name -- * XtAugmentTranslations ignores new actions if the old exists, XtOverride * replaces the old, etc. (And XtActions involve far more complexity than * anyone should have to endure). * * so... drop down into the sashes...(using undocumented stuff throughout this code) */ static void sash_lock_control_panel(snd_info *sp) { if (showing_controls(sp)) { /* lock to its current size */ int hgt; hgt = control_panel_height(sp); XtVaSetValues(CONTROLS(sp), XmNpaneMinimum, hgt, XmNpaneMaximum, hgt, NULL); } } static void sash_unlock_control_panel(snd_info *sp) { if (showing_controls(sp)) { XtVaSetValues(CONTROLS(sp), XmNpaneMinimum, 1, XmNpaneMaximum, LOTSA_PIXELS, NULL); } } static int outer_panes = 0; static int *inner_panes = NULL; static Dimension *outer_sizes = NULL; static Dimension **inner_sizes = NULL; static void watch_sash(Widget w, XtPointer closure, XtPointer info) { SashCallData call_data = (SashCallData)info; /* call_data->params[0]: Commit, Move, Key, Start (as strings) */ if ((call_data->params) && (call_data->params[0]) && (with_relative_panes(ss)) && (sound_style(ss) == SOUNDS_VERTICAL)) { int i, k; snd_info *sp; if (mus_strcmp(call_data->params[0], "Start")) { for (i = 0; i < ss->max_sounds; i++) { sp = ss->sounds[i]; if ((sp) && (sp->inuse == SOUND_NORMAL) && (sp->nchans > 1) && (sp->channel_style == CHANNELS_SEPARATE)) outer_panes++; } for_each_sound(sash_lock_control_panel); if (outer_panes > 0) { int outer_ctr; inner_panes = (int *)calloc(outer_panes, sizeof(int)); outer_sizes = (Dimension *)calloc(outer_panes, sizeof(Dimension)); inner_sizes = (Dimension **)calloc(outer_panes, sizeof(Dimension *)); outer_ctr = 0; for (i = 0; i < ss->max_sounds; i++) { sp = ss->sounds[i]; if ((sp) && (sp->inuse == SOUND_NORMAL) && (sp->nchans > 1) && (sp->channel_style == CHANNELS_SEPARATE)) { Widget child; child = SND_PANE(sp); inner_panes[outer_ctr] = sp->nchans; inner_sizes[outer_ctr] = (Dimension *)calloc(sp->nchans, sizeof(Dimension)); XtVaGetValues(child, XmNheight, &(outer_sizes[outer_ctr]), NULL); for (k = 0; k < (int)sp->nchans; k++) XtVaGetValues(channel_main_pane(sp->chans[k]), XmNheight, &(inner_sizes[outer_ctr][k]), NULL); outer_ctr++; if (outer_ctr >= outer_panes) break; } } } } else { if (mus_strcmp(call_data->params[0], "Commit")) /* release sash */ { if (outer_panes > 0) { int outer_ctr = 0; Dimension cur_outer_size = 0; for (i = 0; i < ss->max_sounds; i++) { sp = ss->sounds[i]; if ((sp) && (sp->inuse == SOUND_NORMAL) && (sp->nchans > 1) && (sp->channel_style == CHANNELS_SEPARATE)) { XtVaGetValues(SND_PANE(sp), XmNheight, &cur_outer_size, NULL); if ((cur_outer_size > 40) && (abs(cur_outer_size - outer_sizes[outer_ctr]) > (int)(sp->nchans * 2))) { /* this pane has multiple chans and its size has changed enough to matter */ Dimension total_inner = 0, diff; double ratio; for (k = 0; k < (int)sp->nchans; k++) total_inner += inner_sizes[outer_ctr][k]; diff = outer_sizes[outer_ctr] - total_inner; /* this is non-channel stuff */ for (k = 0; k < (int)sp->nchans; k++) XtUnmanageChild(channel_main_pane(sp->chans[k])); ratio = (double)(cur_outer_size - diff) / (double)(outer_sizes[outer_ctr] - diff); if (ratio > 0.0) { for (k = 0; k < (int)sp->nchans; k++) { int size; size = (int)(ratio * inner_sizes[outer_ctr][k]); XtVaSetValues(channel_main_pane(sp->chans[k]), XmNpaneMinimum, size - 1, XmNpaneMaximum, size + 1, NULL); } for (k = 0; k < (int)sp->nchans; k++) XtManageChild(channel_main_pane(sp->chans[k])); for (k = 0; k < (int)sp->nchans; k++) XtVaSetValues(channel_main_pane(sp->chans[k]), XmNpaneMinimum, 1, XmNpaneMaximum, LOTSA_PIXELS, NULL); } } outer_ctr++; } } for (i = 0; i < outer_panes; i++) if (inner_sizes[i]) free(inner_sizes[i]); free(inner_panes); free(inner_sizes); free(outer_sizes); outer_panes = 0; } for_each_sound(sash_unlock_control_panel); } } } } static Widget *sashes = NULL; static int sashes_size = 0; static void remember_sash(Widget w) { /* add callback only once (means remembering which widgets already have our callback */ int loc = -1; if (sashes_size == 0) { sashes = (Widget *)calloc(16, sizeof(Widget)); sashes_size = 16; loc = 0; } else { int i; for (i = 0; i < sashes_size; i++) { if (sashes[i] == w) return; if (!sashes[i]) { loc = i; break; } } if (loc == -1) { sashes = (Widget *)realloc(sashes, sashes_size * 2 * sizeof(Widget)); for (i = sashes_size; i < sashes_size * 2; i++) sashes[i] = NULL; loc = sashes_size; sashes_size *= 2; } } sashes[loc] = w; XtAddCallback(w, XmNcallback, watch_sash, NULL); } static void add_sash_watchers(Widget w) { /* if relative panes, add sash watchers to the outer paned window sashes (sound_pane(ss)) */ uint32_t i; CompositeWidget cw = (CompositeWidget)w; for (i = 0; i < cw->composite.num_children; i++) /* only outermost sashes count here */ { Widget child; child = cw->composite.children[i]; if ((XtIsWidget(child)) && (XtIsManaged(child)) && (XtIsSubclass(child, xmSashWidgetClass))) remember_sash(child); } } #endif static bool cant_write(char *name) { #ifndef _MSC_VER return((access(name, W_OK)) != 0); #else return(false); #endif } /* bitmaps for the playback direction arrow */ static unsigned char speed_r_bits1[] = { 0x00, 0x04, 0x10, 0x08, 0x00, 0x10, 0x04, 0x20, 0x00, 0x40, 0xa5, 0xbf, 0x00, 0x40, 0x04, 0x20, 0x00, 0x10, 0x10, 0x08, 0x00, 0x04, 0x00, 0x00}; static unsigned char speed_l_bits1[] = { 0x20, 0x00, 0x10, 0x08, 0x08, 0x00, 0x04, 0x20, 0x02, 0x00, 0xfd, 0xa5, 0x02, 0x00, 0x04, 0x20, 0x08, 0x00, 0x10, 0x08, 0x20, 0x00, 0x00, 0x00}; #define NUM_BOMBS 15 static Pixmap mini_lock = 0; static Pixmap close_icon = 0; static Pixmap blank_pixmap = 0; static bool mini_lock_allocated = false; static Pixmap bombs[NUM_BOMBS]; static Pixmap hourglasses[NUM_HOURGLASSES]; static Pixmap stop_sign = 0; void show_lock(snd_info *sp) { if (!has_widgets(sp)) return; if (mini_lock) XtVaSetValues(LOCK_OR_BOMB(sp), XmNlabelPixmap, mini_lock, NULL); } void hide_lock(snd_info *sp) { if (!has_widgets(sp)) return; if (mini_lock) XtVaSetValues(LOCK_OR_BOMB(sp), XmNlabelPixmap, blank_pixmap, NULL); /* these Pixmaps can be null if the colormap is screwed up */ } static void show_stop_sign(snd_info *sp) { if (!has_widgets(sp)) return; if (stop_sign) XtVaSetValues(STOP_ICON(sp), XmNlabelPixmap, stop_sign, NULL); } static void hide_stop_sign(snd_info *sp) { if (!has_widgets(sp)) return; if (blank_pixmap) XtVaSetValues(STOP_ICON(sp), XmNlabelPixmap, blank_pixmap, NULL); } static void show_bomb(snd_info *sp) { if (!has_widgets(sp)) return; if (sp->bomb_ctr >= NUM_BOMBS) sp->bomb_ctr = 0; if (bombs[sp->bomb_ctr]) XtVaSetValues(LOCK_OR_BOMB(sp), XmNlabelPixmap, bombs[sp->bomb_ctr], NULL); sp->bomb_ctr++; } static void hide_bomb(snd_info *sp) { if (!has_widgets(sp)) return; XtVaSetValues(LOCK_OR_BOMB(sp), XmNlabelPixmap, blank_pixmap, NULL); sp->bomb_ctr = 0; } #define BOMB_TIME 200 static void tick_bomb(XtPointer context, XtIntervalId *id) { snd_info *sp = (snd_info *)context; if (!has_widgets(sp)) return; if ((sp->need_update) || (sp->file_unreadable)) { show_bomb(sp); XtAppAddTimeOut(main_app(ss), (unsigned long)BOMB_TIME, (XtTimerCallbackProc)tick_bomb, context); } else { hide_bomb(sp); sp->bomb_in_progress = false; } } void start_bomb(snd_info *sp) { if (!has_widgets(sp)) return; sp->bomb_ctr = 0; if (!(sp->bomb_in_progress)) { sp->bomb_in_progress = true; XtAppAddTimeOut(main_app(ss), (unsigned long)BOMB_TIME, (XtTimerCallbackProc)tick_bomb, (void *)sp); } } void stop_bomb(snd_info *sp) { if (!has_widgets(sp)) return; hide_bomb(sp); sp->bomb_in_progress = false; } static char *bits_to_string(const char **icon) { /* show first few lines */ char *buf; buf = (char *)calloc(128, sizeof(char)); snprintf(buf, 128, "\n%s\n%s\n%s...", icon[0], icon[1], icon[2]); return(buf); } static void allocate_icons(Widget w) { Pixmap shape1, shape2, shape3, shape4; XpmAttributes attributes; XpmColorSymbol symbols[1]; int scr, k, pixerr; Display *dp; Drawable wn; dp = XtDisplay(w); wn = XtWindow(w); scr = DefaultScreen(dp); XtVaGetValues(w, XmNdepth, &attributes.depth, XmNcolormap, &attributes.colormap, NULL); attributes.visual = DefaultVisual(dp, scr); symbols[0].name = (char *)"basiccolor"; symbols[0].value = NULL; symbols[0].pixel = ss->basic_color; attributes.colorsymbols = symbols; attributes.numsymbols = 1; attributes.valuemask = XpmColorSymbols | XpmDepth | XpmColormap | XpmVisual; pixerr = XpmCreatePixmapFromData(dp, wn, (char **)mini_lock_bits(), &mini_lock, &shape1, &attributes); if (pixerr != XpmSuccess) snd_error("lock pixmap trouble: %s from %s\n", XpmGetErrorString(pixerr), bits_to_string(mini_lock_bits())); pixerr = XpmCreatePixmapFromData(dp, wn, (char **)blank_bits(), &blank_pixmap, &shape1, &attributes); if (pixerr != XpmSuccess) snd_error("blank pixmap trouble: %s from %s\n", XpmGetErrorString(pixerr), bits_to_string(blank_bits())); pixerr = XpmCreatePixmapFromData(dp, wn, (char **)stop_sign_bits(), &stop_sign, &shape4, &attributes); if (pixerr != XpmSuccess) snd_error("stop sign pixmap trouble: %s from %s\n", XpmGetErrorString(pixerr), bits_to_string(stop_sign_bits())); pixerr = XpmCreatePixmapFromData(dp, wn, (char **)close_icon_bits(), &close_icon, &shape1, &attributes); if (pixerr != XpmSuccess) snd_error("stop sign pixmap trouble: %s from %s\n", XpmGetErrorString(pixerr), bits_to_string(close_icon_bits())); for (k = 0; k < NUM_BOMBS; k++) { pixerr = XpmCreatePixmapFromData(dp, wn, (char **)mini_bomb_bits(k), &(bombs[k]), &shape2, &attributes); if (pixerr != XpmSuccess) { snd_error("bomb pixmap trouble: %s from %s\n", XpmGetErrorString(pixerr), bits_to_string(mini_bomb_bits(k))); break; } pixerr = XpmCreatePixmapFromData(dp, wn, (char **)mini_glass_bits(k), &(hourglasses[k]), &shape3, &attributes); /* NUM_HOURGLASSES == NUM_BOMBS so this is safe */ if (pixerr != XpmSuccess) { snd_error("glass pixmap trouble: %s from %s\n", XpmGetErrorString(pixerr), bits_to_string(mini_glass_bits(k))); break; } } mini_lock_allocated = true; } static void change_pixmap_background(Widget w, Pixmap orig, Pixel old_color, Pixel new_color, int width, int height) { XImage *before; Display *dp; Drawable wn; Visual *vis; XGCValues v; GC draw_gc; int depth, depth_bytes, x, y; char *data; dp = XtDisplay(w); wn = XtWindow(w); vis = DefaultVisual(dp, DefaultScreen(dp)); XtVaGetValues(w, XmNdepth, &depth, NULL); depth_bytes = (depth >> 3); data = (char *)calloc((width + 1) * (height + 1) * depth_bytes, sizeof(char)); /* not calloc since X will free this */ /* there's overflow in X here, apparently -- the +1's fix it according to valgrind */ /* perhaps this is supposed to be rounded up to byte boundaries? */ before = XCreateImage(dp, vis, depth, XYPixmap, 0, data, width, height, 8, 0); XGetSubImage(dp, orig, 0, 0, width, height, AllPlanes, XYPixmap, before, 0, 0); v.background = new_color; draw_gc = XCreateGC(dp, wn, GCBackground, &v); XSetBackground(dp, draw_gc, new_color); for (x = 0; x < width; x++) for (y = 0; y < height; y++) if (XGetPixel(before, x, y) == old_color) XPutPixel(before, x, y, new_color); XPutImage(dp, orig, draw_gc, before, 0, 0, 0, 0, width, height); XDestroyImage(before); /* frees data as well */ XFreeGC(dp, draw_gc); } void make_sound_icons_transparent_again(Pixel old_color, Pixel new_color) { int i; if (!mini_lock_allocated) allocate_icons(main_shell(ss)); change_pixmap_background(main_shell(ss), mini_lock, old_color, new_color, 16, 14); change_pixmap_background(main_shell(ss), blank_pixmap, old_color, new_color, 16, 14); change_pixmap_background(main_shell(ss), close_icon, old_color, new_color, 16, 14); /* change_pixmap_background(main_shell(ss), stop_sign, old_color, new_color, 17, 17); */ /* memory corruption here! */ for (i = 0; i < NUM_BOMBS; i++) change_pixmap_background(main_shell(ss), bombs[i], old_color, new_color, 16, 14); for (i = 0; i < NUM_HOURGLASSES; i++) change_pixmap_background(main_shell(ss), hourglasses[i], old_color, new_color, 16, 14); } static Pixmap spd_r, spd_l; static bool spd_ok = false; static void close_sound_dialog(Widget w, XtPointer context, XtPointer info) { snd_info *sp = (snd_info *)context; if (sp) snd_close_file(sp); } static void manage_sync_button(snd_info *sp) { XtManageChild(SYNC_BUTTON(sp)); } static void attach_status_area(snd_info *sp) { XtUnmanageChild(STATUS_AREA(sp)); XtVaSetValues(STATUS_AREA(sp), XmNrightAttachment, XmATTACH_WIDGET, XmNrightWidget, (XtIsManaged(UNITE_BUTTON(sp))) ? UNITE_BUTTON(sp) : ((XtIsManaged(SYNC_BUTTON(sp))) ? SYNC_BUTTON(sp) : PLAY_BUTTON(sp)), NULL); XtManageChild(STATUS_AREA(sp)); } snd_info *add_sound_window(char *filename, read_only_t read_only, file_info *hdr) { snd_info *sp = NULL, *osp; Widget *sw; XmString s1; int snd_slot, nchans = 1, i, old_chans; bool make_widgets; Arg args[32]; char *old_name = NULL, *title; Dimension app_dy, screen_y, chan_min_y; Position app_y; /* these dimensions are used to try to get a reasonable channel graph size without falling off the screen bottom */ Pixmap rb, lb; int depth; bool free_filename = false; Widget form; XtCallbackList n1, n2, n3, n4, n5, n6, n7, n8, n9, n10, n11, n12; Atom sound_delete; if (ss->translated_filename) { old_name = filename; filename = ss->translated_filename; free_filename = true; ss->translated_filename = NULL; } nchans = hdr->chans; if (nchans <= 0) nchans = 1; XtVaGetValues(main_shell(ss), XmNy, &app_y, XmNheight, &app_dy, NULL); screen_y = DisplayHeight(main_display(ss), DefaultScreen(main_display(ss))); app_dy = (screen_y - app_y - app_dy - 20 * nchans); chan_min_y = (Dimension)(app_dy / (Dimension)nchans); if (chan_min_y > (Dimension)(ss->channel_min_height)) chan_min_y = ss->channel_min_height; else if (chan_min_y < 5) chan_min_y = 5; snd_slot = find_free_sound_slot(nchans); /* expands sound list if needed */ if (ss->sounds[snd_slot]) /* we're trying to re-use an old, inactive set of widgets and whatnot */ { osp = ss->sounds[snd_slot]; old_chans = osp->allocated_chans; } else old_chans = 0; make_widgets = (!ss->sounds[snd_slot]); ss->sounds[snd_slot] = make_snd_info(ss->sounds[snd_slot], filename, hdr, snd_slot, read_only); sp = ss->sounds[snd_slot]; sp->inuse = SOUND_NORMAL; sp->bomb_ctr = 0; sp->write_date = file_write_date(filename); /* needed early in this process by the peak-env handlers */ if (!sp->widgets) sp->widgets = (Widget *)calloc(SP_NUM_WIDGETS, sizeof(Widget)); sw = sp->widgets; if ((!make_widgets) && (old_chans < nchans)) { for (i = old_chans; i < nchans; i++) add_channel_window(sp, i, chan_min_y, 1, NULL, WITH_FW_BUTTONS, WITH_EVENTS); } if (make_widgets) { int n; if (sound_style(ss) == SOUNDS_IN_SEPARATE_WINDOWS) { title = (char *)calloc(PRINT_BUFFER_SIZE, sizeof(char)); snprintf(title, PRINT_BUFFER_SIZE, "%d: %s", snd_slot, sp->short_filename); if (!sp->dialog) { n = 0; XtSetArg(args[n], XmNbackground, ss->basic_color); n++; XtSetArg(args[n], XmNautoUnmanage, false); n++; XtSetArg(args[n], XmNresizePolicy, XmRESIZE_GROW); n++; XtSetArg(args[n], XmNnoResize, false); n++; XtSetArg(args[n], XmNtransient, false); n++; sp->dialog = XtCreatePopupShell(title, xmDialogShellWidgetClass, main_shell(ss), args, n); /* using popup shell here gets around the problem that the shell passes resize requests to all its children * -- as a popup, it's not considered a child, but that means we don't inherit things like popup menus from * the main shell. */ sound_delete = XmInternAtom(XtDisplay(sp->dialog), (char *)"WM_DELETE_WINDOW", false); XmAddWMProtocolCallback(sp->dialog, sound_delete, close_sound_dialog, (XtPointer)sp); } else XtVaSetValues(sp->dialog, XmNtitle, title, NULL); free(title); if (!XtIsManaged(sp->dialog)) XtManageChild(sp->dialog); } n = 0; XtSetArg(args[n], XmNbackground, ss->basic_color); n++; n = attach_all_sides(args, n); XtSetArg(args[n], XmNallowResize, true); n++; XtSetArg(args[n], XmNsashIndent, ss->channel_sash_indent); n++; XtSetArg(args[n], XmNpaneMaximum, LOTSA_PIXELS); n++; /* Xm/Paned.c initializes this to 1000! */ if (ss->channel_sash_size != 0) { XtSetArg(args[n], XmNsashHeight, ss->channel_sash_size); n++; XtSetArg(args[n], XmNsashWidth, ss->channel_sash_size); n++; } /* if (mumble_style(ss) == CHANNELS_HORIZONTAL) {XtSetArg(args[n], XmNorientation, XmHORIZONTAL); n++;} */ /* this doesn't work yet because the control panel is screwed up when trying to display itself horizontally */ /* Perhaps another layer of panes? */ if (sound_style(ss) == SOUNDS_VERTICAL) { if (ss->toolbar) XtSetArg(args[n], XmNpositionIndex, snd_slot + 1); else XtSetArg(args[n], XmNpositionIndex, snd_slot); n++; } XtSetArg(args[n], XmNuserData, sp->index); n++; if (sound_style(ss) == SOUNDS_IN_SEPARATE_WINDOWS) SND_PANE(sp) = XtCreateManagedWidget("snd-pane", xmPanedWindowWidgetClass, sp->dialog, args, n); else { uint32_t i; CompositeWidget cw = (CompositeWidget)sound_pane(ss); SND_PANE(sp) = XtCreateManagedWidget("snd-pane", xmPanedWindowWidgetClass, sound_pane(ss), args, n); /* try to make the division between sounds more obvious */ for (i = 0; i < cw->composite.num_children; i++) { Widget child; child = cw->composite.children[i]; if (((XtIsWidget(child))|| (XmIsGadget(child))) && (XtIsManaged(child)) && ((XmIsSeparator(child)) || (XmIsSeparatorGadget(child)))) XtVaSetValues(child, XmNseparatorType, XmDOUBLE_LINE, XmNbackground, ss->white, NULL); } } XtAddEventHandler(SND_PANE(sp), KeyPressMask, false, graph_key_press, (XtPointer)sp); /* if user clicks in controls, then starts typing, try to send key events to current active channel */ /* all widgets in the control-pane that would otherwise intercept the key events get this event handler */ for (i = 0; i < nchans; i++) add_channel_window(sp, i, chan_min_y, 0, NULL, WITH_FW_BUTTONS, WITH_EVENTS); /* creates channel (horizontal) paned window widget as child of w_snd_pane(sp) == SND_PANE(sp) */ /* -------- sound file name, status area, various buttons -------- */ n = 0; XtSetArg(args[n], XmNbackground, ss->basic_color); n++; XtSetArg(args[n], XmNpaneMinimum, 20); n++; XtSetArg(args[n], XmNpaneMaximum, 20); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++; NAME_BOX(sp) = XtCreateManagedWidget("snd-name-form", xmFormWidgetClass, SND_PANE(sp), args, n); XtAddEventHandler(NAME_BOX(sp), KeyPressMask, false, graph_key_press, (XtPointer)sp); if (!mini_lock_allocated) allocate_icons(NAME_BOX(sp)); n = 0; XtSetArg(args[n], XmNbackground, ss->basic_color); n++; XtSetArg(args[n], XmNlabelType, XmPIXMAP); n++; XtSetArg(args[n], XmNlabelPixmap, close_icon); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNwidth, 32); n++; XtSetArg(args[n], XmNshadowThickness, 0); n++; XtSetArg(args[n], XmNhighlightThickness, 0); n++; XtSetArg(args[n], XmNalignment, XmALIGNMENT_BEGINNING); n++; CLOSE_BUTTON(sp) = XtCreateManagedWidget("close-button", xmPushButtonWidgetClass, NAME_BOX(sp), args, n); XtAddCallback(CLOSE_BUTTON(sp), XmNactivateCallback, close_button_callback, (XtPointer)sp); n = 0; s1 = XmStringCreateLocalized(shortname_indexed(sp)); XtSetArg(args[n], XmNbackground, ss->highlight_color); n++; XtSetArg(args[n], XmNalignment, XmALIGNMENT_BEGINNING); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++; /* XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++; */ XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNleftWidget, CLOSE_BUTTON(sp)); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNlabelString, s1); n++; XtSetArg(args[n], XmNshadowThickness, 0); n++; XtSetArg(args[n], XmNhighlightThickness, 0); n++; XtSetArg(args[n], XmNfillOnArm, false); n++; NAME_LABEL(sp) = XtCreateManagedWidget("snd-name", xmPushButtonWidgetClass, NAME_BOX(sp), args, n); XtAddEventHandler(NAME_LABEL(sp), KeyPressMask, false, graph_key_press, (XtPointer)sp); XtAddCallback(NAME_LABEL(sp), XmNactivateCallback, name_click_callback, (XtPointer)sp); XmStringFree(s1); n = 0; XtSetArg(args[n], XmNbackground, ss->basic_color); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNleftWidget, NAME_LABEL(sp)); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_NONE); n++; if (blank_pixmap) { /* if xpm failed (blank_pixmap == 0), this can cause X to kill Snd! */ XtSetArg(args[n], XmNlabelType, XmPIXMAP); n++; XtSetArg(args[n], XmNlabelPixmap, blank_pixmap); n++; } LOCK_OR_BOMB(sp) = XtCreateManagedWidget("", xmLabelWidgetClass, NAME_BOX(sp), args, n); { uint32_t i; Widget left_widget; left_widget = LOCK_OR_BOMB(sp); sp->progress_widgets = (Widget *)calloc(sp->nchans, sizeof(Widget)); sp->num_progress_widgets = sp->nchans; /* when an unused sound is reopened in snd-data.c, it's possible for its channel number * to be increased. If we then try to draw the clock icon in the new channel, its * widget will be unallocated -> segfault, so to keep things simple, we check this number. */ for (i = 0; i < sp->nchans; i++) { n = 0; XtSetArg(args[n], XmNbackground, ss->basic_color); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNleftWidget, left_widget); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_NONE); n++; if (blank_pixmap) { /* if xpm failed (blank_pixmap == 0), this can cause X to kill Snd! */ XtSetArg(args[n], XmNlabelType, XmPIXMAP); n++; XtSetArg(args[n], XmNlabelPixmap, blank_pixmap); n++; } sp->progress_widgets[i] = XtCreateManagedWidget("", xmLabelWidgetClass, NAME_BOX(sp), args, n); left_widget = sp->progress_widgets[i]; } n = 0; XtSetArg(args[n], XmNbackground, ss->basic_color); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNleftWidget, left_widget); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_NONE); n++; if (blank_pixmap) { XtSetArg(args[n], XmNlabelType, XmPIXMAP); n++; XtSetArg(args[n], XmNlabelPixmap, blank_pixmap); n++; } XtSetArg(args[n], XmNshadowThickness, 0); n++; XtSetArg(args[n], XmNhighlightThickness, 0); n++; XtSetArg(args[n], XmNfillOnArm, false); n++; STOP_ICON(sp) = XtCreateManagedWidget("", xmPushButtonWidgetClass, NAME_BOX(sp), args, n); XtAddCallback(STOP_ICON(sp), XmNactivateCallback, stop_sign_click_callback, (XtPointer)sp); } n = 0; XtSetArg(args[n], XmNbackground, ss->basic_color); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNleftWidget, STOP_ICON(sp)); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNresizeWidth, true); n++; XtSetArg(args[n], XmNmarginHeight, 1); n++; XtSetArg(args[n], XmNshadowThickness, 0); n++; XtSetArg(args[n], XmNeditable, false); n++; XtSetArg(args[n], XmNcursorPositionVisible, false); n++; STATUS_AREA(sp) = XtCreateManagedWidget("snd-info", xmTextFieldWidgetClass, NAME_BOX(sp), args, n); #if WITH_AUDIO n = 0; XtSetArg(args[n], XmNbackground, ss->basic_color); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++; #ifdef TOGGLE_MARGIN XtSetArg(args[n], XmNmarginHeight, TOGGLE_MARGIN); n++; XtSetArg(args[n], XmNmarginTop, TOGGLE_MARGIN); n++; #endif XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNrecomputeSize, false); n++; /* in Motif 2.2 this sets up a tooltip: XtSetArg(args[n], XmNtoolTipString, XmStringCreateLocalized((char *)"play this sound")); n++; */ XtSetArg(args[n], XmNselectColor, ss->selection_color); n++; PLAY_BUTTON(sp) = make_togglebutton_widget("play", NAME_BOX(sp), args, n); XtAddCallback(PLAY_BUTTON(sp), XmNvalueChangedCallback, play_button_callback, (XtPointer)sp); #endif n = 0; XtSetArg(args[n], XmNbackground, ss->basic_color); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++; #ifdef TOGGLE_MARGIN XtSetArg(args[n], XmNmarginHeight, TOGGLE_MARGIN); n++; XtSetArg(args[n], XmNmarginTop, TOGGLE_MARGIN); n++; #endif XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_NONE); n++; #if WITH_AUDIO XtSetArg(args[n], XmNrightAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNrightWidget, PLAY_BUTTON(sp)); n++; #else XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++; #endif XtSetArg(args[n], XmNselectColor, ss->selection_color); n++; SYNC_BUTTON(sp) = make_togglebutton_widget("sync", NAME_BOX(sp), args, n); XtAddEventHandler(SYNC_BUTTON(sp), KeyPressMask, false, graph_key_press, (XtPointer)sp); XtAddCallback(SYNC_BUTTON(sp), XmNvalueChangedCallback, sync_button_callback, (XtPointer)sp); n = 0; XtSetArg(args[n], XmNbackground, ss->basic_color); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_OPPOSITE_WIDGET); n++; XtSetArg(args[n], XmNbottomWidget, SYNC_BUTTON(sp)); n++; #ifdef TOGGLE_MARGIN XtSetArg(args[n], XmNmarginHeight, TOGGLE_MARGIN); n++; XtSetArg(args[n], XmNmarginTop, TOGGLE_MARGIN); n++; #endif XtSetArg(args[n], XmNleftAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNrightWidget, SYNC_BUTTON(sp)); n++; XtSetArg(args[n], XmNselectColor, ss->selection_color); n++; UNITE_BUTTON(sp) = make_togglebutton_widget("unite", NAME_BOX(sp), args, n); XtAddEventHandler(UNITE_BUTTON(sp), KeyPressMask, false, graph_key_press, (XtPointer)sp); XtAddCallback(UNITE_BUTTON(sp), XmNvalueChangedCallback, unite_button_callback, (XtPointer)sp); /* ---------------- control panel ---------------- */ n = 0; XtSetArg(args[n], XmNbackground, ss->basic_color); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++; CONTROLS(sp) = XtCreateManagedWidget("snd-amp", xmFormWidgetClass, SND_PANE(sp), args, n); XtAddEventHandler(CONTROLS(sp), KeyPressMask, false, graph_key_press, (XtPointer)sp); n = 0; /* AMP */ s1 = XmStringCreateLocalized((char *)"amp:"); XtSetArg(args[n], XmNbackground, ss->basic_color); n++; XtSetArg(args[n], XmNalignment, XmALIGNMENT_BEGINNING); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNlabelString, s1); n++; XtSetArg(args[n], XmNmarginHeight, CONTROLS_MARGIN); n++; XtSetArg(args[n], XmNrecomputeSize, false); n++; XtSetArg(args[n], XmNshadowThickness, 0); n++; XtSetArg(args[n], XmNhighlightThickness, 0); n++; XtSetArg(args[n], XmNfillOnArm, false); n++; AMP_BUTTON(sp) = make_pushbutton_widget("amp-label", CONTROLS(sp), args, n); XtAddEventHandler(AMP_BUTTON(sp), KeyPressMask, false, graph_key_press, (XtPointer)sp); XtAddCallback(AMP_BUTTON(sp), XmNactivateCallback, amp_click_callback, (XtPointer)sp); XmStringFree(s1); n = 0; s1 = XmStringCreateLocalized((char *)"1.0 "); XtSetArg(args[n], XmNbackground, ss->basic_color); n++; XtSetArg(args[n], XmNalignment, XmALIGNMENT_BEGINNING); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_OPPOSITE_WIDGET); n++; XtSetArg(args[n], XmNtopWidget, AMP_BUTTON(sp)); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNleftWidget, AMP_BUTTON(sp)); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNmarginHeight, CONTROLS_MARGIN); n++; XtSetArg(args[n], XmNrecomputeSize, false); n++; XtSetArg(args[n], XmNlabelString, s1); n++; XtSetArg(args[n], XmNmarginRight, 3); n++; AMP_LABEL(sp) = XtCreateManagedWidget("amp-number", xmLabelWidgetClass, CONTROLS(sp), args, n); XmStringFree(s1); n = 0; XtSetArg(args[n], XmNbackground, ss->position_color); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_OPPOSITE_WIDGET); n++; XtSetArg(args[n], XmNtopWidget, AMP_BUTTON(sp)); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNheight, 16); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNleftWidget, AMP_LABEL(sp)); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNorientation, XmHORIZONTAL); n++; XtSetArg(args[n], XmNmaximum, SCROLLBAR_MAX); n++; XtSetArg(args[n], XmNvalue, amp_to_scroll(sp->amp_control_min, 1.0, sp->amp_control_max)); n++; XtSetArg(args[n], XmNdragCallback, n1 = make_callback_list(amp_drag_callback, (XtPointer)sp)); n++; XtSetArg(args[n], XmNvalueChangedCallback, n2 = make_callback_list(amp_valuechanged_callback, (XtPointer)sp)); n++; AMP_SCROLLBAR(sp) = XtCreateManagedWidget("amp", xmScrollBarWidgetClass, CONTROLS(sp), args, n); XtAddEventHandler(AMP_SCROLLBAR(sp), KeyPressMask, false, graph_key_press, (XtPointer)sp); n = 0; /* SPEED */ s1 = XmStringCreateLocalized((char *)"speed:"); XtSetArg(args[n], XmNbackground, ss->basic_color); n++; XtSetArg(args[n], XmNalignment, XmALIGNMENT_BEGINNING); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNtopWidget, AMP_BUTTON(sp)); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNlabelString, s1); n++; XtSetArg(args[n], XmNmarginHeight, CONTROLS_MARGIN); n++; XtSetArg(args[n], XmNrecomputeSize, false); n++; XtSetArg(args[n], XmNshadowThickness, 0); n++; XtSetArg(args[n], XmNhighlightThickness, 0); n++; XtSetArg(args[n], XmNfillOnArm, false); n++; SPEED_BUTTON(sp) = make_pushbutton_widget("speed-label", CONTROLS(sp), args, n); XtAddEventHandler(SPEED_BUTTON(sp), KeyPressMask, false, graph_key_press, (XtPointer)sp); XtAddCallback(SPEED_BUTTON(sp), XmNactivateCallback, speed_click_callback, (XtPointer)sp); XmStringFree(s1); n = 0; s1 = initial_speed_label(sp->speed_control_style); XtSetArg(args[n], XmNbackground, ss->basic_color); n++; XtSetArg(args[n], XmNalignment, XmALIGNMENT_BEGINNING); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_OPPOSITE_WIDGET); n++; XtSetArg(args[n], XmNtopWidget, SPEED_BUTTON(sp)); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNleftWidget, SPEED_BUTTON(sp)); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNlabelString, s1); n++; XtSetArg(args[n], XmNmarginHeight, CONTROLS_MARGIN); n++; XtSetArg(args[n], XmNrecomputeSize, false); n++; XtSetArg(args[n], XmNmarginRight, 3); n++; XtSetArg(args[n], XmNshadowThickness, 0); n++; XtSetArg(args[n], XmNhighlightThickness, 0); n++; XtSetArg(args[n], XmNfillOnArm, false); n++; SPEED_LABEL(sp) = make_pushbutton_widget("speed-number", CONTROLS(sp), args, n); XtAddEventHandler(SPEED_LABEL(sp), KeyPressMask, false, graph_key_press, (XtPointer)sp); XtAddCallback(SPEED_LABEL(sp), XmNactivateCallback, speed_label_click_callback, (XtPointer)sp); XmStringFree(s1); n = 0; XtSetArg(args[n], XmNbackground, ss->basic_color); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_OPPOSITE_WIDGET); n++; XtSetArg(args[n], XmNtopWidget, SPEED_BUTTON(sp)); n++; XtSetArg(args[n], XmNindicatorOn, false); n++; XtSetArg(args[n], XmNlabelType, XmPIXMAP); n++; XtSetArg(args[n], XmNmarginHeight, 0); n++; XtSetArg(args[n], XmNmarginWidth, 0); n++; XtSetArg(args[n], XmNmarginTop, 0); n++; XtSetArg(args[n], XmNtopOffset, 0); n++; SPEED_ARROW(sp) = make_togglebutton_widget("dir", CONTROLS(sp), args, n); form = SPEED_ARROW(sp); if (!spd_ok) { rb = XCreateBitmapFromData(XtDisplay(form), RootWindowOfScreen(XtScreen(form)), (const char *)speed_r_bits1, 16, 12); lb = XCreateBitmapFromData(XtDisplay(form), RootWindowOfScreen(XtScreen(form)), (const char *)speed_l_bits1, 16, 12); XtVaGetValues(form, XmNdepth, &depth, NULL); spd_r = XCreatePixmap(XtDisplay(form), RootWindowOfScreen(XtScreen(form)), 16, 12, depth); spd_l = XCreatePixmap(XtDisplay(form), RootWindowOfScreen(XtScreen(form)), 16, 12, depth); XCopyPlane(XtDisplay(form), rb, spd_r, ss->fltenv_basic_gc, 0, 0, 16, 12, 0, 0, 1); XCopyPlane(XtDisplay(form), lb, spd_l, ss->fltenv_basic_gc, 0, 0, 16, 12, 0, 0, 1); XFreePixmap(XtDisplay(form), rb); XFreePixmap(XtDisplay(form), lb); spd_ok = true; } XtVaSetValues(form, XmNselectPixmap, spd_l, XmNlabelPixmap, spd_r, NULL); XtAddEventHandler(SPEED_ARROW(sp), KeyPressMask, false, graph_key_press, (XtPointer)sp); XtAddCallback(SPEED_ARROW(sp), XmNvalueChangedCallback, play_arrow_callback, (XtPointer)sp); n = 0; XtSetArg(args[n], XmNbackground, ss->position_color); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_OPPOSITE_WIDGET); n++; XtSetArg(args[n], XmNtopWidget, SPEED_BUTTON(sp)); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNleftWidget, SPEED_LABEL(sp)); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNrightWidget, SPEED_ARROW(sp)); n++; XtSetArg(args[n], XmNorientation, XmHORIZONTAL); n++; XtSetArg(args[n], XmNmaximum, SCROLLBAR_MAX); n++; XtSetArg(args[n], XmNvalue, speed_to_scroll(sp->speed_control_min, 1.0, sp->speed_control_max)); n++; XtSetArg(args[n], XmNheight, 16); n++; XtSetArg(args[n], XmNdragCallback, n3 = make_callback_list(speed_drag_callback, (XtPointer)sp)); n++; XtSetArg(args[n], XmNvalueChangedCallback, n4 = make_callback_list(speed_valuechanged_callback, (XtPointer)sp)); n++; SPEED_SCROLLBAR(sp) = XtCreateManagedWidget("speed-scroll", xmScrollBarWidgetClass, CONTROLS(sp), args, n); XtAddEventHandler(SPEED_SCROLLBAR(sp), KeyPressMask, false, graph_key_press, (XtPointer)sp); n = 0; /* EXPAND */ s1 = XmStringCreateLocalized((char *)"expand:"); XtSetArg(args[n], XmNbackground, ss->basic_color); n++; XtSetArg(args[n], XmNalignment, XmALIGNMENT_BEGINNING); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNtopWidget, SPEED_BUTTON(sp)); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNlabelString, s1); n++; XtSetArg(args[n], XmNmarginHeight, CONTROLS_MARGIN); n++; XtSetArg(args[n], XmNrecomputeSize, false); n++; XtSetArg(args[n], XmNshadowThickness, 0); n++; XtSetArg(args[n], XmNhighlightThickness, 0); n++; XtSetArg(args[n], XmNfillOnArm, false); n++; EXPAND_LEFT_BUTTON(sp) = make_pushbutton_widget("expand-label", CONTROLS(sp), args, n); XtAddEventHandler(EXPAND_LEFT_BUTTON(sp), KeyPressMask, false, graph_key_press, (XtPointer)sp); XtAddCallback(EXPAND_LEFT_BUTTON(sp), XmNactivateCallback, expand_click_callback, (XtPointer)sp); XmStringFree(s1); n = 0; s1 = XmStringCreateLocalized((char *)"1.0 "); XtSetArg(args[n], XmNbackground, ss->basic_color); n++; XtSetArg(args[n], XmNalignment, XmALIGNMENT_BEGINNING); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_OPPOSITE_WIDGET); n++; XtSetArg(args[n], XmNtopWidget, EXPAND_LEFT_BUTTON(sp)); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNleftWidget, EXPAND_LEFT_BUTTON(sp)); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNmarginHeight, CONTROLS_MARGIN); n++; XtSetArg(args[n], XmNrecomputeSize, false); n++; XtSetArg(args[n], XmNlabelString, s1); n++; XtSetArg(args[n], XmNmarginRight, 3); n++; EXPAND_LABEL(sp) = XtCreateManagedWidget("expand-number", xmLabelWidgetClass, CONTROLS(sp), args, n); XmStringFree(s1); n = 0; s1 = XmStringCreateLocalized((char *)""); XtSetArg(args[n], XmNbackground, ss->basic_color); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_OPPOSITE_WIDGET); n++; XtSetArg(args[n], XmNtopWidget, EXPAND_LEFT_BUTTON(sp)); n++; XtSetArg(args[n], XmNheight, 16); n++; XtSetArg(args[n], XmNmarginHeight, CONTROLS_MARGIN); n++; XtSetArg(args[n], XmNmarginWidth, 0); n++; XtSetArg(args[n], XmNtopOffset, 1); n++; XtSetArg(args[n], XmNspacing, 0); n++; XtSetArg(args[n], XmNlabelString, s1); n++; if (ss->toggle_size > 0) {XtSetArg(args[n], XmNindicatorSize, ss->toggle_size); n++;} XtSetArg(args[n], XmNselectColor, ss->selection_color); n++; EXPAND_RIGHT_BUTTON(sp) = make_togglebutton_widget("expoff", CONTROLS(sp), args, n); XtAddEventHandler(EXPAND_RIGHT_BUTTON(sp), KeyPressMask, false, graph_key_press, (XtPointer)sp); XtAddCallback(EXPAND_RIGHT_BUTTON(sp), XmNvalueChangedCallback, expand_button_callback, (XtPointer)sp); XmStringFree(s1); n = 0; XtSetArg(args[n], XmNbackground, ss->basic_color); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_OPPOSITE_WIDGET); n++; XtSetArg(args[n], XmNtopWidget, EXPAND_LEFT_BUTTON(sp)); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNleftWidget, EXPAND_LABEL(sp)); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNrightWidget, EXPAND_RIGHT_BUTTON(sp)); n++; XtSetArg(args[n], XmNorientation, XmHORIZONTAL); n++; XtSetArg(args[n], XmNmaximum, SCROLLBAR_MAX); n++; XtSetArg(args[n], XmNvalue, expand_to_scroll(sp->expand_control_min, 1.0, sp->expand_control_max)); n++; XtSetArg(args[n], XmNheight, 16); n++; XtSetArg(args[n], XmNmarginHeight, CONTROLS_MARGIN); n++; XtSetArg(args[n], XmNdragCallback, n5 = make_callback_list(expand_drag_callback, (XtPointer)sp)); n++; XtSetArg(args[n], XmNvalueChangedCallback, n6 = make_callback_list(expand_valuechanged_callback, (XtPointer)sp)); n++; EXPAND_SCROLLBAR(sp) = XtCreateManagedWidget("expand-scroll", xmScrollBarWidgetClass, CONTROLS(sp), args, n); XtAddEventHandler(EXPAND_SCROLLBAR(sp), KeyPressMask, false, graph_key_press, (XtPointer)sp); /* CONTRAST */ n = 0; s1 = XmStringCreateLocalized((char *)"contrast:"); XtSetArg(args[n], XmNbackground, ss->basic_color); n++; XtSetArg(args[n], XmNalignment, XmALIGNMENT_BEGINNING); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNtopWidget, EXPAND_LEFT_BUTTON(sp)); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNlabelString, s1); n++; XtSetArg(args[n], XmNmarginHeight, CONTROLS_MARGIN); n++; XtSetArg(args[n], XmNrecomputeSize, false); n++; XtSetArg(args[n], XmNshadowThickness, 0); n++; XtSetArg(args[n], XmNhighlightThickness, 0); n++; XtSetArg(args[n], XmNfillOnArm, false); n++; CONTRAST_LEFT_BUTTON(sp) = make_pushbutton_widget("contrast-label", CONTROLS(sp), args, n); XtAddEventHandler(CONTRAST_LEFT_BUTTON(sp), KeyPressMask, false, graph_key_press, (XtPointer)sp); XtAddCallback(CONTRAST_LEFT_BUTTON(sp), XmNactivateCallback, contrast_click_callback, (XtPointer)sp); XmStringFree(s1); n = 0; s1 = XmStringCreateLocalized((char *)"1.0 "); XtSetArg(args[n], XmNbackground, ss->basic_color); n++; XtSetArg(args[n], XmNalignment, XmALIGNMENT_BEGINNING); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_OPPOSITE_WIDGET); n++; XtSetArg(args[n], XmNtopWidget, CONTRAST_LEFT_BUTTON(sp)); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNleftWidget, CONTRAST_LEFT_BUTTON(sp)); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNmarginHeight, CONTROLS_MARGIN); n++; XtSetArg(args[n], XmNrecomputeSize, false); n++; XtSetArg(args[n], XmNlabelString, s1); n++; XtSetArg(args[n], XmNmarginRight, 3); n++; CONTRAST_LABEL(sp) = XtCreateManagedWidget("contrast-number", xmLabelWidgetClass, CONTROLS(sp), args, n); XmStringFree(s1); n = 0; s1 = XmStringCreateLocalized((char *)""); XtSetArg(args[n], XmNbackground, ss->basic_color); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_OPPOSITE_WIDGET); n++; XtSetArg(args[n], XmNtopWidget, CONTRAST_LEFT_BUTTON(sp)); n++; XtSetArg(args[n], XmNheight, 16); n++; XtSetArg(args[n], XmNmarginHeight, CONTROLS_MARGIN); n++; XtSetArg(args[n], XmNmarginWidth, 0); n++; XtSetArg(args[n], XmNtopOffset, 1); n++; XtSetArg(args[n], XmNlabelString, s1); n++; XtSetArg(args[n], XmNspacing, 0); n++; if (ss->toggle_size > 0) {XtSetArg(args[n], XmNindicatorSize, ss->toggle_size); n++;} XtSetArg(args[n], XmNselectColor, ss->selection_color); n++; CONTRAST_RIGHT_BUTTON(sp) = make_togglebutton_widget("conoff", CONTROLS(sp), args, n); XtAddEventHandler(CONTRAST_RIGHT_BUTTON(sp), KeyPressMask, false, graph_key_press, (XtPointer)sp); XtAddCallback(CONTRAST_RIGHT_BUTTON(sp), XmNvalueChangedCallback, contrast_button_callback, (XtPointer)sp); XmStringFree(s1); n = 0; XtSetArg(args[n], XmNbackground, ss->basic_color); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_OPPOSITE_WIDGET); n++; XtSetArg(args[n], XmNtopWidget, CONTRAST_LEFT_BUTTON(sp)); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNleftWidget, CONTRAST_LABEL(sp)); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNrightWidget, CONTRAST_RIGHT_BUTTON(sp)); n++; XtSetArg(args[n], XmNorientation, XmHORIZONTAL); n++; XtSetArg(args[n], XmNmaximum, SCROLLBAR_MAX); n++; XtSetArg(args[n], XmNheight, 16); n++; XtSetArg(args[n], XmNvalue, 0); n++; XtSetArg(args[n], XmNmarginHeight, CONTROLS_MARGIN); n++; XtSetArg(args[n], XmNdragCallback, n7 = make_callback_list(contrast_drag_callback, (XtPointer)sp)); n++; XtSetArg(args[n], XmNvalueChangedCallback, n8 = make_callback_list(contrast_valuechanged_callback, (XtPointer)sp)); n++; CONTRAST_SCROLLBAR(sp) = XtCreateManagedWidget("contrast-scroll", xmScrollBarWidgetClass, CONTROLS(sp), args, n); XtAddEventHandler(CONTRAST_SCROLLBAR(sp), KeyPressMask, false, graph_key_press, (XtPointer)sp); /* REVERB */ /* REVSCL */ n = 0; s1 = XmStringCreateLocalized((char *)"reverb:"); XtSetArg(args[n], XmNbackground, ss->basic_color); n++; XtSetArg(args[n], XmNalignment, XmALIGNMENT_BEGINNING); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNtopWidget, CONTRAST_LEFT_BUTTON(sp)); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNlabelString, s1); n++; XtSetArg(args[n], XmNmarginHeight, CONTROLS_MARGIN); n++; XtSetArg(args[n], XmNrecomputeSize, false); n++; XtSetArg(args[n], XmNshadowThickness, 0); n++; XtSetArg(args[n], XmNhighlightThickness, 0); n++; XtSetArg(args[n], XmNfillOnArm, false); n++; REVSCL_BUTTON(sp) = make_pushbutton_widget("revscl-label", CONTROLS(sp), args, n); XtAddEventHandler(REVSCL_BUTTON(sp), KeyPressMask, false, graph_key_press, (XtPointer)sp); XtAddCallback(REVSCL_BUTTON(sp), XmNactivateCallback, revscl_click_callback, (XtPointer)sp); XmStringFree(s1); n = 0; s1 = XmStringCreateLocalized((char *)"0.0 "); XtSetArg(args[n], XmNbackground, ss->basic_color); n++; XtSetArg(args[n], XmNalignment, XmALIGNMENT_BEGINNING); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_OPPOSITE_WIDGET); n++; XtSetArg(args[n], XmNtopWidget, REVSCL_BUTTON(sp)); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNleftWidget, REVSCL_BUTTON(sp)); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNlabelString, s1); n++; XtSetArg(args[n], XmNmarginHeight, CONTROLS_MARGIN); n++; XtSetArg(args[n], XmNrecomputeSize, false); n++; XtSetArg(args[n], XmNmarginRight, 3); n++; REVSCL_LABEL(sp) = XtCreateManagedWidget("revscl-number", xmLabelWidgetClass, CONTROLS(sp), args, n); XmStringFree(s1); n = 0; XtSetArg(args[n], XmNbackground, ss->basic_color); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_OPPOSITE_WIDGET); n++; XtSetArg(args[n], XmNtopWidget, REVSCL_BUTTON(sp)); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNleftWidget, REVSCL_LABEL(sp)); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_POSITION); n++; XtSetArg(args[n], XmNrightPosition, 60); n++; XtSetArg(args[n], XmNorientation, XmHORIZONTAL); n++; XtSetArg(args[n], XmNheight, 16); n++; XtSetArg(args[n], XmNmaximum, SCROLLBAR_MAX); n++; XtSetArg(args[n], XmNvalue, 0); n++; XtSetArg(args[n], XmNmarginHeight, CONTROLS_MARGIN); n++; XtSetArg(args[n], XmNdragCallback, n9 = make_callback_list(revscl_drag_callback, (XtPointer)sp)); n++; XtSetArg(args[n], XmNvalueChangedCallback, n10 = make_callback_list(revscl_valuechanged_callback, (XtPointer)sp)); n++; REVSCL_SCROLLBAR(sp) = XtCreateManagedWidget("revscl-scroll", xmScrollBarWidgetClass, CONTROLS(sp), args, n); XtAddEventHandler(REVSCL_SCROLLBAR(sp), KeyPressMask, false, graph_key_press, (XtPointer)sp); /* REVOFF */ n = 0; s1 = XmStringCreateLocalized((char *)""); XtSetArg(args[n], XmNbackground, ss->basic_color); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_OPPOSITE_WIDGET); n++; XtSetArg(args[n], XmNtopWidget, REVSCL_BUTTON(sp)); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_OPPOSITE_WIDGET); n++; XtSetArg(args[n], XmNrightWidget, CONTRAST_RIGHT_BUTTON(sp)); n++; XtSetArg(args[n], XmNheight, 16); n++; XtSetArg(args[n], XmNmarginHeight, CONTROLS_MARGIN); n++; XtSetArg(args[n], XmNmarginWidth, 0); n++; XtSetArg(args[n], XmNtopOffset, 1); n++; XtSetArg(args[n], XmNspacing, 0); n++; XtSetArg(args[n], XmNlabelString, s1); n++; if (ss->toggle_size > 0) {XtSetArg(args[n], XmNindicatorSize, ss->toggle_size); n++;} XtSetArg(args[n], XmNselectColor, ss->selection_color); n++; REVERB_BUTTON(sp) = make_togglebutton_widget("revoff", CONTROLS(sp), args, n); XtAddEventHandler(REVERB_BUTTON(sp), KeyPressMask, false, graph_key_press, (XtPointer)sp); XtAddCallback(REVERB_BUTTON(sp), XmNvalueChangedCallback, reverb_button_callback, (XtPointer)sp); XmStringFree(s1); /* REVLEN */ n = 0; s1 = XmStringCreateLocalized((char *)"len:"); XtSetArg(args[n], XmNbackground, ss->basic_color); n++; XtSetArg(args[n], XmNalignment, XmALIGNMENT_BEGINNING); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_OPPOSITE_WIDGET); n++; XtSetArg(args[n], XmNtopWidget, REVSCL_SCROLLBAR(sp)); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_POSITION); n++; XtSetArg(args[n], XmNleftPosition, 60); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNlabelString, s1); n++; XtSetArg(args[n], XmNmarginHeight, CONTROLS_MARGIN); n++; XtSetArg(args[n], XmNrecomputeSize, false); n++; XtSetArg(args[n], XmNshadowThickness, 0); n++; XtSetArg(args[n], XmNhighlightThickness, 0); n++; XtSetArg(args[n], XmNfillOnArm, false); n++; REVLEN_BUTTON(sp) = make_pushbutton_widget("revlen-label", CONTROLS(sp), args, n); XtAddEventHandler(REVLEN_BUTTON(sp), KeyPressMask, false, graph_key_press, (XtPointer)sp); XtAddCallback(REVLEN_BUTTON(sp), XmNactivateCallback, revlen_click_callback, (XtPointer)sp); XmStringFree(s1); n = 0; s1 = XmStringCreateLocalized((char *)"1.0 "); XtSetArg(args[n], XmNbackground, ss->basic_color); n++; XtSetArg(args[n], XmNalignment, XmALIGNMENT_BEGINNING); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_OPPOSITE_WIDGET); n++; XtSetArg(args[n], XmNtopWidget, REVLEN_BUTTON(sp)); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNleftWidget, REVLEN_BUTTON(sp)); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNlabelString, s1); n++; XtSetArg(args[n], XmNmarginHeight, CONTROLS_MARGIN); n++; XtSetArg(args[n], XmNrecomputeSize, false); n++; XtSetArg(args[n], XmNmarginRight, 3); n++; REVLEN_LABEL(sp) = XtCreateManagedWidget("revlen-number", xmLabelWidgetClass, CONTROLS(sp), args, n); XmStringFree(s1); n = 0; XtSetArg(args[n], XmNbackground, ss->basic_color); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_OPPOSITE_WIDGET); n++; XtSetArg(args[n], XmNtopWidget, REVLEN_BUTTON(sp)); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNleftWidget, REVLEN_LABEL(sp)); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNrightWidget, REVERB_BUTTON(sp)); n++; XtSetArg(args[n], XmNorientation, XmHORIZONTAL); n++; XtSetArg(args[n], XmNheight, 16); n++; XtSetArg(args[n], XmNmaximum, SCROLLBAR_MAX); n++; XtSetArg(args[n], XmNvalue, revlen_to_scroll(sp->reverb_control_length_min, 1.0, sp->reverb_control_length_max)); n++; XtSetArg(args[n], XmNmarginHeight, CONTROLS_MARGIN); n++; XtSetArg(args[n], XmNdragCallback, n11 = make_callback_list(revlen_drag_callback, (XtPointer)sp)); n++; XtSetArg(args[n], XmNvalueChangedCallback, n12 = make_callback_list(revlen_valuechanged_callback, (XtPointer)sp)); n++; REVLEN_SCROLLBAR(sp) = XtCreateManagedWidget("revlen-scroll", xmScrollBarWidgetClass, CONTROLS(sp), args, n); XtAddEventHandler(REVLEN_SCROLLBAR(sp), KeyPressMask, false, graph_key_press, (XtPointer)sp); /* FILTER */ n = 0; s1 = XmStringCreateLocalized((char *)"filter:"); XtSetArg(args[n], XmNbackground, ss->basic_color); n++; XtSetArg(args[n], XmNalignment, XmALIGNMENT_BEGINNING); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNtopWidget, REVSCL_BUTTON(sp)); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNlabelString, s1); n++; XtSetArg(args[n], XmNmarginHeight, CONTROLS_MARGIN); n++; XtSetArg(args[n], XmNrecomputeSize, false); n++; XtSetArg(args[n], XmNshadowThickness, 0); n++; XtSetArg(args[n], XmNhighlightThickness, 0); n++; XtSetArg(args[n], XmNfillOnArm, false); n++; FILTER_LABEL(sp) = XtCreateManagedWidget("filter-label", xmLabelWidgetClass, CONTROLS(sp), args, n); XmStringFree(s1); /* filter order */ n = 0; XtSetArg(args[n], XmNbackground, ss->basic_color); n++; XtSetArg(args[n], XmNresizeWidth, false); n++; XtSetArg(args[n], XmNcolumns, 3); n++; XtSetArg(args[n], XmNalignment, XmALIGNMENT_BEGINNING); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_OPPOSITE_WIDGET); n++; XtSetArg(args[n], XmNtopWidget, FILTER_LABEL(sp)); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNleftWidget, FILTER_LABEL(sp)); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNmarginHeight, CONTROLS_MARGIN); n++; XtSetArg(args[n], XmNrecomputeSize, false); n++; FILTER_ORDER_TEXT(sp) = make_textfield_widget("filter-order", CONTROLS(sp), args, n, ACTIVATABLE, NO_COMPLETER); XmTextSetString(FILTER_ORDER_TEXT(sp), (char *)" 20"); XtAddCallback(FILTER_ORDER_TEXT(sp), XmNactivateCallback, filter_order_activate_callback, (XtPointer)sp); #define ARROW_SIZE 12 n = 0; XtSetArg(args[n], XmNbackground, ss->basic_color); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_OPPOSITE_WIDGET); n++; XtSetArg(args[n], XmNtopWidget, FILTER_ORDER_TEXT(sp)); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNleftWidget, FILTER_ORDER_TEXT(sp)); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNheight, ARROW_SIZE); n++; XtSetArg(args[n], XmNwidth, ARROW_SIZE); n++; XtSetArg(args[n], XmNborderWidth, 0); n++; XtSetArg(args[n], XmNmarginWidth, 0); n++; XtSetArg(args[n], XmNarmColor, ss->selection_color); n++; FILTER_ORDER_DOWN(sp) = make_pushbutton_widget("", CONTROLS(sp), args, n); XtAddEventHandler(FILTER_ORDER_DOWN(sp), KeyPressMask, false, graph_key_press, (XtPointer)sp); XtAddCallback(FILTER_ORDER_DOWN(sp), XmNactivateCallback, filter_order_down_callback, (XtPointer)sp); n = 0; XtSetArg(args[n], XmNbackground, ss->basic_color); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNtopWidget, FILTER_ORDER_DOWN(sp)); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNleftWidget, FILTER_ORDER_TEXT(sp)); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNheight, ARROW_SIZE); n++; XtSetArg(args[n], XmNwidth, ARROW_SIZE); n++; XtSetArg(args[n], XmNborderWidth, 0); n++; XtSetArg(args[n], XmNmarginWidth, 0); n++; XtSetArg(args[n], XmNarmColor, ss->selection_color); n++; FILTER_ORDER_UP(sp) = make_pushbutton_widget("", CONTROLS(sp), args, n); XtAddEventHandler(FILTER_ORDER_UP(sp), KeyPressMask, false, graph_key_press, (XtPointer)sp); XtAddCallback(FILTER_ORDER_UP(sp), XmNactivateCallback, filter_order_up_callback, (XtPointer)sp); n = 0; s1 = XmStringCreateLocalized((char *)""); XtSetArg(args[n], XmNbackground, ss->basic_color); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNtopWidget, REVERB_BUTTON(sp)); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNheight, 16); n++; XtSetArg(args[n], XmNmarginWidth, 0); n++; XtSetArg(args[n], XmNtopOffset, 2); n++; XtSetArg(args[n], XmNspacing, 0); n++; XtSetArg(args[n], XmNlabelString, s1); n++; if (ss->toggle_size > 0) {XtSetArg(args[n], XmNindicatorSize, ss->toggle_size); n++;} XtSetArg(args[n], XmNselectColor, ss->selection_color); n++; FILTER_BUTTON(sp) = make_togglebutton_widget("fltoff", CONTROLS(sp), args, n); XtAddEventHandler(FILTER_BUTTON(sp), KeyPressMask, false, graph_key_press, (XtPointer)sp); XtAddCallback(FILTER_BUTTON(sp), XmNvalueChangedCallback, filter_button_callback, (XtPointer)sp); XmStringFree(s1); n = 0; s1 = XmStringCreateLocalized((char *)"hz"); XtSetArg(args[n], XmNbackground, ss->basic_color); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_OPPOSITE_WIDGET); n++; XtSetArg(args[n], XmNtopWidget, FILTER_BUTTON(sp)); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNrightWidget, FILTER_BUTTON(sp)); n++; XtSetArg(args[n], XmNlabelString, s1); n++; XtSetArg(args[n], XmNvalue, sp->filter_control_in_hz); n++; if (ss->toggle_size > 0) {XtSetArg(args[n], XmNindicatorSize, ss->toggle_size); n++;} XtSetArg(args[n], XmNselectColor, ss->selection_color); n++; FILTER_HZ_BUTTON(sp) = make_togglebutton_widget("flthz", CONTROLS(sp), args, n); XtAddEventHandler(FILTER_HZ_BUTTON(sp), KeyPressMask, false, graph_key_press, (XtPointer)sp); XtAddCallback(FILTER_HZ_BUTTON(sp), XmNvalueChangedCallback, filter_hz_callback, (XtPointer)sp); XmStringFree(s1); n = 0; s1 = XmStringCreateLocalized((char *)"dB"); XtSetArg(args[n], XmNbackground, ss->basic_color); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_OPPOSITE_WIDGET); n++; XtSetArg(args[n], XmNtopWidget, FILTER_HZ_BUTTON(sp)); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNrightWidget, FILTER_HZ_BUTTON(sp)); n++; XtSetArg(args[n], XmNlabelString, s1); n++; XtSetArg(args[n], XmNvalue, sp->filter_control_in_dB); n++; if (ss->toggle_size > 0) {XtSetArg(args[n], XmNindicatorSize, ss->toggle_size); n++;} XtSetArg(args[n], XmNselectColor, ss->selection_color); n++; FILTER_DB_BUTTON(sp) = make_togglebutton_widget("fltdB", CONTROLS(sp), args, n); XtAddEventHandler(FILTER_DB_BUTTON(sp), KeyPressMask, false, graph_key_press, (XtPointer)sp); XtAddCallback(FILTER_DB_BUTTON(sp), XmNvalueChangedCallback, filter_dB_callback, (XtPointer)sp); XmStringFree(s1); n = 0; XtSetArg(args[n], XmNbackground, ss->basic_color); n++; XtSetArg(args[n], XmNalignment, XmALIGNMENT_BEGINNING); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_OPPOSITE_WIDGET); n++; XtSetArg(args[n], XmNtopWidget, FILTER_ORDER_DOWN(sp)); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNleftWidget, FILTER_ORDER_DOWN(sp)); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNrightWidget, FILTER_DB_BUTTON(sp)); n++; XtSetArg(args[n], XmNmarginHeight, CONTROLS_MARGIN); n++; FILTER_COEFFS_TEXT(sp) = make_textfield_widget("filter-text", CONTROLS(sp), args, n, ACTIVATABLE, add_completer_func(filename_completer, NULL)); XtAddCallback(FILTER_COEFFS_TEXT(sp), XmNactivateCallback, filter_activate_callback, (XtPointer)sp); /* FILTER GRAPH */ n = 0; XtSetArg(args[n], XmNbackground, ss->basic_color); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNtopWidget, FILTER_COEFFS_TEXT(sp)); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_POSITION); n++; XtSetArg(args[n], XmNleftPosition, 4); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_POSITION); n++; XtSetArg(args[n], XmNrightPosition, 98); n++; XtSetArg(args[n], XmNallowResize, true); n++; XtSetArg(args[n], XmNshadowType, XmSHADOW_ETCHED_IN); n++; XtSetArg(args[n], XmNshadowThickness, 4); n++; FILTER_FRAME(sp) = XtCreateManagedWidget("filter-frame", xmFrameWidgetClass, CONTROLS(sp), args, n); n = 0; XtSetArg(args[n], XmNbackground, ss->highlight_color); n++; n = attach_all_sides(args, n); XtSetArg(args[n], XmNallowResize, true); n++; FILTER_GRAPH(sp) = XtCreateManagedWidget("filter-window", xmDrawingAreaWidgetClass, FILTER_FRAME(sp), args, n); XtAddCallback(FILTER_GRAPH(sp), XmNresizeCallback, filter_drawer_resize, (XtPointer)sp); XtAddCallback(FILTER_GRAPH(sp), XmNexposeCallback, filter_drawer_resize, (XtPointer)sp); sp->flt = new_env_editor(); XtAddEventHandler(FILTER_GRAPH(sp), ButtonPressMask, false, filter_drawer_button_press, sp); XtAddEventHandler(FILTER_GRAPH(sp), ButtonMotionMask, false, filter_drawer_button_motion, sp); XtAddEventHandler(FILTER_GRAPH(sp), ButtonReleaseMask, false, filter_drawer_button_release, sp); XtAddEventHandler(FILTER_GRAPH(sp), KeyPressMask, false, graph_key_press, (XtPointer)sp); free(n1); free(n2); free(n3); free(n4); free(n5); free(n6); free(n7); free(n8); free(n9); free(n10); free(n11); free(n12); /* end if control-panel */ if (sound_style(ss) == SOUNDS_IN_NOTEBOOK) { char *name; name = just_filename(sp->short_filename); /* copies */ if (strlen(name) > 8) name[8] = '\0'; n = 0; XtSetArg(args[n], XmNbackground, ss->graph_color); n++; XtSetArg(args[n], XmNnotebookChildType, XmMAJOR_TAB); n++; XtSetArg(args[n], XmNuserData, sp->index); n++; sp->tab = XtCreateManagedWidget(name, xmPushButtonWidgetClass, sound_pane(ss), args, n); free(name); } if (sound_style(ss) != SOUNDS_IN_SEPARATE_WINDOWS) run_new_widget_hook(SND_PANE(sp)); else run_new_widget_hook(sp->dialog); #if WITH_RELATIVE_PANES if (sound_style(ss) == SOUNDS_VERTICAL) add_sash_watchers(sound_pane(ss)); /* add in any case since we might later change the sense of with_relative_panes */ #endif } /* new sound ss */ else { /* re-manage currently inactive chan */ int k; if (sound_style(ss) == SOUNDS_IN_SEPARATE_WINDOWS) { title = (char *)calloc(PRINT_BUFFER_SIZE, sizeof(char)); snprintf(title, PRINT_BUFFER_SIZE, "%d: %s", snd_slot, sp->short_filename); XtVaSetValues(sp->dialog, XmNtitle, title, NULL); free(title); if (!XtIsManaged(sp->dialog)) XtManageChild(sp->dialog); } for (i = 0; i < SP_NUM_WIDGETS - 1; i++) if ((sw[i]) && (!XtIsManaged(sw[i])) && (in_show_controls(ss) || (i != W_amp_form))) XtManageChild(sw[i]); for (k = 0; k < nchans; k++) add_channel_window(sp, k, chan_min_y, 0, NULL, WITH_FW_BUTTONS, WITH_EVENTS); set_button_label(NAME_LABEL(sp), shortname_indexed(sp)); XtVaSetValues(SND_PANE(sp), XmNuserData, sp->index, NULL); if (sound_style(ss) == SOUNDS_IN_NOTEBOOK) { char *name; name = just_filename(sp->short_filename); set_label(sp->tab, name); free(name); } } map_over_children(sound_pane(ss), color_sashes); if (!(in_show_controls(ss))) hide_controls(sp); else show_controls(sp); if (sp->nchans == 1) { XmToggleButtonSetState(UNITE_BUTTON(sp), false, false); XtUnmanageChild(UNITE_BUTTON(sp)); if (ss->active_sounds == 0) /* ticked at the end in snd-file.c */ { XmToggleButtonSetState(SYNC_BUTTON(sp), false, false); XtUnmanageChild(SYNC_BUTTON(sp)); } else { for_each_sound(manage_sync_button); } } else { for_each_sound(manage_sync_button); } attach_status_area(sp); add_sound_data(filename, sp, WITH_GRAPH); if (cant_write(sp->filename)) sp->file_read_only = FILE_READ_ONLY; if ((sp->file_read_only == FILE_READ_ONLY) || (sp->user_read_only == FILE_READ_ONLY)) show_lock(sp); else hide_lock(sp); if (old_name) status_report(sp, "(translated %s)", old_name); if (sound_style(ss) != SOUNDS_IN_SEPARATE_WINDOWS) { reset_controls(sp); } else { XtVaSetValues(sp->dialog, XmNwidth, 100, XmNheight, 100, NULL); /* this is not redundant -- apparently they're trying to ignore size resets to the "current" */ /* value, but forgot that unmanage/remanage does not return to the previous size */ XtVaSetValues(sp->dialog, XmNwidth, (Dimension)(widget_width(main_shell(ss))), XmNheight, (Dimension)(chan_min_y * nchans), /* bugfix thanks to Paul @pobox */ NULL); } after_open(sp); if (free_filename) free(filename); return(sp); } void update_sound_label(snd_info *sp) { if (has_widgets(sp)) set_button_label(NAME_LABEL(sp), shortname_indexed(sp)); } void snd_info_cleanup(snd_info *sp) { if (has_widgets(sp)) { clear_status_area(sp); if (SYNC_BUTTON(sp)) { XtVaSetValues(SYNC_BUTTON(sp), XmNset, false, NULL); XtVaSetValues(EXPAND_RIGHT_BUTTON(sp), XmNset, false, NULL); XtVaSetValues(CONTRAST_RIGHT_BUTTON(sp), XmNset, false, NULL); XtVaSetValues(SPEED_ARROW(sp), XmNset, false, NULL); XtVaSetValues(FILTER_BUTTON(sp), XmNset, false, NULL); XtVaSetValues(REVERB_BUTTON(sp), XmNset, false, NULL); XmToggleButtonSetState(UNITE_BUTTON(sp), false, false); sp->channel_style = CHANNELS_SEPARATE; if (sound_style(ss) == SOUNDS_IN_NOTEBOOK) { set_label(sp->tab, "none"); XmChangeColor(sp->tab, ss->graph_color); } XtUnmanageChild(SND_PANE(sp)); } if ((sp->dialog) && (XtIsManaged(sp->dialog))) XtUnmanageChild(sp->dialog); } } static Xen reflect_file_close_in_sync(Xen hook_or_reason) { int reason; #if HAVE_SCHEME reason = Xen_integer_to_C_int(s7_let_ref(s7, hook_or_reason, s7_make_symbol(s7, "reason"))); #else reason = Xen_integer_to_C_int(hook_or_reason); #endif if ((reason == FILE_CLOSED) && /* snd-file.c */ (ss->active_sounds == 1)) { snd_info *sp; sp = any_selected_sound(); if ((sp) && (sp->nchans == 1)) { XtUnmanageChild(SYNC_BUTTON(sp)); attach_status_area(sp); } } return(Xen_false); } void set_sound_pane_file_label(snd_info *sp, const char *str) { if (!(mus_strcmp(sp->name_string, str))) { if (sp->name_string) free(sp->name_string); sp->name_string = mus_strdup(str); set_button_label(SND_NAME(sp), str); /* this causes an expose event, so it's worth minimizing */ } } void color_filter_waveform(Pixel color) { int i; XSetForeground(main_display(ss), ss->fltenv_data_gc, color); for (i = 0; i < ss->max_sounds; i++) { snd_info *sp; sp = ss->sounds[i]; if ((sp) && (sp->inuse == SOUND_NORMAL)) display_filter_env(sp); } } void show_controls(snd_info *sp) { Dimension hgt; XtVaGetValues(FILTER_LABEL(sp), XmNy, &hgt, NULL); if (XtIsManaged(CONTROLS(sp))) XtUnmanageChild(CONTROLS(sp)); XtVaSetValues(CONTROLS(sp), XmNpaneMinimum, hgt, XmNpaneMaximum, hgt, NULL); XtManageChild(CONTROLS(sp)); XtVaSetValues(CONTROLS(sp), XmNpaneMinimum, 1, XmNpaneMaximum, LOTSA_PIXELS, NULL); } void hide_controls(snd_info *sp) { XtUnmanageChild(CONTROLS(sp)); } bool showing_controls(snd_info *sp) { return((bool)(XtIsManaged(CONTROLS(sp)))); } void show_all_controls(void) { int i; for (i = 0; i < ss->max_sounds; i++) { snd_info *sp; sp = ss->sounds[i]; if ((sp) && (sp->inuse == SOUND_NORMAL)) show_controls(sp); } } void hide_all_controls(void) { int i; for (i = 0; i < ss->max_sounds; i++) { snd_info *sp; sp = ss->sounds[i]; if ((sp) && (sp->inuse == SOUND_NORMAL)) hide_controls(sp); } } int control_panel_height(snd_info *sp) { return(widget_height(CONTROLS(sp))); } /* -------- PROGRESS REPORT -------- */ void progress_report(chan_info *cp, mus_float_t pct) { int which; snd_info *sp; sp = cp->sound; if ((!has_widgets(sp)) || (sp->inuse != SOUND_NORMAL)) return; which = (int)(pct * NUM_HOURGLASSES); if (which >= NUM_HOURGLASSES) which = NUM_HOURGLASSES - 1; if (which < 0) which = 0; if ((hourglasses[which]) && (cp->chan < sp->num_progress_widgets) && ((cp->chan == 0) || (sp->channel_style != CHANNELS_SUPERIMPOSED))) { XtVaSetValues(PROGRESS_ICON(cp), XmNlabelPixmap, hourglasses[which], NULL); XmUpdateDisplay(PROGRESS_ICON(cp)); } check_for_event(); } void finish_progress_report(chan_info *cp) { snd_info *sp; sp = cp->sound; if ((!has_widgets(sp)) || (sp->inuse != SOUND_NORMAL)) return; if ((cp->chan < sp->num_progress_widgets) && ((cp->chan == 0) || (sp->channel_style != CHANNELS_SUPERIMPOSED))) { XtVaSetValues(PROGRESS_ICON(cp), XmNlabelPixmap, blank_pixmap, NULL); XmUpdateDisplay(PROGRESS_ICON(cp)); hide_stop_sign(sp); } } void start_progress_report(chan_info *cp) { snd_info *sp; sp = cp->sound; if ((!has_widgets(sp)) || (sp->inuse != SOUND_NORMAL)) return; if ((cp->chan < sp->num_progress_widgets) && ((cp->chan == 0) || (sp->channel_style != CHANNELS_SUPERIMPOSED))) { XtVaSetValues(PROGRESS_ICON(cp), XmNlabelPixmap, hourglasses[0], NULL); XmUpdateDisplay(PROGRESS_ICON(cp)); show_stop_sign(sp); } } void reflect_sound_selection(snd_info *sp) { /* sp is the newly selected sound, ss->selected_sound is the previous one */ snd_info *osp = NULL; if (ss->selected_sound != NO_SELECTION) osp = ss->sounds[ss->selected_sound]; if ((osp) && (sp != osp) && (osp->inuse == SOUND_NORMAL)) { XmChangeColor(SND_NAME(osp), ss->highlight_color); if (sound_style(ss) == SOUNDS_IN_NOTEBOOK) XmChangeColor(osp->tab, ss->graph_color); } if (sp->selected_channel != NO_SELECTION) { XmChangeColor(SND_NAME(sp), ss->white); if (sound_style(ss) == SOUNDS_IN_NOTEBOOK) { int page, current_page; XmNotebookPageStatus status; XmNotebookPageInfo info; XmChangeColor(sp->tab, ss->selected_graph_color); XtVaGetValues(sound_pane(ss), XmNcurrentPageNumber, ¤t_page, NULL); XtVaGetValues(sp->tab, XmNpageNumber, &page, NULL); if (page != current_page) { status = XmNotebookGetPageInfo(sound_pane(ss), page, &info); if (status == XmPAGE_FOUND) { XtVaSetValues(sound_pane(ss), XmNcurrentPageNumber, page, NULL); } } } } } /* -------- controls dialog -------- */ static Widget controls_dialog = NULL; enum {EXPAND_HOP, EXPAND_LENGTH, EXPAND_RAMP, EXPAND_JITTER, CONTRAST_AMP, REVERB_LOWPASS, REVERB_FEEDBACK}; static Widget controls[7]; static void reset_all_sliders(void) { expand_control_set_hop(DEFAULT_EXPAND_CONTROL_HOP); expand_control_set_length(DEFAULT_EXPAND_CONTROL_LENGTH); expand_control_set_ramp(DEFAULT_EXPAND_CONTROL_RAMP); expand_control_set_jitter(DEFAULT_EXPAND_CONTROL_JITTER); contrast_control_set_amp(DEFAULT_CONTRAST_CONTROL_AMP); reverb_control_set_lowpass(DEFAULT_REVERB_CONTROL_LOWPASS); reverb_control_set_feedback(DEFAULT_REVERB_CONTROL_FEEDBACK); XtVaSetValues(controls[EXPAND_HOP], XmNvalue, (int)(expand_control_hop(ss) * 1000), NULL); XtVaSetValues(controls[EXPAND_LENGTH], XmNvalue, (int)(expand_control_length(ss) * 1000), NULL); XtVaSetValues(controls[EXPAND_RAMP], XmNvalue, (int)(expand_control_ramp(ss) * 1000), NULL); XtVaSetValues(controls[EXPAND_JITTER], XmNvalue, (int)(expand_control_jitter(ss) * 1000), NULL); XtVaSetValues(controls[CONTRAST_AMP], XmNvalue, (int)(contrast_control_amp(ss) * 1000), NULL); XtVaSetValues(controls[REVERB_LOWPASS], XmNvalue, (int)(reverb_control_lowpass(ss) * 1000), NULL); XtVaSetValues(controls[REVERB_FEEDBACK], XmNvalue, (int)(reverb_control_feedback(ss) * 1000), NULL); } static void controls_reset_callback(Widget w, XtPointer context, XtPointer info) { if (XmGetFocusWidget(controls_dialog) == XmMessageBoxGetChild(controls_dialog, XmDIALOG_OK_BUTTON)) reset_all_sliders(); } static void controls_help_callback(Widget w, XtPointer context, XtPointer info) { snd_help("More controls", "This dialog controls all the otherwise hidden control-panel variables.\n\ Expand-hop sets the time in seconds between successive grains.\n\ Expand-length sets the length of each grain.\n\ Expand-ramp sets the ramp-time in the grain envelope.\n\ Expand-jitter sets the grain timing jitter.\n\ Contrast-amp sets the prescaler for contrast-enhancement.\n\ Reverb-lowpass sets the feedback lowpass filter coeficient.\n\ Reverb-feedback sets the scaler on the feedback.", WITHOUT_WORD_WRAP); } static void controls_quit_callback(Widget w, XtPointer context, XtPointer info) { XtUnmanageChild(controls_dialog); } static void expand_hop_callback(Widget w, XtPointer context, XtPointer info) { XmScaleCallbackStruct *cbs = (XmScaleCallbackStruct *)info; expand_control_set_hop(cbs->value * 0.001); } static void expand_length_callback(Widget w, XtPointer context, XtPointer info) { XmScaleCallbackStruct *cbs = (XmScaleCallbackStruct *)info; expand_control_set_length(cbs->value * 0.001); } static void expand_ramp_callback(Widget w, XtPointer context, XtPointer info) { XmScaleCallbackStruct *cbs = (XmScaleCallbackStruct *)info; expand_control_set_ramp(cbs->value * 0.001); } static void expand_jitter_callback(Widget w, XtPointer context, XtPointer info) { XmScaleCallbackStruct *cbs = (XmScaleCallbackStruct *)info; expand_control_set_jitter(cbs->value * 0.001); } static void contrast_amp_callback(Widget w, XtPointer context, XtPointer info) { XmScaleCallbackStruct *cbs = (XmScaleCallbackStruct *)info; contrast_control_set_amp(cbs->value * 0.001); } static void reverb_lowpass_callback(Widget w, XtPointer context, XtPointer info) { XmScaleCallbackStruct *cbs = (XmScaleCallbackStruct *)info; reverb_control_set_lowpass(cbs->value * 0.001); } static void reverb_feedback_callback(Widget w, XtPointer context, XtPointer info) { XmScaleCallbackStruct *cbs = (XmScaleCallbackStruct *)info; reverb_control_set_feedback(cbs->value * 0.001); } void make_controls_dialog(void) { #define MSG_BOX(Dialog, Child) XmMessageBoxGetChild(Dialog, Child) if (!controls_dialog) { int n; Arg args[32]; XmString go_away, xhelp, titlestr, xreset; Widget mainform, slider, reset_button; go_away = XmStringCreateLocalized((char *)I_GO_AWAY); xhelp = XmStringCreateLocalized((char *)I_HELP); titlestr = XmStringCreateLocalized((char *)"More controls"); xreset = XmStringCreateLocalized((char *)"Reset"); n = 0; XtSetArg(args[n], XmNbackground, ss->basic_color); n++; XtSetArg(args[n], XmNhelpLabelString, xhelp); n++; XtSetArg(args[n], XmNokLabelString, xreset); n++; XtSetArg(args[n], XmNcancelLabelString, go_away); n++; XtSetArg(args[n], XmNautoUnmanage, false); n++; XtSetArg(args[n], XmNdialogTitle, titlestr); n++; XtSetArg(args[n], XmNresizePolicy, XmRESIZE_GROW); n++; XtSetArg(args[n], XmNnoResize, false); n++; XtSetArg(args[n], XmNtransient, false); n++; XtSetArg(args[n], XmNwidth, 400); n++; controls_dialog = XmCreateTemplateDialog(main_shell(ss), (char *)"More controls", args, n); reset_button = MSG_BOX(controls_dialog, XmDIALOG_OK_BUTTON); XtAddCallback(controls_dialog, XmNhelpCallback, controls_help_callback, NULL); /* XtAddCallback(controls_dialog, XmNokCallback, controls_reset_callback, NULL); */ XtAddCallback(reset_button, XmNactivateCallback, controls_reset_callback, NULL); XtAddCallback(controls_dialog, XmNcancelCallback, controls_quit_callback, NULL); XmStringFree(xhelp); XmStringFree(go_away); XmStringFree(titlestr); XmStringFree(xreset); XtVaSetValues(MSG_BOX(controls_dialog, XmDIALOG_OK_BUTTON), XmNarmColor, ss->selection_color, NULL); XtVaSetValues(MSG_BOX(controls_dialog, XmDIALOG_HELP_BUTTON), XmNarmColor, ss->selection_color, NULL); XtVaSetValues(MSG_BOX(controls_dialog, XmDIALOG_CANCEL_BUTTON), XmNarmColor, ss->selection_color, NULL); XtVaSetValues(MSG_BOX(controls_dialog, XmDIALOG_OK_BUTTON), XmNbackground, ss->highlight_color, NULL); XtVaSetValues(MSG_BOX(controls_dialog, XmDIALOG_HELP_BUTTON), XmNbackground, ss->highlight_color, NULL); XtVaSetValues(MSG_BOX(controls_dialog, XmDIALOG_CANCEL_BUTTON), XmNbackground, ss->highlight_color, NULL); mainform = XtVaCreateManagedWidget("formd", xmRowColumnWidgetClass, controls_dialog, XmNleftAttachment, XmATTACH_FORM, XmNrightAttachment, XmATTACH_FORM, XmNtopAttachment, XmATTACH_FORM, XmNbottomAttachment, XmATTACH_WIDGET, XmNbottomWidget, XmMessageBoxGetChild(controls_dialog, XmDIALOG_SEPARATOR), XmNorientation, XmVERTICAL, NULL); titlestr = XmStringCreateLocalized((char *)"expand hop"); slider = XtVaCreateManagedWidget("expand-hop", xmScaleWidgetClass, mainform, XmNorientation, XmHORIZONTAL, XmNshowValue, true, XmNminimum, 1, XmNmaximum, 300, XmNvalue, (int)(expand_control_hop(ss) * 1000), XmNdecimalPoints, 3, XmNtitleString, titlestr, XmNborderWidth, 1, XmNbackground, ss->basic_color, NULL); XmStringFree(titlestr); XtAddCallback(slider, XmNvalueChangedCallback, expand_hop_callback, NULL); XtAddCallback(slider, XmNdragCallback, expand_hop_callback, NULL); controls[EXPAND_HOP] = slider; titlestr = XmStringCreateLocalized((char *)"expand length"); slider = XtVaCreateManagedWidget("expand-length", xmScaleWidgetClass, mainform, XmNorientation, XmHORIZONTAL, XmNshowValue, true, XmNminimum, 10, XmNmaximum, 500, XmNvalue, (int)(expand_control_length(ss) * 1000), XmNdecimalPoints, 3, XmNtitleString, titlestr, XmNborderWidth, 1, XmNbackground, ss->basic_color, NULL); XmStringFree(titlestr); XtAddCallback(slider, XmNvalueChangedCallback, expand_length_callback, NULL); XtAddCallback(slider, XmNdragCallback, expand_length_callback, NULL); controls[EXPAND_LENGTH] = slider; titlestr = XmStringCreateLocalized((char *)"expand ramp"); slider = XtVaCreateManagedWidget("expand-ramp", xmScaleWidgetClass, mainform, XmNorientation, XmHORIZONTAL, XmNshowValue, true, XmNminimum, 10, XmNmaximum, 500, XmNvalue, (int)(expand_control_ramp(ss) * 1000), XmNdecimalPoints, 3, XmNtitleString, titlestr, XmNborderWidth, 1, XmNbackground, ss->basic_color, NULL); XmStringFree(titlestr); XtAddCallback(slider, XmNvalueChangedCallback, expand_ramp_callback, NULL); XtAddCallback(slider, XmNdragCallback, expand_ramp_callback, NULL); controls[EXPAND_RAMP] = slider; titlestr = XmStringCreateLocalized((char *)"expand jitter"); slider = XtVaCreateManagedWidget("expand-hop", xmScaleWidgetClass, mainform, XmNorientation, XmHORIZONTAL, XmNshowValue, true, XmNminimum, 0, XmNmaximum, 200, XmNvalue, (int)(expand_control_jitter(ss) * 1000), XmNdecimalPoints, 3, XmNtitleString, titlestr, XmNborderWidth, 1, XmNbackground, ss->basic_color, NULL); XmStringFree(titlestr); XtAddCallback(slider, XmNvalueChangedCallback, expand_jitter_callback, NULL); XtAddCallback(slider, XmNdragCallback, expand_jitter_callback, NULL); controls[EXPAND_JITTER] = slider; titlestr = XmStringCreateLocalized((char *)"contrast amp"); slider = XtVaCreateManagedWidget("contrast-amp", xmScaleWidgetClass, mainform, XmNorientation, XmHORIZONTAL, XmNshowValue, true, XmNminimum, 0, XmNmaximum, 2000, XmNvalue, (int)(contrast_control_amp(ss) * 1000), XmNdecimalPoints, 3, XmNtitleString, titlestr, XmNborderWidth, 1, XmNbackground, ss->basic_color, NULL); XmStringFree(titlestr); XtAddCallback(slider, XmNvalueChangedCallback, contrast_amp_callback, NULL); XtAddCallback(slider, XmNdragCallback, contrast_amp_callback, NULL); controls[CONTRAST_AMP] = slider; titlestr = XmStringCreateLocalized((char *)"reverb lowpass"); slider = XtVaCreateManagedWidget("reverb-lowpass", xmScaleWidgetClass, mainform, XmNorientation, XmHORIZONTAL, XmNshowValue, true, XmNminimum, 0, XmNmaximum, 1000, XmNvalue, (int)(reverb_control_lowpass(ss) * 1000), XmNdecimalPoints, 3, XmNtitleString, titlestr, XmNborderWidth, 1, XmNbackground, ss->basic_color, NULL); XmStringFree(titlestr); XtAddCallback(slider, XmNvalueChangedCallback, reverb_lowpass_callback, NULL); XtAddCallback(slider, XmNdragCallback, reverb_lowpass_callback, NULL); controls[REVERB_LOWPASS] = slider; titlestr = XmStringCreateLocalized((char *)"reverb feedback"); slider = XtVaCreateManagedWidget("reverb-feedback", xmScaleWidgetClass, mainform, XmNorientation, XmHORIZONTAL, XmNshowValue, true, XmNminimum, 0, XmNmaximum, 1250, XmNvalue, (int)(reverb_control_feedback(ss) * 1000), XmNdecimalPoints, 3, XmNtitleString, titlestr, XmNborderWidth, 1, XmNbackground, ss->basic_color, NULL); XmStringFree(titlestr); XtAddCallback(slider, XmNvalueChangedCallback, reverb_feedback_callback, NULL); XtAddCallback(slider, XmNdragCallback, reverb_feedback_callback, NULL); controls[REVERB_FEEDBACK] = slider; set_dialog_widget(CONTROLS_DIALOG, controls_dialog); } if (!XtIsManaged(controls_dialog)) XtManageChild(controls_dialog); } /* ---------------------------------------- */ static Xen g_sound_widgets(Xen snd) { #define H_sound_widgets "(" S_sound_widgets " :optional snd): a list of \ widgets: (0)pane (1)name (2)control-panel (3)status area (4)play-button (5)filter-env (6)unite-button (7)name-label (8)name-icon (9)sync-button" snd_info *sp; Snd_assert_sound(S_sound_widgets, snd, 1); sp = get_sp(snd); if (!sp) return(snd_no_such_sound_error(S_sound_widgets, snd)); if (!has_widgets(sp)) return(Xen_empty_list); return(Xen_cons(Xen_wrap_widget(SND_PANE(sp)), Xen_cons(Xen_wrap_widget(SND_NAME(sp)), Xen_cons(Xen_wrap_widget(CONTROLS(sp)), Xen_cons(Xen_wrap_widget(STATUS_AREA(sp)), #if WITH_AUDIO Xen_cons(Xen_wrap_widget(PLAY_BUTTON(sp)), #else Xen_cons(Xen_false, #endif Xen_cons(Xen_wrap_widget(FILTER_GRAPH(sp)), /* this is the drawingarea widget */ Xen_cons(Xen_wrap_widget(UNITE_BUTTON(sp)), Xen_cons(Xen_false, Xen_cons(Xen_wrap_widget(LOCK_OR_BOMB(sp)), Xen_cons(Xen_wrap_widget(SYNC_BUTTON(sp)), Xen_empty_list))))))))))); } #define FALLBACK_FONT "fixed" #define DEFAULT_LISTENER_FONT "9x15" #define DEFAULT_FONTLIST "9x15" #define HIGHLIGHT_COLOR "ivory1" #define BASIC_COLOR "ivory2" #define POSITION_COLOR "ivory3" #define ZOOM_COLOR "ivory4" #define CURSOR_COLOR "red" #define SELECTION_COLOR "lightsteelblue1" #define ENVED_WAVEFORM_COLOR "blue" #define MIX_COLOR "darkgray" #define GRAPH_COLOR "white" #define SELECTED_GRAPH_COLOR "white" #define DATA_COLOR "black" #define SELECTED_DATA_COLOR "black" #define MARK_COLOR "red" #define LISTENER_COLOR "AliceBlue" #define LISTENER_TEXT_COLOR "black" #define LIGHT_BLUE_COLOR "lightsteelblue1" #define LIGHTER_BLUE_COLOR "AliceBlue" #define WHITE_COLOR "white" #define BLACK_COLOR "black" #define GREEN_COLOR "green2" #define RED_COLOR "red" #define YELLOW_COLOR "yellow" #define TEXT_FOCUS_COLOR "white" #define FILTER_CONTROL_WAVEFORM_COLOR "blue" #define SASH_COLOR "lightgreen" #define CHANNEL_SASH_INDENT -10 #define CHANNEL_SASH_SIZE 0 /* 0 means: use Motif default size */ #define POSITION_SLIDER_WIDTH 13 #define ZOOM_SLIDER_WIDTH 10 #if (!__linux__) && (!_LINUX__) #define TOGGLE_SIZE 0 #else #define TOGGLE_SIZE 15 #endif #define CHANNEL_MIN_HEIGHT 150 /* open size (set to 5 immediately thereafter) */ /* paned window default setup is not very smart, so we force these to be this size to begin with */ /* this number is only a first approximation -- we try not to expand below the screen */ /* if too small (i.e. 100), the scrollbars are sometimes messed up on the initial layout */ #define SASH_SIZE 16 #define SASH_INDENT -20 #define AUTO_RESIZE_DEFAULT 1 #define INITIAL_WINDOW_WIDTH 700 #define INITIAL_WINDOW_HEIGHT 300 static void window_close(Widget w, XtPointer context, XtPointer info) { /* this is called from the window manager close event, not (exit) or the File:Exit item */ snd_exit_cleanly(EXIT_FORCED); } static XtIntervalId auto_update_proc = 0; static void auto_update_check(XtPointer context, XtIntervalId *id) { if (auto_update_interval(ss) > 0.0) { if (!(play_in_progress())) for_each_sound(sound_not_current); auto_update_proc = XtAppAddTimeOut(main_app(ss), (unsigned long)(auto_update_interval(ss) * 1000), (XtTimerCallbackProc)auto_update_check, context); } else auto_update_proc = 0; } void auto_update_restart(void) { if (auto_update_proc == 0) auto_update_proc = XtAppAddTimeOut(main_app(ss), (unsigned long)(auto_update_interval(ss) * 1000), (XtTimerCallbackProc)auto_update_check, (XtPointer)NULL); } /* handle iconification */ static Widget *iconify_active_dialogs = NULL; static void minify_maxify_window(Widget w, XtPointer context, XEvent *event, Boolean *cont) { XMapEvent *ev = (XMapEvent *)event; if ((!ss) || (!(ss->dialogs))) return; /* ev->type can be several things, but the ones we care about here are * MapNotify and UnmapNotify. Snd dialogs are "windows" in X-jargon, so * when the main window is minimized (iconified), other active dialogs * aren't also closed unless we mess with them explicitly here. We keep * a list of created dialogs, and depend on XtIsManaged to tell us which * ones need to be unmanaged. But, if the user has several "desks", a change * of desk can also generate an unmap event, and if we dismiss the dialogs, * they don't come back upon remap; if we save a list of live dialogs, they * don't return to their previous location upon being re-managed. We * need to see just iconfication events here, but there's no way I can * see to distinguish an iconify event from a desk event (WM_STATE atom state * of property changed event is identical etc), so I'll do what I can... * This problem may be a side-effect of using non-transient dialogs: * perhaps XSetTransientFor would handle this more cleanly? * * Also, ideally we'd equalize/relative-panes upon maxify, but ICCC thinks maxify * is the same as map (i.e. from iconified state), and the only difference * I can see in the mwm code is the window size. * * a rumor in the air that what we need is to catch StructureNotify event, then * check in that for UnmapNotify */ if (ev->type == UnmapNotify) { Atom _NET_WM_STATE, _NET_WM_STATE_HIDDEN, actual_type; int actual_format; unsigned long nitems, bytes_after; unsigned char *prop = NULL; /* this code thanks to Tito Latini */ _NET_WM_STATE = XInternAtom(main_display(ss), "_NET_WM_STATE", false); _NET_WM_STATE_HIDDEN = XInternAtom(main_display(ss), "_NET_WM_STATE_HIDDEN", false); if (XGetWindowProperty(main_display(ss), XtWindow(w), _NET_WM_STATE, 0, 1024, false, XA_ATOM, &actual_type, &actual_format, &nitems, &bytes_after, &prop) == Success) { Atom *atoms = (Atom *)prop; bool iconified = false; unsigned long i; for (i = 0; i < nitems; i++) { if (atoms[i] == _NET_WM_STATE_HIDDEN) { iconified = true; break; } } XFree(prop); if (!iconified) return; } if (iconify_active_dialogs) free(iconify_active_dialogs); iconify_active_dialogs = (Widget *)calloc(ss->num_dialogs, sizeof(Widget)); { int i; for (i = 0; i < ss->num_dialogs; i++) if (ss->dialogs[i]) { if (XtIsManaged(ss->dialogs[i])) iconify_active_dialogs[i] = ss->dialogs[i]; XtUnmanageChild(ss->dialogs[i]); } } } else { if (ev->type == MapNotify) { if (iconify_active_dialogs) { int i; for (i = 0; i < ss->num_dialogs; i++) if (iconify_active_dialogs[i]) XtManageChild(iconify_active_dialogs[i]); free(iconify_active_dialogs); iconify_active_dialogs = NULL; } } } } #ifndef _MSC_VER #include static jmp_buf top_level_jump; void top_level_catch(int ignore); void top_level_catch(int ignore) { longjmp(top_level_jump, 1); } #endif static char **auto_open_file_names = NULL; static int auto_open_files = 0; static bool noglob = false, noinit = false, batch = false, nostdin = false; #if HAVE_EXTENSION_LANGUAGE static XtInputId stdin_id = 0; static void get_stdin_string(XtPointer context, int *fd, XtInputId *id) { int size; ssize_t bytes; char *buf; buf = (char *)calloc(1024, sizeof(char)); size = 1024; bytes = read(*fd, buf, 1024); if (bytes <= 0) { /* redirected to /dev/null?? -- apparently in kde/kfm the process is started without stdin? */ XtRemoveInput(stdin_id); stdin_id = 0; } else { while (bytes == 1024) { size += 1024; buf = (char *)realloc(buf, size); bytes = read(*fd, (char *)(buf + size - 1024), 1024); } snd_eval_stdin_str(buf); } free(buf); } #endif static void startup_funcs(void) { Atom wm_delete_window; Display *dpy; Widget shell; static int auto_open_ctr = 0; ss->file_monitor_ok = initialize_file_monitor(); shell = ss->mainshell; dpy = main_display(ss); #ifndef __alpha__ add_menu_drop(); #endif /* trap outer-level Close for cleanup check */ wm_delete_window = XmInternAtom(dpy, (char *)"WM_DELETE_WINDOW", false); XmAddWMProtocolCallback(shell, wm_delete_window, window_close, NULL); XtAddEventHandler(shell, StructureNotifyMask, false, minify_maxify_window, NULL); ss->graph_cursor = XCreateFontCursor(XtDisplay(main_shell(ss)), in_graph_cursor(ss)); ss->wait_cursor = XCreateFontCursor(XtDisplay(main_shell(ss)), XC_watch); ss->bounds_cursor = XCreateFontCursor(XtDisplay(main_shell(ss)), XC_sb_h_double_arrow); ss->yaxis_cursor = XCreateFontCursor(XtDisplay(main_shell(ss)), XC_sb_v_double_arrow); ss->play_cursor = XCreateFontCursor(XtDisplay(main_shell(ss)), XC_sb_right_arrow); ss->loop_play_cursor = XCreateFontCursor(XtDisplay(main_shell(ss)), XC_sb_left_arrow); #if HAVE_EXTENSION_LANGUAGE snd_load_init_file(noglob, noinit); #endif #if (!_MSC_VER) && HAVE_EXTENSION_LANGUAGE && !__MINGW32__ if (!nostdin) { signal(SIGTTIN, SIG_IGN); signal(SIGTTOU, SIG_IGN); /* these signals are sent by a shell if we start Snd as a background process, * but try to read stdin (needed to support the emacs subjob connection). If * we don't do this, the background job is suspended when the shell sends SIGTTIN. */ stdin_id = XtAppAddInput(main_app(ss), STDIN_FILENO, (XtPointer)XtInputReadMask, get_stdin_string, NULL); } #endif while (auto_open_ctr < auto_open_files) auto_open_ctr = handle_next_startup_arg(auto_open_ctr, auto_open_file_names, false, auto_open_files); if (ss->init_window_width > 0) set_widget_width(main_shell(ss), ss->init_window_width); if (ss->init_window_height > 0) set_widget_height(main_shell(ss), ss->init_window_height); if (ss->init_window_x != DEFAULT_INIT_WINDOW_X) set_widget_x(main_shell(ss), ss->init_window_x); if (ss->init_window_y != DEFAULT_INIT_WINDOW_Y) set_widget_y(main_shell(ss), ss->init_window_y); if (!ss->file_monitor_ok) { if (auto_update_interval(ss) > 0.0) XtAppAddTimeOut(main_app(ss), (unsigned long)(auto_update_interval(ss) * 1000), auto_update_check, NULL); } if ((ss->sounds) && (ss->selected_sound == NO_SELECTION)) { snd_info *sp; sp = ss->sounds[0]; if ((sp) && (sp->inuse == SOUND_NORMAL) && (sp->selected_channel == NO_SELECTION)) /* don't clobber possible select-channel in loaded startup files */ select_channel(sp, 0); } if ((ss->init_window_height == 0) && (sound_style(ss) == SOUNDS_HORIZONTAL)) set_widget_height(main_shell(ss), 200); /* otherwise it's just a title bar! */ } static void SetupIcon(Widget shell) { Display *dpy; Window root; int scr; Pixmap pix, mask; XpmAttributes attributes; dpy = XtDisplay(shell); root = DefaultRootWindow(dpy); scr = DefaultScreen(dpy); XtVaGetValues(shell, XmNdepth, &attributes.depth, XmNcolormap, &attributes.colormap, NULL); attributes.visual = DefaultVisual(dpy, scr); attributes.valuemask = XpmDepth | XpmColormap | XpmVisual; XpmCreatePixmapFromData(dpy, root, (char **)snd_icon_bits(), &pix, &mask, &attributes); if (mask) XFreePixmap(dpy, mask); XtVaSetValues(shell, XmNiconPixmap, pix, NULL); } static void muffle_warning(char *name, char *type, char *klass, char *defaultp, char **params, uint32_t *num_params) { } static void notebook_page_changed_callback(Widget w, XtPointer context, XtPointer info) { /* if page chosen via major tab click, select that sound */ XmNotebookCallbackStruct *nb = (XmNotebookCallbackStruct *)info; Widget page; if ((nb->reason == XmCR_MAJOR_TAB) && (nb->page_widget)) { page = nb->page_widget; if (page) { int index; intptr_t data; XtVaGetValues(page, XmNuserData, &data, NULL); index = (int)data; if ((index < ss->max_sounds) && (snd_ok(ss->sounds[index]))) { snd_info *sp; sp = ss->sounds[index]; if (sp->selected_channel == NO_SELECTION) select_channel(ss->sounds[index], 0); else select_channel(ss->sounds[index], sp->selected_channel); } } } } color_t get_in_between_color(color_t fg, color_t bg) { Colormap cmap; Display *dpy; int scr; XColor fg_color, bg_color, new_color; dpy = main_display(ss); scr = DefaultScreen(dpy); cmap = DefaultColormap(dpy, scr); fg_color.flags = DoRed | DoGreen | DoBlue; fg_color.pixel = fg; XQueryColor(dpy, cmap, &fg_color); bg_color.flags = DoRed | DoGreen | DoBlue; bg_color.pixel = bg; XQueryColor(dpy, cmap, &bg_color); new_color.flags = DoRed | DoGreen | DoBlue; new_color.red = (rgb_t)((fg_color.red + (2 * bg_color.red)) / 3); new_color.green = (rgb_t)((fg_color.green + (2 * bg_color.green)) / 3); new_color.blue = (rgb_t)((fg_color.blue + (2 * bg_color.blue)) / 3); if ((XAllocColor(dpy, cmap, &new_color)) == 0) return(fg); return(new_color.pixel); } static Pixel get_color(Widget shell, const char *defined_color, const char *fallback_color, const char *second_fallback_color, bool use_white) { Colormap cmap; Display *dpy; int scr; XColor tmp_color, ignore; dpy = XtDisplay(shell); scr = DefaultScreen(dpy); cmap = DefaultColormap(dpy, scr); /* I suppose we could use XQueryColors and search for the closest available, or try yet again to get XCreateColormap to behave itself */ if ((!XAllocNamedColor(dpy, cmap, defined_color, &tmp_color, &ignore)) && ((!fallback_color) || (!XAllocNamedColor(dpy, cmap, fallback_color, &tmp_color, &ignore))) && ((!second_fallback_color) || (!XAllocNamedColor(dpy, cmap, second_fallback_color, &tmp_color, &ignore)))) { /* snd_error here causes a seg fault (it builds on mainpane which has not yet been created) */ if (use_white) { fprintf(stderr, "can't get color %s -- will use white\n", defined_color); return(WhitePixel(dpy, scr)); } else { fprintf(stderr, "can't get color %s -- will use black\n", defined_color); return(BlackPixel(dpy, scr)); } } return(tmp_color.pixel); } static void save_a_color(FILE *Fp, Display *dpy, Colormap cmap, const char *name, Pixel pix, const char *ext_name) { #if HAVE_EXTENSION_LANGUAGE Status lookup_ok; XColor default_color, ignore; lookup_ok = XLookupColor(dpy, cmap, name, &default_color, &ignore); if (lookup_ok) { XColor current_color; current_color.flags = DoRed | DoGreen | DoBlue; current_color.pixel = pix; XQueryColor(dpy, cmap, ¤t_color); if ((current_color.red != default_color.red) || (current_color.green != default_color.green) || (current_color.blue != default_color.blue)) #if HAVE_FORTH fprintf(Fp, "%.3f %.3f %.3f %s set-%s drop\n", rgb_to_float(current_color.red), rgb_to_float(current_color.green), rgb_to_float(current_color.blue), S_make_color, ext_name); #else #if HAVE_SCHEME fprintf(Fp, "(set! (%s) (%s %.3f %.3f %.3f))\n", #endif #if HAVE_RUBY fprintf(Fp, "set_%s(%s(%.3f, %.3f, %.3f))\n", #endif to_proc_name(ext_name), to_proc_name(S_make_color), rgb_to_float(current_color.red), rgb_to_float(current_color.green), rgb_to_float(current_color.blue)); #endif } #endif } void save_colors(FILE *Fp) { Colormap cmap; Display *dpy; int scr; dpy = XtDisplay(ss->mainshell); scr = DefaultScreen(dpy); cmap = DefaultColormap(dpy, scr); save_a_color(Fp, dpy, cmap, BASIC_COLOR, ss->basic_color, S_basic_color); save_a_color(Fp, dpy, cmap, CURSOR_COLOR, ss->cursor_color, S_cursor_color); save_a_color(Fp, dpy, cmap, DATA_COLOR, ss->data_color, S_data_color); save_a_color(Fp, dpy, cmap, SELECTED_DATA_COLOR, ss->selected_data_color, S_selected_data_color); save_a_color(Fp, dpy, cmap, HIGHLIGHT_COLOR, ss->highlight_color, S_highlight_color); save_a_color(Fp, dpy, cmap, POSITION_COLOR, ss->position_color, S_position_color); save_a_color(Fp, dpy, cmap, ZOOM_COLOR, ss->zoom_color, S_zoom_color); save_a_color(Fp, dpy, cmap, SELECTION_COLOR, ss->selection_color, S_selection_color); save_a_color(Fp, dpy, cmap, MIX_COLOR, ss->mix_color, S_mix_color); save_a_color(Fp, dpy, cmap, ENVED_WAVEFORM_COLOR, ss->enved_waveform_color, S_enved_waveform_color); save_a_color(Fp, dpy, cmap, LISTENER_COLOR, ss->listener_color, S_listener_color); save_a_color(Fp, dpy, cmap, LISTENER_TEXT_COLOR, ss->listener_text_color, S_listener_text_color); save_a_color(Fp, dpy, cmap, GRAPH_COLOR, ss->graph_color, S_graph_color); save_a_color(Fp, dpy, cmap, SELECTED_GRAPH_COLOR, ss->selected_graph_color, S_selected_graph_color); save_a_color(Fp, dpy, cmap, MARK_COLOR, ss->mark_color, S_mark_color); save_a_color(Fp, dpy, cmap, SASH_COLOR, ss->sash_color, S_sash_color); save_a_color(Fp, dpy, cmap, TEXT_FOCUS_COLOR, ss->text_focus_color, S_text_focus_color); save_a_color(Fp, dpy, cmap, FILTER_CONTROL_WAVEFORM_COLOR, ss->filter_control_waveform_color, S_filter_control_waveform_color); } static char *fallbacks[] = { (char *)"*fontList: " DEFAULT_FONTLIST, (char *)"*enableEtchedInMenu: True", (char *)"*enableThinThickness: True", (char *)"*enableToggleColor: True", (char *)"*enableToggleVisual: True", NULL }; void snd_doit(int argc, char **argv) { XtAppContext app; Widget shell; Display *dpy; Drawable wn; Arg args[32]; int i, n; Widget menu; XGCValues gv; char *app_title = NULL; int err = 0; XtSetLanguageProc(NULL, NULL, NULL); ss->channel_min_height = CHANNEL_MIN_HEIGHT; ss->Graph_Cursor = DEFAULT_GRAPH_CURSOR; #ifndef __alpha__ XtSetArg(args[0], XtNwidth, INITIAL_WINDOW_WIDTH); XtSetArg(args[1], XtNheight, INITIAL_WINDOW_HEIGHT); shell = XtAppInitialize(&app, "Snd", NULL, 0, &argc, argv, fallbacks, args, 2); #else shell = XtVaOpenApplication(&app, "Snd", NULL, 0, &argc, argv, fallbacks, applicationShellWidgetClass, XmNallowShellResize, AUTO_RESIZE_DEFAULT, NULL); #endif #ifndef _MSC_VER setlocale(LC_NUMERIC, "C"); #endif /* if user has *keyboardFocusPolicy: Pointer in .Xdefaults, it can screw up Snd's attempt to * keep the channel graphics window as the active widget in case of keyboard input. So, * we try to force Snd's focus policy to be XmEXPLICIT */ XtVaGetValues(shell, XmNkeyboardFocusPolicy, &err, NULL); if (err != XmEXPLICIT) XtVaSetValues(shell, XmNkeyboardFocusPolicy, XmEXPLICIT, NULL); auto_open_files = argc - 1; if (argc > 1) auto_open_file_names = (char **)(argv + 1); dpy = XtDisplay(shell); XtVaGetValues(shell, XmNtitle, &app_title, NULL); /* perhaps caller included -title arg */ if (app_title) ss->startup_title = mus_strdup(app_title); else ss->startup_title = mus_strdup("snd"); for (i = 1; i < argc; i++) if ((mus_strcmp(argv[i], "-h")) || (mus_strcmp(argv[i], "-horizontal")) || (mus_strcmp(argv[i], "--horizontal"))) set_sound_style(SOUNDS_HORIZONTAL); else if ((mus_strcmp(argv[i], "-v")) || (mus_strcmp(argv[i], "-vertical")) || (mus_strcmp(argv[i], "--vertical"))) set_sound_style(SOUNDS_VERTICAL); else if ((mus_strcmp(argv[i], "-notebook")) || (mus_strcmp(argv[i], "--notebook"))) { set_sound_style(SOUNDS_IN_NOTEBOOK); set_auto_resize(false); } else if ((mus_strcmp(argv[i], "-separate")) || (mus_strcmp(argv[i], "--separate"))) set_sound_style(SOUNDS_IN_SEPARATE_WINDOWS); else if (mus_strcmp(argv[i], "-noglob")) noglob = true; else if (mus_strcmp(argv[i], "-noinit")) noinit = true; else if (mus_strcmp(argv[i], "-nostdin")) nostdin = true; else if ((mus_strcmp(argv[i], "-b")) || (mus_strcmp(argv[i], "-batch")) || (mus_strcmp(argv[i], "--batch"))) batch = true; else if (mus_strcmp(argv[i], "--features")) /* testing (compsnd) */ check_features_list(argv[i + 1]); ss->batch_mode = batch; if (batch) XtSetMappedWhenManaged(shell, 0); ss->zoom_slider_width = ZOOM_SLIDER_WIDTH; ss->position_slider_width = POSITION_SLIDER_WIDTH; ss->channel_sash_indent = CHANNEL_SASH_INDENT; ss->channel_sash_size = CHANNEL_SASH_SIZE; ss->sash_size = SASH_SIZE; ss->sash_indent = SASH_INDENT; ss->toggle_size = TOGGLE_SIZE; ss->click_time = (oclock_t)XtGetMultiClickTime(dpy); #if HAVE_GL { /* this taken from glxmotif.c from xjournal/sgi */ XVisualInfo *vi = NULL; Colormap cmap; GLXContext cx; int dblBuf[] = {GLX_RGBA, GLX_DEPTH_SIZE, 16, GLX_DOUBLEBUFFER, None}; vi = glXChooseVisual(dpy, DefaultScreen(dpy), dblBuf); if (vi) ss->gl_has_double_buffer = true; else { int snglBuf[] = {GLX_RGBA, GLX_DEPTH_SIZE, 16, None}; ss->gl_has_double_buffer = false; vi = glXChooseVisual(dpy, DefaultScreen(dpy), snglBuf); } if (!vi) fprintf(stderr, "%s", "no RGB visual with desired depth\n"); /* not snd_error -- shell not ready yet */ else { /* create an OpenGL rendering context */ cx = glXCreateContext(dpy, vi, /* no display list sharing */ None, /* favor direct */ GL_TRUE); if (!cx) fprintf(stderr, "%s", "could not create rendering context\n"); else { /* create an X colormap since probably not using default visual */ cmap = XCreateColormap(dpy, RootWindow(dpy, vi->screen), vi->visual, AllocNone); XtVaSetValues(shell, XtNvisual, vi->visual, XtNdepth, vi->depth, XtNcolormap, cmap, NULL); ss->cx = cx; } XFree(vi); } } #endif XtAppSetWarningMsgHandler(app, muffle_warning); ss->mainapp = app; ss->mainshell = shell; ss->mdpy = dpy; ss->toolbar = NULL; ss->white = get_color(shell, WHITE_COLOR, NULL, NULL, true); ss->black = get_color(shell, BLACK_COLOR, NULL, NULL, false); ss->light_blue = get_color(shell, LIGHT_BLUE_COLOR, "blue", NULL, true); ss->lighter_blue = get_color(shell, LIGHTER_BLUE_COLOR, "blue", NULL, true); ss->red = get_color(shell, RED_COLOR, NULL, NULL, false); ss->green = get_color(shell, GREEN_COLOR, NULL, NULL, false); ss->blue = get_color(shell, "blue", NULL, NULL, false); ss->yellow = get_color(shell, YELLOW_COLOR, NULL, NULL, true); ss->highlight_color = get_color(shell, HIGHLIGHT_COLOR, "gray90", NULL, true); ss->basic_color = get_color(shell, BASIC_COLOR, "gray80", "gray", true); ss->position_color = get_color(shell, POSITION_COLOR, "gray60", "blue", false); ss->zoom_color = get_color(shell, ZOOM_COLOR, "gray20", "gray", false); ss->cursor_color = get_color(shell, CURSOR_COLOR, NULL, NULL, false); ss->selection_color = get_color(shell, SELECTION_COLOR, "gray80", NULL, false); ss->mix_color = get_color(shell, MIX_COLOR, "red", NULL, false); ss->enved_waveform_color = get_color(shell, ENVED_WAVEFORM_COLOR, "red", NULL, false); ss->filter_control_waveform_color = get_color(shell, FILTER_CONTROL_WAVEFORM_COLOR, "blue", NULL, false); ss->listener_color = get_color(shell, LISTENER_COLOR, NULL, NULL, true); ss->listener_text_color = get_color(shell, LISTENER_TEXT_COLOR, NULL, NULL, false); ss->graph_color = get_color(shell, GRAPH_COLOR, NULL, NULL, true); ss->selected_graph_color = get_color(shell, SELECTED_GRAPH_COLOR, NULL, NULL, true); ss->data_color = get_color(shell, DATA_COLOR, NULL, NULL, false); ss->selected_data_color = get_color(shell, SELECTED_DATA_COLOR, NULL, NULL, false); ss->mark_color = get_color(shell, MARK_COLOR, "red", NULL, false); ss->sash_color = get_color(shell, SASH_COLOR, NULL, NULL, false); ss->text_focus_color = get_color(shell, TEXT_FOCUS_COLOR, NULL, NULL, true); ss->grid_color = get_in_between_color(ss->data_color, ss->graph_color); ss->selected_grid_color = get_in_between_color(ss->selected_data_color, ss->selected_graph_color); #if HAVE_SCHEME s7_symbol_set_value(s7, ss->highlight_color_symbol, Xen_wrap_pixel(ss->highlight_color)); s7_symbol_set_value(s7, ss->basic_color_symbol, Xen_wrap_pixel(ss->basic_color)); s7_symbol_set_value(s7, ss->position_color_symbol, Xen_wrap_pixel(ss->position_color)); s7_symbol_set_value(s7, ss->zoom_color_symbol, Xen_wrap_pixel(ss->zoom_color)); s7_symbol_set_value(s7, ss->cursor_color_symbol, Xen_wrap_pixel(ss->cursor_color)); s7_symbol_set_value(s7, ss->selection_color_symbol, Xen_wrap_pixel(ss->selection_color)); s7_symbol_set_value(s7, ss->mix_color_symbol, Xen_wrap_pixel(ss->mix_color)); s7_symbol_set_value(s7, ss->enved_waveform_color_symbol, Xen_wrap_pixel(ss->enved_waveform_color)); s7_symbol_set_value(s7, ss->filter_control_waveform_color_symbol, Xen_wrap_pixel(ss->filter_control_waveform_color)); s7_symbol_set_value(s7, ss->listener_color_symbol, Xen_wrap_pixel(ss->listener_color)); s7_symbol_set_value(s7, ss->listener_text_color_symbol, Xen_wrap_pixel(ss->listener_text_color)); s7_symbol_set_value(s7, ss->graph_color_symbol, Xen_wrap_pixel(ss->graph_color)); s7_symbol_set_value(s7, ss->selected_graph_color_symbol, Xen_wrap_pixel(ss->selected_graph_color)); s7_symbol_set_value(s7, ss->data_color_symbol, Xen_wrap_pixel(ss->data_color)); s7_symbol_set_value(s7, ss->selected_data_color_symbol, Xen_wrap_pixel(ss->selected_data_color)); s7_symbol_set_value(s7, ss->mark_color_symbol, Xen_wrap_pixel(ss->mark_color)); s7_symbol_set_value(s7, ss->sash_color_symbol, Xen_wrap_pixel(ss->sash_color)); s7_symbol_set_value(s7, ss->text_focus_color_symbol, Xen_wrap_pixel(ss->text_focus_color)); #endif ss->axis_color_set = false; ss->orig_data_color = ss->data_color; ss->orig_selected_data_color = ss->selected_data_color; ss->orig_mark_color = ss->mark_color; ss->orig_mix_color = ss->mix_color; ss->orig_graph_color = ss->graph_color; ss->orig_selected_graph_color = ss->selected_graph_color; ss->orig_listener_color = ss->listener_color; ss->orig_listener_text_color = ss->listener_text_color; ss->orig_cursor_color = ss->cursor_color; ss->orig_basic_color = ss->basic_color; ss->orig_selection_color = ss->selection_color; ss->orig_zoom_color = ss->zoom_color; ss->orig_position_color = ss->position_color; ss->orig_highlight_color = ss->highlight_color; if ((!(set_peaks_font(DEFAULT_PEAKS_FONT))) && (!(set_peaks_font(FALLBACK_FONT)))) fprintf(stderr, "can't find peaks font %s", DEFAULT_PEAKS_FONT); if ((!(set_tiny_font(DEFAULT_TINY_FONT))) && (!(set_tiny_font(FALLBACK_FONT)))) fprintf(stderr, "can't find tiny font %s", DEFAULT_TINY_FONT); if ((!(set_bold_peaks_font(DEFAULT_BOLD_PEAKS_FONT))) && (!(set_bold_peaks_font(FALLBACK_FONT)))) fprintf(stderr, "can't find bold peaks font %s", DEFAULT_BOLD_PEAKS_FONT); if ((!(set_axis_label_font(DEFAULT_AXIS_LABEL_FONT))) && (!(set_axis_label_font(FALLBACK_FONT)))) fprintf(stderr, "can't find axis label font %s", DEFAULT_AXIS_LABEL_FONT); if ((!(set_axis_numbers_font(DEFAULT_AXIS_NUMBERS_FONT))) && (!(set_axis_numbers_font(FALLBACK_FONT)))) fprintf(stderr, "can't find axis numbers font %s", DEFAULT_AXIS_NUMBERS_FONT); set_listener_font(DEFAULT_LISTENER_FONT); /* we need some sort of font here! */ ss->orig_axis_label_font = mus_strdup(axis_label_font(ss)); ss->orig_axis_numbers_font = mus_strdup(axis_numbers_font(ss)); ss->orig_peaks_font = mus_strdup(peaks_font(ss)); ss->orig_bold_peaks_font = mus_strdup(bold_peaks_font(ss)); ss->orig_listener_font = mus_strdup(listener_font(ss)); ss->orig_tiny_font = mus_strdup(tiny_font(ss)); XtVaSetValues(shell, XmNbackground, ss->basic_color, NULL); n = 0; XtSetArg(args[n], XmNbackground, ss->basic_color); n++; n = attach_all_sides(args, n); XtSetArg(args[n], XmNallowResize, true); n++; ss->mainpane = XtCreateManagedWidget("mainpane", xmFormWidgetClass, shell, args, n); menu = add_menu(); n = 0; XtSetArg(args[n], XmNbackground, ss->basic_color); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNtopWidget, menu); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNallowResize, true); n++; XtSetArg(args[n], XmNpaneMaximum, LOTSA_PIXELS); n++; switch (sound_style(ss)) { case SOUNDS_IN_SEPARATE_WINDOWS: ss->soundpane = XtCreateManagedWidget("soundpane", xmFormWidgetClass, ss->mainpane, args, n); break; case SOUNDS_HORIZONTAL: XtSetArg(args[n], XmNorientation, XmVERTICAL); n++; ss->soundpanebox = XtCreateManagedWidget("soundpane", xmPanedWindowWidgetClass, ss->mainpane, args, n); n = 0; XtSetArg(args[n], XmNbackground, ss->basic_color); n++; XtSetArg(args[n], XmNsashHeight, ss->sash_size); n++; XtSetArg(args[n], XmNsashWidth, ss->sash_size); n++; XtSetArg(args[n], XmNorientation, XmHORIZONTAL); n++; XtSetArg(args[n], XmNsashIndent, ss->sash_indent); n++; ss->soundpane = XtCreateManagedWidget("soundpane", xmPanedWindowWidgetClass, ss->soundpanebox, args, n); break; case SOUNDS_VERTICAL: XtSetArg(args[n], XmNsashHeight, ss->sash_size); n++; XtSetArg(args[n], XmNsashWidth, ss->sash_size); n++; XtSetArg(args[n], XmNsashIndent, ss->sash_indent); n++; ss->soundpane = XtCreateManagedWidget("soundpane", xmPanedWindowWidgetClass, ss->mainpane, args, n); break; case SOUNDS_IN_NOTEBOOK: XtSetArg(args[n], XmNorientation, XmVERTICAL); n++; ss->soundpanebox = XtCreateManagedWidget("soundpane", xmPanedWindowWidgetClass, ss->mainpane, args, n); n = 0; XtSetArg(args[n], XmNbackground, ss->basic_color); n++; XtSetArg(args[n], XmNframeBackground, ss->zoom_color); n++; XtSetArg(args[n], XmNbindingType, XmNONE); n++; XtSetArg(args[n], XmNbackPagePlacement, XmTOP_RIGHT); n++; XtSetArg(args[n], XmNorientation, XmVERTICAL); n++; ss->soundpane = XtCreateWidget("nb", xmNotebookWidgetClass, ss->soundpanebox, args, n); { /* get rid of the useless spinbox */ n = 0; XtSetArg(args[n], XmNnotebookChildType, XmPAGE_SCROLLER); n++; XtCreateWidget("scroller", xmScrollBarWidgetClass, ss->soundpane, NULL, 0); } XtManageChild(ss->soundpane); XtAddCallback(ss->soundpane, XmNpageChangedCallback, notebook_page_changed_callback, NULL); map_over_children(ss->soundpane, set_main_color_of_widget); /* appears to be a no-op */ break; } SetupIcon(shell); XtRealizeWidget(shell); if (auto_resize(ss) != AUTO_RESIZE_DEFAULT) XtVaSetValues(shell, XmNallowShellResize, auto_resize(ss), NULL); wn = XtWindow(shell); gv.background = ss->graph_color; gv.foreground = ss->data_color; ss->basic_gc = XCreateGC(dpy, wn, GCForeground | GCBackground, &gv); gv.background = ss->graph_color; gv.foreground = ss->data_color; ss->combined_basic_gc = XCreateGC(dpy, wn, GCForeground | GCBackground, &gv); gv.background = ss->graph_color; gv.foreground = ss->mix_color; ss->mix_gc = XCreateGC(dpy, wn, GCForeground | GCBackground, &gv); gv.function = GXxor; gv.background = ss->graph_color; gv.foreground = (Pixel)(XOR(ss->cursor_color, gv.background)); ss->cursor_gc = XCreateGC(dpy, wn, GCForeground | GCFunction, &gv); gv.function = GXxor; gv.background = ss->graph_color; gv.foreground = (Pixel)(XOR(ss->selection_color, gv.background)); ss->selection_gc = XCreateGC(dpy, wn, GCForeground | GCFunction, &gv); gv.function = GXxor; gv.background = ss->graph_color; gv.foreground = (Pixel)(XOR(ss->mark_color, gv.background)); ss->mark_gc = XCreateGC(dpy, wn, GCForeground | GCFunction, &gv); gv.function = GXcopy; gv.background = ss->data_color; gv.foreground = ss->graph_color; ss->erase_gc = XCreateGC(dpy, wn, GCForeground | GCBackground | GCFunction, &gv); gv.background = ss->selected_graph_color; gv.foreground = ss->selected_data_color; ss->selected_basic_gc = XCreateGC(dpy, wn, GCForeground | GCBackground, &gv); gv.function = GXxor; gv.background = ss->selected_graph_color; gv.foreground = (Pixel)(XOR(ss->cursor_color, gv.background)); ss->selected_cursor_gc = XCreateGC(dpy, wn, GCForeground | GCFunction, &gv); gv.function = GXxor; gv.background = ss->selected_graph_color; gv.foreground = (Pixel)(XOR(ss->selection_color, gv.background)); ss->selected_selection_gc = XCreateGC(dpy, wn, GCForeground | GCFunction, &gv); gv.function = GXxor; gv.background = ss->selected_graph_color; gv.foreground = (Pixel)(XOR(ss->mark_color, gv.background)); ss->selected_mark_gc = XCreateGC(dpy, wn, GCForeground | GCFunction, &gv); gv.function = GXcopy; gv.background = ss->selected_data_color; gv.foreground = ss->selected_graph_color; ss->selected_erase_gc = XCreateGC(dpy, wn, GCForeground | GCBackground | GCFunction, &gv); gv.function = GXcopy; gv.background = ss->basic_color; gv.foreground = ss->black; ss->fltenv_basic_gc = XCreateGC(dpy, wn, GCBackground | GCForeground | GCFunction, &gv); gv.function = GXcopy; gv.background = ss->basic_color; gv.foreground = ss->filter_control_waveform_color; ss->fltenv_data_gc = XCreateGC(dpy, wn, GCBackground | GCForeground | GCFunction, &gv); initialize_colormap(); /* X11 not ours */ make_icons_transparent(BASIC_COLOR); if (with_toolbar(ss)) show_toolbar(); #ifndef _MSC_VER if (setjmp(top_level_jump)) { if (!(ss->jump_ok)) snd_error_without_format("Caught top level error (will try to continue):\n"); else ss->jump_ok = false; } else #endif startup_funcs(); /* snd /tmp -> segfault if this happens before the setjmp(top_level_jump) */ if (ss->startup_errors) { post_it("Error in initialization", ss->startup_errors); free(ss->startup_errors); ss->startup_errors = NULL; } XtAppMainLoop(app); } /* -------------------------------------------------------------------------------- */ Xen_wrap_2_optional_args(g_find_dialog_w, g_find_dialog) Xen_wrap_no_args(g_find_dialog_widgets_w, g_find_dialog_widgets) Xen_wrap_1_arg(reflect_file_in_enved_w, reflect_file_in_enved) Xen_wrap_no_args(g_enved_filter_w, g_enved_filter) Xen_wrap_1_arg(g_set_enved_filter_w, g_set_enved_filter) Xen_wrap_no_args(g_enved_envelope_w, g_enved_envelope) Xen_wrap_1_arg(g_set_enved_envelope_w, g_set_enved_envelope) Xen_wrap_1_arg(reflect_file_in_region_browser_w, reflect_file_in_region_browser) Xen_wrap_no_args(g_view_regions_dialog_w, g_view_regions_dialog) Xen_wrap_1_arg(mix_open_file_watcher_w, mix_open_file_watcher) Xen_wrap_1_optional_arg(insert_open_file_watcher_w, insert_open_file_watcher) Xen_wrap_1_arg(vf_open_file_watcher_w, vf_open_file_watcher) Xen_wrap_1_optional_arg(g_view_files_sort_w, g_view_files_sort) Xen_wrap_2_optional_args(g_set_view_files_sort_w, g_set_view_files_sort) Xen_wrap_2_optional_args(g_add_directory_to_view_files_list_w, g_add_directory_to_view_files_list) Xen_wrap_2_optional_args(g_add_file_to_view_files_list_w, g_add_file_to_view_files_list) Xen_wrap_2_optional_args(g_view_files_dialog_w, g_view_files_dialog) Xen_wrap_1_arg(g_view_files_amp_w, g_view_files_amp) Xen_wrap_2_args(g_view_files_set_amp_w, g_view_files_set_amp) Xen_wrap_1_arg(g_view_files_speed_w, g_view_files_speed) Xen_wrap_2_args(g_view_files_set_speed_w, g_view_files_set_speed) Xen_wrap_1_arg(g_view_files_amp_env_w, g_view_files_amp_env) Xen_wrap_2_args(g_view_files_set_amp_env_w, g_view_files_set_amp_env) Xen_wrap_1_arg(g_view_files_speed_style_w, g_view_files_speed_style) Xen_wrap_2_args(g_view_files_set_speed_style_w, g_view_files_set_speed_style) Xen_wrap_1_arg(g_view_files_selected_files_w, g_view_files_selected_files) Xen_wrap_1_arg(g_view_files_files_w, g_view_files_files) Xen_wrap_2_args(g_view_files_set_selected_files_w, g_view_files_set_selected_files) Xen_wrap_2_args(g_view_files_set_files_w, g_view_files_set_files) Xen_wrap_1_arg(g_delete_file_sorter_w, g_delete_file_sorter) Xen_wrap_2_args(g_add_file_sorter_w, g_add_file_sorter) Xen_wrap_no_args(g_menu_widgets_w, g_menu_widgets) Xen_wrap_no_args(g_listener_selection_w, g_listener_selection) Xen_wrap_no_args(g_reset_listener_cursor_w, g_reset_listener_cursor) Xen_wrap_no_args(g_goto_listener_end_w, g_goto_listener_end) Xen_wrap_2_args(g_in_w, g_in) Xen_wrap_no_args(g_graph_cursor_w, g_graph_cursor) Xen_wrap_1_arg(g_set_graph_cursor_w, g_set_graph_cursor) Xen_wrap_2_optional_args(g_channel_widgets_w, g_channel_widgets) Xen_wrap_1_arg(reflect_file_close_in_sync_w, reflect_file_close_in_sync) Xen_wrap_1_optional_arg(g_sound_widgets_w, g_sound_widgets) static void add_reflect_enved_hook(void) { Xen_add_to_hook_list(ss->snd_open_file_hook, reflect_file_in_enved_w, "enved-file-open-handler", "enved dialog's file-open-hook handler"); } static void add_reflect_region_hook(void) { Xen_add_to_hook_list(ss->snd_open_file_hook, reflect_file_in_region_browser_w, "region-dialog-open-file-watcher", "region dialog open-file-hook handler"); } static void add_reflect_mix_hook(void) { Xen_add_to_hook_list(ss->snd_open_file_hook, mix_open_file_watcher_w, "mix-dialog-open-file-watcher", "mix dialog's open-file-hook handler"); } static void add_reflect_insert_hook(void) { Xen_add_to_hook_list(ss->snd_open_file_hook, insert_open_file_watcher_w, "insert-dialog-open-file-watcher", "insert dialog's open-file-hook handler"); } #if HAVE_SCHEME static s7_pointer acc_view_files_sort(s7_scheme *sc, s7_pointer args) {return(g_set_view_files_sort(s7_cadr(args), s7_undefined(sc)));} static s7_pointer acc_graph_cursor(s7_scheme *sc, s7_pointer args) {return(g_set_graph_cursor(s7_cadr(args)));} #endif #define H_orientation_hook S_orientation_hook " (): called whenever one of the variables associated with the orientation dialog changes" #define H_color_hook S_color_hook " (): called whenever one of the variables associated with the color dialog changes" #define H_drop_hook S_drop_hook " (name): called whenever Snd receives a drag-and-drop \ event. If it returns " PROC_TRUE ", the file is not opened or mixed by Snd." #define H_view_files_select_hook S_view_files_select_hook "(dialog name): called when a file is selected in the \ files list of the View Files dialog. If it returns " PROC_TRUE ", the default action, opening the file, is omitted." #define H_mouse_leave_label_hook S_mouse_leave_label_hook " (type position label): called when the mouse leaves a file viewer or region label" #define H_mouse_leave_text_hook S_mouse_leave_text_hook " (widget): called when the mouse leaves a text widget" #define H_listener_click_hook S_listener_click_hook " (position): called when listener clicked; position is text pos of click in listener" #define H_mouse_leave_listener_hook S_mouse_leave_listener_hook " (widget): called when the mouse leaves the lisp listener pane" #if HAVE_SCHEME #define H_mouse_enter_label_hook S_mouse_enter_label_hook " (type position label): called when the mouse enters a file viewer or region label. \ The 'type' is 1 for view-files, and 2 for regions. The 'position' \ is the scrolled list position of the label. The label itself is 'label'. We could use the 'finfo' procedure in examp.scm \ to popup file info as follows: \n\ (hook-push " S_mouse_enter_label_hook "\n\ (lambda (type position name)\n\ (if (not (= type 2))\n\ (" S_info_dialog " name (finfo name)))))\n\ See also nb.scm." #endif #if HAVE_RUBY #define H_mouse_enter_label_hook S_mouse_enter_label_hook " (type position label): called when the mouse enters a file viewer or region label. \ The 'type' is 1 for view-files, and 2 for regions. The 'position' \ is the scrolled list position of the label. The label itself is 'label'. We could use the 'finfo' procedure in examp.rb \ to popup file info as follows: \n\ $mouse_enter_label_hook.add_hook!(\"finfo\") do |type, position, name|\n\ if type != 2\n\ " S_info_dialog "(name, finfo(name))\n\ end\n\ end\n\ See also nb.rb." #endif #if HAVE_FORTH #define H_mouse_enter_label_hook S_mouse_enter_label_hook " (type position label): called when the mouse enters a file viewer or region label. \ The 'type' is 1 for view-files, and 2 for regions. The 'position' \ is the scrolled list position of the label. The label itself is 'label'. We could use the 'finfo' procedure in examp.fs \ to popup file info as follows: \n\ " S_mouse_enter_label_hook " lambda: <{ type position name }>\n\ type 2 <> if\n\ name name finfo info-dialog\n\ else\n\ #f\n\ then\n\ ; add-hook!" #endif #if HAVE_SCHEME #define H_mouse_enter_graph_hook S_mouse_enter_graph_hook " (snd chn): called when the mouse \ enters the drawing area (graph pane) of the given channel.\n\ (hook-push " S_mouse_enter_graph_hook "\n\ (lambda (hook)\n\ (" S_focus_widget " (car (" S_channel_widgets " (hook 'snd) (hook 'chn))))))" #define H_mouse_leave_graph_hook S_mouse_leave_graph_hook " (snd chn): is called when the mouse \ leaves the drawing area (graph pane) of the given channel." #endif #if HAVE_RUBY #define H_mouse_enter_graph_hook S_mouse_enter_graph_hook " (snd chn): called when the mouse \ enters the drawing area (graph pane) of the given channel.\n\ $mouse_enter_graph_hook.add-hook!(\"focus\") do |snd chn|\n\ focus_widget(channel_widgets(snd, chn)[0])\n\ end" #define H_mouse_leave_graph_hook S_mouse_leave_graph_hook " (snd chn): called when the mouse \ leaves the drawing area (graph pane) of the given channel." #endif #if HAVE_FORTH #define H_mouse_enter_graph_hook S_mouse_enter_graph_hook " (snd chn): called when the mouse \ enters the drawing area (graph pane) of the given channel.\n\ " S_mouse_enter_graph_hook " lambda: <{ snd chn }>\n\ snd chn " S_channel_widgets " car " S_focus_widget "\n\ ; add-hook!" #define H_mouse_leave_graph_hook S_mouse_leave_graph_hook " (snd chn): is called when the mouse \ leaves the drawing area (graph pane) of the given channel." #endif #if HAVE_SCHEME #define H_mouse_enter_listener_hook S_mouse_enter_listener_hook " (widget): called when the mouse \ enters the lisp listener pane:\n\ (hook-push " S_mouse_enter_listener_hook "\n\ (lambda (hook)\n\ (" S_focus_widget " (hook 'widget))))" #endif #if HAVE_RUBY #define H_mouse_enter_listener_hook S_mouse_enter_listener_hook " (listener): called when the mouse \ enters the lisp listener pane:\n\ $mouse_enter_listener_hook.add-hook!(\"enter\") do |widget|\n\ focus_widget(widget)\n\ end" #endif #if HAVE_FORTH #define H_mouse_enter_listener_hook S_mouse_enter_listener_hook " (listener): called when the mouse \ enters the lisp listener pane:\n\ " S_mouse_enter_listener_hook " lambda: <{ wid }> wid " S_focus_widget " ; add-hook!" #endif #if HAVE_SCHEME #define H_mouse_enter_text_hook S_mouse_enter_text_hook " (widget): called when the mouse enters a text widget:\n\ (hook-push " S_mouse_enter_text_hook "\n\ (lambda (w)\n\ (" S_focus_widget " w)))" #endif #if HAVE_RUBY #define H_mouse_enter_text_hook S_mouse_enter_text_hook " (widget): called when the mouse enters a text widget:\n\ $mouse_enter_text_hook.add_hook!(\"enter\") do |w|\n\ focus_widget(w)\n\ end" #endif #if HAVE_FORTH #define H_mouse_enter_text_hook S_mouse_enter_text_hook " (widget): called when the mouse enters a text widget:\n\ " S_mouse_enter_text_hook " lambda: <{ wid }> wid " S_focus_widget " ; add-hook!" #endif void g_init_motif(void) { #if HAVE_SCHEME s7_pointer i, b, p, t, r, s, l, fnc; i = s7_make_symbol(s7, "integer?"); b = s7_make_symbol(s7, "boolean?"); p = s7_make_symbol(s7, "pair?"); l = s7_make_symbol(s7, "list?"); r = s7_make_symbol(s7, "real?"); s = s7_make_symbol(s7, "string?"); fnc = s7_make_symbol(s7, "procedure?"); t = s7_t(s7); #endif orientation_hook = Xen_define_hook(S_orientation_hook, "(make-hook)", 0, H_orientation_hook); color_hook = Xen_define_hook(S_color_hook, "(make-hook)", 0, H_color_hook); mouse_enter_label_hook = Xen_define_hook(S_mouse_enter_label_hook, "(make-hook 'type 'position 'label)", 3, H_mouse_enter_label_hook); mouse_leave_label_hook = Xen_define_hook(S_mouse_leave_label_hook, "(make-hook 'type 'position 'label)", 3, H_mouse_leave_label_hook); view_files_select_hook = Xen_define_hook(S_view_files_select_hook, "(make-hook 'dialog 'name)", 2, H_view_files_select_hook); drop_hook = Xen_define_hook(S_drop_hook, "(make-hook 'name)", 1, H_drop_hook); mouse_enter_listener_hook = Xen_define_hook(S_mouse_enter_listener_hook, "(make-hook 'widget)", 1, H_mouse_enter_listener_hook); mouse_leave_listener_hook = Xen_define_hook(S_mouse_leave_listener_hook, "(make-hook 'widget)", 1, H_mouse_leave_listener_hook); mouse_enter_text_hook = Xen_define_hook(S_mouse_enter_text_hook, "(make-hook 'widget)", 1, H_mouse_enter_text_hook); mouse_leave_text_hook = Xen_define_hook(S_mouse_leave_text_hook, "(make-hook 'widget)", 1, H_mouse_leave_text_hook); listener_click_hook = Xen_define_hook(S_listener_click_hook, "(make-hook 'position)", 1, H_listener_click_hook); mouse_enter_graph_hook = Xen_define_hook(S_mouse_enter_graph_hook, "(make-hook 'snd 'chn)", 2, H_mouse_enter_graph_hook); mouse_leave_graph_hook = Xen_define_hook(S_mouse_leave_graph_hook, "(make-hook 'snd 'chn)", 2, H_mouse_leave_graph_hook); Xen_define_typed_procedure(S_find_dialog, g_find_dialog_w, 0, 2, 0, H_find_dialog, s7_make_signature(s7, 3, p, b, s)); Xen_define_typed_procedure("find-dialog-widgets", g_find_dialog_widgets_w, 0, 0, 0, "test function", s7_make_signature(s7, 1, l)); Xen_define_typed_procedure(S_view_regions_dialog, g_view_regions_dialog_w, 0, 0, 0, H_view_regions_dialog, s7_make_signature(s7, 1, p)); Xen_define_typed_procedure(S_view_files_dialog, g_view_files_dialog_w, 0, 2, 0, H_view_files_dialog, s7_make_signature(s7, 3, p, b, b)); Xen_define_typed_procedure(S_add_file_sorter, g_add_file_sorter_w, 2, 0, 0, H_add_file_sorter, s7_make_signature(s7, 3, i, s, fnc)); Xen_define_typed_procedure(S_delete_file_sorter, g_delete_file_sorter_w, 1, 0, 0, H_delete_file_sorter, s7_make_signature(s7, 2, i, i)); Xen_define_typed_procedure(S_menu_widgets, g_menu_widgets_w, 0, 0, 0, H_menu_widgets, s7_make_signature(s7, 1, p)); Xen_define_typed_procedure(S_listener_selection, g_listener_selection_w, 0, 0, 0, H_listener_selection, s7_make_signature(s7, 1, s7_make_signature(s7, 2, b, s))); Xen_define_typed_procedure(S_reset_listener_cursor, g_reset_listener_cursor_w, 0, 0, 0, H_reset_listener_cursor, s7_make_signature(s7, 1, b)); Xen_define_typed_procedure(S_goto_listener_end, g_goto_listener_end_w, 0, 0, 0, H_goto_listener_end, s7_make_signature(s7, 1, i)); Xen_define_typed_procedure(S_channel_widgets, g_channel_widgets_w, 0, 2, 0, H_channel_widgets, s7_make_signature(s7, 3, p, t, t)); Xen_define_typed_procedure(S_sound_widgets, g_sound_widgets_w, 0, 1, 0, H_sound_widgets, s7_make_signature(s7, 2, p, t)); Xen_define_typed_procedure(S_add_directory_to_view_files_list, g_add_directory_to_view_files_list_w, 1, 1, 0, H_add_directory_to_view_files_list, s7_make_signature(s7, 3, s, s, p)); Xen_define_typed_procedure(S_add_file_to_view_files_list, g_add_file_to_view_files_list_w, 1, 1, 0, H_add_file_to_view_files_list, s7_make_signature(s7, 3, s, s, p)); Xen_define_typed_dilambda(S_enved_filter, g_enved_filter_w, H_enved_filter, S_set S_enved_filter, g_set_enved_filter_w, 0, 0, 1, 0, s7_make_signature(s7, 1, b), s7_make_signature(s7, 2, b, b)); Xen_define_typed_dilambda(S_enved_envelope, g_enved_envelope_w, H_enved_envelope, S_set S_enved_envelope, g_set_enved_envelope_w, 0, 0, 1, 0, s7_make_signature(s7, 1, p), s7_make_signature(s7, 2, t, t)); Xen_define_typed_dilambda(S_view_files_amp, g_view_files_amp_w, H_view_files_amp, S_set S_view_files_amp, g_view_files_set_amp_w, 1, 0, 2, 0, s7_make_signature(s7, 2, r, t), s7_make_signature(s7, 3, r, t, r)); Xen_define_typed_dilambda(S_view_files_amp_env, g_view_files_amp_env_w, H_view_files_amp_env, S_set S_view_files_amp_env, g_view_files_set_amp_env_w, 1, 0, 2, 0, s7_make_signature(s7, 2, p, t), s7_make_signature(s7, 3, p, t, p)); Xen_define_typed_dilambda(S_view_files_speed_style, g_view_files_speed_style_w, H_view_files_speed_style, S_set S_view_files_speed_style, g_view_files_set_speed_style_w, 1, 0, 2, 0, s7_make_signature(s7, 2, i, t), s7_make_signature(s7, 3, i, t, i)); Xen_define_typed_dilambda(S_view_files_speed, g_view_files_speed_w, H_view_files_speed, S_set S_view_files_speed, g_view_files_set_speed_w, 1, 0, 2, 0, s7_make_signature(s7, 2, r, t), s7_make_signature(s7, 3, r, t, r)); Xen_define_typed_dilambda(S_view_files_files, g_view_files_files_w, H_view_files_files, S_set S_view_files_files, g_view_files_set_files_w, 1, 0, 2, 0, s7_make_signature(s7, 2, l, t), s7_make_signature(s7, 3, l, t, l)); Xen_define_typed_dilambda(S_view_files_selected_files, g_view_files_selected_files_w, H_view_files_selected_files, S_set S_view_files_selected_files, g_view_files_set_selected_files_w, 1, 0, 2, 0, s7_make_signature(s7, 2, l, t), s7_make_signature(s7, 3, l, t, l)); Xen_define_typed_dilambda(S_view_files_sort, g_view_files_sort_w, H_view_files_sort, S_set S_view_files_sort, g_set_view_files_sort_w, 0, 1, 1, 1, s7_make_signature(s7, 2, i, t), s7_make_signature(s7, 3, i, t, i)); Xen_define_typed_dilambda(S_graph_cursor, g_graph_cursor_w, H_graph_cursor, S_set S_graph_cursor, g_set_graph_cursor_w, 0, 0, 1, 0, s7_make_signature(s7, 1, i), s7_make_signature(s7, 2, i, i)); Xen_add_to_hook_list(ss->snd_open_file_hook, vf_open_file_watcher_w, "view-files-dialog-open-file-handler", "view-files dialog open-file handler"); Xen_add_to_hook_list(ss->snd_open_file_hook, reflect_file_close_in_sync_w, "sync-open-file-watcher", "sound sync open-file-hook handler"); /* file-filters and file-sorters are lists from user's point of view, but I want to * make sure they're gc-protected through add/delete/set, and want such code compatible * with current Ruby xen macros, so I'll use an array internally. */ ss->file_sorters_size = INITIAL_FILE_SORTERS_SIZE; ss->file_sorters = Xen_make_vector(ss->file_sorters_size, Xen_false); Xen_GC_protect(ss->file_sorters); #if HAVE_SCHEME s7_set_setter(s7, ss->view_files_sort_symbol, s7_make_function(s7, "[acc-" S_view_files_sort "]", acc_view_files_sort, 2, 0, false, "accessor")); top_level_let = s7_nil(s7); s7_define_variable(s7, "top-level-let", s7_dilambda(s7, "top-level-let", g_top_level_let, 0, 0, g_set_top_level_let, 1, 0, "listener environment")); s7_set_setter(s7, ss->graph_cursor_symbol, s7_make_function(s7, "[acc-" S_graph_cursor "]", acc_graph_cursor, 2, 0, false, "accessor")); s7_set_documentation(s7, ss->graph_cursor_symbol, "*graph-cursor*: current graph cursor shape"); #endif preload_best_completions(); Xen_define_procedure(S_in, g_in_w, 2, 0, 0, H_in); }