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