blob: 5cce4c5ef2263ad5cedc60e53d68e235e3aa2cf5 [file] [log] [blame]
cristy3ed852e2009-09-05 21:47:34 +00001/*
2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3% %
4% %
5% %
6% %
7% W W IIIII DDDD GGGG EEEEE TTTTT %
8% W W I D D G E T %
9% W W W I D D G GG EEE T %
10% WW WW I D D G G E T %
11% W W IIIII DDDD GGGG EEEEE T %
12% %
13% %
14% MagickCore X11 User Interface Methods %
15% %
16% Software Design %
17% John Cristy %
18% September 1993 %
19% %
20% %
cristy7e41fe82010-12-04 23:12:08 +000021% Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization %
cristy3ed852e2009-09-05 21:47:34 +000022% dedicated to making software imaging solutions freely available. %
23% %
24% You may not use this file except in compliance with the License. You may %
25% obtain a copy of the License at %
26% %
27% http://www.imagemagick.org/script/license.php %
28% %
29% Unless required by applicable law or agreed to in writing, software %
30% distributed under the License is distributed on an "AS IS" BASIS, %
31% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %
32% See the License for the specific language governing permissions and %
33% limitations under the License. %
34% %
35%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
36%
37%
38*/
39
40/*
41 Include declarations.
42*/
43#include "magick/studio.h"
44#include "magick/color.h"
45#include "magick/color-private.h"
46#include "magick/exception.h"
47#include "magick/exception-private.h"
48#include "magick/image.h"
49#include "magick/magick.h"
50#include "magick/memory_.h"
51#include "magick/PreRvIcccm.h"
52#include "magick/string_.h"
53#include "magick/token.h"
54#include "magick/utility.h"
55#include "magick/xwindow-private.h"
56#include "magick/widget.h"
57
58#if defined(MAGICKCORE_X11_DELEGATE)
59
60/*
61 Define declarations.
62*/
63#define AreaIsActive(matte_info,position) ( \
64 ((position.y >= (int) (matte_info.y-matte_info.bevel_width)) && \
65 (position.y < (int) (matte_info.y+matte_info.height+matte_info.bevel_width))) \
66 ? MagickTrue : MagickFalse)
67#define Extent(s) ((int) strlen(s))
68#define MatteIsActive(matte_info,position) ( \
69 ((position.x >= (int) (matte_info.x-matte_info.bevel_width)) && \
70 (position.y >= (int) (matte_info.y-matte_info.bevel_width)) && \
71 (position.x < (int) (matte_info.x+matte_info.width+matte_info.bevel_width)) && \
72 (position.y < (int) (matte_info.y+matte_info.height+matte_info.bevel_width))) \
73 ? MagickTrue : MagickFalse)
74#define MaxTextWidth ((unsigned int) (255*XTextWidth(font_info,"_",1)))
75#define MinTextWidth (26*XTextWidth(font_info,"_",1))
76#define QuantumMargin MagickMax(font_info->max_bounds.width,12)
77#define WidgetTextWidth(font_info,text) \
78 ((unsigned int) XTextWidth(font_info,text,Extent(text)))
79#define WindowIsActive(window_info,position) ( \
80 ((position.x >= 0) && (position.y >= 0) && \
81 (position.x < (int) window_info.width) && \
82 (position.y < (int) window_info.height)) ? MagickTrue : MagickFalse)
83
84/*
85 Enum declarations.
86*/
87typedef enum
88{
89 ControlState = 0x0001,
90 InactiveWidgetState = 0x0004,
91 JumpListState = 0x0008,
92 RedrawActionState = 0x0010,
93 RedrawListState = 0x0020,
94 RedrawWidgetState = 0x0040,
95 UpdateListState = 0x0100
96} WidgetState;
97
98/*
99 Typedef declarations.
100*/
101typedef struct _XWidgetInfo
102{
103 char
104 *cursor,
105 *text,
106 *marker;
107
108 int
109 id;
110
111 unsigned int
112 bevel_width,
113 width,
114 height;
115
116 int
117 x,
118 y,
119 min_y,
120 max_y;
121
122 MagickStatusType
123 raised,
124 active,
125 center,
126 trough,
127 highlight;
128} XWidgetInfo;
129
130/*
131 Variable declarations.
132*/
133static XWidgetInfo
134 monitor_info =
135 {
136 (char *) NULL, (char *) NULL, (char *) NULL, 0, 0, 0, 0, 0, 0, 0, 0,
137 MagickFalse, MagickFalse, MagickFalse, MagickFalse, MagickFalse
138 },
139 submenu_info =
140 {
141 (char *) NULL, (char *) NULL, (char *) NULL, 0, 0, 0, 0, 0, 0, 0, 0,
142 MagickFalse, MagickFalse, MagickFalse, MagickFalse, MagickFalse
143 },
144 *selection_info = (XWidgetInfo *) NULL,
145 toggle_info =
146 {
147 (char *) NULL, (char *) NULL, (char *) NULL, 0, 0, 0, 0, 0, 0, 0, 0,
148 MagickFalse, MagickFalse, MagickFalse, MagickFalse, MagickFalse
149 };
150
151/*
152 Constant declarations.
153*/
154static const int
155 BorderOffset = 4,
156 DoubleClick = 250;
157
158/*
159 Method prototypes.
160*/
161static void
162 XDrawMatte(Display *,const XWindowInfo *,const XWidgetInfo *),
163 XSetBevelColor(Display *,const XWindowInfo *,const MagickStatusType),
164 XSetMatteColor(Display *,const XWindowInfo *,const MagickStatusType),
165 XSetTextColor(Display *,const XWindowInfo *,const MagickStatusType);
166
167/*
168%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
169% %
170% %
171% %
172% D e s t r o y X W i d g e t %
173% %
174% %
175% %
176%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
177%
178% DestroyXWidget() destroys resources associated with the X widget.
179%
180% The format of the DestroyXWidget method is:
181%
182% void DestroyXWidget()
183%
184% A description of each parameter follows:
185%
186*/
187MagickExport void DestroyXWidget(void)
188{
189 if (selection_info != (XWidgetInfo *) NULL)
190 selection_info=(XWidgetInfo *) RelinquishMagickMemory(selection_info);
191}
192
193/*
194%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
195% %
196% %
197% %
198+ X D r a w B e v e l %
199% %
200% %
201% %
202%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
203%
204% XDrawBevel() "sets off" an area with a highlighted upper and left bevel and
205% a shadowed lower and right bevel. The highlighted and shadowed bevels
206% create a 3-D effect.
207%
208% The format of the XDrawBevel function is:
209%
210% XDrawBevel(display,window_info,bevel_info)
211%
212% A description of each parameter follows:
213%
214% o display: Specifies a pointer to the Display structure; returned from
215% XOpenDisplay.
216%
217% o window_info: Specifies a pointer to a X11 XWindowInfo structure.
218%
219% o bevel_info: Specifies a pointer to a XWidgetInfo structure. It
220% contains the extents of the bevel.
221%
222*/
223static void XDrawBevel(Display *display,const XWindowInfo *window_info,
224 const XWidgetInfo *bevel_info)
225{
226 int
227 x1,
228 x2,
229 y1,
230 y2;
231
232 unsigned int
233 bevel_width;
234
235 XPoint
236 points[6];
237
238 /*
239 Draw upper and left beveled border.
240 */
241 x1=bevel_info->x;
242 y1=bevel_info->y+bevel_info->height;
243 x2=bevel_info->x+bevel_info->width;
244 y2=bevel_info->y;
245 bevel_width=bevel_info->bevel_width;
246 points[0].x=x1;
247 points[0].y=y1;
248 points[1].x=x1;
249 points[1].y=y2;
250 points[2].x=x2;
251 points[2].y=y2;
252 points[3].x=x2+bevel_width;
253 points[3].y=y2-bevel_width;
254 points[4].x=x1-bevel_width;
255 points[4].y=y2-bevel_width;
256 points[5].x=x1-bevel_width;
257 points[5].y=y1+bevel_width;
258 XSetBevelColor(display,window_info,bevel_info->raised);
259 (void) XFillPolygon(display,window_info->id,window_info->widget_context,
260 points,6,Complex,CoordModeOrigin);
261 /*
262 Draw lower and right beveled border.
263 */
264 points[0].x=x1;
265 points[0].y=y1;
266 points[1].x=x2;
267 points[1].y=y1;
268 points[2].x=x2;
269 points[2].y=y2;
270 points[3].x=x2+bevel_width;
271 points[3].y=y2-bevel_width;
272 points[4].x=x2+bevel_width;
273 points[4].y=y1+bevel_width;
274 points[5].x=x1-bevel_width;
275 points[5].y=y1+bevel_width;
276 XSetBevelColor(display,window_info,!bevel_info->raised);
277 (void) XFillPolygon(display,window_info->id,window_info->widget_context,
278 points,6,Complex,CoordModeOrigin);
279 (void) XSetFillStyle(display,window_info->widget_context,FillSolid);
280}
281
282/*
283%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
284% %
285% %
286% %
287+ X D r a w B e v e l e d B u t t o n %
288% %
289% %
290% %
291%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
292%
293% XDrawBeveledButton() draws a button with a highlighted upper and left bevel
294% and a shadowed lower and right bevel. The highlighted and shadowed bevels
295% create a 3-D effect.
296%
297% The format of the XDrawBeveledButton function is:
298%
299% XDrawBeveledButton(display,window_info,button_info)
300%
301% A description of each parameter follows:
302%
303% o display: Specifies a pointer to the Display structure; returned from
304% XOpenDisplay.
305%
306% o window_info: Specifies a pointer to a X11 XWindowInfo structure.
307%
308% o button_info: Specifies a pointer to a XWidgetInfo structure. It
309% contains the extents of the button.
310%
311*/
312
313static inline int MagickAbsoluteValue(const int x)
314{
315 if (x < 0)
316 return(-x);
317 return(x);
318}
319
320static inline int MagickMax(const int x,const int y)
321{
322 if (x > y)
323 return(x);
324 return(y);
325}
326
327static inline int MagickMin(const int x,const int y)
328{
329 if (x < y)
330 return(x);
331 return(y);
332}
333
334static void XDrawBeveledButton(Display *display,const XWindowInfo *window_info,
335 const XWidgetInfo *button_info)
336{
337 int
338 x,
339 y;
340
341 unsigned int
342 width;
343
344 XFontStruct
345 *font_info;
346
347 XRectangle
348 crop_info;
349
350 /*
351 Draw matte.
352 */
353 XDrawBevel(display,window_info,button_info);
354 XSetMatteColor(display,window_info,button_info->raised);
355 (void) XFillRectangle(display,window_info->id,window_info->widget_context,
356 button_info->x,button_info->y,button_info->width,button_info->height);
357 x=button_info->x-button_info->bevel_width-1;
358 y=button_info->y-button_info->bevel_width-1;
359 (void) XSetForeground(display,window_info->widget_context,
360 window_info->pixel_info->trough_color.pixel);
361 if (button_info->raised || (window_info->depth == 1))
362 (void) XDrawRectangle(display,window_info->id,window_info->widget_context,
363 x,y,button_info->width+(button_info->bevel_width << 1)+1,
364 button_info->height+(button_info->bevel_width << 1)+1);
365 if (button_info->text == (char *) NULL)
366 return;
367 /*
368 Set cropping region.
369 */
370 crop_info.width=(unsigned short) button_info->width;
371 crop_info.height=(unsigned short) button_info->height;
372 crop_info.x=button_info->x;
373 crop_info.y=button_info->y;
374 /*
375 Draw text.
376 */
377 font_info=window_info->font_info;
378 width=WidgetTextWidth(font_info,button_info->text);
379 x=button_info->x+(QuantumMargin >> 1);
380 if (button_info->center)
381 x=button_info->x+(button_info->width >> 1)-(width >> 1);
382 y=button_info->y+((button_info->height-
383 (font_info->ascent+font_info->descent)) >> 1)+font_info->ascent;
384 if ((int) button_info->width == (QuantumMargin >> 1))
385 {
386 /*
387 Option button-- write label to right of button.
388 */
389 XSetTextColor(display,window_info,MagickTrue);
390 x=button_info->x+button_info->width+button_info->bevel_width+
391 (QuantumMargin >> 1);
392 (void) XDrawString(display,window_info->id,window_info->widget_context,
393 x,y,button_info->text,Extent(button_info->text));
394 return;
395 }
396 (void) XSetClipRectangles(display,window_info->widget_context,0,0,&crop_info,
397 1,Unsorted);
398 XSetTextColor(display,window_info,button_info->raised);
399 (void) XDrawString(display,window_info->id,window_info->widget_context,x,y,
400 button_info->text,Extent(button_info->text));
401 (void) XSetClipMask(display,window_info->widget_context,None);
402 if (button_info->raised == MagickFalse)
403 XDelay(display,SuspendTime << 2);
404}
405
406/*
407%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
408% %
409% %
410% %
411+ X D r a w B e v e l e d M a t t e %
412% %
413% %
414% %
415%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
416%
417% XDrawBeveledMatte() draws a matte with a shadowed upper and left bevel and
418% a highlighted lower and right bevel. The highlighted and shadowed bevels
419% create a 3-D effect.
420%
421% The format of the XDrawBeveledMatte function is:
422%
423% XDrawBeveledMatte(display,window_info,matte_info)
424%
425% A description of each parameter follows:
426%
427% o display: Specifies a pointer to the Display structure; returned from
428% XOpenDisplay.
429%
430% o window_info: Specifies a pointer to a X11 XWindowInfo structure.
431%
432% o matte_info: Specifies a pointer to a XWidgetInfo structure. It
433% contains the extents of the matte.
434%
435*/
436static void XDrawBeveledMatte(Display *display,const XWindowInfo *window_info,
437 const XWidgetInfo *matte_info)
438{
439 /*
440 Draw matte.
441 */
442 XDrawBevel(display,window_info,matte_info);
443 XDrawMatte(display,window_info,matte_info);
444}
445
446/*
447%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
448% %
449% %
450% %
451+ X D r a w M a t t e %
452% %
453% %
454% %
455%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
456%
457% XDrawMatte() fills a rectangular area with the matte color.
458%
459% The format of the XDrawMatte function is:
460%
461% XDrawMatte(display,window_info,matte_info)
462%
463% A description of each parameter follows:
464%
465% o display: Specifies a pointer to the Display structure; returned from
466% XOpenDisplay.
467%
468% o window_info: Specifies a pointer to a X11 XWindowInfo structure.
469%
470% o matte_info: Specifies a pointer to a XWidgetInfo structure. It
471% contains the extents of the matte.
472%
473*/
474static void XDrawMatte(Display *display,const XWindowInfo *window_info,
475 const XWidgetInfo *matte_info)
476{
477 /*
478 Draw matte.
479 */
480 if ((matte_info->trough == MagickFalse) || (window_info->depth == 1))
481 (void) XFillRectangle(display,window_info->id,
482 window_info->highlight_context,matte_info->x,matte_info->y,
483 matte_info->width,matte_info->height);
484 else
485 {
486 (void) XSetForeground(display,window_info->widget_context,
487 window_info->pixel_info->trough_color.pixel);
488 (void) XFillRectangle(display,window_info->id,window_info->widget_context,
489 matte_info->x,matte_info->y,matte_info->width,matte_info->height);
490 }
491}
492
493/*
494%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
495% %
496% %
497% %
498+ X D r a w M a t t e T e x t %
499% %
500% %
501% %
502%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
503%
504% XDrawMatteText() draws a matte with text. If the text exceeds the extents
505% of the text, a portion of the text relative to the cursor is displayed.
506%
507% The format of the XDrawMatteText function is:
508%
509% XDrawMatteText(display,window_info,text_info)
510%
511% A description of each parameter follows:
512%
513% o display: Specifies a pointer to the Display structure; returned from
514% XOpenDisplay.
515%
516% o window_info: Specifies a pointer to a X11 XWindowInfo structure.
517%
518% o text_info: Specifies a pointer to a XWidgetInfo structure. It
519% contains the extents of the text.
520%
521*/
522static void XDrawMatteText(Display *display,const XWindowInfo *window_info,
523 XWidgetInfo *text_info)
524{
525 const char
526 *text;
527
528 int
529 n,
530 x,
531 y;
532
533 register int
534 i;
535
536 unsigned int
537 height,
538 width;
539
540 XFontStruct
541 *font_info;
542
543 XRectangle
544 crop_info;
545
546 /*
547 Clear the text area.
548 */
549 XSetMatteColor(display,window_info,MagickFalse);
550 (void) XFillRectangle(display,window_info->id,window_info->widget_context,
551 text_info->x,text_info->y,text_info->width,text_info->height);
552 if (text_info->text == (char *) NULL)
553 return;
554 XSetTextColor(display,window_info,text_info->highlight);
555 font_info=window_info->font_info;
556 x=text_info->x+(QuantumMargin >> 2);
557 y=text_info->y+font_info->ascent+(text_info->height >> 2);
558 width=text_info->width-(QuantumMargin >> 1);
559 height=(unsigned int) (font_info->ascent+font_info->descent);
560 if (*text_info->text == '\0')
561 {
562 /*
563 No text-- just draw cursor.
564 */
565 (void) XDrawLine(display,window_info->id,window_info->annotate_context,
566 x,y+3,x,y-height+3);
567 return;
568 }
569 /*
570 Set cropping region.
571 */
572 crop_info.width=(unsigned short) text_info->width;
573 crop_info.height=(unsigned short) text_info->height;
574 crop_info.x=text_info->x;
575 crop_info.y=text_info->y;
576 /*
577 Determine beginning of the visible text.
578 */
579 if (text_info->cursor < text_info->marker)
580 text_info->marker=text_info->cursor;
581 else
582 {
583 text=text_info->marker;
584 if (XTextWidth(font_info,(char *) text,(int) (text_info->cursor-text)) >
585 (int) width)
586 {
587 text=text_info->text;
588 for (i=0; i < Extent(text); i++)
589 {
590 n=XTextWidth(font_info,(char *) text+i,(int)
591 (text_info->cursor-text-i));
592 if (n <= (int) width)
593 break;
594 }
595 text_info->marker=(char *) text+i;
596 }
597 }
598 /*
599 Draw text and cursor.
600 */
601 if (text_info->highlight == MagickFalse)
602 {
603 (void) XSetClipRectangles(display,window_info->widget_context,0,0,
604 &crop_info,1,Unsorted);
605 (void) XDrawString(display,window_info->id,window_info->widget_context,
606 x,y,text_info->marker,Extent(text_info->marker));
607 (void) XSetClipMask(display,window_info->widget_context,None);
608 }
609 else
610 {
611 (void) XSetClipRectangles(display,window_info->annotate_context,0,0,
612 &crop_info,1,Unsorted);
613 width=WidgetTextWidth(font_info,text_info->marker);
614 (void) XFillRectangle(display,window_info->id,
615 window_info->annotate_context,x,y-font_info->ascent,width,height);
616 (void) XSetClipMask(display,window_info->annotate_context,None);
617 (void) XSetClipRectangles(display,window_info->highlight_context,0,0,
618 &crop_info,1,Unsorted);
619 (void) XDrawString(display,window_info->id,
620 window_info->highlight_context,x,y,text_info->marker,
621 Extent(text_info->marker));
622 (void) XSetClipMask(display,window_info->highlight_context,None);
623 }
624 x+=XTextWidth(font_info,text_info->marker,(int)
625 (text_info->cursor-text_info->marker));
626 (void) XDrawLine(display,window_info->id,window_info->annotate_context,x,y+3,
627 x,y-height+3);
628}
629
630/*
631%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
632% %
633% %
634% %
635+ X D r a w T r i a n g l e E a s t %
636% %
637% %
638% %
639%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
640%
641% XDrawTriangleEast() draws a triangle with a highlighted left bevel and a
642% shadowed right and lower bevel. The highlighted and shadowed bevels create
643% a 3-D effect.
644%
645% The format of the XDrawTriangleEast function is:
646%
647% XDrawTriangleEast(display,window_info,triangle_info)
648%
649% A description of each parameter follows:
650%
651% o display: Specifies a pointer to the Display structure; returned from
652% XOpenDisplay.
653%
654% o window_info: Specifies a pointer to a X11 XWindowInfo structure.
655%
656% o triangle_info: Specifies a pointer to a XWidgetInfo structure. It
657% contains the extents of the triangle.
658%
659*/
660static void XDrawTriangleEast(Display *display,const XWindowInfo *window_info,
661 const XWidgetInfo *triangle_info)
662{
663 int
664 x1,
665 x2,
666 x3,
667 y1,
668 y2,
669 y3;
670
671 unsigned int
672 bevel_width;
673
674 XFontStruct
675 *font_info;
676
677 XPoint
678 points[4];
679
680 /*
681 Draw triangle matte.
682 */
683 x1=triangle_info->x;
684 y1=triangle_info->y;
685 x2=triangle_info->x+triangle_info->width;
686 y2=triangle_info->y+(triangle_info->height >> 1);
687 x3=triangle_info->x;
688 y3=triangle_info->y+triangle_info->height;
689 bevel_width=triangle_info->bevel_width;
690 points[0].x=x1;
691 points[0].y=y1;
692 points[1].x=x2;
693 points[1].y=y2;
694 points[2].x=x3;
695 points[2].y=y3;
696 XSetMatteColor(display,window_info,triangle_info->raised);
697 (void) XFillPolygon(display,window_info->id,window_info->widget_context,
698 points,3,Complex,CoordModeOrigin);
699 /*
700 Draw bottom bevel.
701 */
702 points[0].x=x2;
703 points[0].y=y2;
704 points[1].x=x3;
705 points[1].y=y3;
706 points[2].x=x3-bevel_width;
707 points[2].y=y3+bevel_width;
708 points[3].x=x2+bevel_width;
709 points[3].y=y2;
710 XSetBevelColor(display,window_info,!triangle_info->raised);
711 (void) XFillPolygon(display,window_info->id,window_info->widget_context,
712 points,4,Complex,CoordModeOrigin);
713 /*
714 Draw Left bevel.
715 */
716 points[0].x=x3;
717 points[0].y=y3;
718 points[1].x=x1;
719 points[1].y=y1;
720 points[2].x=x1-bevel_width+1;
721 points[2].y=y1-bevel_width;
722 points[3].x=x3-bevel_width+1;
723 points[3].y=y3+bevel_width;
724 XSetBevelColor(display,window_info,triangle_info->raised);
725 (void) XFillPolygon(display,window_info->id,window_info->widget_context,
726 points,4,Complex,CoordModeOrigin);
727 /*
728 Draw top bevel.
729 */
730 points[0].x=x1;
731 points[0].y=y1;
732 points[1].x=x2;
733 points[1].y=y2;
734 points[2].x=x2+bevel_width;
735 points[2].y=y2;
736 points[3].x=x1-bevel_width;
737 points[3].y=y1-bevel_width;
738 (void) XFillPolygon(display,window_info->id,window_info->widget_context,
739 points,4,Complex,CoordModeOrigin);
740 (void) XSetFillStyle(display,window_info->widget_context,FillSolid);
741 if (triangle_info->text == (char *) NULL)
742 return;
743 /*
744 Write label to right of triangle.
745 */
746 font_info=window_info->font_info;
747 XSetTextColor(display,window_info,MagickTrue);
748 x1=triangle_info->x+triangle_info->width+triangle_info->bevel_width+
749 (QuantumMargin >> 1);
750 y1=triangle_info->y+((triangle_info->height-
751 (font_info->ascent+font_info->descent)) >> 1)+font_info->ascent;
752 (void) XDrawString(display,window_info->id,window_info->widget_context,x1,y1,
753 triangle_info->text,Extent(triangle_info->text));
754}
755
756/*
757%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
758% %
759% %
760% %
761+ X D r a w T r i a n g l e N o r t h %
762% %
763% %
764% %
765%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
766%
767% XDrawTriangleNorth() draws a triangle with a highlighted left bevel and a
768% shadowed right and lower bevel. The highlighted and shadowed bevels create
769% a 3-D effect.
770%
771% The format of the XDrawTriangleNorth function is:
772%
773% XDrawTriangleNorth(display,window_info,triangle_info)
774%
775% A description of each parameter follows:
776%
777% o display: Specifies a pointer to the Display structure; returned from
778% XOpenDisplay.
779%
780% o window_info: Specifies a pointer to a X11 XWindowInfo structure.
781%
782% o triangle_info: Specifies a pointer to a XWidgetInfo structure. It
783% contains the extents of the triangle.
784%
785*/
786static void XDrawTriangleNorth(Display *display,const XWindowInfo *window_info,
787 const XWidgetInfo *triangle_info)
788{
789 int
790 x1,
791 x2,
792 x3,
793 y1,
794 y2,
795 y3;
796
797 unsigned int
798 bevel_width;
799
800 XPoint
801 points[4];
802
803 /*
804 Draw triangle matte.
805 */
806 x1=triangle_info->x;
807 y1=triangle_info->y+triangle_info->height;
808 x2=triangle_info->x+(triangle_info->width >> 1);
809 y2=triangle_info->y;
810 x3=triangle_info->x+triangle_info->width;
811 y3=triangle_info->y+triangle_info->height;
812 bevel_width=triangle_info->bevel_width;
813 points[0].x=x1;
814 points[0].y=y1;
815 points[1].x=x2;
816 points[1].y=y2;
817 points[2].x=x3;
818 points[2].y=y3;
819 XSetMatteColor(display,window_info,triangle_info->raised);
820 (void) XFillPolygon(display,window_info->id,window_info->widget_context,
821 points,3,Complex,CoordModeOrigin);
822 /*
823 Draw left bevel.
824 */
825 points[0].x=x1;
826 points[0].y=y1;
827 points[1].x=x2;
828 points[1].y=y2;
829 points[2].x=x2;
830 points[2].y=y2-bevel_width-2;
831 points[3].x=x1-bevel_width-1;
832 points[3].y=y1+bevel_width;
833 XSetBevelColor(display,window_info,triangle_info->raised);
834 (void) XFillPolygon(display,window_info->id,window_info->widget_context,
835 points,4,Complex,CoordModeOrigin);
836 /*
837 Draw right bevel.
838 */
839 points[0].x=x2;
840 points[0].y=y2;
841 points[1].x=x3;
842 points[1].y=y3;
843 points[2].x=x3+bevel_width;
844 points[2].y=y3+bevel_width;
845 points[3].x=x2;
846 points[3].y=y2-bevel_width;
847 XSetBevelColor(display,window_info,!triangle_info->raised);
848 (void) XFillPolygon(display,window_info->id,window_info->widget_context,
849 points,4,Complex,CoordModeOrigin);
850 /*
851 Draw lower bevel.
852 */
853 points[0].x=x3;
854 points[0].y=y3;
855 points[1].x=x1;
856 points[1].y=y1;
857 points[2].x=x1-bevel_width;
858 points[2].y=y1+bevel_width;
859 points[3].x=x3+bevel_width;
860 points[3].y=y3+bevel_width;
861 (void) XFillPolygon(display,window_info->id,window_info->widget_context,
862 points,4,Complex,CoordModeOrigin);
863 (void) XSetFillStyle(display,window_info->widget_context,FillSolid);
864}
865
866/*
867%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
868% %
869% %
870% %
871+ X D r a w T r i a n g l e S o u t h %
872% %
873% %
874% %
875%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
876%
877% XDrawTriangleSouth() draws a border with a highlighted left and right bevel
878% and a shadowed lower bevel. The highlighted and shadowed bevels create a
879% 3-D effect.
880%
881% The format of the XDrawTriangleSouth function is:
882%
883% XDrawTriangleSouth(display,window_info,triangle_info)
884%
885% A description of each parameter follows:
886%
887% o display: Specifies a pointer to the Display structure; returned from
888% XOpenDisplay.
889%
890% o window_info: Specifies a pointer to a X11 XWindowInfo structure.
891%
892% o triangle_info: Specifies a pointer to a XWidgetInfo structure. It
893% contains the extents of the triangle.
894%
895*/
896static void XDrawTriangleSouth(Display *display,const XWindowInfo *window_info,
897 const XWidgetInfo *triangle_info)
898{
899 int
900 x1,
901 x2,
902 x3,
903 y1,
904 y2,
905 y3;
906
907 unsigned int
908 bevel_width;
909
910 XPoint
911 points[4];
912
913 /*
914 Draw triangle matte.
915 */
916 x1=triangle_info->x;
917 y1=triangle_info->y;
918 x2=triangle_info->x+(triangle_info->width >> 1);
919 y2=triangle_info->y+triangle_info->height;
920 x3=triangle_info->x+triangle_info->width;
921 y3=triangle_info->y;
922 bevel_width=triangle_info->bevel_width;
923 points[0].x=x1;
924 points[0].y=y1;
925 points[1].x=x2;
926 points[1].y=y2;
927 points[2].x=x3;
928 points[2].y=y3;
929 XSetMatteColor(display,window_info,triangle_info->raised);
930 (void) XFillPolygon(display,window_info->id,window_info->widget_context,
931 points,3,Complex,CoordModeOrigin);
932 /*
933 Draw top bevel.
934 */
935 points[0].x=x3;
936 points[0].y=y3;
937 points[1].x=x1;
938 points[1].y=y1;
939 points[2].x=x1-bevel_width;
940 points[2].y=y1-bevel_width;
941 points[3].x=x3+bevel_width;
942 points[3].y=y3-bevel_width;
943 XSetBevelColor(display,window_info,triangle_info->raised);
944 (void) XFillPolygon(display,window_info->id,window_info->widget_context,
945 points,4,Complex,CoordModeOrigin);
946 /*
947 Draw right bevel.
948 */
949 points[0].x=x2;
950 points[0].y=y2;
951 points[1].x=x3+1;
952 points[1].y=y3-bevel_width;
953 points[2].x=x3+bevel_width;
954 points[2].y=y3-bevel_width;
955 points[3].x=x2;
956 points[3].y=y2+bevel_width;
957 XSetBevelColor(display,window_info,!triangle_info->raised);
958 (void) XFillPolygon(display,window_info->id,window_info->widget_context,
959 points,4,Complex,CoordModeOrigin);
960 /*
961 Draw left bevel.
962 */
963 points[0].x=x1;
964 points[0].y=y1;
965 points[1].x=x2;
966 points[1].y=y2;
967 points[2].x=x2;
968 points[2].y=y2+bevel_width;
969 points[3].x=x1-bevel_width;
970 points[3].y=y1-bevel_width;
971 XSetBevelColor(display,window_info,triangle_info->raised);
972 (void) XFillPolygon(display,window_info->id,window_info->widget_context,
973 points,4,Complex,CoordModeOrigin);
974 (void) XSetFillStyle(display,window_info->widget_context,FillSolid);
975}
976
977/*
978%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
979% %
980% %
981% %
982+ X D r a w W i d g e t T e x t %
983% %
984% %
985% %
986%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
987%
988% XDrawWidgetText() first clears the widget and draws a text string justifed
989% left (or center) in the x-direction and centered within the y-direction.
990%
991% The format of the XDrawWidgetText function is:
992%
993% XDrawWidgetText(display,window_info,text_info)
994%
995% A description of each parameter follows:
996%
997% o display: Specifies a pointer to the Display structure; returned from
998% XOpenDisplay.
999%
1000% o window_info: Specifies a pointer to a XWindowText structure.
1001%
1002% o text_info: Specifies a pointer to XWidgetInfo structure.
1003%
1004*/
1005static void XDrawWidgetText(Display *display,const XWindowInfo *window_info,
1006 XWidgetInfo *text_info)
1007{
1008 GC
1009 widget_context;
1010
1011 int
1012 x,
1013 y;
1014
1015 unsigned int
1016 height,
1017 width;
1018
1019 XFontStruct
1020 *font_info;
1021
1022 XRectangle
1023 crop_info;
1024
1025 /*
1026 Clear the text area.
1027 */
1028 widget_context=window_info->annotate_context;
1029 if (text_info->raised)
1030 (void) XClearArea(display,window_info->id,text_info->x,text_info->y,
1031 text_info->width,text_info->height,MagickFalse);
1032 else
1033 {
1034 (void) XFillRectangle(display,window_info->id,widget_context,text_info->x,
1035 text_info->y,text_info->width,text_info->height);
1036 widget_context=window_info->highlight_context;
1037 }
1038 if (text_info->text == (char *) NULL)
1039 return;
1040 if (*text_info->text == '\0')
1041 return;
1042 /*
1043 Set cropping region.
1044 */
1045 font_info=window_info->font_info;
1046 crop_info.width=(unsigned short) text_info->width;
1047 crop_info.height=(unsigned short) text_info->height;
1048 crop_info.x=text_info->x;
1049 crop_info.y=text_info->y;
1050 /*
1051 Draw text.
1052 */
1053 width=WidgetTextWidth(font_info,text_info->text);
1054 x=text_info->x+(QuantumMargin >> 1);
1055 if (text_info->center)
1056 x=text_info->x+(text_info->width >> 1)-(width >> 1);
1057 if (text_info->raised)
1058 if (width > (text_info->width-QuantumMargin))
1059 x+=(text_info->width-QuantumMargin-width);
1060 height=(unsigned int) (font_info->ascent+font_info->descent);
1061 y=text_info->y+((text_info->height-height) >> 1)+font_info->ascent;
1062 (void) XSetClipRectangles(display,widget_context,0,0,&crop_info,1,Unsorted);
1063 (void) XDrawString(display,window_info->id,widget_context,x,y,text_info->text,
1064 Extent(text_info->text));
1065 (void) XSetClipMask(display,widget_context,None);
1066 if (x < text_info->x)
1067 (void) XDrawLine(display,window_info->id,window_info->annotate_context,
1068 text_info->x,text_info->y,text_info->x,text_info->y+text_info->height-1);
1069}
1070
1071/*
1072%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1073% %
1074% %
1075% %
1076+ X E d i t T e x t %
1077% %
1078% %
1079% %
1080%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1081%
1082% XEditText() edits a text string as indicated by the key symbol.
1083%
1084% The format of the XEditText function is:
1085%
1086% XEditText(display,text_info,key_symbol,text,state)
1087%
1088% A description of each parameter follows:
1089%
1090% o display: Specifies a connection to an X server; returned from
1091% XOpenDisplay.
1092%
1093% o text_info: Specifies a pointer to a XWidgetInfo structure. It
1094% contains the extents of the text.
1095%
1096% o key_symbol: A X11 KeySym that indicates what editing function to
1097% perform to the text.
1098%
1099% o text: A character string to insert into the text.
1100%
cristybb503372010-05-27 20:51:26 +00001101% o state: An size_t that indicates whether the key symbol is a
cristy3ed852e2009-09-05 21:47:34 +00001102% control character or not.
1103%
1104*/
1105static void XEditText(Display *display,XWidgetInfo *text_info,
cristybb503372010-05-27 20:51:26 +00001106 const KeySym key_symbol,char *text,const size_t state)
cristy3ed852e2009-09-05 21:47:34 +00001107{
1108 switch ((int) key_symbol)
1109 {
1110 case XK_BackSpace:
1111 case XK_Delete:
1112 {
1113 if (text_info->highlight)
1114 {
1115 /*
1116 Erase the entire line of text.
1117 */
1118 *text_info->text='\0';
1119 text_info->cursor=text_info->text;
1120 text_info->marker=text_info->text;
1121 text_info->highlight=MagickFalse;
1122 }
1123 /*
1124 Erase one character.
1125 */
1126 if (text_info->cursor != text_info->text)
1127 {
1128 text_info->cursor--;
1129 (void) CopyMagickString(text_info->cursor,text_info->cursor+1,
1130 MaxTextExtent);
1131 text_info->highlight=MagickFalse;
1132 break;
1133 }
1134 }
1135 case XK_Left:
1136 case XK_KP_Left:
1137 {
1138 /*
1139 Move cursor one position left.
1140 */
1141 if (text_info->cursor == text_info->text)
1142 break;
1143 text_info->cursor--;
1144 break;
1145 }
1146 case XK_Right:
1147 case XK_KP_Right:
1148 {
1149 /*
1150 Move cursor one position right.
1151 */
1152 if (text_info->cursor == (text_info->text+Extent(text_info->text)))
1153 break;
1154 text_info->cursor++;
1155 break;
1156 }
1157 default:
1158 {
1159 register char
1160 *p,
1161 *q;
1162
1163 register int
1164 i;
1165
1166 if (state & ControlState)
1167 break;
1168 if (*text == '\0')
1169 break;
cristy49e2d862010-11-12 02:50:30 +00001170 if ((Extent(text_info->text)+1) >= (int) MaxTextExtent)
cristy3ed852e2009-09-05 21:47:34 +00001171 (void) XBell(display,0);
1172 else
1173 {
1174 if (text_info->highlight)
1175 {
1176 /*
1177 Erase the entire line of text.
1178 */
1179 *text_info->text='\0';
1180 text_info->cursor=text_info->text;
1181 text_info->marker=text_info->text;
1182 text_info->highlight=MagickFalse;
1183 }
1184 /*
1185 Insert a string into the text.
1186 */
1187 q=text_info->text+Extent(text_info->text)+strlen(text);
1188 for (i=0; i <= Extent(text_info->cursor); i++)
1189 {
1190 *q=(*(q-Extent(text)));
1191 q--;
1192 }
1193 p=text;
1194 for (i=0; i < Extent(text); i++)
1195 *text_info->cursor++=(*p++);
1196 }
1197 break;
1198 }
1199 }
1200}
1201
1202/*
1203%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1204% %
1205% %
1206% %
1207+ X G e t W i d g e t I n f o %
1208% %
1209% %
1210% %
1211%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1212%
1213% XGetWidgetInfo() initializes the XWidgetInfo structure.
1214%
1215% The format of the XGetWidgetInfo function is:
1216%
1217% XGetWidgetInfo(text,widget_info)
1218%
1219% A description of each parameter follows:
1220%
1221% o text: A string of characters associated with the widget.
1222%
1223% o widget_info: Specifies a pointer to a X11 XWidgetInfo structure.
1224%
1225*/
1226static void XGetWidgetInfo(const char *text,XWidgetInfo *widget_info)
1227{
1228 /*
1229 Initialize widget info.
1230 */
1231 widget_info->id=(~0);
1232 widget_info->bevel_width=3;
1233 widget_info->width=1;
1234 widget_info->height=1;
1235 widget_info->x=0;
1236 widget_info->y=0;
1237 widget_info->min_y=0;
1238 widget_info->max_y=0;
1239 widget_info->raised=MagickTrue;
1240 widget_info->active=MagickFalse;
1241 widget_info->center=MagickTrue;
1242 widget_info->trough=MagickFalse;
1243 widget_info->highlight=MagickFalse;
1244 widget_info->text=(char *) text;
1245 widget_info->cursor=(char *) text;
1246 if (text != (char *) NULL)
1247 widget_info->cursor+=Extent(text);
1248 widget_info->marker=(char *) text;
1249}
1250
1251/*
1252%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1253% %
1254% %
1255% %
1256+ X H i g h l i g h t W i d g e t %
1257% %
1258% %
1259% %
1260%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1261%
1262% XHighlightWidget() draws a highlighted border around a window.
1263%
1264% The format of the XHighlightWidget function is:
1265%
1266% XHighlightWidget(display,window_info,x,y)
1267%
1268% A description of each parameter follows:
1269%
1270% o display: Specifies a pointer to the Display structure; returned from
1271% XOpenDisplay.
1272%
1273% o window_info: Specifies a pointer to a X11 XWindowInfo structure.
1274%
1275% o x: Specifies an integer representing the rectangle offset in the
1276% x-direction.
1277%
1278% o y: Specifies an integer representing the rectangle offset in the
1279% y-direction.
1280%
1281*/
1282static void XHighlightWidget(Display *display,const XWindowInfo *window_info,
1283 const int x,const int y)
1284{
1285 /*
1286 Draw the widget highlighting rectangle.
1287 */
1288 XSetBevelColor(display,window_info,MagickTrue);
1289 (void) XDrawRectangle(display,window_info->id,window_info->widget_context,x,y,
1290 window_info->width-(x << 1),window_info->height-(y << 1));
1291 (void) XDrawRectangle(display,window_info->id,window_info->widget_context,
1292 x-1,y-1,window_info->width-(x << 1)+1,window_info->height-(y << 1)+1);
1293 XSetBevelColor(display,window_info,MagickFalse);
1294 (void) XDrawRectangle(display,window_info->id,window_info->widget_context,
1295 x-1,y-1,window_info->width-(x << 1),window_info->height-(y << 1));
1296 (void) XSetFillStyle(display,window_info->widget_context,FillSolid);
1297}
1298
1299/*
1300%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1301% %
1302% %
1303% %
1304+ X S c r e e n E v e n t %
1305% %
1306% %
1307% %
1308%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1309%
1310% XScreenEvent() returns MagickTrue if the any event on the X server queue is
1311% associated with the widget window.
1312%
1313% The format of the XScreenEvent function is:
1314%
1315% int XScreenEvent(Display *display,XEvent *event,char *data)
1316%
1317% A description of each parameter follows:
1318%
1319% o display: Specifies a pointer to the Display structure; returned from
1320% XOpenDisplay.
1321%
1322% o event: Specifies a pointer to a X11 XEvent structure.
1323%
1324% o data: Specifies a pointer to a XWindows structure.
1325%
1326*/
1327
1328#if defined(__cplusplus) || defined(c_plusplus)
1329extern "C" {
1330#endif
1331
1332static int XScreenEvent(Display *display,XEvent *event,char *data)
1333{
1334 XWindows
1335 *windows;
1336
1337 windows=(XWindows *) data;
1338 if (event->xany.window == windows->popup.id)
1339 {
1340 if (event->type == MapNotify)
1341 windows->popup.mapped=MagickTrue;
1342 if (event->type == UnmapNotify)
1343 windows->popup.mapped=MagickFalse;
1344 return(MagickTrue);
1345 }
1346 if (event->xany.window == windows->widget.id)
1347 {
1348 if (event->type == MapNotify)
1349 windows->widget.mapped=MagickTrue;
1350 if (event->type == UnmapNotify)
1351 windows->widget.mapped=MagickFalse;
1352 return(MagickTrue);
1353 }
1354 switch (event->type)
1355 {
1356 case ButtonPress:
1357 {
1358 if ((event->xbutton.button == Button3) &&
1359 (event->xbutton.state & Mod1Mask))
1360 {
1361 /*
1362 Convert Alt-Button3 to Button2.
1363 */
1364 event->xbutton.button=Button2;
1365 event->xbutton.state&=(~Mod1Mask);
1366 }
1367 return(MagickTrue);
1368 }
1369 case Expose:
1370 {
1371 if (event->xexpose.window == windows->image.id)
1372 {
1373 XRefreshWindow(display,&windows->image,event);
1374 break;
1375 }
1376 if (event->xexpose.window == windows->magnify.id)
1377 if (event->xexpose.count == 0)
1378 if (windows->magnify.mapped)
1379 {
1380 XMakeMagnifyImage(display,windows);
1381 break;
1382 }
1383 if (event->xexpose.window == windows->command.id)
1384 if (event->xexpose.count == 0)
1385 {
1386 (void) XCommandWidget(display,windows,(const char **) NULL,event);
1387 break;
1388 }
1389 break;
1390 }
1391 case FocusOut:
1392 {
1393 /*
1394 Set input focus for backdrop window.
1395 */
1396 if (event->xfocus.window == windows->image.id)
1397 (void) XSetInputFocus(display,windows->image.id,RevertToNone,
1398 CurrentTime);
1399 return(MagickTrue);
1400 }
1401 case ButtonRelease:
1402 case KeyPress:
1403 case KeyRelease:
1404 case MotionNotify:
1405 case SelectionNotify:
1406 return(MagickTrue);
1407 default:
1408 break;
1409 }
1410 return(MagickFalse);
1411}
1412
1413#if defined(__cplusplus) || defined(c_plusplus)
1414}
1415#endif
1416
1417/*
1418%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1419% %
1420% %
1421% %
1422+ X S e t B e v e l C o l o r %
1423% %
1424% %
1425% %
1426%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1427%
1428% XSetBevelColor() sets the graphic context for drawing a beveled border.
1429%
1430% The format of the XSetBevelColor function is:
1431%
1432% XSetBevelColor(display,window_info,raised)
1433%
1434% A description of each parameter follows:
1435%
1436% o display: Specifies a pointer to the Display structure; returned from
1437% XOpenDisplay.
1438%
1439% o window_info: Specifies a pointer to a X11 XWindowInfo structure.
1440%
1441% o raised: A value other than zero indicates the color show be a
1442% "highlight" color, otherwise the "shadow" color is set.
1443%
1444*/
1445static void XSetBevelColor(Display *display,const XWindowInfo *window_info,
1446 const MagickStatusType raised)
1447{
1448 if (window_info->depth == 1)
1449 {
1450 Pixmap
1451 stipple;
1452
1453 /*
1454 Monochrome window.
1455 */
1456 (void) XSetBackground(display,window_info->widget_context,
1457 XBlackPixel(display,window_info->screen));
1458 (void) XSetForeground(display,window_info->widget_context,
1459 XWhitePixel(display,window_info->screen));
1460 (void) XSetFillStyle(display,window_info->widget_context,
1461 FillOpaqueStippled);
1462 stipple=window_info->highlight_stipple;
1463 if (raised == MagickFalse)
1464 stipple=window_info->shadow_stipple;
1465 (void) XSetStipple(display,window_info->widget_context,stipple);
1466 }
1467 else
1468 if (raised)
1469 (void) XSetForeground(display,window_info->widget_context,
1470 window_info->pixel_info->highlight_color.pixel);
1471 else
1472 (void) XSetForeground(display,window_info->widget_context,
1473 window_info->pixel_info->shadow_color.pixel);
1474}
1475
1476/*
1477%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1478% %
1479% %
1480% %
1481+ X S e t M a t t e C o l o r %
1482% %
1483% %
1484% %
1485%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1486%
1487% XSetMatteColor() sets the graphic context for drawing the matte.
1488%
1489% The format of the XSetMatteColor function is:
1490%
1491% XSetMatteColor(display,window_info,raised)
1492%
1493% A description of each parameter follows:
1494%
1495% o display: Specifies a pointer to the Display structure; returned from
1496% XOpenDisplay.
1497%
1498% o window_info: Specifies a pointer to a X11 XWindowInfo structure.
1499%
1500% o raised: A value other than zero indicates the matte is active.
1501%
1502*/
1503static void XSetMatteColor(Display *display,const XWindowInfo *window_info,
1504 const MagickStatusType raised)
1505{
1506 if (window_info->depth == 1)
1507 {
1508 /*
1509 Monochrome window.
1510 */
1511 if (raised)
1512 (void) XSetForeground(display,window_info->widget_context,
1513 XWhitePixel(display,window_info->screen));
1514 else
1515 (void) XSetForeground(display,window_info->widget_context,
1516 XBlackPixel(display,window_info->screen));
1517 }
1518 else
1519 if (raised)
1520 (void) XSetForeground(display,window_info->widget_context,
1521 window_info->pixel_info->matte_color.pixel);
1522 else
1523 (void) XSetForeground(display,window_info->widget_context,
1524 window_info->pixel_info->depth_color.pixel);
1525}
1526
1527/*
1528%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1529% %
1530% %
1531% %
1532+ X S e t T e x t C o l o r %
1533% %
1534% %
1535% %
1536%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1537%
1538% XSetTextColor() sets the graphic context for drawing text on a matte.
1539%
1540% The format of the XSetTextColor function is:
1541%
1542% XSetTextColor(display,window_info,raised)
1543%
1544% A description of each parameter follows:
1545%
1546% o display: Specifies a pointer to the Display structure; returned from
1547% XOpenDisplay.
1548%
1549% o window_info: Specifies a pointer to a X11 XWindowInfo structure.
1550%
1551% o raised: A value other than zero indicates the color show be a
1552% "highlight" color, otherwise the "shadow" color is set.
1553%
1554*/
1555static void XSetTextColor(Display *display,const XWindowInfo *window_info,
1556 const MagickStatusType raised)
1557{
cristybb503372010-05-27 20:51:26 +00001558 ssize_t
cristy3ed852e2009-09-05 21:47:34 +00001559 foreground,
1560 matte;
1561
1562 if (window_info->depth == 1)
1563 {
1564 /*
1565 Monochrome window.
1566 */
1567 if (raised)
1568 (void) XSetForeground(display,window_info->widget_context,
1569 XBlackPixel(display,window_info->screen));
1570 else
1571 (void) XSetForeground(display,window_info->widget_context,
1572 XWhitePixel(display,window_info->screen));
1573 return;
1574 }
cristy49e2d862010-11-12 02:50:30 +00001575 foreground=(ssize_t) XPixelIntensity(
1576 &window_info->pixel_info->foreground_color);
cristybb503372010-05-27 20:51:26 +00001577 matte=(ssize_t) XPixelIntensity(&window_info->pixel_info->matte_color);
cristy49e2d862010-11-12 02:50:30 +00001578 if (MagickAbsoluteValue((int) (foreground-matte)) > (65535L >> 3))
cristy3ed852e2009-09-05 21:47:34 +00001579 (void) XSetForeground(display,window_info->widget_context,
1580 window_info->pixel_info->foreground_color.pixel);
1581 else
1582 (void) XSetForeground(display,window_info->widget_context,
1583 window_info->pixel_info->background_color.pixel);
1584}
1585
1586/*
1587%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1588% %
1589% %
1590% %
1591% X C o l o r B r o w s e r W i d g e t %
1592% %
1593% %
1594% %
1595%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1596%
1597% XColorBrowserWidget() displays a Color Browser widget with a color query
1598% to the user. The user keys a reply and presses the Action or Cancel button
1599% to exit. The typed text is returned as the reply function parameter.
1600%
1601% The format of the XColorBrowserWidget method is:
1602%
1603% void XColorBrowserWidget(Display *display,XWindows *windows,
1604% const char *action,char *reply)
1605%
1606% A description of each parameter follows:
1607%
1608% o display: Specifies a connection to an X server; returned from
1609% XOpenDisplay.
1610%
1611% o window: Specifies a pointer to a XWindows structure.
1612%
1613% o action: Specifies a pointer to the action of this widget.
1614%
1615% o reply: the response from the user is returned in this parameter.
1616%
1617*/
1618MagickExport void XColorBrowserWidget(Display *display,XWindows *windows,
1619 const char *action,char *reply)
1620{
1621#define CancelButtonText "Cancel"
1622#define ColornameText "Name:"
1623#define ColorPatternText "Pattern:"
1624#define GrabButtonText "Grab"
1625#define ResetButtonText "Reset"
1626
1627 char
1628 **colorlist,
1629 primary_selection[MaxTextExtent],
1630 reset_pattern[MaxTextExtent],
1631 text[MaxTextExtent];
1632
1633 ExceptionInfo
1634 *exception;
1635
1636 int
1637 x,
1638 y;
1639
1640 register int
1641 i;
1642
1643 static char
1644 glob_pattern[MaxTextExtent] = "*";
1645
1646 static MagickStatusType
1647 mask = (MagickStatusType) (CWWidth | CWHeight | CWX | CWY);
1648
1649 Status
1650 status;
1651
1652 unsigned int
1653 height,
1654 text_width,
1655 visible_colors,
1656 width;
1657
cristybb503372010-05-27 20:51:26 +00001658 size_t
cristy3ed852e2009-09-05 21:47:34 +00001659 colors,
1660 delay,
1661 state;
1662
1663 XColor
1664 color;
1665
1666 XEvent
1667 event;
1668
1669 XFontStruct
1670 *font_info;
1671
1672 XTextProperty
1673 window_name;
1674
1675 XWidgetInfo
1676 action_info,
1677 cancel_info,
1678 expose_info,
1679 grab_info,
1680 list_info,
1681 mode_info,
1682 north_info,
1683 reply_info,
1684 reset_info,
1685 scroll_info,
1686 selection_info,
1687 slider_info,
1688 south_info,
1689 text_info;
1690
1691 XWindowChanges
1692 window_changes;
1693
1694 /*
1695 Get color list and sort in ascending order.
1696 */
1697 assert(display != (Display *) NULL);
1698 assert(windows != (XWindows *) NULL);
1699 assert(action != (char *) NULL);
1700 assert(reply != (char *) NULL);
1701 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",action);
1702 XSetCursorState(display,windows,MagickTrue);
1703 XCheckRefreshWindows(display,windows);
1704 (void) CopyMagickString(reset_pattern,"*",MaxTextExtent);
1705 exception=AcquireExceptionInfo();
1706 colorlist=GetColorList(glob_pattern,&colors,exception);
1707 if (colorlist == (char **) NULL)
1708 {
1709 /*
1710 Pattern failed, obtain all the colors.
1711 */
1712 (void) CopyMagickString(glob_pattern,"*",MaxTextExtent);
1713 colorlist=GetColorList(glob_pattern,&colors,exception);
1714 if (colorlist == (char **) NULL)
1715 {
1716 XNoticeWidget(display,windows,"Unable to obtain colors names:",
1717 glob_pattern);
1718 (void) XDialogWidget(display,windows,action,"Enter color name:",
1719 reply);
1720 return;
1721 }
1722 }
1723 /*
1724 Determine Color Browser widget attributes.
1725 */
1726 font_info=windows->widget.font_info;
1727 text_width=0;
cristy49e2d862010-11-12 02:50:30 +00001728 for (i=0; i < (int) colors; i++)
cristy3ed852e2009-09-05 21:47:34 +00001729 if (WidgetTextWidth(font_info,colorlist[i]) > text_width)
1730 text_width=WidgetTextWidth(font_info,colorlist[i]);
1731 width=WidgetTextWidth(font_info,(char *) action);
1732 if (WidgetTextWidth(font_info,CancelButtonText) > width)
1733 width=WidgetTextWidth(font_info,CancelButtonText);
1734 if (WidgetTextWidth(font_info,ResetButtonText) > width)
1735 width=WidgetTextWidth(font_info,ResetButtonText);
1736 if (WidgetTextWidth(font_info,GrabButtonText) > width)
1737 width=WidgetTextWidth(font_info,GrabButtonText);
1738 width+=QuantumMargin;
1739 if (WidgetTextWidth(font_info,ColorPatternText) > width)
1740 width=WidgetTextWidth(font_info,ColorPatternText);
1741 if (WidgetTextWidth(font_info,ColornameText) > width)
1742 width=WidgetTextWidth(font_info,ColornameText);
1743 height=(unsigned int) (font_info->ascent+font_info->descent);
1744 /*
1745 Position Color Browser widget.
1746 */
1747 windows->widget.width=(unsigned int)
1748 (width+MagickMin((int) text_width,(int) MaxTextWidth)+6*QuantumMargin);
1749 windows->widget.min_width=(unsigned int)
1750 (width+MinTextWidth+4*QuantumMargin);
1751 if (windows->widget.width < windows->widget.min_width)
1752 windows->widget.width=windows->widget.min_width;
1753 windows->widget.height=(unsigned int)
1754 ((81*height) >> 2)+((13*QuantumMargin) >> 1)+4;
1755 windows->widget.min_height=(unsigned int)
1756 (((23*height) >> 1)+((13*QuantumMargin) >> 1)+4);
1757 if (windows->widget.height < windows->widget.min_height)
1758 windows->widget.height=windows->widget.min_height;
1759 XConstrainWindowPosition(display,&windows->widget);
1760 /*
1761 Map Color Browser widget.
1762 */
1763 (void) CopyMagickString(windows->widget.name,"Browse and Select a Color",
1764 MaxTextExtent);
1765 status=XStringListToTextProperty(&windows->widget.name,1,&window_name);
1766 if (status != False)
1767 {
1768 XSetWMName(display,windows->widget.id,&window_name);
1769 XSetWMIconName(display,windows->widget.id,&window_name);
1770 (void) XFree((void *) window_name.value);
1771 }
1772 window_changes.width=(int) windows->widget.width;
1773 window_changes.height=(int) windows->widget.height;
1774 window_changes.x=windows->widget.x;
1775 window_changes.y=windows->widget.y;
1776 (void) XReconfigureWMWindow(display,windows->widget.id,windows->widget.screen,
1777 mask,&window_changes);
1778 (void) XMapRaised(display,windows->widget.id);
1779 windows->widget.mapped=MagickFalse;
1780 /*
1781 Respond to X events.
1782 */
1783 XGetWidgetInfo((char *) NULL,&slider_info);
1784 XGetWidgetInfo((char *) NULL,&north_info);
1785 XGetWidgetInfo((char *) NULL,&south_info);
1786 XGetWidgetInfo((char *) NULL,&expose_info);
1787 visible_colors=0;
1788 delay=SuspendTime << 2;
1789 state=UpdateConfigurationState;
1790 do
1791 {
1792 if (state & UpdateConfigurationState)
1793 {
1794 int
1795 id;
1796
1797 /*
1798 Initialize button information.
1799 */
1800 XGetWidgetInfo(CancelButtonText,&cancel_info);
1801 cancel_info.width=width;
1802 cancel_info.height=(unsigned int) ((3*height) >> 1);
1803 cancel_info.x=(int)
1804 (windows->widget.width-cancel_info.width-QuantumMargin-2);
1805 cancel_info.y=(int)
1806 (windows->widget.height-cancel_info.height-QuantumMargin);
1807 XGetWidgetInfo(action,&action_info);
1808 action_info.width=width;
1809 action_info.height=(unsigned int) ((3*height) >> 1);
1810 action_info.x=cancel_info.x-(cancel_info.width+(QuantumMargin >> 1)+
1811 (action_info.bevel_width << 1));
1812 action_info.y=cancel_info.y;
1813 XGetWidgetInfo(GrabButtonText,&grab_info);
1814 grab_info.width=width;
1815 grab_info.height=(unsigned int) ((3*height) >> 1);
1816 grab_info.x=QuantumMargin;
1817 grab_info.y=((5*QuantumMargin) >> 1)+height;
1818 XGetWidgetInfo(ResetButtonText,&reset_info);
1819 reset_info.width=width;
1820 reset_info.height=(unsigned int) ((3*height) >> 1);
1821 reset_info.x=QuantumMargin;
1822 reset_info.y=grab_info.y+grab_info.height+QuantumMargin;
1823 /*
1824 Initialize reply information.
1825 */
1826 XGetWidgetInfo(reply,&reply_info);
1827 reply_info.raised=MagickFalse;
1828 reply_info.bevel_width--;
1829 reply_info.width=windows->widget.width-width-((6*QuantumMargin) >> 1);
1830 reply_info.height=height << 1;
1831 reply_info.x=(int) (width+(QuantumMargin << 1));
1832 reply_info.y=action_info.y-reply_info.height-QuantumMargin;
1833 /*
1834 Initialize mode information.
1835 */
1836 XGetWidgetInfo((char *) NULL,&mode_info);
1837 mode_info.active=MagickTrue;
1838 mode_info.bevel_width=0;
1839 mode_info.width=(unsigned int) (action_info.x-(QuantumMargin << 1));
1840 mode_info.height=action_info.height;
1841 mode_info.x=QuantumMargin;
1842 mode_info.y=action_info.y;
1843 /*
1844 Initialize scroll information.
1845 */
1846 XGetWidgetInfo((char *) NULL,&scroll_info);
1847 scroll_info.bevel_width--;
1848 scroll_info.width=height;
1849 scroll_info.height=(unsigned int) (reply_info.y-grab_info.y-
1850 (QuantumMargin >> 1));
1851 scroll_info.x=reply_info.x+(reply_info.width-scroll_info.width);
1852 scroll_info.y=grab_info.y-reply_info.bevel_width;
1853 scroll_info.raised=MagickFalse;
1854 scroll_info.trough=MagickTrue;
1855 north_info=scroll_info;
1856 north_info.raised=MagickTrue;
1857 north_info.width-=(north_info.bevel_width << 1);
1858 north_info.height=north_info.width-1;
1859 north_info.x+=north_info.bevel_width;
1860 north_info.y+=north_info.bevel_width;
1861 south_info=north_info;
1862 south_info.y=scroll_info.y+scroll_info.height-scroll_info.bevel_width-
1863 south_info.height;
1864 id=slider_info.id;
1865 slider_info=north_info;
1866 slider_info.id=id;
1867 slider_info.width-=2;
1868 slider_info.min_y=north_info.y+north_info.height+north_info.bevel_width+
1869 slider_info.bevel_width+2;
1870 slider_info.height=scroll_info.height-((slider_info.min_y-
1871 scroll_info.y+1) << 1)+4;
1872 visible_colors=scroll_info.height/(height+(height >> 3));
1873 if (colors > visible_colors)
1874 slider_info.height=(unsigned int)
1875 ((visible_colors*slider_info.height)/colors);
1876 slider_info.max_y=south_info.y-south_info.bevel_width-
1877 slider_info.bevel_width-2;
1878 slider_info.x=scroll_info.x+slider_info.bevel_width+1;
1879 slider_info.y=slider_info.min_y;
1880 expose_info=scroll_info;
1881 expose_info.y=slider_info.y;
1882 /*
1883 Initialize list information.
1884 */
1885 XGetWidgetInfo((char *) NULL,&list_info);
1886 list_info.raised=MagickFalse;
1887 list_info.bevel_width--;
1888 list_info.width=(unsigned int)
1889 (scroll_info.x-reply_info.x-(QuantumMargin >> 1));
1890 list_info.height=scroll_info.height;
1891 list_info.x=reply_info.x;
1892 list_info.y=scroll_info.y;
1893 if (windows->widget.mapped == MagickFalse)
1894 state|=JumpListState;
1895 /*
1896 Initialize text information.
1897 */
1898 *text='\0';
1899 XGetWidgetInfo(text,&text_info);
1900 text_info.center=MagickFalse;
1901 text_info.width=reply_info.width;
1902 text_info.height=height;
1903 text_info.x=list_info.x-(QuantumMargin >> 1);
1904 text_info.y=QuantumMargin;
1905 /*
1906 Initialize selection information.
1907 */
1908 XGetWidgetInfo((char *) NULL,&selection_info);
1909 selection_info.center=MagickFalse;
1910 selection_info.width=list_info.width;
1911 selection_info.height=(unsigned int) ((9*height) >> 3);
1912 selection_info.x=list_info.x;
1913 state&=(~UpdateConfigurationState);
1914 }
1915 if (state & RedrawWidgetState)
1916 {
1917 /*
1918 Redraw Color Browser window.
1919 */
1920 x=QuantumMargin;
1921 y=text_info.y+((text_info.height-height) >> 1)+font_info->ascent;
1922 (void) XDrawString(display,windows->widget.id,
1923 windows->widget.annotate_context,x,y,ColorPatternText,
1924 Extent(ColorPatternText));
1925 (void) CopyMagickString(text_info.text,glob_pattern,MaxTextExtent);
1926 XDrawWidgetText(display,&windows->widget,&text_info);
1927 XDrawBeveledButton(display,&windows->widget,&grab_info);
1928 XDrawBeveledButton(display,&windows->widget,&reset_info);
1929 XDrawBeveledMatte(display,&windows->widget,&list_info);
1930 XDrawBeveledMatte(display,&windows->widget,&scroll_info);
1931 XDrawTriangleNorth(display,&windows->widget,&north_info);
1932 XDrawBeveledButton(display,&windows->widget,&slider_info);
1933 XDrawTriangleSouth(display,&windows->widget,&south_info);
1934 x=QuantumMargin;
1935 y=reply_info.y+((reply_info.height-height) >> 1)+font_info->ascent;
1936 (void) XDrawString(display,windows->widget.id,
1937 windows->widget.annotate_context,x,y,ColornameText,
1938 Extent(ColornameText));
1939 XDrawBeveledMatte(display,&windows->widget,&reply_info);
1940 XDrawMatteText(display,&windows->widget,&reply_info);
1941 XDrawBeveledButton(display,&windows->widget,&action_info);
1942 XDrawBeveledButton(display,&windows->widget,&cancel_info);
1943 XHighlightWidget(display,&windows->widget,BorderOffset,BorderOffset);
1944 selection_info.id=(~0);
1945 state|=RedrawActionState;
1946 state|=RedrawListState;
1947 state&=(~RedrawWidgetState);
1948 }
1949 if (state & UpdateListState)
1950 {
1951 char
1952 **checklist;
1953
cristybb503372010-05-27 20:51:26 +00001954 size_t
cristy3ed852e2009-09-05 21:47:34 +00001955 number_colors;
1956
1957 status=XParseColor(display,windows->widget.map_info->colormap,
1958 glob_pattern,&color);
1959 if ((status != False) || (strchr(glob_pattern,'-') != (char *) NULL))
1960 {
1961 /*
1962 Reply is a single color name-- exit.
1963 */
1964 (void) CopyMagickString(reply,glob_pattern,MaxTextExtent);
1965 (void) CopyMagickString(glob_pattern,reset_pattern,MaxTextExtent);
1966 action_info.raised=MagickFalse;
1967 XDrawBeveledButton(display,&windows->widget,&action_info);
1968 break;
1969 }
1970 /*
1971 Update color list.
1972 */
1973 checklist=GetColorList(glob_pattern,&number_colors,exception);
1974 if (number_colors == 0)
1975 {
1976 (void) CopyMagickString(glob_pattern,reset_pattern,MaxTextExtent);
1977 (void) XBell(display,0);
1978 }
1979 else
1980 {
cristy49e2d862010-11-12 02:50:30 +00001981 for (i=0; i < (int) colors; i++)
cristy3ed852e2009-09-05 21:47:34 +00001982 colorlist[i]=DestroyString(colorlist[i]);
1983 if (colorlist != (char **) NULL)
1984 colorlist=(char **) RelinquishMagickMemory(colorlist);
1985 colorlist=checklist;
1986 colors=number_colors;
1987 }
1988 /*
1989 Sort color list in ascending order.
1990 */
1991 slider_info.height=
1992 scroll_info.height-((slider_info.min_y-scroll_info.y+1) << 1)+1;
1993 if (colors > visible_colors)
1994 slider_info.height=(unsigned int)
1995 ((visible_colors*slider_info.height)/colors);
1996 slider_info.max_y=south_info.y-south_info.bevel_width-
1997 slider_info.bevel_width-2;
1998 slider_info.id=0;
1999 slider_info.y=slider_info.min_y;
2000 expose_info.y=slider_info.y;
2001 selection_info.id=(~0);
2002 list_info.id=(~0);
2003 state|=RedrawListState;
2004 /*
2005 Redraw color name & reply.
2006 */
2007 *reply_info.text='\0';
2008 reply_info.cursor=reply_info.text;
2009 (void) CopyMagickString(text_info.text,glob_pattern,MaxTextExtent);
2010 XDrawWidgetText(display,&windows->widget,&text_info);
2011 XDrawMatteText(display,&windows->widget,&reply_info);
2012 XDrawBeveledMatte(display,&windows->widget,&scroll_info);
2013 XDrawTriangleNorth(display,&windows->widget,&north_info);
2014 XDrawBeveledButton(display,&windows->widget,&slider_info);
2015 XDrawTriangleSouth(display,&windows->widget,&south_info);
2016 XHighlightWidget(display,&windows->widget,BorderOffset,BorderOffset);
2017 state&=(~UpdateListState);
2018 }
2019 if (state & JumpListState)
2020 {
2021 /*
2022 Jump scroll to match user color.
2023 */
2024 list_info.id=(~0);
cristy49e2d862010-11-12 02:50:30 +00002025 for (i=0; i < (int) colors; i++)
cristy3ed852e2009-09-05 21:47:34 +00002026 if (LocaleCompare(colorlist[i],reply) >= 0)
2027 {
2028 list_info.id=LocaleCompare(colorlist[i],reply) == 0 ? i : ~0;
2029 break;
2030 }
2031 if ((i < slider_info.id) ||
2032 (i >= (int) (slider_info.id+visible_colors)))
2033 slider_info.id=i-(visible_colors >> 1);
2034 selection_info.id=(~0);
2035 state|=RedrawListState;
2036 state&=(~JumpListState);
2037 }
2038 if (state & RedrawListState)
2039 {
2040 /*
2041 Determine slider id and position.
2042 */
2043 if (slider_info.id >= (int) (colors-visible_colors))
2044 slider_info.id=(int) (colors-visible_colors);
2045 if ((slider_info.id < 0) || (colors <= visible_colors))
2046 slider_info.id=0;
2047 slider_info.y=slider_info.min_y;
2048 if (colors != 0)
cristy8891f9c2010-06-04 23:32:17 +00002049 slider_info.y+=(int) (slider_info.id*(slider_info.max_y-
2050 slider_info.min_y+1)/colors);
cristy3ed852e2009-09-05 21:47:34 +00002051 if (slider_info.id != selection_info.id)
2052 {
2053 /*
2054 Redraw scroll bar and file names.
2055 */
2056 selection_info.id=slider_info.id;
2057 selection_info.y=list_info.y+(height >> 3)+2;
2058 for (i=0; i < (int) visible_colors; i++)
2059 {
2060 selection_info.raised=(slider_info.id+i) != list_info.id ?
2061 MagickTrue : MagickFalse;
2062 selection_info.text=(char *) NULL;
cristy49e2d862010-11-12 02:50:30 +00002063 if ((slider_info.id+i) < (int) colors)
cristy3ed852e2009-09-05 21:47:34 +00002064 selection_info.text=colorlist[slider_info.id+i];
2065 XDrawWidgetText(display,&windows->widget,&selection_info);
2066 selection_info.y+=(int) selection_info.height;
2067 }
2068 /*
2069 Update slider.
2070 */
2071 if (slider_info.y > expose_info.y)
2072 {
2073 expose_info.height=(unsigned int) slider_info.y-expose_info.y;
2074 expose_info.y=slider_info.y-expose_info.height-
2075 slider_info.bevel_width-1;
2076 }
2077 else
2078 {
2079 expose_info.height=(unsigned int) expose_info.y-slider_info.y;
2080 expose_info.y=slider_info.y+slider_info.height+
2081 slider_info.bevel_width+1;
2082 }
2083 XDrawTriangleNorth(display,&windows->widget,&north_info);
2084 XDrawMatte(display,&windows->widget,&expose_info);
2085 XDrawBeveledButton(display,&windows->widget,&slider_info);
2086 XDrawTriangleSouth(display,&windows->widget,&south_info);
2087 expose_info.y=slider_info.y;
2088 }
2089 state&=(~RedrawListState);
2090 }
2091 if (state & RedrawActionState)
2092 {
2093 static char
2094 colorname[MaxTextExtent];
2095
2096 /*
2097 Display the selected color in a drawing area.
2098 */
2099 color=windows->widget.pixel_info->matte_color;
2100 (void) XParseColor(display,windows->widget.map_info->colormap,
2101 reply_info.text,&windows->widget.pixel_info->matte_color);
2102 XBestPixel(display,windows->widget.map_info->colormap,(XColor *) NULL,
2103 (unsigned int) windows->widget.visual_info->colormap_size,
2104 &windows->widget.pixel_info->matte_color);
2105 mode_info.text=colorname;
2106 (void) FormatMagickString(mode_info.text,MaxTextExtent,"#%02x%02x%02x",
2107 windows->widget.pixel_info->matte_color.red,
2108 windows->widget.pixel_info->matte_color.green,
2109 windows->widget.pixel_info->matte_color.blue);
2110 XDrawBeveledButton(display,&windows->widget,&mode_info);
2111 windows->widget.pixel_info->matte_color=color;
2112 state&=(~RedrawActionState);
2113 }
2114 /*
2115 Wait for next event.
2116 */
2117 if (north_info.raised && south_info.raised)
2118 (void) XIfEvent(display,&event,XScreenEvent,(char *) windows);
2119 else
2120 {
2121 /*
2122 Brief delay before advancing scroll bar.
2123 */
2124 XDelay(display,delay);
2125 delay=SuspendTime;
2126 (void) XCheckIfEvent(display,&event,XScreenEvent,(char *) windows);
2127 if (north_info.raised == MagickFalse)
2128 if (slider_info.id > 0)
2129 {
2130 /*
2131 Move slider up.
2132 */
2133 slider_info.id--;
2134 state|=RedrawListState;
2135 }
2136 if (south_info.raised == MagickFalse)
cristy49e2d862010-11-12 02:50:30 +00002137 if (slider_info.id < (int) colors)
cristy3ed852e2009-09-05 21:47:34 +00002138 {
2139 /*
2140 Move slider down.
2141 */
2142 slider_info.id++;
2143 state|=RedrawListState;
2144 }
2145 if (event.type != ButtonRelease)
2146 continue;
2147 }
2148 switch (event.type)
2149 {
2150 case ButtonPress:
2151 {
2152 if (MatteIsActive(slider_info,event.xbutton))
2153 {
2154 /*
2155 Track slider.
2156 */
2157 slider_info.active=MagickTrue;
2158 break;
2159 }
2160 if (MatteIsActive(north_info,event.xbutton))
2161 if (slider_info.id > 0)
2162 {
2163 /*
2164 Move slider up.
2165 */
2166 north_info.raised=MagickFalse;
2167 slider_info.id--;
2168 state|=RedrawListState;
2169 break;
2170 }
2171 if (MatteIsActive(south_info,event.xbutton))
cristy49e2d862010-11-12 02:50:30 +00002172 if (slider_info.id < (int) colors)
cristy3ed852e2009-09-05 21:47:34 +00002173 {
2174 /*
2175 Move slider down.
2176 */
2177 south_info.raised=MagickFalse;
2178 slider_info.id++;
2179 state|=RedrawListState;
2180 break;
2181 }
2182 if (MatteIsActive(scroll_info,event.xbutton))
2183 {
2184 /*
2185 Move slider.
2186 */
2187 if (event.xbutton.y < slider_info.y)
2188 slider_info.id-=(visible_colors-1);
2189 else
2190 slider_info.id+=(visible_colors-1);
2191 state|=RedrawListState;
2192 break;
2193 }
2194 if (MatteIsActive(list_info,event.xbutton))
2195 {
2196 int
2197 id;
2198
2199 /*
2200 User pressed list matte.
2201 */
2202 id=slider_info.id+(event.xbutton.y-(list_info.y+(height >> 1))+1)/
2203 selection_info.height;
2204 if (id >= (int) colors)
2205 break;
2206 (void) CopyMagickString(reply_info.text,colorlist[id],
2207 MaxTextExtent);
2208 reply_info.highlight=MagickFalse;
2209 reply_info.marker=reply_info.text;
2210 reply_info.cursor=reply_info.text+Extent(reply_info.text);
2211 XDrawMatteText(display,&windows->widget,&reply_info);
2212 state|=RedrawActionState;
2213 if (id == list_info.id)
2214 {
2215 (void) CopyMagickString(glob_pattern,reply_info.text,
2216 MaxTextExtent);
2217 state|=UpdateListState;
2218 }
2219 selection_info.id=(~0);
2220 list_info.id=id;
2221 state|=RedrawListState;
2222 break;
2223 }
2224 if (MatteIsActive(grab_info,event.xbutton))
2225 {
2226 /*
2227 User pressed Grab button.
2228 */
2229 grab_info.raised=MagickFalse;
2230 XDrawBeveledButton(display,&windows->widget,&grab_info);
2231 break;
2232 }
2233 if (MatteIsActive(reset_info,event.xbutton))
2234 {
2235 /*
2236 User pressed Reset button.
2237 */
2238 reset_info.raised=MagickFalse;
2239 XDrawBeveledButton(display,&windows->widget,&reset_info);
2240 break;
2241 }
2242 if (MatteIsActive(mode_info,event.xbutton))
2243 {
2244 /*
2245 User pressed mode button.
2246 */
2247 (void) CopyMagickString(reply_info.text,mode_info.text,
2248 MaxTextExtent);
2249 (void) CopyMagickString(primary_selection,reply_info.text,
2250 MaxTextExtent);
2251 (void) XSetSelectionOwner(display,XA_PRIMARY,windows->widget.id,
2252 event.xbutton.time);
2253 reply_info.highlight=XGetSelectionOwner(display,XA_PRIMARY) ==
2254 windows->widget.id ? MagickTrue : MagickFalse;
2255 reply_info.marker=reply_info.text;
2256 reply_info.cursor=reply_info.text+Extent(reply_info.text);
2257 XDrawMatteText(display,&windows->widget,&reply_info);
2258 break;
2259 }
2260 if (MatteIsActive(action_info,event.xbutton))
2261 {
2262 /*
2263 User pressed action button.
2264 */
2265 action_info.raised=MagickFalse;
2266 XDrawBeveledButton(display,&windows->widget,&action_info);
2267 break;
2268 }
2269 if (MatteIsActive(cancel_info,event.xbutton))
2270 {
2271 /*
2272 User pressed Cancel button.
2273 */
2274 cancel_info.raised=MagickFalse;
2275 XDrawBeveledButton(display,&windows->widget,&cancel_info);
2276 break;
2277 }
2278 if (MatteIsActive(reply_info,event.xbutton) == MagickFalse)
2279 break;
2280 if (event.xbutton.button != Button2)
2281 {
2282 static Time
2283 click_time;
2284
2285 /*
2286 Move text cursor to position of button press.
2287 */
2288 x=event.xbutton.x-reply_info.x-(QuantumMargin >> 2);
2289 for (i=1; i <= Extent(reply_info.marker); i++)
2290 if (XTextWidth(font_info,reply_info.marker,i) > x)
2291 break;
2292 reply_info.cursor=reply_info.marker+i-1;
2293 if (event.xbutton.time > (click_time+DoubleClick))
2294 reply_info.highlight=MagickFalse;
2295 else
2296 {
2297 /*
2298 Become the XA_PRIMARY selection owner.
2299 */
2300 (void) CopyMagickString(primary_selection,reply_info.text,
2301 MaxTextExtent);
2302 (void) XSetSelectionOwner(display,XA_PRIMARY,windows->widget.id,
2303 event.xbutton.time);
2304 reply_info.highlight=XGetSelectionOwner(display,XA_PRIMARY) ==
2305 windows->widget.id ? MagickTrue : MagickFalse;
2306 }
2307 XDrawMatteText(display,&windows->widget,&reply_info);
2308 click_time=event.xbutton.time;
2309 break;
2310 }
2311 /*
2312 Request primary selection.
2313 */
2314 (void) XConvertSelection(display,XA_PRIMARY,XA_STRING,XA_STRING,
2315 windows->widget.id,event.xbutton.time);
2316 break;
2317 }
2318 case ButtonRelease:
2319 {
2320 if (windows->widget.mapped == MagickFalse)
2321 break;
2322 if (north_info.raised == MagickFalse)
2323 {
2324 /*
2325 User released up button.
2326 */
2327 delay=SuspendTime << 2;
2328 north_info.raised=MagickTrue;
2329 XDrawTriangleNorth(display,&windows->widget,&north_info);
2330 }
2331 if (south_info.raised == MagickFalse)
2332 {
2333 /*
2334 User released down button.
2335 */
2336 delay=SuspendTime << 2;
2337 south_info.raised=MagickTrue;
2338 XDrawTriangleSouth(display,&windows->widget,&south_info);
2339 }
2340 if (slider_info.active)
2341 {
2342 /*
2343 Stop tracking slider.
2344 */
2345 slider_info.active=MagickFalse;
2346 break;
2347 }
2348 if (grab_info.raised == MagickFalse)
2349 {
2350 if (event.xbutton.window == windows->widget.id)
2351 if (MatteIsActive(grab_info,event.xbutton))
2352 {
2353 /*
2354 Select a pen color from the X server.
2355 */
2356 (void) XGetWindowColor(display,windows,reply_info.text);
2357 reply_info.marker=reply_info.text;
2358 reply_info.cursor=reply_info.text+Extent(reply_info.text);
2359 XDrawMatteText(display,&windows->widget,&reply_info);
2360 state|=RedrawActionState;
2361 }
2362 grab_info.raised=MagickTrue;
2363 XDrawBeveledButton(display,&windows->widget,&grab_info);
2364 }
2365 if (reset_info.raised == MagickFalse)
2366 {
2367 if (event.xbutton.window == windows->widget.id)
2368 if (MatteIsActive(reset_info,event.xbutton))
2369 {
2370 (void) CopyMagickString(glob_pattern,reset_pattern,
2371 MaxTextExtent);
2372 state|=UpdateListState;
2373 }
2374 reset_info.raised=MagickTrue;
2375 XDrawBeveledButton(display,&windows->widget,&reset_info);
2376 }
2377 if (action_info.raised == MagickFalse)
2378 {
2379 if (event.xbutton.window == windows->widget.id)
2380 {
2381 if (MatteIsActive(action_info,event.xbutton))
2382 {
2383 if (*reply_info.text == '\0')
2384 (void) XBell(display,0);
2385 else
2386 state|=ExitState;
2387 }
2388 }
2389 action_info.raised=MagickTrue;
2390 XDrawBeveledButton(display,&windows->widget,&action_info);
2391 }
2392 if (cancel_info.raised == MagickFalse)
2393 {
2394 if (event.xbutton.window == windows->widget.id)
2395 if (MatteIsActive(cancel_info,event.xbutton))
2396 {
2397 *reply_info.text='\0';
2398 state|=ExitState;
2399 }
2400 cancel_info.raised=MagickTrue;
2401 XDrawBeveledButton(display,&windows->widget,&cancel_info);
2402 }
2403 if (MatteIsActive(reply_info,event.xbutton) == MagickFalse)
2404 break;
2405 break;
2406 }
2407 case ClientMessage:
2408 {
2409 /*
2410 If client window delete message, exit.
2411 */
2412 if (event.xclient.message_type != windows->wm_protocols)
2413 break;
2414 if (*event.xclient.data.l == (int) windows->wm_take_focus)
2415 {
2416 (void) XSetInputFocus(display,event.xclient.window,RevertToParent,
2417 (Time) event.xclient.data.l[1]);
2418 break;
2419 }
2420 if (*event.xclient.data.l != (int) windows->wm_delete_window)
2421 break;
2422 if (event.xclient.window == windows->widget.id)
2423 {
2424 *reply_info.text='\0';
2425 state|=ExitState;
2426 break;
2427 }
2428 break;
2429 }
2430 case ConfigureNotify:
2431 {
2432 /*
2433 Update widget configuration.
2434 */
2435 if (event.xconfigure.window != windows->widget.id)
2436 break;
2437 if ((event.xconfigure.width == (int) windows->widget.width) &&
2438 (event.xconfigure.height == (int) windows->widget.height))
2439 break;
2440 windows->widget.width=(unsigned int)
2441 MagickMax(event.xconfigure.width,(int) windows->widget.min_width);
2442 windows->widget.height=(unsigned int)
2443 MagickMax(event.xconfigure.height,(int) windows->widget.min_height);
2444 state|=UpdateConfigurationState;
2445 break;
2446 }
2447 case EnterNotify:
2448 {
2449 if (event.xcrossing.window != windows->widget.id)
2450 break;
2451 state&=(~InactiveWidgetState);
2452 break;
2453 }
2454 case Expose:
2455 {
2456 if (event.xexpose.window != windows->widget.id)
2457 break;
2458 if (event.xexpose.count != 0)
2459 break;
2460 state|=RedrawWidgetState;
2461 break;
2462 }
2463 case KeyPress:
2464 {
2465 static char
2466 command[MaxTextExtent];
2467
2468 static int
2469 length;
2470
2471 static KeySym
2472 key_symbol;
2473
2474 /*
2475 Respond to a user key press.
2476 */
2477 if (event.xkey.window != windows->widget.id)
2478 break;
2479 length=XLookupString((XKeyEvent *) &event.xkey,command,
2480 (int) sizeof(command),&key_symbol,(XComposeStatus *) NULL);
2481 *(command+length)='\0';
2482 if (AreaIsActive(scroll_info,event.xkey))
2483 {
2484 /*
2485 Move slider.
2486 */
2487 switch ((int) key_symbol)
2488 {
2489 case XK_Home:
2490 case XK_KP_Home:
2491 {
2492 slider_info.id=0;
2493 break;
2494 }
2495 case XK_Up:
2496 case XK_KP_Up:
2497 {
2498 slider_info.id--;
2499 break;
2500 }
2501 case XK_Down:
2502 case XK_KP_Down:
2503 {
2504 slider_info.id++;
2505 break;
2506 }
2507 case XK_Prior:
2508 case XK_KP_Prior:
2509 {
2510 slider_info.id-=visible_colors;
2511 break;
2512 }
2513 case XK_Next:
2514 case XK_KP_Next:
2515 {
2516 slider_info.id+=visible_colors;
2517 break;
2518 }
2519 case XK_End:
2520 case XK_KP_End:
2521 {
2522 slider_info.id=(int) colors;
2523 break;
2524 }
2525 }
2526 state|=RedrawListState;
2527 break;
2528 }
2529 if ((key_symbol == XK_Return) || (key_symbol == XK_KP_Enter))
2530 {
2531 /*
2532 Read new color or glob patterm.
2533 */
2534 if (*reply_info.text == '\0')
2535 break;
2536 (void) CopyMagickString(glob_pattern,reply_info.text,MaxTextExtent);
2537 state|=UpdateListState;
2538 break;
2539 }
2540 if (key_symbol == XK_Control_L)
2541 {
2542 state|=ControlState;
2543 break;
2544 }
2545 if (state & ControlState)
2546 switch ((int) key_symbol)
2547 {
2548 case XK_u:
2549 case XK_U:
2550 {
2551 /*
2552 Erase the entire line of text.
2553 */
2554 *reply_info.text='\0';
2555 reply_info.cursor=reply_info.text;
2556 reply_info.marker=reply_info.text;
2557 reply_info.highlight=MagickFalse;
2558 break;
2559 }
2560 default:
2561 break;
2562 }
2563 XEditText(display,&reply_info,key_symbol,command,state);
2564 XDrawMatteText(display,&windows->widget,&reply_info);
2565 state|=JumpListState;
2566 status=XParseColor(display,windows->widget.map_info->colormap,
2567 reply_info.text,&color);
2568 if (status != False)
2569 state|=RedrawActionState;
2570 break;
2571 }
2572 case KeyRelease:
2573 {
2574 static char
2575 command[MaxTextExtent];
2576
2577 static KeySym
2578 key_symbol;
2579
2580 /*
2581 Respond to a user key release.
2582 */
2583 if (event.xkey.window != windows->widget.id)
2584 break;
2585 (void) XLookupString((XKeyEvent *) &event.xkey,command,
2586 (int) sizeof(command),&key_symbol,(XComposeStatus *) NULL);
2587 if (key_symbol == XK_Control_L)
2588 state&=(~ControlState);
2589 break;
2590 }
2591 case LeaveNotify:
2592 {
2593 if (event.xcrossing.window != windows->widget.id)
2594 break;
2595 state|=InactiveWidgetState;
2596 break;
2597 }
2598 case MapNotify:
2599 {
2600 mask&=(~CWX);
2601 mask&=(~CWY);
2602 break;
2603 }
2604 case MotionNotify:
2605 {
2606 /*
2607 Discard pending button motion events.
2608 */
2609 while (XCheckMaskEvent(display,ButtonMotionMask,&event)) ;
2610 if (slider_info.active)
2611 {
2612 /*
2613 Move slider matte.
2614 */
2615 slider_info.y=event.xmotion.y-
2616 ((slider_info.height+slider_info.bevel_width) >> 1)+1;
2617 if (slider_info.y < slider_info.min_y)
2618 slider_info.y=slider_info.min_y;
2619 if (slider_info.y > slider_info.max_y)
2620 slider_info.y=slider_info.max_y;
2621 slider_info.id=0;
2622 if (slider_info.y != slider_info.min_y)
2623 slider_info.id=(int) ((colors*(slider_info.y-
2624 slider_info.min_y+1))/(slider_info.max_y-slider_info.min_y+1));
2625 state|=RedrawListState;
2626 break;
2627 }
2628 if (state & InactiveWidgetState)
2629 break;
2630 if (grab_info.raised == MatteIsActive(grab_info,event.xmotion))
2631 {
2632 /*
2633 Grab button status changed.
2634 */
2635 grab_info.raised=!grab_info.raised;
2636 XDrawBeveledButton(display,&windows->widget,&grab_info);
2637 break;
2638 }
2639 if (reset_info.raised == MatteIsActive(reset_info,event.xmotion))
2640 {
2641 /*
2642 Reset button status changed.
2643 */
2644 reset_info.raised=!reset_info.raised;
2645 XDrawBeveledButton(display,&windows->widget,&reset_info);
2646 break;
2647 }
2648 if (action_info.raised == MatteIsActive(action_info,event.xmotion))
2649 {
2650 /*
2651 Action button status changed.
2652 */
2653 action_info.raised=action_info.raised == MagickFalse ?
2654 MagickTrue : MagickFalse;
2655 XDrawBeveledButton(display,&windows->widget,&action_info);
2656 break;
2657 }
2658 if (cancel_info.raised == MatteIsActive(cancel_info,event.xmotion))
2659 {
2660 /*
2661 Cancel button status changed.
2662 */
2663 cancel_info.raised=cancel_info.raised == MagickFalse ?
2664 MagickTrue : MagickFalse;
2665 XDrawBeveledButton(display,&windows->widget,&cancel_info);
2666 break;
2667 }
2668 break;
2669 }
2670 case SelectionClear:
2671 {
2672 reply_info.highlight=MagickFalse;
2673 XDrawMatteText(display,&windows->widget,&reply_info);
2674 break;
2675 }
2676 case SelectionNotify:
2677 {
2678 Atom
2679 type;
2680
2681 int
2682 format;
2683
2684 unsigned char
2685 *data;
2686
cristyf2faecf2010-05-28 19:19:36 +00002687 unsigned long
cristy3ed852e2009-09-05 21:47:34 +00002688 after,
2689 length;
2690
2691 /*
2692 Obtain response from primary selection.
2693 */
2694 if (event.xselection.property == (Atom) None)
2695 break;
2696 status=XGetWindowProperty(display,event.xselection.requestor,
2697 event.xselection.property,0L,2047L,MagickTrue,XA_STRING,&type,
2698 &format,&length,&after,&data);
2699 if ((status != Success) || (type != XA_STRING) || (format == 32) ||
2700 (length == 0))
2701 break;
2702 if ((Extent(reply_info.text)+length) >= MaxTextExtent)
2703 (void) XBell(display,0);
2704 else
2705 {
2706 /*
2707 Insert primary selection in reply text.
2708 */
2709 *(data+length)='\0';
2710 XEditText(display,&reply_info,(KeySym) XK_Insert,(char *) data,
2711 state);
2712 XDrawMatteText(display,&windows->widget,&reply_info);
2713 state|=JumpListState;
2714 state|=RedrawActionState;
2715 }
2716 (void) XFree((void *) data);
2717 break;
2718 }
2719 case SelectionRequest:
2720 {
2721 XSelectionEvent
2722 notify;
2723
2724 XSelectionRequestEvent
2725 *request;
2726
2727 if (reply_info.highlight == MagickFalse)
2728 break;
2729 /*
2730 Set primary selection.
2731 */
2732 request=(&(event.xselectionrequest));
2733 (void) XChangeProperty(request->display,request->requestor,
2734 request->property,request->target,8,PropModeReplace,
2735 (unsigned char *) primary_selection,Extent(primary_selection));
2736 notify.type=SelectionNotify;
2737 notify.send_event=MagickTrue;
2738 notify.display=request->display;
2739 notify.requestor=request->requestor;
2740 notify.selection=request->selection;
2741 notify.target=request->target;
2742 notify.time=request->time;
2743 if (request->property == None)
2744 notify.property=request->target;
2745 else
2746 notify.property=request->property;
2747 (void) XSendEvent(request->display,request->requestor,False,
2748 NoEventMask,(XEvent *) &notify);
2749 }
2750 default:
2751 break;
2752 }
2753 } while ((state & ExitState) == 0);
2754 XSetCursorState(display,windows,MagickFalse);
2755 (void) XWithdrawWindow(display,windows->widget.id,windows->widget.screen);
2756 XCheckRefreshWindows(display,windows);
2757 /*
2758 Free color list.
2759 */
cristy49e2d862010-11-12 02:50:30 +00002760 for (i=0; i < (int) colors; i++)
cristy3ed852e2009-09-05 21:47:34 +00002761 colorlist[i]=DestroyString(colorlist[i]);
2762 if (colorlist != (char **) NULL)
2763 colorlist=(char **) RelinquishMagickMemory(colorlist);
2764 exception=DestroyExceptionInfo(exception);
2765 if ((*reply == '\0') || (strchr(reply,'-') != (char *) NULL))
2766 return;
2767 status=XParseColor(display,windows->widget.map_info->colormap,reply,&color);
2768 if (status != False)
2769 return;
2770 XNoticeWidget(display,windows,"Color is unknown to X server:",reply);
2771 (void) CopyMagickString(reply,"gray",MaxTextExtent);
2772}
2773
2774/*
2775%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2776% %
2777% %
2778% %
2779% X C o m m a n d W i d g e t %
2780% %
2781% %
2782% %
2783%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2784%
2785% XCommandWidget() maps a menu and returns the command pointed to by the user
2786% when the button is released.
2787%
2788% The format of the XCommandWidget method is:
2789%
2790% int XCommandWidget(Display *display,XWindows *windows,
2791% const char **selections,XEvent *event)
2792%
2793% A description of each parameter follows:
2794%
2795% o selection_number: Specifies the number of the selection that the
2796% user choose.
2797%
2798% o display: Specifies a connection to an X server; returned from
2799% XOpenDisplay.
2800%
2801% o window: Specifies a pointer to a XWindows structure.
2802%
2803% o selections: Specifies a pointer to one or more strings that comprise
2804% the choices in the menu.
2805%
2806% o event: Specifies a pointer to a X11 XEvent structure.
2807%
2808*/
2809MagickExport int XCommandWidget(Display *display,XWindows *windows,
2810 const char **selections,XEvent *event)
2811{
2812#define tile_width 112
2813#define tile_height 70
2814
2815 static const unsigned char
2816 tile_bits[]=
2817 {
2818 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2819 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2820 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2821 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00,
2822 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00,
2823 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x00,
2824 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2825 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2826 0x00, 0x00, 0x1e, 0x38, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2827 0x00, 0x00, 0x00, 0x00, 0x1e, 0xbc, 0x9f, 0x03, 0x00, 0x3e, 0x00, 0xc0,
2828 0x1f, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x1e, 0xfc, 0xff, 0x0f, 0x80, 0x3f,
2829 0x00, 0xf0, 0x1f, 0xc0, 0x0f, 0x00, 0x00, 0x00, 0x1e, 0xfc, 0xff, 0x1f,
2830 0xe0, 0x3f, 0x00, 0xfc, 0x1f, 0xf0, 0x0f, 0x00, 0x00, 0x00, 0x1e, 0xfc,
2831 0xff, 0x1f, 0xf0, 0x3f, 0x00, 0xfe, 0x1f, 0xf8, 0x0f, 0x00, 0x00, 0x00,
2832 0x1e, 0xfc, 0xfc, 0x3f, 0xf8, 0x3f, 0x00, 0xff, 0x1e, 0xfc, 0x0f, 0x00,
2833 0x00, 0x00, 0x1e, 0x7c, 0xfc, 0x3e, 0xf8, 0x3c, 0x80, 0x1f, 0x1e, 0x7c,
2834 0x0f, 0x00, 0x00, 0x00, 0x1e, 0x78, 0x78, 0x3c, 0x7c, 0x3c, 0xc0, 0x0f,
2835 0x1e, 0x3e, 0x0f, 0x00, 0x00, 0x00, 0x1e, 0x78, 0x78, 0x3c, 0x7c, 0x3c,
2836 0xc0, 0x07, 0x1e, 0x3e, 0x0f, 0x00, 0x00, 0x00, 0x1e, 0x78, 0x78, 0x3c,
2837 0x7c, 0x7c, 0xc0, 0x0f, 0x1e, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x78,
2838 0x78, 0x3c, 0xfc, 0x7c, 0x80, 0x7f, 0x1e, 0x7c, 0x00, 0x00, 0x00, 0x00,
2839 0x1e, 0xf8, 0x78, 0x7c, 0xf8, 0xff, 0x00, 0xff, 0x1f, 0xf8, 0xff, 0x00,
2840 0x00, 0x00, 0x1e, 0xf8, 0x78, 0x7c, 0xf0, 0xff, 0x07, 0xfe, 0x1f, 0xf8,
2841 0xff, 0x00, 0x00, 0x00, 0x1e, 0xf8, 0x78, 0x7c, 0xf0, 0xff, 0x07, 0xf8,
2842 0x1f, 0xf0, 0xff, 0x01, 0x00, 0x00, 0x1e, 0xf8, 0x78, 0x7c, 0xc0, 0xef,
2843 0x07, 0xe0, 0x1f, 0xc0, 0xff, 0x01, 0x00, 0x00, 0x1e, 0x70, 0x40, 0x78,
2844 0x00, 0xc7, 0x07, 0x00, 0x1e, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x1e, 0x00,
2845 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00,
2846 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00,
2847 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00,
2848 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
2849 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2850 0x00, 0xc0, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2851 0x00, 0x00, 0x00, 0xe0, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2852 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00,
2853 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x01, 0x00, 0x00, 0x00,
2854 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x00, 0x00,
2855 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78,
2856 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2857 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x02, 0x00,
2858 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x07,
2859 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2860 0xc0, 0x0f, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2861 0x60, 0x00, 0xc0, 0x0f, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2862 0x00, 0x00, 0x78, 0x00, 0xc0, 0x8f, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00,
2863 0x00, 0x00, 0x00, 0x00, 0x78, 0x00, 0xc0, 0x8f, 0x3f, 0x00, 0x00, 0x00,
2864 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x00, 0xe0, 0x9f, 0x7f, 0x00,
2865 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x00, 0xe0, 0xdf,
2866 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x78, 0x00,
2867 0xe0, 0xdf, 0x7b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x0c,
2868 0x78, 0x30, 0xf0, 0xff, 0x7b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e,
2869 0x00, 0x0f, 0xf8, 0x70, 0xf0, 0xff, 0x7b, 0x00, 0x00, 0x1f, 0x00, 0xe0,
2870 0x0f, 0x1e, 0x80, 0x0f, 0xf8, 0x78, 0xf0, 0xfd, 0xf9, 0x00, 0xc0, 0x1f,
2871 0x00, 0xf8, 0x0f, 0x00, 0xe0, 0x1f, 0xf8, 0x7c, 0xf0, 0xfc, 0xf9, 0x00,
2872 0xf0, 0x1f, 0x00, 0xfe, 0x0f, 0x00, 0xf0, 0x07, 0xf8, 0x3e, 0xf8, 0xfc,
2873 0xf0, 0x01, 0xf8, 0x1f, 0x00, 0xff, 0x0f, 0x1e, 0xf0, 0x03, 0xf8, 0x3f,
2874 0xf8, 0xf8, 0xf0, 0x01, 0xfc, 0x1f, 0x80, 0x7f, 0x0f, 0x1e, 0xf8, 0x00,
2875 0xf8, 0x1f, 0x78, 0x18, 0xf0, 0x01, 0x7c, 0x1e, 0xc0, 0x0f, 0x0f, 0x1e,
2876 0x7c, 0x00, 0xf0, 0x0f, 0x78, 0x00, 0xf0, 0x01, 0x3e, 0x1e, 0xe0, 0x07,
2877 0x0f, 0x1e, 0x7c, 0x00, 0xf0, 0x07, 0x7c, 0x00, 0xe0, 0x01, 0x3e, 0x1e,
2878 0xe0, 0x03, 0x0f, 0x1e, 0x3e, 0x00, 0xf0, 0x0f, 0x7c, 0x00, 0xe0, 0x03,
2879 0x3e, 0x3e, 0xe0, 0x07, 0x0f, 0x1e, 0x1e, 0x00, 0xf0, 0x1f, 0x3c, 0x00,
2880 0xe0, 0x03, 0x7e, 0x3e, 0xc0, 0x3f, 0x0f, 0x1e, 0x3e, 0x00, 0xf0, 0x1f,
2881 0x3e, 0x00, 0xe0, 0x03, 0xfc, 0x7f, 0x80, 0xff, 0x0f, 0x1e, 0xfc, 0x00,
2882 0xf0, 0x3e, 0x3e, 0x00, 0xc0, 0x03, 0xf8, 0xff, 0x03, 0xff, 0x0f, 0x1e,
2883 0xfc, 0x07, 0xf0, 0x7c, 0x1e, 0x00, 0xc0, 0x03, 0xf8, 0xff, 0x03, 0xfc,
2884 0x0f, 0x1e, 0xf8, 0x1f, 0xf0, 0xf8, 0x1e, 0x00, 0xc0, 0x03, 0xe0, 0xf7,
2885 0x03, 0xf0, 0x0f, 0x1e, 0xe0, 0x3f, 0xf0, 0x78, 0x1c, 0x00, 0x80, 0x03,
2886 0x80, 0xe3, 0x03, 0x00, 0x0f, 0x1e, 0xc0, 0x3f, 0xf0, 0x30, 0x00, 0x00,
2887 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x0e, 0x00, 0x3e, 0x00, 0x00,
2888 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x0f, 0x00, 0x00, 0x10,
2889 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x0f, 0x00,
2890 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
2891 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2892 0x00, 0xe0, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2893 0x00, 0x00, 0x00, 0xf0, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2894 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
2895 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x00, 0x00,
2896 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00,
2897 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c,
2898 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2899 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
2900 };
2901
2902 int
2903 id,
2904 y;
2905
2906 register int
2907 i;
2908
2909 static unsigned int
2910 number_selections;
2911
2912 unsigned int
2913 height;
2914
cristybb503372010-05-27 20:51:26 +00002915 size_t
cristy3ed852e2009-09-05 21:47:34 +00002916 state;
2917
2918 XFontStruct
2919 *font_info;
2920
2921 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
2922 assert(display != (Display *) NULL);
2923 assert(windows != (XWindows *) NULL);
2924 font_info=windows->command.font_info;
2925 height=(unsigned int) (font_info->ascent+font_info->descent);
2926 id=(~0);
2927 state=DefaultState;
2928 if (event == (XEvent *) NULL)
2929 {
2930 unsigned int
2931 width;
2932
2933 XTextProperty
2934 window_name;
2935
2936 XWindowChanges
2937 window_changes;
2938
2939 /*
2940 Determine command window attributes.
2941 */
2942 assert(selections != (const char **) NULL);
2943 windows->command.width=0;
2944 for (i=0; selections[i] != (char *) NULL; i++)
2945 {
2946 width=WidgetTextWidth(font_info,(char *) selections[i]);
2947 if (width > windows->command.width)
2948 windows->command.width=width;
2949 }
2950 number_selections=(unsigned int) i;
2951 windows->command.width+=3*QuantumMargin+10;
2952 if ((int) windows->command.width < (tile_width+QuantumMargin+10))
2953 windows->command.width=(unsigned int) (tile_width+QuantumMargin+10);
2954 windows->command.height=(unsigned int) (number_selections*
2955 (((3*height) >> 1)+10)+tile_height+20);
2956 windows->command.min_width=windows->command.width;
2957 windows->command.min_height=windows->command.height;
2958 XConstrainWindowPosition(display,&windows->command);
2959 if (windows->command.id != (Window) NULL)
2960 {
2961 Status
2962 status;
2963
2964 /*
2965 Reconfigure command window.
2966 */
2967 status=XStringListToTextProperty(&windows->command.name,1,
2968 &window_name);
2969 if (status != False)
2970 {
2971 XSetWMName(display,windows->command.id,&window_name);
2972 XSetWMIconName(display,windows->command.id,&window_name);
2973 (void) XFree((void *) window_name.value);
2974 }
2975 window_changes.width=(int) windows->command.width;
2976 window_changes.height=(int) windows->command.height;
2977 (void) XReconfigureWMWindow(display,windows->command.id,
2978 windows->command.screen,(unsigned int) (CWWidth | CWHeight),
2979 &window_changes);
2980 }
2981 /*
2982 Allocate selection info memory.
2983 */
2984 if (selection_info != (XWidgetInfo *) NULL)
2985 selection_info=(XWidgetInfo *) RelinquishMagickMemory(selection_info);
2986 selection_info=(XWidgetInfo *) AcquireQuantumMemory(number_selections,
2987 sizeof(*selection_info));
2988 if (selection_info == (XWidgetInfo *) NULL)
2989 {
2990 ThrowXWindowFatalException(ResourceLimitError,
2991 "MemoryAllocationFailed","...");
2992 return(id);
2993 }
2994 state|=UpdateConfigurationState | RedrawWidgetState;
2995 }
2996 /*
2997 Wait for next event.
2998 */
2999 if (event != (XEvent *) NULL)
3000 switch (event->type)
3001 {
3002 case ButtonPress:
3003 {
3004 for (i=0; i < (int) number_selections; i++)
3005 {
3006 if (MatteIsActive(selection_info[i],event->xbutton) == MagickFalse)
3007 continue;
3008 if (i >= (int) windows->command.data)
3009 {
3010 selection_info[i].raised=MagickFalse;
3011 XDrawBeveledButton(display,&windows->command,&selection_info[i]);
3012 break;
3013 }
3014 submenu_info=selection_info[i];
3015 submenu_info.active=MagickTrue;
3016 toggle_info.y=
3017 submenu_info.y+(submenu_info.height >> 1)-(toggle_info.height >> 1);
3018 id=i;
3019 (void) XCheckWindowEvent(display,windows->widget.id,LeaveWindowMask,
3020 event);
3021 break;
3022 }
3023 break;
3024 }
3025 case ButtonRelease:
3026 {
3027 for (i=0; i < (int) number_selections; i++)
3028 {
3029 if (MatteIsActive(selection_info[i],event->xbutton) == MagickFalse)
3030 continue;
3031 id=i;
3032 if (id >= (int) windows->command.data)
3033 {
3034 selection_info[id].raised=MagickTrue;
3035 XDrawBeveledButton(display,&windows->command,&selection_info[id]);
3036 break;
3037 }
3038 break;
3039 }
3040 break;
3041 }
3042 case ClientMessage:
3043 {
3044 /*
3045 If client window delete message, withdraw command widget.
3046 */
3047 if (event->xclient.message_type != windows->wm_protocols)
3048 break;
3049 if (*event->xclient.data.l != (int) windows->wm_delete_window)
3050 break;
3051 (void) XWithdrawWindow(display,windows->command.id,
3052 windows->command.screen);
3053 break;
3054 }
3055 case ConfigureNotify:
3056 {
3057 /*
3058 Update widget configuration.
3059 */
3060 if (event->xconfigure.window != windows->command.id)
3061 break;
3062 if (event->xconfigure.send_event != 0)
3063 {
3064 windows->command.x=event->xconfigure.x;
3065 windows->command.y=event->xconfigure.y;
3066 }
3067 if ((event->xconfigure.width == (int) windows->command.width) &&
3068 (event->xconfigure.height == (int) windows->command.height))
3069 break;
3070 windows->command.width=(unsigned int)
3071 MagickMax(event->xconfigure.width,(int) windows->command.min_width);
3072 windows->command.height=(unsigned int)
3073 MagickMax(event->xconfigure.height,(int) windows->command.min_height);
3074 state|=UpdateConfigurationState;
3075 break;
3076 }
3077 case Expose:
3078 {
3079 if (event->xexpose.window != windows->command.id)
3080 break;
3081 if (event->xexpose.count != 0)
3082 break;
3083 state|=RedrawWidgetState;
3084 break;
3085 }
3086 case MotionNotify:
3087 {
3088 /*
3089 Return the ID of the highlighted menu entry.
3090 */
3091 for ( ; ; )
3092 {
3093 for (i=0; i < (int) number_selections; i++)
3094 {
3095 if (i >= (int) windows->command.data)
3096 {
3097 if (selection_info[i].raised ==
3098 MatteIsActive(selection_info[i],event->xmotion))
3099 {
3100 /*
3101 Button status changed.
3102 */
3103 selection_info[i].raised=!selection_info[i].raised;
3104 XDrawBeveledButton(display,&windows->command,
3105 &selection_info[i]);
3106 }
3107 continue;
3108 }
3109 if (MatteIsActive(selection_info[i],event->xmotion) == MagickFalse)
3110 continue;
3111 submenu_info=selection_info[i];
3112 submenu_info.active=MagickTrue;
3113 toggle_info.raised=MagickTrue;
3114 toggle_info.y=submenu_info.y+(submenu_info.height >> 1)-
3115 (toggle_info.height >> 1);
3116 XDrawTriangleEast(display,&windows->command,&toggle_info);
3117 id=i;
3118 }
3119 XDelay(display,SuspendTime);
3120 if (XCheckMaskEvent(display,ButtonMotionMask,event) == MagickFalse)
3121 break;
3122 while (XCheckMaskEvent(display,ButtonMotionMask,event)) ;
3123 toggle_info.raised=MagickFalse;
3124 if (windows->command.data != 0)
3125 XDrawTriangleEast(display,&windows->command,&toggle_info);
3126 }
3127 break;
3128 }
3129 case MapNotify:
3130 {
3131 windows->command.mapped=MagickTrue;
3132 break;
3133 }
3134 case UnmapNotify:
3135 {
3136 windows->command.mapped=MagickFalse;
3137 break;
3138 }
3139 default:
3140 break;
3141 }
3142 if (state & UpdateConfigurationState)
3143 {
3144 /*
3145 Initialize button information.
3146 */
3147 assert(selections != (const char **) NULL);
3148 y=tile_height+20;
3149 for (i=0; i < (int) number_selections; i++)
3150 {
3151 XGetWidgetInfo(selections[i],&selection_info[i]);
3152 selection_info[i].center=MagickFalse;
3153 selection_info[i].bevel_width--;
3154 selection_info[i].height=(unsigned int) ((3*height) >> 1);
3155 selection_info[i].x=(QuantumMargin >> 1)+4;
3156 selection_info[i].width=(unsigned int)
3157 (windows->command.width-(selection_info[i].x << 1));
3158 selection_info[i].y=y;
3159 y+=selection_info[i].height+(selection_info[i].bevel_width << 1)+6;
3160 }
3161 XGetWidgetInfo((char *) NULL,&toggle_info);
3162 toggle_info.bevel_width--;
3163 toggle_info.width=(unsigned int)
3164 (((5*height) >> 3)-(toggle_info.bevel_width << 1));
3165 toggle_info.height=toggle_info.width;
3166 toggle_info.x=selection_info[0].x+selection_info[0].width-
3167 toggle_info.width-(QuantumMargin >> 1);
3168 if (windows->command.mapped)
3169 (void) XClearWindow(display,windows->command.id);
3170 }
3171 if (state & RedrawWidgetState)
3172 {
3173 Pixmap
3174 tile_pixmap;
3175
3176 /*
3177 Draw command buttons.
3178 */
3179 tile_pixmap=XCreatePixmapFromBitmapData(display,windows->command.id,
3180 (char *) tile_bits,tile_width,tile_height,1L,0L,1);
3181 if (tile_pixmap != (Pixmap) NULL)
3182 {
3183 (void) XCopyPlane(display,tile_pixmap,windows->command.id,
3184 windows->command.annotate_context,0,0,tile_width,tile_height,
3185 (int) ((windows->command.width-tile_width) >> 1),10,1L);
3186 (void) XFreePixmap(display,tile_pixmap);
3187 }
3188 for (i=0; i < (int) number_selections; i++)
3189 {
3190 XDrawBeveledButton(display,&windows->command,&selection_info[i]);
3191 if (i >= (int) windows->command.data)
3192 continue;
3193 toggle_info.raised=i == id ? MagickTrue : MagickFalse;
3194 toggle_info.y=selection_info[i].y+
3195 (selection_info[i].height >> 1)-(toggle_info.height >> 1);
3196 XDrawTriangleEast(display,&windows->command,&toggle_info);
3197 }
3198 XHighlightWidget(display,&windows->command,BorderOffset,BorderOffset);
3199 }
3200 return(id);
3201}
3202
3203/*
3204%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3205% %
3206% %
3207% %
3208% X C o n f i r m W i d g e t %
3209% %
3210% %
3211% %
3212%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3213%
3214% XConfirmWidget() displays a Confirm widget with a notice to the user. The
3215% function returns -1 if Dismiss is pressed, 0 for Cancel, and 1 for Yes.
3216%
3217% The format of the XConfirmWidget method is:
3218%
3219% int XConfirmWidget(Display *display,XWindows *windows,
3220% const char *reason,const char *description)
3221%
3222% A description of each parameter follows:
3223%
3224% o display: Specifies a connection to an X server; returned from
3225% XOpenDisplay.
3226%
3227% o window: Specifies a pointer to a XWindows structure.
3228%
3229% o reason: Specifies the message to display before terminating the
3230% program.
3231%
3232% o description: Specifies any description to the message.
3233%
3234*/
3235MagickExport int XConfirmWidget(Display *display,XWindows *windows,
3236 const char *reason,const char *description)
3237{
3238#define CancelButtonText "Cancel"
3239#define DismissButtonText "Dismiss"
3240#define YesButtonText "Yes"
3241
3242 int
3243 confirm,
3244 x,
3245 y;
3246
3247 Status
3248 status;
3249
3250 unsigned int
3251 height,
3252 width;
3253
cristybb503372010-05-27 20:51:26 +00003254 size_t
cristy3ed852e2009-09-05 21:47:34 +00003255 state;
3256
3257 XEvent
3258 event;
3259
3260 XFontStruct
3261 *font_info;
3262
3263 XTextProperty
3264 window_name;
3265
3266 XWidgetInfo
3267 cancel_info,
3268 dismiss_info,
3269 yes_info;
3270
3271 XWindowChanges
3272 window_changes;
3273
3274 /*
3275 Determine Confirm widget attributes.
3276 */
3277 assert(display != (Display *) NULL);
3278 assert(windows != (XWindows *) NULL);
3279 assert(reason != (char *) NULL);
3280 assert(description != (char *) NULL);
3281 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",reason);
3282 XCheckRefreshWindows(display,windows);
3283 font_info=windows->widget.font_info;
3284 width=WidgetTextWidth(font_info,CancelButtonText);
3285 if (WidgetTextWidth(font_info,DismissButtonText) > width)
3286 width=WidgetTextWidth(font_info,DismissButtonText);
3287 if (WidgetTextWidth(font_info,YesButtonText) > width)
3288 width=WidgetTextWidth(font_info,YesButtonText);
3289 width<<=1;
3290 if (description != (char *) NULL)
3291 if (WidgetTextWidth(font_info,(char *) description) > width)
3292 width=WidgetTextWidth(font_info,(char *) description);
3293 height=(unsigned int) (font_info->ascent+font_info->descent);
3294 /*
3295 Position Confirm widget.
3296 */
3297 windows->widget.width=(unsigned int) (width+9*QuantumMargin);
3298 windows->widget.min_width=(unsigned int) (9*QuantumMargin+
3299 WidgetTextWidth(font_info,CancelButtonText)+
3300 WidgetTextWidth(font_info,DismissButtonText)+
3301 WidgetTextWidth(font_info,YesButtonText));
3302 if (windows->widget.width < windows->widget.min_width)
3303 windows->widget.width=windows->widget.min_width;
3304 windows->widget.height=(unsigned int) (12*height);
3305 windows->widget.min_height=(unsigned int) (7*height);
3306 if (windows->widget.height < windows->widget.min_height)
3307 windows->widget.height=windows->widget.min_height;
3308 XConstrainWindowPosition(display,&windows->widget);
3309 /*
3310 Map Confirm widget.
3311 */
3312 (void) CopyMagickString(windows->widget.name,"Confirm",MaxTextExtent);
3313 status=XStringListToTextProperty(&windows->widget.name,1,&window_name);
3314 if (status != False)
3315 {
3316 XSetWMName(display,windows->widget.id,&window_name);
3317 XSetWMIconName(display,windows->widget.id,&window_name);
3318 (void) XFree((void *) window_name.value);
3319 }
3320 window_changes.width=(int) windows->widget.width;
3321 window_changes.height=(int) windows->widget.height;
3322 window_changes.x=windows->widget.x;
3323 window_changes.y=windows->widget.y;
3324 (void) XReconfigureWMWindow(display,windows->widget.id,windows->widget.screen,
3325 (unsigned int) (CWWidth | CWHeight | CWX | CWY),&window_changes);
3326 (void) XMapRaised(display,windows->widget.id);
3327 windows->widget.mapped=MagickFalse;
3328 /*
3329 Respond to X events.
3330 */
3331 confirm=0;
3332 state=UpdateConfigurationState;
3333 XSetCursorState(display,windows,MagickTrue);
3334 do
3335 {
3336 if (state & UpdateConfigurationState)
3337 {
3338 /*
3339 Initialize button information.
3340 */
3341 XGetWidgetInfo(CancelButtonText,&cancel_info);
3342 cancel_info.width=(unsigned int) QuantumMargin+
3343 WidgetTextWidth(font_info,CancelButtonText);
3344 cancel_info.height=(unsigned int) ((3*height) >> 1);
3345 cancel_info.x=(int) (windows->widget.width-cancel_info.width-
3346 QuantumMargin);
3347 cancel_info.y=(int) (windows->widget.height-(cancel_info.height << 1));
3348 dismiss_info=cancel_info;
3349 dismiss_info.text=(char *) DismissButtonText;
3350 if (LocaleCompare(description,"Do you want to save it") == 0)
3351 dismiss_info.text=(char *) "Don't Save";
3352 dismiss_info.width=(unsigned int) QuantumMargin+
3353 WidgetTextWidth(font_info,dismiss_info.text);
3354 dismiss_info.x=(int)
3355 ((windows->widget.width >> 1)-(dismiss_info.width >> 1));
3356 yes_info=cancel_info;
3357 yes_info.text=(char *) YesButtonText;
3358 if (LocaleCompare(description,"Do you want to save it") == 0)
3359 yes_info.text=(char *) "Save";
3360 yes_info.width=(unsigned int) QuantumMargin+
3361 WidgetTextWidth(font_info,yes_info.text);
3362 if (yes_info.width < cancel_info.width)
3363 yes_info.width=cancel_info.width;
3364 yes_info.x=QuantumMargin;
3365 state&=(~UpdateConfigurationState);
3366 }
3367 if (state & RedrawWidgetState)
3368 {
3369 /*
3370 Redraw Confirm widget.
3371 */
3372 width=WidgetTextWidth(font_info,(char *) reason);
3373 x=(int) ((windows->widget.width >> 1)-(width >> 1));
3374 y=(int) ((windows->widget.height >> 1)-(height << 1));
3375 (void) XDrawString(display,windows->widget.id,
3376 windows->widget.annotate_context,x,y,(char *) reason,Extent(reason));
3377 if (description != (char *) NULL)
3378 {
3379 char
3380 question[MaxTextExtent];
3381
3382 (void) CopyMagickString(question,description,MaxTextExtent);
3383 (void) ConcatenateMagickString(question,"?",MaxTextExtent);
3384 width=WidgetTextWidth(font_info,question);
3385 x=(int) ((windows->widget.width >> 1)-(width >> 1));
3386 y+=height;
3387 (void) XDrawString(display,windows->widget.id,
3388 windows->widget.annotate_context,x,y,question,Extent(question));
3389 }
3390 XDrawBeveledButton(display,&windows->widget,&cancel_info);
3391 XDrawBeveledButton(display,&windows->widget,&dismiss_info);
3392 XDrawBeveledButton(display,&windows->widget,&yes_info);
3393 XHighlightWidget(display,&windows->widget,BorderOffset,BorderOffset);
3394 state&=(~RedrawWidgetState);
3395 }
3396 /*
3397 Wait for next event.
3398 */
3399 (void) XIfEvent(display,&event,XScreenEvent,(char *) windows);
3400 switch (event.type)
3401 {
3402 case ButtonPress:
3403 {
3404 if (MatteIsActive(cancel_info,event.xbutton))
3405 {
3406 /*
3407 User pressed No button.
3408 */
3409 cancel_info.raised=MagickFalse;
3410 XDrawBeveledButton(display,&windows->widget,&cancel_info);
3411 break;
3412 }
3413 if (MatteIsActive(dismiss_info,event.xbutton))
3414 {
3415 /*
3416 User pressed Dismiss button.
3417 */
3418 dismiss_info.raised=MagickFalse;
3419 XDrawBeveledButton(display,&windows->widget,&dismiss_info);
3420 break;
3421 }
3422 if (MatteIsActive(yes_info,event.xbutton))
3423 {
3424 /*
3425 User pressed Yes button.
3426 */
3427 yes_info.raised=MagickFalse;
3428 XDrawBeveledButton(display,&windows->widget,&yes_info);
3429 break;
3430 }
3431 break;
3432 }
3433 case ButtonRelease:
3434 {
3435 if (windows->widget.mapped == MagickFalse)
3436 break;
3437 if (cancel_info.raised == MagickFalse)
3438 {
3439 if (event.xbutton.window == windows->widget.id)
3440 if (MatteIsActive(cancel_info,event.xbutton))
3441 {
3442 confirm=0;
3443 state|=ExitState;
3444 }
3445 cancel_info.raised=MagickTrue;
3446 XDrawBeveledButton(display,&windows->widget,&cancel_info);
3447 }
3448 if (dismiss_info.raised == MagickFalse)
3449 {
3450 if (event.xbutton.window == windows->widget.id)
3451 if (MatteIsActive(dismiss_info,event.xbutton))
3452 {
3453 confirm=(-1);
3454 state|=ExitState;
3455 }
3456 dismiss_info.raised=MagickTrue;
3457 XDrawBeveledButton(display,&windows->widget,&dismiss_info);
3458 }
3459 if (yes_info.raised == MagickFalse)
3460 {
3461 if (event.xbutton.window == windows->widget.id)
3462 if (MatteIsActive(yes_info,event.xbutton))
3463 {
3464 confirm=1;
3465 state|=ExitState;
3466 }
3467 yes_info.raised=MagickTrue;
3468 XDrawBeveledButton(display,&windows->widget,&yes_info);
3469 }
3470 break;
3471 }
3472 case ClientMessage:
3473 {
3474 /*
3475 If client window delete message, exit.
3476 */
3477 if (event.xclient.message_type != windows->wm_protocols)
3478 break;
3479 if (*event.xclient.data.l == (int) windows->wm_take_focus)
3480 {
3481 (void) XSetInputFocus(display,event.xclient.window,RevertToParent,
3482 (Time) event.xclient.data.l[1]);
3483 break;
3484 }
3485 if (*event.xclient.data.l != (int) windows->wm_delete_window)
3486 break;
3487 if (event.xclient.window == windows->widget.id)
3488 {
3489 state|=ExitState;
3490 break;
3491 }
3492 break;
3493 }
3494 case ConfigureNotify:
3495 {
3496 /*
3497 Update widget configuration.
3498 */
3499 if (event.xconfigure.window != windows->widget.id)
3500 break;
3501 if ((event.xconfigure.width == (int) windows->widget.width) &&
3502 (event.xconfigure.height == (int) windows->widget.height))
3503 break;
3504 windows->widget.width=(unsigned int)
3505 MagickMax(event.xconfigure.width,(int) windows->widget.min_width);
3506 windows->widget.height=(unsigned int)
3507 MagickMax(event.xconfigure.height,(int) windows->widget.min_height);
3508 state|=UpdateConfigurationState;
3509 break;
3510 }
3511 case EnterNotify:
3512 {
3513 if (event.xcrossing.window != windows->widget.id)
3514 break;
3515 state&=(~InactiveWidgetState);
3516 break;
3517 }
3518 case Expose:
3519 {
3520 if (event.xexpose.window != windows->widget.id)
3521 break;
3522 if (event.xexpose.count != 0)
3523 break;
3524 state|=RedrawWidgetState;
3525 break;
3526 }
3527 case KeyPress:
3528 {
3529 static char
3530 command[MaxTextExtent];
3531
3532 static KeySym
3533 key_symbol;
3534
3535 /*
3536 Respond to a user key press.
3537 */
3538 if (event.xkey.window != windows->widget.id)
3539 break;
3540 (void) XLookupString((XKeyEvent *) &event.xkey,command,
3541 (int) sizeof(command),&key_symbol,(XComposeStatus *) NULL);
3542 if ((key_symbol == XK_Return) || (key_symbol == XK_KP_Enter))
3543 {
3544 yes_info.raised=MagickFalse;
3545 XDrawBeveledButton(display,&windows->widget,&yes_info);
3546 confirm=1;
3547 state|=ExitState;
3548 break;
3549 }
3550 break;
3551 }
3552 case LeaveNotify:
3553 {
3554 if (event.xcrossing.window != windows->widget.id)
3555 break;
3556 state|=InactiveWidgetState;
3557 break;
3558 }
3559 case MotionNotify:
3560 {
3561 /*
3562 Discard pending button motion events.
3563 */
3564 while (XCheckMaskEvent(display,ButtonMotionMask,&event)) ;
3565 if (state & InactiveWidgetState)
3566 break;
3567 if (cancel_info.raised == MatteIsActive(cancel_info,event.xmotion))
3568 {
3569 /*
3570 Cancel button status changed.
3571 */
3572 cancel_info.raised=cancel_info.raised == MagickFalse ?
3573 MagickTrue : MagickFalse;
3574 XDrawBeveledButton(display,&windows->widget,&cancel_info);
3575 break;
3576 }
3577 if (dismiss_info.raised == MatteIsActive(dismiss_info,event.xmotion))
3578 {
3579 /*
3580 Dismiss button status changed.
3581 */
3582 dismiss_info.raised=cancel_info.raised == MagickFalse ?
3583 MagickTrue : MagickFalse;
3584 XDrawBeveledButton(display,&windows->widget,&dismiss_info);
3585 break;
3586 }
3587 if (yes_info.raised == MatteIsActive(yes_info,event.xmotion))
3588 {
3589 /*
3590 Yes button status changed.
3591 */
3592 yes_info.raised=yes_info.raised == MagickFalse ?
3593 MagickTrue : MagickFalse;
3594 XDrawBeveledButton(display,&windows->widget,&yes_info);
3595 break;
3596 }
3597 break;
3598 }
3599 default:
3600 break;
3601 }
3602 } while ((state & ExitState) == 0);
3603 XSetCursorState(display,windows,MagickFalse);
3604 (void) XWithdrawWindow(display,windows->widget.id,windows->widget.screen);
3605 XCheckRefreshWindows(display,windows);
3606 return(confirm);
3607}
3608
3609/*
3610%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3611% %
3612% %
3613% %
3614% X D i a l o g W i d g e t %
3615% %
3616% %
3617% %
3618%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3619%
3620% XDialogWidget() displays a Dialog widget with a query to the user. The user
3621% keys a reply and presses the Ok or Cancel button to exit. The typed text is
3622% returned as the reply function parameter.
3623%
3624% The format of the XDialogWidget method is:
3625%
3626% int XDialogWidget(Display *display,XWindows *windows,const char *action,
3627% const char *query,char *reply)
3628%
3629% A description of each parameter follows:
3630%
3631% o display: Specifies a connection to an X server; returned from
3632% XOpenDisplay.
3633%
3634% o window: Specifies a pointer to a XWindows structure.
3635%
3636% o action: Specifies a pointer to the action of this widget.
3637%
3638% o query: Specifies a pointer to the query to present to the user.
3639%
3640% o reply: the response from the user is returned in this parameter.
3641%
3642*/
3643MagickExport int XDialogWidget(Display *display,XWindows *windows,
3644 const char *action,const char *query,char *reply)
3645{
3646#define CancelButtonText "Cancel"
3647
3648 char
3649 primary_selection[MaxTextExtent];
3650
3651 int
3652 x;
3653
3654 register int
3655 i;
3656
3657 static MagickBooleanType
3658 raised = MagickFalse;
3659
3660 Status
3661 status;
3662
3663 unsigned int
3664 anomaly,
3665 height,
3666 width;
3667
cristybb503372010-05-27 20:51:26 +00003668 size_t
cristy3ed852e2009-09-05 21:47:34 +00003669 state;
3670
3671 XEvent
3672 event;
3673
3674 XFontStruct
3675 *font_info;
3676
3677 XTextProperty
3678 window_name;
3679
3680 XWidgetInfo
3681 action_info,
3682 cancel_info,
3683 reply_info,
3684 special_info,
3685 text_info;
3686
3687 XWindowChanges
3688 window_changes;
3689
3690 /*
3691 Determine Dialog widget attributes.
3692 */
3693 assert(display != (Display *) NULL);
3694 assert(windows != (XWindows *) NULL);
3695 assert(action != (char *) NULL);
3696 assert(query != (char *) NULL);
3697 assert(reply != (char *) NULL);
3698 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",action);
3699 XCheckRefreshWindows(display,windows);
3700 font_info=windows->widget.font_info;
3701 width=WidgetTextWidth(font_info,(char *) action);
3702 if (WidgetTextWidth(font_info,CancelButtonText) > width)
3703 width=WidgetTextWidth(font_info,CancelButtonText);
3704 width+=(3*QuantumMargin) >> 1;
3705 height=(unsigned int) (font_info->ascent+font_info->descent);
3706 /*
3707 Position Dialog widget.
3708 */
cristy49e2d862010-11-12 02:50:30 +00003709 windows->widget.width=(unsigned int) MagickMax((int) (2*width),(int)
3710 WidgetTextWidth(font_info,(char *) query));
cristy3ed852e2009-09-05 21:47:34 +00003711 if (windows->widget.width < WidgetTextWidth(font_info,reply))
3712 windows->widget.width=WidgetTextWidth(font_info,reply);
3713 windows->widget.width+=6*QuantumMargin;
3714 windows->widget.min_width=(unsigned int)
3715 (width+28*XTextWidth(font_info,"#",1)+4*QuantumMargin);
3716 if (windows->widget.width < windows->widget.min_width)
3717 windows->widget.width=windows->widget.min_width;
3718 windows->widget.height=(unsigned int) (7*height+(QuantumMargin << 1));
3719 windows->widget.min_height=windows->widget.height;
3720 if (windows->widget.height < windows->widget.min_height)
3721 windows->widget.height=windows->widget.min_height;
3722 XConstrainWindowPosition(display,&windows->widget);
3723 /*
3724 Map Dialog widget.
3725 */
3726 (void) CopyMagickString(windows->widget.name,"Dialog",MaxTextExtent);
3727 status=XStringListToTextProperty(&windows->widget.name,1,&window_name);
3728 if (status != False)
3729 {
3730 XSetWMName(display,windows->widget.id,&window_name);
3731 XSetWMIconName(display,windows->widget.id,&window_name);
3732 (void) XFree((void *) window_name.value);
3733 }
3734 window_changes.width=(int) windows->widget.width;
3735 window_changes.height=(int) windows->widget.height;
3736 window_changes.x=windows->widget.x;
3737 window_changes.y=windows->widget.y;
3738 (void) XReconfigureWMWindow(display,windows->widget.id,windows->widget.screen,
3739 (unsigned int) (CWWidth | CWHeight | CWX | CWY),&window_changes);
3740 (void) XMapRaised(display,windows->widget.id);
3741 windows->widget.mapped=MagickFalse;
3742 /*
3743 Respond to X events.
3744 */
3745 anomaly=(LocaleCompare(action,"Background") == 0) ||
3746 (LocaleCompare(action,"New") == 0) ||
3747 (LocaleCompare(action,"Quantize") == 0) ||
3748 (LocaleCompare(action,"Resize") == 0) ||
3749 (LocaleCompare(action,"Save") == 0) ||
3750 (LocaleCompare(action,"Shade") == 0);
3751 state=UpdateConfigurationState;
3752 XSetCursorState(display,windows,MagickTrue);
3753 do
3754 {
3755 if (state & UpdateConfigurationState)
3756 {
3757 /*
3758 Initialize button information.
3759 */
3760 XGetWidgetInfo(CancelButtonText,&cancel_info);
3761 cancel_info.width=width;
3762 cancel_info.height=(unsigned int) ((3*height) >> 1);
3763 cancel_info.x=(int)
3764 (windows->widget.width-cancel_info.width-((3*QuantumMargin) >> 1));
3765 cancel_info.y=(int)
3766 (windows->widget.height-cancel_info.height-((3*QuantumMargin) >> 1));
3767 XGetWidgetInfo(action,&action_info);
3768 action_info.width=width;
3769 action_info.height=(unsigned int) ((3*height) >> 1);
3770 action_info.x=cancel_info.x-(cancel_info.width+QuantumMargin+
3771 (action_info.bevel_width << 1));
3772 action_info.y=cancel_info.y;
3773 /*
3774 Initialize reply information.
3775 */
3776 XGetWidgetInfo(reply,&reply_info);
3777 reply_info.raised=MagickFalse;
3778 reply_info.bevel_width--;
3779 reply_info.width=windows->widget.width-(3*QuantumMargin);
3780 reply_info.height=height << 1;
3781 reply_info.x=(3*QuantumMargin) >> 1;
3782 reply_info.y=action_info.y-reply_info.height-QuantumMargin;
3783 /*
3784 Initialize option information.
3785 */
3786 XGetWidgetInfo("Dither",&special_info);
3787 special_info.raised=raised;
3788 special_info.bevel_width--;
3789 special_info.width=(unsigned int) QuantumMargin >> 1;
3790 special_info.height=(unsigned int) QuantumMargin >> 1;
3791 special_info.x=reply_info.x;
3792 special_info.y=action_info.y+action_info.height-special_info.height;
3793 if (LocaleCompare(action,"Background") == 0)
3794 special_info.text=(char *) "Backdrop";
3795 if (LocaleCompare(action,"New") == 0)
3796 special_info.text=(char *) "Gradation";
3797 if (LocaleCompare(action,"Resize") == 0)
3798 special_info.text=(char *) "Constrain ratio";
3799 if (LocaleCompare(action,"Save") == 0)
3800 special_info.text=(char *) "Non-progressive";
3801 if (LocaleCompare(action,"Shade") == 0)
3802 special_info.text=(char *) "Color shading";
3803 /*
3804 Initialize text information.
3805 */
3806 XGetWidgetInfo(query,&text_info);
3807 text_info.width=reply_info.width;
3808 text_info.height=height;
3809 text_info.x=reply_info.x-(QuantumMargin >> 1);
3810 text_info.y=QuantumMargin;
3811 text_info.center=MagickFalse;
3812 state&=(~UpdateConfigurationState);
3813 }
3814 if (state & RedrawWidgetState)
3815 {
3816 /*
3817 Redraw Dialog widget.
3818 */
3819 XDrawWidgetText(display,&windows->widget,&text_info);
3820 XDrawBeveledMatte(display,&windows->widget,&reply_info);
3821 XDrawMatteText(display,&windows->widget,&reply_info);
3822 if (anomaly)
3823 XDrawBeveledButton(display,&windows->widget,&special_info);
3824 XDrawBeveledButton(display,&windows->widget,&action_info);
3825 XDrawBeveledButton(display,&windows->widget,&cancel_info);
3826 XHighlightWidget(display,&windows->widget,BorderOffset,BorderOffset);
3827 state&=(~RedrawWidgetState);
3828 }
3829 /*
3830 Wait for next event.
3831 */
3832 (void) XIfEvent(display,&event,XScreenEvent,(char *) windows);
3833 switch (event.type)
3834 {
3835 case ButtonPress:
3836 {
3837 if (anomaly)
3838 if (MatteIsActive(special_info,event.xbutton))
3839 {
3840 /*
3841 Option button status changed.
3842 */
3843 special_info.raised=!special_info.raised;
3844 XDrawBeveledButton(display,&windows->widget,&special_info);
3845 break;
3846 }
3847 if (MatteIsActive(action_info,event.xbutton))
3848 {
3849 /*
3850 User pressed Action button.
3851 */
3852 action_info.raised=MagickFalse;
3853 XDrawBeveledButton(display,&windows->widget,&action_info);
3854 break;
3855 }
3856 if (MatteIsActive(cancel_info,event.xbutton))
3857 {
3858 /*
3859 User pressed Cancel button.
3860 */
3861 cancel_info.raised=MagickFalse;
3862 XDrawBeveledButton(display,&windows->widget,&cancel_info);
3863 break;
3864 }
3865 if (MatteIsActive(reply_info,event.xbutton) == MagickFalse)
3866 break;
3867 if (event.xbutton.button != Button2)
3868 {
3869 static Time
3870 click_time;
3871
3872 /*
3873 Move text cursor to position of button press.
3874 */
3875 x=event.xbutton.x-reply_info.x-(QuantumMargin >> 2);
3876 for (i=1; i <= Extent(reply_info.marker); i++)
3877 if (XTextWidth(font_info,reply_info.marker,i) > x)
3878 break;
3879 reply_info.cursor=reply_info.marker+i-1;
3880 if (event.xbutton.time > (click_time+DoubleClick))
3881 reply_info.highlight=MagickFalse;
3882 else
3883 {
3884 /*
3885 Become the XA_PRIMARY selection owner.
3886 */
3887 (void) CopyMagickString(primary_selection,reply_info.text,
3888 MaxTextExtent);
3889 (void) XSetSelectionOwner(display,XA_PRIMARY,windows->widget.id,
3890 event.xbutton.time);
3891 reply_info.highlight=XGetSelectionOwner(display,XA_PRIMARY) ==
3892 windows->widget.id ? MagickTrue : MagickFalse;
3893 }
3894 XDrawMatteText(display,&windows->widget,&reply_info);
3895 click_time=event.xbutton.time;
3896 break;
3897 }
3898 /*
3899 Request primary selection.
3900 */
3901 (void) XConvertSelection(display,XA_PRIMARY,XA_STRING,XA_STRING,
3902 windows->widget.id,event.xbutton.time);
3903 break;
3904 }
3905 case ButtonRelease:
3906 {
3907 if (windows->widget.mapped == MagickFalse)
3908 break;
3909 if (action_info.raised == MagickFalse)
3910 {
3911 if (event.xbutton.window == windows->widget.id)
3912 if (MatteIsActive(action_info,event.xbutton))
3913 state|=ExitState;
3914 action_info.raised=MagickTrue;
3915 XDrawBeveledButton(display,&windows->widget,&action_info);
3916 }
3917 if (cancel_info.raised == MagickFalse)
3918 {
3919 if (event.xbutton.window == windows->widget.id)
3920 if (MatteIsActive(cancel_info,event.xbutton))
3921 {
3922 *reply_info.text='\0';
3923 state|=ExitState;
3924 }
3925 cancel_info.raised=MagickTrue;
3926 XDrawBeveledButton(display,&windows->widget,&cancel_info);
3927 }
3928 break;
3929 }
3930 case ClientMessage:
3931 {
3932 /*
3933 If client window delete message, exit.
3934 */
3935 if (event.xclient.message_type != windows->wm_protocols)
3936 break;
3937 if (*event.xclient.data.l == (int) windows->wm_take_focus)
3938 {
3939 (void) XSetInputFocus(display,event.xclient.window,RevertToParent,
3940 (Time) event.xclient.data.l[1]);
3941 break;
3942 }
3943 if (*event.xclient.data.l != (int) windows->wm_delete_window)
3944 break;
3945 if (event.xclient.window == windows->widget.id)
3946 {
3947 *reply_info.text='\0';
3948 state|=ExitState;
3949 break;
3950 }
3951 break;
3952 }
3953 case ConfigureNotify:
3954 {
3955 /*
3956 Update widget configuration.
3957 */
3958 if (event.xconfigure.window != windows->widget.id)
3959 break;
3960 if ((event.xconfigure.width == (int) windows->widget.width) &&
3961 (event.xconfigure.height == (int) windows->widget.height))
3962 break;
3963 windows->widget.width=(unsigned int)
3964 MagickMax(event.xconfigure.width,(int) windows->widget.min_width);
3965 windows->widget.height=(unsigned int)
3966 MagickMax(event.xconfigure.height,(int) windows->widget.min_height);
3967 state|=UpdateConfigurationState;
3968 break;
3969 }
3970 case EnterNotify:
3971 {
3972 if (event.xcrossing.window != windows->widget.id)
3973 break;
3974 state&=(~InactiveWidgetState);
3975 break;
3976 }
3977 case Expose:
3978 {
3979 if (event.xexpose.window != windows->widget.id)
3980 break;
3981 if (event.xexpose.count != 0)
3982 break;
3983 state|=RedrawWidgetState;
3984 break;
3985 }
3986 case KeyPress:
3987 {
3988 static char
3989 command[MaxTextExtent];
3990
3991 static int
3992 length;
3993
3994 static KeySym
3995 key_symbol;
3996
3997 /*
3998 Respond to a user key press.
3999 */
4000 if (event.xkey.window != windows->widget.id)
4001 break;
4002 length=XLookupString((XKeyEvent *) &event.xkey,command,
4003 (int) sizeof(command),&key_symbol,(XComposeStatus *) NULL);
4004 *(command+length)='\0';
4005 if ((key_symbol == XK_Return) || (key_symbol == XK_KP_Enter))
4006 {
4007 action_info.raised=MagickFalse;
4008 XDrawBeveledButton(display,&windows->widget,&action_info);
4009 state|=ExitState;
4010 break;
4011 }
4012 if (key_symbol == XK_Control_L)
4013 {
4014 state|=ControlState;
4015 break;
4016 }
4017 if (state & ControlState)
4018 switch ((int) key_symbol)
4019 {
4020 case XK_u:
4021 case XK_U:
4022 {
4023 /*
4024 Erase the entire line of text.
4025 */
4026 *reply_info.text='\0';
4027 reply_info.cursor=reply_info.text;
4028 reply_info.marker=reply_info.text;
4029 reply_info.highlight=MagickFalse;
4030 break;
4031 }
4032 default:
4033 break;
4034 }
4035 XEditText(display,&reply_info,key_symbol,command,state);
4036 XDrawMatteText(display,&windows->widget,&reply_info);
4037 break;
4038 }
4039 case KeyRelease:
4040 {
4041 static char
4042 command[MaxTextExtent];
4043
4044 static KeySym
4045 key_symbol;
4046
4047 /*
4048 Respond to a user key release.
4049 */
4050 if (event.xkey.window != windows->widget.id)
4051 break;
4052 (void) XLookupString((XKeyEvent *) &event.xkey,command,
4053 (int) sizeof(command),&key_symbol,(XComposeStatus *) NULL);
4054 if (key_symbol == XK_Control_L)
4055 state&=(~ControlState);
4056 break;
4057 }
4058 case LeaveNotify:
4059 {
4060 if (event.xcrossing.window != windows->widget.id)
4061 break;
4062 state|=InactiveWidgetState;
4063 break;
4064 }
4065 case MotionNotify:
4066 {
4067 /*
4068 Discard pending button motion events.
4069 */
4070 while (XCheckMaskEvent(display,ButtonMotionMask,&event)) ;
4071 if (state & InactiveWidgetState)
4072 break;
4073 if (action_info.raised == MatteIsActive(action_info,event.xmotion))
4074 {
4075 /*
4076 Action button status changed.
4077 */
4078 action_info.raised=action_info.raised == MagickFalse ?
4079 MagickTrue : MagickFalse;
4080 XDrawBeveledButton(display,&windows->widget,&action_info);
4081 break;
4082 }
4083 if (cancel_info.raised == MatteIsActive(cancel_info,event.xmotion))
4084 {
4085 /*
4086 Cancel button status changed.
4087 */
4088 cancel_info.raised=cancel_info.raised == MagickFalse ?
4089 MagickTrue : MagickFalse;
4090 XDrawBeveledButton(display,&windows->widget,&cancel_info);
4091 break;
4092 }
4093 break;
4094 }
4095 case SelectionClear:
4096 {
4097 reply_info.highlight=MagickFalse;
4098 XDrawMatteText(display,&windows->widget,&reply_info);
4099 break;
4100 }
4101 case SelectionNotify:
4102 {
4103 Atom
4104 type;
4105
4106 int
4107 format;
4108
4109 unsigned char
4110 *data;
4111
cristyf2faecf2010-05-28 19:19:36 +00004112 unsigned long
cristy3ed852e2009-09-05 21:47:34 +00004113 after,
4114 length;
4115
4116 /*
4117 Obtain response from primary selection.
4118 */
4119 if (event.xselection.property == (Atom) None)
4120 break;
4121 status=XGetWindowProperty(display,event.xselection.requestor,
4122 event.xselection.property,0L,2047L,MagickTrue,XA_STRING,&type,
4123 &format,&length,&after,&data);
4124 if ((status != Success) || (type != XA_STRING) || (format == 32) ||
4125 (length == 0))
4126 break;
4127 if ((Extent(reply_info.text)+length) >= MaxTextExtent)
4128 (void) XBell(display,0);
4129 else
4130 {
4131 /*
4132 Insert primary selection in reply text.
4133 */
4134 *(data+length)='\0';
4135 XEditText(display,&reply_info,(KeySym) XK_Insert,(char *) data,
4136 state);
4137 XDrawMatteText(display,&windows->widget,&reply_info);
4138 }
4139 (void) XFree((void *) data);
4140 break;
4141 }
4142 case SelectionRequest:
4143 {
4144 XSelectionEvent
4145 notify;
4146
4147 XSelectionRequestEvent
4148 *request;
4149
4150 if (reply_info.highlight == MagickFalse)
4151 break;
4152 /*
4153 Set primary selection.
4154 */
4155 request=(&(event.xselectionrequest));
4156 (void) XChangeProperty(request->display,request->requestor,
4157 request->property,request->target,8,PropModeReplace,
4158 (unsigned char *) primary_selection,Extent(primary_selection));
4159 notify.type=SelectionNotify;
4160 notify.display=request->display;
4161 notify.requestor=request->requestor;
4162 notify.selection=request->selection;
4163 notify.target=request->target;
4164 notify.time=request->time;
4165 if (request->property == None)
4166 notify.property=request->target;
4167 else
4168 notify.property=request->property;
4169 (void) XSendEvent(request->display,request->requestor,False,0,
4170 (XEvent *) &notify);
4171 }
4172 default:
4173 break;
4174 }
4175 } while ((state & ExitState) == 0);
4176 XSetCursorState(display,windows,MagickFalse);
4177 (void) XWithdrawWindow(display,windows->widget.id,windows->widget.screen);
4178 XCheckRefreshWindows(display,windows);
4179 if (anomaly)
4180 if (special_info.raised)
4181 if (*reply != '\0')
4182 raised=MagickTrue;
4183 return(raised == MagickFalse);
4184}
4185
4186/*
4187%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4188% %
4189% %
4190% %
4191% X F i l e B r o w s e r W i d g e t %
4192% %
4193% %
4194% %
4195%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4196%
4197% XFileBrowserWidget() displays a File Browser widget with a file query to the
4198% user. The user keys a reply and presses the Action or Cancel button to
4199% exit. The typed text is returned as the reply function parameter.
4200%
4201% The format of the XFileBrowserWidget method is:
4202%
4203% void XFileBrowserWidget(Display *display,XWindows *windows,
4204% const char *action,char *reply)
4205%
4206% A description of each parameter follows:
4207%
4208% o display: Specifies a connection to an X server; returned from
4209% XOpenDisplay.
4210%
4211% o window: Specifies a pointer to a XWindows structure.
4212%
4213% o action: Specifies a pointer to the action of this widget.
4214%
4215% o reply: the response from the user is returned in this parameter.
4216%
4217*/
4218MagickExport void XFileBrowserWidget(Display *display,XWindows *windows,
4219 const char *action,char *reply)
4220{
4221#define CancelButtonText "Cancel"
4222#define DirectoryText "Directory:"
4223#define FilenameText "File name:"
4224#define GrabButtonText "Grab"
4225#define FormatButtonText "Format"
4226#define HomeButtonText "Home"
4227#define UpButtonText "Up"
4228
4229 char
cristy3ed852e2009-09-05 21:47:34 +00004230 **filelist,
4231 home_directory[MaxTextExtent],
4232 primary_selection[MaxTextExtent],
4233 text[MaxTextExtent],
4234 working_path[MaxTextExtent];
4235
4236 int
4237 x,
4238 y;
4239
cristyecd0ab52010-05-30 14:59:20 +00004240 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00004241 i;
4242
4243 static char
4244 glob_pattern[MaxTextExtent] = "*",
4245 format[MaxTextExtent] = "miff";
4246
4247 static MagickStatusType
4248 mask = (MagickStatusType) (CWWidth | CWHeight | CWX | CWY);
4249
4250 Status
4251 status;
4252
4253 unsigned int
4254 anomaly,
4255 height,
4256 text_width,
4257 visible_files,
4258 width;
4259
cristybb503372010-05-27 20:51:26 +00004260 size_t
cristy3ed852e2009-09-05 21:47:34 +00004261 delay,
4262 files,
4263 state;
4264
4265 XEvent
4266 event;
4267
4268 XFontStruct
4269 *font_info;
4270
4271 XTextProperty
4272 window_name;
4273
4274 XWidgetInfo
4275 action_info,
4276 cancel_info,
4277 expose_info,
4278 special_info,
4279 list_info,
4280 home_info,
4281 north_info,
4282 reply_info,
4283 scroll_info,
4284 selection_info,
4285 slider_info,
4286 south_info,
4287 text_info,
4288 up_info;
4289
4290 XWindowChanges
4291 window_changes;
4292
4293 /*
4294 Read filelist from current directory.
4295 */
4296 assert(display != (Display *) NULL);
4297 assert(windows != (XWindows *) NULL);
4298 assert(action != (char *) NULL);
4299 assert(reply != (char *) NULL);
4300 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",action);
4301 XSetCursorState(display,windows,MagickTrue);
4302 XCheckRefreshWindows(display,windows);
cristyda16f162011-02-19 23:52:17 +00004303 (void) getcwd(home_directory,MaxTextExtent);
cristy3ed852e2009-09-05 21:47:34 +00004304 (void) CopyMagickString(working_path,home_directory,MaxTextExtent);
4305 filelist=ListFiles(working_path,glob_pattern,&files);
4306 if (filelist == (char **) NULL)
4307 {
4308 /*
4309 Directory read failed.
4310 */
4311 XNoticeWidget(display,windows,"Unable to read directory:",working_path);
4312 (void) XDialogWidget(display,windows,action,"Enter filename:",reply);
4313 return;
4314 }
4315 /*
4316 Determine File Browser widget attributes.
4317 */
4318 font_info=windows->widget.font_info;
4319 text_width=0;
cristybb503372010-05-27 20:51:26 +00004320 for (i=0; i < (ssize_t) files; i++)
cristy3ed852e2009-09-05 21:47:34 +00004321 if (WidgetTextWidth(font_info,filelist[i]) > text_width)
4322 text_width=WidgetTextWidth(font_info,filelist[i]);
4323 width=WidgetTextWidth(font_info,(char *) action);
4324 if (WidgetTextWidth(font_info,GrabButtonText) > width)
4325 width=WidgetTextWidth(font_info,GrabButtonText);
4326 if (WidgetTextWidth(font_info,FormatButtonText) > width)
4327 width=WidgetTextWidth(font_info,FormatButtonText);
4328 if (WidgetTextWidth(font_info,CancelButtonText) > width)
4329 width=WidgetTextWidth(font_info,CancelButtonText);
4330 if (WidgetTextWidth(font_info,HomeButtonText) > width)
4331 width=WidgetTextWidth(font_info,HomeButtonText);
4332 if (WidgetTextWidth(font_info,UpButtonText) > width)
4333 width=WidgetTextWidth(font_info,UpButtonText);
4334 width+=QuantumMargin;
4335 if (WidgetTextWidth(font_info,DirectoryText) > width)
4336 width=WidgetTextWidth(font_info,DirectoryText);
4337 if (WidgetTextWidth(font_info,FilenameText) > width)
4338 width=WidgetTextWidth(font_info,FilenameText);
4339 height=(unsigned int) (font_info->ascent+font_info->descent);
4340 /*
4341 Position File Browser widget.
4342 */
4343 windows->widget.width=width+MagickMin((int) text_width,(int) MaxTextWidth)+
4344 6*QuantumMargin;
4345 windows->widget.min_width=width+MinTextWidth+4*QuantumMargin;
4346 if (windows->widget.width < windows->widget.min_width)
4347 windows->widget.width=windows->widget.min_width;
4348 windows->widget.height=(unsigned int)
4349 (((81*height) >> 2)+((13*QuantumMargin) >> 1)+4);
4350 windows->widget.min_height=(unsigned int)
4351 (((23*height) >> 1)+((13*QuantumMargin) >> 1)+4);
4352 if (windows->widget.height < windows->widget.min_height)
4353 windows->widget.height=windows->widget.min_height;
4354 XConstrainWindowPosition(display,&windows->widget);
4355 /*
4356 Map File Browser widget.
4357 */
4358 (void) CopyMagickString(windows->widget.name,"Browse and Select a File",
4359 MaxTextExtent);
4360 status=XStringListToTextProperty(&windows->widget.name,1,&window_name);
4361 if (status != False)
4362 {
4363 XSetWMName(display,windows->widget.id,&window_name);
4364 XSetWMIconName(display,windows->widget.id,&window_name);
4365 (void) XFree((void *) window_name.value);
4366 }
4367 window_changes.width=(int) windows->widget.width;
4368 window_changes.height=(int) windows->widget.height;
4369 window_changes.x=windows->widget.x;
4370 window_changes.y=windows->widget.y;
4371 (void) XReconfigureWMWindow(display,windows->widget.id,
4372 windows->widget.screen,mask,&window_changes);
4373 (void) XMapRaised(display,windows->widget.id);
4374 windows->widget.mapped=MagickFalse;
4375 /*
4376 Respond to X events.
4377 */
4378 XGetWidgetInfo((char *) NULL,&slider_info);
4379 XGetWidgetInfo((char *) NULL,&north_info);
4380 XGetWidgetInfo((char *) NULL,&south_info);
4381 XGetWidgetInfo((char *) NULL,&expose_info);
4382 visible_files=0;
4383 anomaly=(LocaleCompare(action,"Composite") == 0) ||
4384 (LocaleCompare(action,"Open") == 0) || (LocaleCompare(action,"Map") == 0);
4385 *reply='\0';
4386 delay=SuspendTime << 2;
4387 state=UpdateConfigurationState;
4388 do
4389 {
4390 if (state & UpdateConfigurationState)
4391 {
4392 int
4393 id;
4394
4395 /*
4396 Initialize button information.
4397 */
4398 XGetWidgetInfo(CancelButtonText,&cancel_info);
4399 cancel_info.width=width;
4400 cancel_info.height=(unsigned int) ((3*height) >> 1);
4401 cancel_info.x=(int)
4402 (windows->widget.width-cancel_info.width-QuantumMargin-2);
4403 cancel_info.y=(int)
4404 (windows->widget.height-cancel_info.height-QuantumMargin);
4405 XGetWidgetInfo(action,&action_info);
4406 action_info.width=width;
4407 action_info.height=(unsigned int) ((3*height) >> 1);
4408 action_info.x=cancel_info.x-(cancel_info.width+(QuantumMargin >> 1)+
4409 (action_info.bevel_width << 1));
4410 action_info.y=cancel_info.y;
4411 XGetWidgetInfo(GrabButtonText,&special_info);
4412 special_info.width=width;
4413 special_info.height=(unsigned int) ((3*height) >> 1);
4414 special_info.x=action_info.x-(action_info.width+(QuantumMargin >> 1)+
4415 (special_info.bevel_width << 1));
4416 special_info.y=action_info.y;
4417 if (anomaly == MagickFalse)
4418 {
4419 register char
4420 *p;
4421
4422 special_info.text=(char *) FormatButtonText;
4423 p=reply+Extent(reply)-1;
4424 while ((p > (reply+1)) && (*(p-1) != '.'))
4425 p--;
4426 if ((p > (reply+1)) && (*(p-1) == '.'))
4427 (void) CopyMagickString(format,p,MaxTextExtent);
4428 }
4429 XGetWidgetInfo(UpButtonText,&up_info);
4430 up_info.width=width;
4431 up_info.height=(unsigned int) ((3*height) >> 1);
4432 up_info.x=QuantumMargin;
4433 up_info.y=((5*QuantumMargin) >> 1)+height;
4434 XGetWidgetInfo(HomeButtonText,&home_info);
4435 home_info.width=width;
4436 home_info.height=(unsigned int) ((3*height) >> 1);
4437 home_info.x=QuantumMargin;
4438 home_info.y=up_info.y+up_info.height+QuantumMargin;
4439 /*
4440 Initialize reply information.
4441 */
4442 XGetWidgetInfo(reply,&reply_info);
4443 reply_info.raised=MagickFalse;
4444 reply_info.bevel_width--;
4445 reply_info.width=windows->widget.width-width-((6*QuantumMargin) >> 1);
4446 reply_info.height=height << 1;
4447 reply_info.x=(int) (width+(QuantumMargin << 1));
4448 reply_info.y=action_info.y-reply_info.height-QuantumMargin;
4449 /*
4450 Initialize scroll information.
4451 */
4452 XGetWidgetInfo((char *) NULL,&scroll_info);
4453 scroll_info.bevel_width--;
4454 scroll_info.width=height;
4455 scroll_info.height=(unsigned int)
4456 (reply_info.y-up_info.y-(QuantumMargin >> 1));
4457 scroll_info.x=reply_info.x+(reply_info.width-scroll_info.width);
4458 scroll_info.y=up_info.y-reply_info.bevel_width;
4459 scroll_info.raised=MagickFalse;
4460 scroll_info.trough=MagickTrue;
4461 north_info=scroll_info;
4462 north_info.raised=MagickTrue;
4463 north_info.width-=(north_info.bevel_width << 1);
4464 north_info.height=north_info.width-1;
4465 north_info.x+=north_info.bevel_width;
4466 north_info.y+=north_info.bevel_width;
4467 south_info=north_info;
4468 south_info.y=scroll_info.y+scroll_info.height-scroll_info.bevel_width-
4469 south_info.height;
4470 id=slider_info.id;
4471 slider_info=north_info;
4472 slider_info.id=id;
4473 slider_info.width-=2;
4474 slider_info.min_y=north_info.y+north_info.height+north_info.bevel_width+
4475 slider_info.bevel_width+2;
4476 slider_info.height=scroll_info.height-((slider_info.min_y-
4477 scroll_info.y+1) << 1)+4;
4478 visible_files=scroll_info.height/(height+(height >> 3));
4479 if (files > visible_files)
4480 slider_info.height=(unsigned int)
4481 ((visible_files*slider_info.height)/files);
4482 slider_info.max_y=south_info.y-south_info.bevel_width-
4483 slider_info.bevel_width-2;
4484 slider_info.x=scroll_info.x+slider_info.bevel_width+1;
4485 slider_info.y=slider_info.min_y;
4486 expose_info=scroll_info;
4487 expose_info.y=slider_info.y;
4488 /*
4489 Initialize list information.
4490 */
4491 XGetWidgetInfo((char *) NULL,&list_info);
4492 list_info.raised=MagickFalse;
4493 list_info.bevel_width--;
4494 list_info.width=(unsigned int)
4495 (scroll_info.x-reply_info.x-(QuantumMargin >> 1));
4496 list_info.height=scroll_info.height;
4497 list_info.x=reply_info.x;
4498 list_info.y=scroll_info.y;
4499 if (windows->widget.mapped == MagickFalse)
4500 state|=JumpListState;
4501 /*
4502 Initialize text information.
4503 */
4504 *text='\0';
4505 XGetWidgetInfo(text,&text_info);
4506 text_info.center=MagickFalse;
4507 text_info.width=reply_info.width;
4508 text_info.height=height;
4509 text_info.x=list_info.x-(QuantumMargin >> 1);
4510 text_info.y=QuantumMargin;
4511 /*
4512 Initialize selection information.
4513 */
4514 XGetWidgetInfo((char *) NULL,&selection_info);
4515 selection_info.center=MagickFalse;
4516 selection_info.width=list_info.width;
4517 selection_info.height=(unsigned int) ((9*height) >> 3);
4518 selection_info.x=list_info.x;
4519 state&=(~UpdateConfigurationState);
4520 }
4521 if (state & RedrawWidgetState)
4522 {
4523 /*
4524 Redraw File Browser window.
4525 */
4526 x=QuantumMargin;
4527 y=text_info.y+((text_info.height-height) >> 1)+font_info->ascent;
4528 (void) XDrawString(display,windows->widget.id,
4529 windows->widget.annotate_context,x,y,DirectoryText,
4530 Extent(DirectoryText));
4531 (void) CopyMagickString(text_info.text,working_path,MaxTextExtent);
4532 (void) ConcatenateMagickString(text_info.text,DirectorySeparator,
4533 MaxTextExtent);
4534 (void) ConcatenateMagickString(text_info.text,glob_pattern,
4535 MaxTextExtent);
4536 XDrawWidgetText(display,&windows->widget,&text_info);
4537 XDrawBeveledButton(display,&windows->widget,&up_info);
4538 XDrawBeveledButton(display,&windows->widget,&home_info);
4539 XDrawBeveledMatte(display,&windows->widget,&list_info);
4540 XDrawBeveledMatte(display,&windows->widget,&scroll_info);
4541 XDrawTriangleNorth(display,&windows->widget,&north_info);
4542 XDrawBeveledButton(display,&windows->widget,&slider_info);
4543 XDrawTriangleSouth(display,&windows->widget,&south_info);
4544 x=QuantumMargin;
4545 y=reply_info.y+((reply_info.height-height) >> 1)+font_info->ascent;
4546 (void) XDrawString(display,windows->widget.id,
4547 windows->widget.annotate_context,x,y,FilenameText,
4548 Extent(FilenameText));
4549 XDrawBeveledMatte(display,&windows->widget,&reply_info);
4550 XDrawMatteText(display,&windows->widget,&reply_info);
4551 XDrawBeveledButton(display,&windows->widget,&special_info);
4552 XDrawBeveledButton(display,&windows->widget,&action_info);
4553 XDrawBeveledButton(display,&windows->widget,&cancel_info);
4554 XHighlightWidget(display,&windows->widget,BorderOffset,BorderOffset);
4555 selection_info.id=(~0);
4556 state|=RedrawListState;
4557 state&=(~RedrawWidgetState);
4558 }
4559 if (state & UpdateListState)
4560 {
4561 char
4562 **checklist;
4563
cristybb503372010-05-27 20:51:26 +00004564 size_t
cristy3ed852e2009-09-05 21:47:34 +00004565 number_files;
4566
4567 /*
4568 Update file list.
4569 */
4570 checklist=ListFiles(working_path,glob_pattern,&number_files);
4571 if (checklist == (char **) NULL)
4572 {
4573 /*
4574 Reply is a filename, exit.
4575 */
4576 action_info.raised=MagickFalse;
4577 XDrawBeveledButton(display,&windows->widget,&action_info);
4578 break;
4579 }
cristybb503372010-05-27 20:51:26 +00004580 for (i=0; i < (ssize_t) files; i++)
cristy3ed852e2009-09-05 21:47:34 +00004581 filelist[i]=DestroyString(filelist[i]);
4582 if (filelist != (char **) NULL)
4583 filelist=(char **) RelinquishMagickMemory(filelist);
4584 filelist=checklist;
4585 files=number_files;
4586 /*
4587 Update file list.
4588 */
4589 slider_info.height=
4590 scroll_info.height-((slider_info.min_y-scroll_info.y+1) << 1)+1;
4591 if (files > visible_files)
4592 slider_info.height=(unsigned int)
4593 ((visible_files*slider_info.height)/files);
4594 slider_info.max_y=south_info.y-south_info.bevel_width-
4595 slider_info.bevel_width-2;
4596 slider_info.id=0;
4597 slider_info.y=slider_info.min_y;
4598 expose_info.y=slider_info.y;
4599 selection_info.id=(~0);
4600 list_info.id=(~0);
4601 state|=RedrawListState;
4602 /*
4603 Redraw directory name & reply.
4604 */
4605 if (IsGlob(reply_info.text) == MagickFalse)
4606 {
4607 *reply_info.text='\0';
4608 reply_info.cursor=reply_info.text;
4609 }
4610 (void) CopyMagickString(text_info.text,working_path,MaxTextExtent);
4611 (void) ConcatenateMagickString(text_info.text,DirectorySeparator,
4612 MaxTextExtent);
4613 (void) ConcatenateMagickString(text_info.text,glob_pattern,
4614 MaxTextExtent);
4615 XDrawWidgetText(display,&windows->widget,&text_info);
4616 XDrawMatteText(display,&windows->widget,&reply_info);
4617 XDrawBeveledMatte(display,&windows->widget,&scroll_info);
4618 XDrawTriangleNorth(display,&windows->widget,&north_info);
4619 XDrawBeveledButton(display,&windows->widget,&slider_info);
4620 XDrawTriangleSouth(display,&windows->widget,&south_info);
4621 XHighlightWidget(display,&windows->widget,BorderOffset,BorderOffset);
4622 state&=(~UpdateListState);
4623 }
4624 if (state & JumpListState)
4625 {
4626 /*
4627 Jump scroll to match user filename.
4628 */
4629 list_info.id=(~0);
cristybb503372010-05-27 20:51:26 +00004630 for (i=0; i < (ssize_t) files; i++)
cristy3ed852e2009-09-05 21:47:34 +00004631 if (LocaleCompare(filelist[i],reply) >= 0)
4632 {
cristy49e2d862010-11-12 02:50:30 +00004633 list_info.id=(int)
4634 (LocaleCompare(filelist[i],reply) == 0 ? i : ~0);
cristy3ed852e2009-09-05 21:47:34 +00004635 break;
4636 }
cristy49e2d862010-11-12 02:50:30 +00004637 if ((i < (ssize_t) slider_info.id) ||
4638 (i >= (ssize_t) (slider_info.id+visible_files)))
4639 slider_info.id=(int) i-(visible_files >> 1);
cristy3ed852e2009-09-05 21:47:34 +00004640 selection_info.id=(~0);
4641 state|=RedrawListState;
4642 state&=(~JumpListState);
4643 }
4644 if (state & RedrawListState)
4645 {
4646 /*
4647 Determine slider id and position.
4648 */
4649 if (slider_info.id >= (int) (files-visible_files))
4650 slider_info.id=(int) (files-visible_files);
4651 if ((slider_info.id < 0) || (files <= visible_files))
4652 slider_info.id=0;
4653 slider_info.y=slider_info.min_y;
4654 if (files > 0)
cristydfe2b662010-08-22 16:17:24 +00004655 slider_info.y+=(int) (slider_info.id*(slider_info.max_y-
cristy8891f9c2010-06-04 23:32:17 +00004656 slider_info.min_y+1)/files);
cristy3ed852e2009-09-05 21:47:34 +00004657 if (slider_info.id != selection_info.id)
4658 {
4659 /*
4660 Redraw scroll bar and file names.
4661 */
4662 selection_info.id=slider_info.id;
4663 selection_info.y=list_info.y+(height >> 3)+2;
cristy49e2d862010-11-12 02:50:30 +00004664 for (i=0; i < (ssize_t) visible_files; i++)
cristy3ed852e2009-09-05 21:47:34 +00004665 {
cristy49e2d862010-11-12 02:50:30 +00004666 selection_info.raised=(int) (slider_info.id+i) != list_info.id ?
cristy3ed852e2009-09-05 21:47:34 +00004667 MagickTrue : MagickFalse;
4668 selection_info.text=(char *) NULL;
cristybb503372010-05-27 20:51:26 +00004669 if ((slider_info.id+i) < (ssize_t) files)
cristy3ed852e2009-09-05 21:47:34 +00004670 selection_info.text=filelist[slider_info.id+i];
4671 XDrawWidgetText(display,&windows->widget,&selection_info);
4672 selection_info.y+=(int) selection_info.height;
4673 }
4674 /*
4675 Update slider.
4676 */
4677 if (slider_info.y > expose_info.y)
4678 {
4679 expose_info.height=(unsigned int) slider_info.y-expose_info.y;
4680 expose_info.y=slider_info.y-expose_info.height-
4681 slider_info.bevel_width-1;
4682 }
4683 else
4684 {
4685 expose_info.height=(unsigned int) expose_info.y-slider_info.y;
4686 expose_info.y=slider_info.y+slider_info.height+
4687 slider_info.bevel_width+1;
4688 }
4689 XDrawTriangleNorth(display,&windows->widget,&north_info);
4690 XDrawMatte(display,&windows->widget,&expose_info);
4691 XDrawBeveledButton(display,&windows->widget,&slider_info);
4692 XDrawTriangleSouth(display,&windows->widget,&south_info);
4693 expose_info.y=slider_info.y;
4694 }
4695 state&=(~RedrawListState);
4696 }
4697 /*
4698 Wait for next event.
4699 */
4700 if (north_info.raised && south_info.raised)
4701 (void) XIfEvent(display,&event,XScreenEvent,(char *) windows);
4702 else
4703 {
4704 /*
4705 Brief delay before advancing scroll bar.
4706 */
4707 XDelay(display,delay);
4708 delay=SuspendTime;
4709 (void) XCheckIfEvent(display,&event,XScreenEvent,(char *) windows);
4710 if (north_info.raised == MagickFalse)
4711 if (slider_info.id > 0)
4712 {
4713 /*
4714 Move slider up.
4715 */
4716 slider_info.id--;
4717 state|=RedrawListState;
4718 }
4719 if (south_info.raised == MagickFalse)
cristy49e2d862010-11-12 02:50:30 +00004720 if (slider_info.id < (int) files)
cristy3ed852e2009-09-05 21:47:34 +00004721 {
4722 /*
4723 Move slider down.
4724 */
4725 slider_info.id++;
4726 state|=RedrawListState;
4727 }
4728 if (event.type != ButtonRelease)
4729 continue;
4730 }
4731 switch (event.type)
4732 {
4733 case ButtonPress:
4734 {
4735 if (MatteIsActive(slider_info,event.xbutton))
4736 {
4737 /*
4738 Track slider.
4739 */
4740 slider_info.active=MagickTrue;
4741 break;
4742 }
4743 if (MatteIsActive(north_info,event.xbutton))
4744 if (slider_info.id > 0)
4745 {
4746 /*
4747 Move slider up.
4748 */
4749 north_info.raised=MagickFalse;
4750 slider_info.id--;
4751 state|=RedrawListState;
4752 break;
4753 }
4754 if (MatteIsActive(south_info,event.xbutton))
cristy49e2d862010-11-12 02:50:30 +00004755 if (slider_info.id < (int) files)
cristy3ed852e2009-09-05 21:47:34 +00004756 {
4757 /*
4758 Move slider down.
4759 */
4760 south_info.raised=MagickFalse;
4761 slider_info.id++;
4762 state|=RedrawListState;
4763 break;
4764 }
4765 if (MatteIsActive(scroll_info,event.xbutton))
4766 {
4767 /*
4768 Move slider.
4769 */
4770 if (event.xbutton.y < slider_info.y)
4771 slider_info.id-=(visible_files-1);
4772 else
4773 slider_info.id+=(visible_files-1);
4774 state|=RedrawListState;
4775 break;
4776 }
4777 if (MatteIsActive(list_info,event.xbutton))
4778 {
4779 int
4780 id;
4781
4782 /*
4783 User pressed file matte.
4784 */
4785 id=slider_info.id+(event.xbutton.y-(list_info.y+(height >> 1))+1)/
4786 selection_info.height;
cristy49e2d862010-11-12 02:50:30 +00004787 if (id >= (int) files)
cristy3ed852e2009-09-05 21:47:34 +00004788 break;
4789 (void) CopyMagickString(reply_info.text,filelist[id],MaxTextExtent);
4790 reply_info.highlight=MagickFalse;
4791 reply_info.marker=reply_info.text;
4792 reply_info.cursor=reply_info.text+Extent(reply_info.text);
4793 XDrawMatteText(display,&windows->widget,&reply_info);
4794 if (id == list_info.id)
4795 {
4796 register char
4797 *p;
4798
cristy3ed852e2009-09-05 21:47:34 +00004799 p=reply_info.text+strlen(reply_info.text)-1;
4800 if (*p == *DirectorySeparator)
4801 ChopPathComponents(reply_info.text,1);
4802 (void) ConcatenateMagickString(working_path,DirectorySeparator,
4803 MaxTextExtent);
4804 (void) ConcatenateMagickString(working_path,reply_info.text,
4805 MaxTextExtent);
4806 *reply='\0';
4807 state|=UpdateListState;
4808 }
4809 selection_info.id=(~0);
4810 list_info.id=id;
4811 state|=RedrawListState;
4812 break;
4813 }
4814 if (MatteIsActive(up_info,event.xbutton))
4815 {
4816 /*
4817 User pressed Up button.
4818 */
4819 up_info.raised=MagickFalse;
4820 XDrawBeveledButton(display,&windows->widget,&up_info);
4821 break;
4822 }
4823 if (MatteIsActive(home_info,event.xbutton))
4824 {
4825 /*
4826 User pressed Home button.
4827 */
4828 home_info.raised=MagickFalse;
4829 XDrawBeveledButton(display,&windows->widget,&home_info);
4830 break;
4831 }
4832 if (MatteIsActive(special_info,event.xbutton))
4833 {
4834 /*
4835 User pressed Special button.
4836 */
4837 special_info.raised=MagickFalse;
4838 XDrawBeveledButton(display,&windows->widget,&special_info);
4839 break;
4840 }
4841 if (MatteIsActive(action_info,event.xbutton))
4842 {
4843 /*
4844 User pressed action button.
4845 */
4846 action_info.raised=MagickFalse;
4847 XDrawBeveledButton(display,&windows->widget,&action_info);
4848 break;
4849 }
4850 if (MatteIsActive(cancel_info,event.xbutton))
4851 {
4852 /*
4853 User pressed Cancel button.
4854 */
4855 cancel_info.raised=MagickFalse;
4856 XDrawBeveledButton(display,&windows->widget,&cancel_info);
4857 break;
4858 }
4859 if (MatteIsActive(reply_info,event.xbutton) == MagickFalse)
4860 break;
4861 if (event.xbutton.button != Button2)
4862 {
4863 static Time
4864 click_time;
4865
4866 /*
4867 Move text cursor to position of button press.
4868 */
4869 x=event.xbutton.x-reply_info.x-(QuantumMargin >> 2);
cristy49e2d862010-11-12 02:50:30 +00004870 for (i=1; i <= (ssize_t) Extent(reply_info.marker); i++)
4871 if (XTextWidth(font_info,reply_info.marker,(int) i) > x)
cristy3ed852e2009-09-05 21:47:34 +00004872 break;
4873 reply_info.cursor=reply_info.marker+i-1;
4874 if (event.xbutton.time > (click_time+DoubleClick))
4875 reply_info.highlight=MagickFalse;
4876 else
4877 {
4878 /*
4879 Become the XA_PRIMARY selection owner.
4880 */
4881 (void) CopyMagickString(primary_selection,reply_info.text,
4882 MaxTextExtent);
4883 (void) XSetSelectionOwner(display,XA_PRIMARY,windows->widget.id,
4884 event.xbutton.time);
4885 reply_info.highlight=XGetSelectionOwner(display,XA_PRIMARY) ==
4886 windows->widget.id ? MagickTrue : MagickFalse;
4887 }
4888 XDrawMatteText(display,&windows->widget,&reply_info);
4889 click_time=event.xbutton.time;
4890 break;
4891 }
4892 /*
4893 Request primary selection.
4894 */
4895 (void) XConvertSelection(display,XA_PRIMARY,XA_STRING,XA_STRING,
4896 windows->widget.id,event.xbutton.time);
4897 break;
4898 }
4899 case ButtonRelease:
4900 {
4901 if (windows->widget.mapped == MagickFalse)
4902 break;
4903 if (north_info.raised == MagickFalse)
4904 {
4905 /*
4906 User released up button.
4907 */
4908 delay=SuspendTime << 2;
4909 north_info.raised=MagickTrue;
4910 XDrawTriangleNorth(display,&windows->widget,&north_info);
4911 }
4912 if (south_info.raised == MagickFalse)
4913 {
4914 /*
4915 User released down button.
4916 */
4917 delay=SuspendTime << 2;
4918 south_info.raised=MagickTrue;
4919 XDrawTriangleSouth(display,&windows->widget,&south_info);
4920 }
4921 if (slider_info.active)
4922 {
4923 /*
4924 Stop tracking slider.
4925 */
4926 slider_info.active=MagickFalse;
4927 break;
4928 }
4929 if (up_info.raised == MagickFalse)
4930 {
4931 if (event.xbutton.window == windows->widget.id)
4932 if (MatteIsActive(up_info,event.xbutton))
4933 {
4934 ChopPathComponents(working_path,1);
4935 if (*working_path == '\0')
4936 (void) CopyMagickString(working_path,DirectorySeparator,
4937 MaxTextExtent);
4938 state|=UpdateListState;
4939 }
4940 up_info.raised=MagickTrue;
4941 XDrawBeveledButton(display,&windows->widget,&up_info);
4942 }
4943 if (home_info.raised == MagickFalse)
4944 {
4945 if (event.xbutton.window == windows->widget.id)
4946 if (MatteIsActive(home_info,event.xbutton))
4947 {
4948 (void) CopyMagickString(working_path,home_directory,
4949 MaxTextExtent);
4950 state|=UpdateListState;
4951 }
4952 home_info.raised=MagickTrue;
4953 XDrawBeveledButton(display,&windows->widget,&home_info);
4954 }
4955 if (special_info.raised == MagickFalse)
4956 {
4957 if (anomaly == MagickFalse)
4958 {
4959 char
4960 **formats;
4961
4962 ExceptionInfo
4963 *exception;
4964
cristybb503372010-05-27 20:51:26 +00004965 size_t
cristy3ed852e2009-09-05 21:47:34 +00004966 number_formats;
4967
4968 /*
4969 Let user select image format.
4970 */
4971 exception=AcquireExceptionInfo();
4972 formats=GetMagickList("*",&number_formats,exception);
4973 exception=DestroyExceptionInfo(exception);
4974 (void) XCheckDefineCursor(display,windows->widget.id,
4975 windows->widget.busy_cursor);
4976 windows->popup.x=windows->widget.x+60;
4977 windows->popup.y=windows->widget.y+60;
4978 XListBrowserWidget(display,windows,&windows->popup,
4979 (const char **) formats,"Select","Select image format type:",
4980 format);
4981 XSetCursorState(display,windows,MagickTrue);
4982 (void) XCheckDefineCursor(display,windows->widget.id,
4983 windows->widget.cursor);
4984 LocaleLower(format);
4985 AppendImageFormat(format,reply_info.text);
4986 reply_info.cursor=reply_info.text+Extent(reply_info.text);
4987 XDrawMatteText(display,&windows->widget,&reply_info);
4988 special_info.raised=MagickTrue;
4989 XDrawBeveledButton(display,&windows->widget,&special_info);
cristy49e2d862010-11-12 02:50:30 +00004990 for (i=0; i < (ssize_t) number_formats; i++)
cristy3ed852e2009-09-05 21:47:34 +00004991 formats[i]=DestroyString(formats[i]);
4992 formats=(char **) RelinquishMagickMemory(formats);
4993 break;
4994 }
4995 if (event.xbutton.window == windows->widget.id)
4996 if (MatteIsActive(special_info,event.xbutton))
4997 {
4998 (void) CopyMagickString(working_path,"x:",MaxTextExtent);
4999 state|=ExitState;
5000 }
5001 special_info.raised=MagickTrue;
5002 XDrawBeveledButton(display,&windows->widget,&special_info);
5003 }
5004 if (action_info.raised == MagickFalse)
5005 {
5006 if (event.xbutton.window == windows->widget.id)
5007 {
5008 if (MatteIsActive(action_info,event.xbutton))
5009 {
5010 if (*reply_info.text == '\0')
5011 (void) XBell(display,0);
5012 else
5013 state|=ExitState;
5014 }
5015 }
5016 action_info.raised=MagickTrue;
5017 XDrawBeveledButton(display,&windows->widget,&action_info);
5018 }
5019 if (cancel_info.raised == MagickFalse)
5020 {
5021 if (event.xbutton.window == windows->widget.id)
5022 if (MatteIsActive(cancel_info,event.xbutton))
5023 {
5024 *reply_info.text='\0';
5025 *reply='\0';
5026 state|=ExitState;
5027 }
5028 cancel_info.raised=MagickTrue;
5029 XDrawBeveledButton(display,&windows->widget,&cancel_info);
5030 }
5031 break;
5032 }
5033 case ClientMessage:
5034 {
5035 /*
5036 If client window delete message, exit.
5037 */
5038 if (event.xclient.message_type != windows->wm_protocols)
5039 break;
5040 if (*event.xclient.data.l == (int) windows->wm_take_focus)
5041 {
5042 (void) XSetInputFocus(display,event.xclient.window,RevertToParent,
5043 (Time) event.xclient.data.l[1]);
5044 break;
5045 }
5046 if (*event.xclient.data.l != (int) windows->wm_delete_window)
5047 break;
5048 if (event.xclient.window == windows->widget.id)
5049 {
5050 *reply_info.text='\0';
5051 state|=ExitState;
5052 break;
5053 }
5054 break;
5055 }
5056 case ConfigureNotify:
5057 {
5058 /*
5059 Update widget configuration.
5060 */
5061 if (event.xconfigure.window != windows->widget.id)
5062 break;
5063 if ((event.xconfigure.width == (int) windows->widget.width) &&
5064 (event.xconfigure.height == (int) windows->widget.height))
5065 break;
5066 windows->widget.width=(unsigned int)
5067 MagickMax(event.xconfigure.width,(int) windows->widget.min_width);
5068 windows->widget.height=(unsigned int)
5069 MagickMax(event.xconfigure.height,(int) windows->widget.min_height);
5070 state|=UpdateConfigurationState;
5071 break;
5072 }
5073 case EnterNotify:
5074 {
5075 if (event.xcrossing.window != windows->widget.id)
5076 break;
5077 state&=(~InactiveWidgetState);
5078 break;
5079 }
5080 case Expose:
5081 {
5082 if (event.xexpose.window != windows->widget.id)
5083 break;
5084 if (event.xexpose.count != 0)
5085 break;
5086 state|=RedrawWidgetState;
5087 break;
5088 }
5089 case KeyPress:
5090 {
5091 static char
5092 command[MaxTextExtent];
5093
5094 static int
5095 length;
5096
5097 static KeySym
5098 key_symbol;
5099
5100 /*
5101 Respond to a user key press.
5102 */
5103 if (event.xkey.window != windows->widget.id)
5104 break;
5105 length=XLookupString((XKeyEvent *) &event.xkey,command,
5106 (int) sizeof(command),&key_symbol,(XComposeStatus *) NULL);
5107 *(command+length)='\0';
5108 if (AreaIsActive(scroll_info,event.xkey))
5109 {
5110 /*
5111 Move slider.
5112 */
5113 switch ((int) key_symbol)
5114 {
5115 case XK_Home:
5116 case XK_KP_Home:
5117 {
5118 slider_info.id=0;
5119 break;
5120 }
5121 case XK_Up:
5122 case XK_KP_Up:
5123 {
5124 slider_info.id--;
5125 break;
5126 }
5127 case XK_Down:
5128 case XK_KP_Down:
5129 {
5130 slider_info.id++;
5131 break;
5132 }
5133 case XK_Prior:
5134 case XK_KP_Prior:
5135 {
5136 slider_info.id-=visible_files;
5137 break;
5138 }
5139 case XK_Next:
5140 case XK_KP_Next:
5141 {
5142 slider_info.id+=visible_files;
5143 break;
5144 }
5145 case XK_End:
5146 case XK_KP_End:
5147 {
5148 slider_info.id=(int) files;
5149 break;
5150 }
5151 }
5152 state|=RedrawListState;
5153 break;
5154 }
5155 if ((key_symbol == XK_Return) || (key_symbol == XK_KP_Enter))
5156 {
5157 /*
5158 Read new directory or glob patterm.
5159 */
5160 if (*reply_info.text == '\0')
5161 break;
5162 if (IsGlob(reply_info.text))
5163 (void) CopyMagickString(glob_pattern,reply_info.text,
5164 MaxTextExtent);
5165 else
5166 {
5167 (void) ConcatenateMagickString(working_path,DirectorySeparator,
5168 MaxTextExtent);
5169 (void) ConcatenateMagickString(working_path,reply_info.text,
5170 MaxTextExtent);
5171 if (*working_path == '~')
5172 ExpandFilename(working_path);
5173 *reply='\0';
5174 }
5175 state|=UpdateListState;
5176 break;
5177 }
5178 if (key_symbol == XK_Control_L)
5179 {
5180 state|=ControlState;
5181 break;
5182 }
5183 if (state & ControlState)
5184 switch ((int) key_symbol)
5185 {
5186 case XK_u:
5187 case XK_U:
5188 {
5189 /*
5190 Erase the entire line of text.
5191 */
5192 *reply_info.text='\0';
5193 reply_info.cursor=reply_info.text;
5194 reply_info.marker=reply_info.text;
5195 reply_info.highlight=MagickFalse;
5196 break;
5197 }
5198 default:
5199 break;
5200 }
5201 XEditText(display,&reply_info,key_symbol,command,state);
5202 XDrawMatteText(display,&windows->widget,&reply_info);
5203 state|=JumpListState;
5204 break;
5205 }
5206 case KeyRelease:
5207 {
5208 static char
5209 command[MaxTextExtent];
5210
5211 static KeySym
5212 key_symbol;
5213
5214 /*
5215 Respond to a user key release.
5216 */
5217 if (event.xkey.window != windows->widget.id)
5218 break;
5219 (void) XLookupString((XKeyEvent *) &event.xkey,command,
5220 (int) sizeof(command),&key_symbol,(XComposeStatus *) NULL);
5221 if (key_symbol == XK_Control_L)
5222 state&=(~ControlState);
5223 break;
5224 }
5225 case LeaveNotify:
5226 {
5227 if (event.xcrossing.window != windows->widget.id)
5228 break;
5229 state|=InactiveWidgetState;
5230 break;
5231 }
5232 case MapNotify:
5233 {
5234 mask&=(~CWX);
5235 mask&=(~CWY);
5236 break;
5237 }
5238 case MotionNotify:
5239 {
5240 /*
5241 Discard pending button motion events.
5242 */
5243 while (XCheckMaskEvent(display,ButtonMotionMask,&event)) ;
5244 if (slider_info.active)
5245 {
5246 /*
5247 Move slider matte.
5248 */
5249 slider_info.y=event.xmotion.y-
5250 ((slider_info.height+slider_info.bevel_width) >> 1)+1;
5251 if (slider_info.y < slider_info.min_y)
5252 slider_info.y=slider_info.min_y;
5253 if (slider_info.y > slider_info.max_y)
5254 slider_info.y=slider_info.max_y;
5255 slider_info.id=0;
5256 if (slider_info.y != slider_info.min_y)
5257 slider_info.id=(int) ((files*(slider_info.y-slider_info.min_y+1))/
5258 (slider_info.max_y-slider_info.min_y+1));
5259 state|=RedrawListState;
5260 break;
5261 }
5262 if (state & InactiveWidgetState)
5263 break;
5264 if (up_info.raised == MatteIsActive(up_info,event.xmotion))
5265 {
5266 /*
5267 Up button status changed.
5268 */
5269 up_info.raised=!up_info.raised;
5270 XDrawBeveledButton(display,&windows->widget,&up_info);
5271 break;
5272 }
5273 if (home_info.raised == MatteIsActive(home_info,event.xmotion))
5274 {
5275 /*
5276 Home button status changed.
5277 */
5278 home_info.raised=!home_info.raised;
5279 XDrawBeveledButton(display,&windows->widget,&home_info);
5280 break;
5281 }
5282 if (special_info.raised == MatteIsActive(special_info,event.xmotion))
5283 {
5284 /*
5285 Grab button status changed.
5286 */
5287 special_info.raised=!special_info.raised;
5288 XDrawBeveledButton(display,&windows->widget,&special_info);
5289 break;
5290 }
5291 if (action_info.raised == MatteIsActive(action_info,event.xmotion))
5292 {
5293 /*
5294 Action button status changed.
5295 */
5296 action_info.raised=action_info.raised == MagickFalse ?
5297 MagickTrue : MagickFalse;
5298 XDrawBeveledButton(display,&windows->widget,&action_info);
5299 break;
5300 }
5301 if (cancel_info.raised == MatteIsActive(cancel_info,event.xmotion))
5302 {
5303 /*
5304 Cancel button status changed.
5305 */
5306 cancel_info.raised=cancel_info.raised == MagickFalse ?
5307 MagickTrue : MagickFalse;
5308 XDrawBeveledButton(display,&windows->widget,&cancel_info);
5309 break;
5310 }
5311 break;
5312 }
5313 case SelectionClear:
5314 {
5315 reply_info.highlight=MagickFalse;
5316 XDrawMatteText(display,&windows->widget,&reply_info);
5317 break;
5318 }
5319 case SelectionNotify:
5320 {
5321 Atom
5322 type;
5323
5324 int
5325 format;
5326
5327 unsigned char
5328 *data;
5329
cristyf2faecf2010-05-28 19:19:36 +00005330 unsigned long
cristy3ed852e2009-09-05 21:47:34 +00005331 after,
5332 length;
5333
5334 /*
5335 Obtain response from primary selection.
5336 */
5337 if (event.xselection.property == (Atom) None)
5338 break;
5339 status=XGetWindowProperty(display,event.xselection.requestor,
5340 event.xselection.property,0L,2047L,MagickTrue,XA_STRING,&type,
5341 &format,&length,&after,&data);
5342 if ((status != Success) || (type != XA_STRING) || (format == 32) ||
5343 (length == 0))
5344 break;
5345 if ((Extent(reply_info.text)+length) >= MaxTextExtent)
5346 (void) XBell(display,0);
5347 else
5348 {
5349 /*
5350 Insert primary selection in reply text.
5351 */
5352 *(data+length)='\0';
5353 XEditText(display,&reply_info,(KeySym) XK_Insert,(char *) data,
5354 state);
5355 XDrawMatteText(display,&windows->widget,&reply_info);
5356 state|=JumpListState;
5357 state|=RedrawActionState;
5358 }
5359 (void) XFree((void *) data);
5360 break;
5361 }
5362 case SelectionRequest:
5363 {
5364 XSelectionEvent
5365 notify;
5366
5367 XSelectionRequestEvent
5368 *request;
5369
5370 if (reply_info.highlight == MagickFalse)
5371 break;
5372 /*
5373 Set primary selection.
5374 */
5375 request=(&(event.xselectionrequest));
5376 (void) XChangeProperty(request->display,request->requestor,
5377 request->property,request->target,8,PropModeReplace,
5378 (unsigned char *) primary_selection,Extent(primary_selection));
5379 notify.type=SelectionNotify;
5380 notify.display=request->display;
5381 notify.requestor=request->requestor;
5382 notify.selection=request->selection;
5383 notify.target=request->target;
5384 notify.time=request->time;
5385 if (request->property == None)
5386 notify.property=request->target;
5387 else
5388 notify.property=request->property;
5389 (void) XSendEvent(request->display,request->requestor,False,0,
5390 (XEvent *) &notify);
5391 }
5392 default:
5393 break;
5394 }
5395 } while ((state & ExitState) == 0);
5396 XSetCursorState(display,windows,MagickFalse);
5397 (void) XWithdrawWindow(display,windows->widget.id,windows->widget.screen);
5398 XCheckRefreshWindows(display,windows);
5399 /*
5400 Free file list.
5401 */
cristybb503372010-05-27 20:51:26 +00005402 for (i=0; i < (ssize_t) files; i++)
cristy3ed852e2009-09-05 21:47:34 +00005403 filelist[i]=DestroyString(filelist[i]);
5404 if (filelist != (char **) NULL)
5405 filelist=(char **) RelinquishMagickMemory(filelist);
5406 if (*reply != '\0')
5407 {
5408 (void) ConcatenateMagickString(working_path,DirectorySeparator,
5409 MaxTextExtent);
5410 (void) ConcatenateMagickString(working_path,reply,MaxTextExtent);
5411 }
5412 (void) CopyMagickString(reply,working_path,MaxTextExtent);
5413 if (*reply == '~')
5414 ExpandFilename(reply);
5415}
5416
5417/*
5418%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5419% %
5420% %
5421% %
5422% X F o n t B r o w s e r W i d g e t %
5423% %
5424% %
5425% %
5426%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5427%
5428% XFontBrowserWidget() displays a Font Browser widget with a font query to the
5429% user. The user keys a reply and presses the Action or Cancel button to
5430% exit. The typed text is returned as the reply function parameter.
5431%
5432% The format of the XFontBrowserWidget method is:
5433%
5434% void XFontBrowserWidget(Display *display,XWindows *windows,
5435% const char *action,char *reply)
5436%
5437% A description of each parameter follows:
5438%
5439% o display: Specifies a connection to an X server; returned from
5440% XOpenDisplay.
5441%
5442% o window: Specifies a pointer to a XWindows structure.
5443%
5444% o action: Specifies a pointer to the action of this widget.
5445%
5446% o reply: the response from the user is returned in this parameter.
5447%
5448%
5449*/
5450
5451#if defined(__cplusplus) || defined(c_plusplus)
5452extern "C" {
5453#endif
5454
5455static int FontCompare(const void *x,const void *y)
5456{
5457 register char
5458 *p,
5459 *q;
5460
5461 p=(char *) *((char **) x);
5462 q=(char *) *((char **) y);
5463 while ((*p != '\0') && (*q != '\0') && (*p == *q))
5464 {
5465 p++;
5466 q++;
5467 }
5468 return(*p-(*q));
5469}
5470
5471#if defined(__cplusplus) || defined(c_plusplus)
5472}
5473#endif
5474
5475MagickExport void XFontBrowserWidget(Display *display,XWindows *windows,
5476 const char *action,char *reply)
5477{
5478#define BackButtonText "Back"
5479#define CancelButtonText "Cancel"
5480#define FontnameText "Name:"
5481#define FontPatternText "Pattern:"
5482#define ResetButtonText "Reset"
5483
5484 char
5485 back_pattern[MaxTextExtent],
5486 **fontlist,
5487 **listhead,
5488 primary_selection[MaxTextExtent],
5489 reset_pattern[MaxTextExtent],
5490 text[MaxTextExtent];
5491
5492 int
5493 fonts,
5494 x,
5495 y;
5496
5497 register int
5498 i;
5499
5500 static char
5501 glob_pattern[MaxTextExtent] = "*";
5502
5503 static MagickStatusType
5504 mask = (MagickStatusType) (CWWidth | CWHeight | CWX | CWY);
5505
5506 Status
5507 status;
5508
5509 unsigned int
5510 height,
5511 text_width,
5512 visible_fonts,
5513 width;
5514
cristybb503372010-05-27 20:51:26 +00005515 size_t
cristy3ed852e2009-09-05 21:47:34 +00005516 delay,
5517 state;
5518
5519 XEvent
5520 event;
5521
5522 XFontStruct
5523 *font_info;
5524
5525 XTextProperty
5526 window_name;
5527
5528 XWidgetInfo
5529 action_info,
5530 back_info,
5531 cancel_info,
5532 expose_info,
5533 list_info,
5534 mode_info,
5535 north_info,
5536 reply_info,
5537 reset_info,
5538 scroll_info,
5539 selection_info,
5540 slider_info,
5541 south_info,
5542 text_info;
5543
5544 XWindowChanges
5545 window_changes;
5546
5547 /*
5548 Get font list and sort in ascending order.
5549 */
5550 assert(display != (Display *) NULL);
5551 assert(windows != (XWindows *) NULL);
5552 assert(action != (char *) NULL);
5553 assert(reply != (char *) NULL);
5554 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",action);
5555 XSetCursorState(display,windows,MagickTrue);
5556 XCheckRefreshWindows(display,windows);
5557 (void) CopyMagickString(back_pattern,glob_pattern,MaxTextExtent);
5558 (void) CopyMagickString(reset_pattern,"*",MaxTextExtent);
5559 fontlist=XListFonts(display,glob_pattern,32767,&fonts);
5560 if (fonts == 0)
5561 {
5562 /*
5563 Pattern failed, obtain all the fonts.
5564 */
5565 XNoticeWidget(display,windows,"Unable to obtain fonts names:",
5566 glob_pattern);
5567 (void) CopyMagickString(glob_pattern,"*",MaxTextExtent);
5568 fontlist=XListFonts(display,glob_pattern,32767,&fonts);
5569 if (fontlist == (char **) NULL)
5570 {
5571 XNoticeWidget(display,windows,"Unable to obtain fonts names:",
5572 glob_pattern);
5573 return;
5574 }
5575 }
5576 /*
5577 Sort font list in ascending order.
5578 */
5579 listhead=fontlist;
5580 fontlist=(char **) AcquireQuantumMemory((size_t) fonts,sizeof(*fontlist));
5581 if (fontlist == (char **) NULL)
5582 {
5583 XNoticeWidget(display,windows,"MemoryAllocationFailed",
5584 "UnableToViewFonts");
5585 return;
5586 }
5587 for (i=0; i < fonts; i++)
5588 fontlist[i]=listhead[i];
5589 qsort((void *) fontlist,(size_t) fonts,sizeof(*fontlist),FontCompare);
5590 /*
5591 Determine Font Browser widget attributes.
5592 */
5593 font_info=windows->widget.font_info;
5594 text_width=0;
5595 for (i=0; i < fonts; i++)
5596 if (WidgetTextWidth(font_info,fontlist[i]) > text_width)
5597 text_width=WidgetTextWidth(font_info,fontlist[i]);
5598 width=WidgetTextWidth(font_info,(char *) action);
5599 if (WidgetTextWidth(font_info,CancelButtonText) > width)
5600 width=WidgetTextWidth(font_info,CancelButtonText);
5601 if (WidgetTextWidth(font_info,ResetButtonText) > width)
5602 width=WidgetTextWidth(font_info,ResetButtonText);
5603 if (WidgetTextWidth(font_info,BackButtonText) > width)
5604 width=WidgetTextWidth(font_info,BackButtonText);
5605 width+=QuantumMargin;
5606 if (WidgetTextWidth(font_info,FontPatternText) > width)
5607 width=WidgetTextWidth(font_info,FontPatternText);
5608 if (WidgetTextWidth(font_info,FontnameText) > width)
5609 width=WidgetTextWidth(font_info,FontnameText);
5610 height=(unsigned int) (font_info->ascent+font_info->descent);
5611 /*
5612 Position Font Browser widget.
5613 */
5614 windows->widget.width=width+MagickMin((int) text_width,(int) MaxTextWidth)+
5615 6*QuantumMargin;
5616 windows->widget.min_width=width+MinTextWidth+4*QuantumMargin;
5617 if (windows->widget.width < windows->widget.min_width)
5618 windows->widget.width=windows->widget.min_width;
5619 windows->widget.height=(unsigned int)
5620 (((85*height) >> 2)+((13*QuantumMargin) >> 1)+4);
5621 windows->widget.min_height=(unsigned int)
5622 (((27*height) >> 1)+((13*QuantumMargin) >> 1)+4);
5623 if (windows->widget.height < windows->widget.min_height)
5624 windows->widget.height=windows->widget.min_height;
5625 XConstrainWindowPosition(display,&windows->widget);
5626 /*
5627 Map Font Browser widget.
5628 */
5629 (void) CopyMagickString(windows->widget.name,"Browse and Select a Font",
5630 MaxTextExtent);
5631 status=XStringListToTextProperty(&windows->widget.name,1,&window_name);
5632 if (status != False)
5633 {
5634 XSetWMName(display,windows->widget.id,&window_name);
5635 XSetWMIconName(display,windows->widget.id,&window_name);
5636 (void) XFree((void *) window_name.value);
5637 }
5638 window_changes.width=(int) windows->widget.width;
5639 window_changes.height=(int) windows->widget.height;
5640 window_changes.x=windows->widget.x;
5641 window_changes.y=windows->widget.y;
5642 (void) XReconfigureWMWindow(display,windows->widget.id,
5643 windows->widget.screen,mask,&window_changes);
5644 (void) XMapRaised(display,windows->widget.id);
5645 windows->widget.mapped=MagickFalse;
5646 /*
5647 Respond to X events.
5648 */
5649 XGetWidgetInfo((char *) NULL,&slider_info);
5650 XGetWidgetInfo((char *) NULL,&north_info);
5651 XGetWidgetInfo((char *) NULL,&south_info);
5652 XGetWidgetInfo((char *) NULL,&expose_info);
5653 visible_fonts=0;
5654 delay=SuspendTime << 2;
5655 state=UpdateConfigurationState;
5656 do
5657 {
5658 if (state & UpdateConfigurationState)
5659 {
5660 int
5661 id;
5662
5663 /*
5664 Initialize button information.
5665 */
5666 XGetWidgetInfo(CancelButtonText,&cancel_info);
5667 cancel_info.width=width;
5668 cancel_info.height=(unsigned int) ((3*height) >> 1);
5669 cancel_info.x=(int)
5670 (windows->widget.width-cancel_info.width-QuantumMargin-2);
5671 cancel_info.y=(int)
5672 (windows->widget.height-cancel_info.height-QuantumMargin);
5673 XGetWidgetInfo(action,&action_info);
5674 action_info.width=width;
5675 action_info.height=(unsigned int) ((3*height) >> 1);
5676 action_info.x=cancel_info.x-(cancel_info.width+(QuantumMargin >> 1)+
5677 (action_info.bevel_width << 1));
5678 action_info.y=cancel_info.y;
5679 XGetWidgetInfo(BackButtonText,&back_info);
5680 back_info.width=width;
5681 back_info.height=(unsigned int) ((3*height) >> 1);
5682 back_info.x=QuantumMargin;
5683 back_info.y=((5*QuantumMargin) >> 1)+height;
5684 XGetWidgetInfo(ResetButtonText,&reset_info);
5685 reset_info.width=width;
5686 reset_info.height=(unsigned int) ((3*height) >> 1);
5687 reset_info.x=QuantumMargin;
5688 reset_info.y=back_info.y+back_info.height+QuantumMargin;
5689 /*
5690 Initialize reply information.
5691 */
5692 XGetWidgetInfo(reply,&reply_info);
5693 reply_info.raised=MagickFalse;
5694 reply_info.bevel_width--;
5695 reply_info.width=windows->widget.width-width-((6*QuantumMargin) >> 1);
5696 reply_info.height=height << 1;
5697 reply_info.x=(int) (width+(QuantumMargin << 1));
5698 reply_info.y=action_info.y-(action_info.height << 1)-QuantumMargin;
5699 /*
5700 Initialize mode information.
5701 */
5702 XGetWidgetInfo(reply,&mode_info);
5703 mode_info.bevel_width=0;
5704 mode_info.width=(unsigned int)
5705 (action_info.x-reply_info.x-QuantumMargin);
5706 mode_info.height=action_info.height << 1;
5707 mode_info.x=reply_info.x;
5708 mode_info.y=action_info.y-action_info.height+action_info.bevel_width;
5709 /*
5710 Initialize scroll information.
5711 */
5712 XGetWidgetInfo((char *) NULL,&scroll_info);
5713 scroll_info.bevel_width--;
5714 scroll_info.width=height;
5715 scroll_info.height=(unsigned int)
5716 (reply_info.y-back_info.y-(QuantumMargin >> 1));
5717 scroll_info.x=reply_info.x+(reply_info.width-scroll_info.width);
5718 scroll_info.y=back_info.y-reply_info.bevel_width;
5719 scroll_info.raised=MagickFalse;
5720 scroll_info.trough=MagickTrue;
5721 north_info=scroll_info;
5722 north_info.raised=MagickTrue;
5723 north_info.width-=(north_info.bevel_width << 1);
5724 north_info.height=north_info.width-1;
5725 north_info.x+=north_info.bevel_width;
5726 north_info.y+=north_info.bevel_width;
5727 south_info=north_info;
5728 south_info.y=scroll_info.y+scroll_info.height-scroll_info.bevel_width-
5729 south_info.height;
5730 id=slider_info.id;
5731 slider_info=north_info;
5732 slider_info.id=id;
5733 slider_info.width-=2;
5734 slider_info.min_y=north_info.y+north_info.height+north_info.bevel_width+
5735 slider_info.bevel_width+2;
5736 slider_info.height=scroll_info.height-((slider_info.min_y-
5737 scroll_info.y+1) << 1)+4;
5738 visible_fonts=scroll_info.height/(height+(height >> 3));
5739 if (fonts > (int) visible_fonts)
5740 slider_info.height=(visible_fonts*slider_info.height)/fonts;
5741 slider_info.max_y=south_info.y-south_info.bevel_width-
5742 slider_info.bevel_width-2;
5743 slider_info.x=scroll_info.x+slider_info.bevel_width+1;
5744 slider_info.y=slider_info.min_y;
5745 expose_info=scroll_info;
5746 expose_info.y=slider_info.y;
5747 /*
5748 Initialize list information.
5749 */
5750 XGetWidgetInfo((char *) NULL,&list_info);
5751 list_info.raised=MagickFalse;
5752 list_info.bevel_width--;
5753 list_info.width=(unsigned int)
5754 (scroll_info.x-reply_info.x-(QuantumMargin >> 1));
5755 list_info.height=scroll_info.height;
5756 list_info.x=reply_info.x;
5757 list_info.y=scroll_info.y;
5758 if (windows->widget.mapped == MagickFalse)
5759 state|=JumpListState;
5760 /*
5761 Initialize text information.
5762 */
5763 *text='\0';
5764 XGetWidgetInfo(text,&text_info);
5765 text_info.center=MagickFalse;
5766 text_info.width=reply_info.width;
5767 text_info.height=height;
5768 text_info.x=list_info.x-(QuantumMargin >> 1);
5769 text_info.y=QuantumMargin;
5770 /*
5771 Initialize selection information.
5772 */
5773 XGetWidgetInfo((char *) NULL,&selection_info);
5774 selection_info.center=MagickFalse;
5775 selection_info.width=list_info.width;
5776 selection_info.height=(unsigned int) ((9*height) >> 3);
5777 selection_info.x=list_info.x;
5778 state&=(~UpdateConfigurationState);
5779 }
5780 if (state & RedrawWidgetState)
5781 {
5782 /*
5783 Redraw Font Browser window.
5784 */
5785 x=QuantumMargin;
5786 y=text_info.y+((text_info.height-height) >> 1)+font_info->ascent;
5787 (void) XDrawString(display,windows->widget.id,
5788 windows->widget.annotate_context,x,y,FontPatternText,
5789 Extent(FontPatternText));
5790 (void) CopyMagickString(text_info.text,glob_pattern,MaxTextExtent);
5791 XDrawWidgetText(display,&windows->widget,&text_info);
5792 XDrawBeveledButton(display,&windows->widget,&back_info);
5793 XDrawBeveledButton(display,&windows->widget,&reset_info);
5794 XDrawBeveledMatte(display,&windows->widget,&list_info);
5795 XDrawBeveledMatte(display,&windows->widget,&scroll_info);
5796 XDrawTriangleNorth(display,&windows->widget,&north_info);
5797 XDrawBeveledButton(display,&windows->widget,&slider_info);
5798 XDrawTriangleSouth(display,&windows->widget,&south_info);
5799 x=QuantumMargin;
5800 y=reply_info.y+((reply_info.height-height) >> 1)+font_info->ascent;
5801 (void) XDrawString(display,windows->widget.id,
5802 windows->widget.annotate_context,x,y,FontnameText,
5803 Extent(FontnameText));
5804 XDrawBeveledMatte(display,&windows->widget,&reply_info);
5805 XDrawMatteText(display,&windows->widget,&reply_info);
5806 XDrawBeveledButton(display,&windows->widget,&action_info);
5807 XDrawBeveledButton(display,&windows->widget,&cancel_info);
5808 XHighlightWidget(display,&windows->widget,BorderOffset,BorderOffset);
5809 selection_info.id=(~0);
5810 state|=RedrawActionState;
5811 state|=RedrawListState;
5812 state&=(~RedrawWidgetState);
5813 }
5814 if (state & UpdateListState)
5815 {
5816 char
5817 **checklist;
5818
5819 int
5820 number_fonts;
5821
5822 /*
5823 Update font list.
5824 */
5825 checklist=XListFonts(display,glob_pattern,32767,&number_fonts);
5826 if (checklist == (char **) NULL)
5827 {
5828 if ((strchr(glob_pattern,'*') == (char *) NULL) &&
5829 (strchr(glob_pattern,'?') == (char *) NULL))
5830 {
5831 /*
5832 Might be a scaleable font-- exit.
5833 */
5834 (void) CopyMagickString(reply,glob_pattern,MaxTextExtent);
5835 (void) CopyMagickString(glob_pattern,back_pattern,MaxTextExtent);
5836 action_info.raised=MagickFalse;
5837 XDrawBeveledButton(display,&windows->widget,&action_info);
5838 break;
5839 }
5840 (void) CopyMagickString(glob_pattern,back_pattern,MaxTextExtent);
5841 (void) XBell(display,0);
5842 }
5843 else
5844 if (number_fonts == 1)
5845 {
5846 /*
5847 Reply is a single font name-- exit.
5848 */
5849 (void) CopyMagickString(reply,checklist[0],MaxTextExtent);
5850 (void) CopyMagickString(glob_pattern,back_pattern,MaxTextExtent);
5851 (void) XFreeFontNames(checklist);
5852 action_info.raised=MagickFalse;
5853 XDrawBeveledButton(display,&windows->widget,&action_info);
5854 break;
5855 }
5856 else
5857 {
5858 (void) XFreeFontNames(listhead);
5859 fontlist=(char **) RelinquishMagickMemory(fontlist);
5860 fontlist=checklist;
5861 fonts=number_fonts;
5862 }
5863 /*
5864 Sort font list in ascending order.
5865 */
5866 listhead=fontlist;
5867 fontlist=(char **) AcquireQuantumMemory((size_t) fonts,
5868 sizeof(*fontlist));
5869 if (fontlist == (char **) NULL)
5870 {
5871 XNoticeWidget(display,windows,"MemoryAllocationFailed",
5872 "UnableToViewFonts");
5873 return;
5874 }
5875 for (i=0; i < fonts; i++)
5876 fontlist[i]=listhead[i];
5877 qsort((void *) fontlist,(size_t) fonts,sizeof(*fontlist),FontCompare);
5878 slider_info.height=
5879 scroll_info.height-((slider_info.min_y-scroll_info.y+1) << 1)+1;
5880 if (fonts > (int) visible_fonts)
5881 slider_info.height=(visible_fonts*slider_info.height)/fonts;
5882 slider_info.max_y=south_info.y-south_info.bevel_width-
5883 slider_info.bevel_width-2;
5884 slider_info.id=0;
5885 slider_info.y=slider_info.min_y;
5886 expose_info.y=slider_info.y;
5887 selection_info.id=(~0);
5888 list_info.id=(~0);
5889 state|=RedrawListState;
5890 /*
5891 Redraw font name & reply.
5892 */
5893 *reply_info.text='\0';
5894 reply_info.cursor=reply_info.text;
5895 (void) CopyMagickString(text_info.text,glob_pattern,MaxTextExtent);
5896 XDrawWidgetText(display,&windows->widget,&text_info);
5897 XDrawMatteText(display,&windows->widget,&reply_info);
5898 XDrawBeveledMatte(display,&windows->widget,&scroll_info);
5899 XDrawTriangleNorth(display,&windows->widget,&north_info);
5900 XDrawBeveledButton(display,&windows->widget,&slider_info);
5901 XDrawTriangleSouth(display,&windows->widget,&south_info);
5902 XHighlightWidget(display,&windows->widget,BorderOffset,BorderOffset);
5903 state&=(~UpdateListState);
5904 }
5905 if (state & JumpListState)
5906 {
5907 /*
5908 Jump scroll to match user font.
5909 */
5910 list_info.id=(~0);
5911 for (i=0; i < fonts; i++)
5912 if (LocaleCompare(fontlist[i],reply) >= 0)
5913 {
5914 list_info.id=LocaleCompare(fontlist[i],reply) == 0 ? i : ~0;
5915 break;
5916 }
5917 if ((i < slider_info.id) || (i >= (int) (slider_info.id+visible_fonts)))
5918 slider_info.id=i-(visible_fonts >> 1);
5919 selection_info.id=(~0);
5920 state|=RedrawListState;
5921 state&=(~JumpListState);
5922 }
5923 if (state & RedrawListState)
5924 {
5925 /*
5926 Determine slider id and position.
5927 */
5928 if (slider_info.id >= (int) (fonts-visible_fonts))
5929 slider_info.id=fonts-visible_fonts;
5930 if ((slider_info.id < 0) || (fonts <= (int) visible_fonts))
5931 slider_info.id=0;
5932 slider_info.y=slider_info.min_y;
5933 if (fonts > 0)
5934 slider_info.y+=
5935 slider_info.id*(slider_info.max_y-slider_info.min_y+1)/fonts;
5936 if (slider_info.id != selection_info.id)
5937 {
5938 /*
5939 Redraw scroll bar and file names.
5940 */
5941 selection_info.id=slider_info.id;
5942 selection_info.y=list_info.y+(height >> 3)+2;
5943 for (i=0; i < (int) visible_fonts; i++)
5944 {
5945 selection_info.raised=(slider_info.id+i) != list_info.id ?
5946 MagickTrue : MagickFalse;
5947 selection_info.text=(char *) NULL;
5948 if ((slider_info.id+i) < fonts)
5949 selection_info.text=fontlist[slider_info.id+i];
5950 XDrawWidgetText(display,&windows->widget,&selection_info);
5951 selection_info.y+=(int) selection_info.height;
5952 }
5953 /*
5954 Update slider.
5955 */
5956 if (slider_info.y > expose_info.y)
5957 {
5958 expose_info.height=(unsigned int) slider_info.y-expose_info.y;
5959 expose_info.y=slider_info.y-expose_info.height-
5960 slider_info.bevel_width-1;
5961 }
5962 else
5963 {
5964 expose_info.height=(unsigned int) expose_info.y-slider_info.y;
5965 expose_info.y=slider_info.y+slider_info.height+
5966 slider_info.bevel_width+1;
5967 }
5968 XDrawTriangleNorth(display,&windows->widget,&north_info);
5969 XDrawMatte(display,&windows->widget,&expose_info);
5970 XDrawBeveledButton(display,&windows->widget,&slider_info);
5971 XDrawTriangleSouth(display,&windows->widget,&south_info);
5972 expose_info.y=slider_info.y;
5973 }
5974 state&=(~RedrawListState);
5975 }
5976 if (state & RedrawActionState)
5977 {
5978 XFontStruct
5979 *save_info;
5980
5981 /*
5982 Display the selected font in a drawing area.
5983 */
5984 save_info=windows->widget.font_info;
5985 font_info=XLoadQueryFont(display,reply_info.text);
5986 if (font_info != (XFontStruct *) NULL)
5987 {
5988 windows->widget.font_info=font_info;
5989 (void) XSetFont(display,windows->widget.widget_context,
5990 font_info->fid);
5991 }
5992 XDrawBeveledButton(display,&windows->widget,&mode_info);
5993 windows->widget.font_info=save_info;
5994 if (font_info != (XFontStruct *) NULL)
5995 {
5996 (void) XSetFont(display,windows->widget.widget_context,
5997 windows->widget.font_info->fid);
5998 (void) XFreeFont(display,font_info);
5999 }
6000 XHighlightWidget(display,&windows->widget,BorderOffset,BorderOffset);
6001 XDrawMatteText(display,&windows->widget,&reply_info);
6002 state&=(~RedrawActionState);
6003 }
6004 /*
6005 Wait for next event.
6006 */
6007 if (north_info.raised && south_info.raised)
6008 (void) XIfEvent(display,&event,XScreenEvent,(char *) windows);
6009 else
6010 {
6011 /*
6012 Brief delay before advancing scroll bar.
6013 */
6014 XDelay(display,delay);
6015 delay=SuspendTime;
6016 (void) XCheckIfEvent(display,&event,XScreenEvent,(char *) windows);
6017 if (north_info.raised == MagickFalse)
6018 if (slider_info.id > 0)
6019 {
6020 /*
6021 Move slider up.
6022 */
6023 slider_info.id--;
6024 state|=RedrawListState;
6025 }
6026 if (south_info.raised == MagickFalse)
6027 if (slider_info.id < fonts)
6028 {
6029 /*
6030 Move slider down.
6031 */
6032 slider_info.id++;
6033 state|=RedrawListState;
6034 }
6035 if (event.type != ButtonRelease)
6036 continue;
6037 }
6038 switch (event.type)
6039 {
6040 case ButtonPress:
6041 {
6042 if (MatteIsActive(slider_info,event.xbutton))
6043 {
6044 /*
6045 Track slider.
6046 */
6047 slider_info.active=MagickTrue;
6048 break;
6049 }
6050 if (MatteIsActive(north_info,event.xbutton))
6051 if (slider_info.id > 0)
6052 {
6053 /*
6054 Move slider up.
6055 */
6056 north_info.raised=MagickFalse;
6057 slider_info.id--;
6058 state|=RedrawListState;
6059 break;
6060 }
6061 if (MatteIsActive(south_info,event.xbutton))
6062 if (slider_info.id < fonts)
6063 {
6064 /*
6065 Move slider down.
6066 */
6067 south_info.raised=MagickFalse;
6068 slider_info.id++;
6069 state|=RedrawListState;
6070 break;
6071 }
6072 if (MatteIsActive(scroll_info,event.xbutton))
6073 {
6074 /*
6075 Move slider.
6076 */
6077 if (event.xbutton.y < slider_info.y)
6078 slider_info.id-=(visible_fonts-1);
6079 else
6080 slider_info.id+=(visible_fonts-1);
6081 state|=RedrawListState;
6082 break;
6083 }
6084 if (MatteIsActive(list_info,event.xbutton))
6085 {
6086 int
6087 id;
6088
6089 /*
6090 User pressed list matte.
6091 */
6092 id=slider_info.id+(event.xbutton.y-(list_info.y+(height >> 1))+1)/
6093 selection_info.height;
6094 if (id >= (int) fonts)
6095 break;
6096 (void) CopyMagickString(reply_info.text,fontlist[id],MaxTextExtent);
6097 reply_info.highlight=MagickFalse;
6098 reply_info.marker=reply_info.text;
6099 reply_info.cursor=reply_info.text+Extent(reply_info.text);
6100 XDrawMatteText(display,&windows->widget,&reply_info);
6101 state|=RedrawActionState;
6102 if (id == list_info.id)
6103 {
6104 (void) CopyMagickString(glob_pattern,reply_info.text,
6105 MaxTextExtent);
6106 state|=UpdateListState;
6107 }
6108 selection_info.id=(~0);
6109 list_info.id=id;
6110 state|=RedrawListState;
6111 break;
6112 }
6113 if (MatteIsActive(back_info,event.xbutton))
6114 {
6115 /*
6116 User pressed Back button.
6117 */
6118 back_info.raised=MagickFalse;
6119 XDrawBeveledButton(display,&windows->widget,&back_info);
6120 break;
6121 }
6122 if (MatteIsActive(reset_info,event.xbutton))
6123 {
6124 /*
6125 User pressed Reset button.
6126 */
6127 reset_info.raised=MagickFalse;
6128 XDrawBeveledButton(display,&windows->widget,&reset_info);
6129 break;
6130 }
6131 if (MatteIsActive(action_info,event.xbutton))
6132 {
6133 /*
6134 User pressed action button.
6135 */
6136 action_info.raised=MagickFalse;
6137 XDrawBeveledButton(display,&windows->widget,&action_info);
6138 break;
6139 }
6140 if (MatteIsActive(cancel_info,event.xbutton))
6141 {
6142 /*
6143 User pressed Cancel button.
6144 */
6145 cancel_info.raised=MagickFalse;
6146 XDrawBeveledButton(display,&windows->widget,&cancel_info);
6147 break;
6148 }
6149 if (MatteIsActive(reply_info,event.xbutton) == MagickFalse)
6150 break;
6151 if (event.xbutton.button != Button2)
6152 {
6153 static Time
6154 click_time;
6155
6156 /*
6157 Move text cursor to position of button press.
6158 */
6159 x=event.xbutton.x-reply_info.x-(QuantumMargin >> 2);
6160 for (i=1; i <= Extent(reply_info.marker); i++)
6161 if (XTextWidth(font_info,reply_info.marker,i) > x)
6162 break;
6163 reply_info.cursor=reply_info.marker+i-1;
6164 if (event.xbutton.time > (click_time+DoubleClick))
6165 reply_info.highlight=MagickFalse;
6166 else
6167 {
6168 /*
6169 Become the XA_PRIMARY selection owner.
6170 */
6171 (void) CopyMagickString(primary_selection,reply_info.text,
6172 MaxTextExtent);
6173 (void) XSetSelectionOwner(display,XA_PRIMARY,windows->widget.id,
6174 event.xbutton.time);
6175 reply_info.highlight=XGetSelectionOwner(display,XA_PRIMARY) ==
6176 windows->widget.id ? MagickTrue : MagickFalse;
6177 }
6178 XDrawMatteText(display,&windows->widget,&reply_info);
6179 click_time=event.xbutton.time;
6180 break;
6181 }
6182 /*
6183 Request primary selection.
6184 */
6185 (void) XConvertSelection(display,XA_PRIMARY,XA_STRING,XA_STRING,
6186 windows->widget.id,event.xbutton.time);
6187 break;
6188 }
6189 case ButtonRelease:
6190 {
6191 if (windows->widget.mapped == MagickFalse)
6192 break;
6193 if (north_info.raised == MagickFalse)
6194 {
6195 /*
6196 User released up button.
6197 */
6198 delay=SuspendTime << 2;
6199 north_info.raised=MagickTrue;
6200 XDrawTriangleNorth(display,&windows->widget,&north_info);
6201 }
6202 if (south_info.raised == MagickFalse)
6203 {
6204 /*
6205 User released down button.
6206 */
6207 delay=SuspendTime << 2;
6208 south_info.raised=MagickTrue;
6209 XDrawTriangleSouth(display,&windows->widget,&south_info);
6210 }
6211 if (slider_info.active)
6212 {
6213 /*
6214 Stop tracking slider.
6215 */
6216 slider_info.active=MagickFalse;
6217 break;
6218 }
6219 if (back_info.raised == MagickFalse)
6220 {
6221 if (event.xbutton.window == windows->widget.id)
6222 if (MatteIsActive(back_info,event.xbutton))
6223 {
6224 (void) CopyMagickString(glob_pattern,back_pattern,
6225 MaxTextExtent);
6226 state|=UpdateListState;
6227 }
6228 back_info.raised=MagickTrue;
6229 XDrawBeveledButton(display,&windows->widget,&back_info);
6230 }
6231 if (reset_info.raised == MagickFalse)
6232 {
6233 if (event.xbutton.window == windows->widget.id)
6234 if (MatteIsActive(reset_info,event.xbutton))
6235 {
6236 (void) CopyMagickString(back_pattern,glob_pattern,MaxTextExtent);
6237 (void) CopyMagickString(glob_pattern,reset_pattern,MaxTextExtent);
6238 state|=UpdateListState;
6239 }
6240 reset_info.raised=MagickTrue;
6241 XDrawBeveledButton(display,&windows->widget,&reset_info);
6242 }
6243 if (action_info.raised == MagickFalse)
6244 {
6245 if (event.xbutton.window == windows->widget.id)
6246 {
6247 if (MatteIsActive(action_info,event.xbutton))
6248 {
6249 if (*reply_info.text == '\0')
6250 (void) XBell(display,0);
6251 else
6252 state|=ExitState;
6253 }
6254 }
6255 action_info.raised=MagickTrue;
6256 XDrawBeveledButton(display,&windows->widget,&action_info);
6257 }
6258 if (cancel_info.raised == MagickFalse)
6259 {
6260 if (event.xbutton.window == windows->widget.id)
6261 if (MatteIsActive(cancel_info,event.xbutton))
6262 {
6263 *reply_info.text='\0';
6264 state|=ExitState;
6265 }
6266 cancel_info.raised=MagickTrue;
6267 XDrawBeveledButton(display,&windows->widget,&cancel_info);
6268 }
6269 break;
6270 }
6271 case ClientMessage:
6272 {
6273 /*
6274 If client window delete message, exit.
6275 */
6276 if (event.xclient.message_type != windows->wm_protocols)
6277 break;
6278 if (*event.xclient.data.l == (int) windows->wm_take_focus)
6279 {
6280 (void) XSetInputFocus(display,event.xclient.window,RevertToParent,
6281 (Time) event.xclient.data.l[1]);
6282 break;
6283 }
6284 if (*event.xclient.data.l != (int) windows->wm_delete_window)
6285 break;
6286 if (event.xclient.window == windows->widget.id)
6287 {
6288 *reply_info.text='\0';
6289 state|=ExitState;
6290 break;
6291 }
6292 break;
6293 }
6294 case ConfigureNotify:
6295 {
6296 /*
6297 Update widget configuration.
6298 */
6299 if (event.xconfigure.window != windows->widget.id)
6300 break;
6301 if ((event.xconfigure.width == (int) windows->widget.width) &&
6302 (event.xconfigure.height == (int) windows->widget.height))
6303 break;
6304 windows->widget.width=(unsigned int)
6305 MagickMax(event.xconfigure.width,(int) windows->widget.min_width);
6306 windows->widget.height=(unsigned int)
6307 MagickMax(event.xconfigure.height,(int) windows->widget.min_height);
6308 state|=UpdateConfigurationState;
6309 break;
6310 }
6311 case EnterNotify:
6312 {
6313 if (event.xcrossing.window != windows->widget.id)
6314 break;
6315 state&=(~InactiveWidgetState);
6316 break;
6317 }
6318 case Expose:
6319 {
6320 if (event.xexpose.window != windows->widget.id)
6321 break;
6322 if (event.xexpose.count != 0)
6323 break;
6324 state|=RedrawWidgetState;
6325 break;
6326 }
6327 case KeyPress:
6328 {
6329 static char
6330 command[MaxTextExtent];
6331
6332 static int
6333 length;
6334
6335 static KeySym
6336 key_symbol;
6337
6338 /*
6339 Respond to a user key press.
6340 */
6341 if (event.xkey.window != windows->widget.id)
6342 break;
6343 length=XLookupString((XKeyEvent *) &event.xkey,command,
6344 (int) sizeof(command),&key_symbol,(XComposeStatus *) NULL);
6345 *(command+length)='\0';
6346 if (AreaIsActive(scroll_info,event.xkey))
6347 {
6348 /*
6349 Move slider.
6350 */
6351 switch ((int) key_symbol)
6352 {
6353 case XK_Home:
6354 case XK_KP_Home:
6355 {
6356 slider_info.id=0;
6357 break;
6358 }
6359 case XK_Up:
6360 case XK_KP_Up:
6361 {
6362 slider_info.id--;
6363 break;
6364 }
6365 case XK_Down:
6366 case XK_KP_Down:
6367 {
6368 slider_info.id++;
6369 break;
6370 }
6371 case XK_Prior:
6372 case XK_KP_Prior:
6373 {
6374 slider_info.id-=visible_fonts;
6375 break;
6376 }
6377 case XK_Next:
6378 case XK_KP_Next:
6379 {
6380 slider_info.id+=visible_fonts;
6381 break;
6382 }
6383 case XK_End:
6384 case XK_KP_End:
6385 {
6386 slider_info.id=fonts;
6387 break;
6388 }
6389 }
6390 state|=RedrawListState;
6391 break;
6392 }
6393 if ((key_symbol == XK_Return) || (key_symbol == XK_KP_Enter))
6394 {
6395 /*
6396 Read new font or glob patterm.
6397 */
6398 if (*reply_info.text == '\0')
6399 break;
6400 (void) CopyMagickString(back_pattern,glob_pattern,MaxTextExtent);
6401 (void) CopyMagickString(glob_pattern,reply_info.text,MaxTextExtent);
6402 state|=UpdateListState;
6403 break;
6404 }
6405 if (key_symbol == XK_Control_L)
6406 {
6407 state|=ControlState;
6408 break;
6409 }
6410 if (state & ControlState)
6411 switch ((int) key_symbol)
6412 {
6413 case XK_u:
6414 case XK_U:
6415 {
6416 /*
6417 Erase the entire line of text.
6418 */
6419 *reply_info.text='\0';
6420 reply_info.cursor=reply_info.text;
6421 reply_info.marker=reply_info.text;
6422 reply_info.highlight=MagickFalse;
6423 break;
6424 }
6425 default:
6426 break;
6427 }
6428 XEditText(display,&reply_info,key_symbol,command,state);
6429 XDrawMatteText(display,&windows->widget,&reply_info);
6430 state|=JumpListState;
6431 break;
6432 }
6433 case KeyRelease:
6434 {
6435 static char
6436 command[MaxTextExtent];
6437
6438 static KeySym
6439 key_symbol;
6440
6441 /*
6442 Respond to a user key release.
6443 */
6444 if (event.xkey.window != windows->widget.id)
6445 break;
6446 (void) XLookupString((XKeyEvent *) &event.xkey,command,
6447 (int) sizeof(command),&key_symbol,(XComposeStatus *) NULL);
6448 if (key_symbol == XK_Control_L)
6449 state&=(~ControlState);
6450 break;
6451 }
6452 case LeaveNotify:
6453 {
6454 if (event.xcrossing.window != windows->widget.id)
6455 break;
6456 state|=InactiveWidgetState;
6457 break;
6458 }
6459 case MapNotify:
6460 {
6461 mask&=(~CWX);
6462 mask&=(~CWY);
6463 break;
6464 }
6465 case MotionNotify:
6466 {
6467 /*
6468 Discard pending button motion events.
6469 */
6470 while (XCheckMaskEvent(display,ButtonMotionMask,&event)) ;
6471 if (slider_info.active)
6472 {
6473 /*
6474 Move slider matte.
6475 */
6476 slider_info.y=event.xmotion.y-
6477 ((slider_info.height+slider_info.bevel_width) >> 1)+1;
6478 if (slider_info.y < slider_info.min_y)
6479 slider_info.y=slider_info.min_y;
6480 if (slider_info.y > slider_info.max_y)
6481 slider_info.y=slider_info.max_y;
6482 slider_info.id=0;
6483 if (slider_info.y != slider_info.min_y)
6484 slider_info.id=(fonts*(slider_info.y-slider_info.min_y+1))/
6485 (slider_info.max_y-slider_info.min_y+1);
6486 state|=RedrawListState;
6487 break;
6488 }
6489 if (state & InactiveWidgetState)
6490 break;
6491 if (back_info.raised == MatteIsActive(back_info,event.xmotion))
6492 {
6493 /*
6494 Back button status changed.
6495 */
6496 back_info.raised=!back_info.raised;
6497 XDrawBeveledButton(display,&windows->widget,&back_info);
6498 break;
6499 }
6500 if (reset_info.raised == MatteIsActive(reset_info,event.xmotion))
6501 {
6502 /*
6503 Reset button status changed.
6504 */
6505 reset_info.raised=!reset_info.raised;
6506 XDrawBeveledButton(display,&windows->widget,&reset_info);
6507 break;
6508 }
6509 if (action_info.raised == MatteIsActive(action_info,event.xmotion))
6510 {
6511 /*
6512 Action button status changed.
6513 */
6514 action_info.raised=action_info.raised == MagickFalse ?
6515 MagickTrue : MagickFalse;
6516 XDrawBeveledButton(display,&windows->widget,&action_info);
6517 break;
6518 }
6519 if (cancel_info.raised == MatteIsActive(cancel_info,event.xmotion))
6520 {
6521 /*
6522 Cancel button status changed.
6523 */
6524 cancel_info.raised=cancel_info.raised == MagickFalse ?
6525 MagickTrue : MagickFalse;
6526 XDrawBeveledButton(display,&windows->widget,&cancel_info);
6527 break;
6528 }
6529 break;
6530 }
6531 case SelectionClear:
6532 {
6533 reply_info.highlight=MagickFalse;
6534 XDrawMatteText(display,&windows->widget,&reply_info);
6535 break;
6536 }
6537 case SelectionNotify:
6538 {
6539 Atom
6540 type;
6541
6542 int
6543 format;
6544
6545 unsigned char
6546 *data;
6547
cristyf2faecf2010-05-28 19:19:36 +00006548 unsigned long
cristy3ed852e2009-09-05 21:47:34 +00006549 after,
6550 length;
6551
6552 /*
6553 Obtain response from primary selection.
6554 */
6555 if (event.xselection.property == (Atom) None)
6556 break;
6557 status=XGetWindowProperty(display,event.xselection.requestor,
6558 event.xselection.property,0L,2047L,MagickTrue,XA_STRING,&type,
6559 &format,&length,&after,&data);
6560 if ((status != Success) || (type != XA_STRING) || (format == 32) ||
6561 (length == 0))
6562 break;
6563 if ((Extent(reply_info.text)+length) >= MaxTextExtent)
6564 (void) XBell(display,0);
6565 else
6566 {
6567 /*
6568 Insert primary selection in reply text.
6569 */
6570 *(data+length)='\0';
6571 XEditText(display,&reply_info,(KeySym) XK_Insert,(char *) data,
6572 state);
6573 XDrawMatteText(display,&windows->widget,&reply_info);
6574 state|=JumpListState;
6575 state|=RedrawActionState;
6576 }
6577 (void) XFree((void *) data);
6578 break;
6579 }
6580 case SelectionRequest:
6581 {
6582 XSelectionEvent
6583 notify;
6584
6585 XSelectionRequestEvent
6586 *request;
6587
6588 /*
6589 Set XA_PRIMARY selection.
6590 */
6591 request=(&(event.xselectionrequest));
6592 (void) XChangeProperty(request->display,request->requestor,
6593 request->property,request->target,8,PropModeReplace,
6594 (unsigned char *) primary_selection,Extent(primary_selection));
6595 notify.type=SelectionNotify;
6596 notify.display=request->display;
6597 notify.requestor=request->requestor;
6598 notify.selection=request->selection;
6599 notify.target=request->target;
6600 notify.time=request->time;
6601 if (request->property == None)
6602 notify.property=request->target;
6603 else
6604 notify.property=request->property;
6605 (void) XSendEvent(request->display,request->requestor,False,0,
6606 (XEvent *) &notify);
6607 }
6608 default:
6609 break;
6610 }
6611 } while ((state & ExitState) == 0);
6612 XSetCursorState(display,windows,MagickFalse);
6613 (void) XWithdrawWindow(display,windows->widget.id,windows->widget.screen);
6614 XCheckRefreshWindows(display,windows);
6615 /*
6616 Free font list.
6617 */
6618 (void) XFreeFontNames(listhead);
6619 fontlist=(char **) RelinquishMagickMemory(fontlist);
6620}
6621
6622/*
6623%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6624% %
6625% %
6626% %
6627% X I n f o W i d g e t %
6628% %
6629% %
6630% %
6631%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6632%
6633% XInfoWidget() displays text in the Info widget. The purpose is to inform
6634% the user that what activity is currently being performed (e.g. reading
6635% an image, rotating an image, etc.).
6636%
6637% The format of the XInfoWidget method is:
6638%
6639% void XInfoWidget(Display *display,XWindows *windows,const char *activity)
6640%
6641% A description of each parameter follows:
6642%
6643% o display: Specifies a connection to an X server; returned from
6644% XOpenDisplay.
6645%
6646% o window: Specifies a pointer to a XWindows structure.
6647%
6648% o activity: This character string reflects the current activity and is
6649% displayed in the Info widget.
6650%
6651*/
6652MagickExport void XInfoWidget(Display *display,XWindows *windows,
6653 const char *activity)
6654{
6655 unsigned int
6656 height,
6657 margin,
6658 width;
6659
6660 XFontStruct
6661 *font_info;
6662
6663 XWindowChanges
6664 window_changes;
6665
6666 /*
6667 Map Info widget.
6668 */
6669 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
6670 assert(display != (Display *) NULL);
6671 assert(windows != (XWindows *) NULL);
6672 assert(activity != (char *) NULL);
6673 font_info=windows->info.font_info;
6674 width=WidgetTextWidth(font_info,(char *) activity)+((3*QuantumMargin) >> 1)+4;
6675 height=(unsigned int) (((6*(font_info->ascent+font_info->descent)) >> 2)+4);
6676 if ((windows->info.width != width) || (windows->info.height != height))
6677 {
6678 /*
6679 Size Info widget to accommodate the activity text.
6680 */
6681 windows->info.width=width;
6682 windows->info.height=height;
6683 window_changes.width=(int) width;
6684 window_changes.height=(int) height;
6685 (void) XReconfigureWMWindow(display,windows->info.id,windows->info.screen,
6686 (unsigned int) (CWWidth | CWHeight),&window_changes);
6687 }
6688 if (windows->info.mapped == MagickFalse)
6689 {
6690 (void) XMapRaised(display,windows->info.id);
6691 windows->info.mapped=MagickTrue;
6692 }
6693 /*
6694 Initialize Info matte information.
6695 */
6696 height=(unsigned int) (font_info->ascent+font_info->descent);
6697 XGetWidgetInfo(activity,&monitor_info);
6698 monitor_info.bevel_width--;
6699 margin=monitor_info.bevel_width+((windows->info.height-height) >> 1)-2;
6700 monitor_info.center=MagickFalse;
6701 monitor_info.x=(int) margin;
6702 monitor_info.y=(int) margin;
6703 monitor_info.width=windows->info.width-(margin << 1);
6704 monitor_info.height=windows->info.height-(margin << 1)+1;
6705 /*
6706 Draw Info widget.
6707 */
6708 monitor_info.raised=MagickFalse;
6709 XDrawBeveledMatte(display,&windows->info,&monitor_info);
6710 monitor_info.raised=MagickTrue;
6711 XDrawWidgetText(display,&windows->info,&monitor_info);
6712}
6713
6714/*
6715%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6716% %
6717% %
6718% %
6719% X L i s t B r o w s e r W i d g e t %
6720% %
6721% %
6722% %
6723%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6724%
6725% XListBrowserWidget() displays a List Browser widget with a query to the
6726% user. The user keys a reply or select a reply from the list. Finally, the
6727% user presses the Action or Cancel button to exit. The typed text is
6728% returned as the reply function parameter.
6729%
6730% The format of the XListBrowserWidget method is:
6731%
6732% void XListBrowserWidget(Display *display,XWindows *windows,
6733% XWindowInfo *window_info,const char **list,const char *action,
6734% const char *query,char *reply)
6735%
6736% A description of each parameter follows:
6737%
6738% o display: Specifies a connection to an X server; returned from
6739% XOpenDisplay.
6740%
6741% o window: Specifies a pointer to a XWindows structure.
6742%
6743% o list: Specifies a pointer to an array of strings. The user can
6744% select from these strings as a possible reply value.
6745%
6746% o action: Specifies a pointer to the action of this widget.
6747%
6748% o query: Specifies a pointer to the query to present to the user.
6749%
6750% o reply: the response from the user is returned in this parameter.
6751%
6752*/
6753MagickExport void XListBrowserWidget(Display *display,XWindows *windows,
6754 XWindowInfo *window_info,const char **list,const char *action,
6755 const char *query,char *reply)
6756{
6757#define CancelButtonText "Cancel"
6758
6759 char
6760 primary_selection[MaxTextExtent];
6761
6762 int
6763 x;
6764
6765 register int
6766 i;
6767
6768 static MagickStatusType
6769 mask = (MagickStatusType) (CWWidth | CWHeight | CWX | CWY);
6770
6771 Status
6772 status;
6773
6774 unsigned int
6775 entries,
6776 height,
6777 text_width,
6778 visible_entries,
6779 width;
6780
cristybb503372010-05-27 20:51:26 +00006781 size_t
cristy3ed852e2009-09-05 21:47:34 +00006782 delay,
6783 state;
6784
6785 XEvent
6786 event;
6787
6788 XFontStruct
6789 *font_info;
6790
6791 XTextProperty
6792 window_name;
6793
6794 XWidgetInfo
6795 action_info,
6796 cancel_info,
6797 expose_info,
6798 list_info,
6799 north_info,
6800 reply_info,
6801 scroll_info,
6802 selection_info,
6803 slider_info,
6804 south_info,
6805 text_info;
6806
6807 XWindowChanges
6808 window_changes;
6809
6810 /*
6811 Count the number of entries in the list.
6812 */
6813 assert(display != (Display *) NULL);
6814 assert(windows != (XWindows *) NULL);
6815 assert(window_info != (XWindowInfo *) NULL);
6816 assert(list != (const char **) NULL);
6817 assert(action != (char *) NULL);
6818 assert(query != (char *) NULL);
6819 assert(reply != (char *) NULL);
6820 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",action);
6821 XSetCursorState(display,windows,MagickTrue);
6822 XCheckRefreshWindows(display,windows);
6823 if (list == (const char **) NULL)
6824 {
6825 XNoticeWidget(display,windows,"No text to browse:",(char *) NULL);
6826 return;
6827 }
6828 for (entries=0; ; entries++)
6829 if (list[entries] == (char *) NULL)
6830 break;
6831 /*
6832 Determine Font Browser widget attributes.
6833 */
6834 font_info=window_info->font_info;
6835 text_width=WidgetTextWidth(font_info,(char *) query);
6836 for (i=0; i < (int) entries; i++)
6837 if (WidgetTextWidth(font_info,(char *) list[i]) > text_width)
6838 text_width=WidgetTextWidth(font_info,(char *) list[i]);
6839 width=WidgetTextWidth(font_info,(char *) action);
6840 if (WidgetTextWidth(font_info,CancelButtonText) > width)
6841 width=WidgetTextWidth(font_info,CancelButtonText);
6842 width+=QuantumMargin;
6843 height=(unsigned int) (font_info->ascent+font_info->descent);
6844 /*
6845 Position List Browser widget.
6846 */
6847 window_info->width=(unsigned int) MagickMin((int) text_width,(int)
6848 MaxTextWidth)+((9*QuantumMargin) >> 1);
6849 window_info->min_width=(unsigned int) (MinTextWidth+4*QuantumMargin);
6850 if (window_info->width < window_info->min_width)
6851 window_info->width=window_info->min_width;
6852 window_info->height=(unsigned int)
6853 (((81*height) >> 2)+((13*QuantumMargin) >> 1)+4);
6854 window_info->min_height=(unsigned int)
6855 (((23*height) >> 1)+((13*QuantumMargin) >> 1)+4);
6856 if (window_info->height < window_info->min_height)
6857 window_info->height=window_info->min_height;
6858 XConstrainWindowPosition(display,window_info);
6859 /*
6860 Map List Browser widget.
6861 */
6862 (void) CopyMagickString(window_info->name,"Browse",MaxTextExtent);
6863 status=XStringListToTextProperty(&window_info->name,1,&window_name);
6864 if (status != False)
6865 {
6866 XSetWMName(display,window_info->id,&window_name);
6867 XSetWMIconName(display,windows->widget.id,&window_name);
6868 (void) XFree((void *) window_name.value);
6869 }
6870 window_changes.width=(int) window_info->width;
6871 window_changes.height=(int) window_info->height;
6872 window_changes.x=window_info->x;
6873 window_changes.y=window_info->y;
6874 (void) XReconfigureWMWindow(display,window_info->id,window_info->screen,mask,
6875 &window_changes);
6876 (void) XMapRaised(display,window_info->id);
6877 window_info->mapped=MagickFalse;
6878 /*
6879 Respond to X events.
6880 */
6881 XGetWidgetInfo((char *) NULL,&slider_info);
6882 XGetWidgetInfo((char *) NULL,&north_info);
6883 XGetWidgetInfo((char *) NULL,&south_info);
6884 XGetWidgetInfo((char *) NULL,&expose_info);
6885 visible_entries=0;
6886 delay=SuspendTime << 2;
6887 state=UpdateConfigurationState;
6888 do
6889 {
6890 if (state & UpdateConfigurationState)
6891 {
6892 int
6893 id;
6894
6895 /*
6896 Initialize button information.
6897 */
6898 XGetWidgetInfo(CancelButtonText,&cancel_info);
6899 cancel_info.width=width;
6900 cancel_info.height=(unsigned int) ((3*height) >> 1);
6901 cancel_info.x=(int)
6902 (window_info->width-cancel_info.width-QuantumMargin-2);
6903 cancel_info.y=(int)
6904 (window_info->height-cancel_info.height-QuantumMargin);
6905 XGetWidgetInfo(action,&action_info);
6906 action_info.width=width;
6907 action_info.height=(unsigned int) ((3*height) >> 1);
6908 action_info.x=cancel_info.x-(cancel_info.width+(QuantumMargin >> 1)+
6909 (action_info.bevel_width << 1));
6910 action_info.y=cancel_info.y;
6911 /*
6912 Initialize reply information.
6913 */
6914 XGetWidgetInfo(reply,&reply_info);
6915 reply_info.raised=MagickFalse;
6916 reply_info.bevel_width--;
6917 reply_info.width=window_info->width-((4*QuantumMargin) >> 1);
6918 reply_info.height=height << 1;
6919 reply_info.x=QuantumMargin;
6920 reply_info.y=action_info.y-reply_info.height-QuantumMargin;
6921 /*
6922 Initialize scroll information.
6923 */
6924 XGetWidgetInfo((char *) NULL,&scroll_info);
6925 scroll_info.bevel_width--;
6926 scroll_info.width=height;
6927 scroll_info.height=(unsigned int)
6928 (reply_info.y-((6*QuantumMargin) >> 1)-height);
6929 scroll_info.x=reply_info.x+(reply_info.width-scroll_info.width);
6930 scroll_info.y=((5*QuantumMargin) >> 1)+height-reply_info.bevel_width;
6931 scroll_info.raised=MagickFalse;
6932 scroll_info.trough=MagickTrue;
6933 north_info=scroll_info;
6934 north_info.raised=MagickTrue;
6935 north_info.width-=(north_info.bevel_width << 1);
6936 north_info.height=north_info.width-1;
6937 north_info.x+=north_info.bevel_width;
6938 north_info.y+=north_info.bevel_width;
6939 south_info=north_info;
6940 south_info.y=scroll_info.y+scroll_info.height-scroll_info.bevel_width-
6941 south_info.height;
6942 id=slider_info.id;
6943 slider_info=north_info;
6944 slider_info.id=id;
6945 slider_info.width-=2;
6946 slider_info.min_y=north_info.y+north_info.height+north_info.bevel_width+
6947 slider_info.bevel_width+2;
6948 slider_info.height=scroll_info.height-((slider_info.min_y-
6949 scroll_info.y+1) << 1)+4;
6950 visible_entries=scroll_info.height/(height+(height >> 3));
6951 if (entries > visible_entries)
6952 slider_info.height=(visible_entries*slider_info.height)/entries;
6953 slider_info.max_y=south_info.y-south_info.bevel_width-
6954 slider_info.bevel_width-2;
6955 slider_info.x=scroll_info.x+slider_info.bevel_width+1;
6956 slider_info.y=slider_info.min_y;
6957 expose_info=scroll_info;
6958 expose_info.y=slider_info.y;
6959 /*
6960 Initialize list information.
6961 */
6962 XGetWidgetInfo((char *) NULL,&list_info);
6963 list_info.raised=MagickFalse;
6964 list_info.bevel_width--;
6965 list_info.width=(unsigned int)
6966 (scroll_info.x-reply_info.x-(QuantumMargin >> 1));
6967 list_info.height=scroll_info.height;
6968 list_info.x=reply_info.x;
6969 list_info.y=scroll_info.y;
6970 if (window_info->mapped == MagickFalse)
6971 for (i=0; i < (int) entries; i++)
6972 if (LocaleCompare(list[i],reply) == 0)
6973 {
6974 list_info.id=i;
6975 slider_info.id=i-(visible_entries >> 1);
6976 if (slider_info.id < 0)
6977 slider_info.id=0;
6978 }
6979 /*
6980 Initialize text information.
6981 */
6982 XGetWidgetInfo(query,&text_info);
6983 text_info.width=reply_info.width;
6984 text_info.height=height;
6985 text_info.x=list_info.x-(QuantumMargin >> 1);
6986 text_info.y=QuantumMargin;
6987 /*
6988 Initialize selection information.
6989 */
6990 XGetWidgetInfo((char *) NULL,&selection_info);
6991 selection_info.center=MagickFalse;
6992 selection_info.width=list_info.width;
6993 selection_info.height=(unsigned int) ((9*height) >> 3);
6994 selection_info.x=list_info.x;
6995 state&=(~UpdateConfigurationState);
6996 }
6997 if (state & RedrawWidgetState)
6998 {
6999 /*
7000 Redraw List Browser window.
7001 */
7002 XDrawWidgetText(display,window_info,&text_info);
7003 XDrawBeveledMatte(display,window_info,&list_info);
7004 XDrawBeveledMatte(display,window_info,&scroll_info);
7005 XDrawTriangleNorth(display,window_info,&north_info);
7006 XDrawBeveledButton(display,window_info,&slider_info);
7007 XDrawTriangleSouth(display,window_info,&south_info);
7008 XDrawBeveledMatte(display,window_info,&reply_info);
7009 XDrawMatteText(display,window_info,&reply_info);
7010 XDrawBeveledButton(display,window_info,&action_info);
7011 XDrawBeveledButton(display,window_info,&cancel_info);
7012 XHighlightWidget(display,window_info,BorderOffset,BorderOffset);
7013 selection_info.id=(~0);
7014 state|=RedrawActionState;
7015 state|=RedrawListState;
7016 state&=(~RedrawWidgetState);
7017 }
7018 if (state & RedrawListState)
7019 {
7020 /*
7021 Determine slider id and position.
7022 */
7023 if (slider_info.id >= (int) (entries-visible_entries))
7024 slider_info.id=(int) (entries-visible_entries);
7025 if ((slider_info.id < 0) || (entries <= visible_entries))
7026 slider_info.id=0;
7027 slider_info.y=slider_info.min_y;
7028 if (entries > 0)
7029 slider_info.y+=
7030 slider_info.id*(slider_info.max_y-slider_info.min_y+1)/entries;
7031 if (slider_info.id != selection_info.id)
7032 {
7033 /*
7034 Redraw scroll bar and file names.
7035 */
7036 selection_info.id=slider_info.id;
7037 selection_info.y=list_info.y+(height >> 3)+2;
7038 for (i=0; i < (int) visible_entries; i++)
7039 {
7040 selection_info.raised=(slider_info.id+i) != list_info.id ?
7041 MagickTrue : MagickFalse;
7042 selection_info.text=(char *) NULL;
7043 if ((slider_info.id+i) < (int) entries)
7044 selection_info.text=(char *) list[slider_info.id+i];
7045 XDrawWidgetText(display,window_info,&selection_info);
7046 selection_info.y+=(int) selection_info.height;
7047 }
7048 /*
7049 Update slider.
7050 */
7051 if (slider_info.y > expose_info.y)
7052 {
7053 expose_info.height=(unsigned int) slider_info.y-expose_info.y;
7054 expose_info.y=slider_info.y-expose_info.height-
7055 slider_info.bevel_width-1;
7056 }
7057 else
7058 {
7059 expose_info.height=(unsigned int) expose_info.y-slider_info.y;
7060 expose_info.y=slider_info.y+slider_info.height+
7061 slider_info.bevel_width+1;
7062 }
7063 XDrawTriangleNorth(display,window_info,&north_info);
7064 XDrawMatte(display,window_info,&expose_info);
7065 XDrawBeveledButton(display,window_info,&slider_info);
7066 XDrawTriangleSouth(display,window_info,&south_info);
7067 expose_info.y=slider_info.y;
7068 }
7069 state&=(~RedrawListState);
7070 }
7071 /*
7072 Wait for next event.
7073 */
7074 if (north_info.raised && south_info.raised)
7075 (void) XIfEvent(display,&event,XScreenEvent,(char *) windows);
7076 else
7077 {
7078 /*
7079 Brief delay before advancing scroll bar.
7080 */
7081 XDelay(display,delay);
7082 delay=SuspendTime;
7083 (void) XCheckIfEvent(display,&event,XScreenEvent,(char *) windows);
7084 if (north_info.raised == MagickFalse)
7085 if (slider_info.id > 0)
7086 {
7087 /*
7088 Move slider up.
7089 */
7090 slider_info.id--;
7091 state|=RedrawListState;
7092 }
7093 if (south_info.raised == MagickFalse)
7094 if (slider_info.id < (int) entries)
7095 {
7096 /*
7097 Move slider down.
7098 */
7099 slider_info.id++;
7100 state|=RedrawListState;
7101 }
7102 if (event.type != ButtonRelease)
7103 continue;
7104 }
7105 switch (event.type)
7106 {
7107 case ButtonPress:
7108 {
7109 if (MatteIsActive(slider_info,event.xbutton))
7110 {
7111 /*
7112 Track slider.
7113 */
7114 slider_info.active=MagickTrue;
7115 break;
7116 }
7117 if (MatteIsActive(north_info,event.xbutton))
7118 if (slider_info.id > 0)
7119 {
7120 /*
7121 Move slider up.
7122 */
7123 north_info.raised=MagickFalse;
7124 slider_info.id--;
7125 state|=RedrawListState;
7126 break;
7127 }
7128 if (MatteIsActive(south_info,event.xbutton))
7129 if (slider_info.id < (int) entries)
7130 {
7131 /*
7132 Move slider down.
7133 */
7134 south_info.raised=MagickFalse;
7135 slider_info.id++;
7136 state|=RedrawListState;
7137 break;
7138 }
7139 if (MatteIsActive(scroll_info,event.xbutton))
7140 {
7141 /*
7142 Move slider.
7143 */
7144 if (event.xbutton.y < slider_info.y)
7145 slider_info.id-=(visible_entries-1);
7146 else
7147 slider_info.id+=(visible_entries-1);
7148 state|=RedrawListState;
7149 break;
7150 }
7151 if (MatteIsActive(list_info,event.xbutton))
7152 {
7153 int
7154 id;
7155
7156 /*
7157 User pressed list matte.
7158 */
7159 id=slider_info.id+(event.xbutton.y-(list_info.y+(height >> 1))+1)/
7160 selection_info.height;
7161 if (id >= (int) entries)
7162 break;
7163 (void) CopyMagickString(reply_info.text,list[id],MaxTextExtent);
7164 reply_info.highlight=MagickFalse;
7165 reply_info.marker=reply_info.text;
7166 reply_info.cursor=reply_info.text+Extent(reply_info.text);
7167 XDrawMatteText(display,window_info,&reply_info);
7168 selection_info.id=(~0);
7169 if (id == list_info.id)
7170 {
7171 action_info.raised=MagickFalse;
7172 XDrawBeveledButton(display,window_info,&action_info);
7173 state|=ExitState;
7174 }
7175 list_info.id=id;
7176 state|=RedrawListState;
7177 break;
7178 }
7179 if (MatteIsActive(action_info,event.xbutton))
7180 {
7181 /*
7182 User pressed action button.
7183 */
7184 action_info.raised=MagickFalse;
7185 XDrawBeveledButton(display,window_info,&action_info);
7186 break;
7187 }
7188 if (MatteIsActive(cancel_info,event.xbutton))
7189 {
7190 /*
7191 User pressed Cancel button.
7192 */
7193 cancel_info.raised=MagickFalse;
7194 XDrawBeveledButton(display,window_info,&cancel_info);
7195 break;
7196 }
7197 if (MatteIsActive(reply_info,event.xbutton) == MagickFalse)
7198 break;
7199 if (event.xbutton.button != Button2)
7200 {
7201 static Time
7202 click_time;
7203
7204 /*
7205 Move text cursor to position of button press.
7206 */
7207 x=event.xbutton.x-reply_info.x-(QuantumMargin >> 2);
7208 for (i=1; i <= Extent(reply_info.marker); i++)
7209 if (XTextWidth(font_info,reply_info.marker,i) > x)
7210 break;
7211 reply_info.cursor=reply_info.marker+i-1;
7212 if (event.xbutton.time > (click_time+DoubleClick))
7213 reply_info.highlight=MagickFalse;
7214 else
7215 {
7216 /*
7217 Become the XA_PRIMARY selection owner.
7218 */
7219 (void) CopyMagickString(primary_selection,reply_info.text,
7220 MaxTextExtent);
7221 (void) XSetSelectionOwner(display,XA_PRIMARY,window_info->id,
7222 event.xbutton.time);
7223 reply_info.highlight=XGetSelectionOwner(display,XA_PRIMARY) ==
7224 window_info->id ? MagickTrue : MagickFalse;
7225 }
7226 XDrawMatteText(display,window_info,&reply_info);
7227 click_time=event.xbutton.time;
7228 break;
7229 }
7230 /*
7231 Request primary selection.
7232 */
7233 (void) XConvertSelection(display,XA_PRIMARY,XA_STRING,XA_STRING,
7234 window_info->id,event.xbutton.time);
7235 break;
7236 }
7237 case ButtonRelease:
7238 {
7239 if (window_info->mapped == MagickFalse)
7240 break;
7241 if (north_info.raised == MagickFalse)
7242 {
7243 /*
7244 User released up button.
7245 */
7246 delay=SuspendTime << 2;
7247 north_info.raised=MagickTrue;
7248 XDrawTriangleNorth(display,window_info,&north_info);
7249 }
7250 if (south_info.raised == MagickFalse)
7251 {
7252 /*
7253 User released down button.
7254 */
7255 delay=SuspendTime << 2;
7256 south_info.raised=MagickTrue;
7257 XDrawTriangleSouth(display,window_info,&south_info);
7258 }
7259 if (slider_info.active)
7260 {
7261 /*
7262 Stop tracking slider.
7263 */
7264 slider_info.active=MagickFalse;
7265 break;
7266 }
7267 if (action_info.raised == MagickFalse)
7268 {
7269 if (event.xbutton.window == window_info->id)
7270 {
7271 if (MatteIsActive(action_info,event.xbutton))
7272 {
7273 if (*reply_info.text == '\0')
7274 (void) XBell(display,0);
7275 else
7276 state|=ExitState;
7277 }
7278 }
7279 action_info.raised=MagickTrue;
7280 XDrawBeveledButton(display,window_info,&action_info);
7281 }
7282 if (cancel_info.raised == MagickFalse)
7283 {
7284 if (event.xbutton.window == window_info->id)
7285 if (MatteIsActive(cancel_info,event.xbutton))
7286 {
7287 *reply_info.text='\0';
7288 state|=ExitState;
7289 }
7290 cancel_info.raised=MagickTrue;
7291 XDrawBeveledButton(display,window_info,&cancel_info);
7292 }
7293 if (MatteIsActive(reply_info,event.xbutton) == MagickFalse)
7294 break;
7295 break;
7296 }
7297 case ClientMessage:
7298 {
7299 /*
7300 If client window delete message, exit.
7301 */
7302 if (event.xclient.message_type != windows->wm_protocols)
7303 break;
7304 if (*event.xclient.data.l == (int) windows->wm_take_focus)
7305 {
7306 (void) XSetInputFocus(display,event.xclient.window,RevertToParent,
7307 (Time) event.xclient.data.l[1]);
7308 break;
7309 }
7310 if (*event.xclient.data.l != (int) windows->wm_delete_window)
7311 break;
7312 if (event.xclient.window == window_info->id)
7313 {
7314 *reply_info.text='\0';
7315 state|=ExitState;
7316 break;
7317 }
7318 break;
7319 }
7320 case ConfigureNotify:
7321 {
7322 /*
7323 Update widget configuration.
7324 */
7325 if (event.xconfigure.window != window_info->id)
7326 break;
7327 if ((event.xconfigure.width == (int) window_info->width) &&
7328 (event.xconfigure.height == (int) window_info->height))
7329 break;
7330 window_info->width=(unsigned int)
7331 MagickMax(event.xconfigure.width,(int) window_info->min_width);
7332 window_info->height=(unsigned int)
7333 MagickMax(event.xconfigure.height,(int) window_info->min_height);
7334 state|=UpdateConfigurationState;
7335 break;
7336 }
7337 case EnterNotify:
7338 {
7339 if (event.xcrossing.window != window_info->id)
7340 break;
7341 state&=(~InactiveWidgetState);
7342 break;
7343 }
7344 case Expose:
7345 {
7346 if (event.xexpose.window != window_info->id)
7347 break;
7348 if (event.xexpose.count != 0)
7349 break;
7350 state|=RedrawWidgetState;
7351 break;
7352 }
7353 case KeyPress:
7354 {
7355 static char
7356 command[MaxTextExtent];
7357
7358 static int
7359 length;
7360
7361 static KeySym
7362 key_symbol;
7363
7364 /*
7365 Respond to a user key press.
7366 */
7367 if (event.xkey.window != window_info->id)
7368 break;
7369 length=XLookupString((XKeyEvent *) &event.xkey,command,
7370 (int) sizeof(command),&key_symbol,(XComposeStatus *) NULL);
7371 *(command+length)='\0';
7372 if (AreaIsActive(scroll_info,event.xkey))
7373 {
7374 /*
7375 Move slider.
7376 */
7377 switch ((int) key_symbol)
7378 {
7379 case XK_Home:
7380 case XK_KP_Home:
7381 {
7382 slider_info.id=0;
7383 break;
7384 }
7385 case XK_Up:
7386 case XK_KP_Up:
7387 {
7388 slider_info.id--;
7389 break;
7390 }
7391 case XK_Down:
7392 case XK_KP_Down:
7393 {
7394 slider_info.id++;
7395 break;
7396 }
7397 case XK_Prior:
7398 case XK_KP_Prior:
7399 {
7400 slider_info.id-=visible_entries;
7401 break;
7402 }
7403 case XK_Next:
7404 case XK_KP_Next:
7405 {
7406 slider_info.id+=visible_entries;
7407 break;
7408 }
7409 case XK_End:
7410 case XK_KP_End:
7411 {
7412 slider_info.id=(int) entries;
7413 break;
7414 }
7415 }
7416 state|=RedrawListState;
7417 break;
7418 }
7419 if ((key_symbol == XK_Return) || (key_symbol == XK_KP_Enter))
7420 {
7421 /*
7422 Read new entry.
7423 */
7424 if (*reply_info.text == '\0')
7425 break;
7426 action_info.raised=MagickFalse;
7427 XDrawBeveledButton(display,window_info,&action_info);
7428 state|=ExitState;
7429 break;
7430 }
7431 if (key_symbol == XK_Control_L)
7432 {
7433 state|=ControlState;
7434 break;
7435 }
7436 if (state & ControlState)
7437 switch ((int) key_symbol)
7438 {
7439 case XK_u:
7440 case XK_U:
7441 {
7442 /*
7443 Erase the entire line of text.
7444 */
7445 *reply_info.text='\0';
7446 reply_info.cursor=reply_info.text;
7447 reply_info.marker=reply_info.text;
7448 reply_info.highlight=MagickFalse;
7449 break;
7450 }
7451 default:
7452 break;
7453 }
7454 XEditText(display,&reply_info,key_symbol,command,state);
7455 XDrawMatteText(display,window_info,&reply_info);
7456 break;
7457 }
7458 case KeyRelease:
7459 {
7460 static char
7461 command[MaxTextExtent];
7462
7463 static KeySym
7464 key_symbol;
7465
7466 /*
7467 Respond to a user key release.
7468 */
7469 if (event.xkey.window != window_info->id)
7470 break;
7471 (void) XLookupString((XKeyEvent *) &event.xkey,command,
7472 (int) sizeof(command),&key_symbol,(XComposeStatus *) NULL);
7473 if (key_symbol == XK_Control_L)
7474 state&=(~ControlState);
7475 break;
7476 }
7477 case LeaveNotify:
7478 {
7479 if (event.xcrossing.window != window_info->id)
7480 break;
7481 state|=InactiveWidgetState;
7482 break;
7483 }
7484 case MapNotify:
7485 {
7486 mask&=(~CWX);
7487 mask&=(~CWY);
7488 break;
7489 }
7490 case MotionNotify:
7491 {
7492 /*
7493 Discard pending button motion events.
7494 */
7495 while (XCheckMaskEvent(display,ButtonMotionMask,&event)) ;
7496 if (slider_info.active)
7497 {
7498 /*
7499 Move slider matte.
7500 */
7501 slider_info.y=event.xmotion.y-
7502 ((slider_info.height+slider_info.bevel_width) >> 1)+1;
7503 if (slider_info.y < slider_info.min_y)
7504 slider_info.y=slider_info.min_y;
7505 if (slider_info.y > slider_info.max_y)
7506 slider_info.y=slider_info.max_y;
7507 slider_info.id=0;
7508 if (slider_info.y != slider_info.min_y)
7509 slider_info.id=(int) ((entries*(slider_info.y-
7510 slider_info.min_y+1))/(slider_info.max_y-slider_info.min_y+1));
7511 state|=RedrawListState;
7512 break;
7513 }
7514 if (state & InactiveWidgetState)
7515 break;
7516 if (action_info.raised == MatteIsActive(action_info,event.xmotion))
7517 {
7518 /*
7519 Action button status changed.
7520 */
7521 action_info.raised=action_info.raised == MagickFalse ?
7522 MagickTrue : MagickFalse;
7523 XDrawBeveledButton(display,window_info,&action_info);
7524 break;
7525 }
7526 if (cancel_info.raised == MatteIsActive(cancel_info,event.xmotion))
7527 {
7528 /*
7529 Cancel button status changed.
7530 */
7531 cancel_info.raised=cancel_info.raised == MagickFalse ?
7532 MagickTrue : MagickFalse;
7533 XDrawBeveledButton(display,window_info,&cancel_info);
7534 break;
7535 }
7536 break;
7537 }
7538 case SelectionClear:
7539 {
7540 reply_info.highlight=MagickFalse;
7541 XDrawMatteText(display,window_info,&reply_info);
7542 break;
7543 }
7544 case SelectionNotify:
7545 {
7546 Atom
7547 type;
7548
7549 int
7550 format;
7551
7552 unsigned char
7553 *data;
7554
cristyf2faecf2010-05-28 19:19:36 +00007555 unsigned long
cristy3ed852e2009-09-05 21:47:34 +00007556 after,
7557 length;
7558
7559 /*
7560 Obtain response from primary selection.
7561 */
7562 if (event.xselection.property == (Atom) None)
7563 break;
7564 status=XGetWindowProperty(display,
7565 event.xselection.requestor,event.xselection.property,0L,2047L,
7566 MagickTrue,XA_STRING,&type,&format,&length,&after,&data);
7567 if ((status != Success) || (type != XA_STRING) || (format == 32) ||
7568 (length == 0))
7569 break;
7570 if ((Extent(reply_info.text)+length) >= MaxTextExtent)
7571 (void) XBell(display,0);
7572 else
7573 {
7574 /*
7575 Insert primary selection in reply text.
7576 */
7577 *(data+length)='\0';
7578 XEditText(display,&reply_info,(KeySym) XK_Insert,(char *) data,
7579 state);
7580 XDrawMatteText(display,window_info,&reply_info);
7581 state|=RedrawActionState;
7582 }
7583 (void) XFree((void *) data);
7584 break;
7585 }
7586 case SelectionRequest:
7587 {
7588 XSelectionEvent
7589 notify;
7590
7591 XSelectionRequestEvent
7592 *request;
7593
7594 if (reply_info.highlight == MagickFalse)
7595 break;
7596 /*
7597 Set primary selection.
7598 */
7599 request=(&(event.xselectionrequest));
7600 (void) XChangeProperty(request->display,request->requestor,
7601 request->property,request->target,8,PropModeReplace,
7602 (unsigned char *) primary_selection,Extent(primary_selection));
7603 notify.type=SelectionNotify;
7604 notify.send_event=MagickTrue;
7605 notify.display=request->display;
7606 notify.requestor=request->requestor;
7607 notify.selection=request->selection;
7608 notify.target=request->target;
7609 notify.time=request->time;
7610 if (request->property == None)
7611 notify.property=request->target;
7612 else
7613 notify.property=request->property;
7614 (void) XSendEvent(request->display,request->requestor,False,NoEventMask,
7615 (XEvent *) &notify);
7616 }
7617 default:
7618 break;
7619 }
7620 } while ((state & ExitState) == 0);
7621 XSetCursorState(display,windows,MagickFalse);
7622 (void) XWithdrawWindow(display,window_info->id,window_info->screen);
7623 XCheckRefreshWindows(display,windows);
7624}
7625
7626/*
7627%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
7628% %
7629% %
7630% %
7631% X M e n u W i d g e t %
7632% %
7633% %
7634% %
7635%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
7636%
7637% XMenuWidget() maps a menu and returns the command pointed to by the user
7638% when the button is released.
7639%
7640% The format of the XMenuWidget method is:
7641%
7642% int XMenuWidget(Display *display,XWindows *windows,const char *title,
7643% const char **selections,char *item)
7644%
7645% A description of each parameter follows:
7646%
7647% o selection_number: Specifies the number of the selection that the
7648% user choose.
7649%
7650% o display: Specifies a connection to an X server; returned from
7651% XOpenDisplay.
7652%
7653% o window: Specifies a pointer to a XWindows structure.
7654%
7655% o title: Specifies a character string that describes the menu selections.
7656%
7657% o selections: Specifies a pointer to one or more strings that comprise
7658% the choices in the menu.
7659%
7660% o item: Specifies a character array. The item selected from the menu
7661% is returned here.
7662%
7663*/
7664MagickExport int XMenuWidget(Display *display,XWindows *windows,
7665 const char *title,const char **selections,char *item)
7666{
7667 Cursor
7668 cursor;
7669
7670 int
7671 id,
7672 x,
7673 y;
7674
7675 unsigned int
7676 height,
7677 number_selections,
7678 title_height,
7679 top_offset,
7680 width;
7681
cristybb503372010-05-27 20:51:26 +00007682 size_t
cristy3ed852e2009-09-05 21:47:34 +00007683 state;
7684
7685 XEvent
7686 event;
7687
7688 XFontStruct
7689 *font_info;
7690
7691 XSetWindowAttributes
7692 window_attributes;
7693
7694 XWidgetInfo
7695 highlight_info,
7696 menu_info,
7697 selection_info;
7698
7699 XWindowChanges
7700 window_changes;
7701
7702 /*
7703 Determine Menu widget attributes.
7704 */
7705 assert(display != (Display *) NULL);
7706 assert(windows != (XWindows *) NULL);
7707 assert(title != (char *) NULL);
7708 assert(selections != (const char **) NULL);
7709 assert(item != (char *) NULL);
7710 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",title);
7711 font_info=windows->widget.font_info;
7712 windows->widget.width=submenu_info.active == 0 ?
7713 WidgetTextWidth(font_info,(char *) title) : 0;
7714 for (id=0; selections[id] != (char *) NULL; id++)
7715 {
7716 width=WidgetTextWidth(font_info,(char *) selections[id]);
7717 if (width > windows->widget.width)
7718 windows->widget.width=width;
7719 }
7720 number_selections=(unsigned int) id;
7721 XGetWidgetInfo((char *) NULL,&menu_info);
7722 title_height=(unsigned int) (submenu_info.active == 0 ?
7723 (3*(font_info->descent+font_info->ascent) >> 1)+5 : 2);
7724 width=WidgetTextWidth(font_info,(char *) title);
7725 height=(unsigned int) ((3*(font_info->ascent+font_info->descent)) >> 1);
7726 /*
7727 Position Menu widget.
7728 */
7729 windows->widget.width+=QuantumMargin+(menu_info.bevel_width << 1);
7730 top_offset=title_height+menu_info.bevel_width-1;
7731 windows->widget.height=top_offset+number_selections*height+4;
7732 windows->widget.min_width=windows->widget.width;
7733 windows->widget.min_height=windows->widget.height;
7734 XQueryPosition(display,windows->widget.root,&x,&y);
7735 windows->widget.x=x-(QuantumMargin >> 1);
7736 if (submenu_info.active != 0)
7737 {
7738 windows->widget.x=
7739 windows->command.x+windows->command.width-QuantumMargin;
7740 toggle_info.raised=MagickTrue;
7741 XDrawTriangleEast(display,&windows->command,&toggle_info);
7742 }
cristy49e2d862010-11-12 02:50:30 +00007743 windows->widget.y=submenu_info.active == 0 ? y-(int)
cristy3ed852e2009-09-05 21:47:34 +00007744 ((3*title_height) >> 2) : y;
7745 if (submenu_info.active != 0)
7746 windows->widget.y=windows->command.y+submenu_info.y;
7747 XConstrainWindowPosition(display,&windows->widget);
7748 /*
7749 Map Menu widget.
7750 */
7751 window_attributes.override_redirect=MagickTrue;
7752 (void) XChangeWindowAttributes(display,windows->widget.id,
cristybb503372010-05-27 20:51:26 +00007753 (size_t) CWOverrideRedirect,&window_attributes);
cristy3ed852e2009-09-05 21:47:34 +00007754 window_changes.width=(int) windows->widget.width;
7755 window_changes.height=(int) windows->widget.height;
7756 window_changes.x=windows->widget.x;
7757 window_changes.y=windows->widget.y;
7758 (void) XReconfigureWMWindow(display,windows->widget.id,windows->widget.screen,
7759 (unsigned int) (CWWidth | CWHeight | CWX | CWY),&window_changes);
7760 (void) XMapRaised(display,windows->widget.id);
7761 windows->widget.mapped=MagickFalse;
7762 /*
7763 Respond to X events.
7764 */
7765 selection_info.height=height;
7766 cursor=XCreateFontCursor(display,XC_right_ptr);
7767 (void) XCheckDefineCursor(display,windows->image.id,cursor);
7768 (void) XCheckDefineCursor(display,windows->command.id,cursor);
7769 (void) XCheckDefineCursor(display,windows->widget.id,cursor);
7770 state=UpdateConfigurationState;
7771 do
7772 {
7773 if (state & UpdateConfigurationState)
7774 {
7775 /*
7776 Initialize selection information.
7777 */
7778 XGetWidgetInfo((char *) NULL,&menu_info);
7779 menu_info.bevel_width--;
7780 menu_info.width=windows->widget.width-((menu_info.bevel_width) << 1);
7781 menu_info.height=windows->widget.height-((menu_info.bevel_width) << 1);
7782 menu_info.x=(int) menu_info.bevel_width;
7783 menu_info.y=(int) menu_info.bevel_width;
7784 XGetWidgetInfo((char *) NULL,&selection_info);
7785 selection_info.center=MagickFalse;
7786 selection_info.width=menu_info.width;
7787 selection_info.height=height;
7788 selection_info.x=menu_info.x;
7789 highlight_info=selection_info;
7790 highlight_info.bevel_width--;
7791 highlight_info.width-=(highlight_info.bevel_width << 1);
7792 highlight_info.height-=(highlight_info.bevel_width << 1);
7793 highlight_info.x+=highlight_info.bevel_width;
7794 state&=(~UpdateConfigurationState);
7795 }
7796 if (state & RedrawWidgetState)
7797 {
7798 /*
7799 Redraw Menu widget.
7800 */
7801 if (submenu_info.active == 0)
7802 {
7803 y=(int) title_height;
7804 XSetBevelColor(display,&windows->widget,MagickFalse);
7805 (void) XDrawLine(display,windows->widget.id,
7806 windows->widget.widget_context,selection_info.x,y-1,
7807 (int) selection_info.width,y-1);
7808 XSetBevelColor(display,&windows->widget,MagickTrue);
7809 (void) XDrawLine(display,windows->widget.id,
7810 windows->widget.widget_context,selection_info.x,y,
7811 (int) selection_info.width,y);
7812 (void) XSetFillStyle(display,windows->widget.widget_context,
7813 FillSolid);
7814 }
7815 /*
7816 Draw menu selections.
7817 */
7818 selection_info.center=MagickTrue;
7819 selection_info.y=(int) menu_info.bevel_width;
7820 selection_info.text=(char *) title;
7821 if (submenu_info.active == 0)
7822 XDrawWidgetText(display,&windows->widget,&selection_info);
7823 selection_info.center=MagickFalse;
7824 selection_info.y=(int) top_offset;
7825 for (id=0; id < (int) number_selections; id++)
7826 {
7827 selection_info.text=(char *) selections[id];
7828 XDrawWidgetText(display,&windows->widget,&selection_info);
7829 highlight_info.y=selection_info.y+highlight_info.bevel_width;
7830 if (id == selection_info.id)
7831 XDrawBevel(display,&windows->widget,&highlight_info);
7832 selection_info.y+=(int) selection_info.height;
7833 }
7834 XDrawBevel(display,&windows->widget,&menu_info);
7835 state&=(~RedrawWidgetState);
7836 }
7837 if (number_selections > 2)
7838 {
7839 /*
7840 Redraw Menu line.
7841 */
7842 y=(int) (top_offset+selection_info.height*(number_selections-1));
7843 XSetBevelColor(display,&windows->widget,MagickFalse);
7844 (void) XDrawLine(display,windows->widget.id,
7845 windows->widget.widget_context,selection_info.x,y-1,
7846 (int) selection_info.width,y-1);
7847 XSetBevelColor(display,&windows->widget,MagickTrue);
7848 (void) XDrawLine(display,windows->widget.id,
7849 windows->widget.widget_context,selection_info.x,y,
7850 (int) selection_info.width,y);
7851 (void) XSetFillStyle(display,windows->widget.widget_context,FillSolid);
7852 }
7853 /*
7854 Wait for next event.
7855 */
7856 (void) XIfEvent(display,&event,XScreenEvent,(char *) windows);
7857 switch (event.type)
7858 {
7859 case ButtonPress:
7860 {
7861 if (event.xbutton.window != windows->widget.id)
7862 {
7863 /*
7864 exit menu.
7865 */
7866 if (event.xbutton.window == windows->command.id)
7867 (void) XPutBackEvent(display,&event);
7868 selection_info.id=(~0);
7869 *item='\0';
7870 state|=ExitState;
7871 break;
7872 }
7873 state&=(~InactiveWidgetState);
7874 id=(event.xbutton.y-top_offset)/(int) selection_info.height;
7875 selection_info.id=id;
7876 if ((id < 0) || (id >= (int) number_selections))
7877 break;
7878 /*
7879 Highlight this selection.
7880 */
7881 selection_info.y=(int) (top_offset+id*selection_info.height);
7882 selection_info.text=(char *) selections[id];
7883 XDrawWidgetText(display,&windows->widget,&selection_info);
7884 highlight_info.y=selection_info.y+highlight_info.bevel_width;
7885 XDrawBevel(display,&windows->widget,&highlight_info);
7886 break;
7887 }
7888 case ButtonRelease:
7889 {
7890 if (windows->widget.mapped == MagickFalse)
7891 break;
7892 if (event.xbutton.window == windows->command.id)
7893 if ((state & InactiveWidgetState) == 0)
7894 break;
7895 /*
7896 exit menu.
7897 */
7898 XSetCursorState(display,windows,MagickFalse);
7899 *item='\0';
7900 state|=ExitState;
7901 break;
7902 }
7903 case ConfigureNotify:
7904 {
7905 /*
7906 Update widget configuration.
7907 */
7908 if (event.xconfigure.window != windows->widget.id)
7909 break;
7910 if ((event.xconfigure.width == (int) windows->widget.width) &&
7911 (event.xconfigure.height == (int) windows->widget.height))
7912 break;
7913 windows->widget.width=(unsigned int)
7914 MagickMax(event.xconfigure.width,(int) windows->widget.min_width);
7915 windows->widget.height=(unsigned int)
7916 MagickMax(event.xconfigure.height,(int) windows->widget.min_height);
7917 state|=UpdateConfigurationState;
7918 break;
7919 }
7920 case EnterNotify:
7921 {
7922 if (event.xcrossing.window != windows->widget.id)
7923 break;
7924 if (event.xcrossing.state == 0)
7925 break;
7926 state&=(~InactiveWidgetState);
7927 id=((event.xcrossing.y-top_offset)/(int) selection_info.height);
7928 if ((selection_info.id >= 0) &&
7929 (selection_info.id < (int) number_selections))
7930 {
7931 /*
7932 Unhighlight last selection.
7933 */
7934 if (id == selection_info.id)
7935 break;
7936 selection_info.y=(int)
7937 (top_offset+selection_info.id*selection_info.height);
7938 selection_info.text=(char *) selections[selection_info.id];
7939 XDrawWidgetText(display,&windows->widget,&selection_info);
7940 }
7941 if ((id < 0) || (id >= (int) number_selections))
7942 break;
7943 /*
7944 Highlight this selection.
7945 */
7946 selection_info.id=id;
7947 selection_info.y=(int)
7948 (top_offset+selection_info.id*selection_info.height);
7949 selection_info.text=(char *) selections[selection_info.id];
7950 XDrawWidgetText(display,&windows->widget,&selection_info);
7951 highlight_info.y=selection_info.y+highlight_info.bevel_width;
7952 XDrawBevel(display,&windows->widget,&highlight_info);
7953 break;
7954 }
7955 case Expose:
7956 {
7957 if (event.xexpose.window != windows->widget.id)
7958 break;
7959 if (event.xexpose.count != 0)
7960 break;
7961 state|=RedrawWidgetState;
7962 break;
7963 }
7964 case LeaveNotify:
7965 {
7966 if (event.xcrossing.window != windows->widget.id)
7967 break;
7968 state|=InactiveWidgetState;
7969 id=selection_info.id;
7970 if ((id < 0) || (id >= (int) number_selections))
7971 break;
7972 /*
7973 Unhighlight last selection.
7974 */
7975 selection_info.y=(int) (top_offset+id*selection_info.height);
7976 selection_info.id=(~0);
7977 selection_info.text=(char *) selections[id];
7978 XDrawWidgetText(display,&windows->widget,&selection_info);
7979 break;
7980 }
7981 case MotionNotify:
7982 {
7983 /*
7984 Discard pending button motion events.
7985 */
7986 while (XCheckMaskEvent(display,ButtonMotionMask,&event)) ;
7987 if (submenu_info.active != 0)
7988 if (event.xmotion.window == windows->command.id)
7989 {
7990 if ((state & InactiveWidgetState) == 0)
7991 {
7992 if (MatteIsActive(submenu_info,event.xmotion) == MagickFalse)
7993 {
7994 selection_info.id=(~0);
7995 *item='\0';
7996 state|=ExitState;
7997 break;
7998 }
7999 }
8000 else
8001 if (WindowIsActive(windows->command,event.xmotion))
8002 {
8003 selection_info.id=(~0);
8004 *item='\0';
8005 state|=ExitState;
8006 break;
8007 }
8008 }
8009 if (event.xmotion.window != windows->widget.id)
8010 break;
8011 if (state & InactiveWidgetState)
8012 break;
8013 id=(event.xmotion.y-top_offset)/(int) selection_info.height;
8014 if ((selection_info.id >= 0) &&
8015 (selection_info.id < (int) number_selections))
8016 {
8017 /*
8018 Unhighlight last selection.
8019 */
8020 if (id == selection_info.id)
8021 break;
8022 selection_info.y=(int)
8023 (top_offset+selection_info.id*selection_info.height);
8024 selection_info.text=(char *) selections[selection_info.id];
8025 XDrawWidgetText(display,&windows->widget,&selection_info);
8026 }
8027 selection_info.id=id;
8028 if ((id < 0) || (id >= (int) number_selections))
8029 break;
8030 /*
8031 Highlight this selection.
8032 */
8033 selection_info.y=(int) (top_offset+id*selection_info.height);
8034 selection_info.text=(char *) selections[id];
8035 XDrawWidgetText(display,&windows->widget,&selection_info);
8036 highlight_info.y=selection_info.y+highlight_info.bevel_width;
8037 XDrawBevel(display,&windows->widget,&highlight_info);
8038 break;
8039 }
8040 default:
8041 break;
8042 }
8043 } while ((state & ExitState) == 0);
8044 (void) XFreeCursor(display,cursor);
8045 window_attributes.override_redirect=MagickFalse;
8046 (void) XChangeWindowAttributes(display,windows->widget.id,
cristybb503372010-05-27 20:51:26 +00008047 (size_t) CWOverrideRedirect,&window_attributes);
cristy3ed852e2009-09-05 21:47:34 +00008048 (void) XWithdrawWindow(display,windows->widget.id,windows->widget.screen);
8049 XCheckRefreshWindows(display,windows);
8050 if (submenu_info.active != 0)
8051 {
8052 submenu_info.active=MagickFalse;
8053 toggle_info.raised=MagickFalse;
8054 XDrawTriangleEast(display,&windows->command,&toggle_info);
8055 }
8056 if ((selection_info.id < 0) || (selection_info.id >= (int) number_selections))
8057 return(~0);
8058 (void) CopyMagickString(item,selections[selection_info.id],MaxTextExtent);
8059 return(selection_info.id);
8060}
8061
8062/*
8063%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
8064% %
8065% %
8066% %
8067% X N o t i c e W i d g e t %
8068% %
8069% %
8070% %
8071%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
8072%
8073% XNoticeWidget() displays a Notice widget with a notice to the user. The
8074% function returns when the user presses the "Dismiss" button.
8075%
8076% The format of the XNoticeWidget method is:
8077%
8078% void XNoticeWidget(Display *display,XWindows *windows,
8079% const char *reason,const char *description)
8080%
8081% A description of each parameter follows:
8082%
8083% o display: Specifies a connection to an X server; returned from
8084% XOpenDisplay.
8085%
8086% o window: Specifies a pointer to a XWindows structure.
8087%
8088% o reason: Specifies the message to display before terminating the
8089% program.
8090%
8091% o description: Specifies any description to the message.
8092%
8093*/
8094MagickExport void XNoticeWidget(Display *display,XWindows *windows,
8095 const char *reason,const char *description)
8096{
8097#define DismissButtonText "Dismiss"
8098#define Timeout 8
8099
8100 const char
8101 *text;
8102
8103 int
8104 x,
8105 y;
8106
8107 Status
8108 status;
8109
8110 time_t
8111 timer;
8112
8113 unsigned int
8114 height,
8115 width;
8116
cristybb503372010-05-27 20:51:26 +00008117 size_t
cristy3ed852e2009-09-05 21:47:34 +00008118 state;
8119
8120 XEvent
8121 event;
8122
8123 XFontStruct
8124 *font_info;
8125
8126 XTextProperty
8127 window_name;
8128
8129 XWidgetInfo
8130 dismiss_info;
8131
8132 XWindowChanges
8133 window_changes;
8134
8135 /*
8136 Determine Notice widget attributes.
8137 */
8138 assert(display != (Display *) NULL);
8139 assert(windows != (XWindows *) NULL);
8140 assert(reason != (char *) NULL);
8141 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",reason);
8142 XDelay(display,SuspendTime << 3); /* avoid surpise with delay */
8143 XSetCursorState(display,windows,MagickTrue);
8144 XCheckRefreshWindows(display,windows);
8145 font_info=windows->widget.font_info;
8146 width=WidgetTextWidth(font_info,DismissButtonText);
8147 text=GetLocaleExceptionMessage(XServerError,reason);
8148 if (text != (char *) NULL)
8149 if (WidgetTextWidth(font_info,(char *) text) > width)
8150 width=WidgetTextWidth(font_info,(char *) text);
8151 if (description != (char *) NULL)
8152 {
8153 text=GetLocaleExceptionMessage(XServerError,description);
8154 if (text != (char *) NULL)
8155 if (WidgetTextWidth(font_info,(char *) text) > width)
8156 width=WidgetTextWidth(font_info,(char *) text);
8157 }
8158 height=(unsigned int) (font_info->ascent+font_info->descent);
8159 /*
8160 Position Notice widget.
8161 */
8162 windows->widget.width=width+4*QuantumMargin;
8163 windows->widget.min_width=width+QuantumMargin;
8164 if (windows->widget.width < windows->widget.min_width)
8165 windows->widget.width=windows->widget.min_width;
8166 windows->widget.height=(unsigned int) (12*height);
8167 windows->widget.min_height=(unsigned int) (7*height);
8168 if (windows->widget.height < windows->widget.min_height)
8169 windows->widget.height=windows->widget.min_height;
8170 XConstrainWindowPosition(display,&windows->widget);
8171 /*
8172 Map Notice widget.
8173 */
8174 (void) CopyMagickString(windows->widget.name,"Notice",MaxTextExtent);
8175 status=XStringListToTextProperty(&windows->widget.name,1,&window_name);
8176 if (status != False)
8177 {
8178 XSetWMName(display,windows->widget.id,&window_name);
8179 XSetWMIconName(display,windows->widget.id,&window_name);
8180 (void) XFree((void *) window_name.value);
8181 }
8182 window_changes.width=(int) windows->widget.width;
8183 window_changes.height=(int) windows->widget.height;
8184 window_changes.x=windows->widget.x;
8185 window_changes.y=windows->widget.y;
8186 (void) XReconfigureWMWindow(display,windows->widget.id,windows->widget.screen,
8187 (unsigned int) (CWWidth | CWHeight | CWX | CWY),&window_changes);
8188 (void) XMapRaised(display,windows->widget.id);
8189 windows->widget.mapped=MagickFalse;
8190 (void) XBell(display,0);
8191 /*
8192 Respond to X events.
8193 */
8194 timer=time((time_t *) NULL)+Timeout;
8195 state=UpdateConfigurationState;
8196 do
8197 {
8198 if (time((time_t *) NULL) > timer)
8199 break;
8200 if (state & UpdateConfigurationState)
8201 {
8202 /*
8203 Initialize Dismiss button information.
8204 */
8205 XGetWidgetInfo(DismissButtonText,&dismiss_info);
8206 dismiss_info.width=(unsigned int) QuantumMargin+
8207 WidgetTextWidth(font_info,DismissButtonText);
8208 dismiss_info.height=(unsigned int) ((3*height) >> 1);
8209 dismiss_info.x=(int)
8210 ((windows->widget.width >> 1)-(dismiss_info.width >> 1));
8211 dismiss_info.y=(int)
8212 (windows->widget.height-(dismiss_info.height << 1));
8213 state&=(~UpdateConfigurationState);
8214 }
8215 if (state & RedrawWidgetState)
8216 {
8217 /*
8218 Redraw Notice widget.
8219 */
8220 width=WidgetTextWidth(font_info,(char *) reason);
8221 x=(int) ((windows->widget.width >> 1)-(width >> 1));
8222 y=(int) ((windows->widget.height >> 1)-(height << 1));
8223 (void) XDrawString(display,windows->widget.id,
8224 windows->widget.annotate_context,x,y,(char *) reason,Extent(reason));
8225 if (description != (char *) NULL)
8226 {
8227 width=WidgetTextWidth(font_info,(char *) description);
8228 x=(int) ((windows->widget.width >> 1)-(width >> 1));
8229 y+=height;
8230 (void) XDrawString(display,windows->widget.id,
8231 windows->widget.annotate_context,x,y,(char *) description,
8232 Extent(description));
8233 }
8234 XDrawBeveledButton(display,&windows->widget,&dismiss_info);
8235 XHighlightWidget(display,&windows->widget,BorderOffset,BorderOffset);
8236 state&=(~RedrawWidgetState);
8237 }
8238 /*
8239 Wait for next event.
8240 */
8241 if (XCheckIfEvent(display,&event,XScreenEvent,(char *) windows) == MagickFalse)
8242 {
8243 /*
8244 Do not block if delay > 0.
8245 */
8246 XDelay(display,SuspendTime << 2);
8247 continue;
8248 }
8249 switch (event.type)
8250 {
8251 case ButtonPress:
8252 {
8253 if (MatteIsActive(dismiss_info,event.xbutton))
8254 {
8255 /*
8256 User pressed Dismiss button.
8257 */
8258 dismiss_info.raised=MagickFalse;
8259 XDrawBeveledButton(display,&windows->widget,&dismiss_info);
8260 break;
8261 }
8262 break;
8263 }
8264 case ButtonRelease:
8265 {
8266 if (windows->widget.mapped == MagickFalse)
8267 break;
8268 if (dismiss_info.raised == MagickFalse)
8269 {
8270 if (event.xbutton.window == windows->widget.id)
8271 if (MatteIsActive(dismiss_info,event.xbutton))
8272 state|=ExitState;
8273 dismiss_info.raised=MagickTrue;
8274 XDrawBeveledButton(display,&windows->widget,&dismiss_info);
8275 }
8276 break;
8277 }
8278 case ClientMessage:
8279 {
8280 /*
8281 If client window delete message, exit.
8282 */
8283 if (event.xclient.message_type != windows->wm_protocols)
8284 break;
8285 if (*event.xclient.data.l == (int) windows->wm_take_focus)
8286 {
8287 (void) XSetInputFocus(display,event.xclient.window,RevertToParent,
8288 (Time) event.xclient.data.l[1]);
8289 break;
8290 }
8291 if (*event.xclient.data.l != (int) windows->wm_delete_window)
8292 break;
8293 if (event.xclient.window == windows->widget.id)
8294 {
8295 state|=ExitState;
8296 break;
8297 }
8298 break;
8299 }
8300 case ConfigureNotify:
8301 {
8302 /*
8303 Update widget configuration.
8304 */
8305 if (event.xconfigure.window != windows->widget.id)
8306 break;
8307 if ((event.xconfigure.width == (int) windows->widget.width) &&
8308 (event.xconfigure.height == (int) windows->widget.height))
8309 break;
8310 windows->widget.width=(unsigned int)
8311 MagickMax(event.xconfigure.width,(int) windows->widget.min_width);
8312 windows->widget.height=(unsigned int)
8313 MagickMax(event.xconfigure.height,(int) windows->widget.min_height);
8314 state|=UpdateConfigurationState;
8315 break;
8316 }
8317 case EnterNotify:
8318 {
8319 if (event.xcrossing.window != windows->widget.id)
8320 break;
8321 state&=(~InactiveWidgetState);
8322 break;
8323 }
8324 case Expose:
8325 {
8326 if (event.xexpose.window != windows->widget.id)
8327 break;
8328 if (event.xexpose.count != 0)
8329 break;
8330 state|=RedrawWidgetState;
8331 break;
8332 }
8333 case KeyPress:
8334 {
8335 static char
8336 command[MaxTextExtent];
8337
8338 static KeySym
8339 key_symbol;
8340
8341 /*
8342 Respond to a user key press.
8343 */
8344 if (event.xkey.window != windows->widget.id)
8345 break;
8346 (void) XLookupString((XKeyEvent *) &event.xkey,command,
8347 (int) sizeof(command),&key_symbol,(XComposeStatus *) NULL);
8348 if ((key_symbol == XK_Return) || (key_symbol == XK_KP_Enter))
8349 {
8350 dismiss_info.raised=MagickFalse;
8351 XDrawBeveledButton(display,&windows->widget,&dismiss_info);
8352 state|=ExitState;
8353 break;
8354 }
8355 break;
8356 }
8357 case LeaveNotify:
8358 {
8359 if (event.xcrossing.window != windows->widget.id)
8360 break;
8361 state|=InactiveWidgetState;
8362 break;
8363 }
8364 case MotionNotify:
8365 {
8366 /*
8367 Discard pending button motion events.
8368 */
8369 while (XCheckMaskEvent(display,ButtonMotionMask,&event)) ;
8370 if (state & InactiveWidgetState)
8371 break;
8372 if (dismiss_info.raised == MatteIsActive(dismiss_info,event.xmotion))
8373 {
8374 /*
8375 Dismiss button status changed.
8376 */
8377 dismiss_info.raised=
8378 dismiss_info.raised == MagickFalse ? MagickTrue : MagickFalse;
8379 XDrawBeveledButton(display,&windows->widget,&dismiss_info);
8380 break;
8381 }
8382 break;
8383 }
8384 default:
8385 break;
8386 }
8387 } while ((state & ExitState) == 0);
8388 XSetCursorState(display,windows,MagickFalse);
8389 (void) XWithdrawWindow(display,windows->widget.id,windows->widget.screen);
8390 XCheckRefreshWindows(display,windows);
8391}
8392
8393/*
8394%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
8395% %
8396% %
8397% %
8398% X P r e f e r e n c e s W i d g e t %
8399% %
8400% %
8401% %
8402%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
8403%
8404% XPreferencesWidget() displays a Preferences widget with program preferences.
8405% If the user presses the Apply button, the preferences are stored in a
8406% configuration file in the users' home directory.
8407%
8408% The format of the XPreferencesWidget method is:
8409%
8410% MagickBooleanType XPreferencesWidget(Display *display,
8411% XResourceInfo *resource_info,XWindows *windows)
8412%
8413% A description of each parameter follows:
8414%
8415% o display: Specifies a connection to an X server; returned from
8416% XOpenDisplay.
8417%
8418% o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
8419%
8420% o window: Specifies a pointer to a XWindows structure.
8421%
8422*/
8423MagickExport MagickBooleanType XPreferencesWidget(Display *display,
8424 XResourceInfo *resource_info,XWindows *windows)
8425{
8426#define ApplyButtonText "Apply"
8427#define CacheButtonText "%lu mega-bytes of memory in the undo edit cache "
8428#define CancelButtonText "Cancel"
8429#define NumberPreferences 8
8430
8431 static const char
8432 *Preferences[] =
8433 {
8434 "display image centered on a backdrop",
8435 "confirm on program exit",
8436 "confirm on image edits",
8437 "correct image for display gamma",
8438 "display warning messages",
8439 "apply Floyd/Steinberg error diffusion to image",
8440 "use a shared colormap for colormapped X visuals",
8441 "display images as an X server pixmap"
8442 };
8443
8444 char
8445 cache[MaxTextExtent];
8446
8447 int
8448 x,
8449 y;
8450
8451 register int
8452 i;
8453
8454 Status
8455 status;
8456
8457 unsigned int
8458 height,
8459 text_width,
8460 width;
8461
cristybb503372010-05-27 20:51:26 +00008462 size_t
cristy3ed852e2009-09-05 21:47:34 +00008463 state;
8464
8465 XEvent
8466 event;
8467
8468 XFontStruct
8469 *font_info;
8470
8471 XTextProperty
8472 window_name;
8473
8474 XWidgetInfo
8475 apply_info,
8476 cache_info,
8477 cancel_info,
8478 preferences_info[NumberPreferences];
8479
8480 XWindowChanges
8481 window_changes;
8482
8483 /*
8484 Determine Preferences widget attributes.
8485 */
8486 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
8487 assert(display != (Display *) NULL);
8488 assert(resource_info != (XResourceInfo *) NULL);
8489 assert(windows != (XWindows *) NULL);
8490 XCheckRefreshWindows(display,windows);
8491 font_info=windows->widget.font_info;
8492 text_width=WidgetTextWidth(font_info,CacheButtonText);
8493 for (i=0; i < NumberPreferences; i++)
8494 if (WidgetTextWidth(font_info,(char *) Preferences[i]) > text_width)
8495 text_width=WidgetTextWidth(font_info,(char *) Preferences[i]);
8496 width=WidgetTextWidth(font_info,ApplyButtonText);
8497 if (WidgetTextWidth(font_info,CancelButtonText) > width)
8498 width=WidgetTextWidth(font_info,CancelButtonText);
8499 width+=(unsigned int) QuantumMargin;
8500 height=(unsigned int) (font_info->ascent+font_info->descent);
8501 /*
8502 Position Preferences widget.
8503 */
8504 windows->widget.width=(unsigned int) (MagickMax((int) (width << 1),
8505 (int) text_width)+6*QuantumMargin);
8506 windows->widget.min_width=(width << 1)+QuantumMargin;
8507 if (windows->widget.width < windows->widget.min_width)
8508 windows->widget.width=windows->widget.min_width;
8509 windows->widget.height=(unsigned int)
8510 (7*height+NumberPreferences*(height+(QuantumMargin >> 1)));
8511 windows->widget.min_height=(unsigned int)
8512 (7*height+NumberPreferences*(height+(QuantumMargin >> 1)));
8513 if (windows->widget.height < windows->widget.min_height)
8514 windows->widget.height=windows->widget.min_height;
8515 XConstrainWindowPosition(display,&windows->widget);
8516 /*
8517 Map Preferences widget.
8518 */
8519 (void) CopyMagickString(windows->widget.name,"Preferences",MaxTextExtent);
8520 status=XStringListToTextProperty(&windows->widget.name,1,&window_name);
8521 if (status != False)
8522 {
8523 XSetWMName(display,windows->widget.id,&window_name);
8524 XSetWMIconName(display,windows->widget.id,&window_name);
8525 (void) XFree((void *) window_name.value);
8526 }
8527 window_changes.width=(int) windows->widget.width;
8528 window_changes.height=(int) windows->widget.height;
8529 window_changes.x=windows->widget.x;
8530 window_changes.y=windows->widget.y;
8531 (void) XReconfigureWMWindow(display,windows->widget.id,windows->widget.screen,
8532 (unsigned int) (CWWidth | CWHeight | CWX | CWY),&window_changes);
8533 (void) XMapRaised(display,windows->widget.id);
8534 windows->widget.mapped=MagickFalse;
8535 /*
8536 Respond to X events.
8537 */
8538 state=UpdateConfigurationState;
8539 XSetCursorState(display,windows,MagickTrue);
8540 do
8541 {
8542 if (state & UpdateConfigurationState)
8543 {
8544 /*
8545 Initialize button information.
8546 */
8547 XGetWidgetInfo(CancelButtonText,&cancel_info);
8548 cancel_info.width=width;
8549 cancel_info.height=(unsigned int) (3*height) >> 1;
8550 cancel_info.x=(int) windows->widget.width-cancel_info.width-
8551 (QuantumMargin << 1);
8552 cancel_info.y=(int) windows->widget.height-
8553 cancel_info.height-QuantumMargin;
8554 XGetWidgetInfo(ApplyButtonText,&apply_info);
8555 apply_info.width=width;
8556 apply_info.height=(unsigned int) (3*height) >> 1;
8557 apply_info.x=QuantumMargin << 1;
8558 apply_info.y=cancel_info.y;
8559 y=(int) (height << 1);
8560 for (i=0; i < NumberPreferences; i++)
8561 {
8562 XGetWidgetInfo(Preferences[i],&preferences_info[i]);
8563 preferences_info[i].bevel_width--;
8564 preferences_info[i].width=(unsigned int) QuantumMargin >> 1;
8565 preferences_info[i].height=(unsigned int) QuantumMargin >> 1;
8566 preferences_info[i].x=QuantumMargin << 1;
8567 preferences_info[i].y=y;
8568 y+=height+(QuantumMargin >> 1);
8569 }
8570 preferences_info[0].raised=resource_info->backdrop ==
8571 MagickFalse ? MagickTrue : MagickFalse;
8572 preferences_info[1].raised=resource_info->confirm_exit ==
8573 MagickFalse ? MagickTrue : MagickFalse;
8574 preferences_info[2].raised=resource_info->confirm_edit ==
8575 MagickFalse ? MagickTrue : MagickFalse;
8576 preferences_info[3].raised=resource_info->gamma_correct ==
8577 MagickFalse ? MagickTrue : MagickFalse;
8578 preferences_info[4].raised=resource_info->display_warnings ==
8579 MagickFalse ? MagickTrue : MagickFalse;
8580 preferences_info[5].raised=resource_info->quantize_info->dither ==
8581 MagickFalse ? MagickTrue : MagickFalse;
8582 preferences_info[6].raised=resource_info->colormap !=
8583 SharedColormap ? MagickTrue : MagickFalse;
8584 preferences_info[7].raised=resource_info->use_pixmap ==
8585 MagickFalse ? MagickTrue : MagickFalse;
8586 (void) FormatMagickString(cache,MaxTextExtent,CacheButtonText,
cristyf2faecf2010-05-28 19:19:36 +00008587 (unsigned long) resource_info->undo_cache);
cristy3ed852e2009-09-05 21:47:34 +00008588 XGetWidgetInfo(cache,&cache_info);
8589 cache_info.bevel_width--;
8590 cache_info.width=(unsigned int) QuantumMargin >> 1;
8591 cache_info.height=(unsigned int) QuantumMargin >> 1;
8592 cache_info.x=QuantumMargin << 1;
8593 cache_info.y=y;
8594 state&=(~UpdateConfigurationState);
8595 }
8596 if (state & RedrawWidgetState)
8597 {
8598 /*
8599 Redraw Preferences widget.
8600 */
8601 XDrawBeveledButton(display,&windows->widget,&apply_info);
8602 XDrawBeveledButton(display,&windows->widget,&cancel_info);
8603 for (i=0; i < NumberPreferences; i++)
8604 XDrawBeveledButton(display,&windows->widget,&preferences_info[i]);
8605 XDrawTriangleEast(display,&windows->widget,&cache_info);
8606 XHighlightWidget(display,&windows->widget,BorderOffset,BorderOffset);
8607 state&=(~RedrawWidgetState);
8608 }
8609 /*
8610 Wait for next event.
8611 */
8612 (void) XIfEvent(display,&event,XScreenEvent,(char *) windows);
8613 switch (event.type)
8614 {
8615 case ButtonPress:
8616 {
8617 if (MatteIsActive(apply_info,event.xbutton))
8618 {
8619 /*
8620 User pressed Apply button.
8621 */
8622 apply_info.raised=MagickFalse;
8623 XDrawBeveledButton(display,&windows->widget,&apply_info);
8624 break;
8625 }
8626 if (MatteIsActive(cancel_info,event.xbutton))
8627 {
8628 /*
8629 User pressed Cancel button.
8630 */
8631 cancel_info.raised=MagickFalse;
8632 XDrawBeveledButton(display,&windows->widget,&cancel_info);
8633 break;
8634 }
8635 for (i=0; i < NumberPreferences; i++)
8636 if (MatteIsActive(preferences_info[i],event.xbutton))
8637 {
8638 /*
8639 User pressed a Preferences button.
8640 */
8641 preferences_info[i].raised=preferences_info[i].raised ==
8642 MagickFalse ? MagickTrue : MagickFalse;
8643 XDrawBeveledButton(display,&windows->widget,&preferences_info[i]);
8644 break;
8645 }
8646 if (MatteIsActive(cache_info,event.xbutton))
8647 {
8648 /*
8649 User pressed Cache button.
8650 */
8651 x=cache_info.x+cache_info.width+cache_info.bevel_width+
8652 (QuantumMargin >> 1);
8653 y=cache_info.y+((cache_info.height-height) >> 1);
8654 width=WidgetTextWidth(font_info,cache);
8655 (void) XClearArea(display,windows->widget.id,x,y,width,height,
8656 False);
8657 resource_info->undo_cache<<=1;
8658 if (resource_info->undo_cache > 256)
8659 resource_info->undo_cache=1;
8660 (void) FormatMagickString(cache,MaxTextExtent,CacheButtonText,
cristyf2faecf2010-05-28 19:19:36 +00008661 (unsigned long) resource_info->undo_cache);
cristy3ed852e2009-09-05 21:47:34 +00008662 cache_info.raised=MagickFalse;
8663 XDrawTriangleEast(display,&windows->widget,&cache_info);
8664 break;
8665 }
8666 break;
8667 }
8668 case ButtonRelease:
8669 {
8670 if (windows->widget.mapped == MagickFalse)
8671 break;
8672 if (apply_info.raised == MagickFalse)
8673 {
8674 if (event.xbutton.window == windows->widget.id)
8675 if (MatteIsActive(apply_info,event.xbutton))
8676 state|=ExitState;
8677 apply_info.raised=MagickTrue;
8678 XDrawBeveledButton(display,&windows->widget,&apply_info);
8679 apply_info.raised=MagickFalse;
8680 }
8681 if (cancel_info.raised == MagickFalse)
8682 {
8683 if (event.xbutton.window == windows->widget.id)
8684 if (MatteIsActive(cancel_info,event.xbutton))
8685 state|=ExitState;
8686 cancel_info.raised=MagickTrue;
8687 XDrawBeveledButton(display,&windows->widget,&cancel_info);
8688 }
8689 if (cache_info.raised == MagickFalse)
8690 {
8691 cache_info.raised=MagickTrue;
8692 XDrawTriangleEast(display,&windows->widget,&cache_info);
8693 }
8694 break;
8695 }
8696 case ClientMessage:
8697 {
8698 /*
8699 If client window delete message, exit.
8700 */
8701 if (event.xclient.message_type != windows->wm_protocols)
8702 break;
8703 if (*event.xclient.data.l == (int) windows->wm_take_focus)
8704 {
8705 (void) XSetInputFocus(display,event.xclient.window,RevertToParent,
8706 (Time) event.xclient.data.l[1]);
8707 break;
8708 }
8709 if (*event.xclient.data.l != (int) windows->wm_delete_window)
8710 break;
8711 if (event.xclient.window == windows->widget.id)
8712 {
8713 state|=ExitState;
8714 break;
8715 }
8716 break;
8717 }
8718 case ConfigureNotify:
8719 {
8720 /*
8721 Update widget configuration.
8722 */
8723 if (event.xconfigure.window != windows->widget.id)
8724 break;
8725 if ((event.xconfigure.width == (int) windows->widget.width) &&
8726 (event.xconfigure.height == (int) windows->widget.height))
8727 break;
8728 windows->widget.width=(unsigned int)
8729 MagickMax(event.xconfigure.width,(int) windows->widget.min_width);
8730 windows->widget.height=(unsigned int)
8731 MagickMax(event.xconfigure.height,(int) windows->widget.min_height);
8732 state|=UpdateConfigurationState;
8733 break;
8734 }
8735 case EnterNotify:
8736 {
8737 if (event.xcrossing.window != windows->widget.id)
8738 break;
8739 state&=(~InactiveWidgetState);
8740 break;
8741 }
8742 case Expose:
8743 {
8744 if (event.xexpose.window != windows->widget.id)
8745 break;
8746 if (event.xexpose.count != 0)
8747 break;
8748 state|=RedrawWidgetState;
8749 break;
8750 }
8751 case KeyPress:
8752 {
8753 static char
8754 command[MaxTextExtent];
8755
8756 static KeySym
8757 key_symbol;
8758
8759 /*
8760 Respond to a user key press.
8761 */
8762 if (event.xkey.window != windows->widget.id)
8763 break;
8764 (void) XLookupString((XKeyEvent *) &event.xkey,command,
8765 (int) sizeof(command),&key_symbol,(XComposeStatus *) NULL);
8766 if ((key_symbol == XK_Return) || (key_symbol == XK_KP_Enter))
8767 {
8768 apply_info.raised=MagickFalse;
8769 XDrawBeveledButton(display,&windows->widget,&apply_info);
8770 state|=ExitState;
8771 break;
8772 }
8773 break;
8774 }
8775 case LeaveNotify:
8776 {
8777 if (event.xcrossing.window != windows->widget.id)
8778 break;
8779 state|=InactiveWidgetState;
8780 break;
8781 }
8782 case MotionNotify:
8783 {
8784 /*
8785 Discard pending button motion events.
8786 */
8787 while (XCheckMaskEvent(display,ButtonMotionMask,&event)) ;
8788 if (state & InactiveWidgetState)
8789 break;
8790 if (apply_info.raised == MatteIsActive(apply_info,event.xmotion))
8791 {
8792 /*
8793 Apply button status changed.
8794 */
8795 apply_info.raised=
8796 apply_info.raised == MagickFalse ? MagickTrue : MagickFalse;
8797 XDrawBeveledButton(display,&windows->widget,&apply_info);
8798 break;
8799 }
8800 if (cancel_info.raised == MatteIsActive(cancel_info,event.xmotion))
8801 {
8802 /*
8803 Cancel button status changed.
8804 */
8805 cancel_info.raised=
8806 cancel_info.raised == MagickFalse ? MagickTrue : MagickFalse;
8807 XDrawBeveledButton(display,&windows->widget,&cancel_info);
8808 break;
8809 }
8810 break;
8811 }
8812 default:
8813 break;
8814 }
8815 } while ((state & ExitState) == 0);
8816 XSetCursorState(display,windows,MagickFalse);
8817 (void) XWithdrawWindow(display,windows->widget.id,windows->widget.screen);
8818 XCheckRefreshWindows(display,windows);
8819 if (apply_info.raised)
8820 return(MagickFalse);
8821 /*
8822 Save user preferences to the client configuration file.
8823 */
8824 resource_info->backdrop=
8825 preferences_info[0].raised == MagickFalse ? MagickTrue : MagickFalse;
8826 resource_info->confirm_exit=
8827 preferences_info[1].raised == MagickFalse ? MagickTrue : MagickFalse;
8828 resource_info->confirm_edit=
8829 preferences_info[2].raised == MagickFalse ? MagickTrue : MagickFalse;
8830 resource_info->gamma_correct=
8831 preferences_info[3].raised == MagickFalse ? MagickTrue : MagickFalse;
8832 resource_info->display_warnings=
8833 preferences_info[4].raised == MagickFalse ? MagickTrue : MagickFalse;
8834 resource_info->quantize_info->dither=
8835 preferences_info[5].raised == MagickFalse ? MagickTrue : MagickFalse;
8836 resource_info->colormap=SharedColormap;
8837 if (preferences_info[6].raised)
8838 resource_info->colormap=PrivateColormap;
8839 resource_info->use_pixmap=
8840 preferences_info[7].raised == MagickFalse ? MagickTrue : MagickFalse;
8841 XUserPreferences(resource_info);
8842 return(MagickTrue);
8843}
8844
8845/*
8846%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
8847% %
8848% %
8849% %
8850% X P r o g r e s s M o n i t o r W i d g e t %
8851% %
8852% %
8853% %
8854%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
8855%
8856% XProgressMonitorWidget() displays the progress a task is making in
8857% completing a task. A span of zero toggles the active status. An inactive
8858% state disables the progress monitor.
8859%
8860% The format of the XProgressMonitorWidget method is:
8861%
8862% void XProgressMonitorWidget(Display *display,XWindows *windows,
8863% const char *task,const MagickOffsetType offset,
8864% const MagickSizeType span)
8865%
8866% A description of each parameter follows:
8867%
8868% o display: Specifies a connection to an X server; returned from
8869% XOpenDisplay.
8870%
8871% o window: Specifies a pointer to a XWindows structure.
8872%
8873% o task: Identifies the task in progress.
8874%
8875% o offset: Specifies the offset position within the span which represents
8876% how much progress has been made in completing a task.
8877%
8878% o span: Specifies the span relative to completing a task.
8879%
8880*/
8881MagickExport void XProgressMonitorWidget(Display *display,XWindows *windows,
8882 const char *task,const MagickOffsetType offset,const MagickSizeType span)
8883{
8884 unsigned int
8885 width;
8886
8887 XEvent
8888 event;
8889
8890 assert(display != (Display *) NULL);
8891 assert(windows != (XWindows *) NULL);
8892 assert(task != (const char *) NULL);
8893 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",task);
8894 if (span == 0)
8895 return;
8896 /*
8897 Update image windows if there is a pending expose event.
8898 */
8899 while (XCheckTypedWindowEvent(display,windows->command.id,Expose,&event))
8900 (void) XCommandWidget(display,windows,(const char **) NULL,&event);
8901 while (XCheckTypedWindowEvent(display,windows->image.id,Expose,&event))
8902 XRefreshWindow(display,&windows->image,&event);
8903 while (XCheckTypedWindowEvent(display,windows->info.id,Expose,&event))
8904 if (monitor_info.text != (char *) NULL)
8905 XInfoWidget(display,windows,monitor_info.text);
8906 /*
8907 Draw progress monitor bar to represent percent completion of a task.
8908 */
8909 if ((windows->info.mapped == MagickFalse) || (task != monitor_info.text))
8910 XInfoWidget(display,windows,task);
8911 width=(unsigned int) (((offset+1)*(windows->info.width-
8912 (2*monitor_info.x)))/span);
8913 if (width < monitor_info.width)
8914 {
8915 monitor_info.raised=MagickTrue;
8916 XDrawWidgetText(display,&windows->info,&monitor_info);
8917 monitor_info.raised=MagickFalse;
8918 }
8919 monitor_info.width=width;
8920 XDrawWidgetText(display,&windows->info,&monitor_info);
8921 (void) XFlush(display);
8922}
8923
8924/*
8925%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
8926% %
8927% %
8928% %
8929% X T e x t V i e w W i d g e t %
8930% %
8931% %
8932% %
8933%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
8934%
8935% XTextViewWidget() displays text in a Text View widget.
8936%
8937% The format of the XTextViewWidget method is:
8938%
8939% void XTextViewWidget(Display *display,const XResourceInfo *resource_info,
8940% XWindows *windows,const MagickBooleanType mono,const char *title,
8941% const char **textlist)
8942%
8943% A description of each parameter follows:
8944%
8945% o display: Specifies a connection to an X server; returned from
8946% XOpenDisplay.
8947%
8948% o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
8949%
8950% o window: Specifies a pointer to a XWindows structure.
8951%
8952% o mono: Use mono-spaced font when displaying text.
8953%
8954% o title: This character string is displayed at the top of the widget
8955% window.
8956%
8957% o textlist: This string list is displayed within the Text View widget.
8958%
8959*/
8960MagickExport void XTextViewWidget(Display *display,
8961 const XResourceInfo *resource_info,XWindows *windows,
8962 const MagickBooleanType mono,const char *title,const char **textlist)
8963{
8964#define DismissButtonText "Dismiss"
8965
8966 char
8967 primary_selection[MaxTextExtent];
8968
8969 register int
8970 i;
8971
8972 static MagickStatusType
8973 mask = (MagickStatusType) (CWWidth | CWHeight | CWX | CWY);
8974
8975 Status
8976 status;
8977
8978 unsigned int
8979 height,
8980 lines,
8981 text_width,
8982 visible_lines,
8983 width;
8984
cristybb503372010-05-27 20:51:26 +00008985 size_t
cristy3ed852e2009-09-05 21:47:34 +00008986 delay,
8987 state;
8988
8989 XEvent
8990 event;
8991
8992 XFontStruct
8993 *font_info,
8994 *text_info;
8995
8996 XTextProperty
8997 window_name;
8998
8999 XWidgetInfo
9000 dismiss_info,
9001 expose_info,
9002 list_info,
9003 north_info,
9004 scroll_info,
9005 selection_info,
9006 slider_info,
9007 south_info;
9008
9009 XWindowChanges
9010 window_changes;
9011
9012 /*
9013 Convert text string to a text list.
9014 */
9015 assert(display != (Display *) NULL);
9016 assert(resource_info != (XResourceInfo *) NULL);
9017 assert(windows != (XWindows *) NULL);
9018 assert(title != (const char *) NULL);
9019 assert(textlist != (const char **) NULL);
9020 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",title);
9021 XSetCursorState(display,windows,MagickTrue);
9022 XCheckRefreshWindows(display,windows);
9023 if (textlist == (const char **) NULL)
9024 {
9025 XNoticeWidget(display,windows,"No text to view:",(char *) NULL);
9026 return;
9027 }
9028 /*
9029 Determine Text View widget attributes.
9030 */
9031 font_info=windows->widget.font_info;
9032 text_info=(XFontStruct *) NULL;
9033 if (mono != MagickFalse)
9034 text_info=XBestFont(display,resource_info,MagickTrue);
9035 if (text_info == (XFontStruct *) NULL)
9036 text_info=windows->widget.font_info;
9037 text_width=0;
9038 for (i=0; textlist[i] != (char *) NULL; i++)
9039 if (WidgetTextWidth(text_info,(char *) textlist[i]) > text_width)
9040 text_width=(unsigned int) XTextWidth(text_info,(char *) textlist[i],
9041 MagickMin(Extent(textlist[i]),160));
9042 lines=(unsigned int) i;
9043 width=WidgetTextWidth(font_info,DismissButtonText);
9044 width+=QuantumMargin;
9045 height=(unsigned int) (text_info->ascent+text_info->descent);
9046 /*
9047 Position Text View widget.
9048 */
9049 windows->widget.width=(unsigned int) (MagickMin((int) text_width,
9050 (int) MaxTextWidth)+5*QuantumMargin);
9051 windows->widget.min_width=(unsigned int) (MinTextWidth+4*QuantumMargin);
9052 if (windows->widget.width < windows->widget.min_width)
9053 windows->widget.width=windows->widget.min_width;
9054 windows->widget.height=(unsigned int) (MagickMin(MagickMax((int) lines,3),32)*
9055 height+((13*height) >> 1)+((9*QuantumMargin) >> 1));
9056 windows->widget.min_height=(unsigned int) (3*height+((13*height) >> 1)+((9*
9057 QuantumMargin) >> 1));
9058 if (windows->widget.height < windows->widget.min_height)
9059 windows->widget.height=windows->widget.min_height;
9060 XConstrainWindowPosition(display,&windows->widget);
9061 /*
9062 Map Text View widget.
9063 */
9064 (void) CopyMagickString(windows->widget.name,title,MaxTextExtent);
9065 status=XStringListToTextProperty(&windows->widget.name,1,&window_name);
9066 if (status != False)
9067 {
9068 XSetWMName(display,windows->widget.id,&window_name);
9069 XSetWMIconName(display,windows->widget.id,&window_name);
9070 (void) XFree((void *) window_name.value);
9071 }
9072 window_changes.width=(int) windows->widget.width;
9073 window_changes.height=(int) windows->widget.height;
9074 window_changes.x=windows->widget.x;
9075 window_changes.y=windows->widget.y;
9076 (void) XReconfigureWMWindow(display,windows->widget.id,
9077 windows->widget.screen,(unsigned int) mask,&window_changes);
9078 (void) XMapRaised(display,windows->widget.id);
9079 windows->widget.mapped=MagickFalse;
9080 /*
9081 Respond to X events.
9082 */
9083 XGetWidgetInfo((char *) NULL,&slider_info);
9084 XGetWidgetInfo((char *) NULL,&north_info);
9085 XGetWidgetInfo((char *) NULL,&south_info);
9086 XGetWidgetInfo((char *) NULL,&expose_info);
9087 visible_lines=0;
9088 delay=SuspendTime << 2;
9089 height=(unsigned int) (font_info->ascent+font_info->descent);
9090 state=UpdateConfigurationState;
9091 do
9092 {
9093 if (state & UpdateConfigurationState)
9094 {
9095 int
9096 id;
9097
9098 /*
9099 Initialize button information.
9100 */
9101 XGetWidgetInfo(DismissButtonText,&dismiss_info);
9102 dismiss_info.width=width;
9103 dismiss_info.height=(unsigned int) ((3*height) >> 1);
9104 dismiss_info.x=(int) windows->widget.width-dismiss_info.width-
9105 QuantumMargin-2;
9106 dismiss_info.y=(int) windows->widget.height-dismiss_info.height-
9107 QuantumMargin;
9108 /*
9109 Initialize scroll information.
9110 */
9111 XGetWidgetInfo((char *) NULL,&scroll_info);
9112 scroll_info.bevel_width--;
9113 scroll_info.width=height;
9114 scroll_info.height=(unsigned int) (dismiss_info.y-((5*QuantumMargin) >>
9115 1));
9116 scroll_info.x=(int) windows->widget.width-QuantumMargin-
9117 scroll_info.width;
9118 scroll_info.y=(3*QuantumMargin) >> 1;
9119 scroll_info.raised=MagickFalse;
9120 scroll_info.trough=MagickTrue;
9121 north_info=scroll_info;
9122 north_info.raised=MagickTrue;
9123 north_info.width-=(north_info.bevel_width << 1);
9124 north_info.height=north_info.width-1;
9125 north_info.x+=north_info.bevel_width;
9126 north_info.y+=north_info.bevel_width;
9127 south_info=north_info;
9128 south_info.y=scroll_info.y+scroll_info.height-scroll_info.bevel_width-
9129 south_info.height;
9130 id=slider_info.id;
9131 slider_info=north_info;
9132 slider_info.id=id;
9133 slider_info.width-=2;
9134 slider_info.min_y=north_info.y+north_info.height+north_info.bevel_width+
9135 slider_info.bevel_width+2;
9136 slider_info.height=scroll_info.height-((slider_info.min_y-
9137 scroll_info.y+1) << 1)+4;
9138 visible_lines=scroll_info.height/(text_info->ascent+text_info->descent+
9139 ((text_info->ascent+text_info->descent) >> 3));
9140 if (lines > visible_lines)
9141 slider_info.height=(unsigned int) (visible_lines*slider_info.height)/
9142 lines;
9143 slider_info.max_y=south_info.y-south_info.bevel_width-
9144 slider_info.bevel_width-2;
9145 slider_info.x=scroll_info.x+slider_info.bevel_width+1;
9146 slider_info.y=slider_info.min_y;
9147 expose_info=scroll_info;
9148 expose_info.y=slider_info.y;
9149 /*
9150 Initialize list information.
9151 */
9152 XGetWidgetInfo((char *) NULL,&list_info);
9153 list_info.raised=MagickFalse;
9154 list_info.bevel_width--;
9155 list_info.width=(unsigned int) scroll_info.x-((3*QuantumMargin) >> 1);
9156 list_info.height=scroll_info.height;
9157 list_info.x=QuantumMargin;
9158 list_info.y=scroll_info.y;
9159 /*
9160 Initialize selection information.
9161 */
9162 XGetWidgetInfo((char *) NULL,&selection_info);
9163 selection_info.center=MagickFalse;
9164 selection_info.width=list_info.width;
9165 selection_info.height=(unsigned int)
9166 (9*(text_info->ascent+text_info->descent)) >> 3;
9167 selection_info.x=list_info.x;
9168 state&=(~UpdateConfigurationState);
9169 }
9170 if (state & RedrawWidgetState)
9171 {
9172 /*
9173 Redraw Text View window.
9174 */
9175 XDrawBeveledMatte(display,&windows->widget,&list_info);
9176 XDrawBeveledMatte(display,&windows->widget,&scroll_info);
9177 XDrawTriangleNorth(display,&windows->widget,&north_info);
9178 XDrawBeveledButton(display,&windows->widget,&slider_info);
9179 XDrawTriangleSouth(display,&windows->widget,&south_info);
9180 XDrawBeveledButton(display,&windows->widget,&dismiss_info);
9181 XHighlightWidget(display,&windows->widget,BorderOffset,BorderOffset);
9182 selection_info.id=(~0);
9183 state|=RedrawListState;
9184 state&=(~RedrawWidgetState);
9185 }
9186 if (state & RedrawListState)
9187 {
9188 /*
9189 Determine slider id and position.
9190 */
9191 if (slider_info.id >= (int) (lines-visible_lines))
9192 slider_info.id=(int) lines-visible_lines;
9193 if ((slider_info.id < 0) || (lines <= visible_lines))
9194 slider_info.id=0;
9195 slider_info.y=slider_info.min_y;
9196 if (lines != 0)
9197 slider_info.y+=
9198 slider_info.id*(slider_info.max_y-slider_info.min_y+1)/lines;
9199 if (slider_info.id != selection_info.id)
9200 {
9201 /*
9202 Redraw scroll bar and text.
9203 */
9204 windows->widget.font_info=text_info;
9205 (void) XSetFont(display,windows->widget.annotate_context,
9206 text_info->fid);
9207 (void) XSetFont(display,windows->widget.highlight_context,
9208 text_info->fid);
9209 selection_info.id=slider_info.id;
9210 selection_info.y=list_info.y+(height >> 3)+2;
9211 for (i=0; i < (int) visible_lines; i++)
9212 {
9213 selection_info.raised=
9214 (slider_info.id+i) != list_info.id ? MagickTrue : MagickFalse;
9215 selection_info.text=(char *) NULL;
9216 if ((slider_info.id+i) < (int) lines)
9217 selection_info.text=(char *) textlist[slider_info.id+i];
9218 XDrawWidgetText(display,&windows->widget,&selection_info);
9219 selection_info.y+=(int) selection_info.height;
9220 }
9221 windows->widget.font_info=font_info;
9222 (void) XSetFont(display,windows->widget.annotate_context,
9223 font_info->fid);
9224 (void) XSetFont(display,windows->widget.highlight_context,
9225 font_info->fid);
9226 /*
9227 Update slider.
9228 */
9229 if (slider_info.y > expose_info.y)
9230 {
9231 expose_info.height=(unsigned int) slider_info.y-expose_info.y;
9232 expose_info.y=slider_info.y-expose_info.height-
9233 slider_info.bevel_width-1;
9234 }
9235 else
9236 {
9237 expose_info.height=(unsigned int) expose_info.y-slider_info.y;
9238 expose_info.y=slider_info.y+slider_info.height+
9239 slider_info.bevel_width+1;
9240 }
9241 XDrawTriangleNorth(display,&windows->widget,&north_info);
9242 XDrawMatte(display,&windows->widget,&expose_info);
9243 XDrawBeveledButton(display,&windows->widget,&slider_info);
9244 XDrawTriangleSouth(display,&windows->widget,&south_info);
9245 expose_info.y=slider_info.y;
9246 }
9247 state&=(~RedrawListState);
9248 }
9249 /*
9250 Wait for next event.
9251 */
9252 if (north_info.raised && south_info.raised)
9253 (void) XIfEvent(display,&event,XScreenEvent,(char *) windows);
9254 else
9255 {
9256 /*
9257 Brief delay before advancing scroll bar.
9258 */
9259 XDelay(display,delay);
9260 delay=SuspendTime;
9261 (void) XCheckIfEvent(display,&event,XScreenEvent,(char *) windows);
9262 if (north_info.raised == MagickFalse)
9263 if (slider_info.id > 0)
9264 {
9265 /*
9266 Move slider up.
9267 */
9268 slider_info.id--;
9269 state|=RedrawListState;
9270 }
9271 if (south_info.raised == MagickFalse)
9272 if (slider_info.id < (int) lines)
9273 {
9274 /*
9275 Move slider down.
9276 */
9277 slider_info.id++;
9278 state|=RedrawListState;
9279 }
9280 if (event.type != ButtonRelease)
9281 continue;
9282 }
9283 switch (event.type)
9284 {
9285 case ButtonPress:
9286 {
9287 if (MatteIsActive(slider_info,event.xbutton))
9288 {
9289 /*
9290 Track slider.
9291 */
9292 slider_info.active=MagickTrue;
9293 break;
9294 }
9295 if (MatteIsActive(north_info,event.xbutton))
9296 if (slider_info.id > 0)
9297 {
9298 /*
9299 Move slider up.
9300 */
9301 north_info.raised=MagickFalse;
9302 slider_info.id--;
9303 state|=RedrawListState;
9304 break;
9305 }
9306 if (MatteIsActive(south_info,event.xbutton))
9307 if (slider_info.id < (int) lines)
9308 {
9309 /*
9310 Move slider down.
9311 */
9312 south_info.raised=MagickFalse;
9313 slider_info.id++;
9314 state|=RedrawListState;
9315 break;
9316 }
9317 if (MatteIsActive(scroll_info,event.xbutton))
9318 {
9319 /*
9320 Move slider.
9321 */
9322 if (event.xbutton.y < slider_info.y)
9323 slider_info.id-=(visible_lines-1);
9324 else
9325 slider_info.id+=(visible_lines-1);
9326 state|=RedrawListState;
9327 break;
9328 }
9329 if (MatteIsActive(dismiss_info,event.xbutton))
9330 {
9331 /*
9332 User pressed Dismiss button.
9333 */
9334 dismiss_info.raised=MagickFalse;
9335 XDrawBeveledButton(display,&windows->widget,&dismiss_info);
9336 break;
9337 }
9338 if (MatteIsActive(list_info,event.xbutton))
9339 {
9340 int
9341 id;
9342
9343 static Time
9344 click_time;
9345
9346 /*
9347 User pressed list matte.
9348 */
9349 id=slider_info.id+(event.xbutton.y-(list_info.y+(height >> 1))+1)/
9350 selection_info.height;
9351 if (id >= (int) lines)
9352 break;
9353 if (id != list_info.id)
9354 {
9355 list_info.id=id;
9356 click_time=event.xbutton.time;
9357 break;
9358 }
9359 list_info.id=id;
9360 if (event.xbutton.time >= (click_time+DoubleClick))
9361 {
9362 click_time=event.xbutton.time;
9363 break;
9364 }
9365 click_time=event.xbutton.time;
9366 /*
9367 Become the XA_PRIMARY selection owner.
9368 */
9369 (void) CopyMagickString(primary_selection,textlist[list_info.id],
9370 MaxTextExtent);
9371 (void) XSetSelectionOwner(display,XA_PRIMARY,windows->widget.id,
9372 event.xbutton.time);
9373 if (XGetSelectionOwner(display,XA_PRIMARY) != windows->widget.id)
9374 break;
9375 selection_info.id=(~0);
9376 list_info.id=id;
9377 state|=RedrawListState;
9378 break;
9379 }
9380 break;
9381 }
9382 case ButtonRelease:
9383 {
9384 if (windows->widget.mapped == MagickFalse)
9385 break;
9386 if (north_info.raised == MagickFalse)
9387 {
9388 /*
9389 User released up button.
9390 */
9391 delay=SuspendTime << 2;
9392 north_info.raised=MagickTrue;
9393 XDrawTriangleNorth(display,&windows->widget,&north_info);
9394 }
9395 if (south_info.raised == MagickFalse)
9396 {
9397 /*
9398 User released down button.
9399 */
9400 delay=SuspendTime << 2;
9401 south_info.raised=MagickTrue;
9402 XDrawTriangleSouth(display,&windows->widget,&south_info);
9403 }
9404 if (slider_info.active)
9405 {
9406 /*
9407 Stop tracking slider.
9408 */
9409 slider_info.active=MagickFalse;
9410 break;
9411 }
9412 if (dismiss_info.raised == MagickFalse)
9413 {
9414 if (event.xbutton.window == windows->widget.id)
9415 if (MatteIsActive(dismiss_info,event.xbutton))
9416 state|=ExitState;
9417 dismiss_info.raised=MagickTrue;
9418 XDrawBeveledButton(display,&windows->widget,&dismiss_info);
9419 }
9420 break;
9421 }
9422 case ClientMessage:
9423 {
9424 /*
9425 If client window delete message, exit.
9426 */
9427 if (event.xclient.message_type != windows->wm_protocols)
9428 break;
9429 if (*event.xclient.data.l == (int) windows->wm_take_focus)
9430 {
9431 (void) XSetInputFocus(display,event.xclient.window,RevertToParent,
9432 (Time) event.xclient.data.l[1]);
9433 break;
9434 }
9435 if (*event.xclient.data.l != (int) windows->wm_delete_window)
9436 break;
9437 if (event.xclient.window == windows->widget.id)
9438 {
9439 state|=ExitState;
9440 break;
9441 }
9442 break;
9443 }
9444 case ConfigureNotify:
9445 {
9446 /*
9447 Update widget configuration.
9448 */
9449 if (event.xconfigure.window != windows->widget.id)
9450 break;
9451 if ((event.xconfigure.width == (int) windows->widget.width) &&
9452 (event.xconfigure.height == (int) windows->widget.height))
9453 break;
9454 windows->widget.width=(unsigned int)
9455 MagickMax(event.xconfigure.width,(int) windows->widget.min_width);
9456 windows->widget.height=(unsigned int)
9457 MagickMax(event.xconfigure.height,(int) windows->widget.min_height);
9458 state|=UpdateConfigurationState;
9459 break;
9460 }
9461 case EnterNotify:
9462 {
9463 if (event.xcrossing.window != windows->widget.id)
9464 break;
9465 state&=(~InactiveWidgetState);
9466 break;
9467 }
9468 case Expose:
9469 {
9470 if (event.xexpose.window != windows->widget.id)
9471 break;
9472 if (event.xexpose.count != 0)
9473 break;
9474 state|=RedrawWidgetState;
9475 break;
9476 }
9477 case KeyPress:
9478 {
9479 static char
9480 command[MaxTextExtent];
9481
9482 static int
9483 length;
9484
9485 static KeySym
9486 key_symbol;
9487
9488 /*
9489 Respond to a user key press.
9490 */
9491 if (event.xkey.window != windows->widget.id)
9492 break;
9493 length=XLookupString((XKeyEvent *) &event.xkey,command,
9494 (int) sizeof(command),&key_symbol,(XComposeStatus *) NULL);
9495 *(command+length)='\0';
9496 if ((key_symbol == XK_Return) || (key_symbol == XK_KP_Enter))
9497 {
9498 dismiss_info.raised=MagickFalse;
9499 XDrawBeveledButton(display,&windows->widget,&dismiss_info);
9500 state|=ExitState;
9501 break;
9502 }
9503 if (AreaIsActive(scroll_info,event.xkey))
9504 {
9505 /*
9506 Move slider.
9507 */
9508 switch ((int) key_symbol)
9509 {
9510 case XK_Home:
9511 case XK_KP_Home:
9512 {
9513 slider_info.id=0;
9514 break;
9515 }
9516 case XK_Up:
9517 case XK_KP_Up:
9518 {
9519 slider_info.id--;
9520 break;
9521 }
9522 case XK_Down:
9523 case XK_KP_Down:
9524 {
9525 slider_info.id++;
9526 break;
9527 }
9528 case XK_Prior:
9529 case XK_KP_Prior:
9530 {
9531 slider_info.id-=visible_lines;
9532 break;
9533 }
9534 case XK_Next:
9535 case XK_KP_Next:
9536 {
9537 slider_info.id+=visible_lines;
9538 break;
9539 }
9540 case XK_End:
9541 case XK_KP_End:
9542 {
9543 slider_info.id=(int) lines;
9544 break;
9545 }
9546 }
9547 state|=RedrawListState;
9548 break;
9549 }
9550 break;
9551 }
9552 case KeyRelease:
9553 break;
9554 case LeaveNotify:
9555 {
9556 if (event.xcrossing.window != windows->widget.id)
9557 break;
9558 state|=InactiveWidgetState;
9559 break;
9560 }
9561 case MapNotify:
9562 {
9563 mask&=(~CWX);
9564 mask&=(~CWY);
9565 break;
9566 }
9567 case MotionNotify:
9568 {
9569 /*
9570 Discard pending button motion events.
9571 */
9572 while (XCheckMaskEvent(display,ButtonMotionMask,&event)) ;
9573 if (slider_info.active)
9574 {
9575 /*
9576 Move slider matte.
9577 */
9578 slider_info.y=event.xmotion.y-
9579 ((slider_info.height+slider_info.bevel_width) >> 1)+1;
9580 if (slider_info.y < slider_info.min_y)
9581 slider_info.y=slider_info.min_y;
9582 if (slider_info.y > slider_info.max_y)
9583 slider_info.y=slider_info.max_y;
9584 slider_info.id=0;
9585 if (slider_info.y != slider_info.min_y)
9586 slider_info.id=(int) (lines*(slider_info.y-slider_info.min_y+1))/
9587 (slider_info.max_y-slider_info.min_y+1);
9588 state|=RedrawListState;
9589 break;
9590 }
9591 if (state & InactiveWidgetState)
9592 break;
9593 if (dismiss_info.raised == MatteIsActive(dismiss_info,event.xmotion))
9594 {
9595 /*
9596 Dismiss button status changed.
9597 */
9598 dismiss_info.raised=
9599 dismiss_info.raised == MagickFalse ? MagickTrue : MagickFalse;
9600 XDrawBeveledButton(display,&windows->widget,&dismiss_info);
9601 break;
9602 }
9603 break;
9604 }
9605 case SelectionClear:
9606 {
9607 list_info.id=(~0);
9608 selection_info.id=(~0);
9609 state|=RedrawListState;
9610 break;
9611 }
9612 case SelectionRequest:
9613 {
9614 XSelectionEvent
9615 notify;
9616
9617 XSelectionRequestEvent
9618 *request;
9619
9620 if (list_info.id == (~0))
9621 break;
9622 /*
9623 Set primary selection.
9624 */
9625 request=(&(event.xselectionrequest));
9626 (void) XChangeProperty(request->display,request->requestor,
9627 request->property,request->target,8,PropModeReplace,
9628 (unsigned char *) primary_selection,Extent(primary_selection));
9629 notify.type=SelectionNotify;
9630 notify.send_event=MagickTrue;
9631 notify.display=request->display;
9632 notify.requestor=request->requestor;
9633 notify.selection=request->selection;
9634 notify.target=request->target;
9635 notify.time=request->time;
9636 if (request->property == None)
9637 notify.property=request->target;
9638 else
9639 notify.property=request->property;
9640 (void) XSendEvent(request->display,request->requestor,False,NoEventMask,
9641 (XEvent *) &notify);
9642 }
9643 default:
9644 break;
9645 }
9646 } while ((state & ExitState) == 0);
9647 if (text_info != windows->widget.font_info)
9648 (void) XFreeFont(display,text_info);
9649 XSetCursorState(display,windows,MagickFalse);
9650 (void) XWithdrawWindow(display,windows->widget.id,windows->widget.screen);
9651 XCheckRefreshWindows(display,windows);
9652}
9653#endif