Página 1 de 1

Can I get help with this example?

Publicado: Mié Feb 19, 2025 9:50 pm
por DC
Thanks Ignacio for the TForm suggestion,

but I think I will need a TCanvas. The component need to have some text display methods.

I was able to fix several problems with the class, e.g. there was a problem setting the font, when using the

TCanvas:SelectFont

help topic. That topic example is

Código: Seleccionar todo

WITH OBJECT oFont := TFont():New()
       :Name    := "Arial"
       :oDevice := Printer
       :Create()
END WITH

WITH OBJECT oDevice:oCanvas
       :SelectFont( oFont )
       .....
END WITH

, but my use of that example results in an error when the :Name is assigned to "Courier New"

That problem is fixed, but I have a feeling there will be many more. Would it be possible for you to look this over, and offer some suggestions on how better to structure this? I'm trying to do a Text Mode emulation. I'll share the code when it's done.

Código: Seleccionar todo

/*
 * Project: TextModeEmulation
 * File: TextModeEmulator.prg
 * Description:
 * Author:
 * Date: 02-18-2025
 */

#include "Xailer.ch"

#define SCREEN_ROWS    25
#define SCREEN_COLS    80
#define CHAR_WIDTH     8  // pixels
#define CHAR_HEIGHT    16 // pixels

CLASS TScreenBuffer
      VAR aBuffer       // 2D array to hold characters
      VAR aAttributes   // 2D array to hold color attributes
      VAR nCursorRow
      VAR nCursorCol
      VAR oFont
      VAR oWindow      // GUI window reference

      METHOD New()
      METHOD t_DispOut(cText)
      METHOD t_QOut(cText)
      METHOD t_SetPos(nRow, nCol)
      METHOD t_Row()
      METHOD t_Col()
      METHOD t_SetColor(cColor)
      METHOD Refresh()   // Updates the GUI display
      METHOD ColorToAttribute(cColor)
      METHOD AttributeToRGB(nAttr)

      METHOD MakeAttribute(nFore, nBack)
      METHOD CurrentBackColor()


ENDCLASS

METHOD New() CLASS TScreenBuffer
   Local oFont
   ::aBuffer     := Array(SCREEN_ROWS, SCREEN_COLS)
   ::aAttributes := Array(SCREEN_ROWS, SCREEN_COLS)
   ::nCursorRow  := 0
   ::nCursorCol  := 0
   ::oFont := TFont():Create( "Courier New", 10 )


   // Initialize buffer with spaces
   AEval(::aBuffer, {|a| AFill(a, " ")})

/*
   WITH OBJECT oFont := TFont():New()
      :Name := "Courier New"
      :Create()
   END WITH
   ::oFont := oFont
*/

   // Create the GUI window with fixed-width font
   // ::oWindow := TFORM():New()   // Doesn't have TextOut or anything similar.
      ::oWindow := TCANVAS():New()

   // ::oWindow := TWindow():New()  // No oWindow
   // ::oWindow:Create()
   ::oWindow:SelectFont( ::oFont )
   // ::oWindow:SetFont("Courier New", 10)  // Doesn't work.

RETURN Self

METHOD t_DispOut(cText) CLASS TScreenBuffer
   LOCAL nLen := Len(cText)
   LOCAL i

   FOR i := 1 TO nLen
      IF ::nCursorCol >= SCREEN_COLS
         ::nCursorRow++
         ::nCursorCol := 0
         IF ::nCursorRow >= SCREEN_ROWS
            // Scroll buffer up
            ::ScrollUp()
         ENDIF
      ENDIF

      ::aBuffer[::nCursorRow + 1, ::nCursorCol + 1] := SubStr(cText, i, 1)
      ::nCursorCol++
   NEXT

   ::Refresh()
   RETURN NIL

METHOD Refresh() CLASS TScreenBuffer
   LOCAL nRow, nCol
   LOCAL cLine := ""

   // Convert buffer to GUI display
   // This is where we'd draw to the GUI window
   FOR nRow := 1 TO SCREEN_ROWS
      cLine := ""
      FOR nCol := 1 TO SCREEN_COLS
         cLine += ::aBuffer[nRow, nCol]
      NEXT
      // Draw line to GUI at proper position
      ::oWindow:TextOut(cLine, ;
                        nCol * CHAR_WIDTH, ;
                        nRow * CHAR_HEIGHT)
   NEXT

   // ::oWindow:Refresh() // There's no Refresh Method in TCanvas
   RETURN NIL

METHOD t_QOut(cText) CLASS TScreenBuffer
   ::t_DispOut(cText + HB_EOL())
   RETURN NIL

