Новые книги

Перевод книги Adam Tepper «Bitcoin – The People's Money». Книга представляет собой отличное введение в биткойн «с нуля», но может оказаться полезной и тем, кто уже разбирается в теме.
Не так давно от столь популярного в наше время прилагательного «креативный»1 образовалось новое существительное. Если вы — один из нас, миллионов людей, зарабатывающих на жизнь своим умом, вас можно смело назвать представителем «креативного класса», или попросту — креативщиком. Каждый день вы решаете проблемы, предлагаете нововведения, разрабатываете системы, создаете дизайнерские решения, пишете, занимаетесь стратегическим планированием и работаете головой. Именно благодаря вам рождаются новые концепции и формируются целые рабочие системы, закладывающие основу будущего экономического роста, — создается принципиально новый продукт, которого не было и в помине, пока на сцену не вышли вы.

Может быть, вы вовсе и не собирались становиться творческой личностью. Более того, возможно, вы даже содрогаетесь всякий раз, когда вас называют «креативным». И это вполне понятно, ведь ярлык «креативщик» обычно вызывает в воображении этакого рекламного гуру из Сохо2, мельтешащего туда-сюда в своих фирменных джинсах за 500 долларов. Скорее всего, вам приятнее называть себя стратегом или менеджером, что звучит более определенно, более реально. Называйте себя как пожелаете, но если вы отвечаете за решение проблем, разработку стратегий или напряженно трудитесь над генерированием новых идей, я буду называть вас креативщиком, даже если выходит, что вы стали им случайно.

Примеры.

Пример 19

/* ________________________файл menu.h __________________________ */
/*                     РОЛЛИРУЕМОЕ МЕНЮ                           */
/* _______________________________________________________________*/
#include              <ctype.h>
#include              <sys/param.h>
#define M_HOT         '\\'      /* горячий ключ */
#define M_CTRL        '\1'      /* признак горизонтальной черты */
#define MXEND(m)      XEND((m)->win,(m)->scrollok)
#define NOKEY        (-33)      /* горячего ключа нет         */
#define MAXLEN       MAXPATHLEN /* макс. длина имен файлов    */
typedef enum { /* Коды, возвращаемые handler-ом (HandlerReply *reply) */
    HANDLER_OUT      = 0,  /* выйти из функции выбора          */
    HANDLER_CONTINUE = 1,  /* читать очередную букву           */
    HANDLER_NEWCHAR  = 2,  /* пойти на анализ кода handler-ом. */
    HANDLER_SWITCH   = 3,  /* пойти на switch()                */
    HANDLER_AGAIN    = 4   /* перезапустить всю функцию выбора */
} HandlerReply;
typedef struct _Menu {          /* паспорт меню               */
    int     nitems;             /* число элементов меню       */
    Info   *items;              /* сам массив элементов       */
    int    *hotkeys;            /* "горячие" клавиши          */
    int     key;		/* клавиша, завершившая выбор */
    int     current;            /* текущая строка списка      */
    int     shift;              /* сдвиг окна от начала меню  */
    int     scrollok;           /* окно роллируемое ?         */
    WINDOW *win;                /* окно для меню              */
    int     left, top, height, width; /* координаты меню на экране и
					 размер окна win       */
    int     textwidth, textheight;    /* размер подокна выбора */
    int     bg_attrib;          /* атрибут фона окна           */
    int     sel_attrib;         /* атрибут выбранной строки    */
    char   *title;              /* заголовок меню              */
    Point   savep;
    void  (*showMe)    (struct _Menu *m);
    void  (*scrollBar) (struct _Menu *m, int n, int among);
    int    *hitkeys;            /* клавиши, обрабатываемые особо */
    int   (*handler)   (struct _Menu *m, int c, HandlerReply *reply);
} Menu;
/* Структура окна с меню:
	*--------------*    +0
	|  ЗАГОЛОВОК   |    +1
	*-----------*--*    +2
	|+ стр1ааа  |  |    +3
	|  стр2ббб  |##| <- scroll bar шириной BARWIDTH
	|  стр3ввв  |  |
	*___________|__*
	|DX| len |DX|BS|
 */
