Annotation of OpenXM_contrib/gnuplot/win/wgraph.c, Revision 1.1.1.1
1.1 maekawa 1: #ifndef lint
2: static char *RCSid = "$Id: wgraph.c,v 1.14 1998/03/22 23:32:00 drd Exp $";
3: #endif
4:
5: /* GNUPLOT - win/wgraph.c */
6: /*[
7: * Copyright 1992, 1993, 1998 Maurice Castro, Russell Lang
8: *
9: * Permission to use, copy, and distribute this software and its
10: * documentation for any purpose with or without fee is hereby granted,
11: * provided that the above copyright notice appear in all copies and
12: * that both that copyright notice and this permission notice appear
13: * in supporting documentation.
14: *
15: * Permission to modify the software is granted, but not the right to
16: * distribute the complete modified source code. Modifications are to
17: * be distributed as patches to the released version. Permission to
18: * distribute binaries produced by compiling modified sources is granted,
19: * provided you
20: * 1. distribute the corresponding source modifications from the
21: * released version in the form of a patch file along with the binaries,
22: * 2. add special version identification to distinguish your version
23: * in addition to the base release version number,
24: * 3. provide your name and address as the primary contact for the
25: * support of your modified version, and
26: * 4. retain our contact information in regard to use of the base
27: * software.
28: * Permission to distribute the released version of the source code along
29: * with corresponding source modifications in the form of a patch file is
30: * granted with same provisions 2 through 4 for binary distributions.
31: *
32: * This software is provided "as is" without express or implied warranty
33: * to the extent permitted by applicable law.
34: ]*/
35:
36: /*
37: * AUTHORS
38: *
39: * Maurice Castro
40: * Russell Lang
41: *
42: * Send your comments or suggestions to
43: * info-gnuplot@dartmouth.edu.
44: * This is a mailing list; to join it send a note to
45: * majordomo@dartmouth.edu.
46: * Send bug reports to
47: * bug-gnuplot@dartmouth.edu.
48: */
49:
50: #define STRICT
51: #include <windows.h>
52: #include <windowsx.h>
53: #if WINVER >= 0x030a
54: #include <commdlg.h>
55: #endif
56: #ifndef __MSC__
57: #include <mem.h>
58: #endif
59: #include <stdio.h>
60: #include <string.h>
61: #include "wgnuplib.h"
62: #include "wresourc.h"
63: #include "wcommon.h"
64:
65: LRESULT CALLBACK WINEXPORT WndGraphProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);
66:
67: void ReadGraphIni(LPGW lpgw);
68:
69: /* ================================== */
70:
71: #define MAXSTR 255
72:
73: #define WGDEFCOLOR 15
74: COLORREF wginitcolor[WGDEFCOLOR] = {
75: RGB(255,0,0), /* red */
76: RGB(0,255,0), /* green */
77: RGB(0,0,255), /* blue */
78: RGB(255,0,255), /* magenta */
79: RGB(0,0,128), /* dark blue */
80: RGB(128,0,0), /* dark red */
81: RGB(0,128,128), /* dark cyan */
82: RGB(0,0,0), /* black */
83: RGB(128,128,128), /* grey */
84: RGB(0,128,64), /* very dark cyan */
85: RGB(128,128,0), /* dark yellow */
86: RGB(128,0,128), /* dark magenta */
87: RGB(192,192,192), /* light grey */
88: RGB(0,255,255), /* cyan */
89: RGB(255,255,0), /* yellow */
90: };
91: #define WGDEFSTYLE 5
92: int wginitstyle[WGDEFSTYLE] = {PS_SOLID, PS_DASH, PS_DOT, PS_DASHDOT, PS_DASHDOTDOT};
93:
94: /* ================================== */
95:
96: /* destroy memory blocks holding graph operations */
97: void
98: DestroyBlocks(LPGW lpgw)
99: {
100: struct GWOPBLK *this, *next;
101: struct GWOP FAR *gwop;
102: unsigned int i;
103:
104: this = lpgw->gwopblk_head;
105: while (this != NULL) {
106: next = this->next;
107: if (!this->gwop) {
108: this->gwop = (struct GWOP FAR *)GlobalLock(this->hblk);
109: }
110: if (this->gwop) {
111: /* free all text strings within this block */
112: gwop = this->gwop;
113: for (i=0; i<GWOPMAX; i++) {
114: if (gwop->htext)
115: LocalFree(gwop->htext);
116: gwop++;
117: }
118: }
119: GlobalUnlock(this->hblk);
120: GlobalFree(this->hblk);
121: LocalFreePtr(this);
122: this = next;
123: }
124: lpgw->gwopblk_head = NULL;
125: lpgw->gwopblk_tail = NULL;
126: lpgw->nGWOP = 0;
127: }
128:
129:
130: /* add a new memory block for graph operations */
131: /* returns TRUE if block allocated */
132: BOOL
133: AddBlock(LPGW lpgw)
134: {
135: HGLOBAL hblk;
136: struct GWOPBLK *next, *this;
137:
138: /* create new block */
139: next = (struct GWOPBLK *)LocalAllocPtr(LHND, sizeof(struct GWOPBLK) );
140: if (next == NULL)
141: return FALSE;
142: hblk = GlobalAlloc(GHND, GWOPMAX*sizeof(struct GWOP));
143: if (hblk == NULL)
144: return FALSE;
145: next->hblk = hblk;
146: next->gwop = (struct GWOP FAR *)NULL;
147: next->next = (struct GWOPBLK *)NULL;
148: next->used = 0;
149:
150: /* attach it to list */
151: this = lpgw->gwopblk_tail;
152: if (this == NULL) {
153: lpgw->gwopblk_head = next;
154: }
155: else {
156: this->next = next;
157: this->gwop = (struct GWOP FAR *)NULL;
158: GlobalUnlock(this->hblk);
159: }
160: lpgw->gwopblk_tail = next;
161: next->gwop = (struct GWOP FAR *)GlobalLock(next->hblk);
162: if (next->gwop == (struct GWOP FAR *)NULL)
163: return FALSE;
164:
165: return TRUE;
166: }
167:
168:
169: void WDPROC
170: GraphOp(LPGW lpgw, WORD op, WORD x, WORD y, LPSTR str)
171: {
172: struct GWOPBLK *this;
173: struct GWOP FAR *gwop;
174: char *npstr;
175:
176: this = lpgw->gwopblk_tail;
177: if ( (this==NULL) || (this->used >= GWOPMAX) ) {
178: /* not enough space so get new block */
179: if (!AddBlock(lpgw))
180: return;
181: this = lpgw->gwopblk_tail;
182: }
183: gwop = &this->gwop[this->used];
184: gwop->op = op;
185: gwop->x = x;
186: gwop->y = y;
187: gwop->htext = 0;
188: if (str) {
189: gwop->htext = LocalAlloc(LHND, _fstrlen(str)+1);
190: npstr = LocalLock(gwop->htext);
191: if (gwop->htext && (npstr != (char *)NULL))
192: lstrcpy(npstr, str);
193: LocalUnlock(gwop->htext);
194: }
195: this->used++;
196: lpgw->nGWOP++;
197: return;
198: }
199:
200: /* ================================== */
201:
202: void WDPROC
203: GraphInit(LPGW lpgw)
204: {
205: HMENU sysmenu;
206: WNDCLASS wndclass;
207: char buf[80];
208:
209: if (!lpgw->hPrevInstance) {
210: wndclass.style = CS_HREDRAW | CS_VREDRAW;
211: wndclass.lpfnWndProc = WndGraphProc;
212: wndclass.cbClsExtra = 0;
213: wndclass.cbWndExtra = 2 * sizeof(void FAR *);
214: wndclass.hInstance = lpgw->hInstance;
215: wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
216: wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
217: wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
218: wndclass.lpszMenuName = NULL;
219: wndclass.lpszClassName = szGraphClass;
220: RegisterClass(&wndclass);
221: }
222:
223: ReadGraphIni(lpgw);
224:
225: lpgw->hWndGraph = CreateWindow(szGraphClass, lpgw->Title,
226: WS_OVERLAPPEDWINDOW,
227: lpgw->Origin.x, lpgw->Origin.y,
228: lpgw->Size.x, lpgw->Size.y,
229: NULL, NULL, lpgw->hInstance, lpgw);
230:
231: lpgw->hPopMenu = CreatePopupMenu();
232: AppendMenu(lpgw->hPopMenu, MF_STRING | (lpgw->graphtotop ? MF_CHECKED : MF_UNCHECKED),
233: M_GRAPH_TO_TOP, "Bring to &Top");
234: AppendMenu(lpgw->hPopMenu, MF_STRING | (lpgw->color ? MF_CHECKED : MF_UNCHECKED),
235: M_COLOR, "C&olor");
236: AppendMenu(lpgw->hPopMenu, MF_STRING, M_COPY_CLIP, "&Copy to Clipboard");
237: #if WINVER >= 0x030a
238: AppendMenu(lpgw->hPopMenu, MF_STRING, M_BACKGROUND, "&Background...");
239: AppendMenu(lpgw->hPopMenu, MF_STRING, M_CHOOSE_FONT, "Choose &Font...");
240: AppendMenu(lpgw->hPopMenu, MF_STRING, M_LINESTYLE, "&Line Styles...");
241: #endif
242: AppendMenu(lpgw->hPopMenu, MF_STRING, M_PRINT, "&Print...");
243: if (lpgw->IniFile != (LPSTR)NULL) {
244: wsprintf(buf,"&Update %s",lpgw->IniFile);
245: AppendMenu(lpgw->hPopMenu, MF_STRING, M_WRITEINI, (LPSTR)buf);
246: }
247:
248: /* modify the system menu to have the new items we want */
249: sysmenu = GetSystemMenu(lpgw->hWndGraph,0);
250: AppendMenu(sysmenu, MF_SEPARATOR, 0, NULL);
251: AppendMenu(sysmenu, MF_POPUP, (UINT)lpgw->hPopMenu, "&Options");
252: AppendMenu(sysmenu, MF_STRING, M_ABOUT, "&About");
253:
254: if (!IsWindowVisible(lpgw->lptw->hWndParent)) {
255: AppendMenu(sysmenu, MF_SEPARATOR, 0, NULL);
256: AppendMenu(sysmenu, MF_STRING, M_COMMANDLINE, "C&ommand Line");
257: }
258:
259: ShowWindow(lpgw->hWndGraph, SW_SHOWNORMAL);
260: }
261:
262: /* close a graph window */
263: void WDPROC
264: GraphClose(LPGW lpgw)
265: {
266: /* close window */
267: if (lpgw->hWndGraph)
268: DestroyWindow(lpgw->hWndGraph);
269: TextMessage();
270: lpgw->hWndGraph = NULL;
271:
272: lpgw->locked = TRUE;
273: DestroyBlocks(lpgw);
274: lpgw->locked = FALSE;
275:
276: }
277:
278:
279: void WDPROC
280: GraphStart(LPGW lpgw, double pointsize)
281: {
282: lpgw->locked = TRUE;
283: DestroyBlocks(lpgw);
284: lpgw->org_pointsize = pointsize;
285: if ( !lpgw->hWndGraph || !IsWindow(lpgw->hWndGraph) )
286: GraphInit(lpgw);
287: if (IsIconic(lpgw->hWndGraph))
288: ShowWindow(lpgw->hWndGraph, SW_SHOWNORMAL);
289: if (lpgw->graphtotop)
290: BringWindowToTop(lpgw->hWndGraph);
291:
292: }
293:
294: void WDPROC
295: GraphEnd(LPGW lpgw)
296: {
297: RECT rect;
298: GetClientRect(lpgw->hWndGraph, &rect);
299: InvalidateRect(lpgw->hWndGraph, (LPRECT) &rect, 1);
300: lpgw->locked = FALSE;
301: UpdateWindow(lpgw->hWndGraph);
302: }
303:
304: void WDPROC
305: GraphResume(LPGW lpgw)
306: {
307: lpgw->locked = TRUE;
308: }
309:
310: void WDPROC
311: GraphPrint(LPGW lpgw)
312: {
313: if (lpgw->hWndGraph && IsWindow(lpgw->hWndGraph))
314: SendMessage(lpgw->hWndGraph,WM_COMMAND,M_PRINT,0L);
315: }
316:
317: void WDPROC
318: GraphRedraw(LPGW lpgw)
319: {
320: if (lpgw->hWndGraph && IsWindow(lpgw->hWndGraph))
321: SendMessage(lpgw->hWndGraph,WM_COMMAND,M_REBUILDTOOLS,0L);
322: }
323: /* ================================== */
324:
325: void
326: StorePen(LPGW lpgw, int i, COLORREF ref, int colorstyle, int monostyle)
327: {
328: LOGPEN FAR *plp;
329:
330: plp = &lpgw->colorpen[i];
331: plp->lopnColor = ref;
332: if (colorstyle < 0) {
333: plp->lopnWidth.x = -colorstyle;
334: plp->lopnStyle = 0;
335: }
336: else {
337: plp->lopnWidth.x = 1;
338: plp->lopnStyle = colorstyle % 5;
339: }
340: plp->lopnWidth.y = 0;
341:
342: plp = &lpgw->monopen[i];
343: plp->lopnColor = RGB(0,0,0);
344: if (monostyle < 0) {
345: plp->lopnWidth.x = -monostyle;
346: plp->lopnStyle = 0;
347: }
348: else {
349: plp->lopnWidth.x = 1;
350: plp->lopnStyle = monostyle % 5;
351: }
352: plp->lopnWidth.y = 0;
353: }
354:
355: void
356: MakePens(LPGW lpgw, HDC hdc)
357: {
358: int i;
359:
360: if ((GetDeviceCaps(hdc,NUMCOLORS) == 2) || !lpgw->color) {
361: /* Monochrome Device */
362: /* create border pens */
363: lpgw->hbpen = CreatePenIndirect((LOGPEN FAR *)&lpgw->monopen[0]); /* border */
364: lpgw->hapen = CreatePenIndirect((LOGPEN FAR *)&lpgw->monopen[1]); /* axis */
365: /* create drawing pens */
366: for (i=0; i<WGNUMPENS; i++)
367: {
368: lpgw->hpen[i] = CreatePenIndirect((LOGPEN FAR *)&lpgw->monopen[i+2]);
369: }
370: /* find number of solid, unit width line styles */
371: for (i=0; i<WGNUMPENS && lpgw->monopen[i+2].lopnStyle==PS_SOLID
372: && lpgw->monopen[i+2].lopnWidth.x==1; i++) ;
373: lpgw->numsolid = i ? i : 1; /* must be at least 1 */
374: lpgw->hbrush = CreateSolidBrush(RGB(255,255,255));
375: for (i=0; i<WGNUMPENS+2; i++)
376: lpgw->colorbrush[i] = CreateSolidBrush(RGB(0,0,0));
377: }
378: else {
379: /* Color Device */
380: /* create border pens */
381: lpgw->hbpen = CreatePenIndirect((LOGPEN FAR *)&lpgw->colorpen[0]); /* border */
382: lpgw->hapen = CreatePenIndirect((LOGPEN FAR *)&lpgw->colorpen[1]); /* axis */
383: /* create drawing pens */
384: for (i=0; i<WGNUMPENS; i++)
385: {
386: lpgw->hpen[i] = CreatePenIndirect((LOGPEN FAR *)&lpgw->colorpen[i+2]);
387: }
388: /* find number of solid, unit width line styles */
389: for (i=0; i<WGNUMPENS && lpgw->colorpen[i+2].lopnStyle==PS_SOLID
390: && lpgw->colorpen[i+2].lopnWidth.x==1; i++) ;
391: lpgw->numsolid = i ? i : 1; /* must be at least 1 */
392: lpgw->hbrush = CreateSolidBrush(lpgw->background);
393: for (i=0; i<WGNUMPENS+2; i++)
394: lpgw->colorbrush[i] = CreateSolidBrush(lpgw->colorpen[i].lopnColor);
395: }
396: }
397:
398: void
399: DestroyPens(LPGW lpgw)
400: {
401: int i;
402:
403: DeleteObject(lpgw->hbrush);
404: DeleteObject(lpgw->hbpen);
405: DeleteObject(lpgw->hapen);
406: for (i=0; i<WGNUMPENS; i++)
407: DeleteObject(lpgw->hpen[i]);
408: for (i=0; i<WGNUMPENS+2; i++)
409: DeleteObject(lpgw->colorbrush[i]);
410: }
411:
412: /* ================================== */
413:
414: void
415: MakeFonts(LPGW lpgw, LPRECT lprect, HDC hdc)
416: {
417: LOGFONT lf;
418: HFONT hfontold;
419: TEXTMETRIC tm;
420: int result;
421: char FAR *p;
422: int cx, cy;
423:
424: lpgw->rotate = FALSE;
425: _fmemset(&lf, 0, sizeof(LOGFONT));
426: _fstrncpy(lf.lfFaceName,lpgw->fontname,LF_FACESIZE);
427: lf.lfHeight = -MulDiv(lpgw->fontsize, GetDeviceCaps(hdc, LOGPIXELSY), 72);
428: lf.lfCharSet = DEFAULT_CHARSET;
429: if ( (p = _fstrstr(lpgw->fontname," Italic")) != (LPSTR)NULL ) {
430: lf.lfFaceName[ (unsigned int)(p-lpgw->fontname) ] = '\0';
431: lf.lfItalic = TRUE;
432: }
433: if ( (p = _fstrstr(lpgw->fontname," Bold")) != (LPSTR)NULL ) {
434: lf.lfFaceName[ (unsigned int)(p-lpgw->fontname) ] = '\0';
435: lf.lfWeight = FW_BOLD;
436: }
437:
438: if (lpgw->hfonth == 0) {
439: lpgw->hfonth = CreateFontIndirect((LOGFONT FAR *)&lf);
440: }
441:
442: if (lpgw->hfontv == 0) {
443: lf.lfEscapement = 900;
444: lf.lfOrientation = 900;
445: lpgw->hfontv = CreateFontIndirect((LOGFONT FAR *)&lf);
446: }
447:
448: /* save text size */
449: hfontold = SelectObject(hdc, lpgw->hfonth);
450: #ifdef WIN32
451: {
452: SIZE size;
453: GetTextExtentPoint(hdc,"0123456789",10, (LPSIZE)&size);
454: cx = size.cx;
455: cy = size.cy;
456: }
457: #else
458: {
459: DWORD extent;
460: extent = GetTextExtent(hdc,"0123456789",10);
461: cx = LOWORD(extent);
462: cy = HIWORD(extent);
463: }
464: #endif
465: lpgw->vchar = MulDiv(cy,lpgw->ymax,lprect->bottom - lprect->top);
466: lpgw->hchar = MulDiv(cx/10,lpgw->xmax,lprect->right - lprect->left);
467: /* CMW: Base tick size on character size */
468: lpgw->htic = lpgw->hchar/2;
469: cy = MulDiv(cx/20, GetDeviceCaps(hdc,LOGPIXELSY), GetDeviceCaps(hdc,LOGPIXELSX));
470: lpgw->vtic = MulDiv(cy,lpgw->ymax,lprect->bottom - lprect->top);
471: /* find out if we can rotate text 90deg */
472: SelectObject(hdc, lpgw->hfontv);
473: result = GetDeviceCaps(hdc, TEXTCAPS);
474: if ((result & TC_CR_90) || (result & TC_CR_ANY))
475: lpgw->rotate = 1;
476: GetTextMetrics(hdc,(TEXTMETRIC FAR *)&tm);
477: if (tm.tmPitchAndFamily & TMPF_VECTOR)
478: lpgw->rotate = 1; /* vector fonts can all be rotated */
479: #if WINVER >=0x030a
480: if (tm.tmPitchAndFamily & TMPF_TRUETYPE)
481: lpgw->rotate = 1; /* truetype fonts can all be rotated */
482: #endif
483: SelectObject(hdc, hfontold);
484: return;
485: }
486:
487: void
488: DestroyFonts(LPGW lpgw)
489: {
490: if (lpgw->hfonth) {
491: DeleteObject(lpgw->hfonth);
492: lpgw->hfonth = 0;
493: }
494: if (lpgw->hfontv) {
495: DeleteObject(lpgw->hfontv);
496: lpgw->hfontv = 0;
497: }
498: return;
499: }
500:
501: void
502: SetFont(LPGW lpgw, HDC hdc)
503: {
504: if (lpgw->rotate && lpgw->angle) {
505: if (lpgw->hfontv)
506: SelectObject(hdc, lpgw->hfontv);
507: }
508: else {
509: if (lpgw->hfonth)
510: SelectObject(hdc, lpgw->hfonth);
511: }
512: return;
513: }
514:
515: void
516: SelFont(LPGW lpgw) {
517: #if WINVER >= 0x030a
518: LOGFONT lf;
519: CHOOSEFONT cf;
520: HDC hdc;
521: char lpszStyle[LF_FACESIZE];
522: char FAR *p;
523:
524: /* Set all structure fields to zero. */
525: _fmemset(&cf, 0, sizeof(CHOOSEFONT));
526: _fmemset(&lf, 0, sizeof(LOGFONT));
527: cf.lStructSize = sizeof(CHOOSEFONT);
528: cf.hwndOwner = lpgw->hWndGraph;
529: _fstrncpy(lf.lfFaceName,lpgw->fontname,LF_FACESIZE);
530: if ( (p = _fstrstr(lpgw->fontname," Bold")) != (LPSTR)NULL ) {
531: _fstrncpy(lpszStyle,p+1,LF_FACESIZE);
532: lf.lfFaceName[ (unsigned int)(p-lpgw->fontname) ] = '\0';
533: }
534: else if ( (p = _fstrstr(lpgw->fontname," Italic")) != (LPSTR)NULL ) {
535: _fstrncpy(lpszStyle,p+1,LF_FACESIZE);
536: lf.lfFaceName[ (unsigned int)(p-lpgw->fontname) ] = '\0';
537: }
538: else
539: _fstrcpy(lpszStyle,"Regular");
540: cf.lpszStyle = lpszStyle;
541: hdc = GetDC(lpgw->hWndGraph);
542: lf.lfHeight = -MulDiv(lpgw->fontsize, GetDeviceCaps(hdc, LOGPIXELSY), 72);
543: ReleaseDC(lpgw->hWndGraph, hdc);
544: cf.lpLogFont = &lf;
545: cf.nFontType = SCREEN_FONTTYPE;
546: cf.Flags = CF_SCREENFONTS | CF_INITTOLOGFONTSTRUCT | CF_USESTYLE;
547: if (ChooseFont(&cf)) {
548: _fstrcpy(lpgw->fontname,lf.lfFaceName);
549: lpgw->fontsize = cf.iPointSize / 10;
550: if (cf.nFontType & BOLD_FONTTYPE)
551: lstrcat(lpgw->fontname," Bold");
552: if (cf.nFontType & ITALIC_FONTTYPE)
553: lstrcat(lpgw->fontname," Italic");
554: SendMessage(lpgw->hWndGraph,WM_COMMAND,M_REBUILDTOOLS,0L);
555: }
556: #endif
557: }
558:
559: /* ================================== */
560:
561: static void dot(HDC hdc, int xdash, int ydash)
562: {
563: MoveTo(hdc, xdash, ydash);
564: LineTo(hdc, xdash, ydash+1);
565: }
566:
567:
568: void
569: drawgraph(LPGW lpgw, HDC hdc, LPRECT rect)
570: {
571: int xdash, ydash; /* the transformed coordinates */
572: int rr, rl, rt, rb;
573: struct GWOP FAR *curptr;
574: struct GWOPBLK *blkptr;
575: int htic, vtic;
576: int hshift, vshift;
577: unsigned int lastop=-1; /* used for plotting last point on a line */
578: int pen, numsolid;
579: int polymax = 200;
580: int polyi = 0;
581: POINT *ppt;
582: unsigned int ngwop=0;
583: BOOL isColor;
584:
585: if (lpgw->locked)
586: return;
587:
588: isColor= (GetDeviceCaps(hdc, PLANES)*GetDeviceCaps(hdc,BITSPIXEL)) > 2;
589: if (lpgw->background != RGB(255,255,255) && lpgw->color && isColor) {
590: SetBkColor(hdc,lpgw->background);
591: FillRect(hdc, rect, lpgw->hbrush);
592: }
593:
594: ppt = (POINT *)LocalAllocPtr(LHND, (polymax+1) * sizeof(POINT));
595:
596: rr = rect->right;
597: rl = rect->left;
598: rt = rect->top;
599: rb = rect->bottom;
600:
601: htic = lpgw->org_pointsize*MulDiv(lpgw->htic, rr-rl, lpgw->xmax) + 1;
602: vtic = lpgw->org_pointsize*MulDiv(lpgw->vtic, rb-rt, lpgw->ymax) + 1;
603:
604: lpgw->angle = 0;
605: SetFont(lpgw, hdc);
606: SetTextAlign(hdc, TA_LEFT|TA_BOTTOM);
607: vshift = MulDiv(lpgw->vchar, rb-rt, lpgw->ymax)/2;
608: /* HBB 980630: new variable for moving rotated text to the correct
609: * position: */
610: hshift = MulDiv(lpgw->vchar, rr-rl, lpgw->xmax)/2;
611:
612: pen = 0;
613: SelectObject(hdc, lpgw->hpen[pen]);
614: SelectObject(hdc, lpgw->colorbrush[pen+2]);
615: numsolid = lpgw->numsolid;
616:
617: /* do the drawing */
618: blkptr = lpgw->gwopblk_head;
619: curptr = NULL;
620: if (blkptr) {
621: if (!blkptr->gwop)
622: blkptr->gwop = (struct GWOP FAR *)GlobalLock(blkptr->hblk);
623: if (!blkptr->gwop)
624: return;
625: curptr = (struct GWOP FAR *)blkptr->gwop;
626: }
627: while(ngwop < lpgw->nGWOP)
628: {
629: /* transform the coordinates */
630: xdash = MulDiv(curptr->x, rr-rl-1, lpgw->xmax) + rl;
631: ydash = MulDiv(curptr->y, rt-rb+1, lpgw->ymax) + rb - 1;
632: if ((lastop==W_vect) && (curptr->op!=W_vect)) {
633: if (polyi >= 2)
634: Polyline(hdc, ppt, polyi);
635: polyi = 0;
636: }
637: switch (curptr->op) {
638: case 0: /* have run past last in this block */
639: break;
640: case W_move:
641: ppt[0].x = xdash;
642: ppt[0].y = ydash;
643: polyi = 1;
644: break;
645: case W_vect:
646: ppt[polyi].x = xdash;
647: ppt[polyi].y = ydash;
648: polyi++;
649: if (polyi >= polymax) {
650: Polyline(hdc, ppt, polyi);
651: ppt[0].x = xdash;
652: ppt[0].y = ydash;
653: polyi = 1;;
654: }
655: break;
656: case W_line_type:
657: switch (curptr->x)
658: {
659: case (WORD) -2: /* black 2 pixel wide */
660: SelectObject(hdc, lpgw->hbpen);
661: if (lpgw->color && isColor)
662: SetTextColor(hdc, lpgw->colorpen[0].lopnColor);
663: break;
664: case (WORD) -1: /* black 1 pixel wide doted */
665: SelectObject(hdc, lpgw->hapen);
666: if (lpgw->color && isColor)
667: SetTextColor(hdc, lpgw->colorpen[1].lopnColor);
668: break;
669: default:
670: SelectObject(hdc, lpgw->hpen[(curptr->x)%WGNUMPENS]);
671: if (lpgw->color && isColor)
672: SetTextColor(hdc, lpgw->colorpen[(curptr->x)%WGNUMPENS + 2].lopnColor);
673: }
674: pen = curptr->x;
675: SelectObject(hdc, lpgw->colorbrush[pen%WGNUMPENS + 2]);
676: break;
677: case W_put_text:
678: {char *str;
679: str = LocalLock(curptr->htext);
680: if (str) {
681: /* HBB 980630: shift differently for rotated text: */
682: if (lpgw->angle)
683: xdash += hshift;
684: else
685: ydash += vshift;
686: SetBkMode(hdc,TRANSPARENT);
687: TextOut(hdc,xdash,ydash,str,lstrlen(str));
688: SetBkMode(hdc,OPAQUE);
689: }
690: LocalUnlock(curptr->htext);
691: }
692: break;
693: case W_text_angle:
694: lpgw->angle = curptr->x;
695: SetFont(lpgw,hdc);
696: break;
697: case W_justify:
698: switch (curptr->x)
699: {
700: case LEFT:
701: SetTextAlign(hdc, TA_LEFT|TA_BOTTOM);
702: break;
703: case RIGHT:
704: SetTextAlign(hdc, TA_RIGHT|TA_BOTTOM);
705: break;
706: case CENTRE:
707: SetTextAlign(hdc, TA_CENTER|TA_BOTTOM);
708: break;
709: }
710: break;
711: case W_pointsize:
712: /* HBB 980309: term->pointsize() passes the number as a scaled-up
713: * integer now, so we can avoid calling sscanf() here (in a Win16
714: * DLL sharing stack with the stack-starved wgnuplot.exe !).
715: */
716: if (curptr->x != 0) {
717: double pointsize = curptr->x / 100.0;
718: /* HBB 980309: the older code didn't make *any* use of the
719: * pointsize at all! That obviously can't be correct. So use it! */
720: htic = pointsize*MulDiv(lpgw->htic, rr-rl, lpgw->xmax) + 1;
721: vtic = pointsize*MulDiv(lpgw->vtic, rb-rt, lpgw->ymax) + 1;
722: } else {
723: char *str;
724: str = LocalLock(curptr->htext);
725: if (str) {
726: double pointsize;
727: sscanf(str, "%lg", &pointsize);
728: htic = lpgw->org_pointsize*MulDiv(lpgw->htic, rr-rl, lpgw->xmax) + 1;
729: vtic = lpgw->org_pointsize*MulDiv(lpgw->vtic, rb-rt, lpgw->ymax) + 1;
730: }
731: LocalUnlock(curptr->htext);
732: }
733: break;
734: default: /* A plot mark */
735: if (pen >= numsolid) {
736: pen %= numsolid; /* select solid pen */
737: SelectObject(hdc, lpgw->hpen[pen]);
738: SelectObject(hdc, lpgw->colorbrush[pen+2]);
739: }
740: switch (curptr->op) {
741: case W_dot:
742: dot(hdc, xdash, ydash);
743: break;
744: case W_plus: /* do plus */
745: MoveTo(hdc,xdash-htic,ydash);
746: LineTo(hdc,xdash+htic+1,ydash);
747: MoveTo(hdc,xdash,ydash-vtic);
748: LineTo(hdc,xdash,ydash+vtic+1);
749: break;
750: case W_cross: /* do X */
751: MoveTo(hdc,xdash-htic,ydash-vtic);
752: LineTo(hdc,xdash+htic+1,ydash+vtic+1);
753: MoveTo(hdc,xdash-htic,ydash+vtic);
754: LineTo(hdc,xdash+htic+1,ydash-vtic-1);
755: break;
756: case W_star: /* do star */
757: MoveTo(hdc,xdash-htic,ydash);
758: LineTo(hdc,xdash+htic+1,ydash);
759: MoveTo(hdc,xdash,ydash-vtic);
760: LineTo(hdc,xdash,ydash+vtic+1);
761: MoveTo(hdc,xdash-htic,ydash-vtic);
762: LineTo(hdc,xdash+htic+1,ydash+vtic+1);
763: MoveTo(hdc,xdash-htic,ydash+vtic);
764: LineTo(hdc,xdash+htic+1,ydash-vtic-1);
765: break;
766: case W_circle: /* do open circle */
767: Arc(hdc, xdash-htic, ydash-vtic, xdash+htic+1, ydash+vtic+1, xdash, ydash+vtic+1, xdash, ydash+vtic+1);
768: dot(hdc, xdash, ydash);
769: break;
770: case W_fcircle: /* do filled circle */
771: Ellipse(hdc, xdash-htic, ydash-vtic, xdash+htic+1, ydash+vtic+1);
772: break;
773: default: /* Closed figure */
774: { POINT p[6];
775: int i;
776: int shape;
777: int filled = 0;
778: static float pointshapes[5][10] = {
779: {-1, -1, +1, -1, +1, +1, -1, +1, 0, 0}, /* box */
780: { 0, +1, -1, 0, 0, -1, +1, 0, 0, 0}, /* diamond */
781: { 0, -4./3, -4./3, 2./3, 4./3, 2./3, 0, 0}, /* triangle */
782: { 0, 4./3, -4./3, -2./3, 4./3, -2./3, 0, 0}, /* inverted triangle */
783: { 0, 1, 0.95106, 0.30902, 0.58779, -0.80902, -0.58779, -0.80902, -0.95106, 0.30902} /* pentagon (not used) */
784: };
785: switch (curptr->op) {
786: case W_box: shape = 0; break;
787: case W_diamond: shape = 1; break;
788: case W_itriangle: shape = 2; break;
789: case W_triangle: shape = 3; break;
790: default: shape = curptr->op-W_fbox;
791: filled = 1;
792: break;
793: }
794:
795: for ( i = 0; i<5; ++i )
796: if ( pointshapes[shape][i*2+1] == 0 && pointshapes[shape][i*2] == 0 )
797: break;
798: else {
799: p[i].x = xdash + htic*pointshapes[shape][i*2] + 0.5;
800: p[i].y = ydash + vtic*pointshapes[shape][i*2+1] + 0.5;
801: }
802: if ( filled )
803: /* Filled polygon */
804: Polygon(hdc, p, i);
805: else {
806: /* Outline polygon */
807: p[i].x = p[0].x;
808: p[i].y = p[0].y;
809: Polyline(hdc, p, i+1);
810: dot(hdc, xdash, ydash);
811: }
812: }
813: }
814: }
815: lastop = curptr->op;
816: ngwop++;
817: curptr++;
818: if ((unsigned)(curptr - blkptr->gwop) >= GWOPMAX) {
819: GlobalUnlock(blkptr->hblk);
820: blkptr->gwop = (struct GWOP FAR *)NULL;
821: blkptr = blkptr->next;
822: if (!blkptr->gwop)
823: blkptr->gwop = (struct GWOP FAR *)GlobalLock(blkptr->hblk);
824: if (!blkptr->gwop)
825: return;
826: curptr = (struct GWOP FAR *)blkptr->gwop;
827: }
828: }
829: if (polyi >= 2)
830: Polyline(hdc, ppt, polyi);
831: LocalFreePtr(ppt);
832: }
833:
834: /* ================================== */
835:
836: /* copy graph window to clipboard */
837: void
838: CopyClip(LPGW lpgw)
839: {
840: RECT rect;
841: HDC mem;
842: HBITMAP bitmap;
843: HANDLE hmf;
844: GLOBALHANDLE hGMem;
845: LPMETAFILEPICT lpMFP;
846: HWND hwnd;
847: HDC hdc;
848:
849: hwnd = lpgw->hWndGraph;
850:
851: /* view the window */
852: if (IsIconic(hwnd))
853: ShowWindow(hwnd, SW_SHOWNORMAL);
854: BringWindowToTop(hwnd);
855: UpdateWindow(hwnd);
856:
857: /* get the context */
858: hdc = GetDC(hwnd);
859: GetClientRect(hwnd, &rect);
860: /* make a bitmap and copy it there */
861: mem = CreateCompatibleDC(hdc);
862: bitmap = CreateCompatibleBitmap(hdc, rect.right - rect.left,
863: rect.bottom - rect.top);
864: if (bitmap) {
865: /* there is enough memory and the bitmaps OK */
866: SelectObject(mem, bitmap);
867: BitBlt(mem,0,0,rect.right - rect.left,
868: rect.bottom - rect.top, hdc, rect.left,
869: rect.top, SRCCOPY);
870: }
871: else {
872: MessageBeep(MB_ICONHAND);
873: MessageBox(hwnd, "Insufficient Memory to Copy Clipboard",
874: lpgw->Title, MB_ICONHAND | MB_OK);
875: }
876: DeleteDC(mem);
877: {
878: GW gwclip = *lpgw;
879: int windowfontsize = MulDiv(lpgw->fontsize, GetDeviceCaps(hdc, LOGPIXELSY), 72);
880: int i;
881: gwclip.fontsize = MulDiv(windowfontsize, lpgw->ymax, rect.bottom);
882: gwclip.hfonth = gwclip.hfontv = 0;
883:
884: /* HBB 981203: scale up pens as well... */
885: for (i=0; i<WGNUMPENS+2; i++) {
886: if(gwclip.monopen[i].lopnWidth.x > 1)
887: gwclip.monopen[i].lopnWidth.x =
888: MulDiv(gwclip.monopen[i].lopnWidth.x,
889: gwclip.xmax, rect.right-rect.left);
890: if(gwclip.colorpen[i].lopnWidth.x > 1)
891: gwclip.colorpen[i].lopnWidth.x =
892: MulDiv(gwclip.colorpen[i].lopnWidth.x,
893: gwclip.xmax, rect.right-rect.left);
894: }
895:
896: rect.right = lpgw->xmax;
897: rect.bottom = lpgw->ymax;
898:
899: MakePens(&gwclip, hdc);
900: MakeFonts(&gwclip, &rect, hdc);
901:
902: ReleaseDC(hwnd, hdc);
903:
904: hdc = CreateMetaFile((LPSTR)NULL);
905:
906: /* HBB 981203: According to Petzold, Metafiles shouldn't contain SetMapMode() calls: */
907: /*SetMapMode(hdc, MM_ANISOTROPIC);*/
908: #ifdef WIN32
909: SetWindowExtEx(hdc, rect.right, rect.bottom, (LPSIZE)NULL);
910: #else
911: SetWindowExt(hdc, rect.right, rect.bottom);
912: #endif
913: drawgraph(&gwclip, hdc, (void *) &rect);
914: hmf = CloseMetaFile(hdc);
915: DestroyFonts(&gwclip);
916: DestroyPens(&gwclip);
917: }
918:
919: hGMem = GlobalAlloc(GMEM_MOVEABLE, (DWORD)sizeof(METAFILEPICT));
920: lpMFP = (LPMETAFILEPICT) GlobalLock(hGMem);
921: hdc = GetDC(hwnd); /* get window size */
922: GetClientRect(hwnd, &rect);
923: /* in MM_ANISOTROPIC, xExt & yExt give suggested size in 0.01mm units */
924: lpMFP->mm = MM_ANISOTROPIC;
925: lpMFP->xExt = MulDiv(rect.right-rect.left, 2540, GetDeviceCaps(hdc, LOGPIXELSX));
926: /* HBB 981203: Seems it should be LOGPIXELS_Y_, here, not _X_*/
927: lpMFP->yExt = MulDiv(rect.bottom-rect.top, 2540, GetDeviceCaps(hdc, LOGPIXELSY));
928: lpMFP->hMF = hmf;
929: ReleaseDC(hwnd, hdc);
930: GlobalUnlock(hGMem);
931:
932: OpenClipboard(hwnd);
933: EmptyClipboard();
934: SetClipboardData(CF_METAFILEPICT,hGMem);
935: SetClipboardData(CF_BITMAP, bitmap);
936: CloseClipboard();
937: return;
938: }
939:
940: /* copy graph window to printer */
941: void
942: CopyPrint(LPGW lpgw)
943: {
944: #ifdef WIN32
945: DOCINFO docInfo;
946: #endif
947:
948: #if WINVER >= 0x030a
949: HDC printer;
950: DLGPROC lpfnAbortProc;
951: DLGPROC lpfnPrintDlgProc;
952: PRINTDLG pd;
953: HWND hwnd;
954: RECT rect;
955: PRINT pr;
956: UINT widabort;
957:
958: hwnd = lpgw->hWndGraph;
959:
960: _fmemset(&pd, 0, sizeof(PRINTDLG));
961: pd.lStructSize = sizeof(PRINTDLG);
962: pd.hwndOwner = hwnd;
963: pd.Flags = PD_PRINTSETUP | PD_RETURNDC;
964:
965: if (!PrintDlg(&pd))
966: return;
967: printer = pd.hDC;
968: if (NULL == printer)
969: return; /* abort */
970:
971: if (!PrintSize(printer, hwnd, &rect)) {
972: DeleteDC(printer);
973: return; /* abort */
974: }
975:
976: pr.hdcPrn = printer;
977: SetWindowLong(hwnd, 4, (LONG)((LPPRINT)&pr));
978: #ifdef WIN32
979: PrintRegister((LPPRINT)&pr);
980: #endif
981:
982: EnableWindow(hwnd,FALSE);
983: pr.bUserAbort = FALSE;
984: #ifdef WIN32
985: pr.hDlgPrint = CreateDialogParam(hdllInstance,"CancelDlgBox",hwnd,PrintDlgProc,(LPARAM)lpgw->Title);
986: SetAbortProc(printer,PrintAbortProc);
987:
988: memset(&docInfo, 0, sizeof(DOCINFO));
989: docInfo.cbSize = sizeof(DOCINFO);
990: docInfo.lpszDocName = lpgw->Title;
991:
992: if (StartDoc(printer, &docInfo) > 0) {
993: #else
994: #ifdef __DLL__
995: lpfnPrintDlgProc = (DLGPROC)GetProcAddress(hdllInstance, "PrintDlgProc");
996: lpfnAbortProc = (DLGPROC)GetProcAddress(hdllInstance, "PrintAbortProc");
997: #else
998: lpfnPrintDlgProc = (DLGPROC)MakeProcInstance((FARPROC)PrintDlgProc, hdllInstance);
999: lpfnAbortProc = (DLGPROC)MakeProcInstance((FARPROC)PrintAbortProc, hdllInstance);
1000: #endif
1001: pr.hDlgPrint = CreateDialogParam(hdllInstance,"CancelDlgBox",hwnd,lpfnPrintDlgProc,(LPARAM)lpgw->Title);
1002: Escape(printer,SETABORTPROC,0,(LPSTR)lpfnAbortProc,NULL);
1003: if (Escape(printer, STARTDOC, lstrlen(lpgw->Title),lpgw->Title, NULL) > 0) {
1004: #endif
1005: SetMapMode(printer, MM_TEXT);
1006: SetBkMode(printer,OPAQUE);
1007: #ifdef WIN32
1008: StartPage(printer);
1009: #endif
1010: DestroyFonts(lpgw);
1011: MakeFonts(lpgw, (RECT FAR *)&rect, printer);
1012: DestroyPens(lpgw); /* rebuild pens */
1013: MakePens(lpgw, printer);
1014: drawgraph(lpgw, printer, (void *) &rect);
1015: #ifdef WIN32
1016: if (EndPage(printer) > 0)
1017: EndDoc(printer);
1018: #else
1019: if (Escape(printer,NEWFRAME,0,NULL,NULL) > 0)
1020: Escape(printer,ENDDOC,0,NULL,NULL);
1021: #endif
1022: }
1023: if (!pr.bUserAbort) {
1024: EnableWindow(hwnd,TRUE);
1025: DestroyWindow(pr.hDlgPrint);
1026: }
1027: #ifndef WIN32
1028: #ifndef __DLL__
1029: FreeProcInstance((FARPROC)lpfnPrintDlgProc);
1030: FreeProcInstance((FARPROC)lpfnAbortProc);
1031: #endif
1032: #endif
1033: DeleteDC(printer);
1034: SetWindowLong(hwnd, 4, (LONG)(0L));
1035: #ifdef WIN32
1036: PrintUnregister((LPPRINT)&pr);
1037: #endif
1038: /* make certain that the screen pen set is restored */
1039: SendMessage(lpgw->hWndGraph,WM_COMMAND,M_REBUILDTOOLS,0L);
1040: #endif
1041: return;
1042: }
1043:
1044: /* ================================== */
1045: /* INI file stuff */
1046: void
1047: WriteGraphIni(LPGW lpgw)
1048: {
1049: RECT rect;
1050: int i;
1051: char entry[32];
1052: LPLOGPEN pc;
1053: LPLOGPEN pm;
1054: LPSTR file = lpgw->IniFile;
1055: LPSTR section = lpgw->IniSection;
1056: char profile[80];
1057:
1058: if ((file == (LPSTR)NULL) || (section == (LPSTR)NULL))
1059: return;
1060: if (IsIconic(lpgw->hWndGraph))
1061: ShowWindow(lpgw->hWndGraph, SW_SHOWNORMAL);
1062: GetWindowRect(lpgw->hWndGraph,&rect);
1063: wsprintf(profile, "%d %d", rect.left, rect.top);
1064: WritePrivateProfileString(section, "GraphOrigin", profile, file);
1065: wsprintf(profile, "%d %d", rect.right-rect.left, rect.bottom-rect.top);
1066: WritePrivateProfileString(section, "GraphSize", profile, file);
1067: wsprintf(profile, "%s,%d", lpgw->fontname, lpgw->fontsize);
1068: WritePrivateProfileString(section, "GraphFont", profile, file);
1069: wsprintf(profile, "%d", lpgw->color);
1070: WritePrivateProfileString(section, "GraphColor", profile, file);
1071: wsprintf(profile, "%d", lpgw->graphtotop);
1072: WritePrivateProfileString(section, "GraphToTop", profile, file);
1073: wsprintf(profile, "%d %d %d",GetRValue(lpgw->background),
1074: GetGValue(lpgw->background), GetBValue(lpgw->background));
1075: WritePrivateProfileString(section, "GraphBackground", profile, file);
1076:
1077: /* now save pens */
1078: for (i=0; i<WGNUMPENS+2; i++) {
1079: if (i==0)
1080: _fstrcpy(entry,"Border");
1081: else if (i==1)
1082: _fstrcpy(entry,"Axis");
1083: else
1084: wsprintf(entry,"Line%d",i-1);
1085: pc = &lpgw->colorpen[i];
1086: pm = &lpgw->monopen[i];
1087: wsprintf(profile, "%d %d %d %d %d",GetRValue(pc->lopnColor),
1088: GetGValue(pc->lopnColor), GetBValue(pc->lopnColor),
1089: (pc->lopnWidth.x != 1) ? -pc->lopnWidth.x : pc->lopnStyle,
1090: (pm->lopnWidth.x != 1) ? -pm->lopnWidth.x : pm->lopnStyle);
1091: WritePrivateProfileString(section, entry, profile, file);
1092: }
1093: return;
1094: }
1095:
1096: void
1097: ReadGraphIni(LPGW lpgw)
1098: {
1099: LPSTR file = lpgw->IniFile;
1100: LPSTR section = lpgw->IniSection;
1101: char profile[81];
1102: char entry[32];
1103: LPSTR p;
1104: int i,r,g,b,colorstyle,monostyle;
1105: COLORREF ref;
1106: BOOL bOKINI;
1107:
1108: bOKINI = (file != (LPSTR)NULL) && (section != (LPSTR)NULL);
1109: if (!bOKINI)
1110: profile[0] = '\0';
1111:
1112: if (bOKINI)
1113: GetPrivateProfileString(section, "GraphOrigin", "", profile, 80, file);
1114: if ( (p = GetInt(profile, (LPINT)&lpgw->Origin.x)) == NULL)
1115: lpgw->Origin.x = CW_USEDEFAULT;
1116: if ( (p = GetInt(p, (LPINT)&lpgw->Origin.y)) == NULL)
1117: lpgw->Origin.y = CW_USEDEFAULT;
1118: if (bOKINI)
1119: GetPrivateProfileString(section, "GraphSize", "", profile, 80, file);
1120: if ( (p = GetInt(profile, (LPINT)&lpgw->Size.x)) == NULL)
1121: lpgw->Size.x = CW_USEDEFAULT;
1122: if ( (p = GetInt(p, (LPINT)&lpgw->Size.y)) == NULL)
1123: lpgw->Size.y = CW_USEDEFAULT;
1124:
1125: if (bOKINI)
1126: GetPrivateProfileString(section, "GraphFont", "", profile, 80, file);
1127: {
1128: char FAR *size;
1129: size = _fstrchr(profile,',');
1130: if (size) {
1131: *size++ = '\0';
1132: if ( (p = GetInt(size, (LPINT)&lpgw->fontsize)) == NULL)
1133: lpgw->fontsize = WINFONTSIZE;
1134: }
1135: _fstrcpy(lpgw->fontname, profile);
1136: if (lpgw->fontsize == 0)
1137: lpgw->fontsize = WINFONTSIZE;
1138: if (!(*lpgw->fontname))
1139: if (LOWORD(GetVersion()) == 3)
1140: _fstrcpy(lpgw->fontname,WIN30FONT);
1141: else
1142: _fstrcpy(lpgw->fontname,WINFONT);
1143: }
1144:
1145: if (bOKINI)
1146: GetPrivateProfileString(section, "GraphColor", "", profile, 80, file);
1147: if ( (p = GetInt(profile, (LPINT)&lpgw->color)) == NULL)
1148: lpgw->color = TRUE;
1149:
1150: if (bOKINI)
1151: GetPrivateProfileString(section, "GraphToTop", "", profile, 80, file);
1152: if ( (p = GetInt(profile, (LPINT)&lpgw->graphtotop)) == NULL)
1153: lpgw->graphtotop = TRUE;
1154:
1155: lpgw->background = RGB(255,255,255);
1156: if (bOKINI)
1157: GetPrivateProfileString(section, "GraphBackground", "", profile, 80, file);
1158: if ( ((p = GetInt(profile, (LPINT)&r)) != NULL) &&
1159: ((p = GetInt(p, (LPINT)&g)) != NULL) &&
1160: ((p = GetInt(p, (LPINT)&b)) != NULL) )
1161: lpgw->background = RGB(r,g,b);
1162:
1163: StorePen(lpgw, 0,RGB(0,0,0),PS_SOLID,PS_SOLID);
1164: if (bOKINI)
1165: GetPrivateProfileString(section, "Border", "", profile, 80, file);
1166: if ( ((p = GetInt(profile, (LPINT)&r)) != NULL) &&
1167: ((p = GetInt(p, (LPINT)&g)) != NULL) &&
1168: ((p = GetInt(p, (LPINT)&b)) != NULL) &&
1169: ((p = GetInt(p, (LPINT)&colorstyle)) != NULL) &&
1170: ((p = GetInt(p, (LPINT)&monostyle)) != NULL) )
1171: StorePen(lpgw,0,RGB(r,g,b),colorstyle,monostyle);
1172:
1173: StorePen(lpgw, 1,RGB(192,192,192),PS_DOT,PS_DOT);
1174: if (bOKINI)
1175: GetPrivateProfileString(section, "Axis", "", profile, 80, file);
1176: if ( ((p = GetInt(profile, (LPINT)&r)) != NULL) &&
1177: ((p = GetInt(p, (LPINT)&g)) != NULL) &&
1178: ((p = GetInt(p, (LPINT)&b)) != NULL) &&
1179: ((p = GetInt(p, (LPINT)&colorstyle)) != NULL) &&
1180: ((p = GetInt(p, (LPINT)&monostyle)) != NULL) )
1181: StorePen(lpgw,1,RGB(r,g,b),colorstyle,monostyle);
1182:
1183: for (i=0; i<WGNUMPENS; i++)
1184: {
1185: ref = wginitcolor[ i%WGDEFCOLOR ];
1186: colorstyle = wginitstyle[ (i/WGDEFCOLOR) % WGDEFSTYLE ];
1187: monostyle = wginitstyle[ i%WGDEFSTYLE ];
1188: StorePen(lpgw, i+2,ref,colorstyle,monostyle);
1189: wsprintf(entry,"Line%d",i+1);
1190: if (bOKINI)
1191: GetPrivateProfileString(section, entry, "", profile, 80, file);
1192: if ( ((p = GetInt(profile, (LPINT)&r)) != NULL) &&
1193: ((p = GetInt(p, (LPINT)&g)) != NULL) &&
1194: ((p = GetInt(p, (LPINT)&b)) != NULL) &&
1195: ((p = GetInt(p, (LPINT)&colorstyle)) != NULL) &&
1196: ((p = GetInt(p, (LPINT)&monostyle)) != NULL) )
1197: StorePen(lpgw,i+2,RGB(r,g,b),colorstyle,monostyle);
1198: }
1199: }
1200:
1201:
1202: /* ================================== */
1203:
1204: #define LS_DEFLINE 2
1205: typedef struct tagLS {
1206: int widtype;
1207: int wid;
1208: HWND hwnd;
1209: int pen; /* current pen number */
1210: LOGPEN colorpen[WGNUMPENS+2]; /* logical color pens */
1211: LOGPEN monopen[WGNUMPENS+2]; /* logical mono pens */
1212: } LS;
1213: typedef LS FAR* LPLS;
1214:
1215:
1216: COLORREF
1217: GetColor(HWND hwnd, COLORREF ref)
1218: {
1219: CHOOSECOLOR cc;
1220: COLORREF aclrCust[16];
1221: int i;
1222:
1223: for (i=0; i<16; i++) {
1224: aclrCust[i] = RGB(0,0,0);
1225: }
1226: _fmemset(&cc, 0, sizeof(CHOOSECOLOR));
1227: cc.lStructSize = sizeof(CHOOSECOLOR);
1228: cc.hwndOwner = hwnd;
1229: cc.lpCustColors = aclrCust;
1230: cc.rgbResult = ref;
1231: cc.Flags = CC_RGBINIT;
1232: if (ChooseColor(&cc))
1233: return cc.rgbResult;
1234: return ref;
1235: }
1236:
1237:
1238: /* force update of owner draw button */
1239: void
1240: UpdateColorSample(HWND hdlg)
1241: {
1242: RECT rect;
1243: POINT ptul, ptlr;
1244: GetWindowRect( GetDlgItem(hdlg, LS_COLORSAMPLE), &rect);
1245: ptul.x = rect.left;
1246: ptul.y = rect.top;
1247: ptlr.x = rect.right;
1248: ptlr.y = rect.bottom;
1249: ScreenToClient(hdlg, &ptul);
1250: ScreenToClient(hdlg, &ptlr);
1251: rect.left = ptul.x;
1252: rect.top = ptul.y;
1253: rect.right = ptlr.x;
1254: rect.bottom = ptlr.y;
1255: InvalidateRect(hdlg, &rect, TRUE);
1256: UpdateWindow(hdlg);
1257: }
1258:
1259: BOOL CALLBACK WINEXPORT
1260: LineStyleDlgProc(HWND hdlg, UINT wmsg, WPARAM wparam, LPARAM lparam)
1261: {
1262: char buf[16];
1263: LPLS lpls;
1264: int i;
1265: UINT pen;
1266: LPLOGPEN plpm, plpc;
1267: lpls = (LPLS)GetWindowLong(GetParent(hdlg), 4);
1268:
1269: switch (wmsg) {
1270: case WM_INITDIALOG:
1271: pen = 2;
1272: for (i=0; i<WGNUMPENS+2; i++) {
1273: if (i==0)
1274: _fstrcpy(buf,"Border");
1275: else if (i==1)
1276: _fstrcpy(buf,"Axis");
1277: else
1278: wsprintf(buf,"Line%d",i-1);
1279: SendDlgItemMessage(hdlg, LS_LINENUM, LB_ADDSTRING, 0,
1280: (LPARAM)((LPSTR)buf));
1281: }
1282: SendDlgItemMessage(hdlg, LS_LINENUM, LB_SETCURSEL, pen, 0L);
1283:
1284: SendDlgItemMessage(hdlg, LS_MONOSTYLE, CB_ADDSTRING, 0,
1285: (LPARAM)((LPSTR)"Solid"));
1286: SendDlgItemMessage(hdlg, LS_MONOSTYLE, CB_ADDSTRING, 0,
1287: (LPARAM)((LPSTR)"Dash"));
1288: SendDlgItemMessage(hdlg, LS_MONOSTYLE, CB_ADDSTRING, 0,
1289: (LPARAM)((LPSTR)"Dot"));
1290: SendDlgItemMessage(hdlg, LS_MONOSTYLE, CB_ADDSTRING, 0,
1291: (LPARAM)((LPSTR)"DashDot"));
1292: SendDlgItemMessage(hdlg, LS_MONOSTYLE, CB_ADDSTRING, 0,
1293: (LPARAM)((LPSTR)"DashDotDot"));
1294:
1295: plpm = &lpls->monopen[pen];
1296: SendDlgItemMessage(hdlg, LS_MONOSTYLE, CB_SETCURSEL,
1297: plpm->lopnStyle, 0L);
1298: wsprintf(buf,"%d",plpm->lopnWidth.x);
1299: SetDlgItemText(hdlg, LS_MONOWIDTH, buf);
1300:
1301: SendDlgItemMessage(hdlg, LS_COLORSTYLE, CB_ADDSTRING, 0,
1302: (LPARAM)((LPSTR)"Solid"));
1303: SendDlgItemMessage(hdlg, LS_COLORSTYLE, CB_ADDSTRING, 0,
1304: (LPARAM)((LPSTR)"Dash"));
1305: SendDlgItemMessage(hdlg, LS_COLORSTYLE, CB_ADDSTRING, 0,
1306: (LPARAM)((LPSTR)"Dot"));
1307: SendDlgItemMessage(hdlg, LS_COLORSTYLE, CB_ADDSTRING, 0,
1308: (LPARAM)((LPSTR)"DashDot"));
1309: SendDlgItemMessage(hdlg, LS_COLORSTYLE, CB_ADDSTRING, 0,
1310: (LPARAM)((LPSTR)"DashDotDot"));
1311:
1312: plpc = &lpls->colorpen[pen];
1313: SendDlgItemMessage(hdlg, LS_COLORSTYLE, CB_SETCURSEL,
1314: plpc->lopnStyle, 0L);
1315: wsprintf(buf,"%d",plpc->lopnWidth.x);
1316: SetDlgItemText(hdlg, LS_COLORWIDTH, buf);
1317:
1318: return TRUE;
1319: case WM_COMMAND:
1320: pen = (UINT)SendDlgItemMessage(hdlg, LS_LINENUM, LB_GETCURSEL, 0, 0L);
1321: plpm = &lpls->monopen[pen];
1322: plpc = &lpls->colorpen[pen];
1323: switch (LOWORD(wparam)) {
1324: case LS_LINENUM:
1325: wsprintf(buf,"%d",plpm->lopnWidth.x);
1326: SetDlgItemText(hdlg, LS_MONOWIDTH, buf);
1327: SendDlgItemMessage(hdlg, LS_MONOSTYLE, CB_SETCURSEL,
1328: plpm->lopnStyle, 0L);
1329: wsprintf(buf,"%d",plpc->lopnWidth.x);
1330: SetDlgItemText(hdlg, LS_COLORWIDTH, buf);
1331: SendDlgItemMessage(hdlg, LS_COLORSTYLE, CB_SETCURSEL,
1332: plpc->lopnStyle, 0L);
1333: UpdateColorSample(hdlg);
1334: return FALSE;
1335: case LS_MONOSTYLE:
1336: plpm->lopnStyle =
1337: (UINT)SendDlgItemMessage(hdlg, LS_MONOSTYLE, CB_GETCURSEL, 0, 0L);
1338: if (plpm->lopnStyle != 0) {
1339: plpm->lopnWidth.x = 1;
1340: wsprintf(buf,"%d",plpm->lopnWidth.x);
1341: SetDlgItemText(hdlg, LS_MONOWIDTH, buf);
1342: }
1343: return FALSE;
1344: case LS_MONOWIDTH:
1345: GetDlgItemText(hdlg, LS_MONOWIDTH, buf, 15);
1346: GetInt(buf, (LPINT)&plpm->lopnWidth.x);
1347: if (plpm->lopnWidth.x != 1) {
1348: plpm->lopnStyle = 0;
1349: SendDlgItemMessage(hdlg, LS_MONOSTYLE, CB_SETCURSEL,
1350: plpm->lopnStyle, 0L);
1351: }
1352: return FALSE;
1353: case LS_CHOOSECOLOR:
1354: plpc->lopnColor = GetColor(hdlg, plpc->lopnColor);
1355: UpdateColorSample(hdlg);
1356: return FALSE;
1357: case LS_COLORSTYLE:
1358: plpc->lopnStyle =
1359: (UINT)SendDlgItemMessage(hdlg, LS_COLORSTYLE, CB_GETCURSEL, 0, 0L);
1360: if (plpc->lopnStyle != 0) {
1361: plpc->lopnWidth.x = 1;
1362: wsprintf(buf,"%d",plpc->lopnWidth.x);
1363: SetDlgItemText(hdlg, LS_COLORWIDTH, buf);
1364: }
1365: return FALSE;
1366: case LS_COLORWIDTH:
1367: GetDlgItemText(hdlg, LS_COLORWIDTH, buf, 15);
1368: GetInt(buf, (LPINT)&plpc->lopnWidth.x);
1369: if (plpc->lopnWidth.x != 1) {
1370: plpc->lopnStyle = 0;
1371: SendDlgItemMessage(hdlg, LS_COLORSTYLE, CB_SETCURSEL,
1372: plpc->lopnStyle, 0L);
1373: }
1374: return FALSE;
1375: case LS_DEFAULT:
1376: plpm = lpls->monopen;
1377: plpc = lpls->colorpen;
1378: /* border */
1379: plpc->lopnColor = RGB(0,0,0);
1380: plpc->lopnStyle = PS_SOLID;
1381: plpc->lopnWidth.x = 1;
1382: plpm->lopnStyle = PS_SOLID;
1383: plpm->lopnWidth.x = 1;
1384: plpc++; plpm++;
1385: /* axis */
1386: plpc->lopnColor = RGB(192,192,192);
1387: plpc->lopnStyle = PS_DOT;
1388: plpc->lopnWidth.x = 1;
1389: plpm->lopnStyle = PS_DOT;
1390: plpm->lopnWidth.x = 1;
1391: /* LineX */
1392: for (i=0; i<WGNUMPENS; i++) {
1393: plpc++; plpm++;
1394: plpc->lopnColor = wginitcolor[ i%WGDEFCOLOR ];
1395: plpc->lopnStyle = wginitstyle[ (i/WGDEFCOLOR) % WGDEFSTYLE ];
1396: plpc->lopnWidth.x = 1;
1397: plpm->lopnStyle = wginitstyle[ i%WGDEFSTYLE ];
1398: plpm->lopnWidth.x = 1;
1399: }
1400: /* update window */
1401: plpm = &lpls->monopen[pen];
1402: plpc = &lpls->colorpen[pen];
1403: SendDlgItemMessage(hdlg, LS_LINENUM, LB_SETCURSEL, pen, 0L);
1404: wsprintf(buf,"%d",plpm->lopnWidth.x);
1405: SetDlgItemText(hdlg, LS_MONOWIDTH, buf);
1406: SendDlgItemMessage(hdlg, LS_MONOSTYLE, CB_SETCURSEL,
1407: plpm->lopnStyle, 0L);
1408: wsprintf(buf,"%d",plpc->lopnWidth.x);
1409: SetDlgItemText(hdlg, LS_COLORWIDTH, buf);
1410: SendDlgItemMessage(hdlg, LS_COLORSTYLE, CB_SETCURSEL,
1411: plpc->lopnStyle, 0L);
1412: UpdateColorSample(hdlg);
1413: return FALSE;
1414: case IDOK:
1415: EndDialog(hdlg, IDOK);
1416: return TRUE;
1417: case IDCANCEL:
1418: EndDialog(hdlg, IDCANCEL);
1419: return TRUE;
1420: }
1421: break;
1422: case WM_DRAWITEM:
1423: {
1424: HBRUSH hBrush;
1425: LPDRAWITEMSTRUCT lpdis = (LPDRAWITEMSTRUCT)lparam;
1426: pen = (UINT)SendDlgItemMessage(hdlg, LS_LINENUM, LB_GETCURSEL, (WPARAM)0, (LPARAM)0);
1427: plpc = &lpls->colorpen[pen];
1428: hBrush = CreateSolidBrush(plpc->lopnColor);
1429: FillRect(lpdis->hDC, &lpdis->rcItem, hBrush);
1430: FrameRect(lpdis->hDC, &lpdis->rcItem, (HBRUSH)GetStockObject(BLACK_BRUSH));
1431: DeleteObject(hBrush);
1432: }
1433: return FALSE;
1434: }
1435: return FALSE;
1436: }
1437:
1438:
1439:
1440: /* GetWindowLong(hwnd, 4) must be available for use */
1441: BOOL
1442: LineStyle(LPGW lpgw)
1443: {
1444: DLGPROC lpfnLineStyleDlgProc ;
1445: BOOL status = FALSE;
1446: LS ls;
1447:
1448: SetWindowLong(lpgw->hWndGraph, 4, (LONG)((LPLS)&ls));
1449: _fmemcpy(&ls.colorpen, &lpgw->colorpen, (WGNUMPENS + 2) * sizeof(LOGPEN));
1450: _fmemcpy(&ls.monopen, &lpgw->monopen, (WGNUMPENS + 2) * sizeof(LOGPEN));
1451:
1452: #ifdef WIN32
1453: if (DialogBox (hdllInstance, "LineStyleDlgBox", lpgw->hWndGraph, LineStyleDlgProc)
1454: #else
1455: #ifdef __DLL__
1456: lpfnLineStyleDlgProc = (DLGPROC)GetProcAddress(hdllInstance, "LineStyleDlgProc");
1457: #else
1458: lpfnLineStyleDlgProc = (DLGPROC)MakeProcInstance((FARPROC)LineStyleDlgProc, hdllInstance);
1459: #endif
1460: if (DialogBox (hdllInstance, "LineStyleDlgBox", lpgw->hWndGraph, lpfnLineStyleDlgProc)
1461: #endif
1462: == IDOK) {
1463: _fmemcpy(&lpgw->colorpen, &ls.colorpen, (WGNUMPENS + 2) * sizeof(LOGPEN));
1464: _fmemcpy(&lpgw->monopen, &ls.monopen, (WGNUMPENS + 2) * sizeof(LOGPEN));
1465: status = TRUE;
1466: }
1467: #ifndef WIN32
1468: #ifndef __DLL__
1469: FreeProcInstance((FARPROC)lpfnLineStyleDlgProc);
1470: #endif
1471: #endif
1472: SetWindowLong(lpgw->hWndGraph, 4, (LONG)(0L));
1473: return status;
1474: }
1475:
1476: /* ================================== */
1477:
1478: LRESULT CALLBACK WINEXPORT
1479: WndGraphProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
1480: {
1481: HDC hdc;
1482: PAINTSTRUCT ps;
1483: RECT rect;
1484: LPGW lpgw;
1485: HMENU sysmenu;
1486: int i;
1487:
1488: lpgw = (LPGW)GetWindowLong(hwnd, 0);
1489:
1490: switch(message)
1491: {
1492: case WM_SYSCOMMAND:
1493: switch(LOWORD(wParam))
1494: {
1495: case M_GRAPH_TO_TOP:
1496: case M_COLOR:
1497: case M_CHOOSE_FONT:
1498: case M_COPY_CLIP:
1499: case M_LINESTYLE:
1500: case M_BACKGROUND:
1501: case M_PRINT:
1502: case M_WRITEINI:
1503: case M_REBUILDTOOLS:
1504: SendMessage(hwnd, WM_COMMAND, wParam, lParam);
1505: break;
1506: case M_ABOUT:
1507: if (lpgw->lptw)
1508: AboutBox(hwnd,lpgw->lptw->AboutText);
1509: return 0;
1510: case M_COMMANDLINE:
1511: sysmenu = GetSystemMenu(lpgw->hWndGraph,0);
1512: i = GetMenuItemCount (sysmenu);
1513: DeleteMenu (sysmenu, --i, MF_BYPOSITION);
1514: DeleteMenu (sysmenu, --i, MF_BYPOSITION);
1515: ShowWindow (lpgw->lptw->hWndParent, SW_SHOW);
1516: break;
1517: }
1518: break;
1519: case WM_COMMAND:
1520: switch(LOWORD(wParam))
1521: {
1522: case M_GRAPH_TO_TOP:
1523: lpgw->graphtotop = !lpgw->graphtotop;
1524: SendMessage(hwnd,WM_COMMAND,M_REBUILDTOOLS,0L);
1525: return(0);
1526: case M_COLOR:
1527: lpgw->color = !lpgw->color;
1528: SendMessage(hwnd,WM_COMMAND,M_REBUILDTOOLS,0L);
1529: return(0);
1530: case M_CHOOSE_FONT:
1531: SelFont(lpgw);
1532: return 0;
1533: case M_COPY_CLIP:
1534: CopyClip(lpgw);
1535: return 0;
1536: case M_LINESTYLE:
1537: if (LineStyle(lpgw))
1538: SendMessage(hwnd,WM_COMMAND,M_REBUILDTOOLS,0L);
1539: return 0;
1540: case M_BACKGROUND:
1541: lpgw->background = GetColor(hwnd, lpgw->background);
1542: SendMessage(hwnd,WM_COMMAND,M_REBUILDTOOLS,0L);
1543: return 0;
1544: case M_PRINT:
1545: CopyPrint(lpgw);
1546: return 0;
1547: case M_WRITEINI:
1548: WriteGraphIni(lpgw);
1549: if (lpgw->lptw)
1550: WriteTextIni(lpgw->lptw);
1551: return 0;
1552: case M_REBUILDTOOLS:
1553: lpgw->resized = TRUE;
1554: if (lpgw->color)
1555: CheckMenuItem(lpgw->hPopMenu, M_COLOR, MF_BYCOMMAND | MF_CHECKED);
1556: else
1557: CheckMenuItem(lpgw->hPopMenu, M_COLOR, MF_BYCOMMAND | MF_UNCHECKED);
1558: if (lpgw->graphtotop)
1559: CheckMenuItem(lpgw->hPopMenu, M_GRAPH_TO_TOP, MF_BYCOMMAND | MF_CHECKED);
1560: else
1561: CheckMenuItem(lpgw->hPopMenu, M_GRAPH_TO_TOP, MF_BYCOMMAND | MF_UNCHECKED);
1562: DestroyPens(lpgw);
1563: DestroyFonts(lpgw);
1564: hdc = GetDC(hwnd);
1565: MakePens(lpgw, hdc);
1566: GetClientRect(hwnd, &rect);
1567: MakeFonts(lpgw, (LPRECT)&rect, hdc);
1568: ReleaseDC(hwnd, hdc);
1569: GetClientRect(hwnd, &rect);
1570: InvalidateRect(hwnd, (LPRECT) &rect, 1);
1571: UpdateWindow(hwnd);
1572: return 0;
1573: }
1574: return 0;
1575: case WM_RBUTTONDOWN:
1576: {
1577: POINT pt;
1578: pt.x = LOWORD(lParam);
1579: pt.y = HIWORD(lParam);
1580: ClientToScreen(hwnd,&pt);
1581: TrackPopupMenu(lpgw->hPopMenu, TPM_LEFTALIGN,
1582: pt.x, pt.y, 0, hwnd, NULL);
1583: }
1584: return(0);
1585: case WM_CREATE:
1586: lpgw = ((CREATESTRUCT FAR *)lParam)->lpCreateParams;
1587: SetWindowLong(hwnd, 0, (LONG)lpgw);
1588: lpgw->hWndGraph = hwnd;
1589: hdc = GetDC(hwnd);
1590: MakePens(lpgw, hdc);
1591: GetClientRect(hwnd, &rect);
1592: MakeFonts(lpgw, (LPRECT)&rect, hdc);
1593: ReleaseDC(hwnd, hdc);
1594: #if WINVER >= 0x030a
1595: {
1596: WORD version = LOWORD(GetVersion());
1597: if ((LOBYTE(version)*100 + HIBYTE(version)) >= 310)
1598: if ( lpgw->lptw && (lpgw->lptw->DragPre!=(LPSTR)NULL) && (lpgw->lptw->DragPost!=(LPSTR)NULL) )
1599: DragAcceptFiles(hwnd, TRUE);
1600: }
1601: #endif
1602: return(0);
1603: case WM_PAINT:
1604: hdc = BeginPaint(hwnd, &ps);
1605: SetMapMode(hdc, MM_TEXT);
1606: SetBkMode(hdc,OPAQUE);
1607: GetClientRect(hwnd, &rect);
1608: #ifdef WIN32
1609: SetViewportExtEx(hdc, rect.right, rect.bottom, NULL);
1610: #else
1611: SetViewportExt(hdc, rect.right, rect.bottom);
1612: #endif
1613: drawgraph(lpgw, hdc, (void *) &rect);
1614: EndPaint(hwnd, &ps);
1615: return 0;
1616: case WM_SIZE:
1617: /* update font sizes if graph resized */
1618: if ((wParam == SIZE_MAXIMIZED) || (wParam == SIZE_RESTORED)) {
1619: RECT rect;
1620: SendMessage(hwnd,WM_SYSCOMMAND,M_REBUILDTOOLS,0L);
1621: GetWindowRect(hwnd,&rect);
1622: lpgw->Size.x = rect.right-rect.left;
1623: lpgw->Size.y = rect.bottom-rect.top;
1624: }
1625: break;
1626: #if WINVER >= 0x030a
1627: case WM_DROPFILES:
1628: {
1629: WORD version = LOWORD(GetVersion());
1630: if ((LOBYTE(version)*100 + HIBYTE(version)) >= 310)
1631: if (lpgw->lptw)
1632: DragFunc(lpgw->lptw, (HDROP)wParam);
1633: }
1634: break;
1635: #endif
1636: case WM_DESTROY:
1637: DestroyPens(lpgw);
1638: DestroyFonts(lpgw);
1639: #if __TURBOC__ >= 0x410 /* Borland C++ 3.1 or later */
1640: {
1641: WORD version = LOWORD(GetVersion());
1642: if ((LOBYTE(version)*100 + HIBYTE(version)) >= 310)
1643: DragAcceptFiles(hwnd, FALSE);
1644: }
1645: #endif
1646: if (lpgw->lptw && !IsWindowVisible(lpgw->lptw->hWndParent)) {
1647: PostMessage (lpgw->lptw->hWndParent, WM_CLOSE, 0, 0);
1648: }
1649: return 0;
1650: case WM_CLOSE:
1651: GraphClose(lpgw);
1652: return 0;
1653: }
1654: return DefWindowProc(hwnd, message, wParam, lParam);
1655: }
1656:
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>