1 /*
2  * tkMacOSXEntry.c --
3  *
4  *	This file implements the native aqua entry widget.
5  *
6  * Copyright 2001, Apple Computer, Inc.
7  * Copyright (c) 2006-2009 Daniel A. Steffen <das@users.sourceforge.net>
8  * Copyright 2008-2009, Apple Inc.
9  *
10  * See the file "license.terms" for information on usage and redistribution
11  * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
12  */
13 
14 #include "tkMacOSXPrivate.h"
15 #include "tkEntry.h"
16 
17 static ThemeButtonKind	ComputeIncDecParameters(int height, int *width);
18 
19 #define HIOrientation kHIThemeOrientationNormal
20 
21 /*
22  *--------------------------------------------------------------
23  *
24  * ComputeIncDecParameters --
25  *
26  *	This procedure figures out which of the kThemeIncDec buttons to use.
27  *	It also sets width to the width of the IncDec button.
28  *
29  * Results:
30  *	The ThemeButtonKind of the button we should use.
31  *
32  * Side effects:
33  *	May draw the entry border into pixmap.
34  *
35  *--------------------------------------------------------------
36  */
37 
38 static ThemeButtonKind
ComputeIncDecParameters(int height,int * width)39 ComputeIncDecParameters(
40     int height,
41     int *width)
42 {
43     ThemeButtonKind kind;
44 
45     if (height < 11 || height > 28) {
46 	*width = 0;
47 	kind = (ThemeButtonKind) 0;
48     } else {
49 	if (height >= 21) {
50 	    *width = 13;
51 	    kind = kThemeIncDecButton;
52 	} else if (height >= 18) {
53 	    *width = 12;
54 	    kind = kThemeIncDecButtonSmall;
55 	} else {
56 	    *width = 11;
57 	    kind = kThemeIncDecButtonMini;
58 	}
59     }
60 
61     return kind;
62 }
63 
64 /*
65  *--------------------------------------------------------------
66  *
67  * TkpDrawEntryBorderAndFocus --
68  *
69  *	This procedure redraws the border of an entry window. It overrides the
70  *	generic border drawing code if the entry widget parameters are such
71  *	that the native widget drawing is a good fit. This version just
72  *	returns 1, so platforms that don't do special native drawing don't
73  *	have to implement it.
74  *
75  * Results:
76  *	1 if it has drawn the border, 0 if not.
77  *
78  * Side effects:
79  *	May draw the entry border into pixmap.
80  *
81  *--------------------------------------------------------------
82  */
83 
84 int
TkpDrawEntryBorderAndFocus(Entry * entryPtr,Drawable d,int isSpinbox)85 TkpDrawEntryBorderAndFocus(
86     Entry *entryPtr,
87     Drawable d,
88     int isSpinbox)
89 {
90     CGRect bounds;
91     TkMacOSXDrawingContext dc;
92     GC bgGC;
93     Tk_Window tkwin = entryPtr->tkwin;
94     int oldWidth = 0;
95     MacDrawable *macDraw = (MacDrawable *)d;
96     const HIThemeFrameDrawInfo info = {
97 	.version = 0,
98 	.kind = kHIThemeFrameTextFieldSquare,
99 	.state = (entryPtr->state == STATE_DISABLED ? kThemeStateInactive :
100 		kThemeStateActive),
101 	.isFocused = (entryPtr->flags & GOT_FOCUS ? 1 : 0),
102     };
103 
104     /*
105      * I use 6 as the borderwidth. 2 of the 5 go into the actual frame the 3
106      * are because the Mac OS Entry widgets leave more space around the Text
107      * than Tk does on X11.
108      */
109 
110     if (entryPtr->borderWidth != MAC_OSX_ENTRY_BORDER
111 	    || entryPtr->highlightWidth != MAC_OSX_FOCUS_WIDTH
112 	    || entryPtr->relief != MAC_OSX_ENTRY_RELIEF) {
113 	return 0;
114     }
115 
116     /*
117      * For the spinbox, we have to make the entry part smaller by the size of
118      * the buttons. We also leave 2 pixels to the left (as per the HIG) and
119      * space for one pixel to the right, 'cause it makes the buttons look
120      * nicer.
121      */
122 
123     if (isSpinbox) {
124 	int incDecWidth;
125 
126 	/*
127 	 * If native spinbox buttons are going to be drawn, then temporarily
128 	 * change the width of the widget so that the same code can be used
129 	 * for drawing the Entry portion of the Spinbox as is used to draw
130 	 * an ordinary Entry.  The width must be restored before returning.
131 	 */
132 
133 	oldWidth = Tk_Width(tkwin);
134 	if (ComputeIncDecParameters(Tk_Height(tkwin) - 2 * MAC_OSX_FOCUS_WIDTH,
135 		&incDecWidth) != 0) {
136 	    Tk_Width(tkwin) -= incDecWidth + 1;
137 	}
138     }
139 
140    /*
141     * The focus ring is drawn with an Alpha at the outside part of the ring,
142     * so we have to draw over the edges of the ring before drawing the focus
143     * or the text will peep through.
144     */
145 
146     bgGC = Tk_GCForColor(entryPtr->highlightBgColorPtr, d);
147     TkDrawInsetFocusHighlight(entryPtr->tkwin, bgGC, MAC_OSX_FOCUS_WIDTH, d, 0);
148 
149     /*
150      * Inset the entry Frame by the maximum width of the focus rect, which is
151      * 3 according to the Carbon docs.
152      */
153 
154     bounds.origin.x = macDraw->xOff + MAC_OSX_FOCUS_WIDTH;
155     bounds.origin.y = macDraw->yOff + MAC_OSX_FOCUS_WIDTH;
156     bounds.size.width = Tk_Width(tkwin) - 2*MAC_OSX_FOCUS_WIDTH;
157     bounds.size.height = Tk_Height(tkwin) - 2*MAC_OSX_FOCUS_WIDTH;
158     if (!TkMacOSXSetupDrawingContext(d, NULL, &dc)) {
159 
160 	/*
161 	 * No graphics context is available.  If the widget is a Spinbox, we
162 	 * must restore its width before returning 0. (Ticket [273b6a4996].)
163 	 */
164 
165 	if (isSpinbox) {
166 	    Tk_Width(tkwin) = oldWidth;
167 	}
168 	return 0;
169     }
170     ChkErr(HIThemeDrawFrame, &bounds, &info, dc.context, HIOrientation);
171     TkMacOSXRestoreDrawingContext(&dc);
172     if (isSpinbox) {
173 	Tk_Width(tkwin) = oldWidth;
174     }
175     return 1;
176 }
177 
178 /*
179  *--------------------------------------------------------------
180  *
181  * TkpDrawSpinboxButtons --
182  *
183  *	This procedure redraws the buttons of an spinbox widget. It overrides
184  *	the generic button drawing code if the spinbox widget parameters are
185  *	such that the native widget drawing is a good fit. This version just
186  *	returns 0, so platforms that don't do special native drawing don't
187  *	have to implement it.
188  *
189  * Results:
190  *	1 if it has drawn the buttons, 0 if not.
191  *
192  * Side effects:
193  *	May draw the buttons into pixmap.
194  *
195  *--------------------------------------------------------------
196  */
197 
198 int
TkpDrawSpinboxButtons(Spinbox * sbPtr,Drawable d)199 TkpDrawSpinboxButtons(
200     Spinbox *sbPtr,
201     Drawable d)
202 {
203     CGRect bounds;
204     Tk_Window tkwin = sbPtr->entry.tkwin;
205     int height = Tk_Height(tkwin);
206     int buttonHeight = height - 2 * MAC_OSX_FOCUS_WIDTH;
207     int incDecWidth;
208     TkMacOSXDrawingContext dc;
209     XRectangle rects[1];
210     GC bgGC;
211     MacDrawable *macDraw = (MacDrawable *)d;
212     HIThemeButtonDrawInfo info = {
213 	.version = 0,
214 	.adornment = kThemeAdornmentNone,
215     };
216 
217     /*
218      * FIXME: RAISED really makes more sense
219      */
220 
221     if (sbPtr->buRelief != TK_RELIEF_FLAT) {
222 	return 0;
223     }
224 
225     /*
226      * The actual sizes of the IncDec button are 21 for the normal, 18 for the
227      * small and 15 for the mini. But the spinbox still looks okay if the
228      * entry is a little bigger than this, so we give it a little slop.
229      */
230 
231     info.kind = ComputeIncDecParameters(buttonHeight, &incDecWidth);
232     if (info.kind == (ThemeButtonKind) 0) {
233 	return 0;
234     }
235 
236     if (sbPtr->entry.state == STATE_DISABLED) {
237 	info.state = kThemeStateInactive;
238 	info.value = kThemeButtonOff;
239     } else if (sbPtr->selElement == SEL_BUTTONUP) {
240 	info.state = kThemeStatePressedUp;
241 	info.value = kThemeButtonOn;
242     } else if (sbPtr->selElement == SEL_BUTTONDOWN) {
243 	info.state = kThemeStatePressedDown;
244 	info.value = kThemeButtonOn;
245     } else {
246 	info.state = kThemeStateActive;
247 	info.value = kThemeButtonOff;
248     }
249 
250     bounds.origin.x = macDraw->xOff + Tk_Width(tkwin) - incDecWidth - 1;
251     bounds.origin.y = macDraw->yOff + MAC_OSX_FOCUS_WIDTH;
252     bounds.size.width = incDecWidth;
253     bounds.size.height = Tk_Height(tkwin) - 2*MAC_OSX_FOCUS_WIDTH;
254 
255     /*
256      * We had to make the entry part of the window smaller so that we wouldn't
257      * overdraw the spin buttons with the focus highlight. So now we have to
258      * draw the highlightbackground.
259      */
260 
261     bgGC = Tk_GCForColor(sbPtr->entry.highlightBgColorPtr, d);
262     rects[0].x = Tk_Width(tkwin) - incDecWidth - 1;
263     rects[0].y = 0;
264     rects[0].width = incDecWidth + 1;
265     rects[0].height = Tk_Height(tkwin);
266     XFillRectangles(Tk_Display(tkwin), d, bgGC, rects, 1);
267 
268     if (!TkMacOSXSetupDrawingContext(d, NULL, &dc)) {
269 	return 0;
270     }
271     ChkErr(HIThemeDrawButton, &bounds, &info, dc.context, HIOrientation, NULL);
272     TkMacOSXRestoreDrawingContext(&dc);
273     return 1;
274 }
275 
276 /*
277  * Local Variables:
278  * mode: objc
279  * c-basic-offset: 4
280  * fill-column: 79
281  * coding: utf-8
282  * End:
283  */
284