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