📄 tview.cpp
字号:
#endif
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CTView message handlers
BOOL CTView::PreCreateWindow(CREATESTRUCT& cs)
{
if (!CWnd::PreCreateWindow(cs))
return FALSE;
cs.style &= ~WS_BORDER;
cs.lpszClass = AfxRegisterWndClass(CS_HREDRAW|CS_VREDRAW|CS_DBLCLKS,
NULL, NULL, NULL);
return TRUE;
}
struct FormatterGetLine: public CTView::IGetLine {
TextFormatter *m_tf;
int m_page;
int m_off;
int m_len;
FormatterGetLine(TextFormatter *tf,int page) : m_tf(tf), m_page(page), m_off(0) {
for (int i=0;i<page;++i)
m_off+=tf->PageLength(i);
m_len=tf->PageLength(page);
}
int Length() { return m_len; }
const Line& At(int i) { return m_tf->GetLine(m_off+i); }
};
static inline bool Overlap(const RECT& r1,const RECT& r2) {
return !(
r1.right<=r2.left ||
r1.left>=r2.right ||
r1.bottom<=r2.top ||
r1.top>=r2.bottom
);
}
void CTView::OnPaint()
{
RECT update_rect;
if (!GetUpdateRect(&update_rect))
return;
System2Window(update_rect,m_Window.cli);
PAINTSTRUCT ps;
{
// do a quick check for bookmarks
bool checkbmk=false;
if (m_Window.showprogress() && m_textfile->bmk().BookmarksInRange(
m_formatter->Top(),m_formatter->Bottom()))
checkbmk=true;
// draw stuff
CFDC fdc(m_hWnd,&ps);
RECT col;
col.left=col.top=0;
col.right=m_Window.width;
col.bottom=m_Window.rheight;
if (m_Window.showprogress())
col.bottom-=m_Window.progress_height;
for (int column=0;column<m_Window.columns;++column) {
if (Overlap(col,update_rect)) {
FormatterGetLine gl(m_formatter.get(),column);
PaintColumn(fdc,update_rect,col,m_Window.cli,
&gl,m_TextDisp.margin_width,checkbmk);
}
col.left+=m_Window.width;
col.right+=m_Window.width;
}
if (m_Window.showprogress()) {
col.left=0; col.top=m_Window.rheight-m_Window.progress_height;
col.right=m_Window.rwidth; col.bottom=m_Window.rheight;
if (Overlap(col,update_rect)) {
UpdateWindowPD();
PaintProgressBar(fdc,col,m_Window.cli);
}
}
if (m_UI.visible && Overlap(m_UI.rc,update_rect))
PaintUserInput(fdc,m_UI.rc,m_Window.cli,Unicode::ToWCbuf(m_UI.inp));
if (m_BP.visible && Overlap(m_BP.rc,update_rect))
PaintBookmarkPopup(fdc,m_BP.rc,m_Window.cli);
}
}
void CTView::RedrawProgressBar() {
if (!m_Window.showprogress())
return;
CFDC fdc(m_hWnd);
RECT col;
col.left=0; col.top=m_Window.rheight-m_Window.progress_height;
col.right=m_Window.rwidth; col.bottom=m_Window.rheight;
UpdateWindowPD();
PaintProgressBar(fdc,col,m_Window.cli);
}
void CTView::PaintSingleLine(int column,int line,COLORREF underline) {
if (column<0 || column>=m_Window.columns)
return;
if (line<0 || line>=m_formatter->PageLength(column))
return;
FormatterGetLine gl(m_formatter.get(),column);
RECT line_rect;
line_rect.left=m_Window.width*column;
line_rect.right=line_rect.left+m_Window.width;
line_rect.top=0;
for (int i=0;i<line;++i)
line_rect.top+=gl.At(i).height;
const Line& line_data=gl.At(line);
line_rect.bottom=line_rect.top+line_data.height;
RECT cli;
GetClientRect(&cli);
CFDC dc(m_hWnd);
dc.SetTextColor(C_NORM);
dc.SetBkColor(v_C_BG());
RECT tmp=line_rect;
PaintLine(dc,cli,tmp,m_TextDisp.margin_width,line_data);
dc.SetColor(C_TOCBM);
HighlightBookmarks(dc,cli,line_rect.left,m_TextDisp.margin_width,
line_rect.top,line_data,line_data.pos,gl.At(line+1).pos);
if (underline!=CLR_DEFAULT) {
tmp=line_rect;
tmp.top=tmp.bottom=tmp.bottom-1;
dc.SetColor(underline);
TDrawLine(dc.DC(),cli,tmp);
}
// if this is the last line in column, then paint till column bottom
if (line==gl.Length()-1) {
line_rect.top=line_rect.bottom;
line_rect.bottom=m_Window.rheight;
TDrawText(dc.DC(),line_rect.left,line_rect.top,cli,line_rect,NULL,0,NULL);
if (m_Window.showprogress()) {
tmp.left=0; tmp.top=m_Window.rheight-m_Window.progress_height;
tmp.right=m_Window.rwidth; tmp.bottom=m_Window.rheight;
UpdateWindowPD();
PaintProgressBar(dc,tmp,m_Window.cli);
}
}
}
void CTView::PaintSbItem(CFDC& dc,const wchar_t *text,int len,const RECT& rc,
const RECT& cli,int& pb_width)
{
if (len<0)
len=wcslen(text);
RECT ii;
SIZE sz;
int nch=0;
dc.GetTextExtent(text,len,rc.right-rc.left,nch,NULL,sz);
if (pb_width>0)
sz.cx+=3; // XXX padding
ii.top=rc.top-2;
ii.bottom=rc.bottom;
ii.left=rc.right-sz.cx-pb_width-1;
ii.right=ii.left+sz.cx;
TDrawText(dc.DC(),ii.left,ii.top,cli,ii,text,len,NULL,ETO_OPAQUE);
pb_width+=sz.cx;
}
bool CTView::UpdateWindowPD() {
bool upd=false;
// calculate current position
int top=m_textfile->GetTotalLength(m_formatter->DocId());
int cur=m_formatter->DocId()<0 ? m_textfile->GetPStart(m_formatter->DocId(),m_formatter->Top().para) :
m_textfile->AbsPos(m_formatter->Bottom());
m_Window.pd.cc=cur;
if (m_formatter->DocId()>=0)
cur=(cur+1)>>11;
else
cur=-(top ? MulDivS(100,cur,top) : 100) - 1;
if (cur!=m_Window.pd.pos) {
if (m_Window.pb.position)
upd=true;
m_Window.pd.pos=cur;
}
if (top!=m_Window.pd.top) {
if (m_Window.pb.top && m_formatter->DocId()>=0)
upd=true;
m_Window.pd.top=top;
}
// find current chapter title
if (m_Window.pb.chapter) {
int idx=m_textfile->bmk().BFind(m_formatter->Top(),Bookmarks::SPREVCH);
if (idx<m_textfile->bmk().GetSize() &&
m_textfile->bmk().Ref(idx).docid==m_formatter->Top().docid)
{
CString cur=m_textfile->bmk().Text(idx,m_textfile.get());
if (cur!=m_Window.pd.title) {
upd=true;
m_Window.pd.title=cur;
}
} else if (!m_Window.pd.title.IsEmpty()) {
m_Window.pd.title.Empty();
upd=true;
}
}
cur=m_AS.delay/1000;
if (cur!=m_Window.pd.as) {
if (m_Window.pb.as_delay)
upd=true;
m_Window.pd.as=cur;
}
SYSTEMTIME stm;
::GetLocalTime(&stm);
cur=(stm.wHour<<8) | stm.wMinute;
if (cur!=m_Window.pd.tm) {
if (m_Window.pb.time)
upd=true;
m_Window.pd.tm=cur;
}
#ifdef _WIN32_WCE
SYSTEM_POWER_STATUS_EX pws;
BOOL ok=GetSystemPowerStatusEx(&pws,FALSE);
#else
SYSTEM_POWER_STATUS pws;
BOOL ok=GetSystemPowerStatus(&pws);
#endif
if (ok && pws.BatteryLifePercent>=0 && pws.BatteryLifePercent<=100) {
if (pws.ACLineStatus==1)
cur=101;
else
cur=pws.BatteryLifePercent;
} else
cur=-1;
if (cur!=m_Window.pd.bat) {
if (m_Window.pb.battery)
upd=true;
m_Window.pd.bat=cur;
}
return upd;
}
void CTView::StartWindowPDTimer() {
if (m_Window.showprogress() && (m_Window.pb.battery || m_Window.pb.time))
m_Window.pd_timer=SetTimer(TM_PD,2000,NULL);
else {
KillTimer(m_Window.pd_timer);
m_Window.pd_timer=0;
}
}
void CTView::UpdateProgressBar() {
if (UpdateWindowPD()) {
CFDC fdc(m_hWnd);
RECT col;
col.left=0; col.top=m_Window.rheight-m_Window.progress_height;
col.right=m_Window.rwidth; col.bottom=m_Window.rheight;
PaintProgressBar(fdc,col,m_Window.cli);
}
}
void CTView::PaintProgressBar(CFDC& dc,const RECT& rc,const RECT& cli) {
RECT col;
wchar_t buf[128];
int fonthdpi = MulDivS(PROGRESS_F, GetDeviceCaps(dc.DC(), LOGPIXELSY), 72);
dc.SelectFontAbs(fonthdpi,CFDC::FORCENORMALWEIGHT|CFDC::FORCETAHOMA);
::SetBkMode(dc.DC(),OPAQUE);
// clear area
dc.SetBkColor(v_C_BG());
TDrawText(dc.DC(),rc.left,rc.top,m_Window.cli,rc,NULL,0,NULL);
m_Window.pb_width=0;
if (m_Window.pb.battery && m_Window.pd.bat>=0) {
if (m_Window.pd.bat>100)
wcscpy(buf,L"AC");
else
swprintf(buf,L"%d%%",m_Window.pd.bat);
PaintSbItem(dc,buf,-1,rc,m_Window.cli,m_Window.pb_width);
}
if (m_Window.pb.time) {
swprintf(buf,L"%02d:%02d",m_Window.pd.tm>>8,m_Window.pd.tm&0xff);
PaintSbItem(dc,buf,-1,rc,m_Window.cli,m_Window.pb_width);
}
if (m_Window.pb.as_delay && m_AS.timer) {
swprintf(buf,L"%d",m_Window.pd.as);
PaintSbItem(dc,buf,-1,rc,m_Window.cli,m_Window.pb_width);
}
// draw vpage number for normal docs, or a back button for dictionary
if (m_Window.pb.position || (m_Window.pb.top && m_Window.pd.pos>=0)) {
if (m_Window.pd.pos>=0) {
if (m_Window.pb.top)
swprintf(buf,L"%d/%d",m_Window.pd.pos,m_Window.pd.top>>11);
else
swprintf(buf,L"%d",m_Window.pd.pos);
} else
swprintf(buf,L"%d%%",-m_Window.pd.pos-1);
PaintSbItem(dc,buf,-1,rc,m_Window.cli,m_Window.pb_width);
}
if (m_Window.pb.chapter && !m_Window.pd.title.IsEmpty()) {
// draw chapter title
RECT rc2=rc;
rc2.top-=2;
rc2.left+=3; // XXX padding
rc2.right-=m_Window.pb_width+2; // XXX padding
SIZE sz;
int nch=0;
CString tmp(m_Window.pd.title);
dc.SelectFontAbs(fonthdpi,CFDC::FORCENORMALWEIGHT|CFDC::FORCETAHOMA,true);
dc.GetTextExtent(tmp,tmp.GetLength(),rc2.right-rc2.left,nch,NULL,sz);
if (nch<tmp.GetLength()) { // doesnt fit
int nch2;
wchar_t ch=0x2026;
dc.GetTextExtent(&ch,1,8192,nch2,NULL,sz);
dc.GetTextExtent(tmp,tmp.GetLength(),rc2.right-rc2.left-sz.cx,nch,NULL,sz);
if (nch>0) {
tmp.Delete(nch,tmp.GetLength()-nch);
tmp+=ch;
} else
tmp.Empty();
}
dc.SelectFontAbs(fonthdpi,CFDC::FORCENORMALWEIGHT|CFDC::FORCETAHOMA);
TDrawText(dc.DC(),rc2.left,rc2.top,cli,rc2,tmp,tmp.GetLength(),NULL,ETO_OPAQUE|ETO_CLIPPED);
} else {
// draw position bar
RECT rc2=rc;
rc2.top += 1 + (m_Window.progress_height - 5) / 2;
int bw=rc2.right-rc2.left-2*PROGRESS_M-2*PROGRESS_A-m_Window.pb_width;
int pos=m_Window.pd.top ? MulDivS(bw,m_Window.pd.cc,m_Window.pd.top) : bw;
col.left=rc2.left+PROGRESS_M+PROGRESS_A; col.top=rc2.top+1;
col.right=col.left+pos; col.bottom=col.top;
dc.SetColor(C_GAUGE);
TDrawLine(dc.DC(),m_Window.cli,col);
col.top+=2;
col.bottom=col.top;
TDrawLine(dc.DC(),m_Window.cli,col);
// draw a thin black line
col.left=rc2.left+PROGRESS_M; col.top=col.bottom=rc2.top+2;
col.right=rc2.right-PROGRESS_M-m_Window.pb_width;
dc.SetColor(C_TOCL0); // XXX
TDrawLine(dc.DC(),m_Window.cli,col);
// draw arrows
col.top=rc2.top+1;
col.bottom=col.top+3;
col.left=col.right=rc2.left+PROGRESS_M+1;
TDrawLine(dc.DC(),m_Window.cli,col);
col.left=col.right=rc2.left+PROGRESS_M+4;
TDrawLine(dc.DC(),m_Window.cli,col);
col.left=col.right=rc2.right-PROGRESS_M-m_Window.pb_width-5;
TDrawLine(dc.DC(),m_Window.cli,col);
col.left=col.right=rc2.right-PROGRESS_M-m_Window.pb_width-2;
TDrawLine(dc.DC(),m_Window.cli,col);
col.top=rc2.top;
col.bottom=col.top+5;
col.left=col.right=rc2.left+PROGRESS_M+2;
TDrawLine(dc.DC(),m_Window.cli,col);
col.left=col.right=rc2.left+PROGRESS_M+5;
TDrawLine(dc.DC(),m_Window.cli,col);
col.left=col.right=rc2.right-PROGRESS_M-m_Window.pb_width-6;
TDrawLine(dc.DC(),m_Window.cli,col);
col.left=col.right=rc2.right-PROGRESS_M-m_Window.pb_width-3;
TDrawLine(dc.DC(),m_Window.cli,col);
// draw chapter ticks
if (m_Window.pd.top) {
Bookmarks& bm=m_textfile->bmk();
bool doall=bm.GetSize()<(rc2.right-rc2.left)/3;
bool doch=bm.NumTopMarks()<(rc2.right-rc2.left)/3;
bool dobm=bm.NumBookmarks()<(rc2.right-rc2.left)/3;
if (doch||dobm||doall) {
for (int ii=0;ii<bm.GetSize();++ii) {
if (bm.Ref(ii).docid!=m_formatter->DocId())
continue;
COLORREF color=C_TOCL0;
col.top=rc2.top;
col.bottom=col.top+5;
if (bm.Flags(ii)&Bookmarks::BMK) {
if (!dobm)
continue;
color=C_TOCBM;
} else if (bm.Level(ii)>0) {
if (!doall)
continue;
col.top=rc2.top+1;
col.bottom=col.top+3;
} else if (!doch)
continue;
col.left=col.right=rc2.left+PROGRESS_M+PROGRESS_A+MulDivS(bw,
m_textfile->AbsPos(bm.Ref(ii)),m_Window.pd.top);
dc.SetColor(color);
TDrawLine(dc.DC(),m_Window.cli,col);
}
}
}
}
}
void CTView::PaintBookmarkPopup(CFDC& dc,const RECT& rc,const RECT& cli) {
// bascially it's a rectangle+paintcolumn
// draw frame first
POINT pt[5];
pt[0].x=rc.left; pt[0].y=rc.top;
pt[1].x=rc.right-1; pt[1].y=rc.top;
pt[2].x=rc.right-1; pt[2].y=rc.bottom-1;
pt[3].x=rc.left; pt[3].y=rc.bottom-1;
pt[4]=pt[0];
dc.SetColor(C_NORM);
TDrawPolyLine(dc.DC(),cli,pt,5);
// shrink rc a bit to avoid overwriting frame
RECT nrc=rc;
nrc.left++; nrc.right--;
nrc.top++; nrc.bottom--;
PaintColumn(dc,nrc,nrc,cli,&m_BP,FRAME_SIZE-1,false);
}
void CTView::OnSize(UINT nType, int cx, int cy) {
CWnd::OnSize(nType, cx, cy);
if (cx==0 || cy==0) // don't bother with invalid sizes
return;
GetClientRect(&m_Window.cli);
CalcSizes();
}
void CTView::PaintLine(CFDC& dc,const RECT& cli,RECT& line,
int margin,const Line& l)
{
int x=margin+l.ispace;
if (l.flags&Line::image) {
Image img;
if (m_textfile->GetImage(l.href,dc.DC(),l.base,l.imageheight,
m_TextDisp.angle,img))
{
// clean left and right margins
RECT rma=line;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -