TVision

 view release on metacpan or  search on metacpan

TVision-methods.xs.in  view on Meta::CPAN

	int isValid
	int canUndo
	int modified
	int selecting
	int overwrite
	int autoIndent
	#static TEditorDialog _NEAR editorDialog;
	#static ushort _NEAR editorFlags;
	#static char _NEAR findStr[maxFindStrLen];
	#static char _NEAR replaceStr[maxReplaceStrLen];
	#static TEditor * _NEAR clipboard;
	int lockCount
	int updateFlags
	int keyState
      TEditWindow:
	TFileEditor *editor
      TWindow:
	int flags
	TRect zoomRect
	int number
	int palette

TVision.pm  view on Meta::CPAN

#[ ]    enum EolType { eolCrLf, eolLf, eolCr } eolType;
#[ ]    enum Encoding { encDefault, encSingleByte } encoding;
#[ ]    void nextChar( TStringView, uint &P, uint &width );
#[ ]    Boolean formatCell( TSpan<TScreenCell>, uint&, TStringView, uint& , TColorAttr );
#[ ]    TStringView bufChars( uint );
#[ ]    TStringView prevBufChars( uint );
#[ ]    static TEditorDialog _NEAR editorDialog;
#[ ]    static ushort _NEAR editorFlags;
#[ ]    static char _NEAR findStr[maxFindStrLen];
#[ ]    static char _NEAR replaceStr[maxReplaceStrLen];
#[ ]    static TEditor * _NEAR clipboard;
#[ ]    uchar lockCount;
#[ ]    uchar updateFlags;
#[ ]    int keyState;
#[ ]    static const char * const _NEAR name;
#[ ]    static TStreamable *build();
#};
package TVision::TMemo;
#class TMemo : public TEditor {
#public:
#    TMemo( const TRect&, TScrollBar *, TScrollBar *, TIndicator *, ushort ) noexcept;

