Visualizzazione post con etichetta ncurses. Mostra tutti i post
Visualizzazione post con etichetta ncurses. Mostra tutti i post

giovedì 2 maggio 2019

Emulatore CHIP-8 su NCurses

Questo e' un post intermedio a cui seguira' la creazione di un emulatore CHIP-8 su Arduino


CHIP-8 e' un linguaggio di programmazione interpretato che girava in macchina virtuale su macchine di fine anni 70 come COSMAC VIP

TelMac 1800


La partenza di tutto e' un codice di James Griffin disponibile su GitHub che simula CHIP-8 mediante la libreria SDL

Per semplificare il progetto da portare su Arduino ho creato un progetto intermedio con grafica testuale con NCurses che rimuove la dipendenza dal file system (la rom non viene piu' caricata da un file ma e' inclusa in modo statico in un array nel codice..nel file main.cpp c'e' un programma MAZE commentato ed un programma PONG non commentato)

main.cpp
---------------------------------------------------------------
#include <chrono>
#include <thread>
#include "stdint.h"
#include <curses.h>
#include <math.h>

#include "chip8.h"

using namespace std;
//MAZE
/*
static unsigned char prg[] =
{
    0xA2,0x1E, 0xC2, 0x01, 0x32, 0x01, 0xA2, 0x1A,
    0xD0,0x14, 0x70, 0x04, 0x30, 0x40, 0x12, 0x00,
    0x60,0x00, 0x71, 0x04, 0x31, 0x20, 0x12, 0x00,
    0x12,0x18, 0x80, 0x40, 0x20, 0x10, 0x20, 0x40,
    0x80,0x10
};
*/

//PONG

static unsigned char prg[] =
{
    0x6A,0x02, 0x6B, 0x0C, 0x6C, 0x3F, 0x6D, 0x0C,
    0xA2,0xEA, 0xDA, 0xB6, 0xDC, 0xD6, 0x6E, 0x00,
    0x22,0xD4, 0x66, 0x03, 0x68, 0x02, 0x60, 0x60,
    0xF0,0x15, 0xF0, 0x07, 0x30, 0x00, 0x12, 0x1A,
    0xC7,0x17, 0x77, 0x08,

    0x69,0xFF, 0xA2, 0xF0, 0xD6, 0x71, 0xA2, 0xEA,
    0xDA,0xB6, 0xDC, 0xD6, 0x60, 0x01, 0xE0, 0xA1,
    0x7B,0xFE, 0x60, 0x04, 0xE0, 0xA1, 0x7B, 0x02,
    0x60,0x1F, 0x8B, 0x02, 0xDA, 0xB6, 0x60, 0x0C,
    0xE0,0xA1, 0x7D, 0xFE,

    0x60,0x0D, 0xE0, 0xA1, 0x7D, 0x02, 0x60, 0x1F,
    0x8D,0x02, 0xDC, 0xD6, 0xA2, 0xF0, 0xD6, 0x71,
    0x86,0x84, 0x87, 0x94, 0x60, 0x3F, 0x86, 0x02,
    0x61,0x1F, 0x87, 0x12, 0x46, 0x02, 0x12, 0x78,
    0x46,0x3F, 0x12, 0x82,

    0x47,0x1F, 0x69, 0xFF, 0x47, 0x00, 0x69, 0x01,
    0xD6,0x71, 0x12, 0x2A, 0x68, 0x02, 0x63, 0x01,
    0x80,0x70, 0x80, 0xB5, 0x12, 0x8A, 0x68, 0xFE,
    0x63,0x0A, 0x80, 0x70, 0x80, 0xD5, 0x3F, 0x01,
    0x12,0xA2, 0x61, 0x02,

    0x80,0x15, 0x3F, 0x01, 0x12, 0xBA, 0x80, 0x15,
    0x3F,0x01, 0x12, 0xC8, 0x80, 0x15, 0x3F, 0x01,
    0x12,0xC2, 0x60, 0x20, 0xF0, 0x18, 0x22, 0xD4,
    0x8E,0x34, 0x22, 0xD4, 0x66, 0x3E, 0x33, 0x01,
    0x66,0x03, 0x68, 0xFE,

    0x33,0x01, 0x68, 0x02, 0x12, 0x16, 0x79, 0xFF,
    0x49,0xFE, 0x69, 0xFF, 0x12, 0xC8, 0x79, 0x01,
    0x49,0x02, 0x69, 0x01, 0x60, 0x04, 0xF0, 0x18,
    0x76,0x01, 0x46, 0x40, 0x76, 0xFE, 0x12, 0x6C,
    0xA2,0xF2, 0xFE, 0x33,

    0xF2,0x65, 0xF1, 0x29, 0x64, 0x14, 0x65, 0x00,
    0xD4,0x55, 0x74, 0x15, 0xF2, 0x29, 0xD4, 0x55,
    0x00,0xEE, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
    0x80,0x00, 0x00, 0x00, 0x00, 0x00

};

