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