/* Метки у элементов меню */
#define M_BOLD       I_DIR      /* яркая строка */
#define M_HATCH      0x08       /* строка тусклая     */
#define M_LFT        0x10       /* для использования в pulldown menu */
#define M_RGT        0x20       /* для использования в pulldown menu */
#define M_LABEL      0x40       /* строка имеет метку */
#define M_LEFT       (-111)
#define M_RIGHT      (-112)
#define TOTAL_NOSEL  (-I_NOSEL)
#define M_SET(m, i, flg)        (((m)->items)[i]). fl |=  (flg)
#define M_CLR(m, i, flg)        (((m)->items)[i]). fl &= ~(flg)
#define M_TST(m, i, flg)        ((((m)->items)[i]).fl &   (flg))
#define M_ITEM(m, i)            ((((m)->items)[i]).s)
	/* Прототипы */
int  MnuInit (Menu *m); void MnuDeinit (Menu *m);
void MnuDrawItem (Menu * m, int y, int reverse, int selection);
int     MnuNext (Menu *m); int     MnuPrev (Menu *m);
int     MnuFirst(Menu *m); int     MnuLast (Menu *m);
int     MnuPgUp (Menu *m); int     MnuPgDn (Menu *m);
int     MnuThis (Menu *m); int     MnuHot  (Menu *m, unsigned c);
int     MnuName (Menu *m, char *name);
void MnuDraw        (Menu *m);     void MnuHide(Menu *m);
void MnuPointAt     (Menu *m, int y);
void MnuPoint       (Menu *m, int line, int eraseOld);
int  MnuUsualSelect (Menu *m, int block);
int is_in(register int c, register int s[]);
char *MnuConvert    (char *s, int *pos);
#define M_REFUSED(m)    ((m)->key < 0 || (m)->key == ESC )
#define MNU_DY           1
/* _______________________ файл menu.c __________________________ */
#include "w.h"
#include "glob.h"
#include "menu.h"
#include <signal.h>
/* ---------------- implementation module ------------------------- */
/* Не входит ли символ в специальный набор? Массив завершается (-1) */
int is_in(register int c, register int s[]){
    while (*s >= 0) {
	if(*s == c) return YES;
	s++;
    }
    return NO;
}
char STRING_BUFFER[ MAXLEN ]; /* временный буфер */
/* Снять пометку с "горячей" клавиши.            */
char *MnuConvert (char *s, int *pos){
    int i = 0;
    *pos = (-1);
    while (*s) {
	if (*s == M_HOT) { *pos = i; s++; }
	else STRING_BUFFER[i++] = *s++;
    }
    STRING_BUFFER[i] = '\0'; return STRING_BUFFER;
}
/* Рамка вокруг окна с меню */
static void MnuWin (Menu *m) {
    WinBorder(m->win, m->bg_attrib, m->sel_attrib,
		      m->title, m->scrollok, YES);
}
/* Нарисовать scroll bar в нужной позиции */
static void MnuWinBar (Menu *m) {
    WINDOW *w = m -> win;  /* окно */
    WinScrollBar(m->win, m->scrollok, m->current, m->nitems,
		 m->title, m->bg_attrib);
    if(m->scrollBar)  /* может быть еще какие-то наши действия */
       m->scrollBar(m, m->current, m->nitems);
}
/* Роллирование меню */
/*
	+---+----->+-МАССИВ--+<-----+
	|  n|всего |;;;;;;;;;|      | shift сдвиг до окна
     cur|   |      |;;;;;;;;;|      |
 текущий|   |   =ОКНО============<---------|
 элемент|   |   I   ;;;;;;;;;   I   | y строка окна
 0..n-1 |   |   I   ;;;;;;;;;   I   |      |
	+------>I###:::::::::###I<--+      |h высота окна
	    |   I   ;;;;;;;;;   I          |
	    |   =================<---------+
	    |      |;;;;;;;;;|
	    +----->|_________|
*/
static void MnuRoll (Menu *ptr,
    int aid,     /* какой новый элемент выбрать (0..n-1) */
    int *cur, int *shift,
    int h,       /* высота окна    (строк)      */
    int n,       /* высота items[] (элементов)  */
    void (*go)   (Menu *p, int y, int eraseOld),
    void (*draw) (Menu *p),
    int DY
) {
    int     y = *cur - *shift;	/* текущая строка окна */
    int     newshift;		/* новый сдвиг */
    int     AID_UP, AID_DN;
    if (aid < 0 || aid >= n) return;  /* incorrect */
    if (y   < 0 || y   >= h) return;  /* incorrect */
    AID_UP = MIN (DY, n);
    AID_DN = MAX (0, MIN (n, h - 1 - DY));
    if (aid < *cur && y <= AID_UP && *shift > 0)
	goto scroll;		/* down */
    if (aid > *cur && y >= AID_DN && *shift + h < n)
	goto scroll;		/* up */
    if (*shift <= aid && aid < *shift + h) {
    /* роллировать не надо, а просто пойти в нужную строку окна */
	(*go) (ptr, aid - *shift, YES);
	*cur = aid;      /* это надо изменять ПОСЛЕ (*go)() !!! */
	return;
    }
scroll:
    if      (aid > *cur)   newshift = aid - AID_DN; /* вверх up   */
    else if (aid < *cur)   newshift = aid - AID_UP; /* вниз  down */
    else                   newshift = *shift;
    if (newshift + h > n)  newshift = n - h;
    if (newshift < 0)      newshift = 0;
    *shift = newshift; *cur = aid;
    (*draw) (ptr); /* перерисовать окно */
    (*go)   (ptr, aid - newshift, NO); /* встать в нужную строку окна */
}
/* Инициализация и разметка меню. На входе:
	m->items       Массив строк.
	m->title       Заголовок  меню.
	m->top         Верхняя строка окна (y).
	m->left        Левый край (x).
	m->handler     Обработчик нажатия клавиш или NULL.
	m->hitkeys     Специальные клавиши [] или NULL.
	m->bg_attrib   Цвет фона окна.
	m->sel_attrib  Цвет селекции.
*/
int MnuInit (Menu *m) {
    int len, pos; char *s; register i;
    m -> current  = m -> shift = 0;
    m -> scrollok = m -> key = 0;
    if (m -> hotkeys) { /* уничтожить старые "горячие" ключи */
	free ((char *) m -> hotkeys); m -> hotkeys = (int *) NULL;
    }
 /* подсчет элементов меню */
    for (i = 0; M_ITEM (m, i) != (char *) NULL; i++);
    m -> nitems = i;
 /* отвести массив для "горячих" клавиш */
    if (m -> hotkeys = (int *) malloc (sizeof (int) * m -> nitems)) {
	for (i = 0; i < m -> nitems; i++)
	    m -> hotkeys[i] = NOKEY;
    }
 /* подсчитать ширину текста */
    len = m -> title ? strlen (m -> title) : 0;
    for (i = 0; i < m -> nitems; i++) {
	if (*(s = M_ITEM (m, i)) == M_CTRL) continue;
	s = MnuConvert (s, &pos);
	if (m -> hotkeys && pos >= 0)
	    m -> hotkeys[i] =
		isupper (s[pos]) ? tolower (s[pos]) : s[pos];
	if ((pos = strlen (s)) > len)
	    len = pos;
    }
 /* сформировать окно */
#define BORDERS_HEIGHT (2 +        (m -> title    ? 2 : 0))
#define BORDERS_WIDTH  (2 + 2*DX + (m -> scrollok ? BARWIDTH + 1 : 0))
    m -> height = m->nitems + BORDERS_HEIGHT;
    if (m -> height > LINES * 2 / 3) { /* слишком высокое меню */
	m -> scrollok = BAR_VER;       /* будет роллироваться  */
	m -> height = LINES * 2 / 3;
    }
    if((m -> width = len + BORDERS_WIDTH) > COLS ) m->width = COLS;
    m -> textheight = m->height - BORDERS_HEIGHT;
    m -> textwidth  = m->width  - BORDERS_WIDTH;
 /* окно должно лежать в пределах экрана */
    if( m->top  + m->height > LINES ) m->top  = LINES - m->height;
    if( m->left + m->width  > COLS  ) m->left = COLS  - m->width;
    if( m->top  < 0 ) m->top  = 0;
    if( m->left < 0 ) m->left = 0;
    if( m->win ){ /* уничтожить старое окно */
	KillWin( m->win ); m->win = NULL; }
    if( m->win == NULL ){ /* создать окно и нарисовать основу */
	if((m->win =  newwin(m->height, m->width, m->top, m->left))
		   == NULL) return 0;
	keypad(m->win, TRUE); MnuWin(m); MnuDraw(m);
	/* но окно пока не вставлено в список активных окон */
    }
    return ( m->win != NULL );
}
/* Деинициализировать меню */
void MnuDeinit (Menu *m) {
    if( m->win ){ KillWin (m->win); m->win = NULL; }
    if( m->hotkeys ){
	free ((char *) m -> hotkeys); m -> hotkeys = (int *) NULL;
    }
}
/* Спрятать меню */
void MnuHide (Menu *m){ if( m->win ) HideWin(m->win); }
/* Зачистить место для line-той строки окна меню */
static void MnuBox (Menu *m, int line, int attr) {
    register    WINDOW *w = m -> win;
    register    i, xend   = MXEND(m);
    wattrset (w, attr);
    for (i = 1; i < xend; i++)
	mvwaddch (w, line, i, ' ');
    /* ликвидировать последствия M_CTRL-линии */
    wattrset (w, m->bg_attrib);
    mvwaddch (w, line, 0,    VER_LINE);
    mvwaddch (w, line, xend, VER_LINE);
    wattrset (w, m->bg_attrib);
}
/* Нарисовать строку меню в y-ой строке окна выбора */
void MnuDrawItem (Menu *m, int y, int reverse, int selection) {
    register WINDOW *w = m -> win;
    int     pos, l, attr;
    int     ay = WY (m->title, y), ax = WX (0);
    char   *s, c;
    int     hatch, bold, label, cont = NO, under;
    if (y + m -> shift >= 0 && y + m -> shift < m -> nitems) {
	s =    M_ITEM (m, y + m -> shift);
	hatch = M_TST (m, y + m -> shift, I_NOSEL) ||
		M_TST (m, y + m -> shift, M_HATCH);
	bold  = M_TST (m, y + m -> shift, M_BOLD);
	label = M_TST (m, y + m -> shift, M_LABEL);
	under = M_TST (m, y + m -> shift, I_EXE);
    }
    else {  /* строка вне допустимого диапазона */
	s = "~"; label = hatch = bold = NO;
    }
    if (*s == M_CTRL) { /* нарисовать горизонтальную черту */
	int x, xend = MXEND(m);
	wattrset(w, m->bg_attrib);
	for(x=1; x < xend; x++)
		mvwaddch(w, ay, x, HOR_LINE);
	mvwaddch (w, ay, 0,    LEFT_JOIN);
	mvwaddch (w, ay, xend, RIGHT_JOIN);
	wattrset (w, m->bg_attrib);
	return;
    }
    l = strlen(s = MnuConvert (s, &pos));
    c = '\0';
    if (l > m -> textwidth) { /* слишком длинная строка */
	c = s[m -> textwidth];
	s[m -> textwidth] = '\0'; cont = YES;
	if (pos > m -> textwidth) pos = (-1);
    }
    if (selection)
	MnuBox (m, ay, reverse ? m->sel_attrib   : m->bg_attrib);
    wattrset (w, attr = (bold    ? A_BOLD        : 0) |
			(hatch   ? A_ITALICS     : 0) |
			(under   ? A_UNDERLINE   : 0) |
			(reverse ? m->sel_attrib : m->bg_attrib));
    mvwaddstr (w, ay, ax, s);
    if( cont ) mvwaddch(w, ay, ax+m->textwidth, RIGHT_TRIANG);
 /* Hot key letter */
    if (pos >= 0) {
	wattron (w, bold ? A_ITALICS : A_BOLD);
	mvwaddch (w, ay, WX(pos), s[pos]);
    }
    if (label){  /* строка помечена */
	wattrset (w, attr | A_BOLD);
	mvwaddch (w, ay, 1, LABEL);
    }
    if (under){
	wattrset (w, A_BOLD);
	mvwaddch (w, ay, ax-1, BOX_HATCHED);
    }
    if (c) s[m->textwidth] = c;
    wattrset (w, m->bg_attrib);
    SetPoint (m->savep, ay, ax-1);  /* курсор поставить перед словом */
}
/* Выбор в меню подходящего элемента */
int MnuNext (Menu *m) {
    char *s; register y = m -> current;
    for (++y; y < m -> nitems; y++)
      if ((s = M_ITEM (m, y)) && *s != M_CTRL && !M_TST (m, y, I_NOSEL))
	 return y;
    return (-1);
}
int MnuPrev (Menu *m) {
    char *s; register y = m -> current;
    for (--y; y >= 0; --y)
      if ((s = M_ITEM (m, y)) && *s != M_CTRL && !M_TST (m, y, I_NOSEL))
	 return y;
    return (-1);
}
int MnuPgUp (Menu *m) {
    char *s; register n, y = m -> current;
    for (--y, n = 0; y >= 0; --y) {
      if ((s = M_ITEM (m, y)) && *s != M_CTRL && !M_TST (m, y, I_NOSEL))
	  n++;
      if (n == m -> textheight) return y;
    }
    return MnuFirst (m);
}
int MnuPgDn (Menu *m) {
    char *s; register n, y = m -> current;
    for (++y, n = 0; y < m -> nitems; y++) {
      if ((s = M_ITEM (m, y)) && *s != M_CTRL && !M_TST (m, y, I_NOSEL))
	 n++;
      if (n == m -> textheight) return y;
    }
    return MnuLast (m);
}
int MnuFirst (Menu *m) {
    char *s; register y;
    for (y = 0; y < m -> nitems; y++)
      if ((s = M_ITEM (m, y)) && *s != M_CTRL && !M_TST (m, y, I_NOSEL))
	 return y;
    return (-1);
}
int MnuLast (Menu *m) {
    char *s; register y;
    for (y = m -> nitems - 1; y >= 0; --y)
      if ((s = M_ITEM (m, y)) && *s != M_CTRL && !M_TST (m, y, I_NOSEL))
	 return y;
    return (-1);
}
int MnuThis (Menu *m) {
    char *s;
    if (m -> current < 0 || m -> current >= m -> nitems)
	return (-1);		/* error */
    if ((s = M_ITEM (m, m -> current)) &&
	 *s != M_CTRL && !M_TST (m, m -> current, I_NOSEL))
	return m -> current;
    return (-1);
}
int MnuName (Menu *m, char *name) {
    char *s; register y; int pos;
    for(y = 0; y < m -> nitems; ++y)
      if ((s = M_ITEM (m, y)) && *s != M_CTRL && !M_TST (m, y, I_NOSEL) &&
	   strcmp(name, MnuConvert(s, &pos)) == 0 ) return y;
    return (-1);
}
int MnuHot (Menu *m, unsigned c) {
    register y; char *s;
    if (m -> hotkeys == (int *) NULL)
	return (-1);
    if (c < 0400 && isupper (c))
	c = tolower (c);
    for (y = 0; y < m -> nitems; y++)
	if (c == m -> hotkeys[y] &&
	   (s = M_ITEM (m, y)) && *s != M_CTRL && !M_TST (m, y, I_NOSEL))
	    return y;
    return (-1);
}
/* Нарисовать содержимое меню для выбора */
void MnuDraw (Menu *m) {
    register    i, j;
    for (i = 0; i < m -> textheight; i++)
	MnuDrawItem (m, i, NO, m -> scrollok ? YES : NO);
}
/* Поставить курсор в line-тую строку окна. */
void MnuPoint(Menu *m, int line,
	      int eraseOld /* стирать старую селекцию? */){
    int curline = m->current - m->shift; /* текущая строка окна */
    if (line < 0 || line >= m -> textheight) return;  /* ошибка */
    if (eraseOld && curline != line) /* стереть старый выбор    */
	MnuDrawItem (m, curline, NO, YES);
    MnuDrawItem (m, line, YES, YES); /* подсветить новую строку */
}
/* Перейти к y-той строке массива элементов, изменить картинку  */
void MnuPointAt (Menu *m, int y) { char *s;
    if (y < 0 || y >= m->nitems) return; /* ошибка! */
    if ((s = M_ITEM (m, y)) == NULL || *s == M_CTRL) return;
    MnuRoll (m, y, &m -> current,    &m -> shift,
		    m -> textheight,  m -> nitems,
	     MnuPoint, MnuDraw, MNU_DY);
    if (m -> scrollok) MnuWinBar(m); /* сдвинуть scroll bar */
    GetBack(m->savep, m->win); /* вернуть курсор в начало строки селекции,
				* откуда он был сбит MnuWinBar-ом */
}
/* Выбор в меню без участия "мыши". */
int MnuUsualSelect (Menu *m, int block) {
    int sel, snew, c, done = 0;
    m -> key = (-1);
    if( ! m->win ) return TOTAL_NOSEL;
    if((sel = MnuThis  (m)) < 0)
    if((sel = MnuFirst (m)) < 0)
	return TOTAL_NOSEL; /* в меню нельзя ничего выбрать */
    RaiseWin   (m->win);    /* сделать окно верхним         */
    MnuPointAt (m, sel);    /* проявить */
    if(m->showMe) m->showMe(m);  /* может быть изменить позицию ? */
    for (;;) {
	c = WinGetch (m->win);
INP:
	if (m -> hitkeys && m -> handler) {
	    HandlerReply reply;
	    if (is_in (c, m -> hitkeys)) {
		c = (*m -> handler) (m, c, &reply);
	    /* восстановить scroll bar */
		MnuPointAt (m, m -> current);
		switch (reply) {
		    case HANDLER_CONTINUE:     continue;
		    case HANDLER_NEWCHAR:      goto INP;
		    case HANDLER_OUT:          goto out;
		    case HANDLER_SWITCH:       default:
			break;	/* goto switch(c) */
		}
	    }
	}
	switch (c) {
	    case KEY_UP:
		if ((snew = MnuPrev (m)) < 0)  break;
		goto mv;
	    case KEY_DOWN:
	next:
		if ((snew = MnuNext (m)) < 0)  break;
		goto mv;
	    case KEY_HOME:
		if ((snew = MnuFirst (m)) < 0) break;
		goto mv;
	    case KEY_END:
		if ((snew = MnuLast (m)) < 0)  break;
		goto mv;
	    case KEY_NPAGE:
		if ((snew = MnuPgDn (m)) < 0)  break;
		goto mv;
	    case KEY_PPAGE:
		if ((snew = MnuPgUp (m)) < 0)  break;
		goto mv;
	    case KEY_IC:   /* поставить/снять пометку */
		if (M_TST (m, sel, M_LABEL)) M_CLR (m, sel, M_LABEL);
		else                         M_SET (m, sel, M_LABEL);
		MnuPointAt (m, sel);
	    /* Если вы вычеркнете  goto next;
	     * и оставите просто   break;
	     * то вставьте в это место
	     * MnuPoint( m, m->current - m->shift, NO ); */
		goto next;
	    case KEY_DC:
		if (M_TST (m, sel, M_HATCH)) M_CLR (m, sel, M_HATCH);
		else                         M_SET (m, sel, M_HATCH);
		MnuPointAt (m, sel); goto next;
	    case KEY_LEFT:
		if (block & M_LFT) {
		    sel = M_LEFT;  goto out;
		} break;
	    case KEY_RIGHT:
		if (block & M_RGT) {
		    sel = M_RIGHT; goto out;
		} break;
	    case 0: break;
	    default:
		if (c == '\n' || c == '\r' || c == ESC)
		    goto out;
		if ((snew = MnuHot (m, c)) < 0) {
		    beep(); break;
		}
	    /* иначе найден HOT KEY (горячая клавиша) */
		done++; goto mv;
	}
	continue;
mv:
	MnuPointAt (m, sel = snew);
	if(done){ wrefresh(m->win); /* проявить новую позицию */ break; }
    }
out: wnoutrefresh(m->win);
     return((m->key = c) == ESC ? -1 : sel);
     /* Меню автоматически НЕ ИСЧЕЗАЕТ: если надо
      * явно делайте MnuHide(m); после MnuUsualSelect(); */
}

© Copyright А. Богатырев, 1992-95
Си в UNIX

Назад | Содержание | Вперед