//------------------------------------------------------------------------------ // emTextFilePanel.cpp // // Copyright (C) 2004-2010,2014-2019 Oliver Hamann. // // Homepage: http://eaglemode.sourceforge.net/ // // This program is free software: you can redistribute it and/or modify it under // the terms of the GNU General Public License version 3 as published by the // Free Software Foundation. // // This program is distributed in the hope that it will be useful, but WITHOUT // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS // FOR A PARTICULAR PURPOSE. See the GNU General Public License version 3 for // more details. // // You should have received a copy of the GNU General Public License version 3 // along with this program. If not, see . //------------------------------------------------------------------------------ #include #include emTextFilePanel::emTextFilePanel( ParentArg parent, const emString & name, emTextFileModel * fileModel, bool updateFileModel, bool alternativeView ) : emFilePanel(parent,name) { AlternativeView=alternativeView; Model=NULL; AddWakeUpSignal(GetVirFileStateSignal()); SetFileModel(fileModel,updateFileModel); } void emTextFilePanel::SetFileModel( emFileModel * fileModel, bool updateFileModel ) { Model=dynamic_cast(fileModel); emFilePanel::SetFileModel(Model,updateFileModel); } emString emTextFilePanel::GetIconFileName() const { if (IsVFSGood()) { if (Model->GetCharEncoding()!=emTextFileModel::CE_BINARY) { return "plain_text.tga"; } } return emFilePanel::GetIconFileName(); } bool emTextFilePanel::Cycle() { static const char * const ALT_ERROR="Hex display is not an alternative."; if (IsSignaled(GetVirFileStateSignal())) { InvalidateControlPanel(); //??? very cheap solution, but okay for now. InvalidatePainting(); if (IsVFSGood()) { if (AlternativeView && Model->GetCharEncoding()==emTextFileModel::CE_BINARY) { SetCustomError(ALT_ERROR); } } else if (GetCustomError()==ALT_ERROR) { switch (Model->GetFileState()) { case emFileModel::FS_LOADED: case emFileModel::FS_UNSAVED: case emFileModel::FS_SAVING: if (AlternativeView && Model->GetCharEncoding()==emTextFileModel::CE_BINARY) { break; } default: ClearCustomError(); } } } return emFilePanel::Cycle(); } bool emTextFilePanel::IsOpaque() const { if (IsVFSGood()) { return false; } else { return emFilePanel::IsOpaque(); } } void emTextFilePanel::Paint(const emPainter & painter, emColor canvasColor) const { if (IsVFSGood()) { painter.LeaveUserSpace(); //!!! if (Model->GetCharEncoding()==emTextFileModel::CE_BINARY || AlternativeView) { PaintAsHex(painter,canvasColor); } else { PaintAsText(painter,canvasColor); } painter.EnterUserSpace(); //!!! } else { emFilePanel::Paint(painter,canvasColor); } } emPanel * emTextFilePanel::CreateControlPanel( ParentArg parent, const emString & name ) { emRasterGroup * grp; const char * p; if ( IsVFSGood() && Model->GetCharEncoding()!=emTextFileModel::CE_BINARY && !AlternativeView ) { grp=new emRasterGroup( parent, name, "Text File Info" ); grp->SetRowByRow(); grp->SetPrefChildTallness(0.1); switch (Model->GetCharEncoding()) { case emTextFileModel::CE_7BIT : p="7-Bit" ; break; case emTextFileModel::CE_8BIT : p="8-Bit" ; break; case emTextFileModel::CE_UTF8 : p="UTF-8" ; break; case emTextFileModel::CE_UTF16LE: p="UTF-16LE" ; break; case emTextFileModel::CE_UTF16BE: p="UTF-16BE" ; break; default : p="Binary" ; } new emTextField( grp, "enc", "Character Encoding", emString(), emImage(), p ); switch (Model->GetLineBreakEncoding()) { case emTextFileModel::LBE_MAC : p="MAC (CR)" ; break; case emTextFileModel::LBE_DOS : p="DOS (CRLF)"; break; case emTextFileModel::LBE_UNIX : p="UNIX (LF)" ; break; case emTextFileModel::LBE_MIXED: p="Mixed" ; break; default : p="None" ; } new emTextField( grp, "lbenc", "Line Break Encoding", emString(), emImage(), p ); new emTextField( grp, "lines", "Number of Lines", emString(), emImage(), emString::Format("%d",Model->GetLineCount()) ); new emTextField( grp, "columns", "Number of Columns", emString(), emImage(), emString::Format("%d",Model->GetColumnCount()) ); return grp; } else { return emFilePanel::CreateControlPanel(parent,name); } } void emTextFilePanel::PaintAsText( const emPainter & painter, emColor canvasColor ) const { static const emColor textBgColor(255,255,255); static const emColor textFgColor(0,0,0); static const emColor textFgColor96(textFgColor,96); const char * pContent, * pRow; int i1,i2,i3,row,row2,col,cols,rows,page,pages,pagerows,step; double h,ch,cw,f,t,pagew,gap,x,y,clipx1,clipy1,clipx2,clipy2; h=GetHeight(); clipx1=painter.GetUserClipX1(); clipy1=painter.GetUserClipY1(); clipx2=painter.GetUserClipX2(); clipy2=painter.GetUserClipY2(); pContent=Model->GetContent(); rows=Model->GetLineCount(); cols=Model->GetColumnCount(); if (cols<8) cols=8; f=painter.GetTextSize("X",1.0,false); gap=1.0; t=0.5*gap/(cols+gap); pages=(int)floor(t+sqrt((2*rows/(h*f*gap)+t)*t)); // pages*h/rows*f*(cols*pages+gap*(pages-1)) <= 1.0 if (pages<1) { pages=1; pagerows=rows; cw=1.0/cols; ch=cw/f; pagew=1.0; gap*=cw; } else { pagerows=(rows+pages-1)/pages; ch=h/pagerows; cw=ch*f; gap*=cw; pagew=(1.0-(pages-1)*gap)/pages; } page=(int)(clipx1/(pagew+gap)); if (page<0) page=0; x=page*(pagew+gap); for (; pagepagerows) row2=pagerows; row2+=page*pagerows; if (row2>rows) row2=rows; if (ch*GetViewedWidth()<0.5) { step=(int)(0.5/(ch*GetViewedWidth())); if (step<1) step=1; row=((row-1)/step+1)*step; while (rowGetRelativeLineIndent(row)*f, y+ch*0.1, Model->GetRelativeLineWidth(row)*f, ch*step*0.8, textFgColor96, textBgColor ); y+=ch*step; row+=step; } } else { while (rowGetLineStart(row); pRow=pContent+i1; i3=Model->GetLineEnd(row)-i1; i2=0; col=0; for (;;) { switch (Model->GetCharEncoding()) { case emTextFileModel::CE_UTF16LE: while (i2=i2) break; switch (Model->GetCharEncoding()) { case emTextFileModel::CE_8BIT: if (emIsUtf8System()) { col+=PaintTextLatin1( painter, x+col*cw, y, cw, ch, pRow+i1, i2-i1, textFgColor, textBgColor ); } else { painter.PaintText( x+col*cw, y, pRow+i1, ch, 1.0, textFgColor, textBgColor, i2-i1 ); col+=emGetDecodedCharCount(pRow+i1,i2-i1); } break; case emTextFileModel::CE_UTF8: col+=PaintTextUtf8( painter, x+col*cw, y, cw, ch, pRow+i1, i2-i1, textFgColor, textBgColor ); break; case emTextFileModel::CE_UTF16LE: case emTextFileModel::CE_UTF16BE: col+=PaintTextUtf16( painter, x+col*cw, y, cw, ch, pRow+i1, i2-i1, textFgColor, textBgColor ); break; default: painter.PaintText( x+col*cw, y, pRow+i1, ch, 1.0, textFgColor, textBgColor, i2-i1 ); col+=i2-i1; break; } } y+=ch; row++; } } } } int emTextFilePanel::PaintTextLatin1( const emPainter & painter, double x, double y, double charWidth, double charHeight, const char * text, int textLen, emColor color, emColor canvasColor ) const { char buf[256+EM_MB_LEN_MAX]; int i,l,c,bufPos; bufPos=0; l=0; emMBState mbState; for (i=0; i=(int)sizeof(buf)-EM_MB_LEN_MAX) { painter.PaintText( x+bufPos*charWidth, y, buf, charHeight, 1.0, color, canvasColor, l ); bufPos=i; l=0; } c=(unsigned char)text[i]; if (c>=0x80) { if (c<=0x9F) { static const int latin1ExtraTap[32]={ 0x20AC,0x0081,0x201A,0x0192,0x201E,0x2026,0x2020,0x2021, 0x02C6,0x2030,0x0160,0x2039,0x0152,0x0164,0x017D,0x0179, 0x0090,0x2035,0x2032,0x2036,0x2033,0x2022,0x2013,0x2014, 0x02DC,0x2122,0x0161,0x203A,0x0153,0x0165,0x017E,0x0178 }; c=latin1ExtraTap[c-0x80]; } l+=emEncodeChar(buf+l,c,&mbState); } else { buf[l++]=(char)c; } } if (l>0) { painter.PaintText( x+bufPos*charWidth, y, buf, charHeight, 1.0, color, canvasColor, l ); } return textLen; } int emTextFilePanel::PaintTextUtf8( const emPainter & painter, double x, double y, double charWidth, double charHeight, const char * text, int textLen, emColor color, emColor canvasColor ) const { char buf[256+EM_MB_LEN_MAX]; int i,l,c,pos,bufPos; if (emIsUtf8System()) { painter.PaintText(x,y,text,charHeight,1.0,color,canvasColor,textLen); return emGetDecodedCharCount(text,textLen); } pos=0; bufPos=0; l=0; emMBState mbState; for (i=0; i=(int)sizeof(buf)-EM_MB_LEN_MAX) { painter.PaintText( x+bufPos*charWidth, y, buf, charHeight, 1.0, color, canvasColor, l ); bufPos=pos; l=0; } c=(unsigned char)text[i]; if (c>=128) { i+=emDecodeUtf8Char(&c,text+i,textLen-i); l+=emEncodeChar(buf+l,c,&mbState); } else { i++; buf[l++]=(char)c; } pos++; } if (l>0) { painter.PaintText( x+bufPos*charWidth, y, buf, charHeight, 1.0, color, canvasColor, l ); } return pos; } int emTextFilePanel::PaintTextUtf16( const emPainter & painter, double x, double y, double charWidth, double charHeight, const char * text, int textLen, emColor color, emColor canvasColor ) const { char buf[256+EM_MB_LEN_MAX]; int i,l,c,c2,pos,bufPos,sh1,sh2; if (Model->GetCharEncoding()==emTextFileModel::CE_UTF16LE) { sh1=0; sh2=8; } else { sh1=8; sh2=0; } pos=0; bufPos=0; l=0; emMBState mbState; for (i=0; i=(int)sizeof(buf)-EM_MB_LEN_MAX) { painter.PaintText( x+bufPos*charWidth, y, buf, charHeight, 1.0, color, canvasColor, l ); bufPos=pos; l=0; } c=((((emByte)text[i])<=0xD800 && c<=0xDBFF && i=0xDC00 && c2<=0xDFFF) { i+=2; c=0x10000+((c&0x03FF)<<10)+(c2&0x03FF); } } l+=emEncodeChar(buf+l,c,&mbState); pos++; } } if (l>0) { painter.PaintText( x+bufPos*charWidth, y, buf, charHeight, 1.0, color, canvasColor, l ); } return pos; } void emTextFilePanel::PaintAsHex( const emPainter & painter, emColor canvasColor ) const { static const emColor colBg(0,0,0); static const emColor colAddr(64,128,64); static const emColor colHex(128,128,64); static const emColor colAsc(64,96,128); static const emColor colAddr64(colAddr,64); static const emColor colHex48(colHex,48); static const emColor colAsc64(colAsc,64); static const emColor colAddr96(colAddr,96); static const emColor colHex96(colHex,96); char buf[256]; char buf2[32]; const char * pStart, * pEnd, * p; int i,j,k,count,row,cols,rows,page,pages,pagerows; double h,cw,ch,f,t,pagex,gap,pagew,bx,rowy,clipx1,clipy1,clipx2,clipy2; count=Model->GetContent().GetCount(); pStart=Model->GetContent(); pEnd=pStart+count; h=GetHeight(); clipx1=painter.GetUserClipX1(); clipy1=painter.GetUserClipY1(); clipx2=painter.GetUserClipX2(); clipy2=painter.GetUserClipY2(); painter.PaintRect(0,0,1,h,colBg,canvasColor); rows=(int)(((unsigned)count+15)/16); if (!rows) return; cols=73; f=painter.GetTextSize("X",1.0,false); gap=2.0; t=0.5*gap/(cols+gap); pages=(int)floor(t+sqrt((2*rows/(h*f*gap)+t)*t)); // pages*h/rows*f*(cols*pages+gap*(pages-1)) <= 1.0 if (pages<1) { pages=1; pagerows=rows; cw=1.0/cols; ch=cw/f; } else { pagerows=(rows+pages-1)/pages; ch=h/pagerows; cw=ch*f; } gap*=cw; pagew=cols*cw+gap; p=pStart; page=0; pagex=0; if (pagex+pagew<=clipx1) { page=(int)((clipx1-pagex)/pagew); pagex+=page*pagew; p+=page*pagerows*16; } if (ch*GetViewedWidth()<1.0) { for (; pageh) f=h; painter.PaintRect( pagex, 0, cw*8, f, colAddr64, colBg ); painter.PaintRect( pagex+cw*9, 0, cw*47, f, colHex48, colBg ); painter.PaintRect( pagex+cw*(9+48), 0, cw*16, f, colAsc64, colBg ); p+=16*pagerows; } } else if (ch*GetViewedWidth()<3.0) { for (; page>4)+'0'; if (j>'9') j+='A'-'9'-1; buf[0]=(char)j; j=(k&0xF)+'0'; if (j>'9') j+='A'-'9'-1; buf[1]=(char)j; if (((unsigned)(k-0x20))>=0x60) k='.'; buf2[i]=(char)k; painter.PaintText(bx+3*i*cw,rowy,buf,ch,1.0,colHex,colBg,2); } painter.PaintText(bx+48*cw,rowy,buf2,ch,1.0,colAsc,colBg,i); row++; rowy+=ch; } p+=16*(pagerows-row); } } }