int tasto;

uint8_t keymap[16];

#define SCREEN_WIDTH 64
#define SCREEN_HEIGHT 32


int main() {
    Chip8 chip8 = Chip8();

    initscr();
    cbreak();
    noecho();
    clear();
    timeout(0); // per fare kbhit non bloccante
    uint32_t pixels[2048];

    chip8.load(prg,sizeof(prg));

    while (true) {
        chip8.emulate_cycle();


        for (int f=0;f<16;++f)
            {
                chip8.key[f] = 0;
            }


        tasto = getch();

        switch (tasto)
        {
          case 49 :  //1
            chip8.key[1] = 1;
            break;
          case 113 :  //q
            chip8.key[4] = 1;
            break;
          case 97 :  //a
            chip8.key[7] = 1;
            break;
          case 122 :  //z
            chip8.key[10] = 1;
            break;
          case 50 :  //2
            chip8.key[2] = 1;
            break;
          case 119 :  //w
            chip8.key[5] = 1;
            break;
          case 115 :  //s
            chip8.key[8] = 1;
            break;
          case 120 :  //x
            chip8.key[0] = 1;
            break;
          case 51 :  //3
            chip8.key[3] = 1;
            break;
          case 101 :  //e
            chip8.key[6] = 1;
            break;
          case 100 :  //d
          chip8.key[9] = 1;
            break;
          case 99 :  //c
          chip8.key[11] = 1;
            break;
          case 52 :  //4
          chip8.key[12] = 1;
            break;
          case 114 :  //r
          chip8.key[13] = 1;
            break;
          case 102 :  //f
          chip8.key[14] = 1;
            break;
          case 118 :  //v
          chip8.key[15] = 1;
            break;
          case 27:
            endwin();
            exit(0);
            break;
          default:
          break;
        }


        if (chip8.drawFlag) {
            chip8.drawFlag = false;
            clear();
            for (int i = 0; i < 2048; ++i) {
                uint8_t pixel = chip8.gfx[i];
                int k = (int)i/64;
                int j = i%64;
                if (pixel == 1)
                {
                  move(k,j);
                  addch(ACS_CKBOARD);
                }
            }
            refresh();
        }
        std::this_thread::sleep_for(std::chrono::microseconds(12000));
    }
}

---------------------------------------------------------------

chip8.h
---------------------------------------------------------------
#ifndef CHIP_8_H
#define CHIP_8_H

#include <stdint.h>

class Chip8 {
private:
    uint16_t stack[16];                 // Stack
    uint16_t sp;                        // Stack pointer

    uint8_t memory[4096];               // Memory (4k)
    uint8_t V[16];                      // V registers (V0-VF)

    uint16_t pc;                        // Program counter
    uint16_t opcode;                    // Current op code
    uint16_t I;                         // Index register

    uint8_t delay_timer;                // Delay timer
    uint8_t sound_timer;                // Sound timer

