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

📄 singleedit.h

📁 vc编写的
💻 H
字号:
/*
 Copyright (c) 1999, kSet Lab 
 Author: Konstantin Bukreev 
 E-mail: konstantin@mail.primorye.ru 

 Created: 12.10.99 22:59:42
 Version: 1.0.1

 implementation of the buffer for single line editor box

 

*/

#ifndef _SingleEdit_80a721e9_7432_11d3_9285_0080adb811c5
#define _SingleEdit_80a721e9_7432_11d3_9285_0080adb811c5

#if _MSC_VER > 1000 
#pragma once
#endif // _MSC_VER > 1000

#include <deque>
#include <malloc.h>
#include "convert.h"

#ifdef _UNICODE 
#define _CF_TEXT CF_UNICODETEXT
#else
#define _CF_TEXT CF_TEXT
#endif

template <class _char>
class _sedit
{
public:
	typedef unsigned int _position;

	struct _sink
	{	
		void virtual onchange() = 0;
	};

private:
	enum {MIN_SIZE = 12};

	typedef _sedit<_char> T;
	class _stack;
	
	class _undo
	{
	protected:
		T* m_pT;
		const _position m_caret;
		const _position m_sel;
	public:
		_undo (T* p, _position caret, _position sel) : m_pT(p), m_caret(caret), m_sel(sel) {}
		virtual ~_undo() {}	
		virtual void Run(_stack* pstack) = 0;
	};

	class _undo_delete : public _undo
	{
		_char* m_str;	
	public:		
		_undo_delete (T* p, _position caret, _position sel, _char* str, int size)	: _undo(p, caret, sel)
		{
			m_str = new _char [size + 1];
			memcpy(m_str, str, size * sizeof _char);
			m_str[size] = _char(0);
		}
		~_undo_delete()
		{
			delete [] m_str;
		}
		void Run(_stack* pstack)
		{
			m_pT->caret(m_caret);
			m_pT->insert(m_str, pstack);			
		}
	};

	class _undo_insert : public _undo
	{		
	public:
		_undo_insert (T* p, _position caret, _position sel) : _undo(p, caret, sel) 
		{
		}
		~_undo_insert()
		{			
		}
		void Run(_stack* pstack)
		{
			m_pT->caret(m_caret);
			m_pT->select(m_sel);
			m_pT->del(pstack);			
		}
	};

	friend class _undo_delete;
	friend class _undo_insert;
	
	typedef std::deque <_undo*> _deque;

	class _stack : protected _deque
	{
	public:
		_undo* top () const {return back();}
		virtual void push (_undo* x) {push_back(x);}
		void pop () {pop_back();}
		bool empty() const {return _deque::empty();}
	};

	class _undostack : public _stack
	{
		int m_size;
	public:
		_undostack () : m_size(0) 
		{
		}
		virtual ~ _undostack () 
		{
			free();
		}
		void push(_undo* x)
		{
			_stack::push(x);			
			recheck();
		}    
		void set_stack_size(int size)
		{
			m_size = size;
			recheck();
		}		
		void free()
		{
			while(!empty())
				erase_top();
		}

	private:
		void recheck()
		{
			while (size() > m_size)
				erase_down();
		}
		void erase_top()
		{
			delete top();		
			pop();
		}
		void erase_down()
		{
			delete front();
			pop_front();
		};
	};
	
	typedef _undostack _redostack;

	class _undo_composite : public _stack, public _undo
	{		
	public:
		_undo_composite() : _undo(0,0,0) {}
		~_undo_composite()
		{
			while(!empty())
			{
				delete top();		
				pop();
			}
		}
		void Run(_stack* pstack)
		{
			_undo_composite* pundo = 0;
			if (pstack)
				pundo = new _undo_composite;

			while(!empty())
			{
				_undo* p = top();
				p->Run(pundo); 
				delete p;
				pop();				
			}

			if (pstack && pundo)
				pstack->push(pundo);
		}
	};
		
public:
	class _error
	{
	};

