blob: 1186c25603c4805e64bb2391d7578f05dc1c8d7d [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% %
cristy16af1cb2009-12-11 21:38:29 +000021% Copyright 1999-2010 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;
cristybb503372010-05-27 20:51:26 +00001170 if ((Extent(text_info->text)+1) >= (ssize_t) 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 }
cristybb503372010-05-27 20:51:26 +00001575 foreground=(ssize_t) XPixelIntensity(&window_info->pixel_info->foreground_color);
1576 matte=(ssize_t) XPixelIntensity(&window_info->pixel_info->matte_color);
cristy3ed852e2009-09-05 21:47:34 +00001577 if (MagickAbsoluteValue(foreground-matte) > (65535L >> 3))
1578 (void) XSetForeground(display,window_info->widget_context,
1579 window_info->pixel_info->foreground_color.pixel);
1580 else
1581 (void) XSetForeground(display,window_info->widget_context,
1582 window_info->pixel_info->background_color.pixel);
1583}
1584
1585/*
1586%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1587% %
1588% %
1589% %
1590% X C o l o r B r o w s e r W i d g e t %
1591% %
1592% %
1593% %
1594%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1595%
1596% XColorBrowserWidget() displays a Color Browser widget with a color query
1597% to the user. The user keys a reply and presses the Action or Cancel button
1598% to exit. The typed text is returned as the reply function parameter.
1599%
1600% The format of the XColorBrowserWidget method is:
1601%
1602% void XColorBrowserWidget(Display *display,XWindows *windows,
1603% const char *action,char *reply)
1604%
1605% A description of each parameter follows:
1606%
1607% o display: Specifies a connection to an X server; returned from
1608% XOpenDisplay.
1609%
1610% o window: Specifies a pointer to a XWindows structure.
1611%
1612% o action: Specifies a pointer to the action of this widget.
1613%
1614% o reply: the response from the user is returned in this parameter.
1615%
1616*/
1617MagickExport void XColorBrowserWidget(Display *display,XWindows *windows,
1618 const char *action,char *reply)
1619{
1620#define CancelButtonText "Cancel"
1621#define ColornameText "Name:"
1622#define ColorPatternText "Pattern:"
1623#define GrabButtonText "Grab"
1624#define ResetButtonText "Reset"
1625
1626 char
1627 **colorlist,
1628 primary_selection[MaxTextExtent],
1629 reset_pattern[MaxTextExtent],
1630 text[MaxTextExtent];
1631
1632 ExceptionInfo
1633 *exception;
1634
1635 int
1636 x,
1637 y;
1638
1639 register int
1640 i;
1641
1642 static char
1643 glob_pattern[MaxTextExtent] = "*";
1644
1645 static MagickStatusType
1646 mask = (MagickStatusType) (CWWidth | CWHeight | CWX | CWY);
1647
1648 Status
1649 status;
1650
1651 unsigned int
1652 height,
1653 text_width,
1654 visible_colors,
1655 width;
1656
cristybb503372010-05-27 20:51:26 +00001657 size_t
cristy3ed852e2009-09-05 21:47:34 +00001658 colors,
1659 delay,
1660 state;
1661
1662 XColor
1663 color;
1664
1665 XEvent
1666 event;
1667
1668 XFontStruct
1669 *font_info;
1670
1671 XTextProperty
1672 window_name;
1673
1674 XWidgetInfo
1675 action_info,
1676 cancel_info,
1677 expose_info,
1678 grab_info,
1679 list_info,
1680 mode_info,
1681 north_info,
1682 reply_info,
1683 reset_info,
1684 scroll_info,
1685 selection_info,
1686 slider_info,
1687 south_info,
1688 text_info;
1689
1690 XWindowChanges
1691 window_changes;
1692
1693 /*
1694 Get color list and sort in ascending order.
1695 */
1696 assert(display != (Display *) NULL);
1697 assert(windows != (XWindows *) NULL);
1698 assert(action != (char *) NULL);
1699 assert(reply != (char *) NULL);
1700 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",action);
1701 XSetCursorState(display,windows,MagickTrue);
1702 XCheckRefreshWindows(display,windows);
1703 (void) CopyMagickString(reset_pattern,"*",MaxTextExtent);
1704 exception=AcquireExceptionInfo();
1705 colorlist=GetColorList(glob_pattern,&colors,exception);
1706 if (colorlist == (char **) NULL)
1707 {
1708 /*
1709 Pattern failed, obtain all the colors.
1710 */
1711 (void) CopyMagickString(glob_pattern,"*",MaxTextExtent);
1712 colorlist=GetColorList(glob_pattern,&colors,exception);
1713 if (colorlist == (char **) NULL)
1714 {
1715 XNoticeWidget(display,windows,"Unable to obtain colors names:",
1716 glob_pattern);
1717 (void) XDialogWidget(display,windows,action,"Enter color name:",
1718 reply);
1719 return;
1720 }
1721 }
1722 /*
1723 Determine Color Browser widget attributes.
1724 */
1725 font_info=windows->widget.font_info;
1726 text_width=0;
cristybb503372010-05-27 20:51:26 +00001727 for (i=0; i < (ssize_t) colors; i++)
cristy3ed852e2009-09-05 21:47:34 +00001728 if (WidgetTextWidth(font_info,colorlist[i]) > text_width)
1729 text_width=WidgetTextWidth(font_info,colorlist[i]);
1730 width=WidgetTextWidth(font_info,(char *) action);
1731 if (WidgetTextWidth(font_info,CancelButtonText) > width)
1732 width=WidgetTextWidth(font_info,CancelButtonText);
1733 if (WidgetTextWidth(font_info,ResetButtonText) > width)
1734 width=WidgetTextWidth(font_info,ResetButtonText);
1735 if (WidgetTextWidth(font_info,GrabButtonText) > width)
1736 width=WidgetTextWidth(font_info,GrabButtonText);
1737 width+=QuantumMargin;
1738 if (WidgetTextWidth(font_info,ColorPatternText) > width)
1739 width=WidgetTextWidth(font_info,ColorPatternText);
1740 if (WidgetTextWidth(font_info,ColornameText) > width)
1741 width=WidgetTextWidth(font_info,ColornameText);
1742 height=(unsigned int) (font_info->ascent+font_info->descent);
1743 /*
1744 Position Color Browser widget.
1745 */
1746 windows->widget.width=(unsigned int)
1747 (width+MagickMin((int) text_width,(int) MaxTextWidth)+6*QuantumMargin);
1748 windows->widget.min_width=(unsigned int)
1749 (width+MinTextWidth+4*QuantumMargin);
1750 if (windows->widget.width < windows->widget.min_width)
1751 windows->widget.width=windows->widget.min_width;
1752 windows->widget.height=(unsigned int)
1753 ((81*height) >> 2)+((13*QuantumMargin) >> 1)+4;
1754 windows->widget.min_height=(unsigned int)
1755 (((23*height) >> 1)+((13*QuantumMargin) >> 1)+4);
1756 if (windows->widget.height < windows->widget.min_height)
1757 windows->widget.height=windows->widget.min_height;
1758 XConstrainWindowPosition(display,&windows->widget);
1759 /*
1760 Map Color Browser widget.
1761 */
1762 (void) CopyMagickString(windows->widget.name,"Browse and Select a Color",
1763 MaxTextExtent);
1764 status=XStringListToTextProperty(&windows->widget.name,1,&window_name);
1765 if (status != False)
1766 {
1767 XSetWMName(display,windows->widget.id,&window_name);
1768 XSetWMIconName(display,windows->widget.id,&window_name);
1769 (void) XFree((void *) window_name.value);
1770 }
1771 window_changes.width=(int) windows->widget.width;
1772 window_changes.height=(int) windows->widget.height;
1773 window_changes.x=windows->widget.x;
1774 window_changes.y=windows->widget.y;
1775 (void) XReconfigureWMWindow(display,windows->widget.id,windows->widget.screen,
1776 mask,&window_changes);
1777 (void) XMapRaised(display,windows->widget.id);
1778 windows->widget.mapped=MagickFalse;
1779 /*
1780 Respond to X events.
1781 */
1782 XGetWidgetInfo((char *) NULL,&slider_info);
1783 XGetWidgetInfo((char *) NULL,&north_info);
1784 XGetWidgetInfo((char *) NULL,&south_info);
1785 XGetWidgetInfo((char *) NULL,&expose_info);
1786 visible_colors=0;
1787 delay=SuspendTime << 2;
1788 state=UpdateConfigurationState;
1789 do
1790 {
1791 if (state & UpdateConfigurationState)
1792 {
1793 int
1794 id;
1795
1796 /*
1797 Initialize button information.
1798 */
1799 XGetWidgetInfo(CancelButtonText,&cancel_info);
1800 cancel_info.width=width;
1801 cancel_info.height=(unsigned int) ((3*height) >> 1);
1802 cancel_info.x=(int)
1803 (windows->widget.width-cancel_info.width-QuantumMargin-2);
1804 cancel_info.y=(int)
1805 (windows->widget.height-cancel_info.height-QuantumMargin);
1806 XGetWidgetInfo(action,&action_info);
1807 action_info.width=width;
1808 action_info.height=(unsigned int) ((3*height) >> 1);
1809 action_info.x=cancel_info.x-(cancel_info.width+(QuantumMargin >> 1)+
1810 (action_info.bevel_width << 1));
1811 action_info.y=cancel_info.y;
1812 XGetWidgetInfo(GrabButtonText,&grab_info);
1813 grab_info.width=width;
1814 grab_info.height=(unsigned int) ((3*height) >> 1);
1815 grab_info.x=QuantumMargin;
1816 grab_info.y=((5*QuantumMargin) >> 1)+height;
1817 XGetWidgetInfo(ResetButtonText,&reset_info);
1818 reset_info.width=width;
1819 reset_info.height=(unsigned int) ((3*height) >> 1);
1820 reset_info.x=QuantumMargin;
1821 reset_info.y=grab_info.y+grab_info.height+QuantumMargin;
1822 /*
1823 Initialize reply information.
1824 */
1825 XGetWidgetInfo(reply,&reply_info);
1826 reply_info.raised=MagickFalse;
1827 reply_info.bevel_width--;
1828 reply_info.width=windows->widget.width-width-((6*QuantumMargin) >> 1);
1829 reply_info.height=height << 1;
1830 reply_info.x=(int) (width+(QuantumMargin << 1));
1831 reply_info.y=action_info.y-reply_info.height-QuantumMargin;
1832 /*
1833 Initialize mode information.
1834 */
1835 XGetWidgetInfo((char *) NULL,&mode_info);
1836 mode_info.active=MagickTrue;
1837 mode_info.bevel_width=0;
1838 mode_info.width=(unsigned int) (action_info.x-(QuantumMargin << 1));
1839 mode_info.height=action_info.height;
1840 mode_info.x=QuantumMargin;
1841 mode_info.y=action_info.y;
1842 /*
1843 Initialize scroll information.
1844 */
1845 XGetWidgetInfo((char *) NULL,&scroll_info);
1846 scroll_info.bevel_width--;
1847 scroll_info.width=height;
1848 scroll_info.height=(unsigned int) (reply_info.y-grab_info.y-
1849 (QuantumMargin >> 1));
1850 scroll_info.x=reply_info.x+(reply_info.width-scroll_info.width);
1851 scroll_info.y=grab_info.y-reply_info.bevel_width;
1852 scroll_info.raised=MagickFalse;
1853 scroll_info.trough=MagickTrue;
1854 north_info=scroll_info;
1855 north_info.raised=MagickTrue;
1856 north_info.width-=(north_info.bevel_width << 1);
1857 north_info.height=north_info.width-1;
1858 north_info.x+=north_info.bevel_width;
1859 north_info.y+=north_info.bevel_width;
1860 south_info=north_info;
1861 south_info.y=scroll_info.y+scroll_info.height-scroll_info.bevel_width-
1862 south_info.height;
1863 id=slider_info.id;
1864 slider_info=north_info;
1865 slider_info.id=id;
1866 slider_info.width-=2;
1867 slider_info.min_y=north_info.y+north_info.height+north_info.bevel_width+
1868 slider_info.bevel_width+2;
1869 slider_info.height=scroll_info.height-((slider_info.min_y-
1870 scroll_info.y+1) << 1)+4;
1871 visible_colors=scroll_info.height/(height+(height >> 3));
1872 if (colors > visible_colors)
1873 slider_info.height=(unsigned int)
1874 ((visible_colors*slider_info.height)/colors);
1875 slider_info.max_y=south_info.y-south_info.bevel_width-
1876 slider_info.bevel_width-2;
1877 slider_info.x=scroll_info.x+slider_info.bevel_width+1;
1878 slider_info.y=slider_info.min_y;
1879 expose_info=scroll_info;
1880 expose_info.y=slider_info.y;
1881 /*
1882 Initialize list information.
1883 */
1884 XGetWidgetInfo((char *) NULL,&list_info);
1885 list_info.raised=MagickFalse;
1886 list_info.bevel_width--;
1887 list_info.width=(unsigned int)
1888 (scroll_info.x-reply_info.x-(QuantumMargin >> 1));
1889 list_info.height=scroll_info.height;
1890 list_info.x=reply_info.x;
1891 list_info.y=scroll_info.y;
1892 if (windows->widget.mapped == MagickFalse)
1893 state|=JumpListState;
1894 /*
1895 Initialize text information.
1896 */
1897 *text='\0';
1898 XGetWidgetInfo(text,&text_info);
1899 text_info.center=MagickFalse;
1900 text_info.width=reply_info.width;
1901 text_info.height=height;
1902 text_info.x=list_info.x-(QuantumMargin >> 1);
1903 text_info.y=QuantumMargin;
1904 /*
1905 Initialize selection information.
1906 */
1907 XGetWidgetInfo((char *) NULL,&selection_info);
1908 selection_info.center=MagickFalse;
1909 selection_info.width=list_info.width;
1910 selection_info.height=(unsigned int) ((9*height) >> 3);
1911 selection_info.x=list_info.x;
1912 state&=(~UpdateConfigurationState);
1913 }
1914 if (state & RedrawWidgetState)
1915 {
1916 /*
1917 Redraw Color Browser window.
1918 */
1919 x=QuantumMargin;
1920 y=text_info.y+((text_info.height-height) >> 1)+font_info->ascent;
1921 (void) XDrawString(display,windows->widget.id,
1922 windows->widget.annotate_context,x,y,ColorPatternText,
1923 Extent(ColorPatternText));
1924 (void) CopyMagickString(text_info.text,glob_pattern,MaxTextExtent);
1925 XDrawWidgetText(display,&windows->widget,&text_info);
1926 XDrawBeveledButton(display,&windows->widget,&grab_info);
1927 XDrawBeveledButton(display,&windows->widget,&reset_info);
1928 XDrawBeveledMatte(display,&windows->widget,&list_info);
1929 XDrawBeveledMatte(display,&windows->widget,&scroll_info);
1930 XDrawTriangleNorth(display,&windows->widget,&north_info);
1931 XDrawBeveledButton(display,&windows->widget,&slider_info);
1932 XDrawTriangleSouth(display,&windows->widget,&south_info);
1933 x=QuantumMargin;
1934 y=reply_info.y+((reply_info.height-height) >> 1)+font_info->ascent;
1935 (void) XDrawString(display,windows->widget.id,
1936 windows->widget.annotate_context,x,y,ColornameText,
1937 Extent(ColornameText));
1938 XDrawBeveledMatte(display,&windows->widget,&reply_info);
1939 XDrawMatteText(display,&windows->widget,&reply_info);
1940 XDrawBeveledButton(display,&windows->widget,&action_info);
1941 XDrawBeveledButton(display,&windows->widget,&cancel_info);
1942 XHighlightWidget(display,&windows->widget,BorderOffset,BorderOffset);
1943 selection_info.id=(~0);
1944 state|=RedrawActionState;
1945 state|=RedrawListState;
1946 state&=(~RedrawWidgetState);
1947 }
1948 if (state & UpdateListState)
1949 {
1950 char
1951 **checklist;
1952
cristybb503372010-05-27 20:51:26 +00001953 size_t
cristy3ed852e2009-09-05 21:47:34 +00001954 number_colors;
1955
1956 status=XParseColor(display,windows->widget.map_info->colormap,
1957 glob_pattern,&color);
1958 if ((status != False) || (strchr(glob_pattern,'-') != (char *) NULL))
1959 {
1960 /*
1961 Reply is a single color name-- exit.
1962 */
1963 (void) CopyMagickString(reply,glob_pattern,MaxTextExtent);
1964 (void) CopyMagickString(glob_pattern,reset_pattern,MaxTextExtent);
1965 action_info.raised=MagickFalse;
1966 XDrawBeveledButton(display,&windows->widget,&action_info);
1967 break;
1968 }
1969 /*
1970 Update color list.
1971 */
1972 checklist=GetColorList(glob_pattern,&number_colors,exception);
1973 if (number_colors == 0)
1974 {
1975 (void) CopyMagickString(glob_pattern,reset_pattern,MaxTextExtent);
1976 (void) XBell(display,0);
1977 }
1978 else
1979 {
cristybb503372010-05-27 20:51:26 +00001980 for (i=0; i < (ssize_t) colors; i++)
cristy3ed852e2009-09-05 21:47:34 +00001981 colorlist[i]=DestroyString(colorlist[i]);
1982 if (colorlist != (char **) NULL)
1983 colorlist=(char **) RelinquishMagickMemory(colorlist);
1984 colorlist=checklist;
1985 colors=number_colors;
1986 }
1987 /*
1988 Sort color list in ascending order.
1989 */
1990 slider_info.height=
1991 scroll_info.height-((slider_info.min_y-scroll_info.y+1) << 1)+1;
1992 if (colors > visible_colors)
1993 slider_info.height=(unsigned int)
1994 ((visible_colors*slider_info.height)/colors);
1995 slider_info.max_y=south_info.y-south_info.bevel_width-
1996 slider_info.bevel_width-2;
1997 slider_info.id=0;
1998 slider_info.y=slider_info.min_y;
1999 expose_info.y=slider_info.y;
2000 selection_info.id=(~0);
2001 list_info.id=(~0);
2002 state|=RedrawListState;
2003 /*
2004 Redraw color name & reply.
2005 */
2006 *reply_info.text='\0';
2007 reply_info.cursor=reply_info.text;
2008 (void) CopyMagickString(text_info.text,glob_pattern,MaxTextExtent);
2009 XDrawWidgetText(display,&windows->widget,&text_info);
2010 XDrawMatteText(display,&windows->widget,&reply_info);
2011 XDrawBeveledMatte(display,&windows->widget,&scroll_info);
2012 XDrawTriangleNorth(display,&windows->widget,&north_info);
2013 XDrawBeveledButton(display,&windows->widget,&slider_info);
2014 XDrawTriangleSouth(display,&windows->widget,&south_info);
2015 XHighlightWidget(display,&windows->widget,BorderOffset,BorderOffset);
2016 state&=(~UpdateListState);
2017 }
2018 if (state & JumpListState)
2019 {
2020 /*
2021 Jump scroll to match user color.
2022 */
2023 list_info.id=(~0);
cristybb503372010-05-27 20:51:26 +00002024 for (i=0; i < (ssize_t) colors; i++)
cristy3ed852e2009-09-05 21:47:34 +00002025 if (LocaleCompare(colorlist[i],reply) >= 0)
2026 {
2027 list_info.id=LocaleCompare(colorlist[i],reply) == 0 ? i : ~0;
2028 break;
2029 }
2030 if ((i < slider_info.id) ||
2031 (i >= (int) (slider_info.id+visible_colors)))
2032 slider_info.id=i-(visible_colors >> 1);
2033 selection_info.id=(~0);
2034 state|=RedrawListState;
2035 state&=(~JumpListState);
2036 }
2037 if (state & RedrawListState)
2038 {
2039 /*
2040 Determine slider id and position.
2041 */
2042 if (slider_info.id >= (int) (colors-visible_colors))
2043 slider_info.id=(int) (colors-visible_colors);
2044 if ((slider_info.id < 0) || (colors <= visible_colors))
2045 slider_info.id=0;
2046 slider_info.y=slider_info.min_y;
2047 if (colors != 0)
cristy8891f9c2010-06-04 23:32:17 +00002048 slider_info.y+=(int) (slider_info.id*(slider_info.max_y-
2049 slider_info.min_y+1)/colors);
cristy3ed852e2009-09-05 21:47:34 +00002050 if (slider_info.id != selection_info.id)
2051 {
2052 /*
2053 Redraw scroll bar and file names.
2054 */
2055 selection_info.id=slider_info.id;
2056 selection_info.y=list_info.y+(height >> 3)+2;
2057 for (i=0; i < (int) visible_colors; i++)
2058 {
2059 selection_info.raised=(slider_info.id+i) != list_info.id ?
2060 MagickTrue : MagickFalse;
2061 selection_info.text=(char *) NULL;
cristybb503372010-05-27 20:51:26 +00002062 if ((slider_info.id+i) < (ssize_t) colors)
cristy3ed852e2009-09-05 21:47:34 +00002063 selection_info.text=colorlist[slider_info.id+i];
2064 XDrawWidgetText(display,&windows->widget,&selection_info);
2065 selection_info.y+=(int) selection_info.height;
2066 }
2067 /*
2068 Update slider.
2069 */
2070 if (slider_info.y > expose_info.y)
2071 {
2072 expose_info.height=(unsigned int) slider_info.y-expose_info.y;
2073 expose_info.y=slider_info.y-expose_info.height-
2074 slider_info.bevel_width-1;
2075 }
2076 else
2077 {
2078 expose_info.height=(unsigned int) expose_info.y-slider_info.y;
2079 expose_info.y=slider_info.y+slider_info.height+
2080 slider_info.bevel_width+1;
2081 }
2082 XDrawTriangleNorth(display,&windows->widget,&north_info);
2083 XDrawMatte(display,&windows->widget,&expose_info);
2084 XDrawBeveledButton(display,&windows->widget,&slider_info);
2085 XDrawTriangleSouth(display,&windows->widget,&south_info);
2086 expose_info.y=slider_info.y;
2087 }
2088 state&=(~RedrawListState);
2089 }
2090 if (state & RedrawActionState)
2091 {
2092 static char
2093 colorname[MaxTextExtent];
2094
2095 /*
2096 Display the selected color in a drawing area.
2097 */
2098 color=windows->widget.pixel_info->matte_color;
2099 (void) XParseColor(display,windows->widget.map_info->colormap,
2100 reply_info.text,&windows->widget.pixel_info->matte_color);
2101 XBestPixel(display,windows->widget.map_info->colormap,(XColor *) NULL,
2102 (unsigned int) windows->widget.visual_info->colormap_size,
2103 &windows->widget.pixel_info->matte_color);
2104 mode_info.text=colorname;
2105 (void) FormatMagickString(mode_info.text,MaxTextExtent,"#%02x%02x%02x",
2106 windows->widget.pixel_info->matte_color.red,
2107 windows->widget.pixel_info->matte_color.green,
2108 windows->widget.pixel_info->matte_color.blue);
2109 XDrawBeveledButton(display,&windows->widget,&mode_info);
2110 windows->widget.pixel_info->matte_color=color;
2111 state&=(~RedrawActionState);
2112 }
2113 /*
2114 Wait for next event.
2115 */
2116 if (north_info.raised && south_info.raised)
2117 (void) XIfEvent(display,&event,XScreenEvent,(char *) windows);
2118 else
2119 {
2120 /*
2121 Brief delay before advancing scroll bar.
2122 */
2123 XDelay(display,delay);
2124 delay=SuspendTime;
2125 (void) XCheckIfEvent(display,&event,XScreenEvent,(char *) windows);
2126 if (north_info.raised == MagickFalse)
2127 if (slider_info.id > 0)
2128 {
2129 /*
2130 Move slider up.
2131 */
2132 slider_info.id--;
2133 state|=RedrawListState;
2134 }
2135 if (south_info.raised == MagickFalse)
cristybb503372010-05-27 20:51:26 +00002136 if (slider_info.id < (ssize_t) colors)
cristy3ed852e2009-09-05 21:47:34 +00002137 {
2138 /*
2139 Move slider down.
2140 */
2141 slider_info.id++;
2142 state|=RedrawListState;
2143 }
2144 if (event.type != ButtonRelease)
2145 continue;
2146 }
2147 switch (event.type)
2148 {
2149 case ButtonPress:
2150 {
2151 if (MatteIsActive(slider_info,event.xbutton))
2152 {
2153 /*
2154 Track slider.
2155 */
2156 slider_info.active=MagickTrue;
2157 break;
2158 }
2159 if (MatteIsActive(north_info,event.xbutton))
2160 if (slider_info.id > 0)
2161 {
2162 /*
2163 Move slider up.
2164 */
2165 north_info.raised=MagickFalse;
2166 slider_info.id--;
2167 state|=RedrawListState;
2168 break;
2169 }
2170 if (MatteIsActive(south_info,event.xbutton))
cristybb503372010-05-27 20:51:26 +00002171 if (slider_info.id < (ssize_t) colors)
cristy3ed852e2009-09-05 21:47:34 +00002172 {
2173 /*
2174 Move slider down.
2175 */
2176 south_info.raised=MagickFalse;
2177 slider_info.id++;
2178 state|=RedrawListState;
2179 break;
2180 }
2181 if (MatteIsActive(scroll_info,event.xbutton))
2182 {
2183 /*
2184 Move slider.
2185 */
2186 if (event.xbutton.y < slider_info.y)
2187 slider_info.id-=(visible_colors-1);
2188 else
2189 slider_info.id+=(visible_colors-1);
2190 state|=RedrawListState;
2191 break;
2192 }
2193 if (MatteIsActive(list_info,event.xbutton))
2194 {
2195 int
2196 id;
2197
2198 /*
2199 User pressed list matte.
2200 */
2201 id=slider_info.id+(event.xbutton.y-(list_info.y+(height >> 1))+1)/
2202 selection_info.height;
2203 if (id >= (int) colors)
2204 break;
2205 (void) CopyMagickString(reply_info.text,colorlist[id],
2206 MaxTextExtent);
2207 reply_info.highlight=MagickFalse;
2208 reply_info.marker=reply_info.text;
2209 reply_info.cursor=reply_info.text+Extent(reply_info.text);
2210 XDrawMatteText(display,&windows->widget,&reply_info);
2211 state|=RedrawActionState;
2212 if (id == list_info.id)
2213 {
2214 (void) CopyMagickString(glob_pattern,reply_info.text,
2215 MaxTextExtent);
2216 state|=UpdateListState;
2217 }
2218 selection_info.id=(~0);
2219 list_info.id=id;
2220 state|=RedrawListState;
2221 break;
2222 }
2223 if (MatteIsActive(grab_info,event.xbutton))
2224 {
2225 /*
2226 User pressed Grab button.
2227 */
2228 grab_info.raised=MagickFalse;
2229 XDrawBeveledButton(display,&windows->widget,&grab_info);
2230 break;
2231 }
2232 if (MatteIsActive(reset_info,event.xbutton))
2233 {
2234 /*
2235 User pressed Reset button.
2236 */
2237 reset_info.raised=MagickFalse;
2238 XDrawBeveledButton(display,&windows->widget,&reset_info);
2239 break;
2240 }
2241 if (MatteIsActive(mode_info,event.xbutton))
2242 {
2243 /*
2244 User pressed mode button.
2245 */
2246 (void) CopyMagickString(reply_info.text,mode_info.text,
2247 MaxTextExtent);
2248 (void) CopyMagickString(primary_selection,reply_info.text,
2249 MaxTextExtent);
2250 (void) XSetSelectionOwner(display,XA_PRIMARY,windows->widget.id,
2251 event.xbutton.time);
2252 reply_info.highlight=XGetSelectionOwner(display,XA_PRIMARY) ==
2253 windows->widget.id ? MagickTrue : MagickFalse;
2254 reply_info.marker=reply_info.text;
2255 reply_info.cursor=reply_info.text+Extent(reply_info.text);
2256 XDrawMatteText(display,&windows->widget,&reply_info);
2257 break;
2258 }
2259 if (MatteIsActive(action_info,event.xbutton))
2260 {
2261 /*
2262 User pressed action button.
2263 */
2264 action_info.raised=MagickFalse;
2265 XDrawBeveledButton(display,&windows->widget,&action_info);
2266 break;
2267 }
2268 if (MatteIsActive(cancel_info,event.xbutton))
2269 {
2270 /*
2271 User pressed Cancel button.
2272 */
2273 cancel_info.raised=MagickFalse;
2274 XDrawBeveledButton(display,&windows->widget,&cancel_info);
2275 break;
2276 }
2277 if (MatteIsActive(reply_info,event.xbutton) == MagickFalse)
2278 break;
2279 if (event.xbutton.button != Button2)
2280 {
2281 static Time
2282 click_time;
2283
2284 /*
2285 Move text cursor to position of button press.
2286 */
2287 x=event.xbutton.x-reply_info.x-(QuantumMargin >> 2);
2288 for (i=1; i <= Extent(reply_info.marker); i++)
2289 if (XTextWidth(font_info,reply_info.marker,i) > x)
2290 break;
2291 reply_info.cursor=reply_info.marker+i-1;
2292 if (event.xbutton.time > (click_time+DoubleClick))
2293 reply_info.highlight=MagickFalse;
2294 else
2295 {
2296 /*
2297 Become the XA_PRIMARY selection owner.
2298 */
2299 (void) CopyMagickString(primary_selection,reply_info.text,
2300 MaxTextExtent);
2301 (void) XSetSelectionOwner(display,XA_PRIMARY,windows->widget.id,
2302 event.xbutton.time);
2303 reply_info.highlight=XGetSelectionOwner(display,XA_PRIMARY) ==
2304 windows->widget.id ? MagickTrue : MagickFalse;
2305 }
2306 XDrawMatteText(display,&windows->widget,&reply_info);
2307 click_time=event.xbutton.time;
2308 break;
2309 }
2310 /*
2311 Request primary selection.
2312 */
2313 (void) XConvertSelection(display,XA_PRIMARY,XA_STRING,XA_STRING,
2314 windows->widget.id,event.xbutton.time);
2315 break;
2316 }
2317 case ButtonRelease:
2318 {
2319 if (windows->widget.mapped == MagickFalse)
2320 break;
2321 if (north_info.raised == MagickFalse)
2322 {
2323 /*
2324 User released up button.
2325 */
2326 delay=SuspendTime << 2;
2327 north_info.raised=MagickTrue;
2328 XDrawTriangleNorth(display,&windows->widget,&north_info);
2329 }
2330 if (south_info.raised == MagickFalse)
2331 {
2332 /*
2333 User released down button.
2334 */
2335 delay=SuspendTime << 2;
2336 south_info.raised=MagickTrue;
2337 XDrawTriangleSouth(display,&windows->widget,&south_info);
2338 }
2339 if (slider_info.active)
2340 {
2341 /*
2342 Stop tracking slider.
2343 */
2344 slider_info.active=MagickFalse;
2345 break;
2346 }
2347 if (grab_info.raised == MagickFalse)
2348 {
2349 if (event.xbutton.window == windows->widget.id)
2350 if (MatteIsActive(grab_info,event.xbutton))
2351 {
2352 /*
2353 Select a pen color from the X server.
2354 */
2355 (void) XGetWindowColor(display,windows,reply_info.text);
2356 reply_info.marker=reply_info.text;
2357 reply_info.cursor=reply_info.text+Extent(reply_info.text);
2358 XDrawMatteText(display,&windows->widget,&reply_info);
2359 state|=RedrawActionState;
2360 }
2361 grab_info.raised=MagickTrue;
2362 XDrawBeveledButton(display,&windows->widget,&grab_info);
2363 }
2364 if (reset_info.raised == MagickFalse)
2365 {
2366 if (event.xbutton.window == windows->widget.id)
2367 if (MatteIsActive(reset_info,event.xbutton))
2368 {
2369 (void) CopyMagickString(glob_pattern,reset_pattern,
2370 MaxTextExtent);
2371 state|=UpdateListState;
2372 }
2373 reset_info.raised=MagickTrue;
2374 XDrawBeveledButton(display,&windows->widget,&reset_info);
2375 }
2376 if (action_info.raised == MagickFalse)
2377 {
2378 if (event.xbutton.window == windows->widget.id)
2379 {
2380 if (MatteIsActive(action_info,event.xbutton))
2381 {
2382 if (*reply_info.text == '\0')
2383 (void) XBell(display,0);
2384 else
2385 state|=ExitState;
2386 }
2387 }
2388 action_info.raised=MagickTrue;
2389 XDrawBeveledButton(display,&windows->widget,&action_info);
2390 }
2391 if (cancel_info.raised == MagickFalse)
2392 {
2393 if (event.xbutton.window == windows->widget.id)
2394 if (MatteIsActive(cancel_info,event.xbutton))
2395 {
2396 *reply_info.text='\0';
2397 state|=ExitState;
2398 }
2399 cancel_info.raised=MagickTrue;
2400 XDrawBeveledButton(display,&windows->widget,&cancel_info);
2401 }
2402 if (MatteIsActive(reply_info,event.xbutton) == MagickFalse)
2403 break;
2404 break;
2405 }
2406 case ClientMessage:
2407 {
2408 /*
2409 If client window delete message, exit.
2410 */
2411 if (event.xclient.message_type != windows->wm_protocols)
2412 break;
2413 if (*event.xclient.data.l == (int) windows->wm_take_focus)
2414 {
2415 (void) XSetInputFocus(display,event.xclient.window,RevertToParent,
2416 (Time) event.xclient.data.l[1]);
2417 break;
2418 }
2419 if (*event.xclient.data.l != (int) windows->wm_delete_window)
2420 break;
2421 if (event.xclient.window == windows->widget.id)
2422 {
2423 *reply_info.text='\0';
2424 state|=ExitState;
2425 break;
2426 }
2427 break;
2428 }
2429 case ConfigureNotify:
2430 {
2431 /*
2432 Update widget configuration.
2433 */
2434 if (event.xconfigure.window != windows->widget.id)
2435 break;
2436 if ((event.xconfigure.width == (int) windows->widget.width) &&
2437 (event.xconfigure.height == (int) windows->widget.height))
2438 break;
2439 windows->widget.width=(unsigned int)
2440 MagickMax(event.xconfigure.width,(int) windows->widget.min_width);
2441 windows->widget.height=(unsigned int)
2442 MagickMax(event.xconfigure.height,(int) windows->widget.min_height);
2443 state|=UpdateConfigurationState;
2444 break;
2445 }
2446 case EnterNotify:
2447 {
2448 if (event.xcrossing.window != windows->widget.id)
2449 break;
2450 state&=(~InactiveWidgetState);
2451 break;
2452 }
2453 case Expose:
2454 {
2455 if (event.xexpose.window != windows->widget.id)
2456 break;
2457 if (event.xexpose.count != 0)
2458 break;
2459 state|=RedrawWidgetState;
2460 break;
2461 }
2462 case KeyPress:
2463 {
2464 static char
2465 command[MaxTextExtent];
2466
2467 static int
2468 length;
2469
2470 static KeySym
2471 key_symbol;
2472
2473 /*
2474 Respond to a user key press.
2475 */
2476 if (event.xkey.window != windows->widget.id)
2477 break;
2478 length=XLookupString((XKeyEvent *) &event.xkey,command,
2479 (int) sizeof(command),&key_symbol,(XComposeStatus *) NULL);
2480 *(command+length)='\0';
2481 if (AreaIsActive(scroll_info,event.xkey))
2482 {
2483 /*
2484 Move slider.
2485 */
2486 switch ((int) key_symbol)
2487 {
2488 case XK_Home:
2489 case XK_KP_Home:
2490 {
2491 slider_info.id=0;
2492 break;
2493 }
2494 case XK_Up:
2495 case XK_KP_Up:
2496 {
2497 slider_info.id--;
2498 break;
2499 }
2500 case XK_Down:
2501 case XK_KP_Down:
2502 {
2503 slider_info.id++;
2504 break;
2505 }
2506 case XK_Prior:
2507 case XK_KP_Prior:
2508 {
2509 slider_info.id-=visible_colors;
2510 break;
2511 }
2512 case XK_Next:
2513 case XK_KP_Next:
2514 {
2515 slider_info.id+=visible_colors;
2516 break;
2517 }
2518 case XK_End:
2519 case XK_KP_End:
2520 {
2521 slider_info.id=(int) colors;
2522 break;
2523 }
2524 }
2525 state|=RedrawListState;
2526 break;
2527 }
2528 if ((key_symbol == XK_Return) || (key_symbol == XK_KP_Enter))
2529 {
2530 /*
2531 Read new color or glob patterm.
2532 */
2533 if (*reply_info.text == '\0')
2534 break;
2535 (void) CopyMagickString(glob_pattern,reply_info.text,MaxTextExtent);
2536 state|=UpdateListState;
2537 break;
2538 }
2539 if (key_symbol == XK_Control_L)
2540 {
2541 state|=ControlState;
2542 break;
2543 }
2544 if (state & ControlState)
2545 switch ((int) key_symbol)
2546 {
2547 case XK_u:
2548 case XK_U:
2549 {
2550 /*
2551 Erase the entire line of text.
2552 */
2553 *reply_info.text='\0';
2554 reply_info.cursor=reply_info.text;
2555 reply_info.marker=reply_info.text;
2556 reply_info.highlight=MagickFalse;
2557 break;
2558 }
2559 default:
2560 break;
2561 }
2562 XEditText(display,&reply_info,key_symbol,command,state);
2563 XDrawMatteText(display,&windows->widget,&reply_info);
2564 state|=JumpListState;
2565 status=XParseColor(display,windows->widget.map_info->colormap,
2566 reply_info.text,&color);
2567 if (status != False)
2568 state|=RedrawActionState;
2569 break;
2570 }
2571 case KeyRelease:
2572 {
2573 static char
2574 command[MaxTextExtent];
2575
2576 static KeySym
2577 key_symbol;
2578
2579 /*
2580 Respond to a user key release.
2581 */
2582 if (event.xkey.window != windows->widget.id)
2583 break;
2584 (void) XLookupString((XKeyEvent *) &event.xkey,command,
2585 (int) sizeof(command),&key_symbol,(XComposeStatus *) NULL);
2586 if (key_symbol == XK_Control_L)
2587 state&=(~ControlState);
2588 break;
2589 }
2590 case LeaveNotify:
2591 {
2592 if (event.xcrossing.window != windows->widget.id)
2593 break;
2594 state|=InactiveWidgetState;
2595 break;
2596 }
2597 case MapNotify:
2598 {
2599 mask&=(~CWX);
2600 mask&=(~CWY);
2601 break;
2602 }
2603 case MotionNotify:
2604 {
2605 /*
2606 Discard pending button motion events.
2607 */
2608 while (XCheckMaskEvent(display,ButtonMotionMask,&event)) ;
2609 if (slider_info.active)
2610 {
2611 /*
2612 Move slider matte.
2613 */
2614 slider_info.y=event.xmotion.y-
2615 ((slider_info.height+slider_info.bevel_width) >> 1)+1;
2616 if (slider_info.y < slider_info.min_y)
2617 slider_info.y=slider_info.min_y;
2618 if (slider_info.y > slider_info.max_y)
2619 slider_info.y=slider_info.max_y;
2620 slider_info.id=0;
2621 if (slider_info.y != slider_info.min_y)
2622 slider_info.id=(int) ((colors*(slider_info.y-
2623 slider_info.min_y+1))/(slider_info.max_y-slider_info.min_y+1));
2624 state|=RedrawListState;
2625 break;
2626 }
2627 if (state & InactiveWidgetState)
2628 break;
2629 if (grab_info.raised == MatteIsActive(grab_info,event.xmotion))
2630 {
2631 /*
2632 Grab button status changed.
2633 */
2634 grab_info.raised=!grab_info.raised;
2635 XDrawBeveledButton(display,&windows->widget,&grab_info);
2636 break;
2637 }
2638 if (reset_info.raised == MatteIsActive(reset_info,event.xmotion))
2639 {
2640 /*
2641 Reset button status changed.
2642 */
2643 reset_info.raised=!reset_info.raised;
2644 XDrawBeveledButton(display,&windows->widget,&reset_info);
2645 break;
2646 }
2647 if (action_info.raised == MatteIsActive(action_info,event.xmotion))
2648 {
2649 /*
2650 Action button status changed.
2651 */
2652 action_info.raised=action_info.raised == MagickFalse ?
2653 MagickTrue : MagickFalse;
2654 XDrawBeveledButton(display,&windows->widget,&action_info);
2655 break;
2656 }
2657 if (cancel_info.raised == MatteIsActive(cancel_info,event.xmotion))
2658 {
2659 /*
2660 Cancel button status changed.
2661 */
2662 cancel_info.raised=cancel_info.raised == MagickFalse ?
2663 MagickTrue : MagickFalse;
2664 XDrawBeveledButton(display,&windows->widget,&cancel_info);
2665 break;
2666 }
2667 break;
2668 }
2669 case SelectionClear:
2670 {
2671 reply_info.highlight=MagickFalse;
2672 XDrawMatteText(display,&windows->widget,&reply_info);
2673 break;
2674 }
2675 case SelectionNotify:
2676 {
2677 Atom
2678 type;
2679
2680 int
2681 format;
2682
2683 unsigned char
2684 *data;
2685
cristyf2faecf2010-05-28 19:19:36 +00002686 unsigned long
cristy3ed852e2009-09-05 21:47:34 +00002687 after,
2688 length;
2689
2690 /*
2691 Obtain response from primary selection.
2692 */
2693 if (event.xselection.property == (Atom) None)
2694 break;
2695 status=XGetWindowProperty(display,event.xselection.requestor,
2696 event.xselection.property,0L,2047L,MagickTrue,XA_STRING,&type,
2697 &format,&length,&after,&data);
2698 if ((status != Success) || (type != XA_STRING) || (format == 32) ||
2699 (length == 0))
2700 break;
2701 if ((Extent(reply_info.text)+length) >= MaxTextExtent)
2702 (void) XBell(display,0);
2703 else
2704 {
2705 /*
2706 Insert primary selection in reply text.
2707 */
2708 *(data+length)='\0';
2709 XEditText(display,&reply_info,(KeySym) XK_Insert,(char *) data,
2710 state);
2711 XDrawMatteText(display,&windows->widget,&reply_info);
2712 state|=JumpListState;
2713 state|=RedrawActionState;
2714 }
2715 (void) XFree((void *) data);
2716 break;
2717 }
2718 case SelectionRequest:
2719 {
2720 XSelectionEvent
2721 notify;
2722
2723 XSelectionRequestEvent
2724 *request;
2725
2726 if (reply_info.highlight == MagickFalse)
2727 break;
2728 /*
2729 Set primary selection.
2730 */
2731 request=(&(event.xselectionrequest));
2732 (void) XChangeProperty(request->display,request->requestor,
2733 request->property,request->target,8,PropModeReplace,
2734 (unsigned char *) primary_selection,Extent(primary_selection));
2735 notify.type=SelectionNotify;
2736 notify.send_event=MagickTrue;
2737 notify.display=request->display;
2738 notify.requestor=request->requestor;
2739 notify.selection=request->selection;
2740 notify.target=request->target;
2741 notify.time=request->time;
2742 if (request->property == None)
2743 notify.property=request->target;
2744 else
2745 notify.property=request->property;
2746 (void) XSendEvent(request->display,request->requestor,False,
2747 NoEventMask,(XEvent *) &notify);
2748 }
2749 default:
2750 break;
2751 }
2752 } while ((state & ExitState) == 0);
2753 XSetCursorState(display,windows,MagickFalse);
2754 (void) XWithdrawWindow(display,windows->widget.id,windows->widget.screen);
2755 XCheckRefreshWindows(display,windows);
2756 /*
2757 Free color list.
2758 */
cristybb503372010-05-27 20:51:26 +00002759 for (i=0; i < (ssize_t) colors; i++)
cristy3ed852e2009-09-05 21:47:34 +00002760 colorlist[i]=DestroyString(colorlist[i]);
2761 if (colorlist != (char **) NULL)
2762 colorlist=(char **) RelinquishMagickMemory(colorlist);
2763 exception=DestroyExceptionInfo(exception);
2764 if ((*reply == '\0') || (strchr(reply,'-') != (char *) NULL))
2765 return;
2766 status=XParseColor(display,windows->widget.map_info->colormap,reply,&color);
2767 if (status != False)
2768 return;
2769 XNoticeWidget(display,windows,"Color is unknown to X server:",reply);
2770 (void) CopyMagickString(reply,"gray",MaxTextExtent);
2771}
2772
2773/*
2774%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2775% %
2776% %
2777% %
2778% X C o m m a n d W i d g e t %
2779% %
2780% %
2781% %
2782%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2783%
2784% XCommandWidget() maps a menu and returns the command pointed to by the user
2785% when the button is released.
2786%
2787% The format of the XCommandWidget method is:
2788%
2789% int XCommandWidget(Display *display,XWindows *windows,
2790% const char **selections,XEvent *event)
2791%
2792% A description of each parameter follows:
2793%
2794% o selection_number: Specifies the number of the selection that the
2795% user choose.
2796%
2797% o display: Specifies a connection to an X server; returned from
2798% XOpenDisplay.
2799%
2800% o window: Specifies a pointer to a XWindows structure.
2801%
2802% o selections: Specifies a pointer to one or more strings that comprise
2803% the choices in the menu.
2804%
2805% o event: Specifies a pointer to a X11 XEvent structure.
2806%
2807*/
2808MagickExport int XCommandWidget(Display *display,XWindows *windows,
2809 const char **selections,XEvent *event)
2810{
2811#define tile_width 112
2812#define tile_height 70
2813
2814 static const unsigned char
2815 tile_bits[]=
2816 {
2817 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2818 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2819 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2820 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00,
2821 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00,
2822 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x00,
2823 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2824 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2825 0x00, 0x00, 0x1e, 0x38, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2826 0x00, 0x00, 0x00, 0x00, 0x1e, 0xbc, 0x9f, 0x03, 0x00, 0x3e, 0x00, 0xc0,
2827 0x1f, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x1e, 0xfc, 0xff, 0x0f, 0x80, 0x3f,
2828 0x00, 0xf0, 0x1f, 0xc0, 0x0f, 0x00, 0x00, 0x00, 0x1e, 0xfc, 0xff, 0x1f,
2829 0xe0, 0x3f, 0x00, 0xfc, 0x1f, 0xf0, 0x0f, 0x00, 0x00, 0x00, 0x1e, 0xfc,
2830 0xff, 0x1f, 0xf0, 0x3f, 0x00, 0xfe, 0x1f, 0xf8, 0x0f, 0x00, 0x00, 0x00,
2831 0x1e, 0xfc, 0xfc, 0x3f, 0xf8, 0x3f, 0x00, 0xff, 0x1e, 0xfc, 0x0f, 0x00,
2832 0x00, 0x00, 0x1e, 0x7c, 0xfc, 0x3e, 0xf8, 0x3c, 0x80, 0x1f, 0x1e, 0x7c,
2833 0x0f, 0x00, 0x00, 0x00, 0x1e, 0x78, 0x78, 0x3c, 0x7c, 0x3c, 0xc0, 0x0f,
2834 0x1e, 0x3e, 0x0f, 0x00, 0x00, 0x00, 0x1e, 0x78, 0x78, 0x3c, 0x7c, 0x3c,
2835 0xc0, 0x07, 0x1e, 0x3e, 0x0f, 0x00, 0x00, 0x00, 0x1e, 0x78, 0x78, 0x3c,
2836 0x7c, 0x7c, 0xc0, 0x0f, 0x1e, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x78,
2837 0x78, 0x3c, 0xfc, 0x7c, 0x80, 0x7f, 0x1e, 0x7c, 0x00, 0x00, 0x00, 0x00,
2838 0x1e, 0xf8, 0x78, 0x7c, 0xf8, 0xff, 0x00, 0xff, 0x1f, 0xf8, 0xff, 0x00,
2839 0x00, 0x00, 0x1e, 0xf8, 0x78, 0x7c, 0xf0, 0xff, 0x07, 0xfe, 0x1f, 0xf8,
2840 0xff, 0x00, 0x00, 0x00, 0x1e, 0xf8, 0x78, 0x7c, 0xf0, 0xff, 0x07, 0xf8,
2841 0x1f, 0xf0, 0xff, 0x01, 0x00, 0x00, 0x1e, 0xf8, 0x78, 0x7c, 0xc0, 0xef,
2842 0x07, 0xe0, 0x1f, 0xc0, 0xff, 0x01, 0x00, 0x00, 0x1e, 0x70, 0x40, 0x78,
2843 0x00, 0xc7, 0x07, 0x00, 0x1e, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x1e, 0x00,
2844 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00,
2845 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00,
2846 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00,
2847 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
2848 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2849 0x00, 0xc0, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2850 0x00, 0x00, 0x00, 0xe0, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2851 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00,
2852 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x01, 0x00, 0x00, 0x00,
2853 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x00, 0x00,
2854 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78,
2855 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2856 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x02, 0x00,
2857 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x07,
2858 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2859 0xc0, 0x0f, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2860 0x60, 0x00, 0xc0, 0x0f, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2861 0x00, 0x00, 0x78, 0x00, 0xc0, 0x8f, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00,
2862 0x00, 0x00, 0x00, 0x00, 0x78, 0x00, 0xc0, 0x8f, 0x3f, 0x00, 0x00, 0x00,
2863 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x00, 0xe0, 0x9f, 0x7f, 0x00,
2864 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x00, 0xe0, 0xdf,
2865 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x78, 0x00,
2866 0xe0, 0xdf, 0x7b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x0c,
2867 0x78, 0x30, 0xf0, 0xff, 0x7b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e,
2868 0x00, 0x0f, 0xf8, 0x70, 0xf0, 0xff, 0x7b, 0x00, 0x00, 0x1f, 0x00, 0xe0,
2869 0x0f, 0x1e, 0x80, 0x0f, 0xf8, 0x78, 0xf0, 0xfd, 0xf9, 0x00, 0xc0, 0x1f,
2870 0x00, 0xf8, 0x0f, 0x00, 0xe0, 0x1f, 0xf8, 0x7c, 0xf0, 0xfc, 0xf9, 0x00,
2871 0xf0, 0x1f, 0x00, 0xfe, 0x0f, 0x00, 0xf0, 0x07, 0xf8, 0x3e, 0xf8, 0xfc,
2872 0xf0, 0x01, 0xf8, 0x1f, 0x00, 0xff, 0x0f, 0x1e, 0xf0, 0x03, 0xf8, 0x3f,
2873 0xf8, 0xf8, 0xf0, 0x01, 0xfc, 0x1f, 0x80, 0x7f, 0x0f, 0x1e, 0xf8, 0x00,
2874 0xf8, 0x1f, 0x78, 0x18, 0xf0, 0x01, 0x7c, 0x1e, 0xc0, 0x0f, 0x0f, 0x1e,
2875 0x7c, 0x00, 0xf0, 0x0f, 0x78, 0x00, 0xf0, 0x01, 0x3e, 0x1e, 0xe0, 0x07,
2876 0x0f, 0x1e, 0x7c, 0x00, 0xf0, 0x07, 0x7c, 0x00, 0xe0, 0x01, 0x3e, 0x1e,
2877 0xe0, 0x03, 0x0f, 0x1e, 0x3e, 0x00, 0xf0, 0x0f, 0x7c, 0x00, 0xe0, 0x03,
2878 0x3e, 0x3e, 0xe0, 0x07, 0x0f, 0x1e, 0x1e, 0x00, 0xf0, 0x1f, 0x3c, 0x00,
2879 0xe0, 0x03, 0x7e, 0x3e, 0xc0, 0x3f, 0x0f, 0x1e, 0x3e, 0x00, 0xf0, 0x1f,
2880 0x3e, 0x00, 0xe0, 0x03, 0xfc, 0x7f, 0x80, 0xff, 0x0f, 0x1e, 0xfc, 0x00,
2881 0xf0, 0x3e, 0x3e, 0x00, 0xc0, 0x03, 0xf8, 0xff, 0x03, 0xff, 0x0f, 0x1e,
2882 0xfc, 0x07, 0xf0, 0x7c, 0x1e, 0x00, 0xc0, 0x03, 0xf8, 0xff, 0x03, 0xfc,
2883 0x0f, 0x1e, 0xf8, 0x1f, 0xf0, 0xf8, 0x1e, 0x00, 0xc0, 0x03, 0xe0, 0xf7,
2884 0x03, 0xf0, 0x0f, 0x1e, 0xe0, 0x3f, 0xf0, 0x78, 0x1c, 0x00, 0x80, 0x03,
2885 0x80, 0xe3, 0x03, 0x00, 0x0f, 0x1e, 0xc0, 0x3f, 0xf0, 0x30, 0x00, 0x00,
2886 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x0e, 0x00, 0x3e, 0x00, 0x00,
2887 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x0f, 0x00, 0x00, 0x10,
2888 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x0f, 0x00,
2889 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
2890 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2891 0x00, 0xe0, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2892 0x00, 0x00, 0x00, 0xf0, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2893 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
2894 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x00, 0x00,
2895 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00,
2896 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c,
2897 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2898 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
2899 };
2900
2901 int
2902 id,
2903 y;
2904
2905 register int
2906 i;
2907
2908 static unsigned int
2909 number_selections;
2910
2911 unsigned int
2912 height;
2913
cristybb503372010-05-27 20:51:26 +00002914 size_t
cristy3ed852e2009-09-05 21:47:34 +00002915 state;
2916
2917 XFontStruct
2918 *font_info;
2919
2920 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
2921 assert(display != (Display *) NULL);
2922 assert(windows != (XWindows *) NULL);
2923 font_info=windows->command.font_info;
2924 height=(unsigned int) (font_info->ascent+font_info->descent);
2925 id=(~0);
2926 state=DefaultState;
2927 if (event == (XEvent *) NULL)
2928 {
2929 unsigned int
2930 width;
2931
2932 XTextProperty
2933 window_name;
2934
2935 XWindowChanges
2936 window_changes;
2937
2938 /*
2939 Determine command window attributes.
2940 */
2941 assert(selections != (const char **) NULL);
2942 windows->command.width=0;
2943 for (i=0; selections[i] != (char *) NULL; i++)
2944 {
2945 width=WidgetTextWidth(font_info,(char *) selections[i]);
2946 if (width > windows->command.width)
2947 windows->command.width=width;
2948 }
2949 number_selections=(unsigned int) i;
2950 windows->command.width+=3*QuantumMargin+10;
2951 if ((int) windows->command.width < (tile_width+QuantumMargin+10))
2952 windows->command.width=(unsigned int) (tile_width+QuantumMargin+10);
2953 windows->command.height=(unsigned int) (number_selections*
2954 (((3*height) >> 1)+10)+tile_height+20);
2955 windows->command.min_width=windows->command.width;
2956 windows->command.min_height=windows->command.height;
2957 XConstrainWindowPosition(display,&windows->command);
2958 if (windows->command.id != (Window) NULL)
2959 {
2960 Status
2961 status;
2962
2963 /*
2964 Reconfigure command window.
2965 */
2966 status=XStringListToTextProperty(&windows->command.name,1,
2967 &window_name);
2968 if (status != False)
2969 {
2970 XSetWMName(display,windows->command.id,&window_name);
2971 XSetWMIconName(display,windows->command.id,&window_name);
2972 (void) XFree((void *) window_name.value);
2973 }
2974 window_changes.width=(int) windows->command.width;
2975 window_changes.height=(int) windows->command.height;
2976 (void) XReconfigureWMWindow(display,windows->command.id,
2977 windows->command.screen,(unsigned int) (CWWidth | CWHeight),
2978 &window_changes);
2979 }
2980 /*
2981 Allocate selection info memory.
2982 */
2983 if (selection_info != (XWidgetInfo *) NULL)
2984 selection_info=(XWidgetInfo *) RelinquishMagickMemory(selection_info);
2985 selection_info=(XWidgetInfo *) AcquireQuantumMemory(number_selections,
2986 sizeof(*selection_info));
2987 if (selection_info == (XWidgetInfo *) NULL)
2988 {
2989 ThrowXWindowFatalException(ResourceLimitError,
2990 "MemoryAllocationFailed","...");
2991 return(id);
2992 }
2993 state|=UpdateConfigurationState | RedrawWidgetState;
2994 }
2995 /*
2996 Wait for next event.
2997 */
2998 if (event != (XEvent *) NULL)
2999 switch (event->type)
3000 {
3001 case ButtonPress:
3002 {
3003 for (i=0; i < (int) number_selections; i++)
3004 {
3005 if (MatteIsActive(selection_info[i],event->xbutton) == MagickFalse)
3006 continue;
3007 if (i >= (int) windows->command.data)
3008 {
3009 selection_info[i].raised=MagickFalse;
3010 XDrawBeveledButton(display,&windows->command,&selection_info[i]);
3011 break;
3012 }
3013 submenu_info=selection_info[i];
3014 submenu_info.active=MagickTrue;
3015 toggle_info.y=
3016 submenu_info.y+(submenu_info.height >> 1)-(toggle_info.height >> 1);
3017 id=i;
3018 (void) XCheckWindowEvent(display,windows->widget.id,LeaveWindowMask,
3019 event);
3020 break;
3021 }
3022 break;
3023 }
3024 case ButtonRelease:
3025 {
3026 for (i=0; i < (int) number_selections; i++)
3027 {
3028 if (MatteIsActive(selection_info[i],event->xbutton) == MagickFalse)
3029 continue;
3030 id=i;
3031 if (id >= (int) windows->command.data)
3032 {
3033 selection_info[id].raised=MagickTrue;
3034 XDrawBeveledButton(display,&windows->command,&selection_info[id]);
3035 break;
3036 }
3037 break;
3038 }
3039 break;
3040 }
3041 case ClientMessage:
3042 {
3043 /*
3044 If client window delete message, withdraw command widget.
3045 */
3046 if (event->xclient.message_type != windows->wm_protocols)
3047 break;
3048 if (*event->xclient.data.l != (int) windows->wm_delete_window)
3049 break;
3050 (void) XWithdrawWindow(display,windows->command.id,
3051 windows->command.screen);
3052 break;
3053 }
3054 case ConfigureNotify:
3055 {
3056 /*
3057 Update widget configuration.
3058 */
3059 if (event->xconfigure.window != windows->command.id)
3060 break;
3061 if (event->xconfigure.send_event != 0)
3062 {
3063 windows->command.x=event->xconfigure.x;
3064 windows->command.y=event->xconfigure.y;
3065 }
3066 if ((event->xconfigure.width == (int) windows->command.width) &&
3067 (event->xconfigure.height == (int) windows->command.height))
3068 break;
3069 windows->command.width=(unsigned int)
3070 MagickMax(event->xconfigure.width,(int) windows->command.min_width);
3071 windows->command.height=(unsigned int)
3072 MagickMax(event->xconfigure.height,(int) windows->command.min_height);
3073 state|=UpdateConfigurationState;
3074 break;
3075 }
3076 case Expose:
3077 {
3078 if (event->xexpose.window != windows->command.id)
3079 break;
3080 if (event->xexpose.count != 0)
3081 break;
3082 state|=RedrawWidgetState;
3083 break;
3084 }
3085 case MotionNotify:
3086 {
3087 /*
3088 Return the ID of the highlighted menu entry.
3089 */
3090 for ( ; ; )
3091 {
3092 for (i=0; i < (int) number_selections; i++)
3093 {
3094 if (i >= (int) windows->command.data)
3095 {
3096 if (selection_info[i].raised ==
3097 MatteIsActive(selection_info[i],event->xmotion))
3098 {
3099 /*
3100 Button status changed.
3101 */
3102 selection_info[i].raised=!selection_info[i].raised;
3103 XDrawBeveledButton(display,&windows->command,
3104 &selection_info[i]);
3105 }
3106 continue;
3107 }
3108 if (MatteIsActive(selection_info[i],event->xmotion) == MagickFalse)
3109 continue;
3110 submenu_info=selection_info[i];
3111 submenu_info.active=MagickTrue;
3112 toggle_info.raised=MagickTrue;
3113 toggle_info.y=submenu_info.y+(submenu_info.height >> 1)-
3114 (toggle_info.height >> 1);
3115 XDrawTriangleEast(display,&windows->command,&toggle_info);
3116 id=i;
3117 }
3118 XDelay(display,SuspendTime);
3119 if (XCheckMaskEvent(display,ButtonMotionMask,event) == MagickFalse)
3120 break;
3121 while (XCheckMaskEvent(display,ButtonMotionMask,event)) ;
3122 toggle_info.raised=MagickFalse;
3123 if (windows->command.data != 0)
3124 XDrawTriangleEast(display,&windows->command,&toggle_info);
3125 }
3126 break;
3127 }
3128 case MapNotify:
3129 {
3130 windows->command.mapped=MagickTrue;
3131 break;
3132 }
3133 case UnmapNotify:
3134 {
3135 windows->command.mapped=MagickFalse;
3136 break;
3137 }
3138 default:
3139 break;
3140 }
3141 if (state & UpdateConfigurationState)
3142 {
3143 /*
3144 Initialize button information.
3145 */
3146 assert(selections != (const char **) NULL);
3147 y=tile_height+20;
3148 for (i=0; i < (int) number_selections; i++)
3149 {
3150 XGetWidgetInfo(selections[i],&selection_info[i]);
3151 selection_info[i].center=MagickFalse;
3152 selection_info[i].bevel_width--;
3153 selection_info[i].height=(unsigned int) ((3*height) >> 1);
3154 selection_info[i].x=(QuantumMargin >> 1)+4;
3155 selection_info[i].width=(unsigned int)
3156 (windows->command.width-(selection_info[i].x << 1));
3157 selection_info[i].y=y;
3158 y+=selection_info[i].height+(selection_info[i].bevel_width << 1)+6;
3159 }
3160 XGetWidgetInfo((char *) NULL,&toggle_info);
3161 toggle_info.bevel_width--;
3162 toggle_info.width=(unsigned int)
3163 (((5*height) >> 3)-(toggle_info.bevel_width << 1));
3164 toggle_info.height=toggle_info.width;
3165 toggle_info.x=selection_info[0].x+selection_info[0].width-
3166 toggle_info.width-(QuantumMargin >> 1);
3167 if (windows->command.mapped)
3168 (void) XClearWindow(display,windows->command.id);
3169 }
3170 if (state & RedrawWidgetState)
3171 {
3172 Pixmap
3173 tile_pixmap;
3174
3175 /*
3176 Draw command buttons.
3177 */
3178 tile_pixmap=XCreatePixmapFromBitmapData(display,windows->command.id,
3179 (char *) tile_bits,tile_width,tile_height,1L,0L,1);
3180 if (tile_pixmap != (Pixmap) NULL)
3181 {
3182 (void) XCopyPlane(display,tile_pixmap,windows->command.id,
3183 windows->command.annotate_context,0,0,tile_width,tile_height,
3184 (int) ((windows->command.width-tile_width) >> 1),10,1L);
3185 (void) XFreePixmap(display,tile_pixmap);
3186 }
3187 for (i=0; i < (int) number_selections; i++)
3188 {
3189 XDrawBeveledButton(display,&windows->command,&selection_info[i]);
3190 if (i >= (int) windows->command.data)
3191 continue;
3192 toggle_info.raised=i == id ? MagickTrue : MagickFalse;
3193 toggle_info.y=selection_info[i].y+
3194 (selection_info[i].height >> 1)-(toggle_info.height >> 1);
3195 XDrawTriangleEast(display,&windows->command,&toggle_info);
3196 }
3197 XHighlightWidget(display,&windows->command,BorderOffset,BorderOffset);
3198 }
3199 return(id);
3200}
3201
3202/*
3203%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3204% %
3205% %
3206% %
3207% X C o n f i r m W i d g e t %
3208% %
3209% %
3210% %
3211%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3212%
3213% XConfirmWidget() displays a Confirm widget with a notice to the user. The
3214% function returns -1 if Dismiss is pressed, 0 for Cancel, and 1 for Yes.
3215%
3216% The format of the XConfirmWidget method is:
3217%
3218% int XConfirmWidget(Display *display,XWindows *windows,
3219% const char *reason,const char *description)
3220%
3221% A description of each parameter follows:
3222%
3223% o display: Specifies a connection to an X server; returned from
3224% XOpenDisplay.
3225%
3226% o window: Specifies a pointer to a XWindows structure.
3227%
3228% o reason: Specifies the message to display before terminating the
3229% program.
3230%
3231% o description: Specifies any description to the message.
3232%
3233*/
3234MagickExport int XConfirmWidget(Display *display,XWindows *windows,
3235 const char *reason,const char *description)
3236{
3237#define CancelButtonText "Cancel"
3238#define DismissButtonText "Dismiss"
3239#define YesButtonText "Yes"
3240
3241 int
3242 confirm,
3243 x,
3244 y;
3245
3246 Status
3247 status;
3248
3249 unsigned int
3250 height,
3251 width;
3252
cristybb503372010-05-27 20:51:26 +00003253 size_t
cristy3ed852e2009-09-05 21:47:34 +00003254 state;
3255
3256 XEvent
3257 event;
3258
3259 XFontStruct
3260 *font_info;
3261
3262 XTextProperty
3263 window_name;
3264
3265 XWidgetInfo
3266 cancel_info,
3267 dismiss_info,
3268 yes_info;
3269
3270 XWindowChanges
3271 window_changes;
3272
3273 /*
3274 Determine Confirm widget attributes.
3275 */
3276 assert(display != (Display *) NULL);
3277 assert(windows != (XWindows *) NULL);
3278 assert(reason != (char *) NULL);
3279 assert(description != (char *) NULL);
3280 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",reason);
3281 XCheckRefreshWindows(display,windows);
3282 font_info=windows->widget.font_info;
3283 width=WidgetTextWidth(font_info,CancelButtonText);
3284 if (WidgetTextWidth(font_info,DismissButtonText) > width)
3285 width=WidgetTextWidth(font_info,DismissButtonText);
3286 if (WidgetTextWidth(font_info,YesButtonText) > width)
3287 width=WidgetTextWidth(font_info,YesButtonText);
3288 width<<=1;
3289 if (description != (char *) NULL)
3290 if (WidgetTextWidth(font_info,(char *) description) > width)
3291 width=WidgetTextWidth(font_info,(char *) description);
3292 height=(unsigned int) (font_info->ascent+font_info->descent);
3293 /*
3294 Position Confirm widget.
3295 */
3296 windows->widget.width=(unsigned int) (width+9*QuantumMargin);
3297 windows->widget.min_width=(unsigned int) (9*QuantumMargin+
3298 WidgetTextWidth(font_info,CancelButtonText)+
3299 WidgetTextWidth(font_info,DismissButtonText)+
3300 WidgetTextWidth(font_info,YesButtonText));
3301 if (windows->widget.width < windows->widget.min_width)
3302 windows->widget.width=windows->widget.min_width;
3303 windows->widget.height=(unsigned int) (12*height);
3304 windows->widget.min_height=(unsigned int) (7*height);
3305 if (windows->widget.height < windows->widget.min_height)
3306 windows->widget.height=windows->widget.min_height;
3307 XConstrainWindowPosition(display,&windows->widget);
3308 /*
3309 Map Confirm widget.
3310 */
3311 (void) CopyMagickString(windows->widget.name,"Confirm",MaxTextExtent);
3312 status=XStringListToTextProperty(&windows->widget.name,1,&window_name);
3313 if (status != False)
3314 {
3315 XSetWMName(display,windows->widget.id,&window_name);
3316 XSetWMIconName(display,windows->widget.id,&window_name);
3317 (void) XFree((void *) window_name.value);
3318 }
3319 window_changes.width=(int) windows->widget.width;
3320 window_changes.height=(int) windows->widget.height;
3321 window_changes.x=windows->widget.x;
3322 window_changes.y=windows->widget.y;
3323 (void) XReconfigureWMWindow(display,windows->widget.id,windows->widget.screen,
3324 (unsigned int) (CWWidth | CWHeight | CWX | CWY),&window_changes);
3325 (void) XMapRaised(display,windows->widget.id);
3326 windows->widget.mapped=MagickFalse;
3327 /*
3328 Respond to X events.
3329 */
3330 confirm=0;
3331 state=UpdateConfigurationState;
3332 XSetCursorState(display,windows,MagickTrue);
3333 do
3334 {
3335 if (state & UpdateConfigurationState)
3336 {
3337 /*
3338 Initialize button information.
3339 */
3340 XGetWidgetInfo(CancelButtonText,&cancel_info);
3341 cancel_info.width=(unsigned int) QuantumMargin+
3342 WidgetTextWidth(font_info,CancelButtonText);
3343 cancel_info.height=(unsigned int) ((3*height) >> 1);
3344 cancel_info.x=(int) (windows->widget.width-cancel_info.width-
3345 QuantumMargin);
3346 cancel_info.y=(int) (windows->widget.height-(cancel_info.height << 1));
3347 dismiss_info=cancel_info;
3348 dismiss_info.text=(char *) DismissButtonText;
3349 if (LocaleCompare(description,"Do you want to save it") == 0)
3350 dismiss_info.text=(char *) "Don't Save";
3351 dismiss_info.width=(unsigned int) QuantumMargin+
3352 WidgetTextWidth(font_info,dismiss_info.text);
3353 dismiss_info.x=(int)
3354 ((windows->widget.width >> 1)-(dismiss_info.width >> 1));
3355 yes_info=cancel_info;
3356 yes_info.text=(char *) YesButtonText;
3357 if (LocaleCompare(description,"Do you want to save it") == 0)
3358 yes_info.text=(char *) "Save";
3359 yes_info.width=(unsigned int) QuantumMargin+
3360 WidgetTextWidth(font_info,yes_info.text);
3361 if (yes_info.width < cancel_info.width)
3362 yes_info.width=cancel_info.width;
3363 yes_info.x=QuantumMargin;
3364 state&=(~UpdateConfigurationState);
3365 }
3366 if (state & RedrawWidgetState)
3367 {
3368 /*
3369 Redraw Confirm widget.
3370 */
3371 width=WidgetTextWidth(font_info,(char *) reason);
3372 x=(int) ((windows->widget.width >> 1)-(width >> 1));
3373 y=(int) ((windows->widget.height >> 1)-(height << 1));
3374 (void) XDrawString(display,windows->widget.id,
3375 windows->widget.annotate_context,x,y,(char *) reason,Extent(reason));
3376 if (description != (char *) NULL)
3377 {
3378 char
3379 question[MaxTextExtent];
3380
3381 (void) CopyMagickString(question,description,MaxTextExtent);
3382 (void) ConcatenateMagickString(question,"?",MaxTextExtent);
3383 width=WidgetTextWidth(font_info,question);
3384 x=(int) ((windows->widget.width >> 1)-(width >> 1));
3385 y+=height;
3386 (void) XDrawString(display,windows->widget.id,
3387 windows->widget.annotate_context,x,y,question,Extent(question));
3388 }
3389 XDrawBeveledButton(display,&windows->widget,&cancel_info);
3390 XDrawBeveledButton(display,&windows->widget,&dismiss_info);
3391 XDrawBeveledButton(display,&windows->widget,&yes_info);
3392 XHighlightWidget(display,&windows->widget,BorderOffset,BorderOffset);
3393 state&=(~RedrawWidgetState);
3394 }
3395 /*
3396 Wait for next event.
3397 */
3398 (void) XIfEvent(display,&event,XScreenEvent,(char *) windows);
3399 switch (event.type)
3400 {
3401 case ButtonPress:
3402 {
3403 if (MatteIsActive(cancel_info,event.xbutton))
3404 {
3405 /*
3406 User pressed No button.
3407 */
3408 cancel_info.raised=MagickFalse;
3409 XDrawBeveledButton(display,&windows->widget,&cancel_info);
3410 break;
3411 }
3412 if (MatteIsActive(dismiss_info,event.xbutton))
3413 {
3414 /*
3415 User pressed Dismiss button.
3416 */
3417 dismiss_info.raised=MagickFalse;
3418 XDrawBeveledButton(display,&windows->widget,&dismiss_info);
3419 break;
3420 }
3421 if (MatteIsActive(yes_info,event.xbutton))
3422 {
3423 /*
3424 User pressed Yes button.
3425 */
3426 yes_info.raised=MagickFalse;
3427 XDrawBeveledButton(display,&windows->widget,&yes_info);
3428 break;
3429 }
3430 break;
3431 }
3432 case ButtonRelease:
3433 {
3434 if (windows->widget.mapped == MagickFalse)
3435 break;
3436 if (cancel_info.raised == MagickFalse)
3437 {
3438 if (event.xbutton.window == windows->widget.id)
3439 if (MatteIsActive(cancel_info,event.xbutton))
3440 {
3441 confirm=0;
3442 state|=ExitState;
3443 }
3444 cancel_info.raised=MagickTrue;
3445 XDrawBeveledButton(display,&windows->widget,&cancel_info);
3446 }
3447 if (dismiss_info.raised == MagickFalse)
3448 {
3449 if (event.xbutton.window == windows->widget.id)
3450 if (MatteIsActive(dismiss_info,event.xbutton))
3451 {
3452 confirm=(-1);
3453 state|=ExitState;
3454 }
3455 dismiss_info.raised=MagickTrue;
3456 XDrawBeveledButton(display,&windows->widget,&dismiss_info);
3457 }
3458 if (yes_info.raised == MagickFalse)
3459 {
3460 if (event.xbutton.window == windows->widget.id)
3461 if (MatteIsActive(yes_info,event.xbutton))
3462 {
3463 confirm=1;
3464 state|=ExitState;
3465 }
3466 yes_info.raised=MagickTrue;
3467 XDrawBeveledButton(display,&windows->widget,&yes_info);
3468 }
3469 break;
3470 }
3471 case ClientMessage:
3472 {
3473 /*
3474 If client window delete message, exit.
3475 */
3476 if (event.xclient.message_type != windows->wm_protocols)
3477 break;
3478 if (*event.xclient.data.l == (int) windows->wm_take_focus)
3479 {
3480 (void) XSetInputFocus(display,event.xclient.window,RevertToParent,
3481 (Time) event.xclient.data.l[1]);
3482 break;
3483 }
3484 if (*event.xclient.data.l != (int) windows->wm_delete_window)
3485 break;
3486 if (event.xclient.window == windows->widget.id)
3487 {
3488 state|=ExitState;
3489 break;
3490 }
3491 break;
3492 }
3493 case ConfigureNotify:
3494 {
3495 /*
3496 Update widget configuration.
3497 */
3498 if (event.xconfigure.window != windows->widget.id)
3499 break;
3500 if ((event.xconfigure.width == (int) windows->widget.width) &&
3501 (event.xconfigure.height == (int) windows->widget.height))
3502 break;
3503 windows->widget.width=(unsigned int)
3504 MagickMax(event.xconfigure.width,(int) windows->widget.min_width);
3505 windows->widget.height=(unsigned int)
3506 MagickMax(event.xconfigure.height,(int) windows->widget.min_height);
3507 state|=UpdateConfigurationState;
3508 break;
3509 }
3510 case EnterNotify:
3511 {
3512 if (event.xcrossing.window != windows->widget.id)
3513 break;
3514 state&=(~InactiveWidgetState);
3515 break;
3516 }
3517 case Expose:
3518 {
3519 if (event.xexpose.window != windows->widget.id)
3520 break;
3521 if (event.xexpose.count != 0)
3522 break;
3523 state|=RedrawWidgetState;
3524 break;
3525 }
3526 case KeyPress:
3527 {
3528 static char
3529 command[MaxTextExtent];
3530
3531 static KeySym
3532 key_symbol;
3533
3534 /*
3535 Respond to a user key press.
3536 */
3537 if (event.xkey.window != windows->widget.id)
3538 break;
3539 (void) XLookupString((XKeyEvent *) &event.xkey,command,
3540 (int) sizeof(command),&key_symbol,(XComposeStatus *) NULL);
3541 if ((key_symbol == XK_Return) || (key_symbol == XK_KP_Enter))
3542 {
3543 yes_info.raised=MagickFalse;
3544 XDrawBeveledButton(display,&windows->widget,&yes_info);
3545 confirm=1;
3546 state|=ExitState;
3547 break;
3548 }
3549 break;
3550 }
3551 case LeaveNotify:
3552 {
3553 if (event.xcrossing.window != windows->widget.id)
3554 break;
3555 state|=InactiveWidgetState;
3556 break;
3557 }
3558 case MotionNotify:
3559 {
3560 /*
3561 Discard pending button motion events.
3562 */
3563 while (XCheckMaskEvent(display,ButtonMotionMask,&event)) ;
3564 if (state & InactiveWidgetState)
3565 break;
3566 if (cancel_info.raised == MatteIsActive(cancel_info,event.xmotion))
3567 {
3568 /*
3569 Cancel button status changed.
3570 */
3571 cancel_info.raised=cancel_info.raised == MagickFalse ?
3572 MagickTrue : MagickFalse;
3573 XDrawBeveledButton(display,&windows->widget,&cancel_info);
3574 break;
3575 }
3576 if (dismiss_info.raised == MatteIsActive(dismiss_info,event.xmotion))
3577 {
3578 /*
3579 Dismiss button status changed.
3580 */
3581 dismiss_info.raised=cancel_info.raised == MagickFalse ?
3582 MagickTrue : MagickFalse;
3583 XDrawBeveledButton(display,&windows->widget,&dismiss_info);
3584 break;
3585 }
3586 if (yes_info.raised == MatteIsActive(yes_info,event.xmotion))
3587 {
3588 /*
3589 Yes button status changed.
3590 */
3591 yes_info.raised=yes_info.raised == MagickFalse ?
3592 MagickTrue : MagickFalse;
3593 XDrawBeveledButton(display,&windows->widget,&yes_info);
3594 break;
3595 }
3596 break;
3597 }
3598 default:
3599 break;
3600 }
3601 } while ((state & ExitState) == 0);
3602 XSetCursorState(display,windows,MagickFalse);
3603 (void) XWithdrawWindow(display,windows->widget.id,windows->widget.screen);
3604 XCheckRefreshWindows(display,windows);
3605 return(confirm);
3606}
3607
3608/*
3609%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3610% %
3611% %
3612% %
3613% X D i a l o g W i d g e t %
3614% %
3615% %
3616% %
3617%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3618%
3619% XDialogWidget() displays a Dialog widget with a query to the user. The user
3620% keys a reply and presses the Ok or Cancel button to exit. The typed text is
3621% returned as the reply function parameter.
3622%
3623% The format of the XDialogWidget method is:
3624%
3625% int XDialogWidget(Display *display,XWindows *windows,const char *action,
3626% const char *query,char *reply)
3627%
3628% A description of each parameter follows:
3629%
3630% o display: Specifies a connection to an X server; returned from
3631% XOpenDisplay.
3632%
3633% o window: Specifies a pointer to a XWindows structure.
3634%
3635% o action: Specifies a pointer to the action of this widget.
3636%
3637% o query: Specifies a pointer to the query to present to the user.
3638%
3639% o reply: the response from the user is returned in this parameter.
3640%
3641*/
3642MagickExport int XDialogWidget(Display *display,XWindows *windows,
3643 const char *action,const char *query,char *reply)
3644{
3645#define CancelButtonText "Cancel"
3646
3647 char
3648 primary_selection[MaxTextExtent];
3649
3650 int
3651 x;
3652
3653 register int
3654 i;
3655
3656 static MagickBooleanType
3657 raised = MagickFalse;
3658
3659 Status
3660 status;
3661
3662 unsigned int
3663 anomaly,
3664 height,
3665 width;
3666
cristybb503372010-05-27 20:51:26 +00003667 size_t
cristy3ed852e2009-09-05 21:47:34 +00003668 state;
3669
3670 XEvent
3671 event;
3672
3673 XFontStruct
3674 *font_info;
3675
3676 XTextProperty
3677 window_name;
3678
3679 XWidgetInfo
3680 action_info,
3681 cancel_info,
3682 reply_info,
3683 special_info,
3684 text_info;
3685
3686 XWindowChanges
3687 window_changes;
3688
3689 /*
3690 Determine Dialog widget attributes.
3691 */
3692 assert(display != (Display *) NULL);
3693 assert(windows != (XWindows *) NULL);
3694 assert(action != (char *) NULL);
3695 assert(query != (char *) NULL);
3696 assert(reply != (char *) NULL);
3697 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",action);
3698 XCheckRefreshWindows(display,windows);
3699 font_info=windows->widget.font_info;
3700 width=WidgetTextWidth(font_info,(char *) action);
3701 if (WidgetTextWidth(font_info,CancelButtonText) > width)
3702 width=WidgetTextWidth(font_info,CancelButtonText);
3703 width+=(3*QuantumMargin) >> 1;
3704 height=(unsigned int) (font_info->ascent+font_info->descent);
3705 /*
3706 Position Dialog widget.
3707 */
3708 windows->widget.width=(unsigned int) MagickMax(2*width,(int) WidgetTextWidth(
3709 font_info,(char *) query));
3710 if (windows->widget.width < WidgetTextWidth(font_info,reply))
3711 windows->widget.width=WidgetTextWidth(font_info,reply);
3712 windows->widget.width+=6*QuantumMargin;
3713 windows->widget.min_width=(unsigned int)
3714 (width+28*XTextWidth(font_info,"#",1)+4*QuantumMargin);
3715 if (windows->widget.width < windows->widget.min_width)
3716 windows->widget.width=windows->widget.min_width;
3717 windows->widget.height=(unsigned int) (7*height+(QuantumMargin << 1));
3718 windows->widget.min_height=windows->widget.height;
3719 if (windows->widget.height < windows->widget.min_height)
3720 windows->widget.height=windows->widget.min_height;
3721 XConstrainWindowPosition(display,&windows->widget);
3722 /*
3723 Map Dialog widget.
3724 */
3725 (void) CopyMagickString(windows->widget.name,"Dialog",MaxTextExtent);
3726 status=XStringListToTextProperty(&windows->widget.name,1,&window_name);
3727 if (status != False)
3728 {
3729 XSetWMName(display,windows->widget.id,&window_name);
3730 XSetWMIconName(display,windows->widget.id,&window_name);
3731 (void) XFree((void *) window_name.value);
3732 }
3733 window_changes.width=(int) windows->widget.width;
3734 window_changes.height=(int) windows->widget.height;
3735 window_changes.x=windows->widget.x;
3736 window_changes.y=windows->widget.y;
3737 (void) XReconfigureWMWindow(display,windows->widget.id,windows->widget.screen,
3738 (unsigned int) (CWWidth | CWHeight | CWX | CWY),&window_changes);
3739 (void) XMapRaised(display,windows->widget.id);
3740 windows->widget.mapped=MagickFalse;
3741 /*
3742 Respond to X events.
3743 */
3744 anomaly=(LocaleCompare(action,"Background") == 0) ||
3745 (LocaleCompare(action,"New") == 0) ||
3746 (LocaleCompare(action,"Quantize") == 0) ||
3747 (LocaleCompare(action,"Resize") == 0) ||
3748 (LocaleCompare(action,"Save") == 0) ||
3749 (LocaleCompare(action,"Shade") == 0);
3750 state=UpdateConfigurationState;
3751 XSetCursorState(display,windows,MagickTrue);
3752 do
3753 {
3754 if (state & UpdateConfigurationState)
3755 {
3756 /*
3757 Initialize button information.
3758 */
3759 XGetWidgetInfo(CancelButtonText,&cancel_info);
3760 cancel_info.width=width;
3761 cancel_info.height=(unsigned int) ((3*height) >> 1);
3762 cancel_info.x=(int)
3763 (windows->widget.width-cancel_info.width-((3*QuantumMargin) >> 1));
3764 cancel_info.y=(int)
3765 (windows->widget.height-cancel_info.height-((3*QuantumMargin) >> 1));
3766 XGetWidgetInfo(action,&action_info);
3767 action_info.width=width;
3768 action_info.height=(unsigned int) ((3*height) >> 1);
3769 action_info.x=cancel_info.x-(cancel_info.width+QuantumMargin+
3770 (action_info.bevel_width << 1));
3771 action_info.y=cancel_info.y;
3772 /*
3773 Initialize reply information.
3774 */
3775 XGetWidgetInfo(reply,&reply_info);
3776 reply_info.raised=MagickFalse;
3777 reply_info.bevel_width--;
3778 reply_info.width=windows->widget.width-(3*QuantumMargin);
3779 reply_info.height=height << 1;
3780 reply_info.x=(3*QuantumMargin) >> 1;
3781 reply_info.y=action_info.y-reply_info.height-QuantumMargin;
3782 /*
3783 Initialize option information.
3784 */
3785 XGetWidgetInfo("Dither",&special_info);
3786 special_info.raised=raised;
3787 special_info.bevel_width--;
3788 special_info.width=(unsigned int) QuantumMargin >> 1;
3789 special_info.height=(unsigned int) QuantumMargin >> 1;
3790 special_info.x=reply_info.x;
3791 special_info.y=action_info.y+action_info.height-special_info.height;
3792 if (LocaleCompare(action,"Background") == 0)
3793 special_info.text=(char *) "Backdrop";
3794 if (LocaleCompare(action,"New") == 0)
3795 special_info.text=(char *) "Gradation";
3796 if (LocaleCompare(action,"Resize") == 0)
3797 special_info.text=(char *) "Constrain ratio";
3798 if (LocaleCompare(action,"Save") == 0)
3799 special_info.text=(char *) "Non-progressive";
3800 if (LocaleCompare(action,"Shade") == 0)
3801 special_info.text=(char *) "Color shading";
3802 /*
3803 Initialize text information.
3804 */
3805 XGetWidgetInfo(query,&text_info);
3806 text_info.width=reply_info.width;
3807 text_info.height=height;
3808 text_info.x=reply_info.x-(QuantumMargin >> 1);
3809 text_info.y=QuantumMargin;
3810 text_info.center=MagickFalse;
3811 state&=(~UpdateConfigurationState);
3812 }
3813 if (state & RedrawWidgetState)
3814 {
3815 /*
3816 Redraw Dialog widget.
3817 */
3818 XDrawWidgetText(display,&windows->widget,&text_info);
3819 XDrawBeveledMatte(display,&windows->widget,&reply_info);
3820 XDrawMatteText(display,&windows->widget,&reply_info);
3821 if (anomaly)
3822 XDrawBeveledButton(display,&windows->widget,&special_info);
3823 XDrawBeveledButton(display,&windows->widget,&action_info);
3824 XDrawBeveledButton(display,&windows->widget,&cancel_info);
3825 XHighlightWidget(display,&windows->widget,BorderOffset,BorderOffset);
3826 state&=(~RedrawWidgetState);
3827 }
3828 /*
3829 Wait for next event.
3830 */
3831 (void) XIfEvent(display,&event,XScreenEvent,(char *) windows);
3832 switch (event.type)
3833 {
3834 case ButtonPress:
3835 {
3836 if (anomaly)
3837 if (MatteIsActive(special_info,event.xbutton))
3838 {
3839 /*
3840 Option button status changed.
3841 */
3842 special_info.raised=!special_info.raised;
3843 XDrawBeveledButton(display,&windows->widget,&special_info);
3844 break;
3845 }
3846 if (MatteIsActive(action_info,event.xbutton))
3847 {
3848 /*
3849 User pressed Action button.
3850 */
3851 action_info.raised=MagickFalse;
3852 XDrawBeveledButton(display,&windows->widget,&action_info);
3853 break;
3854 }
3855 if (MatteIsActive(cancel_info,event.xbutton))
3856 {
3857 /*
3858 User pressed Cancel button.
3859 */
3860 cancel_info.raised=MagickFalse;
3861 XDrawBeveledButton(display,&windows->widget,&cancel_info);
3862 break;
3863 }
3864 if (MatteIsActive(reply_info,event.xbutton) == MagickFalse)
3865 break;
3866 if (event.xbutton.button != Button2)
3867 {
3868 static Time
3869 click_time;
3870
3871 /*
3872 Move text cursor to position of button press.
3873 */
3874 x=event.xbutton.x-reply_info.x-(QuantumMargin >> 2);
3875 for (i=1; i <= Extent(reply_info.marker); i++)
3876 if (XTextWidth(font_info,reply_info.marker,i) > x)
3877 break;
3878 reply_info.cursor=reply_info.marker+i-1;
3879 if (event.xbutton.time > (click_time+DoubleClick))
3880 reply_info.highlight=MagickFalse;
3881 else
3882 {
3883 /*
3884 Become the XA_PRIMARY selection owner.
3885 */
3886 (void) CopyMagickString(primary_selection,reply_info.text,
3887 MaxTextExtent);
3888 (void) XSetSelectionOwner(display,XA_PRIMARY,windows->widget.id,
3889 event.xbutton.time);
3890 reply_info.highlight=XGetSelectionOwner(display,XA_PRIMARY) ==
3891 windows->widget.id ? MagickTrue : MagickFalse;
3892 }
3893 XDrawMatteText(display,&windows->widget,&reply_info);
3894 click_time=event.xbutton.time;
3895 break;
3896 }
3897 /*
3898 Request primary selection.
3899 */
3900 (void) XConvertSelection(display,XA_PRIMARY,XA_STRING,XA_STRING,
3901 windows->widget.id,event.xbutton.time);
3902 break;
3903 }
3904 case ButtonRelease:
3905 {
3906 if (windows->widget.mapped == MagickFalse)
3907 break;
3908 if (action_info.raised == MagickFalse)
3909 {
3910 if (event.xbutton.window == windows->widget.id)
3911 if (MatteIsActive(action_info,event.xbutton))
3912 state|=ExitState;
3913 action_info.raised=MagickTrue;
3914 XDrawBeveledButton(display,&windows->widget,&action_info);
3915 }
3916 if (cancel_info.raised == MagickFalse)
3917 {
3918 if (event.xbutton.window == windows->widget.id)
3919 if (MatteIsActive(cancel_info,event.xbutton))
3920 {
3921 *reply_info.text='\0';
3922 state|=ExitState;
3923 }
3924 cancel_info.raised=MagickTrue;
3925 XDrawBeveledButton(display,&windows->widget,&cancel_info);
3926 }
3927 break;
3928 }
3929 case ClientMessage:
3930 {
3931 /*
3932 If client window delete message, exit.
3933 */
3934 if (event.xclient.message_type != windows->wm_protocols)
3935 break;
3936 if (*event.xclient.data.l == (int) windows->wm_take_focus)
3937 {
3938 (void) XSetInputFocus(display,event.xclient.window,RevertToParent,
3939 (Time) event.xclient.data.l[1]);
3940 break;
3941 }
3942 if (*event.xclient.data.l != (int) windows->wm_delete_window)
3943 break;
3944 if (event.xclient.window == windows->widget.id)
3945 {
3946 *reply_info.text='\0';
3947 state|=ExitState;
3948 break;
3949 }
3950 break;
3951 }
3952 case ConfigureNotify:
3953 {
3954 /*
3955 Update widget configuration.
3956 */
3957 if (event.xconfigure.window != windows->widget.id)
3958 break;
3959 if ((event.xconfigure.width == (int) windows->widget.width) &&
3960 (event.xconfigure.height == (int) windows->widget.height))
3961 break;
3962 windows->widget.width=(unsigned int)
3963 MagickMax(event.xconfigure.width,(int) windows->widget.min_width);
3964 windows->widget.height=(unsigned int)
3965 MagickMax(event.xconfigure.height,(int) windows->widget.min_height);
3966 state|=UpdateConfigurationState;
3967 break;
3968 }
3969 case EnterNotify:
3970 {
3971 if (event.xcrossing.window != windows->widget.id)
3972 break;
3973 state&=(~InactiveWidgetState);
3974 break;
3975 }
3976 case Expose:
3977 {
3978 if (event.xexpose.window != windows->widget.id)
3979 break;
3980 if (event.xexpose.count != 0)
3981 break;
3982 state|=RedrawWidgetState;
3983 break;
3984 }
3985 case KeyPress:
3986 {
3987 static char
3988 command[MaxTextExtent];
3989
3990 static int
3991 length;
3992
3993 static KeySym
3994 key_symbol;
3995
3996 /*
3997 Respond to a user key press.
3998 */
3999 if (event.xkey.window != windows->widget.id)
4000 break;
4001 length=XLookupString((XKeyEvent *) &event.xkey,command,
4002 (int) sizeof(command),&key_symbol,(XComposeStatus *) NULL);
4003 *(command+length)='\0';
4004 if ((key_symbol == XK_Return) || (key_symbol == XK_KP_Enter))
4005 {
4006 action_info.raised=MagickFalse;
4007 XDrawBeveledButton(display,&windows->widget,&action_info);
4008 state|=ExitState;
4009 break;
4010 }
4011 if (key_symbol == XK_Control_L)
4012 {
4013 state|=ControlState;
4014 break;
4015 }
4016 if (state & ControlState)
4017 switch ((int) key_symbol)
4018 {
4019 case XK_u:
4020 case XK_U:
4021 {
4022 /*
4023 Erase the entire line of text.
4024 */
4025 *reply_info.text='\0';
4026 reply_info.cursor=reply_info.text;
4027 reply_info.marker=reply_info.text;
4028 reply_info.highlight=MagickFalse;
4029 break;
4030 }
4031 default:
4032 break;
4033 }
4034 XEditText(display,&reply_info,key_symbol,command,state);
4035 XDrawMatteText(display,&windows->widget,&reply_info);
4036 break;
4037 }
4038 case KeyRelease:
4039 {
4040 static char
4041 command[MaxTextExtent];
4042
4043 static KeySym
4044 key_symbol;
4045
4046 /*
4047 Respond to a user key release.
4048 */
4049 if (event.xkey.window != windows->widget.id)
4050 break;
4051 (void) XLookupString((XKeyEvent *) &event.xkey,command,
4052 (int) sizeof(command),&key_symbol,(XComposeStatus *) NULL);
4053 if (key_symbol == XK_Control_L)
4054 state&=(~ControlState);
4055 break;
4056 }
4057 case LeaveNotify:
4058 {
4059 if (event.xcrossing.window != windows->widget.id)
4060 break;
4061 state|=InactiveWidgetState;
4062 break;
4063 }
4064 case MotionNotify:
4065 {
4066 /*
4067 Discard pending button motion events.
4068 */
4069 while (XCheckMaskEvent(display,ButtonMotionMask,&event)) ;
4070 if (state & InactiveWidgetState)
4071 break;
4072 if (action_info.raised == MatteIsActive(action_info,event.xmotion))
4073 {
4074 /*
4075 Action button status changed.
4076 */
4077 action_info.raised=action_info.raised == MagickFalse ?
4078 MagickTrue : MagickFalse;
4079 XDrawBeveledButton(display,&windows->widget,&action_info);
4080 break;
4081 }
4082 if (cancel_info.raised == MatteIsActive(cancel_info,event.xmotion))
4083 {
4084 /*
4085 Cancel button status changed.
4086 */
4087 cancel_info.raised=cancel_info.raised == MagickFalse ?
4088 MagickTrue : MagickFalse;
4089 XDrawBeveledButton(display,&windows->widget,&cancel_info);
4090 break;
4091 }
4092 break;
4093 }
4094 case SelectionClear:
4095 {
4096 reply_info.highlight=MagickFalse;
4097 XDrawMatteText(display,&windows->widget,&reply_info);
4098 break;
4099 }
4100 case SelectionNotify:
4101 {
4102 Atom
4103 type;
4104
4105 int
4106 format;
4107
4108 unsigned char
4109 *data;
4110
cristyf2faecf2010-05-28 19:19:36 +00004111 unsigned long
cristy3ed852e2009-09-05 21:47:34 +00004112 after,
4113 length;
4114
4115 /*
4116 Obtain response from primary selection.
4117 */
4118 if (event.xselection.property == (Atom) None)
4119 break;
4120 status=XGetWindowProperty(display,event.xselection.requestor,
4121 event.xselection.property,0L,2047L,MagickTrue,XA_STRING,&type,
4122 &format,&length,&after,&data);
4123 if ((status != Success) || (type != XA_STRING) || (format == 32) ||
4124 (length == 0))
4125 break;
4126 if ((Extent(reply_info.text)+length) >= MaxTextExtent)
4127 (void) XBell(display,0);
4128 else
4129 {
4130 /*
4131 Insert primary selection in reply text.
4132 */
4133 *(data+length)='\0';
4134 XEditText(display,&reply_info,(KeySym) XK_Insert,(char *) data,
4135 state);
4136 XDrawMatteText(display,&windows->widget,&reply_info);
4137 }
4138 (void) XFree((void *) data);
4139 break;
4140 }
4141 case SelectionRequest:
4142 {
4143 XSelectionEvent
4144 notify;
4145
4146 XSelectionRequestEvent
4147 *request;
4148
4149 if (reply_info.highlight == MagickFalse)
4150 break;
4151 /*
4152 Set primary selection.
4153 */
4154 request=(&(event.xselectionrequest));
4155 (void) XChangeProperty(request->display,request->requestor,
4156 request->property,request->target,8,PropModeReplace,
4157 (unsigned char *) primary_selection,Extent(primary_selection));
4158 notify.type=SelectionNotify;
4159 notify.display=request->display;
4160 notify.requestor=request->requestor;
4161 notify.selection=request->selection;
4162 notify.target=request->target;
4163 notify.time=request->time;
4164 if (request->property == None)
4165 notify.property=request->target;
4166 else
4167 notify.property=request->property;
4168 (void) XSendEvent(request->display,request->requestor,False,0,
4169 (XEvent *) &notify);
4170 }
4171 default:
4172 break;
4173 }
4174 } while ((state & ExitState) == 0);
4175 XSetCursorState(display,windows,MagickFalse);
4176 (void) XWithdrawWindow(display,windows->widget.id,windows->widget.screen);
4177 XCheckRefreshWindows(display,windows);
4178 if (anomaly)
4179 if (special_info.raised)
4180 if (*reply != '\0')
4181 raised=MagickTrue;
4182 return(raised == MagickFalse);
4183}
4184
4185/*
4186%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4187% %
4188% %
4189% %
4190% X F i l e B r o w s e r W i d g e t %
4191% %
4192% %
4193% %
4194%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4195%
4196% XFileBrowserWidget() displays a File Browser widget with a file query to the
4197% user. The user keys a reply and presses the Action or Cancel button to
4198% exit. The typed text is returned as the reply function parameter.
4199%
4200% The format of the XFileBrowserWidget method is:
4201%
4202% void XFileBrowserWidget(Display *display,XWindows *windows,
4203% const char *action,char *reply)
4204%
4205% A description of each parameter follows:
4206%
4207% o display: Specifies a connection to an X server; returned from
4208% XOpenDisplay.
4209%
4210% o window: Specifies a pointer to a XWindows structure.
4211%
4212% o action: Specifies a pointer to the action of this widget.
4213%
4214% o reply: the response from the user is returned in this parameter.
4215%
4216*/
4217MagickExport void XFileBrowserWidget(Display *display,XWindows *windows,
4218 const char *action,char *reply)
4219{
4220#define CancelButtonText "Cancel"
4221#define DirectoryText "Directory:"
4222#define FilenameText "File name:"
4223#define GrabButtonText "Grab"
4224#define FormatButtonText "Format"
4225#define HomeButtonText "Home"
4226#define UpButtonText "Up"
4227
4228 char
4229 *cwd,
4230 **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);
4303 cwd=getcwd(home_directory,MaxTextExtent);
4304 (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 {
4633 list_info.id=LocaleCompare(filelist[i],reply) == 0 ? i : ~0;
4634 break;
4635 }
4636 if ((i < slider_info.id) || (i >= (int) (slider_info.id+visible_files)))
4637 slider_info.id=i-(visible_files >> 1);
4638 selection_info.id=(~0);
4639 state|=RedrawListState;
4640 state&=(~JumpListState);
4641 }
4642 if (state & RedrawListState)
4643 {
4644 /*
4645 Determine slider id and position.
4646 */
4647 if (slider_info.id >= (int) (files-visible_files))
4648 slider_info.id=(int) (files-visible_files);
4649 if ((slider_info.id < 0) || (files <= visible_files))
4650 slider_info.id=0;
4651 slider_info.y=slider_info.min_y;
4652 if (files > 0)
cristy8891f9c2010-06-04 23:32:17 +00004653 slider_info.y+=(slider_info.id*(slider_info.max_y-
4654 slider_info.min_y+1)/files);
cristy3ed852e2009-09-05 21:47:34 +00004655 if (slider_info.id != selection_info.id)
4656 {
4657 /*
4658 Redraw scroll bar and file names.
4659 */
4660 selection_info.id=slider_info.id;
4661 selection_info.y=list_info.y+(height >> 3)+2;
4662 for (i=0; i < (int) visible_files; i++)
4663 {
4664 selection_info.raised=(slider_info.id+i) != list_info.id ?
4665 MagickTrue : MagickFalse;
4666 selection_info.text=(char *) NULL;
cristybb503372010-05-27 20:51:26 +00004667 if ((slider_info.id+i) < (ssize_t) files)
cristy3ed852e2009-09-05 21:47:34 +00004668 selection_info.text=filelist[slider_info.id+i];
4669 XDrawWidgetText(display,&windows->widget,&selection_info);
4670 selection_info.y+=(int) selection_info.height;
4671 }
4672 /*
4673 Update slider.
4674 */
4675 if (slider_info.y > expose_info.y)
4676 {
4677 expose_info.height=(unsigned int) slider_info.y-expose_info.y;
4678 expose_info.y=slider_info.y-expose_info.height-
4679 slider_info.bevel_width-1;
4680 }
4681 else
4682 {
4683 expose_info.height=(unsigned int) expose_info.y-slider_info.y;
4684 expose_info.y=slider_info.y+slider_info.height+
4685 slider_info.bevel_width+1;
4686 }
4687 XDrawTriangleNorth(display,&windows->widget,&north_info);
4688 XDrawMatte(display,&windows->widget,&expose_info);
4689 XDrawBeveledButton(display,&windows->widget,&slider_info);
4690 XDrawTriangleSouth(display,&windows->widget,&south_info);
4691 expose_info.y=slider_info.y;
4692 }
4693 state&=(~RedrawListState);
4694 }
4695 /*
4696 Wait for next event.
4697 */
4698 if (north_info.raised && south_info.raised)
4699 (void) XIfEvent(display,&event,XScreenEvent,(char *) windows);
4700 else
4701 {
4702 /*
4703 Brief delay before advancing scroll bar.
4704 */
4705 XDelay(display,delay);
4706 delay=SuspendTime;
4707 (void) XCheckIfEvent(display,&event,XScreenEvent,(char *) windows);
4708 if (north_info.raised == MagickFalse)
4709 if (slider_info.id > 0)
4710 {
4711 /*
4712 Move slider up.
4713 */
4714 slider_info.id--;
4715 state|=RedrawListState;
4716 }
4717 if (south_info.raised == MagickFalse)
cristybb503372010-05-27 20:51:26 +00004718 if (slider_info.id < (ssize_t) files)
cristy3ed852e2009-09-05 21:47:34 +00004719 {
4720 /*
4721 Move slider down.
4722 */
4723 slider_info.id++;
4724 state|=RedrawListState;
4725 }
4726 if (event.type != ButtonRelease)
4727 continue;
4728 }
4729 switch (event.type)
4730 {
4731 case ButtonPress:
4732 {
4733 if (MatteIsActive(slider_info,event.xbutton))
4734 {
4735 /*
4736 Track slider.
4737 */
4738 slider_info.active=MagickTrue;
4739 break;
4740 }
4741 if (MatteIsActive(north_info,event.xbutton))
4742 if (slider_info.id > 0)
4743 {
4744 /*
4745 Move slider up.
4746 */
4747 north_info.raised=MagickFalse;
4748 slider_info.id--;
4749 state|=RedrawListState;
4750 break;
4751 }
4752 if (MatteIsActive(south_info,event.xbutton))
cristybb503372010-05-27 20:51:26 +00004753 if (slider_info.id < (ssize_t) files)
cristy3ed852e2009-09-05 21:47:34 +00004754 {
4755 /*
4756 Move slider down.
4757 */
4758 south_info.raised=MagickFalse;
4759 slider_info.id++;
4760 state|=RedrawListState;
4761 break;
4762 }
4763 if (MatteIsActive(scroll_info,event.xbutton))
4764 {
4765 /*
4766 Move slider.
4767 */
4768 if (event.xbutton.y < slider_info.y)
4769 slider_info.id-=(visible_files-1);
4770 else
4771 slider_info.id+=(visible_files-1);
4772 state|=RedrawListState;
4773 break;
4774 }
4775 if (MatteIsActive(list_info,event.xbutton))
4776 {
4777 int
4778 id;
4779
4780 /*
4781 User pressed file matte.
4782 */
4783 id=slider_info.id+(event.xbutton.y-(list_info.y+(height >> 1))+1)/
4784 selection_info.height;
cristybb503372010-05-27 20:51:26 +00004785 if (id >= (ssize_t) files)
cristy3ed852e2009-09-05 21:47:34 +00004786 break;
4787 (void) CopyMagickString(reply_info.text,filelist[id],MaxTextExtent);
4788 reply_info.highlight=MagickFalse;
4789 reply_info.marker=reply_info.text;
4790 reply_info.cursor=reply_info.text+Extent(reply_info.text);
4791 XDrawMatteText(display,&windows->widget,&reply_info);
4792 if (id == list_info.id)
4793 {
4794 register char
4795 *p;
4796
4797
4798 p=reply_info.text+strlen(reply_info.text)-1;
4799 if (*p == *DirectorySeparator)
4800 ChopPathComponents(reply_info.text,1);
4801 (void) ConcatenateMagickString(working_path,DirectorySeparator,
4802 MaxTextExtent);
4803 (void) ConcatenateMagickString(working_path,reply_info.text,
4804 MaxTextExtent);
4805 *reply='\0';
4806 state|=UpdateListState;
4807 }
4808 selection_info.id=(~0);
4809 list_info.id=id;
4810 state|=RedrawListState;
4811 break;
4812 }
4813 if (MatteIsActive(up_info,event.xbutton))
4814 {
4815 /*
4816 User pressed Up button.
4817 */
4818 up_info.raised=MagickFalse;
4819 XDrawBeveledButton(display,&windows->widget,&up_info);
4820 break;
4821 }
4822 if (MatteIsActive(home_info,event.xbutton))
4823 {
4824 /*
4825 User pressed Home button.
4826 */
4827 home_info.raised=MagickFalse;
4828 XDrawBeveledButton(display,&windows->widget,&home_info);
4829 break;
4830 }
4831 if (MatteIsActive(special_info,event.xbutton))
4832 {
4833 /*
4834 User pressed Special button.
4835 */
4836 special_info.raised=MagickFalse;
4837 XDrawBeveledButton(display,&windows->widget,&special_info);
4838 break;
4839 }
4840 if (MatteIsActive(action_info,event.xbutton))
4841 {
4842 /*
4843 User pressed action button.
4844 */
4845 action_info.raised=MagickFalse;
4846 XDrawBeveledButton(display,&windows->widget,&action_info);
4847 break;
4848 }
4849 if (MatteIsActive(cancel_info,event.xbutton))
4850 {
4851 /*
4852 User pressed Cancel button.
4853 */
4854 cancel_info.raised=MagickFalse;
4855 XDrawBeveledButton(display,&windows->widget,&cancel_info);
4856 break;
4857 }
4858 if (MatteIsActive(reply_info,event.xbutton) == MagickFalse)
4859 break;
4860 if (event.xbutton.button != Button2)
4861 {
4862 static Time
4863 click_time;
4864
4865 /*
4866 Move text cursor to position of button press.
4867 */
4868 x=event.xbutton.x-reply_info.x-(QuantumMargin >> 2);
4869 for (i=1; i <= Extent(reply_info.marker); i++)
4870 if (XTextWidth(font_info,reply_info.marker,i) > x)
4871 break;
4872 reply_info.cursor=reply_info.marker+i-1;
4873 if (event.xbutton.time > (click_time+DoubleClick))
4874 reply_info.highlight=MagickFalse;
4875 else
4876 {
4877 /*
4878 Become the XA_PRIMARY selection owner.
4879 */
4880 (void) CopyMagickString(primary_selection,reply_info.text,
4881 MaxTextExtent);
4882 (void) XSetSelectionOwner(display,XA_PRIMARY,windows->widget.id,
4883 event.xbutton.time);
4884 reply_info.highlight=XGetSelectionOwner(display,XA_PRIMARY) ==
4885 windows->widget.id ? MagickTrue : MagickFalse;
4886 }
4887 XDrawMatteText(display,&windows->widget,&reply_info);
4888 click_time=event.xbutton.time;
4889 break;
4890 }
4891 /*
4892 Request primary selection.
4893 */
4894 (void) XConvertSelection(display,XA_PRIMARY,XA_STRING,XA_STRING,
4895 windows->widget.id,event.xbutton.time);
4896 break;
4897 }
4898 case ButtonRelease:
4899 {
4900 if (windows->widget.mapped == MagickFalse)
4901 break;
4902 if (north_info.raised == MagickFalse)
4903 {
4904 /*
4905 User released up button.
4906 */
4907 delay=SuspendTime << 2;
4908 north_info.raised=MagickTrue;
4909 XDrawTriangleNorth(display,&windows->widget,&north_info);
4910 }
4911 if (south_info.raised == MagickFalse)
4912 {
4913 /*
4914 User released down button.
4915 */
4916 delay=SuspendTime << 2;
4917 south_info.raised=MagickTrue;
4918 XDrawTriangleSouth(display,&windows->widget,&south_info);
4919 }
4920 if (slider_info.active)
4921 {
4922 /*
4923 Stop tracking slider.
4924 */
4925 slider_info.active=MagickFalse;
4926 break;
4927 }
4928 if (up_info.raised == MagickFalse)
4929 {
4930 if (event.xbutton.window == windows->widget.id)
4931 if (MatteIsActive(up_info,event.xbutton))
4932 {
4933 ChopPathComponents(working_path,1);
4934 if (*working_path == '\0')
4935 (void) CopyMagickString(working_path,DirectorySeparator,
4936 MaxTextExtent);
4937 state|=UpdateListState;
4938 }
4939 up_info.raised=MagickTrue;
4940 XDrawBeveledButton(display,&windows->widget,&up_info);
4941 }
4942 if (home_info.raised == MagickFalse)
4943 {
4944 if (event.xbutton.window == windows->widget.id)
4945 if (MatteIsActive(home_info,event.xbutton))
4946 {
4947 (void) CopyMagickString(working_path,home_directory,
4948 MaxTextExtent);
4949 state|=UpdateListState;
4950 }
4951 home_info.raised=MagickTrue;
4952 XDrawBeveledButton(display,&windows->widget,&home_info);
4953 }
4954 if (special_info.raised == MagickFalse)
4955 {
4956 if (anomaly == MagickFalse)
4957 {
4958 char
4959 **formats;
4960
4961 ExceptionInfo
4962 *exception;
4963
cristybb503372010-05-27 20:51:26 +00004964 size_t
cristy3ed852e2009-09-05 21:47:34 +00004965 number_formats;
4966
4967 /*
4968 Let user select image format.
4969 */
4970 exception=AcquireExceptionInfo();
4971 formats=GetMagickList("*",&number_formats,exception);
4972 exception=DestroyExceptionInfo(exception);
4973 (void) XCheckDefineCursor(display,windows->widget.id,
4974 windows->widget.busy_cursor);
4975 windows->popup.x=windows->widget.x+60;
4976 windows->popup.y=windows->widget.y+60;
4977 XListBrowserWidget(display,windows,&windows->popup,
4978 (const char **) formats,"Select","Select image format type:",
4979 format);
4980 XSetCursorState(display,windows,MagickTrue);
4981 (void) XCheckDefineCursor(display,windows->widget.id,
4982 windows->widget.cursor);
4983 LocaleLower(format);
4984 AppendImageFormat(format,reply_info.text);
4985 reply_info.cursor=reply_info.text+Extent(reply_info.text);
4986 XDrawMatteText(display,&windows->widget,&reply_info);
4987 special_info.raised=MagickTrue;
4988 XDrawBeveledButton(display,&windows->widget,&special_info);
4989 for (i=0; i < (int) number_formats; i++)
4990 formats[i]=DestroyString(formats[i]);
4991 formats=(char **) RelinquishMagickMemory(formats);
4992 break;
4993 }
4994 if (event.xbutton.window == windows->widget.id)
4995 if (MatteIsActive(special_info,event.xbutton))
4996 {
4997 (void) CopyMagickString(working_path,"x:",MaxTextExtent);
4998 state|=ExitState;
4999 }
5000 special_info.raised=MagickTrue;
5001 XDrawBeveledButton(display,&windows->widget,&special_info);
5002 }
5003 if (action_info.raised == MagickFalse)
5004 {
5005 if (event.xbutton.window == windows->widget.id)
5006 {
5007 if (MatteIsActive(action_info,event.xbutton))
5008 {
5009 if (*reply_info.text == '\0')
5010 (void) XBell(display,0);
5011 else
5012 state|=ExitState;
5013 }
5014 }
5015 action_info.raised=MagickTrue;
5016 XDrawBeveledButton(display,&windows->widget,&action_info);
5017 }
5018 if (cancel_info.raised == MagickFalse)
5019 {
5020 if (event.xbutton.window == windows->widget.id)
5021 if (MatteIsActive(cancel_info,event.xbutton))
5022 {
5023 *reply_info.text='\0';
5024 *reply='\0';
5025 state|=ExitState;
5026 }
5027 cancel_info.raised=MagickTrue;
5028 XDrawBeveledButton(display,&windows->widget,&cancel_info);
5029 }
5030 break;
5031 }
5032 case ClientMessage:
5033 {
5034 /*
5035 If client window delete message, exit.
5036 */
5037 if (event.xclient.message_type != windows->wm_protocols)
5038 break;
5039 if (*event.xclient.data.l == (int) windows->wm_take_focus)
5040 {
5041 (void) XSetInputFocus(display,event.xclient.window,RevertToParent,
5042 (Time) event.xclient.data.l[1]);
5043 break;
5044 }
5045 if (*event.xclient.data.l != (int) windows->wm_delete_window)
5046 break;
5047 if (event.xclient.window == windows->widget.id)
5048 {
5049 *reply_info.text='\0';
5050 state|=ExitState;
5051 break;
5052 }
5053 break;
5054 }
5055 case ConfigureNotify:
5056 {
5057 /*
5058 Update widget configuration.
5059 */
5060 if (event.xconfigure.window != windows->widget.id)
5061 break;
5062 if ((event.xconfigure.width == (int) windows->widget.width) &&
5063 (event.xconfigure.height == (int) windows->widget.height))
5064 break;
5065 windows->widget.width=(unsigned int)
5066 MagickMax(event.xconfigure.width,(int) windows->widget.min_width);
5067 windows->widget.height=(unsigned int)
5068 MagickMax(event.xconfigure.height,(int) windows->widget.min_height);
5069 state|=UpdateConfigurationState;
5070 break;
5071 }
5072 case EnterNotify:
5073 {
5074 if (event.xcrossing.window != windows->widget.id)
5075 break;
5076 state&=(~InactiveWidgetState);
5077 break;
5078 }
5079 case Expose:
5080 {
5081 if (event.xexpose.window != windows->widget.id)
5082 break;
5083 if (event.xexpose.count != 0)
5084 break;
5085 state|=RedrawWidgetState;
5086 break;
5087 }
5088 case KeyPress:
5089 {
5090 static char
5091 command[MaxTextExtent];
5092
5093 static int
5094 length;
5095
5096 static KeySym
5097 key_symbol;
5098
5099 /*
5100 Respond to a user key press.
5101 */
5102 if (event.xkey.window != windows->widget.id)
5103 break;
5104 length=XLookupString((XKeyEvent *) &event.xkey,command,
5105 (int) sizeof(command),&key_symbol,(XComposeStatus *) NULL);
5106 *(command+length)='\0';
5107 if (AreaIsActive(scroll_info,event.xkey))
5108 {
5109 /*
5110 Move slider.
5111 */
5112 switch ((int) key_symbol)
5113 {
5114 case XK_Home:
5115 case XK_KP_Home:
5116 {
5117 slider_info.id=0;
5118 break;
5119 }
5120 case XK_Up:
5121 case XK_KP_Up:
5122 {
5123 slider_info.id--;
5124 break;
5125 }
5126 case XK_Down:
5127 case XK_KP_Down:
5128 {
5129 slider_info.id++;
5130 break;
5131 }
5132 case XK_Prior:
5133 case XK_KP_Prior:
5134 {
5135 slider_info.id-=visible_files;
5136 break;
5137 }
5138 case XK_Next:
5139 case XK_KP_Next:
5140 {
5141 slider_info.id+=visible_files;
5142 break;
5143 }
5144 case XK_End:
5145 case XK_KP_End:
5146 {
5147 slider_info.id=(int) files;
5148 break;
5149 }
5150 }
5151 state|=RedrawListState;
5152 break;
5153 }
5154 if ((key_symbol == XK_Return) || (key_symbol == XK_KP_Enter))
5155 {
5156 /*
5157 Read new directory or glob patterm.
5158 */
5159 if (*reply_info.text == '\0')
5160 break;
5161 if (IsGlob(reply_info.text))
5162 (void) CopyMagickString(glob_pattern,reply_info.text,
5163 MaxTextExtent);
5164 else
5165 {
5166 (void) ConcatenateMagickString(working_path,DirectorySeparator,
5167 MaxTextExtent);
5168 (void) ConcatenateMagickString(working_path,reply_info.text,
5169 MaxTextExtent);
5170 if (*working_path == '~')
5171 ExpandFilename(working_path);
5172 *reply='\0';
5173 }
5174 state|=UpdateListState;
5175 break;
5176 }
5177 if (key_symbol == XK_Control_L)
5178 {
5179 state|=ControlState;
5180 break;
5181 }
5182 if (state & ControlState)
5183 switch ((int) key_symbol)
5184 {
5185 case XK_u:
5186 case XK_U:
5187 {
5188 /*
5189 Erase the entire line of text.
5190 */
5191 *reply_info.text='\0';
5192 reply_info.cursor=reply_info.text;
5193 reply_info.marker=reply_info.text;
5194 reply_info.highlight=MagickFalse;
5195 break;
5196 }
5197 default:
5198 break;
5199 }
5200 XEditText(display,&reply_info,key_symbol,command,state);
5201 XDrawMatteText(display,&windows->widget,&reply_info);
5202 state|=JumpListState;
5203 break;
5204 }
5205 case KeyRelease:
5206 {
5207 static char
5208 command[MaxTextExtent];
5209
5210 static KeySym
5211 key_symbol;
5212
5213 /*
5214 Respond to a user key release.
5215 */
5216 if (event.xkey.window != windows->widget.id)
5217 break;
5218 (void) XLookupString((XKeyEvent *) &event.xkey,command,
5219 (int) sizeof(command),&key_symbol,(XComposeStatus *) NULL);
5220 if (key_symbol == XK_Control_L)
5221 state&=(~ControlState);
5222 break;
5223 }
5224 case LeaveNotify:
5225 {
5226 if (event.xcrossing.window != windows->widget.id)
5227 break;
5228 state|=InactiveWidgetState;
5229 break;
5230 }
5231 case MapNotify:
5232 {
5233 mask&=(~CWX);
5234 mask&=(~CWY);
5235 break;
5236 }
5237 case MotionNotify:
5238 {
5239 /*
5240 Discard pending button motion events.
5241 */
5242 while (XCheckMaskEvent(display,ButtonMotionMask,&event)) ;
5243 if (slider_info.active)
5244 {
5245 /*
5246 Move slider matte.
5247 */
5248 slider_info.y=event.xmotion.y-
5249 ((slider_info.height+slider_info.bevel_width) >> 1)+1;
5250 if (slider_info.y < slider_info.min_y)
5251 slider_info.y=slider_info.min_y;
5252 if (slider_info.y > slider_info.max_y)
5253 slider_info.y=slider_info.max_y;
5254 slider_info.id=0;
5255 if (slider_info.y != slider_info.min_y)
5256 slider_info.id=(int) ((files*(slider_info.y-slider_info.min_y+1))/
5257 (slider_info.max_y-slider_info.min_y+1));
5258 state|=RedrawListState;
5259 break;
5260 }
5261 if (state & InactiveWidgetState)
5262 break;
5263 if (up_info.raised == MatteIsActive(up_info,event.xmotion))
5264 {
5265 /*
5266 Up button status changed.
5267 */
5268 up_info.raised=!up_info.raised;
5269 XDrawBeveledButton(display,&windows->widget,&up_info);
5270 break;
5271 }
5272 if (home_info.raised == MatteIsActive(home_info,event.xmotion))
5273 {
5274 /*
5275 Home button status changed.
5276 */
5277 home_info.raised=!home_info.raised;
5278 XDrawBeveledButton(display,&windows->widget,&home_info);
5279 break;
5280 }
5281 if (special_info.raised == MatteIsActive(special_info,event.xmotion))
5282 {
5283 /*
5284 Grab button status changed.
5285 */
5286 special_info.raised=!special_info.raised;
5287 XDrawBeveledButton(display,&windows->widget,&special_info);
5288 break;
5289 }
5290 if (action_info.raised == MatteIsActive(action_info,event.xmotion))
5291 {
5292 /*
5293 Action button status changed.
5294 */
5295 action_info.raised=action_info.raised == MagickFalse ?
5296 MagickTrue : MagickFalse;
5297 XDrawBeveledButton(display,&windows->widget,&action_info);
5298 break;
5299 }
5300 if (cancel_info.raised == MatteIsActive(cancel_info,event.xmotion))
5301 {
5302 /*
5303 Cancel button status changed.
5304 */
5305 cancel_info.raised=cancel_info.raised == MagickFalse ?
5306 MagickTrue : MagickFalse;
5307 XDrawBeveledButton(display,&windows->widget,&cancel_info);
5308 break;
5309 }
5310 break;
5311 }
5312 case SelectionClear:
5313 {
5314 reply_info.highlight=MagickFalse;
5315 XDrawMatteText(display,&windows->widget,&reply_info);
5316 break;
5317 }
5318 case SelectionNotify:
5319 {
5320 Atom
5321 type;
5322
5323 int
5324 format;
5325
5326 unsigned char
5327 *data;
5328
cristyf2faecf2010-05-28 19:19:36 +00005329 unsigned long
cristy3ed852e2009-09-05 21:47:34 +00005330 after,
5331 length;
5332
5333 /*
5334 Obtain response from primary selection.
5335 */
5336 if (event.xselection.property == (Atom) None)
5337 break;
5338 status=XGetWindowProperty(display,event.xselection.requestor,
5339 event.xselection.property,0L,2047L,MagickTrue,XA_STRING,&type,
5340 &format,&length,&after,&data);
5341 if ((status != Success) || (type != XA_STRING) || (format == 32) ||
5342 (length == 0))
5343 break;
5344 if ((Extent(reply_info.text)+length) >= MaxTextExtent)
5345 (void) XBell(display,0);
5346 else
5347 {
5348 /*
5349 Insert primary selection in reply text.
5350 */
5351 *(data+length)='\0';
5352 XEditText(display,&reply_info,(KeySym) XK_Insert,(char *) data,
5353 state);
5354 XDrawMatteText(display,&windows->widget,&reply_info);
5355 state|=JumpListState;
5356 state|=RedrawActionState;
5357 }
5358 (void) XFree((void *) data);
5359 break;
5360 }
5361 case SelectionRequest:
5362 {
5363 XSelectionEvent
5364 notify;
5365
5366 XSelectionRequestEvent
5367 *request;
5368
5369 if (reply_info.highlight == MagickFalse)
5370 break;
5371 /*
5372 Set primary selection.
5373 */
5374 request=(&(event.xselectionrequest));
5375 (void) XChangeProperty(request->display,request->requestor,
5376 request->property,request->target,8,PropModeReplace,
5377 (unsigned char *) primary_selection,Extent(primary_selection));
5378 notify.type=SelectionNotify;
5379 notify.display=request->display;
5380 notify.requestor=request->requestor;
5381 notify.selection=request->selection;
5382 notify.target=request->target;
5383 notify.time=request->time;
5384 if (request->property == None)
5385 notify.property=request->target;
5386 else
5387 notify.property=request->property;
5388 (void) XSendEvent(request->display,request->requestor,False,0,
5389 (XEvent *) &notify);
5390 }
5391 default:
5392 break;
5393 }
5394 } while ((state & ExitState) == 0);
5395 XSetCursorState(display,windows,MagickFalse);
5396 (void) XWithdrawWindow(display,windows->widget.id,windows->widget.screen);
5397 XCheckRefreshWindows(display,windows);
5398 /*
5399 Free file list.
5400 */
cristybb503372010-05-27 20:51:26 +00005401 for (i=0; i < (ssize_t) files; i++)
cristy3ed852e2009-09-05 21:47:34 +00005402 filelist[i]=DestroyString(filelist[i]);
5403 if (filelist != (char **) NULL)
5404 filelist=(char **) RelinquishMagickMemory(filelist);
5405 if (*reply != '\0')
5406 {
5407 (void) ConcatenateMagickString(working_path,DirectorySeparator,
5408 MaxTextExtent);
5409 (void) ConcatenateMagickString(working_path,reply,MaxTextExtent);
5410 }
5411 (void) CopyMagickString(reply,working_path,MaxTextExtent);
5412 if (*reply == '~')
5413 ExpandFilename(reply);
5414}
5415
5416/*
5417%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5418% %
5419% %
5420% %
5421% X F o n t B r o w s e r W i d g e t %
5422% %
5423% %
5424% %
5425%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5426%
5427% XFontBrowserWidget() displays a Font Browser widget with a font query to the
5428% user. The user keys a reply and presses the Action or Cancel button to
5429% exit. The typed text is returned as the reply function parameter.
5430%
5431% The format of the XFontBrowserWidget method is:
5432%
5433% void XFontBrowserWidget(Display *display,XWindows *windows,
5434% const char *action,char *reply)
5435%
5436% A description of each parameter follows:
5437%
5438% o display: Specifies a connection to an X server; returned from
5439% XOpenDisplay.
5440%
5441% o window: Specifies a pointer to a XWindows structure.
5442%
5443% o action: Specifies a pointer to the action of this widget.
5444%
5445% o reply: the response from the user is returned in this parameter.
5446%
5447%
5448*/
5449
5450#if defined(__cplusplus) || defined(c_plusplus)
5451extern "C" {
5452#endif
5453
5454static int FontCompare(const void *x,const void *y)
5455{
5456 register char
5457 *p,
5458 *q;
5459
5460 p=(char *) *((char **) x);
5461 q=(char *) *((char **) y);
5462 while ((*p != '\0') && (*q != '\0') && (*p == *q))
5463 {
5464 p++;
5465 q++;
5466 }
5467 return(*p-(*q));
5468}
5469
5470#if defined(__cplusplus) || defined(c_plusplus)
5471}
5472#endif
5473
5474MagickExport void XFontBrowserWidget(Display *display,XWindows *windows,
5475 const char *action,char *reply)
5476{
5477#define BackButtonText "Back"
5478#define CancelButtonText "Cancel"
5479#define FontnameText "Name:"
5480#define FontPatternText "Pattern:"
5481#define ResetButtonText "Reset"
5482
5483 char
5484 back_pattern[MaxTextExtent],
5485 **fontlist,
5486 **listhead,
5487 primary_selection[MaxTextExtent],
5488 reset_pattern[MaxTextExtent],
5489 text[MaxTextExtent];
5490
5491 int
5492 fonts,
5493 x,
5494 y;
5495
5496 register int
5497 i;
5498
5499 static char
5500 glob_pattern[MaxTextExtent] = "*";
5501
5502 static MagickStatusType
5503 mask = (MagickStatusType) (CWWidth | CWHeight | CWX | CWY);
5504
5505 Status
5506 status;
5507
5508 unsigned int
5509 height,
5510 text_width,
5511 visible_fonts,
5512 width;
5513
cristybb503372010-05-27 20:51:26 +00005514 size_t
cristy3ed852e2009-09-05 21:47:34 +00005515 delay,
5516 state;
5517
5518 XEvent
5519 event;
5520
5521 XFontStruct
5522 *font_info;
5523
5524 XTextProperty
5525 window_name;
5526
5527 XWidgetInfo
5528 action_info,
5529 back_info,
5530 cancel_info,
5531 expose_info,
5532 list_info,
5533 mode_info,
5534 north_info,
5535 reply_info,
5536 reset_info,
5537 scroll_info,
5538 selection_info,
5539 slider_info,
5540 south_info,
5541 text_info;
5542
5543 XWindowChanges
5544 window_changes;
5545
5546 /*
5547 Get font list and sort in ascending order.
5548 */
5549 assert(display != (Display *) NULL);
5550 assert(windows != (XWindows *) NULL);
5551 assert(action != (char *) NULL);
5552 assert(reply != (char *) NULL);
5553 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",action);
5554 XSetCursorState(display,windows,MagickTrue);
5555 XCheckRefreshWindows(display,windows);
5556 (void) CopyMagickString(back_pattern,glob_pattern,MaxTextExtent);
5557 (void) CopyMagickString(reset_pattern,"*",MaxTextExtent);
5558 fontlist=XListFonts(display,glob_pattern,32767,&fonts);
5559 if (fonts == 0)
5560 {
5561 /*
5562 Pattern failed, obtain all the fonts.
5563 */
5564 XNoticeWidget(display,windows,"Unable to obtain fonts names:",
5565 glob_pattern);
5566 (void) CopyMagickString(glob_pattern,"*",MaxTextExtent);
5567 fontlist=XListFonts(display,glob_pattern,32767,&fonts);
5568 if (fontlist == (char **) NULL)
5569 {
5570 XNoticeWidget(display,windows,"Unable to obtain fonts names:",
5571 glob_pattern);
5572 return;
5573 }
5574 }
5575 /*
5576 Sort font list in ascending order.
5577 */
5578 listhead=fontlist;
5579 fontlist=(char **) AcquireQuantumMemory((size_t) fonts,sizeof(*fontlist));
5580 if (fontlist == (char **) NULL)
5581 {
5582 XNoticeWidget(display,windows,"MemoryAllocationFailed",
5583 "UnableToViewFonts");
5584 return;
5585 }
5586 for (i=0; i < fonts; i++)
5587 fontlist[i]=listhead[i];
5588 qsort((void *) fontlist,(size_t) fonts,sizeof(*fontlist),FontCompare);
5589 /*
5590 Determine Font Browser widget attributes.
5591 */
5592 font_info=windows->widget.font_info;
5593 text_width=0;
5594 for (i=0; i < fonts; i++)
5595 if (WidgetTextWidth(font_info,fontlist[i]) > text_width)
5596 text_width=WidgetTextWidth(font_info,fontlist[i]);
5597 width=WidgetTextWidth(font_info,(char *) action);
5598 if (WidgetTextWidth(font_info,CancelButtonText) > width)
5599 width=WidgetTextWidth(font_info,CancelButtonText);
5600 if (WidgetTextWidth(font_info,ResetButtonText) > width)
5601 width=WidgetTextWidth(font_info,ResetButtonText);
5602 if (WidgetTextWidth(font_info,BackButtonText) > width)
5603 width=WidgetTextWidth(font_info,BackButtonText);
5604 width+=QuantumMargin;
5605 if (WidgetTextWidth(font_info,FontPatternText) > width)
5606 width=WidgetTextWidth(font_info,FontPatternText);
5607 if (WidgetTextWidth(font_info,FontnameText) > width)
5608 width=WidgetTextWidth(font_info,FontnameText);
5609 height=(unsigned int) (font_info->ascent+font_info->descent);
5610 /*
5611 Position Font Browser widget.
5612 */
5613 windows->widget.width=width+MagickMin((int) text_width,(int) MaxTextWidth)+
5614 6*QuantumMargin;
5615 windows->widget.min_width=width+MinTextWidth+4*QuantumMargin;
5616 if (windows->widget.width < windows->widget.min_width)
5617 windows->widget.width=windows->widget.min_width;
5618 windows->widget.height=(unsigned int)
5619 (((85*height) >> 2)+((13*QuantumMargin) >> 1)+4);
5620 windows->widget.min_height=(unsigned int)
5621 (((27*height) >> 1)+((13*QuantumMargin) >> 1)+4);
5622 if (windows->widget.height < windows->widget.min_height)
5623 windows->widget.height=windows->widget.min_height;
5624 XConstrainWindowPosition(display,&windows->widget);
5625 /*
5626 Map Font Browser widget.
5627 */
5628 (void) CopyMagickString(windows->widget.name,"Browse and Select a Font",
5629 MaxTextExtent);
5630 status=XStringListToTextProperty(&windows->widget.name,1,&window_name);
5631 if (status != False)
5632 {
5633 XSetWMName(display,windows->widget.id,&window_name);
5634 XSetWMIconName(display,windows->widget.id,&window_name);
5635 (void) XFree((void *) window_name.value);
5636 }
5637 window_changes.width=(int) windows->widget.width;
5638 window_changes.height=(int) windows->widget.height;
5639 window_changes.x=windows->widget.x;
5640 window_changes.y=windows->widget.y;
5641 (void) XReconfigureWMWindow(display,windows->widget.id,
5642 windows->widget.screen,mask,&window_changes);
5643 (void) XMapRaised(display,windows->widget.id);
5644 windows->widget.mapped=MagickFalse;
5645 /*
5646 Respond to X events.
5647 */
5648 XGetWidgetInfo((char *) NULL,&slider_info);
5649 XGetWidgetInfo((char *) NULL,&north_info);
5650 XGetWidgetInfo((char *) NULL,&south_info);
5651 XGetWidgetInfo((char *) NULL,&expose_info);
5652 visible_fonts=0;
5653 delay=SuspendTime << 2;
5654 state=UpdateConfigurationState;
5655 do
5656 {
5657 if (state & UpdateConfigurationState)
5658 {
5659 int
5660 id;
5661
5662 /*
5663 Initialize button information.
5664 */
5665 XGetWidgetInfo(CancelButtonText,&cancel_info);
5666 cancel_info.width=width;
5667 cancel_info.height=(unsigned int) ((3*height) >> 1);
5668 cancel_info.x=(int)
5669 (windows->widget.width-cancel_info.width-QuantumMargin-2);
5670 cancel_info.y=(int)
5671 (windows->widget.height-cancel_info.height-QuantumMargin);
5672 XGetWidgetInfo(action,&action_info);
5673 action_info.width=width;
5674 action_info.height=(unsigned int) ((3*height) >> 1);
5675 action_info.x=cancel_info.x-(cancel_info.width+(QuantumMargin >> 1)+
5676 (action_info.bevel_width << 1));
5677 action_info.y=cancel_info.y;
5678 XGetWidgetInfo(BackButtonText,&back_info);
5679 back_info.width=width;
5680 back_info.height=(unsigned int) ((3*height) >> 1);
5681 back_info.x=QuantumMargin;
5682 back_info.y=((5*QuantumMargin) >> 1)+height;
5683 XGetWidgetInfo(ResetButtonText,&reset_info);
5684 reset_info.width=width;
5685 reset_info.height=(unsigned int) ((3*height) >> 1);
5686 reset_info.x=QuantumMargin;
5687 reset_info.y=back_info.y+back_info.height+QuantumMargin;
5688 /*
5689 Initialize reply information.
5690 */
5691 XGetWidgetInfo(reply,&reply_info);
5692 reply_info.raised=MagickFalse;
5693 reply_info.bevel_width--;
5694 reply_info.width=windows->widget.width-width-((6*QuantumMargin) >> 1);
5695 reply_info.height=height << 1;
5696 reply_info.x=(int) (width+(QuantumMargin << 1));
5697 reply_info.y=action_info.y-(action_info.height << 1)-QuantumMargin;
5698 /*
5699 Initialize mode information.
5700 */
5701 XGetWidgetInfo(reply,&mode_info);
5702 mode_info.bevel_width=0;
5703 mode_info.width=(unsigned int)
5704 (action_info.x-reply_info.x-QuantumMargin);
5705 mode_info.height=action_info.height << 1;
5706 mode_info.x=reply_info.x;
5707 mode_info.y=action_info.y-action_info.height+action_info.bevel_width;
5708 /*
5709 Initialize scroll information.
5710 */
5711 XGetWidgetInfo((char *) NULL,&scroll_info);
5712 scroll_info.bevel_width--;
5713 scroll_info.width=height;
5714 scroll_info.height=(unsigned int)
5715 (reply_info.y-back_info.y-(QuantumMargin >> 1));
5716 scroll_info.x=reply_info.x+(reply_info.width-scroll_info.width);
5717 scroll_info.y=back_info.y-reply_info.bevel_width;
5718 scroll_info.raised=MagickFalse;
5719 scroll_info.trough=MagickTrue;
5720 north_info=scroll_info;
5721 north_info.raised=MagickTrue;
5722 north_info.width-=(north_info.bevel_width << 1);
5723 north_info.height=north_info.width-1;
5724 north_info.x+=north_info.bevel_width;
5725 north_info.y+=north_info.bevel_width;
5726 south_info=north_info;
5727 south_info.y=scroll_info.y+scroll_info.height-scroll_info.bevel_width-
5728 south_info.height;
5729 id=slider_info.id;
5730 slider_info=north_info;
5731 slider_info.id=id;
5732 slider_info.width-=2;
5733 slider_info.min_y=north_info.y+north_info.height+north_info.bevel_width+
5734 slider_info.bevel_width+2;
5735 slider_info.height=scroll_info.height-((slider_info.min_y-
5736 scroll_info.y+1) << 1)+4;
5737 visible_fonts=scroll_info.height/(height+(height >> 3));
5738 if (fonts > (int) visible_fonts)
5739 slider_info.height=(visible_fonts*slider_info.height)/fonts;
5740 slider_info.max_y=south_info.y-south_info.bevel_width-
5741 slider_info.bevel_width-2;
5742 slider_info.x=scroll_info.x+slider_info.bevel_width+1;
5743 slider_info.y=slider_info.min_y;
5744 expose_info=scroll_info;
5745 expose_info.y=slider_info.y;
5746 /*
5747 Initialize list information.
5748 */
5749 XGetWidgetInfo((char *) NULL,&list_info);
5750 list_info.raised=MagickFalse;
5751 list_info.bevel_width--;
5752 list_info.width=(unsigned int)
5753 (scroll_info.x-reply_info.x-(QuantumMargin >> 1));
5754 list_info.height=scroll_info.height;
5755 list_info.x=reply_info.x;
5756 list_info.y=scroll_info.y;
5757 if (windows->widget.mapped == MagickFalse)
5758 state|=JumpListState;
5759 /*
5760 Initialize text information.
5761 */
5762 *text='\0';
5763 XGetWidgetInfo(text,&text_info);
5764 text_info.center=MagickFalse;
5765 text_info.width=reply_info.width;
5766 text_info.height=height;
5767 text_info.x=list_info.x-(QuantumMargin >> 1);
5768 text_info.y=QuantumMargin;
5769 /*
5770 Initialize selection information.
5771 */
5772 XGetWidgetInfo((char *) NULL,&selection_info);
5773 selection_info.center=MagickFalse;
5774 selection_info.width=list_info.width;
5775 selection_info.height=(unsigned int) ((9*height) >> 3);
5776 selection_info.x=list_info.x;
5777 state&=(~UpdateConfigurationState);
5778 }
5779 if (state & RedrawWidgetState)
5780 {
5781 /*
5782 Redraw Font Browser window.
5783 */
5784 x=QuantumMargin;
5785 y=text_info.y+((text_info.height-height) >> 1)+font_info->ascent;
5786 (void) XDrawString(display,windows->widget.id,
5787 windows->widget.annotate_context,x,y,FontPatternText,
5788 Extent(FontPatternText));
5789 (void) CopyMagickString(text_info.text,glob_pattern,MaxTextExtent);
5790 XDrawWidgetText(display,&windows->widget,&text_info);
5791 XDrawBeveledButton(display,&windows->widget,&back_info);
5792 XDrawBeveledButton(display,&windows->widget,&reset_info);
5793 XDrawBeveledMatte(display,&windows->widget,&list_info);
5794 XDrawBeveledMatte(display,&windows->widget,&scroll_info);
5795 XDrawTriangleNorth(display,&windows->widget,&north_info);
5796 XDrawBeveledButton(display,&windows->widget,&slider_info);
5797 XDrawTriangleSouth(display,&windows->widget,&south_info);
5798 x=QuantumMargin;
5799 y=reply_info.y+((reply_info.height-height) >> 1)+font_info->ascent;
5800 (void) XDrawString(display,windows->widget.id,
5801 windows->widget.annotate_context,x,y,FontnameText,
5802 Extent(FontnameText));
5803 XDrawBeveledMatte(display,&windows->widget,&reply_info);
5804 XDrawMatteText(display,&windows->widget,&reply_info);
5805 XDrawBeveledButton(display,&windows->widget,&action_info);
5806 XDrawBeveledButton(display,&windows->widget,&cancel_info);
5807 XHighlightWidget(display,&windows->widget,BorderOffset,BorderOffset);
5808 selection_info.id=(~0);
5809 state|=RedrawActionState;
5810 state|=RedrawListState;
5811 state&=(~RedrawWidgetState);
5812 }
5813 if (state & UpdateListState)
5814 {
5815 char
5816 **checklist;
5817
5818 int
5819 number_fonts;
5820
5821 /*
5822 Update font list.
5823 */
5824 checklist=XListFonts(display,glob_pattern,32767,&number_fonts);
5825 if (checklist == (char **) NULL)
5826 {
5827 if ((strchr(glob_pattern,'*') == (char *) NULL) &&
5828 (strchr(glob_pattern,'?') == (char *) NULL))
5829 {
5830 /*
5831 Might be a scaleable font-- exit.
5832 */
5833 (void) CopyMagickString(reply,glob_pattern,MaxTextExtent);
5834 (void) CopyMagickString(glob_pattern,back_pattern,MaxTextExtent);
5835 action_info.raised=MagickFalse;
5836 XDrawBeveledButton(display,&windows->widget,&action_info);
5837 break;
5838 }
5839 (void) CopyMagickString(glob_pattern,back_pattern,MaxTextExtent);
5840 (void) XBell(display,0);
5841 }
5842 else
5843 if (number_fonts == 1)
5844 {
5845 /*
5846 Reply is a single font name-- exit.
5847 */
5848 (void) CopyMagickString(reply,checklist[0],MaxTextExtent);
5849 (void) CopyMagickString(glob_pattern,back_pattern,MaxTextExtent);
5850 (void) XFreeFontNames(checklist);
5851 action_info.raised=MagickFalse;
5852 XDrawBeveledButton(display,&windows->widget,&action_info);
5853 break;
5854 }
5855 else
5856 {
5857 (void) XFreeFontNames(listhead);
5858 fontlist=(char **) RelinquishMagickMemory(fontlist);
5859 fontlist=checklist;
5860 fonts=number_fonts;
5861 }
5862 /*
5863 Sort font list in ascending order.
5864 */
5865 listhead=fontlist;
5866 fontlist=(char **) AcquireQuantumMemory((size_t) fonts,
5867 sizeof(*fontlist));
5868 if (fontlist == (char **) NULL)
5869 {
5870 XNoticeWidget(display,windows,"MemoryAllocationFailed",
5871 "UnableToViewFonts");
5872 return;
5873 }
5874 for (i=0; i < fonts; i++)
5875 fontlist[i]=listhead[i];
5876 qsort((void *) fontlist,(size_t) fonts,sizeof(*fontlist),FontCompare);
5877 slider_info.height=
5878 scroll_info.height-((slider_info.min_y-scroll_info.y+1) << 1)+1;
5879 if (fonts > (int) visible_fonts)
5880 slider_info.height=(visible_fonts*slider_info.height)/fonts;
5881 slider_info.max_y=south_info.y-south_info.bevel_width-
5882 slider_info.bevel_width-2;
5883 slider_info.id=0;
5884 slider_info.y=slider_info.min_y;
5885 expose_info.y=slider_info.y;
5886 selection_info.id=(~0);
5887 list_info.id=(~0);
5888 state|=RedrawListState;
5889 /*
5890 Redraw font name & reply.
5891 */
5892 *reply_info.text='\0';
5893 reply_info.cursor=reply_info.text;
5894 (void) CopyMagickString(text_info.text,glob_pattern,MaxTextExtent);
5895 XDrawWidgetText(display,&windows->widget,&text_info);
5896 XDrawMatteText(display,&windows->widget,&reply_info);
5897 XDrawBeveledMatte(display,&windows->widget,&scroll_info);
5898 XDrawTriangleNorth(display,&windows->widget,&north_info);
5899 XDrawBeveledButton(display,&windows->widget,&slider_info);
5900 XDrawTriangleSouth(display,&windows->widget,&south_info);
5901 XHighlightWidget(display,&windows->widget,BorderOffset,BorderOffset);
5902 state&=(~UpdateListState);
5903 }
5904 if (state & JumpListState)
5905 {
5906 /*
5907 Jump scroll to match user font.
5908 */
5909 list_info.id=(~0);
5910 for (i=0; i < fonts; i++)
5911 if (LocaleCompare(fontlist[i],reply) >= 0)
5912 {
5913 list_info.id=LocaleCompare(fontlist[i],reply) == 0 ? i : ~0;
5914 break;
5915 }
5916 if ((i < slider_info.id) || (i >= (int) (slider_info.id+visible_fonts)))
5917 slider_info.id=i-(visible_fonts >> 1);
5918 selection_info.id=(~0);
5919 state|=RedrawListState;
5920 state&=(~JumpListState);
5921 }
5922 if (state & RedrawListState)
5923 {
5924 /*
5925 Determine slider id and position.
5926 */
5927 if (slider_info.id >= (int) (fonts-visible_fonts))
5928 slider_info.id=fonts-visible_fonts;
5929 if ((slider_info.id < 0) || (fonts <= (int) visible_fonts))
5930 slider_info.id=0;
5931 slider_info.y=slider_info.min_y;
5932 if (fonts > 0)
5933 slider_info.y+=
5934 slider_info.id*(slider_info.max_y-slider_info.min_y+1)/fonts;
5935 if (slider_info.id != selection_info.id)
5936 {
5937 /*
5938 Redraw scroll bar and file names.
5939 */
5940 selection_info.id=slider_info.id;
5941 selection_info.y=list_info.y+(height >> 3)+2;
5942 for (i=0; i < (int) visible_fonts; i++)
5943 {
5944 selection_info.raised=(slider_info.id+i) != list_info.id ?
5945 MagickTrue : MagickFalse;
5946 selection_info.text=(char *) NULL;
5947 if ((slider_info.id+i) < fonts)
5948 selection_info.text=fontlist[slider_info.id+i];
5949 XDrawWidgetText(display,&windows->widget,&selection_info);
5950 selection_info.y+=(int) selection_info.height;
5951 }
5952 /*
5953 Update slider.
5954 */
5955 if (slider_info.y > expose_info.y)
5956 {
5957 expose_info.height=(unsigned int) slider_info.y-expose_info.y;
5958 expose_info.y=slider_info.y-expose_info.height-
5959 slider_info.bevel_width-1;
5960 }
5961 else
5962 {
5963 expose_info.height=(unsigned int) expose_info.y-slider_info.y;
5964 expose_info.y=slider_info.y+slider_info.height+
5965 slider_info.bevel_width+1;
5966 }
5967 XDrawTriangleNorth(display,&windows->widget,&north_info);
5968 XDrawMatte(display,&windows->widget,&expose_info);
5969 XDrawBeveledButton(display,&windows->widget,&slider_info);
5970 XDrawTriangleSouth(display,&windows->widget,&south_info);
5971 expose_info.y=slider_info.y;
5972 }
5973 state&=(~RedrawListState);
5974 }
5975 if (state & RedrawActionState)
5976 {
5977 XFontStruct
5978 *save_info;
5979
5980 /*
5981 Display the selected font in a drawing area.
5982 */
5983 save_info=windows->widget.font_info;
5984 font_info=XLoadQueryFont(display,reply_info.text);
5985 if (font_info != (XFontStruct *) NULL)
5986 {
5987 windows->widget.font_info=font_info;
5988 (void) XSetFont(display,windows->widget.widget_context,
5989 font_info->fid);
5990 }
5991 XDrawBeveledButton(display,&windows->widget,&mode_info);
5992 windows->widget.font_info=save_info;
5993 if (font_info != (XFontStruct *) NULL)
5994 {
5995 (void) XSetFont(display,windows->widget.widget_context,
5996 windows->widget.font_info->fid);
5997 (void) XFreeFont(display,font_info);
5998 }
5999 XHighlightWidget(display,&windows->widget,BorderOffset,BorderOffset);
6000 XDrawMatteText(display,&windows->widget,&reply_info);
6001 state&=(~RedrawActionState);
6002 }
6003 /*
6004 Wait for next event.
6005 */
6006 if (north_info.raised && south_info.raised)
6007 (void) XIfEvent(display,&event,XScreenEvent,(char *) windows);
6008 else
6009 {
6010 /*
6011 Brief delay before advancing scroll bar.
6012 */
6013 XDelay(display,delay);
6014 delay=SuspendTime;
6015 (void) XCheckIfEvent(display,&event,XScreenEvent,(char *) windows);
6016 if (north_info.raised == MagickFalse)
6017 if (slider_info.id > 0)
6018 {
6019 /*
6020 Move slider up.
6021 */
6022 slider_info.id--;
6023 state|=RedrawListState;
6024 }
6025 if (south_info.raised == MagickFalse)
6026 if (slider_info.id < fonts)
6027 {
6028 /*
6029 Move slider down.
6030 */
6031 slider_info.id++;
6032 state|=RedrawListState;
6033 }
6034 if (event.type != ButtonRelease)
6035 continue;
6036 }
6037 switch (event.type)
6038 {
6039 case ButtonPress:
6040 {
6041 if (MatteIsActive(slider_info,event.xbutton))
6042 {
6043 /*
6044 Track slider.
6045 */
6046 slider_info.active=MagickTrue;
6047 break;
6048 }
6049 if (MatteIsActive(north_info,event.xbutton))
6050 if (slider_info.id > 0)
6051 {
6052 /*
6053 Move slider up.
6054 */
6055 north_info.raised=MagickFalse;
6056 slider_info.id--;
6057 state|=RedrawListState;
6058 break;
6059 }
6060 if (MatteIsActive(south_info,event.xbutton))
6061 if (slider_info.id < fonts)
6062 {
6063 /*
6064 Move slider down.
6065 */
6066 south_info.raised=MagickFalse;
6067 slider_info.id++;
6068 state|=RedrawListState;
6069 break;
6070 }
6071 if (MatteIsActive(scroll_info,event.xbutton))
6072 {
6073 /*
6074 Move slider.
6075 */
6076 if (event.xbutton.y < slider_info.y)
6077 slider_info.id-=(visible_fonts-1);
6078 else
6079 slider_info.id+=(visible_fonts-1);
6080 state|=RedrawListState;
6081 break;
6082 }
6083 if (MatteIsActive(list_info,event.xbutton))
6084 {
6085 int
6086 id;
6087
6088 /*
6089 User pressed list matte.
6090 */
6091 id=slider_info.id+(event.xbutton.y-(list_info.y+(height >> 1))+1)/
6092 selection_info.height;
6093 if (id >= (int) fonts)
6094 break;
6095 (void) CopyMagickString(reply_info.text,fontlist[id],MaxTextExtent);
6096 reply_info.highlight=MagickFalse;
6097 reply_info.marker=reply_info.text;
6098 reply_info.cursor=reply_info.text+Extent(reply_info.text);
6099 XDrawMatteText(display,&windows->widget,&reply_info);
6100 state|=RedrawActionState;
6101 if (id == list_info.id)
6102 {
6103 (void) CopyMagickString(glob_pattern,reply_info.text,
6104 MaxTextExtent);
6105 state|=UpdateListState;
6106 }
6107 selection_info.id=(~0);
6108 list_info.id=id;
6109 state|=RedrawListState;
6110 break;
6111 }
6112 if (MatteIsActive(back_info,event.xbutton))
6113 {
6114 /*
6115 User pressed Back button.
6116 */
6117 back_info.raised=MagickFalse;
6118 XDrawBeveledButton(display,&windows->widget,&back_info);
6119 break;
6120 }
6121 if (MatteIsActive(reset_info,event.xbutton))
6122 {
6123 /*
6124 User pressed Reset button.
6125 */
6126 reset_info.raised=MagickFalse;
6127 XDrawBeveledButton(display,&windows->widget,&reset_info);
6128 break;
6129 }
6130 if (MatteIsActive(action_info,event.xbutton))
6131 {
6132 /*
6133 User pressed action button.
6134 */
6135 action_info.raised=MagickFalse;
6136 XDrawBeveledButton(display,&windows->widget,&action_info);
6137 break;
6138 }
6139 if (MatteIsActive(cancel_info,event.xbutton))
6140 {
6141 /*
6142 User pressed Cancel button.
6143 */
6144 cancel_info.raised=MagickFalse;
6145 XDrawBeveledButton(display,&windows->widget,&cancel_info);
6146 break;
6147 }
6148 if (MatteIsActive(reply_info,event.xbutton) == MagickFalse)
6149 break;
6150 if (event.xbutton.button != Button2)
6151 {
6152 static Time
6153 click_time;
6154
6155 /*
6156 Move text cursor to position of button press.
6157 */
6158 x=event.xbutton.x-reply_info.x-(QuantumMargin >> 2);
6159 for (i=1; i <= Extent(reply_info.marker); i++)
6160 if (XTextWidth(font_info,reply_info.marker,i) > x)
6161 break;
6162 reply_info.cursor=reply_info.marker+i-1;
6163 if (event.xbutton.time > (click_time+DoubleClick))
6164 reply_info.highlight=MagickFalse;
6165 else
6166 {
6167 /*
6168 Become the XA_PRIMARY selection owner.
6169 */
6170 (void) CopyMagickString(primary_selection,reply_info.text,
6171 MaxTextExtent);
6172 (void) XSetSelectionOwner(display,XA_PRIMARY,windows->widget.id,
6173 event.xbutton.time);
6174 reply_info.highlight=XGetSelectionOwner(display,XA_PRIMARY) ==
6175 windows->widget.id ? MagickTrue : MagickFalse;
6176 }
6177 XDrawMatteText(display,&windows->widget,&reply_info);
6178 click_time=event.xbutton.time;
6179 break;
6180 }
6181 /*
6182 Request primary selection.
6183 */
6184 (void) XConvertSelection(display,XA_PRIMARY,XA_STRING,XA_STRING,
6185 windows->widget.id,event.xbutton.time);
6186 break;
6187 }
6188 case ButtonRelease:
6189 {
6190 if (windows->widget.mapped == MagickFalse)
6191 break;
6192 if (north_info.raised == MagickFalse)
6193 {
6194 /*
6195 User released up button.
6196 */
6197 delay=SuspendTime << 2;
6198 north_info.raised=MagickTrue;
6199 XDrawTriangleNorth(display,&windows->widget,&north_info);
6200 }
6201 if (south_info.raised == MagickFalse)
6202 {
6203 /*
6204 User released down button.
6205 */
6206 delay=SuspendTime << 2;
6207 south_info.raised=MagickTrue;
6208 XDrawTriangleSouth(display,&windows->widget,&south_info);
6209 }
6210 if (slider_info.active)
6211 {
6212 /*
6213 Stop tracking slider.
6214 */
6215 slider_info.active=MagickFalse;
6216 break;
6217 }
6218 if (back_info.raised == MagickFalse)
6219 {
6220 if (event.xbutton.window == windows->widget.id)
6221 if (MatteIsActive(back_info,event.xbutton))
6222 {
6223 (void) CopyMagickString(glob_pattern,back_pattern,
6224 MaxTextExtent);
6225 state|=UpdateListState;
6226 }
6227 back_info.raised=MagickTrue;
6228 XDrawBeveledButton(display,&windows->widget,&back_info);
6229 }
6230 if (reset_info.raised == MagickFalse)
6231 {
6232 if (event.xbutton.window == windows->widget.id)
6233 if (MatteIsActive(reset_info,event.xbutton))
6234 {
6235 (void) CopyMagickString(back_pattern,glob_pattern,MaxTextExtent);
6236 (void) CopyMagickString(glob_pattern,reset_pattern,MaxTextExtent);
6237 state|=UpdateListState;
6238 }
6239 reset_info.raised=MagickTrue;
6240 XDrawBeveledButton(display,&windows->widget,&reset_info);
6241 }
6242 if (action_info.raised == MagickFalse)
6243 {
6244 if (event.xbutton.window == windows->widget.id)
6245 {
6246 if (MatteIsActive(action_info,event.xbutton))
6247 {
6248 if (*reply_info.text == '\0')
6249 (void) XBell(display,0);
6250 else
6251 state|=ExitState;
6252 }
6253 }
6254 action_info.raised=MagickTrue;
6255 XDrawBeveledButton(display,&windows->widget,&action_info);
6256 }
6257 if (cancel_info.raised == MagickFalse)
6258 {
6259 if (event.xbutton.window == windows->widget.id)
6260 if (MatteIsActive(cancel_info,event.xbutton))
6261 {
6262 *reply_info.text='\0';
6263 state|=ExitState;
6264 }
6265 cancel_info.raised=MagickTrue;
6266 XDrawBeveledButton(display,&windows->widget,&cancel_info);
6267 }
6268 break;
6269 }
6270 case ClientMessage:
6271 {
6272 /*
6273 If client window delete message, exit.
6274 */
6275 if (event.xclient.message_type != windows->wm_protocols)
6276 break;
6277 if (*event.xclient.data.l == (int) windows->wm_take_focus)
6278 {
6279 (void) XSetInputFocus(display,event.xclient.window,RevertToParent,
6280 (Time) event.xclient.data.l[1]);
6281 break;
6282 }
6283 if (*event.xclient.data.l != (int) windows->wm_delete_window)
6284 break;
6285 if (event.xclient.window == windows->widget.id)
6286 {
6287 *reply_info.text='\0';
6288 state|=ExitState;
6289 break;
6290 }
6291 break;
6292 }
6293 case ConfigureNotify:
6294 {
6295 /*
6296 Update widget configuration.
6297 */
6298 if (event.xconfigure.window != windows->widget.id)
6299 break;
6300 if ((event.xconfigure.width == (int) windows->widget.width) &&
6301 (event.xconfigure.height == (int) windows->widget.height))
6302 break;
6303 windows->widget.width=(unsigned int)
6304 MagickMax(event.xconfigure.width,(int) windows->widget.min_width);
6305 windows->widget.height=(unsigned int)
6306 MagickMax(event.xconfigure.height,(int) windows->widget.min_height);
6307 state|=UpdateConfigurationState;
6308 break;
6309 }
6310 case EnterNotify:
6311 {
6312 if (event.xcrossing.window != windows->widget.id)
6313 break;
6314 state&=(~InactiveWidgetState);
6315 break;
6316 }
6317 case Expose:
6318 {
6319 if (event.xexpose.window != windows->widget.id)
6320 break;
6321 if (event.xexpose.count != 0)
6322 break;
6323 state|=RedrawWidgetState;
6324 break;
6325 }
6326 case KeyPress:
6327 {
6328 static char
6329 command[MaxTextExtent];
6330
6331 static int
6332 length;
6333
6334 static KeySym
6335 key_symbol;
6336
6337 /*
6338 Respond to a user key press.
6339 */
6340 if (event.xkey.window != windows->widget.id)
6341 break;
6342 length=XLookupString((XKeyEvent *) &event.xkey,command,
6343 (int) sizeof(command),&key_symbol,(XComposeStatus *) NULL);
6344 *(command+length)='\0';
6345 if (AreaIsActive(scroll_info,event.xkey))
6346 {
6347 /*
6348 Move slider.
6349 */
6350 switch ((int) key_symbol)
6351 {
6352 case XK_Home:
6353 case XK_KP_Home:
6354 {
6355 slider_info.id=0;
6356 break;
6357 }
6358 case XK_Up:
6359 case XK_KP_Up:
6360 {
6361 slider_info.id--;
6362 break;
6363 }
6364 case XK_Down:
6365 case XK_KP_Down:
6366 {
6367 slider_info.id++;
6368 break;
6369 }
6370 case XK_Prior:
6371 case XK_KP_Prior:
6372 {
6373 slider_info.id-=visible_fonts;
6374 break;
6375 }
6376 case XK_Next:
6377 case XK_KP_Next:
6378 {
6379 slider_info.id+=visible_fonts;
6380 break;
6381 }
6382 case XK_End:
6383 case XK_KP_End:
6384 {
6385 slider_info.id=fonts;
6386 break;
6387 }
6388 }
6389 state|=RedrawListState;
6390 break;
6391 }
6392 if ((key_symbol == XK_Return) || (key_symbol == XK_KP_Enter))
6393 {
6394 /*
6395 Read new font or glob patterm.
6396 */
6397 if (*reply_info.text == '\0')
6398 break;
6399 (void) CopyMagickString(back_pattern,glob_pattern,MaxTextExtent);
6400 (void) CopyMagickString(glob_pattern,reply_info.text,MaxTextExtent);
6401 state|=UpdateListState;
6402 break;
6403 }
6404 if (key_symbol == XK_Control_L)
6405 {
6406 state|=ControlState;
6407 break;
6408 }
6409 if (state & ControlState)
6410 switch ((int) key_symbol)
6411 {
6412 case XK_u:
6413 case XK_U:
6414 {
6415 /*
6416 Erase the entire line of text.
6417 */
6418 *reply_info.text='\0';
6419 reply_info.cursor=reply_info.text;
6420 reply_info.marker=reply_info.text;
6421 reply_info.highlight=MagickFalse;
6422 break;
6423 }
6424 default:
6425 break;
6426 }
6427 XEditText(display,&reply_info,key_symbol,command,state);
6428 XDrawMatteText(display,&windows->widget,&reply_info);
6429 state|=JumpListState;
6430 break;
6431 }
6432 case KeyRelease:
6433 {
6434 static char
6435 command[MaxTextExtent];
6436
6437 static KeySym
6438 key_symbol;
6439
6440 /*
6441 Respond to a user key release.
6442 */
6443 if (event.xkey.window != windows->widget.id)
6444 break;
6445 (void) XLookupString((XKeyEvent *) &event.xkey,command,
6446 (int) sizeof(command),&key_symbol,(XComposeStatus *) NULL);
6447 if (key_symbol == XK_Control_L)
6448 state&=(~ControlState);
6449 break;
6450 }
6451 case LeaveNotify:
6452 {
6453 if (event.xcrossing.window != windows->widget.id)
6454 break;
6455 state|=InactiveWidgetState;
6456 break;
6457 }
6458 case MapNotify:
6459 {
6460 mask&=(~CWX);
6461 mask&=(~CWY);
6462 break;
6463 }
6464 case MotionNotify:
6465 {
6466 /*
6467 Discard pending button motion events.
6468 */
6469 while (XCheckMaskEvent(display,ButtonMotionMask,&event)) ;
6470 if (slider_info.active)
6471 {
6472 /*
6473 Move slider matte.
6474 */
6475 slider_info.y=event.xmotion.y-
6476 ((slider_info.height+slider_info.bevel_width) >> 1)+1;
6477 if (slider_info.y < slider_info.min_y)
6478 slider_info.y=slider_info.min_y;
6479 if (slider_info.y > slider_info.max_y)
6480 slider_info.y=slider_info.max_y;
6481 slider_info.id=0;
6482 if (slider_info.y != slider_info.min_y)
6483 slider_info.id=(fonts*(slider_info.y-slider_info.min_y+1))/
6484 (slider_info.max_y-slider_info.min_y+1);
6485 state|=RedrawListState;
6486 break;
6487 }
6488 if (state & InactiveWidgetState)
6489 break;
6490 if (back_info.raised == MatteIsActive(back_info,event.xmotion))
6491 {
6492 /*
6493 Back button status changed.
6494 */
6495 back_info.raised=!back_info.raised;
6496 XDrawBeveledButton(display,&windows->widget,&back_info);
6497 break;
6498 }
6499 if (reset_info.raised == MatteIsActive(reset_info,event.xmotion))
6500 {
6501 /*
6502 Reset button status changed.
6503 */
6504 reset_info.raised=!reset_info.raised;
6505 XDrawBeveledButton(display,&windows->widget,&reset_info);
6506 break;
6507 }
6508 if (action_info.raised == MatteIsActive(action_info,event.xmotion))
6509 {
6510 /*
6511 Action button status changed.
6512 */
6513 action_info.raised=action_info.raised == MagickFalse ?
6514 MagickTrue : MagickFalse;
6515 XDrawBeveledButton(display,&windows->widget,&action_info);
6516 break;
6517 }
6518 if (cancel_info.raised == MatteIsActive(cancel_info,event.xmotion))
6519 {
6520 /*
6521 Cancel button status changed.
6522 */
6523 cancel_info.raised=cancel_info.raised == MagickFalse ?
6524 MagickTrue : MagickFalse;
6525 XDrawBeveledButton(display,&windows->widget,&cancel_info);
6526 break;
6527 }
6528 break;
6529 }
6530 case SelectionClear:
6531 {
6532 reply_info.highlight=MagickFalse;
6533 XDrawMatteText(display,&windows->widget,&reply_info);
6534 break;
6535 }
6536 case SelectionNotify:
6537 {
6538 Atom
6539 type;
6540
6541 int
6542 format;
6543
6544 unsigned char
6545 *data;
6546
cristyf2faecf2010-05-28 19:19:36 +00006547 unsigned long
cristy3ed852e2009-09-05 21:47:34 +00006548 after,
6549 length;
6550
6551 /*
6552 Obtain response from primary selection.
6553 */
6554 if (event.xselection.property == (Atom) None)
6555 break;
6556 status=XGetWindowProperty(display,event.xselection.requestor,
6557 event.xselection.property,0L,2047L,MagickTrue,XA_STRING,&type,
6558 &format,&length,&after,&data);
6559 if ((status != Success) || (type != XA_STRING) || (format == 32) ||
6560 (length == 0))
6561 break;
6562 if ((Extent(reply_info.text)+length) >= MaxTextExtent)
6563 (void) XBell(display,0);
6564 else
6565 {
6566 /*
6567 Insert primary selection in reply text.
6568 */
6569 *(data+length)='\0';
6570 XEditText(display,&reply_info,(KeySym) XK_Insert,(char *) data,
6571 state);
6572 XDrawMatteText(display,&windows->widget,&reply_info);
6573 state|=JumpListState;
6574 state|=RedrawActionState;
6575 }
6576 (void) XFree((void *) data);
6577 break;
6578 }
6579 case SelectionRequest:
6580 {
6581 XSelectionEvent
6582 notify;
6583
6584 XSelectionRequestEvent
6585 *request;
6586
6587 /*
6588 Set XA_PRIMARY selection.
6589 */
6590 request=(&(event.xselectionrequest));
6591 (void) XChangeProperty(request->display,request->requestor,
6592 request->property,request->target,8,PropModeReplace,
6593 (unsigned char *) primary_selection,Extent(primary_selection));
6594 notify.type=SelectionNotify;
6595 notify.display=request->display;
6596 notify.requestor=request->requestor;
6597 notify.selection=request->selection;
6598 notify.target=request->target;
6599 notify.time=request->time;
6600 if (request->property == None)
6601 notify.property=request->target;
6602 else
6603 notify.property=request->property;
6604 (void) XSendEvent(request->display,request->requestor,False,0,
6605 (XEvent *) &notify);
6606 }
6607 default:
6608 break;
6609 }
6610 } while ((state & ExitState) == 0);
6611 XSetCursorState(display,windows,MagickFalse);
6612 (void) XWithdrawWindow(display,windows->widget.id,windows->widget.screen);
6613 XCheckRefreshWindows(display,windows);
6614 /*
6615 Free font list.
6616 */
6617 (void) XFreeFontNames(listhead);
6618 fontlist=(char **) RelinquishMagickMemory(fontlist);
6619}
6620
6621/*
6622%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6623% %
6624% %
6625% %
6626% X I n f o W i d g e t %
6627% %
6628% %
6629% %
6630%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6631%
6632% XInfoWidget() displays text in the Info widget. The purpose is to inform
6633% the user that what activity is currently being performed (e.g. reading
6634% an image, rotating an image, etc.).
6635%
6636% The format of the XInfoWidget method is:
6637%
6638% void XInfoWidget(Display *display,XWindows *windows,const char *activity)
6639%
6640% A description of each parameter follows:
6641%
6642% o display: Specifies a connection to an X server; returned from
6643% XOpenDisplay.
6644%
6645% o window: Specifies a pointer to a XWindows structure.
6646%
6647% o activity: This character string reflects the current activity and is
6648% displayed in the Info widget.
6649%
6650*/
6651MagickExport void XInfoWidget(Display *display,XWindows *windows,
6652 const char *activity)
6653{
6654 unsigned int
6655 height,
6656 margin,
6657 width;
6658
6659 XFontStruct
6660 *font_info;
6661
6662 XWindowChanges
6663 window_changes;
6664
6665 /*
6666 Map Info widget.
6667 */
6668 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
6669 assert(display != (Display *) NULL);
6670 assert(windows != (XWindows *) NULL);
6671 assert(activity != (char *) NULL);
6672 font_info=windows->info.font_info;
6673 width=WidgetTextWidth(font_info,(char *) activity)+((3*QuantumMargin) >> 1)+4;
6674 height=(unsigned int) (((6*(font_info->ascent+font_info->descent)) >> 2)+4);
6675 if ((windows->info.width != width) || (windows->info.height != height))
6676 {
6677 /*
6678 Size Info widget to accommodate the activity text.
6679 */
6680 windows->info.width=width;
6681 windows->info.height=height;
6682 window_changes.width=(int) width;
6683 window_changes.height=(int) height;
6684 (void) XReconfigureWMWindow(display,windows->info.id,windows->info.screen,
6685 (unsigned int) (CWWidth | CWHeight),&window_changes);
6686 }
6687 if (windows->info.mapped == MagickFalse)
6688 {
6689 (void) XMapRaised(display,windows->info.id);
6690 windows->info.mapped=MagickTrue;
6691 }
6692 /*
6693 Initialize Info matte information.
6694 */
6695 height=(unsigned int) (font_info->ascent+font_info->descent);
6696 XGetWidgetInfo(activity,&monitor_info);
6697 monitor_info.bevel_width--;
6698 margin=monitor_info.bevel_width+((windows->info.height-height) >> 1)-2;
6699 monitor_info.center=MagickFalse;
6700 monitor_info.x=(int) margin;
6701 monitor_info.y=(int) margin;
6702 monitor_info.width=windows->info.width-(margin << 1);
6703 monitor_info.height=windows->info.height-(margin << 1)+1;
6704 /*
6705 Draw Info widget.
6706 */
6707 monitor_info.raised=MagickFalse;
6708 XDrawBeveledMatte(display,&windows->info,&monitor_info);
6709 monitor_info.raised=MagickTrue;
6710 XDrawWidgetText(display,&windows->info,&monitor_info);
6711}
6712
6713/*
6714%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6715% %
6716% %
6717% %
6718% X L i s t B r o w s e r W i d g e t %
6719% %
6720% %
6721% %
6722%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6723%
6724% XListBrowserWidget() displays a List Browser widget with a query to the
6725% user. The user keys a reply or select a reply from the list. Finally, the
6726% user presses the Action or Cancel button to exit. The typed text is
6727% returned as the reply function parameter.
6728%
6729% The format of the XListBrowserWidget method is:
6730%
6731% void XListBrowserWidget(Display *display,XWindows *windows,
6732% XWindowInfo *window_info,const char **list,const char *action,
6733% const char *query,char *reply)
6734%
6735% A description of each parameter follows:
6736%
6737% o display: Specifies a connection to an X server; returned from
6738% XOpenDisplay.
6739%
6740% o window: Specifies a pointer to a XWindows structure.
6741%
6742% o list: Specifies a pointer to an array of strings. The user can
6743% select from these strings as a possible reply value.
6744%
6745% o action: Specifies a pointer to the action of this widget.
6746%
6747% o query: Specifies a pointer to the query to present to the user.
6748%
6749% o reply: the response from the user is returned in this parameter.
6750%
6751*/
6752MagickExport void XListBrowserWidget(Display *display,XWindows *windows,
6753 XWindowInfo *window_info,const char **list,const char *action,
6754 const char *query,char *reply)
6755{
6756#define CancelButtonText "Cancel"
6757
6758 char
6759 primary_selection[MaxTextExtent];
6760
6761 int
6762 x;
6763
6764 register int
6765 i;
6766
6767 static MagickStatusType
6768 mask = (MagickStatusType) (CWWidth | CWHeight | CWX | CWY);
6769
6770 Status
6771 status;
6772
6773 unsigned int
6774 entries,
6775 height,
6776 text_width,
6777 visible_entries,
6778 width;
6779
cristybb503372010-05-27 20:51:26 +00006780 size_t
cristy3ed852e2009-09-05 21:47:34 +00006781 delay,
6782 state;
6783
6784 XEvent
6785 event;
6786
6787 XFontStruct
6788 *font_info;
6789
6790 XTextProperty
6791 window_name;
6792
6793 XWidgetInfo
6794 action_info,
6795 cancel_info,
6796 expose_info,
6797 list_info,
6798 north_info,
6799 reply_info,
6800 scroll_info,
6801 selection_info,
6802 slider_info,
6803 south_info,
6804 text_info;
6805
6806 XWindowChanges
6807 window_changes;
6808
6809 /*
6810 Count the number of entries in the list.
6811 */
6812 assert(display != (Display *) NULL);
6813 assert(windows != (XWindows *) NULL);
6814 assert(window_info != (XWindowInfo *) NULL);
6815 assert(list != (const char **) NULL);
6816 assert(action != (char *) NULL);
6817 assert(query != (char *) NULL);
6818 assert(reply != (char *) NULL);
6819 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",action);
6820 XSetCursorState(display,windows,MagickTrue);
6821 XCheckRefreshWindows(display,windows);
6822 if (list == (const char **) NULL)
6823 {
6824 XNoticeWidget(display,windows,"No text to browse:",(char *) NULL);
6825 return;
6826 }
6827 for (entries=0; ; entries++)
6828 if (list[entries] == (char *) NULL)
6829 break;
6830 /*
6831 Determine Font Browser widget attributes.
6832 */
6833 font_info=window_info->font_info;
6834 text_width=WidgetTextWidth(font_info,(char *) query);
6835 for (i=0; i < (int) entries; i++)
6836 if (WidgetTextWidth(font_info,(char *) list[i]) > text_width)
6837 text_width=WidgetTextWidth(font_info,(char *) list[i]);
6838 width=WidgetTextWidth(font_info,(char *) action);
6839 if (WidgetTextWidth(font_info,CancelButtonText) > width)
6840 width=WidgetTextWidth(font_info,CancelButtonText);
6841 width+=QuantumMargin;
6842 height=(unsigned int) (font_info->ascent+font_info->descent);
6843 /*
6844 Position List Browser widget.
6845 */
6846 window_info->width=(unsigned int) MagickMin((int) text_width,(int)
6847 MaxTextWidth)+((9*QuantumMargin) >> 1);
6848 window_info->min_width=(unsigned int) (MinTextWidth+4*QuantumMargin);
6849 if (window_info->width < window_info->min_width)
6850 window_info->width=window_info->min_width;
6851 window_info->height=(unsigned int)
6852 (((81*height) >> 2)+((13*QuantumMargin) >> 1)+4);
6853 window_info->min_height=(unsigned int)
6854 (((23*height) >> 1)+((13*QuantumMargin) >> 1)+4);
6855 if (window_info->height < window_info->min_height)
6856 window_info->height=window_info->min_height;
6857 XConstrainWindowPosition(display,window_info);
6858 /*
6859 Map List Browser widget.
6860 */
6861 (void) CopyMagickString(window_info->name,"Browse",MaxTextExtent);
6862 status=XStringListToTextProperty(&window_info->name,1,&window_name);
6863 if (status != False)
6864 {
6865 XSetWMName(display,window_info->id,&window_name);
6866 XSetWMIconName(display,windows->widget.id,&window_name);
6867 (void) XFree((void *) window_name.value);
6868 }
6869 window_changes.width=(int) window_info->width;
6870 window_changes.height=(int) window_info->height;
6871 window_changes.x=window_info->x;
6872 window_changes.y=window_info->y;
6873 (void) XReconfigureWMWindow(display,window_info->id,window_info->screen,mask,
6874 &window_changes);
6875 (void) XMapRaised(display,window_info->id);
6876 window_info->mapped=MagickFalse;
6877 /*
6878 Respond to X events.
6879 */
6880 XGetWidgetInfo((char *) NULL,&slider_info);
6881 XGetWidgetInfo((char *) NULL,&north_info);
6882 XGetWidgetInfo((char *) NULL,&south_info);
6883 XGetWidgetInfo((char *) NULL,&expose_info);
6884 visible_entries=0;
6885 delay=SuspendTime << 2;
6886 state=UpdateConfigurationState;
6887 do
6888 {
6889 if (state & UpdateConfigurationState)
6890 {
6891 int
6892 id;
6893
6894 /*
6895 Initialize button information.
6896 */
6897 XGetWidgetInfo(CancelButtonText,&cancel_info);
6898 cancel_info.width=width;
6899 cancel_info.height=(unsigned int) ((3*height) >> 1);
6900 cancel_info.x=(int)
6901 (window_info->width-cancel_info.width-QuantumMargin-2);
6902 cancel_info.y=(int)
6903 (window_info->height-cancel_info.height-QuantumMargin);
6904 XGetWidgetInfo(action,&action_info);
6905 action_info.width=width;
6906 action_info.height=(unsigned int) ((3*height) >> 1);
6907 action_info.x=cancel_info.x-(cancel_info.width+(QuantumMargin >> 1)+
6908 (action_info.bevel_width << 1));
6909 action_info.y=cancel_info.y;
6910 /*
6911 Initialize reply information.
6912 */
6913 XGetWidgetInfo(reply,&reply_info);
6914 reply_info.raised=MagickFalse;
6915 reply_info.bevel_width--;
6916 reply_info.width=window_info->width-((4*QuantumMargin) >> 1);
6917 reply_info.height=height << 1;
6918 reply_info.x=QuantumMargin;
6919 reply_info.y=action_info.y-reply_info.height-QuantumMargin;
6920 /*
6921 Initialize scroll information.
6922 */
6923 XGetWidgetInfo((char *) NULL,&scroll_info);
6924 scroll_info.bevel_width--;
6925 scroll_info.width=height;
6926 scroll_info.height=(unsigned int)
6927 (reply_info.y-((6*QuantumMargin) >> 1)-height);
6928 scroll_info.x=reply_info.x+(reply_info.width-scroll_info.width);
6929 scroll_info.y=((5*QuantumMargin) >> 1)+height-reply_info.bevel_width;
6930 scroll_info.raised=MagickFalse;
6931 scroll_info.trough=MagickTrue;
6932 north_info=scroll_info;
6933 north_info.raised=MagickTrue;
6934 north_info.width-=(north_info.bevel_width << 1);
6935 north_info.height=north_info.width-1;
6936 north_info.x+=north_info.bevel_width;
6937 north_info.y+=north_info.bevel_width;
6938 south_info=north_info;
6939 south_info.y=scroll_info.y+scroll_info.height-scroll_info.bevel_width-
6940 south_info.height;
6941 id=slider_info.id;
6942 slider_info=north_info;
6943 slider_info.id=id;
6944 slider_info.width-=2;
6945 slider_info.min_y=north_info.y+north_info.height+north_info.bevel_width+
6946 slider_info.bevel_width+2;
6947 slider_info.height=scroll_info.height-((slider_info.min_y-
6948 scroll_info.y+1) << 1)+4;
6949 visible_entries=scroll_info.height/(height+(height >> 3));
6950 if (entries > visible_entries)
6951 slider_info.height=(visible_entries*slider_info.height)/entries;
6952 slider_info.max_y=south_info.y-south_info.bevel_width-
6953 slider_info.bevel_width-2;
6954 slider_info.x=scroll_info.x+slider_info.bevel_width+1;
6955 slider_info.y=slider_info.min_y;
6956 expose_info=scroll_info;
6957 expose_info.y=slider_info.y;
6958 /*
6959 Initialize list information.
6960 */
6961 XGetWidgetInfo((char *) NULL,&list_info);
6962 list_info.raised=MagickFalse;
6963 list_info.bevel_width--;
6964 list_info.width=(unsigned int)
6965 (scroll_info.x-reply_info.x-(QuantumMargin >> 1));
6966 list_info.height=scroll_info.height;
6967 list_info.x=reply_info.x;
6968 list_info.y=scroll_info.y;
6969 if (window_info->mapped == MagickFalse)
6970 for (i=0; i < (int) entries; i++)
6971 if (LocaleCompare(list[i],reply) == 0)
6972 {
6973 list_info.id=i;
6974 slider_info.id=i-(visible_entries >> 1);
6975 if (slider_info.id < 0)
6976 slider_info.id=0;
6977 }
6978 /*
6979 Initialize text information.
6980 */
6981 XGetWidgetInfo(query,&text_info);
6982 text_info.width=reply_info.width;
6983 text_info.height=height;
6984 text_info.x=list_info.x-(QuantumMargin >> 1);
6985 text_info.y=QuantumMargin;
6986 /*
6987 Initialize selection information.
6988 */
6989 XGetWidgetInfo((char *) NULL,&selection_info);
6990 selection_info.center=MagickFalse;
6991 selection_info.width=list_info.width;
6992 selection_info.height=(unsigned int) ((9*height) >> 3);
6993 selection_info.x=list_info.x;
6994 state&=(~UpdateConfigurationState);
6995 }
6996 if (state & RedrawWidgetState)
6997 {
6998 /*
6999 Redraw List Browser window.
7000 */
7001 XDrawWidgetText(display,window_info,&text_info);
7002 XDrawBeveledMatte(display,window_info,&list_info);
7003 XDrawBeveledMatte(display,window_info,&scroll_info);
7004 XDrawTriangleNorth(display,window_info,&north_info);
7005 XDrawBeveledButton(display,window_info,&slider_info);
7006 XDrawTriangleSouth(display,window_info,&south_info);
7007 XDrawBeveledMatte(display,window_info,&reply_info);
7008 XDrawMatteText(display,window_info,&reply_info);
7009 XDrawBeveledButton(display,window_info,&action_info);
7010 XDrawBeveledButton(display,window_info,&cancel_info);
7011 XHighlightWidget(display,window_info,BorderOffset,BorderOffset);
7012 selection_info.id=(~0);
7013 state|=RedrawActionState;
7014 state|=RedrawListState;
7015 state&=(~RedrawWidgetState);
7016 }
7017 if (state & RedrawListState)
7018 {
7019 /*
7020 Determine slider id and position.
7021 */
7022 if (slider_info.id >= (int) (entries-visible_entries))
7023 slider_info.id=(int) (entries-visible_entries);
7024 if ((slider_info.id < 0) || (entries <= visible_entries))
7025 slider_info.id=0;
7026 slider_info.y=slider_info.min_y;
7027 if (entries > 0)
7028 slider_info.y+=
7029 slider_info.id*(slider_info.max_y-slider_info.min_y+1)/entries;
7030 if (slider_info.id != selection_info.id)
7031 {
7032 /*
7033 Redraw scroll bar and file names.
7034 */
7035 selection_info.id=slider_info.id;
7036 selection_info.y=list_info.y+(height >> 3)+2;
7037 for (i=0; i < (int) visible_entries; i++)
7038 {
7039 selection_info.raised=(slider_info.id+i) != list_info.id ?
7040 MagickTrue : MagickFalse;
7041 selection_info.text=(char *) NULL;
7042 if ((slider_info.id+i) < (int) entries)
7043 selection_info.text=(char *) list[slider_info.id+i];
7044 XDrawWidgetText(display,window_info,&selection_info);
7045 selection_info.y+=(int) selection_info.height;
7046 }
7047 /*
7048 Update slider.
7049 */
7050 if (slider_info.y > expose_info.y)
7051 {
7052 expose_info.height=(unsigned int) slider_info.y-expose_info.y;
7053 expose_info.y=slider_info.y-expose_info.height-
7054 slider_info.bevel_width-1;
7055 }
7056 else
7057 {
7058 expose_info.height=(unsigned int) expose_info.y-slider_info.y;
7059 expose_info.y=slider_info.y+slider_info.height+
7060 slider_info.bevel_width+1;
7061 }
7062 XDrawTriangleNorth(display,window_info,&north_info);
7063 XDrawMatte(display,window_info,&expose_info);
7064 XDrawBeveledButton(display,window_info,&slider_info);
7065 XDrawTriangleSouth(display,window_info,&south_info);
7066 expose_info.y=slider_info.y;
7067 }
7068 state&=(~RedrawListState);
7069 }
7070 /*
7071 Wait for next event.
7072 */
7073 if (north_info.raised && south_info.raised)
7074 (void) XIfEvent(display,&event,XScreenEvent,(char *) windows);
7075 else
7076 {
7077 /*
7078 Brief delay before advancing scroll bar.
7079 */
7080 XDelay(display,delay);
7081 delay=SuspendTime;
7082 (void) XCheckIfEvent(display,&event,XScreenEvent,(char *) windows);
7083 if (north_info.raised == MagickFalse)
7084 if (slider_info.id > 0)
7085 {
7086 /*
7087 Move slider up.
7088 */
7089 slider_info.id--;
7090 state|=RedrawListState;
7091 }
7092 if (south_info.raised == MagickFalse)
7093 if (slider_info.id < (int) entries)
7094 {
7095 /*
7096 Move slider down.
7097 */
7098 slider_info.id++;
7099 state|=RedrawListState;
7100 }
7101 if (event.type != ButtonRelease)
7102 continue;
7103 }
7104 switch (event.type)
7105 {
7106 case ButtonPress:
7107 {
7108 if (MatteIsActive(slider_info,event.xbutton))
7109 {
7110 /*
7111 Track slider.
7112 */
7113 slider_info.active=MagickTrue;
7114 break;
7115 }
7116 if (MatteIsActive(north_info,event.xbutton))
7117 if (slider_info.id > 0)
7118 {
7119 /*
7120 Move slider up.
7121 */
7122 north_info.raised=MagickFalse;
7123 slider_info.id--;
7124 state|=RedrawListState;
7125 break;
7126 }
7127 if (MatteIsActive(south_info,event.xbutton))
7128 if (slider_info.id < (int) entries)
7129 {
7130 /*
7131 Move slider down.
7132 */
7133 south_info.raised=MagickFalse;
7134 slider_info.id++;
7135 state|=RedrawListState;
7136 break;
7137 }
7138 if (MatteIsActive(scroll_info,event.xbutton))
7139 {
7140 /*
7141 Move slider.
7142 */
7143 if (event.xbutton.y < slider_info.y)
7144 slider_info.id-=(visible_entries-1);
7145 else
7146 slider_info.id+=(visible_entries-1);
7147 state|=RedrawListState;
7148 break;
7149 }
7150 if (MatteIsActive(list_info,event.xbutton))
7151 {
7152 int
7153 id;
7154
7155 /*
7156 User pressed list matte.
7157 */
7158 id=slider_info.id+(event.xbutton.y-(list_info.y+(height >> 1))+1)/
7159 selection_info.height;
7160 if (id >= (int) entries)
7161 break;
7162 (void) CopyMagickString(reply_info.text,list[id],MaxTextExtent);
7163 reply_info.highlight=MagickFalse;
7164 reply_info.marker=reply_info.text;
7165 reply_info.cursor=reply_info.text+Extent(reply_info.text);
7166 XDrawMatteText(display,window_info,&reply_info);
7167 selection_info.id=(~0);
7168 if (id == list_info.id)
7169 {
7170 action_info.raised=MagickFalse;
7171 XDrawBeveledButton(display,window_info,&action_info);
7172 state|=ExitState;
7173 }
7174 list_info.id=id;
7175 state|=RedrawListState;
7176 break;
7177 }
7178 if (MatteIsActive(action_info,event.xbutton))
7179 {
7180 /*
7181 User pressed action button.
7182 */
7183 action_info.raised=MagickFalse;
7184 XDrawBeveledButton(display,window_info,&action_info);
7185 break;
7186 }
7187 if (MatteIsActive(cancel_info,event.xbutton))
7188 {
7189 /*
7190 User pressed Cancel button.
7191 */
7192 cancel_info.raised=MagickFalse;
7193 XDrawBeveledButton(display,window_info,&cancel_info);
7194 break;
7195 }
7196 if (MatteIsActive(reply_info,event.xbutton) == MagickFalse)
7197 break;
7198 if (event.xbutton.button != Button2)
7199 {
7200 static Time
7201 click_time;
7202
7203 /*
7204 Move text cursor to position of button press.
7205 */
7206 x=event.xbutton.x-reply_info.x-(QuantumMargin >> 2);
7207 for (i=1; i <= Extent(reply_info.marker); i++)
7208 if (XTextWidth(font_info,reply_info.marker,i) > x)
7209 break;
7210 reply_info.cursor=reply_info.marker+i-1;
7211 if (event.xbutton.time > (click_time+DoubleClick))
7212 reply_info.highlight=MagickFalse;
7213 else
7214 {
7215 /*
7216 Become the XA_PRIMARY selection owner.
7217 */
7218 (void) CopyMagickString(primary_selection,reply_info.text,
7219 MaxTextExtent);
7220 (void) XSetSelectionOwner(display,XA_PRIMARY,window_info->id,
7221 event.xbutton.time);
7222 reply_info.highlight=XGetSelectionOwner(display,XA_PRIMARY) ==
7223 window_info->id ? MagickTrue : MagickFalse;
7224 }
7225 XDrawMatteText(display,window_info,&reply_info);
7226 click_time=event.xbutton.time;
7227 break;
7228 }
7229 /*
7230 Request primary selection.
7231 */
7232 (void) XConvertSelection(display,XA_PRIMARY,XA_STRING,XA_STRING,
7233 window_info->id,event.xbutton.time);
7234 break;
7235 }
7236 case ButtonRelease:
7237 {
7238 if (window_info->mapped == MagickFalse)
7239 break;
7240 if (north_info.raised == MagickFalse)
7241 {
7242 /*
7243 User released up button.
7244 */
7245 delay=SuspendTime << 2;
7246 north_info.raised=MagickTrue;
7247 XDrawTriangleNorth(display,window_info,&north_info);
7248 }
7249 if (south_info.raised == MagickFalse)
7250 {
7251 /*
7252 User released down button.
7253 */
7254 delay=SuspendTime << 2;
7255 south_info.raised=MagickTrue;
7256 XDrawTriangleSouth(display,window_info,&south_info);
7257 }
7258 if (slider_info.active)
7259 {
7260 /*
7261 Stop tracking slider.
7262 */
7263 slider_info.active=MagickFalse;
7264 break;
7265 }
7266 if (action_info.raised == MagickFalse)
7267 {
7268 if (event.xbutton.window == window_info->id)
7269 {
7270 if (MatteIsActive(action_info,event.xbutton))
7271 {
7272 if (*reply_info.text == '\0')
7273 (void) XBell(display,0);
7274 else
7275 state|=ExitState;
7276 }
7277 }
7278 action_info.raised=MagickTrue;
7279 XDrawBeveledButton(display,window_info,&action_info);
7280 }
7281 if (cancel_info.raised == MagickFalse)
7282 {
7283 if (event.xbutton.window == window_info->id)
7284 if (MatteIsActive(cancel_info,event.xbutton))
7285 {
7286 *reply_info.text='\0';
7287 state|=ExitState;
7288 }
7289 cancel_info.raised=MagickTrue;
7290 XDrawBeveledButton(display,window_info,&cancel_info);
7291 }
7292 if (MatteIsActive(reply_info,event.xbutton) == MagickFalse)
7293 break;
7294 break;
7295 }
7296 case ClientMessage:
7297 {
7298 /*
7299 If client window delete message, exit.
7300 */
7301 if (event.xclient.message_type != windows->wm_protocols)
7302 break;
7303 if (*event.xclient.data.l == (int) windows->wm_take_focus)
7304 {
7305 (void) XSetInputFocus(display,event.xclient.window,RevertToParent,
7306 (Time) event.xclient.data.l[1]);
7307 break;
7308 }
7309 if (*event.xclient.data.l != (int) windows->wm_delete_window)
7310 break;
7311 if (event.xclient.window == window_info->id)
7312 {
7313 *reply_info.text='\0';
7314 state|=ExitState;
7315 break;
7316 }
7317 break;
7318 }
7319 case ConfigureNotify:
7320 {
7321 /*
7322 Update widget configuration.
7323 */
7324 if (event.xconfigure.window != window_info->id)
7325 break;
7326 if ((event.xconfigure.width == (int) window_info->width) &&
7327 (event.xconfigure.height == (int) window_info->height))
7328 break;
7329 window_info->width=(unsigned int)
7330 MagickMax(event.xconfigure.width,(int) window_info->min_width);
7331 window_info->height=(unsigned int)
7332 MagickMax(event.xconfigure.height,(int) window_info->min_height);
7333 state|=UpdateConfigurationState;
7334 break;
7335 }
7336 case EnterNotify:
7337 {
7338 if (event.xcrossing.window != window_info->id)
7339 break;
7340 state&=(~InactiveWidgetState);
7341 break;
7342 }
7343 case Expose:
7344 {
7345 if (event.xexpose.window != window_info->id)
7346 break;
7347 if (event.xexpose.count != 0)
7348 break;
7349 state|=RedrawWidgetState;
7350 break;
7351 }
7352 case KeyPress:
7353 {
7354 static char
7355 command[MaxTextExtent];
7356
7357 static int
7358 length;
7359
7360 static KeySym
7361 key_symbol;
7362
7363 /*
7364 Respond to a user key press.
7365 */
7366 if (event.xkey.window != window_info->id)
7367 break;
7368 length=XLookupString((XKeyEvent *) &event.xkey,command,
7369 (int) sizeof(command),&key_symbol,(XComposeStatus *) NULL);
7370 *(command+length)='\0';
7371 if (AreaIsActive(scroll_info,event.xkey))
7372 {
7373 /*
7374 Move slider.
7375 */
7376 switch ((int) key_symbol)
7377 {
7378 case XK_Home:
7379 case XK_KP_Home:
7380 {
7381 slider_info.id=0;
7382 break;
7383 }
7384 case XK_Up:
7385 case XK_KP_Up:
7386 {
7387 slider_info.id--;
7388 break;
7389 }
7390 case XK_Down:
7391 case XK_KP_Down:
7392 {
7393 slider_info.id++;
7394 break;
7395 }
7396 case XK_Prior:
7397 case XK_KP_Prior:
7398 {
7399 slider_info.id-=visible_entries;
7400 break;
7401 }
7402 case XK_Next:
7403 case XK_KP_Next:
7404 {
7405 slider_info.id+=visible_entries;
7406 break;
7407 }
7408 case XK_End:
7409 case XK_KP_End:
7410 {
7411 slider_info.id=(int) entries;
7412 break;
7413 }
7414 }
7415 state|=RedrawListState;
7416 break;
7417 }
7418 if ((key_symbol == XK_Return) || (key_symbol == XK_KP_Enter))
7419 {
7420 /*
7421 Read new entry.
7422 */
7423 if (*reply_info.text == '\0')
7424 break;
7425 action_info.raised=MagickFalse;
7426 XDrawBeveledButton(display,window_info,&action_info);
7427 state|=ExitState;
7428 break;
7429 }
7430 if (key_symbol == XK_Control_L)
7431 {
7432 state|=ControlState;
7433 break;
7434 }
7435 if (state & ControlState)
7436 switch ((int) key_symbol)
7437 {
7438 case XK_u:
7439 case XK_U:
7440 {
7441 /*
7442 Erase the entire line of text.
7443 */
7444 *reply_info.text='\0';
7445 reply_info.cursor=reply_info.text;
7446 reply_info.marker=reply_info.text;
7447 reply_info.highlight=MagickFalse;
7448 break;
7449 }
7450 default:
7451 break;
7452 }
7453 XEditText(display,&reply_info,key_symbol,command,state);
7454 XDrawMatteText(display,window_info,&reply_info);
7455 break;
7456 }
7457 case KeyRelease:
7458 {
7459 static char
7460 command[MaxTextExtent];
7461
7462 static KeySym
7463 key_symbol;
7464
7465 /*
7466 Respond to a user key release.
7467 */
7468 if (event.xkey.window != window_info->id)
7469 break;
7470 (void) XLookupString((XKeyEvent *) &event.xkey,command,
7471 (int) sizeof(command),&key_symbol,(XComposeStatus *) NULL);
7472 if (key_symbol == XK_Control_L)
7473 state&=(~ControlState);
7474 break;
7475 }
7476 case LeaveNotify:
7477 {
7478 if (event.xcrossing.window != window_info->id)
7479 break;
7480 state|=InactiveWidgetState;
7481 break;
7482 }
7483 case MapNotify:
7484 {
7485 mask&=(~CWX);
7486 mask&=(~CWY);
7487 break;
7488 }
7489 case MotionNotify:
7490 {
7491 /*
7492 Discard pending button motion events.
7493 */
7494 while (XCheckMaskEvent(display,ButtonMotionMask,&event)) ;
7495 if (slider_info.active)
7496 {
7497 /*
7498 Move slider matte.
7499 */
7500 slider_info.y=event.xmotion.y-
7501 ((slider_info.height+slider_info.bevel_width) >> 1)+1;
7502 if (slider_info.y < slider_info.min_y)
7503 slider_info.y=slider_info.min_y;
7504 if (slider_info.y > slider_info.max_y)
7505 slider_info.y=slider_info.max_y;
7506 slider_info.id=0;
7507 if (slider_info.y != slider_info.min_y)
7508 slider_info.id=(int) ((entries*(slider_info.y-
7509 slider_info.min_y+1))/(slider_info.max_y-slider_info.min_y+1));
7510 state|=RedrawListState;
7511 break;
7512 }
7513 if (state & InactiveWidgetState)
7514 break;
7515 if (action_info.raised == MatteIsActive(action_info,event.xmotion))
7516 {
7517 /*
7518 Action button status changed.
7519 */
7520 action_info.raised=action_info.raised == MagickFalse ?
7521 MagickTrue : MagickFalse;
7522 XDrawBeveledButton(display,window_info,&action_info);
7523 break;
7524 }
7525 if (cancel_info.raised == MatteIsActive(cancel_info,event.xmotion))
7526 {
7527 /*
7528 Cancel button status changed.
7529 */
7530 cancel_info.raised=cancel_info.raised == MagickFalse ?
7531 MagickTrue : MagickFalse;
7532 XDrawBeveledButton(display,window_info,&cancel_info);
7533 break;
7534 }
7535 break;
7536 }
7537 case SelectionClear:
7538 {
7539 reply_info.highlight=MagickFalse;
7540 XDrawMatteText(display,window_info,&reply_info);
7541 break;
7542 }
7543 case SelectionNotify:
7544 {
7545 Atom
7546 type;
7547
7548 int
7549 format;
7550
7551 unsigned char
7552 *data;
7553
cristyf2faecf2010-05-28 19:19:36 +00007554 unsigned long
cristy3ed852e2009-09-05 21:47:34 +00007555 after,
7556 length;
7557
7558 /*
7559 Obtain response from primary selection.
7560 */
7561 if (event.xselection.property == (Atom) None)
7562 break;
7563 status=XGetWindowProperty(display,
7564 event.xselection.requestor,event.xselection.property,0L,2047L,
7565 MagickTrue,XA_STRING,&type,&format,&length,&after,&data);
7566 if ((status != Success) || (type != XA_STRING) || (format == 32) ||
7567 (length == 0))
7568 break;
7569 if ((Extent(reply_info.text)+length) >= MaxTextExtent)
7570 (void) XBell(display,0);
7571 else
7572 {
7573 /*
7574 Insert primary selection in reply text.
7575 */
7576 *(data+length)='\0';
7577 XEditText(display,&reply_info,(KeySym) XK_Insert,(char *) data,
7578 state);
7579 XDrawMatteText(display,window_info,&reply_info);
7580 state|=RedrawActionState;
7581 }
7582 (void) XFree((void *) data);
7583 break;
7584 }
7585 case SelectionRequest:
7586 {
7587 XSelectionEvent
7588 notify;
7589
7590 XSelectionRequestEvent
7591 *request;
7592
7593 if (reply_info.highlight == MagickFalse)
7594 break;
7595 /*
7596 Set primary selection.
7597 */
7598 request=(&(event.xselectionrequest));
7599 (void) XChangeProperty(request->display,request->requestor,
7600 request->property,request->target,8,PropModeReplace,
7601 (unsigned char *) primary_selection,Extent(primary_selection));
7602 notify.type=SelectionNotify;
7603 notify.send_event=MagickTrue;
7604 notify.display=request->display;
7605 notify.requestor=request->requestor;
7606 notify.selection=request->selection;
7607 notify.target=request->target;
7608 notify.time=request->time;
7609 if (request->property == None)
7610 notify.property=request->target;
7611 else
7612 notify.property=request->property;
7613 (void) XSendEvent(request->display,request->requestor,False,NoEventMask,
7614 (XEvent *) &notify);
7615 }
7616 default:
7617 break;
7618 }
7619 } while ((state & ExitState) == 0);
7620 XSetCursorState(display,windows,MagickFalse);
7621 (void) XWithdrawWindow(display,window_info->id,window_info->screen);
7622 XCheckRefreshWindows(display,windows);
7623}
7624
7625/*
7626%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
7627% %
7628% %
7629% %
7630% X M e n u W i d g e t %
7631% %
7632% %
7633% %
7634%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
7635%
7636% XMenuWidget() maps a menu and returns the command pointed to by the user
7637% when the button is released.
7638%
7639% The format of the XMenuWidget method is:
7640%
7641% int XMenuWidget(Display *display,XWindows *windows,const char *title,
7642% const char **selections,char *item)
7643%
7644% A description of each parameter follows:
7645%
7646% o selection_number: Specifies the number of the selection that the
7647% user choose.
7648%
7649% o display: Specifies a connection to an X server; returned from
7650% XOpenDisplay.
7651%
7652% o window: Specifies a pointer to a XWindows structure.
7653%
7654% o title: Specifies a character string that describes the menu selections.
7655%
7656% o selections: Specifies a pointer to one or more strings that comprise
7657% the choices in the menu.
7658%
7659% o item: Specifies a character array. The item selected from the menu
7660% is returned here.
7661%
7662*/
7663MagickExport int XMenuWidget(Display *display,XWindows *windows,
7664 const char *title,const char **selections,char *item)
7665{
7666 Cursor
7667 cursor;
7668
7669 int
7670 id,
7671 x,
7672 y;
7673
7674 unsigned int
7675 height,
7676 number_selections,
7677 title_height,
7678 top_offset,
7679 width;
7680
cristybb503372010-05-27 20:51:26 +00007681 size_t
cristy3ed852e2009-09-05 21:47:34 +00007682 state;
7683
7684 XEvent
7685 event;
7686
7687 XFontStruct
7688 *font_info;
7689
7690 XSetWindowAttributes
7691 window_attributes;
7692
7693 XWidgetInfo
7694 highlight_info,
7695 menu_info,
7696 selection_info;
7697
7698 XWindowChanges
7699 window_changes;
7700
7701 /*
7702 Determine Menu widget attributes.
7703 */
7704 assert(display != (Display *) NULL);
7705 assert(windows != (XWindows *) NULL);
7706 assert(title != (char *) NULL);
7707 assert(selections != (const char **) NULL);
7708 assert(item != (char *) NULL);
7709 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",title);
7710 font_info=windows->widget.font_info;
7711 windows->widget.width=submenu_info.active == 0 ?
7712 WidgetTextWidth(font_info,(char *) title) : 0;
7713 for (id=0; selections[id] != (char *) NULL; id++)
7714 {
7715 width=WidgetTextWidth(font_info,(char *) selections[id]);
7716 if (width > windows->widget.width)
7717 windows->widget.width=width;
7718 }
7719 number_selections=(unsigned int) id;
7720 XGetWidgetInfo((char *) NULL,&menu_info);
7721 title_height=(unsigned int) (submenu_info.active == 0 ?
7722 (3*(font_info->descent+font_info->ascent) >> 1)+5 : 2);
7723 width=WidgetTextWidth(font_info,(char *) title);
7724 height=(unsigned int) ((3*(font_info->ascent+font_info->descent)) >> 1);
7725 /*
7726 Position Menu widget.
7727 */
7728 windows->widget.width+=QuantumMargin+(menu_info.bevel_width << 1);
7729 top_offset=title_height+menu_info.bevel_width-1;
7730 windows->widget.height=top_offset+number_selections*height+4;
7731 windows->widget.min_width=windows->widget.width;
7732 windows->widget.min_height=windows->widget.height;
7733 XQueryPosition(display,windows->widget.root,&x,&y);
7734 windows->widget.x=x-(QuantumMargin >> 1);
7735 if (submenu_info.active != 0)
7736 {
7737 windows->widget.x=
7738 windows->command.x+windows->command.width-QuantumMargin;
7739 toggle_info.raised=MagickTrue;
7740 XDrawTriangleEast(display,&windows->command,&toggle_info);
7741 }
cristybb503372010-05-27 20:51:26 +00007742 windows->widget.y=submenu_info.active == 0 ? y-(ssize_t)
cristy3ed852e2009-09-05 21:47:34 +00007743 ((3*title_height) >> 2) : y;
7744 if (submenu_info.active != 0)
7745 windows->widget.y=windows->command.y+submenu_info.y;
7746 XConstrainWindowPosition(display,&windows->widget);
7747 /*
7748 Map Menu widget.
7749 */
7750 window_attributes.override_redirect=MagickTrue;
7751 (void) XChangeWindowAttributes(display,windows->widget.id,
cristybb503372010-05-27 20:51:26 +00007752 (size_t) CWOverrideRedirect,&window_attributes);
cristy3ed852e2009-09-05 21:47:34 +00007753 window_changes.width=(int) windows->widget.width;
7754 window_changes.height=(int) windows->widget.height;
7755 window_changes.x=windows->widget.x;
7756 window_changes.y=windows->widget.y;
7757 (void) XReconfigureWMWindow(display,windows->widget.id,windows->widget.screen,
7758 (unsigned int) (CWWidth | CWHeight | CWX | CWY),&window_changes);
7759 (void) XMapRaised(display,windows->widget.id);
7760 windows->widget.mapped=MagickFalse;
7761 /*
7762 Respond to X events.
7763 */
7764 selection_info.height=height;
7765 cursor=XCreateFontCursor(display,XC_right_ptr);
7766 (void) XCheckDefineCursor(display,windows->image.id,cursor);
7767 (void) XCheckDefineCursor(display,windows->command.id,cursor);
7768 (void) XCheckDefineCursor(display,windows->widget.id,cursor);
7769 state=UpdateConfigurationState;
7770 do
7771 {
7772 if (state & UpdateConfigurationState)
7773 {
7774 /*
7775 Initialize selection information.
7776 */
7777 XGetWidgetInfo((char *) NULL,&menu_info);
7778 menu_info.bevel_width--;
7779 menu_info.width=windows->widget.width-((menu_info.bevel_width) << 1);
7780 menu_info.height=windows->widget.height-((menu_info.bevel_width) << 1);
7781 menu_info.x=(int) menu_info.bevel_width;
7782 menu_info.y=(int) menu_info.bevel_width;
7783 XGetWidgetInfo((char *) NULL,&selection_info);
7784 selection_info.center=MagickFalse;
7785 selection_info.width=menu_info.width;
7786 selection_info.height=height;
7787 selection_info.x=menu_info.x;
7788 highlight_info=selection_info;
7789 highlight_info.bevel_width--;
7790 highlight_info.width-=(highlight_info.bevel_width << 1);
7791 highlight_info.height-=(highlight_info.bevel_width << 1);
7792 highlight_info.x+=highlight_info.bevel_width;
7793 state&=(~UpdateConfigurationState);
7794 }
7795 if (state & RedrawWidgetState)
7796 {
7797 /*
7798 Redraw Menu widget.
7799 */
7800 if (submenu_info.active == 0)
7801 {
7802 y=(int) title_height;
7803 XSetBevelColor(display,&windows->widget,MagickFalse);
7804 (void) XDrawLine(display,windows->widget.id,
7805 windows->widget.widget_context,selection_info.x,y-1,
7806 (int) selection_info.width,y-1);
7807 XSetBevelColor(display,&windows->widget,MagickTrue);
7808 (void) XDrawLine(display,windows->widget.id,
7809 windows->widget.widget_context,selection_info.x,y,
7810 (int) selection_info.width,y);
7811 (void) XSetFillStyle(display,windows->widget.widget_context,
7812 FillSolid);
7813 }
7814 /*
7815 Draw menu selections.
7816 */
7817 selection_info.center=MagickTrue;
7818 selection_info.y=(int) menu_info.bevel_width;
7819 selection_info.text=(char *) title;
7820 if (submenu_info.active == 0)
7821 XDrawWidgetText(display,&windows->widget,&selection_info);
7822 selection_info.center=MagickFalse;
7823 selection_info.y=(int) top_offset;
7824 for (id=0; id < (int) number_selections; id++)
7825 {
7826 selection_info.text=(char *) selections[id];
7827 XDrawWidgetText(display,&windows->widget,&selection_info);
7828 highlight_info.y=selection_info.y+highlight_info.bevel_width;
7829 if (id == selection_info.id)
7830 XDrawBevel(display,&windows->widget,&highlight_info);
7831 selection_info.y+=(int) selection_info.height;
7832 }
7833 XDrawBevel(display,&windows->widget,&menu_info);
7834 state&=(~RedrawWidgetState);
7835 }
7836 if (number_selections > 2)
7837 {
7838 /*
7839 Redraw Menu line.
7840 */
7841 y=(int) (top_offset+selection_info.height*(number_selections-1));
7842 XSetBevelColor(display,&windows->widget,MagickFalse);
7843 (void) XDrawLine(display,windows->widget.id,
7844 windows->widget.widget_context,selection_info.x,y-1,
7845 (int) selection_info.width,y-1);
7846 XSetBevelColor(display,&windows->widget,MagickTrue);
7847 (void) XDrawLine(display,windows->widget.id,
7848 windows->widget.widget_context,selection_info.x,y,
7849 (int) selection_info.width,y);
7850 (void) XSetFillStyle(display,windows->widget.widget_context,FillSolid);
7851 }
7852 /*
7853 Wait for next event.
7854 */
7855 (void) XIfEvent(display,&event,XScreenEvent,(char *) windows);
7856 switch (event.type)
7857 {
7858 case ButtonPress:
7859 {
7860 if (event.xbutton.window != windows->widget.id)
7861 {
7862 /*
7863 exit menu.
7864 */
7865 if (event.xbutton.window == windows->command.id)
7866 (void) XPutBackEvent(display,&event);
7867 selection_info.id=(~0);
7868 *item='\0';
7869 state|=ExitState;
7870 break;
7871 }
7872 state&=(~InactiveWidgetState);
7873 id=(event.xbutton.y-top_offset)/(int) selection_info.height;
7874 selection_info.id=id;
7875 if ((id < 0) || (id >= (int) number_selections))
7876 break;
7877 /*
7878 Highlight this selection.
7879 */
7880 selection_info.y=(int) (top_offset+id*selection_info.height);
7881 selection_info.text=(char *) selections[id];
7882 XDrawWidgetText(display,&windows->widget,&selection_info);
7883 highlight_info.y=selection_info.y+highlight_info.bevel_width;
7884 XDrawBevel(display,&windows->widget,&highlight_info);
7885 break;
7886 }
7887 case ButtonRelease:
7888 {
7889 if (windows->widget.mapped == MagickFalse)
7890 break;
7891 if (event.xbutton.window == windows->command.id)
7892 if ((state & InactiveWidgetState) == 0)
7893 break;
7894 /*
7895 exit menu.
7896 */
7897 XSetCursorState(display,windows,MagickFalse);
7898 *item='\0';
7899 state|=ExitState;
7900 break;
7901 }
7902 case ConfigureNotify:
7903 {
7904 /*
7905 Update widget configuration.
7906 */
7907 if (event.xconfigure.window != windows->widget.id)
7908 break;
7909 if ((event.xconfigure.width == (int) windows->widget.width) &&
7910 (event.xconfigure.height == (int) windows->widget.height))
7911 break;
7912 windows->widget.width=(unsigned int)
7913 MagickMax(event.xconfigure.width,(int) windows->widget.min_width);
7914 windows->widget.height=(unsigned int)
7915 MagickMax(event.xconfigure.height,(int) windows->widget.min_height);
7916 state|=UpdateConfigurationState;
7917 break;
7918 }
7919 case EnterNotify:
7920 {
7921 if (event.xcrossing.window != windows->widget.id)
7922 break;
7923 if (event.xcrossing.state == 0)
7924 break;
7925 state&=(~InactiveWidgetState);
7926 id=((event.xcrossing.y-top_offset)/(int) selection_info.height);
7927 if ((selection_info.id >= 0) &&
7928 (selection_info.id < (int) number_selections))
7929 {
7930 /*
7931 Unhighlight last selection.
7932 */
7933 if (id == selection_info.id)
7934 break;
7935 selection_info.y=(int)
7936 (top_offset+selection_info.id*selection_info.height);
7937 selection_info.text=(char *) selections[selection_info.id];
7938 XDrawWidgetText(display,&windows->widget,&selection_info);
7939 }
7940 if ((id < 0) || (id >= (int) number_selections))
7941 break;
7942 /*
7943 Highlight this selection.
7944 */
7945 selection_info.id=id;
7946 selection_info.y=(int)
7947 (top_offset+selection_info.id*selection_info.height);
7948 selection_info.text=(char *) selections[selection_info.id];
7949 XDrawWidgetText(display,&windows->widget,&selection_info);
7950 highlight_info.y=selection_info.y+highlight_info.bevel_width;
7951 XDrawBevel(display,&windows->widget,&highlight_info);
7952 break;
7953 }
7954 case Expose:
7955 {
7956 if (event.xexpose.window != windows->widget.id)
7957 break;
7958 if (event.xexpose.count != 0)
7959 break;
7960 state|=RedrawWidgetState;
7961 break;
7962 }
7963 case LeaveNotify:
7964 {
7965 if (event.xcrossing.window != windows->widget.id)
7966 break;
7967 state|=InactiveWidgetState;
7968 id=selection_info.id;
7969 if ((id < 0) || (id >= (int) number_selections))
7970 break;
7971 /*
7972 Unhighlight last selection.
7973 */
7974 selection_info.y=(int) (top_offset+id*selection_info.height);
7975 selection_info.id=(~0);
7976 selection_info.text=(char *) selections[id];
7977 XDrawWidgetText(display,&windows->widget,&selection_info);
7978 break;
7979 }
7980 case MotionNotify:
7981 {
7982 /*
7983 Discard pending button motion events.
7984 */
7985 while (XCheckMaskEvent(display,ButtonMotionMask,&event)) ;
7986 if (submenu_info.active != 0)
7987 if (event.xmotion.window == windows->command.id)
7988 {
7989 if ((state & InactiveWidgetState) == 0)
7990 {
7991 if (MatteIsActive(submenu_info,event.xmotion) == MagickFalse)
7992 {
7993 selection_info.id=(~0);
7994 *item='\0';
7995 state|=ExitState;
7996 break;
7997 }
7998 }
7999 else
8000 if (WindowIsActive(windows->command,event.xmotion))
8001 {
8002 selection_info.id=(~0);
8003 *item='\0';
8004 state|=ExitState;
8005 break;
8006 }
8007 }
8008 if (event.xmotion.window != windows->widget.id)
8009 break;
8010 if (state & InactiveWidgetState)
8011 break;
8012 id=(event.xmotion.y-top_offset)/(int) selection_info.height;
8013 if ((selection_info.id >= 0) &&
8014 (selection_info.id < (int) number_selections))
8015 {
8016 /*
8017 Unhighlight last selection.
8018 */
8019 if (id == selection_info.id)
8020 break;
8021 selection_info.y=(int)
8022 (top_offset+selection_info.id*selection_info.height);
8023 selection_info.text=(char *) selections[selection_info.id];
8024 XDrawWidgetText(display,&windows->widget,&selection_info);
8025 }
8026 selection_info.id=id;
8027 if ((id < 0) || (id >= (int) number_selections))
8028 break;
8029 /*
8030 Highlight this selection.
8031 */
8032 selection_info.y=(int) (top_offset+id*selection_info.height);
8033 selection_info.text=(char *) selections[id];
8034 XDrawWidgetText(display,&windows->widget,&selection_info);
8035 highlight_info.y=selection_info.y+highlight_info.bevel_width;
8036 XDrawBevel(display,&windows->widget,&highlight_info);
8037 break;
8038 }
8039 default:
8040 break;
8041 }
8042 } while ((state & ExitState) == 0);
8043 (void) XFreeCursor(display,cursor);
8044 window_attributes.override_redirect=MagickFalse;
8045 (void) XChangeWindowAttributes(display,windows->widget.id,
cristybb503372010-05-27 20:51:26 +00008046 (size_t) CWOverrideRedirect,&window_attributes);
cristy3ed852e2009-09-05 21:47:34 +00008047 (void) XWithdrawWindow(display,windows->widget.id,windows->widget.screen);
8048 XCheckRefreshWindows(display,windows);
8049 if (submenu_info.active != 0)
8050 {
8051 submenu_info.active=MagickFalse;
8052 toggle_info.raised=MagickFalse;
8053 XDrawTriangleEast(display,&windows->command,&toggle_info);
8054 }
8055 if ((selection_info.id < 0) || (selection_info.id >= (int) number_selections))
8056 return(~0);
8057 (void) CopyMagickString(item,selections[selection_info.id],MaxTextExtent);
8058 return(selection_info.id);
8059}
8060
8061/*
8062%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
8063% %
8064% %
8065% %
8066% X N o t i c e W i d g e t %
8067% %
8068% %
8069% %
8070%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
8071%
8072% XNoticeWidget() displays a Notice widget with a notice to the user. The
8073% function returns when the user presses the "Dismiss" button.
8074%
8075% The format of the XNoticeWidget method is:
8076%
8077% void XNoticeWidget(Display *display,XWindows *windows,
8078% const char *reason,const char *description)
8079%
8080% A description of each parameter follows:
8081%
8082% o display: Specifies a connection to an X server; returned from
8083% XOpenDisplay.
8084%
8085% o window: Specifies a pointer to a XWindows structure.
8086%
8087% o reason: Specifies the message to display before terminating the
8088% program.
8089%
8090% o description: Specifies any description to the message.
8091%
8092*/
8093MagickExport void XNoticeWidget(Display *display,XWindows *windows,
8094 const char *reason,const char *description)
8095{
8096#define DismissButtonText "Dismiss"
8097#define Timeout 8
8098
8099 const char
8100 *text;
8101
8102 int
8103 x,
8104 y;
8105
8106 Status
8107 status;
8108
8109 time_t
8110 timer;
8111
8112 unsigned int
8113 height,
8114 width;
8115
cristybb503372010-05-27 20:51:26 +00008116 size_t
cristy3ed852e2009-09-05 21:47:34 +00008117 state;
8118
8119 XEvent
8120 event;
8121
8122 XFontStruct
8123 *font_info;
8124
8125 XTextProperty
8126 window_name;
8127
8128 XWidgetInfo
8129 dismiss_info;
8130
8131 XWindowChanges
8132 window_changes;
8133
8134 /*
8135 Determine Notice widget attributes.
8136 */
8137 assert(display != (Display *) NULL);
8138 assert(windows != (XWindows *) NULL);
8139 assert(reason != (char *) NULL);
8140 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",reason);
8141 XDelay(display,SuspendTime << 3); /* avoid surpise with delay */
8142 XSetCursorState(display,windows,MagickTrue);
8143 XCheckRefreshWindows(display,windows);
8144 font_info=windows->widget.font_info;
8145 width=WidgetTextWidth(font_info,DismissButtonText);
8146 text=GetLocaleExceptionMessage(XServerError,reason);
8147 if (text != (char *) NULL)
8148 if (WidgetTextWidth(font_info,(char *) text) > width)
8149 width=WidgetTextWidth(font_info,(char *) text);
8150 if (description != (char *) NULL)
8151 {
8152 text=GetLocaleExceptionMessage(XServerError,description);
8153 if (text != (char *) NULL)
8154 if (WidgetTextWidth(font_info,(char *) text) > width)
8155 width=WidgetTextWidth(font_info,(char *) text);
8156 }
8157 height=(unsigned int) (font_info->ascent+font_info->descent);
8158 /*
8159 Position Notice widget.
8160 */
8161 windows->widget.width=width+4*QuantumMargin;
8162 windows->widget.min_width=width+QuantumMargin;
8163 if (windows->widget.width < windows->widget.min_width)
8164 windows->widget.width=windows->widget.min_width;
8165 windows->widget.height=(unsigned int) (12*height);
8166 windows->widget.min_height=(unsigned int) (7*height);
8167 if (windows->widget.height < windows->widget.min_height)
8168 windows->widget.height=windows->widget.min_height;
8169 XConstrainWindowPosition(display,&windows->widget);
8170 /*
8171 Map Notice widget.
8172 */
8173 (void) CopyMagickString(windows->widget.name,"Notice",MaxTextExtent);
8174 status=XStringListToTextProperty(&windows->widget.name,1,&window_name);
8175 if (status != False)
8176 {
8177 XSetWMName(display,windows->widget.id,&window_name);
8178 XSetWMIconName(display,windows->widget.id,&window_name);
8179 (void) XFree((void *) window_name.value);
8180 }
8181 window_changes.width=(int) windows->widget.width;
8182 window_changes.height=(int) windows->widget.height;
8183 window_changes.x=windows->widget.x;
8184 window_changes.y=windows->widget.y;
8185 (void) XReconfigureWMWindow(display,windows->widget.id,windows->widget.screen,
8186 (unsigned int) (CWWidth | CWHeight | CWX | CWY),&window_changes);
8187 (void) XMapRaised(display,windows->widget.id);
8188 windows->widget.mapped=MagickFalse;
8189 (void) XBell(display,0);
8190 /*
8191 Respond to X events.
8192 */
8193 timer=time((time_t *) NULL)+Timeout;
8194 state=UpdateConfigurationState;
8195 do
8196 {
8197 if (time((time_t *) NULL) > timer)
8198 break;
8199 if (state & UpdateConfigurationState)
8200 {
8201 /*
8202 Initialize Dismiss button information.
8203 */
8204 XGetWidgetInfo(DismissButtonText,&dismiss_info);
8205 dismiss_info.width=(unsigned int) QuantumMargin+
8206 WidgetTextWidth(font_info,DismissButtonText);
8207 dismiss_info.height=(unsigned int) ((3*height) >> 1);
8208 dismiss_info.x=(int)
8209 ((windows->widget.width >> 1)-(dismiss_info.width >> 1));
8210 dismiss_info.y=(int)
8211 (windows->widget.height-(dismiss_info.height << 1));
8212 state&=(~UpdateConfigurationState);
8213 }
8214 if (state & RedrawWidgetState)
8215 {
8216 /*
8217 Redraw Notice widget.
8218 */
8219 width=WidgetTextWidth(font_info,(char *) reason);
8220 x=(int) ((windows->widget.width >> 1)-(width >> 1));
8221 y=(int) ((windows->widget.height >> 1)-(height << 1));
8222 (void) XDrawString(display,windows->widget.id,
8223 windows->widget.annotate_context,x,y,(char *) reason,Extent(reason));
8224 if (description != (char *) NULL)
8225 {
8226 width=WidgetTextWidth(font_info,(char *) description);
8227 x=(int) ((windows->widget.width >> 1)-(width >> 1));
8228 y+=height;
8229 (void) XDrawString(display,windows->widget.id,
8230 windows->widget.annotate_context,x,y,(char *) description,
8231 Extent(description));
8232 }
8233 XDrawBeveledButton(display,&windows->widget,&dismiss_info);
8234 XHighlightWidget(display,&windows->widget,BorderOffset,BorderOffset);
8235 state&=(~RedrawWidgetState);
8236 }
8237 /*
8238 Wait for next event.
8239 */
8240 if (XCheckIfEvent(display,&event,XScreenEvent,(char *) windows) == MagickFalse)
8241 {
8242 /*
8243 Do not block if delay > 0.
8244 */
8245 XDelay(display,SuspendTime << 2);
8246 continue;
8247 }
8248 switch (event.type)
8249 {
8250 case ButtonPress:
8251 {
8252 if (MatteIsActive(dismiss_info,event.xbutton))
8253 {
8254 /*
8255 User pressed Dismiss button.
8256 */
8257 dismiss_info.raised=MagickFalse;
8258 XDrawBeveledButton(display,&windows->widget,&dismiss_info);
8259 break;
8260 }
8261 break;
8262 }
8263 case ButtonRelease:
8264 {
8265 if (windows->widget.mapped == MagickFalse)
8266 break;
8267 if (dismiss_info.raised == MagickFalse)
8268 {
8269 if (event.xbutton.window == windows->widget.id)
8270 if (MatteIsActive(dismiss_info,event.xbutton))
8271 state|=ExitState;
8272 dismiss_info.raised=MagickTrue;
8273 XDrawBeveledButton(display,&windows->widget,&dismiss_info);
8274 }
8275 break;
8276 }
8277 case ClientMessage:
8278 {
8279 /*
8280 If client window delete message, exit.
8281 */
8282 if (event.xclient.message_type != windows->wm_protocols)
8283 break;
8284 if (*event.xclient.data.l == (int) windows->wm_take_focus)
8285 {
8286 (void) XSetInputFocus(display,event.xclient.window,RevertToParent,
8287 (Time) event.xclient.data.l[1]);
8288 break;
8289 }
8290 if (*event.xclient.data.l != (int) windows->wm_delete_window)
8291 break;
8292 if (event.xclient.window == windows->widget.id)
8293 {
8294 state|=ExitState;
8295 break;
8296 }
8297 break;
8298 }
8299 case ConfigureNotify:
8300 {
8301 /*
8302 Update widget configuration.
8303 */
8304 if (event.xconfigure.window != windows->widget.id)
8305 break;
8306 if ((event.xconfigure.width == (int) windows->widget.width) &&
8307 (event.xconfigure.height == (int) windows->widget.height))
8308 break;
8309 windows->widget.width=(unsigned int)
8310 MagickMax(event.xconfigure.width,(int) windows->widget.min_width);
8311 windows->widget.height=(unsigned int)
8312 MagickMax(event.xconfigure.height,(int) windows->widget.min_height);
8313 state|=UpdateConfigurationState;
8314 break;
8315 }
8316 case EnterNotify:
8317 {
8318 if (event.xcrossing.window != windows->widget.id)
8319 break;
8320 state&=(~InactiveWidgetState);
8321 break;
8322 }
8323 case Expose:
8324 {
8325 if (event.xexpose.window != windows->widget.id)
8326 break;
8327 if (event.xexpose.count != 0)
8328 break;
8329 state|=RedrawWidgetState;
8330 break;
8331 }
8332 case KeyPress:
8333 {
8334 static char
8335 command[MaxTextExtent];
8336
8337 static KeySym
8338 key_symbol;
8339
8340 /*
8341 Respond to a user key press.
8342 */
8343 if (event.xkey.window != windows->widget.id)
8344 break;
8345 (void) XLookupString((XKeyEvent *) &event.xkey,command,
8346 (int) sizeof(command),&key_symbol,(XComposeStatus *) NULL);
8347 if ((key_symbol == XK_Return) || (key_symbol == XK_KP_Enter))
8348 {
8349 dismiss_info.raised=MagickFalse;
8350 XDrawBeveledButton(display,&windows->widget,&dismiss_info);
8351 state|=ExitState;
8352 break;
8353 }
8354 break;
8355 }
8356 case LeaveNotify:
8357 {
8358 if (event.xcrossing.window != windows->widget.id)
8359 break;
8360 state|=InactiveWidgetState;
8361 break;
8362 }
8363 case MotionNotify:
8364 {
8365 /*
8366 Discard pending button motion events.
8367 */
8368 while (XCheckMaskEvent(display,ButtonMotionMask,&event)) ;
8369 if (state & InactiveWidgetState)
8370 break;
8371 if (dismiss_info.raised == MatteIsActive(dismiss_info,event.xmotion))
8372 {
8373 /*
8374 Dismiss button status changed.
8375 */
8376 dismiss_info.raised=
8377 dismiss_info.raised == MagickFalse ? MagickTrue : MagickFalse;
8378 XDrawBeveledButton(display,&windows->widget,&dismiss_info);
8379 break;
8380 }
8381 break;
8382 }
8383 default:
8384 break;
8385 }
8386 } while ((state & ExitState) == 0);
8387 XSetCursorState(display,windows,MagickFalse);
8388 (void) XWithdrawWindow(display,windows->widget.id,windows->widget.screen);
8389 XCheckRefreshWindows(display,windows);
8390}
8391
8392/*
8393%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
8394% %
8395% %
8396% %
8397% X P r e f e r e n c e s W i d g e t %
8398% %
8399% %
8400% %
8401%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
8402%
8403% XPreferencesWidget() displays a Preferences widget with program preferences.
8404% If the user presses the Apply button, the preferences are stored in a
8405% configuration file in the users' home directory.
8406%
8407% The format of the XPreferencesWidget method is:
8408%
8409% MagickBooleanType XPreferencesWidget(Display *display,
8410% XResourceInfo *resource_info,XWindows *windows)
8411%
8412% A description of each parameter follows:
8413%
8414% o display: Specifies a connection to an X server; returned from
8415% XOpenDisplay.
8416%
8417% o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
8418%
8419% o window: Specifies a pointer to a XWindows structure.
8420%
8421*/
8422MagickExport MagickBooleanType XPreferencesWidget(Display *display,
8423 XResourceInfo *resource_info,XWindows *windows)
8424{
8425#define ApplyButtonText "Apply"
8426#define CacheButtonText "%lu mega-bytes of memory in the undo edit cache "
8427#define CancelButtonText "Cancel"
8428#define NumberPreferences 8
8429
8430 static const char
8431 *Preferences[] =
8432 {
8433 "display image centered on a backdrop",
8434 "confirm on program exit",
8435 "confirm on image edits",
8436 "correct image for display gamma",
8437 "display warning messages",
8438 "apply Floyd/Steinberg error diffusion to image",
8439 "use a shared colormap for colormapped X visuals",
8440 "display images as an X server pixmap"
8441 };
8442
8443 char
8444 cache[MaxTextExtent];
8445
8446 int
8447 x,
8448 y;
8449
8450 register int
8451 i;
8452
8453 Status
8454 status;
8455
8456 unsigned int
8457 height,
8458 text_width,
8459 width;
8460
cristybb503372010-05-27 20:51:26 +00008461 size_t
cristy3ed852e2009-09-05 21:47:34 +00008462 state;
8463
8464 XEvent
8465 event;
8466
8467 XFontStruct
8468 *font_info;
8469
8470 XTextProperty
8471 window_name;
8472
8473 XWidgetInfo
8474 apply_info,
8475 cache_info,
8476 cancel_info,
8477 preferences_info[NumberPreferences];
8478
8479 XWindowChanges
8480 window_changes;
8481
8482 /*
8483 Determine Preferences widget attributes.
8484 */
8485 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
8486 assert(display != (Display *) NULL);
8487 assert(resource_info != (XResourceInfo *) NULL);
8488 assert(windows != (XWindows *) NULL);
8489 XCheckRefreshWindows(display,windows);
8490 font_info=windows->widget.font_info;
8491 text_width=WidgetTextWidth(font_info,CacheButtonText);
8492 for (i=0; i < NumberPreferences; i++)
8493 if (WidgetTextWidth(font_info,(char *) Preferences[i]) > text_width)
8494 text_width=WidgetTextWidth(font_info,(char *) Preferences[i]);
8495 width=WidgetTextWidth(font_info,ApplyButtonText);
8496 if (WidgetTextWidth(font_info,CancelButtonText) > width)
8497 width=WidgetTextWidth(font_info,CancelButtonText);
8498 width+=(unsigned int) QuantumMargin;
8499 height=(unsigned int) (font_info->ascent+font_info->descent);
8500 /*
8501 Position Preferences widget.
8502 */
8503 windows->widget.width=(unsigned int) (MagickMax((int) (width << 1),
8504 (int) text_width)+6*QuantumMargin);
8505 windows->widget.min_width=(width << 1)+QuantumMargin;
8506 if (windows->widget.width < windows->widget.min_width)
8507 windows->widget.width=windows->widget.min_width;
8508 windows->widget.height=(unsigned int)
8509 (7*height+NumberPreferences*(height+(QuantumMargin >> 1)));
8510 windows->widget.min_height=(unsigned int)
8511 (7*height+NumberPreferences*(height+(QuantumMargin >> 1)));
8512 if (windows->widget.height < windows->widget.min_height)
8513 windows->widget.height=windows->widget.min_height;
8514 XConstrainWindowPosition(display,&windows->widget);
8515 /*
8516 Map Preferences widget.
8517 */
8518 (void) CopyMagickString(windows->widget.name,"Preferences",MaxTextExtent);
8519 status=XStringListToTextProperty(&windows->widget.name,1,&window_name);
8520 if (status != False)
8521 {
8522 XSetWMName(display,windows->widget.id,&window_name);
8523 XSetWMIconName(display,windows->widget.id,&window_name);
8524 (void) XFree((void *) window_name.value);
8525 }
8526 window_changes.width=(int) windows->widget.width;
8527 window_changes.height=(int) windows->widget.height;
8528 window_changes.x=windows->widget.x;
8529 window_changes.y=windows->widget.y;
8530 (void) XReconfigureWMWindow(display,windows->widget.id,windows->widget.screen,
8531 (unsigned int) (CWWidth | CWHeight | CWX | CWY),&window_changes);
8532 (void) XMapRaised(display,windows->widget.id);
8533 windows->widget.mapped=MagickFalse;
8534 /*
8535 Respond to X events.
8536 */
8537 state=UpdateConfigurationState;
8538 XSetCursorState(display,windows,MagickTrue);
8539 do
8540 {
8541 if (state & UpdateConfigurationState)
8542 {
8543 /*
8544 Initialize button information.
8545 */
8546 XGetWidgetInfo(CancelButtonText,&cancel_info);
8547 cancel_info.width=width;
8548 cancel_info.height=(unsigned int) (3*height) >> 1;
8549 cancel_info.x=(int) windows->widget.width-cancel_info.width-
8550 (QuantumMargin << 1);
8551 cancel_info.y=(int) windows->widget.height-
8552 cancel_info.height-QuantumMargin;
8553 XGetWidgetInfo(ApplyButtonText,&apply_info);
8554 apply_info.width=width;
8555 apply_info.height=(unsigned int) (3*height) >> 1;
8556 apply_info.x=QuantumMargin << 1;
8557 apply_info.y=cancel_info.y;
8558 y=(int) (height << 1);
8559 for (i=0; i < NumberPreferences; i++)
8560 {
8561 XGetWidgetInfo(Preferences[i],&preferences_info[i]);
8562 preferences_info[i].bevel_width--;
8563 preferences_info[i].width=(unsigned int) QuantumMargin >> 1;
8564 preferences_info[i].height=(unsigned int) QuantumMargin >> 1;
8565 preferences_info[i].x=QuantumMargin << 1;
8566 preferences_info[i].y=y;
8567 y+=height+(QuantumMargin >> 1);
8568 }
8569 preferences_info[0].raised=resource_info->backdrop ==
8570 MagickFalse ? MagickTrue : MagickFalse;
8571 preferences_info[1].raised=resource_info->confirm_exit ==
8572 MagickFalse ? MagickTrue : MagickFalse;
8573 preferences_info[2].raised=resource_info->confirm_edit ==
8574 MagickFalse ? MagickTrue : MagickFalse;
8575 preferences_info[3].raised=resource_info->gamma_correct ==
8576 MagickFalse ? MagickTrue : MagickFalse;
8577 preferences_info[4].raised=resource_info->display_warnings ==
8578 MagickFalse ? MagickTrue : MagickFalse;
8579 preferences_info[5].raised=resource_info->quantize_info->dither ==
8580 MagickFalse ? MagickTrue : MagickFalse;
8581 preferences_info[6].raised=resource_info->colormap !=
8582 SharedColormap ? MagickTrue : MagickFalse;
8583 preferences_info[7].raised=resource_info->use_pixmap ==
8584 MagickFalse ? MagickTrue : MagickFalse;
8585 (void) FormatMagickString(cache,MaxTextExtent,CacheButtonText,
cristyf2faecf2010-05-28 19:19:36 +00008586 (unsigned long) resource_info->undo_cache);
cristy3ed852e2009-09-05 21:47:34 +00008587 XGetWidgetInfo(cache,&cache_info);
8588 cache_info.bevel_width--;
8589 cache_info.width=(unsigned int) QuantumMargin >> 1;
8590 cache_info.height=(unsigned int) QuantumMargin >> 1;
8591 cache_info.x=QuantumMargin << 1;
8592 cache_info.y=y;
8593 state&=(~UpdateConfigurationState);
8594 }
8595 if (state & RedrawWidgetState)
8596 {
8597 /*
8598 Redraw Preferences widget.
8599 */
8600 XDrawBeveledButton(display,&windows->widget,&apply_info);
8601 XDrawBeveledButton(display,&windows->widget,&cancel_info);
8602 for (i=0; i < NumberPreferences; i++)
8603 XDrawBeveledButton(display,&windows->widget,&preferences_info[i]);
8604 XDrawTriangleEast(display,&windows->widget,&cache_info);
8605 XHighlightWidget(display,&windows->widget,BorderOffset,BorderOffset);
8606 state&=(~RedrawWidgetState);
8607 }
8608 /*
8609 Wait for next event.
8610 */
8611 (void) XIfEvent(display,&event,XScreenEvent,(char *) windows);
8612 switch (event.type)
8613 {
8614 case ButtonPress:
8615 {
8616 if (MatteIsActive(apply_info,event.xbutton))
8617 {
8618 /*
8619 User pressed Apply button.
8620 */
8621 apply_info.raised=MagickFalse;
8622 XDrawBeveledButton(display,&windows->widget,&apply_info);
8623 break;
8624 }
8625 if (MatteIsActive(cancel_info,event.xbutton))
8626 {
8627 /*
8628 User pressed Cancel button.
8629 */
8630 cancel_info.raised=MagickFalse;
8631 XDrawBeveledButton(display,&windows->widget,&cancel_info);
8632 break;
8633 }
8634 for (i=0; i < NumberPreferences; i++)
8635 if (MatteIsActive(preferences_info[i],event.xbutton))
8636 {
8637 /*
8638 User pressed a Preferences button.
8639 */
8640 preferences_info[i].raised=preferences_info[i].raised ==
8641 MagickFalse ? MagickTrue : MagickFalse;
8642 XDrawBeveledButton(display,&windows->widget,&preferences_info[i]);
8643 break;
8644 }
8645 if (MatteIsActive(cache_info,event.xbutton))
8646 {
8647 /*
8648 User pressed Cache button.
8649 */
8650 x=cache_info.x+cache_info.width+cache_info.bevel_width+
8651 (QuantumMargin >> 1);
8652 y=cache_info.y+((cache_info.height-height) >> 1);
8653 width=WidgetTextWidth(font_info,cache);
8654 (void) XClearArea(display,windows->widget.id,x,y,width,height,
8655 False);
8656 resource_info->undo_cache<<=1;
8657 if (resource_info->undo_cache > 256)
8658 resource_info->undo_cache=1;
8659 (void) FormatMagickString(cache,MaxTextExtent,CacheButtonText,
cristyf2faecf2010-05-28 19:19:36 +00008660 (unsigned long) resource_info->undo_cache);
cristy3ed852e2009-09-05 21:47:34 +00008661 cache_info.raised=MagickFalse;
8662 XDrawTriangleEast(display,&windows->widget,&cache_info);
8663 break;
8664 }
8665 break;
8666 }
8667 case ButtonRelease:
8668 {
8669 if (windows->widget.mapped == MagickFalse)
8670 break;
8671 if (apply_info.raised == MagickFalse)
8672 {
8673 if (event.xbutton.window == windows->widget.id)
8674 if (MatteIsActive(apply_info,event.xbutton))
8675 state|=ExitState;
8676 apply_info.raised=MagickTrue;
8677 XDrawBeveledButton(display,&windows->widget,&apply_info);
8678 apply_info.raised=MagickFalse;
8679 }
8680 if (cancel_info.raised == MagickFalse)
8681 {
8682 if (event.xbutton.window == windows->widget.id)
8683 if (MatteIsActive(cancel_info,event.xbutton))
8684 state|=ExitState;
8685 cancel_info.raised=MagickTrue;
8686 XDrawBeveledButton(display,&windows->widget,&cancel_info);
8687 }
8688 if (cache_info.raised == MagickFalse)
8689 {
8690 cache_info.raised=MagickTrue;
8691 XDrawTriangleEast(display,&windows->widget,&cache_info);
8692 }
8693 break;
8694 }
8695 case ClientMessage:
8696 {
8697 /*
8698 If client window delete message, exit.
8699 */
8700 if (event.xclient.message_type != windows->wm_protocols)
8701 break;
8702 if (*event.xclient.data.l == (int) windows->wm_take_focus)
8703 {
8704 (void) XSetInputFocus(display,event.xclient.window,RevertToParent,
8705 (Time) event.xclient.data.l[1]);
8706 break;
8707 }
8708 if (*event.xclient.data.l != (int) windows->wm_delete_window)
8709 break;
8710 if (event.xclient.window == windows->widget.id)
8711 {
8712 state|=ExitState;
8713 break;
8714 }
8715 break;
8716 }
8717 case ConfigureNotify:
8718 {
8719 /*
8720 Update widget configuration.
8721 */
8722 if (event.xconfigure.window != windows->widget.id)
8723 break;
8724 if ((event.xconfigure.width == (int) windows->widget.width) &&
8725 (event.xconfigure.height == (int) windows->widget.height))
8726 break;
8727 windows->widget.width=(unsigned int)
8728 MagickMax(event.xconfigure.width,(int) windows->widget.min_width);
8729 windows->widget.height=(unsigned int)
8730 MagickMax(event.xconfigure.height,(int) windows->widget.min_height);
8731 state|=UpdateConfigurationState;
8732 break;
8733 }
8734 case EnterNotify:
8735 {
8736 if (event.xcrossing.window != windows->widget.id)
8737 break;
8738 state&=(~InactiveWidgetState);
8739 break;
8740 }
8741 case Expose:
8742 {
8743 if (event.xexpose.window != windows->widget.id)
8744 break;
8745 if (event.xexpose.count != 0)
8746 break;
8747 state|=RedrawWidgetState;
8748 break;
8749 }
8750 case KeyPress:
8751 {
8752 static char
8753 command[MaxTextExtent];
8754
8755 static KeySym
8756 key_symbol;
8757
8758 /*
8759 Respond to a user key press.
8760 */
8761 if (event.xkey.window != windows->widget.id)
8762 break;
8763 (void) XLookupString((XKeyEvent *) &event.xkey,command,
8764 (int) sizeof(command),&key_symbol,(XComposeStatus *) NULL);
8765 if ((key_symbol == XK_Return) || (key_symbol == XK_KP_Enter))
8766 {
8767 apply_info.raised=MagickFalse;
8768 XDrawBeveledButton(display,&windows->widget,&apply_info);
8769 state|=ExitState;
8770 break;
8771 }
8772 break;
8773 }
8774 case LeaveNotify:
8775 {
8776 if (event.xcrossing.window != windows->widget.id)
8777 break;
8778 state|=InactiveWidgetState;
8779 break;
8780 }
8781 case MotionNotify:
8782 {
8783 /*
8784 Discard pending button motion events.
8785 */
8786 while (XCheckMaskEvent(display,ButtonMotionMask,&event)) ;
8787 if (state & InactiveWidgetState)
8788 break;
8789 if (apply_info.raised == MatteIsActive(apply_info,event.xmotion))
8790 {
8791 /*
8792 Apply button status changed.
8793 */
8794 apply_info.raised=
8795 apply_info.raised == MagickFalse ? MagickTrue : MagickFalse;
8796 XDrawBeveledButton(display,&windows->widget,&apply_info);
8797 break;
8798 }
8799 if (cancel_info.raised == MatteIsActive(cancel_info,event.xmotion))
8800 {
8801 /*
8802 Cancel button status changed.
8803 */
8804 cancel_info.raised=
8805 cancel_info.raised == MagickFalse ? MagickTrue : MagickFalse;
8806 XDrawBeveledButton(display,&windows->widget,&cancel_info);
8807 break;
8808 }
8809 break;
8810 }
8811 default:
8812 break;
8813 }
8814 } while ((state & ExitState) == 0);
8815 XSetCursorState(display,windows,MagickFalse);
8816 (void) XWithdrawWindow(display,windows->widget.id,windows->widget.screen);
8817 XCheckRefreshWindows(display,windows);
8818 if (apply_info.raised)
8819 return(MagickFalse);
8820 /*
8821 Save user preferences to the client configuration file.
8822 */
8823 resource_info->backdrop=
8824 preferences_info[0].raised == MagickFalse ? MagickTrue : MagickFalse;
8825 resource_info->confirm_exit=
8826 preferences_info[1].raised == MagickFalse ? MagickTrue : MagickFalse;
8827 resource_info->confirm_edit=
8828 preferences_info[2].raised == MagickFalse ? MagickTrue : MagickFalse;
8829 resource_info->gamma_correct=
8830 preferences_info[3].raised == MagickFalse ? MagickTrue : MagickFalse;
8831 resource_info->display_warnings=
8832 preferences_info[4].raised == MagickFalse ? MagickTrue : MagickFalse;
8833 resource_info->quantize_info->dither=
8834 preferences_info[5].raised == MagickFalse ? MagickTrue : MagickFalse;
8835 resource_info->colormap=SharedColormap;
8836 if (preferences_info[6].raised)
8837 resource_info->colormap=PrivateColormap;
8838 resource_info->use_pixmap=
8839 preferences_info[7].raised == MagickFalse ? MagickTrue : MagickFalse;
8840 XUserPreferences(resource_info);
8841 return(MagickTrue);
8842}
8843
8844/*
8845%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
8846% %
8847% %
8848% %
8849% X P r o g r e s s M o n i t o r W i d g e t %
8850% %
8851% %
8852% %
8853%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
8854%
8855% XProgressMonitorWidget() displays the progress a task is making in
8856% completing a task. A span of zero toggles the active status. An inactive
8857% state disables the progress monitor.
8858%
8859% The format of the XProgressMonitorWidget method is:
8860%
8861% void XProgressMonitorWidget(Display *display,XWindows *windows,
8862% const char *task,const MagickOffsetType offset,
8863% const MagickSizeType span)
8864%
8865% A description of each parameter follows:
8866%
8867% o display: Specifies a connection to an X server; returned from
8868% XOpenDisplay.
8869%
8870% o window: Specifies a pointer to a XWindows structure.
8871%
8872% o task: Identifies the task in progress.
8873%
8874% o offset: Specifies the offset position within the span which represents
8875% how much progress has been made in completing a task.
8876%
8877% o span: Specifies the span relative to completing a task.
8878%
8879*/
8880MagickExport void XProgressMonitorWidget(Display *display,XWindows *windows,
8881 const char *task,const MagickOffsetType offset,const MagickSizeType span)
8882{
8883 unsigned int
8884 width;
8885
8886 XEvent
8887 event;
8888
8889 assert(display != (Display *) NULL);
8890 assert(windows != (XWindows *) NULL);
8891 assert(task != (const char *) NULL);
8892 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",task);
8893 if (span == 0)
8894 return;
8895 /*
8896 Update image windows if there is a pending expose event.
8897 */
8898 while (XCheckTypedWindowEvent(display,windows->command.id,Expose,&event))
8899 (void) XCommandWidget(display,windows,(const char **) NULL,&event);
8900 while (XCheckTypedWindowEvent(display,windows->image.id,Expose,&event))
8901 XRefreshWindow(display,&windows->image,&event);
8902 while (XCheckTypedWindowEvent(display,windows->info.id,Expose,&event))
8903 if (monitor_info.text != (char *) NULL)
8904 XInfoWidget(display,windows,monitor_info.text);
8905 /*
8906 Draw progress monitor bar to represent percent completion of a task.
8907 */
8908 if ((windows->info.mapped == MagickFalse) || (task != monitor_info.text))
8909 XInfoWidget(display,windows,task);
8910 width=(unsigned int) (((offset+1)*(windows->info.width-
8911 (2*monitor_info.x)))/span);
8912 if (width < monitor_info.width)
8913 {
8914 monitor_info.raised=MagickTrue;
8915 XDrawWidgetText(display,&windows->info,&monitor_info);
8916 monitor_info.raised=MagickFalse;
8917 }
8918 monitor_info.width=width;
8919 XDrawWidgetText(display,&windows->info,&monitor_info);
8920 (void) XFlush(display);
8921}
8922
8923/*
8924%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
8925% %
8926% %
8927% %
8928% X T e x t V i e w W i d g e t %
8929% %
8930% %
8931% %
8932%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
8933%
8934% XTextViewWidget() displays text in a Text View widget.
8935%
8936% The format of the XTextViewWidget method is:
8937%
8938% void XTextViewWidget(Display *display,const XResourceInfo *resource_info,
8939% XWindows *windows,const MagickBooleanType mono,const char *title,
8940% const char **textlist)
8941%
8942% A description of each parameter follows:
8943%
8944% o display: Specifies a connection to an X server; returned from
8945% XOpenDisplay.
8946%
8947% o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
8948%
8949% o window: Specifies a pointer to a XWindows structure.
8950%
8951% o mono: Use mono-spaced font when displaying text.
8952%
8953% o title: This character string is displayed at the top of the widget
8954% window.
8955%
8956% o textlist: This string list is displayed within the Text View widget.
8957%
8958*/
8959MagickExport void XTextViewWidget(Display *display,
8960 const XResourceInfo *resource_info,XWindows *windows,
8961 const MagickBooleanType mono,const char *title,const char **textlist)
8962{
8963#define DismissButtonText "Dismiss"
8964
8965 char
8966 primary_selection[MaxTextExtent];
8967
8968 register int
8969 i;
8970
8971 static MagickStatusType
8972 mask = (MagickStatusType) (CWWidth | CWHeight | CWX | CWY);
8973
8974 Status
8975 status;
8976
8977 unsigned int
8978 height,
8979 lines,
8980 text_width,
8981 visible_lines,
8982 width;
8983
cristybb503372010-05-27 20:51:26 +00008984 size_t
cristy3ed852e2009-09-05 21:47:34 +00008985 delay,
8986 state;
8987
8988 XEvent
8989 event;
8990
8991 XFontStruct
8992 *font_info,
8993 *text_info;
8994
8995 XTextProperty
8996 window_name;
8997
8998 XWidgetInfo
8999 dismiss_info,
9000 expose_info,
9001 list_info,
9002 north_info,
9003 scroll_info,
9004 selection_info,
9005 slider_info,
9006 south_info;
9007
9008 XWindowChanges
9009 window_changes;
9010
9011 /*
9012 Convert text string to a text list.
9013 */
9014 assert(display != (Display *) NULL);
9015 assert(resource_info != (XResourceInfo *) NULL);
9016 assert(windows != (XWindows *) NULL);
9017 assert(title != (const char *) NULL);
9018 assert(textlist != (const char **) NULL);
9019 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",title);
9020 XSetCursorState(display,windows,MagickTrue);
9021 XCheckRefreshWindows(display,windows);
9022 if (textlist == (const char **) NULL)
9023 {
9024 XNoticeWidget(display,windows,"No text to view:",(char *) NULL);
9025 return;
9026 }
9027 /*
9028 Determine Text View widget attributes.
9029 */
9030 font_info=windows->widget.font_info;
9031 text_info=(XFontStruct *) NULL;
9032 if (mono != MagickFalse)
9033 text_info=XBestFont(display,resource_info,MagickTrue);
9034 if (text_info == (XFontStruct *) NULL)
9035 text_info=windows->widget.font_info;
9036 text_width=0;
9037 for (i=0; textlist[i] != (char *) NULL; i++)
9038 if (WidgetTextWidth(text_info,(char *) textlist[i]) > text_width)
9039 text_width=(unsigned int) XTextWidth(text_info,(char *) textlist[i],
9040 MagickMin(Extent(textlist[i]),160));
9041 lines=(unsigned int) i;
9042 width=WidgetTextWidth(font_info,DismissButtonText);
9043 width+=QuantumMargin;
9044 height=(unsigned int) (text_info->ascent+text_info->descent);
9045 /*
9046 Position Text View widget.
9047 */
9048 windows->widget.width=(unsigned int) (MagickMin((int) text_width,
9049 (int) MaxTextWidth)+5*QuantumMargin);
9050 windows->widget.min_width=(unsigned int) (MinTextWidth+4*QuantumMargin);
9051 if (windows->widget.width < windows->widget.min_width)
9052 windows->widget.width=windows->widget.min_width;
9053 windows->widget.height=(unsigned int) (MagickMin(MagickMax((int) lines,3),32)*
9054 height+((13*height) >> 1)+((9*QuantumMargin) >> 1));
9055 windows->widget.min_height=(unsigned int) (3*height+((13*height) >> 1)+((9*
9056 QuantumMargin) >> 1));
9057 if (windows->widget.height < windows->widget.min_height)
9058 windows->widget.height=windows->widget.min_height;
9059 XConstrainWindowPosition(display,&windows->widget);
9060 /*
9061 Map Text View widget.
9062 */
9063 (void) CopyMagickString(windows->widget.name,title,MaxTextExtent);
9064 status=XStringListToTextProperty(&windows->widget.name,1,&window_name);
9065 if (status != False)
9066 {
9067 XSetWMName(display,windows->widget.id,&window_name);
9068 XSetWMIconName(display,windows->widget.id,&window_name);
9069 (void) XFree((void *) window_name.value);
9070 }
9071 window_changes.width=(int) windows->widget.width;
9072 window_changes.height=(int) windows->widget.height;
9073 window_changes.x=windows->widget.x;
9074 window_changes.y=windows->widget.y;
9075 (void) XReconfigureWMWindow(display,windows->widget.id,
9076 windows->widget.screen,(unsigned int) mask,&window_changes);
9077 (void) XMapRaised(display,windows->widget.id);
9078 windows->widget.mapped=MagickFalse;
9079 /*
9080 Respond to X events.
9081 */
9082 XGetWidgetInfo((char *) NULL,&slider_info);
9083 XGetWidgetInfo((char *) NULL,&north_info);
9084 XGetWidgetInfo((char *) NULL,&south_info);
9085 XGetWidgetInfo((char *) NULL,&expose_info);
9086 visible_lines=0;
9087 delay=SuspendTime << 2;
9088 height=(unsigned int) (font_info->ascent+font_info->descent);
9089 state=UpdateConfigurationState;
9090 do
9091 {
9092 if (state & UpdateConfigurationState)
9093 {
9094 int
9095 id;
9096
9097 /*
9098 Initialize button information.
9099 */
9100 XGetWidgetInfo(DismissButtonText,&dismiss_info);
9101 dismiss_info.width=width;
9102 dismiss_info.height=(unsigned int) ((3*height) >> 1);
9103 dismiss_info.x=(int) windows->widget.width-dismiss_info.width-
9104 QuantumMargin-2;
9105 dismiss_info.y=(int) windows->widget.height-dismiss_info.height-
9106 QuantumMargin;
9107 /*
9108 Initialize scroll information.
9109 */
9110 XGetWidgetInfo((char *) NULL,&scroll_info);
9111 scroll_info.bevel_width--;
9112 scroll_info.width=height;
9113 scroll_info.height=(unsigned int) (dismiss_info.y-((5*QuantumMargin) >>
9114 1));
9115 scroll_info.x=(int) windows->widget.width-QuantumMargin-
9116 scroll_info.width;
9117 scroll_info.y=(3*QuantumMargin) >> 1;
9118 scroll_info.raised=MagickFalse;
9119 scroll_info.trough=MagickTrue;
9120 north_info=scroll_info;
9121 north_info.raised=MagickTrue;
9122 north_info.width-=(north_info.bevel_width << 1);
9123 north_info.height=north_info.width-1;
9124 north_info.x+=north_info.bevel_width;
9125 north_info.y+=north_info.bevel_width;
9126 south_info=north_info;
9127 south_info.y=scroll_info.y+scroll_info.height-scroll_info.bevel_width-
9128 south_info.height;
9129 id=slider_info.id;
9130 slider_info=north_info;
9131 slider_info.id=id;
9132 slider_info.width-=2;
9133 slider_info.min_y=north_info.y+north_info.height+north_info.bevel_width+
9134 slider_info.bevel_width+2;
9135 slider_info.height=scroll_info.height-((slider_info.min_y-
9136 scroll_info.y+1) << 1)+4;
9137 visible_lines=scroll_info.height/(text_info->ascent+text_info->descent+
9138 ((text_info->ascent+text_info->descent) >> 3));
9139 if (lines > visible_lines)
9140 slider_info.height=(unsigned int) (visible_lines*slider_info.height)/
9141 lines;
9142 slider_info.max_y=south_info.y-south_info.bevel_width-
9143 slider_info.bevel_width-2;
9144 slider_info.x=scroll_info.x+slider_info.bevel_width+1;
9145 slider_info.y=slider_info.min_y;
9146 expose_info=scroll_info;
9147 expose_info.y=slider_info.y;
9148 /*
9149 Initialize list information.
9150 */
9151 XGetWidgetInfo((char *) NULL,&list_info);
9152 list_info.raised=MagickFalse;
9153 list_info.bevel_width--;
9154 list_info.width=(unsigned int) scroll_info.x-((3*QuantumMargin) >> 1);
9155 list_info.height=scroll_info.height;
9156 list_info.x=QuantumMargin;
9157 list_info.y=scroll_info.y;
9158 /*
9159 Initialize selection information.
9160 */
9161 XGetWidgetInfo((char *) NULL,&selection_info);
9162 selection_info.center=MagickFalse;
9163 selection_info.width=list_info.width;
9164 selection_info.height=(unsigned int)
9165 (9*(text_info->ascent+text_info->descent)) >> 3;
9166 selection_info.x=list_info.x;
9167 state&=(~UpdateConfigurationState);
9168 }
9169 if (state & RedrawWidgetState)
9170 {
9171 /*
9172 Redraw Text View window.
9173 */
9174 XDrawBeveledMatte(display,&windows->widget,&list_info);
9175 XDrawBeveledMatte(display,&windows->widget,&scroll_info);
9176 XDrawTriangleNorth(display,&windows->widget,&north_info);
9177 XDrawBeveledButton(display,&windows->widget,&slider_info);
9178 XDrawTriangleSouth(display,&windows->widget,&south_info);
9179 XDrawBeveledButton(display,&windows->widget,&dismiss_info);
9180 XHighlightWidget(display,&windows->widget,BorderOffset,BorderOffset);
9181 selection_info.id=(~0);
9182 state|=RedrawListState;
9183 state&=(~RedrawWidgetState);
9184 }
9185 if (state & RedrawListState)
9186 {
9187 /*
9188 Determine slider id and position.
9189 */
9190 if (slider_info.id >= (int) (lines-visible_lines))
9191 slider_info.id=(int) lines-visible_lines;
9192 if ((slider_info.id < 0) || (lines <= visible_lines))
9193 slider_info.id=0;
9194 slider_info.y=slider_info.min_y;
9195 if (lines != 0)
9196 slider_info.y+=
9197 slider_info.id*(slider_info.max_y-slider_info.min_y+1)/lines;
9198 if (slider_info.id != selection_info.id)
9199 {
9200 /*
9201 Redraw scroll bar and text.
9202 */
9203 windows->widget.font_info=text_info;
9204 (void) XSetFont(display,windows->widget.annotate_context,
9205 text_info->fid);
9206 (void) XSetFont(display,windows->widget.highlight_context,
9207 text_info->fid);
9208 selection_info.id=slider_info.id;
9209 selection_info.y=list_info.y+(height >> 3)+2;
9210 for (i=0; i < (int) visible_lines; i++)
9211 {
9212 selection_info.raised=
9213 (slider_info.id+i) != list_info.id ? MagickTrue : MagickFalse;
9214 selection_info.text=(char *) NULL;
9215 if ((slider_info.id+i) < (int) lines)
9216 selection_info.text=(char *) textlist[slider_info.id+i];
9217 XDrawWidgetText(display,&windows->widget,&selection_info);
9218 selection_info.y+=(int) selection_info.height;
9219 }
9220 windows->widget.font_info=font_info;
9221 (void) XSetFont(display,windows->widget.annotate_context,
9222 font_info->fid);
9223 (void) XSetFont(display,windows->widget.highlight_context,
9224 font_info->fid);
9225 /*
9226 Update slider.
9227 */
9228 if (slider_info.y > expose_info.y)
9229 {
9230 expose_info.height=(unsigned int) slider_info.y-expose_info.y;
9231 expose_info.y=slider_info.y-expose_info.height-
9232 slider_info.bevel_width-1;
9233 }
9234 else
9235 {
9236 expose_info.height=(unsigned int) expose_info.y-slider_info.y;
9237 expose_info.y=slider_info.y+slider_info.height+
9238 slider_info.bevel_width+1;
9239 }
9240 XDrawTriangleNorth(display,&windows->widget,&north_info);
9241 XDrawMatte(display,&windows->widget,&expose_info);
9242 XDrawBeveledButton(display,&windows->widget,&slider_info);
9243 XDrawTriangleSouth(display,&windows->widget,&south_info);
9244 expose_info.y=slider_info.y;
9245 }
9246 state&=(~RedrawListState);
9247 }
9248 /*
9249 Wait for next event.
9250 */
9251 if (north_info.raised && south_info.raised)
9252 (void) XIfEvent(display,&event,XScreenEvent,(char *) windows);
9253 else
9254 {
9255 /*
9256 Brief delay before advancing scroll bar.
9257 */
9258 XDelay(display,delay);
9259 delay=SuspendTime;
9260 (void) XCheckIfEvent(display,&event,XScreenEvent,(char *) windows);
9261 if (north_info.raised == MagickFalse)
9262 if (slider_info.id > 0)
9263 {
9264 /*
9265 Move slider up.
9266 */
9267 slider_info.id--;
9268 state|=RedrawListState;
9269 }
9270 if (south_info.raised == MagickFalse)
9271 if (slider_info.id < (int) lines)
9272 {
9273 /*
9274 Move slider down.
9275 */
9276 slider_info.id++;
9277 state|=RedrawListState;
9278 }
9279 if (event.type != ButtonRelease)
9280 continue;
9281 }
9282 switch (event.type)
9283 {
9284 case ButtonPress:
9285 {
9286 if (MatteIsActive(slider_info,event.xbutton))
9287 {
9288 /*
9289 Track slider.
9290 */
9291 slider_info.active=MagickTrue;
9292 break;
9293 }
9294 if (MatteIsActive(north_info,event.xbutton))
9295 if (slider_info.id > 0)
9296 {
9297 /*
9298 Move slider up.
9299 */
9300 north_info.raised=MagickFalse;
9301 slider_info.id--;
9302 state|=RedrawListState;
9303 break;
9304 }
9305 if (MatteIsActive(south_info,event.xbutton))
9306 if (slider_info.id < (int) lines)
9307 {
9308 /*
9309 Move slider down.
9310 */
9311 south_info.raised=MagickFalse;
9312 slider_info.id++;
9313 state|=RedrawListState;
9314 break;
9315 }
9316 if (MatteIsActive(scroll_info,event.xbutton))
9317 {
9318 /*
9319 Move slider.
9320 */
9321 if (event.xbutton.y < slider_info.y)
9322 slider_info.id-=(visible_lines-1);
9323 else
9324 slider_info.id+=(visible_lines-1);
9325 state|=RedrawListState;
9326 break;
9327 }
9328 if (MatteIsActive(dismiss_info,event.xbutton))
9329 {
9330 /*
9331 User pressed Dismiss button.
9332 */
9333 dismiss_info.raised=MagickFalse;
9334 XDrawBeveledButton(display,&windows->widget,&dismiss_info);
9335 break;
9336 }
9337 if (MatteIsActive(list_info,event.xbutton))
9338 {
9339 int
9340 id;
9341
9342 static Time
9343 click_time;
9344
9345 /*
9346 User pressed list matte.
9347 */
9348 id=slider_info.id+(event.xbutton.y-(list_info.y+(height >> 1))+1)/
9349 selection_info.height;
9350 if (id >= (int) lines)
9351 break;
9352 if (id != list_info.id)
9353 {
9354 list_info.id=id;
9355 click_time=event.xbutton.time;
9356 break;
9357 }
9358 list_info.id=id;
9359 if (event.xbutton.time >= (click_time+DoubleClick))
9360 {
9361 click_time=event.xbutton.time;
9362 break;
9363 }
9364 click_time=event.xbutton.time;
9365 /*
9366 Become the XA_PRIMARY selection owner.
9367 */
9368 (void) CopyMagickString(primary_selection,textlist[list_info.id],
9369 MaxTextExtent);
9370 (void) XSetSelectionOwner(display,XA_PRIMARY,windows->widget.id,
9371 event.xbutton.time);
9372 if (XGetSelectionOwner(display,XA_PRIMARY) != windows->widget.id)
9373 break;
9374 selection_info.id=(~0);
9375 list_info.id=id;
9376 state|=RedrawListState;
9377 break;
9378 }
9379 break;
9380 }
9381 case ButtonRelease:
9382 {
9383 if (windows->widget.mapped == MagickFalse)
9384 break;
9385 if (north_info.raised == MagickFalse)
9386 {
9387 /*
9388 User released up button.
9389 */
9390 delay=SuspendTime << 2;
9391 north_info.raised=MagickTrue;
9392 XDrawTriangleNorth(display,&windows->widget,&north_info);
9393 }
9394 if (south_info.raised == MagickFalse)
9395 {
9396 /*
9397 User released down button.
9398 */
9399 delay=SuspendTime << 2;
9400 south_info.raised=MagickTrue;
9401 XDrawTriangleSouth(display,&windows->widget,&south_info);
9402 }
9403 if (slider_info.active)
9404 {
9405 /*
9406 Stop tracking slider.
9407 */
9408 slider_info.active=MagickFalse;
9409 break;
9410 }
9411 if (dismiss_info.raised == MagickFalse)
9412 {
9413 if (event.xbutton.window == windows->widget.id)
9414 if (MatteIsActive(dismiss_info,event.xbutton))
9415 state|=ExitState;
9416 dismiss_info.raised=MagickTrue;
9417 XDrawBeveledButton(display,&windows->widget,&dismiss_info);
9418 }
9419 break;
9420 }
9421 case ClientMessage:
9422 {
9423 /*
9424 If client window delete message, exit.
9425 */
9426 if (event.xclient.message_type != windows->wm_protocols)
9427 break;
9428 if (*event.xclient.data.l == (int) windows->wm_take_focus)
9429 {
9430 (void) XSetInputFocus(display,event.xclient.window,RevertToParent,
9431 (Time) event.xclient.data.l[1]);
9432 break;
9433 }
9434 if (*event.xclient.data.l != (int) windows->wm_delete_window)
9435 break;
9436 if (event.xclient.window == windows->widget.id)
9437 {
9438 state|=ExitState;
9439 break;
9440 }
9441 break;
9442 }
9443 case ConfigureNotify:
9444 {
9445 /*
9446 Update widget configuration.
9447 */
9448 if (event.xconfigure.window != windows->widget.id)
9449 break;
9450 if ((event.xconfigure.width == (int) windows->widget.width) &&
9451 (event.xconfigure.height == (int) windows->widget.height))
9452 break;
9453 windows->widget.width=(unsigned int)
9454 MagickMax(event.xconfigure.width,(int) windows->widget.min_width);
9455 windows->widget.height=(unsigned int)
9456 MagickMax(event.xconfigure.height,(int) windows->widget.min_height);
9457 state|=UpdateConfigurationState;
9458 break;
9459 }
9460 case EnterNotify:
9461 {
9462 if (event.xcrossing.window != windows->widget.id)
9463 break;
9464 state&=(~InactiveWidgetState);
9465 break;
9466 }
9467 case Expose:
9468 {
9469 if (event.xexpose.window != windows->widget.id)
9470 break;
9471 if (event.xexpose.count != 0)
9472 break;
9473 state|=RedrawWidgetState;
9474 break;
9475 }
9476 case KeyPress:
9477 {
9478 static char
9479 command[MaxTextExtent];
9480
9481 static int
9482 length;
9483
9484 static KeySym
9485 key_symbol;
9486
9487 /*
9488 Respond to a user key press.
9489 */
9490 if (event.xkey.window != windows->widget.id)
9491 break;
9492 length=XLookupString((XKeyEvent *) &event.xkey,command,
9493 (int) sizeof(command),&key_symbol,(XComposeStatus *) NULL);
9494 *(command+length)='\0';
9495 if ((key_symbol == XK_Return) || (key_symbol == XK_KP_Enter))
9496 {
9497 dismiss_info.raised=MagickFalse;
9498 XDrawBeveledButton(display,&windows->widget,&dismiss_info);
9499 state|=ExitState;
9500 break;
9501 }
9502 if (AreaIsActive(scroll_info,event.xkey))
9503 {
9504 /*
9505 Move slider.
9506 */
9507 switch ((int) key_symbol)
9508 {
9509 case XK_Home:
9510 case XK_KP_Home:
9511 {
9512 slider_info.id=0;
9513 break;
9514 }
9515 case XK_Up:
9516 case XK_KP_Up:
9517 {
9518 slider_info.id--;
9519 break;
9520 }
9521 case XK_Down:
9522 case XK_KP_Down:
9523 {
9524 slider_info.id++;
9525 break;
9526 }
9527 case XK_Prior:
9528 case XK_KP_Prior:
9529 {
9530 slider_info.id-=visible_lines;
9531 break;
9532 }
9533 case XK_Next:
9534 case XK_KP_Next:
9535 {
9536 slider_info.id+=visible_lines;
9537 break;
9538 }
9539 case XK_End:
9540 case XK_KP_End:
9541 {
9542 slider_info.id=(int) lines;
9543 break;
9544 }
9545 }
9546 state|=RedrawListState;
9547 break;
9548 }
9549 break;
9550 }
9551 case KeyRelease:
9552 break;
9553 case LeaveNotify:
9554 {
9555 if (event.xcrossing.window != windows->widget.id)
9556 break;
9557 state|=InactiveWidgetState;
9558 break;
9559 }
9560 case MapNotify:
9561 {
9562 mask&=(~CWX);
9563 mask&=(~CWY);
9564 break;
9565 }
9566 case MotionNotify:
9567 {
9568 /*
9569 Discard pending button motion events.
9570 */
9571 while (XCheckMaskEvent(display,ButtonMotionMask,&event)) ;
9572 if (slider_info.active)
9573 {
9574 /*
9575 Move slider matte.
9576 */
9577 slider_info.y=event.xmotion.y-
9578 ((slider_info.height+slider_info.bevel_width) >> 1)+1;
9579 if (slider_info.y < slider_info.min_y)
9580 slider_info.y=slider_info.min_y;
9581 if (slider_info.y > slider_info.max_y)
9582 slider_info.y=slider_info.max_y;
9583 slider_info.id=0;
9584 if (slider_info.y != slider_info.min_y)
9585 slider_info.id=(int) (lines*(slider_info.y-slider_info.min_y+1))/
9586 (slider_info.max_y-slider_info.min_y+1);
9587 state|=RedrawListState;
9588 break;
9589 }
9590 if (state & InactiveWidgetState)
9591 break;
9592 if (dismiss_info.raised == MatteIsActive(dismiss_info,event.xmotion))
9593 {
9594 /*
9595 Dismiss button status changed.
9596 */
9597 dismiss_info.raised=
9598 dismiss_info.raised == MagickFalse ? MagickTrue : MagickFalse;
9599 XDrawBeveledButton(display,&windows->widget,&dismiss_info);
9600 break;
9601 }
9602 break;
9603 }
9604 case SelectionClear:
9605 {
9606 list_info.id=(~0);
9607 selection_info.id=(~0);
9608 state|=RedrawListState;
9609 break;
9610 }
9611 case SelectionRequest:
9612 {
9613 XSelectionEvent
9614 notify;
9615
9616 XSelectionRequestEvent
9617 *request;
9618
9619 if (list_info.id == (~0))
9620 break;
9621 /*
9622 Set primary selection.
9623 */
9624 request=(&(event.xselectionrequest));
9625 (void) XChangeProperty(request->display,request->requestor,
9626 request->property,request->target,8,PropModeReplace,
9627 (unsigned char *) primary_selection,Extent(primary_selection));
9628 notify.type=SelectionNotify;
9629 notify.send_event=MagickTrue;
9630 notify.display=request->display;
9631 notify.requestor=request->requestor;
9632 notify.selection=request->selection;
9633 notify.target=request->target;
9634 notify.time=request->time;
9635 if (request->property == None)
9636 notify.property=request->target;
9637 else
9638 notify.property=request->property;
9639 (void) XSendEvent(request->display,request->requestor,False,NoEventMask,
9640 (XEvent *) &notify);
9641 }
9642 default:
9643 break;
9644 }
9645 } while ((state & ExitState) == 0);
9646 if (text_info != windows->widget.font_info)
9647 (void) XFreeFont(display,text_info);
9648 XSetCursorState(display,windows,MagickFalse);
9649 (void) XWithdrawWindow(display,windows->widget.id,windows->widget.screen);
9650 XCheckRefreshWindows(display,windows);
9651}
9652#endif