    void init();

public:
    uint8_t  gfx[64 * 32];              // Graphics buffer
    uint8_t  key[16];                   // Keypad
    bool drawFlag;                      // Indicates a draw has occurred

    Chip8();
    ~Chip8();

    void emulate_cycle();               // Emulate one cycle
    bool load(unsigned char programma[],int size);   // Load application
};

#endif // CHIP_8_H
---------------------------------------------------------------

chip8.cpp
---------------------------------------------------------------
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#include <random>
#include "time.h"


#include "chip8.h"

unsigned char chip8_fontset[80] =
{
    0xF0, 0x90, 0x90, 0x90, 0xF0, //0
    0x20, 0x60, 0x20, 0x20, 0x70, //1
    0xF0, 0x10, 0xF0, 0x80, 0xF0, //2
    0xF0, 0x10, 0xF0, 0x10, 0xF0, //3
    0x90, 0x90, 0xF0, 0x10, 0x10, //4
    0xF0, 0x80, 0xF0, 0x10, 0xF0, //5
    0xF0, 0x80, 0xF0, 0x90, 0xF0, //6
    0xF0, 0x10, 0x20, 0x40, 0x40, //7
    0xF0, 0x90, 0xF0, 0x90, 0xF0, //8
    0xF0, 0x90, 0xF0, 0x10, 0xF0, //9
    0xF0, 0x90, 0xF0, 0x90, 0x90, //A
    0xE0, 0x90, 0xE0, 0x90, 0xE0, //B
    0xF0, 0x80, 0x80, 0x80, 0xF0, //C
    0xE0, 0x90, 0x90, 0x90, 0xE0, //D
    0xF0, 0x80, 0xF0, 0x80, 0xF0, //E
    0xF0, 0x80, 0xF0, 0x80, 0x80  //F
};



Chip8::Chip8() {}
Chip8::~Chip8() {}

// Initialise
void Chip8::init() {
    pc      = 0x200;    // Set program counter to 0x200
    opcode  = 0;        // Reset op code
    I     = 0;          // Reset I
    sp      = 0;        // Reset stack pointer

    // Clear the display
    for (int i = 0; i < 2048; ++i) {
        gfx[i] = 0;
    }

    // Clear the stack, keypad, and V registers
    for (int i = 0; i < 16; ++i) {
        stack[i]    = 0;
        key[i]      = 0;
        V[i]        = 0;
    }

    // Clear memory
    for (int i = 0; i < 4096; ++i) {
        memory[i] = 0;
    }

    // Load font set into memory
    for (int i = 0; i < 80; ++i) {
        memory[i] = chip8_fontset[i];
    }

    // Reset timers
    delay_timer = 0;
    sound_timer = 0;

    // Seed rng
    srand (time(NULL));
}

// Initialise and load ROM into memory
bool Chip8::load(unsigned char programma[],int size) {
    // Initialise
    init();

    //long rom_size = sizeof(programma);
    int rom_size = size;
    // Copy buffer to memory
    if ((4096-512) > rom_size){
        for (int i = 0; i < rom_size; ++i) {
            memory[i + 512] = (uint8_t)programma[i];   // Load into memory starting
                                                        // at 0x200 (=512)
        }
    }
    else {
        std::cerr << "ROM too large to fit in memory" << std::endl;
        return false;
    }

    return true;
}