	_sedit ();
	_sedit (_char*, int, _sink*);
	~_sedit ();

	//read-write properties
	void      text(_char*)            throw(_error);
	const _char* text()         const throw();	
	void      caret(_position, bool shift = false) throw(_error);
	_position caret()           const throw();
	void      select(_position)       throw(_error);
	_position select()          const throw();
	void      enabled(bool)				 throw();
	bool      enabled(void) 	 const throw();
	void      sink (_sink* p)         throw();
	_sink*    sink (void)       const throw();

	//read properties
	bool      canundo()         const throw();
	bool      canredo()         const throw();
	int       length ()         const throw();	
	bool      isselect()        const throw();
		
	//methods
	void      reset_undo()            throw();
	void      empty  ()					 throw();
	void      undo	  ()					 throw(_error);	
	void      redo	  ()					 throw(_error);	
	void      insert (_char*)         throw(_error);
	void      insert (_char)          throw(_error);
	void      del    ()				    throw(_error);
	bool      left   (bool shift = false) throw();
	bool      right  (bool shift = false) throw();
	
	void      cut    ()					 throw(_error);	
	void      copy   ()               throw(_error); 
	void      paste  ()					 throw(_error);

	void      set_stack_size(int size)throw();
	void		 select_word()           throw();

private:
	
	void alloc(int size, bool bSave = false) throw(_error);
	void free() throw();
	int optimal_size(int) throw();
	void delete_select(_stack*) throw(_error);
	void normalize() throw();

	void insert (_char*, _stack*) throw(_error);	
	void del    (_stack*) throw(_error);

	_char*  m_pbuffer;
	_position m_sel;   //select
	_position m_caret; //input position
	int       m_len;   //size of data in buffer
	int       m_size;  //size of allocate memory
	bool      m_benabled;
	
	_undostack m_undo;
	_redostack m_redo;

	_sink* m_psink;
};

///////////////////////////////////////////////////////////////////////
//implement

//ctor/dtor
template <class _char>
_sedit<_char>::_sedit ()
{
	m_size = m_sel = m_caret = m_len = 0; 
	m_benabled = true;
	m_pbuffer = 0;
	alloc(0, false);
	m_pbuffer[0] = _char(0);	
	m_psink = 0;
}

template <class _char>
_sedit<_char>::_sedit (_char* txt, int stack_size, _sink* psink)
{
	m_size = m_sel = m_caret = m_len = 0; 
	m_benabled = true;
	m_pbuffer = 0;
	m_psink = 0;

	insert(txt, 0);
	set_stack_size(stack_size);
	sink(psink);
}

template <class _char>
_sedit<_char>::~_sedit ()
{
	free();	
}

//undo/redo stack support
template <class _char>
void _sedit<_char>::reset_undo() throw()
{
	m_undo.free();
	m_redo.free();
}

template <class _char>
void _sedit<_char>::set_stack_size(int size) throw()
{
	m_undo.set_stack_size(size);
	m_redo.set_stack_size(size);
}

//utilites
template <class _char>
int _sedit<_char>::optimal_size(int size)
{	
	if (size <= MIN_SIZE)
		return MIN_SIZE;

	int x = 16;
	while  (x < size)
		x = x << 1;	
	return x;	
};

template <class _char>
void _sedit<_char>::alloc(int size, bool bSave) throw(_error)
{
	size = optimal_size (size + 1); //for null terminate

	if (size == m_size)
		return;
	
	_char* p = m_pbuffer;
	__try {m_pbuffer = new _char[size];}
	__except(1) {m_pbuffer = p; throw _error();}

	if (p)
	{
		if (bSave)
			memcpy(m_pbuffer, p, m_len * sizeof _char);	
		delete [] p;	
	}	
	m_size = size;
}

template <class _char>
void _sedit<_char>::free() throw()
{
	if (m_pbuffer)
		delete [] m_pbuffer;

	m_caret = m_sel = m_size = m_len = 0; 
	m_pbuffer = 0;		
}

