The Code


#include <panel.h>
#include <curses.h>
#include <string.h>

enum{ RED_ON_BLACK = 1,
      GREEN_ON_BLACK,
      CYAN_ON_BLACK,
      WINDOW_FILL_COLOR};

#define LOG_WINDOW_X_POS   2
#define LOG_WINDOW_Y_POS   2
#define LOG_WINDOW_WIDTH  40
#define LOG_WINDOW_HEIGHT 10

#define LOG_MSGS_IN_WIN (LOG_WINDOW_HEIGHT - 2)

#define MAX_LOG_MESSAGES 120

char log_messages[MAX_LOG_MESSAGES][LOG_WINDOW_WIDTH];

void win_show(WINDOW *win, char *label, int label_color, int background_color);

WINDOW* log_window;

int log_lines_stored = 0;

/* Last place we stuck some logging data
 */
int log_last_ptr = -1;
int log_offset_from_bottom = 0;

/* TODO: ASSERT if # messages storable < window height
 */

/* DO: Debug macro for   mvprintw(18, 0, "---------------"); refresh(); */

typedef struct window_data_TAG
{
   int size_x;
   int size_y;
} window_data;

void scroll_log_page_down();
void scroll_log_page_up();
void scroll_log_window(int num_lines);


void scroll_log_page_down()
{
   scroll_log_window(-1 * LOG_MSGS_IN_WIN);
}

void scroll_log_page_up()
{
   scroll_log_window(LOG_MSGS_IN_WIN);
}

void scroll_log_home()
{
   log_offset_from_bottom = log_lines_stored - LOG_MSGS_IN_WIN;
}

void scroll_log_end()
{
   log_offset_from_bottom = 0;
}

void scroll_log_window(int num_lines) 
{
   if (log_lines_stored <= LOG_MSGS_IN_WIN)
   {
      return;
   }
   
   else
   {
      log_offset_from_bottom += num_lines;

   /* At the top?
    */
      if (log_lines_stored - log_offset_from_bottom <= LOG_MSGS_IN_WIN) 
      {
         log_offset_from_bottom = log_lines_stored - LOG_MSGS_IN_WIN;
      }
   /* At the bottom?
    */
      else if (log_offset_from_bottom < 0)
      {   
         log_offset_from_bottom = 0;
      }
   }
}

void render_log_window()
{
   int screen_ptr;
   int x, y;
   int thumb_offset;
   int thumb_width;
   int data_ptr;

   /* Clear the screen
    */
   box(log_window, 0, 0);

   for (y = 1; y < LOG_WINDOW_HEIGHT - 1; y++)
   {
      for (x = 1; x < LOG_WINDOW_WIDTH - 1; x++)
      {   
          mvwaddch(log_window, y, x, ' ');
      }
   }
   /* Is there anything to render ?
    */
   if (log_last_ptr == -1)
   {   
      return;
   }

   /* We draw from newest to oldest, so figure out where we should
    *  start - do we have enough lines for a complete screen of msgs?
    */
   if (log_lines_stored > LOG_MSGS_IN_WIN)
   {
      screen_ptr = LOG_MSGS_IN_WIN;

      data_ptr = log_last_ptr - log_offset_from_bottom;

      if (data_ptr < 0)
      {
         data_ptr += MAX_LOG_MESSAGES;
      }

      /* Draw the scrollbar background
       */
      for (y = 2; y < LOG_MSGS_IN_WIN; y++)
      {   
         mvwaddch(log_window, y, LOG_WINDOW_WIDTH - 1, ACS_CKBOARD);
      }

      /* Draw the arrows
       */
      wattron(log_window, COLOR_PAIR(GREEN_ON_BLACK));
      mvwaddch(log_window, 1, LOG_WINDOW_WIDTH - 1, ACS_UARROW);
      mvwaddch(log_window, LOG_WINDOW_HEIGHT - 2, LOG_WINDOW_WIDTH - 1, ACS_DARROW);
      wattroff(log_window, COLOR_PAIR(GREEN_ON_BLACK));

      /* Draw the 'thumb'.  The thumb size is == the percentage
       *  of the visible screen
       */
      thumb_width = (LOG_WINDOW_HEIGHT - 4) * LOG_MSGS_IN_WIN
                      / log_lines_stored;
      
      if (thumb_width <= 0)
      {   thumb_width = 1;
      }


      thumb_offset = log_offset_from_bottom * 
               (LOG_WINDOW_HEIGHT - 4 - thumb_width) /
               (log_lines_stored - LOG_MSGS_IN_WIN);


      wattron(log_window, COLOR_PAIR(RED_ON_BLACK));
      for (y = thumb_width; y > 0; y--)
      {
         mvwaddch(log_window, LOG_MSGS_IN_WIN - y - thumb_offset, 
               LOG_WINDOW_WIDTH - 1, ACS_BLOCK);
      }
      wattroff(log_window, COLOR_PAIR(RED_ON_BLACK));
   }
   else
   {
      screen_ptr = log_lines_stored;
      data_ptr = log_last_ptr;
   }

   wattron(log_window, COLOR_PAIR(CYAN_ON_BLACK));
   while (screen_ptr)
   {
      mvwprintw(log_window, screen_ptr, 1, log_messages[data_ptr]); 
      data_ptr--;
      if (data_ptr < 0)
      {
         data_ptr = MAX_LOG_MESSAGES - 1;
      }
      screen_ptr--;
   }
   wattroff(log_window, COLOR_PAIR(CYAN_ON_BLACK));
}