METHOD t_SetPos(nRow, nCol) CLASS TScreenBuffer
   // Ensure coordinates are within bounds
   ::nCursorRow := Min(Max(nRow, 0), SCREEN_ROWS - 1)
   ::nCursorCol := Min(Max(nCol, 0), SCREEN_COLS - 1)

   // Update cursor position in GUI
   // There's No SetCaretxxx method
   ::oWindow:SetCaretPos(::nCursorCol * CHAR_WIDTH, ;
                        ::nCursorRow * CHAR_HEIGHT)
   RETURN NIL

METHOD t_Row() CLASS TScreenBuffer
   RETURN ::nCursorRow

METHOD t_Col() CLASS TScreenBuffer
   RETURN ::nCursorCol

METHOD t_SetColor(cColor) CLASS TScreenBuffer
   LOCAL nFore, nBack
   LOCAL cChar

   // Parse standard color string (e.g., "W/N" for White on Black)
   IF "/"$ cColor
      cChar := SubStr(cColor, 1, 1)
      nFore := ::ColorToAttribute(cChar)

      cChar := SubStr(cColor, At("/", cColor) + 1, 1)
      nBack := ::ColorToAttribute(cChar)
   ELSE
      // If no background specified, use current background
      nFore := ::ColorToAttribute(SubStr(cColor, 1, 1))
      nBack := ::CurrentBackColor()
   ENDIF

   // Store current position's attribute
   ::aAttributes[::nCursorRow + 1, ::nCursorCol + 1] := ;
      ::MakeAttribute(nFore, nBack)

   // Update GUI colors
   ::oWindow:SetTextColor(::AttributeToRGB(nFore))
   ::oWindow:SetBkColor(::AttributeToRGB(nBack))

   RETURN NIL

// Helper methods for color handling
METHOD ColorToAttribute(cColor) CLASS TScreenBuffer
   LOCAL nAttr

   SWITCH Upper(cColor)
      CASE "N"; nAttr := 0; EXIT  // Black
      CASE "B"; nAttr := 1; EXIT  // Blue
      CASE "G"; nAttr := 2; EXIT  // Green
      CASE "C"; nAttr := 3; EXIT  // Cyan
      CASE "R"; nAttr := 4; EXIT  // Red
      CASE "M"; nAttr := 5; EXIT  // Magenta
      CASE "Y"; nAttr := 6; EXIT  // Yellow
      CASE "W"; nAttr := 7; EXIT  // White
      OTHERWISE
         nAttr := 7  // Default to white
   END

   RETURN nAttr

METHOD AttributeToRGB(nAttr) CLASS TScreenBuffer
   LOCAL aColors := { ;
      {   0,   0,   0 }, ;  // Black
      {   0,   0, 255 }, ;  // Blue
      {   0, 255,   0 }, ;  // Green
      {   0, 255, 255 }, ;  // Cyan
      { 255,   0,   0 }, ;  // Red
      { 255,   0, 255 }, ;  // Magenta
      { 255, 255,   0 }, ;  // Yellow
      { 255, 255, 255 } }   // White

   RETURN RGB(aColors[nAttr + 1, 1], ;
              aColors[nAttr + 1, 2], ;
              aColors[nAttr + 1, 3])

METHOD MakeAttribute(nFore, nBack) CLASS TScreenBuffer
   // Combine foreground and background into single attribute
   RETURN nFore + (nBack * 16)

METHOD CurrentBackColor() CLASS TScreenBuffer
   // Extract background color from current position's attribute
   RETURN Int(::aAttributes[::nCursorRow + 1, ::nCursorCol + 1] / 16)


FUNCTION TextModeEmulator()
   LOCAL oScreen := TScreenBuffer():New()

   // These would work similar to their console counterparts
   oScreen:t_DispOut("Hello from text-mode emulation!")
   oScreen:t_SetPos(5, 10)
   oScreen:t_QOut("Positioned text")

   RETURN NIL

Re: Can I get help with this example?

Publicado: Mar Mar 04, 2025 4:59 pm
por DC
No reply.

Well, I was looking for a reason to stop doing Harbour and focus on Python. Maybe this is a good time.

Re: Can I get help with this example?

Publicado: Mar Mar 04, 2025 10:38 pm
por ignacio
Hi,

Sorry, but I really do not understand what is your goal. If you need to simulate a terminal window, just use a Memo control with TCourier font or any other monospace font. If you really want to use a terminal window, Harbour HAS EVERYTHING YOU NEED. Xailer is for Windows desktop applications, BTW, I believe you can mix both worlds: windows desktop and terminal apps. On the project MinGW linking options just check the 'console mode' checkbox. You will see that with your desktop app, there will be a console window, that surely accepts Harbour console functions. BTW, I have never used. I do not know how it works. I even do not know how to hide or show that terminal window. Maybe some one in this forum can give you some advice.

