1/*
2
3Copyright 1988, 1998  The Open Group
4
5Permission to use, copy, modify, distribute, and sell this software and its
6documentation for any purpose is hereby granted without fee, provided that
7the above copyright notice appear in all copies and that both that
8copyright notice and this permission notice appear in supporting
9documentation.
10
11The above copyright notice and this permission notice shall be included in
12all copies or substantial portions of the Software.
13
14THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
17OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
18AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
19CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20
21Except as contained in this notice, the name of The Open Group shall not be
22used in advertising or otherwise to promote the sale, use or other dealings
23in this Software without prior written authorization from The Open Group.
24
25*/
26
27#ifdef HAVE_CONFIG_H
28#include <config.h>
29#endif
30#include <X11/IntrinsicP.h>
31#include <X11/extensions/shape.h>
32#include "Converters.h"
33#include "Drawing.h"
34#include "Misc.h"
35
36/*
37 * Prototypes
38 */
39static void ShapeEllipseOrRoundedRectangle(Widget, Bool, int, int);
40static void ShapeError(Widget);
41static void ShapeOval(Widget);
42static void ShapeRectangle(Widget);
43
44/*
45 * Implementation
46 */
47Boolean
48XmuReshapeWidget(Widget w, int shape_style,
49		 int corner_width, int corner_height)
50{
51  switch (shape_style)
52    {
53      case XmuShapeRectangle:
54	ShapeRectangle(w);
55	break;
56      case XmuShapeOval:
57	ShapeOval(w);
58	break;
59      case XmuShapeEllipse:
60      case XmuShapeRoundedRectangle:
61      ShapeEllipseOrRoundedRectangle(w, shape_style == XmuShapeEllipse,
62				     corner_width, corner_height);
63	break;
64      default:
65	ShapeError(w);
66      return (False);
67    }
68  return (True);
69}
70
71static void
72ShapeError(Widget w)
73{
74    String params[1];
75    Cardinal num_params = 1;
76
77    params[0] = XtName(w);
78  XtAppWarningMsg(XtWidgetToApplicationContext(w),
79		     "shapeUnknown", "xmuReshapeWidget", "XmuLibrary",
80		     "Unsupported shape style for Command widget \"%s\"",
81		  params, &num_params);
82}
83
84static void
85ShapeRectangle(Widget w)
86{
87  XShapeCombineMask(XtDisplay(w), XtWindow(w),
88		    ShapeBounding, 0, 0, None, ShapeSet);
89  XShapeCombineMask(XtDisplay(w), XtWindow(w),
90		    ShapeClip, 0, 0, None, ShapeSet);
91}
92
93/*
94 * Function:
95 *	ShapeOval
96 *
97 * Parameters:
98 *	w - widget to be reshaped
99 *
100 * Description:
101 *	Reshapes a widget to a oval format.
102 *
103 * Notes:
104 *	  X11R6.3 behaviour changed. Now if the height is larger than the
105 *	width, this function inverts the sense of the oval, instead of
106 *	fallbacking to ellipse.
107 */
108static void
109ShapeOval(Widget w)
110{
111    Display *dpy = XtDisplay(w);
112    int width = w->core.width;
113    int height = w->core.height;
114    Pixmap p;
115    XGCValues values;
116    GC gc;
117    int rad;
118
119    if (width < 3 || height < 3)
120      return;
121    width += w->core.border_width << 1;
122    height += w->core.border_width << 1;
123
124    p = XCreatePixmap(dpy, XtWindow(w), width, height, 1);
125    values.foreground = 0;
126    values.background = 1;
127    values.cap_style = CapRound;
128    values.line_width = Min(width, height);
129    gc = XCreateGC(dpy, p,
130		    GCForeground | GCBackground | GCLineWidth | GCCapStyle,
131		    &values);
132    XFillRectangle(dpy, p, gc, 0, 0, width, height);
133    XSetForeground(dpy, gc, 1);
134
135    if (width < height)
136      {
137	rad = width >> 1;
138	XDrawLine(dpy, p, gc, rad, rad, rad, height - rad - 1);
139      }
140    else
141      {
142	rad = height >> 1;
143	XDrawLine(dpy, p, gc, rad, rad, width - rad - 1, rad);
144    }
145    XShapeCombineMask(dpy, XtWindow(w), ShapeBounding,
146		      -(int)w->core.border_width, -(int)w->core.border_width,
147		      p, ShapeSet);
148    if (w->core.border_width)
149      {
150	XSetForeground(dpy, gc, 0);
151	XFillRectangle(dpy, p, gc, 0, 0, width, height);
152	values.line_width = Min(w->core.width, w->core.height);
153	values.foreground = 1;
154	XChangeGC(dpy, gc, GCLineWidth | GCForeground, &values);
155	if (w->core.width < w->core.height)
156	  {
157	    rad = w->core.width >> 1;
158	    XDrawLine(dpy, p, gc, rad, rad, rad, w->core.height - rad - 1);
159	  }
160	else
161	  {
162	    rad = w->core.height >> 1;
163	    XDrawLine(dpy, p, gc, rad, rad, w->core.width - rad - 1, rad);
164	}
165	XShapeCombineMask(dpy, XtWindow(w), ShapeClip, 0, 0, p, ShapeSet);
166    }
167    else
168      XShapeCombineMask(XtDisplay(w), XtWindow(w),
169			ShapeClip, 0, 0, None, ShapeSet);
170
171    XFreePixmap(dpy, p);
172    XFreeGC(dpy, gc);
173}
174
175/*
176 * Function:
177 *	ShapeEllipseOrRoundedRectangle
178 *
179 * Parameters:
180 *	w	- widget to be reshaped
181 *	ellipse - True if shape to ellipse, rounded rectangle otherwise
182 *	ew	- horizontal radius of rounded rectangle
183 *	eh	- vertical radius of rounded rectangle
184 *
185 * Description:
186 *	  Based on the ellipse parameter, gives the widget a elliptical
187 *	shape, or rounded rectangle shape.
188 *
189 * Notes:
190 *	  The GC is created with a line width of 2, what seens to draw the
191 *	widget border correctly, if the width - height is not proportional.
192 */
193static void
194ShapeEllipseOrRoundedRectangle(Widget w, Bool ellipse, int ew, int eh)
195{
196    Display *dpy = XtDisplay(w);
197  unsigned width = w->core.width;
198  unsigned height = w->core.height;
199  Pixmap p;
200    XGCValues values;
201    GC gc;
202  unsigned long mask;
203
204  if (width < 3 || height < 3)
205    return;
206  width += w->core.border_width << 1;
207  height += w->core.border_width << 1;
208
209  mask = GCForeground | GCLineWidth;
210  p = XCreatePixmap(dpy, XtWindow(w), width, height, 1);
211
212    values.foreground = 0;
213  values.line_width = 2;
214
215  gc = XCreateGC(dpy, p, mask, &values);
216  XFillRectangle(dpy, p, gc, 0, 0, width, height);
217  XSetForeground(dpy, gc, 1);
218    if (!ellipse)
219    XmuFillRoundedRectangle(dpy, p, gc, 1, 1, width - 2, height - 2, ew, eh);
220    else
221    {
222      XDrawArc(dpy, p, gc, 1, 1, width - 2, height - 2, 0, 360 * 64);
223      XFillArc(dpy, p, gc, 2, 2, width - 4, height - 4, 0, 360 * 64);
224    }
225  XShapeCombineMask(dpy, XtWindow(w), ShapeBounding,
226		    -(int)w->core.border_width, -(int)w->core.border_width,
227		    p, ShapeSet);
228  if (w->core.border_width)
229    {
230      XSetForeground(dpy, gc, 0);
231      XFillRectangle(dpy, p, gc, 0, 0, width, height);
232      XSetForeground(dpy, gc, 1);
233	if (!ellipse)
234	XmuFillRoundedRectangle(dpy, p, gc, 1, 1,
235				w->core.width - 2, w->core.height - 2,
236				ew, eh);
237      else
238	XFillArc(dpy, p, gc, 0, 0, w->core.width, w->core.height,
239		 0, 360 * 64);
240      XShapeCombineMask(dpy, XtWindow(w), ShapeClip, 0, 0, p, ShapeSet);
241    }
242  else
243    XShapeCombineMask(XtDisplay(w), XtWindow(w),
244		      ShapeClip, 0, 0, None, ShapeSet);
245
246  XFreePixmap(dpy, p);
247  XFreeGC(dpy, gc);
248}
249