// Emulate one cycle
void Chip8::emulate_cycle() {

    // Fetch op code
    opcode = memory[pc] << 8 | memory[pc + 1];   // Op code is two bytes

    switch(opcode & 0xF000){

        // 00E_
        case 0x0000:

            switch (opcode & 0x000F) {
                // 00E0 - Clear screen
                case 0x0000:
                    for (int i = 0; i < 2048; ++i) {
                        gfx[i] = 0;
                    }
                    drawFlag = true;
                    pc+=2;
                    break;

                // 00EE - Return from subroutine
                case 0x000E:
                    --sp;
                    pc = stack[sp];
                    pc += 2;
                    break;

                default:
                    printf("\nUnknown op code: %.4X\n", opcode);
                    exit(3);
            }
            break;

        // 1NNN - Jumps to address NNN
        case 0x1000:
            pc = opcode & 0x0FFF;
            break;

        // 2NNN - Calls subroutine at NNN
        case 0x2000:
            stack[sp] = pc;
            ++sp;
            pc = opcode & 0x0FFF;
            break;

        // 3XNN - Skips the next instruction if VX equals NN.
        case 0x3000:
            if (V[(opcode & 0x0F00) >> 8] == (opcode & 0x00FF))
                pc += 4;
            else
                pc += 2;
            break;

        // 4XNN - Skips the next instruction if VX does not equal NN.
        case 0x4000:
            if (V[(opcode & 0x0F00) >> 8] != (opcode & 0x00FF))
                pc += 4;
            else
                pc += 2;
            break;

        // 5XY0 - Skips the next instruction if VX equals VY.
        case 0x5000:
            if (V[(opcode & 0x0F00) >> 8] == V[(opcode & 0x00F0) >> 4])
                pc += 4;
            else
                pc += 2;
            break;

        // 6XNN - Sets VX to NN.
        case 0x6000:
            V[(opcode & 0x0F00) >> 8] = opcode & 0x00FF;
            pc += 2;
            break;

        // 7XNN - Adds NN to VX.
        case 0x7000:
            V[(opcode & 0x0F00) >> 8] += opcode & 0x00FF;
            pc += 2;
            break;

        // 8XY_
        case 0x8000:
            switch (opcode & 0x000F) {

                // 8XY0 - Sets VX to the value of VY.
                case 0x0000:
                    V[(opcode & 0x0F00) >> 8] = V[(opcode & 0x00F0) >> 4];
                    pc += 2;
                    break;

                // 8XY1 - Sets VX to (VX OR VY).
                case 0x0001:
                    V[(opcode & 0x0F00) >> 8] |= V[(opcode & 0x00F0) >> 4];
                    pc += 2;
                    break;

                // 8XY2 - Sets VX to (VX AND VY).
                case 0x0002:
                    V[(opcode & 0x0F00) >> 8] &= V[(opcode & 0x00F0) >> 4];
                    pc += 2;
                    break;

                // 8XY3 - Sets VX to (VX XOR VY).
                case 0x0003:
                    V[(opcode & 0x0F00) >> 8] ^= V[(opcode & 0x00F0) >> 4];
                    pc += 2;
                    break;

                // 8XY4 - Adds VY to VX. VF is set to 1 when there's a carry,
                // and to 0 when there isn't.
                case 0x0004:
                    V[(opcode & 0x0F00) >> 8] += V[(opcode & 0x00F0) >> 4];
                    if(V[(opcode & 0x00F0) >> 4] > (0xFF - V[(opcode & 0x0F00) >> 8]))
                        V[0xF] = 1; //carry
                    else
                        V[0xF] = 0;
                    pc += 2;
                    break;

                // 8XY5 - VY is subtracted from VX. VF is set to 0 when
                // there's a borrow, and 1 when there isn't.
                case 0x0005:
                    if(V[(opcode & 0x00F0) >> 4] > V[(opcode & 0x0F00) >> 8])
                        V[0xF] = 0; // there is a borrow
                    else
                        V[0xF] = 1;
                    V[(opcode & 0x0F00) >> 8] -= V[(opcode & 0x00F0) >> 4];
                    pc += 2;
                    break;

                // 0x8XY6 - Shifts VX right by one. VF is set to the value of
                // the least significant bit of VX before the shift.
                case 0x0006:
                    V[0xF] = V[(opcode & 0x0F00) >> 8] & 0x1;
                    V[(opcode & 0x0F00) >> 8] >>= 1;
                    pc += 2;
                    break;

                // 0x8XY7: Sets VX to VY minus VX. VF is set to 0 when there's
                // a borrow, and 1 when there isn't.
                case 0x0007:
                    if(V[(opcode & 0x0F00) >> 8] > V[(opcode & 0x00F0) >> 4]) // VY-VX
                        V[0xF] = 0; // there is a borrow
                    else
                        V[0xF] = 1;
                    V[(opcode & 0x0F00) >> 8] = V[(opcode & 0x00F0) >> 4] - V[(opcode & 0x0F00) >> 8];
                    pc += 2;
                    break;

                // 0x8XYE: Shifts VX left by one. VF is set to the value of
                // the most significant bit of VX before the shift.
                case 0x000E:
                    V[0xF] = V[(opcode & 0x0F00) >> 8] >> 7;
                    V[(opcode & 0x0F00) >> 8] <<= 1;
                    pc += 2;
                    break;

                default:
                    printf("\nUnknown op code: %.4X\n", opcode);
                    exit(3);
            }
            break;

        // 9XY0 - Skips the next instruction if VX doesn't equal VY.
        case 0x9000:
            if (V[(opcode & 0x0F00) >> 8] != V[(opcode & 0x00F0) >> 4])
                pc += 4;
            else
                pc += 2;
            break;

        // ANNN - Sets I to the address NNN.
        case 0xA000:
            I = opcode & 0x0FFF;
            pc += 2;
            break;

        // BNNN - Jumps to the address NNN plus V0.
        case 0xB000:
            pc = (opcode & 0x0FFF) + V[0];
            break;

        // CXNN - Sets VX to a random number, masked by NN.
        case 0xC000:
            V[(opcode & 0x0F00) >> 8] = (rand() % (0xFF + 1)) & (opcode & 0x00FF);
            pc += 2;
            break;

        // DXYN: Draws a sprite at coordinate (VX, VY) that has a width of 8
        // pixels and a height of N pixels.
        // Each row of 8 pixels is read as bit-coded starting from memory
        // location I;
        // I value doesn't change after the execution of this instruction.
        // VF is set to 1 if any screen pixels are flipped from set to unset
        // when the sprite is drawn, and to 0 if that doesn't happen.
        case 0xD000:
        {
            unsigned short x = V[(opcode & 0x0F00) >> 8];
            unsigned short y = V[(opcode & 0x00F0) >> 4];
            unsigned short height = opcode & 0x000F;
            unsigned short pixel;

            V[0xF] = 0;
            for (int yline = 0; yline < height; yline++)
            {
                pixel = memory[I + yline];
                for(int xline = 0; xline < 8; xline++)
                {
                    if((pixel & (0x80 >> xline)) != 0)
                    {
                        if(gfx[(x + xline + ((y + yline) * 64))] == 1)
                        {
                            V[0xF] = 1;
                        }
                        gfx[x + xline + ((y + yline) * 64)] ^= 1;
                    }
                }
            }

            drawFlag = true;
            pc += 2;
        }
            break;

        // EX__
        case 0xE000:

            switch (opcode & 0x00FF) {
                // EX9E - Skips the next instruction if the key stored
                // in VX is pressed.
                case 0x009E:
                    if (key[V[(opcode & 0x0F00) >> 8]] != 0)
                        pc +=  4;
                    else
                        pc += 2;
                    break;

                // EXA1 - Skips the next instruction if the key stored
                // in VX isn't pressed.
                case 0x00A1:
                    if (key[V[(opcode & 0x0F00) >> 8]] == 0)
                        pc +=  4;
                    else
                        pc += 2;
                    break;

                default:
                    printf("\nUnknown op code: %.4X\n", opcode);
                    exit(3);
            }
            break;

        // FX__
        case 0xF000:
            switch(opcode & 0x00FF)
            {
                // FX07 - Sets VX to the value of the delay timer
                case 0x0007:
                    V[(opcode & 0x0F00) >> 8] = delay_timer;
                    pc += 2;
                    break;

                // FX0A - A key press is awaited, and then stored in VX
                case 0x000A:
                {
                    bool key_pressed = false;

                    for(int i = 0; i < 16; ++i)
                    {
                        if(key[i] != 0)
                        {
                            V[(opcode & 0x0F00) >> 8] = i;
                            key_pressed = true;
                        }
                    }

                    // If no key is pressed, return and try again.
                    if(!key_pressed)
                        return;

                    pc += 2;
                }
                    break;

                // FX15 - Sets the delay timer to VX
                case 0x0015:
                    delay_timer = V[(opcode & 0x0F00) >> 8];
                    pc += 2;
                    break;

                // FX18 - Sets the sound timer to VX
                case 0x0018:
                    sound_timer = V[(opcode & 0x0F00) >> 8];
                    pc += 2;
                    break;

                // FX1E - Adds VX to I
                case 0x001E:
                    // VF is set to 1 when range overflow (I+VX>0xFFF), and 0
                    // when there isn't.
                    if(I + V[(opcode & 0x0F00) >> 8] > 0xFFF)
                        V[0xF] = 1;
                    else
                        V[0xF] = 0;
                    I += V[(opcode & 0x0F00) >> 8];
                    pc += 2;
                    break;

                // FX29 - Sets I to the location of the sprite for the
                // character in VX. Characters 0-F (in hexadecimal) are
                // represented by a 4x5 font
                case 0x0029:
                    I = V[(opcode & 0x0F00) >> 8] * 0x5;
                    pc += 2;
                    break;

                // FX33 - Stores the Binary-coded decimal representation of VX
                // at the addresses I, I plus 1, and I plus 2
                case 0x0033:
                    memory[I]     = V[(opcode & 0x0F00) >> 8] / 100;
                    memory[I + 1] = (V[(opcode & 0x0F00) >> 8] / 10) % 10;
                    memory[I + 2] = V[(opcode & 0x0F00) >> 8] % 10;
                    pc += 2;
                    break;

                // FX55 - Stores V0 to VX in memory starting at address I
                case 0x0055:
                    for (int i = 0; i <= ((opcode & 0x0F00) >> 8); ++i)
                        memory[I + i] = V[i];

                    // On the original interpreter, when the
                    // operation is done, I = I + X + 1.
                    I += ((opcode & 0x0F00) >> 8) + 1;
                    pc += 2;
                    break;

                case 0x0065:
                    for (int i = 0; i <= ((opcode & 0x0F00) >> 8); ++i)
                        V[i] = memory[I + i];

                    // On the original interpreter,
                    // when the operation is done, I = I + X + 1.
                    I += ((opcode & 0x0F00) >> 8) + 1;
                    pc += 2;
                    break;

                default:
                    printf ("Unknown opcode [0xF000]: 0x%X\n", opcode);
            }
            break;

        default:
            printf("\nUnimplemented op code: %.4X\n", opcode);
            exit(3);
    }


    // Update timers
    if (delay_timer > 0)
        --delay_timer;

    if (sound_timer > 0)
        if(sound_timer == 1);
            // TODO: Implement sound
        --sound_timer;

}
---------------------------------------------------------------


