+ All Categories
Home > Documents > Alaska Hybrid Start For Clipper programmer

Alaska Hybrid Start For Clipper programmer

Date post: 14-Oct-2014
Category:
Upload: anon-812054
View: 723 times
Download: 0 times
Share this document with a friend
Description:
Clipper migration to Alaska Xbase++ can be easy if you know how to do it and where to start.If you don't.We will show you, step by step.
Popular Tags:
17
Second life for Clipper Application by Aleksandar Stefanovic 1 Alaska Hybrid Start for Clipper programmers Clipper migration can be easy if you know how to do that and where to start.
Transcript
Page 1: Alaska Hybrid Start For Clipper programmer

Second life for Clipper Application by Aleksandar Stefanovic

1

Alaska

Hybrid Start

for Clipper programmers

Clipper migration can be easy if you know

how to do that and where to start.

Page 2: Alaska Hybrid Start For Clipper programmer

Second life for Clipper Application by Aleksandar Stefanovic

2

Windows applications differ from DOS applications. Windows provides more then

thousand functions you can call. There is different program structure. Remember, from

the user’s point of view program seems to run in bordered rectangle (window). When we

start application a window appears, when we close the window, the programs stops.

When the user made a click in the window, application responds. You can have more

then one window active at the same time, window can be visible or hidden by other

windows, window need procedure to repaint themselves. Remember what Microsoft want

at start. Software that is easy to use. If someone learned one windows application, he or

she can use many others. WHY? Standard GUI elements, they are already familiar with

it.

Standard windows have borders, title bar, menu bar, drop down menu, control box,

system minimize and maximize buttons, scroll bars… Windows part inside windows

borders without title bar and menu bar we call client area. There we display information

to the user. In clipper DOS application we use screen for output and we have full control

of it. On windows, this is another story. We can use something that ALASKA call

HYBRID system or we can use full GUI system. Many programmers said that it is better

to move on to full GUI. For some applications I believe that they are right but sometimes

we DON’T NEED that. I love HYBRID system. Why they call it this way? Because you

have window who act like old DOS screen, you can control it by row and colons. All

clipper display functions work well with that kind of windows. Inside them you can use

all GUI elements but… This application can look nice but remember, if you want OLD

way of application control and if you thing that your users can and will accept it just do

it. On the other hand if you have time to separate display logic from your application you

can try to migrate to full GUI application. Some accounting applications (most clipper

ones are like that) don’t need that event driven logic and you can only try to make nicer

screens. You have to decide what to do and how you will make migration to windows

world. At start HYBRID model is perfect. There is some limitation and you must live

with that.

So, for clipper programmer first thing that is how to have window for input and output

which act like old DOS screen. In description of Alaska was said that it is 100% clipper

compatible. We can use our clipper display functions and commands. Question is not

how but where. In special window that is created using Alaska XbpCrt class.

This is window just like other but we have row and column in it and we can use it in

“old” DOS way. Nice thing is that we can create it before our let say clipper application

start. For this we will place it in special Alaska procedure APPSYS. This procedure is

executed before our MAIN function. We can write it once and we can forget about it.

Page 3: Alaska Hybrid Start For Clipper programmer

Second life for Clipper Application by Aleksandar Stefanovic

3

Lets write this procedure.

//////////////////////////////////////////////////////////////////////

// APPSYS.PRG

//////////////////////////////////////////////////////////////////////

#include "appevent.ch"

#include "xbp.ch"

#define DEF_ROWS 40

#define DEF_COLS 120

PROCEDURE AppSys()

LOCAL oCrt

LOCAL aSizeDesktop, aPos

local DEF_FONTHEIGHT:=16

local DEF_FONTWIDTH:=8

public maincrtobj

public maincrtwin

aSizeDesktop := AppDesktop():currentSize()

aPos := { (aSizeDesktop[1]-(DEF_COLS * DEF_FONTWIDTH)) /2, ;

(aSizeDesktop[2]-(DEF_ROWS * DEF_FONTHEIGHT)) /2 }

Do Case

Case aSizeDeskTop[1] = 1024

Def_FontHeight := 18

Def_FontWidth := 10

Endcase

oCrt := XbpCrt():New ( NIL, NIL, aPos, DEF_ROWS, DEF_COLS )

