|
|
1.1 root 1: /*---------------------------------------------------------------------
2: SQBTNLIB.C -- Dynamic link library version of square 3D push button
3: ---------------------------------------------------------------------*/
4:
5: #define INCL_WIN
6: #define INCL_GPI
7: #include <os2.h>
8: #include <malloc.h>
9: #include <string.h>
10: #include "sqbtnlib.h"
11:
12: #define LCID_ITALIC 1L
13:
14: /*--------------------------------------------------
15: Structure for storing data unique to each window
16: --------------------------------------------------*/
17: typedef struct
18: {
19: PSZ pszText ;
20: BOOL fHaveCapture ;
21: BOOL fHaveFocus ;
22: BOOL fInsideRect ;
23: BOOL fSpaceDown ;
24: }
25: SQBTN ;
26:
27: typedef SQBTN *PSQBTN ;
28:
29: MRESULT EXPENTRY SqBtnWndProc (HWND, USHORT, MPARAM, MPARAM) ;
30: VOID DrawButton (HWND, HPS, PSQBTN) ;
31:
32: HAB hab ;
33:
34: /*--------------------------------------------------------
35: RegisterSqBtnClass function available to other modules
36: --------------------------------------------------------*/
37:
38: BOOL APIENTRY RegisterSqBtnClass (HAB habIn)
39: {
40: hab = habIn ;
41:
42: return WinRegisterClass (hab, "SqBtn", SqBtnWndProc,
43: CS_SIZEREDRAW, sizeof (PSQBTN)) ;
44: }
45:
46: /*-------------------------------
47: SqBtnWndProc window procedure
48: -------------------------------*/
49:
50: MRESULT EXPENTRY SqBtnWndProc (HWND hwnd, USHORT msg, MPARAM mp1, MPARAM mp2)
51: {
52: BOOL fTestInsideRect ;
53: HPS hps ;
54: PCREATESTRUCT pcrst ;
55: POINTL ptl ;
56: PSQBTN pSqBtn ;
57: PWNDPARAMS pwprm ;
58: RECTL rcl ;
59:
60: pSqBtn = WinQueryWindowPtr (hwnd, 0) ;
61:
62: switch (msg)
63: {
64: case WM_CREATE:
65: pSqBtn = malloc (sizeof (SQBTN)) ;
66:
67: // Initialize structure
68:
69: pSqBtn->fHaveCapture = FALSE ;
70: pSqBtn->fHaveFocus = FALSE ;
71: pSqBtn->fInsideRect = FALSE ;
72: pSqBtn->fSpaceDown = FALSE ;
73:
74: // Get window text from creation structure
75:
76: pcrst = (PCREATESTRUCT) PVOIDFROMMP (mp2) ;
77:
78: pSqBtn->pszText = malloc (1 + strlen (pcrst->pszText)) ;
79: strcpy (pSqBtn->pszText, pcrst->pszText) ;
80:
81: WinSetWindowPtr (hwnd, 0, pSqBtn) ;
82: return 0 ;
83:
84: case WM_SETWINDOWPARAMS:
85: pwprm = (PWNDPARAMS) PVOIDFROMMP (mp1) ;
86:
87: // Get window text from window parameter structure
88:
89: if (pwprm->fsStatus & WPM_TEXT)
90: {
91: free (pSqBtn->pszText) ;
92: pSqBtn->pszText = malloc (1 + pwprm->cchText) ;
93: strcpy (pSqBtn->pszText, pwprm->pszText) ;
94: }
95: return 1 ;
96:
97: case WM_QUERYWINDOWPARAMS:
98: pwprm == (PWNDPARAMS) PVOIDFROMMP (mp1) ;
99:
100: // Set window parameter structure fields
101:
102: if (pwprm->fsStatus & WPM_CCHTEXT)
103: pwprm->cchText = strlen (pSqBtn->pszText) ;
104:
105: if (pwprm->fsStatus & WPM_TEXT)
106: strcpy (pwprm->pszText, pSqBtn->pszText) ;
107:
108: if (pwprm->fsStatus & WPM_CBPRESPARAMS)
109: pwprm->cbPresParams = 0 ;
110:
111: if (pwprm->fsStatus & WPM_PRESPARAMS)
112: pwprm->pPresParams = NULL ;
113:
114: if (pwprm->fsStatus & WPM_CBCTLDATA)
115: pwprm->cbCtlData = 0 ;
116:
117: if (pwprm->fsStatus & WPM_CTLDATA)
118: pwprm->pCtlData = NULL ;
119:
120: return 1 ;
121:
122: case WM_BUTTON1DOWN:
123: WinSetFocus (HWND_DESKTOP, hwnd) ;
124: WinSetCapture (HWND_DESKTOP, hwnd) ;
125: pSqBtn->fHaveCapture = TRUE ;
126: pSqBtn->fInsideRect = TRUE ;
127: WinInvalidateRect (hwnd, NULL, FALSE) ;
128: return 0 ;
129:
130: case WM_MOUSEMOVE:
131: if (!pSqBtn->fHaveCapture)
132: break ;
133:
134: WinQueryWindowRect (hwnd, &rcl) ;
135: ptl.x = MOUSEMSG(&msg)->x ;
136: ptl.y = MOUSEMSG(&msg)->y ;
137:
138: // Test if mouse pointer is still in window
139:
140: fTestInsideRect = WinPtInRect (hab, &rcl, &ptl) ;
141:
142: if (pSqBtn->fInsideRect != fTestInsideRect)
143: {
144: pSqBtn->fInsideRect = fTestInsideRect ;
145: WinInvalidateRect (hwnd, NULL, FALSE) ;
146: }
147: break ;
148:
149: case WM_BUTTON1UP:
150: if (!pSqBtn->fHaveCapture)
151: break ;
152:
153: WinSetCapture (HWND_DESKTOP, NULL) ;
154: pSqBtn->fHaveCapture = FALSE ;
155: pSqBtn->fInsideRect = FALSE ;
156:
157: WinQueryWindowRect (hwnd, &rcl) ;
158: ptl.x = MOUSEMSG(&msg)->x ;
159: ptl.y = MOUSEMSG(&msg)->y ;
160:
161: // Post WM_COMMAND if mouse pointer is in window
162:
163: if (WinPtInRect (hab, &rcl, &ptl))
164: WinPostMsg (WinQueryWindow (hwnd, QW_OWNER, FALSE),
165: WM_COMMAND,
166: MPFROMSHORT (WinQueryWindowUShort (hwnd, QWS_ID)),
167: MPFROM2SHORT (CMDSRC_OTHER, TRUE)) ;
168:
169: WinInvalidateRect (hwnd, NULL, FALSE) ;
170: return 0 ;
171:
172: case WM_ENABLE:
173: WinInvalidateRect (hwnd, NULL, FALSE) ;
174: return 0 ;
175:
176: case WM_SETFOCUS:
177: pSqBtn->fHaveFocus = SHORT1FROMMP (mp2) ;
178: WinInvalidateRect (hwnd, NULL, FALSE) ;
179: return 0 ;
180:
181: case WM_CHAR:
182: if (!(CHARMSG(&msg)->fs & KC_VIRTUALKEY) ||
183: CHARMSG(&msg)->vkey != VK_SPACE ||
184: CHARMSG(&msg)->fs & KC_PREVDOWN)
185: break ;
186:
187: // Post WM_COMMAND when space bar is released
188:
189: if (!(CHARMSG(&msg)->fs & KC_KEYUP))
190: pSqBtn->fSpaceDown = TRUE ;
191: else
192: {
193: pSqBtn->fSpaceDown = FALSE ;
194: WinPostMsg (WinQueryWindow (hwnd, QW_OWNER, FALSE),
195: WM_COMMAND,
196: MPFROMSHORT (WinQueryWindowUShort (hwnd, QWS_ID)),
197: MPFROM2SHORT (CMDSRC_OTHER, FALSE)) ;
198: }
199: WinInvalidateRect (hwnd, NULL, FALSE) ;
200: return 0 ;
201:
202: case WM_PAINT:
203: hps = WinBeginPaint (hwnd, NULL, NULL) ;
204: DrawButton (hwnd, hps, pSqBtn) ;
205: WinEndPaint (hps) ;
206: return 0 ;
207:
208: case WM_DESTROY:
209: free (pSqBtn->pszText) ;
210: free (pSqBtn) ;
211: return 0 ;
212: }
213: return WinDefWindowProc (hwnd, msg, mp1, mp2) ;
214: }
215:
216: /*--------------------------------------------------------
217: Draws filled and outlined polygon (used by DrawButton)
218: --------------------------------------------------------*/
219:
220: VOID Polygon (HPS hps, LONG lPoints, POINTL aptl[], LONG lColor)
221: {
222: // Draw interior in specified color
223:
224: GpiSavePS (hps) ;
225: GpiSetColor (hps, lColor) ;
226:
227: GpiBeginArea (hps, BA_NOBOUNDARY | BA_ALTERNATE) ;
228: GpiMove (hps, aptl) ;
229: GpiPolyLine (hps, lPoints - 1, aptl + 1) ;
230: GpiEndArea (hps) ;
231:
232: GpiRestorePS (hps, -1L) ;
233:
234: // Draw boundary in default color
235:
236: GpiMove (hps, aptl + lPoints - 1) ;
237: GpiPolyLine (hps, lPoints, aptl) ;
238: }
239:
240: /*---------------------
241: Draws Square Button
242: ---------------------*/
243:
244: VOID DrawButton (HWND hwnd, HPS hps, PSQBTN pSqBtn)
245: {
246: FATTRS fat ;
247: FONTMETRICS fm ;
248: HDC hdc ;
249: LONG lColor, lHorzRes, lVertRes, cxEdge, cyEdge ;
250: POINTL aptl[10], aptlTextBox[TXTBOX_COUNT], ptlShadow, ptlText ;
251: RECTL rcl ;
252:
253: // Find 2 millimeter edge width in pixels
254:
255: hdc = GpiQueryDevice (hps) ;
256: DevQueryCaps (hdc, CAPS_HORIZONTAL_RESOLUTION, 1L, &lHorzRes) ;
257: DevQueryCaps (hdc, CAPS_VERTICAL_RESOLUTION, 1L, &lVertRes) ;
258:
259: cxEdge = lHorzRes / 500 ;
260: cyEdge = lVertRes / 500 ;
261:
262: // Set up coordinates for drawing the button
263:
264: WinQueryWindowRect (hwnd, &rcl) ;
265:
266: aptl[0].x = 0 ; aptl[0].y = 0 ;
267: aptl[1].x = cxEdge ; aptl[1].y = cyEdge ;
268: aptl[2].x = rcl.xRight - cxEdge ; aptl[2].y = cyEdge ;
269: aptl[3].x = rcl.xRight - 1 ; aptl[3].y = 0 ;
270: aptl[4].x = rcl.xRight - 1 ; aptl[4].y = rcl.yTop - 1 ;
271: aptl[5].x = rcl.xRight - cxEdge ; aptl[5].y = rcl.yTop - cyEdge ;
272: aptl[6].x = cxEdge ; aptl[6].y = rcl.yTop - cyEdge ;
273: aptl[7].x = 0 ; aptl[7].y = rcl.yTop - 1 ;
274: aptl[8].x = 0 ; aptl[8].y = 0 ;
275: aptl[9].x = cxEdge ; aptl[9].y = cyEdge ;
276:
277: // Paint edges at bottom and right side
278:
279: GpiSetColor (hps, CLR_BLACK) ;
280: lColor = (pSqBtn->fInsideRect || pSqBtn->fSpaceDown) ?
281: CLR_PALEGRAY : CLR_DARKGRAY ;
282: Polygon (hps, 4L, aptl + 0, lColor) ;
283: Polygon (hps, 4L, aptl + 2, lColor) ;
284:
285: // Paint edges at top and left side
286:
287: lColor = (pSqBtn->fInsideRect || pSqBtn->fSpaceDown) ?
288: CLR_DARKGRAY : CLR_WHITE ;
289: Polygon (hps, 4L, aptl + 4, lColor) ;
290: Polygon (hps, 4L, aptl + 6, lColor) ;
291:
292: // Paint interior area
293:
294: GpiSavePS (hps) ;
295: GpiSetColor (hps, (pSqBtn->fInsideRect || pSqBtn->fSpaceDown) ?
296: CLR_DARKGRAY : CLR_PALEGRAY) ;
297: GpiMove (hps, aptl + 1) ;
298: GpiBox (hps, DRO_FILL, aptl + 5, 0L, 0L) ;
299: GpiRestorePS (hps, -1L) ;
300: GpiBox (hps, DRO_OUTLINE, aptl + 5, 0L, 0L) ;
301:
302: // If button has focus, use italic font
303:
304: GpiQueryFontMetrics (hps, (LONG) sizeof fm, &fm) ;
305:
306: if (pSqBtn->fHaveFocus)
307: {
308: fat.usRecordLength = sizeof fat ;
309: fat.fsSelection = FATTR_SEL_ITALIC ;
310: fat.lMatch = 0 ;
311: fat.idRegistry = fm.idRegistry ;
312: fat.usCodePage = fm.usCodePage ;
313: fat.lMaxBaselineExt = fm.lMaxBaselineExt ;
314: fat.lAveCharWidth = fm.lAveCharWidth ;
315: fat.fsType = 0 ;
316: fat.fsFontUse = 0 ;
317: strcpy (fat.szFacename, fm.szFacename) ;
318:
319: GpiCreateLogFont (hps, NULL, LCID_ITALIC, &fat) ;
320: GpiSetCharSet (hps, LCID_ITALIC) ;
321: }
322: // Calculate text position
323:
324: GpiQueryTextBox (hps, (LONG) strlen (pSqBtn->pszText), pSqBtn->pszText,
325: TXTBOX_COUNT, aptlTextBox) ;
326:
327: ptlText.x = (rcl.xRight - aptlTextBox[TXTBOX_CONCAT].x) / 2 ;
328: ptlText.y = (rcl.yTop - aptlTextBox[TXTBOX_TOPLEFT].y -
329: aptlTextBox[TXTBOX_BOTTOMLEFT].y) / 2 ;
330:
331: ptlShadow.x = ptlText.x + fm.lAveCharWidth / 3 ;
332: ptlShadow.y = ptlText.y - fm.lMaxBaselineExt / 8 ;
333:
334: // Display text shadow in black, and text in white
335:
336: GpiSetColor (hps, CLR_BLACK) ;
337: GpiCharStringAt (hps, &ptlShadow, (LONG) strlen (pSqBtn->pszText),
338: pSqBtn->pszText) ;
339: GpiSetColor (hps, CLR_WHITE) ;
340: GpiCharStringAt (hps, &ptlText, (LONG) strlen (pSqBtn->pszText),
341: pSqBtn->pszText) ;
342:
343: // X out button if the window is not enabled
344:
345: if (!WinIsWindowEnabled (hwnd))
346: {
347: GpiMove (hps, aptl + 1) ;
348: GpiLine (hps, aptl + 5) ;
349: GpiMove (hps, aptl + 2) ;
350: GpiLine (hps, aptl + 6) ;
351: }
352: // Clean up
353:
354: if (pSqBtn->fHaveFocus)
355: {
356: GpiSetCharSet (hps, LCID_DEFAULT) ;
357: GpiDeleteSetId (hps, LCID_ITALIC) ;
358: }
359: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.