Calculadora usando classe

Aqui você poderá oferecer suas Contribuições, Dicas e Tutoriais (Texto ou Vídeo) que sejam de interesse de todos.

Moderador: Moderadores

Avatar do usuário
JoséQuintas
Administrador
Administrador
Mensagens: 20267
Registrado em: 26 Fev 2007 11:59
Localização: São Paulo-SP

Calculadora usando classe

Mensagem por JoséQuintas »

Depois de 20 anos sem mexer na minha calculadora, cismei de refazer.
Só que não lembrava mais pra que servia cada variável... rs
Acabei fazendo uma nova usando classes, e deixando fácil entender pra que serve cada coisa.
Senão daqui a um tempo vou esquecer de novo.... rs

Também pode ser útil pra estudar sobre classe.

Acho que tá fácil de entender e mexer.

No caso da porcentagem, funciona assim:

1000 - display 1000
5 % display 50
= display 950

e o bloco do percentual é este, só pra mostrar como tá fácil de mexer:

Código: Selecionar todos

METHOD Percent()
   IF ::cPendingOperation $ "+-"
      ::cValueDisplay := ValToString( ::nValueTotal * Val( ::cValueDisplay ) / 100 )
   ELSE
      ::cValueDisplay := ValToString( Val( ::cValueDisplay ) / 100 )
   ENDIF
   RETURN NIL
Até postei o fonte, mas retirei porque vou postar um mais completo.
José M. C. Quintas
Harbour 3.2, mingw, gtwvg mt, fivewin 25.04, multithread, dbfcdx, MySQL, ADOClass, PDFClass, SefazClass, (hwgui mt), (hmg3), (hmg extended), (oohg), PNotepad, ASP, stored procedure, stored function, Linux (Flagship/harbour 3.2)
"The world is full of kings and queens, who blind our eyes and steal our dreams Its Heaven and Hell"

https://github.com/JoseQuintas/
Avatar do usuário
JoséQuintas
Administrador
Administrador
Mensagens: 20267
Registrado em: 26 Fev 2007 11:59
Localização: São Paulo-SP

Calculadora usando classe

Mensagem por JoséQuintas »

O fonte, com fita infinita.
Coloquei cores padrão pra poder postar, porque aqui pego do sistema.

Código: Selecionar todos

#include "hbgtinfo.ch"
#include "inkey.ch"
#include "hbclass.ch"

PROCEDURE Main
   LOCAL oCalculator := CalculatorClass():New()
   SetMode( 25, 80 )
   oCalculator:Execute()
   RETURN

CREATE CLASS CalculatorClass
   DATA   nTop                INIT 10
   DATA   nLeft               INIT Int( ( MaxCol() - 30 ) / 2 )
   DATA   nValueTotal         INIT 0
   DATA   nValueMemory        INIT 0
   DATA   cValueDisplay       INIT ""
   DATA   cPendingOperation   INIT " "
   DATA   lBeginNumber        INIT .T.
   DATA   cSaveScreen
   DATA   acTape              INIT { " " }
   METHOD Execute()
   METHOD Number( cNumber )
   METHOD Comma()
   METHOD Back()
   METHOD Clear()
   METHOD Operation( cOperation )
   METHOD Percent()
   METHOD MemoryClear()
   METHOD MemoryRead()
   METHOD MemoryAdd()
   METHOD MemorySubtract()
   METHOD Show()
   METHOD WriteTape( cFlag )
   METHOD ShowTape()
   METHOD Move( nKey )
   ENDCLASS

