|
Build as a Windows application. Link with XFT.lib. !======================================================================= ! ___________ ! \\//----------- ! )( //== // ! //\\ // // !======================================================================= ! EXTENDED FORTRAN TYPES LIBRARY SAMPLES !======================================================================= ! _Yamb.f90 - Main application module for XYamb sample. ! ! XYamb is a simple game written in XFT. The Yamb game is slightly ! modified "Yacht" or "Yachtzee". The sample demonstrates: ! * usage of SDI architecture with menu, view window, toolbar and status bar ! * drawing on application windows using XFTGDI routines ! * usage of registry routines to store last user name and high score list ! ! 2005. Jugoslav Dujic (jdujic@uns.ns.ac.yu) ! ! You are free to use the code for both commercial and non-commercial ! use. The code is provided as-is without warranties. You are free to ! distribute and modify this source code provided that the list of ! original author(s) remains untouched and your revisions are indicated ! as such. Contributions are welcome. !======================================================================= !XChild_OnPaint !XFrame_OnGetMMInfo !XChild_OnLButtonUp !OnNewRoll !OnRoll !OnTopTen !OnAnnounce !OnUndo !OnNewGame !OnExit !DrawTable !CalcResult !GameOver !ResetState !XInit !======================================================= MODULE XYamb USE XFT USE DFWIN IMPLICIT NONE TYPE(X_WINDOW):: xChild !View window TYPE(X_MENU):: xMenu !Main menu TYPE(X_TOOLBAR):: xTb !Toolbar INTEGER, PARAMETER:: COMPLETE = 0, & !Field is completed LOCKED = 1, & !Field is free, but disabled FREE = 2 !Field is free, but enabled INTEGER, PARAMETER:: ACT_WRITE = 1, & !Last action is "enter the result" ACT_ANNOUNCE = 2, & !Last action is "announce" ACT_ANNOUNCE_SEL = 3 !Last action is "select announced field" INTEGER, PARAMETER:: nColumns = 4 INTEGER:: iResult(15, nColumns), & !Result of each field (including the intermediates) iState(15, nColumns), & !State of each field in the table nLastAction = 0, & !Last action to be undid nLastCol = 0, & !Last filled column nLastRow = 0, & !Last filled row iDice(6), & !Numbers on each dice nRolls = 1, & !Current roll iTotal !Total game result CHARACTER(100) sPlayerName !Name of actual player CHARACTER(*), PARAMETER:: APP_REGKEY = "Software\XFT\Yamb\2.0" LOGICAL:: bKeep(6) = .FALSE., & !Selected dice bAnnounce = .FALSE. !TRUE if "Announce" is selected but the field is not chosen yet CHARACTER(20):: sTopTenName(10) !Names of top 10 players INTEGER:: iTopTenResult(10) !Results of top 10 players INTEGER:: IDC_STATUS !======================================================= CONTAINS !======================================================= !PURPOSE: Initialization function called by XFT library on app start. INTEGER FUNCTION XInit(szCmdLine, nCmdShow) !DEC$ATTRIBUTES DEFAULT, DECORATE, ALIAS: 'XINIT':: XInit USE XFT USE XFTMENU USE XFTCTRL USE DFWIN !USE COMCTL32 IMPLICIT NONE CHARACTER*(*) szCmdLine INTEGER, INTENT(IN):: nCmdShow TYPE(X_WINDOW):: xWnd INTEGER:: iSt, iParts(2) = (/80, -1/), iX1, iY1, iX2, iY2, iWidth, iHeight, & hKey, iSize, iType, tbHeight, sbHeight LOGICAL:: bSt TYPE(T_RECT):: Rect TYPE(X_WINDOW):: Dlg TYPE(X_TBBUTTON):: xButtons(5) TYPE(X_BITMAP):: xBmp INCLUDE 'Resource.fd' !Loading menu resource & attaching it to the frame xMenu = XLoadMenu(IDR_MENU_YAMB) !Creation of App & frame window iSt = XCreateSDIApp(xMenu, "XYamb", IDI_ICON_YAMB) iSt = XSetWindowMenu(XW_FRAME, xMenu) !Moving frame to screen center iSt = SystemParametersInfo(SPI_GETWORKAREA, 0, LOC(Rect), 0) iX1 = Rect%Right/2 iY1 = Rect%Bottom/2 iSt = XSetWindowPos(XW_FRAME, iX1-200, iY1-300, 400, 600) iSt = XGetClientRect(XW_FRAME, iWidth, iHeight) !Creation of toolbar iSt = XCreateToolbar(XW_FRAME, xTb, IDR_TOOLBAR2, WS_BORDER.OR.TBSTYLE_FLAT.OR.TBSTYLE_TOOLTIPS, 16, 16, 16, 15) bSt = XCreateBitmap(xBmp, IDR_TOOLBAR2, LR_LOADMAP3DCOLORS) iSt = XToolbarSet(xTb, IDR_TOOLBAR2, xBmp%hBmp, CTL_BITMAP) xButtons(1) = X_TBBUTTON(ID_ACTION_ROLL, TBSTATE_ENABLED, TBSTYLE_BUTTON, 1, 0) xButtons(2) = X_TBBUTTON(ID_ACTION_NEWROLL, TBSTATE_ENABLED, TBSTYLE_BUTTON, 2, 0) xButtons(3) = X_TBBUTTON(0, 0, TBSTYLE_SEP, 0, 0) xButtons(4) = X_TBBUTTON(ID_ACTION_ANNOUNCE, TBSTATE_ENABLED, TBSTYLE_BUTTON, 3, 0) xButtons(5) = X_TBBUTTON(ID_ACTION_UNDO, TBSTATE_ENABLED, TBSTYLE_BUTTON, 4, 0) iSt = XToolbarAddButtons(xTb, xButtons(1:5), 0) IDC_STATUS = XCtlCreate(XW_FRAME, 2, XCTL_STATUS, 0) iSt = XCtlSet(XW_FRAME, IDC_STATUS, iParts, CTL_RECTS) iSt = XCtlSet(XW_FRAME, IDC_STATUS, .TRUE., CTL_VISIBLE) iSt = XCtlGetPos(XW_FRAME, IDC_STATUS, iHeight=sbHeight) iSt = XToolbarGetPos(xTb, iHeight=tbHeight) iSt = XCreateWindow(xChild, XW_FRAME, WS_CHILD, ""C, XS_EX_DBLBUFFERED, 0, tbHeight, iWidth, iHeight-tbHeight-sbHeight) iSt = XShowWindow(xChild, SW_SHOW) bSt = XSetHandler(xChild, WM_PAINT, XChild_OnPaint) bSt = XSetHandler(xChild, WM_LBUTTONUP, XChild_OnLButtonUp) bSt = XSetHandler(XW_FRAME, WM_GETMINMAXINFO, XFrame_OnGetMMInfo) bSt = XSetCommand(XW_FRAME, ID_GAME_NEW, OnNewGame) bSt = XSetCommand(XW_FRAME, ID_GAME_TOPTEN, OnTopTen) bSt = XSetCommand(XW_FRAME, ID_GAME_EXIT, OnExit) bSt = XSetCommand(XW_FRAME, ID_ACTION_ROLL, OnRoll) bSt = XSetCommand(XW_FRAME, ID_ACTION_NEWROLL, OnNewRoll) bSt = XSetCommand(XW_FRAME, ID_ACTION_ANNOUNCE, OnAnnounce) bSt = XSetCommand(XW_FRAME, ID_ACTION_UNDO, OnUndo) hKey = XRegOpen(HKEY_LOCAL_MACHINE, APP_REGKEY) iSt = XRegRead(hKey, "Player", sPlayerName) iSt = XRegRead(hKey, "TopTenResult", LOC(iTopTenResult), SIZEOF(iTopTenResult)) iSt = XRegRead(hKey, "TopTenName", LOC(sTopTenName), SIZEOF(sTopTenName)) iSt = XLoadDialog(IDD_NAME, Dlg, XW_FRAME) iSt = XCtlSet(Dlg, IDC_EDIT_NAME, sPlayerName, CTL_STATE) iSt = XModalDialog(Dlg) iSt = XCtlGet(Dlg, IDC_EDIT_NAME, sPlayerName, CTL_STATE) CALL XDestroyDialog(Dlg) iSt = XCtlSet(XW_FRAME, IDC_STATUS, sPlayerName, 1) iSt = XRegWrite(hKey, "Player", sPlayerName) CALL XRegClose(hKey) iDice = 0 XInit = 1 CALL OnNewGame(XW_FRAME, 0, 0) END FUNCTION XInit !======================================================= !PURPOSE: handler for WM_GETMINMAXINFO message. Prevents the !frame from resizing by setting nMinSize and nMaxSize to (400, 600) INTEGER FUNCTION XFrame_OnGetMMInfo(xWnd, xSizeMax, xMaxPos, xMinSize, xMaxSize) TYPE(X_WINDOW), INTENT(IN):: xWnd TYPE(X_POINT), INTENT(INOUT):: xSizeMax TYPE(X_POINT), INTENT(INOUT):: xMaxPos TYPE(X_POINT), INTENT(INOUT):: xMinSize !Minimal allowed size TYPE(X_POINT), INTENT(INOUT):: xMaxSize !Maximal allowed size xMinSize = X_POINT(400, 600) xMaxSize = X_POINT(400, 600) XFrame_OnGetMMInfo = 0 END FUNCTION XFrame_OnGetMMInfo !======================================================= !PURPOSE: handler for WM_PAINT message. Draws the dice and !the table. INTEGER FUNCTION XChild_OnPaint(xWnd, xDC, iX1, iY1, iX2, iY2) TYPE(X_WINDOW):: xWnd !Window ( = xChild) TYPE(X_DC):: xDC !Window's DC INTEGER, INTENT(IN):: iX1, iY1, iX2, iY2 !Dimensions of update rectangle INTEGER:: iSt, i, nColor, iX, iY, n INTEGER, PARAMETER:: iSpot(9,6) = (/0, 0, 0, 0, 1, 0, 0, 0, 0, & !Spots on dice 1, 0, 0, 0, 0, 0, 0, 0, 1, & 0, 0, 1, 0, 1, 0, 1, 0, 0, & 1, 0, 1, 0, 0, 0, 1, 0, 1, & 1, 0, 1, 0, 1, 0, 1, 0, 1, & 1, 0, 1, 1, 0, 1, 1, 0, 1/) !ClearScreen CALL XSetBrush(xDC, XCOLOR_GREEN) CALL XSetPen(xDC, XCOLOR_GREEN) iSt = XRectangle(xDC, 0, 0, xDC%xView%iXExt, xDC%xView%iYExt) XChild_OnPaint = 0 !Don't draw if the game is not started yet IF (iDice(1).EQ.0) RETURN !Drawing dice DO i = 1, 6 IF (bKeep(i)) THEN nColor = XCOLOR_LTCYAN ELSE nColor = XCOLOR_YELLOW END IF iSt = XRectangle(xDC, 20, 80*i-60, 80, 80*i, & X_PEN(PS_SOLID, 0, nColor), & X_BRUSH(BS_SOLID, nColor, 0)) CALL XSetBrush(xDC, XCOLOR_GREEN) CALL XSetPen(xDC, XCOLOR_GREEN) iSt = XRectangle(xDC, 20, 80*I-60, 30, 80*I-50) iSt = XRectangle(xDC, 70, 80*I-60, 80, 80*I-50) iSt = XRectangle(xDC, 20, 80*I-10, 30, 80*I) iSt = XRectangle(xDC, 70, 80*I-10, 80, 80*I) CALL XSetBrush(xDC, nColor) CALL XSetPen(xDC, nColor) iSt = XEllipse(xDC, 20, 80*I-60, 40, 80*I-40) iSt = XEllipse(xDC, 60, 80*I-60, 80, 80*I-40) iSt = XEllipse(xDC, 20, 80*I-20, 40, 80*I) iSt = XEllipse(xDC, 60, 80*I-20, 80, 80*I) CALL XSetBrush(xDC, XCOLOR_BLACK) !Draw spots DO ix = 1, 3 DO iy = 1, 3 n = ix+3*(iy-1) IF(iSpot(n, iDice(i)).eq.1) THEN iSt = XEllipse(xDC, 16+15*ix, 80*i-64+15*iy, 24+15*ix, 80*i-60+15*iy+4) END IF END DO END DO END DO CALL DrawTable(xDC) END FUNCTION XChild_OnPaint !======================================================= !PURPOSE: handler for WM_LBUTTONUP message INTEGER FUNCTION XChild_OnLButtonUp(xWnd, iX, iY, Msg, iKeyState) TYPE(X_WINDOW):: xWnd !Window ( = xChild) INTEGER:: iX, iY, Msg, iKeyState !Click coordinates and state of keys INTEGER:: iSt, i, j, k, m, iX1, iY1, iX2, iY2, iXStep, iYStep INCLUDE "Resource.fd" !If one of dice is hit, toggle its keep state DO i = 1, 6 IF(iY.GE.80*I-60 .AND. iY.LE.80*I .AND. iX.GE.20 .AND. (iX.LE.80)) & bKeep(i) = .NOT.bKeep(i) END DO iXStep = 50 iYStep = 30 XChild_OnLButtonUp = 0 !Checking the table for click DO j = 1, nColumns DO k = 1, 14 ix1 = 100+j*(iXStep) ix2 = ix1+45 iy1 = k*(iYStep) iy2 = iy1+25 IF(iY.GE.iy1 .AND. iY.LE.iy2 .AND. iX.GE.ix1 .AND.iX.LE.ix2) THEN IF(iState(k, j).eq.FREE) THEN !The clicked field (k, j) is found IF (bAnnounce) THEN bAnnounce = .FALSE. !Enable roll & disable re-announce iSt = XMenuSet(xMenu, ID_ACTION_ROLL, .TRUE., XC_ENABLE) iSt = XMenuSet(xMenu, ID_ACTION_ANNOUNCE, .FALSE., XC_ENABLE) iSt = XToolbarSet(xTb, ID_ACTION_ROLL, .TRUE., XC_ENABLE) iSt = XToolbarSet(xTb, ID_ACTION_ANNOUNCE, .FALSE., XC_ENABLE) !Save Undo information nLastCol = j nLastRow = k nLastAction = ACT_ANNOUNCE_SEL iSt = XMenuSet(xMenu, ID_ACTION_UNDO, .TRUE., XC_ENABLE) iSt = XToolbarSet(xTb, ID_ACTION_UNDO, .TRUE., XC_ENABLE) !Lock all other fields for writing DO m = 1, 14 IF (iState(m, 4).NE.COMPLETE .AND. m.NE.k) iState(m, 4) = LOCKED END DO iSt = XCtlSet(XW_FRAME, IDC_STATUS, "Roll the dice.", 2) ELSE !Save Undo information nLastCol = j nLastRow = k nLastAction = ACT_WRITE !Enable undo except if last roll with announcement IF (.NOT.(j.EQ.4 .AND. nRolls.EQ.3)) THEN iSt = XMenuSet(xMenu, ID_ACTION_UNDO, .TRUE., XC_ENABLE) iSt = XToolbarSet(xTb, ID_ACTION_UNDO, .TRUE., XC_ENABLE) END IF CALL CalcResult(k, j) !Lock entire table - no entry can be made until undo or new roll WHERE (iState.EQ.FREE) iState = LOCKED END WHERE END IF CALL XUpdateWindow(xWnd) RETURN ELSE RETURN END IF END IF END DO END DO CALL XUpdateWindow(xWnd) END FUNCTION XChild_OnLButtonUp !======================================================= !PURPOSE: Handler for Action/New Roll menu. SUBROUTINE OnNewRoll(xWnd, ID, nCode) TYPE(X_WINDOW):: xWnd INTEGER, INTENT(IN):: ID, nCode INTEGER:: iSt INCLUDE "Resource.fd" IF (nCode.EQ.0) THEN iSt = XMenuSet(xMenu, ID_ACTION_NEWROLL, .FALSE., XC_ENABLE) iSt = XToolbarSet(xTb, ID_ACTION_NEWROLL, .FALSE., XC_ENABLE) !Reset keep status and number of rolls bKeep = .FALSE. nRolls = 0 !Reset the table to normal state CALL ResetState CALL OnRoll(xWnd, ID, nCode) END IF END SUBROUTINE OnNewRoll !======================================================= !PURPOSE: Handler for Action/Roll menu. SUBROUTINE OnRoll(xWnd, ID, nCode) USE MSFLIB TYPE(X_WINDOW):: xWnd INTEGER, INTENT(IN):: ID, nCode INTEGER:: iSt, i REAL:: fRnd CHARACTER(30):: sMessage INCLUDE "Resource.fd" IF (nCode.EQ.0) THEN nRolls = nRolls+1 IF (nRolls.EQ.3) THEN sMessage = "Enter the result." ELSE WRITE(sMessage, "('Roll ', i1, a1)") nRolls END IF !iSt = XSendMessage(xStatus, SB_SETTEXT, 1, LOC(sMessage)) iSt = XCtlSet(XW_FRAME, IDC_STATUS, sMessage, 2) !Enable announce if 1st roll; disable roll if 3rd roll iSt = XMenuSet(xMenu, ID_ACTION_ANNOUNCE, nRolls.EQ.1, XC_ENABLE) iSt = XMenuSet(xMenu, ID_ACTION_ROLL, nRolls.LT.3, XC_ENABLE) iSt = XToolbarSet(xTb, ID_ACTION_ANNOUNCE, nRolls.EQ.1, XC_ENABLE) iSt = XToolbarSet(xTb, ID_ACTION_ROLL, nRolls.LT.3, XC_ENABLE) IF (nRolls.EQ.1) THEN !If only "announced" column is left, disable "Roll" item IF (ALL(iState(1:14, 1:3).EQ.COMPLETE)) iSt = XMenuSet(xMenu, ID_ACTION_ROLL, .FALSE., XC_ENABLE) END IF iSt = XMenuSet(xMenu, ID_ACTION_UNDO, .FALSE., XC_ENABLE) iSt = XToolbarSet(xTb, ID_ACTION_UNDO, .FALSE., XC_ENABLE) !Assign random numbers to dice CALL SEED(RND$TIMESEED) DO i = 1, 6 IF (.NOT.bKeep(i)) THEN CALL RANDOM(fRnd) iDice(i) = INT(6*fRnd)+1 END IF END DO CALL XUpdateWindow(xChild) END IF END SUBROUTINE OnRoll !======================================================= !PURPOSE: Callback for Game/Top ten menu item. Displays the "Top ten" !Dialog SUBROUTINE OnTopTen(xWnd, ID, nCode) USE XSTRINGS USE XFTCTRL !USE XFLOGM2 TYPE(X_WINDOW):: xWnd INTEGER, INTENT(IN):: ID, nCode TYPE(X_WINDOW):: Dlg !TYPE(DIALOG):: Dlg CHARACTER*5:: sTemp INTEGER:: iSt, i INCLUDE "Resource.fd" iSt = XLoadDialog(IDD_TOPTEN, Dlg, XW_FRAME) DO i = 1, 10 iSt = XCtlSet(Dlg, IDC_IME1+i-1, sTopTenName(i), CTL_TITLE) WRITE(sTemp, '(i4)') iTopTenResult(i) iSt = XCtlSet(Dlg, IDC_REZ1+i-1, sTemp, CTL_TITLE) IF (iTopTenResult(i).EQ.iTotal .AND. STRCMP(sTopTenName(i), sPlayerName)) THEN iSt = XCtlSet(Dlg, IDC_IME1+i-1, #FF, CTL_COLOR) END IF END DO iSt = XModalDialog(Dlg) CALL XDestroyDialog(Dlg) !xDlg = XLoadDialog(IDD_TOPTEN) !DO i = 1, 10 ! iSt = XCtlSet(xDlg, IDC_IME1+i-1, sTopTenName(i), CTL_TITLE) ! WRITE(sTemp, '(i4)') iTopTenResult(i) ! iSt = XCtlSet(xDlg, IDC_REZ1+i-1, sTemp, CTL_TITLE) ! IF (iTopTenResult(i).EQ.iTotal .AND. sTopTenName(i).EQ.sPlayerName) THEN !! iSt = XCtlSet(xDlg, IDC_IME1+i-1, #FF, CTL_COLOR) ! END IF !END DO !iSt = XModalDialog(xDlg, xChild%hWnd) !CALL xDlgUnInit(xDlg) END SUBROUTINE OnTopTen !======================================================= !PURPOSE: Callback for Announce/Top Ten menu item. SUBROUTINE OnAnnounce(xWnd, ID, nCode) TYPE(X_WINDOW):: xWnd INTEGER, INTENT(IN):: ID, nCode INTEGER:: iSt, j, k INCLUDE "Resource.fd" IF (nCode.EQ.0) THEN !Lock the entire table except "announce" column DO j = 1, 14 IF (iState(j, 4).eq.LOCKED) iState(j, 4) = FREE DO k = 1, 3 IF(iState(j, k).eq.FREE) iState(j, k) = LOCKED END DO END DO !Save undo information nLastAction = ACT_ANNOUNCE bAnnounce = .TRUE. !Disable "Announce" & "Roll" (until a field is selected in OnLButtonUp). !Enable "Undo". iSt = XMenuSet(xMenu, ID_ACTION_ANNOUNCE, .FALSE., XC_ENABLE) iSt = XMenuSet(xMenu, ID_ACTION_ROLL, .FALSE., XC_ENABLE) iSt = XMenuSet(xMenu, ID_ACTION_UNDO, .TRUE., XC_ENABLE) iSt = XToolbarSet(xTb, ID_ACTION_ANNOUNCE, .FALSE., XC_ENABLE) iSt = XToolbarSet(xTb, ID_ACTION_ROLL, .FALSE., XC_ENABLE) iSt = XToolbarSet(xTb, ID_ACTION_UNDO, .TRUE., XC_ENABLE) iSt = XCtlSet(XW_FRAME, IDC_STATUS, "Select the field to announce.", 2) CALL XUpdateWindow(xChild) END IF END SUBROUTINE OnAnnounce !======================================================= !PURPOSE: Handler for Action/Undo menu item. Restores the previous !state (applicable in case of misclicking a field or changing mind !when making an announcement) SUBROUTINE OnUndo(xWnd, ID, nCode) TYPE(X_WINDOW):: xWnd INTEGER, INTENT(IN):: ID, nCode CHARACTER(40):: sMessage INTEGER:: iSt, j, k INCLUDE "Resource.fd" IF (nCode.EQ.0) THEN SELECT CASE (nLastAction) CASE(ACT_ANNOUNCE) !Last action is Action/Announce. Reset the table into !normal state, re-enable "Roll" and "Announce" menu items. bAnnounce = .FALSE. iSt = XCtlGet(XW_FRAME, IDC_STATUS, sMessage, 2) CALL ResetState() iSt = XCtlSet(XW_FRAME, IDC_STATUS, sMessage, 2) iSt = XMenuSet(xMenu, ID_ACTION_ANNOUNCE, .TRUE., XC_ENABLE) iSt = XMenuSet(xMenu, ID_ACTION_ROLL, .TRUE., XC_ENABLE) iSt = XToolbarSet(xTb, ID_ACTION_ANNOUNCE, .TRUE., XC_ENABLE) iSt = XToolbarSet(xTb, ID_ACTION_ROLL, .TRUE., XC_ENABLE) CASE(ACT_ANNOUNCE_SEL) !Last action is selection of announce field. Allow only !to change selection, not to get back to another column. !Free selected field & unlock "Announced" column iState(nLastRow, nLastCol) = FREE DO j = 1, 14 IF (iState(j, 4).EQ.LOCKED) iState(j, 4) = FREE END DO !Disable roll & go back to announcement-selection mode iSt = XMenuSet(xMenu, ID_ACTION_ROLL, .FALSE., XC_ENABLE) iSt = XToolbarSet(xTb, ID_ACTION_ROLL, .FALSE., XC_ENABLE) bAnnounce = .TRUE. iSt = XCtlSet(XW_FRAME, IDC_STATUS, "Select the field to announce.", 2) CASE(ACT_WRITE) !Last action is writing down the result. iSt = XCtlGet(XW_FRAME, IDC_STATUS, sMessage, 2) IF (nLastCol.NE.4) THEN !If in first three columns, free the clicked field !and reset the table. iState(nLastRow, nLastCol) = FREE iResult(nLastRow, nLastCol) = 0 CALL CalcResult(0, 0) CALL ResetState() ELSE IF (nLastCol.EQ.4 .AND. nRolls.LT.3) THEN !If in "Announced" column, free only that field, and recalculate !the result iState(nLastRow, nLastCol) = FREE iResult(nLastRow, nLastCol) = 0 CALL CalcResult(0, 0) END IF IF (nRolls.LT.3) THEN iSt = XMenuSet(xMenu, ID_ACTION_ROLL, .TRUE., XC_ENABLE) iSt = XToolbarSet(xTb, ID_ACTION_ROLL, .TRUE., XC_ENABLE) END IF !Disable new roll until the result is written down (OnLButtonUp) iSt = XCtlSet(XW_FRAME, IDC_STATUS, sMessage, 2) iSt = XMenuSet(xMenu, ID_ACTION_NEWROLL, .FALSE., XC_ENABLE) iSt = XToolbarSet(xTb, ID_ACTION_NEWROLL, .FALSE., XC_ENABLE) END SELECT iSt = XMenuSet(xMenu, ID_ACTION_UNDO, .FALSE., XC_ENABLE) iSt = XToolbarSet(xTb, ID_ACTION_UNDO, .FALSE., XC_ENABLE) CALL XUpdateWindow(xChild) END IF END SUBROUTINE OnUndo !======================================================= !PURPOSE: Handler for Game/New menu item SUBROUTINE OnNewGame(xWnd, ID, nCode) TYPE(X_WINDOW):: xWnd INTEGER, INTENT(IN):: ID, nCode INTEGER:: iSt, nFiles IF (nCode.EQ.0) THEN !Free entire table iState = LOCKED iState(1, 1) = FREE iState(14, 3) = FREE iState(:, 2) = FREE iState(7, :) = COMPLETE iState(10, :) = COMPLETE iState(15, :) = COMPLETE iResult = 0 iResult(7, :) = 0 iResult(10, :) = 0 iResult(15, :) = 0 iTotal = 0 CALL OnNewRoll(xWnd, ID, nCode) END IF END SUBROUTINE OnNewGame !======================================================= !PURPOSE: Handler for exit menu item SUBROUTINE OnExit(xWnd, ID, nCode) TYPE(X_WINDOW):: xWnd INTEGER:: ID, nCode INTEGER:: iSt iSt = XSendMessage(XW_FRAME, WM_CLOSE, 0, 0) END SUBROUTINE OnExit !======================================================= !PURPOSE: Draws the table on xDC. Called from OnPaint callback. SUBROUTINE DrawTable(xDC) TYPE(X_DC):: xDC !Column titles (arrows in "Symbol" font) INTEGER, PARAMETER:: sColTitle(8) = (/175, 171, 173, 65, 65, 65, 65, 65/) CHARACTER(15), PARAMETER:: sGames = '123456S+-SSFPYS' CHARACTER(4):: sNum INTEGER:: iSt, iXStep, iYStep, j, k, iLength, iX1, iY1, iX2, iY2, nColor1, nColor2, nColorText iXStep = 50 iYStep = 30 DO k = 1, 15 IF (k.NE.7 .AND. k.NE.10 .AND. k.NE.15) THEN iSt = XSetFont(xDC, "Arial"C, 12) ELSE iSt = XSetFont(xDC, "Symbol"C, 12) END IF iSt = XTextOut(xDC, 140, k*30+5, sGames(k:k), XCOLOR_LTGRAY) END DO DO j = 1, nColumns iSt = XSetFont(xDC, "Symbol"C, 12) iSt = XTextOut(xDC, 100+j*iXStep+iXStep/2-3, 5, CHAR(sColTitle(j)), XCOLOR_LTGRAY) iSt = XSetFont(xDC, "Arial"C, 12) DO k = 1, 15 ix1 = 100+j*(iXStep) ix2 = ix1+45 iy1 = k*(iYStep) iy2 = iy1+25 SELECT CASE (iState(k, j)) CASE(COMPLETE) nColor1 = XCOLOR_GREEN nColor2 = XCOLOR_BLACK nColorText = XCOLOR_LTGRAY CASE(LOCKED) nColor1 = XCOLOR_LTGRAY nColor2 = XCOLOR_GRAY nColorText = XCOLOR_GRAY CASE(FREE) nColor1 = XCOLOR_WHITE nColor2 = XCOLOR_BLACK nColorText = XCOLOR_BLACK END SELECT IF (k.NE.7 .AND. k.NE.10 .AND. k.NE.15) THEN CALL XSetBrush(xDC, nColor1) CALL XSetPen(xDC, nColor2) iSt = XRectangle(xDC, ix1, iy1, ix2, iy2) iSt = XRectangle(xDC, ix1+1, iy1+1, ix2-1, iy2-1) CALL XSetPen(xDC, XCOLOR_LTGRAY) CALL XMoveTo(xDC, ix1, iy2) iSt = XLineTo(xDC, ix2, iy2) iSt = XLineTo(xDC, ix2, iy1) CALL XMoveTo(xDC, ix1+1, iy2-1) iSt = XLineTo(xDC, ix2-1, iy2-1) iSt = XLineTo(xDC, ix2-1, iy1+1) END IF IF((iState(k, j).eq.COMPLETE)) THEN WRITE(sNum, "(i4)") iResult(k, j) CALL XGetTextExtent(xDC, sNum, iLength, iSt) |