textformatter.cpp

来自「俄罗斯人开发的大名鼎鼎的Pocket Pc 阅读器haaliread的源代码,v」· C++ 代码 · 共 775 行 · 第 1/2 页

CPP
775
字号
  bool header=true;
  for (int page=0;page<m_pages;++page) {
    int h=0;
    int beg=m_lines.GetSize();
    while (h<m_height && start.para<m_tf->Length(start.docid)) {
      Paragraph   para(m_tf->GetParagraph(start.docid,start.para));
      bool empty=para.len==0 || para.len==1 && para.str[0]==_T(' ');
      if (h==0 && empty) {
	start.off=para.len;
	AdjustPos(start);
	continue;
      }
      if (para.flags & Paragraph::header) {
	if (!header)
	  break;
      } else
	if (!empty && !(para.flags & Paragraph::image))
	  header=false;
      int lh=WrapLine(dc,para,start,m_lines,h,m_height-h);
      if (lh<0)
	break;
      AdjustPos(start);
      h+=lh;
    }
    m_pagelen.SetAtGrow(page,m_lines.GetSize()-beg);
  }
  m_bot=start;
  Highlight();
  // add one dummy line always
  Line l;
  l.pos=m_bot;
  m_lines.Add(l);
  return true;
}

bool	    TextFormatter::FormatBack(CFDC& dc,FilePos start,FilePos prev_top) {
  AdjustPos(start,true);
  if (start.para==0 && start.off==0)
    return false; // at the top
  m_lines.RemoveAll();
  m_bot=start;
  for (int page=m_pages-1;page>=0;--page) {
    LineArray   tmp;
    FilePos     pos=start;
    int	      h=0;
    // while there are still paragrahs before
    while (h<m_height && (pos.para>0 || pos.off>0)) {
      // format entire paragraph
      LineArray cp;
      Paragraph   para(m_tf->GetParagraph(pos.docid,pos.para));
      if (pos.off<para.len) // double check args
	para.len=pos.off;
      else
	pos.off=para.len;
      WrapLine(dc,para,FilePos(pos.para,0,pos.docid),cp,0,32768);
      // insert the formatted paragraph at start of list
      tmp.InsertAt(0,&cp);
      for (int i=0;i<cp.GetSize();++i)
	h+=cp[i].height;
      pos.off=0;
      AdjustPos(pos,true);
    }
    // delete extra lines
    int j;
    // remove top lines
    for (h=0,j=tmp.GetUpperBound();j>=0 && h+tmp[j].height<=m_height;--j)
      h+=tmp[j].height;
    if (j<tmp.GetUpperBound()) {
      if (j>=0 && prev_top!=0 && tmp[j+1].pos>=prev_top) {
	--j;
	tmp.RemoveAt(0,j+1);
	// now remove bottom lines
	for (h=j=0;j<tmp.GetSize() && h+tmp[j].height<=m_height;++j)
	  h+=tmp[j].height;
	if (j<tmp.GetSize())
	  tmp.RemoveAt(j,tmp.GetSize()-j);
      } else
	tmp.RemoveAt(0,j+1);
    }
    // save lines
    m_lines.InsertAt(0,&tmp);
    m_pagelen.SetAtGrow(page,tmp.GetSize());
    start=m_lines[0].pos;
    if (start.para==0 && start.off==0) // we reached the top of file
      return FormatFwd(dc,FilePos(0,0,start.docid));
  }
  // save positions
  m_top=m_lines[0].pos;
  Highlight();
  // add one dummy line always
  Line l;
  l.pos=m_bot;
  m_lines.Add(l);
  return true;
}

void	    TextFormatter::AdjustPos(FilePos& p,bool back) {
  if (back) {
    if (p.para>0) {
      if (p.para>=m_tf->Length(p.docid)) {
	if (m_tf->Length(p.docid)>0) {
	  p.para=m_tf->Length(p.docid)-1;
	  p.off=m_tf->GetPLength(p.docid,p.para);
	}
      } else {
	if (p.off==0) {
	  --p.para;
	  p.off=m_tf->GetPLength(p.docid,p.para);
	}
      }
    }
  } else {
    if (p.para>=0 && p.para<m_tf->Length(p.docid) && p.off>=m_tf->GetPLength(p.docid,p.para)) {
      p.off=0;
      p.para++;
    }
  }
}

