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