METHOD Execute() CLASS CalculatorClass
   LOCAL oGet, cOldColor := SetColor()
   LOCAL nKey, cStrKey

   oGet := GetActive()

   IF oGet != NIL
      IF oGet:Type == "N"
         ::cValueDisplay = LTrim( Str( oGet:varGet(), 22, 2 ) )
      ENDIF
   ENDIF
   SAVE SCREEN TO ::cSaveScreen
   DO WHILE .T.
      ::Show()
      nKey    := Inkey(0)
      cStrKey := iif( nKey == K_ENTER, "=", Upper( Chr( nKey ) ) )
      DO CASE 
      CASE nKey == K_ESC
         KEYBOARD Chr( 205 )
         Inkey(0)
         EXIT
      CASE cStrKey == "D"
         IF oGet != NIL
            IF oGet:Type == "N"
               oGet:varPut( Val( ::cValueDisplay ) )
            ENDIF
            EXIT
         ENDIF
      CASE nKey == K_BS
         ::Back()
      CASE nKey == K_LEFT .OR. nKey == K_RIGHT .OR. nKey == K_UP .OR. nKey == K_DOWN
         ::Move( nKey )
      CASE cStrKey $ "0123456789"
         ::Number( cStrKey )
      CASE cStrKey $ ".,"
         ::Comma()
      CASE cStrKey $ "+-*/="
         ::Operation( cStrKey )
      CASE cStrKey == "%"
         ::Percent()
      CASE cStrKey == "C"
         ::Clear()
      CASE cStrKey == "M"
         cStrKey := " "
         nKey    := 0
         DO WHILE .NOT. cStrKey $ "CR+-" .AND. nKey != K_BS // .AND. nKey != K_CTRL_BS
            nKey := Inkey(0)
            cStrKey := Upper( Chr( nKey ) )
         ENDDO
         cStrKey := "M" + cStrKey
         DO CASE
         CASE nKey == K_BS // .OR. nKey == K_CTRL_BS
            RETURN NIL
         CASE cStrKey == "MC"
            ::MemoryClear()
         CASE cStrKey == "MR"
            ::MemoryRead()
         CASE cStrKey == "M+"
            ::MemoryAdd()
         CASE cStrKey == "M-"
            ::MemorySubtract()
         ENDCASE
      CASE cStrKey == "T"
         ::ShowTape()
      ENDCASE
   ENDDO
   RESTORE SCREEN FROM ::cSaveScreen
   SetColor( cOldColor )
   RETURN NIL

METHOD Percent() CLASS CalculatorClass
   ::WriteTape( "%" )
   IF ::cPendingOperation $ "+-"
      ::cValueDisplay := ValToString( ::nValueTotal * Val( ::cValueDisplay ) / 100 )
   ELSE
      ::cValueDisplay := ValToString( Val( ::cValueDisplay ) / 100 )
   ENDIF
   RETURN NIL

METHOD Operation( cOperation ) CLASS CalculatorClass
   DO CASE
   CASE ::cPendingOperation == "+"
      ::nValueTotal := ::nValueTotal + Val( ::cValueDisplay )
   CASE ::cPendingOperation == "-"
      ::nValueTotal := ::nValueTotal - Val( ::cValueDisplay )
   CASE ::cPendingOperation == "*"
      ::nValueTotal := ::nValueTotal * Val( ::cValueDisplay )
   CASE ::cPendingOperation == "/"
      ::nValueTotal := ::nValueTotal / Val( ::cValueDisplay )
   OTHERWISE
      ::nValueTotal := Val( ::cValueDisplay )
   ENDCASE
   ::WriteTape( iif( ::cPendingOperation $ "+-*/", ::cPendingOperation, " " ) )
   ::cValueDisplay     := ValToString( ::nValueTotal )
   ::cPendingOperation := cOperation
   ::lBeginNumber      := .T.
   IF cOperation == "="
      ::WriteTape( cOperation )
   ENDIF
   RETURN NIL

METHOD Comma() CLASS CalculatorClass
   IF ::lBeginNumber
      ::cValueDisplay := ""
   ENDIF
   ::lBeginNumber := .F.
   IF .NOT. "." $ ::cValueDisplay
      IF Len( ::cValueDisplay ) == 0
         ::cValueDisplay += "0"
      ENDIF
      ::cValueDisplay += "."
   ENDIF
   RETURN NIL

METHOD Number( cNumber ) CLASS CalculatorClass
   IF ::lBeginNumber
      ::cValueDisplay := ""
   ENDIF
   ::lBeginNumber := .F.
   IF cNumber == "0" .AND. Len( ::cValueDisplay ) == 0
      RETURN NIL
   ENDIF
   ::cValueDisplay += cNumber
   RETURN NIL

METHOD Back() CLASS CalculatorClass
   IF Len( ::cValueDisplay ) > 0
      ::cValueDisplay := Left( ::cValueDisplay, Len( ::cValueDisplay ) - 1 )
   ENDIF
   RETURN NIL

METHOD Clear() CLASS CalculatorClass
   ::cValueDisplay = ""
   IF ::cPendingOperation == "C"
      ::nValueTotal := 0
   ENDIF
   ::cPendingOperation := "C"
   RETURN NIL

METHOD MemoryClear() CLASS CalculatorClass
   ::nValueMemory := 0
   RETURN NIL
   
METHOD MemoryRead() CLASS CalculatorClass
   ::cValueDisplay := ValToString( ::nValueMemory )
   RETURN NIL
   