oCrt:FontWidth := DEF_FONTWIDTH

oCrt:FontHeight := DEF_FONTHEIGHT

oCrt:title := "This is Title"

oCRT:icon := ID_AS_ICON

oCrt:FontName := "Alaska Crt"

oCrt:sysmenu:=.f.

oCrt:visible:=.t.

oCrt:automark:=.f.

oCrt:Create()

oCrt:PresSpace()

SetAppWindow ( oCrt )

maincrtobj:=oCrt

maincrtwin:=oCrt:gethwnd()

RETURN

Page 4: Alaska Hybrid Start For Clipper programmer

Second life for Clipper Application by Aleksandar Stefanovic

4

As you see we define numbers for rows end columns. In DOS time we have limited

number of screen sizes but in ALASKA we have bigger freedom.

We start from windows desktop. We can get information about screen size (in pixels) and

use it to place our window on it. We can use different font size but here is first limit. We

can’t use all windows fonts. Why? Simple, we need fonts where we have the same size

for all characters. We have rows and columns. We can try to use other fonts in this crt

window but we will not get error if Alaska can’t display it in crt window.

Under windows we don’t have access to hardware divices but we can use windows

functions to access them. We can get identification and sometimes we call it handlers.

AppDesktop() function will give us desktop handler. Now we can use function

currentSize() and we will get array with X and Y size of desktop. Alaska don’t have

support for calling windows functions to change screen resolution, we can only detect

current screen size and act on it. If this size is 1024 and 768 we can create “DOS”

window that has 40 rows and 120 columns with font size 18 by 10 pixels. This is nice if

we have in our old DOS clipper applications support for only 80 by 25 screen size, we

can use this extra space for something else (pictures for example) and our screen will not

be monotony black screen.

How to create this class? This way:

First we must define it.

oCrt := XbpCrt():New ( NIL, NIL, aPos, DEF_ROWS, DEF_COLS )

In variable oCrt we have handler for our new class instance.

Function that actually create our class is method function

NEW() with parameters

XbpCrt():new( [<oParent>] , [<oOwner>] , [<aPos>] , ;

[<nRowCount>], [<nColCount>], [<cTitle>], ;

[<lVisible>] ) --> oXbpCrt

We will create instance of our window. Parent and owner are something that every

window have, If we put NIL for these parameters we want DESKTOP to be parent and

no owner. When we create this class we can define rows and columns numbers, title for

this window and is it visible or not.

Now we can start with 3 files, project.xpj, appsys.prg and testcrt.prg

Page 5: Alaska Hybrid Start For Clipper programmer

Second life for Clipper Application by Aleksandar Stefanovic

5

Project.xpj

[PROJECT]

COMPILE = xpp

COMPILE_FLAGS = /q /l

DEBUG = yes

GUI = yes

LINKER = alink

LINK_FLAGS =

RC_COMPILE = arc

RC_FLAGS = /v

VERSION = 2.0

TESTCRT.XPJ

[TESTCRT.XPJ]

testcrt.exe

[testcrt.exe]

testcrt.prg

appsys.prg

testcrt.obj

appsys.obj

appsys.prg

Appsys listing

//////////////////////////////////////////////////////////////////////

// APPSYS.PRG

//////////////////////////////////////////////////////////////////////

#include "xbp.ch"

PROCEDURE AppSys()

#define DEF_ROWS 40

#define DEF_COLS 120

LOCAL oCrt

LOCAL aSizeDesktop, aPos

local DEF_FONTHEIGHT:=16

local DEF_FONTWIDTH:=8

public maincrtobj

public maincrtwin

aSizeDesktop:=AppDesktop():currentSize()

Do Case

Case aSizeDeskTop[1] = 1024

Def_FontHeight := 18

Page 6: Alaska Hybrid Start For Clipper programmer

Second life for Clipper Application by Aleksandar Stefanovic

6

Def_FontWidth := 10

Endcase

oCrt := XbpCrt():New ( NIL, NIL, aPos, DEF_ROWS, DEF_COLS )

oCrt:FontWidth := DEF_FONTWIDTH

oCrt:FontHeight := DEF_FONTHEIGHT

oCrt:title := "Title for our application"

oCrt:FontName := "Alaska Crt"