mercoledì 12 settembre 2012

Esempio Mandelbrot in C/Ncurses

In questo caso l'insieme di Mandelbrot e' stato restituito su un display a caratteri 80x25 usando la libreria ncurses

Il progetto puo' essere scaricato a questo link
----------------------------------------------

#include <ncurses.h>

#define SCREEN_WIDTH 80
#define SCREEN_HEIGHT 25


float re_min = -2.0;
float im_min = -1.2;

float re_max = 1.0;
float im_max = 1.2;
int iterazioni = 255;


float a,b;
float x,y,x_new,y_new;

int k,j,i;

int keypress = 0;


int main() {


initscr();
start_color();

init_pair(0,COLOR_RED,COLOR_BLACK);
init_pair(1,COLOR_RED,COLOR_RED);
init_pair(2,COLOR_RED,COLOR_GREEN);
init_pair(3,COLOR_RED,COLOR_YELLOW);
init_pair(4,COLOR_RED,COLOR_BLUE);
init_pair(5,COLOR_RED,COLOR_MAGENTA);
init_pair(6,COLOR_RED,COLOR_CYAN);
init_pair(7,COLOR_RED,COLOR_WHITE);

float re_factor = (re_max-re_min);
float im_factor = (im_max-im_min);
     

for (i=0;i<SCREEN_HEIGHT;i++)
{
for (j=0;j<SCREEN_WIDTH;j++)
{
a = re_min+(j*re_factor/SCREEN_WIDTH);
b = im_min+(i*im_factor/SCREEN_HEIGHT);

x = 0;
y = 0;

for (k=0;k<iterazioni;k++)
{
x_new = (x*x)-(y*y)+a;
y_new = (2*x*y)+b;
if (((x_new*x_new)+(y_new*y_new))>4)
{
switch (k%8)
{
case 0:
attron(COLOR_PAIR(0));
break;
case 1:
attron(COLOR_PAIR(1));
break;
case 2:
attron(COLOR_PAIR(2));
break;
case 3:
attron(COLOR_PAIR(3));
break;
case 4:
attron(COLOR_PAIR(4));
break;
case 5:
attron(COLOR_PAIR(5));
break;
case 6:
attron(COLOR_PAIR(6));
break;
case 7:
attron(COLOR_PAIR(7));
break;

}


mvprintw(i,j," ");
break;
}
x = x_new;
y = y_new;
}
       
}

}
refresh();
getch();
endwin();

return(0);
}