METHOD MemoryAdd() CLASS CalculatorClass
   ::nValueMemory := ::nValueMemory + Val( ::cValueDisplay )
   RETURN NIL

METHOD MemorySubtract() CLASS CalculatorClass
   ::nValueMemory := ::nValueMemory - Val( ::cValueDisplay )
   RETURN NIL

METHOD Show() CLASS CalculatorClass
   LOCAL acCalculatorKeys, nCont, nCont2
   DispBegin()
   SetColor( "N/W" )
   @ ::nTop, ::nLeft CLEAR TO ::nTop + 11, ::nLeft + 30
   @ ::nTop, ::nLeft TO ::nTop + 11 , ::nLeft + 30
   @ ::nTop, ::nLeft + 1 SAY Padc( "Calculadora", 28 ) COLOR "W/B"
   @ ::nTop + 1, ::nLeft + 4  SAY iif( ::nValueMemory == 0, " ", "M" ) + Space(15)
   @ ::nTop + 1, ::nLeft + 20 SAY ::cPendingOperation
   IF Val( ::cValueDisplay ) > 9999999999999999999999999
      @ ::nTop + 2, ::nLeft + 1 SAY Padc( "OVERFLOW", 26 ) COLOR "R/W"
   ELSE
      @ ::nTop + 2, ::nLeft + 1  SAY Padl( ValToString( Val( ::cValueDisplay ) ), 28 ) + " " COLOR "W/N"
   ENDIF
   @ ::nTop + 3, ::nLeft + 1 TO ::nTop + 3, ::nLeft + 28
   acCalculatorKeys := { ;
      { "7", "8", "9", "/", "C",  "MC" }, ;
      { "4", "5", "6", "*", "CC", "MR" }, ;
      { "1", "2", "3", "-", "%",  "M+" }, ;
      { "0", ".", "=", "+", "T",  "M-" } }
   FOR nCont = 1 TO Len( acCalculatorKeys )
      FOR nCont2 = 1 TO Len( acCalculatorKeys[ nCont ] )
         @ ::nTop + 2 + nCont * 2, ::nLeft + nCont2 * 4 SAY acCalculatorKeys[ nCont, nCont2 ]
      NEXT
   NEXT
   DispEnd()
   RETURN NIL

METHOD WriteTape( cFlag ) CLASS CalculatorClass
   Aadd( ::acTape, Padl( ValToString( Val( ::cValueDisplay ) ), 28 ) + cFlag )
   RETURN NIL

METHOD Move( nKey ) CLASS CalculatorClass
   RESTORE SCREEN FROM ::cSaveScreen
   DO CASE
   CASE nKey == K_LEFT   
      ::nLeft := Max( 0, ::nLeft - 1 )
   CASE nKey == K_RIGHT
      ::nLeft := Min( MaxCol() - 32, ::nLeft + 1 )
   CASE nKey == K_UP
     ::nTop := Max( 0, ::nTop - 1 )
   CASE nKey == K_DOWN
      ::nTop := Min( MaxRow() - 11, ::nTop + 1 )
   ENDCASE
   RETURN NIL

METHOD ShowTape() CLASS CalculatorClass
   LOCAL cScreen, cOldColor
   cOldColor := SetColor( "N/W,W/N" )
   SAVE SCREEN TO cScreen
   @ ::nTop + 1, ::nLeft + 1 CLEAR TO ::nTop + 10, ::nLeft + 29
   aChoice( ::nTop + 1, ::nLeft + 1, ::nTop + 10, ::nLeft + 29, ::acTape, .t., , Len( ::acTape ) )
   RESTORE SCREEN FROM cScreen
   SetColor( cOldColor )
   RETURN NIL

STATIC FUNCTION ValToString( nValue )
   LOCAL cValue := Ltrim( Str( nValue, 50, 16 ) )
   IF "." $ cValue
      DO WHILE Right( cValue, 1 ) $ "0"
         cValue := Left( cValue, Len( cValue ) - 1 )
      ENDDO
      IF Right( cValue, 1 ) == "."
         cValue := Left( cValue, Len( cValue ) - 1 )
      ENDIF
   ENDIF
   RETURN cValue
José M. C. Quintas
Harbour 3.2, mingw, gtwvg mt, fivewin 25.04, multithread, dbfcdx, MySQL, ADOClass, PDFClass, SefazClass, (hwgui mt), (hmg3), (hmg extended), (oohg), PNotepad, ASP, stored procedure, stored function, Linux (Flagship/harbour 3.2)
"The world is full of kings and queens, who blind our eyes and steal our dreams Its Heaven and Hell"