oCrt:Create()

oCrt:PresSpace()

SetAppWindow ( oCrt )

maincrtobj:=oCrt

maincrtwin:=oCrt:gethwnd()

RETURN

Testcrt listing:

//////////////////////////////////////////////////////////////////////

//

// TESTCRT.PRG

//

//////////////////////////////////////////////////////////////////////

#include "Appevent.ch"

#include "Xbp.ch"

PROCEDURE Main

LOCAL nEvent

DO WHILE nEvent <> xbeP_Close

nEvent := AppEvent( @mp1, @mp2, @oXbp )

oXbp:handleEvent( nEvent, mp1, mp2 )

ENDDO

RETURN

Page 7: Alaska Hybrid Start For Clipper programmer

Second life for Clipper Application by Aleksandar Stefanovic

7

When we start PBUILD we will get testcrt.exe and now we have active window for our

application like old DOS one.

Let stop for a moment and learn how we can change some parameters of our window.

Properties for XbpCrt are

AlwaysOnTop, border, clipChildren, closeable, fontHeight, fontWidth, fontName,

gridMove, icon, minMax, SysMenu, takList, title, titleBar,visible, autoFocus. AutoMark,

DropFont. DropZone, helpLink, maxCol, maxRow, mouseMode, modalResult,

asyncFlush, toolTipText, useShortCuts, xSize, ySize.

Don’t be afraid of this, all of them have default values so you don’t need to change it. But

sometimes if you need or like you can set it to values you want.

Creating, reconfigurating or destroying our window with these methods.

:create( [<oParent>] , [<oOwner>] , [<aPos>] , ;

[<nRowCount>], [<nColCount>], [<cTitle>], ;

[<lVisible>] ) --> self

Page 8: Alaska Hybrid Start For Clipper programmer

Second life for Clipper Application by Aleksandar Stefanovic

8

:configure( [<oParent>] , [<oOwner>] , [<aPos>] , ;

[<nRowCount>], [<nColCount>], [<cTitle>], ;

[<lVisible>] ) --> self

:destroy()

there is more methods that you can use to get some values or to change them

:currentPos()

:currentSize()

:showModal()

:getFrameState()

:getModalState()

:hide()

:isVisible()

;menuBar()

:presSpace()

:setFont()

:setCompoundname()

:setFrameState()

:setModalState()

:setPointer()

:setTrackPointer()

:setPos()

:setSize()

:setTitle()

:show()

:toBack()

:toFront()

If you want you can control and act on mouse events using code blocks. You can define

events for:

enter(), leave(), lbClick(), lbDblClick(), lbDown(), lbUp(), mbClick(), mbDblClick(),

mbDown(), mbUp(), motion(), rbClick(), rbDblClick(), rbDown(), rbUp(), wheel().

How you can use these events?

Declare function MyMouseEnter() and MyMouseLeave()

Function MyMouseEnter(aPos)

@ 1,1 say “Mouse enter”

return (NIL)

Function MyMouseLeave()

@ 1,1 say “Mouse lieve”

return (NIL)

Page 9: Alaska Hybrid Start For Clipper programmer

Second life for Clipper Application by Aleksandar Stefanovic

9

We will define code blocks

Local block_me:={|s|MyMouseEnter(s)}

Local block_ml:={||MyMouseLeave()}

Now we must make connection with our window and these functions:

oCrt:enter:=block_me

oCrt:leave:=block_ml

All these function we can put in our TESTCRT.PRG.

This is only demonstration, but you have to use

Setmouse(.t.)

And

oCcrt:setTrackPointer(.t.)

In testcrt module we don’t have accees to oCrt but in APPSYS we define public variable

maincrtobj so you must use it.

New our testcrt looks like this

#include "Appevent.ch"

#include "Xbp.ch"

PROCEDURE Main

LOCAL nEvent

local block_me:={|s|MyMouseEnter(s)}

local block_ml:={||MyMouseLeave()}

maincrtobj:enter:=block_me

maincrtobj:leave:=block_ml

SetMouse(.t.)

maincrtobj:setTrackpointer(.t.)

DO WHILE nEvent <> xbeP_Close

nEvent := AppEvent( @mp1, @mp2, @oXbp )

oXbp:handleEvent( nEvent, mp1, mp2 )