void	    TextFormatter::SetSize(int width,int margin,int height,int pages,
				   int angle)
{
  if (height<1)
    height=1;
  if (pages<1)
    pages=1;
  m_total_width=width;
  m_margin=margin;
  m_width=m_total_width-2*m_margin;
  if (m_width<1)
    m_width=1;
  m_height=height;
  m_pages=pages;
  m_angle=angle;
}

bool TextFormatter::AtTop()
{
  FilePos   p(m_top);
  AdjustPos(p,true);
  return p.off==0 && p.para==0;
}

bool TextFormatter::AtEof()
{
  FilePos   p(m_bot);
  AdjustPos(p);
  return p.para>=m_tf->Length(p.docid);
}

static bool  intersect(int a,int la,int b,int lb,int& i,int& li) {
  if (a>=b && a<b+lb) {
    i=a-b;
    if (la>b+lb-a)
      li=b+lb-a;
    else
      li=la;
    return true;
  }
  if (b>=a && b<a+la) {
    i=0;
    if (lb>a+la-b)
      li=a+la-b;
    else
      li=lb;
    return true;
  }
  return false;
}

void TextFormatter::Highlight() {
  if (!m_hllen || m_hlstart.docid!=DocId())
    return;

  FilePos   hls(m_hlstart);
  int	    hll=m_hllen;
  for (int i=0;i<m_lines.GetSize();++i)
    if (hls.para==m_lines[i].pos.para) {
      int beg,len;
      if (hls.off-m_lines[i].pos.off<m_lines[i].real_len &&
	intersect(hls.off,hll,m_lines[i].pos.off,m_lines[i].str.size(),beg,len))
      {
	int top=beg+len;
	while (beg<top)
	  m_lines[i].attr[beg++].hibg=true;
	m_lines[i].flags&=~Line::defstyle;
      } else
	m_lines[i].CheckStyle();
      // advance our pointer
      if (i<m_lines.GetSize()-1 && m_lines[i+1].pos.para>hls.para &&
	    hls.off+hll>m_tf->GetPLength(hls.docid,hls.para))
      {
	hll-=m_tf->GetPLength(hls.docid,hls.para)-hls.off;
	++hls.para;
	hls.off=0;
      }
    } else
      m_lines[i].CheckStyle();
}

bool TextFormatter::SetHighlight(FilePos pos,int len) {
  if (m_hllen==len && (!len || pos==m_hlstart)) // avoid extra work
    return false;
  // remove highlighting
  for (int i=0;i<m_lines.GetSize();++i) {
    for (int j=0;j<m_lines[i].attr.size();++j)
      m_lines[i].attr[j].hibg=false;
  }
  m_hlstart=pos;
  m_hllen=len;
  Highlight();
  return true;
}

void  Line::CheckStyle() {
  Attr	*p=attr;
  Attr	*e=p+attr.size();
  while (p<e)
    if ((*p++).wa) {
      flags&=~defstyle;
      return;
    }
  flags|=defstyle;
}

int TextFormatter::Distance(const FilePos& a,const FilePos& b)
{
  FilePos start(a), end(b);
  bool	  sign=false;
  if (a>b) {
    start=b;
    end=a;
    sign=true;
  }
  // check bounds
  if (start.para<0)
    start.para=0;
  if (start.para>m_tf->Length(start.docid)) {
    start.para=m_tf->Length(start.docid);
    start.off=0;
  }
  if (start.off<0)
    start.off=0;
  if (start.off>m_tf->GetPLength(start.docid,start.para))
    start.off=m_tf->GetPLength(start.docid,start.para);
  if (end.para<0)
    end.para=0;
  if (end.para>m_tf->Length(end.docid)) {
    end.para=m_tf->Length(end.docid);
    end.off=0;
  }
  if (end.off<0)
    end.off=0;
  if (end.off>m_tf->GetPLength(end.docid,end.para))
    end.off=m_tf->GetPLength(end.docid,end.para);
  // calc distance now
  int	dist;
  if (start.para==end.para)
    dist=end.off-start.off;
  else {
    dist=m_tf->GetPLength(start.docid,start.para)-start.off;
    ++start.para;
    while (start.para<end.para) {
      dist+=m_tf->GetPLength(start.docid,start.para);
      ++start.para;
    }
    dist+=end.off;
  }
  return sign ? -dist : dist;
}

