home *** CD-ROM | disk | FTP | other *** search
Wrap
/*============================================================================== REP.C ReportEase Plus - Window process and painting functions. ReportEase Plus Version 2.0 Sub Systems, Inc. ReportEase Plus, Copyright (c) 1993, Sub Systems, Inc. All Rights Reserved. 159 Main Street, #8C, Stoneham, MA 02180 (617) 438-8901. Software License Agreement (1993) ---------------------------------- This license agreement allows the purchaser the right to modify the source code to incorporate in their application. The target application must not be distributed as a standalone report writer or a mail merge product. Sub Systems, Inc. reserves the right to prosecute anybody found to be making illegal copies of the executable software or compiling the source code for the purpose of selling there after. ===============================================================================*/ #include "windows.h" #if defined (_WIN32) #if !defined(WIN32) #define WIN32 #endif #endif #if !defined(WIN32) #include "print.h" #endif #include "stdio.h" #include "stdlib.h" #include "ctype.h" #include "dos.h" #include "fcntl.h" #include "io.h" #include "signal.h" #include "string.h" #include "malloc.h" #include "memory.h" #include "sys\types.h" #include "sys\stat.h" #include "setjmp.h" #include "rep.h" #define PREFIX #include "rep1.h" /**************************************************************************** form: This routine simply call FORM initialization routine. The routine returns a 0 if successful, otherwise it returns an error code. see ERR_ in rew.h file. *****************************************************************************/ int WINAPI _export form(struct StrForm far *ArgPtr) { int result,WinVer; // prepare to return an error code #if defined (WIN32) if (setjmp(FrAbort)==-1) return ErrorCode; // Fatal error return location #else if (Catch((LPCATCHBUF)&FrAbort)==-1) return ErrorCode; // Fatal error return location #endif SessionType='F'; // form editor session FormArg=(*ArgPtr); //* Transfer the some input parameter variables to the global area * strcpy(FrFileName,FormArg.file); // current report file name FrShowHorBar=FormArg.ShowHorBar; // show horizontal scroll bar FrShowVerBar=FormArg.ShowVerBar; // show vertical scroll bar //hFrInst=FormArg.hInst; // uncomment for STATIC linking //hFrPrevInst=FormArg.hPrevInst; // uncomment for STATIC linking hFrParentWnd=FormArg.hParentWnd; // Handle to the parent window //************ initialize other variables ********** UseScreen=TRUE; FormArg.modified =FALSE; //********************** assign the default font and point size ********* if (FormArg.FontTypeFace[0]==0) { WinVer=(int)GetVersion(); if ((LOBYTE(WinVer))==3 && (HIBYTE(WinVer))==0) { // windows 3.0 lstrcpy(FormArg.FontTypeFace,"Helv"); } else { // windows 3.1 lstrcpy(FormArg.FontTypeFace,"Arial"); } } if (0!=(result=InitFr(FormArg.style,FormArg.x,FormArg.y,FormArg.width,FormArg.height))) return result; FormArg.open=TRUE; // mark this window as open (*ArgPtr)=FormArg; // pass back the updated structure return 0; } /**************************************************************************** RepSetMsgCallback: This function is called by the application to set a call back function to receive the DLL messages. This function is needed only by the application which do not have the capability to receive Windows messages. *****************************************************************************/ int WINAPI _export RepSetMsgCallback(MSG_CALLBACK funct) { MsgCallback=funct; return TRUE; } /****************************************************************************** LibMain: Function to initialize DLL ******************************************************************************/ #if defined (WIN32) BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD reason, LPVOID reserved) #else int CALLBACK LibMain(HINSTANCE hInstance, WORD wDataSeg, WORD cbHeapSize, LPSTR lpszCmdLine) #endif { // process the 'reason' flag for WIN32 #if defined (WIN32) Win32=TRUE; if (reason == DLL_PROCESS_DETACH) return WEP(0); if (reason != DLL_PROCESS_ATTACH) return TRUE; #else Win32=FALSE; #endif hFrInst=hInstance; hFrPrevInst=0; return TRUE; } /***************************************************************************** WEP: Library exit routine. ******************************************************************************/ int CALLBACK _export WEP(int nParameter) { return 1; } /**************************************************************************** FrWndProc: This routine process the messages coming to the main FORM window. ****************************************************************************/ LRESULT CALLBACK _export FrWndProc(HWND hWnd,UINT message,WPARAM wParam,LPARAM lParam) { int opt,i; if (WindowBeingCreated) return (DefWindowProc(hWnd, message, wParam, lParam)); //*********** translate accelerator *********** if (FrTranslateAccelerator(hWnd,message,wParam,lParam)) return TRUE; // accelerator translated switch (message) { case WM_INITMENU: // initialize menu if ((GetMenu(hWnd)!=(HMENU)wParam)) break; FrInitMenu((HMENU)wParam);break; case WM_VSCROLL: // vertical scroll bar commands switch (SCROLL_MSG(wParam,lParam)) { case SB_LINEDOWN: // scroll window one line down FrWinDown();break; case SB_LINEUP: // scroll window one line up FrWinUp();break; case SB_PAGEDOWN: // next page FrWinOrgY+=FrWinHeight/2; PaintFlag=PAINT_WIN;FrPaint();break; case SB_PAGEUP: // previous page FrWinOrgY-=FrWinHeight/2; PaintFlag=PAINT_WIN;FrPaint();break; case SB_THUMBTRACK: // absolute line position as the thump moves FrWinOrgY=(int)(((long)FrHeight*THUMB_POS(wParam,lParam))/(VER_SCROLL_MAX-VER_SCROLL_MIN)); PaintFlag=PAINT_WIN;FrPaint();break; default: break; } break; case WM_HSCROLL: // horizontal scroll bar commands switch (SCROLL_MSG(wParam,lParam)) { case SB_LINEDOWN: // scroll window one column toward right FrWinRight();break; case SB_LINEUP: // scroll window one column toward left FrWinLeft();break; case SB_PAGEDOWN: // next horizontal page FrWinOrgX+=FrWinWidth/2; PaintFlag=PAINT_WIN;FrPaint();break; case SB_PAGEUP: // previous horizontal page FrWinOrgX-=FrWinWidth/2; PaintFlag=PAINT_WIN;FrPaint();break; case SB_THUMBTRACK: // absolute column position as the thump moves FrWinOrgX=(int)(((long)FrWidth*THUMB_POS(wParam,lParam))/(HOR_SCROLL_MAX-HOR_SCROLL_MIN)); PaintFlag=PAINT_WIN;FrPaint();break; default: break; } break; case WM_COMMAND: if (FrHelpWanted) { // show contect sensitive help if requrested WinHelp(hWnd,FrHelpFile,HELP_CONTEXT,wParam); FrHelpWanted=FALSE; break; } if (UndoItem && wParam!=ID_UNDO && wParam!=ID_DESC_WND) DiscardUndo(); // discard the previous undo data switch (COMMAND_ID(wParam,lParam)) { //********************************************************* // Navigation commands //********************************************************* case ID_PGUP: // process page-up key FrWinOrgY-=FrHeight/2; PaintFlag=PAINT_WIN;FrPaint();break; case ID_PGDN: // process page-down key FrWinOrgY+=FrHeight/2; PaintFlag=PAINT_WIN;FrPaint();break; case ID_UP: // process the up arrow key if (SelItem<0 || item[SelItem].type==SECTION) FrWinUp(); else FrKeyMove(ID_UP); // move the item break; case ID_DOWN: // process the down arrow key if (SelItem<0 || item[SelItem].type==SECTION) FrWinDown(); else FrKeyMove(ID_DOWN); // move the item break; case ID_LEFT: // process the left arrow if (SelItem<0 || item[SelItem].type==SECTION) FrWinLeft(); else FrKeyMove(ID_LEFT); // move the item break; case ID_RIGHT: // process the right arrow if (SelItem<0 || item[SelItem].type==SECTION) FrWinRight(); else FrKeyMove(ID_RIGHT); // move the item break; //********************************************************* // Edit functions //********************************************************* case ID_POS_ITEM: // position the text inside the item PosItem();break; case ID_ITEM_OUTLINE: // edit the item outlines EditItemOutline();break; case ID_ITEM_BACKGROUND: // edit the item background EditItemBackground();break; case ID_CENTER_ITEM: // center an item horizontally CenterItem();break; case ID_DEL_ITEM: // delete the selected item DeleteItem();break; case ID_FONTS: // display fonts FrFonts();break; case ID_EXPAND_HORZ: // insert space horizontally ExpandHorizontal();break; case ID_EXPAND_VERT: // insert space vertically ExpandVertical();break; case ID_COMPRESS_HORZ: // delete space horizontally CompressHorizontal();break; case ID_COMPRESS_VERT: // delete space vertically CompressVertical();break; //********************************************************* // File Menu functions //********************************************************* case ID_SAVE: // save the modified text FrSave(FrFileName);break; case ID_SAVEAS: // save the modified text, as user for the file name FrSaveAs(FrFileName);break; case ID_REP_PARAM: // accepts report name, page layout, etc options from the users FrRepParameters();break; case ID_REP_FILTER: // accepts record filter for the report FrRepFilter();break; case ID_PRINT_OPTIONS: // accepts printer options from the users FrPrintOptions();break; case ID_QUIT: // quit FORM session CloseFr();break; //******************************************************** // Field Functions //******************************************************** case ID_INSERT_DATA: // insert a data field case ID_INSERT_CALC: // insert a calculation field case ID_INSERT_SYS: // insert a system field case ID_INSERT_DLG: // insert a dialog field InsertFieldPartI(wParam);// begin the field insertion process break; case ID_EDIT_FLD: // edit field attributes ModifyField();break; case ID_EDIT_FLD_EXP: // edit calculation field expression EditFieldExp();break; case ID_DLG_CREATE: // create a dialog field CreateDlgField();break; case ID_DLG_MODIFY: // modify a dialog field ModifyDlgField();break; case ID_DLG_DELETE: // delete a dialog field DeleteDlgField();break; //******************************************************** // Section Functions //******************************************************** case ID_SEC_NEW: // create new section NewSection();break; case ID_SEC_EDIT: // create new section EditSection();break; case ID_SEC_FILTER: // Edit section selection crieteria EditSectionFilter();break; case ID_SEC_SORT: // Edit section sort field EditSectionSort();break; case ID_SEC_BREAK: // Edit section break field EditSectionBreak();break; //********************************************************* // Line functions //********************************************************* case ID_INSERT_LINE: // insert a line InsertLinePartI();break; case ID_EDIT_LINE: // edit line EditLine();break; //********************************************************* // Label functions //********************************************************* case ID_INSERT_LABEL: // insert a label InsertLabelPartI();break; case ID_EDIT_LABEL: // edit a label if (hDescWnd) { SetFocus(hDescWnd); } break; //********************************************************* // Picture functions //********************************************************* case ID_PICT_FROM_CB: // copy a picture from clipboard case ID_PICT_FROM_FILE: // insert a picture from a bitmap file InsertPicturePartI(COMMAND_ID(wParam,lParam));break; //********************************************************* // Arrange Menu functions //********************************************************* case ID_ALIGN_HORZ_TOP: // Align at top edge AlignHorzTop();break; case ID_ALIGN_HORZ_BOT: // Align at bottom edge AlignHorzBot();break; case ID_ALIGN_HORZ_CENTER: // Align horizontal at center line. AlignHorzCenter();break; case ID_ALIGN_VERT_LEFT: // Align at left edge AlignVertLeft();break; case ID_ALIGN_VERT_RIGHT: // Align at right edge AlignVertRight();break; case ID_ALIGN_VERT_CENTER: // Align at the vertical center line AlignVertCenter();break; case ID_EVEN_SPACE_HORZ: // set the equal horizontal space between the items EvenSpaceHorz();break; case ID_EVEN_SPACE_VERT: // set the equal vertical space between the items EvenSpaceVert();break; case ID_EVEN_SIZE_HORZ: // set the same width for the selected items EvenSizeHorz();break; case ID_EVEN_SIZE_VERT: // set the same height for the selected items EvenSizeVert();break; case ID_UNDO: // undo previous arrange command Undo();break; //********************************************************* // Miscellaneous functions //********************************************************* case ID_HELP: // display help on functions WinHelp(hWnd,FrHelpFile,HELP_INDEX,0L); break; case ID_DESC_WND: // update label text if (NOTIFY_MSG(wParam,lParam)==EN_KILLFOCUS) UpdateLabelText(); break; default: return (DefWindowProc(hWnd, message, wParam, lParam)); } break; //*************************************************************** // Mouse functions //*************************************************************** case WM_LBUTTONDOWN: // position or select the object case WM_MBUTTONDOWN: // position or select the object case WM_RBUTTONDOWN: // position or select the object FrMouseDown(wParam,lParam); break; case WM_MOUSEMOVE: // set highlighted areas if (IgnoreMouseMove) FrSetCursorShape(lParam); else FrMouseMove(wParam,lParam); break; case WM_LBUTTONUP: // stop stretching highlighted area now case WM_RBUTTONUP: case WM_MBUTTONUP: switch (CurCmd) { case ID_MOVE_ITEM: MoveItem();break; // move the selected item case ID_SIZE_ITEM: SizeItem(); // resize the selected item DiscardUndo(); // discard unwanted undo break; case ID_SELECT_MULTIPLE: // select multiple items SelectGroupItemPartII(); break; default: if (CurCmd!=-1 || !DrawOptRect) break; // check if any option rectangle has been selected opt=GetMouseOpt(lParam); if (opt==OPT_LABEL)InsertLabelPartI(); else if (opt==OPT_DATA) InsertFieldPartI(ID_INSERT_DATA); else if (opt==OPT_CALC) InsertFieldPartI(ID_INSERT_CALC); else if (opt==OPT_SYS) InsertFieldPartI(ID_INSERT_SYS); else if (opt==OPT_DLG) { // check if any dialog field available for (i=0;i<MAX_DLGS;i++) if (DlgField[i].InUse) break; if (i<MAX_DLGS) InsertFieldPartI(ID_INSERT_DLG); else CreateDlgField(); // create a dialog field in the dialog table } else if (opt==OPT_LINE) InsertLinePartI(); else IgnoreMouseMove=TRUE; break; } break; case WM_LBUTTONDBLCLK: if (CurCmd==-1 && SelItem>=0) { // modify items if (item[SelItem].type==LABEL) EditItemOutline(); else if (item[SelItem].type==LINE) EditLine(); else if (item[SelItem].type==FIELD) { if (field[item[SelItem].field].type==TYPE_PICT) EditItemOutline(); else ModifyField(); } else if (item[SelItem].type==SECTION) EditSection(); } break; case WM_RBUTTONDBLCLK: if (CurCmd==-1 && SelItem>=0) { // modify items if (item[SelItem].type==LABEL) FrFonts(); else if (item[SelItem].type==LINE) EditItemBackground(); else if (item[SelItem].type==FIELD) { if (field[item[SelItem].field].type==TYPE_PICT) EditItemBackground(); else FrFonts(); } else if (item[SelItem].type==SECTION) FrRepParameters(); } break; case WM_MBUTTONDBLCLK: // edit field if (CurCmd==-1 && SelItem>=0) EditItemBackground(); break; case WM_PAINT: RepaintFr(); break; case WM_SETFOCUS: PaintFlag=PAINT_WIN; // next time paint the entire client area break; case WM_ENTERIDLE: // check if context sensitive help is requested if ((wParam == MSGF_MENU) && (GetKeyState(VK_F1) & 0x8000)) { FrHelpWanted=TRUE; PostMessage(hWnd,WM_KEYDOWN,VK_RETURN,0L); // generate a dummy <CR> key, cause selection of the menu item } break; case WM_CLOSE: CloseFr(); return (LRESULT)(NULL); case WM_QUERYENDSESSION: return (CloseFr()); case WM_DESTROY: FormArg.open=FALSE; // mark this window as closed break; case WM_GETDLGCODE: return (long)(DLGC_WANTMESSAGE|DLGC_WANTALLKEYS |DLGC_WANTARROWS|DLGC_WANTCHARS|DLGC_WANTTAB); /* process all messages when REP used as a control */ default: return (DefWindowProc(hWnd, message, wParam, lParam)); } FormArg.modified=FrModified; // pass the file status return (LRESULT)(NULL); } /**************************************************************************** FrEditSubclass: This routine subclass the label input edit control to access the carriage return key. ****************************************************************************/ BOOL CALLBACK _export FrEditSubclass(HWND hWnd,UINT message,WPARAM wParam,LPARAM lParam) { if (message==WM_CHAR && wParam==VK_RETURN) { UpdateLabelText(); // update the label text SetFocus(hFrWnd); // set the focus to the main window return TRUE; } else return (BOOL) CallWindowProc(OrigEditProc,hWnd,message,wParam,lParam); } /****************************************************************************** FrInitMenu: Initialze the menu before displaying ******************************************************************************/ FrInitMenu(HMENU hMenu) { int i,CurSec,CurField; BOOL DlgTableFull,DlgTableEmpty; if (SelItem>=0 && item[SelItem].type==FIELD) CurField=item[SelItem].field; else CurField=-1; //****** File Menu ***** EnableMenuItem(hMenu,ID_PRINT_OPTIONS,PrinterName[0]!=0 ? MF_ENABLED : MF_GRAYED); EnableMenuItem(hMenu,ID_SAVE,FrModified ? MF_ENABLED : MF_GRAYED); //**** Edit Menu *** EnableMenuItem(hMenu,ID_FONTS,SelItem>=0 && (item[SelItem].type==LABEL || (item[SelItem].type==FIELD && field[CurField].type!=TYPE_PICT)|| item[SelItem].type==GROUP) ? MF_ENABLED : MF_GRAYED); EnableMenuItem(hMenu,ID_POS_ITEM,SelItem>=0 && (item[SelItem].type==LABEL || (item[SelItem].type==FIELD && field[CurField].type!=TYPE_PICT) || item[SelItem].type==GROUP) ? MF_ENABLED : MF_GRAYED); EnableMenuItem(hMenu,ID_ITEM_OUTLINE,SelItem>=0 ? MF_ENABLED : MF_GRAYED); EnableMenuItem(hMenu,ID_ITEM_BACKGROUND,SelItem>=0 && item[SelItem].type!=PICT? MF_ENABLED : MF_GRAYED); EnableMenuItem(hMenu,ID_CENTER_ITEM,SelItem>=0 && item[SelItem].type!=SECTION ? MF_ENABLED : MF_GRAYED); EnableMenuItem(hMenu,ID_DEL_ITEM,SelItem>=0 ? MF_ENABLED : MF_GRAYED); EnableMenuItem(hMenu,ID_EXPAND_HORZ,SelItem>=0 && item[SelItem].type==GROUP? MF_ENABLED : MF_GRAYED); EnableMenuItem(hMenu,ID_EXPAND_VERT,SelItem>=0 && item[SelItem].type==GROUP? MF_ENABLED : MF_GRAYED); EnableMenuItem(hMenu,ID_COMPRESS_HORZ,SelItem>=0 && item[SelItem].type==GROUP? MF_ENABLED : MF_GRAYED); EnableMenuItem(hMenu,ID_COMPRESS_VERT,SelItem>=0 && item[SelItem].type==GROUP? MF_ENABLED : MF_GRAYED); //**** Field Menu *** EnableMenuItem(hMenu,ID_EDIT_FLD ,CurField>=0 && field[CurField].type!=TYPE_PICT ? MF_ENABLED : MF_GRAYED); EnableMenuItem(hMenu,ID_EDIT_FLD_EXP,CurField>=0 && field[CurField].source==SRC_CALC ? MF_ENABLED : MF_GRAYED); //**** section menu Menu *** if (SelItem>=0 && item[SelItem].type==SECTION) CurSec=item[SelItem].section; else CurSec=-1; EnableMenuItem(hMenu,ID_SEC_EDIT,CurSec>=0 ? MF_ENABLED : MF_GRAYED); EnableMenuItem(hMenu,ID_SEC_SORT,CurSec>=SEC_HDR_LVL1 && CurSec<=SEC_HDR_LVL9 ? MF_ENABLED : MF_GRAYED); EnableMenuItem(hMenu,ID_SEC_BREAK,CurSec>=SEC_HDR_LVL1 && CurSec<=SEC_HDR_LVL9 ? MF_ENABLED : MF_GRAYED); EnableMenuItem(hMenu,ID_SEC_FILTER,CurSec>=0 ? MF_ENABLED : MF_GRAYED); //**** Line Menu *** EnableMenuItem(hMenu,ID_EDIT_LINE,SelItem>=0 && item[SelItem].type==LINE ? MF_ENABLED : MF_GRAYED); //**** Label Menu *** EnableMenuItem(hMenu,ID_EDIT_LABEL,SelItem>=0 && item[SelItem].type==LABEL ? MF_ENABLED : MF_GRAYED); //**** Picture Menu *** EnableMenuItem(hMenu,ID_PICT_FROM_CB, IsClipboardFormatAvailable(CF_BITMAP) ? MF_ENABLED : MF_GRAYED); //******* dialog field table options ****** DlgTableFull=TRUE; DlgTableEmpty=TRUE; for (i=0;i<MAX_DLGS;i++) { if (DlgField[i].InUse) DlgTableEmpty=FALSE; if (!DlgField[i].InUse) DlgTableFull=FALSE; } EnableMenuItem(hMenu,ID_INSERT_DLG , !DlgTableEmpty ? MF_ENABLED : MF_GRAYED); EnableMenuItem(hMenu,ID_DLG_CREATE , !DlgTableFull ? MF_ENABLED : MF_GRAYED); EnableMenuItem(hMenu,ID_DLG_MODIFY , !DlgTableEmpty ? MF_ENABLED : MF_GRAYED); EnableMenuItem(hMenu,ID_DLG_DELETE , !DlgTableEmpty ? MF_ENABLED : MF_GRAYED); //**** Arrange Menu *** EnableMenuItem(GetSubMenu(hMenu,MENU_ARRANGE),0, SelItem>=0 && item[SelItem].type==GROUP? MF_ENABLED|MF_BYPOSITION : MF_GRAYED|MF_BYPOSITION); // align EnableMenuItem(GetSubMenu(hMenu,MENU_ARRANGE),1, SelItem>=0 && item[SelItem].type==GROUP? MF_ENABLED|MF_BYPOSITION : MF_GRAYED|MF_BYPOSITION); // even space EnableMenuItem(GetSubMenu(hMenu,MENU_ARRANGE),2, SelItem>=0 && item[SelItem].type==GROUP? MF_ENABLED|MF_BYPOSITION : MF_GRAYED|MF_BYPOSITION); // even size EnableMenuItem(hMenu,ID_UNDO, UndoItem ? MF_ENABLED : MF_GRAYED); return TRUE; } /****************************************************************************** FrTranslateAccelerator: Translates the accelerator keys for the form editor window ******************************************************************************/ BOOL FrTranslateAccelerator(HWND hWnd,UINT message,WPARAM wParam,LPARAM lParam) { MSG msg; if ( message==WM_NCHITTEST || message==WM_MOUSEMOVE || message==WM_SETCURSOR) return FALSE; if (!hFrAccTable) return FALSE; // translation table not defined yet msg.hwnd=hWnd; // fill the message structure msg.message=message; msg.wParam=wParam; msg.lParam=lParam; msg.time=0; msg.pt.x=msg.pt.y=0; if (TranslateAccelerator(hWnd,hFrAccTable,&msg)) { // accelerator tranlated // remove any messages generated by the TranslateMessage function in WinMain while (PeekMessage(&msg,hWnd,WM_CHAR,WM_CHAR,PM_REMOVE|PM_NOYIELD)); while (PeekMessage(&msg,hWnd,WM_INITMENU,WM_INITMENUPOPUP,PM_REMOVE|PM_NOYIELD)); while (PeekMessage(&msg,hWnd,WM_MENUSELECT,WM_MENUCHAR,PM_REMOVE|PM_NOYIELD)); while (PeekMessage(&msg,hWnd,WM_SYSKEYDOWN,WM_SYSKEYDOWN,PM_REMOVE|PM_NOYIELD)); while (PeekMessage(&msg,hWnd,WM_SYSKEYUP,WM_SYSKEYUP,PM_REMOVE|PM_NOYIELD)); while (PeekMessage(&msg,hWnd,WM_SYSCOMMAND,WM_SYSCOMMAND,PM_REMOVE|PM_NOYIELD)); while (PeekMessage(&msg,hWnd,WM_SYSCHAR,WM_SYSCHAR,PM_REMOVE|PM_NOYIELD)); return TRUE; } else return FALSE; } /****************************************************************************** SetScrollBars: Set horizontal and vertical scroll bar positions *******************************************************************************/ SetScrollBars() { int ScrollPos; if (!UseScreen || SessionType=='R') return TRUE; // window not being used if (FrShowVerBar) { // check for any change in vertical bar status if (FrHeight==0) ScrollPos=0; else ScrollPos=VER_SCROLL_MIN+(int)((long)FrWinOrgY*(VER_SCROLL_MAX-VER_SCROLL_MIN)/FrHeight); if (ScrollPos!=VerScrollPos) { // redraw VerScrollPos=ScrollPos; SetScrollPos(hFrWnd,SB_VERT,VerScrollPos,TRUE); } } if (FrShowHorBar) { // check for any change in horizontal bar status if (FrWidth==0) ScrollPos=0; else ScrollPos=HOR_SCROLL_MIN+(int)((long)FrWinOrgX*(HOR_SCROLL_MAX-HOR_SCROLL_MIN)/FrWidth); if (ScrollPos!=HorScrollPos) { // redraw HorScrollPos=ScrollPos; SetScrollPos(hFrWnd,SB_HORZ,HorScrollPos,TRUE); } } return TRUE; } /****************************************************************************** RepaintFr: This routine is called when a paint message is received. This routine repaint the entire client area. *******************************************************************************/ RepaintFr() { PAINTSTRUCT PaintData; BeginPaint(hFrWnd,&PaintData); EndPaint(hFrWnd,&PaintData); if (WindowBeingCreated) return TRUE; GetWinDimension(); // get window dimensions PaintFlag=PAINT_WIN; // paint the entire window FrPaint(); return TRUE; } /****************************************************************************** GetWinDimension: The the following dimensions of the various screen areas. *******************************************************************************/ void GetWinDimension() { int width,height; RECT rect; //****************** get window dimensions in logical units ********* GetClientRect(hFrWnd,(LPRECT) &rect); width = PixToUnitX(rect.right); height = PixToUnitY(rect.bottom); // *********** calculate input area coordinates ********************* InputRect.left=0; InputRect.top=0; InputRect.right=width; InputRect.bottom=InputRect.top+FrFont[DEFAULT_CFMT].height*2; // *********** calculate ruler area coordinates ********************* RulerRect.left=0; RulerRect.top=InputRect.bottom; RulerRect.right=width; if (FormHdr.RulerType==RULER_OFF) RulerRect.bottom=RulerRect.top; else RulerRect.bottom=RulerRect.top+FrFont[DEFAULT_CFMT].height + RULER_MARK1_LEN; // *********** calculate form area coordinates ********************* FrWinRect.left=0; FrWinRect.top=RulerRect.bottom; FrWinRect.right=width; FrWinRect.bottom=height; if (FrWinRect.bottom<FrWinRect.top) FrWinRect.bottom=FrWinRect.top; FrWinWidth=FrWinRect.right-FrWinRect.left+1; // form window width FrWinHeight=FrWinRect.bottom-FrWinRect.top+1; // form window height // ********* calculate form area rectangle in pixel units FrRect.left=UnitToPixX(FrWinRect.left); FrRect.right=rect.right; FrRect.top=UnitToPixY(FrWinRect.top); FrRect.bottom=rect.bottom; // ******* Create the memory device if (hBM) { // delete current bitmap SelectObject(hMemDC,hOldBM); DeleteObject(hBM); } if (NULL==(hBM=CreateCompatibleBitmap(hFrDC,rect.right,rect.bottom)) ) { AbortFr("Unable to create compatible DC",ERR_DISPLAY); } hOldBM=SelectObject(hMemDC,hBM); // set view port origin SetViewportOrgEx(hFrDC,FrRect.left,FrRect.top,NULL); // set view port origins SetViewportOrgEx(hMemDC,FrRect.left,FrRect.top,NULL); // set view port origins } /****************************************************************************** FrSetViewWindow: Set the portion of the form that will be visible in the view port. *******************************************************************************/ void FrSetViewWindow() { if (FrWinOrgX<0) FrWinOrgX=0; if (FrWinOrgY<0) FrWinOrgY=0; if (SessionType=='F') { // check limit during editing if (FrWinOrgX>FrWidth) FrWinOrgX=FrWidth; if (FrWinOrgY>FrHeight) FrWinOrgY=FrHeight; } SetWindowOrgEx(hFrDC,FrWinOrgX,FrWinOrgY,NULL); // set the logical window origin SetWindowOrgEx(hMemDC,FrWinOrgX,FrWinOrgY,NULL); // set the logical window origin } /****************************************************************************** FrPaint: Main FORM window paint routine *******************************************************************************/ void FrPaint() { RECT rect,iRect; HRGN rgn; int i; BOOL SaveFocusRectDrawn; if (!PaintEnabled) return; // painting disabled SaveFocusRectDrawn=FocusRectDrawn; // save the status of the focus rectangle FocusRectDrawn=FALSE; // focus rectangle will be erased // promote the scope of painting when a section selected if (SelItem>=0 && item[SelItem].type==SECTION && PaintFlag!=PAINT_WIN) PaintFlag=PAINT_PARTIAL_WIN; FrSetViewWindow(); // set the window origin // clear the ruler and drawing area SelectClipRgn(hMemDC,NULL); // entire client are enabled for drawing rect.left=FrWinOrgX; // build the drawing area rectangle rect.right=rect.left+FrWinWidth; rect.top=FrWinOrgY; rect.bottom=FrWinOrgY+FrWinHeight; if (PaintFlag==PAINT_WIN) { // redraw the whole screen // clear the input area iRect.left=FrWinOrgX; // build the input area rectangle iRect.right=iRect.left+FrWinWidth; iRect.top=FrWinOrgY-FrWinRect.top; iRect.bottom=iRect.top+(InputRect.bottom-InputRect.top); FillRect(hMemDC,&iRect,hInputAreaBrush); // Clear the ruler and drawing area rect.top-=(RulerRect.bottom-RulerRect.top); FillRect(hMemDC,&rect,hBackBrush); rect.top=iRect.top; // include the input area DrawOptRects(hMemDC); // draw option rectangles DrawDividers(hMemDC); // draw the divider lines DrawTopRuler(hMemDC); // draw the top ruler } else if (PaintFlag==PAINT_PARTIAL_WIN){// paint the ruler and the drawing area rect.top-=(RulerRect.bottom-RulerRect.top); FillRect(hMemDC,&rect,hBackBrush); DrawDividers(hMemDC); // draw the divider lines DrawTopRuler(hMemDC); // draw the ruler } else FillRect(hMemDC,&rect,hBackBrush);// paint just the drawing area // Set clipping region to include only the drawing area (default mode) rgn=CreateRectRgn(FrRect.left,FrRect.top,FrRect.right,FrRect.bottom); SelectClipRgn(hMemDC,rgn); // Draw screen items for (i=0;i<TotalItems;i++) DrawItem(hMemDC,i); // Copy the memory bitmap to the device SelectClipRgn(hFrDC,NULL); BitBlt(hFrDC,rect.left,rect.top,rect.right-rect.left,rect.bottom-rect.top,hMemDC,rect.left,rect.top,SRCCOPY); SelectClipRgn(hFrDC,rgn); // highlight the selected item if (SelItem>=0) SelectItem(SelItem); if (SaveFocusRectDrawn || SelItem>=0) FrDrawFocusRect(hFrDC,&CursRect); // redraw the focus rectangle // reset flags PaintFlag=PAINT_PARTIAL_WIN; // reset the paint flag DeleteObject(rgn); // delete the temporary region if (FrShowHorBar || FrShowVerBar) SetScrollBars(); ValidateRect(hFrWnd,NULL); // remove any pending paint messages } /****************************************************************************** DrawItem: Draw the specified item *******************************************************************************/ void DrawItem(HDC hDC,int CurItem) { RECT rect; HPEN hPen; HBRUSH hBrush; // Do not draw items that are outside the current window if (item[CurItem].x>FrWinOrgX+FrWinWidth) return; if (item[CurItem].x+item[CurItem].width<FrWinOrgX) return; if (item[CurItem].y>FrWinOrgY+FrWinHeight) return; if (item[CurItem].y+item[CurItem].height<FrWinOrgY) return; // build the rectangle rect.left=item[CurItem].x; rect.right=item[CurItem].x+item[CurItem].width; rect.top=item[CurItem].y; rect.bottom=item[CurItem].y+item[CurItem].height; // fill rectangle if needed if (item[CurItem].flags&OFLAG_FILL && item[CurItem].type!=GROUP) { // fill rectangle if (NULL!=(hBrush=CreateBrushIndirect(&(item[CurItem].brush)))) { FillRect(hDC,&rect,hBrush); DeleteObject(hBrush); // delete the temporary brush } } // draw the bounding rectangle if (item[CurItem].type==GROUP) { // draw the multiple selection rectangle if (CurItem==SelItem) { // Group item selected SelectObject(hDC,hSelectionPen); FrDrawRect(hDC,&rect); } } else if (item[CurItem].OutlineSelect) {// draw rectangle if (NULL!=(hPen=CreatePen(item[CurItem].OutlineStyle,item[CurItem].OutlineWidth,item[CurItem].OutlineColor))) { SelectObject(hDC,hPen); FrDrawOutline(hDC,&rect,item[CurItem].OutlineSelect); SelectObject(hDC,hFrPen); DeleteObject(hPen); // delete the temporary pen } } // draw the item interior if (item[CurItem].type==SECTION) DrawSection(hDC,CurItem); else if (item[CurItem].type==LABEL) DrawLabel(hDC,CurItem); else if (item[CurItem].type==FIELD) DrawField(hDC,CurItem); else if (item[CurItem].type==LINE) DrawLine(hDC,CurItem); else if (item[CurItem].type==PICT) DrawPicture(hDC,CurItem); // draw focus pen if this item is part of multiple selection item if (InGroup(CurItem)) { SelectObject(hDC,hFocusPen); FrDrawRect(hDC,&rect); } } /****************************************************************************** DrawLabel: Draw a label *******************************************************************************/ void DrawLabel(HDC hDC, int CurItem) { RECT rect; int LabelWidth,LabelHeight,LabelLen,x,y,flags,font; // build the bounding rectangle rect.left=item[CurItem].x; rect.right=item[CurItem].x+item[CurItem].width; rect.top=item[CurItem].y; rect.bottom=item[CurItem].y+item[CurItem].height; // Get label dimension font=item[CurItem].font; LabelWidth=GetLabelLen(item[CurItem].label,font); LabelHeight=FrFont[font].height; LabelLen=lstrlen(item[CurItem].label); // Get the label position flags=item[CurItem].flags; if (flags&OFLAG_HLEFT) x=rect.left+DESC_MARGIN; else if (flags&OFLAG_HRIGHT) x=rect.left+(item[CurItem].width-LabelWidth)-DESC_MARGIN; else x=rect.left+(item[CurItem].width-LabelWidth)/2; // center if (flags&OFLAG_VTOP) y=rect.top; else if (flags&OFLAG_VBOTTOM)y=rect.top+(item[CurItem].height-LabelHeight); else y=rect.top+(item[CurItem].height-LabelHeight)/2; // center // Draw the label SetFont(hDC,(BYTE)font); SetTextColor(hDC,item[CurItem].TextColor); SetBkMode(hDC,TRANSPARENT); if (LabelLen>0) ExtTextOut(hDC,x,y,ETO_CLIPPED,&rect,item[CurItem].label,LabelLen,NULL); } /****************************************************************************** DrawField: Draw a field item *******************************************************************************/ void DrawField(HDC hDC, int CurItem) { RECT rect; int LabelWidth,LabelHeight,LabelLen,x,y,flags,font; struct StrField huge *pField; BOOL wrap=FALSE; pField=&(field[item[CurItem].field]); // pointer to current field if (pField->type==TYPE_PICT) return; // picture field is left empty if (pField->type==TYPE_TEXT && (pField->flags)&(FLAG_WRAP|FLAG_WORD_WRAP)) wrap=TRUE; // build the bounding rectangle rect.left=item[CurItem].x; rect.right=item[CurItem].x+item[CurItem].width; rect.top=item[CurItem].y; rect.bottom=item[CurItem].y+item[CurItem].height; // Get label dimension font=item[CurItem].font; LabelWidth=GetLabelLen(item[CurItem].label,font); LabelHeight=FrFont[font].height; LabelLen=lstrlen(item[CurItem].label); if (LabelLen==0) return; // Get the label X position flags=item[CurItem].flags; if (flags&OFLAG_HLEFT) x=rect.left+DESC_MARGIN; else if (flags&OFLAG_HRIGHT) x=rect.left+(item[CurItem].width-LabelWidth)-DESC_MARGIN; else x=rect.left+(item[CurItem].width-LabelWidth)/2; // center if (wrap) y=rect.top+(DEF_RECT_HEIGHT-CharHeight)/2-1; else { if (flags&OFLAG_VTOP) y=rect.top; else if (flags&OFLAG_VBOTTOM)y=rect.top+(item[CurItem].height-LabelHeight); else y=rect.top+(item[CurItem].height-LabelHeight)/2; // center } // Draw the label SetFont(hDC,(BYTE)font); SetTextColor(hDC,item[CurItem].TextColor); SetBkMode(hDC,TRANSPARENT); if (wrap) { // print multiple lines while (y+LabelHeight<rect.bottom) { ExtTextOut(hDC,x,y,ETO_CLIPPED,&rect,item[CurItem].label,LabelLen,NULL); y+=LabelHeight; // position for the next line } } else ExtTextOut(hDC,x,y,ETO_CLIPPED,&rect,item[CurItem].label,LabelLen,NULL); } /****************************************************************************** DrawLine: Draw a 'line' type item *******************************************************************************/ void DrawLine(HDC hDC, int CurItem) { int x1,y1,x2,y2; HPEN hPen; // build the line beginning and ending coordinates if (item[CurItem].LineAngle==ANGLE_HORZ) { // horizontal line x1=item[CurItem].x; y1=item[CurItem].y+item[CurItem].height/2; x2=x1+item[CurItem].width; y2=y1; } else if (item[CurItem].LineAngle==ANGLE_VERT) { // vertical line x1=item[CurItem].x+item[CurItem].width/2; y1=item[CurItem].y; x2=x1; y2=y1+item[CurItem].height; } else if (item[CurItem].LineAngle==ANGLE_FDIAG) { // diagonal line x1=item[CurItem].x; y1=item[CurItem].y; x2=x1+item[CurItem].width; y2=y1+item[CurItem].height; } else { // backword diagonal line x1=item[CurItem].x; y1=item[CurItem].y+item[CurItem].height; x2=x1+item[CurItem].width; y2=item[CurItem].y; } // create the line pen if (NULL!=(hPen=CreatePen(item[CurItem].LineStyle,item[CurItem].LineWidth,item[CurItem].LineColor))) { SelectObject(hDC,hPen); // draw the line MoveToEx(hDC,x1,y1,NULL); LineTo(hDC,x2,y2); SelectObject(hDC,hFrPen); DeleteObject(hPen); // delete the temporary pen } } /****************************************************************************** DrawPicture: Draw a picture bitmap *******************************************************************************/ void DrawPicture(HDC hDC, int CurItem) { HBITMAP hOldBM,hCurBM; int width,height,pict; pict=item[CurItem].font; // index into the font structure width=FrFont[pict].CharWidth['_']; // width and height of the picture height=FrFont[pict].height; hCurBM=FrFont[pict].hBM; if (NULL!=(hOldBM=SelectObject(hPictDC,hCurBM))) { StretchBlt(hDC,item[CurItem].x,item[CurItem].y,item[CurItem].width,item[CurItem].height,hPictDC,0,0,width,height,SRCCOPY); SelectObject(hPictDC,hOldBM); // deselect the bitmap } } /****************************************************************************** DrawSection: Draw the specified section boundaries *******************************************************************************/ void DrawSection(HDC hDC,int CurItem) { int CurSec,NameLen,NameX,CharCount; RECT rect; // Draw the bounding rectangle for visual aid if section does not have outlines if (!item[CurItem].OutlineSelect) { SelectObject(hDC,hFrPen); // select default pen MoveToEx(hDC,item[CurItem].x,item[CurItem].y,NULL); LineTo(hDC,item[CurItem].x+item[CurItem].width,item[CurItem].y); LineTo(hDC,item[CurItem].x+item[CurItem].width,item[CurItem].y+item[CurItem].height); LineTo(hDC,item[CurItem].x,item[CurItem].y+item[CurItem].height); LineTo(hDC,item[CurItem].x,item[CurItem].y); } // build the section banner rectangle CurSec=item[CurItem].section; rect.left=item[CurItem].x; rect.right=item[CurItem].x+item[CurItem].width; rect.top=item[CurItem].y; rect.bottom=item[CurItem].y+FormHdr.SecBannerHeight; if (rect.left<FrWinOrgX) rect.left=FrWinOrgX; if (rect.right>FrWinOrgX+FrWinWidth) rect.right=FrWinOrgX+FrWinWidth; if (rect.right<=rect.left) return; // center the section description NameLen=GetLabelLen(SectionName[CurSec],DEFAULT_CFMT); CharCount=lstrlen(SectionName[CurSec]); NameX=rect.left+(rect.right-rect.left-NameLen)/2; if (NameX<rect.left) CharCount=0; // Select font and print the label SetFont(hDC,DEFAULT_CFMT); SetTextColor(hDC,BackColor); SetBkColor(hDC,DrawColor); ExtTextOut(hDC,NameX,rect.top+(FormHdr.SecBannerHeight-CharHeight)/2,ETO_CLIPPED|ETO_OPAQUE,&rect,SectionName[CurSec],CharCount,NULL); SetTextColor(hDC,DrawColor); // reset to regular colors SetBkColor(hDC,BackColor); // Draw the left and right rulers if (item[CurItem].x>FrWinOrgX) DrawSideRuler(hDC,TRUE,CurItem); if (item[CurItem].x+item[CurItem].width<FrWinOrgX+FrWinWidth) DrawSideRuler(hDC,FALSE,CurItem); } /****************************************************************************** DrawDividers: Draw the dividers lines for the input and ruler areas *******************************************************************************/ void DrawDividers(HDC hDC) { int y; // ******************* select pen ************** SelectObject(hDC,hFrPen); // general purpose pen // ***************** draw the line above the ruler *********** y=FrWinOrgY-(RulerRect.bottom-RulerRect.top); MoveToEx(hDC,FrWinOrgX,y,NULL); LineTo(hDC,FrWinOrgX+FrWinWidth,y); // ***************** draw the line below the ruler *********** y=FrWinOrgY; MoveToEx(hDC,FrWinOrgX,y,NULL); LineTo(hDC,FrWinOrgX+FrWinWidth,y); } /****************************************************************************** DrawOptRects: Draw the option rectangles *******************************************************************************/ void DrawOptRects(HDC hDC) { int i,TotalWidth,LabelWidth,DataWidth,CalcWidth,SysWidth,DlgWidth,LineWidth, FieldWidth,x,TopY,BotY; HBRUSH hBrush; // Get the widths of the option rectangles LabelWidth=GetLabelLen(OPT_LBL_LABEL,DEFAULT_CFMT)+2*DESC_MARGIN; DataWidth=GetLabelLen(OPT_LBL_DATA,DEFAULT_CFMT)+2*DESC_MARGIN; CalcWidth=GetLabelLen(OPT_LBL_CALC,DEFAULT_CFMT)+2*DESC_MARGIN; SysWidth=GetLabelLen(OPT_LBL_SYS,DEFAULT_CFMT)+2*DESC_MARGIN; DlgWidth=GetLabelLen(OPT_LBL_DLG,DEFAULT_CFMT)+2*DESC_MARGIN; LineWidth=GetLabelLen(OPT_LBL_LINE,DEFAULT_CFMT)+2*DESC_MARGIN; FieldWidth=DataWidth+CalcWidth+SysWidth+DlgWidth; TotalWidth=LabelWidth+FieldWidth+LineWidth+CharHeight; // check if we have space for the option rectangle and the input control if (TotalWidth+DESC_WIDTH+CharHeight>FrWinWidth) { DrawOptRect=FALSE; return; } else DrawOptRect=TRUE; // calculate the dimension relative to the window top/left x=FrWinWidth-TotalWidth; // beginning x position TopY=InputRect.top; BotY=InputRect.bottom; // label rectangle OptRect[OPT_LABEL].top=TopY; OptRect[OPT_LABEL].bottom=BotY; OptRect[OPT_LABEL].left=x; OptRect[OPT_LABEL].right=x=x+LabelWidth; // data field rectangle OptRect[OPT_DATA].top=TopY+CharHeight; OptRect[OPT_DATA].bottom=BotY; OptRect[OPT_DATA].left=x; OptRect[OPT_DATA].right=x=x+DataWidth; // calculation field rectangle OptRect[OPT_CALC].top=TopY+CharHeight; OptRect[OPT_CALC].bottom=BotY; OptRect[OPT_CALC].left=x; OptRect[OPT_CALC].right=x=x+CalcWidth; // system field rectangle OptRect[OPT_SYS].top=TopY+CharHeight; OptRect[OPT_SYS].bottom=BotY; OptRect[OPT_SYS].left=x; OptRect[OPT_SYS].right=x=x+SysWidth; // dialog field rectangle OptRect[OPT_DLG].top=TopY+CharHeight; OptRect[OPT_DLG].bottom=BotY; OptRect[OPT_DLG].left=x; OptRect[OPT_DLG].right=x=x+DlgWidth; // Line rectangle OptRect[OPT_LINE].top=TopY; OptRect[OPT_LINE].bottom=BotY; OptRect[OPT_LINE].left=x; OptRect[OPT_LINE].right=x+LineWidth; // Field label rectangle OptRect[OPT_FIELD].top=TopY; OptRect[OPT_FIELD].bottom=OptRect[OPT_DATA].top; OptRect[OPT_FIELD].left=OptRect[OPT_DATA].left; OptRect[OPT_FIELD].right=OptRect[OPT_DLG].right; // translate the rectangle dimensions to current window origin and draw hBrush=CreateSolidBrush(OptRectColor); SelectObject(hDC,hFrPen); for (i=0;i<MAX_OPTS;i++) { OptRect[i].top=FrWinOrgY+OptRect[i].top-FrWinRect.top; OptRect[i].bottom=FrWinOrgY+OptRect[i].bottom-FrWinRect.top; OptRect[i].left=FrWinOrgX+OptRect[i].left; OptRect[i].right=FrWinOrgX+OptRect[i].right; FillRect(hDC,&OptRect[i],hBrush); FrDrawRect(hDC,&OptRect[i]); } DeleteObject(hBrush); // write the option labels SetFont(hDC,(BYTE)DEFAULT_CFMT); SetTextColor(hDC,BackColor); SetBkMode(hDC,TRANSPARENT); // write the label text ExtTextOut(hDC,OptRect[OPT_LABEL].left+DESC_MARGIN,OptRect[OPT_LABEL].top+CharHeight,ETO_CLIPPED,&OptRect[OPT_LABEL],OPT_LBL_LABEL,lstrlen(OPT_LBL_LABEL),NULL); ExtTextOut(hDC,OptRect[OPT_DATA].left+DESC_MARGIN,OptRect[OPT_DATA].top,ETO_CLIPPED,&OptRect[OPT_DATA],OPT_LBL_DATA,lstrlen(OPT_LBL_DATA),NULL); ExtTextOut(hDC,OptRect[OPT_CALC].left+DESC_MARGIN,OptRect[OPT_CALC].top,ETO_CLIPPED,&OptRect[OPT_CALC],OPT_LBL_CALC,lstrlen(OPT_LBL_CALC),NULL); ExtTextOut(hDC,OptRect[OPT_SYS].left+DESC_MARGIN,OptRect[OPT_SYS].top,ETO_CLIPPED,&OptRect[OPT_SYS],OPT_LBL_SYS,lstrlen(OPT_LBL_SYS),NULL); ExtTextOut(hDC,OptRect[OPT_DLG].left+DESC_MARGIN,OptRect[OPT_DLG].top,ETO_CLIPPED,&OptRect[OPT_DLG],OPT_LBL_DLG,lstrlen(OPT_LBL_DLG),NULL); ExtTextOut(hDC,OptRect[OPT_LINE].left+DESC_MARGIN,OptRect[OPT_LINE].top+CharHeight,ETO_CLIPPED,&OptRect[OPT_LINE],OPT_LBL_LINE,lstrlen(OPT_LBL_LINE),NULL); // write the field header x=OptRect[OPT_FIELD].left+(FieldWidth-GetLabelLen(OPT_LBL_FIELD,DEFAULT_CFMT))/2; ExtTextOut(hDC,x,OptRect[OPT_FIELD].top,ETO_CLIPPED,&OptRect[OPT_FIELD],OPT_LBL_FIELD,lstrlen(OPT_LBL_FIELD),NULL); } /****************************************************************************** DrawTopRuler: Draw the ruler on the top of the window *******************************************************************************/ void DrawTopRuler(HDC hDC) { int y1,y2,count,len; float x,interval; char string[10]; if (FormHdr.RulerType==RULER_OFF) return; // ******************* select pen, font, color etc ************** SelectObject(hDC,hFrPen); // general purpose pen SetFont(hDC,DEFAULT_CFMT); // use the default font SetTextColor(hDC,DrawColor); SetBkMode(hDC,TRANSPARENT); // ************ Print the ruler line ************************* y1=FrWinOrgY-RULER_MARK1_LEN; MoveToEx(hDC,FrWinOrgX,y1,NULL); LineTo(hDC,FrWinOrgX+FrWinWidth,y1); // ***************** draw ruler marks ************************* if (FormHdr.RulerType==RULER_INCH) { // draw inch ruler // draw the inch marks interval=x=(float)UNITS_PER_INCH; y2=FrWinOrgY; count=1; // start with one inch while (x<=FrWidth) { MoveToEx(hDC,(int)x,y1,NULL); LineTo(hDC,(int)x,y2); // print inch label wsprintf(string,"%d",count); len=GetLabelLen(string,DEFAULT_CFMT); // get the length of the label in logical units TextOut(hDC,(int)(x-len/2),y1-CharHeight,string,lstrlen(string)); // increment to next inch x+=interval; count++; } // close the ruler MoveToEx(hDC,FrWidth,y1,NULL); LineTo(hDC,FrWidth,y2); // draw the half marks interval=x=(float)UNITS_PER_INCH/2; y2=y1+RULER_MARK2_LEN; while (x<FrWidth) { MoveToEx(hDC,(int)x,y1,NULL); LineTo(hDC,(int)x,y2); x+=interval; } // draw the 1/8 marks interval=x=(float)UNITS_PER_INCH/8; y2=y1+RULER_MARK3_LEN; while (x<FrWidth) { MoveToEx(hDC,(int)x,y1,NULL); LineTo(hDC,(int)x,y2); x+=interval; } } else { // draw centimeter ruler // draw the centimeter marks interval=x=((float)UNITS_PER_INCH*10)/25; y2=FrWinOrgY; count=1; // start with one cm while (x<=FrWidth) { MoveToEx(hDC,(int)x,y1,NULL); LineTo(hDC,(int)x,y2); // print inch label wsprintf(string,"%d",count); len=GetLabelLen(string,DEFAULT_CFMT); // get the length of the label in logical units TextOut(hDC,(int)(x-len/2),y1-CharHeight,string,lstrlen(string)); // increment to next cm x+=interval; count++; } // close the ruler MoveToEx(hDC,FrWidth,y1,NULL); LineTo(hDC,FrWidth,y2); // draw the half marks interval=x=((float)UNITS_PER_INCH*10)/50; y2=y1+RULER_MARK2_LEN; while (x<FrWidth) { MoveToEx(hDC,(int)x,y1,NULL); LineTo(hDC,(int)x,y2); x+=interval; } // draw the 1/10 marks interval=x=((float)UNITS_PER_INCH*10)/250; y2=y1+RULER_MARK3_LEN; while (x<FrWidth) { MoveToEx(hDC,(int)x,y1,NULL); LineTo(hDC,(int)x,y2); x+=interval; } } return; } /****************************************************************************** DrawSideRuler: Draw the ruler on the left or right side of the given section *******************************************************************************/ void DrawSideRuler(HDC hDC,BOOL left, int CurSec) { int y1,x1,x2,LastY,count,len; float y,interval; char string[10]; if (FormHdr.RulerType==RULER_OFF) return; // ******************* select pen, font, color etc ************** SelectObject(hDC,hFrPen); // general purpose pen SetFont(hDC,DEFAULT_CFMT); // use the default font SetTextColor(hDC,DrawColor); SetBkMode(hDC,TRANSPARENT); // ************ Print the ruler line ************************* if (left) x1=item[CurSec].x-RULER_MARK1_LEN; else x1=item[CurSec].x+item[CurSec].width+RULER_MARK1_LEN; y1=item[CurSec].y+CharHeight; LastY=item[CurSec].y+item[CurSec].height; // last y position MoveToEx(hDC,x1,y1,NULL); LineTo(hDC,x1,LastY); // ***************** draw ruler marks ************************* if (FormHdr.RulerType==RULER_INCH) {// draw inch ruler // draw the inch marks interval=(float)UNITS_PER_INCH; if (left) x2=item[CurSec].x; // ending x position else x2=item[CurSec].x+item[CurSec].width; y=(float)y1; // starting y position count=0; // start with one inch while (y<=LastY) { MoveToEx(hDC,x1,(int)y,NULL); LineTo(hDC,x2,(int)y); // print inch label wsprintf(string,"%d",count); len=GetLabelLen(string,DEFAULT_CFMT); // get the length of the label in logical units if (left) TextOut(hDC,x1-len,(int)(y-CharHeight/2),string,lstrlen(string)); else TextOut(hDC,x1,(int)(y-CharHeight/2),string,lstrlen(string)); // increment to next inch y+=interval; count++; } // close the ruler MoveToEx(hDC,x1,LastY,NULL); LineTo(hDC,x2,LastY); // draw the half marks interval=(float)UNITS_PER_INCH/2; y=(float)y1+interval; // starting y position if (left) x2=x1+RULER_MARK2_LEN; else x2=x1-RULER_MARK2_LEN; while (y<=LastY) { MoveToEx(hDC,x1,(int)y,NULL); LineTo(hDC,x2,(int)y); y+=interval; } // draw the 1/8 marks interval=(float)UNITS_PER_INCH/8; y=(float)y1+interval; // starting y position if (left) x2=x1+RULER_MARK3_LEN; else x2=x1-RULER_MARK3_LEN; while (y<=LastY) { MoveToEx(hDC,x1,(int)y,NULL); LineTo(hDC,x2,(int)y); y+=interval; } } else { // draw centimeter ruler // draw the centimeter marks interval=((float)UNITS_PER_INCH*(float)10)/25; if (left) x2=item[CurSec].x; // ending x position else x2=item[CurSec].x+item[CurSec].width; y=(float)y1; // starting y position count=0; // start with one inch while (y<=LastY) { MoveToEx(hDC,x1,(int)y,NULL); LineTo(hDC,x2,(int)y); // print inch label wsprintf(string,"%d",count); len=GetLabelLen(string,DEFAULT_CFMT); // get the length of the label in logical units if (left) TextOut(hDC,x1-len,(int)(y-CharHeight/2),string,lstrlen(string)); else TextOut(hDC,x1,(int)(y-CharHeight/2),string,lstrlen(string)); // increment to next cm y+=interval; count++; } // close the ruler MoveToEx(hDC,x1,LastY,NULL); LineTo(hDC,x2,LastY); // draw the half marks interval=((float)UNITS_PER_INCH*(float)10)/50; y=(float)y1+interval; // starting y position if (left) x2=x1+RULER_MARK2_LEN; else x2=x1-RULER_MARK2_LEN; while (y<=LastY) { MoveToEx(hDC,x1,(int)y,NULL); LineTo(hDC,x2,(int)y); y+=interval; } // draw the 1/10 marks interval=((float)UNITS_PER_INCH*(float)10)/250; y=(float)y1+interval; // starting y position if (left) x2=x1+RULER_MARK3_LEN; else x2=x1-RULER_MARK3_LEN; while (y<=LastY) { MoveToEx(hDC,x1,(int)y,NULL); LineTo(hDC,x2,(int)y); y+=interval; } } return; } /****************************************************************************** InGroup: This routine return TRUE if the specified item is included in the multiple selection group. *******************************************************************************/ BOOL InGroup(int CurItem) { RECT GroupRect,CurRect; BOOL inside=TRUE; if (SelItem<0 || item[SelItem].type!=GROUP) return FALSE; // group not active if (item[CurItem].type==GROUP) return FALSE; // exclude group item iteself if (item[CurItem].type==SECTION) return FALSE; // exclude the section type items // build the group rectangle GroupRect.left=item[SelItem].x; GroupRect.right=GroupRect.left+item[SelItem].width; GroupRect.top=item[SelItem].y; GroupRect.bottom=GroupRect.top+item[SelItem].height; // build the current item rectangle CurRect.left=item[CurItem].x; CurRect.right=CurRect.left+item[CurItem].width; CurRect.top=item[CurItem].y; CurRect.bottom=CurRect.top+item[CurItem].height; // check if the item falls withing the group rectangle if (CurRect.right<GroupRect.left) inside=FALSE; if (CurRect.left>GroupRect.right) inside=FALSE; if (CurRect.bottom<GroupRect.top) inside=FALSE; if (CurRect.top>GroupRect.bottom) inside=FALSE; if (item[CurItem].flags&OFLAG_SELECT_TOGGLE) inside=!inside; return inside; } /****************************************************************************** SetFont: Select a suitable font for a character format into the display context *******************************************************************************/ SetFont(HDC hDC,unsigned char font) { HFONT hFont; if (FrFont[font].IsPict) return TRUE; // not a true font hFont=FrFont[font].hFont; SelectObject(hDC,hFont); return TRUE; } /****************************************************************************** FrMouseDown: Select an object, or position a moving object. *******************************************************************************/ FrMouseDown(WPARAM wParam,LPARAM lParam) { int i,x,y,CurItem; // calculate logical mouse position x=FrWinOrgX+PixToUnitX((int)(LOSHORT(lParam))-FrRect.left); y=FrWinOrgY+PixToUnitY((int)(HISHORT(lParam))-FrRect.top); // check if mouse outside the drawing area if ( HISHORT(lParam)<FrRect.top || y>FrHeight+TAB_HEIGHT/2) { // went outside the drawing area SetCursor(hArrowCursor); CurCmd=-1; // no more command being served IgnoreMouseMove=TRUE; // ignore mouse move now FrEraseFocusRect(hFrDC,&CursRect); FrPaint(); return TRUE; } // Process the command in progress switch (CurCmd) { case ID_INSERT_LABEL: // insert a label at the current position InsertLabelPartII(); // finish the label creation process break; case ID_INSERT_LINE: // insert a line at the current position InsertLinePartII(); // finish the line creation process break; case ID_PICT_FROM_CB: // insert the clipboard picture at the current position case ID_PICT_FROM_FILE: // insert the bitmap file picture at the current position InsertPicturePartII(); // finish the picture insertion process break; case ID_INSERT_DATA: // insert data field case ID_INSERT_CALC: // insert calculation field case ID_INSERT_SYS: // insert system field case ID_INSERT_DLG: // insert dialog field InsertFieldPartII(); // finish the field insertion process break; default: if (SelItem>=0) { // if on a selected item // Insert or remove this item form group selection if (item[SelItem].type==GROUP && GetKeyState(VK_SHIFT)&0x8000) { CurItem=GetMouseItem(x,y); // Get the item selected by the mouse if (!(item[CurItem].type&(SECTION|GROUP))) { if (item[CurItem].flags&OFLAG_SELECT_TOGGLE) item[CurItem].flags=ResetUintFlag(item[CurItem].flags,OFLAG_SELECT_TOGGLE); else item[CurItem].flags|=OFLAG_SELECT_TOGGLE; PaintFlag=PAINT_ITEMS; // restricted painting FrPaint(); // repaint the screen } CurCmd=-1; break; } // Check if a tab on a selected item is clicked for (i=0;i<TotalTabRects;i++) { if (TabRect[i].left==TabRect[i].right) continue; // tab not in use if ( x>=TabRect[i].left && x<TabRect[i].right && y>=TabRect[i].top && y<TabRect[i].bottom) break; } if (i<TotalTabRects) { // size the item CurTab=i; if (CurTab==TAB_NORTH || CurTab==TAB_SOUTH) SetCursor(hVertCursor); else if (CurTab==TAB_WEST || CurTab==TAB_EAST) SetCursor(hHorzCursor); else if (CurTab==TAB_NE || CurTab==TAB_SW) SetCursor(hDiagCursor); else if (CurTab==TAB_NW || CurTab==TAB_SE) SetCursor(hDiagBackCursor); CurCmd=ID_SIZE_ITEM; // initiate the sizing command IgnoreMouseMove=FALSE; // now monitor the mouse movement } else { // no tab selected CurItem=GetMouseItem(x,y); // Get the item selected by the mouse if (CurItem!=SelItem) { // new selection DeselectItem(); // deselect the previous selection SelItem=CurItem; PaintFlag=PAINT_ITEMS; // restricted painting FrPaint(); // repaint the screen } CurCmd=-1; // no command in progress IgnoreMouseMove=FALSE; // now monitor the mouse movement } } else { // find item to select SelItem=GetMouseItem(x,y); // Get the item selected by the mouse PaintFlag=PAINT_ITEMS; // restricted painting FrPaint(); // repaint the screen CurCmd=-1; IgnoreMouseMove=FALSE; // now monitor the mouse movement } } return TRUE; } /****************************************************************************** GetMouseItem: This function returns the item number which enclosed the given x and y position. When more than one item contain the given point, item with smallest area is selected *******************************************************************************/ GetMouseItem(int x,int y) { int i,CurItem; long MinArea,ItemArea; // save the mouse position MouseX=x; MouseY=y; // find the item where the mouse is positioned CurItem=-1; for (i=0;i<TotalItems;i++) { if (x<item[i].x || x>item[i].x+item[i].width) continue; // outside if (y<item[i].y || y>item[i].y+item[i].height) continue; // outside if (item[i].type==GROUP && item[i].width<=DESC_MARGIN && item[i].height<=DESC_MARGIN) continue; //no selection // compare the item area ItemArea=(long)item[i].width*(long)item[i].height; // check right side if (ItemArea<0) ItemArea=-ItemArea; if (CurItem<0) { // no item selected yet CurItem=i; MinArea=ItemArea; } else if (ItemArea<=MinArea) {// compare with the previously selected item CurItem=i; MinArea=ItemArea; } } if (CurItem<0) CurItem=0; return CurItem; } /****************************************************************************** GetMouseOpt: Get the option rectangle hit by the mouse *******************************************************************************/ GetMouseOpt(DWORD lParam) { int i,x,y; HRGN rgn; // calculate logical mouse position x=FrWinOrgX+PixToUnitX((int)(LOSHORT(lParam))-FrRect.left); y=FrWinOrgY+PixToUnitY((int)(HISHORT(lParam))-FrRect.top); // find the rectangle that is hit for (i=0;i<MAX_OPTS;i++) { if (x<OptRect[i].left || x>OptRect[i].right) continue; // outside if (y<OptRect[i].top || y>OptRect[i].bottom) continue; // outside break; } // highlight rectangle if a valid option selected if (i<MAX_OPTS-1) { SelectClipRgn(hFrDC,NULL); BitBlt(hFrDC,OptRect[i].left,OptRect[i].top, OptRect[i].right-OptRect[i].left,OptRect[i].bottom-OptRect[i].top, NULL,0,0,DSTINVERT); // reset clipping region to include only the drawing area (default mode) rgn=CreateRectRgn(FrRect.left,FrRect.top,FrRect.right,FrRect.bottom); SelectClipRgn(hFrDC,rgn); DeleteObject(rgn); // delete the temporary region } return i; } /****************************************************************************** FrMouseMove: Process the mouse movement. *******************************************************************************/ FrMouseMove(WPARAM wParam,LPARAM lParam) { int x,y,width,height; RECT NewRect; BOOL ButtonDown; MSG msg; // calculate logical mouse position x=FrWinOrgX+PixToUnitX((int)(LOSHORT(lParam))-FrRect.left); y=FrWinOrgY+PixToUnitY((int)(HISHORT(lParam))-FrRect.top); ButtonDown=wParam&(MK_LBUTTON|MK_RBUTTON|MK_MBUTTON); // True when one of the buttons are down // Begin the multiple item selection when mouse clicked in a 'section' type item if (CurCmd==-1) { if (ButtonDown && SelItem>=0) { if (item[SelItem].type==SECTION) return SelectGroupItemPartI(x,y); // begin multiple item selection else { CurCmd=ID_MOVE_ITEM; // start moving the selected item x=item[SelItem].x+item[SelItem].width/2; // set the mouse position y=item[SelItem].y+item[SelItem].height/2; // set the mouse position FrSetCursor(x,y); // remove any pending mouse move messages while (PeekMessage(&msg,hFrWnd,WM_MOUSEMOVE,WM_MOUSEMOVE,PM_REMOVE|PM_NOYIELD)); return TRUE; // move next time } } else return FrSetCursorShape(lParam); // no action } // check if mouse outside the drawing area if ( HISHORT(lParam)<FrRect.top) { // went outside the drawing area SetCursor(hArrowCursor); return TRUE; } // check for any mouse action outside the window if (CurCmd==ID_MOVE_ITEM || CurCmd==ID_SIZE_ITEM || CurCmd==ID_SELECT_MULTIPLE) { if (!ButtonDown) { // mouse status not acceptable CurCmd=-1; // reset current command IgnoreMouseMove=TRUE; SetCursor(hArrowCursor); return TRUE; } } // Set cursor shape if (CurCmd==ID_SIZE_ITEM) { if (CurTab==TAB_NORTH || CurTab==TAB_SOUTH) SetCursor(hVertCursor); else if (CurTab==TAB_WEST || CurTab==TAB_EAST) SetCursor(hHorzCursor); else if (CurTab==TAB_NE || CurTab==TAB_SW) SetCursor(hDiagCursor); else if (CurTab==TAB_NW || CurTab==TAB_SE) SetCursor(hDiagBackCursor); } else if (CurCmd==ID_SELECT_MULTIPLE) SetCursor(hArrowCursor); else SetCursor(hCrossCursor); // Calculate the new cursor position FarMove(&CursRect,&NewRect,sizeof(RECT)); if (CurCmd==ID_SIZE_ITEM || CurCmd==ID_SELECT_MULTIPLE) {// object being sized if (CurTab==TAB_NORTH) NewRect.top=y; else if (CurTab==TAB_SOUTH) NewRect.bottom=y; else if (CurTab==TAB_WEST) NewRect.left=x; else if (CurTab==TAB_EAST) NewRect.right=x; else if (CurTab==TAB_NW) { NewRect.left=x; NewRect.top=y; } else if (CurTab==TAB_NW) { NewRect.left=x; NewRect.top=y; } else if (CurTab==TAB_NE) { NewRect.right=x; NewRect.top=y; } else if (CurTab==TAB_SW) { NewRect.left=x; NewRect.bottom=y; } else if (CurTab==TAB_SE) { NewRect.right=x; NewRect.bottom=y; } } else { // object being moved width=CursRect.right-CursRect.left; // dimension of the current rectangle height=CursRect.bottom-CursRect.top; NewRect.left=x-width/2; NewRect.right=NewRect.left+width; NewRect.top=y-height/2; NewRect.bottom=NewRect.top+height; } // Check if the screen needs to scroll to show the new rectangle if (FrAdjustScroll(&NewRect)) FrSetCursor(x,y); // set the new mouse poisition // Erase the old rectangle FrEraseFocusRect(hFrDC,&CursRect); // Draw the new focus rectangle FarMove(&NewRect,&CursRect,sizeof(RECT)); FrDrawFocusRect(hFrDC,&CursRect); return TRUE; } /****************************************************************************** FrKeyMove: Move the selected item as the arrow keys are pressed. *******************************************************************************/ FrKeyMove(WPARAM wParam) { int delta,CurSec,SecItem; RECT rect,SecRect; MSG msg; if (SelItem<0 || item[SelItem].type==SECTION) return TRUE; // discard any addition key messages while (PeekMessage(&msg,hFrWnd,WM_KEYFIRST,WM_KEYLAST,PM_REMOVE|PM_NOYIELD));; delta=CharHeight/16; // amount of movement // build the new item position rect.left=item[SelItem].x; rect.top=item[SelItem].y; if (wParam==ID_UP) rect.top-=delta; else if (wParam==ID_DOWN) rect.top+=delta; else if (wParam==ID_LEFT) rect.left-=delta; else if (wParam==ID_RIGHT) rect.left+=delta; rect.right=rect.left+item[SelItem].width; rect.bottom=rect.top+item[SelItem].height; // make sure that the item remains within the section CurSec=item[SelItem].section; SecItem=section[CurSec].ScrItem; SecRect.top=item[SecItem].y+FormHdr.SecBannerHeight; SecRect.bottom=item[SecItem].y+item[SecItem].height; if (rect.top<=SecRect.top) return TRUE; // item heading out if (rect.bottom>=SecRect.bottom) return TRUE; // scroll the screen if necessary FrEraseFocusRect(hFrDC,&CursRect); FarMove(&rect,&CursRect,sizeof(RECT)); FrAdjustScroll(&CursRect); MoveItem(); // move the item to the new location return TRUE; } /****************************************************************************** FrSetCursorShape: The shape of the mouse cursor as it is being moved in the drawing area. *******************************************************************************/ int FrSetCursorShape(DWORD lParam) { int i,x,y,CurTab; if (SelItem<0) SetCursor(hArrowCursor); else { // check if cursor positioned on a tab // calculate logical mouse position x=FrWinOrgX+PixToUnitX((LOSHORT(lParam))-FrRect.left); y=FrWinOrgY+PixToUnitY((HISHORT(lParam))-FrRect.top); for (i=0;i<TotalTabRects;i++) { if (TabRect[i].left==TabRect[i].right) continue; // tab not in use if ( x>=TabRect[i].left && x<TabRect[i].right && y>=TabRect[i].top && y<TabRect[i].bottom) break; } if (i<TotalTabRects) { // size the item CurTab=i; if (CurTab==TAB_NORTH || CurTab==TAB_SOUTH) SetCursor(hVertCursor); else if (CurTab==TAB_WEST || CurTab==TAB_EAST) SetCursor(hHorzCursor); else if (CurTab==TAB_NE || CurTab==TAB_SW) SetCursor(hDiagCursor); else if (CurTab==TAB_NW || CurTab==TAB_SE) SetCursor(hDiagBackCursor); } else SetCursor(hArrowCursor); } return TRUE; } /****************************************************************************** FrSetCursor: Set the mouse cursor at the specified logical position (x and y). *******************************************************************************/ int FrSetCursor(int x,int y) { POINT pt; pt.x=UnitToPixX(x-FrWinOrgX)+FrRect.left; pt.y=UnitToPixY(y-FrWinOrgY)+FrRect.top; ClientToScreen(hFrWnd,&pt); SetCursorPos(pt.x,pt.y); return TRUE; } /****************************************************************************** FrAdjustCursorRect: Adjust the cursor rectangle position such that it completely falls within as section. This function returns the section which contains the item. *******************************************************************************/ int FrAdjustCursorRect() { int height,i,SecItem,CurSec,SecTop,SecBottom,temp; // normalize cursor coordinates if (CursRect.top>CursRect.bottom) { temp=CursRect.top; CursRect.top=CursRect.bottom; CursRect.bottom=temp; } if (CursRect.left>CursRect.right) { temp=CursRect.left; CursRect.left=CursRect.right; CursRect.right=temp; } // calculate rectangle height height=CursRect.bottom-CursRect.top; // find the section that includes the cursor rectangle CurSec=-1; for (i=0;i<TotalItems;i++) { if (item[i].type!=SECTION) continue; if (CursRect.top >=item[i].y && CursRect.top <=item[i].y+item[i].height) { SecItem=i; CurSec=item[i].section; } } if (CurSec==-1) { // select the first or the last section if (CursRect.top<0) { // select the first section for (i=0;i<TotalItems;i++) if (item[i].type==SECTION) break; } else { // select the last section for (i=TotalItems-1;i>=0;i--) if (item[i].type==SECTION) break; } if (i==TotalItems || i==-1) AbortFr("Error Section Selection",ERR_DISPLAY); SecItem=i; CurSec=item[i].section; } // do not try to fit the selection rectangle within a section if (CurCmd==ID_SELECT_MULTIPLE) return CurSec; // adjust the cursor rectangle if necessary SecTop=item[SecItem].y+FormHdr.SecBannerHeight; // subtract the banner height SecBottom=item[SecItem].y+item[SecItem].height; if (CursRect.bottom>SecBottom) { CursRect.bottom=SecBottom; CursRect.top=CursRect.bottom-height; } if (CursRect.top<=SecTop) { CursRect.top=SecTop+1; CursRect.bottom=CursRect.top+height; if (CursRect.bottom>SecBottom) CursRect.bottom=SecBottom; } return CurSec; } /****************************************************************************** FrFindItemSlot: This routine returns the sorted position of the cursor rectangle within the item array. The calling function should provide the section placement of the cursor rectangle. *******************************************************************************/ int FrFindItemSlot(int CurSec) { int i; for (i=0;i<TotalItems;i++) { if (item[i].type==SECTION && item[i].section>CurSec) break; // slot found if (item[i].y<CursRect.top) continue; if (item[i].y>CursRect.top) break; // slot found if (item[i].x<CursRect.left) continue; break; // slot found } return i; } /****************************************************************************** FrAdjustScroll: If necessary scroll the drawing area to keep the cursor rectangle in view. The first parameter specifies the new location of the cursor rectangle. This function returns a TRUE value if the scrolling was adjusted. *******************************************************************************/ int FrAdjustScroll(RECT far *rect) { int width,height,SaveOrg; BOOL paint=FALSE; if (SelItem>=0 && item[SelItem].type==SECTION) return FALSE; // not applicable to sections if (CurCmd==ID_SIZE_ITEM) return FALSE; // Check the horizontal direction if ( rect->right<=FrWinOrgX || rect->left>=FrWinOrgX+FrWinWidth) { width=rect->right-rect->left; if (width<FrWinWidth) { SaveOrg=FrWinOrgX; FrWinOrgX=rect->left-(FrWinWidth-width)/2; if (FrWinOrgX<0) FrWinOrgX=0; if (FrWinOrgX>FrWidth) FrWinOrgX=FrWidth; if (FrWinOrgX!=SaveOrg) paint=TRUE; } } // Check the vertical direction if ( rect->bottom<=FrWinOrgY || rect->top>=FrWinOrgY+FrWinHeight) { height=rect->bottom-rect->top; if (height<FrWinHeight) { SaveOrg=FrWinOrgY; FrWinOrgY=rect->top-(FrWinHeight-height)/2; if (FrWinOrgY<0) FrWinOrgY=0; if (FrWinOrgY!=SaveOrg) paint=TRUE; } } // refresh the screen if (paint) { PaintFlag=PAINT_WIN; FrPaint(); if (FrShowHorBar || FrShowVerBar) SetScrollBars(); return TRUE; } else return FALSE; } /****************************************************************************** DeselectItem: Deselect the currently selected item. *******************************************************************************/ int DeselectItem() { int i; if (SelItem<0) return TRUE; // no item selected if (item[SelItem].type==LABEL) UpdateLabelText(); // update the label text for the previous label FrEraseFocusRect(hFrDC,&CursRect); // turnoff the cursor rectangle // erase each tab rectangle for (i=0;i<TotalTabRects;i++) { if (TabRect[i].left==TabRect[i].right) continue; // tab not used FillRect(hFrDC,&TabRect[i],hBackBrush); } if (item[SelItem].type==GROUP) { // shrink the group item as it is deselected item[SelItem].width=item[SelItem].height=0; } SelItem=-1; TotalTabRects=0; // erase the description window text if (hDescWnd) SetWindowText(hDescWnd,""); return TRUE; } /****************************************************************************** SelectItem: Select the specified item. *******************************************************************************/ int SelectItem(int CurItem) { int i,x,y,width,height,fld; FrEraseFocusRect(hFrDC,&CursRect); // turnoff the cursor rectangle SelItem=CurItem; TotalTabRects=MAX_TABS; x=item[CurItem].x; // item location y=item[CurItem].y; width=item[CurItem].width; // item width and height height=item[CurItem].height; // Create north tab TabRect[TAB_NORTH].left=x+(width-TAB_WIDTH)/2; TabRect[TAB_NORTH].top=y-TAB_HEIGHT/2; // Create south tab TabRect[TAB_SOUTH].left=x+(width-TAB_WIDTH)/2; TabRect[TAB_SOUTH].top=y+height-TAB_HEIGHT/2; // Create west tab TabRect[TAB_WEST].left=x-TAB_WIDTH/2; TabRect[TAB_WEST].top=y+(height-TAB_HEIGHT)/2; // Create east tab TabRect[TAB_EAST].left=x+width-TAB_WIDTH/2; TabRect[TAB_EAST].top=y+(height-TAB_HEIGHT)/2; // Create north-west tab TabRect[TAB_NW].left=x-TAB_WIDTH/2; TabRect[TAB_NW].top=y-TAB_HEIGHT/2; // Create north-east tab TabRect[TAB_NE].left=x+width-TAB_WIDTH/2; TabRect[TAB_NE].top=y-TAB_HEIGHT/2; // Create south-west tab TabRect[TAB_SW].left=x-TAB_WIDTH/2; TabRect[TAB_SW].top=y+height-TAB_HEIGHT/2; // Create south-east tab TabRect[TAB_SE].left=x+width-TAB_WIDTH/2; TabRect[TAB_SE].top=y+height-TAB_HEIGHT/2; // set the right and bottom coordinates for (i=0;i<TotalTabRects;i++) { // calculate right and bottom coord for the tabs TabRect[i].right=TabRect[i].left+TAB_WIDTH; TabRect[i].bottom=TabRect[i].top+TAB_HEIGHT; } // Modify tabs for a section item if (item[SelItem].type==SECTION) { for (i=0;i<TotalTabRects;i++) { // Move the north tab below the section banner if (i==TAB_NORTH) { TabRect[i].top=y+FormHdr.SecBannerHeight-TAB_HEIGHT/2; TabRect[i].bottom=TabRect[i].top+TAB_HEIGHT; } // disable all tabs other than north and south if (i!=TAB_NORTH && i!=TAB_SOUTH) { TabRect[i].right=TabRect[i].left; TabRect[i].bottom=TabRect[i].top; } } } // Draw each tab rectangle for (i=0;i<TotalTabRects;i++) { if (TabRect[i].left==TabRect[i].right) continue; // tab not used FillRect(hFrDC,&TabRect[i],hDrawBrush); } // show the selection rectangle CursRect.left=x; CursRect.right=x+width; CursRect.top=y; CursRect.bottom=y+height; // create the description window width=UnitToPixX(DESC_WIDTH); height=UnitToPixY(DESC_HEIGHT); y=UnitToPixY((InputRect.bottom-InputRect.top-DESC_HEIGHT)/2); x=UnitToPixX((InputRect.bottom-InputRect.top-DESC_HEIGHT)/2); if (item[SelItem].type==LABEL) { // create an edit control if (hDescWnd && DescWndType!=DESC_EDIT) { // delete the old control DestroyWindow(hDescWnd); hDescWnd=0; } if (!hDescWnd) { // create a new edit control window hDescWnd=CreateWindow("EDIT","",WS_CHILD|WS_BORDER|WS_VISIBLE|ES_AUTOHSCROLL, x,y,width,height,hFrWnd,(HMENU)ID_DESC_WND,hFrInst,NULL); // Subclass to access the carriage return key OrigEditProc=(WNDPROC)GetWindowLong(hDescWnd,GWL_WNDPROC); // original control proceedure SetWindowLong(hDescWnd,GWL_WNDPROC,(DWORD)OurEditProc); } if (hDescWnd) { EnableWindow(hDescWnd,TRUE); DescWndType=DESC_EDIT; SetWindowText(hDescWnd,item[SelItem].label); SendMessage(hDescWnd,WM_PAINT,0,0L); } } else if (item[SelItem].type==FIELD) { // create an static control if (hDescWnd && DescWndType!=DESC_STATIC) {// delete the old control DestroyWindow(hDescWnd); hDescWnd=0; } if (!hDescWnd) hDescWnd=CreateWindow("STATIC","",WS_CHILD|WS_BORDER|WS_VISIBLE,x,y,width,height,hFrWnd,(HMENU)ID_DESC_WND,hFrInst,NULL); if (hDescWnd) { EnableWindow(hDescWnd,TRUE); DescWndType=DESC_STATIC; fld=item[SelItem].field; SetWindowText(hDescWnd,field[fld].name); SendMessage(hDescWnd,WM_PAINT,0,0L); } } else { // erase any description text if (hDescWnd) { SetWindowText(hDescWnd,""); SendMessage(hDescWnd,WM_PAINT,0,0L); EnableWindow(hDescWnd,FALSE); } } return TRUE; } /****************************************************************************** FrDrawFocusRect: Draw a rectangle of the given dimension using the focus pen. ******************************************************************************/ int FrDrawFocusRect(HDC hDC,RECT far *rect) { int SaveRop; if (FocusRectDrawn) return TRUE; // Focus rectangle already drawn SelectObject(hDC,hFocusPen); SaveRop=SetROP2(hDC,R2_NOTXORPEN); // Use XOR drawing mode FrDrawRect(hDC,rect); // draw the rectangle SetROP2(hDC,SaveRop); // reset the drawing mode FocusRectDrawn=TRUE; // focus rectangle drawn return TRUE; } /****************************************************************************** FrEraseFocusRect: Erase the focus rectangle ******************************************************************************/ int FrEraseFocusRect(HDC hDC, RECT far *rect) { int SaveRop; if (!FocusRectDrawn) return TRUE; SelectObject(hDC,hFocusPen); SaveRop=SetROP2(hDC,R2_NOTXORPEN); // Use XOR drawing mode FrDrawRect(hDC,rect); // draw the rectangle SetROP2(hDC,SaveRop); // reset the drawing mode FocusRectDrawn=FALSE; // Focus rectangle no more visible return TRUE; } /****************************************************************************** MarkGroupItems: Mark all the items in the current selection group. The calling routine should eventually demark these items. ******************************************************************************/ int MarkGroupItems() { int i; for (i=0;i<TotalItems;i++) { if (InGroup(i)) item[i].InGroup=TRUE; else item[i].InGroup=FALSE; } return TRUE; } /****************************************************************************** NextGroupItem: This function return the next item from the selected group of items. The selected item is also excluded from the group. This function returns -1 if no more items are found in the group ******************************************************************************/ int NextGroupItem() { int i; for (i=0;i<TotalItems;i++) if (item[i].InGroup) break; if (i<TotalItems) { item[i].InGroup=FALSE; return i; } else return -1; } /****************************************************************************** LeftMostItem: This function return the left most item from the current group of items. The function return -1 if a group does not have any item. ******************************************************************************/ int LeftMostItem() { int i,CurItem,CompVal,MinVal=0; CurItem=-1; for (i=0;i<TotalItems;i++) { if (!item[i].InGroup) continue; CompVal=item[i].x; // value to be compared if (CurItem<0 || CompVal<MinVal) { CurItem=i; MinVal=CompVal; } } return CurItem; } /****************************************************************************** TopMostItem: This function return the top most item from the current group of items. The function return -1 if a group does not have any item. ******************************************************************************/ int TopMostItem() { int i,CurItem,CompVal,MinVal=0; CurItem=-1; for (i=0;i<TotalItems;i++) { if (!item[i].InGroup) continue; CompVal=item[i].y; // value to be compared if (CurItem<0 || CompVal<MinVal) { CurItem=i; MinVal=CompVal; } } return CurItem; } /****************************************************************************** FrDrawOutline: Draw the specified sides of the given rectangle ******************************************************************************/ int FrDrawOutline(HDC hDC,RECT far *rect,int select) { if (select&OUTLINE_LEFT) { // draw the left side MoveToEx(hDC,rect->left,rect->bottom,NULL); LineTo(hDC,rect->left,rect->top); } if (select&OUTLINE_TOP) { // draw the top side MoveToEx(hDC,rect->left,rect->top,NULL); LineTo(hDC,rect->right,rect->top); } if (select&OUTLINE_RIGHT) { // draw the right side MoveToEx(hDC,rect->right,rect->top,NULL); LineTo(hDC,rect->right,rect->bottom); } if (select&OUTLINE_BOT) { // draw the bottom side MoveToEx(hDC,rect->right,rect->bottom,NULL); LineTo(hDC,rect->left,rect->bottom); } return TRUE; } /****************************************************************************** FrDrawRect: Draw a rectangle of the given dimension using the selected pen. ******************************************************************************/ int FrDrawRect(HDC hDC,RECT far *rect) { POINT pt[5]; // build points for the rectangle pt[0].x=rect->left; pt[0].y=rect->top; pt[1].x=rect->right; pt[1].y=rect->top; pt[2].x=rect->right; pt[2].y=rect->bottom; pt[3].x=rect->left; pt[3].y=rect->bottom; pt[4].x=rect->left; pt[4].y=rect->top; Polyline(hDC,pt,5); return TRUE; } /****************************************************************************** MakeRect: This routine simply converts x,y,width and height to the RECT structure. ******************************************************************************/ MakeRect(RECT far *rect,int x,int y,int width, int height) { rect->left=x; rect->right=x+width; rect->top=y; rect->bottom=y+height; return TRUE; } /****************************************************************************** InitItem: Initialize the specified item structure. ******************************************************************************/ int InitItem(struct StrItem huge *CurItem) { CurItem->type=LABEL; // screen item type: LABEL,FIELD,SECTION,LINE CurItem->x=0; // X position of the top/left corner of the object CurItem->y=0; // Y position of the top/left coner of the object CurItem->width=0; // width of the object CurItem->height=0; // height of the object CurItem->flags=OFLAG_HLEFT|OFLAG_VCENTER; // Attributes, see OFLAG_ constants CurItem->font=DEFAULT_CFMT; // index into font structure for types LABEL or FIELD CurItem->field=0; // index into 'field' array for type = FIELD CurItem->section=0; // index into 'section' array for type = SECTION CurItem->label[0]=0; // label text when type is LABEL CurItem->TextColor=RGB(0,0,0); // text color CurItem->OutlineSelect=0; // sides to draw CurItem->OutlineStyle=PS_SOLID; // line style of the bounding rectangle CurItem->OutlineWidth=0; // line width of the bounding rectangle CurItem->OutlineColor=DrawColor;// line color of the bounding rectangle CurItem->LineAngle=ANGLE_HORZ; // horizontal line CurItem->LineStyle=PS_SOLID; // line style of the line type item CurItem->LineWidth=0; // line width of the line type item CurItem->LineColor=DrawColor; // line color of the line type item CurItem->brush.lbStyle=BS_SOLID; // brush to paint the bounding rectangle CurItem->brush.lbColor=BackColor; CurItem->sized=FALSE; // TRUE when manually sized return TRUE; } /****************************************************************************** GetLabelLen: This routine gets the length of a label in logical units. The second argument specifies the chosen font. ******************************************************************************/ int GetLabelLen(LPSTR label, int font) { int len,count; int far *WidthTable,i; count = lstrlen(label); // number of characters in the label WidthTable=FrFont[font].CharWidth; len=0; // length in logical units for (i=0;i<count;i++) len=len+WidthTable[(BYTE)(label[i])]; return len; } /****************************************************************************** TruncateText: This routine truncates the text (first argument) to fit within the the specified width. ******************************************************************************/ TruncateText(LPSTR text, int width, int font) { int far *WidthTable,count,len; count = lstrlen(text); // number of characters in the text WidthTable=FrFont[font].CharWidth; len=0; // text length in number of characters while (len<count) { width=width-WidthTable[(BYTE)(text[len])]; if (width<0) break; len++; } text[len]=0; // truncate the field return TRUE; } /****************************************************************************** OurAlloc: Allocate a far memory object of given size. Lock the object, and return the far pointer to the object. *******************************************************************************/ void far *OurAlloc(UINT size) { HGLOBAL hMem; if (NULL==(hMem=GlobalAlloc(GMEM_MOVEABLE, size+1))) AbortFr("Memory Allocation Error (OurAlloc)",1); return (void far *) GlobalLock(hMem); } /****************************************************************************** OurRealloc: Realloc a far memory object to a given size. Lock the object, and return the far pointer to the object. *******************************************************************************/ void far *OurRealloc(void far *pMem,UINT size) { HGLOBAL hMem; #if defined(WIN32) hMem=GlobalHandle(pMem); // convert pointer to handle #else { DWORD temp=GlobalHandle((UINT)(((DWORD)pMem)>>16)); hMem=(HGLOBAL)LOWORD(temp); } #endif GlobalUnlock(hMem); if (NULL==(hMem=GlobalReAlloc(hMem,size+1, 0))) AbortFr("Memory Allocation Error (OurAlloc)",1); return (void far *) GlobalLock(hMem); } /****************************************************************************** OurFree: Free up the given memory object. This object must have been allocated using the OurAlloc routine. *******************************************************************************/ void OurFree(void far *pMem) { HGLOBAL hMem; if (pMem!=NULL) { #if defined(WIN32) hMem=GlobalHandle(pMem); // convert pointer to handle #else { DWORD temp=GlobalHandle((UINT)(((DWORD)pMem)>>16)); hMem=(HGLOBAL)LOWORD(temp); } #endif GlobalUnlock(hMem); GlobalFree(hMem); } } /****************************************************************************** sAlloc: Replacement of the Winmem package routine. Simply allocates the memory, and returns the handle as a 32 bit quantity. *******************************************************************************/ DWORD sAlloc(UINT size) { HGLOBAL hMem; if (NULL==(hMem=GlobalAlloc(GMEM_MOVEABLE, size+1))) AbortFr("Memory Allocation Error (OurAlloc)",1); return (DWORD) ((LPSTR)hMem); } /****************************************************************************** sReAlloc: Replacement of the Winmem package routine. Simply reallocates the memory, and returns the handle as a 32 bit quantity. *******************************************************************************/ DWORD sReAlloc(DWORD hMem,UINT size) { HGLOBAL hGlb; if (NULL==(hGlb=GlobalReAlloc((HGLOBAL)hMem,size+1, 0))) AbortFr("Memory Allocation Error (OurAlloc)",1); return (DWORD) ((LPSTR)hGlb); } /****************************************************************************** sLock: Replacement of the Winmem package routine. Simply locks the global handle and returns the far pointer. *******************************************************************************/ void far * sLock(DWORD hMem) { return GlobalLock((HGLOBAL)hMem); } /****************************************************************************** sUnlock: Replacement of the Winmem package routine. Simply unlocks the global handle. *******************************************************************************/ int sUnlock(DWORD hMem) { GlobalUnlock((HGLOBAL)hMem); return TRUE; } /****************************************************************************** sFree: Replacement of the Winmem package routine. Simply frees the global handle. *******************************************************************************/ int sFree(DWORD hMem) { GlobalFree((HGLOBAL)hMem); return TRUE; }