ENDDO

RETURN

Function MyMouseEnter(aPos)

@ 1,1 say "Mouse Enter"

Page 10: Alaska Hybrid Start For Clipper programmer

Second life for Clipper Application by Aleksandar Stefanovic

10

return (NIL)

Function MyMouseLeave()

@ 1,1 say "Mouse Leave"

return (NIL)

Sometimes these functions DON’T WORK WELL. If we start our application and mouse

is not inside our windows, when we move it Alaska trigger our functions for mouse

detection but if application start and mouse is inside, NOTHING is happened. Nobody is

perfect. Other support is much, much better.

So, let’s find out some “nice” thing that we can do with our xbpcrt window.

If we need to change window title we can use:

Maincrtobj:setTitle(“New title”)

Changing frame state with

maincrtobj:setFrameState(XBPDLG_FRAMESTAT_MINIMIZED)

maincrtobj:setFrameState(XBPDLG_FRAMESTAT_NORMALIZED)

maincrtobj:setFrameState(XBPDLG_FRAMESTAT_MAXMIZED)

Hide and show window with

maincrtobj:hide()

maincrtobj:show()

Border can be set using maincrtobj:border:= one of these constants

XBPDLG_NO_BORDER

XBPDLG_SIZEBORDER

XBPDLG_THINBORDER

XBPDLG_DLGBORDER

XBPDLG_RAISEDBORDERTHICK

XBPDLG_RAISEDBORDERTHIN

XBPDLG_RECESSEDBORDERTHICK

XBPDLG_RECESSEDBORDERTHIN

XBPDLG_RAISEDBORDERTHICK_FIXED

XBPDLG_RAISEDBORDERTHIN_FIXED

XBPDLG_RECESSEDBORDERTHICK_FIXED

XBPDLG_RECESSEDBORDERTHIN_FIXED

System menu (in left upper corner) can be disabled

maincrtobj:sysmenu:=.f.

Pushbuttons in right upper corner can be hidden with

Page 11: Alaska Hybrid Start For Clipper programmer

Second life for Clipper Application by Aleksandar Stefanovic

11

Maincrtobj:closeable:=.f.

Maincrtobj:minMax:=.f.

I think that this is enough for start playing with CRT window.

On the other hand if you ever want to use other windows API functions that need window

handle you will get it using

Maincrtobj:gethwnd()

For now we have window where all text display functions work and we can add other

things that Alaska simple call xbase parts.

Now we can go on. What most window applications have? Menu. Now we will add menu

to our window.

In our application we will add:

AS_MENU( SetAppWindow():menuBar() )

We will define menu options in separate function as_menu.

function AS_MENU( oMenubar )

LOCAL oMenu

oMenu := XbpMenu():new( oMenuBar )

oMenu:title := "~System"

oMenu:create()

oMenu:itemSelected := {|nItem| MenuDispatcher( 100+nItem ) }

oMenu:addItem( {"~a) End" , NIL} )

oMenu:addItem( {NIL, NIL, XBPMENUBAR_MIS_SEPARATOR, 0} )

oMenu:addItem( {"~b) Indexing service", {||Indexserv()}} )

oMenubar:addItem( {oMenu, NIL} )

oMenu := XbpMenu():new( oMenuBar )

oMenu:title := "~AS Software"

oMenu:create()

oMenu:itemSelected := {|nItem| MenuDispatcher( 700+nItem ) }

oMenu:addItem( {"~a) About application" ,{||aboutas()}} )

oMenubar:addItem( {oMenu, NIL} )

RETURN (NIL)

Menu have to be build.

Page 12: Alaska Hybrid Start For Clipper programmer

Second life for Clipper Application by Aleksandar Stefanovic

12

First we must get handler for our menu

oMenu := XbpMenu():new( oMenuBar )

Now we will add title

oMenu:title := "~System"

and we create it

oMenu:create()

and we will add items (one by one).

First we define numeric values for menu items:

oMenu:itemSelected := {|nItem| MenuDispatcher( 100+nItem ) }

Then we define text and action

oMenu:addItem( {"~a) End" , NIL} )

oMenu:addItem( {NIL, NIL, XBPMENUBAR_MIS_SEPARATOR, 0} )