Regards,

Re: Can I get help with this example?

Publicado: Mié Mar 05, 2025 5:14 pm
por DC
Couple of things.

1. I didn't know there was a console checkbox in the project settings, thanks. Although I won't be using Xailer or Harbour as much, I'm trying to avoid any further Harbour frustration related to environmental variables or a change in the C compiler. Sometimes, I waste weeks trying to compile an app, without getting anything done. Some examples are when I have to modify a harbour application that's compiled in MingW or VC, when my setup is primarily Borland. Or trying to use a third party library like some of the SQL Rdds, but all sorts of unresolved externals show up, and it doesn't matter what you add on the command line or hbmk2 configuration files or hwbc files.

The Xailer project manager is ideal for avoiding those frustrations, partly because it doesn't depend on PATHs or external environmental variables.

2. I'm not building a console application, in this case. I'm trying to emulate one. This Would be the best of both worlds, because both the Xailer project manager & debugger are available in this environment, as well as all of the common windows elements if needed.

Attached is a non-Harbour/Xailer example of this emulation, using React.

At any rate, I don't think you can help with this. I'm focusing more on Python anyway, but still want to modify apps with the Harbour language from time to time.

Código: Seleccionar todo

import React, { useState } from 'react';

const TextModeEmulator = () => {
  const [selectedItem, setSelectedItem] = useState(0);
  const menuItems = ['File', 'Edit', 'View', 'Help'];

  // Simulated text-mode colors
  const styles = {
    screen: 'bg-blue-900 text-white font-mono p-4 w-full h-96 border-4 border-gray-300',
    header: 'bg-blue-900 text-white p-1',
    menuBar: 'flex bg-gray-200 text-black',
    menuItem: 'px-4 py-1',
    selectedMenuItem: 'px-4 py-1 bg-blue-900 text-white',
    content: 'mt-2 p-2 border border-white'
  };

  const handleKeyDown = (e) => {
    if (e.key === 'ArrowLeft') {
      setSelectedItem(prev => (prev > 0 ? prev - 1 : menuItems.length - 1));
    } else if (e.key === 'ArrowRight') {
      setSelectedItem(prev => (prev < menuItems.length - 1 ? prev + 1 : 0));
    }
  };

  return (
    <div 
      className={styles.screen}
      tabIndex={0}
      onKeyDown={handleKeyDown}
    >
      <div className={styles.header}>
        Demo Text-Mode Application
      </div>
      <div className={styles.menuBar}>
        {menuItems.map((item, index) => (
          <div
            key={item}
            className={index === selectedItem ? styles.selectedMenuItem : styles.menuItem}
          >
            {item}
          </div>
        ))}
      </div>
      <div className={styles.content}>
        Content Area
        <div className="mt-4">
          Use Left/Right arrow keys to navigate menu
        </div>
        <div className="mt-4 text-green-400">
          Ready_
        </div>
      </div>
    </div>
  );
};

export default TextModeEmulator;




ignacio escribió: Mar Mar 04, 2025 10:38 pm Hi,

Sorry, but I really do not understand what is your goal. If you need to simulate a terminal window, just use a Memo control with TCourier font or any other monospace font. If you really want to use a terminal window, Harbour HAS EVERYTHING YOU NEED. Xailer is for Windows desktop applications, BTW, I believe you can mix both worlds: windows desktop and terminal apps. On the project MinGW linking options just check the 'console mode' checkbox. You will see that with your desktop app, there will be a console window, that surely accepts Harbour console functions. BTW, I have never used. I do not know how it works. I even do not know how to hide or show that terminal window. Maybe some one in this forum can give you some advice.

Regards,

Re: Can I get help with this example?

Publicado: Mié Mar 05, 2025 9:44 pm
por ignacio
HI,

I sincerely wish you the best of luck with your new development environment. It has been a pleasure to have your support all this time.

Best regards,

Re: Can I get help with this example?

Publicado: Jue Mar 06, 2025 12:00 am
por DC
I will renew the Enterprise subscription for this year.

If you put a Donate button on your website, I can send a Paypal donation from time to time. You'd be surprised how many users want to express their appreciation, regardless of how large or small the developer shop is.

ignacio escribió: Mié Mar 05, 2025 9:44 pm HI,

I sincerely wish you the best of luck with your new development environment. It has been a pleasure to have your support all this time.

Best regards,