----------------------------------------------

Era un po' di tempo che non vedevo Mandelbrot in modalita' testo...piu' o meno dal 1991 quando un virus per DOS visualizzava l'immagine sottostante  (nel dettaglio era Tequila Virus)

Il virus era scritto in Assembler e ricordo che lo debuggai per estrarre la parte di codice relativa a Mandelbrot

mercoledì 5 settembre 2012

Esempio GUI (TUI) con CDK/NCurses in C

Tecnicamente la libreria CDK non fornisce una GUI (Graphic User Interface) bensi' una TUI (Text User Interface)


L'esempio riportato e' preso integralmente dai file di esempio; a differenza dei casi precedenti questo tool mette insieme sia lo slider che la progress bar quindi e' tutto integrato in un solo comando

Per modificare il valore dello slider si usano le frecce cursore alto/basso
----------------------------------------------------------

#include <cdk/cdk.h>

int main (int argc, char **argv)
{
   /* *INDENT-EQLS* */
   CDKSCREEN *cdkscreen = 0;
   CDKSLIDER *widget    = 0;
   WINDOW *cursesWin    = 0;
   const char *title    = "<C></U>ProgressBar";
   const char *label    = "</B>Valore:";
   char temp[256];
   const char *mesg[5];
   int selection;

   CDK_PARAMS params;
   int high;
   int inc;
   int low;

   CDKparseParams (argc, argv, &params, "h:i:l:w:" CDK_MIN_PARAMS);
   high = CDKparamNumber2 (&params, 'h', 100);
   inc = CDKparamNumber2 (&params, 'i', 1);
   low = CDKparamNumber2 (&params, 'l', 1);

   /* Set up CDK. */
   cursesWin = initscr ();
   cdkscreen = initCDKScreen (cursesWin);

   /* Start CDK Colors. */
   initCDKColor ();

   /* Create the widget. */
   widget = newCDKSlider (cdkscreen,
 CDKparamValue (&params, 'X', CENTER),
 CDKparamValue (&params, 'Y', CENTER),
 title, label,
 A_REVERSE | COLOR_PAIR (29) | ' ',
 CDKparamNumber2 (&params, 'w', 50),
 low, low, high,
 inc, (inc * 2),
 CDKparamValue (&params, 'N', TRUE),
 CDKparamValue (&params, 'S', FALSE));

   /* Is the widget null? */
   if (widget == 0)
   {
      /* Exit CDK. */
      destroyCDKScreen (cdkscreen);
      endCDK ();

      printf ("Cannot make the widget. Is the window too small?\n");
      return 1;
   }

   /* Activate the widget. */
   selection = activateCDKSlider (widget, 0);

   /* Check the exit value of the widget. */
   if (widget->exitType == vESCAPE_HIT)
   {
      mesg[0] = "<C>Nessun valore selezionato";
      mesg[1] = "",
      mesg[2] = "<C>Un tasto per continuare.";
      popupLabel (cdkscreen, (CDK_CSTRING2) mesg, 3);
   }
   else if (widget->exitType == vNORMAL)
   {
      sprintf (temp, "<C>E'stato selezionato %d", selection);
      mesg[0] = temp;
      mesg[1] = "",
mesg[2] = "<C>Un tasto per continuare.";
      popupLabel (cdkscreen, (CDK_CSTRING2) mesg, 3);
   }

   /* Clean up. */
   destroyCDKSlider (widget);
   destroyCDKScreen (cdkscreen);
   endCDK ();
   return 0;
}