oMenu:addItem( {"~b) Indexing service", {||Indexserv()}} )

oMenubar:addItem( {oMenu, NIL} )

We need this procedure to:

PROCEDURE MenuDispatcher( nSelection )

DO CASE

CASE nSelection == 101

QUIT

ENDCASE

RETURN

First option will quit our application, then we have separator, then we add code block to

start one our function. We then send this data to windows. This way we will define all

application options.

All applications have big number of parts, I believe that your clipper application is

structured this way, so it will not be a big problem to make menu options to call your

modules.

To avoid problems, fist menu start with 100+nItem, second with 200+nItem… Don’t

forget this.

Page 13: Alaska Hybrid Start For Clipper programmer

Second life for Clipper Application by Aleksandar Stefanovic

13

We must have PRG file with function definition for our Indexserv() function and

aboutas()

Now we can add one more option for access our application modules. We will add

pushbutton but with pictures in it.

We need picture handle and we will load image from external file.

oBMP1:=XbpBitmap():new()

oBMP1:loadfile("pic1.jpg")

oBMP2:=XbpBitmap():new()

oBMP2:loadfile("pic2.jpg")

We will add 3 more pictures for decoration

oBMPdec0:=XbpBitmap():new()

oBMPdec0:loadfile("dec0.jpg")

oBMPdec1:=XbpBitmap():new()

oBMPdec1:loadfile("dec1.jpg")