https://github.com/JoseQuintas/
Avatar do usuário
JoséQuintas
Administrador
Administrador
Mensagens: 20267
Registrado em: 26 Fev 2007 11:59
Localização: São Paulo-SP

Calculadora usando classe

Mensagem por JoséQuintas »

Mexi de novo, mas só estética de fonte.

Agrupei os métodos de memória em um único.

Código: Selecionar todos

METHOD Memory( cStrKey ) CLASS CalculatorClass
   DO CASE
   CASE cStrKey == "MC"
      ::nValueMemory := 0
   CASE cStrKey == "MR"
      ::cValueDisplay := ValToString( ::nValueMemory )
   CASE cStrKey == "M+"
      ::nValueMemory := ::nValueMemory + Val( ::cValueDisplay )
   CASE cStrKey == "M-"
      ::nValueMemory := ::nValueMemory - Val( ::cValueDisplay )
   ENDCASE
   RETURN NIL
e agrupei o salva/restaura get em um método

Código: Selecionar todos

METHOD GetSaveLoad( lSave )
   LOCAL oGet
   
   lSave := iif( lSave == NIL, .f., lSave )
   oGet := GetActive()
   IF oGet != NIL
      IF oGet:Type == "N"
         IF lSave
            oGet:varPut( Val( ::cValueDisplay ) )
         ELSE
            ::cValueDisplay = LTrim( Str( oGet:varGet(), 22, 2 ) )
         ENDIF
      ENDIF
   ENDIF
   RETURN NIL
Vai ficar assim.... até a próxima mexida... rs
Talvez em alguma GUI.
José M. C. Quintas
Harbour 3.2, mingw, gtwvg mt, fivewin 25.04, multithread, dbfcdx, MySQL, ADOClass, PDFClass, SefazClass, (hwgui mt), (hmg3), (hmg extended), (oohg), PNotepad, ASP, stored procedure, stored function, Linux (Flagship/harbour 3.2)
"The world is full of kings and queens, who blind our eyes and steal our dreams Its Heaven and Hell"

https://github.com/JoseQuintas/
Avatar do usuário
JoséQuintas
Administrador
Administrador
Mensagens: 20267
Registrado em: 26 Fev 2007 11:59
Localização: São Paulo-SP

Calculadora usando classe

Mensagem por JoséQuintas »

Falei que era até a próxima mexida... rs