bool  TextFormatter::EnsureVisible(CFDC& dc,FilePos pos) {
  if (pos>=m_top && pos<m_bot)
    return false;
  FilePos   ptop(pos);
  ptop.off=0;
  if (!FormatFwd(dc,ptop))
    return true;
  while (m_top.para==pos.para && pos>=m_bot)
    if (!FormatFwd(dc))
      break;
  return true;
}

void  TextFormatter::FormatPlainText(CFDC& dc,
				     int& width,int& height,
				     int fontsize,
				     const wchar_t *text,int len,
				     LineArray& lines)
{
  lines.RemoveAll();

  int	  save_width=m_width;
  bool	  save_justified=m_justified;
  m_width=width;
  m_justified=false;
  
  const wchar_t	  *top=text+len;

  Attr	  attr;
  attr.wa=0;
  attr.fsize=fontsize;
  
  int	curh=0;

  while (text<top && curh<height) {
    const wchar_t   *p_end=text;
    while (p_end<top && *p_end!='\r' && *p_end!='\n')
      ++p_end;
    Paragraph	    p(p_end-text);
    memcpy(p.str,text,(p_end-text)*sizeof(wchar_t));
    for (int i=0;i<p.cflags.size();++i)
      p.cflags[i].wa=attr.wa;
    p.findent=3; // XXX
    int last=lines.GetSize();
    int lh=WrapLine(dc,p,FilePos(),lines,curh,height-curh);
    if (lh<0) { // it still might add something
      while (last<lines.GetSize())
	curh+=lines[last++].height;
      break;
    }
    curh+=lh;
    while (p_end<top && (*p_end=='\r' || *p_end=='\n'))
      ++p_end;
    text=p_end;
  }

  m_width=save_width;
  m_justified=save_justified;

  // deduct ispace
  int	min_ispace=-1,max_width=0;
  for (int i=0;i<lines.GetSize();++i) {
    const Line&	  ll=lines[i];
    int	  w=0;
    for (int j=0;j<ll.dx.size();++j)
      w+=ll.dx[j];
    w+=ll.ispace;
    if (max_width<w)
      max_width=w;
    if (min_ispace<0 || min_ispace>ll.ispace)
      min_ispace=ll.ispace;
  }

  if (min_ispace>0) {
    for (int i=0;i<lines.GetSize();++i)
      lines[i].ispace-=min_ispace;
    max_width-=min_ispace;
  }

  height=curh;
  width=max_width;
}

bool  TextFormatter::FormatFwdAdj(CFDC& dc) {
  // if an image crosses the bottom of the window, and does not start
  // at the top of window, then move down only until the image is
  // fully visible
  AdjustPos(m_bot);
  Paragraph   p(m_tf->GetParagraph(m_bot.docid,m_bot.para));
  if (p.flags&Paragraph::image && // image
      m_bot.off>0 && // crosses window border
      (m_top.docid!=m_bot.docid || m_top.para!=m_bot.para)) // is not visible at top
  // then do a partial move forward to show a whole image
    m_bot.off=0;
  return FormatFwd(dc,m_bot);
}

void  TextFormatter::SetTop(FilePos pos) {
  if (pos.docid >= m_tf->GetSubDocCount()) {
    pos.docid = m_tf->GetSubDocCount() - 1;
    if (pos.docid < 0)
      pos.docid=0;
  }
  if (pos.para >= m_tf->Length(pos.docid)) {
    pos.para=m_tf->Length(pos.docid)-1;
    if (pos.para<0)
      pos.para=0;
  }
  if (pos.off >= m_tf->GetPLength(pos.docid,pos.para)) {
    pos.off = m_tf->GetPLength(pos.docid,pos.para) - 1;
    if (pos.off<0)
      pos.off=0;
  }
  m_top=pos;
}

⌨️ 快捷键说明

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