oBMP1 and oBMP2 are handler for our pictures pushbutton (all pictures are 150x150

pixels.

First we need handler for it.

Xbpb := XbpPushButton():new()

We will create it

oXbpb:create( , , {10,450}, {150,150})

We create button 150x150 pixel at location 10,450.

We use cargo variable

oXbpb:cargo := .F

When button is activated we will start our test1 module.

oXbpb:activate := {|mp1, mp2, obj| obj:cargo := ! obj:cargo, ;

DrawBMPall( obj,oBMP2,0 ),test1() }

We have 2 pictures for our button and we want to act when mouse pointer is over it

oXbpb:paint := {|mp1, mp2, obj| DrawBMPall( obj,oBMP1,0 ) }

oXbpb:enter := {|mp1, mp2, obj| DrawBMPall( obj,oBMP1,0) }

oXbpb:leave := {|mp1, mp2, obj| DrawBMPall( obj,oBMP1,0) }

oXbpb:lbdown := {|mp1, mp2, obj| DrawBMPall( obj,oBMP2,0 ) }

oXbpb:motion := {|mp1, mp2, obj| DrawBMPall( obj,oBMP2,0 ) }

oXbpb:lbup := {|mp1, mp2, obj| DrawBMPall( obj,oBMP1,0 ) }

oXbpb:drawmode:=XBP_DRAW_OWNER

Page 14: Alaska Hybrid Start For Clipper programmer

Second life for Clipper Application by Aleksandar Stefanovic

14

DrawBmpall(oXbpb,oBMP1,-1)

Function for displaying pictures inside pushbutton is

STATIC PROCEDURE DrawBMPall( oControl,oBitmap,nn)

LOCAL oPS,

oPS := oControl:lockPS()

oBitmap:draw( oPS, {0 , 0})

oControl:unlockPS( oPS )

do case

case nn==0

oBMPden0:draw(oPSg,{500,50})

case nn==1

oBMPden1:draw(oPSg,{500,50})

ENDCASE

RETURN

What we do here? First we draw inside button. For this we need to use functions lock()

and unlock() to get access to button surface. Other pictures we draw inside our main crt

window. Notice that we don’t need to lock and unlock our main window, but when we

want to draw inside xbase parts we must use it. Lock is must call to enable pushbutton

drawing but don’t forget to unlock it. It is important not only for our application,

windows OS need that.

When mouse pointer move over pushbutton, we have picture change in button and in our

main window. Nice and easy. When we click on picture we start application module.

Until now we have explain XbpCrt, XbpMenu, XbpBitmap, XbpPushButton.

Remember, when we draw inside CRT window we can erase it using standard CLS

function. All drawing will be erased but pushbutton don’t. We can hide it using hide()

method or destroy() when we don’t need it any more.

Now our testcrt.prg is

#include "Appevent.ch"

#include "Xbp.ch"

PROCEDURE Main

LOCAL nEvent

local oBMP1,oBMP2

local oXbpb,oPS

private oPSg

private oBMPdec0,oBMPdec1

oPS := SetAppWindow():presSpace()

Page 15: Alaska Hybrid Start For Clipper programmer

Second life for Clipper Application by Aleksandar Stefanovic

15

oPSg:=oPS

SetMouse(.t.)

oBMP1:=XbpBitmap():new()

oBMP1:loadfile("pic1.jpg")

oBMP2:=XbpBitmap():new()

oBMP2:loadfile("pic2.jpg")

oBMPdec0:=XbpBitmap():new()

oBMPdec0:loadfile("dec0.jpg")

oBMPdec1:=XbpBitmap():new()

oBMPdec1:loadfile("dec1.jpg")

oXbpb := XbpPushButton():new()

oXbpb:create( , , {10,450}, {150,150})

oXbpb:cargo := .F.

oXbpb:activate := {|mp1, mp2, obj| obj:cargo := ! obj:cargo, ;

DrawBMPall( obj,oBMP2,1 ),test1() }

oXbpb:paint := {|mp1, mp2, obj| DrawBMPall( obj,oBMP1,1 ) }

oXbpb:enter := {|mp1, mp2, obj| DrawBMPall( obj,oBMP1,1) }

oXbpb:leave := {|mp1, mp2, obj| DrawBMPall( obj,oBMP1,0) }

oXbpb:lbdown := {|mp1, mp2, obj| DrawBMPall( obj,oBMP2,1 ) }

oXbpb:motion := {|mp1, mp2, obj| DrawBMPall( obj,oBMP2,1 ) }

oXbpb:lbup := {|mp1, mp2, obj| DrawBMPall( obj,oBMP1,1 ) }

oXbpb:drawmode:=XBP_DRAW_OWNER

DrawBmpall(oXbpb,oBMP1,0)

AS_MENU( SetAppWindow():menuBar() )

setcolor("W/N")

DO WHILE nEvent <> xbeP_Close

nEvent := AppEvent( @mp1, @mp2, @oXbp )

oXbp:handleEvent( nEvent, mp1, mp2 )

ENDDO

RETURN

PROCEDURE MenuDispatcher( nSelection )

DO CASE

CASE nSelection == 101

QUIT

Page 16: Alaska Hybrid Start For Clipper programmer

Second life for Clipper Application by Aleksandar Stefanovic

16

ENDCASE

RETURN

PROCEDURE AS_MENU( oMenubar )

LOCAL oMenu

oMenu := XbpMenu():new( oMenuBar )

oMenu:title := "~Sistem"

oMenu:create()

oMenu:itemSelected := {|nItem| MenuDispatcher( 100+nItem ) }

oMenu:addItem( {"~a) End" , NIL} )

oMenu:addItem( {NIL, NIL, XBPMENUBAR_MIS_SEPARATOR, 0} )

oMenu:addItem( {"~b) Indexing", {||indexserv()}} )

oMenubar:addItem( {oMenu, NIL} )

oMenu := XbpMenu():new( oMenuBar )

oMenu:title := "~AS Software"

oMenu:create()

oMenu:itemSelected := {|nItem| MenuDispatcher( 700+nItem ) }

oMenu:addItem( {"~a) Informacije o programu" ,{||aboutas()}} )

oMenubar:addItem( {oMenu, NIL} )

RETURN

STATIC PROCEDURE DrawBMPall( oControl,oBitmap,nn)

LOCAL oPS

oPS := oControl:lockPS()

oBitmap:draw( oPS, {0 , 0})

oControl:unlockPS( oPS )

do case

case nn==0

oBMPdec0:draw(oPSg,{500,50})

case nn==1

oBMPdec1:draw(oPSg,{500,50})

ENDCASE

RETURN

function test1()

msgbox("WE ARE NOW IN TEST1 function")

return (NIL)

Page 17: Alaska Hybrid Start For Clipper programmer

Second life for Clipper Application by Aleksandar Stefanovic

17

func indexserv()

return (NIL)

func aboutas()

return (NIL)

This is screen when we start our application. When we move mouse over picture button,

button will change and picture to.

Now our old Clipper application can look better.


Recommended