alterei a linha acima, ao invés de ltrim(Str(, usei o ValToString(

E agrupei na classe de memória inclusive o segundo inkey(0).

Ficou um fonte legal pra estudo de classe.
Acho que por isso gostei de ficar mexendo, pra praticar separação em métodos: simplificar e/ou agrupar por categoria.
O legal é que a lógica pode ser usada em ambiente gráfico.

Usando GUI no estilo Clipper, o clique de um botão poderia ser um Keyboard, ou uma chamada a um dos métodos específicos.
José M. C. Quintas
Harbour 3.2, mingw, gtwvg mt, fivewin 25.04, multithread, dbfcdx, MySQL, ADOClass, PDFClass, SefazClass, (hwgui mt), (hmg3), (hmg extended), (oohg), PNotepad, ASP, stored procedure, stored function, Linux (Flagship/harbour 3.2)
"The world is full of kings and queens, who blind our eyes and steal our dreams Its Heaven and Hell"

https://github.com/JoseQuintas/
Avatar do usuário
JoséQuintas
Administrador
Administrador
Mensagens: 20267
Registrado em: 26 Fev 2007 11:59
Localização: São Paulo-SP

Calculadora usando classe

Mensagem por JoséQuintas »

Testei usando algo básico da gtwvg.
Um visual simples.

Basicamente adicionei esta rotina pra criar os botões:
Só comparar com a rotina anterior de mostrar os botões, mesma lógica.
E os botões da gtwvg só fazem o keyboard da tecla. Um mixto GUI e não GUI.

Código: Selecionar todos

METHOD GUIButtons() CLASS CalculatorClass
   LOCAL acCalculatorKeys, nCont, nCont2, oThisButton
   acCalculatorKeys := { ;
      { "7", "8", "9", "/", "C",  "MC" }, ;
      { "4", "5", "6", "*", "CC", "MR" }, ;
      { "1", "2", "3", "-", "%",  "M+" }, ;
      { "0", ".", "=", "+", "T",  "M-" } }
   FOR nCont = 1 TO Len( acCalculatorKeys )
      FOR nCont2 = 1 TO Len( acCalculatorKeys[ nCont ] )
         oThisButton := wvgPushButton():New()
         oThisButton:Caption := acCalculatorKeys[ nCont, nCont2 ]
         oThisButton:PointerFocus := .F. 
         oThisButton:Create( , , { -( ::nTop + 2 + nCont * 2 ), -( ::nLeft + nCont2 * 4 ) }, { -1.5, -2.5 } )
         oThisButton:Activate := &( [{ || __Keyboard( "] + acCalculatorKeys[ nCont, nCont2 ] + [" ) }] )
         Aadd( ::aGUIButtons, oThisButton )
      NEXT
   NEXT
   RETURN NIL
Acabei precisando salvar em array, porque ao acionara a fita, precisa esconder/retornar os botões pra usar mesma janela.

Código: Selecionar todos

METHOD GUIButtonsVisible( lVisible ) CLASS CalculatorClass
   LOCAL nCont
   FOR nCont = 1 TO Len( ::aGUIButtons )
      IF lVisible
         ::aGUIButtons[ nCont ]:Show()
      ELSE
         ::aGUIButtons[ nCont ]:Hide()
      ENDIF
   NEXT
   RETURN NIL
Anexos
calculadora.png
calculadora.png (22.19 KiB) Exibido 2127 vezes
José M. C. Quintas
Harbour 3.2, mingw, gtwvg mt, fivewin 25.04, multithread, dbfcdx, MySQL, ADOClass, PDFClass, SefazClass, (hwgui mt), (hmg3), (hmg extended), (oohg), PNotepad, ASP, stored procedure, stored function, Linux (Flagship/harbour 3.2)
"The world is full of kings and queens, who blind our eyes and steal our dreams Its Heaven and Hell"

https://github.com/JoseQuintas/
alxsts
Colaborador
Colaborador
Mensagens: 3092
Registrado em: 12 Ago 2008 15:50
Localização: São Paulo-SP-Brasil

Calculadora usando classe

Mensagem por alxsts »

Olá!

Bacana Quintas. Obrigado por compartilhar.

Naqueles tempos de Clipper era necessário desenvolver tudo isso, se quiséssemos ter este recurso embutido em nossos sistemas. Atualmente é bem mais fácil, executando a calculadora do Windows (no Linux/Unix não sei como seria). Eu gosto de passar meu tempo brincando com essas coisas...
[]´s
Alexandre Santos (AlxSts)
Avatar do usuário
janio
Colaborador
Colaborador
Mensagens: 1846
Registrado em: 06 Jul 2004 07:43
Localização: UBAJARA - CE

Calculadora usando classe

Mensagem por janio »

Quintas,

Poderia postar o fonte completo com todas as alterações que vc foi fazendo no decorrer deste post? rsrss

Janio
fui...
e-mail:janioaguiar@yahoo.com.br
msn: janio_aguiar@hotmail.com
xHarbour1.2.1/Harbour3.2 + wvg + hwgui + Mediator + MySql
Avatar do usuário
JoséQuintas
Administrador
Administrador
Mensagens: 20267
Registrado em: 26 Fev 2007 11:59
Localização: São Paulo-SP

Calculadora usando classe

Mensagem por JoséQuintas »

Código: Selecionar todos

#include "hbgtinfo.ch"
#include "inkey.ch"
#include "hbclass.ch"

PROCEDURE Calcula
   LOCAL oCalculator := CalculatorClass():New()
   MEMVAR  m_Prog
   PRIVATE m_Prog := "CALCULA"

   SetMode( 33, 100 )
   CLS
   SET KEY K_SH_F10 TO
   oCalculator:Execute()
   SET KEY K_SH_F10 TO Calcula
   RETURN

CREATE CLASS CalculatorClass
   DATA   nWidth              INIT 31
   DATA   nHeight             INIT 11
   DATA   nTop                INIT MaxRow() - 12
   DATA   nLeft               INIT Int( ( MaxCol() - 30 ) / 2 )
   DATA   nValueTotal         INIT 0
   DATA   nValueMemory        INIT 0
   DATA   cValueDisplay       INIT ""
   DATA   cPendingOperation   INIT " "
   DATA   lBeginNumber        INIT .T.
   DATA   cSaveScreen
   DATA   acTape              INIT { " " }
   DATA   aGUIButtons         INIT {}
   DATA   acKeyboard          INIT { ;
; //      { "I+-", " ", " ", " ", " ",  "BS" }, ;
      { "7",   "8", "9", "/", "C",  "MC" }, ;
      { "4",   "5", "6", "*", "CC", "MR" }, ;
      { "1",   "2", "3", "-", "%",  "M+" }, ;
      { "0",   ".", "=", "+", "T",  "M-" } }
   METHOD Execute()
   METHOD Number( cNumber )
   METHOD Comma()
   METHOD Back()
   METHOD Clear()
   METHOD InvertSignal()
   METHOD Operation( cOperation )
   METHOD Percent()
   METHOD Memory()
   METHOD LoadSaveValue( lSave )
   METHOD Show()
   METHOD WriteTape( cFlag )
   METHOD ShowTape()
   METHOD Move( nKey )
   METHOD GuiShow()
   METHOD GuiDestroy()
   ENDCLASS

METHOD Execute() CLASS CalculatorClass
   LOCAL cOldColor := SetColor(), nKey, cStrKey

   ::LoadSaveValue()
   SAVE SCREEN TO ::cSaveScreen
   ::GuiShow()
   DO WHILE .T.
      ::Show()
      nKey    := Inkey(0)
      cStrKey := iif( nKey == K_ENTER, "=", Upper( Chr( nKey ) ) )
      DO CASE
      CASE nKey == K_ESC
         KEYBOARD Chr( 205 )
         Inkey(0)
         EXIT
      CASE cStrKey == "D"
         ::LoadSaveValue( .T. )
         KEYBOARD Chr( K_ESC )
      CASE nKey == K_BS .OR. cStrKey == "B"
         ::Back()
      CASE nKey == K_LEFT .OR. nKey == K_RIGHT .OR. nKey == K_UP .OR. nKey == K_DOWN .OR. nKey == K_CTRL_RIGHT ;
         .OR. nKey == K_CTRL_LEFT .OR. nKey == K_CTRL_UP .OR. nKey == K_CTRL_DOWN
         ::Move( nKey )
      CASE cStrKey $ "0123456789"
         ::Number( cStrKey )
      CASE cStrKey $ ".,"
         ::Comma()
      CASE cStrKey $ "+-*/="
         ::Operation( cStrKey )
      CASE cStrKey == "%"
         ::Percent()
      CASE cStrKey == "C"
         ::Clear()
      CASE cStrKey == "I"
         ::InvertSignal()
      CASE cStrKey == "M"
         ::Memory()
      CASE cStrKey == "T"
         ::ShowTape()
      ENDCASE
   ENDDO
   ::GuiDestroy()
   RESTORE SCREEN FROM ::cSaveScreen
   SetColor( cOldColor )
   RETURN NIL

METHOD Percent() CLASS CalculatorClass
   ::WriteTape( "%" )
   IF ::cPendingOperation $ "+-"
      ::cValueDisplay := ValToString( ::nValueTotal * Val( ::cValueDisplay ) / 100 )
   ELSEIF ::cPendingOperation == "/"
      ::cValueDisplay := ValToString( ::nValueTotal / Val( ::cValueDisplay ) * 100 )
   ELSE
      ::cValueDisplay := ValToString( Val( ::cValueDisplay ) / 100 )
   ENDIF
   RETURN NIL

METHOD Operation( cOperation ) CLASS CalculatorClass
   DO CASE
   CASE ::cPendingOperation == "+"
      ::nValueTotal := ::nValueTotal + Val( ::cValueDisplay )
   CASE ::cPendingOperation == "-"
      ::nValueTotal := ::nValueTotal - Val( ::cValueDisplay )
   CASE ::cPendingOperation == "*"
      ::nValueTotal := ::nValueTotal * Val( ::cValueDisplay )
   CASE ::cPendingOperation == "/"
      ::nValueTotal := ::nValueTotal / Val( ::cValueDisplay )
   OTHERWISE
      ::nValueTotal := Val( ::cValueDisplay )
   ENDCASE
   ::WriteTape( iif( ::cPendingOperation $ "+-*/", ::cPendingOperation, " " ) )
   ::cValueDisplay     := ValToString( ::nValueTotal )
   ::cPendingOperation := cOperation
   ::lBeginNumber      := .T.
   IF cOperation == "="
      ::WriteTape( cOperation )
      ::WriteTape()
   ENDIF
   RETURN NIL

METHOD InvertSignal() CLASS CalculatorClass
   ::cValueDisplay := ValToString( -Val( ::cValueDisplay ) )
   RETURN NIL

METHOD Comma() CLASS CalculatorClass
   IF ::lBeginNumber
      ::cValueDisplay := ""
   ENDIF
   ::lBeginNumber := .F.
   IF .NOT. "." $ ::cValueDisplay
      IF Len( ::cValueDisplay ) == 0
         ::cValueDisplay += "0"
      ENDIF
      ::cValueDisplay += "."
   ENDIF
   RETURN NIL

METHOD Number( cNumber ) CLASS CalculatorClass
   IF ::lBeginNumber
      ::cValueDisplay := ""
   ENDIF
   ::lBeginNumber := .F.
   IF cNumber == "0" .AND. Len( ::cValueDisplay ) == 0
      RETURN NIL
   ENDIF
   ::cValueDisplay += cNumber
   RETURN NIL

METHOD Back() CLASS CalculatorClass
   IF Len( ::cValueDisplay ) > 0
      ::cValueDisplay := Left( ::cValueDisplay, Len( ::cValueDisplay ) - 1 )
   ENDIF
   RETURN NIL

METHOD Clear() CLASS CalculatorClass
   ::cValueDisplay = ""
   IF ::cPendingOperation == "C"
      ::nValueTotal := 0
   ENDIF
   ::cPendingOperation := "C"
   RETURN NIL

METHOD Memory() CLASS CalculatorClass
   LOCAL cStrKey := " ", nKey := 0

   DO WHILE .NOT. cStrKey $ "CR+-" .AND. nKey != K_BS
      nKey := Inkey(0)
      cStrKey := Upper( Chr( nKey ) )
   ENDDO
   DO CASE
   CASE cStrKey == "C"
      ::nValueMemory := 0
   CASE cStrKey == "R"
      ::cValueDisplay := ValToString( ::nValueMemory )
   CASE cStrKey == "+"
      ::nValueMemory := ::nValueMemory + Val( ::cValueDisplay )
   CASE cStrKey == "-"
      ::nValueMemory := ::nValueMemory - Val( ::cValueDisplay )
   ENDCASE
   RETURN NIL

METHOD Show() CLASS CalculatorClass
   LOCAL nCont, nCont2

   DispBegin()
   SetColor( SetColorFocus() )
   @ ::nTop, ::nLeft CLEAR TO ::nTop + ::nHeight - 1, ::nLeft + ::nWidth - 1
   @ ::nTop, ::nLeft TO ::nTop + ::nHeight - 1 , ::nLeft + ::nWidth - 1
   @ ::nTop + 1, ::nLeft + 1  SAY iif( ::nValueMemory == 0, " ", "M" ) COLOR SetColorFocus()
   IF Val( ::cValueDisplay ) > 999999999999999999999999
      @ Row(), Col() SAY Padc( "OVERFLOW", ::nWidth - 4 ) COLOR SetColorAlerta()
   ELSE
      @ Row(), Col() SAY Padl( ValToString( Val( ::cValueDisplay ) ), ::nWidth - 5 ) COLOR SetColorFocus()
   ENDIF
   @ Row(), Col() SAY " " COLOR SetColorFocus()
   @ Row(), Col() SAY ::cPendingOperation COLOR SetColorFocus()
   @ ::nTop + 2, ::nLeft + 1 TO ::nTop + 2, ::nLeft + ::nWidth - 2
   FOR nCont = 1 TO Len( ::acKeyboard )
      FOR nCont2 = 1 TO Len( ::acKeyboard[ nCont ] )
         @ ::nTop + 1 + nCont * 2, ::nLeft + 1 + ( nCont2 - 1 ) * 5 SAY ::acKeyboard[ nCont, nCont2 ]
      NEXT
   NEXT
   DispEnd()
   RETURN NIL

METHOD WriteTape( cFlag ) CLASS CalculatorClass
   IF cFlag == NIL
      Aadd( ::acTape, Pad( "", ::nWidth - 2 ) )
   ELSE
      Aadd( ::acTape, Padl( ValToString( Val( ::cValueDisplay ) ), ::nWidth - 4 ) + " " + cFlag )
   ENDIF
   RETURN NIL

METHOD Move( nKey ) CLASS CalculatorClass
   ::GUIDestroy()
   RESTORE SCREEN FROM ::cSaveScreen
   DO CASE
   CASE nKey == K_LEFT
      ::nLeft := Max( 0, ::nLeft - 1 )
   CASE nKey == K_RIGHT
      ::nLeft := Min( MaxCol() - ::nWidth + 1, ::nLeft + 1 )
   CASE nKey == K_UP
      ::nTop := Max( 0, ::nTop - 1 )
   CASE nKey == K_DOWN
      ::nTop := Min( MaxRow() - ::nHeight + 1, ::nTop + 1 )
   CASE nKey == K_CTRL_UP
      ::nTop := 0
   CASE nKey == K_CTRL_DOWN
      ::nTop := MaxRow() - ::nHeight + 1
   CASE nKey == K_CTRL_LEFT
      ::nLeft := 0
   CASE nKey == K_CTRL_RIGHT
      ::nLeft := MaxCol() - ::nWidth + 1
   ENDCASE
   ::GuiShow()
   RETURN NIL

METHOD ShowTape() CLASS CalculatorClass
   LOCAL cScreen

   ::GuiDestroy()
   SAVE SCREEN TO cScreen
   @ ::nTop + 1, ::nLeft + 1 CLEAR TO ::nTop + ::nHeight - 2, ::nLeft + ::nWidth - 2
   aChoice( ::nTop + 1, ::nLeft + 1, ::nTop + ::nHeight - 2, ::nLeft + ::nWidth - 2, ::acTape, .t., , Len( ::acTape ) )
   RESTORE SCREEN FROM cScreen
   ::GUIShow()
   RETURN NIL

METHOD LoadSaveValue( lSave ) CLASS CalculatorClass
   LOCAL oGet

   lSave := iif( lSave == NIL, .f., lSave )
   oGet := GetActive()
   IF oGet != NIL
      IF oGet:Type == "N"
         IF lSave
            oGet:varPut( Val( ::cValueDisplay ) )
         ELSE
            ::cValueDisplay = ValToString( oGet:varGet() )
         ENDIF
      ENDIF
   ENDIF
   RETURN NIL

STATIC FUNCTION ValToString( nValue )
   LOCAL cValue := Ltrim( Str( nValue, 50, 16 ) )

   IF "." $ cValue
      DO WHILE Right( cValue, 1 ) $ "0"
         cValue := Left( cValue, Len( cValue ) - 1 )
      ENDDO
      IF Right( cValue, 1 ) == "."
         cValue := Left( cValue, Len( cValue ) - 1 )
      ENDIF
   ENDIF
   RETURN cValue

METHOD GUIShow() CLASS CalculatorClass
   LOCAL nCont, nCont2, oThisButton
   FOR nCont = 1 TO Len( ::acKeyboard )
      FOR nCont2 = 1 TO Len( ::acKeyboard[ nCont ] )
         oThisButton := wvgPushButton():New()
         oThisButton:Caption := ::acKeyboard[ nCont, nCont2 ]
         oThisButton:PointerFocus := .F.
         oThisButton:Create( , , { -( ::nTop + 1 + nCont * 2 ), -( ::nLeft + 1 + ( nCont2 - 1 ) * 5 ) }, { -1.5, -4 } )
//         oThisButton:Activate := &( [{ || __Keyboard( "] + ::acKeyboard[ nCont, nCont2 ] + [" ) }] )
         oThisButton:Activate := BuildBlockHB_KeyPut( Asc( ::acKeyboard[ nCont, nCont2 ] ) )
         Aadd( ::aGUIButtons, oThisButton )
      NEXT
   NEXT
   RETURN NIL

METHOD GUIDestroy() CLASS CalculatorClass
   LOCAL nCont
   FOR nCont = 1 TO Len( ::aGUIButtons )
      ::aGUIButtons[ nCont ]:Destroy()
   NEXT
   ::aGUIButtons := {}
   RETURN NIL

//-------- from application

FUNCTION BuildBlockHB_KeyPut( nKey )
   RETURN { || HB_KeyPut( nKey ) }

FUNCTION SetColorAlerta()
   RETURN "15/12"

FUNCTION SetColorFocus()
   RETURN "15/9"
José M. C. Quintas
Harbour 3.2, mingw, gtwvg mt, fivewin 25.04, multithread, dbfcdx, MySQL, ADOClass, PDFClass, SefazClass, (hwgui mt), (hmg3), (hmg extended), (oohg), PNotepad, ASP, stored procedure, stored function, Linux (Flagship/harbour 3.2)
"The world is full of kings and queens, who blind our eyes and steal our dreams Its Heaven and Hell"

https://github.com/JoseQuintas/
Responder