воскресенье, 20 декабря 2015 г.

Обратный отсчёт c Curses

Используя возможности библиотеки curses, реализуем обратный отсчет от 9 до 0 в виде электронного циферблата.


Для нашей затеи потребуется одноимённый модуль-обёртка для Perl - Curses.

Шаг 1.


Для начала установим переключатель в модуле, позволяющий нам использовать некоторые
"старые" функции, такие как mvhline, wclear и т.д (см. ниже).

BEGIN { $Curses::OldCurses = 1; }
use Curses;

Шаг 2.


Инициируем основной терминал для "рисования".

BEGIN { $Curses::OldCurses = 1; }
use Curses;

# Непосредственно инициализация терминала. 
initscr;

# Место под Шаг 3.
# Место под Шаг 4.
# Место под Шаг 5.
# Место под Шаг 6.
# Место под Шаг 7.
# Место под Шаг 8.

# Место под Шаг 10.
# Место под Шаг 11.

# Ожидаем нажатия клавишы, чтобы программа сразу не завершалась.
getch;

# Освобождаем память, выделенную под терминал.
endwin;

Шаг 3.


Получаем ширину и высоту терминала.
my ($max_x, $max_y);
getmaxyx($max_y, $max_x); # Да, вначале указывается Y, а затем X.
                          # Это одна из особенностей данной библиотеки.

Шаг 4.


Создаем новое "окно", расположенное в основном терминале по центру экрана.
В нём мы будем отрисовывать наши электронные цифры.

my $width  = 13;
my $height = 11;
my $win = newwin($height, $width, ($max_y-$height)/2, ($max_x-$width)/2);

Шаг 5.


Составляем правила для отрисовки соответствующей линии в цифровом табло.
Сами линии пронумерованы следующим образом.

 ---1--- 
|       |
4       6
|       |
 ---2---
|       |
5       7
|       |
 ---3---

my $sym = 'M'; # Из данного символа будет состоять каждая линия.
my $line = {

    1 => sub { mvwhline($win, 0, 1, $sym, 11) },
    2 => sub { mvwhline($win, 5, 1, $sym, 11) },
    3 => sub { mvwhline($win, 10, 1, $sym, 11) },

    4 => sub { mvwvline($win, 1, 0, $sym, 4) },
    5 => sub { mvwvline($win, 6, 0, $sym, 4) }, 
    6 => sub { mvwvline($win, 1, 12, $sym, 4) },
    7 => sub { mvwvline($win, 6, 12, $sym, 4) }
};

Шаг 6.


Указываем, какие линии необходимо отрисовать для заданной цифры.

my $number = {
    0 => sub { $line->{$_}->() for 1,3,4,5,6,7; },
    1 => sub { $line->{$_}->() for 6,7; },
    2 => sub { $line->{$_}->() for 1,2,3,5,6; },
    3 => sub { $line->{$_}->() for 1,2,3,6,7; },
    4 => sub { $line->{$_}->() for 2,4,6,7; },
    5 => sub { $line->{$_}->() for 1,2,3,4,7; },
    6 => sub { $line->{$_}->() for 1,2,3,4,5,7; },
    7 => sub { $line->{$_}->() for 1,6,7; },
    8 => sub { $line->{$_}->() for 1..7; },
    9 => sub { $line->{$_}->() for 1,2,3,4,6,7; },
};

Шаг 7.


Инициируем функционал для работы с цветом и устанавливаем пару вида:
цвет фона и основной цвет, которую затем можно использовать далее
в коде по её номеру.

start_color;

# Создаем цветовую "пару"
init_pair(2, COLOR_RED, COLOR_RED);

Шаг 8.


Используя ранее созданную цветовую "пару", указываем диапазон действия цветовых
настроек.

wattron($win, COLOR_PAIR(2));    

# Место для Шага 9

wattroff($win, COLOR_PAIR(2));    

Шаг 9.


Непосредственно, отрисовка цифр в обратном порядке.

my $i=9;
while ($i>=0) {
    $number->{$i}->();

    # Необходим для непосредственного вывода изображения на терминал.
    refresh($win);
    sleep 1;

    # Очищаем окно от предыдущей цифры.
    wclear($win);
    $i--;
}

Шаг 10.


Удаляем окно, использованное в качестве циферблата.
delwin($win);

Шаг 11.


Устанавливаем красный фон в конце работы счетчика.

init_pair(8, COLOR_WHITE, COLOR_RED);
bkgd(COLOR_PAIR(8));

Ну и всё вместе.

 #!/usr/bin/perl 

use strict;
use warnings;

BEGIN { $Curses::OldCurses = 1; }
use Curses;

initscr;

my ($max_x, $max_y);
getmaxyx($max_y, $max_x);

my $width  = 13;
my $height = 11;

my $win = newwin($height, $width, ($max_y-$height)/2, ($max_x-$width)/2);

my $sym = 'M';
my $line = {

    1 => sub { mvwhline($win, 0, 1, $sym, 11) },
    2 => sub { mvwhline($win, 5, 1, $sym, 11) },
    3 => sub { mvwhline($win, 10, 1, $sym, 11) },

    4 => sub { mvwvline($win, 1, 0, $sym, 4) },
    5 => sub { mvwvline($win, 6, 0, $sym, 4) }, 
    6 => sub { mvwvline($win, 1, 12, $sym, 4) },
    7 => sub { mvwvline($win, 6, 12, $sym, 4) }
};

my $number = {
    0 => sub { $line->{$_}->() for 1,3,4,5,6,7; },
    1 => sub { $line->{$_}->() for 6,7; },
    2 => sub { $line->{$_}->() for 1,2,3,5,6; },
    3 => sub { $line->{$_}->() for 1,2,3,6,7; },
    4 => sub { $line->{$_}->() for 2,4,6,7; },
    5 => sub { $line->{$_}->() for 1,2,3,4,7; },
    6 => sub { $line->{$_}->() for 1,2,3,4,5,7; },
    7 => sub { $line->{$_}->() for 1,6,7; },
    8 => sub { $line->{$_}->() for 1..7; },
    9 => sub { $line->{$_}->() for 1,2,3,4,6,7; },
};

start_color;

init_pair(2, COLOR_RED, COLOR_RED);

wattron($win, COLOR_PAIR(2));   

my $i=9;
while ($i>=0) {
    $number->{$i}->();
    refresh($win);
    sleep 1;
    wclear($win);
    $i--;
}

wattroff($win, COLOR_PAIR(2));   

delwin($win);

init_pair(8, COLOR_WHITE, COLOR_RED);
bkgd(COLOR_PAIR(8));

getch;
endwin;

Комментариев нет:

Отправить комментарий