tvision.git/README.md  view on Meta::CPAN

    * [Linux](#build-linux)
    * [Windows (MSVC)](#build-msvc)
    * [Windows (MinGW)](#build-mingw)
    * [Windows/DOS (Borland C++)](#build-borland)
    * [Vcpkg](#build-vcpkg)
    * [Turbo Vision as a CMake dependency](#build-cmake)
* [Features](#features)
* [API changes](#apichanges)
* [Applications using Turbo Vision](#applications)
* [Unicode support](#unicode)
* [Clipboard interaction](#clipboard)
* [Extended color support](#color)

<div id="what-for"></div>

## What is Turbo Vision good for?

A lot has changed since Borland created Turbo Vision in the early 90's. Many GUI tools today separate appearance specification from behaviour specification, use safer or dynamic languages which do not segfault on error, and support either parallel or...

Turbo Vision does not excel at any of those, but it certainly overcomes many of the issues programmers still face today when writing terminal applications:

tvision.git/README.md  view on Meta::CPAN

* A compiler supporting C++14.
* `libncursesw` (note the 'w').
* `libgpm` for mouse support on the Linux console (optional).

If your distribution provides separate *devel* packages (e.g. `libncurses-dev`, `libgpm-dev` in Debian-based distros), install these too.

<div id="build-linux-runtime"></div>

The runtime requirements are:

* `xsel` or `xclip` for clipboard support in X11 environments.
* `wl-clipboard` for clipboard support in Wayland environments.

The minimal command line required to build a Turbo Vision application (e.g. `hello.cpp` with GCC) from this project's root is:

```sh
g++ -std=c++14 -o hello hello.cpp ./build/libtvision.a -Iinclude -lncursesw -lgpm
```

You may also need:

* `-Iinclude/tvision` if your application uses Turbo Vision 1.x includes (`#include <tv.h>` instead of `#include <tvision/tv.h>`).

tvision.git/README.md  view on Meta::CPAN

* `TOutlineViewer` now allows the root node to have siblings.
* New function `ushort popupMenu(TPoint where, TMenuItem &aMenu, TGroup *receiver=0)` which spawns a `TMenuPopup` on the desktop. See `source/tvision/popupmnu.cpp`.
* New virtual method `TMenuItem& TEditor::initContextMenu(TPoint p)` that determines the entries of the right-click context menu in `TEditor`.
* `fexpand` can now take a second parameter `relativeTo`.
* New class `TStringView`, inspired by `std::string_view`.
    * Many functions which originally had null-terminated string parameters now receive `TStringView` instead. `TStringView` is compatible with `std::string_view`, `std::string` and `const char *` (even `nullptr`).
* New class `TSpan<T>`, inspired by `std::span`.
* New classes `TDrawSurface` and `TSurfaceView`, see `<tvision/surface.h>`.
* The system integration subsystems (`THardwareInfo`, `TScreen`, `TEventQueue`...) are now initialized when constructing a `TApplication` for the first time, rather than before `main`. They are still destroyed on exit from `main`.
* New method `TVMemMgr::reallocateDiscardable()` which can be used along `allocateDiscardable` and `freeDiscardable`.
* New method `TView::textEvent()` which allows receiving text in an efficient manner, see [Clipboard interaction](#clipboard).
* New class `TClipboard`, see [Clipboard interaction](#clipboard).
* Unicode support, see [Unicode](#unicode).
* True Color support, see [extended colors](#color).
* New method `static void TEventQueue::waitForEvents(int timeoutMs)` which may block for up to `timeoutMs` milliseconds waiting for input events. A negative `timeoutMs` can be used to wait undefinitely. If it blocks, it has the side effect of flushin...
* New method `static void TEventQueue::wakeUp()` which causes the event loop to resume execution if it is blocked at `TEventQueue::waitForEvents()`. This method is thread-safe, since its purpose is to unblock the event loop from secondary threads.
* New method `void TView::getEvent(TEvent &, int timeoutMs)` which allows waiting for an event with an user-provided timeout (instead of `TProgram::eventTimeoutMs`).
* It is now possible to specify a maximum text width or maximum character count in `TInputLine`. This is done through a new parameter in `TInputLine`'s constructor, `ushort limitMode`, which controls how the second constructor parameter, `uint limit`...
    * `ilMaxBytes` (the default): the text can be up to `limit` bytes long, including the null terminator.
    * `ilMaxWidth`: the text can be up to `limit` columns wide.
    * `ilMaxChars`: the text can contain up to `limit` non-combining characters or graphemes.
* New functions which allow getting the names of Turbo Vision's constants at runtime (e.g. `evCommand`, `kbShiftIns`, etc.):

tvision.git/README.md  view on Meta::CPAN


- [x] `TInputLine` ([`81066ee5`](https://github.com/magiblot/tvision/commit/81066ee5c05496612dfcd9cf75df5702cbfb9679), [`cb489d42`](https://github.com/magiblot/tvision/commit/cb489d42d522f7515c870942bcaa8f0f3dea3f35)).
- [x] `TEditor` ([`702114dc`](https://github.com/magiblot/tvision/commit/702114dc03a13ebce2b52504eb122c97f9892de9)). Instances are in UTF-8 mode by default. You may switch back to single-byte mode by pressing `Ctrl+P`. This only changes how the docum...

Views not in this list may not have needed any corrections or I simply forgot to fix them. Please submit an issue if you notice anything not working as expected.

Use cases where Unicode is not supported (not an exhaustive list):

- [ ] Highlighted key shortcuts, in general (e.g. `TMenuBox`, `TStatusLine`, `TButton`...).

<div id="clipboard"></div>

# Clipboard interaction

Originally, Turbo Vision offered no integration with the system clipboard, since there was no such thing on MS-DOS.

It did offer the possibility of using an instance of `TEditor` as an internal clipboard, via the `TEditor::clipboard` static member. However, `TEditor` was the only class able to interact with this clipboard. It was not possible to use it with `TInpu...

Turbo Vision applications are now most likely to be ran in a graphical environment through a terminal emulator. In this context, it would be desirable to interact with the system clipboard in the same way as a regular GUI application would do.

To deal with this, a new class `TClipboard` has been added which allows accessing the system clipboard. If the system clipboard is not accessible, it will instead use an internal clipboard.

## Enabling clipboard support

On Windows (including WSL) and macOS, clipboard integration is supported out-of-the-box.

On Unix systems other than macOS, it is necessary to install some external dependencies. See [runtime requirements](#build-linux-runtime).

For applications running remotely (e.g. through SSH), clipboard integration is supported in the following situations:

* When X11 forwarding over SSH is enabled (`ssh -X`).
* When your terminal emulator supports far2l's terminal extensions ([far2l](https://github.com/elfmz/far2l), [putty4far2l](https://github.com/ivanshatsky/putty4far2l)).
* When your terminal emulator supports OSC 52 escape codes:
    * [alacritty](https://github.com/alacritty/alacritty), [kitty](https://github.com/kovidgoyal/kitty), [foot](https://codeberg.org/dnkl/foot).
    * [xterm](https://invisible-island.net/xterm/), if the `allowWindowOps` option is enabled.
    * A few other terminals only support the Copy action.

Additionally, it is always possible to paste text using your terminal emulator's own Paste command (usually `Ctrl+Shift+V` or `Cmd+V`).

## API usage

To use the `TClipboard` class, define the macro `Uses_TClipboard` before including `<tvision/tv.h>`.

### Writing to the clipboard

```c++
static void TClipboard::setText(TStringView text);
```

Sets the contents of the system clipboard to `text`. If the system clipboard is not accessible, an internal clipboard is used instead.

### Reading the clipboard

```c++
static void TClipboard::requestText();
```

Requests the contents of the system clipboard asynchronously, which will be later received in the form of regular `evKeyDown` events. If the system clipboard is not accessible, an internal clipboard is used instead.

### Processing Paste events

A Turbo Vision application may receive a Paste event for two different reasons:

* Because `TClipboard::requestText()` was invoked.
* Because the user pasted text through the terminal.

In both cases the application will receive the clipboard contents in the form of regular `evKeyDown` events. These events will have a `kbPaste` flag in `keyDown.controlKeyState` so that they can be distinguished from regular key presses.

Therefore, if your view can handle user input it will also handle Paste events by default. However, if the user pastes 5000 characters, the application will behave as if the user pressed the keyboard 5000 times. This involves drawing views, completin...

For the purpose of dealing with this situation, another function has been added:

```c++
bool TView::textEvent(TEvent &event, TSpan<char> dest, size_t &length);
```

`textEvent()` attempts to read text from consecutive `evKeyDown` events and stores it in a user-provided buffer `dest`. It returns `false` when no more events are available or if a non-text event is found, in which case this event is saved with `putE...

The exact number of bytes read is stored in the output parameter `length`, which will never be larger than `dest.size()`.

Here is an example on how to use it:

```c++
// 'ev' is a TEvent, and 'ev.what' equals 'evKeyDown'.
// If we received text from the clipboard...
if (ev.keyDown.controlKeyState & kbPaste) {
    char buf[512];
    size_t length;
    // Fill 'buf' with the text in 'ev' and in
    // upcoming events from the input queue.
    while (textEvent(ev, buf, length)) {
        // Process 'length' bytes of text in 'buf'...
    }
}
```

### Enabling application-wide clipboard usage

The standard views `TEditor` and `TInputLine` react to the `cmCut`, `cmCopy` and `cmPaste` commands. However, your application first has to be set up to use these commands. For example:

```c++
TStatusLine *TMyApplication::initStatusLine( TRect r )
{
    r.a.y = r.b.y - 1;
    return new TStatusLine( r,
        *new TStatusDef( 0, 0xFFFF ) +
            // ...

tvision.git/include/tvision/editors.h  view on Meta::CPAN


    void nextChar( TStringView, uint &P, uint &width );
    Boolean formatCell( TSpan<TScreenCell>, uint&, TStringView, uint& , TColorAttr );
    TStringView bufChars( uint );
    TStringView prevBufChars( uint );

    static TEditorDialog _NEAR editorDialog;
    static ushort _NEAR editorFlags;
    static char _NEAR findStr[maxFindStrLen];
    static char _NEAR replaceStr[maxReplaceStrLen];
    static TEditor * _NEAR clipboard;
    uchar lockCount;
    uchar updateFlags;
    int keyState;

private:

    virtual const char *streamableName() const
        { return name; }

protected:

tvision.git/include/tvision/editors.h  view on Meta::CPAN

    TEditWindow( const TRect&, TStringView, int ) noexcept;
    virtual void close();
    virtual const char *getTitle( short );
    virtual void handleEvent( TEvent& );
    virtual void sizeLimits( TPoint& min, TPoint& max );

    TFileEditor *editor;

private:

    static const char * _NEAR clipboardTitle;
    static const char * _NEAR untitled;

    virtual const char *streamableName() const
        { return name; }

protected:

    TEditWindow( StreamableInit ) noexcept;
    virtual void write( opstream& );
    virtual void *read( ipstream& );

tvision.git/source/platform/termio.cpp  view on Meta::CPAN

        "\x1B[?2004s"   // Save bracketed paste.
        "\x1B[?2004h"   // Enable bracketed paste.
        "\x1B[>4;1m"    // Enable modifyOtherKeys (XTerm).
        "\x1B[>1u"      // Disambiguate escape codes (Kitty).
        "\x1B[?9001h"   // Enable win32-input-mode (Conpty).
        far2lEnableSeq  // Enable far2l terminal extensions.
    );

    if (char *term = getenv("TERM"))
    {
        // Check for full OSC 52 clipboard support.
        if (strstr(term, "alacritty") || strstr(term, "foot"))
            strcat(buf,
                // Request clipboard contents to see if they are readable. It is
                // not safe to print this blindly so only do it for TERMs which
                // we know should work.
                "\x1B]52;;?\x07"
            );
        else
            strcat(buf,
                // Check for the 'kitty-query-clipboard_control' capability (XTGETTCAP).
                "\x1BP+q6b697474792d71756572792d636c6970626f6172645f636f6e74726f6c\x1B\\"
                // Check for 'allowWindowOps' (XTQALLOWED).
                "\x1B]60\x1B\\"
            );
    }

    strcat(buf,
        // Some terminals do not recognize the sequences above and will display
        // them on screen. Clear the screen to prevent this.
        "\x1B[2J"

tvision.git/source/platform/termio.cpp  view on Meta::CPAN

    }
    return Ignored;
}

ParseResult TermIO::parseDCS(GetChBuf &buf, InputState &state) noexcept
// Pre: '\x1BP' has just been read.
{
    if (char *s = readUntilBelOrSt(buf))
    {
        // We only get a DCS in response to our request for kitty capabilities.
        if (strstr(s, "726561642d636c6970626f617264")) // 'read-clipboard'
            state.hasFullOsc52 = true;
        free(s);
    }
    return Ignored;
}

ParseResult TermIO::parseOSC(GetChBuf &buf, InputState &state) noexcept
// Pre: '\x1B]' has just been read.
{
    if (char *s = readUntilBelOrSt(buf))

tvision.git/source/platform/termio.cpp  view on Meta::CPAN

    TStringView suffix = "\x07";
    if (char *buf = (char *) malloc(prefix.size() + suffix.size() + (text.size() * 4)/3 + 4))
    {
        memcpy(buf, prefix.data(), prefix.size());
        TStringView b64 = encodeBase64(text, buf + prefix.size());
        memcpy(buf + prefix.size() + b64.size(), suffix.data(), suffix.size());
        con.write(buf, prefix.size() + b64.size() + suffix.size());
        free(buf);
    }
    // Return false when there is no full OSC 52 support, even though we always
    // make the request. This way, we can still use the internal clipboard.
    return state.hasFullOsc52;
}

static bool requestOsc52Clipboard(ConsoleCtl &con, InputState &state) noexcept
{
    if (state.hasFullOsc52)
    {
        TStringView seq = "\x1B]52;;?\x07";
        con.write(seq.data(), seq.size());
        return true;

tvision.git/source/platform/unixclip.cpp  view on Meta::CPAN

#include <sys/types.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <poll.h>

namespace tvision
{

#define PID_PLACEHOLDER "########"

enum { clipboardTimeoutMs = 1500 };

#ifdef __APPLE__
constexpr const char * pbcopyArgv[] = {"pbcopy", 0};
constexpr const char * pbpasteArgv[] = {"pbpaste", 0};
#else
constexpr const char * wlCopyArgv[] = {"wl-copy", 0};
constexpr const char * xselCopyArgv[] = {"xsel", "--input", "--clipboard", 0};
constexpr const char * xclipCopyArgv[] = {"xclip", "-in", "-selection", "clipboard", 0};
constexpr const char * wslCopyArgv[] = {"/mnt/c/Windows/System32/clip.exe", 0};
constexpr const char * wlPasteArgv[] = {"wl-paste", "--no-newline", 0};
constexpr const char * xselPasteArgv[] = {"xsel", "--output", "--clipboard", 0};
constexpr const char * xclipPasteArgv[] = {"xclip", "-out", "-selection", "clipboard", 0};

static char wslPasteCmd[] =
    // Both PowerShell and CScript can be used to read the clipboard.
    // Although PowerShell is more modern and can be run without a script file,
    // it is far slower and requires a very complicated workaround for
    // https://github.com/microsoft/terminal/issues/280. Therefore, we stick
    // to CScript.
    // The environment variable 'q' is used to insert quoutes in order
    // to work around https://github.com/microsoft/WSL/issues/2835.
    "(FOR"
        " %i IN (%q%%TMP%%q% %q%%TEMP%%q% %q%%USERPROFILE%%q% \\. .)"
    " DO"
        " set SCRIPT_PATH=%q%%~i\\" PID_PLACEHOLDER "%RANDOM%.vbs%q%"
        // Try to write the script file.
        " && cmd /C"
            " echo"
                // Print the clipboard contents in UTF-16.
                " WScript.StdOut.Write"
                    " CreateObject(%q%HTMLFile%q%^).ParentWindow.ClipboardData.GetData(%q%Text%q%^)"
            " ^> ^%SCRIPT_PATH^%"
        // If it worked, run it and exit.
        " && ("
            " cmd /C"
                " cscript //NoLogo //B //U ^%SCRIPT_PATH^%"
                // Delete the files and keep the error status.
                " ^&^& (del /Q ^%SCRIPT_PATH^% ^& exit ^)"
                " ^|^| (del /Q ^%SCRIPT_PATH^% ^& exit 1^)"

tvision.git/source/platform/unixclip.cpp  view on Meta::CPAN

{
    if (char *dstText = (char *) realloc(text.data(), text.size() + 1))
    {
        dstText[text.size()] = '\0';
        text = {dstText, text.size() + 1};
    }
}

static void wslPastePrepare(TSpan<char> &text) noexcept
// Pre: 'text' is malloc-allocated.
// We receive the clipboard contents from CScript in UTF-16, so we have to
// convert them to UTF-8.
{
    uint16_t *srcText = (uint16_t *) text.data();
    size_t srcLength = text.size()/2;
    char *dstText;
    size_t dstLength = 0;
    // Each UTF-16 code unit may produce up to 3 UTF-8 bytes.
    if ((dstText = (char *) malloc(srcLength * 3)))
        dstLength = utf16To8({srcText, srcLength}, dstText);
    free(srcText);

tvision.git/source/platform/unixclip.cpp  view on Meta::CPAN

}

bool UnixClipboard::setClipboardText(TStringView aText) noexcept
{
    for (auto &cmd : copyCommands)
        if (commandIsAvailable(cmd))
        {
            TSpan<char> text = copyStr(aText);
            if (cmd.prepare)
                cmd.prepare(text);
            bool success = write_subprocess(cmd.argv, text, clipboardTimeoutMs);
            free(text.data());
            if (success)
                return true;
            break;
        }
    return false;
}

bool UnixClipboard::requestClipboardText(void (&accept)(TStringView)) noexcept
{
    for (auto &cmd : pasteCommands)
        if (commandIsAvailable(cmd))
        {
            TSpan<char> text = read_subprocess(cmd.argv, cmd.customEnv, clipboardTimeoutMs);
            if (cmd.prepare)
                cmd.prepare(text);
            if (text.data())
            {
                accept(text);
                free(text.data());
                return true;
            }
            break;
        }

tvision.git/source/tvision/editstat.cpp  view on Meta::CPAN


ushort defEditorDialog( int, ... )
{
    return cmCancel;
}

TEditorDialog _NEAR TEditor::editorDialog = defEditorDialog;
ushort _NEAR TEditor::editorFlags = efBackupFiles | efPromptOnReplace;
char _NEAR TEditor::findStr[maxFindStrLen] = "";
char _NEAR TEditor::replaceStr[maxReplaceStrLen] = "";
TEditor * _NEAR TEditor::clipboard = 0;

tvision.git/source/tvision/teditor1.cpp  view on Meta::CPAN

        nextChar(chars, p, pos);
        }
    if( (int) pos > target)
        p = lastP;
    return p;
}

Boolean TEditor::clipCopy()
{
    Boolean res = False;
    if( clipboard != this )
        {
        if( clipboard != 0 )
            res = clipboard->insertFrom(this);
        else
            {
            TClipboard::setText( TStringView( buffer + bufPtr(selStart),
                                              selEnd - selStart ) );
            res = True;
            }
        selecting = False;
        update(ufUpdate);
        }
    return res;
}

void TEditor::clipCut()
{
    if( clipCopy() == True )
        deleteSelect();
}

void TEditor::clipPaste()
{
    if( clipboard != this )
        {
        if( clipboard != 0 )
            insertFrom(clipboard);
        else
            TClipboard::requestText();
        }
}

void TEditor::convertEvent( TEvent& event )
{
    if( event.what == evKeyDown )
        {
        if( (event.keyDown.controlKeyState & kbShift) != 0 &&

tvision.git/source/tvision/teditor2.cpp  view on Meta::CPAN

                        );
}

Boolean TEditor::insertText( const void *text, uint length, Boolean selectText )
{
  return insertBuffer( (const char *)text, 0, length, canUndo, selectText);
}

Boolean TEditor::isClipboard()
{
    return Boolean(clipboard == this);
}

uint TEditor::lineMove( uint p, int count )
{
    uint i = p;
    p = lineStart(p);
    int pos = charPos(p, i);
    while( count != 0 )
        {
        i = p;

tvision.git/source/tvision/teditor2.cpp  view on Meta::CPAN

}

void TEditor::updateCommands()
{
    setCmdState( cmUndo, Boolean( delCount != 0 || insCount != 0 ) );
    if( isClipboard() == False )
        {
        setCmdState(cmCut, hasSelection());
        setCmdState(cmCopy, hasSelection());
        setCmdState(cmPaste,
                    Boolean(clipboard == 0 || clipboard->hasSelection()) );
        }
    setCmdState(cmClear, hasSelection());
    setCmdState(cmFind, True);
    setCmdState(cmReplace, True);
    setCmdState(cmSearchAgain, True);
}

Boolean TEditor::valid( ushort )
{
  return isValid;

tvision.git/source/tvision/teditwnd.cpp  view on Meta::CPAN

{
    if( editor->isClipboard() == True )
        hide();
    else
        TWindow::close();
}

const char *TEditWindow::getTitle( short )
{
    if( editor->isClipboard() == True )
        return clipboardTitle;
    else if( *(editor->fileName) == EOS )
        return untitled;
    else
        return editor->fileName;
}

void TEditWindow::handleEvent( TEvent& event )
{
    TWindow::handleEvent(event);
    if( event.what == evBroadcast && event.message.command == cmUpdateTitle )

tvision.git/source/tvision/tvtext2.cpp  view on Meta::CPAN


const char * _NEAR TRangeValidator::validUnsignedChars = "+0123456789";
const char * _NEAR TRangeValidator::validSignedChars = "+-0123456789";

const char * _NEAR TListViewer::emptyText = "<empty>";

const char * _NEAR THelpWindow::helpWinTitle = "Help";
const char * _NEAR THelpFile::invalidContext =
    "\n No help available in this context.";

const char * _NEAR TEditWindow::clipboardTitle = "Clipboard";
const char * _NEAR TEditWindow::untitled = "Untitled";

const char * _NEAR TFileList::tooManyFiles = "Too many files.";

const char * _NEAR TProgram::exitText = "~Alt-X~ Exit";

const char * _NEAR MsgBoxText::yesText = "~Y~es";
const char * _NEAR MsgBoxText::noText = "~N~o";
const char * _NEAR MsgBoxText::okText = "O~K~";
const char * _NEAR MsgBoxText::cancelText = "~C~ancel";



( run in 2.022 seconds using v1.01-cache-2.11-cpan-2398b32b56e )