Now ColorPage's Pointer to ColorFrame will be updated when a new pointer is set. (Fix getFrame() == nullptr Error)
699 lines
14 KiB
C++
699 lines
14 KiB
C++
#include "ColorUI.h"
|
|
#include <algorithm>
|
|
#include <windows.h>
|
|
#include <conio.h>
|
|
|
|
namespace _cns
|
|
{
|
|
|
|
class _auto_init_console_info_class
|
|
{
|
|
public:
|
|
_auto_init_console_info_class()
|
|
{
|
|
hout=GetStdHandle(STD_OUTPUT_HANDLE);
|
|
CONSOLE_SCREEN_BUFFER_INFO tInfo;
|
|
GetConsoleScreenBufferInfo(hout,&tInfo);
|
|
color=tInfo.wAttributes;
|
|
}
|
|
HANDLE hout;
|
|
WORD color;
|
|
}_auto_init_console_info_obj;
|
|
|
|
inline ConsoleColor _winColor2ConsoleColor(int winColor)
|
|
{
|
|
switch(winColor)
|
|
{
|
|
case 0:
|
|
return ConsoleColor::black;
|
|
case FOREGROUND_BLUE:
|
|
case BACKGROUND_BLUE:
|
|
return ConsoleColor::blue;
|
|
case FOREGROUND_GREEN:
|
|
case BACKGROUND_GREEN:
|
|
return ConsoleColor::green;
|
|
case FOREGROUND_RED:
|
|
case BACKGROUND_RED:
|
|
return ConsoleColor::red;
|
|
case FOREGROUND_GREEN | FOREGROUND_BLUE:
|
|
case BACKGROUND_GREEN | BACKGROUND_BLUE:
|
|
return ConsoleColor::lightblue;
|
|
case FOREGROUND_RED | FOREGROUND_BLUE:
|
|
case BACKGROUND_RED | BACKGROUND_BLUE:
|
|
return ConsoleColor::purple;
|
|
case FOREGROUND_RED | FOREGROUND_GREEN:
|
|
case BACKGROUND_RED | BACKGROUND_GREEN:
|
|
return ConsoleColor::yellow;
|
|
case FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED:
|
|
case BACKGROUND_BLUE | BACKGROUND_GREEN | BACKGROUND_RED:
|
|
return ConsoleColor::white;
|
|
}
|
|
}
|
|
|
|
inline int _ConsoleColor2winForeColor(ConsoleColor conColor)
|
|
{
|
|
switch(conColor)
|
|
{
|
|
case ConsoleColor::black:
|
|
return 0;
|
|
case ConsoleColor::blue:
|
|
return FOREGROUND_BLUE;
|
|
case ConsoleColor::green:
|
|
return FOREGROUND_GREEN;
|
|
case ConsoleColor::red:
|
|
return FOREGROUND_RED;
|
|
case ConsoleColor::lightblue:
|
|
return FOREGROUND_GREEN | FOREGROUND_BLUE;
|
|
case ConsoleColor::purple:
|
|
return FOREGROUND_RED |FOREGROUND_BLUE;
|
|
case ConsoleColor::yellow:
|
|
return FOREGROUND_RED | FOREGROUND_GREEN;
|
|
case ConsoleColor::white:
|
|
return FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED;
|
|
default:
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
inline int _ConsoleColor2winBackColor(ConsoleColor conColor)
|
|
{
|
|
switch(conColor)
|
|
{
|
|
case ConsoleColor::black:
|
|
return 0;
|
|
case ConsoleColor::blue:
|
|
return BACKGROUND_BLUE;
|
|
case ConsoleColor::green:
|
|
return BACKGROUND_GREEN;
|
|
case ConsoleColor::red:
|
|
return BACKGROUND_RED;
|
|
case ConsoleColor::lightblue:
|
|
return BACKGROUND_GREEN | BACKGROUND_BLUE;
|
|
case ConsoleColor::purple:
|
|
return BACKGROUND_RED | BACKGROUND_BLUE;
|
|
case ConsoleColor::yellow:
|
|
return BACKGROUND_RED | BACKGROUND_GREEN;
|
|
case ConsoleColor::white:
|
|
return BACKGROUND_BLUE | BACKGROUND_GREEN | BACKGROUND_RED;
|
|
default:
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
inline void cprint(ConsoleColor FrontColor,ConsoleColor BackColor)
|
|
{
|
|
int iFront=_ConsoleColor2winForeColor(FrontColor);
|
|
int iBack=_ConsoleColor2winBackColor(BackColor);
|
|
if(iFront!=0) iFront=iFront | FOREGROUND_INTENSITY;
|
|
if(iBack!=0) iBack=iBack| BACKGROUND_INTENSITY;
|
|
SetConsoleTextAttribute(_auto_init_console_info_obj.hout,iFront | iBack );
|
|
}
|
|
|
|
inline void cprint()
|
|
{
|
|
SetConsoleTextAttribute(_auto_init_console_info_obj.hout,_auto_init_console_info_obj.color);
|
|
}
|
|
|
|
int _last_keyval;
|
|
int _GetUserInputKey_Real()
|
|
{
|
|
return _last_keyval=getch();///defined in conio.h
|
|
}
|
|
|
|
enum class KEY { UNDEF=0, UP, DOWN, LEFT, RIGHT, CONFIRM, ESC, HOME, END };
|
|
int _last_isSpecial;
|
|
|
|
KEY GetUserInputKey()
|
|
{
|
|
int a=_GetUserInputKey_Real();
|
|
if(a==224||a==0)
|
|
{
|
|
_last_isSpecial=1;
|
|
int b=_GetUserInputKey_Real();
|
|
switch(b)
|
|
{
|
|
case 72:return KEY::UP;
|
|
case 80:return KEY::DOWN;
|
|
case 75:return KEY::LEFT;
|
|
case 77:return KEY::RIGHT;
|
|
case 71:return KEY::HOME;
|
|
case 79:return KEY::END;
|
|
default:return KEY::UNDEF;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
_last_isSpecial=0;
|
|
switch(a)
|
|
{
|
|
case ' ':case '\r':case '\n':case '5':
|
|
return KEY::CONFIRM;
|
|
case 'w':case 'W':case '8':
|
|
return KEY::UP;
|
|
case 's':case 'S':case '2':
|
|
return KEY::DOWN;
|
|
case 'a':case 'A':case '4':
|
|
return KEY::LEFT;
|
|
case 'd':case 'D':case '6':
|
|
return KEY::RIGHT;
|
|
case 27:
|
|
return KEY::ESC;
|
|
|
|
default:
|
|
return KEY::UNDEF;
|
|
}
|
|
}
|
|
}
|
|
|
|
int GetAction(int& cid,int MinVal,int MaxVal,int EscapeVal)
|
|
{
|
|
KEY t=GetUserInputKey();
|
|
switch(t)
|
|
{
|
|
case KEY::UP:
|
|
{
|
|
cid=std::max(std::min(cid-1,MaxVal),MinVal);
|
|
return 0;
|
|
}
|
|
case KEY::DOWN:
|
|
{
|
|
cid=std::max(std::min(cid+1,MaxVal),MinVal);
|
|
return 0;
|
|
}
|
|
case KEY::ESC:
|
|
{
|
|
cid=EscapeVal;
|
|
return 0;
|
|
}
|
|
case KEY::CONFIRM:
|
|
return 1;
|
|
case KEY::HOME:
|
|
{
|
|
cid=MinVal;
|
|
return 0;
|
|
}
|
|
case KEY::END:
|
|
{
|
|
cid=MaxVal;
|
|
return 0;
|
|
}
|
|
default:
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
}/// End of namespace _cns
|
|
|
|
ColorSelection::ColorSelection()
|
|
{
|
|
frontColorNormal=ConsoleColor::white;
|
|
backColorNormal=ConsoleColor::black;
|
|
frontColorActivate=ConsoleColor::black;
|
|
backColorActivate=ConsoleColor::yellow;
|
|
_is_active=false;
|
|
_pframe=nullptr;
|
|
}
|
|
|
|
//virtual
|
|
ColorSelection::~ColorSelection()
|
|
{
|
|
|
|
}
|
|
|
|
//virtual
|
|
void ColorSelection::drawText()
|
|
{
|
|
if(_is_active)
|
|
{
|
|
_cns::cprint(frontColorActivate,backColorActivate);
|
|
}
|
|
else
|
|
{
|
|
_cns::cprint(frontColorNormal,backColorNormal);
|
|
}
|
|
|
|
printf("%s",text.c_str());
|
|
}
|
|
|
|
//virtual
|
|
void ColorSelection::drawInfo()
|
|
{
|
|
printf("%s",info.c_str());
|
|
}
|
|
|
|
bool ColorSelection::hasInfo()
|
|
{
|
|
return !info.empty();
|
|
}
|
|
|
|
//virtual
|
|
void ColorSelection::onActivate()
|
|
{
|
|
_is_active=true;
|
|
}
|
|
|
|
//virtual
|
|
void ColorSelection::onDeActivate()
|
|
{
|
|
_is_active=false;
|
|
}
|
|
|
|
ColorFrame* ColorSelection::getFrame()
|
|
{
|
|
return _pframe;
|
|
}
|
|
|
|
void ColorSelection::setFrame(ColorFrame* pFrame)
|
|
{
|
|
_pframe=pFrame;
|
|
}
|
|
|
|
//virtual
|
|
int ColorSelection::onClick()
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
//virtual
|
|
int ColorSelection::onDelete()
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
ColorPage::ColorPage()
|
|
{
|
|
titleFrontColor=ConsoleColor::black;
|
|
titleBackColor=ConsoleColor::lightblue;
|
|
textFrontColor=ConsoleColor::white;
|
|
textBackColor=ConsoleColor::black;
|
|
_curActive=0;
|
|
_pframe=nullptr;
|
|
}
|
|
|
|
//virtual
|
|
ColorPage::~ColorPage()
|
|
{
|
|
|
|
}
|
|
|
|
void ColorPage::add(ColorSelection* p)
|
|
{
|
|
p->setFrame(getFrame());
|
|
_vec.push_back(p);
|
|
}
|
|
|
|
int ColorPage::del(ColorSelection* p)
|
|
{
|
|
auto iter=std::find(_vec.begin(),_vec.end(),p);
|
|
if(iter==_vec.end())
|
|
{
|
|
/// Object to delete is Not Found
|
|
return 1;
|
|
}
|
|
|
|
if(_curActive==iter-_vec.begin()+1)
|
|
{
|
|
/// Current Activated Selection is to be deleted.
|
|
_curActive=0;
|
|
|
|
/// Delete Selection
|
|
if((*iter)->onDelete()==0)
|
|
{
|
|
(*iter)->setFrame(nullptr);
|
|
delete (*iter);
|
|
}
|
|
else
|
|
{
|
|
(*iter)->setFrame(nullptr);
|
|
}
|
|
|
|
/// Delete From Record.
|
|
_vec.erase(iter);
|
|
}
|
|
else
|
|
{
|
|
/// Get current activated selection.
|
|
ColorSelection* _curActive_ptr=_vec.at(_curActive-1);
|
|
|
|
/// Delete Target Selection
|
|
if((*iter)->onDelete()==0)
|
|
{
|
|
(*iter)->setFrame(nullptr);
|
|
delete (*iter);
|
|
}
|
|
else
|
|
{
|
|
(*iter)->setFrame(nullptr);
|
|
}
|
|
|
|
/// Delete Target From Record.
|
|
_vec.erase(iter);
|
|
|
|
/// Re-Calculate active id.
|
|
_curActive=std::find(_vec.begin(),_vec.end(),_curActive_ptr)-_vec.begin()+1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int ColorPage::getSelectionSize() const
|
|
{
|
|
return _vec.size();
|
|
}
|
|
|
|
int ColorPage::getCurrentActive() const
|
|
{
|
|
return _curActive;
|
|
}
|
|
|
|
|
|
ColorFrame* ColorPage::getFrame()
|
|
{
|
|
return _pframe;
|
|
}
|
|
|
|
void ColorPage::setFrame(ColorFrame* pFrame)
|
|
{
|
|
_pframe=pFrame;
|
|
for(auto& ptr:_vec)
|
|
{
|
|
ptr->setFrame(getFrame());
|
|
}
|
|
}
|
|
|
|
//virtual
|
|
void ColorPage::draw()
|
|
{
|
|
if(!title.empty())
|
|
{
|
|
_cns::cprint(titleFrontColor,titleBackColor);
|
|
printf("%s\n",title.c_str());
|
|
}
|
|
if(!text.empty())
|
|
{
|
|
_cns::cprint(textFrontColor,textBackColor);
|
|
printf("%s\n",text.c_str());
|
|
}
|
|
if(!_curActive) // _curActive==0
|
|
{
|
|
if(!_vec.empty())
|
|
{
|
|
_curActive=1;
|
|
onSelectionOver(_curActive);
|
|
}
|
|
}
|
|
for(auto iter=_vec.begin();iter!=_vec.end();++iter)
|
|
{
|
|
if(!(*iter)->text.empty())
|
|
{
|
|
(*iter)->drawText();
|
|
}
|
|
else
|
|
{
|
|
_cns::cprint();
|
|
printf("(Empty Selection)");
|
|
}
|
|
printf("\n");
|
|
}
|
|
_cns::cprint();
|
|
printf("---------------\n");
|
|
if(_vec.at(_curActive-1)->hasInfo())
|
|
{
|
|
_vec.at(_curActive-1)->drawInfo();
|
|
printf("\n");
|
|
}
|
|
_cns::cprint();
|
|
}
|
|
|
|
//virtual
|
|
int ColorPage::onLoad()
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
//virtual
|
|
void ColorPage::onBackground()
|
|
{
|
|
|
|
}
|
|
|
|
//virtual
|
|
void ColorPage::onForeground()
|
|
{
|
|
|
|
}
|
|
|
|
//virtual
|
|
int ColorPage::onUnload()
|
|
{
|
|
for(auto& ptr:_vec)
|
|
{
|
|
if(!ptr->onDelete())
|
|
{
|
|
delete ptr;
|
|
}
|
|
}
|
|
_vec.clear();
|
|
_curActive=0;
|
|
return 0;
|
|
}
|
|
|
|
//virtual
|
|
void ColorPage::onSelectionOver(int id)
|
|
{
|
|
_vec.at(_curActive-1)->onDeActivate();
|
|
_vec.at(id-1)->onActivate();
|
|
_curActive=id;
|
|
}
|
|
|
|
//virtual
|
|
int ColorPage::onActive(int id)
|
|
{
|
|
return _vec.at(id-1)->onClick();
|
|
}
|
|
|
|
//protected
|
|
std::vector<ColorSelection*>& ColorPage::_getvec()
|
|
{
|
|
return _vec;
|
|
}
|
|
|
|
ColorFrame::ColorFrame()
|
|
{
|
|
_home_page=nullptr;
|
|
_cur_page=nullptr;
|
|
_next_page=nullptr;
|
|
_delete_home_page_on_dtor=true;
|
|
_has_started=false;
|
|
}
|
|
|
|
ColorFrame::~ColorFrame()
|
|
{
|
|
|
|
}
|
|
|
|
void ColorFrame::setHomePage(ColorPage* pPage,bool deleteOnRemove)
|
|
{
|
|
if(_has_started) return;
|
|
_home_page=pPage;
|
|
_delete_home_page_on_dtor=deleteOnRemove;
|
|
pPage->setFrame(this);
|
|
}
|
|
|
|
ColorPage* ColorFrame::getHomePage()
|
|
{
|
|
return _home_page;
|
|
}
|
|
|
|
void ColorFrame::jumpTo(ColorPage* nextPage)
|
|
{
|
|
_next_page=nextPage;
|
|
}
|
|
|
|
void ColorFrame::clearScreen()
|
|
{
|
|
_cns::cprint();
|
|
system("cls");
|
|
}
|
|
|
|
void ColorFrame::clearInput()
|
|
{
|
|
fflush(stdin);
|
|
}
|
|
|
|
void ColorFrame::enterInputMode()
|
|
{
|
|
clearInput();
|
|
}
|
|
|
|
void ColorFrame::exitInputMode()
|
|
{
|
|
clearInput();
|
|
}
|
|
|
|
void ColorFrame::run()
|
|
{
|
|
/// A Frame can only be started once.
|
|
if(_has_started) return;
|
|
|
|
_has_started=true;
|
|
|
|
/// No Home Page
|
|
if(_home_page==nullptr) return;
|
|
_cur_page=_home_page;
|
|
|
|
_cur_page->onLoad();
|
|
|
|
bool stop=false;
|
|
int cid=0;
|
|
while(!stop)
|
|
{
|
|
clearScreen();
|
|
_cur_page->draw();
|
|
if(_cur_page->getSelectionSize()>0)
|
|
{
|
|
cid=_cur_page->getCurrentActive();
|
|
int oldcid=cid;
|
|
if(_cns::GetAction(cid,1,_cur_page->getSelectionSize(),_cur_page->getSelectionSize()))
|
|
{
|
|
/// Confirmed Key Pressed.
|
|
switch(_cur_page->onActive(cid))
|
|
{
|
|
case 0:
|
|
{
|
|
if(_next_page!=nullptr)
|
|
{
|
|
/// New Page!
|
|
/// Bring Current Page to Background
|
|
_cur_page->onBackground();
|
|
_stk.push(_cur_page);
|
|
|
|
/// Load New Page
|
|
_cur_page=_next_page;
|
|
_next_page=nullptr;
|
|
_cur_page->setFrame(this);
|
|
_cur_page->onLoad();
|
|
}
|
|
else
|
|
{
|
|
/// No New Page. Go Straight.
|
|
}
|
|
}
|
|
break;
|
|
case 1:
|
|
{
|
|
/// Unload Current Page
|
|
if(_cur_page->onUnload()==0)
|
|
{
|
|
_cur_page->setFrame(nullptr);
|
|
delete _cur_page;
|
|
}
|
|
else
|
|
{
|
|
_cur_page->setFrame(nullptr);
|
|
}
|
|
_cur_page=nullptr;
|
|
|
|
/// Bring Previous Page to Foreground.
|
|
if(_stk.empty())
|
|
{
|
|
stop=true;
|
|
}
|
|
else
|
|
{
|
|
_cur_page=_stk.top();
|
|
_stk.pop();
|
|
_cur_page->onForeground();
|
|
}
|
|
}
|
|
break;
|
|
case 2:
|
|
default:
|
|
stop=true;
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/// If not confirmed , just go ahead.
|
|
if(oldcid!=cid)
|
|
{
|
|
_cur_page->onSelectionOver(cid);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/// Unload Current Page
|
|
if(_cur_page->onUnload()==0)
|
|
{
|
|
_cur_page->setFrame(nullptr);
|
|
delete _cur_page;
|
|
}
|
|
else
|
|
{
|
|
_cur_page->setFrame(nullptr);
|
|
}
|
|
_cur_page=nullptr;
|
|
|
|
/// Bring Previous Page to Foreground.
|
|
if(_stk.empty())
|
|
{
|
|
stop=true;
|
|
}
|
|
else
|
|
{
|
|
_cur_page=_stk.top();
|
|
_stk.pop();
|
|
_cur_page->onForeground();
|
|
}
|
|
}
|
|
}
|
|
|
|
if(_cur_page)
|
|
{
|
|
if(_cur_page->onUnload()==0)
|
|
{
|
|
_cur_page->setFrame(nullptr);
|
|
delete _cur_page;
|
|
}
|
|
else
|
|
{
|
|
_cur_page->setFrame(nullptr);
|
|
}
|
|
_cur_page=nullptr;
|
|
}
|
|
while(!_stk.empty())
|
|
{
|
|
_cur_page=_stk.top();
|
|
_cur_page->onForeground();
|
|
if(_cur_page->onUnload()==0)
|
|
{
|
|
_cur_page->setFrame(nullptr);
|
|
delete _cur_page;
|
|
}
|
|
else
|
|
{
|
|
_cur_page->setFrame(nullptr);
|
|
}
|
|
}
|
|
_cur_page=nullptr;
|
|
}
|
|
|
|
ColorInputModeGuard::ColorInputModeGuard(ColorFrame* f)
|
|
{
|
|
_pframe=f;
|
|
if(_pframe)
|
|
{
|
|
_pframe->enterInputMode();
|
|
}
|
|
}
|
|
|
|
ColorInputModeGuard::~ColorInputModeGuard()
|
|
{
|
|
if(_pframe)
|
|
{
|
|
_pframe->exitInputMode();
|
|
}
|
|
}
|