1 /*
2  * Copyright (c) 2004 Stefan Ulrich
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a copy
5  * of this software and associated documentation files (the "Software"), to
6  * deal in the Software without restriction, including without limitation the
7  * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
8  * sell copies of the Software, and to permit persons to whom the Software is
9  * furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice shall be included in
12  * all copies or substantial portions of the Software.
13  *
14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
17  * PAUL VOJTA OR ANY OTHER AUTHOR OF THIS SOFTWARE BE LIABLE FOR ANY CLAIM,
18  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20  * OTHER DEALINGS IN THE SOFTWARE.
21  *
22  */
23 
24 /*
25  * Panel 5 (Scrolling behaviour) for xdvik preferences dialog.
26  */
27 
28 #include "xdvi-config.h"
29 #include "xdvi.h"
30 
31 #include "x_util.h"
32 #include "xm_colorsel.h"
33 #include "topic-window.h"
34 #include "util.h"
35 #include "events.h"
36 #include "dvi-init.h"
37 #include "statusline.h"
38 
39 #include "xm_prefsP.h"
40 #include "xm_prefs_scroll.h"
41 #include "my-snprintf.h"
42 
43 #ifdef MOTIF /* entire file */
44 
45 #include <ctype.h>
46 
47 #include <X11/Xatom.h>
48 
49 #include <Xm/Xm.h>
50 #include <Xm/Protocols.h>
51 #include <Xm/DialogS.h>
52 #include <Xm/LabelG.h>
53 #include <Xm/PushB.h>
54 #include <Xm/PushBG.h>
55 #include <Xm/Form.h>
56 #include <Xm/Frame.h>
57 #include <Xm/PanedW.h>
58 #include <Xm/DrawnB.h>
59 #include <Xm/RowColumn.h>
60 #include <Xm/Scale.h>
61 #include <Xm/ToggleBG.h>
62 #include <Xm/Text.h>
63 #include <Xm/TextF.h>
64 #include <Xm/CascadeBG.h>
65 
66 /*
67  * Handy defaults
68  */
69 static Arg one_of_many = { XmNindicatorType, XmONE_OF_MANY };
70 
71 static void
select_unit_cb(Widget w,XtPointer client_data,XtPointer call_data)72 select_unit_cb(Widget w, XtPointer client_data, XtPointer call_data)
73 {
74     struct topic_info *info = (struct topic_info *)client_data;
75     struct prefs_choice *prefs = (struct prefs_choice *)(info->data);
76 
77     Widget pulldown = XtParent(w);
78     Widget form = XtParent(XtParent(pulldown));
79     Widget text_x, text_y;
80 
81     const char *w_name = XtName(w);
82 
83     UNUSED(call_data);
84 
85     fprintf(stderr, "setting name: %s\n", w_name);
86     XtVaSetValues(pulldown,  XmNuserData, (XtPointer)w_name, NULL);
87 
88     if (get_widget_by_name(&text_x, form, Xdvi_HOME_POSITION_X_OFF_TEXT, True)
89 	&& get_widget_by_name(&text_y, form, Xdvi_HOME_POSITION_Y_OFF_TEXT, True)) {
90 	const char *buf_x = XmTextFieldGetString(text_x);
91 	const char *buf_y = XmTextFieldGetString(text_y);
92 
93 	int val_x = strtol(buf_x, (char **)NULL, 10);
94 	int val_y = strtol(buf_y, (char **)NULL, 10);
95 
96 	static char x_off[LENGTH_OF_INT + 16];
97 	static char y_off[LENGTH_OF_INT + 16];
98 
99 	SNPRINTF(x_off, LENGTH_OF_INT + 16, "%s%s", buf_x, w_name);
100 	SNPRINTF(y_off, LENGTH_OF_INT + 16, "%s%s", buf_y, w_name);
101 
102 	resource.sidemargin = x_off;
103 	resource.topmargin = y_off;
104 
105 	resource.sidemargin_int = val_x;
106 	resource.topmargin_int = val_y;
107 
108 	store_preference(&(prefs->db), "sideMargin", "%s", x_off);
109 	store_preference(&(prefs->db), "topMargin", "%s", y_off);
110 
111 	globals.ev.flags |= EV_NEWPAGE;
112 	XFlush(DISP);
113 
114 	XtFree((char *)buf_x);
115 	XtFree((char *)buf_y);
116     }
117 }
118 
119 static void
set_offset_cb(Widget w,XtPointer client_data,XtPointer call_data)120 set_offset_cb(Widget w, XtPointer client_data, XtPointer call_data)
121 {
122     struct topic_info *info = (struct topic_info *)client_data;
123     struct prefs_choice *prefs = (struct prefs_choice *)(info->data);
124 
125     Widget form = XtParent(w);
126     Widget pulldown;
127 
128     UNUSED(call_data);
129 
130     if (get_widget_by_name(&pulldown, form, Xdvi_HOME_POSITION_UNITS_PULLDOWN, True)) {
131 	char *ptr = NULL;
132 	const char *w_name = XtName(w);
133 
134 	XtVaGetValues(pulldown, XmNuserData, &ptr, NULL);
135 
136 	if (ptr == NULL) {
137 	    XDVI_WARNING((stderr, "XmNuserData for %s is NULL in set_offset_cb()\n",
138 			  Xdvi_HOME_POSITION_UNITS_PULLDOWN));
139 	    return;
140 	}
141 	fprintf(stderr, "UNIT: |%s|\n", ptr);
142 
143 	if (strcmp(w_name, Xdvi_HOME_POSITION_X_OFF_TEXT) == 0) {
144 	    static char x_off[LENGTH_OF_INT + 16];
145 	    const char *buf = XmTextFieldGetString(w);
146 	    int val = strtol(buf, (char **)NULL, 10);
147 
148 	    SNPRINTF(x_off, LENGTH_OF_INT + 16, "%s%s", buf, ptr);
149 
150 	    XtFree((char *)buf);
151 
152 	    resource.sidemargin = x_off;
153 	    resource.sidemargin_int = val;
154 	    store_preference(&(prefs->db), "sideMargin", "%s", x_off);
155 
156 	    goto_page(current_page, resource.keep_flag ? NULL : home, True);
157 	}
158 	else if (strcmp(w_name, Xdvi_HOME_POSITION_Y_OFF_TEXT) == 0) {
159 	    static char y_off[LENGTH_OF_INT + 16];
160 	    const char *buf = XmTextFieldGetString(w);
161 	    int val = strtol(buf, (char **)NULL, 10);
162 
163 	    SNPRINTF(y_off, LENGTH_OF_INT + 16, "%s%s", buf, ptr);
164 
165 	    XtFree((char *)buf);
166 
167 	    resource.topmargin = y_off;
168 	    resource.topmargin_int = val;
169 	    store_preference(&(prefs->db), "topMargin", "%s", y_off);
170 
171 	    goto_page(current_page, resource.keep_flag ? NULL : home, True);
172 	}
173 	else {
174 	    XDVI_WARNING((stderr, "unexpected widget name `%s' in set_offset_cb()", w_name));
175 	}
176     }
177 }
178 
179 static void
home_position_cb(Widget w,XtPointer client_data,XtPointer call_data)180 home_position_cb(Widget w, XtPointer client_data, XtPointer call_data)
181 {
182     struct topic_info *info = (struct topic_info *)client_data;
183     struct prefs_choice *prefs = (struct prefs_choice *)(info->data);
184 
185     Widget parent = XtParent(XtParent(w));
186     Widget toggle_home, toggle_curr, label_x, label_y, text_x, text_y, units_menu;
187 
188     UNUSED(call_data);
189 
190     resource.use_current_offset = !resource.use_current_offset;
191 
192     if (get_widget_by_name(&toggle_home, parent, Xdvi_HOME_POSITION_STR, True)
193 	&& get_widget_by_name(&toggle_curr, parent, Xdvi_SCROLL_CURRENT_STR, True)
194 	&& get_widget_by_name(&label_x, parent, Xdvi_HOME_POSITION_X_STR, True)
195 	&& get_widget_by_name(&label_y, parent, Xdvi_HOME_POSITION_Y_STR, True)
196 	&& get_widget_by_name(&text_x, parent, Xdvi_HOME_POSITION_X_OFF_TEXT, True)
197 	&& get_widget_by_name(&text_y, parent, Xdvi_HOME_POSITION_Y_OFF_TEXT, True)
198 	&& get_widget_by_name(&units_menu, parent, Xdvi_HOME_POSITION_UNITS_MENU, True)) {
199 
200 	XmToggleButtonGadgetSetState(toggle_home, !resource.use_current_offset, False);
201 	XmToggleButtonGadgetSetState(toggle_curr, resource.use_current_offset, False);
202 
203 	XtSetSensitive(label_x, !resource.keep_flag && !resource.use_current_offset);
204 	XtSetSensitive(label_y, !resource.keep_flag && !resource.use_current_offset);
205 	XtSetSensitive(text_x, !resource.keep_flag && !resource.use_current_offset);
206 	XtSetSensitive(text_y, !resource.keep_flag && !resource.use_current_offset);
207 	XtSetSensitive(units_menu, !resource.keep_flag && !resource.use_current_offset);
208     }
209 
210     store_preference(&(prefs->db), "useCurrentOffset", "%s", resource.use_current_offset ? "True" : "False");
211 }
212 
213 static void
keep_cb(Widget w,XtPointer client_data,XtPointer call_data)214 keep_cb(Widget w, XtPointer client_data, XtPointer call_data)
215 {
216     struct topic_info *info = (struct topic_info *)client_data;
217     struct prefs_choice *prefs = (struct prefs_choice *)(info->data);
218 
219     Widget parent, keep, unkeep, toggle_home, toggle_curr, label_x, label_y, text_x, text_y, units_menu;
220 
221     UNUSED(call_data);
222 
223     resource.keep_flag = !resource.keep_flag;
224 
225     parent = XtParent(w);
226 
227     if (get_widget_by_name(&keep, parent, Xdvi_SCROLL_KEEP_STR, True)
228 	&& get_widget_by_name(&unkeep, parent, Xdvi_SCROLL_UNKEEP_STR, True)
229 	&& get_widget_by_name(&toggle_home, parent, Xdvi_HOME_POSITION_STR, True)
230 	&& get_widget_by_name(&toggle_curr, parent, Xdvi_SCROLL_CURRENT_STR, True)
231 	&& get_widget_by_name(&label_x, parent, Xdvi_HOME_POSITION_X_STR, True)
232 	&& get_widget_by_name(&label_y, parent, Xdvi_HOME_POSITION_Y_STR, True)
233 	&& get_widget_by_name(&text_x, parent, Xdvi_HOME_POSITION_X_OFF_TEXT, True)
234 	&& get_widget_by_name(&text_y, parent, Xdvi_HOME_POSITION_Y_OFF_TEXT, True)
235 	&& get_widget_by_name(&units_menu, parent, Xdvi_HOME_POSITION_UNITS_MENU, True)) {
236 
237 	XmToggleButtonGadgetSetState(keep, resource.keep_flag, False);
238 	XmToggleButtonGadgetSetState(unkeep, !resource.keep_flag, False);
239 
240 	XtSetSensitive(label_x, !resource.keep_flag && !resource.use_current_offset);
241 	XtSetSensitive(label_y, !resource.keep_flag && !resource.use_current_offset);
242 	XtSetSensitive(text_x, !resource.keep_flag && !resource.use_current_offset);
243 	XtSetSensitive(text_y, !resource.keep_flag && !resource.use_current_offset);
244 	XtSetSensitive(units_menu, !resource.keep_flag && !resource.use_current_offset);
245 	XtSetSensitive(toggle_home, !resource.keep_flag);
246 	XtSetSensitive(toggle_curr, !resource.keep_flag);
247     }
248 
249     store_preference(&(prefs->db), "keepPosition", "%s", resource.keep_flag ? "True" : "False");
250 
251 }
252 
253 static Widget
h_create_scrolling(Widget parent,struct topic_info * info)254 h_create_scrolling(Widget parent, struct topic_info *info)
255 {
256     Widget form, form1, form2, size_option, curr_option;
257     Widget x_off_label, x_off_text;
258     Widget y_off_label, y_off_text;
259     Widget off_units_menu, cascade, entry1, entry2, entry3;
260 
261     Widget scroll_keep, scroll_unkeep;
262 
263     char x_buf[LENGTH_OF_INT + 16];
264     char y_buf[LENGTH_OF_INT + 16];
265     int n;
266     Arg args[8];
267 
268     fprintf(stderr, "sidemargin: %s, topmargin: %s\n", resource.sidemargin, resource.topmargin);
269 
270     if (resource.sidemargin != NULL) {
271 	char *ptr;
272 	strcpy(x_buf, resource.sidemargin);
273 	ptr = x_buf;
274 	if (*ptr == '-')
275 	    ptr++;
276 	while (isdigit((int)*ptr))
277 	    ptr++;
278 	*ptr = '\0';
279     }
280     else
281 	strcpy(x_buf, "0");
282 
283     if (resource.topmargin != NULL) {
284 	char *ptr;
285 	strcpy(y_buf, resource.topmargin);
286 	ptr = y_buf;
287 	if (*ptr == '-')
288 	    ptr++;
289 	while (isdigit((int)*ptr))
290 	    ptr++;
291 	*ptr = '\0';
292     }
293     else
294 	strcpy(y_buf, "0");
295 
296     form = XmCreateForm(parent, "offsets_form", NULL, 0);
297 
298     scroll_keep = XmCreateToggleButtonGadget(form, Xdvi_SCROLL_KEEP_STR, &one_of_many, 1);
299     XtVaSetValues(scroll_keep,
300 		  XmNtopAttachment, XmATTACH_FORM,
301 		  XmNleftAttachment, XmATTACH_FORM,
302 		  NULL);
303     scroll_unkeep = XmCreateToggleButtonGadget(form, Xdvi_SCROLL_UNKEEP_STR, &one_of_many, 1);
304     XtVaSetValues(scroll_unkeep,
305 		  XmNtopAttachment, XmATTACH_WIDGET,
306 		  XmNtopWidget, scroll_keep,
307 		  XmNleftAttachment, XmATTACH_FORM,
308 		  NULL);
309 
310     XmToggleButtonGadgetSetState(scroll_keep, resource.keep_flag, False);
311     XmToggleButtonGadgetSetState(scroll_unkeep, !resource.keep_flag, False);
312 
313     XtAddCallback(scroll_keep, XmNvalueChangedCallback, keep_cb, (XtPointer)info);
314     XtAddCallback(scroll_unkeep, XmNvalueChangedCallback, keep_cb, (XtPointer)info);
315 
316     XtManageChild(scroll_keep);
317     XtManageChild(scroll_unkeep);
318 
319     form1 = XmCreateForm(form, "offsets_form1", NULL, 0);
320     XtVaSetValues(form1,
321 		  XmNtopAttachment, XmATTACH_WIDGET,
322 		  XmNtopWidget, scroll_unkeep,
323 		  XmNleftAttachment, XmATTACH_FORM,
324 		  XmNleftOffset, 20,
325 		  NULL);
326 
327     size_option = XmCreateToggleButtonGadget(form1, Xdvi_HOME_POSITION_STR, &one_of_many, 1);
328     XtVaSetValues(size_option,
329 		  XmNtopAttachment, XmATTACH_FORM,
330 		  XmNleftAttachment, XmATTACH_FORM,
331 		  XmNbottomAttachment, XmATTACH_FORM,
332 		  NULL);
333     x_off_label = XmCreateLabelGadget(form1, Xdvi_HOME_POSITION_X_STR, NULL, 0);
334     XtVaSetValues(x_off_label,
335 		  XmNtopAttachment, XmATTACH_FORM,
336 		  XmNleftAttachment, XmATTACH_WIDGET,
337 		  XmNleftWidget, size_option,
338 		  XmNbottomAttachment, XmATTACH_FORM,
339 		  NULL);
340     x_off_text = XtVaCreateManagedWidget(Xdvi_HOME_POSITION_X_OFF_TEXT,
341 					 xmTextFieldWidgetClass, form1,
342 					 XmNcolumns, 4,
343 					 XmNtopAttachment, XmATTACH_FORM,
344 					 XmNleftAttachment, XmATTACH_WIDGET,
345 					 XmNleftWidget, x_off_label,
346 					 XmNbottomAttachment, XmATTACH_FORM,
347 					 XmNvalue, x_buf,
348 					 /* 					 XmNvalue, buf, */
349 					 NULL);
350     y_off_label = XmCreateLabelGadget(form1, Xdvi_HOME_POSITION_Y_STR, NULL, 0);
351     XtVaSetValues(y_off_label,
352 		  XmNtopAttachment, XmATTACH_FORM,
353 		  XmNleftAttachment, XmATTACH_WIDGET,
354 		  XmNleftWidget, x_off_text,
355 		  XmNleftOffset, 10,
356 		  XmNbottomAttachment, XmATTACH_FORM,
357 		  NULL);
358     y_off_text = XtVaCreateManagedWidget(Xdvi_HOME_POSITION_Y_OFF_TEXT,
359 					 xmTextFieldWidgetClass, form1,
360 					 XmNcolumns, 4,
361 					 XmNtopAttachment, XmATTACH_FORM,
362 					 XmNleftAttachment, XmATTACH_WIDGET,
363 					 XmNleftWidget, y_off_label,
364 					 XmNbottomAttachment, XmATTACH_FORM,
365 					 XmNvalue, y_buf,
366 					 NULL);
367     n = 0;
368     XtSetArg(args[n], XmNuserData, (XtPointer)"in"); n++;
369     off_units_menu = XmCreatePulldownMenu(form1, Xdvi_HOME_POSITION_UNITS_PULLDOWN, args, n);
370 
371     n = 0;
372     XtSetArg(args[n], XmNsubMenuId, off_units_menu); n++;
373     XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++;
374     XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++;
375     XtSetArg(args[n], XmNleftWidget, y_off_text); n++;
376     XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
377     cascade = XmCreateOptionMenu(form1, Xdvi_HOME_POSITION_UNITS_MENU, args, n);
378     entry1 = XtVaCreateManagedWidget("in", xmPushButtonGadgetClass, off_units_menu,
379 				     NULL);
380     XtAddCallback(entry1, XmNactivateCallback, select_unit_cb, info);
381     entry2 = XtVaCreateManagedWidget("cm", xmPushButtonGadgetClass, off_units_menu,
382 				     NULL);
383     XtAddCallback(entry2, XmNactivateCallback, select_unit_cb, info);
384     entry3 = XtVaCreateManagedWidget("Pixel", xmPushButtonGadgetClass, off_units_menu,
385 				     NULL);
386     XtAddCallback(entry3, XmNactivateCallback, select_unit_cb, info);
387 
388     XtAddCallback(x_off_text, XmNvalueChangedCallback, set_offset_cb, (XtPointer)info);
389     XtAddCallback(y_off_text, XmNvalueChangedCallback, set_offset_cb, (XtPointer)info);
390 
391     XtManageChild(size_option);
392     XtManageChild(x_off_label);
393     XtManageChild(x_off_text);
394     XtManageChild(y_off_label);
395     XtManageChild(y_off_text);
396     XtManageChild(cascade);
397 
398     form2 = XmCreateForm(form, "offsets_form2", NULL, 0);
399     XtVaSetValues(form2,
400 		  XmNtopAttachment, XmATTACH_WIDGET,
401 		  XmNtopWidget, form1,
402 		  XmNleftAttachment, XmATTACH_FORM,
403 		  XmNleftOffset, 20,
404 		  NULL);
405 
406     curr_option = XmCreateToggleButtonGadget(form2, Xdvi_SCROLL_CURRENT_STR, &one_of_many, 1);
407     XtVaSetValues(curr_option,
408 		  XmNtopAttachment, XmATTACH_FORM,
409 		  XmNleftAttachment, XmATTACH_FORM,
410 		  XmNbottomAttachment, XmATTACH_FORM,
411 		  NULL);
412     XtManageChild(curr_option);
413 
414     XtSetSensitive(x_off_label, !resource.keep_flag && !resource.use_current_offset);
415     XtSetSensitive(x_off_text, !resource.keep_flag && !resource.use_current_offset);
416     XtSetSensitive(y_off_label, !resource.keep_flag && !resource.use_current_offset);
417     XtSetSensitive(y_off_text, !resource.keep_flag && !resource.use_current_offset);
418     XtSetSensitive(cascade, !resource.keep_flag && !resource.use_current_offset);
419     XtSetSensitive(size_option, !resource.keep_flag);
420     XtSetSensitive(curr_option, !resource.keep_flag);
421 
422     XmToggleButtonGadgetSetState(size_option, !resource.use_current_offset, False);
423     XmToggleButtonGadgetSetState(curr_option, resource.use_current_offset, False);
424 
425     XtAddCallback(size_option, XmNvalueChangedCallback, home_position_cb, (XtPointer)info);
426     XtAddCallback(curr_option, XmNvalueChangedCallback, home_position_cb, (XtPointer)info);
427 
428     XtManageChild(form1);
429     XtManageChild(form2);
430 
431     return form;
432 }
433 
434 Widget
prefs_scrolling(struct topic_info * info)435 prefs_scrolling(struct topic_info *info)
436 {
437     Widget form;
438     Widget scrolling_form, scrolling_frame;
439 
440     form = XtVaCreateWidget("form", xmFormWidgetClass,
441 			    info->right_form,
442 			    XmNtopAttachment, XmATTACH_FORM,
443 			    XmNleftAttachment, XmATTACH_FORM,
444 			    XmNrightAttachment, XmATTACH_FORM,
445 			    XmNbottomAttachment, XmATTACH_FORM,
446 			    NULL);
447 
448     scrolling_frame = XmCreateFrame(form, "scrolling_frame", NULL, 0);
449     h_attach_below(scrolling_frame,  NULL);
450 
451     scrolling_form = h_create_scrolling(scrolling_frame, info);
452     XtVaSetValues(scrolling_form,
453 		  XmNtopAttachment, XmATTACH_WIDGET,
454 		  XmNtopWidget, scrolling_frame,
455 		  XmNleftAttachment, XmATTACH_FORM,
456 		  XmNrightAttachment, XmATTACH_FORM,
457 		  XmNbottomAttachment, XmATTACH_FORM,
458 		  NULL);
459 
460     XtManageChild(scrolling_form);
461     XtManageChild(scrolling_frame);
462 
463     return form;
464 }
465 
466 #else
467 /* silence `empty compilation unit' warnings */
bar(void)468 static void bar(void); static void foo(void) { bar(); } static void bar(void) { foo(); }
469 #endif /* MOTIF */
470 
471