⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 window.cc

📁 Unix下的MUD客户端程序
💻 CC
字号:
#include "mcl.h"#include "cui.h"#include "MessageWindow.h"#include "ProxyWindow.h"#include "Curses.h"#include <stdarg.h>Window* Numbered::list[10];Window::Window(Window *_parent, int _width, int _height,  Style _style, int _x, int _y)    : parent(_parent), width(_width), height(_height),    next(NULL), prev(NULL), child_first(NULL), child_last(NULL), visible(true),    color(fg_white|bg_black),focused(NULL), parent_x(_x), parent_y(_y), cursor_x(0),    cursor_y(0), dirty(true),  style(_style){	if (width == wh_half)		width = parent->width/2;	else if (width == wh_full)		width = parent->width;		if (height == wh_half)		height = parent->height/2;	else if (height == wh_full)		height = parent->height;	if (parent_x == xy_center)		parent_x = parent->width / 2 - width / 2;	else if (parent_x < 0)		parent_x = parent->width + parent_x;			if (parent_y == xy_center)		parent_y = parent->height / 2 - height / 2;	else if (parent_y < 0)        parent_y = parent->height + parent_y;    // Bordered?    if (style & Bordered) {        Window *w = new Border(parent, width, height, parent_x, parent_y);        width -= 2;        height -= 2;        parent_x = parent_y = 1 ;        parent = w;    }	assert(width >= 0);    assert(height >= 0);    clearLine = new attrib[width];    for (attrib *a = clearLine; a < clearLine+width; a++)        *a =  ((fg_white|bg_black) << 8) + ' ';    	canvas = new attrib[width*height];	clear();	if (parent)		parent->insert(this);}bool Window::is_focused(){	if (!parent || !parent->focused || parent->focused == this)		return true;	else		return false;}void Window::insert (Window *window){    if (find(window))        abort();        	if (child_last)	{		child_last->next = window;		window->prev = child_last;	}	else		child_first = window;    child_last = window;    check();}void Window::check(){    Window *w;    int count;    for (count = 0, w = child_first; w; w = w->next)        if (++count > 100)            abort();    for (count = 0, w = child_last; w; w = w->prev)        if (++count > 100)            abort();}void Window::show(bool vis) {    visible = vis;    dirty = true;    if (parent)        parent->visibilityNotify(this, vis);}void Window::remove (Window *window){    if (!find(window))        abort();    	if (window->prev)		window->prev->next = window->next;		if (window->next)		window->next->prev = window->prev;		if (window == child_first)		child_first = window->next;		if (window == child_last)        child_last = window->prev;    window->next = window->prev = NULL;		    dirty = true;    if (focused)        focused->dirty = true;    if (window == focused)        focused = NULL;        check();}Window::~Window(){	Window *w, *w_next;	// Kill all children		for (w = child_first; w; w = w_next)	{		w_next = w->next;		delete w;	}	// Remove me	if (parent)		parent->remove(this);			delete[] canvas;}Window* Window::findByName(const char *name, Window *after){    Window *w;    for (w = after ? after->next : child_first ; w; w = w->next)        if (!strcmp(name, w->getName()))            return w;        return NULL;}bool Window::scroll(){	return false;}#define MAX_PRINTF_BUF 16384void Window::print(const char *s){	const unsigned char *in;	attrib *out;	    dirty = true;	// Position out pointer at the beginning of canvas to write to		out = canvas + cursor_y * width + cursor_x;		for (in = (unsigned char *)s; *in; in++)	{		if (*in == SET_COLOR)         {            switch (in[1]) {            case 0: // ??? black on black?                break;                            case COL_SAVE:                saved_color = color; in++;                break;            case COL_RESTORE:                color = saved_color; in++;                break;            default:                color = *++in;            }		} 		else if (*in == SOFT_CR) // change to a new line if not there already		{			if (cursor_x)			{				cursor_x = 0; 				cursor_y++;				out = canvas + cursor_y * width + cursor_x;			}		}		else if (*in == '\t') // tabstop		{			// Hop to the next tabstop. If we go over the limit, set cursor			// to be = width, then wordwrap will kick in below			cursor_x = min(width, ((cursor_x / config->getOption(opt_tabsize)) + 1) 				* config->getOption(opt_tabsize));		}		else if (*in == '\n') // Change line		{			cursor_x = 0; 			cursor_y++;			out = canvas + cursor_y * width + cursor_x;		}		else		{			// Need to scroll? If we have to, and fail, don't print more			// If scroll succeeds, it is assumed to have adjusted cursor_x/y			// Note that we do not scroll until we actually WRITE something			// at the bottom line!			while (cursor_y >= height)				if (!scroll())					return;			// Recalculate where our output is now that there has been a scroll				out = canvas + cursor_y * width + cursor_x;						*out++ = (color << 8) + *in;			cursor_x++;		}				// Wordwrap required?		if (cursor_x == width)		{			cursor_y++;			cursor_x = 0;		}			}}// Formatted printvoid Window::printf(const char *fmt, ...){	char buf[MAX_PRINTF_BUF];	va_list va;		va_start (va,fmt);	vsnprintf (buf, MAX_PRINTF_BUF, fmt, va);	va_end (va);		print(buf);}// Formatted, centered printvoid Window::cprintf(const char *fmt, ...){	char buf[MAX_PRINTF_BUF];	va_list va;		va_start (va,fmt);	vsnprintf (buf, MAX_PRINTF_BUF, fmt, va);    va_end (va);    gotoxy(0, cursor_y);    if ((int)strlen(buf) > width)        buf[width] = NUL;    printf("%*s%s", (width-strlen(buf))/2, "", buf);}// Copy data from attrib to x,y. Data is w * hvoid Window::copy (attrib *source, int w, int h, int _x, int _y){	// Don't bother if it is clearly outside of our rectangle    if (_y >= width || _x >= width        || (_x+w <= 0) || (_y+h) <= 0) // far out		return;			// Direct copy?	if (width == w && _x == 0)    {        // adjust if _y < 0        if (_y < 0) {            source += (-1 * w*_y);            h += _y;            _y = 0;        }		int size = min(w*h, (height-_y) * width);				// This will not copy more than there is space for in this window		if (size > 0)			memcpy (canvas + _y*width, source, size * sizeof(attrib));	}	else	{		// For each row up to max of our height or source height		for (int y2 = max(0,_y); y2 < height && y2 < (_y+h) ; y2++)			memcpy (				canvas + (y2 * width) + _x,				// Copy to (_x, y2)				source + (y2 - _y) * w,					// Copy from (0, y2 - _y)				sizeof(attrib) * min(w, width - _x));	// Copy w units, or whatever there's space for	}}// This simple window cannot redraw itself// If the canvas somehow is lost, printed stuff is lostvoid Window::redraw(){	dirty = false;}bool Window::refresh(){	bool refreshed = false;	// Don't do anything if we are hidden		if (!visible)	{		if (dirty)		{			dirty = false;			return true;		}		else			return false;	}		// Do we need to redraw?	if (dirty)	{		redraw();		refreshed = true;	}		// Refresh children	// Note that the first in list will be the one behind	for (Window *w = child_first; w ; w = w->next)		refreshed = w->refresh() || refreshed;	draw_on_parent();		 // Copy our canvas to parent	return refreshed;		}// Fill this window with 'color'void Window::clear(){	attrib *p;	attrib *end = canvas + width * height;	attrib blank = (color << 8) + ' ';		for (p = canvas; p < end; p++)		*p = blank;		dirty = true;}// Take care of this keypressbool Window::keypress(int key){	Window *w_prev;		// By default, do not do anything with the key, but just ask the children	// If they can do anything with it	// Keep pointer to prev window in case current gets deleted	// This needs to be rewritten using some List/Iterator!	for (Window *w = child_last; w; w = w_prev)	{		w_prev = w->prev;		if (w->keypress(key))			return true;	}		return false;}// Set hardware cursor coordinates// Asks the parent, translating the coordinates accordinglyvoid Window::set_cursor(int _x, int _y){	if (parent)		parent->set_cursor(_x+parent_x,_y+parent_y);}void Window::idle(){    Window *w_next;    for (Window *w = child_first; w; w = w_next)    {        w_next = w->next;        w->idle();    }}void Window::resize (int w, int h) {    width = w; height = h;    delete[] canvas;    canvas = new attrib[width*height];    clear();    if (parent) {        parent->force_update();        parent->resizeNotify(this, w,h);    }    dirty = true;}void Window::move (int x, int y) {    parent_x = x; parent_y = y;    force_update();    parent->force_update();}        #define BRD_TOP 		(1 << 0)#define BRD_BOTTOM 		(1 << 1)#define BRD_LEFT 		(1 << 2)#define BRD_RIGHT 		(1 << 3)// Draw a box from (x1,y2) to (x2,y2) using border style _bordersvoid    Window::box (int x1, int y1, int x2, int y2, int _borders){	int     box_width = x2 - x1;	char   *s = new char[box_width + 1];	// Top/bottom   	memset (s, special_chars[bc_horizontal], box_width);	s[box_width] = NUL;	if (_borders & BRD_TOP)	{		gotoxy (x1 + 1, y1);		print (s);	}	if (_borders & BRD_BOTTOM)	{		gotoxy (x1, y2);		print (s);	}	// Left/Right	for (int _y = y1 + 1; _y < y2; _y++)	{		if (_borders & BRD_LEFT)		{			gotoxy (x1, _y);			printf ("%c", special_chars[bc_vertical]);		}		if (_borders & BRD_RIGHT)		{			gotoxy (x2, _y);			printf ("%c", special_chars[bc_vertical]);		}	}	// Corners	if (_borders & BRD_TOP)	{		if (_borders & BRD_LEFT)		{			gotoxy (x1, y1);			printf ("%c", special_chars[bc_upper_left]);		}		if (_borders & BRD_RIGHT)		{			gotoxy (x2, y1);			printf ("%c", special_chars[bc_upper_right]);		}	}	if (_borders & BRD_BOTTOM)	{		if (_borders & BRD_LEFT)		{			gotoxy (x1, y2);			printf ("%c", special_chars[bc_lower_left]);		}		if (_borders & BRD_RIGHT)		{			gotoxy (x2, y2);			printf ("%c", special_chars[bc_lower_right]);		}	}	delete[]s;}void Window::clear_line(int _y){    // PROBLEM: if width changes!    if (_y > (height-1))        abort();    memcpy(canvas+width*_y, clearLine, width * sizeof(attrib));}void Window::draw_on_parent(){	if (parent)		parent->copy(canvas, width, height, parent_x, parent_y);}void Window::popUp(){    Window *_parent = parent;    _parent->remove(this);    _parent->insert(this);}void Window::die() {    Window *p = parent;    delete this;     if (p)        p->deathNotify(this);}Window* Window::find(Window* w){    for (Window *u = child_first; u; u = u->next)        if (u == w)            return w;    return NULL;}// Redraw a border windowvoid Border::redraw() {	set_color(fg_white|bg_blue);	    box(0,0,width-1,height-1, BRD_TOP|BRD_LEFT|BRD_RIGHT|BRD_BOTTOM);		// paint top/bottom messages		if (top_message.len()) {		gotoxy(1,0);		printf("%-*.*s", min(strlen(top_message),width-2), min(strlen(top_message),width-2), ~top_message);	}	if (bottom_message.len()) {		gotoxy(1,height-1);		printf("%-*.*s", min(strlen(bottom_message),width-2), min(strlen(bottom_message), width-2), ~bottom_message);	}		dirty = false;}void Border::set_top_message(const char *s) {    top_message = s;	dirty = true;}void Border::set_bottom_message (const char *s)  {    bottom_message = s;	dirty = true;}bool ScrollableWindow::scroll(){	memmove (canvas, canvas+width, sizeof(*canvas) * width*(height-1));		clear_line(height-1);    cursor_y--;	return true;}List<MessageWindow*> MessageWindow::list;MessageWindow* MessageWindow::find (const char *s){    for (MessageWindow *m = list.rewind(); m; m = list.next())        if (m->alias == s)            return m;    return NULL;}MessageWindow::MessageWindow (Window *_parent, const char *_alias, const char *_logfile, int _w, int _h, int _x, int _y, Style _style, int _timeout, bool _popOnInput, int _color):   ScrollableWindow(_parent, _w, _h, _style, _x, _y), Numbered(this),  alias(_alias), logfile(_logfile), popOnInput(_popOnInput), timeout(_timeout), default_color(_color){    char buf[256];    if (number == -1)        buf[0] = NUL;    else        sprintf(buf, "[%d] ", number);    sprintf(buf+strlen(buf), "%s ", _alias);    if (*_logfile)        sprintf(buf+strlen(buf), " => %s", _logfile);    //    set_top_message(buf);        last_input = current_time;    list.insert(this);    set_color(default_color);    clear();}void messageBox(int wait, const char *fmt, ...){    va_list va;    char buf[MAX_MUD_BUF];        va_start(va, fmt);    vsnprintf(buf, sizeof(buf), fmt, va);    va_end(va);        (void)new MessageBox(screen, buf, wait);}MessageBox::MessageBox(Window *_parent, const char *_message, int _wait):    Window(_parent, max(_parent->width/2, 3 + longestLine(_message)),                    countChar(_message, '\n') + 3 + (_wait ? 0 : 1), Bordered, xy_center, xy_center), message(_message),    creation_time(current_time), wait(_wait){    char line[MAX_MUD_BUF];    char *s;        set_color(bg_blue|fg_bold|fg_white);    clear();        strcpy(line, _message);    s = strtok(line, "\n");        while (s)    {        if (*s == *CENTER)        {            cprintf("%s", s+1); // need to center            print("\n");        }        else            printf("%s\n", s);                s = strtok(NULL, "\n");    }        if (!wait)    {        set_color(bg_blue|fg_bold|fg_green);        print ("\n");        cprintf ("Press ENTER to continue");    }}void Window::set_top_message(const char *s) {    if (parent)        parent->set_top_message(s);}void Window::set_bottom_message(const char *s) {    if (parent)        parent->set_bottom_message(s);}void Window::resizeNotify(Window *who, int w, int h) {    if (parent)        parent->resizeNotify(who, w, h);}void Window::visibilityNotify(Window *who, bool visible) {    if (parent)        parent->visibilityNotify(who, visible);}void Window::moveNotify(Window *who, int w, int h) {    if (parent)        parent->moveNotify(who, w, h);}void Window::deathNotify(Window *who) {    if (parent)        parent->deathNotify(who);}int Window::trueX() const {    return parent_x + (parent ? parent->trueX() : 0);}int Window::trueY() const {    return parent_y + (parent ? parent->trueY() : 0);}ProxyWindow::ProxyWindow(Window *_parent, int _w, int _h, int _x, int _y) : Window(_parent, _w, _h, None, _x, _y),proxy_target(NULL) {}Border::Border(Window *_parent, int _w, int _h, int _x, int _y) : ProxyWindow(_parent, _w, _h, _x, _y) {}void Border::visibilityNotify(Window *w, bool visible) {    if (w == proxy_target) {        show(visible);    }}void Border::deathNotify(Window *who) {    if (who == proxy_target)        die();}void ProxyWindow::insert(Window *w) {    proxy_target = w ;    Window::insert(w);}

⌨️ 快捷键说明

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