lunedì 3 settembre 2012

Compilare ncurses e cdk


Esempi di compilazione di sorgenti ncurses e cdk sotto Debian

per entrambe le librerie si possono scaricare i pacchetti gia' compilati (sia libreria che dev)

Nel caso di ncurses
gcc -Wall hello.c -l ncurses -o hello
---------------------------------------------------------------
#include <ncurses.h>

int main()
{
initscr(); /* Start curses mode  */
printw("Hello World !!!"); /* Print Hello World  */
refresh(); /* Print it on to the real screen */
getch(); /* Wait for user input */
endwin(); /* End curses mode  */

return 0;
}

---------------------------------------------------------------

Per compilare CDK si devono unire le librerie ncurses e cdk

gcc -Wall hello_ex.c -lcdk -lncurses -o hello_ex

(nel caso di Debian si deve modificare la riga di include presente nel pacchetto originale degli esempi di CDK per farlo puntare alla directory corretta ovvero #include <cdk.h> diventa #include <cdk/cdk.h>
---------------------------------------------------------------

#include <cdk/cdk.h>

int main (int argc, char **argv)
{
   CDKSCREEN *cdkscreen;
   CDKLABEL *demo;
   WINDOW *cursesWin;
   const char *mesg[4];

   CDK_PARAMS params;

   CDKparseParams (argc, argv, &params, CDK_MIN_PARAMS);

   /* Set up CDK. */
   cursesWin = initscr ();
   cdkscreen = initCDKScreen (cursesWin);

   /* Start CDK Colors. */
   initCDKColor ();

   /* Set the labels up. */
   mesg[0] = "</5><#UL><#HL(30)><#UR>";
   mesg[1] = "</5><#VL(10)>Hello World!<#VL(10)>";
   mesg[2] = "</5><#LL><#HL(30)><#LR>";

   /* Declare the labels. */
   demo = newCDKLabel (cdkscreen,
      CDKparamValue (&params, 'X', CENTER),
      CDKparamValue (&params, 'Y', CENTER),
      (CDK_CSTRING2) mesg, 3,
      CDKparamValue (&params, 'N', TRUE),
      CDKparamValue (&params, 'S', TRUE));

   setCDKLabelBackgroundAttrib (demo, COLOR_PAIR (2));


   /* Draw the CDK screen. */
   refreshCDKScreen (cdkscreen);
   waitCDKLabel (demo, ' ');

   /* Clean up. */
   destroyCDKLabel (demo);
   destroyCDKScreen (cdkscreen);
   endCDK ();
return(0);
   //ExitProgram (EXIT_SUCCESS);
}
---------------------------------------------------------------

In Code::Blocks gli switch di compilazione si devono inserire come nell'esempio riportato in immagine



Geologi

  E so anche espatriare senza praticamente toccare strada asfaltata