ctk-term.c

来自「伟大的Contiki工程, 短小精悍 的操作系统, 学习编程不可不看」· C语言 代码 · 共 1,029 行 · 第 1/2 页

C
1,029
字号
/* * Copyright (c) 2005, Swedish Institute of Computer Science * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright *    notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright *    notice, this list of conditions and the following disclaimer in the *    documentation and/or other materials provided with the distribution. * 3. Neither the name of the Institute nor the names of its contributors *    may be used to endorse or promote products derived from this software *    without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * This file is part of the Contiki operating system. * * @(#)$Id: ctk-term.c,v 1.1 2007/05/26 21:54:33 oliverschmidt Exp $ */#include "ctk/ctk.h"#include "ctk-draw.h"#include "contiki.h"#include "loader.h"#include "ctk-term.h"#include "ctk-term-int.h"#include "ctk-term-out.h"#include "contiki-conf.h"#include "libconio.h"#define PRINTF(x)#define reverse(x)/*-----------------------------------------------------------------------------------*//*  * #defines and enums *//*-----------------------------------------------------------------------------------*/#define CH_ULCORNER '+' //0x00#define CH_TITLEBAR '-' //0x01#define CH_URCORNER '+' //0x02#define CH_WINDOWRBORDER '|' //0x03#define CH_LRCORNER '+' //0x04#define CH_WINDOWLOWERBORDER '-' //0x05#define CH_LLCORNER '+' //0x06#define CH_WINDOWLBORDER '|' //0x07#define CH_DIALOG_ULCORNER '+' //0x12#define CH_DIALOGUPPERBORDER '-' //0x09#define CH_DIALOG_URCORNER '+' //0x0a#define CH_DIALOGRBORDER '|' //0x0b#define CH_DIALOG_LRCORNER '+' //0x0c#define CH_DIALOGLOWERBORDER '-' //0x0d#define CH_DIALOG_LLCORNER '+' //0x0e#define CH_DIALOGLBORDER '|' //0x0f#define CH_BUTTONLEFT  '[' //0x10#define CH_BUTTONRIGHT ']' //0x11#define CH_SEPARATOR   '=' //0x13#ifdef CTK_TERM_CONF_MAX_CLIENTS#define CTK_TERM_NUMCONNS CTK_TERM_CONF_MAX_CLIENTS#else#define CTK_TERM_NUMCONNS 1#endifunsigned char ctk_draw_windowborder_height = 1;unsigned char ctk_draw_windowborder_width = 1;unsigned char ctk_draw_windowtitle_height = 1;/* Term context states */enum {  TERM_DEALLOCATED,  TERM_ALLOCATED};/*-----------------------------------------------------------------------------------*//*  * Local variables *//*-----------------------------------------------------------------------------------*/static unsigned char sizex, sizey;static struct ctk_term_state conns[CTK_TERM_NUMCONNS];/*-----------------------------------------------------------------------------------*//*  * Unconditionally add an update *//*-----------------------------------------------------------------------------------*/void ctk_term_update_add(struct ctk_term_state *ts, struct ctk_term_update *a){  /* XXX: test both head and tail placement!*/  a->next = ts->updates_pending;  ts->updates_pending = a;}/*-----------------------------------------------------------------------------------*//*  * Allocate an update from the update pool *//*-----------------------------------------------------------------------------------*/struct ctk_term_update *ctk_term_update_alloc(struct ctk_term_state *vs){  struct ctk_term_update *a;  a = vs->updates_free;  if(a == NULL) {    return NULL;  }  vs->updates_free = a->next;  a->next = NULL;  return a;}/*-----------------------------------------------------------------------------------*//*  * Return an update to the pool *//*-----------------------------------------------------------------------------------*/voidctk_term_update_free(struct ctk_term_state *ts, struct ctk_term_update *a){  a->next = ts->updates_free;  ts->updates_free = a;}/*-----------------------------------------------------------------------------------*//*  * Fetch update from the update list *//*-----------------------------------------------------------------------------------*/struct ctk_term_update *ctk_term_update_dequeue(struct ctk_term_state *ts){  struct ctk_term_update *a;  a = ts->updates_pending;  if(a == NULL) {    return a;  }  ts->updates_pending = a->next;  a->next = NULL;  return a;}/*-----------------------------------------------------------------------------------*//*  * Remove an update from the update list *//*-----------------------------------------------------------------------------------*/voidctk_term_update_remove(struct ctk_term_state *ts, struct ctk_term_update *a){  struct ctk_term_update *b, *c;  if(a == ts->updates_pending) {    ts->updates_pending = a->next;  } else {    b = ts->updates_pending;    for(c = ts->updates_pending; c != a; b = c, c = c->next);    b->next = a->next;  }}/*-----------------------------------------------------------------------------------*//*  * Add an area update for a specific connection. Overlapping updates are merged *//*-----------------------------------------------------------------------------------*/static voidupdate_area_connection(struct ctk_term_state *ts,		    unsigned char  x, unsigned char  y, unsigned char  w, unsigned char  h){  unsigned char  x2, y2, ax2, ay2;  struct ctk_term_update *a;  PRINTF(("update_area_connection: should update (%d:%d) (%d:%d)\n",	 x, y, w, h));    /* First check if we already have a full update queued. If so, there     is no need to put this update on the list. If there is a full     update, it is always the first one on the list, so there is no     need to go step the list in search for it. */  if(ts->updates_pending != NULL &&     ts->updates_pending->type == UPDATE_FULL) {    PRINTF(("Update_area_connecion: full update already queued...\n"));    return;  }again:    /* Check that we don't update the same area twice by going through     the list and search for an update with the same coordinates. */  for(a = ts->updates_pending; a != NULL; a = a->next) {    if(a->x == x && a->y == y &&       a->w == w && a->h == h) {      PRINTF(("Update_area_connecion: found equal area\n"));      return;    }      }  /* Next we check if this update covers an existing update. If so, we     remove the old update, expand this update so that it covers both     areas to be updated and run through the process again. */  for(a = ts->updates_pending; a != NULL; a = a->next) {          x2 = x + w;    y2 = y + h;        ax2 = a->x + a->w;    ay2 = a->y + a->h;    /* Test if updates overlaps */    if(((x < ax2) && (a->x < x2)) &&      ((y < ay2) && (a->y < y2))) {      /* Remove the old update from the list. */      ctk_term_update_remove(ts, a);      /* Put it on the free list. */      ctk_term_update_free(ts, a);      PRINTF(("update_area_connection: inside (%d:%d, %d:%d)\n",	     a->x, a->y, ax2, ay2));            /* Find the area that covers both updates. */#define MIN(a,b) ((a) < (b)? (a): (b))#define MAX(a,b) ((a) > (b)? (a): (b))      x = MIN(a->x, x);      y = MIN(a->y, y);      ax2 = MAX(ax2, x2);      ay2 = MAX(ay2, y2);      w = ax2 - x;      h = ay2 - y;      /* This should really be done by a recursive call to this	 function: update_area_connection(vs, x, y, w, h); but because	 some compilers might not be able to optimize away the	 recursive call, we do it using a goto instead. */      PRINTF(("Update_area_connecion: trying larger area (%d:%d) (%d:%d)\n", x, y, w, h));      goto again;    }  }    /* Allocate an update object by pulling it off the free list. If     there are no free objects, we go for a full update instead. */  a = ctk_term_update_alloc(ts);  if(a == NULL) {    PRINTF(("Update_area_connecion: no free updates, doing full\n"));    /* Put all pending updates, except for one, on the free list. Use       the remaining update as a full update. */    while(ts->updates_pending != NULL) {      a = ts->updates_pending;      ctk_term_update_remove(ts, a);      ctk_term_update_free(ts, a);    }    a = ctk_term_update_alloc(ts);    a->type = UPDATE_FULL;    ctk_term_update_add(ts, a);					  } else {        PRINTF(("Update_area_connecion: allocated update for (%d:%d) (%d:%d)\n", x, y, w, h));  /* Else, we put the update object at the end of the pending     list. */    a->type = UPDATE_PARTS;    a->x = x;    a->y = y;    a->w = w;    a->h = h;    ctk_term_update_add(ts, a);  }}/*-----------------------------------------------------------------------------------*//*  * Update an area for all connections. *//*-----------------------------------------------------------------------------------*/static voidupdate_area(unsigned char  x, unsigned char  y, unsigned char  w, unsigned char  h){  unsigned char  i;    if(h == 0 || w == 0) {    return;  }  if ((x+w) > sizex) {    w = sizex - x;  }  if ((y+h) > sizey) {    h = sizey - y;  }    /* Update for all active terminal connections. */  for(i = 0; i < CTK_TERM_NUMCONNS; ++i) {    if(conns[i].state != TERM_DEALLOCATED) {      update_area_connection(&conns[i],x, y, w, h);    }  }}/*-----------------------------------------------------------------------------------*//**  * Request a full update for a specific connections. Usefull when a new client is * connected through telnet for example. * * \param ts Terminal connection state *//*-----------------------------------------------------------------------------------*/void ctk_term_redraw(struct ctk_term_state *ts){  update_area_connection(ts,0,0,ts->width, ts->height);}/*-----------------------------------------------------------------------------------*//*  * Initialize a terminal state structure *//*-----------------------------------------------------------------------------------*/static voidinit_state(struct ctk_term_state *ts){  unsigned char i;    ts->width = sizex;  ts->height = sizey;  ts->x = ts->y = ts->x1 = ts->y1 = ts->x2 = ts->y2 = 0;  ts->c1 = ts->c2 = 0;  ts->w = sizex;  ts->h = sizey;  ts->state = TERM_ALLOCATED;  ts->inputstate = ANS_IDLE;  /* Initialize the linked list of updates. */  for(i = 0; i < CTK_TERM_MAX_UPDATES - 1; ++i) {    ts->updates_pool[i].next = &(ts->updates_pool[i + 1]);      }  ts->updates_pool[CTK_TERM_MAX_UPDATES-1].next = NULL;  ts->updates_free = &ts->updates_pool[0];  ts->updates_pending = ts->updates_current = NULL;}/*-----------------------------------------------------------------------------------*//**  * Allocate a new state structure. Returns NULL if none available *//*-----------------------------------------------------------------------------------*/struct ctk_term_state *ctk_term_alloc_state(void){  unsigned char i;  for(i = 0; i < CTK_TERM_NUMCONNS; ++i) {    if(conns[i].state == TERM_DEALLOCATED) {      init_state(&conns[i]);      return &conns[i];    }  }  return NULL;}/*-----------------------------------------------------------------------------------*//**  * Free a state structure. * * \param ts Terminal connection state *//*-----------------------------------------------------------------------------------*/voidctk_term_dealloc_state(struct ctk_term_state *s){  s->state = TERM_DEALLOCATED;}/*-----------------------------------------------------------------------------------*/static char tmp[40];static voidcputsn(char *str, unsigned char len){  strncpy(tmp, str, len);  tmp[len] = 0;  cputs(tmp);}/*-----------------------------------------------------------------------------------*//**  * Initialize the terminal ctk-draw module. Called by the CTK module. * *//*-----------------------------------------------------------------------------------*/voidctk_draw_init(void){  int i;  bgcolor(TERM_BACKGROUNDCOLOR);  screensize(&sizex, &sizey);  ctk_draw_clear(0, sizey);  ctk_term_input_init();  for(i = 0; i < CTK_TERM_NUMCONNS; ++i) {    conns[i].state = TERM_DEALLOCATED;  }}/*-----------------------------------------------------------------------------------*/static voiddraw_widget(struct ctk_widget *w,	    unsigned char x, unsigned char y,	    unsigned char clipx,	    unsigned char clipy,	    unsigned char clipy1, unsigned char clipy2,	    unsigned char focus){  unsigned char xpos, ypos, xscroll;  unsigned char i, j;  char c, *text;  unsigned char len;  xpos = x + w->x;  ypos = y + w->y;      switch(w->type) {  case CTK_WIDGET_SEPARATOR:    textcolor((unsigned char)(TERM_SEPARATORCOLOR + focus));    if(ypos >= clipy1 && ypos < clipy2) {      gotoxy(xpos, ypos);      for(i = 0; i < w->w; ++i) {	cputc(CH_SEPARATOR);      }    }    break;  case CTK_WIDGET_LABEL:    textcolor((unsigned char)(TERM_LABELCOLOR + focus));    text = w->widget.label.text;    for(i = 0; i < w->h; ++i) {      if(ypos >= clipy1 && ypos < clipy2) {	gotoxy(xpos, ypos);	cputsn(text, w->w);	if(w->w - (wherex() - xpos) > 0) {	  cclear((unsigned char)(w->w - (wherex() - xpos)));	}      }      ++ypos;      text += w->w;    }    break;  case CTK_WIDGET_BUTTON:    textcolor((unsigned char)(TERM_BUTTONCOLOR + focus));    if(ypos >= clipy1 && ypos < clipy2) {      if(focus & CTK_FOCUS_WIDGET) {	revers(1);      } else {	revers(0);      }      cputcxy(xpos, ypos, CH_BUTTONLEFT);      cputsn(w->widget.button.text, w->w);      cputc(CH_BUTTONRIGHT);      revers(0);    }    break;  case CTK_WIDGET_HYPERLINK:    textcolor((unsigned char)(TERM_HYPERLINKCOLOR + focus));    if(ypos >= clipy1 && ypos < clipy2) {      if(focus & CTK_FOCUS_WIDGET) {	revers(0);	      } else {	revers(1);      }      gotoxy(xpos, ypos);      cputsn(w->widget.button.text, w->w);      revers(0);    }    break;  case CTK_WIDGET_TEXTENTRY:    textcolor((unsigned char)(TERM_TEXTENTRYCOLOR + focus));    text = w->widget.textentry.text;    xscroll = 0;    if(w->widget.textentry.xpos >= w->w - 1) {      xscroll = w->widget.textentry.xpos - w->w + 1;    }    for(j = 0; j < w->h; ++j) {      if(ypos >= clipy1 && ypos < clipy2) {	if(w->widget.textentry.state == CTK_TEXTENTRY_EDIT &&	   w->widget.textentry.ypos == j) {	  revers(0);	  cputcxy(xpos, ypos, '>');	  c = 1;	  for(i = 0; i < w->w; ++i) {	    if(c != 0) {	      c = text[i + xscroll];	    }	    if(i == w->widget.textentry.xpos - xscroll) {	      textcolor((unsigned char)(TERM_TEXTENTRYCOLOR + (focus ^ 0x01)));

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?