template <class _char>
void _sedit<_char>::normalize() throw()
{
	if (m_caret > m_sel)
	{
		_position temp = m_caret;
		m_caret = m_sel;
		m_sel = temp;
	}
}

template <class _char>
void _sedit<_char>::delete_select(_stack* pstack) throw(_error)
{
	_ASSERTE((m_sel >= m_caret));

	if (pstack)
		pstack->push(new _undo_delete(this, m_caret, m_sel, &m_pbuffer[m_caret], m_sel - m_caret));

	_position move = m_len - m_sel;
	memcpy(&m_pbuffer[m_caret], &m_pbuffer[m_sel], move * sizeof _char);		
	m_len -= m_sel - m_caret;
	m_sel = m_caret;	
}

template <class _char>
void _sedit<_char>::del(_stack* pstack) throw(_error)
{
	if (m_caret == m_len)
		return;

	if (m_sel == m_caret)
		m_sel = m_caret + 1;
	
	delete_select(pstack);	
	alloc(m_len, true);

	if (m_psink) m_psink->onchange();
}

template <class _char>
void _sedit<_char>::insert(_char* str, _stack* pstack) throw(_error)
{	
	if (!str)
		throw _error();
	
	_undo_composite* pundo = 0;
	if (pstack)
		pundo =  new _undo_composite;
	
	if (m_sel != m_caret)
	{		
		normalize();
		delete_select(pundo);
	}

	int len = _ex_util::_convert::_strlen(str);
	_position old = m_caret;
	m_sel = m_caret = m_caret + len;
	m_len += len;

	alloc(m_len, true);

	if (m_caret < m_len)
		memcpy(&m_pbuffer[m_caret], &m_pbuffer[old], (m_len - m_caret) * sizeof _char);

	memcpy(&m_pbuffer[old], str, len * sizeof _char);

	if (pstack && pundo)
	{
		pundo->push(new _undo_insert (this, old, m_caret));
		pstack->push(pundo);
	}

	if (m_psink) m_psink->onchange();
}

//properties
template <class _char>
void _sedit<_char>::enabled(bool value) throw()
{
	m_benabled = value;
}

template <class _char>
bool _sedit<_char>::enabled(void) const throw()
{
	return m_benabled;
}

template <class _char>
void _sedit<_char>::sink(_sink* p) throw()
{
	m_psink = p;
}

template <class _char>
_sedit<_char>::_sink* _sedit<_char>::sink(void) const throw()
{
	return m_psink;
}

template <class _char>
void _sedit<_char>::text (_char* str) throw(_error)
{
	if (!str)
		throw _error();

	caret(0);
	select(length());
	insert(str, 0);
}

template <class _char>
const _char* _sedit<_char>::text () const throw()
{
	m_pbuffer[m_len] = _char(0);
	return m_pbuffer;
}

template <class _char>
void _sedit<_char>::caret(_position caret, bool shift) throw(_error)
{
	if ((caret < 0) || (caret > m_len))
		throw _error();

	m_caret = caret;
	if (!shift)
		m_sel = m_caret;
}

template <class _char>
_sedit<_char>::_position _sedit<_char>::caret() const throw()
{
	return m_caret;
}

template <class _char>
void  _sedit<_char>::select (_position sel) throw(_error)
{
	if ((sel < 0) || (sel > m_len))
		throw _error();

	m_sel = sel;
}

template <class _char>
_sedit<_char>::_position _sedit<_char>::select () const throw()
{
	return m_sel;
}

template <class _char>
bool _sedit<_char>::canundo() const throw()
{
	if (!m_benabled) return false;
	return !m_undo.empty();
}

template <class _char>
bool _sedit<_char>::canredo() const throw()
{
	if (!m_benabled) return false;
	return !m_redo.empty();
}

template <class _char>
int _sedit<_char>::length () const throw()
{
	return m_len;
}

template <class _char>
bool _sedit<_char>::isselect() const throw()
{
	return (m_caret != m_sel);
}