void add_log_line(char* the_line)
{
   log_last_ptr++;
   if (log_last_ptr >= MAX_LOG_MESSAGES)
   {
      log_last_ptr = 0; 
   }

   log_lines_stored++;
   if (log_lines_stored > MAX_LOG_MESSAGES - 1)
   {
      log_lines_stored = MAX_LOG_MESSAGES - 1;
   }


   /* copy the message to our buffer
    */
   strncpy(log_messages[log_last_ptr], the_line, LOG_WINDOW_WIDTH - 2);

}

void add_log_message(char* msg)
{
   int msg_len = strlen(msg);
   char* ptr;

   if (msg_len > LOG_WINDOW_WIDTH - 2)
   {
      ptr = msg;
      while (ptr - msg < msg_len)
      {   add_log_line(ptr);
         ptr += LOG_WINDOW_WIDTH - 2;
      }
   }
   else
   {
      add_log_line(msg);
   }
}



int main(int argc, char* argv[])
{
   char buf[100];
   int i = 0;
   int this_char;

   initscr();            /* Start curses mode         */

   /* Disable all system handling of any keys EXCEPT
    *  CTRL-C and CTRL-z
    */
   cbreak();

   /* enable curses color capability
    */
   start_color();

   keypad(stdscr, TRUE); /* We get F1, F2 etc..        */

   /* Don't echo() characters to the screen while we do getch().
    *  you can turn the chars back on with 'echo()'
    */
   noecho();

   init_pair(RED_ON_BLACK, COLOR_RED, COLOR_BLACK);
   init_pair(GREEN_ON_BLACK, COLOR_GREEN, COLOR_BLACK);
   init_pair(CYAN_ON_BLACK, COLOR_CYAN, COLOR_BLACK);
   init_pair(WINDOW_FILL_COLOR, COLOR_BLACK, COLOR_WHITE);



   /* Create the log window
    */
   log_window = newwin(LOG_WINDOW_HEIGHT,
                        LOG_WINDOW_WIDTH,
                        LOG_WINDOW_Y_POS,
                        LOG_WINDOW_X_POS);

   wrefresh(log_window);
   while(1)
   {
      this_char = getch();
      switch(this_char)
      {
      case KEY_DOWN:
         scroll_log_window(-1);
         break;
   
      case KEY_UP:
         scroll_log_window(1);
         break;

      case KEY_HOME:
         scroll_log_home();
         break;

      case KEY_LL:
         scroll_log_end();
         break;

      case KEY_NPAGE:
         scroll_log_page_down();
         break;

      case KEY_PPAGE:
         scroll_log_page_up();
         break;

      default:
         sprintf(buf, "line %d here this is some really neat stuff, no??? sure really (%c)", i++, this_char);
         add_log_message(buf);
         break;

      }
      render_log_window();
      wrefresh(log_window);

   }
   endwin();

}

The Makefile

CC = gcc

SRCS = # panel.c
OBJS = $(SRCS:.c=.o)

LIBPATH = -L. 
LIBS = -lncurses -lpanel  
INCLS = -I.
CFLAGS = $(INCLS) $(LIBS) -Wall -g
TARGET = production_tester

default: all

all:  $(TARGET) panel

$(OBJS): Makefile 

$(TARGET): $(OBJS) $(TARGET).c
   $(CC) -o $(TARGET) $(TARGET).c $(OBJS) $(CFLAGS)

panel: panel.c
   $(CC) -o panel panel.c $(CFLAGS)

clean:
   $(RM) *.o $(TARGET) core

-- MattWalsh - 12 Apr 2002

Topic revision: r1 - 13 Apr 2002 - 01:41:06 - MattWalsh
 
This site is powered by the TWiki collaboration platformCopyright © by the contributing authors. All material on this collaboration platform is the property of the contributing authors.
Ideas, requests, problems regarding TWiki? Send feedback