// WhoRYou.cmm - CEnvi demonstration for designing a dialog window. // This demo prompts the user for information about // themselves. You can see from this sample code // that dedigning your own windows and windows behavior // is very flexible, but also complicated. #include <Window.lib> #include <WinUtil.lib> #include <Message.lib> main() { do { if ( GetUserID(FirstName,LastName,Sex) ) TryAgain = ShowOKmessage(FirstName,LastName,Sex); else TryAgain = ShowCancelMessage(); } while( TryAgain ); } GetUserID(FirstName,LastName,Sex) // dialog box for user info { // Initialize some size parameters AveCharWidth, AveCharHeight; GetCharacterSizes(AveCharWidth,AveCharHeight); AveRowGap = AveCharHeight / 2; AveColGap = AveCharWidth // Initially make the main window (which will be resized later). // For now draw it off the screen so no one sees MainWindow = MakeWindow(NULL,NULL,"GetUserIDFunc","Scientific Survey", WS_POPUPWINDOW | WS_CAPTION | WS_VISIBLE, -10,-10,9,9,NULL,uid); // Make a couple of lines of descriptive text Description = "This scientifically-designed survery will determine if " "CEnvi is right for you. Use a number 2 pencil. " "Good luck! (no cheating)"; #define MAX_TEXTLEN 40 DescRowCount = (strlen(Description) + 15/*wrap room*/) / MAX_TEXTLEN ; MakeWindow(MainWindow,"static","GetUserIDChildFunc",Description,WS_CHILD | WS_VISIBLE, AveColGap,AveRowGap,MAX_TEXTLEN * AveCharWidth,DescRowCount * AveCharHeight,NULL,uid); BottomRow = AveRowGap + DescRowCount * AveCharHeight; // Request the user's first name, which is three fields #define EDIT_MARGIN (AveCharHeight / 4) // extra space around edit field BottomRow += AveRowGap; prompt = "First Name"; EditLength = 22; // default size of window for data input MakeWindow(MainWindow,"static",NULL,prompt,WS_CHILD | WS_VISIBLE, AveColGap,BottomRow + EDIT_MARGIN, width = AveCharWidth * (strlen(prompt)+1),AveCharHeight,NULL); MakeWindow(MainWindow,"static",NULL,NULL,WS_CHILD | WS_VISIBLE | SS_BLACKFRAME, col = AveColGap * 2 + width,BottomRow, (1+EditLength)*AveCharWidth,AveCharHeight + 2*EDIT_MARGIN,NULL); uid.FirstNameHwnd = MakeWindow(MainWindow,"edit","GetUserIDChildFunc",NULL, WS_CHILD | WS_VISIBLE | ES_AUTOHSCROLL | ES_LEFT, col + AveCharWidth / 2,BottomRow + EDIT_MARGIN, EditLength*AveCharWidth,AveCharHeight,NULL,uid); BottomRow += AveCharHeight + 2*EDIT_MARGIN; // Request the user's last name, which is much like the first BottomRow += AveRowGap; prompt = "Last Name"; EditLength = 30; // default size of window for data input MakeWindow(MainWindow,"static",NULL,prompt,WS_CHILD | WS_VISIBLE, AveColGap,BottomRow + EDIT_MARGIN, width = AveCharWidth * (strlen(prompt)+1),AveCharHeight,NULL); MakeWindow(MainWindow,"static",NULL,NULL,WS_CHILD | WS_VISIBLE | SS_BLACKFRAME, col = AveColGap * 2 + width,BottomRow, (1+EditLength)*AveCharWidth,AveCharHeight + 2*EDIT_MARGIN,NULL); uid.LastNameHwnd = MakeWindow(MainWindow,"edit","GetUserIDChildFunc",NULL, WS_CHILD | WS_VISIBLE | ES_AUTOHSCROLL | ES_LEFT, col + AveCharWidth / 2,BottomRow + EDIT_MARGIN, EditLength*AveCharWidth,AveCharHeight,NULL,uid); BottomRow += AveCharHeight + 2*EDIT_MARGIN; // Add radio buttons to select sex BottomRow += AveRowGap; #define PUSHBUTT_HEIGHT AveCharHeight width = AveCharWidth * (4 + strlen("Female")); uid.FemaleHwnd = MakeWindow(MainWindow,"button","GetUserIDChildFunc","Female",WS_CHILD | WS_VISIBLE | BS_AUTORADIOBUTTON, AveColGap * 3,BottomRow,width,PUSHBUTT_HEIGHT,NULL,uid); uid.MaleHwnd = MakeWindow(MainWindow,"button","GetUserIDChildFunc","Male",WS_CHILD | WS_VISIBLE | BS_AUTORADIOBUTTON, AveColGap * 4 + width,BottomRow,AveCharWidth * (4 + strlen("Male")),PUSHBUTT_HEIGHT,NULL,uid); BottomRow += PUSHBUTT_HEIGHT; // Finally, add the OK and CANCEL buttons BottomRow += AveRowGap * 2; #define BUTTON_WIDTH 10 * AveCharWidth #define BUTTON_HEIGHT AveCharHeight * 3 / 2 uid.OKhwnd = MakeWindow(MainWindow,"button","GetUserIDChildFunc","OK", WS_CHILD | WS_VISIBLE | BS_DEFPUSHBUTTON | WS_DISABLED, AveColGap * 3,BottomRow,BUTTON_WIDTH,BUTTON_HEIGHT,NULL,uid); uid.CancelHwnd = MakeWindow(MainWindow,"button","GetUserIDChildFunc","CANCEL",WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON, AveColGap * 6 + BUTTON_WIDTH,BottomRow,BUTTON_WIDTH,BUTTON_HEIGHT,NULL,uid); SizeAndCenterDisplay(MainWindow,AveColGap,AveRowGap); // Initialize with FirstName as the active field SetFocus(uid.FirstNameHwnd); uid.OKselected = False; while ( DoWindows() && !uid.OKselected ) ; if ( uid.OKselected ) { GetEditText(uid.FirstNameHwnd,FirstName); FirstName[0] = toupper(FirstName[0]); GetEditText(uid.LastNameHwnd,LastName); LastName[0] = toupper(LastName[0]); if ( SendMessage(uid.FemaleHwnd,BM_GETCHECK,0,0) ) strcpy(Sex,"woman"); else if ( SendMessage(uid.MaleHwnd,BM_GETCHECK,0,0) ) strcpy(Sex,"man"); else strcpy(Sex,"person"); BreakWindow(MainWindow); return(TRUE); } return(FALSE); } /**** Windows functions called from GetUserInfo ****/ GetUserIDFunc(hwnd,msg,parm1,parm2,uid) { if ( msg == WM_COMMAND ) { childHwnd = parm2 & 0xFFFF; switch ( (parm2 >> 16) & 0xFFFF ) { case BN_CLICKED: switch( childHwnd ) { case uid.OKhwnd: uid.OKselected = TRUE; break; case uid.CancelHwnd: BreakWindow(hwnd); break; default: ShouldOKbeEnabled(uid); break; } break; case EN_CHANGE: ShouldOKbeEnabled(uid); break; } } } GetUserIDChildFunc(hwnd,msg,parm1,parm2,uid) { #define VK_SHIFT 0x10 if ( WM_CHAR == msg ) { switch ( parm1 ) { case '\t': // Tab to next field or back tab to previous field. Will allow moving // to any field that is not "static" type and not disabled Backward = (0x80 & DynamicLink("USER","GETKEYSTATE",SWORD16,PASCAL,VK_SHIFT)); Sibling = hwnd; BLObSize(_className,40); do { // if this is the end of the list then go to the other end if ( Sibling == GetWindow(Sibling,Backward ? GW_HWNDFIRST : GW_HWNDLAST ) ) Sibling = GetWindow(Sibling,Backward ? GW_HWNDLAST : GW_HWNDFIRST ); else Sibling = GetWindow(Sibling,Backward ? GW_HWNDPREV : GW_HWNDNEXT); _len = GetClassName(Sibling,_className,39); } while( (_len == 6 && !memicmp(_className,"static",6)) || !IsWindowEnabled(Sibling) ); SetFocus(Sibling); return 0; case ' ': // don't let last name or first name accept spaces if ( hwnd == uid.LastNameHwnd || hwnd == uid.FirstNameHwnd ) return 0; break; case '\r'; // Enter selects the OK button, and so post a ' ' to the // OK button window if ( IsWindowEnabled(uid.OKhwnd) ) { PostMessage(uid.OKhwnd,WM_KEYDOWN,' ',parm2); PostMessage(uid.OKhwnd,WM_KEYUP,' ',parm2); } return(0); } } } ShouldOKbeEnabled(uid) // adjust the OK button to be enabled or NOT { WantOKstate = ( 0 != GetWindowTextLength(uid.FirstNameHwnd) && 0 != GetWindowTextLength(uid.LastNameHwnd) && ( SendMessage(uid.FemaleHwnd,BM_GETCHECK,0,0) || SendMessage(uid.MaleHwnd,BM_GETCHECK,0,0) ) ); EnableWindow(uid.OKhwnd,WantOKstate); } /*** Message windows after user id form is complete ***/ #include <MsgBox.lib> ShowOKmessage(FirstName,LastName,Sex) { sprintf(message,"%s %s:\rScientific analysis of your survey indicates that you " "are a %s who knows a good shareware product when you see it. " "Numerological analyses show that you like to have complete " "product manuals and you don't like registration-reminder " "screens." "\rRecommendation: You should register CEnvi right away." "\r\rDo you want to try the survey again?", FirstName,LastName,Sex); return( IDYES == MessageBox(message,"SURVEY RESULTS",MB_YESNO) ); } ShowCancelMessage() { return( IDYES == MessageBox( "You did not complete the survey. You are obviously in a hurry " "to send in your CEnvi registration form." "\r\rDo you want to try the survey again?", "SURVEY CANCELED",MB_YESNO) ); } /*** UTILITIES CALLED BY THE ABOVE CODE ***/ SizeAndCenterDisplay(hwnd,RightMargin,BottomMargin) { // Make the total size of this window fit around its children, with // RightMargin and BottomMargin extra. Then center this in the // screen and display it. // Find maximum row and col of all children ChildList = WindowList(hwnd); assert( NULL != ChildList ); GetWindowRect(hwnd,ParentRect); MaxChildCol = MaxChildRow = 0; for ( i = GetArraySpan(ChildList); 0 <= i; i-- ) { GetWindowRect(ChildList[i],ChildRect); MaxChildCol = max(MaxChildCol,ChildRect.right - ParentRect.left); MaxChildRow = max(MaxChildRow,ChildRect.bottom - ParentRect.top); } // The window width and height must just be big enough for these // maximums plus the margins and the window border width = MaxChildCol + 1 + RightMargin + GetSystemMetrics(SM_CXBORDER); height = MaxChildRow + 1 + BottomMargin + GetSystemMetrics(SM_CXBORDER); // Figure where to center this window in the screen scrWidth = GetSystemMetrics(SM_CXSCREEN); scrHeight = GetSystemMetrics(SM_CYSCREEN); col = (ScrWidth - width) / 2; row = (ScrHeight - height) / 2; MoveWindow(hwnd,col,row,width,height,TRUE); } GetCharacterSizes(width,height) { hdc = GetDC(ScreenHandle()); SelectObject(hdc,GetStockObject(SYSTEM_FONT)); GetTextMetrics(hdc,tm); width = tm.AveCharWidth; height = tm.Height + tm.ExternalLeading; ReleaseDC(ScreenHandle(),hdc); } GetWindowRect(hwnd,Rectangle) { // set up blob to retrieve four integers BLObSize(_rect,4 * 2/*integer size*/); DynamicLink("USER","GETWINDOWRECT",SWORD16,PASCAL,hwnd,_rect); Rectangle.left = BLObGet(_rect,0,SWORD16); Rectangle.top = BLObGet(_rect,2,SWORD16); Rectangle.right = BLObGet(_rect,4,SWORD16); Rectangle.bottom = BLObGet(_rect,6,SWORD16); } MoveWindow(hwnd,col,row,width,height,redraw) { DynamicLink("USER","MOVEWINDOW",SWORD16,PASCAL, hwnd,col,row,width,height,TRUE); } GetClassName(hwnd,ClassName,MaxCount) { return DynamicLink("USER","GETCLASSNAME",SWORD16,PASCAL, hwnd,ClassName,MaxCount); } SetFocus(hwnd) { return DynamicLink("USER","SETFOCUS",SWORD16,PASCAL,hwnd); } GetWindowTextLength(hwnd) { return DynamicLink("USER","GETWINDOWTEXTLENGTH",SWORD16,PASCAL,hwnd); } GetEditText(hwnd,buf) // make buf big enough { _len = GetWindowTextLength(hwnd); BLObSize(buf,_len+1); if ( _len ) DynamicLink("USER","GETWINDOWTEXT",SWORD16,PASCAL,hwnd,buf,_len+1); buf[_len] = '\0'; } IsWindowEnabled(WinHandle) { return DynamicLink("USER","ISWINDOWENABLED",SWORD16,PASCAL,WinHandle); } EnableWindow(WinHandle,EnableState) { return DynamicLink("USER","ENABLEWINDOW",SWORD16,PASCAL,WinHandle,EnableState); }