//methods
template <class _char>
void _sedit<_char>::select_word() throw()
{
	m_sel = m_caret;
	
	while (m_caret && m_pbuffer[m_caret - 1] != _char(' '))
		m_caret--;

	while (m_sel < m_len && m_pbuffer[m_sel] != _char(' '))
		m_sel++;
}

template <class _char>
void _sedit<_char>::empty () throw()
{
	free();
}

template <class _char>
void _sedit<_char>::undo() throw(_error)
{
	if (m_undo.empty())
		return;

	_undo* p = m_undo.top();
	p->Run(&m_redo); 
	delete p;
	m_undo.pop();
}

template <class _char>
void _sedit<_char>::redo() throw(_error)
{
	if (m_redo.empty())
		return;

	_undo* p = m_redo.top();
	p->Run(&m_undo); 
	delete p;
	m_redo.pop();
}

template <class _char>
void _sedit<_char>::insert(_char* ch) throw(_error)
{
	if (!m_benabled) return;	
	m_redo.free();

	insert(ch, &m_undo);
}

template <class _char>
void _sedit<_char>::insert(_char ch) throw(_error)
{
	if (!m_benabled) return;
	m_redo.free();

	_char p[2];
	p[0] = ch; p[1] = _char(0);
	insert(p, &m_undo);
}

template <class _char>
void _sedit<_char>::del() throw(_error)
{
	if (!m_benabled) return;
	m_redo.free();

	normalize();
	del(&m_undo);
}

template <class _char>
bool _sedit<_char>::left(bool shift) throw()
{
	if (0 == m_caret)
		return false;

	m_caret--;
	if (!shift)
		m_sel = m_caret;

	return true;
}

template <class _char>
bool _sedit<_char>::right(bool shift) throw()
{
	if (m_len == m_caret)
		return false;

	m_caret++;
	if (!shift)
		m_sel = m_caret;
	return true;
}

template <class _char>
void _sedit<_char>::copy() throw(_error)
{	
	if (m_sel == m_caret) return;

	bool bResult = false;
	if (OpenClipboard(0)) 
	{
		EmptyClipboard();
		normalize();
		int len = m_sel - m_caret;
		HGLOBAL hMemory = GlobalAlloc(GHND, (len + 1) * sizeof _char);
		if (hMemory)
		{
			void* p = GlobalLock(hMemory);	
			if (p)
			{		
				_char* ptext = (_char*)&text()[m_caret];	
				_ex_util::_convert::make((TCHAR*)p, ptext, len); 	
				//((TCHAR*)p)[len] = TCHAR(0); because GMEM_ZEROINIT in GHND include
				GlobalUnlock(hMemory);
				bResult = (SetClipboardData(_CF_TEXT, hMemory) != 0);
			}
		}

		CloseClipboard();	
	}

	if (!bResult) throw _error();
} 

template <class _char>	
void _sedit<_char>::cut () throw(_error)
{
	if (!m_benabled) return;

	copy();
	del(&m_undo);
}

template <class _char>
void _sedit<_char>::paste() throw(_error)
{
	if (!m_benabled) return; 
	
	_char* buffer = 0;
	int len = 0;
	if (OpenClipboard(0)) 
	{
		HANDLE hMemory = GetClipboardData(_CF_TEXT);	
		if (hMemory)
		{
			TCHAR* p = (TCHAR*)GlobalLock(hMemory);
			if (p)
			{
				len = _ex_util::_convert::_strlen(p);
				buffer = (_char*)_alloca((len + 1) * sizeof _char);
				_ex_util::_convert::make(buffer, p, len); 		
				GlobalUnlock(hMemory);	
			}
		}

		CloseClipboard ();
	}
			
	if (!buffer) throw _error();

	buffer[len] = _char(0);
	insert(buffer, &m_undo);	
}

#endif //_SingleEdit_80a721e9_7432_11d3_9285_0080adb811c5

⌨️ 快捷键说明

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