******************** * C4W2NTK TUTORIAL ******************** * This is a NTK emulation of the original C4W sample named: * \CLIP4WIN\SOURCE\ODRAW.PRG * * * The NTK make procedure is: * MKRAD ODRAW * * * I can't believe it's Clip4Win! * Powered by NTK - http://www.ntkproject.com ******************** //////////////////////////// // // odraw.prg // // Copyright (C) 1993 Skelton Software, Kendal Cottage, Hillam, Leeds, UK. // All Rights Reserved. // // Owner Draw examples. // //////////////////////////// #define WIN_WANT_ALL // NTK: C4W deprecated /* #include "windows.ch" #include "msg.ch" #include "paint.ch" #include "drawitem.ch" */ // jnd: just add that for NTK #include "windows.ch" #include "ntkmsg.ch" // Window messages def. #include "ntkgdi.ch" // NTK Gdi & font def. #include "ntkimg.ch" // NTK bmp & image def. #include "ntkcmd.ch" // NTK rad msg and cmd def. (i.e. @...Say ) #include "c4w2ntk.ch" // C4W msg def and NTK translations // You can define this to get TAB, arrows, etc. between controls, // like in a dialog. Don't define it if you don't want these keystrokes // used that way! #define LIKE_DIALOG #define APPNAME "ODRAW" #ifdef LIKE_DIALOG #define BUTTONSTYLE WS_CHILD + WS_VISIBLE + BS_OWNERDRAW + WS_TABSTOP #else #define BUTTONSTYLE WS_CHILD + WS_VISIBLE + BS_OWNERDRAW #endif // LIKE_DIALOG #define IDC_BTN0 10 #define IDC_BTN1 11 #define IDC_BTN2 12 #define IDC_BTN3 13 static nBtn := 0 // the button id static nBN := 0 // notification code function main() local hWnd local aMsg[MSG_LENGTH] local hBtn0, hBtn1, hBtn2, hBtn3 // set up the main window hWnd = WndSetup(APPNAME, "Clip-4-Win Owner Draw Demo", ; {|hWnd, nMsg, nwParam, nlParam| ; WndProc(hWnd, nMsg, nwParam, nlParam)},; {WM_DESTROY, WM_COMMAND, ; WM_PAINT, ; WM_RBUTTONDOWN, ; WM_DRAWITEM}, ; // sent when time to draw the owner-draw item ,,,, ; // default x,y,w,h ,,, ; // default icon, cursor, background brush WS_OVERLAPPEDWINDOW + WS_CLIPCHILDREN) // window style // a pre-packaged owner-drawn button (PRG source for BitmapButton() is below) hBtn0 = BitmapButton(hWnd, ; // parent 300, 150, ; // x,y 40, 20, ; // width, height ReadDIB("play.bmp"),; // bitmap to show {|| SetPos(1,1), qout("single click")},; {|| SetPos(1,1), qout("double click")},; IDC_BTN0) // id to use // let's have some owner-drawn buttons hBtn1 = CreateWindow("button", ; // wind class "", ; // text BUTTONSTYLE, ; // style 250, 200, ; // x,y 40, 20, ; // w,h hWnd, ; // parent IDC_BTN1) // the id's are what tell these apart // (hBtn1, hBtn2 etc. would do, too) hBtn2 = CreateWindow("button", ; "", ; BUTTONSTYLE, ; 350, 200, ; 40, 20, ; hWnd, ; IDC_BTN2) hBtn3 = CreateWindow("button", ; "", ; BUTTONSTYLE, ; 280, 250, ; 80, 40, ; hWnd, ; IDC_BTN3) #ifdef LIKE_DIALOG SetFocus(hBtn0) do while GetMessage(aMsg, 0, 0, 0) if IsWindow(hWnd) .and. !IsDialogMessage(hWnd, aMsg) TranslateMessage(aMsg) DispatchMessage(aMsg) // WndProc() often gets called from here endif enddo #else do while GetMessage(aMsg, 0, 0, 0) TranslateMessage(aMsg) DispatchMessage(aMsg) // WndProc() often gets called from here enddo #endif // LIKE_DIALOG if IsWindow(hWnd) DestroyWindow(hWnd) endif UnregisterClass(APPNAME, _GetInstance()) return aMsg[MSG_wParam] function WndProc(hWnd, nMsg, nwParam, nlParam) local aPaint[PS_LENGTH], hDC do case case nMsg == WM_PAINT hDC = BeginPaint(hWnd, aPaint) TextOut(hDC, 50, 100, "Id" + str(nBtn)) TextOut(hDC, 50, 120, "Notification code" + str(nBN)) EndPaint(hWnd, aPaint) return 0 // 0 means we processed the msg case nMsg == WM_DRAWITEM // decode what/why/who from // (using the id, but you could test // C4W_LoWord(nlParam) == hBtn1, etc.) do case case nwParam == IDC_BTN1 return DrawBtn1(hWnd, nMsg, nwParam, nlParam) case nwParam == IDC_BTN2 return DrawBtn2(hWnd, nMsg, nwParam, nlParam) case nwParam == IDC_BTN3 return DrawBtn3(hWnd, nMsg, nwParam, nlParam) endcase case nMsg == WM_COMMAND do case case nwParam == IDC_BTN1 ; .or. nwParam == IDC_BTN2 ; .or. nwParam == IDC_BTN3 nBtn = nwParam // save the id nBN = C4W_HiWord(nlParam) // save the notification code InvalidateRect(hWnd) // This doesn't appear to be needed... //#ifdef LIKE_DIALOG // SetFocus(C4W_LoWord(nlParam)) //#endif // LIKE_DIALOG return 0 // 0 means we processed the msg endcase case nMsg == WM_DESTROY // leave out this, and you can't exit!! PostQuitMessage(0) return 0 // 0 means we processed the msg case nMsg == WM_RBUTTONDOWN // GetDlgItem() works for a parent and child DestroyWindow(GetDlgItem(hWnd, IDC_BTN0)) endcase // This could _only_ get used with WM_USER and above msgs -- because of // the array of msgs we specified with RegisterClass() -- and we're // not using WM_USER etc. However, it's always a good idea to allow // for the unexpected. return DefWindowProc(hWnd, nMsg, nwParam, nlParam) #ifdef LIKE_DIALOG #define BMPBTNSTYLE WS_CHILD + WS_VISIBLE + WS_TABSTOP #else #define BMPBTNSTYLE WS_CHILD + WS_VISIBLE #endif // LIKE_DIALOG // // BitmapButton() -- general-purpose function for a button showing a bitmap // function BitmapButton(hWnd, nX, nY, nW, nH, cDIB, bClick, bDblClick, nId) static lWClass := .f., aBtn := {} local hWin, hBtn, hCurWnd := SelectWindow() if !lWClass // register a window class to capture the button messages if !(lWClass := RegisterClass(0, , , , , "BmpButtn", ; {|hW, nMsg, nw, nl| ; DoBmpBtn(hW, nMsg, nw, nl, aBtn)},; {WM_COMMAND, WM_DESTROY, ; WM_DRAWITEM, WM_SETFOCUS})) return 0 // failed endif endif if (hWin := CreateWindow("BmpButtn", , BMPBTNSTYLE, ; nX, nY, nW, nH, hWnd, nId)) == 0 ; .or. (hBtn := CreateWindow("button", "", BUTTONSTYLE, ; 0, 0, nW, nH, hWin, nId)) == 0 return 0 // failed endif aadd(aBtn, {hWin, cDIB, bClick, bDblClick}) SelectWindow(hCurWnd) return hBtn static function DoBmpBtn(hWnd, nMsg, nwParam, nlParam, aBtn) local i, nBN local aDIS, hDC local nDX, nDY local nLeft, nTop, nRight, nBottom local lSelected, hOldPen do case case nMsg == WM_DRAWITEM // nlParam is LPDRAWITEMSTRUCT (i.e. a C pointer to 26 bytes of data) // NTK: C4W deprecated aDIS := bin2a(c4w_peek(nlParam, 26), DIS_STRUCT_DEF) // NTK: This is more NTK Win32 compliant! aDIS := NTK_DRAWITEM2A(nlParam) // See DRAWITEM/DIS structure members in NTKGDI.CH hDC := aDIS[DIS_hDC] nDX := nDY := 0 nLeft := aDIS[DIS_rcLeft] nTop := aDIS[DIS_rcTop] nRight := aDIS[DIS_rcRight] - 1 nBottom := aDIS[DIS_rcBottom] - 1 if (i := ascan(aBtn, {|a| a[1] == hWnd})) == 0 ; .or. aDIS[DIS_CtlType] != ODT_BUTTON return DefWindowProc(hWnd, nMsg, nwParam, nlParam) endif if lSelected := (C4W_And(aDIS[DIS_itemState], ODS_SELECTED) != 0) nDX := nDY := 2 // shift across and down endif ShowDIB(hDC, aBtn[i, 2], nDX, nDY) if C4W_And(aDIS[DIS_itemState], ODS_FOCUS) != 0 DrawFocusRect(hDC, {nLeft + 4, nTop + 4, nRight - 4, nBottom - 4}) endif hOldPen = SelectObject(hDC, GetStockObject(BLACK_PEN)) // draw border MoveTo(hDC, nLeft, nBottom) LineTo(hDC, nLeft, nTop) LineTo(hDC, nRight, nTop) LineTo(hDC, nRight, nBottom) LineTo(hDC, nLeft, nBottom) // draw 3-d effect SelectObject(hDC, GetStockObject(iif(lSelected, BLACK_PEN, WHITE_PEN))) nLeft++ ; nRight-- ; nTop++ ; nBottom-- MoveTo(hDC, nLeft, nBottom) LineTo(hDC, nLeft, nTop) LineTo(hDC, nRight, nTop) SelectObject(hDC, GetStockObject(iif(lSelected, WHITE_PEN, BLACK_PEN))) LineTo(hDC, nRight, nBottom) LineTo(hDC, nLeft, nBottom) SelectObject(hDC, hOldPen) return 0 // 0 means we processed the msg case nMsg == WM_COMMAND if (i := ascan(aBtn, {|a| a[1] == hWnd})) != 0 // found the button if (nBN := C4W_HiWord(nlParam)) == BN_CLICKED eval(aBtn[i, 3]) elseif nBN == BN_DOUBLECLICKED eval(aBtn[i, 4]) endif // This doesn't appear to be needed... //#ifdef LIKE_DIALOG // SetFocus(C4W_LoWord(nlParam)) //#endif // LIKE_DIALOG return 0 endif #ifdef LIKE_DIALOG case nMsg == WM_SETFOCUS // ? "SetFocus" if (i := ascan(aBtn, {|a| a[1] == hWnd})) != 0 // ?? " to child", i SetFocus(GetWindow(hWnd, GW_CHILD)) // focus to the button endif #endif // LIKE_DIALOG case nMsg == WM_DESTROY if (i := ascan(aBtn, {|a| a[1] == hWnd})) != 0 adel(aBtn, i) // remove it, now it's gone asize(aBtn, len(aBtn) - 1) endif endcase return DefWindowProc(hWnd, nMsg, nwParam, nlParam) // this one's very simple, but doesn't do much static function DrawBtn1(hWnd, nMsg, nwParam, nlParam) static cDIB // nMsg == WM_DRAWITEM, so nlParam is LPDRAWITEMSTRUCT (i.e. a C pointer) // NTK: C4W deprecated local aDIS := bin2a(c4w_peek(nlParam, 26), DIS_STRUCT_DEF) // NTK: This is more NTK Win32 compliant! Local aDIS := NTK_DRAWITEM2A(nlParam) // See DRAWITEM/DIS structure members in NTKGDI.CH local hDC := aDIS[DIS_hDC] if cDIB == nil cDIB = ReadDIB("play.bmp") endif if aDIS[DIS_CtlType] == ODT_BUTTON ShowDIB(hDC, cDIB) return 0 // 0 means we processed the msg endif return DefWindowProc(hWnd, nMsg, nwParam, nlParam) // this one's more interesting static function DrawBtn2(hWnd, nMsg, nwParam, nlParam) static cDIB // NTK: C4W deprecated local aDIS := bin2a(c4w_peek(nlParam, 26), DIS_STRUCT_DEF) // NTK: This is more NTK Win32 compliant! Local aDIS := NTK_DRAWITEM2A(nlParam) // See DRAWITEM/DIS structure members in NTKGDI.CH local hDC := aDIS[DIS_hDC] local nDX := 0, nDY := 0 local nLeft := aDIS[DIS_rcLeft], nTop := aDIS[DIS_rcTop], ; nRight := aDIS[DIS_rcRight] - 1, nBottom := aDIS[DIS_rcBottom] - 1 local lSelected, hOldPen if aDIS[DIS_CtlType] != ODT_BUTTON return DefWindowProc(hWnd, nMsg, nwParam, nlParam) endif if cDIB == nil cDIB = ReadDIB("play.bmp") endif if lSelected := (C4W_And(aDIS[DIS_itemState], ODS_SELECTED) != 0) nDX := nDY := 2 // shift across and down endif ShowDIB(hDC, cDIB, nDX, nDY) hOldPen = SelectObject(hDC, GetStockObject(BLACK_PEN)) // draw border MoveTo(hDC, nLeft, nBottom) LineTo(hDC, nLeft, nTop) LineTo(hDC, nRight, nTop) LineTo(hDC, nRight, nBottom) LineTo(hDC, nLeft, nBottom) // draw 3-d effect SelectObject(hDC, GetStockObject(iif(lSelected, BLACK_PEN, WHITE_PEN))) nLeft++ ; nRight-- ; nTop++ ; nBottom-- MoveTo(hDC, nLeft, nBottom) LineTo(hDC, nLeft, nTop) LineTo(hDC, nRight, nTop) SelectObject(hDC, GetStockObject(iif(lSelected, WHITE_PEN, BLACK_PEN))) LineTo(hDC, nRight, nBottom) LineTo(hDC, nLeft, nBottom) SelectObject(hDC, hOldPen) return 0 // 0 means we processed the msg // this one's more interesting static function DrawBtn3(hWnd, nMsg, nwParam, nlParam) static cDIB // NTK: C4W deprecated local aDIS := bin2a(c4w_peek(nlParam, 26), DIS_STRUCT_DEF) // NTK: This is more NTK Win32 compliant! Local aDIS := NTK_DRAWITEM2A(nlParam) // See DRAWITEM/DIS structure members in NTKGDI.CH local hDC := aDIS[DIS_hDC] local nDX := 0, nDY := 0 local nLeft := aDIS[DIS_rcLeft], nTop := aDIS[DIS_rcTop], ; nRight := aDIS[DIS_rcRight] - 1, nBottom := aDIS[DIS_rcBottom] - 1 local lSelected, hOldPen if aDIS[DIS_CtlType] != ODT_BUTTON return DefWindowProc(hWnd, nMsg, nwParam, nlParam) endif if cDIB == nil cDIB = ReadDIB("play.bmp") endif if lSelected := (C4W_And(aDIS[DIS_itemState], ODS_SELECTED) != 0) nDX := nDY := 2 // shift across and down endif StretchDIBits(hDC, ; nDX, nDY, nRight, nBottom, ; , , , , ; , cDIB) hOldPen = SelectObject(hDC, GetStockObject(BLACK_PEN)) // draw border MoveTo(hDC, nLeft, nBottom) LineTo(hDC, nLeft, nTop) LineTo(hDC, nRight, nTop) LineTo(hDC, nRight, nBottom) LineTo(hDC, nLeft, nBottom) // draw 3-d effect SelectObject(hDC, GetStockObject(iif(lSelected, BLACK_PEN, WHITE_PEN))) nLeft++ ; nRight-- ; nTop++ ; nBottom-- MoveTo(hDC, nLeft, nBottom) LineTo(hDC, nLeft, nTop) LineTo(hDC, nRight, nTop) SelectObject(hDC, GetStockObject(iif(lSelected, WHITE_PEN, BLACK_PEN))) LineTo(hDC, nRight, nBottom) LineTo(hDC, nLeft, nBottom) SelectObject(hDC, hOldPen) return 0 // 0 means we processed the msg