Updating uppdev

git-svn-id: svn://ultimatepp.org/upp/trunk@527 f0d560ea-af0d-0410-9eb7-867de7ffcac7
This commit is contained in:
cxl 2008-10-13 20:06:12 +00:00
parent 4b999ee468
commit 893a7924da
49 changed files with 12859 additions and 65 deletions

View file

@ -56,6 +56,7 @@ AddressBook::AddressBook()
SetupSearch();
fs.AllFilesType();
menu.Set(THISBACK(MainMenu));
}
void AddressBook::FileMenu(Bar& bar)

View file

@ -39,6 +39,7 @@ struct App : public TopWindow {
w.DrawImage(20, 500, a);
}
};
GUI_APP_MAIN

View file

@ -9,8 +9,12 @@ thread__ int *alfa[10] = { &x, &x };
CONSOLE_APP_MAIN
{
Any alpha;
alpha.Create<int>();
One<String> x;
x.
if(alpha.Is<int>())
RLOG("int");
if(alpha.Is<int>())

View file

@ -0,0 +1,590 @@
topic "";
[ $$0,0#00000000000000000000000000000000:Default]
[H6;0 $$1,0#05600065144404261032431302351956:begin]
[i448;a25;kKO9;2 $$2,0#37138531426314131252341829483370:codeitem]
[l288;2 $$3,0#27521748481378242620020725143825:desc]
[0 $$4,0#96390100711032703541132217272105:end]
[{_}%EN-US
[s1;%- &]
[s2;:pteback`(OBJECT`*`,void`(`*`)`(P1 p1`,P2 p2`)`):%- Callback_[* Proxy](Callback[@(0.0.255) `&
]_[*@3 cb])&]
[s3; [%-*@3 cb].&]
[s4; &]
[s1; &]
[s2;:pteback`(OBJECT`*`,void`(`*`)`(P1 p1`,P2 p2`)`):%- Callback_[* callback](Callback_
[*@3 cb1], Callback_[*@3 cb2])&]
[s3; [%-*@3 cb1] [%-*@3 cb2].&]
[s4; &]
[s1; &]
[s2;:pteback`(OBJECT`*`,void`(`*`)`(P1 p1`,P2 p2`)`):%- Callback[@(0.0.255) `&]_[* operat
or<<](Callback[@(0.0.255) `&]_[*@3 a], Callback_[*@3 b])&]
[s3; [%-*@3 a] [%-*@3 b].&]
[s4; &]
[s1; &]
[s2;:pteback`(OBJECT`*`,void`(`*`)`(P1 p1`,P2 p2`)`):%- [@(0.0.255) template]_<[@(0.0.255) c
lass]_[*@4 OBJECT], [@(0.0.255) class]_[*@4 METHOD], [@(0.0.255) class]_[*@4 P1][@(0.0.255) >
]_Callback1[@(0.0.255) <][*@4 P1][@(0.0.255) >]_[* pteback]([*@4 OBJECT]_`*[*@3 object],
[@(0.0.255) void]_(METHOD`::[@(0.0.255) `*][*@3 method])([*@4 P1]_p1))&]
[s3; [%-*@3 object] [%-*@3 method].&]
[s4; &]
[s1; &]
[s2;:pteback`(OBJECT`*`,void`(`*`)`(P1 p1`,P2 p2`)`):%- [@(0.0.255) template]_<[@(0.0.255) c
lass]_[*@4 OBJECT], [@(0.0.255) class]_[*@4 METHOD], [@(0.0.255) class]_[*@4 P1][@(0.0.255) >
]_Callback1[@(0.0.255) <][*@4 P1][@(0.0.255) >]_[* callback]([*@4 OBJECT]_`*[*@3 object],
[@(0.0.255) void]_(METHOD`::[@(0.0.255) `*][*@3 method])([*@4 P1]_p1))&]
[s3; [%-*@3 object] [%-*@3 method].&]
[s4; &]
[s1; &]
[s2;:pteback`(OBJECT`*`,void`(`*`)`(P1 p1`,P2 p2`)`):%- [@(0.0.255) template]_<[@(0.0.255) c
lass]_[*@4 OBJECT], [@(0.0.255) class]_[*@4 METHOD], [@(0.0.255) class]_[*@4 P1][@(0.0.255) >
]_Callback1[@(0.0.255) <][*@4 P1][@(0.0.255) >]_[* callback]([@(0.0.255) const]_[*@4 OBJECT]_
`*[*@3 object], [@(0.0.255) void]_(METHOD`::[@(0.0.255) `*][*@3 method])([*@4 P1]_p1)_[@(0.0.255) c
onst])&]
[s3; [%-*@3 object] [%-*@3 method].&]
[s4; &]
[s1; &]
[s2;:pteback`(OBJECT`*`,void`(`*`)`(P1 p1`,P2 p2`)`):%- [@(0.0.255) template]_<[@(0.0.255) c
lass]_[*@4 P1][@(0.0.255) >]_Callback1[@(0.0.255) <][*@4 P1][@(0.0.255) >]_[* callback]([@(0.0.255) v
oid]_(`*[*@3 fn])([*@4 P1]_p1))&]
[s3; [%-*@3 fn].&]
[s4; &]
[s1; &]
[s2;:pteback`(OBJECT`*`,void`(`*`)`(P1 p1`,P2 p2`)`):%- [@(0.0.255) template]_<[@(0.0.255) c
lass]_[*@4 P1][@(0.0.255) >]_Callback1[@(0.0.255) <][*@4 P1][@(0.0.255) >]_[* Proxy](Callback
1[@(0.0.255) <][*@4 P1][@(0.0.255) >`&]_[*@3 cb])&]
[s3; [%-*@3 cb].&]
[s4; &]
[s1; &]
[s2;:pteback`(OBJECT`*`,void`(`*`)`(P1 p1`,P2 p2`)`):%- [@(0.0.255) template]_<[@(0.0.255) c
lass]_[*@4 P1][@(0.0.255) >]_Callback1[@(0.0.255) <][*@4 P1][@(0.0.255) >]_[* callback](Callb
ack1[@(0.0.255) <][*@4 P1][@(0.0.255) >]_[*@3 cb1], Callback1[@(0.0.255) <][*@4 P1][@(0.0.255) >
]_[*@3 cb2])&]
[s3; [%-*@3 cb1] [%-*@3 cb2].&]
[s4; &]
[s1; &]
[s2;:pteback`(OBJECT`*`,void`(`*`)`(P1 p1`,P2 p2`)`):%- [@(0.0.255) template]_<[@(0.0.255) c
lass]_[*@4 P1][@(0.0.255) >]_Callback1[@(0.0.255) <][*@4 P1][@(0.0.255) >`&]_[* operator<<](C
allback1[@(0.0.255) <][*@4 P1][@(0.0.255) >`&]_[*@3 a], Callback1[@(0.0.255) <][*@4 P1][@(0.0.255) >
]_[*@3 b])&]
[s3; [%-*@3 a] [%-*@3 b].&]
[s4; &]
[s1; &]
[s2;:pteback`(OBJECT`*`,void`(`*`)`(P1 p1`,P2 p2`)`):%- [@(0.0.255) template]_<[@(0.0.255) c
lass]_[*@4 OBJECT], [@(0.0.255) class]_[*@4 METHOD], [@(0.0.255) class]_[*@4 P1],
[@(0.0.255) class]_[*@4 P2][@(0.0.255) >]_Callback2[@(0.0.255) <][*@4 P1],
[*@4 P2][@(0.0.255) >]_[* pteback]([*@4 OBJECT]_`*[*@3 object], [@(0.0.255) void]_(METHOD`::[@(0.0.255) `*
][*@3 method])([*@4 P1]_p1, [*@4 P2]_p2))&]
[s3; [%-*@3 object] [%-*@3 method].&]
[s4; &]
[s0;%- &]
[ {{10000 [s0;%- AIndex]
:: [s0;%- AIndex`::ConstIterator]
:: [s0;%- AIndex`::ValueType]
:: [s0;%- AMap]
:: [s0;%- AMap`::ConstIterator]
:: [s0;%- AMap`::Iterator]
:: [s0;%- AMap`::KeyConstIterator]
:: [s0;%- AMap`::KeyType]
:: [s0;%- AMap`::ValueType]
:: [s0;%- AString]
:: [s0;%- AString`::String]
:: [s0;%- AString`::bchar]
:: [s0;%- AString`::buffer]
:: [s0;%- AString`::tchar]
:: [s0;%- AbortExc]
:: [s0;%- AddOps]
:: [s0;%- Any]
:: [s0;%- Any`::BaseData]
:: [s0;%- Any`::Data]
:: [s0;%- Array]
:: [s0;%- Array`::ConstIterator]
:: [s0;%- Array`::ConstIterator`::Array`::ConstIterator]
:: [s0;%- Array`::ConstIterator`::NP]
:: [s0;%- Array`::Iterator]
:: [s0;%- Array`::Iterator`::B]
:: [s0;%- Array`::Iterator`::NP]
:: [s0;%- Array`::ValueType]
:: [s0;%- ArrayIndex]
:: [s0;%- ArrayIndex`::B]
:: [s0;%- ArrayIndex`::ConstIterator]
:: [s0;%- ArrayMap]
:: [s0;%- ArrayMap`::B]
:: [s0;%- ArrayMap`::ConstIterator]
:: [s0;%- ArrayMap`::Iterator]
:: [s0;%- AssignValueTypeNo]
:: [s0;%- Atomic]
:: [s0;%- BiArray]
:: [s0;%- BiArray`::ConstIterator]
:: [s0;%- BiArray`::Iterator]
:: [s0;%- BiArray`::ValueType]
:: [s0;%- BiVector]
:: [s0;%- BiVector`::ConstIterator]
:: [s0;%- BiVector`::Iterator]
:: [s0;%- BiVector`::ValueType]
:: [s0;%- BitAndPtr]
:: [s0;%- Bits]
:: [s0;%- BlockStream]
:: [s0;%- Buffer]
:: [s0;%- CParser]
:: [s0;%- CParser`::Error]
:: [s0;%- CParser`::Pos]
:: [s0;%- Callback]
:: [s0;%- Callback1]
:: [s0;%- Callback1`::CLASSNAME]
:: [s0;%- Callback1Action]
:: [s0;%- Callback1FnAction]
:: [s0;%- Callback1ForkAction]
:: [s0;%- Callback1MethodAction]
:: [s0;%- Callback1MethodActionPte]
:: [s0;%- Callback2]
:: [s0;%- Callback2`::CLASSNAME]
:: [s0;%- Callback2Action]
:: [s0;%- Callback2FnAction]
:: [s0;%- Callback2ForkAction]
:: [s0;%- Callback2MethodAction]
:: [s0;%- Callback2MethodActionPte]
:: [s0;%- Callback3]
:: [s0;%- Callback3`::CLASSNAME]
:: [s0;%- Callback3Action]
:: [s0;%- Callback3FnAction]
:: [s0;%- Callback3ForkAction]
:: [s0;%- Callback3MethodAction]
:: [s0;%- Callback3MethodActionPte]
:: [s0;%- Callback4]
:: [s0;%- Callback4`::CLASSNAME]
:: [s0;%- Callback4Action]
:: [s0;%- Callback4FnAction]
:: [s0;%- Callback4ForkAction]
:: [s0;%- Callback4MethodAction]
:: [s0;%- Callback4MethodActionPte]
:: [s0;%- Callback`::CLASSNAME]
:: [s0;%- CallbackAction]
:: [s0;%- CallbackActionCallArg]
:: [s0;%- CallbackActionCallArg1]
:: [s0;%- CallbackActionCallArg2]
:: [s0;%- CallbackActionCallArg3]
:: [s0;%- CallbackActionCallArg4]
:: [s0;%- CallbackArgTarget]
:: [s0;%- CallbackArgTarget`::CLASSNAME]
:: [s0;%- CallbackFnAction]
:: [s0;%- CallbackForkAction]
:: [s0;%- CallbackMethodAction]
:: [s0;%- CallbackMethodActionArg]
:: [s0;%- CallbackMethodActionArg1]
:: [s0;%- CallbackMethodActionArg1Pte]
:: [s0;%- CallbackMethodActionArg2]
:: [s0;%- CallbackMethodActionArg2Pte]
:: [s0;%- CallbackMethodActionArg3]
:: [s0;%- CallbackMethodActionArg3Pte]
:: [s0;%- CallbackMethodActionArg4]
:: [s0;%- CallbackMethodActionArg4Pte]
:: [s0;%- CallbackMethodActionArgPte]
:: [s0;%- CallbackMethodActionPte]
:: [s0;%- Callexit]
:: [s0;%- Callinit]
:: [s0;%- CerrStream]
:: [s0;%- CharFilter]
:: [s0;%- CharFilterTextTest]
:: [s0;%- CharS]
:: [s0;%- CharSetData]
:: [s0;%- CoWork]
:: [s0;%- CoWork`::Lock]
:: [s0;%- CoWork`::MJob]
:: [s0;%- CoWork`::Pool]
:: [s0;%- Color]
:: [s0;%- ColorF]
:: [s0;%- CombineCompare]
:: [s0;%- CombineHash]
:: [s0;%- Comparable]
:: [s0;%- CompareRelOps]
:: [s0;%- CompareStream]
:: [s0;%- ConstIIterator]
:: [s0;%- ConstIIterator`::NP]
:: [s0;%- ConstIIterator`::T]
:: [s0;%- Convert]
:: [s0;%- ConvertDate]
:: [s0;%- ConvertDouble]
:: [s0;%- ConvertInt]
:: [s0;%- ConvertInt64]
:: [s0;%- ConvertString]
:: [s0;%- ConvertTime]
:: [s0;%- CoutStream]
:: [s0;%- Crc32]
:: [s0;%- CriticalSection]
:: [s0;%- DLLHANDLE]
:: [s0;%- DLLTYPE]
:: [s0;%- Data`_S`_]
:: [s0;%- Date]
:: [s0;%- DbgBlkHeader]
:: [s0;%- DebugLogBlock]
:: [s0;%- DeepCopyOption]
:: [s0;%- DefaultWildcardCompare]
:: [s0;%- EmptyClass]
:: [s0;%- Event]
:: [s0;%- Exc]
:: [s0;%- FieldRelationCls]
:: [s0;%- FileAppend]
:: [s0;%- FileIn]
:: [s0;%- FileMapping]
:: [s0;%- FileMapping`::stat]
:: [s0;%- FileOut]
:: [s0;%- FileStream]
:: [s0;%- FileSystemInfo]
:: [s0;%- FileSystemInfo`::FileInfo]
:: [s0;%- FileTime]
:: [s0;%- FindFile]
:: [s0;%- FindFile`::stat]
:: [s0;%- FnValueOrder]
:: [s0;%- FormId]
:: [s0;%- FormatConvert]
:: [s0;%- Formatter]
:: [s0;%- Formatting]
:: [s0;%- Gate]
:: [s0;%- Gate1]
:: [s0;%- Gate1`::CLASSNAME]
:: [s0;%- Gate1Action]
:: [s0;%- Gate1FnAction]
:: [s0;%- Gate1ForkAction]
:: [s0;%- Gate1MethodAction]
:: [s0;%- Gate1MethodActionPte]
:: [s0;%- Gate2]
:: [s0;%- Gate2`::CLASSNAME]
:: [s0;%- Gate2Action]
:: [s0;%- Gate2FnAction]
:: [s0;%- Gate2ForkAction]
:: [s0;%- Gate2MethodAction]
:: [s0;%- Gate2MethodActionPte]
:: [s0;%- Gate3]
:: [s0;%- Gate3`::CLASSNAME]
:: [s0;%- Gate3Action]
:: [s0;%- Gate3FnAction]
:: [s0;%- Gate3ForkAction]
:: [s0;%- Gate3MethodAction]
:: [s0;%- Gate3MethodActionPte]
:: [s0;%- Gate4]
:: [s0;%- Gate4`::CLASSNAME]
:: [s0;%- Gate4Action]
:: [s0;%- Gate4FnAction]
:: [s0;%- Gate4ForkAction]
:: [s0;%- Gate4MethodAction]
:: [s0;%- Gate4MethodActionPte]
:: [s0;%- Gate`::CLASSNAME]
:: [s0;%- GateAction]
:: [s0;%- GateFnAction]
:: [s0;%- GateForkAction]
:: [s0;%- GateMethodAction]
:: [s0;%- GateMethodActionPte]
:: [s0;%- H`_l`_]
:: [s0;%- HashBase]
:: [s0;%- HashBase`::Link]
:: [s0;%- Heap]
:: [s0;%- Heap`::BigHdr]
:: [s0;%- Heap`::DLink]
:: [s0;%- Heap`::FreeLink]
:: [s0;%- Heap`::Header]
:: [s0;%- Heap`::Page]
:: [s0;%- HitCountInspector]
:: [s0;%- IIterator]
:: [s0;%- IIterator`::NP]
:: [s0;%- IIterator`::T]
:: [s0;%- Id]
:: [s0;%- IdConst]
:: [s0;%- IdList]
:: [s0;%- Index]
:: [s0;%- Index`::B]
:: [s0;%- Index`::ConstIterator]
:: [s0;%- IndexSort2Iterator]
:: [s0;%- IndexSort2Iterator`::Iter]
:: [s0;%- IndexSort3Iterator]
:: [s0;%- IndexSort3Iterator`::Iter]
:: [s0;%- IndexSortIterator]
:: [s0;%- IndexSortIterator`::Iter]
:: [s0;%- JoinConvert]
:: [s0;%- JoinConvert`::Item]
:: [s0;%- LCIDMap]
:: [s0;%- LCTYPE]
:: [s0;%- LRUCache]
:: [s0;%- LRUCache`::Item]
:: [s0;%- LRUCache`::Maker]
:: [s0;%- LangConvertClass]
:: [s0;%- LangModuleRecord]
:: [s0;%- LangTextRecord]
:: [s0;%- LanguageInfo]
:: [s0;%- LanguageInfo`::WildcardCompare]
:: [s0;%- LanguageInfoCS]
:: [s0;%- LanguageInfoEN]
:: [s0;%- LanguageInfoES]
:: [s0;%- LanguageInfoFR]
:: [s0;%- LanguageInfoGE]
:: [s0;%- LanguageInfoMap]
:: [s0;%- Link]
:: [s0;%- LinkOwner]
:: [s0;%- LngEntry`_`_]
:: [s0;%- LngModule]
:: [s0;%- LngRec]
:: [s0;%- LoadingError]
:: [s0;%- LogStream]
:: [s0;%- MapConvert]
:: [s0;%- MemReadStream]
:: [s0;%- MemStream]
:: [s0;%- MemoryIgnoreLeaksBlock]
:: [s0;%- MemoryProfile]
:: [s0;%- MethodRelationCls]
:: [s0;%- Mitor]
:: [s0;%- Moveable]
:: [s0;%- MoveableAndDeepCopyOption]
:: [s0;%- MtInspector]
:: [s0;%- Mutex]
:: [s0;%- Mutex`::Lock]
:: [s0;%- NetNode]
:: [s0;%- NilStreamClass]
:: [s0;%- NoConvertClass]
:: [s0;%- NoCopy]
:: [s0;%- Nuller]
:: [s0;%- One]
:: [s0;%- ParamHelper`_`_]
:: [s0;%- PeFile]
:: [s0;%- Point]
:: [s0;%- Point16]
:: [s0;%- Point64]
:: [s0;%- Point`_]
:: [s0;%- Point`_`::Sz]
:: [s0;%- Pointf]
:: [s0;%- PolyDeepCopyNew]
:: [s0;%- PostfixOps]
:: [s0;%- Pte]
:: [s0;%- PteBase]
:: [s0;%- PteBase`::Prec]
:: [s0;%- Ptr]
:: [s0;%- PtrBase]
:: [s0;%- PtrHash]
:: [s0;%- RGBA]
:: [s0;%- RWMutex]
:: [s0;%- RWMutex`::ReadLock]
:: [s0;%- RWMutex`::WriteLock]
:: [s0;%- RawPickValue]
:: [s0;%- RawPickValue`::PickRep]
:: [s0;%- RawPickValueRep]
:: [s0;%- RawRef]
:: [s0;%- RawValue]
:: [s0;%- RawValue`::Rep]
:: [s0;%- RawValueCreate]
:: [s0;%- RawValueCreate`::Rep]
:: [s0;%- RawValueCreateRep]
:: [s0;%- RawValueRep]
:: [s0;%- Rect]
:: [s0;%- Rect16]
:: [s0;%- Rect64]
:: [s0;%- Rect`_]
:: [s0;%- Rect`_`::Pt]
:: [s0;%- Rect`_`::Sz]
:: [s0;%- Rectf]
:: [s0;%- Ref]
:: [s0;%- Ref`::ValueRef]
:: [s0;%- RefManager]
:: [s0;%- RelOps]
:: [s0;%- RichRef]
:: [s0;%- RichValue]
:: [s0;%- RichValue`::Rep]
:: [s0;%- RichValueRep]
:: [s0;%- Segtor]
:: [s0;%- Segtor`::Block]
:: [s0;%- Segtor`::ConstIterator]
:: [s0;%- Segtor`::Iterator]
:: [s0;%- Segtor`::ValueType]
:: [s0;%- SegtorMap]
:: [s0;%- SegtorMap`::B]
:: [s0;%- SegtorMap`::ConstIterator]
:: [s0;%- SegtorMap`::Iterator]
:: [s0;%- Semaphore]
:: [s0;%- Size]
:: [s0;%- Size16]
:: [s0;%- Size64]
:: [s0;%- SizeStream]
:: [s0;%- Size`_]
:: [s0;%- Sizef]
:: [s0;%- SortOrderIterator]
:: [s0;%- SortOrderIterator`::Iter]
:: [s0;%- StableSortItem]
:: [s0;%- StableSortIterator]
:: [s0;%- StableSortIterator`::Iter]
:: [s0;%- StableSortLessCmp`_]
:: [s0;%- StableSortLess`_]
:: [s0;%- StableSortOrderIterator]
:: [s0;%- StableSortOrderIterator`::Iter]
:: [s0;%- StaticCriticalSection]
:: [s0;%- StaticMutex]
:: [s0;%- StaticRWMutex]
:: [s0;%- StaticSemaphore]
:: [s0;%- StdCmp]
:: [s0;%- StdEqual]
:: [s0;%- StdGreater]
:: [s0;%- StdHash]
:: [s0;%- StdLess]
:: [s0;%- StdValueOrder]
:: [s0;%- Stream]
:: [s0;%- StreamError]
:: [s0;%- String]
:: [s0;%- String0]
:: [s0;%- String0`::Buffer]
:: [s0;%- String0`::Rc]
:: [s0;%- String0`::String]
:: [s0;%- String0`::bchar]
:: [s0;%- String0`::tchar]
:: [s0;%- String`::operatorstd]
:: [s0;%- StringBuffer]
:: [s0;%- StringBuffer`::Rc]
:: [s0;%- StringC]
:: [s0;%- StringICompare`_`_]
:: [s0;%- StringMap]
:: [s0;%- StringStream]
:: [s0;%- SyncObject]
:: [s0;%- TEC]
:: [s0;%- TextSettings]
:: [s0;%- TextTest]
:: [s0;%- Thread]
:: [s0;%- Time]
:: [s0;%- TimeStop]
:: [s0;%- TimingInspector]
:: [s0;%- TimingInspector`::Routine]
:: [s0;%- Topic]
:: [s0;%- TopicData`_`_]
:: [s0;%- TopicLink]
:: [s0;%- Uuid]
:: [s0;%- UuidValueGenClass]
:: [s0;%- Value]
:: [s0;%- Value`::Void]
:: [s0;%- ValueArray]
:: [s0;%- ValueArray`::Data]
:: [s0;%- ValueArray`::NullData]
:: [s0;%- ValueErrorCls]
:: [s0;%- ValueGen]
:: [s0;%- ValueMap]
:: [s0;%- ValueMap`::Data]
:: [s0;%- ValueMap`::NullData]
:: [s0;%- ValueOrder]
:: [s0;%- Vector]
:: [s0;%- Vector`::ConstIterator]
:: [s0;%- Vector`::Iterator]
:: [s0;%- Vector`::ValueType]
:: [s0;%- VectorMap]
:: [s0;%- VectorMap`::B]
:: [s0;%- VectorMap`::ConstIterator]
:: [s0;%- VectorMap`::Iterator]
:: [s0;%- Vector`_]
:: [s0;%- WString]
:: [s0;%- WString0]
:: [s0;%- WString0`::Buffer]
:: [s0;%- WString0`::String]
:: [s0;%- WString0`::bchar]
:: [s0;%- WString0`::tchar]
:: [s0;%- WString`::operatorstd]
:: [s0;%- WStringBuffer]
:: [s0;%- WStringICompare`_`_]
:: [s0;%- WildcardCompareCS]
:: [s0;%- WithDeepCopy]
:: [s0;%- XmlError]
:: [s0;%- XmlIO]
:: [s0;%- XmlNode]
:: [s0;%- XmlParser]
:: [s0;%- XmlParser`::Nesting]
:: [s0;%- XmlTag]
:: [s0;%- ZoneAlloc]
:: [s0;%- byte]
:: [s0;%- chrTextTest]
:: [s0;%- dword]
:: [s0;%- int16]
:: [s0;%- int32]
:: [s0;%- int64]
:: [s0;%- int8]
:: [s0;%- operatorstd]
:: [s0;%- qword]
:: [s0;%- stat]
:: [s0;%- uint16]
:: [s0;%- uint32]
:: [s0;%- uint64]
:: [s0;%- uint8]
:: [s0;%- wchar]
:: [s0;%- word]}}&]
[s1;%- &]
[s2;:cmp`(const T`&`,const T`&`):%- [@(0.0.255) template]_<[@(0.0.255) class]_[*@4 T][@(0.0.255) >
]_[@(0.0.255) int]_[* cmp]([@(0.0.255) const]_[*@4 T][@(0.0.255) `&]_[*@3 a],
[@(0.0.255) const]_[*@4 T][@(0.0.255) `&]_[*@3 b])&]
[s3; [%-*@3 a] [%-*@3 b].&]
[s4; &]
[s1; &]
[s2;:cmp`(const T`&`,const T`&`):%- [@(0.0.255) template]_<[@(0.0.255) class]_[*@4 I][@(0.0.255) >
]_[@(0.0.255) void]_[* Reverse]([*@4 I]_[*@3 start], [*@4 I]_[*@3 end])&]
[s3; [%-*@3 start] [%-*@3 end].&]
[s4; &]
[s1; &]
[s2;:cmp`(const T`&`,const T`&`):%- [@(0.0.255) template]_<[@(0.0.255) class]_[*@4 C][@(0.0.255) >
]_[@(0.0.255) void]_[* Reverse]([*@4 C][@(0.0.255) `&]_[*@3 container])&]
[s3; [%-*@3 container].&]
[s4; &]
[s1; &]
[s2;:cmp`(const T`&`,const T`&`):%- [@(0.0.255) template]_<[@(0.0.255) class]_[*@4 T],
[@(0.0.255) class]_[*@4 V][@(0.0.255) >]_[@(0.0.255) void]_[* Sum]([*@4 V][@(0.0.255) `&]_[*@3 su
m], [*@4 T]_[*@3 ptr], [*@4 T]_[*@3 end])&]
[s3; [%-*@3 sum] [%-*@3 ptr] [%-*@3 end].&]
[s4; &]
[s1; &]
[s2;:cmp`(const T`&`,const T`&`):%- [@(0.0.255) template]_<[@(0.0.255) class]_[*@4 T][@(0.0.255) >
]_[@(0.0.255) typename]_T`::ValueType_[* Sum]([@(0.0.255) const]_[*@4 T][@(0.0.255) `&]_[*@3 c
], [@(0.0.255) const]_[@(0.0.255) typename]_T`::ValueType[@(0.0.255) `&]_[*@3 init]_`=_[@(0.0.255) t
ypename]_T`::ValueType())&]
[s3; [%-*@3 c] [%-*@3 init].&]
[s4; &]
[s1; &]
[s2;:cmp`(const T`&`,const T`&`):%- [@(0.0.255) template]_<[@(0.0.255) class]_[*@4 T][@(0.0.255) >
]_[@(0.0.255) typename]_T`::ValueType_[* Sum0]([@(0.0.255) const]_[*@4 T][@(0.0.255) `&]_[*@3 c
])&]
[s3; [%-*@3 c].&]
[s4; &]
[s1; &]
[s2;:cmp`(const T`&`,const T`&`):%- [@(0.0.255) template]_<[@(0.0.255) class]_[*@4 T][@(0.0.255) >
]_[*@4 T]_[* MinElement]([*@4 T]_[*@3 ptr], [*@4 T]_[*@3 end])&]
[s3; [%-*@3 ptr] [%-*@3 end].&]
[s4; &]
[s1; &]
[s2;:cmp`(const T`&`,const T`&`):%- [@(0.0.255) template]_<[@(0.0.255) class]_[*@4 C][@(0.0.255) >
]_[@(0.0.255) int]_[* MinIndex]([@(0.0.255) const]_[*@4 C][@(0.0.255) `&]_[*@3 c])&]
[s3; [%-*@3 c].&]
[s4; &]
[s1; &]
[s2;:cmp`(const T`&`,const T`&`):%- [@(0.0.255) template]_<[@(0.0.255) class]_[*@4 C][@(0.0.255) >
]_[@(0.0.255) int]_[* MaxIndex]([@(0.0.255) const]_[*@4 C][@(0.0.255) `&]_[*@3 c])&]
[s3; [%-*@3 c].&]
[s4; &]
[s1; &]
[s2;:cmp`(const T`&`,const T`&`):%- [@(0.0.255) template]_<[@(0.0.255) class]_[*@4 T][@(0.0.255) >
]_[@(0.0.255) const]_[@(0.0.255) typename]_T`::ValueType[@(0.0.255) `&]_[* Min]([@(0.0.255) c
onst]_[*@4 T][@(0.0.255) `&]_[*@3 c])&]
[s3; [%-*@3 c].&]
[s4; &]
[s1; &]
[s2;:Min`(const T`&`):%- [@(0.0.255) template]_<[@(0.0.255) class]_[*@4 T][@(0.0.255) >]_[*@4 T
]_[* MaxElement]([*@4 T]_[*@3 ptr], [*@4 T]_[*@3 end])&]
[s3; [%-*@3 ptr] [%-*@3 end].&]
[s4; &]
[s1;%- &]
[s2;:MaxIndex`(const C`&`):%- [@(0.0.255) template]_<[@(0.0.255) class]_[*@4 T][@(0.0.255) >]_
[*@4 T]_[* MinElement]([*@4 T]_[*@3 ptr], [*@4 T]_[*@3 end])&]
[s3; [%-*@3 ptr] [%-*@3 end].&]
[s4; &]
[s1; &]
[s2;:MinElement`(T`,T`):%- [@(0.0.255) template]_<[@(0.0.255) class]_[*@4 C][@(0.0.255) >]_[@(0.0.255) i
nt]_[* MinIndex]([@(0.0.255) const]_[*@4 C][@(0.0.255) `&]_[*@3 c])&]
[s3; [%-*@3 c].&]
[s4; &]
[s1; &]
[s2;:MaxIndex`(const C`&`):%- [@(0.0.255) template]_<[@(0.0.255) class]_[*@4 C][@(0.0.255) >]_
[@(0.0.255) int]_[* MaxIndex]([@(0.0.255) const]_[*@4 C][@(0.0.255) `&]_[*@3 c])&]
[s3; [%-*@3 c].&]
[s4; &]
[s1;%- &]
[s2;:Sum0`(const T`&`):%- [@(0.0.255) template]_<[@(0.0.255) class]_[*@4 T][@(0.0.255) >]_[@(0.0.255) t
ypename]_T`::ValueType_[* Sum0]([@(0.0.255) const]_[*@4 T][@(0.0.255) `&]_[*@3 c])&]
[s3; [%-*@3 c].&]
[s4; &]
[s0; ]

View file

@ -0,0 +1,15 @@
TITLE("")
COMPRESSED
120,156,237,91,251,115,219,184,17,254,87,52,211,75,70,206,56,25,241,33,219,177,211,206,217,178,28,43,39,201,26,75,137,218,122,52,18,68,194,50,107,138,228,145,80,98,93,38,255,123,1,62,36,98,241,160,227,58,246,165,109,126,72,132,239,195,99,119,177,88,44,64,228,170,246,203,47,141,221,198,95,26,21,127,14,79,241,53,90,249,100,114,117,190,119,212,160,141,12,214,168,185,71,169,189,166,97,219,118,195,54,247,140,134,101,218,150,97,53,76,171,105,188,109,238,29,206,241,194,11,38,87,158,109,31,28,33,179,121,116,251,219,197,219,35,147,182,54,105,107,107,223,176,14,154,150,65,27,210,191,12,203,48,155,166,101,27,7,230,91,251,192,178,246,27,135,78,232,98,143,224,229,228,202,55,15,14,210,118,22,109,103,238,55,77,99,223,62,176,15,12,107,255,192,164,205,205,70,195,108,236,155,84,14,235,192,108,30,186,56,113,38,87,76,72,155,86,127,187,103,189,109,24,141,198,190,193,196,219,111,88,77,219,48,44,147,118,97,238,155,70,163,121,136,3,119,
114,245,117,250,237,69,187,255,250,227,176,118,149,24,71,47,94,215,94,78,174,18,243,232,48,34,120,142,156,219,89,253,226,228,67,187,53,154,189,154,237,126,14,61,119,86,167,191,118,102,245,129,81,139,140,217,238,192,172,69,38,45,239,28,210,150,45,228,251,172,205,244,234,85,109,16,135,119,235,73,189,128,174,126,173,55,222,52,222,152,205,230,78,109,246,114,66,107,252,106,213,156,249,100,135,141,102,29,213,106,87,47,94,231,208,27,6,217,71,169,28,198,209,35,137,227,228,191,183,18,21,34,24,147,221,26,196,76,137,92,198,100,251,219,124,124,33,69,3,213,194,8,199,136,132,241,187,119,21,118,68,130,10,162,97,209,70,252,71,180,112,89,26,234,174,145,143,8,158,76,223,149,97,199,71,73,146,202,105,215,178,142,169,176,170,10,189,246,232,252,226,84,83,97,96,76,202,212,223,38,211,66,111,163,140,191,155,40,106,83,171,230,106,78,234,101,145,166,179,87,169,221,194,249,191,176,67,128,0,204,10,147,105,61,19,110,118,120,200,205,193,171,73,218,112,137,
201,77,232,78,118,234,197,192,211,200,216,129,115,144,247,94,20,243,54,255,211,179,177,93,151,255,159,142,63,215,116,148,7,9,131,132,240,98,254,152,25,154,138,163,254,185,39,237,135,153,60,55,97,110,229,235,160,194,149,105,133,159,216,4,32,87,184,79,187,167,202,33,158,211,31,190,183,169,144,206,124,87,195,39,204,121,158,212,168,154,100,234,187,28,13,61,204,176,255,197,153,152,134,52,85,51,102,202,45,71,187,146,183,123,210,132,109,43,197,52,50,31,144,46,52,242,227,83,237,235,87,131,29,29,107,57,116,220,9,92,124,55,57,60,228,1,42,89,139,237,113,29,146,185,166,172,194,39,228,175,240,104,29,225,50,217,67,17,40,234,186,202,104,53,243,27,94,87,180,165,53,36,34,168,164,27,146,216,11,22,34,66,235,107,168,185,115,131,98,57,179,186,190,198,114,138,192,70,243,48,38,237,59,167,12,185,238,69,148,148,129,96,205,151,104,63,39,40,193,167,136,32,129,128,96,28,163,53,44,235,108,47,227,105,249,161,237,250,3,73,37,77,251,82,211,19,
61,45,237,89,58,189,140,19,252,121,3,202,70,170,116,118,86,9,248,116,14,201,186,171,112,247,109,21,25,155,36,222,34,216,232,213,15,203,28,9,151,94,217,117,78,60,56,223,57,162,25,126,91,67,75,202,44,123,226,125,162,241,5,52,200,32,237,128,155,42,122,86,62,36,57,14,220,1,225,155,144,242,114,57,241,67,231,150,46,56,140,150,101,20,174,201,214,0,197,137,12,161,35,183,227,56,148,51,131,176,60,84,177,71,72,32,67,134,49,171,116,143,135,195,254,113,175,45,227,143,29,226,133,129,140,57,11,52,92,24,223,170,217,94,26,245,239,199,15,8,150,84,49,101,88,133,42,166,114,64,83,163,138,169,85,197,172,80,197,172,86,197,146,97,21,170,88,202,1,45,141,42,150,86,21,171,66,21,171,90,21,91,134,85,168,98,43,7,180,53,170,216,90,85,236,10,85,236,106,85,42,164,86,118,157,17,172,116,28,47,170,120,217,130,228,42,200,220,156,171,32,115,30,174,130,108,74,40,60,66,241,2,19,29,87,97,0,205,220,104,167,166,98,102,202,180,
220,128,160,134,204,132,176,138,124,134,65,45,153,169,97,149,123,117,36,155,18,88,229,94,29,201,166,14,86,185,87,71,213,149,196,26,248,206,131,238,225,5,60,132,227,88,216,210,90,52,149,60,243,124,194,111,98,27,112,132,239,200,8,39,4,144,67,88,198,4,228,140,173,112,76,189,74,0,168,147,118,67,71,138,247,62,132,115,25,62,8,67,159,195,125,126,91,101,229,51,14,88,206,189,0,211,127,34,20,99,145,56,71,201,13,143,210,122,104,238,99,1,196,151,216,231,179,232,28,23,173,152,166,41,146,76,132,39,96,198,41,176,35,158,252,140,99,34,34,167,136,159,252,28,13,87,80,135,20,239,4,146,46,40,184,103,139,176,112,80,201,241,145,183,228,123,94,17,209,4,177,99,113,75,50,246,136,231,32,127,136,97,232,56,237,118,207,143,251,167,221,54,143,141,254,49,224,16,234,79,179,233,112,54,229,177,178,28,167,243,197,137,127,123,142,145,203,121,239,41,158,175,22,221,112,145,230,112,28,142,163,86,24,173,47,34,40,80,246,169,115,236,249,174,131,98,
87,244,156,246,50,34,235,86,122,210,47,129,159,49,103,90,254,0,118,230,97,223,165,254,131,210,208,238,39,28,229,227,227,40,98,159,33,121,176,19,0,128,38,244,17,63,33,37,148,186,75,66,16,1,228,197,10,34,194,76,165,224,58,33,120,217,9,174,67,37,65,251,207,132,18,234,0,119,56,243,2,151,193,18,72,34,99,118,12,185,136,249,57,163,91,208,178,227,2,0,17,113,13,100,56,17,26,83,140,183,212,123,222,87,88,209,128,101,197,150,153,114,194,142,151,162,146,93,52,195,101,91,104,202,40,246,79,129,27,8,226,154,176,172,17,87,76,149,83,84,33,174,60,69,78,25,141,184,154,212,152,209,22,44,107,196,21,211,225,20,85,136,43,79,131,83,70,35,174,38,253,101,180,13,203,26,113,197,148,55,69,21,226,202,83,221,148,209,136,171,73,113,25,173,145,78,218,157,66,54,165,104,26,201,212,130,157,207,166,62,23,160,217,222,202,110,149,36,16,219,249,189,160,28,143,105,224,142,64,145,93,124,120,139,115,55,22,241,83,73,107,22,162,98,140,229,
140,176,47,228,248,0,45,56,249,60,26,101,86,1,221,18,147,8,94,68,200,118,116,229,102,174,218,199,185,176,214,113,211,61,159,67,186,30,15,128,91,38,217,5,83,213,221,82,202,15,195,152,152,247,34,243,91,20,89,29,75,215,129,117,143,14,116,237,213,205,63,132,94,32,6,255,18,154,53,41,111,107,221,86,231,148,191,78,235,182,64,78,209,189,252,216,66,206,13,150,64,146,254,182,76,15,221,114,210,117,81,176,200,229,128,89,1,163,122,161,187,242,105,242,232,132,177,11,40,150,79,75,137,21,245,74,176,213,150,97,42,132,58,61,41,87,108,13,21,68,187,175,34,84,45,206,46,21,196,251,182,130,0,230,231,151,37,43,94,124,9,120,67,6,139,118,64,226,245,108,202,133,145,110,97,67,30,163,134,43,3,33,114,233,150,15,175,217,104,226,39,100,60,84,46,209,153,122,120,121,73,67,132,88,25,47,101,88,24,175,59,139,32,140,113,23,163,219,4,230,150,89,133,65,28,94,243,137,80,22,59,229,121,96,207,227,151,69,47,252,140,193,57,164,128,142,
3,87,153,189,246,164,161,171,183,34,92,20,73,203,226,233,171,143,73,63,116,203,67,246,61,63,83,31,122,118,63,84,184,60,35,162,242,125,113,127,69,143,163,101,97,46,130,242,8,3,122,220,90,158,99,63,194,49,152,247,1,6,121,228,128,46,120,2,203,198,30,68,184,179,76,138,240,221,102,8,251,18,243,7,132,175,57,192,95,23,102,238,227,47,28,147,144,107,239,142,63,12,242,123,33,45,129,157,47,71,216,150,19,115,158,203,223,60,211,146,208,48,6,135,212,203,247,39,199,229,226,24,78,111,142,208,177,152,79,131,73,222,146,99,122,40,195,144,69,95,6,158,115,155,166,229,10,152,169,64,127,95,226,72,81,65,96,46,241,53,15,72,186,47,186,22,26,167,68,139,250,32,145,181,200,136,138,118,114,14,160,236,187,38,95,228,92,139,1,156,103,49,128,115,172,12,96,214,129,29,137,222,198,80,206,38,24,148,138,143,21,2,209,67,1,141,175,49,7,130,123,137,75,207,185,1,237,40,34,216,188,192,68,227,21,12,15,15,241,130,143,42,25,192,146,17,
16,255,54,132,42,35,217,84,208,113,178,143,53,25,201,239,44,27,12,164,69,101,92,47,136,242,83,217,16,47,81,116,19,114,251,235,208,251,3,22,57,71,97,0,231,40,12,16,246,16,6,114,222,195,128,242,148,177,140,40,61,23,203,196,130,156,152,50,13,9,219,41,242,180,106,169,34,132,142,5,82,215,115,23,39,73,107,25,241,106,112,172,130,82,234,37,175,33,149,129,120,142,250,82,41,227,97,88,204,80,49,92,102,184,116,174,137,75,21,228,129,246,239,43,228,243,208,251,52,202,240,2,186,32,104,83,132,89,132,71,164,183,31,162,175,164,0,76,109,132,235,185,12,104,136,8,91,23,240,91,229,150,186,116,164,176,170,123,201,51,133,45,3,223,34,108,30,41,20,47,143,18,226,10,180,66,182,12,150,11,216,18,144,78,158,8,131,28,34,35,65,188,72,49,209,202,235,192,185,200,158,183,108,193,81,187,60,20,203,215,135,56,189,91,74,0,12,174,197,71,55,180,247,178,170,224,150,140,21,135,36,140,120,136,233,33,201,222,0,195,76,18,174,168,16,92,
135,97,196,125,183,79,203,217,173,41,103,144,20,7,185,248,199,149,231,130,98,234,152,239,113,0,179,59,184,137,20,27,200,167,144,235,34,133,225,195,129,45,40,62,42,225,56,150,49,202,248,116,5,240,89,115,33,39,132,248,25,47,32,197,184,25,163,26,21,46,79,225,129,66,229,243,4,221,227,4,237,211,132,140,4,186,20,24,216,237,202,184,94,16,229,110,151,203,82,118,151,177,16,6,198,98,152,25,107,226,204,88,19,81,198,234,144,50,86,199,148,113,69,80,25,43,162,202,88,27,40,192,121,154,59,56,143,61,114,83,156,4,74,240,223,151,62,140,201,20,234,92,240,101,112,160,162,136,240,74,100,131,49,47,164,113,132,183,18,101,71,168,12,252,51,12,240,177,79,83,174,18,54,95,115,217,177,115,35,251,86,231,126,225,111,26,224,233,137,150,185,143,54,240,44,69,203,7,165,162,220,252,191,131,65,192,141,255,10,14,186,130,163,174,224,176,43,48,238,23,224,16,233,128,223,190,101,207,71,95,108,254,239,150,67,51,147,122,250,126,190,54,154,189,156,237,
110,127,62,228,177,232,72,120,148,89,42,178,99,105,250,108,153,230,10,202,255,52,192,247,192,61,169,253,206,38,15,121,78,251,184,214,232,232,172,145,189,60,165,230,184,196,159,49,117,235,252,209,106,39,151,158,58,68,76,138,199,174,5,200,62,127,65,165,178,138,69,137,213,120,10,213,90,15,80,173,37,159,39,42,8,65,30,187,227,18,94,149,111,152,167,80,73,247,198,249,211,189,212,29,174,150,185,170,159,228,170,38,180,66,62,165,163,28,138,72,12,33,233,44,211,150,197,111,214,228,169,231,91,187,176,9,221,143,3,68,51,183,233,168,188,69,111,77,242,125,11,215,81,172,245,234,17,165,221,165,47,58,166,179,191,222,167,131,186,240,148,219,217,152,58,237,231,79,110,235,198,3,140,45,106,252,60,74,110,150,64,173,231,5,109,31,47,217,83,129,250,67,22,203,115,44,16,109,64,44,118,62,170,88,246,165,74,57,75,170,24,249,76,179,116,63,173,208,221,207,165,149,118,129,253,39,209,134,77,240,15,92,129,180,247,178,21,30,125,217,161,187,31,184,236,182,
41,103,225,47,133,46,173,159,54,132,108,71,153,213,71,179,221,209,79,29,57,30,107,90,158,59,102,108,29,141,109,136,143,191,96,158,113,51,110,28,213,38,255,6,106,173,94,54,

View file

@ -158,3 +158,7 @@ TOPIC("Atest$en-us")
#include "Atest$en-us.tppi"
END_TOPIC
TOPIC("TestTest$en-us")
#include "TestTest$en-us.tppi"
END_TOPIC

View file

@ -1,8 +1,11 @@
uses
RichEdit;
Core,
CtrlLib,
CodeEditor;
file
test.cpp,
test2.cpp,
ignorelist;
mainconfig

View file

@ -1,4 +1,6 @@
#ifndef _Parser_icpp_init_stub
#define _Parser_icpp_init_stub
#include "RichEdit/init"
#include "Core/init"
#include "CtrlLib/init"
#include "CodeEditor/init"
#endif

View file

@ -1,11 +1,124 @@
#include <RichEdit/RichEdit.h>
struct alpha {
int beta;
};
struct oper2 {
int oper2m;
};
struct oper3 {
int oper3m;
};
struct X {
alpha a;
alpha operator[](int i);
};
struct Y : X{
X b;
int a;
struct H {
int x;
};
H x;
};
template <class T>
struct Tm {
template <class V>
struct H {
T Test();
V Test2();
};
T x;
};
void Test(int a, long b)
{
X().;
Y x;
x.;
x.a. ; // should not work...
x.X::a. ;
x.b.a. ;
x[]. ;
x(). ;
x. ;
x-> ;
y. ;
Tm<X> tm;
Tm< X > :: H <alpha > tt;
tt. ;
tt.Test(). ;
tt.Test2(). ;
X:: ;
;
}
// ------------------------------------------------------------------------------------------
void Foo()
{
}
CppItemInfoDisplay ItemList::display;
class ItemList : public ColumnList {
CppItemInfoDisplay display;
friend struct ItemDisplay;
int GetTopic(Point p, String& key);
String Item(int i);
public:
bool active_topics;
void Clear();
ItemList();
};
void ItemList::Clear()
{
}
void ItemList::Clear(int)
{
}
void Clear();
typedef short unsigned word;
typedef unsigned char byte;
typedef signed char int8;
typedef unsigned char uint8;
typedef short int int16;
typedef short unsigned uint16;
struct FindBrokenRefIterator : RichTxt::Iterator {
int cursor;
Uuid itemstyle;
void Test();
virtual bool operator()(int pos, const RichPara& para)
{
this-> ;
THISBACK( ;
if(pos >= cursor) {
if(para.format.label != "noref") {
if(IsNull(para.format.label))
@ -27,3 +140,44 @@ struct FindBrokenRefIterator : RichTxt::Iterator {
}
};
void FindBrokenRefIterator::Test()
{
}
void Foo()
{
String x;
x.Right(). ;
String(xxx). ;
String x;
x.;
x->;
AttrText("Hello!"). ;
Vector<String> vx;
vx. ;
vx[0]. ;
vx.Add(). ;
vx[654].Right(). ;
vx[654]->Right(). ;
Vector<String>(). ;
x > x.;
EditorBar bar;
bar. ;
EditString es;
es. ;
es.NullText(). ;
THISBACK(
}
struct Dlg : WithEditStringLayout<TopWindow> {
Dlg() {
Ctrl:: ;
Dlg x;
x. ;
this. ;
this-> ;
a
}
Vector<String>::
};

4
uppdev/Parser/test2.cpp Normal file
View file

@ -0,0 +1,4 @@
void ItemList::Clear(String x)
{
}

View file

@ -1,4 +1,5 @@
file
hh.cpp,
test.cpp;
mainconfig

View file

@ -1 +1,68 @@
void Test(int a, long b);
struct alpha {
int beta;
};
struct oper2 {
int oper2m;
};
struct oper3 {
int oper3m;
};
struct X {
alpha a;
alpha operator[](int i);
};
struct Y : X{
X b;
int a;
struct H {
int x;
};
H x;
};
template <class T>
struct Tm {
template <class V>
struct H {
T Test();
V Test2();
};
T x;
};
void Test(int a, long b)
{
X().;
Y x;
x.;
x.a. ; // should not work...
x.X::a. ;
x.b.a. ;
x[]. ;
x(). ;
x. ;
x-> ;
y. ;
Tm<X> tm;
Tm< X > :: H <alpha > tt;
tt. ;
tt.Test(). ;
tt.Test2(). ;
X:: ;
;
}
void Foo(volatile ::String)
{
}

21
uppdev/RichTextP/Copying Normal file
View file

@ -0,0 +1,21 @@
Copyright 1998-2008 The U++ Project. All rights reserved.
Redistribution and use in source and binary forms, with or without modification, are permitted
provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this list of
conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice, this list of
conditions and the following disclaimer in the documentation and/or other materials
provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE U++ PROJECT ``AS IS'' AND ANY EXPRESS OR IMPLIED
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FREEBSD PROJECT OR
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
OF THE POSSIBILITY OF SUCH DAMAGE.

View file

@ -0,0 +1,361 @@
#include "RichText.h"
NAMESPACE_UPP
String HtmlFontStyle(Font f, Font base)
{
String style;
if(f.GetFace() != base.GetFace())
switch(f.GetFace()) {
case Font::ARIAL: style = "font-family:sans-serif;"; break;
case Font::ROMAN: style = "font-family:serif;"; break;
case Font::COURIER: style = "font-family:monospace;"; break;
}
if(f.GetHeight() != base.GetHeight())
style << Sprintf("font-size:%dpt;", f.GetHeight() * 72 / 600);
if(f.IsBold() != base.IsBold())
style << (f.IsBold() ? "font-weight:bold;" : "font-weight:normal;");
if(f.IsItalic() != base.IsItalic())
style << (f.IsItalic() ? "font-style:italic;" : "font-style:normal;");
if(f.IsUnderline() != base.IsUnderline())
style << (f.IsUnderline() ? "text-decoration:underline;" : "text-decoration:none;");
return style;
}
String HtmlFontStyle(Font f)
{
String style;
switch(f.GetFace()) {
case Font::ARIAL: style = "font-family:sans-serif;"; break;
case Font::ROMAN: style = "font-family:serif;"; break;
case Font::COURIER: style = "font-family:monospace;"; break;
}
style << Sprintf("font-size:%dpt;", f.GetHeight() * 72 / 600);
style << (f.IsBold() ? "font-weight:bold;" : "font-weight:normal;");
style << (f.IsItalic() ? "font-style:italic;" : "font-style:normal;");
style << (f.IsUnderline() ? "text-decoration:underline;" : "text-decoration:none;");
return style;
}
String HtmlDot(int q, Zoom z)
{
return String().Cat() << ' ' << z * q << "px";
}
String HtmlDotl(int q, Zoom z)
{
return String().Cat() << ' ' << max((int)!!q, z * q) << "px";
}
String HtmlStyleColor(Color c, const char *cl = "color")
{
return Format(String(cl) + ":#%02x%02x%02x;", c.GetR(), c.GetG(), c.GetB());
}
String HtmlCharStyle(const RichPara::CharFormat& cf, const RichPara::CharFormat& sf)
{
String style;
if(cf.ink != sf.ink)
style = HtmlStyleColor(cf.ink);
return style + HtmlFontStyle(cf, sf);
}
String HtmlParaStyle(const RichPara::Format& f, Zoom z)
{
String style;
int lm = z * f.lm;
if(f.bullet && f.bullet != RichPara::BULLET_TEXT) {
style << "display:list-item;line-style-type:";
switch(f.bullet) {
case RichPara::BULLET_ROUND: style << "disc"; break;
case RichPara::BULLET_ROUNDWHITE: style << "circle"; break;
case RichPara::BULLET_BOX:
case RichPara::BULLET_BOXWHITE: style << "square"; break;
}
style << ";line-style-position:inside;";
lm += 20;
}
style << Format("margin:%d %d %d %d;text-indent:%d;",
z * f.before,
z * f.rm,
z * f.after,
lm,
z * (f.bullet ? 0 : f.indent)
);
style << "text-align:";
switch(f.align) {
case ALIGN_LEFT: style << "left;"; break;
case ALIGN_RIGHT: style << "right;"; break;
case ALIGN_CENTER: style << "center;"; break;
case ALIGN_JUSTIFY: style << "justify;"; break;
}
style << HtmlStyleColor(f.ink) + HtmlFontStyle(f);
if(!IsNull(f.paper))
style << HtmlStyleColor(f.paper, "background-color");
return style;
}
String FormatClass(Index<String>& css, const String& fmt)
{
return " CLASS=" + FormatIntAlpha(css.FindAdd(fmt) + 1);
}
void TabBorder(String& style, const char *txt, int border, Color bordercolor, const RichTable::Format& tf, Zoom z)
{
style << "border-" << txt << ':' << HtmlDotl(border + tf.grid, z) << " solid "
<< ColorToHtml(border ? bordercolor : tf.gridcolor) << ';';
}
String AsHtml(const RichTxt& text, const RichStyles& styles, Index<String>& css,
const VectorMap<String, String>& links,
const VectorMap<String, String>& labels,
const String& outdir, const String& namebase, Zoom z, int& im,
const VectorMap<String, String>& escape,
int imtolerance)
{
String html;
for(int i = 0; i < text.GetPartCount(); i++)
{
if(text.IsTable(i)) {
const RichTable& t = text.GetTable(i);
int nx = t.format.column.GetCount();
int ny = t.cell.GetCount();
const RichTable::Format& tf = t.format;
html << "<TABLE WIDTH=\"100%\" BORDER=0>";
if(tf.before > 0)
html << "<TR><TD HEIGHT=" << HtmlDot(tf.before, z) << " COLSPAN=3></TD></TR>";
html << "<TR><TD><TABLE BORDER=0 WIDTH=" << HtmlDot(tf.lm, z) << "><TR><TD></TD></TR></TABLE></TD>\r\n"
"<TD WIDTH=\"98%\">";
String style;
style << "border-collapse:collapse;table-layout:auto;"
<< "border:" << HtmlDotl(tf.frame, z) << " solid " << ColorToHtml(tf.framecolor) << ';';
html << "<TABLE WIDTH=\"100%\"" << FormatClass(css, style) << ">";
int sum = 0;
for(int i = 0; i < nx; i++)
sum += t.format.column[i];
html << "<COLGROUP>";
for(int i = 0; i < nx; i++)
html << "<COL width=\"" << 100 * t.format.column[i] / sum << "%\">";
html << "\r\n";
for(int i = 0; i < ny; i++) {
const Array<RichCell>& r = t.cell[i];
html << "<TR>";
for(int j = 0; j < r.GetCount(); j++) {
if(t(i, j)) {
const RichCell& c = r[j];
const RichCell::Format& cf = c.format;
String style;
style << "padding:" << HtmlDot(cf.margin.top, z) << HtmlDot(cf.margin.right, z)
<< HtmlDot(cf.margin.bottom, z) << HtmlDot(cf.margin.left, z) << ';';
TabBorder(style, "left", cf.border.left, cf.bordercolor, tf, z);
TabBorder(style, "top", cf.border.top, cf.bordercolor, tf, z);
TabBorder(style, "right", cf.border.right, cf.bordercolor, tf, z);
TabBorder(style, "bottom", cf.border.bottom, cf.bordercolor, tf, z);
style << "background-color:" << ColorToHtml(cf.color) << ';';
style << "vertical-align:";
switch(cf.align) {
case ALIGN_TOP: style << "top"; break;
case ALIGN_CENTER: style << "middle"; break;
case ALIGN_BOTTOM: style << "bottom"; break;
}
style << ';';
html << "<TD" << FormatClass(css, style);
if(c.hspan)
html << " colspan=" << c.hspan + 1;
if(c.vspan)
html << " rowspan=" << c.vspan + 1;
html << '>';
html << AsHtml(c.text, styles, css, links, labels, outdir, namebase, z,
im, escape, imtolerance);
html << "</TD>\r\n";
}
}
html << "</TR>\r\n";
}
html << "</TABLE></TD>\r\n"
<< "<TD><TABLE BORDER=0 WIDTH=" << HtmlDot(tf.rm, z) << "><TR><TD></TD></TR></TABLE></TD>";
if(tf.after > 0)
html << "<TR><TD HEIGHT=" << HtmlDot(tf.after, z) << " COLSPAN=3></TD></TR>";
html << "</TABLE>\r\n";
}
else
if(text.IsPara(i)) {
RichPara p = text.Get(i, styles);
if(p.format.ruler)
html << "<HR>";
String lbl;
if(!IsNull(p.format.label)) {
lbl = labels.Get(p.format.label, Null);
if(lbl.GetCount())
html << "<A NAME=\"" << lbl << "\">";
}
bool bultext = false;
if(p.format.bullet == RichPara::BULLET_TEXT)
for(int i = 0; i < p.part.GetCount(); i++) {
const RichPara::Part& part = p.part[i];
if(part.text.Find(9) >= 0) {
bultext = true;
break;
}
}
if(bultext) {
html << "<TABLE WIDTH=\"100%\" BORDER=0 "
"CELLPADDING=2 CELLSPACING=2>"
"<TR>";
int q = z * p.format.lm - 8;
if(q > 0)
html << Format("<TD WIDTH=%d></TD>", q);
html << Format("<TD VALIGN=\"top\" WIDTH=%d BGCOLOR=\"#F0F0F0\">\r\n",
max(z * p.format.indent, 0));
p.format.ruler = p.format.after = p.format.before = p.format.indent = p.format.lm = 0;
}
String par = "<P" + FormatClass(css, HtmlParaStyle(p.format, z)) + ">";
html << par;
for(int i = 0; i < p.part.GetCount(); i++) {
const RichPara::Part& part = p.part[i];
int q;
if(part.object) {
String name;
name << namebase << "_" << im++ << ".png";
Size psz = part.object.GetPixelSize();
String lname;
lname << "L$" << name;
Size sz = z * part.object.GetSize();
if(abs(100 * (psz.cx - sz.cx) / sz.cx) < imtolerance)
sz = psz;
PNGEncoder png;
png.SaveFile(AppendFileName(outdir, name), part.object.ToImage(sz));
if(psz.cx * psz.cy)
html << "<A HREF=\"" << lname << "\">";
html << "<IMG SRC=\"" << name << "\" BORDER=0 ALT=\"\">";
if(psz.cx * psz.cy) {
html << "</A>";
PNGEncoder png;
png.SaveFile(AppendFileName(outdir, lname), part.object.ToImage(psz));
}
}
else
if(part.format.indexentry.GetCount() &&
(q = escape.Find(part.format.indexentry.ToString())) >= 0)
html << escape[q];
else {
String lnk = part.format.link;
if(lnk.GetCount()) {
int q = links.Find(lnk);
if(q < 0) {
int q = lnk.ReverseFind('#');
if(q >= 0) {
String l = lnk.Left(q);
lnk = links.Get(l, l) + '#' + lnk.Mid(q + 1);
}
}
else
lnk = links[q];
}
String endtag;
if(!lnk.IsEmpty() && lnk[0] != ':') {
html << "<A HREF=\"" << lnk << "\">";
endtag = "</A>";
}
String cs;
if(part.text[0] != 9)
cs = HtmlCharStyle(part.format, p.format);
if(!cs.IsEmpty()) {
html << "<SPAN" << FormatClass(css, cs) << ">";
endtag = "</SPAN>" + endtag;
}
if(part.format.sscript == 1) {
html << "<SUP>";
endtag = "</SUP>" + endtag;
}
if(part.format.sscript == 2) {
html << "<SUB>";
endtag = "</SUB>" + endtag;
}
if(part.format.IsStrikeout()) {
html << "<STRIKE>";
endtag = "</STRIKE>" + endtag;
}
if(part.format.capitals) {
html << "<SPAN STYLE=\"font-variant: small-caps;\">";
endtag << "</SPAN>";
}
bool spc = false;
const wchar *end = part.text.End();
for(const wchar *s = part.text.Begin(); s != end; s++) {
if(*s == ' ') {
html.Cat(spc ? "&nbsp;" : " ");
spc = true;
}
else {
spc = false;
if(*s == 160) html.Cat("&nbsp;");
else
if(*s == '<') html.Cat("&lt;");
else
if(*s == '>') html.Cat("&gt;");
else
if(*s == '&') html.Cat("&amp;");
else
if(*s == '\"') html.Cat("&quot;");
else
if(*s == 9) {
if(bultext) {
if(!cs.IsEmpty() && part.text[0] != 9)
html << "</SPAN>";
html << "</P>";
html << "</TD>\r\n<TD VALIGN=\"top\" BGCOLOR=\"#F0F0F0\">\r\n";
html << par;
if(s[1]) {
cs = HtmlCharStyle(part.format, p.format);
if(!cs.IsEmpty())
html << "<SPAN" << FormatClass(css, cs) << ">";
}
}
else
html.Cat("&nbsp;&nbsp;&nbsp;&nbsp;");
}
else
html.Cat(ToUtf8(*s));
}
}
html << endtag;
}
}
if(p.part.GetCount() == 0)
html << "&nbsp;";
html << "</P>";
if(bultext)
html << "</TD></TR></TABLE>";
if(lbl.GetCount())
html << "</A>";
html << "\r\n";
}
}
return html;
}
String EncodeHtml(const RichText& text, Index<String>& css,
const VectorMap<String, String>& links,
const VectorMap<String, String>& labels,
const String& outdir, const String& namebase, Zoom z,
const VectorMap<String, String>& escape, int imt)
{
int im = 0;
return AsHtml(text, text.GetStyles(), css, links, labels, outdir, namebase, z, im, escape, imt);
}
String AsCss(Index<String>& ss)
{
String css;
for(int i = 0; i < ss.GetCount(); i++) {
css << "." + FormatIntAlpha(i + 1);
css << "{" << ss[i] << "}\r\n";
}
return css;
}
END_UPP_NAMESPACE

View file

@ -0,0 +1,552 @@
#include "RichText.h"
NAMESPACE_UPP
extern Color (*QTFColor[])();
extern int QTFFontHeight[];
void SeparateNumber(String& s)
{
if(*s.Last() >= '0' && *s.Last() <= '9')
s.Cat(';');
}
String FmtColor(Color c)
{
if(IsNull(c)) return "N";
for(int i = 0; i < 10; i++)
if((*QTFColor[i])() == c)
return String(i + '0', 1);
if(c.GetR() == c.GetG() && c.GetG() == c.GetB())
return Sprintf("(%d)", c.GetR());
return Sprintf("(%d.%d.%d)", c.GetR(), c.GetG(), c.GetB());
}
void LngFmt(String& fmt, dword l, dword lang)
{
if(lang != (dword)l)
if(l == 0)
fmt << "%-";
else
if(l == LNG_ENGLISH)
fmt << "%%";
else
fmt << "%" << LNGAsText(l);
}
void CharFmt(String& fmt, const RichPara::CharFormat& a, const RichPara::CharFormat& b)
{
if(a.IsBold() != b.IsBold()) fmt.Cat('*');
if(a.IsItalic() != b.IsItalic()) fmt.Cat('/');
if(a.IsUnderline() != b.IsUnderline()) fmt.Cat('_');
if(a.IsStrikeout() != b.IsStrikeout()) fmt.Cat('-');
if(a.IsNonAntiAliased() != b.IsNonAntiAliased()) fmt.Cat('t');
if(a.capitals != b.capitals) fmt.Cat('c');
if(a.dashed != b.dashed) fmt.Cat('d');
if(a.sscript != b.sscript)
fmt.Cat(b.sscript == 0 ? a.sscript == 1 ? '`' : ',' :
b.sscript == 1 ? '`' : ',');
if(a.GetFace() != b.GetFace())
switch(b.GetFace()) {
case Font::ARIAL: fmt.Cat('A'); break;
case Font::ROMAN: fmt.Cat('R'); break;
case Font::COURIER: fmt.Cat('C'); break;
case Font::STDFONT: fmt.Cat('G'); break;
case Font::SYMBOL: fmt.Cat('S'); break;
default:
fmt << "!" << b.GetFaceName() << "!";
}
if(a.link != b.link)
fmt << '^' << DeQtf(b.link) << '^';
if(a.indexentry != b.indexentry)
fmt << 'I' << DeQtf(ToUtf8(b.indexentry)) << ';';
if(a.ink != b.ink)
fmt << "@" << FmtColor(b.ink);
if(a.paper != b.paper)
fmt << "$" << FmtColor(b.paper);
if(a.GetHeight() != b.GetHeight()) {
for(int i = 0; i < 10; i++)
if(b.GetHeight() == QTFFontHeight[i]) {
SeparateNumber(fmt);
fmt.Cat('0' + i);
return;
}
fmt.Cat(Format("+%d", b.GetHeight()));
}
}
void FmtNumber(String& qtf, char c, int former, int current)
{
qtf << (former != current ? Format("%c%d;", c, current) : String());
}
void QTFEncodeParaFormat(String& qtf, const RichPara::Format& format, const RichPara::Format& style)
{
if(format.align != style.align)
switch(format.align) {
case ALIGN_LEFT: qtf << '<'; break;
case ALIGN_RIGHT: qtf << '>'; break;
case ALIGN_CENTER: qtf << '='; break;
case ALIGN_JUSTIFY: qtf << '#'; break;
}
FmtNumber(qtf, 'l', style.lm, format.lm);
FmtNumber(qtf, 'r', style.rm, format.rm);
FmtNumber(qtf, 'i', style.indent, format.indent);
FmtNumber(qtf, 'H', style.ruler, format.ruler);
if(style.rulerink != format.rulerink)
qtf << "h" << FmtColor(format.rulerink);
FmtNumber(qtf, 'b', style.before, format.before);
FmtNumber(qtf, 'a', style.after, format.after);
if(style.newpage != format.newpage)
qtf << 'P';
if(style.keep != format.keep)
qtf << 'k';
if(style.keepnext != format.keepnext)
qtf << 'K';
if(style.orphan != format.orphan)
qtf << 'Q';
if(style.linespacing != format.linespacing)
switch(format.linespacing) {
case RichPara::LSP15: qtf << "ph"; break;
case RichPara::LSP20: qtf << "pd"; break;
default: qtf << "po"; break;
}
if(style.bullet != format.bullet) {
qtf << 'O';
switch(format.bullet) {
case RichPara::BULLET_NONE: qtf << '_'; break;
case RichPara::BULLET_ROUNDWHITE: qtf << '1'; break;
case RichPara::BULLET_BOX: qtf << '2'; break;
case RichPara::BULLET_BOXWHITE: qtf << '3'; break;
case RichPara::BULLET_TEXT: qtf << '9'; break;
default: qtf << '0'; break;
}
qtf << ';';
}
if(!IsEmpty(format.label))
qtf << ':' << DeQtf(format.label) << ':';
if(NumberingDiffers(style, format)) {
if(format.before_number != style.before_number) {
qtf << "n";
qtf << DeQtf(format.before_number);
qtf << ';';
}
if(format.after_number != style.after_number) {
qtf << "m";
qtf << DeQtf(format.after_number);
qtf << ";";
}
int l;
for(l = 7; l >= 0; --l)
if(format.number[l])
break;
qtf << "N";
for(int i = 0; i <= l; i++) {
static char h[] = { '-', '1', '0', 'a', 'A', 'i', 'I' };
if(format.number[i] <= RichPara::NUMBER_I)
qtf << h[format.number[i]];
else
qtf << '-';
}
if(format.reset_number)
qtf << '!';
else
qtf << ';';
}
FmtNumber(qtf, 't', style.tabsize, format.tabsize);
if(style.tab != format.tab) {
qtf << "~~";
int i;
for(i = 0; i < format.tab.GetCount(); i++) {
RichPara::Tab tab = format.tab[i];
qtf << '~';
if(tab.align == ALIGN_RIGHT)
qtf << '>';
if(tab.align == ALIGN_CENTER)
qtf << '=';
if(tab.fillchar == 1)
qtf << '.';
if(tab.fillchar == 2)
qtf << '-';
if(tab.fillchar == 3)
qtf << '_';
qtf << tab.pos;
}
if(i)
qtf << ';';
}
}
bool s_nodeqtf[128];
void QTFEncodePara(String& qtf, const RichPara& p, const RichPara::Format& style, byte charset, dword lang, bool crlf)
{
int d = qtf.GetLength();
QTFEncodeParaFormat(qtf, p.format, style);
if(p.part.GetCount()) {
dword l = p.part.Top().format.language;
LngFmt(qtf, l, lang);
lang = l;
}
else {
CharFmt(qtf, style, p.format);
LngFmt(qtf, p.format.language, lang);
}
qtf.Cat(' ');
d = qtf.GetLength() - d;
for(int i = 0; i < p.part.GetCount(); i++) {
const RichPara::Part& part = p.part[i];
String cf;
LngFmt(cf, part.format.language, lang);
CharFmt(cf, style, part.format);
if(!cf.IsEmpty()) {
qtf << '[' << cf << ' ';
d += cf.GetLength();
}
if(part.field) {
if(crlf)
qtf << "\r\n";
qtf << "{:" + DeQtf(part.field.ToString()) + ":" + DeQtf(part.fieldparam) + ":}";
if(crlf)
qtf << "\r\n";
d = 0;
}
else
if(part.object) {
const RichObject& object = part.object;
Size sz = object.GetSize();
if(crlf)
qtf << "\r\n";
qtf << "@@" << object.GetTypeName() << ':' << sz.cx
<< (object.IsKeepRatio() ? '&' : '*') << sz.cy;
if(object.GetYDelta())
qtf << '/' << object.GetYDelta();
if(crlf)
qtf << "\r\n";
String data = object.Write();
const char *q = data.Begin();
const char *slim = data.End();
int n = 0;
qtf.Reserve(8 * data.GetLength() / 7);
while(q < slim - 7) {
byte data[8];
data[0] = ((q[0] & 0x80) >> 7) |
((q[1] & 0x80) >> 6) |
((q[2] & 0x80) >> 5) |
((q[3] & 0x80) >> 4) |
((q[4] & 0x80) >> 3) |
((q[5] & 0x80) >> 2) |
((q[6] & 0x80) >> 1) |
0x80;
data[1] = q[0] | 0x80;
data[2] = q[1] | 0x80;
data[3] = q[2] | 0x80;
data[4] = q[3] | 0x80;
data[5] = q[4] | 0x80;
data[6] = q[5] | 0x80;
data[7] = q[6] | 0x80;
qtf.Cat(data, 8);
if(crlf && ++n % 10 == 0)
qtf << "\r\n";
q += 7;
}
while(q < slim) {
byte seven = 0;
const char *lim = slim;
const char *s;
for(s = q; s < lim; s++)
seven = (seven >> 1) | (*s & 0x80);
seven >>= 8 - (lim - q);
qtf.Cat(seven | 0x80);
for(s = q; s < lim; s++)
qtf.Cat(*s | 0x80);
if(crlf && ++n % 10 == 0)
qtf << "\r\n";
q += 7;
}
if(crlf)
qtf << "\r\n";
d = 0;
}
else {
for(const wchar *s = part.text.Begin(); s != part.text.End(); s++) {
int c = *s;
if(c < 128) {
if(s_nodeqtf[c]) {
qtf.Cat(c);
d++;
}
else
if(c == 9) {
qtf.Cat("-|");
d++;
}
else
if(c == ':' && s[1] != ':')
qtf.Cat(':');
else {
qtf.Cat('`');
qtf.Cat(c);
d += 2;
}
if(crlf && d > 60 && c == ' ') {
qtf.Cat("\r\n");
d = 0;
}
}
else {
if(c == 160) {
qtf.Cat("_");
d++;
}
else
if(charset == CHARSET_UTF8) {
String q = ToUtf8(c);
d += q.GetLength();
qtf << q;
}
else {
int ch = FromUnicode(c, charset, 0);
if(ch)
qtf << (char)ch;
else
qtf << "@$" << Format("%04X", ch) << ';';
d++;
}
}
if(crlf && d > 80) {
qtf.Cat("\r\n");
d = 0;
}
}
}
if(!cf.IsEmpty()) {
d++;
qtf << ']';
}
}
}
void FmtNumber2(String& qtf, char c, int da, int a, int db, int b)
{
if(da != a || db != b) {
qtf << c;
if(da != a)
qtf << a;
qtf << '/';
qtf << b;
}
}
void QTFEncodeTxt(String& qtf, const RichTxt& text, const RichStyles& styles, const RichStyle& defstyle,
dword options, const Index<Uuid>& sm, byte charset, dword lang)
{
qtf << '[';
for(int i = 0; i < text.GetPartCount(); i++) {
if(i) {
qtf << "&]";
if(options & QTF_CRLF)
qtf << "\r\n";
qtf << '[';
}
if(text.IsTable(i)) {
qtf << ' ';
const RichTable& t = text.GetTable(i);
int nx = t.format.column.GetCount();
int ny = t.cell.GetCount();
qtf << "{{";
for(int i = 0; i < nx; i++) {
if(i)
qtf << ':';
qtf << t.format.column[i];
}
const RichTable::Format& f = t.format;
const RichTable::Format& d = Single<RichTable::Format>();
FmtNumber(qtf, '<', d.lm, f.lm);
FmtNumber(qtf, '>', d.rm, f.rm);
FmtNumber(qtf, 'B', d.before, f.before);
FmtNumber(qtf, 'A', d.after, f.after);
FmtNumber(qtf, 'f', d.frame, f.frame);
if(f.keep)
qtf << "K";
if(f.framecolor != d.framecolor)
qtf << 'F' << FmtColor(f.framecolor);
FmtNumber(qtf, 'g', d.grid, f.grid);
if(f.gridcolor != d.gridcolor)
qtf << 'G' << FmtColor(f.gridcolor);
FmtNumber(qtf, 'h', d.header, f.header);
RichCell::Format cf = Single<RichCell::Format>();
for(int i = 0; i < ny; i++) {
const Array<RichCell>& r = t.cell[i];
for(int j = 0; j < r.GetCount(); j++) {
const RichCell& c = r[j];
if(i || j) {
if(options & QTF_CRLF)
qtf << "\r\n";
qtf << "::";
}
const RichCell::Format& f = c.format;
if(f.align != cf.align)
switch(f.align) {
case ALIGN_TOP: qtf << '^'; break;
case ALIGN_CENTER: qtf << '='; break;
case ALIGN_BOTTOM: qtf << 'v'; break;
}
FmtNumber2(qtf, 'l', cf.border.left, f.border.left, cf.margin.left, f.margin.left);
FmtNumber2(qtf, 'r', cf.border.right, f.border.right, cf.margin.right, f.margin.right);
FmtNumber2(qtf, 't', cf.border.top, f.border.top, cf.margin.top, f.margin.top);
FmtNumber2(qtf, 'b', cf.border.bottom, f.border.bottom, cf.margin.bottom, f.margin.bottom);
FmtNumber(qtf, 'H', cf.minheight, f.minheight);
if(f.color != cf.color)
qtf << '@' << FmtColor(f.color);
if(f.bordercolor != cf.bordercolor)
qtf << 'R' << FmtColor(f.bordercolor);
cf = f;
if(c.hspan)
qtf << '-' << c.hspan;
if(c.vspan)
qtf << '|' << c.vspan;
if(f.keep)
qtf << "k";
qtf << ' ';
QTFEncodeTxt(qtf, c.text, styles, defstyle, options, sm, charset, lang);
}
}
qtf << "}}";
}
else {
RichPara p = text.Get(i, styles);
int si = sm.Find(text.GetParaStyle(i));
if(!(options & QTF_NOSTYLES))
qtf << "s" << si;
SeparateNumber(qtf);
const RichStyle& s = si < 0 ? defstyle : GetStyle(styles, sm[si]);
QTFEncodePara(qtf, p, options & QTF_NOSTYLES ? defstyle.format : s.format, charset, lang,
(options & QTF_CRLF));
}
}
qtf << ']';
}
void init_s_nodeqtf()
{
ONCELOCK {
for(int c = 1; c < 128; c++)
s_nodeqtf[c] = IsAlNum(c) || strchr(".,;!?%()/<># ", c);
}
}
String AsQTF(const RichText& text, byte charset, dword options)
{
int i;
String qtf;
init_s_nodeqtf();
RichPara::Format dpf;
dpf.Face(Font::ARIAL);
dpf.Height(100);
dpf.language = LNG_ENGLISH;
bool crlf = options & QTF_CRLF;
Index<Uuid> sm;
// if(options & QTF_ALL_STYLES) //!!!! problem -> GetUsedStyles!!!!
for(i = 0; i < text.GetStyleCount(); i++)
sm.FindAdd(text.GetStyleId(i));
// else
// for(i = 0; i < text.GetPartCount(); i++)
// sm.FindAdd(text.GetParaStyle(i));
if(!(options & QTF_NOSTYLES))
for(i = 0; i < sm.GetCount(); i++) {
Uuid id = sm[i];
const RichStyle& s = text.GetStyle(id);
qtf << '[';
QTFEncodeParaFormat(qtf, s.format, dpf);
CharFmt(qtf, dpf, s.format);
qtf << ' ';
qtf << "$$" << i << ',' << max(sm.Find(s.next), 0)
<< '#' << Format(id)
<< ':' << DeQtf(s.name) << "]";
if(crlf)
qtf << "\r\n";
}
if(text.GetPartCount() && (options & QTF_BODY)) {
VectorMap<dword, int> lngc;
int m = min(text.GetPartCount(), 30);
for(int i = 0; i < m; i++)
if(text.IsPara(i)) {
RichPara p = text.Get(i);
lngc.GetAdd(p.format.language, 0)++;
}
dword lang = lngc.GetCount() ? lngc.GetKey(MaxIndex(lngc.GetValues())) : 0;
qtf << "[";
if(!(options & QTF_NOCHARSET)) {
qtf << "{";
if(charset == CHARSET_UTF8)
qtf << "_";
else
if(charset >= CHARSET_WIN1250 && charset <= CHARSET_WIN1258)
qtf << (char)('0' + charset - CHARSET_WIN1250);
else
if(charset >= CHARSET_ISO8859_1 && charset <= CHARSET_ISO8859_16)
qtf << (char)('A' + charset - CHARSET_ISO8859_1);
else
qtf << CharsetName(charset);
qtf << "}";
}
if(lang && !(options & QTF_NOLANG))
qtf << "%" << LNGAsText(SetLNGCharset(lang, CHARSET_DEFAULT));
qtf << " ";
if(crlf)
qtf << "\r\n";
RichStyle defstyle;
defstyle.format.Height(100);
QTFEncodeTxt(qtf, text, text.GetStyles(), defstyle, options, sm, charset, lang);
}
return qtf;
}
String DeQtf(const char *s) {
String r;
r.Reserve(256);
while(*s) {
if((byte)*s > ' ' && !IsDigit(*s) && !IsAlpha(*s) && (byte)*s < 128)
r.Cat('`');
r.Cat(*s++);
}
return r;
}
String DeQtfLf(const char *s) {
String r;
r.Reserve(256);
while(*s) {
if((byte)*s > ' ' && !IsDigit(*s) && !IsAlpha(*s) && (byte)*s < 128)
r.Cat('`');
if((byte)*s >= ' ')
r.Cat(*s);
else
if(*s == '\n')
r.Cat('&');
s++;
}
return r;
}
String AsQTF(const RichObject& obj)
{
RichText x;
RichPara p;
RichPara::Format fmt;
p.Cat(obj, fmt);
x.Cat(p);
return AsQTF(x);
}
END_UPP_NAMESPACE

View file

@ -0,0 +1,658 @@
#include "RichText.h"
#include <plugin/png/png.h>
NAMESPACE_UPP
static int GetParaHeight(const Array<RichPara::Part>& parts)
{
int ht = 0;
for(int i = 0; i < parts.GetCount(); i++) {
int pht = 0;
const RichPara::Part& part = parts[i];
if(part.object)
pht = part.object.GetSize().cy;
else if(part.field)
pht = GetParaHeight(part.fieldpart);
else
pht = tabs(part.format.GetHeight());
if(pht > ht)
ht = pht;
}
return ht;
}
class RTFEncoder {
public:
RTFEncoder(Stream& stream, const RichText& richtext, byte charset);
void Run();
private:
void FacesAddFormat(const RichPara::CharFormat& format);
void GetFaces();
void GetTxtFaces(const RichTxt& txt);
void PutHeader();
void PutDocument();
void PutTxt(const RichTxt& txt, int nesting, int dot_width);
void PutTable(const RichTable& table, int nesting, int dot_width);
void PutParts(const Array<RichPara::Part>& parts,
RichPara::CharFormat& base, int bpart, int boff, int epart, int eoff);
void Begin() { stream.Put('{'); }
void Begin(const char *cmd) { Begin(); Command(cmd); }
void Begin(const char *cmd, int param) { Begin(); Command(cmd, param); }
void End() { stream.Put('}'); }
void Command(const char *cmd);
void Command(const char *cmd, int param);
void Space() { stream.Put(' '); }
void PutText(const char *text);
void PutObject(const RichObject& object);
void PutTabs(const Vector<RichPara::Tab>& tabs);
void PutBinHex(const byte *data, int count);
void PutBinHex(const String& s) { PutBinHex(s, s.GetLength()); }
bool PutParaFormat(const RichPara::Format& pf, const RichPara::Format& difpf);
bool PutCharFormat(const RichPara::CharFormat& cf, const RichPara::CharFormat& difcf, bool pn);
struct Group;
friend struct Group;
struct Group {
Group(RTFEncoder *owner) : owner(owner) { owner->Begin(); }
Group(RTFEncoder *owner, const char *cmd) : owner(owner) { owner->Begin(cmd); }
Group(RTFEncoder *owner, const char *cmd, int param) : owner(owner) { owner->Begin(cmd, param); }
~Group() { owner->End(); }
RTFEncoder *owner;
};
private:
Stream& stream;
const RichText& richtext;
byte charset;
RichPara::CharFormat charfmt;
RichPara::Format parafmt;
Uuid oldstyle;
int old_ht;
int para_ht;
Index<int> used_faces;
enum { SYMBOL_INDEX = 1, WINGDINGS_INDEX = 2 };
VectorMap<Color, int> used_ink, used_paper;
Index<Color> phys_colors;
Index<Uuid> styleid;
};
void EncodeRTF(Stream& stream, const RichText& richtext, byte charset)
{
RTFEncoder(stream, richtext, charset).Run();
}
String EncodeRTF(const RichText& richtext, byte charset)
{
StringStream out;
EncodeRTF(out, richtext, charset);
String s = out.GetResult();
LOG("EncodeRTF <<<<<\n" << s << "\n>>>>> EncodeRTF");
return s;
}
String EncodeRTF(const RichText& richtext)
{
return EncodeRTF(richtext, GetDefaultCharset() == CHARSET_UTF8 ? GetLNGCharset(GetSystemLNG())
: GetDefaultCharset());
}
RTFEncoder::RTFEncoder(Stream& stream, const RichText& richtext, byte charset)
: stream(stream)
, richtext(richtext)
, charset(charset)
{
for(int i = 0; i < richtext.GetStyleCount(); i++)
styleid.Add(richtext.GetStyleId(i));
}
void RTFEncoder::Run()
{
GetFaces();
Group docgrp(this, "rtf");
PutHeader();
PutDocument();
}
void RTFEncoder::FacesAddFormat(const RichPara::CharFormat& format)
{
used_faces.FindAdd(format.GetFace());
if(used_ink.Find(format.ink) < 0) {
Color i(format.ink.GetR(), format.ink.GetG(), format.ink.GetB());
int x = used_ink.Get(i, -1);
if(x < 0)
x = phys_colors.FindAdd(i);
used_ink.Add(format.ink, x);
}
if(used_paper.Find(format.paper) < 0) {
Color p(format.paper.GetR(), format.paper.GetG(), format.paper.GetB());
int x = used_paper.Get(p, -1);
if(x < 0)
x = phys_colors.FindAdd(p);
used_paper.Add(format.paper, x);
}
}
void RTFEncoder::GetFaces()
{
used_faces.Add(Font::ARIAL); // default font
used_faces.Add(Font::SYMBOL); // used for bullets
#ifdef PLATFORM_WIN32
used_faces.Add(Font::WINGDINGS); // used for bullets
#endif
phys_colors.Add(Null);
used_ink.Add(Null, 0);
used_paper.Add(Null, 0);
used_ink.Add(Black(), 0);
used_paper.Add(White(), 0);
GetTxtFaces(richtext);
for(int i = 0; i < richtext.GetStyleCount(); i++)
FacesAddFormat(richtext.GetStyle(i).format);
}
void RTFEncoder::GetTxtFaces(const RichTxt& rt)
{
for(int i = 0; i < rt.GetPartCount(); i++) {
if(rt.IsTable(i)) {
const RichTable& table = rt.GetTable(i);
const RichTable::Format& tfmt = table.GetFormat();
phys_colors.FindAdd(tfmt.framecolor);
phys_colors.FindAdd(tfmt.gridcolor);
for(int r = 0; r < table.GetRows(); r++)
for(int c = 0; c < table.GetColumns(); c++) {
const RichCell& cell = table.cell[r][c];
phys_colors.FindAdd(cell.format.color);
phys_colors.FindAdd(cell.format.bordercolor);
GetTxtFaces(cell.text);
}
}
else {
const RichPara& para = rt.Get(i, richtext.GetStyles());
FacesAddFormat(para.format);
for(int p = 0; p < para.part.GetCount(); p++) {
const RichPara::Part& part = para.part[p];
if(part.IsText())
FacesAddFormat(part.format);
}
}
}
}
void RTFEncoder::Command(const char *cmd)
{
stream.Put('\\');
stream.Put(cmd);
}
void RTFEncoder::Command(const char *cmd, int param)
{
stream.Put('\\');
stream.Put(cmd);
stream.Put(IntStr(param));
}
void RTFEncoder::PutText(const char *text)
{
while(*text) {
if(*text == '{' || *text == '}' || *text == '\\')
stream.Put('\\');
stream.Put(*text++);
}
}
void RTFEncoder::PutBinHex(const byte *b, int count)
{
enum { BLOCK = 32 };
for(int l = count; l > 0; l -= BLOCK) {
stream.PutCrLf();
for(const byte *e = b + min<int>(l, BLOCK); b < e; b++) {
static const char binhex[] = "0123456789abcdef";
stream.Put(binhex[*b >> 4]);
stream.Put(binhex[*b & 15]);
}
}
}
bool RTFEncoder::PutCharFormat(const RichPara::CharFormat& cf, const RichPara::CharFormat& difcf, bool pn)
{
int64 pos = stream.GetPos();
int pn2 = (pn ? 0 : 2);
bool f;
int t;
if(cf.GetFace() != difcf.GetFace())
Command("pnf" + pn2, used_faces.Find(cf.GetFace()));
if((t = DotPoints(2 * tabs(cf.GetHeight()))) != DotPoints(2 * tabs(difcf.GetHeight())))
Command("pnfs" + pn2, t);
if(!pn && dword(t = cf.sscript) != difcf.sscript)
Command(t == 0 ? "nosupersub" : t == 1 ? "super" : "sub");
if((f = cf.IsBold()) != difcf.IsBold()) Command((f ? "pnb" : "pnb0") + pn2);
if((f = cf.IsItalic()) != difcf.IsItalic()) Command((f ? "pni" : "pni0") + pn2);
if((f = cf.IsUnderline()) != difcf.IsUnderline()) Command((f ? "pnul" : "pnul0") + pn2);
if((f = cf.IsStrikeout()) != difcf.IsStrikeout()) Command((f ? "pnstrike" : "pnstrike0") + pn2);
if((f = cf.capitals) != difcf.capitals) Command((f ? "pncaps" : "pncaps0") + pn2);
if((t = used_ink.Get(cf.ink)) != used_ink.Get(difcf.ink)) Command("pncf" + pn2, t);
if((t = used_paper.Get(cf.paper)) != used_paper.Get(difcf.paper)) Command("pncb" + pn2, t);
#ifdef PLATFORM_WIN32 //zapoznamkoval Fidler kdyz chtel zkompilovat pod Linuxem...
if(!pn && cf.language != difcf.language) Command("lang", GetLanguageLCID(cf.language));
#endif
// todo: link
return stream.GetPos() != pos;
}
void RTFEncoder::PutObject(const RichObject& object)
{
#ifdef PLATFORM_WIN32
#ifndef PLATFORM_WINCE
Size log_size = object.GetPixelSize(), out_size = object.GetSize();
if(log_size.cx <= 0 || log_size.cy <= 0) log_size = out_size;
// Size scale = out_size * 100 / log_size;
Group pict_grp(this, "pict");
Command("picw", log_size.cx);
Command("pich", log_size.cy);
Command("picwgoal", DotTwips(out_size.cx));
Command("pichgoal", DotTwips(out_size.cy));
// Command("picscalex", scale.cx);
// Command("picscaley", scale.cy);
if(object.GetTypeName() == "PING") {
Command("pngblip");
PutBinHex(object.GetData());
}
else {
Command("wmetafile", 8);
WinMetaFileDraw wmd(log_size.cx, log_size.cy);
object.Paint(wmd, log_size);
WinMetaFile wmf = wmd.Close();
HENHMETAFILE hemf = wmf.GetHEMF();
int size = GetWinMetaFileBits(hemf, 0, 0, MM_ANISOTROPIC, ScreenHDC());
if(size > 0) {
Buffer<byte> buffer(size);
GetWinMetaFileBits(hemf, size, buffer, MM_ANISOTROPIC, ScreenHDC());
PutBinHex(buffer, size);
}
}
#endif
#endif
}
bool RTFEncoder::PutParaFormat(const RichPara::Format& pf, const RichPara::Format& difpf)
{
int64 pos = stream.GetPos();
if(pf.align != difpf.align)
switch(pf.align) {
case ALIGN_NULL:
case ALIGN_LEFT: Command("ql"); break;
case ALIGN_CENTER: Command("qc"); break;
case ALIGN_RIGHT: Command("qr"); break;
case ALIGN_JUSTIFY: Command("qj"); break;
default: NEVER();
}
int oind = difpf.indent, olm = difpf.lm;
if(difpf.bullet != RichPara::BULLET_NONE) {
olm += oind;
oind = -oind;
}
int nind = pf.indent, nlm = pf.lm;
if(pf.bullet != RichPara::BULLET_NONE) {
nlm += nind;
nind = -nind;
}
if(nind != oind) Command("fi", DotTwips(nind));
if(nlm != olm) Command("li", DotTwips(nlm));
if(pf.rm != difpf.rm) Command("ri", DotTwips(pf.rm));
if(pf.newpage)
Command("pagebb");
if(pf.before != difpf.before) Command("sb", DotTwips(pf.before));
if(pf.after != difpf.after) Command("sa", DotTwips(pf.after));
if(pf.tab != difpf.tab) PutTabs(pf.tab);
return stream.GetPos() != pos;
}
void RTFEncoder::PutTabs(const Vector<RichPara::Tab>& tabs)
{
for(int i = 0; i < tabs.GetCount(); i++) {
RichPara::Tab t = tabs[i];
switch(t.align) {
case ALIGN_NULL:
case ALIGN_LEFT: break;
case ALIGN_CENTER: Command("tqc"); break;
case ALIGN_RIGHT: Command("tqr"); break;
default: NEVER();
}
switch(t.fillchar) {
case 0: break;
case 1: Command("tldot"); break;
case 2: Command("tlhyph"); break;
case 3: Command("tlul"); break;
default: NEVER();
}
Command("tx", DotTwips(t.pos));
}
}
void RTFEncoder::PutParts(const Array<RichPara::Part>& parts,
RichPara::CharFormat& base, int bpart, int boff, int epart, int eoff)
{
if(epart >= parts.GetCount()) {
epart = parts.GetCount() - 1;
eoff = INT_MAX;
}
ASSERT(boff >= 0 && bpart >= 0);
for(int p = bpart; p <= epart; p++) {
const RichPara::Part& part = parts[p];
if(part.IsText()) {
WString px = part.text;
if(p == epart && px.GetLength() > eoff)
px.Trim(eoff);
if(p == bpart)
px.Remove(0, boff);
if(!px.IsEmpty()) {
if(PutCharFormat(part.format, base, false) || p == 0)
Space();
base = part.format;
PutText(FromUnicode(px, charset));
}
}
else if(part.object)
PutObject(part.object);
}
}
void RTFEncoder::PutHeader()
{
static const short ansicpg[][2] = {
{ CHARSET_WIN1250, 1250 },
{ CHARSET_WIN1251, 1251 },
{ CHARSET_WIN1252, 1252 },
{ CHARSET_WIN1253, 1253 },
{ CHARSET_WIN1254, 1254 },
{ CHARSET_WIN1255, 1255 },
{ CHARSET_WIN1256, 1256 },
{ CHARSET_WIN1257, 1257 },
{ CHARSET_WIN1258, 1258 },
};
int i;
for(i = __countof(ansicpg); --i >= 0;)
if(charset == ansicpg[i][0]) {
Command("ansicpg", ansicpg[i][1]);
break;
}
Command("deff", 0);
{
Group ftbl(this, "fonttbl");
for(int i = 0; i < used_faces.GetCount(); i++) {
Group fnt(this, "f", i);
int fn = used_faces[i];
dword info = Font::GetFaceInfo(fn);
if(info & Font::SYMBOLTYPE)
Command("ftech");
else if(info & Font::FIXEDPITCH)
Command("fmodern");
else if(fn == Font::ROMAN)
Command("froman");
else if(fn == Font::ARIAL
#ifdef PLATFORM_WIN32
|| fn == Font::TAHOMA
#endif
)
Command("fswiss");
Space();
stream.Put(Font::GetFaceName(fn));
stream.Put(';');
}
}
if(phys_colors.GetCount() > 1) {
Group ctbl(this, "colortbl");
stream.Put(';');
for(int i = 1; i < phys_colors.GetCount(); i++) {
Color rgb = phys_colors[i];
Command("red", rgb.GetR());
Command("green", rgb.GetG());
Command("blue", rgb.GetB());
stream.Put(';');
}
}
Begin("stylesheet");
RichPara::CharFormat empcfmt;
RichPara::Format emppfmt;
for(i = 0; i < richtext.GetStyleCount(); i++) {
const RichStyle& style = richtext.GetStyle(i);
Begin("s", i);
PutParaFormat(style.format, emppfmt);
PutCharFormat(style.format, empcfmt, false);
Command("sbasedon", 222);
if(style.next != richtext.GetStyleId(i))
Command("snext", styleid.Find(style.next));
Space();
for(const char *n = style.name; *n; n++)
stream.Put(*n == ';' ? '_' : *n);
stream.Put(';');
End();
}
End();
}
void RTFEncoder::PutTable(const RichTable& table, int nesting, int dot_width)
{
Vector<int> vspan_counts;
const RichTable::Format& tfmt = table.GetFormat();
Vector<int> column_pos;
column_pos.SetCount(tfmt.column.GetCount() + 1);
column_pos[0] = tfmt.lm;
int sum = 0;
for(int c = 0; c < tfmt.column.GetCount(); c++)
sum += tfmt.column[c];
int rem_width = dot_width - tfmt.lm - tfmt.rm;
for(int c = 0; c < tfmt.column.GetCount(); c++) {
int part = iscale(tfmt.column[c], rem_width, max(sum, 1));
sum -= tfmt.column[c];
rem_width -= part;
column_pos[c + 1] = column_pos[c] + part;
}
for(int r = 0; r < table.GetRows(); r++) {
String rowfmt;
if(nesting)
rowfmt << "\\*\\nesttableprops";
rowfmt << "\\trowd"
"\\trleft" << DotTwips(tfmt.lm)
// trbrdr[ltrbv]
;
Vector<int> cellindex;
Rect dflt_margin(600, 600, 600, 600);
for(int c = 0; c < table.GetColumns(); c++) {
const RichCell& cell = table.cell[r][c];
dflt_margin.left = min(dflt_margin.left, cell.format.margin.left);
dflt_margin.top = min(dflt_margin.top, cell.format.margin.top);
dflt_margin.right = min(dflt_margin.right, cell.format.margin.right);
dflt_margin.bottom = min(dflt_margin.bottom, cell.format.margin.bottom);
c += cell.hspan;
}
/*
rowfmt <<
"\\trpaddl" << DotTwips(dflt_margin.left) << "\\trpaddfl3"
"\\trpaddt" << DotTwips(dflt_margin.top) << "\\trpaddft3"
"\\trpaddr" << DotTwips(dflt_margin.right) << "\\trpaddfr3"
"\\trpaddb" << DotTwips(dflt_margin.bottom) << "\\trpaddfb3";
*/
for(int c = 0; c < table.GetColumns(); c++) {
const RichCell& cell = table.cell[r][c];
/*
if(cell.format.margin.left != dflt_margin.left)
rowfmt << "\\clpadl" << DotTwips(cell.format.margin.left) << "\\clpadfl3";
if(cell.format.margin.top != dflt_margin.top)
rowfmt << "\\clpadt" << DotTwips(cell.format.margin.top) << "\\clpadft3";
if(cell.format.margin.right != dflt_margin.right)
rowfmt << "\\clpadr" << DotTwips(cell.format.margin.right) << "\\clpadfr3";
if(cell.format.margin.bottom != dflt_margin.bottom)
rowfmt << "\\clpadb" << DotTwips(cell.format.margin.bottom) << "\\clpadfb3";
*/
switch(cell.format.align) {
case ALIGN_TOP: rowfmt << "\\clvertalt"; break;
default:
case ALIGN_CENTER: rowfmt << "\\clvertalc"; break;
case ALIGN_BOTTOM: rowfmt << "\\clvertalb"; break;
}
cellindex.Add(c);
if(cell.hspan)
c += cell.hspan;
int cell_end = column_pos[c + 1];
if(cell.vspan) {
vspan_counts.At(c, 0) = cell.vspan;
rowfmt << "\\clvmgf";
}
else if(c < vspan_counts.GetCount() && vspan_counts[c] > 0)
rowfmt << "\\clvmrg";
if(!IsNull(cell.format.color))
rowfmt << "\\clcbpat" << phys_colors.Find(cell.format.color);
rowfmt << "\\cellx" << DotTwips(cell_end);
}
Begin();
Command("pard");
Command("intbl");
parafmt = RichPara::Format();
charfmt = RichPara::CharFormat();
if(nesting)
Command("itap", nesting + 1);
if(!nesting)
stream.Put(rowfmt);
for(int c = 0; c < cellindex.GetCount(); c++) {
int cx = cellindex[c];
const RichCell& cell = table.cell[r][cx];
int cell_wd = column_pos[cx + cell.hspan + 1] - column_pos[cx];
PutTxt(cell.text, nesting + 1, cell_wd);
Command(nesting ? "nestcell" : "cell");
}
stream.Put(rowfmt);
Command(nesting ? "nestrow" : "row");
End();
}
}
void RTFEncoder::PutTxt(const RichTxt& txt, int nesting, int dot_width)
{
for(int i = 0; i < txt.GetPartCount(); i++) {
if(txt.IsTable(i))
PutTable(txt.GetTable(i), nesting, dot_width);
else {
const RichPara& para = txt.Get(i, richtext.GetStyles());
Uuid pstyle = txt.GetParaStyle(i);
int para_ht = GetParaHeight(para.part);
int first_part = 0, first_ind = 0;
bool hdiff = (para.format.bullet != RichPara::BULLET_NONE
&& para.format.bullet != RichPara::BULLET_TEXT && para_ht != para_ht);
if(pstyle != oldstyle
|| para.format.bullet != parafmt.bullet || para.format.bullet == RichPara::BULLET_TEXT
|| hdiff || para.format.tab != parafmt.tab || para.format.newpage || parafmt.newpage) {
Command("s", styleid.Find(pstyle));
oldstyle = pstyle;
parafmt = richtext.GetStyle(pstyle).format;
Command("pard");
if(nesting)
Command("intbl");
if(nesting > 1)
Command("itap", nesting);
parafmt = RichPara::Format();
para_ht = 0;
}
if(para.format.bullet == RichPara::BULLET_TEXT) {
int epart = 0, eoff = 0;
while(epart < para.part.GetCount() && (eoff = para.part[epart].text.Find('\t')) < 0)
epart++;
RichPara::CharFormat rcf = charfmt;
rcf.Height(0);
Begin("pntext");
PutParts(para.part, rcf, 0, 0, epart, eoff);
stream.Put('\t');
End();
Begin("*\\pn");
Command("pnhang");
Command("pnql");
rcf = charfmt;
if(epart > 0 || eoff > 0)
PutCharFormat(para.part[0].format, rcf, true);
Begin("pntxta");
End();
Begin("pntxtb");
Space();
PutParts(para.part, rcf, 0, 0, epart, eoff);
stream.Put('\t');
End();
End();
}
else if(para.format.bullet != RichPara::BULLET_NONE) {
int sym_face = SYMBOL_INDEX;
byte sym_char = 0xB7;
switch(para.format.bullet) {
default:
NEVER();
case RichPara::BULLET_ROUND: sym_face = SYMBOL_INDEX; sym_char = 0xB7; break;
case RichPara::BULLET_ROUNDWHITE: sym_face = WINGDINGS_INDEX; sym_char = 0xA1; break;
case RichPara::BULLET_BOX: sym_face = WINGDINGS_INDEX; sym_char = 'n'; break;
case RichPara::BULLET_BOXWHITE: sym_face = WINGDINGS_INDEX; sym_char = 'o'; break;
}
Begin("pntext");
// Command("tqr");
// Command("tx", DotTwips(para.format.indent));
// Command("qr");
Command("f", sym_face);
Command("fs", DotPoints(2 * para_ht));
Space();
stream.Put(sym_char);
stream.Put('\t');
End();
Begin("*\\pn");
Command("pnlvlblt");
Command("pnf", sym_face);
Command("pnfs", DotPoints(2 * para_ht));
Command("pnql");
Begin("pntxtb");
Space();
stream.Put(sym_char);
// stream.Put('\t');
End();
Begin("pntxta");
End();
End();
}
PutParaFormat(para.format, parafmt);
para_ht = para_ht;
parafmt = para.format;
PutParts(para.part, charfmt, first_part, first_ind, para.part.GetCount(), 0);
if(i + 1 < txt.GetPartCount())
Command("par");
}
}
}
void RTFEncoder::PutDocument()
{
charfmt.Height(PointDots(0));
charfmt.language = 0;
old_ht = DotPoints(2 * tabs(charfmt.GetHeight()));
para_ht = 0;
oldstyle = Uuid::Create();
PutTxt(richtext, 0, 3600);
}
END_UPP_NAMESPACE

212
uppdev/RichTextP/Format.cpp Normal file
View file

@ -0,0 +1,212 @@
#include "RichText.h"
NAMESPACE_UPP
void RichTxt::FormatInfo::Set(const RichPara::Format& fmt)
{
(RichPara::Format&)*this = fmt;
charvalid = paravalid = 0xffffffff;
}
void RichTxt::FormatInfo::Set(const RichPara::CharFormat& fmt)
{
(RichPara::CharFormat&)*this = fmt;
charvalid = 0xffffffff;
}
void RichTxt::FormatInfo::Combine(const RichPara::CharFormat& fmt)
{
if(IsBold() != fmt.IsBold()) {
charvalid &= ~BOLD;
NoBold();
}
if(IsItalic() != fmt.IsItalic()) {
charvalid &= ~ITALIC;
NoItalic();
}
if(IsUnderline() != fmt.IsUnderline()) {
charvalid &= ~UNDERLINE;
NoUnderline();
}
if(IsStrikeout() != fmt.IsStrikeout()) {
charvalid &= ~STRIKEOUT;
NoStrikeout();
}
if(IsNonAntiAliased() != fmt.IsNonAntiAliased()) {
charvalid &= ~NOAA;
NoNonAntiAliased();
}
if(capitals != fmt.capitals) {
charvalid &= ~CAPITALS;
capitals = false;
}
if(dashed != fmt.dashed) {
charvalid &= ~DASHED;
dashed = false;
}
if(sscript != fmt.sscript) {
charvalid &= ~SSCRIPT;
sscript = 0;
}
if(GetFace() != fmt.GetFace())
charvalid &= ~FACE;
if(GetHeight() != fmt.GetHeight())
charvalid &= ~HEIGHT;
if(ink != fmt.ink) {
charvalid &= ~INK;
ink = Null;
}
if(paper != fmt.paper) {
charvalid &= ~PAPER;
paper = Null;
}
if(language != fmt.language) {
charvalid &= ~LANG;
language = 0;
}
if(link != fmt.link) {
charvalid &= ~LINK;
link = Null;
}
if(indexentry != fmt.indexentry) {
charvalid &= ~INDEXENTRY;
indexentry = Null;
}
}
void RichTxt::FormatInfo::Combine(const RichPara::Format& fmt)
{
if(align != fmt.align)
paravalid &= ~ALIGN;
if(before != fmt.before)
paravalid &= ~BEFORE;
if(lm != fmt.lm)
paravalid &= ~LM;
if(indent != fmt.indent)
paravalid &= ~INDENT;
if(rm != fmt.rm)
paravalid &= ~RM;
if(after != fmt.after)
paravalid &= ~AFTER;
if(tabsize != fmt.tabsize)
paravalid &= ~TABSIZE;
if(bullet != fmt.bullet)
paravalid &= ~BULLET;
if(newpage != fmt.newpage)
paravalid &= ~NEWPAGE;
if(keep != fmt.keep)
paravalid &= ~KEEP;
if(keepnext != fmt.keepnext)
paravalid &= ~KEEPNEXT;
if(orphan != fmt.orphan)
paravalid &= ~ORPHAN;
if(label != fmt.label)
paravalid &= ~LABEL;
if(NumberingDiffers(*this, fmt))
paravalid &= ~NUMBERING;
if(tab.GetCount() != fmt.tab.GetCount()) {
paravalid &= ~TABS;
tab.Clear();
}
else
for(int i = 0; i < tab.GetCount(); i++)
if(tab[i].pos != fmt.tab[i].pos || tab[i].align != fmt.tab[i].align ||
tab[i].fillchar != fmt.tab[i].fillchar) {
paravalid &= ~TABS;
tab.Clear();
break;
}
if(styleid != fmt.styleid)
paravalid &= ~STYLE;
if(linespacing != fmt.linespacing)
paravalid &= ~SPACING;
if(ruler != fmt.ruler)
paravalid &= ~RULER;
if(rulerink != fmt.rulerink)
paravalid &= ~RULERINK;
}
void RichTxt::FormatInfo::ApplyTo(RichPara::CharFormat& fmt) const
{
if(charvalid & BOLD)
fmt.Bold(IsBold());
if(charvalid & ITALIC)
fmt.Italic(IsItalic());
if(charvalid & UNDERLINE)
fmt.Underline(IsUnderline());
if(charvalid & STRIKEOUT)
fmt.Strikeout(IsStrikeout());
if(charvalid & NOAA)
fmt.NonAntiAliased(IsNonAntiAliased());
if(charvalid & CAPITALS)
fmt.capitals = capitals;
if(charvalid & DASHED)
fmt.dashed = dashed;
if(charvalid & SSCRIPT)
fmt.sscript = sscript;
if(charvalid & FACE)
fmt.Face(GetFace());
if(charvalid & HEIGHT)
fmt.Height(GetHeight());
if(charvalid & LANGUAGE)
fmt.language = language;
if(charvalid & INK)
fmt.ink = ink;
if(charvalid & PAPER)
fmt.paper = paper;
if(charvalid & LANG)
fmt.language = language;
if(charvalid & LINK)
fmt.link = link;
if(charvalid & INDEXENTRY)
fmt.indexentry = indexentry;
}
void RichTxt::FormatInfo::ApplyTo(RichPara::Format& fmt) const
{
ApplyTo((RichPara::CharFormat &)fmt);
if(paravalid & ALIGN)
fmt.align = align;
if(paravalid & RULER)
fmt.ruler = ruler;
if(paravalid & BEFORE)
fmt.before = before;
if(paravalid & LM)
fmt.lm = lm;
if(paravalid & INDENT)
fmt.indent = indent;
if(paravalid & RM)
fmt.rm = rm;
if(paravalid & AFTER)
fmt.after = after;
if(paravalid & TABSIZE)
fmt.tabsize = tabsize;
if(paravalid & BULLET)
fmt.bullet = bullet;
if(paravalid & NEWPAGE)
fmt.newpage = newpage;
if(paravalid & KEEP)
fmt.keep = keep;
if(paravalid & KEEPNEXT)
fmt.keepnext = keepnext;
if(paravalid & ORPHAN)
fmt.orphan = orphan;
if(paravalid & LABEL)
fmt.label = label;
if(paravalid & NUMBERING) {
fmt.before_number = before_number;
fmt.after_number = after_number;
fmt.reset_number = reset_number;
memcpy(fmt.number, number, sizeof(number));
}
// if(paravalid & TABS)
// fmt.tab = tab;
if(paravalid & STYLE)
fmt.styleid = styleid;
if(paravalid & SPACING)
fmt.linespacing = linespacing;
if(paravalid & RULERINK)
fmt.rulerink = rulerink;
}
END_UPP_NAMESPACE

401
uppdev/RichTextP/Object.cpp Normal file
View file

@ -0,0 +1,401 @@
#include "RichText.h"
NAMESPACE_UPP
RichObjectType::RichObjectType() {}
RichObjectType::~RichObjectType() {}
String RichObjectType::GetCreateName() const
{
return Null;
}
Size RichObjectType::GetDefaultSize(const Value& data, Size maxsize) const
{
if(IsNull(data)) return Size(0, 0);
Size psz = GetPhysicalSize(data);
if((psz.cx | psz.cy) == 0)
psz = 625 * GetPixelSize(data) / 100;
Size sz;
for(int i = 1; i < 10000; i++) {
sz = psz / i;
if(sz.cx <= maxsize.cx && sz.cy <= maxsize.cy)
break;
}
return sz;
}
Value RichObjectType::Read(const String& s) const
{
return s;
}
String RichObjectType::Write(const Value& v) const
{
return v;
}
bool RichObjectType::Accept(PasteClip& clip)
{
return false;
}
Value RichObjectType::Read(PasteClip& clip)
{
return Null;
}
String RichObjectType::GetClipFmts() const
{
return Null;
}
String RichObjectType::GetClip(const Value& data, const String& fmt) const
{
return Null;
}
void RichObjectType::Menu(Bar& bar, RichObject& data) const {}
void RichObjectType::DefaultAction(RichObject& data) const {}
Size RichObjectType::GetPhysicalSize(const Value& data) const { return Size(0, 0); }
Size RichObjectType::GetPixelSize(const Value& data) const { return Size(1, 1); }
void RichObjectType::Paint(const Value& data, Draw& w, Size sz) const {}
Image RichObjectType::ToImage(const Value& data, Size sz) const
{
ImageDraw w(sz);
Paint(data, w, sz);
return w;
}
String RichObjectType::GetLink(const Value& data, Point pt, Size sz) const
{
return Null;
}
void RichObject::InitSize(int cx, int cy)
{
Size sz;
Size phsz = GetPixelSize();
if(cx || cy)
sz = GetRatioSize(phsz, cx, cy);
else
sz = phsz;
if(sz.cx > 2000 || sz.cy > 2000)
sz = sz.cx > sz.cy ? GetRatioSize(phsz, 2000, 0)
: GetRatioSize(phsz, 0, 2000);
SetSize(sz);
}
typedef VectorMap<String, RichObjectType *> RichObjectHT;
GLOBAL_VAR(RichObjectHT, RichObject::Map);
void RichObject::NewSerial()
{
INTERLOCKED {
static int64 s;
serial = ++s;
}
}
void RichObject::Register(const char *name, RichObjectType *type)
{
AssertST();
Map().FindAdd(name, type);
}
void RichObject::Paint(Draw& w, Size sz) const
{
if(type)
type->Paint(data, w, sz);
else {
w.DrawRect(sz, SColorFace());
DrawFrame(w, sz, SColorText());
w.DrawText(2, 2, type_name);
}
}
Image RichObject::ToImage(Size sz) const
{
if(type)
return type->ToImage(data, sz);
else {
ImageDraw w(sz);
Paint(w, sz);
return w;
}
}
struct UnknownRichObject : RichObjectType {
virtual String GetTypeName(const Value&) const;
};
String UnknownRichObject::GetTypeName(const Value&) const
{
return Null;
}
const RichObjectType& RichObject::GetType() const
{
if(type)
return *type;
return Single<UnknownRichObject>();
}
void RichObject::Set(RichObjectType *_type, const Value& _data, Size maxsize)
{
Clear();
type = _type;
if(type) {
data = _data;
physical_size = type->GetPhysicalSize(data);
pixel_size = type->GetPixelSize(data);
size = type->GetDefaultSize(data, maxsize);
}
NewSerial();
}
bool RichObject::Set(const String& _type_name, const Value& _data, Size maxsize)
{
NewSerial();
type_name = _type_name;
RichObjectType *t = Map().Get(type_name, NULL);
if(t) {
Set(t, _data);
return true;
}
else {
Clear();
data = _data;
physical_size = pixel_size = size = Size(64, 64);
}
return false;
}
bool RichObject::Read(const String& _type_name, const String& _data, Size sz)
{
NewSerial();
type_name = _type_name;
RichObjectType *t = Map().Get(type_name, NULL);
if(t) {
Clear();
type = t;
data = type->Read(_data);
physical_size = type->GetPhysicalSize(data);
pixel_size = type->GetPixelSize(data);
size = sz;
return true;
}
data = _data;
physical_size = pixel_size = size = sz;
return false;
}
String RichObject::GetTypeName() const
{
return type ? type->GetTypeName(data) : type_name;
}
void RichObject::Clear()
{
NewSerial();
keepratio = true;
type = NULL;
data = Value();
size = physical_size = pixel_size = Size(0, 0);
ydelta = 0;
type_name.Clear();
}
RichObject::RichObject()
{
Clear();
}
RichObject::RichObject(RichObjectType *type, const Value& data, Size maxsize)
{
Set(type, data, maxsize);
}
RichObject::RichObject(const String& type, const Value& data, Size maxsize)
{
Set(type, data, maxsize);
}
struct RichObjectTypeDrawingCls : public RichObjectType
{
virtual String GetTypeName(const Value&) const;
virtual Size GetPhysicalSize(const Value& data) const;
virtual Size GetPixelSize(const Value& data) const;
virtual void Paint(const Value& data, Draw& w, Size sz) const;
virtual Value Read(const String& s) const;
virtual String Write(const Value& v) const;
struct Data
{
void Serialize(Stream& stream);
Drawing drawing;
Size dot_size;
};
};
RichObjectType *RichObjectTypeDrawing() { return &Single<RichObjectTypeDrawingCls>(); }
void RichObjectTypeDrawingCls::Data::Serialize(Stream& stream)
{
int version = 1;
stream % version % dot_size % drawing;
}
String RichObjectTypeDrawingCls::GetTypeName(const Value&) const
{
return "Drawing";
}
RichObject CreateDrawingObject(const Drawing& dwg, Size dot_size, Size out_size)
{
RichObjectTypeDrawingCls::Data data;
data.drawing = dwg;
data.dot_size = dot_size;
RichObject obj(RichObjectTypeDrawing(), RawToValue(data));
if(!IsNull(out_size))
obj.SetSize(out_size);
return obj;
}
RichObject CreateDrawingObject(const Drawing& dwg, int cx, int cy)
{
Size dsz = dwg.GetSize();
return CreateDrawingObject(dwg, dsz, cx || cy ? GetRatioSize(dsz, cx, cy) : dsz);
}
Size RichObjectTypeDrawingCls::GetPixelSize(const Value& data) const
{
if(IsTypeRaw<Data>(data))
return ValueTo<Data>(data).drawing.GetSize(); // dot_size; TRC 08/04/04
return Size(0, 0);
}
Size RichObjectTypeDrawingCls::GetPhysicalSize(const Value& data) const
{
if(IsTypeRaw<Data>(data))
return ValueTo<Data>(data).dot_size;
return Size(0, 0);
}
Value RichObjectTypeDrawingCls::Read(const String& s) const
{
Data data;
StringStream ss(s);
ss % data;
if(ss.IsError())
return Value();
return RawToValue(data);
}
String RichObjectTypeDrawingCls::Write(const Value& v) const
{
if(IsTypeRaw<Data>(v))
{
StringStream ss;
ss % const_cast<Data&>(ValueTo<Data>(v));
return ss;
}
return Null;
}
void RichObjectTypeDrawingCls::Paint(const Value& data, Draw& w, Size sz) const
{
w.DrawRect(sz, White);
if(IsTypeRaw<Data>(data))
w.DrawDrawing(Rect(sz), ValueTo<Data>(data).drawing);
}
INITBLOCK {
RichObject::Register("Drawing", &Single<RichObjectTypeDrawingCls>());
};
struct RichObjectTypePNGCls : public RichObjectType
{
virtual String GetTypeName(const Value&) const;
virtual Size GetPhysicalSize(const Value& data) const;
virtual Size GetPixelSize(const Value& data) const;
virtual void Paint(const Value& data, Draw& w, Size sz) const;
virtual Value Read(const String& s) const;
virtual String Write(const Value& v) const;
};
RichObjectType *RichObjectTypePNG() { return &Single<RichObjectTypePNGCls>(); }
String RichObjectTypePNGCls::GetTypeName(const Value&) const
{
return "PING";
}
RichObject CreatePNGObject(const Image& img, Size dot_size, Size out_size)
{
RichObject obj(RichObjectTypePNG(), PNGEncoder().SaveString(img));
if(!IsNull(out_size))
obj.SetSize(out_size);
return obj;
}
RichObject CreatePNGObject(const Image& img, int cx, int cy)
{
Size dsz = img.GetSize();
return CreatePNGObject(img, dsz, cx || cy ? GetRatioSize(dsz, cx, cy) : dsz);
}
Size RichObjectTypePNGCls::GetPixelSize(const Value& data) const
{
if(IsString(data)) {
StringStream strm(data);
One<StreamRaster> ras = StreamRaster::OpenAny(strm);
if(!!ras)
return ras->GetSize();
}
return Size(0, 0);
}
Size RichObjectTypePNGCls::GetPhysicalSize(const Value& data) const
{
if(IsString(data)) {
StringStream strm(data);
One<StreamRaster> ras = StreamRaster::OpenAny(strm);
if(!!ras)
return ras->GetInfo().dots;
}
return Size(0, 0);
}
Value RichObjectTypePNGCls::Read(const String& s) const
{
return s;
}
String RichObjectTypePNGCls::Write(const Value& v) const
{
return v;
}
void RichObjectTypePNGCls::Paint(const Value& data, Draw& w, Size sz) const
{
if(IsString(data)) {
StringStream strm(data);
One<StreamRaster> ras = StreamRaster::OpenAny(strm);
if(!!ras) {
w.DrawRect(sz, White);
w.DrawImage(Rect(sz), ras->GetImage());
return;
}
}
w.DrawRect(sz, LtRed());
}
INITBLOCK {
RichObject::Register("PING", &Single<RichObjectTypePNGCls>());
};
END_UPP_NAMESPACE

294
uppdev/RichTextP/Para.h Normal file
View file

@ -0,0 +1,294 @@
struct RichCaret;
struct RichPos;
struct RichPara {
enum Code {
NONE,
INDEXENTRY = 2,
FIELD = 3,
FACE = 4,
HEIGHT = 5,
LANGUAGE = 6,
INK = 7,
PAPER = 8,
TAB = 9, // placeholder
LINK = 10,
SSCRIPT = 11,
BOLD0 = 12,
BOLD1 = 13,
BOLDS = 14,
ITALIC0 = 15,
ITALIC1 = 16,
ITALICS = 17,
UNDERLINE0 = 18,
UNDERLINE1 = 19,
UNDERLINES = 20,
CAPITALS0 = 21,
CAPITALS1 = 22,
CAPITALSS = 23,
STRIKEOUT0 = 24,
STRIKEOUT1 = 25,
STRIKEOUTS = 26,
DASHED0 = 27,
DASHED1 = 28,
DASHEDS = 29,
EXT = 30,
OBJECT = 31
};
enum ExtCode {
NONAA0 = 1,
NONAA1 = 2,
NONAAS = 3,
};
enum BULLET_STYLE {
BULLET_NONE,
BULLET_ROUND,
BULLET_ROUNDWHITE,
BULLET_BOX,
BULLET_BOXWHITE,
BULLET_TEXT
};
enum NUMBER_STYLE {
NUMBER_NONE,
NUMBER_1,
NUMBER_0,
NUMBER_a,
NUMBER_A,
NUMBER_i,
NUMBER_I,
};
enum LINESPACING {
LSP10 = 0,
LSP15 = -1,
LSP20 = -2,
};
struct CharFormat : public Font {
int language;
Color ink, paper;
String link;
WString indexentry;
dword sscript:2;
bool capitals;
bool dashed;
#ifdef _DEBUG
String ToString() const;
#endif
CharFormat();
};
struct Tab : Moveable<Tab> {
int pos;
byte align;
byte fillchar;
Tab() { align = ALIGN_LEFT; pos = 0; fillchar = 0; }
};
struct NumberFormat {
String before_number, after_number;
bool reset_number;
byte number[8];
bool IsNumbered() const;
int GetNumberLevel() const;
};
struct Format : NumberFormat, CharFormat {
int align;
int ruler, before, lm, indent, rm, after;
Color rulerink;
int tabsize;
int bullet;
int linespacing;
bool newpage, keep, keepnext, orphan;
WithDeepCopy< Vector<Tab> > tab;
String label;
Uuid styleid;
void SortTabs();
#ifdef _DEBUG
String ToString() const;
#endif
Format();
};
struct Number {
int n[8];
String AsText(const NumberFormat& format) const;
void TestReset(const NumberFormat& format);
void Next(const NumberFormat& format);
Number();
};
struct Part {
RichObject object;
WString text;
CharFormat format;
Id field;
String fieldparam;
WithDeepCopy< Array<Part> > fieldpart;
bool NonText() const { return object || field; }
bool IsText() const { return !NonText(); }
int GetLength() const { return object || field ? 1 : text.GetLength(); }
};
struct FieldType {
virtual Array<Part> Evaluate(const String& param, VectorMap<String, Value>& vars,
const CharFormat& fmt) = 0;
virtual void Menu(Bar& bar, String *param) const {}
virtual void DefaultAction(String *param) const {}
virtual ~FieldType() {}
};
struct HeightInfo {
int ascent;
int descent;
int external;
int ydelta;
const RichObject *object;
int Sum() const { return ascent + descent + external; }
};
struct Line : public HeightInfo {
int pos;
int len;
int ppos;
int plen;
int xpos;
int cx;
int objecti;
bool withtabs;
};
struct Lines {
int len;
int clen;
int cx;
Buffer<wchar> text;
Buffer<byte> spell;
Buffer<int> pos;
Buffer<int> width;
Buffer<HeightInfo> height;
Buffer<const CharFormat *> format;
Array<Line> line;
Array<CharFormat> hformat;
int first_indent;
int next_indent;
int GetCount() const { return line.GetCount(); }
Line& operator[](int i) { return line[i]; }
const Line& operator[](int i) const { return line[i]; }
void Justify(const Format& format);
int BodyHeight();
};
static const VectorMap<Id, FieldType *>& fieldtype();
static void Register(Id id, FieldType& ft) init_;
Format format;
Array<Part> part;
static void Charformat(Stream& out, const CharFormat& o, const CharFormat& n,
const CharFormat& s);
void Cat(const WString& s, const CharFormat& f);
void Cat(const char *s, const CharFormat& f);
void Cat(const RichObject& o, const CharFormat& f);
void Cat(Id fieldtype, const String& param, const CharFormat& f);
int GetLength() const;
int GetCount() const { return part.GetCount(); }
bool IsEmpty() const;
String Pack(const Format& style, Array<RichObject>& obj) const;
void Unpack(const String& s, const Array<RichObject>& obj, const Format& style);
void ApplyStyle(const Format& newstyle);
Part& operator[](int i) { return part[i]; }
const Part& operator[](int i) const { return part[i]; }
int FindPart(int& pos) const;
void Trim(int pos);
void Mid(int pos);
void Append(const RichPara& p) { part.Append(p.part); }
void GetRichPos(RichPos& rp, int pos) const;
Lines FormatLines(int cx) const;
void Paint(PageDraw& pw, const Rect& page, PageY py, const PaintInfo& pi,
const Number& n, const Bits& spellerrors,
int nbefore, int nline) const;
RichCaret GetCaret(int pos, const Rect& page, PageY py, int nbefore, int nline) const;
int GetPos(int x, PageY y, const Rect& page, PageY py, int nbefore, int nline) const;
void GatherLabels(Vector<RichValPos>& info, const Rect& page, PageY py,
int pos, int nbefore, int nline) const;
void GatherIndexes(Vector<RichValPos>& info, const Rect& page, PageY py,
int pos, int nbefore, int nline) const;
int GetVertMove(int pos, int gx, const Rect& page, int dir) const;
WString GetText() const;
bool HasPos() const;
bool EvaluateFields(VectorMap<String, Value>& vars);
void operator<<=(const RichPara& p) { format = p.format; part <<= p.part; }
#ifdef _DEBUG
void Dump();
#endif
void ApplyZoom(Zoom z);
private:
Tab GetNextTab(int pos) const;
void Smh(Lines& lines, HeightInfo *th, int cx) const;
Lines Begin(const Rect& page, PageY& py, int nbefore, int nline) const;
bool BreaksPage(PageY py, const Lines& pl, int i, const Rect& page) const;
void PackParts(Stream& out, const CharFormat& chrstyle,
const Array<Part>& part, CharFormat& cf,
Array<RichObject>& obj) const;
void UnpackParts(Stream& in, const CharFormat& chrstyle,
Array<Part>& part, const Array<RichObject>& obj, int& oi);
static void Flush(Draw& draw, const PaintInfo& pi, wchar *text, const CharFormat **i0,
int *wd, int pos, int len, int x0, int x, int y0, int y, int linecy,
int lineascent, Zoom z, bool highlight);
int PosInLine(int x, const Rect& page, const Lines& pl, int lni) const;
struct StorePart;
};
inline bool operator==(const RichPara::Tab& a, const RichPara::Tab& b) {
return a.pos == b.pos && a.align == b.align && a.fillchar == b.fillchar;
}
bool operator==(const Vector<RichPara::Tab>& a, const Vector<RichPara::Tab>& b);
inline
bool operator!=(const Vector<RichPara::Tab>& a, const Vector<RichPara::Tab>& b) {
return !(a == b);
}
bool NumberingDiffers(const RichPara::Format& fmt1, const RichPara::Format& fmt2);
void Sort(Vector<RichPara::Tab>& tab);
void operator*=(RichPara::Format& fmt, Zoom z);

View file

@ -0,0 +1,772 @@
#include "RichText.h"
NAMESPACE_UPP
PaintInfo::PaintInfo()
{
sell = selh = 0;
tablesel = 0;
top = PageY(0, 0);
bottom = PageY(INT_MAX, INT_MAX);
hyperlink = SColorMark();
usecache = false;
sizetracking = false;
showcodes = Null;
spellingchecker = NULL;
highlightpara = -1;
highlight = Yellow();
indexentry = LtGreen();
coloroverride = false;
}
String RichPara::Number::AsText(const RichPara::NumberFormat& format) const
{
String result;
for(int i = 0; i < 8; i++)
if(format.number[i]) {
if(result.GetLength())
result.Cat('.');
int q = n[i];
switch(format.number[i]) {
case NUMBER_1:
result << AsString(q);
break;
case NUMBER_0:
result << AsString(q - 1);
break;
case NUMBER_a:
result << FormatIntAlpha(q, false);
break;
case NUMBER_A:
result << FormatIntAlpha(q, true);
break;
case NUMBER_i:
result << FormatIntRoman(q, false);
break;
case NUMBER_I:
result << FormatIntRoman(q, true);
break;
}
}
return format.before_number + result + format.after_number;
}
void RichPara::Number::TestReset(const RichPara::NumberFormat& fmt)
{
if(fmt.reset_number) {
bool done = false;
for(int i = 7; i >= 0; --i)
if(fmt.number[i]) {
n[i] = 0;
done = true;
break;
}
if(!done && !IsNull(n[0]))
n[0] = 0;
}
}
void RichPara::Number::Next(const RichPara::NumberFormat& fmt)
{
for(int i = 7; i >= 0; --i)
if(fmt.number[i]) {
n[i++]++;
while(i <= 7)
n[i++] = 0;
break;
}
}
RichPara::Number::Number()
{
memset(n, 0, sizeof(n));
}
bool RichPara::NumberFormat::IsNumbered() const
{
if(before_number.GetLength() || after_number.GetLength())
return true;
for(int i = 0; i < 8; i++)
if(number[i])
return true;
return false;
}
int RichPara::NumberFormat::GetNumberLevel() const
{
for(int i = 7; i >= 0; i--)
if(number[i])
return i + 1;
if(before_number.GetLength() || after_number.GetLength())
return 0;
return -1;
}
bool NumberingDiffers(const RichPara::Format& fmt1, const RichPara::Format& fmt2)
{
return fmt1.before_number != fmt2.before_number ||
fmt1.after_number != fmt2.after_number ||
fmt1.reset_number != fmt2.reset_number ||
memcmp(fmt1.number, fmt2.number, sizeof(fmt1.number));
}
bool operator==(const Vector<RichPara::Tab>& a, const Vector<RichPara::Tab>& b)
{
if(a.GetCount() != b.GetCount()) return false;
for(int i = 0; i < a.GetCount(); i++)
if(a[i].pos != b[i].pos || a[i].align != b[i].align || a[i].fillchar != b[i].fillchar)
return false;
return true;
}
RichPara::CharFormat::CharFormat()
{
(Font &)*this = Arial(100);
ink = Black;
paper = Null;
language = 0;
link = Null;
sscript = 0;
capitals = dashed = false;
}
RichPara::Format::Format()
{
align = ALIGN_LEFT;
ruler = before = lm = rm = indent = after = 0;
rulerink = Black;
bullet = 0;
keep = newpage = keepnext = orphan = false;
tabsize = 296;
memset(number, 0, sizeof(number));
reset_number = false;
linespacing = 0;
tab.Clear();
styleid = RichStyle::GetDefaultId();
}
void RichPara::Charformat(Stream& out, const RichPara::CharFormat& o,
const RichPara::CharFormat& n, const RichPara::CharFormat& s)
{
if(o.IsBold() != n.IsBold())
out.Put(n.IsBold() == s.IsBold() ? BOLDS : BOLD0 + n.IsBold());
if(o.IsItalic() != n.IsItalic())
out.Put(n.IsItalic() == s.IsItalic() ? ITALICS
: ITALIC0 + n.IsItalic());
if(o.IsUnderline() != n.IsUnderline())
out.Put(n.IsUnderline() == s.IsUnderline() ? UNDERLINES
: UNDERLINE0 + n.IsUnderline());
if(o.IsStrikeout() != n.IsStrikeout())
out.Put(n.IsStrikeout() == s.IsStrikeout() ? STRIKEOUTS
: STRIKEOUT0 + n.IsStrikeout());
if(o.IsNonAntiAliased() != n.IsNonAntiAliased()) {
out.Put(EXT);
out.Put(n.IsNonAntiAliased() == s.IsNonAntiAliased() ? NONAAS
: NONAA0 + n.IsNonAntiAliased());
}
if(o.capitals != n.capitals)
out.Put(n.capitals == s.capitals ? CAPITALSS
: CAPITALS0 + n.capitals);
if(o.dashed != n.dashed)
out.Put(n.dashed == s.dashed ? DASHEDS
: DASHED0 + n.dashed);
if(o.sscript != n.sscript) {
out.Put(SSCRIPT);
out.Put(n.sscript);
}
if(o.GetFace() != n.GetFace()) {
out.Put(FACE);
out.Put16(n.GetFace() == s.GetFace() ? 0xffff : n.GetFace());
}
if(o.GetHeight() != n.GetHeight()) {
out.Put(HEIGHT);
out.Put16(n.GetHeight() == s.GetHeight() ? 0xffff : n.GetHeight());
}
if(o.link != n.link) {
out.Put(LINK);
String s = n.link;
out % s;
}
if(o.ink != n.ink) {
out.Put(INK);
Color c = n.ink;
c.Serialize(out);
}
if(o.paper != n.paper) {
out.Put(PAPER);
Color c = n.paper;
c.Serialize(out);
}
if(o.language != n.language) {
out.Put(LANGUAGE);
out.Put32(n.language);
}
if(o.indexentry != n.indexentry) {
out.Put(INDEXENTRY);
WString s = n.indexentry;
out % s;
}
}
void RichPara::Cat(const WString& s, const RichPara::CharFormat& f)
{
part.Add();
part.Top().text = s;
part.Top().format = f;
}
void RichPara::Cat(const char *s, const CharFormat& f)
{
Cat(WString(s), f);
}
void RichPara::Cat(const RichObject& o, const RichPara::CharFormat& f)
{
part.Add();
part.Top().object = o;
part.Top().format = f;
}
void RichPara::Cat(Id field, const String& param, const RichPara::CharFormat& f)
{
Part& p = part.Add();
p.field = field;
p.fieldparam = param;
p.format = f;
VectorMap<String, Value> dummy;
FieldType *ft = fieldtype().Get(field, NULL);
if(ft)
p.fieldpart ^= ft->Evaluate(param, dummy, f);
}
struct TabLess {
bool operator () (const RichPara::Tab& a, const RichPara::Tab& b) const {
return a.pos == b.pos ? a.align < b.align : a.pos < b.pos;
}
};
void RichPara::Format::SortTabs()
{
Sort(tab, TabLess());
}
void RichPara::PackParts(Stream& out, const RichPara::CharFormat& chrstyle,
const Array<RichPara::Part>& part, CharFormat& cf,
Array<RichObject>& obj) const
{
for(int i = 0; i < part.GetCount(); i++) {
const Part& p = part[i];
Charformat(out, cf, p.format, chrstyle);
cf = p.format;
if(p.field) {
out.Put(FIELD);
out.Put32(p.field.AsNdx());
String s = p.fieldparam;
out % s;
StringStream oout;
CharFormat subf = cf;
PackParts(oout, chrstyle, p.fieldpart, subf, obj);
s = oout;
out % s;
}
else
if(p.object) {
obj.Add(p.object);
out.Put(OBJECT);
}
else {
String x = ToUtf8(p.text);
out.Put(x);
}
}
}
String RichPara::Pack(const RichPara::Format& style, Array<RichObject>& obj) const
{
StringStream out;
dword pattr = 0;
if(format.align != style.align) pattr |= 1;
if(format.before != style.before) pattr |= 2;
if(format.lm != style.lm) pattr |= 4;
if(format.indent != style.indent) pattr |= 8;
if(format.rm != style.rm) pattr |= 0x10;
if(format.after != style.after) pattr |= 0x20;
if(format.bullet != style.bullet) pattr |= 0x40;
if(format.keep != style.keep) pattr |= 0x80;
if(format.newpage != style.newpage) pattr |= 0x100;
if(format.tabsize != style.tabsize) pattr |= 0x200;
if(!IsNull(format.label)) pattr |= 0x400;
if(format.keepnext != style.keepnext) pattr |= 0x800;
if(format.orphan != style.orphan) pattr |= 0x1000;
if(NumberingDiffers(format, style)) pattr |= 0x2000;
if(format.linespacing != style.linespacing) pattr |= 0x4000;
if(format.tab != style.tab) pattr |= 0x8000;
if(format.ruler != style.ruler) pattr |= 0x10000;
if(format.rulerink != style.rulerink) pattr |= 0x20000;
out.Put32(pattr);
if(pattr & 1) out.Put16(format.align);
if(pattr & 2) out.Put16(format.before);
if(pattr & 4) out.Put16(format.lm);
if(pattr & 8) out.Put16(format.indent);
if(pattr & 0x10) out.Put16(format.rm);
if(pattr & 0x20) out.Put16(format.after);
if(pattr & 0x40) out.Put16(format.bullet);
if(pattr & 0x80) out.Put(format.keep);
if(pattr & 0x100) out.Put(format.newpage);
if(pattr & 0x200) out.Put16(format.tabsize);
if(pattr & 0x400) { String t = format.label; out % t; }
if(pattr & 0x800) out.Put(format.keepnext);
if(pattr & 0x1000) out.Put(format.orphan);
if(pattr & 0x2000) {
String b = format.before_number, a = format.after_number;
out % b % a;
out.Put(format.reset_number);
out.Put(format.number, 8);
}
if(pattr & 0x4000)
out.Put(format.linespacing);
if(pattr & 0x8000) {
int c = 0;
int i;
for(i = 0; i < format.tab.GetCount(); i++) {
if(!IsNull(format.tab[i].pos))
c++;
}
out.Put16(c);
for(i = 0; i < format.tab.GetCount(); i++) {
const RichPara::Tab& w = format.tab[i];
if(!IsNull(w.pos)) {
out.Put32(w.pos);
out.Put(w.align);
out.Put(w.fillchar);
}
}
}
if(pattr & 0x10000)
out.Put16(format.ruler);
if(pattr & 0x20000) {
Color c = format.rulerink;
c.Serialize(out);
}
obj.Clear();
CharFormat cf = style;
if(part.GetCount())
PackParts(out, style, part, cf, obj);
else
Charformat(out, style, format, cf);
String r = out;
r.Shrink();
return r;
}
void RichPara::UnpackParts(Stream& in, const RichPara::CharFormat& chrstyle,
Array<RichPara::Part>& part, const Array<RichObject>& obj,
int& oi) {
part.Add();
part.Top().format = format;
int c;
while((c = in.Term()) >= 0)
if(c < 31 && c != 9 && c != FIELD) {
do
switch(in.Get()) {
case BOLD0:
format.NoBold();
break;
case BOLD1:
format.Bold();
break;
case BOLDS:
format.Bold(chrstyle.IsBold());
break;
case ITALIC0:
format.NoItalic();
break;
case ITALIC1:
format.Italic();
break;
case ITALICS:
format.Italic(chrstyle.IsItalic());
break;
case UNDERLINE0:
format.NoUnderline();
break;
case UNDERLINE1:
format.Underline();
break;
case UNDERLINES:
format.Underline(chrstyle.IsUnderline());
break;
case STRIKEOUT0:
format.NoStrikeout();
break;
case STRIKEOUT1:
format.Strikeout();
break;
case STRIKEOUTS:
format.Strikeout(chrstyle.IsStrikeout());
break;
case CAPITALS0:
format.capitals = false;
break;
case CAPITALS1:
format.capitals = true;
break;
case CAPITALSS:
format.capitals = chrstyle.capitals;
break;
case DASHED0:
format.dashed = false;
break;
case DASHED1:
format.dashed = true;
break;
case DASHEDS:
format.dashed = chrstyle.dashed;
break;
case SSCRIPT:
format.sscript = in.Get();
if(format.sscript == 3)
format.sscript = chrstyle.sscript;
break;
case FACE:
c = in.Get16();
format.Face(c == 0xffff ? chrstyle.GetFace() : c);
break;
case HEIGHT:
c = in.Get16();
format.Height(c == 0xffff ? chrstyle.GetHeight() : c);
break;
case LINK:
in % format.link;
break;
case INDEXENTRY:
in % format.indexentry;
break;
case INK:
in % format.ink;
break;
case PAPER:
in % format.paper;
break;
case LANGUAGE:
format.language = in.Get32();
break;
case EXT:
switch(in.Get()) {
case NONAA0:
format.NonAntiAliased(false);
break;
case NONAA1:
format.NonAntiAliased(true);
break;
case NONAAS:
format.NonAntiAliased(chrstyle.IsNonAntiAliased());
break;
}
}
while((c = in.Term()) < 31 && c != 9 && c != FIELD && c >= 0);
if(part.Top().text.GetLength())
part.Add();
part.Top().format = format;
}
else
if(in.Term() == FIELD) {
RichPara::Format pformat = format;
if(part.Top().text.GetLength()) {
part.Add();
part.Top().format = pformat;
}
in.Get();
Part& p = part.Top();
p.field = Id(in.Get32());
in % p.fieldparam;
String s;
in % s;
StringStream sn(s);
UnpackParts(sn, chrstyle, p.fieldpart, obj, oi);
part.Add();
part.Top().format = format = pformat;
}
else
if(in.Term() == OBJECT) {
if(part.Top().text.GetLength()) {
part.Add();
part.Top().format = format;
}
part.Top().object = obj[oi++];
part.Top().format = format;
part.Add();
part.Top().format = format;
in.Get();
}
else
part.Top().text.Cat(in.GetUtf8());
if(part.Top().text.GetLength() == 0 && part.Top().IsText())
part.Drop();
}
void RichPara::Unpack(const String& data, const Array<RichObject>& obj,
const RichPara::Format& style)
{
part.Clear();
StringStream in(data);
format = style;
dword pattr = in.Get32();
if(pattr & 1) format.align = in.Get16();
if(pattr & 2) format.before = in.Get16();
if(pattr & 4) format.lm = in.Get16();
if(pattr & 8) format.indent = in.Get16();
if(pattr & 0x10) format.rm = in.Get16();
if(pattr & 0x20) format.after = in.Get16();
if(pattr & 0x40) format.bullet = in.Get16();
if(pattr & 0x80) format.keep = in.Get();
if(pattr & 0x100) format.newpage = in.Get();
if(pattr & 0x200) format.tabsize = in.Get16();
if(pattr & 0x400) in % format.label;
if(pattr & 0x800) format.keepnext = in.Get();
if(pattr & 0x1000) format.orphan = in.Get();
if(pattr & 0x2000) {
in % format.before_number;
in % format.after_number;
format.reset_number = in.Get();
in.Get(format.number, 8);
}
if(pattr & 0x4000) {
format.linespacing = (int8)in.Get();
}
if(pattr & 0x8000) {
format.tab.Clear();
int n = in.Get16();
format.tab.Reserve(n);
for(int i = 0; i < n; i++) {
RichPara::Tab& w = format.tab.Add();
w.pos = in.Get32();
w.align = in.Get();
w.fillchar = in.Get();
}
}
if(pattr & 0x10000)
format.ruler = in.Get16();
if(pattr & 0x20000)
format.rulerink.Serialize(in);
part.Clear();
int oi = 0;
UnpackParts(in, style, part, obj, oi);
}
bool RichPara::IsEmpty() const
{
return part.GetCount() == 0 || GetLength() == 0;
}
int RichPara::GetLength() const
{
int n = 0;
for(int i = 0; i < part.GetCount(); i++)
n += part[i].GetLength();
return n;
}
WString RichPara::GetText() const
{
WString r;
for(int i = 0; i < part.GetCount(); i++)
if(part[i].IsText())
r.Cat(part[i].text);
else
r.Cat(127);
return r;
}
typedef VectorMap<Id, RichPara::FieldType *> FieldTypeMap;
GLOBAL_VAR(FieldTypeMap, fieldtype0)
const VectorMap<Id, RichPara::FieldType *>& RichPara::fieldtype()
{
return fieldtype0();
}
void RichPara::Register(Id id, FieldType& ft) init_
{
AssertST();
fieldtype0().GetAdd(id, &ft);
}
bool RichPara::EvaluateFields(VectorMap<String, Value>& vars)
{
bool b = false;
for(int i = 0; i < GetCount(); i++) {
Part& p = part[i];
if(p.field) {
FieldType *f = fieldtype().Get(p.field, NULL);
if(f) {
p.fieldpart ^= f->Evaluate(p.fieldparam, vars, p.format);
b = true;
}
}
}
return b;
}
bool RichPara::HasPos() const
{
if(!format.label.IsEmpty()) return true;
for(int i = 0; i < part.GetCount(); i++)
if(!part[i].format.indexentry.IsEmpty())
return true;
return false;
}
int RichPara::FindPart(int& pos) const
{
int pi = 0;
while(pi < part.GetCount() && pos >= part[pi].GetLength()) {
pos -= part[pi].GetLength();
pi++;
}
return pi;
}
void RichPara::Trim(int pos)
{
int i = FindPart(pos);
if(pos) {
ASSERT(part[i].IsText());
part[i].text.Trim(pos);
part.SetCount(i + 1);
}
else
part.SetCount(i);
}
void RichPara::Mid(int pos)
{
int i = FindPart(pos);
part.Remove(0, i);
if(pos) {
ASSERT(part[0].IsText());
part[0].text = part[0].text.Mid(pos);
}
}
void ApplyCharStyle(RichPara::CharFormat& format, const RichPara::CharFormat& f0,
const RichPara::CharFormat& newstyle) {
if(format.IsBold() == f0.IsBold())
format.Bold(newstyle.IsBold());
if(format.IsUnderline() == f0.IsUnderline())
format.Underline(newstyle.IsUnderline());
if(format.IsItalic() == f0.IsItalic())
format.Italic(newstyle.IsItalic());
if(format.IsStrikeout() == f0.IsStrikeout())
format.Strikeout(newstyle.IsStrikeout());
if(format.IsNonAntiAliased() == f0.IsNonAntiAliased())
format.NonAntiAliased(newstyle.IsNonAntiAliased());
if(format.capitals == f0.capitals)
format.capitals = newstyle.capitals;
if(format.dashed == f0.dashed)
format.dashed = newstyle.dashed;
if(format.sscript == f0.sscript)
format.sscript = newstyle.sscript;
if(format.GetFace() == f0.GetFace())
format.Face(newstyle.GetFace());
if(format.GetHeight() == f0.GetHeight())
format.Height(newstyle.GetHeight());
if(format.ink == f0.ink)
format.ink = newstyle.ink;
if(format.paper == f0.paper)
format.paper = newstyle.paper;
}
void RichPara::ApplyStyle(const Format& newstyle)
{
CharFormat f0 = part.GetCount() ? part[0].format : format;
for(int i = 0; i < part.GetCount(); i++)
ApplyCharStyle(part[i].format, f0, newstyle);
CharFormat h = format;
ApplyCharStyle(h, f0, newstyle);
format = newstyle;
(CharFormat&)format = h;
}
#ifdef _DEBUG
void RichPara::Dump()
{
LOG("RichPara dump" << LOG_BEGIN);
LOG("RULER: " << format.ruler << " " << format.rulerink);
LOG("BEFORE: " << format.before);
LOG("INDENT: " << format.indent);
LOG("LM: " << format.lm);
LOG("RM: " << format.rm);
LOG("AFTER: " << format.after);
LOG("KEEP: " << format.keep);
LOG("NEWPAGE: " << format.newpage);
LOG("BULLET: " << format.bullet);
int i;
for(i = 0; i < format.tab.GetCount(); i++)
LOG("TAB " << format.tab[i].pos << " : " << format.tab[i].align);
for(i = 0; i < part.GetCount(); i++)
LOG("Part[" << i << "] = \"" << part[i].text << "\" "
<< part[i].format);
LOG(LOG_END << "---------");
}
String RichPara::CharFormat::ToString() const
{
String out;
out
<< Font(*this)
<< ", ink " << DumpColor(ink);
if(!UPP::IsNull(paper))
out << ", paper " << DumpColor(paper);
switch(sscript)
{
case 0: break;
case 1: out << ", superscript"; break;
case 2: out << ", subscript"; break;
default: out << ", sscript(" << (int)sscript << ")"; break;
}
out << ", lang " << DumpLanguage(language);
if(!UPP::IsNull(link))
out << ", link " << link;
if(capitals)
out << ", capitals";
if(dashed)
out << ", dashed";
return out;
}
String RichPara::Format::ToString() const
{
String out;
if(!UPP::IsNull(label))
out << "label <" << label << ">: ";
out
<< DumpAlign(align) << ", left " << lm << ", right " << rm
<< ", indent " << indent << ", before " << before << ", after " << after
<< ", tabsize " << tabsize << ", bullet " << bullet
<< (newpage ? ", newpage" : "")
<< (keep ? ", keep" : "")
<< (keepnext ? ", keepnext" : "")
<< (orphan ? ", orphan" : "");
int i;
for(i = 0; i < tab.GetCount(); i++)
out << (i ? "\n" : ", ")
<< "tab[" << i << "] = " << tab[i].pos << ", align " << DumpAlign(tab[i].align)
<< ", fill " << FormatIntHex(tab[i].fillchar, 2);
out << "\n";
out << "before_number " << before_number << ", after_number " << after_number
<< (reset_number ? ", reset_number" : "");
for(i = 0; i < __countof(number); i++)
if(number[i] != RichPara::NUMBER_NONE)
out << " num[" << i << "] = " << (int)number[i];
out << "\n";
return out;
}
#endif
END_UPP_NAMESPACE

View file

@ -0,0 +1,587 @@
#include "RichText.h"
NAMESPACE_UPP
#define IMAGECLASS RichTextImg
#define IMAGEFILE <RichText/RichText.iml>
#include <Draw/iml.h>
RichPara::Lines RichPara::Begin(const Rect& page, PageY& py, int nbefore, int nline) const
{
Lines pl = FormatLines(page.Width());
int cy = format.ruler + format.before;
if(format.keep || format.keepnext)
cy += pl.BodyHeight();
else
cy += pl[0].Sum();
int after = format.after;
if(!format.keepnext)
nbefore = nline = after = 0;
if(page.Height() < 32000 &&
(format.newpage || py.y + cy + after + nbefore + nline > page.bottom &&
cy < page.Height())) {
py.page++;
py.y = page.top;
}
py.y += format.before + format.ruler;
pl.Justify(format);
return pl;
}
void RichPara::Flush(Draw& draw, const PaintInfo& pi, wchar *text,
const CharFormat **i0,
int *wd, int pos, int len, int x0, int x, int y0,
int y, int linecy, int lineascent, Zoom z,
bool highlight)
{
if(*i0) {
const CharFormat& f = **i0;
int width = z * x - z * x0;
int zy0 = z * y0;
int zx0 = z * x0;
if(!IsNull(f.paper) && !highlight)
draw.DrawRect(zx0, z * y, width, z * (y + linecy) - z * y,
pi.coloroverride ? SColorPaper() : f.paper);
if(!IsNull(f.indexentry) && !IsNull(pi.indexentry))
draw.DrawRect(zx0, zy0, width, 2, pi.indexentry);
Font fnt = f;
int zht = z * tabs(f.GetHeight());
int ssa;
int ssd;
if(f.sscript) {
FontInfo fi = fnt(zht).Info();
ssa = fi.GetAscent();
ssd = fi.GetDescent();
zht = 3 * zht / 5;
}
fnt.Height(zht ? zht : 1);
FontInfo fi = fnt.Info();
if(f.dashed) {
int dx = max(fi.GetAscent() / 5, 2);
for(int i = 0; dx * i < width; i++)
draw.DrawRect(zx0 + i * dx, zy0 + fi.GetDescent() / 2,
dx / 2, max(fi.GetDescent() / 3, 1),
pi.coloroverride ? SColorText() : f.ink);
}
Color ink = pi.coloroverride ? SColorText() : f.ink;
if(!IsNull(f.link) && !IsNull(pi.hyperlink) && !(fnt.IsUnderline() || f.dashed)) {
fnt.Underline();
if(!pi.coloroverride)
ink = pi.hyperlink;
}
x = zx0;
for(int i = 0; i < len; i++) {
int w = wd[pos + i];
Image img;
wchar& c = text[pos + i];
if(c == ' ')
img = RichTextImg::SpaceChar();
if(c == 160)
img = RichTextImg::HardSpaceChar();
if(c >= 9 && c < 9 + 4) {
if(c > 9) {
static char fct[] = { ' ', '.', '-', '_' };
int fc = fct[c - 9];
int pw = fi[fc];
int px = (x + pw - 1) / pw * pw;
while(px + pw < x + w) {
draw.DrawText(px, zy0 - fi.GetAscent(), String(fc, 1), fnt, Black);
px += pw;
}
}
img = RichTextImg::TabChar();
c = ' ';
}
if(img && !IsNull(pi.showcodes)) {
Size sz = img.GetSize();
if(sz.cy < z * lineascent)
draw.DrawImage(x + (w - sz.cx) / 2, zy0 - sz.cy, img, pi.showcodes);
}
x += w;
}
draw.DrawText(zx0,
f.sscript == 1 ? zy0 - ssa :
f.sscript == 2 ? zy0 + ssd - fi.GetHeight()
: zy0 - fi.GetAscent(),
text + pos, fnt, ink, len, wd + pos);
}
}
bool RichPara::BreaksPage(PageY py, const Lines& pl, int i, const Rect& page) const
{
int linecy = pl[i].Sum();
if(linecy >= page.Height()) return false;
if(linecy + py.y > page.bottom)
return true;
if(format.orphan || pl.GetCount() < 2) return false;
if((i == 0 || i == pl.GetCount() - 2) && py.y + linecy + pl[i + 1].Sum() > page.bottom)
return true;
return false;
}
struct RichObjectImageMaker : ImageMaker {
RichObject object;
Size sz;
virtual String Key() const;
virtual Image Make() const;
};
String RichObjectImageMaker::Key() const
{
StringBuffer b;
int64 id = object.GetSerialId();
b.Cat((const char *)&id, sizeof(id));
b.Cat((const char *)&sz.cx, sizeof(sz.cx));
b.Cat((const char *)&sz.cy, sizeof(sz.cy));
return b;
}
Image RichObjectImageMaker::Make() const
{
ImageDraw iw(sz);
iw.DrawRect(sz, SColorPaper());
object.Paint(iw, sz);
return iw;
}
void RichPara::Paint(PageDraw& pw, const Rect& page, PageY py, const PaintInfo& pi,
const Number& n, const Bits& spellerror,
int nbefore, int nline) const
{
Zoom z = pi.zoom;
PageY opy = py;
Lines pl = Begin(page, py, nbefore, nline);
bool highlight = pi.highlightpara >= 0 && pi.highlightpara < pl.len;
int hy = py.y - format.before - format.ruler;
int phy = py.page;
if(pi.sell < 0 && pi.selh > 0)
for(int p = opy.page; p <= py.page; p++) {
int top = z * (p == opy.page ? opy.y : page.top);
int bottom = z * (p == py.page ? py.y : page.bottom);
pw.Page(p).DrawRect(z * page.left, top, z * page.right - z * page.left,
bottom - top, InvertColor);
}
opy = py;
int oi = 0;
int x;
int y0;
int lineascent = 0;
for(int lni = 0; lni < pl.GetCount(); lni++) {
Line& li = pl[lni];
int linecy = li.Sum();
lineascent = li.ascent;
if(BreaksPage(py, pl, lni, page)) {
if(li.ppos > pi.sell && li.ppos < pi.selh) {
int y = z * py.y;
pw.Page(py.page).DrawRect(z * page.left, y, z * page.right - z * page.left,
z * page.bottom - y, InvertColor);
}
py.y = page.top;
py.page++;
}
if(py > pi.bottom)
break;
const CharFormat **cf = pl.format + li.pos;
const CharFormat **i = cf;
const CharFormat **ilim = i + li.len;
const HeightInfo *hg = pl.height + li.pos;
if(py + linecy >= pi.top) {
Draw& draw = pw.Page(py.page);
#ifdef _DEBUG
int cloff = draw.GetCloffLevel();
#endif
Buffer<int> wd(li.len);
int x0 = li.xpos + page.left;
x = x0;
int *w = pl.width + li.pos;
int *wl = w + li.len;
int *t = wd;
while(w < wl) {
int x1 = x + *w++;
*t++ = z * x1 - z * x;
x = x1;
}
if(highlight)
draw.DrawRect(z * page.left, z * py.y, z * page.Width(),
z * (py.y + linecy) - z * py.y,
pi.highlight);
const CharFormat **i0 = i;
wchar *text = pl.text + li.pos;
x = x0;
w = pl.width + li.pos;
y0 = py.y + li.ascent;
int pp = li.pos;
int l = page.right;
int h = -1;
while(i < ilim) {
if(pl.pos[pp] == pi.sell && x < l)
l = x;
if(pl.pos[pp] == pi.selh && h < 0)
h = x;
pp++;
if(*i0 != *i || hg->object) {
Flush(draw, pi, text, i0, wd, (int)(i0 - cf),(int)( i - i0), x0, x, y0, py.y, linecy,
lineascent, z, highlight);
i0 = i;
x0 = x;
}
if(hg->object) {
const RichObject& o = *hg->object;
if(o) {
Size sz = z * o.GetSize();
draw.DrawRect(z * x, z * py.y, sz.cx, z * linecy, (*i)->paper);
draw.Clipoff(z * x, z * (y0 - hg->ascent), sz.cx, sz.cy);
if(pi.sizetracking)
draw.DrawRect(sz, SColorFace);
else
if(pi.usecache) {
RichObjectImageMaker im;
im.object = o;
im.sz = sz;
draw.DrawImage(0, 0, MakeImagePaintOnly(im));
}
else
o.Paint(draw, sz);
draw.End();
}
i++;
hg++;
x += *w++;
i0 = i;
x0 = x;
}
else {
i++;
hg++;
x += *w++;
}
}
if(i > i0)
Flush(draw, pi, text, i0, wd, (int)(i0 - cf), (int)(i - i0), x0, x, y0, py.y, linecy,
lineascent, z, highlight);
if(lni == 0) {
Rect r;
r.left = page.left + format.lm;
int q = li.ascent / 2;
r.top = py.y + 4 * (li.ascent - q) / 5;
r.right = r.left + q;
r.bottom = r.top + q;
q = z * (r.Width() / 4);
r.left = z * r.left;
r.top = z * r.top;
r.right = z * r.right;
r.bottom = z * r.bottom;
Rect r1 = r;
r1.Deflate(max(1, q));
switch(format.bullet) {
case BULLET_BOX:
draw.DrawRect(r, pi.coloroverride ? SColorText() : format.ink);
break;
case BULLET_BOXWHITE:
draw.DrawRect(r, pi.coloroverride ? SColorText() : format.ink);
draw.DrawRect(r1, White);
break;
case BULLET_ROUNDWHITE:
draw.DrawEllipse(r, pi.coloroverride ? SColorText() : format.ink);
draw.DrawEllipse(r1, pi.coloroverride ? SColorPaper() : White);
break;
case BULLET_ROUND:
draw.DrawEllipse(r, pi.coloroverride ? SColorText() : format.ink);
break;
default:
String s = n.AsText(format);
if(!IsNull(s)) {
CharFormat cf = li.len && *pl.format ? **pl.format : format;
cf.Height(z * cf.GetHeight());
draw.DrawText(r.left,
z * y0 - cf.Info().GetAscent(),
s, cf, pi.coloroverride ? SColorText() : cf.ink);
}
}
}
int zlcy = z * linecy;
if(pi.spellingchecker && zlcy > 3) {
int x = z * (li.xpos + page.left);
w = wd;
wl = w + li.len;
int i = li.pos;
int q = z * (py.y + linecy);
while(w < wl) {
if(spellerror[pl.pos[i++]]) {
if(zlcy > 10)
draw.DrawRect(x, q - 3, *w, 1, Red);
draw.DrawRect(x, q - 2, *w, 1, LtRed);
}
x += *w++;
}
}
if(pi.selh == li.ppos + li.plen)
h = x;
if(pi.sell == li.ppos + li.plen)
l = x;
if(pi.sell < li.ppos)
l = page.left;
if(pi.selh > li.ppos + li.plen)
h = page.right;
if(pi.sell < pi.selh && pi.selh > li.ppos)
draw.DrawRect(z * l, z * py.y, z * h - z * l,
z * (py.y + linecy) - z * py.y, InvertColor);
ASSERT(draw.GetCloffLevel() == cloff);
}
else
while(i < ilim) {
if(hg->object)
oi++;
i++;
hg++;
}
py.y += linecy;
}
Size sz = RichTextImg::EndParaChar().GetSize();
if(sz.cy < z * lineascent && !IsNull(pi.showcodes))
pw.Page(py.page).DrawImage(z * x, z * y0 - sz.cy,
RichTextImg::EndParaChar(),
format.indexentry.GetCount() ? pi.indexentry : pi.showcodes);
if(format.newpage && !IsNull(pi.showcodes)) {
Draw& w = pw.Page(opy.page);
int wd = z * page.right - z * page.left;
int step = w.Pixels() ? 8 : 50;
int y = z * opy.y;
for(int x = 0; x < wd; x += step)
w.DrawRect(z * page.left + x, y, step >> 1, step >> 3, pi.showcodes);
}
if(pl.len >= pi.sell && pl.len < pi.selh && py < pi.bottom) {
int top = z * py.y;
pw.Page(py.page).DrawRect(z * page.left, top, z * page.right - z * page.left,
z * min(py.y + format.after, page.bottom) - top, InvertColor);
}
if(format.ruler && hy >= 0 && hy + format.ruler < page.bottom)
pw.Page(phy).DrawRect(z * page.left + z * format.lm, z * hy,
z * page.right - z * page.left - z * format.rm - z * format.lm,
max(1, z * format.ruler), format.rulerink);
}
void RichPara::GetRichPos(RichPos& rp, int pos) const
{
rp.format = format;
int i = FindPart(pos);
if(i < GetCount()) {
const Part& p = part[i];
(CharFormat&)rp.format = p.format;
if(p.object) {
rp.chr = -1;
rp.object = p.object;
}
else
if(p.IsText())
rp.chr = p.text[pos];
else {
rp.chr = -2;
rp.field = p.field;
rp.fieldparam = p.fieldparam;
if(p.fieldpart.GetCount() > 0)
rp.fieldformat = p.fieldpart[0].format;
}
}
else
rp.chr = '\n';
}
RichCaret RichPara::GetCaret(int pos, const Rect& page, PageY py, int nbefore, int nline) const
{
Lines pl = Begin(page, py, nbefore, nline);
RichCaret pr;
FontInfo fi = format.Info();
pr.caretascent = fi.GetAscent();
pr.caretdescent = fi.GetDescent();
for(int lni = 0; lni < pl.GetCount(); lni++) {
Line& li = pl[lni];
int linecy = li.Sum();
if(BreaksPage(py, pl, lni, page)) {
py.y = page.top;
py.page++;
}
pr.page = py.page;
pr.top = py.y;
pr.bottom = py.y + linecy;
pr.lineascent = li.ascent;
pr.line = lni;
if(pos < li.ppos + li.plen) {
int *w = pl.width + li.pos;
int *p = pl.pos + li.pos;
const CharFormat **i = pl.format + li.pos;
const HeightInfo *h = pl.height + li.pos;
int x = li.xpos + page.left;
if(li.len && *i) {
pr.caretascent = h->ascent;
pr.caretdescent = h->descent;
}
while(pos > *p) {
x += *w++;
if(*i) {
pr.caretascent = h->ascent;
pr.caretdescent = h->descent;
}
h++;
i++;
p++;
}
pr.objectcy = h->ascent + h->ydelta;
pr.objectyd = h->ydelta;
pr.left = x;
pr.right = x + *w;
pr.caretdescent = min(pr.caretdescent, pr.Height() - pr.lineascent);
return pr;
}
py.y += linecy;
}
const Line& li = pl.line.Top();
pr.left = li.cx + li.xpos + page.left;
pr.right = page.right;
pr.caretdescent = min(pr.caretdescent, pr.Height() - pr.lineascent);
return pr;
}
int RichPara::PosInLine(int x, const Rect& page, const Lines& pl, int lni) const
{
const Line& li = pl[lni];
const int *w = pl.width + li.pos;
const int *wl = w + li.len;
if(lni < pl.GetCount() - 1 && li.len > 0 && pl.text[li.pos + li.len - 1] == ' ')
wl--;
int xp = li.xpos + page.left;
while(w < wl && xp + *w <= x)
xp += *w++;
int pos = (int)(w - pl.width);
return pos < pl.clen ? pl.pos[pos] : pl.len;
}
int RichPara::GetPos(int x, PageY y, const Rect& page, PageY py, int nbefore, int nline) const
{
Lines pl = Begin(page, py, nbefore, nline);
if(pl.len)
for(int lni = 0; lni < pl.GetCount(); lni++) {
const Line& li = pl[lni];
int linecy = li.Sum();
if(BreaksPage(py, pl, lni, page)) {
py.y = page.top;
py.page++;
}
py.y += linecy;
if(y < py || lni == pl.GetCount() - 1)
return PosInLine(x, page, pl, lni);
}
return pl.len;
}
int RichPara::GetVertMove(int pos, int gx, const Rect& page, int dir) const
{
Lines pl = FormatLines(page.Width());
int lni;
if(pos >= 0) {
for(lni = 0; lni < pl.GetCount() - 1; lni++) {
const Line& li = pl[lni];
if(pos < li.ppos + li.plen)
break;
}
lni += sgn(dir);
if(lni < 0 || lni >= pl.GetCount())
return -1;
}
else
lni = dir < 0 ? pl.GetCount() - 1 : 0;
return PosInLine(gx, page, pl, lni);
}
void RichPara::GatherLabels(Vector<RichValPos>& info, const Rect& page, PageY py,
int pos, int nbefore, int nline) const
{
Lines pl = Begin(page, py, nbefore, nline);
WString ie;
if(!pl.GetCount())
return;
if(BreaksPage(py, pl, 0, page)) {
py.y = page.top;
py.page++;
}
if(format.label.IsEmpty())
return;
RichValPos& f = info.Add();
f.py = py;
f.pos = pos;
f.data = format.label.ToWString();
}
void RichPara::GatherIndexes(Vector<RichValPos>& info, const Rect& page, PageY py,
int pos, int nbefore, int nline) const
{
Lines pl = Begin(page, py, nbefore, nline);
WString ie;
for(int lni = 0; lni < pl.GetCount(); lni++) {
Line& li = pl[lni];
int linecy = li.Sum();
if(BreaksPage(py, pl, lni, page)) {
py.y = page.top;
py.page++;
}
const CharFormat **i0 = pl.format + li.pos;
const CharFormat **i = i0;
const CharFormat **ilim = i + li.len;
while(i < ilim) {
if(*i && (*i)->indexentry != ie) {
ie = (*i)->indexentry;
if(!ie.IsEmpty()) {
RichValPos& f = info.Add();
f.py = py;
f.pos = (int)(i - i0) + pos;
f.data = ie;
}
}
i++;
}
py.y += linecy;
}
}
void FontHeightRound(Font& fnt, Zoom z)
{
fnt.Height((fnt.GetHeight() * z.m + (z.d >> 1)) / z.d);
}
void operator*=(RichPara::Format& format, Zoom z)
{
FontHeightRound(format, z);
format.before *= z;
if(format.ruler) {
format.ruler *= z;
if(format.ruler == 0)
format.ruler = 1;
}
int ll = format.lm + format.indent;
format.lm *= z;
format.indent = z * ll - format.lm;
format.rm *= z;
format.after *= z;
format.tabsize *= z;
for(int i = 0; i < format.tab.GetCount(); i++)
format.tab[i].pos *= z;
}
void RichPara::ApplyZoom(Zoom z)
{
format *= z;
for(int i = 0; i < part.GetCount(); i++)
if(part[i].IsText())
FontHeightRound(part[i].format, z);
else
if(part[i].object)
part[i].object.SetSize(z * part[i].object.GetSize());
}
END_UPP_NAMESPACE

View file

@ -0,0 +1,376 @@
#include "RichText.h"
NAMESPACE_UPP
void RichPara::Smh(Lines& lines, HeightInfo *th, int cx) const
{
Line& l = lines.line.Top();
l.ascent = l.descent = l.external = 0;
const HeightInfo *he = th + l.pos + l.len;
for(const HeightInfo *h = th + l.pos; h < he; h++) {
if(h->ascent > l.ascent) l.ascent = h->ascent;
if(h->descent > l.descent) l.descent = h->descent;
if(h->external > l.external) l.external = h->external;
}
if(format.linespacing == LSP15) {
l.ascent = (3 * l.ascent) >> 1;
l.descent = (3 * l.descent) >> 1;
}
if(format.linespacing == LSP20) {
l.ascent = 2 * l.ascent;
l.descent = 2 * l.descent;
}
l.xpos = format.lm;
cx -= format.lm + format.rm;
l.xpos += lines.GetCount() == 1 ? lines.first_indent : lines.next_indent;
if(!l.withtabs)
switch(format.align) {
case ALIGN_RIGHT:
l.xpos += cx - l.cx;
break;
case ALIGN_CENTER:
l.xpos += (cx - l.cx) / 2;
break;
}
l.cx -= lines.GetCount() == 1 ? lines.first_indent : lines.next_indent;
}
RichPara::Tab RichPara::GetNextTab(int pos) const
{
int tabi = -1;
int dist = INT_MAX;
for(int i = 0; i < format.tab.GetCount(); i++) {
const Tab& tab = format.tab[i];
if(tab.pos > pos && tab.pos - pos < dist) {
tabi = i;
dist = tab.pos - pos;
}
}
if(format.bullet == BULLET_TEXT) {
int q = format.indent + format.lm;
if(q > pos && q - pos < dist) {
Tab tab;
tab.align = ALIGN_LEFT;
tab.pos = q;
return tab;
}
}
if(tabi < 0) {
Tab tab;
tab.pos = format.tabsize ? (pos + format.tabsize) / format.tabsize * format.tabsize : 0;
tab.align = ALIGN_LEFT;
return tab;
}
return format.tab[tabi];
}
struct RichPara::StorePart {
wchar *t;
int *w;
int *p;
const CharFormat **f;
HeightInfo *h;
int pos;
FontInfo pfi;
void Store(Lines& lines, const Part& p, int pinc);
};
void RichPara::StorePart::Store(Lines& lines, const Part& part, int pinc)
{
if(part.field && pinc) {
for(int i = 0; i < part.fieldpart.GetCount(); i++)
Store(lines, part.fieldpart[i], 0);
pos++;
}
else
if(part.object) {
*f++ = &part.format;
Size sz = part.object.GetSize();
*w++ = sz.cx;
h->ydelta = part.object.GetYDelta();
h->ascent = sz.cy - h->ydelta;
h->descent = max(h->ydelta, 0);
h->external = 0;
h->object = &part.object;
h++;
*t++ = 'x';
*p++ = pos;
pos += pinc;
}
else {
const wchar *s = part.text;
const wchar *lim = part.text.End();
Font fnt = part.format;
FontInfo fi = fnt.Info();
FontInfo wfi = fi;
if(part.format.sscript) {
fnt.Height(fnt.GetHeight() * 3 / 5);
wfi = fnt.Info();
}
if(part.format.capitals) {
CharFormat& cfmt = lines.hformat.Add();
cfmt = part.format;
cfmt.Height(cfmt.GetHeight() * 4 / 5);
FontInfo cfi = cfmt.Info();
FontInfo cwfi = cfi;
if(part.format.sscript) {
Font fnt = cfmt;
fnt.Height(fnt.GetHeight() * 3 / 5);
cwfi = fnt.Info();
}
while(s < lim) {
wchar c = *s++;
if(c == 9) {
*f++ = &part.format;
h->ascent = pfi.GetAscent();
h->descent = pfi.GetDescent();
h->external = pfi.GetExternal();
*w++ = 0;
}
else
if(IsLower(c)) {
*f++ = &cfmt;
c = ToUpper(c);
h->ascent = cfi.GetAscent();
h->descent = cfi.GetDescent();
h->external = cfi.GetExternal();
*w++ = c >= 32 ? cwfi[c] : 0;
}
else {
*f++ = &part.format;
h->ascent = fi.GetAscent();
h->descent = fi.GetDescent();
h->external = fi.GetExternal();
*w++ = c >= 32 ? wfi[c] : 0;
}
h->object = NULL;
*t++ = c;
*p++ = pos;
pos += pinc;
h++;
}
}
else {
while(s < lim) {
wchar c = *s++;
*f++ = &part.format;
if(c == 9) {
h->ascent = pfi.GetAscent();
h->descent = pfi.GetDescent();
h->external = pfi.GetExternal();
}
else {
h->ascent = fi.GetAscent();
h->descent = fi.GetDescent();
h->external = fi.GetExternal();
}
h->object = NULL;
*p++ = pos;
pos += pinc;
h++;
*w++ = c >= 32 ? wfi[c] : 0;
*t++ = c;
}
}
}
}
static int CountChars(const Array<RichPara::Part>& part)
{
int n = 0;
for(int i = 0; i < part.GetCount(); i++) {
const RichPara::Part& p = part[i];
if(p.field)
n += CountChars(p.fieldpart);
else
n += p.GetLength();
}
return n;
}
RichPara::Lines RichPara::FormatLines(int acx) const
{
int i;
Lines lines;
lines.cx = acx;
lines.len = GetLength();
lines.clen = CountChars(part);
lines.first_indent = lines.next_indent = format.indent;
if(format.bullet == BULLET_TEXT)
lines.first_indent = 0;
else
if(!format.bullet && !format.IsNumbered())
lines.next_indent = 0;
FontInfo pfi = format.Info();
if(lines.len == 0) {
Line& l = lines.line.Add();
l.pos = 0;
l.ppos = 0;
l.plen = 0;
l.len = 0;
l.cx = lines.first_indent;
l.withtabs = false;
HeightInfo dummy;
Smh(lines, &dummy, lines.cx);
l.ascent = pfi.GetAscent();
l.descent = pfi.GetDescent();
l.external = pfi.GetExternal();
return lines;
}
lines.text.Alloc(lines.clen);
lines.width.Alloc(lines.clen);
lines.pos.Alloc(lines.clen);
lines.format.Alloc(lines.clen);
lines.height.Alloc(lines.clen);
StorePart sp;
sp.t = lines.text;
sp.w = lines.width;
sp.p = lines.pos;
sp.f = lines.format;
sp.h = lines.height;
sp.pfi = pfi;
sp.pos = 0;
for(i = 0; i < part.GetCount(); i++)
sp.Store(lines, part[i], 1);
wchar *s = lines.text;
wchar *text = s;
wchar *end = lines.text + lines.clen;
wchar *space = NULL;
int *w = lines.width;
int cx = lines.first_indent;
int rcx = lines.cx - format.lm - format.rm;
bool withtabs = false;
int scx;
while(s < end) {
Tab t;
if(*s == ' ') {
space = s;
scx = cx;
}
else {
if(*s == '\t') {
t = GetNextTab(cx + format.lm);
space = NULL;
}
if(cx + *w > rcx && s > text || *s == '\t' && t.pos - format.lm >= rcx) {
Line& l = lines.line.Add();
l.withtabs = withtabs;
l.pos = (int)(text - lines.text);
if(space) {
l.len = (int)(space - text) + 1;
l.cx = scx;
text = s = space + 1;
}
else {
l.len = (int)(s - text);
l.cx = cx;
text = s;
}
Smh(lines, lines.height, lines.cx);
cx = lines.next_indent;
w = text - ~lines.text + lines.width;
space = NULL;
rcx = lines.cx - format.lm - format.rm;
withtabs = false;
t = GetNextTab(cx + format.lm);
}
}
if(*s == '\t') {
*s += t.fillchar;
if(t.align == ALIGN_LEFT) {
*w++ = t.pos - format.lm - cx;
cx = t.pos - format.lm;
}
else {
int tcx = 0;
int *tw = w + 1;
for(wchar *ts = s + 1; ts < end && *ts != '\t'; ts++)
tcx += *tw++;
int ww = t.pos - format.lm - cx - (t.align == ALIGN_RIGHT ? tcx : tcx / 2);
if(ww > 0) {
*w++ = ww;
cx += ww;
}
else
*w++ = 0;
}
withtabs = true;
}
else
cx += *w++;
s++;
}
Line& l = lines.line.Add();
l.withtabs = withtabs;
l.pos = (int)(text - lines.text);
l.len = (int)(s - text);
l.cx = cx;
Smh(lines, lines.height, lines.cx);
for(i = 0; i < lines.line.GetCount(); i++) {
Line& l = lines.line[i];
l.ppos = lines.pos[l.pos];
l.plen = (l.pos + l.len < lines.clen ? lines.pos[l.pos + l.len] : lines.len) - l.ppos;
}
return lines;
}
void RichPara::Lines::Justify(const RichPara::Format& format)
{
if(format.align != ALIGN_JUSTIFY) return;
for(int i = 0; i < line.GetCount() - 1; i++) {
const Line& li = line[i];
if(!li.withtabs && li.len) {
const wchar *s = ~text + li.pos;
const wchar *lim = s + li.len;
while(lim - 1 > s) {
if(*(lim - 1) != ' ') break;
lim--;
}
while(s < lim) {
if(*s != ' ' && *s != 160) break;
s++;
}
const wchar *beg = s;
int nspc = 0;
while(s < lim) {
if(*s == ' ' || *s == 160) nspc++;
s++;
}
s = beg;
if(nspc) {
int q = ((cx - format.lm - format.rm -
(i == 0 ? first_indent : next_indent) - li.cx) << 16)
/ nspc;
int *w = beg - ~text + width;
int prec = 0;
while(s < lim) {
if(*s == ' ' || *s == 160) {
*w += (prec + q) >> 16;
prec = (prec + q) & 0xffff;
}
w++;
s++;
}
}
}
}
}
int RichPara::Lines::BodyHeight()
{
int sum = 0;
for(int i = 0; i < line.GetCount(); i++)
sum += line[i].Sum();
return sum;
}
END_UPP_NAMESPACE

View file

@ -0,0 +1,967 @@
#include "RichText.h"
NAMESPACE_UPP
Color (*QTFColor[])() = {
Black, LtGray, White, Red, Green, Blue, LtRed, WhiteGray, LtCyan, Yellow
};
Color (*QTFSColor[])()= {
SColorText, SColorFace, SColorPaper, Red, Green, Blue, LtRed, WhiteGray, LtCyan, Yellow
};
Color NullColorF()
{
return Null;
}
static Color (*QTFColorl[])() = {
/*a*/White, /*b*/Blue, /*c*/Cyan, /*d*/White, /*e*/White, /*f*/White, /*g*/ Green, /*h*/White,
/*i*/White, /*j*/White, /*k*/Black, /*l*/LtGray, /*m*/Magenta, /*n*/NullColorF, /*o*/Brown, /*p*/White,
/*q*/White, /*r*/Red, /*s*/White, /*t*/White, /*u*/White, /*v*/White, /*w*/WhiteGray, /*x*/White,
/*y*/Yellow, /*z*/ White
};
static Color (*QTFColorL[])() = {
/*A*/White, /*B*/LtBlue, /*C*/LtCyan, /*D*/White, /*E*/White, /*F*/White, /*G*/LtGreen, /*H*/White,
/*I*/White, /*J*/White, /*K*/Gray, /*L*/WhiteGray, /*M*/LtMagenta, /*N*/NullColorF, /*O*/Brown, /*P*/White,
/*Q*/White, /*R*/LtRed, /*S*/White, /*T*/White, /*U*/White, /*V*/White, /*W*/White, /*X*/White,
/*Y*/LtYellow, /*Z*/White
};
static Color (*QTFSColorl[])() = { //TODO
/*a*/SColorPaper, /*b*/SColorHighlight, /*c*/Cyan, /*d*/SColorPaper, /*e*/SColorPaper, /*f*/SColorPaper, /*g*/ Green, /*h*/SColorPaper,
/*i*/SColorPaper, /*j*/SColorPaper, /*k*/SColorText, /*l*/SColorFace, /*m*/Magenta, /*n*/NullColorF, /*o*/Brown, /*p*/SColorPaper,
/*q*/SColorPaper, /*r*/Red, /*s*/SColorPaper, /*t*/SColorPaper, /*u*/SColorPaper, /*v*/SColorPaper, /*w*/WhiteGray, /*x*/SColorPaper,
/*y*/Yellow, /*z*/ White
};
static Color (*QTFSColorL[])() = { //TODO
/*A*/SColorPaper, /*B*/LtBlue, /*C*/LtCyan, /*D*/SColorPaper, /*E*/SColorPaper, /*F*/SColorPaper, /*G*/LtGreen, /*H*/SColorPaper,
/*I*/SColorPaper, /*J*/SColorPaper, /*K*/SColorShadow, /*L*/WhiteGray, /*M*/LtMagenta, /*N*/NullColorF, /*O*/Brown, /*P*/SColorPaper,
/*Q*/SColorPaper, /*R*/LtRed, /*S*/SColorPaper, /*T*/SColorPaper, /*U*/SColorPaper, /*V*/SColorPaper, /*W*/SColorPaper, /*X*/SColorPaper,
/*Y*/LtYellow, /*Z*/White
};
int QTFFontHeight[] = {
50, 67, 84, 100, 134, 167, 200, 234, 300, 400
};
class RichQtfParser {
const char *term;
bool scolors;
WString text;
RichPara paragraph;
RichTable tablepart;
bool istable;
bool breakpage;
byte accesskey;
struct PFormat : public RichPara::Format {
byte charset;
};
struct Tab {
RichCell::Format format;
int vspan, hspan;
RichTxt text;
RichTable table;
int cell;
Vector<int> rown;
void Old() { RichTable::Format fmt; fmt.grid = 10; table.SetFormat(fmt); }
Tab() { cell = 0; vspan = hspan = 0; }
};
PFormat format;
Array<PFormat> fstack;
Vector<Uuid> styleid;
Vector<int> stylenext;
Array<Tab> table;
bool oldtab;
bool Key(int c) { if(*term == c) { term++; return true; } return false; }
bool Key2(int c, int d);
bool Key2(int c) { return Key2(c, c); }
int GetNumber();
int ReadNumber();
String GetText(int delim);
Color GetColor();
void Number2(int& a, int& b);
void Flush();
void SetFormat();
void FlushStyles();
void Error(const char *s);
void ReadObject();
RichTable& Table();
void TableFormat(bool bw = false);
void FinishCell();
void FinishTable();
void FinishOldTable();
void S(int& x, int a);
void EndPart();
void Cat(int chr);
public:
struct Exc {};
RichText target;
void Parse(const char *qtf, byte accesskey);
RichQtfParser(bool scolors);
};
void init_s_nodeqtf();
RichQtfParser::RichQtfParser(bool _scolors)
{
format.Face(Font::ARIAL);
format.Height(100);
format.charset = GetDefaultCharset();
format.language = 0;
breakpage = false;
istable = false;
oldtab = false;
init_s_nodeqtf();
scolors = _scolors;
}
bool RichQtfParser::Key2(int c, int d)
{
if(term[0] == c && term[1] == d) {
term += 2;
return true;
}
return false;
}
int RichQtfParser::GetNumber()
{
int n = 0;
int sgn = 1;
if(*term == '-') {
sgn = -1;
term++;
}
while(IsDigit(*term))
n = n * 10 + *term++ - '0';
return sgn * n;
}
String RichQtfParser::GetText(int delim) {
String s;
for(;;) {
if(*term == '\0') return s;
if(*term == '`') {
term++;
if(*term == '\0') return s;
s.Cat(*term++);
}
else
if(*term == delim) {
term++;
return s;
}
else
s.Cat(*term++);
}
}
int RichQtfParser::ReadNumber()
{
if(!IsDigit(*term))
Error("Expected number");
return GetNumber();
}
void RichQtfParser::Number2(int& a, int& b)
{
a = -1;
b = -1;
if(IsDigit(*term))
a = GetNumber();
if(*term == '/') {
term++;
b = GetNumber();
}
}
Color RichQtfParser::GetColor()
{
int c = *term++;
if(c == '(') {
byte r = GetNumber();
if(Key(')')) {
r &= 255;
return Color(r, r, r);
}
Key('.');
byte g = GetNumber();
Key('.');
byte b = GetNumber();
Key(')');
return Color(r & 255, g & 255, b & 255);
}
else
if(c >= '0' && c <= '9')
return (*((scolors ? QTFSColor : QTFColor)[c - '0']))();
else
if(c >= 'a' && c <= 'z')
return (*((scolors ? QTFSColorl : QTFColorl)[c - 'a']))();
else
if(c >= 'A' && c <= 'Z')
return (*((scolors ? QTFSColorL : QTFColorL)[c - 'A']))();
else
return Red;
}
void RichQtfParser::SetFormat()
{
paragraph.format = format;
}
void RichQtfParser::Flush() {
if(text.GetLength()) {
ASSERT(!istable);
paragraph.Cat(text, format);
text.Clear();
}
}
void RichQtfParser::EndPart()
{
if(istable) {
if(paragraph.GetCount() == 0 && text.GetCount() == 0)
if(table.GetCount())
table.Top().text.CatPick(tablepart);
else
target.CatPick(tablepart);
else {
paragraph.part.Clear();
text.Clear();
}
}
else {
Flush();
bool b = paragraph.format.newpage;
if(breakpage)
paragraph.format.newpage = true;
if(table.GetCount())
table.Top().text.Cat(paragraph, target.GetStyles());
else
target.Cat(paragraph);
paragraph.part.Clear();;
paragraph.format.newpage = b;
SetFormat();
breakpage = false;
}
istable = false;
}
void RichQtfParser::ReadObject()
{
Flush();
RichObject obj;
if(*term == '#') {
term++;
#ifdef CPU_64
obj = *(RichObject *)stou64(term, &term);
#else
obj = *(RichObject *)stou(term, &term);
#endif
term++;
}
else {
String type;
while(IsAlNum(*term) || *term == '_')
type.Cat(*term++);
Size sz;
Key(':');
sz.cx = ReadNumber();
bool keepratio = false;
if(Key('&'))
keepratio = true;
else
Key('*');
sz.cy = ReadNumber();
int yd = 0;
if(Key('/'))
yd = GetNumber();
StringBuffer data;
for(;;) {
while(*term < 32 && *term > 0) term++;
if((byte)*term >= ' ' && (byte)*term <= 127 || *term == '\0') break;
byte seven = *term++;
for(int i = 0; i < 7; i++) {
while((byte)*term < 32 && (byte)*term > 0) term++;
if((byte)*term >= ' ' && (byte)*term <= 127 || *term == '\0') break;
data.Cat((*term++ & 0x7f) | ((seven << 7) & 0x80));
seven >>= 1;
}
}
obj.Read(type, data, sz);
obj.KeepRatio(keepratio);
obj.SetYDelta(yd);
}
paragraph.Cat(obj, format);
}
int NoLow(int c) {
return (byte)c >= 32 ? c : 0;
}
void RichQtfParser::Error(const char *s) {
RichPara::CharFormat ef;
(Font&) ef = Arial(84).Bold().Underline();
ef.ink = Red;
paragraph.Cat(("ERROR: " + String(s) + ": " +
Filter(String(term, min<int>((int)strlen(term), 20)), NoLow)).ToWString(), ef);
target.Cat(paragraph);
FlushStyles();
throw Exc();
}
void RichQtfParser::FlushStyles()
{
for(int i = 0; i < styleid.GetCount(); i++)
if(stylenext[i] >= 0 && stylenext[i] < styleid.GetCount()) {
RichStyle s = target.GetStyle(styleid[i]);
s.next = styleid[stylenext[i]];
target.SetStyle(styleid[i], s);
}
}
RichTable& RichQtfParser::Table()
{
if(table.GetCount() == 0)
Error("Not in table");
return table.Top().table;
}
void RichQtfParser::S(int& x, int a)
{
if(a >= 0)
x = a;
}
void RichQtfParser::TableFormat(bool bw)
{
RichTable& tab = Table();
Tab& t = table.Top();
int a, b;
for(;;) {
if(bw && IsDigit(*term)) {
t.hspan = GetNumber();
}
else
switch(*term++) {
case ' ': return;
case ';': break;
case '<': tab.format.lm = ReadNumber(); break;
case '>': tab.format.rm = ReadNumber(); break;
case 'B': tab.format.before = ReadNumber(); break;
case 'A': tab.format.after = ReadNumber(); break;
case 'f': tab.format.frame = ReadNumber(); break;
case '_':
case 'F': tab.format.framecolor = GetColor(); break;
case 'g': tab.format.grid = ReadNumber(); break;
case 'G': tab.format.gridcolor = GetColor(); break;
case 'h': tab.format.header = GetNumber(); break;
case '~': tab.format.frame = tab.format.grid = 0; break;
case '^': t.format.align = ALIGN_TOP; break;
case '=': t.format.align = ALIGN_CENTER; break;
case 'v': t.format.align = ALIGN_BOTTOM; break;
case 'l': Number2(a, b); S(t.format.border.left, a); S(t.format.margin.left, b); break;
case 'r': Number2(a, b); S(t.format.border.right, a); S(t.format.margin.right, b); break;
case 't': Number2(a, b); S(t.format.border.top, a); S(t.format.margin.top, b); break;
case 'b': Number2(a, b); S(t.format.border.bottom, a); S(t.format.margin.bottom, b); break;
case 'H': t.format.minheight = ReadNumber(); break;
case '@': t.format.color = GetColor(); break;
case 'R': t.format.bordercolor = GetColor(); break;
case '!': t.format = RichCell::Format(); break;
case 'k': t.format.keep = true;
case 'K': tab.format.keep = true;
case 'a':
Number2(a, b);
if(a >= 0)
t.format.border.left = t.format.border.right = t.format.border.top = t.format.border.bottom = a;
if(b >= 0)
t.format.margin.left = t.format.margin.right = t.format.margin.top = t.format.margin.bottom = b;
break; //!!cell all lines
case '-': t.hspan = GetNumber(); break;
case '+':
case '|': t.vspan = GetNumber(); break;
default:
Error("Invalid cell format");
}
}
}
void RichQtfParser::FinishCell()
{
EndPart();
RichTable& t = Table();
Tab& b = table.Top();
int i, j;
if(oldtab) {
i = b.rown.GetCount() - 1;
j = b.rown.Top();
b.rown.Top()++;
}
else {
i = b.cell / t.GetColumns();
j = b.cell % t.GetColumns();
}
t.SetPick(i, j, b.text);
b.text.Clear();
t.SetFormat(i, j, b.format);
t.SetSpan(i, j, b.vspan, b.hspan);
if(oldtab && b.rown.GetCount() > 1 && j + 1 < b.rown[0])
b.format = t.GetFormat(0, j + 1);
else {
b.cell++;
b.vspan = 0;
b.hspan = oldtab;
}
b.format.keep = false;
}
void RichQtfParser::FinishTable()
{
FinishCell();
tablepart = Table();
istable = true;
table.Drop();
}
void RichQtfParser::FinishOldTable()
{
FinishCell();
Index<int> pos;
Vector<int> srow;
RichTable& t = Table();
Tab& b = table.Top();
for(int i = 0; i < t.GetRows(); i++) {
int& s = srow.Add();
s = 0;
int nx = b.rown[i];
for(int j = 0; j < nx; j++)
s += t.GetSpan(i, j).cx;
int xn = 0;
for(int j = 0; j < nx; j++) {
pos.FindAdd(xn * 10000 / s);
xn += t.GetSpan(i, j).cx;
}
}
Vector<int> h = pos.PickKeys();
if(h.GetCount() == 0)
Error("table");
Sort(h);
pos = h;
pos.Add(10000);
RichTable tab;
tab.SetFormat(t.GetFormat());
for(int i = 0; i < pos.GetCount() - 1; i++) {
tab.AddColumn(pos[i + 1] - pos[i]);
}
for(int i = 0; i < t.GetRows(); i++) {
int s = srow[i];
int nx = b.rown[i];
int xn = 0;
int xi = 0;
for(int j = 0; j < nx; j++) {
Size span = t.GetSpan(i, j);
xn += span.cx;
int nxi = pos.Find(xn * 10000 / s);
tab.SetPick(i, xi, t.GetPick(i, j));
tab.SetFormat(i, xi, t.GetFormat(i, j));
tab.SetSpan(i, xi, max(span.cy - 1, 0), nxi - xi - 1);
xi = nxi;
}
}
table.Drop();
if(table.GetCount())
table.Top().text.CatPick(tab);
else
target.CatPick(tab);
oldtab = false;
}
void RichQtfParser::Cat(int chr)
{
if(accesskey && ToUpper(ToAscii(chr)) == accesskey) {
Flush();
format.Underline(!format.IsUnderline());
text.Cat(chr);
Flush();
format.Underline(!format.IsUnderline());
accesskey = 0;
}
else {
text.Cat(chr);
}
}
extern bool s_nodeqtf[128];
void RichQtfParser::Parse(const char *qtf, byte _accesskey)
{
accesskey = _accesskey;
term = qtf;
while(*term) {
if(Key('[')) {
Flush();
fstack.Add(format);
for(;;) {
int c = *term;
if(!c)
Error("Unexpected end of text");
term++;
if(c == ' ' || c == '\n') break;
switch(c) {
case 's': {
Uuid id;
c = *term;
if(Key('\"') || Key('\''))
id = target.GetStyleId(GetText(c));
else {
int i = ReadNumber();
if(i >= 0 && i < styleid.GetCount())
id = styleid[i];
else
id = RichStyle::GetDefaultId();
}
const RichStyle& s = target.GetStyle(id);
bool p = format.newpage;
int lng = format.language;
(RichPara::Format&) format = s.format;
format.styleid = id;
format.language = lng;
format.newpage = p;
break;
}
case '/': format.Italic(!format.IsItalic()); break;
case '*': format.Bold(!format.IsBold()); break;
case '_': format.Underline(!format.IsUnderline()); break;
case 'T': format.NonAntiAliased(!format.IsNonAntiAliased()); break;
case '-': format.Strikeout(!format.IsStrikeout()); break;
case 'c': format.capitals = !format.capitals; break;
case 'd': format.dashed = !format.dashed; break;
case '`': format.sscript = format.sscript == 1 ? 0 : 1; break;
case ',': format.sscript = format.sscript == 2 ? 0 : 2; break;
case '^': format.link = GetText('^'); break;
case 'I': format.indexentry = FromUtf8(GetText(';')); break;
case '+': format.Height(GetNumber()); break;
case '@': format.ink = GetColor(); break;
case '$': format.paper = GetColor(); break;
case 'A': format.Face(Font::ARIAL); break;
case 'R': format.Face(Font::ROMAN); break;
case 'C': format.Face(Font::COURIER); break;
case 'G': format.Face(Font::STDFONT); break;
case 'S': format.Face(Font::SYMBOL); break;
case '.': {
int n = GetNumber();
if(n >= Font::GetFaceCount())
Error("Invalid face number");
format.Face(n); break;
}
case '!': {
String fn = GetText('!');
int i = Font::FindFaceNameIndex(fn);
if(i < 0)
i = Font::ARIAL;
format.Face(i);
}
break;
case '{': {
String cs = GetText('}');
if(cs.GetLength() == 1) {
int c = *cs;
if(c == '_')
format.charset = CHARSET_UTF8;
if(c >= '0' && c <= '8')
format.charset = c - '0' + CHARSET_WIN1250;
if(c >= 'A' && c <= 'Z')
format.charset = c - '0' + CHARSET_ISO8859_1;
}
else {
for(int i = 0; i < CharsetCount(); i++)
if(stricmp(CharsetName(i), cs) == 0) {
format.charset = i;
break;
}
}
break;
}
case '%': {
String h;
if(*term == '-') {
format.language = 0;
term++;
}
else
if(*term == '%') {
format.language = LNG_ENGLISH;
term++;
}
else {
while(*term && h.GetLength() < 5)
h.Cat(*term++);
format.language = LNGFromText(h);
}
break;
}
default:
if(c >= '0' && c <= '9') {
format.Height(QTFFontHeight[c - '0']);
break;
}
switch(c) {
case ':': format.label = GetText(':'); break;
case '<': format.align = ALIGN_LEFT; break;
case '>': format.align = ALIGN_RIGHT; break;
case '=': format.align = ALIGN_CENTER; break;
case '#': format.align = ALIGN_JUSTIFY; break;
case 'l': format.lm = GetNumber(); break;
case 'r': format.rm = GetNumber(); break;
case 'i': format.indent = GetNumber(); break;
case 'b': format.before = GetNumber(); break;
case 'a': format.after = GetNumber(); break;
case 'P': format.newpage = !format.newpage; break;
case 'k': format.keep = !format.keep; break;
case 'K': format.keepnext = !format.keepnext; break;
case 'H': format.ruler = GetNumber(); break;
case 'h': format.rulerink = GetColor(); break;
case 'Q': format.orphan = !format.orphan; break;
case 'n': format.before_number = GetText(';'); break;
case 'm': format.after_number = GetText(';'); break;
case 'N': {
memset(format.number, 0, sizeof(format.number));
format.reset_number = false;
int i = 0;
while(i < 8) {
int c;
if(Key('-'))
c = RichPara::NUMBER_NONE;
else
if(Key('1'))
c = RichPara::NUMBER_1;
else
if(Key('0'))
c = RichPara::NUMBER_0;
else
if(Key('a'))
c = RichPara::NUMBER_a;
else
if(Key('A'))
c = RichPara::NUMBER_A;
else
if(Key('i'))
c = RichPara::NUMBER_i;
else
if(Key('I'))
c = RichPara::NUMBER_I;
else
break;
format.number[i++] = c;
}
if(Key('!'))
format.reset_number = true;
break;
}
case 'o': format.bullet = RichPara::BULLET_ROUND;
format.indent = 150; break;
case 'O':
if(Key('_'))
format.bullet = RichPara::BULLET_NONE;
else {
int c = *term++;
if(!c)
Error("Unexpected end of text");
format.bullet =
c == '1' ? RichPara::BULLET_ROUNDWHITE :
c == '2' ? RichPara::BULLET_BOX :
c == '3' ? RichPara::BULLET_BOXWHITE :
c == '9' ? RichPara::BULLET_TEXT :
RichPara::BULLET_ROUND;
}
break;
case 'p':
switch(*term++) {
case 0: Error("Unexpected end of text");
case 'h': format.linespacing = RichPara::LSP15; break;
case 'd': format.linespacing = RichPara::LSP20; break;
default: format.linespacing = RichPara::LSP10;
}
break;
case 't':
if(IsDigit(*term)) //temporary fix... :(
format.tabsize = ReadNumber();
break;
case '~': {
if(Key('~'))
format.tab.Clear();
else {
RichPara::Tab tab;
Key('<');
if(Key('>'))
tab.align = ALIGN_RIGHT;
if(Key('='))
tab.align = ALIGN_CENTER;
if(Key('.'))
tab.fillchar = 1;
if(Key('-'))
tab.fillchar = 2;
if(Key('_'))
tab.fillchar = 3;
tab.pos = ReadNumber();
format.tab.Add(tab);
}
}
break;
default:
continue;
}
}
}
SetFormat();
}
else
if(Key(']')) {
Flush();
if(fstack.GetCount()) {
format = fstack.Top();
fstack.Drop();
}
else
Error("Unmatched ']'");
}
else
if(Key2('{')) {
if(oldtab)
Error("{{ in ++ table");
if(text.GetLength() || paragraph.GetCount())
EndPart();
table.Add();
int r = IsDigit(*term) ? ReadNumber() : 1;
Table().AddColumn(r);
while(Key(':'))
Table().AddColumn(ReadNumber());
TableFormat();
}
else
if(Key2('}')) {
if(oldtab)
Error("}} in ++ table");
FinishTable();
}
else
if(Key2('+'))
if(oldtab)
FinishOldTable();
else {
Flush();
if(text.GetLength() || paragraph.GetCount())
EndPart();
Tab& b = table.Add();
b.rown.Add(0);
b.hspan = 1;
b.Old();
oldtab = true;
}
else
if(Key2('|'))
FinishCell();
else
if(Key2('-')) {
FinishCell();
table.Top().rown.Add(0);
}
else
if(Key2(':')) {
if(!oldtab)
FinishCell();
TableFormat(oldtab);
}
else
if(Key2('^')) {
EndPart();
breakpage = true;
}
else
if(Key2('@')) {
ReadObject();
}
else
if(Key2('@', '$')) {
String xu;
while(isxdigit(*term))
xu.Cat(*term++);
int c = stou(~xu, NULL, 16);
if(c >= 32)
Cat(c);
if(*term == ';')
term++;
SetFormat();
}
else
if(Key2('{', ':')) {
Flush();
String field = GetText(':');
String param = GetText(':');
Id fid(field);
if(RichPara::fieldtype().Find(fid) >= 0)
paragraph.Cat(fid, param, format);
Key('}');
}
else
if(Key('&')) {
SetFormat();
EndPart();
}
else
if(Key2('$')) {
Flush();
int i = GetNumber();
Uuid id;
RichStyle style;
style.format = format;
if(Key(','))
stylenext.At(i, 0) = GetNumber();
else
stylenext.At(i, 0) = i;
if(Key('#')) {
String xu;
while(isxdigit(*term))
xu.Cat(*term++);
if(xu.GetLength() != 32)
Error("Invalid UUID !");
id = ScanUuid(xu);
}
else
if(i)
id = Uuid::Create();
else
id = RichStyle::GetDefaultId();
if(Key(':'))
style.name = GetText(']');
if(fstack.GetCount()) {
format = fstack.Top();
fstack.Drop();
}
target.SetStyle(id, style);
styleid.At(i, RichStyle::GetDefaultId()) = id;
if(id == RichStyle::GetDefaultId()) {
bool p = format.newpage;
int lng = format.language;
(RichPara::Format&) format = style.format;
format.styleid = id;
format.language = lng;
format.newpage = p;
}
}
else
if(*term == '_') {
SetFormat();
text.Cat(160);
term++;
}
else
if(Key2('-', '|')) {
SetFormat();
text.Cat(9);
}
else
if(*term == '\1') {
if(istable)
EndPart();
SetFormat();
const char *b = ++term;
for(; *term && *term != '\1'; term++)
if(*term == '\n') {
text.Cat(ToUnicode(b, (int)(term - b), format.charset));
EndPart();
b = term + 1;
}
text.Cat(ToUnicode(b, (int)(term - b), format.charset));
if(*term == '\1')
term++;
}
else {
if(!Key('`')) Key('\\');
if((byte)*term >= ' ') {
SetFormat();
do {
if(istable)
EndPart();
if(format.charset == CHARSET_UTF8) {
word code = (byte)*term++;
if(code <= 0x7F)
Cat(code);
else
if(code <= 0xDF) {
if(*term == '\0') break;
int c0 = (byte)*term++;
if(c0 < 0x80)
Error("Invalid UTF-8 sequence");
Cat(((code - 0xC0) << 6) + c0 - 0x80);
}
else
if(code <= 0xEF) {
int c0 = (byte)*term++;
int c1 = (byte)*term++;
if(c0 < 0x80 || c1 < 0x80)
Error("Invalid UTF-8 sequence");
Cat(((code - 0xE0) << 12) + ((c0 - 0x80) << 6) + c1 - 0x80);
}
else
Error("Invalid UTF-8 sequence");
}
else
Cat(ToUnicode((byte)*term++, format.charset));
}
while((byte)*term >= 128 || s_nodeqtf[(byte)*term]);
}
else
if(*term)
term++;
}
}
if(paragraph.GetCount() == 0)
SetFormat();
if(oldtab)
FinishOldTable();
else
while(table.GetCount())
FinishTable();
EndPart();
FlushStyles();
}
RichText ParseQTF(const char *qtf, bool scolors, byte accesskey)
{
RichQtfParser p(scolors);
try {
p.Parse(qtf, accesskey);
}
catch(RichQtfParser::Exc) {}
return p.target;
}
String QtfRichObject::ToString() const
{
return String("@@#").Cat() << uintptr_t(&obj) << ";";
}
QtfRichObject::QtfRichObject(const RichObject& o)
: obj(o)
{}
END_UPP_NAMESPACE

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,237 @@
#include "RichText.h"
NAMESPACE_UPP
#ifdef NEWIMAGE
struct RichImage : public RichObjectType {
virtual String GetTypeName(const Value& v) const;
virtual Size GetPhysicalSize(const Value& data) const;
virtual Size GetPixelSize(const Value& data) const;
virtual void Paint(const Value& data, Draw& w, Size sz) const;
virtual Image ToImage(const Value& data, Size sz) const;
virtual bool Accept(PasteClip& clip);
virtual Value Read(PasteClip& clip);
virtual String GetClipFmts() const;
virtual String GetClip(const Value& data, const String& fmt) const;
typedef RichImage CLASSNAME;
};
String RichImage::GetTypeName(const Value& v) const
{
return "image";
}
bool RichImage::Accept(PasteClip& clip)
{
return AcceptImage(clip);
}
Value RichImage::Read(PasteClip& clip)
{
return StoreImageAsString(GetImage(clip));
}
String RichImage::GetClipFmts() const
{
return ClipFmtsImage();
}
String RichImage::GetClip(const Value& data, const String& fmt) const
{
return GetImageClip(LoadImageFromString(data), fmt);
}
Size RichImage::GetPixelSize(const Value& data) const
{
return GetImageStringSize(data);
}
Size RichImage::GetPhysicalSize(const Value& data) const
{
Size sz = GetImageStringDots(data);
if(sz.cx == 0 || sz.cy == 0)
sz = 600 * GetPixelSize(data) / 96;
return sz;
}
void RichImage::Paint(const Value& data, Draw& w, Size sz) const
{
Image x = LoadImageFromString(data);
// Size outsz(min(sz.cx, 4 * x.GetWidth()), min(sz.cy, 4 * x.GetHeight()));
w.DrawImage(0, 0, sz.cx, sz.cy, x);
}
Image RichImage::ToImage(const Value& data, Size sz) const
{
return Rescale(LoadImageFromString(data), sz);
}
INITBLOCK {
RichObject::Register("image", &Single<RichImage>());
};
RichObject CreateImageObject(const Image& img, int cx, int cy)
{
RichObject o = RichObject("image", StoreImageAsString(img));
if(cx || cy)
o.SetSize(GetRatioSize(o.GetPixelSize(), cx, cy));
return o;
}
struct RichPNG : public RichObjectType {
virtual String GetTypeName(const Value& v) const;
virtual Value Read(const String& s) const;
virtual String Write(const Value& v) const;
virtual Size GetPhysicalSize(const Value& data) const;
virtual Size GetPixelSize(const Value& data) const;
virtual void Paint(const Value& data, Draw& w, Size sz) const;
virtual Image ToImage(const Value& data, Size sz) const;
};
String RichPNG::GetTypeName(const Value& v) const
{
return IsString(v) ? "PNG" : "image";
}
Value RichPNG::Read(const String& s) const
{
Image img = StreamRaster::LoadStringAny(s);
if(img)
return img;
return s;
}
String RichPNG::Write(const Value& v) const
{
if(IsString(v))
return v;
return StoreImageAsString(v);
}
Size RichPNG::GetPhysicalSize(const Value& data) const
{
if(IsString(data))
return Size(0, 0);
return Image(data).GetDots();
}
Size RichPNG::GetPixelSize(const Value& data) const
{
if(IsString(data))
return Size(0, 0);
return Image(data).GetDots();
}
void RichPNG::Paint(const Value& data, Draw& w, Size sz) const
{
if(IsString(data)) {
w.DrawRect(sz, SColorFace());
DrawFrame(w, sz, SColorText());
w.DrawText(2, 2, "plugin/png missing!");
return;
}
Image x = Image(data);
Size outsz(min(sz.cx, 4 * x.GetWidth()), min(sz.cy, 4 * x.GetHeight()));
w.DrawImage(0, 0, outsz.cx, outsz.cy, x);
}
Image RichPNG::ToImage(const Value& data, Size sz) const
{
if(IsString(data)) {
ImageDraw iw(sz);
Paint(data, iw, sz);
return iw;
}
Image x = Image(data);
Size outsz(min(sz.cx, 4 * x.GetWidth()), min(sz.cy, 4 * x.GetHeight()));
return Rescale(x, outsz);
}
INITBLOCK {
RichObject::Register("PNG", &Single<RichPNG>());
};
struct RichRawImage : public RichObjectType {
virtual String GetTypeName(const Value& v) const;
virtual Value Read(const String& s) const;
virtual String Write(const Value& v) const;
virtual Size GetPhysicalSize(const Value& data) const;
virtual Size GetPixelSize(const Value& data) const;
virtual void Paint(const Value& data, Draw& w, Size sz) const;
virtual Image ToImage(const Value& data, Size sz) const;
};
String RichRawImage::GetTypeName(const Value& v) const
{
return "rawimage";
}
Value RichRawImage::Read(const String& s) const
{
return s;
}
String RichRawImage::Write(const Value& v) const
{
return v;
}
Size RichRawImage::GetPhysicalSize(const Value& data) const
{
String s = data;
StringStream ss(s);
One<StreamRaster> r = StreamRaster::OpenAny(ss);
if(r)
return r->GetInfo().dots;
return Size(0, 0);
}
Size RichRawImage::GetPixelSize(const Value& data) const
{
String s = data;
StringStream ss(s);
One<StreamRaster> r = StreamRaster::OpenAny(ss);
if(r)
return r->GetSize();
return Size(0, 0);
}
void RichRawImage::Paint(const Value& data, Draw& w, Size sz) const
{
String s = data;
StringStream ss(s);
One<StreamRaster> r = StreamRaster::OpenAny(ss);
if(r) {
ImageEncoder m;
Rescale(m, sz, *r, r->GetSize());
w.DrawImage(0, 0, sz.cx, sz.cy, m);
}
}
Image RichRawImage::ToImage(const Value& data, Size sz) const
{
String s = data;
StringStream ss(s);
One<StreamRaster> r = StreamRaster::OpenAny(ss);
if(r)
return r->GetImage();
return Null;
}
INITBLOCK {
RichObject::Register("rawimage", &Single<RichRawImage>());
};
RichObject CreateRawImageObject(const String& s, int cx, int cy)
{
RichObject o = RichObject("rawimage", s);
o.InitSize(cx, cy);
return o;
}
#endif
END_UPP_NAMESPACE

462
uppdev/RichTextP/RichText.h Normal file
View file

@ -0,0 +1,462 @@
#ifndef RICHTEXT_H
#define RICHTEXT_H
#include <CtrlCore/CtrlCore.h>
#include <plugin/png/png.h>
NAMESPACE_UPP
struct Zoom {
int m, d;
int operator*(int x) const { return d ? iscale(x, m, d) : 0; }
int operator&(int x) const { int q = d ? iscale(x, m, d) : 0; return x > 0 ? max(q, 1) : q; }
double AsDouble() const { return (double)m / d; }
Zoom() { m = d = 1; }
Zoom(const Nuller&) { m = d = 0; }
Zoom(int _m, int _d) { m = _m, d = _d; }
void Serialize(Stream& s) { s % m % d; }
bool operator==(Zoom a) { return m == a.m && d == a.d; }
bool operator!=(Zoom a) { return m != a.m || d != a.d; }
friend int operator/(int x, Zoom z) { return z.m ? iscale(x, z.d, z.m) : 0; }
};
inline bool IsNull(Zoom z) { return (z.m | z.d) == 0; }
inline int operator*(int x, Zoom m)
{
return m * x;
}
inline void operator*=(int& i, Zoom m)
{
i = m * i;
}
inline void operator*=(Rect& r, Zoom m)
{
r.left *= m;
r.right *= m;
r.top *= m;
r.bottom *= m;
}
inline Size operator*(Zoom m, Size sz)
{
return Size(m * sz.cx, m * sz.cy);
}
inline Size operator/(Size sz, Zoom m)
{
return Size(sz.cx / m, sz.cy / m);
}
struct PageY : Moveable<PageY, RelOps<PageY> > {
int page;
int y;
PageY(int page, int y) : page(page), y(y) {}
PageY() { page = y = 0; }
#ifdef _DEBUG
String ToString() const { return AsString(page) + ":" + AsString(y); }
#endif
};
inline bool operator<(PageY a, PageY b)
{
return a.page < b.page ? true : a.page == b.page ? a.y < b.y : false;
}
inline bool operator==(PageY a, PageY b)
{
return a.page == b.page && a.y == b.y;
}
inline PageY operator+(PageY a, int b)
{
return PageY(a.page, a.y + b);
}
struct PageRect : public Rect {
int page;
operator int() const { return page; }
operator PageY() const { return PageY(page, top); }
PageRect& operator=(const Rect& r) { (Rect&)(*this) = r; page = 0; return *this; }
PageRect(const Rect& r) { (Rect&)(*this) = r; page = 0; }
PageRect() { Clear(); page = 0; }
};
struct PageDraw {
virtual Draw& Info() = 0;
virtual Draw& Page(int i) = 0;
operator Draw&() { return Info(); }
virtual ~PageDraw() {}
};
class RichObject;
class Bar;
struct RichObjectType : Moveable<RichObjectType> {
virtual String GetTypeName(const Value& v) const = 0;
virtual String GetCreateName() const;
virtual Size GetDefaultSize(const Value& data, Size maxsize) const;
virtual Size GetPhysicalSize(const Value& data) const;
virtual Size GetPixelSize(const Value& data) const;
virtual void Paint(const Value& data, Draw& w, Size sz) const;
virtual Image ToImage(const Value& data, Size sz) const;
virtual Value Read(const String& s) const;
virtual String Write(const Value& v) const;
virtual void Menu(Bar& bar, RichObject& ex) const;
virtual void DefaultAction(RichObject& ex) const;
virtual String GetLink(const Value& data, Point pt, Size sz) const;
virtual bool Accept(PasteClip& clip);
virtual Value Read(PasteClip& clip);
virtual String GetClipFmts() const;
virtual String GetClip(const Value& data, const String& fmt) const;
RichObjectType();
virtual ~RichObjectType();
};
class RichObject : Moveable<RichObject> {
Value data;
int ydelta;
Size size;
Size physical_size;
Size pixel_size;
bool keepratio;
const RichObjectType *type;
int64 serial;
String type_name;
static VectorMap<String, RichObjectType *>& Map();
void NewSerial();
public:
static void Register(const char *name, RichObjectType *type) init_;
static int GetTypeCount() { return Map().GetCount(); }
static int FindType(const String& name) { return Map().Find(name); }
static RichObjectType& GetType(int i) { return *Map()[i]; }
static String GetTypeName(int i) { return Map().GetKey(i); }
void SetSize(int cx, int cy) { size = Size(cx, cy); NewSerial(); }
void SetSize(Size sz) { size = sz; NewSerial(); }
Size GetSize() const { return size; }
void Paint(Draw& w, Size sz) const;
Image ToImage(Size sz) const;
Size GetPhysicalSize() const { return physical_size; }
Size GetPixelSize() const { return pixel_size; }
Size GetDefaultSize(Size maxsize) const { return type ? type->GetDefaultSize(data, maxsize) : physical_size; }
void Set(RichObjectType *type, const Value& data, Size maxsize = Size(3967, 3967));
bool Set(const String& type_name, const Value& data, Size maxsize = Size(3967, 3967));
String GetTypeName() const;
Value GetData() const { return data; }
String GetLink(Point pt, Size sz) const { return type ? type->GetLink(data, pt, sz) : String(); }
const RichObjectType& GetType() const;
bool Read(const String& type, const String& data, Size sz);
String Write() const { return type ? type->Write(data) : (String)data; }
void KeepRatio(bool b) { keepratio = b; }
bool IsKeepRatio() const { return keepratio; }
void SetYDelta(int yd) { ydelta = yd; }
int GetYDelta() const { return ydelta; }
void Menu(Bar& bar) { if(type) type->Menu(bar, *this); }
void DefaultAction() { if(type) type->DefaultAction(*this); }
operator bool() const { return !IsNull(data); }
void Clear();
int64 GetSerialId() const { return serial; }
void InitSize(int cx, int cy);
RichObject();
RichObject(RichObjectType *type, const Value& data, Size maxsize = Size(3967, 3967));
RichObject(const String& type, const Value& data, Size maxsize = Size(3967, 3967));
};
RichObject CreateDrawingObject(const Drawing& dwg, Size dot_size, Size size);
RichObject CreateDrawingObject(const Drawing& dwg, int cx = 0, int cy = 0);
RichObject CreatePNGObject(const Image& img, Size dot_size, Size size);
RichObject CreatePNGObject(const Image& img, Size dot_size, Size size);
RichObject CreateImageObject(const Image& img, int cx = 0, int cy = 0);
RichObject CreateRawImageObject(const String& s, int cx = 0, int cy = 0);
struct RichPara;
enum {
RICHHOT_LM = -1,
RICHHOT_RM = -2,
};
struct RichHotPos {
int table;
int column;
int delta;
int left, cx;
int textleft, textcx;
RichHotPos() { table = 0; column = Null; }
};
struct RichValPos : Moveable<RichValPos> {
PageY py;
int pos;
WString data;
};
struct PaintInfo {
Zoom zoom;
int sell, selh;
int tablesel;
Rect cells;
PageY top;
PageY bottom;
Color hyperlink;
Color indexentry;
bool usecache;
bool sizetracking;
Color showcodes;
Bits (*spellingchecker)(const RichPara& para);
int highlightpara;
Color highlight;
bool coloroverride;
PaintInfo();
};
int LineZoom(Zoom z, int a);
class RichTable;
#include "Para.h"
struct RichPos {
int tabtextparti;
int tabtextpartcount;
int tabposintabtext;
int tabtextlen;
int table;
Size tabsize;
Point cell;
int tablen;
int posintab;
int celllen;
int posincell;
int parai;
int partcount;
int posinpara;
int paralen;
int level;
int parenttab;
RichPara::Format format;
int chr;
RichObject object;
Id field;
String fieldparam;
RichPara::CharFormat fieldformat;
#ifdef _DEBUG
String ToString() const;
#endif
RichPos();
};
inline bool InSameTxt(const RichPos& a, const RichPos& b)
{
return a.table == b.table && (a.table == 0 || a.cell == b.cell);
}
struct RichCaret : PageRect {
int lineascent;
int caretascent;
int caretdescent;
int objectcy;
int objectyd;
int line;
Rect textpage;
RichCaret() { lineascent = caretascent = caretdescent = 0; }
};
struct RichStyle {
RichPara::Format format;
String name;
Uuid next;
static Uuid GetDefaultId();
static const RichStyle& GetDefault();
RichStyle() { next = GetDefaultId(); }
};
typedef ArrayMap<Uuid, RichStyle> RichStyles;
const RichStyle& GetStyle(const RichStyles& s, const Uuid& id);
int FindStyleWithName(const RichStyles& style, const String& name);
struct RichContext {
const RichStyles& styles;
Rect page;
PageY py;
void Page() { py.page++; py.y = page.top; }
RichContext(const RichStyles& styles) : styles(styles) {}
};
struct RichCellPos;
#include "Txt.h"
#include "Table.h"
#include "Text.h"
struct RichCellPos {
int pos;
int textlen;
Size tabsize;
int tabpos;
int tablen;
int cellpos;
int celllen;
int level;
RichCell::Format format;
RichTable::Format tableformat;
#ifdef _DEBUG
String ToString() const;
#endif
};
String DeQtf(const char *s);
String DeQtfLf(const char *s);
struct QtfRichObject {
RichObject obj;
public:
String ToString() const;
QtfRichObject() {}
QtfRichObject(const RichObject& o);
};
String AsQTF(const RichObject& obj);
RichText ParseQTF(const char *qtf, bool scolors = false, byte accesskey = 0);
RichText AsRichText(const wchar *s, const RichPara::Format& f = RichPara::Format());
enum
{
QTF_BODY = 1,
QTF_ALL_STYLES = 2,
QTF_NOSTYLES = 4,
QTF_CRLF = 8,
QTF_NOCHARSET = 16,
QTF_NOLANG = 32,
};
String AsQTF(const RichText& doc, byte charset = CHARSET_UTF8,
dword options = QTF_BODY|QTF_ALL_STYLES|QTF_CRLF);
inline String StylesAsQTF(const RichText& doc, byte charset = CHARSET_UTF8)
{ return AsQTF(doc, charset, QTF_ALL_STYLES|QTF_CRLF); }
inline String BodyAsQTF(const RichText& doc, byte charset = CHARSET_UTF8)
{ return AsQTF(doc, charset, QTF_BODY|QTF_CRLF); }
enum
{
ROUNDOFF = 1 << 20,
MAX_FONTS = 10000,
MAX_DOTS = 600 * 100,
MAX_DOT_HEIGHT = 1200,
MAX_POINT_HEIGHT = MAX_DOT_HEIGHT * 3 / 25,
};
inline int DotTwips (int dots) { return (dots * 12 + 5 * ROUNDOFF + 2) / 5 - ROUNDOFF; }
inline int TwipDots (int twp) { return (twp * 5 + 12 * ROUNDOFF + 6) / 12 - ROUNDOFF; }
inline int DotPoints(int dots) { return (dots * 3 + 25 * ROUNDOFF + 12) / 25 - ROUNDOFF; }
inline int PointDots(int pts) { return (pts * 25 + 3 * ROUNDOFF + 1) / 3 - ROUNDOFF; }
inline int TwipDotSize(int twp) { return IsNull(twp) ? 0 : minmax<int>(TwipDots(twp), 0, MAX_DOTS); }
inline int PointDotHeight(int p) { return (minmax<int>(Nvl(p, 0), 0, MAX_POINT_HEIGHT) * 25 + 5) / 6; }
void EncodeRTF(Stream& stream, const RichText& richtext, byte charset);
String EncodeRTF(const RichText& richtext, byte charset);
String EncodeRTF(const RichText& richtext);
RichText ParseRTF(const char *rtf);
Zoom GetRichTextStdScreenZoom();
const Display& QTFDisplay();
const Display& QTFDisplayVCenter();
String EncodeHtml(const RichText& text, Index<String>& css,
const VectorMap<String, String>& links,
const VectorMap<String, String>& labels,
const String& path, const String& base = Null, Zoom z = Zoom(8, 40),
const VectorMap<String, String>& escape = VectorMap<String, String>(),
int imtolerance = 0);
String AsCss(Index<String>& ss);
inline //BW - no labels
String EncodeHtml(const RichText& text, Index<String>& css,
const VectorMap<String, String>& links,
const String& path, const String& base = Null, Zoom z = Zoom(8, 40)) {
return EncodeHtml(text, css, links, VectorMap<String, String>(), path, base, z);
}
struct SimplePageDraw : PageDraw {
Draw& w;
virtual Draw& Info();
virtual Draw& Page(int);
SimplePageDraw(Draw& w) : w(w) {}
virtual ~SimplePageDraw() {}
};
struct PrintPageDraw : PageDraw {
int page;
Draw& w;
NilDraw nw;
Draw& Page(int _page) { return page == _page ? w : (Draw&)nw; }
Draw& Info() { return w; }
void SetPage(int _page) { page = _page; }
PrintPageDraw(Draw& w) : w(w) {}
virtual ~PrintPageDraw() {}
};
END_UPP_NAMESPACE
#endif

View file

@ -0,0 +1,9 @@
IMAGE_ID(EndParaChar)
IMAGE_ID(TabChar)
IMAGE_ID(SpaceChar)
IMAGE_ID(HardSpaceChar)
IMAGE_BEGIN_DATA
IMAGE_DATA(120,156,99,96,101,224,96,192,3,254,147,33,246,31,11,141,206,70,199,232,234,176,155,205,198,192,74,138,67,73,177,28)
IMAGE_DATA(155,122,236,230,51,1,157,129,199,34,92,6,64,0,11,225,224,198,101,16,46,62,97,75,113,0,0,165,164,44,1,0)
IMAGE_END_DATA(64, 4)

View file

View file

@ -0,0 +1,39 @@
description "Rich-text data structures and painting, including RTF and HTML export/import";
file
RichText.h,
Object.cpp,
RichImage.icpp,
Para.h,
ParaData.cpp optimize_speed,
ParaType.cpp optimize_speed,
ParaPaint.cpp,
Txt.h,
TxtData.cpp,
TxtPaint.cpp,
TxtOp.cpp,
Format.cpp,
Table.h,
TableCell.cpp,
TableLayout.cpp,
TablePaint.cpp,
TableData.cpp,
Text.h,
TextPaint.cpp,
TextStyle.cpp,
TextData.cpp,
TextTable.cpp,
EncodeQtf.cpp optimize_speed,
ParseQtf.cpp optimize_speed,
EncodeRTF.cpp optimize_speed,
ParseRTF.cpp optimize_speed,
EncodeHTML.cpp optimize_speed,
Util.cpp,
RichText.iml,
Info readonly separator,
srcdoc.tpp,
Copying;
mainconfig
"" = "";

220
uppdev/RichTextP/Table.h Normal file
View file

@ -0,0 +1,220 @@
class RichCell : DeepCopyOption<RichCell> {
public:
struct Format {
Rect border;
Rect margin;
int align;
int minheight;
Color color;
Color bordercolor;
bool keep;
Format();
};
Format format;
int vspan, hspan;
RichTxt text;
private:
bool Reduce(RichContext& rc) const;
PageY Align(const RichContext& rc, PageY npy) const;
void DrawCell(Draw& w, int l, int r, int y, int yy, const Rect& border) const;
void ClearText();
void ClearText(const RichPara::Format& format, const RichStyles& style);
void Clear();
PageY GetTop(RichContext rc) const;
PageY GetHeight(RichContext rc) const;
void Paint(PageDraw& pw, RichContext rc, PageY npy,
const Rect& xpg, int y, int ny, const PaintInfo& pi,
bool select) const;
RichCaret GetCaret(int pos, RichContext rc, PageY pyy) const;
int GetPos(int x, PageY y, RichContext rc, PageY pyy) const;
RichHotPos GetHotPos(int x, PageY y, int tolerance, RichContext rc, PageY pyy) const;
void GatherValPos(Vector<RichValPos>& f, RichContext rc, PageY pyy, int pos, int type) const;
friend class RichTable;
friend class RichText;
public:
RichCell(const RichCell& src, int);
RichCell();
};
class RichTable : DeepCopyOption<RichTable> {
public:
struct Format {
int before, lm, rm, after;
int frame;
Color framecolor;
int grid;
Color gridcolor;
WithDeepCopy< Vector<int> > column;
int header;
bool keep;
Format();
};
struct CellInfo {
bool valid;
Point master;
operator bool() const { return valid; }
CellInfo() { valid = true; }
};
Format format;
Array< Array<RichCell> > cell;
private:
struct PaintCell : Moveable<PaintCell> {
int left;
int right;
Rect page;
PageY hy;
bool top;
bool bottom;
PaintCell() { top = true; }
};
struct PaintRow : Moveable<PaintRow> {
PageY gpy;
PageY py, pyy;
Buffer<PaintCell> cell;
bool first;
PaintCell& operator[](int i) { return cell[i]; }
const PaintCell& operator[](int i) const { return cell[i]; }
};
struct Layout {
Buffer<Rect> col;
Buffer<PaintRow> row;
int frame;
int grid;
PageY pyy;
PaintRow& operator[](int i) { return row[i]; }
const PaintRow& operator[](int i) const { return row[i]; }
};
struct TabLayout : Layout {
bool hasheader;
Layout header;
Rect page;
int page0;
Size sz;
};
mutable TabLayout clayout;
mutable Rect cpage;
mutable PageY cpy;
Buffer< Buffer<CellInfo> > ci;
int r_row, r_column;
Rect r_page;
PageY r_py, r_pyy;
void Invalidate();
void InvalidateRefresh(int i, int j);
void InvalidateRefresh(Point p) { InvalidateRefresh(p.y, p.x); }
bool Reduce(RichContext& rc) const;
Layout Realize(RichContext rc, int ny) const;
bool RowPaint(PageDraw& pw, const RichStyles& st, const Layout& tab,
int i, int ny, const Rect& pg, VectorMap<int, Rect>& frr,
PaintInfo& pi, int pd, bool sel) const;
const TabLayout& Realize(RichContext rc) const;
mutable int length, tabcount;
static void ExpandFrr(VectorMap<int, Rect>& frr, int pi, int l, int r, int t, int b);
friend class RichTxt;
friend class RichText;
public:
Array<RichCell>& operator[](int i) { return cell[i]; }
const Array<RichCell>& operator[](int i) const { return cell[i]; }
RichCell& operator[](Point p) { return cell[p.y][p.x]; }
const RichCell& operator[](Point p) const { return cell[p.y][p.x]; }
int GetCellPos(int i, int j) const;
int GetCellPos(Point p) const { return GetCellPos(p.y, p.x); }
int GetTableCount(int i, int j) const;
int GetTableCount(Point p) const { return GetTableCount(p.y, p.x); }
Point GetMasterCell(int i, int j) const;
Point GetMasterCell(Point p) const { return GetMasterCell(p.y, p.x); }
const RichCell& GetMaster(int i, int j) const;
int GetLength() const;
int GetTableCount() const;
private:
void Normalize0();
RichTable Copy(const Rect& sel) const;
void Paste(Point pos, const RichTable& tab);
void RemoveRow0(int rowi);
void RemoveRow(int rowi);
void InsertRow(int rowi, const RichStyles& style);
void RemoveColumn0(int column);
void RemoveColumn(int column);
void InsertColumn(int column, const RichStyles& style);
bool IsRowEmpty(int row);
bool IsColumnEmpty(int column);
void SplitCell(Point cl, Size sz, const RichStyles& style);
RichCell::Format GetCellFormat(const Rect& sel) const;
void SetCellFormat(const Rect& sel, const RichCell::Format& fmt, bool setkeep);
PageY GetHeight(RichContext rc) const;
PageY GetTop(RichContext rc) const;
void Paint(PageDraw& pw, RichContext rc, const PaintInfo& pi) const;
RichCaret GetCaret(int pos, RichContext rc) const;
int GetPos(int x, PageY y, RichContext rc) const;
int GetVertMove(int pos, int gx, RichContext rc, int dir) const;
RichHotPos GetHotPos(int x, PageY y, int tolerance, RichContext rc) const;
void AdjustSel(Rect& sel) const;
void GatherValPos(Vector<RichValPos>& f, RichContext rc, int pos, int type) const;
void ClearSpelling();
Point FindCell(int& pos) const;
RichPos GetRichPos(int pos, const RichStyles& st) const;
CellInfo GetCellInfo(int i, int j) { return ci[i][j]; }
int GetInvalid(PageY& top, PageY& bottom, RichContext rc) const;
void Validate();
void ApplyZoom(Zoom z, const RichStyles& ostyle, const RichStyles& zstyle);
public:
void AddColumn(int cx);
void SetPick(int i, int j, pick_ RichTxt& text);
RichTxt GetPick(int i, int j);
const RichTxt& Get(int i, int j) const { return cell[i][j].text; }
void SetQTF(int i, int j, const char *qtf);
void SetFormat(int i, int j, const RichCell::Format& fmt);
const RichCell::Format& GetFormat(int i, int j) { return cell[i][j].format; }
bool operator()(int i, int j) const { return ci[i][j].valid; }
void SetSpan(int i, int j, int vspan, int hspan);
Size GetSpan(int i, int j) const;
void SetFormat(const Format& fmt);
const Format& GetFormat() const { return format; }
int GetColumns() const { return format.column.GetCount(); }
int GetRows() const { return cell.GetCount(); }
Size GetSize() const { return Size(GetColumns(), GetRows()); }
void Normalize();
RichTable(const RichTable& src, int);
RichTable();
};

View file

@ -0,0 +1,194 @@
#include "RichText.h"
NAMESPACE_UPP
int LineZoom(Zoom z, int a)
{
return a ? max(1, z * a) : 0;
}
RichCell::Format::Format()
{
margin.left = margin.right = 25;
margin.top = margin.bottom = 15;
border.Clear();
align = ALIGN_CENTER;
color = White;
bordercolor = Black;
keep = false;
minheight = 0;
}
void RichCell::ClearText()
{
text.Clear();
RichPara h;
text.Cat(h, RichStyles());
}
void RichCell::ClearText(const RichPara::Format& format, const RichStyles& style)
{
text.Clear();
RichPara h;
h.format = format;
text.Cat(h, style);
}
void RichCell::Clear()
{
format = Format();
vspan = hspan = 0;
ClearText();
}
bool RichCell::Reduce(RichContext& rc) const
{
Rect br = rc.page;
rc.page.top += format.margin.top + format.border.top;
rc.page.bottom -= format.margin.bottom + format.border.bottom;
rc.page.left += format.margin.left + format.border.left;
rc.page.right -= format.margin.right + format.border.right;
if(rc.page.IsEmpty())
rc.page = br;
return !rc.page.IsEmpty();
}
PageY RichCell::GetTop(RichContext rc) const
{
if(!Reduce(rc))
return rc.py;
rc.py.y += format.margin.top + format.border.top;
return text.GetTop(rc);
}
PageY RichCell::GetHeight(RichContext rc) const
{
if(Reduce(rc)) {
PageY py = rc.py;
rc.py.y += format.margin.top + format.border.top;
rc.py = text.GetHeight(rc);
rc.py.y += format.margin.bottom + format.border.bottom;
py.y += format.margin.top + format.border.top +
format.minheight +
format.margin.bottom + format.border.bottom;
return py.y <= rc.page.bottom && py > rc.py ? py : rc.py;
}
else {
rc.py.y += format.margin.top + format.border.top;
rc.py.y += 80;
rc.py.y += format.margin.bottom + format.border.bottom;
if(rc.py.y >= rc.page.bottom) {
rc.Page();
rc.py.y += 80;
}
}
return rc.py;
}
void RichCell::DrawCell(Draw& w, int l, int r, int y, int yy, const Rect& border) const
{
w.DrawRect(l, y, r - l, border.top, format.bordercolor);
w.DrawRect(l, y, border.left, yy - y, format.bordercolor);
w.DrawRect(r - border.right, y, border.right, yy - y, format.bordercolor);
w.DrawRect(l, yy - border.bottom, r - l, border.bottom, format.bordercolor);
w.DrawRect(l + border.left, y + border.top,
r - l - border.left - border.right, yy - y - border.top - border.bottom,
format.color);
}
PageY RichCell::Align(const RichContext& rc, PageY npy) const
{
PageY y = rc.py;
y.y += format.margin.top + format.border.top;
if(rc.py.page == npy.page) {
int dx = npy.y - text.GetHeight(rc).y
- format.margin.top - format.border.top
- format.margin.bottom - format.border.bottom;
if(format.align == ALIGN_CENTER)
y.y += dx / 2;
else
if(format.align == ALIGN_BOTTOM)
y.y += dx;
}
return y;
}
void RichCell::Paint(PageDraw& pw, RichContext rc, PageY npy,
const Rect& xpg, int y, int ny, const PaintInfo& pi, bool select) const
{
if(!Reduce(rc))
return;
Rect border(LineZoom(pi.zoom, format.border.left), LineZoom(pi.zoom, format.border.top),
LineZoom(pi.zoom, format.border.right), LineZoom(pi.zoom, format.border.bottom));
if(rc.py.page == npy.page)
DrawCell(pw.Page(rc.py.page), xpg.left, xpg.right, y, ny, border);
else {
DrawCell(pw.Page(rc.py.page), xpg.left, xpg.right, y, xpg.bottom, border);
for(int i = rc.py.page + 1; i < npy.page; i++)
DrawCell(pw.Page(i), xpg.left, xpg.right, xpg.top, xpg.bottom, border);
DrawCell(pw.Page(npy.page), xpg.left, xpg.right, xpg.top, ny, border);
}
rc.py = Align(rc, npy);
text.Paint(pw, rc, pi);
if(select) {
int cx = xpg.right - xpg.left;
if(rc.py.page == npy.page)
pw.Page(rc.py.page).DrawRect(xpg.left, y, cx, ny - y, InvertColor);
else {
pw.Page(rc.py.page).DrawRect(xpg.left, y, cx, xpg.bottom - y, InvertColor);
for(int i = rc.py.page + 1; i < npy.page; i++)
pw.Page(i).DrawRect(xpg.left, xpg.top, cx, xpg.Height(), InvertColor);
pw.Page(npy.page).DrawRect(xpg.left, xpg.top, cx, ny - xpg.top, InvertColor);
}
}
}
RichCaret RichCell::GetCaret(int pos, RichContext rc, PageY pyy) const
{
if(!Reduce(rc))
return RichCaret();
rc.py = Align(rc, pyy);
return text.GetCaret(pos, rc);
}
int RichCell::GetPos(int x, PageY y, RichContext rc, PageY pyy) const
{
if(!Reduce(rc))
return 0;
rc.py = Align(rc, pyy);
return text.GetPos(x, y, rc);
}
RichHotPos RichCell::GetHotPos(int x, PageY y, int tolerance, RichContext rc, PageY pyy) const
{
if(!Reduce(rc))
return RichHotPos();
rc.py = Align(rc, pyy);
return text.GetHotPos(x, y, tolerance, rc);
}
void RichCell::GatherValPos(Vector<RichValPos>& f, RichContext rc, PageY pyy, int pos, int type) const
{
if(!Reduce(rc))
return;
rc.py = Align(rc, pyy);
text.GatherValPos(f, rc, pos, type);
}
RichCell::RichCell()
{
vspan = hspan = 0;
Clear();
}
RichCell::RichCell(const RichCell& src, int)
{
format = src.format;
hspan = src.hspan;
vspan = src.vspan;
text <<= src.text;
}
END_UPP_NAMESPACE

View file

@ -0,0 +1,580 @@
#include "RichText.h"
NAMESPACE_UPP
void RichTable::Invalidate()
{
cpy.page = -1;
length = tabcount = -1;
}
void RichTable::InvalidateRefresh(int i, int j)
{
if(i < format.header)
r_row = -1;
else
if(r_row != i || r_column != j)
if(r_row == -2 && clayout.sz == GetSize()) {
r_row = i;
r_column = j;
r_py = cpy;
r_pyy = clayout[min(GetRows() - 1, i + cell[i][j].vspan)].pyy;
r_page = cpage;
}
else
r_row = -1;
Invalidate();
}
void RichTable::Normalize0()
{
int nx = format.column.GetCount();
int ny = cell.GetCount();
for(int i = 0; i < ny; i++)
cell[i].SetCount(nx);
Invalidate();
r_py.page = -1;
r_row = -1;
ci.Alloc(ny);
for(int i = 0; i < ny; i++)
ci[i].Alloc(nx);
for(int i = 0; i < ny; i++)
for(int j = 0; j < nx; j++)
if(ci[i][j].valid) {
RichCell& c = cell[i][j];
int vs = i < format.header ? min(format.header - 1, i + c.vspan) : min(ny - 1, i + c.vspan);
int hs = min(nx - 1, j + c.hspan);
c.vspan = vs - i;
c.hspan = hs - j;
for(int ii = i; ii <= vs; ii++)
for(int jj = j; jj <= hs; jj++) {
if(i != ii || j != jj) {
CellInfo& f = ci[ii][jj];
f.valid = false;
cell[ii][jj].Clear();
f.master = Point(j, i);
cell[ii][jj].hspan = hs - jj;
}
}
}
}
bool RichTable::IsRowEmpty(int row)
{
for(int i = 0; i < GetColumns(); i++)
if(ci[row][i].valid && cell[row][i].vspan == 0)
return false;
return true;
}
bool RichTable::IsColumnEmpty(int column)
{
for(int i = 0; i < GetRows(); i++)
if(ci[i][column].valid)
return false;
return true;
}
void RichTable::RemoveRow0(int rowi)
{
if(rowi < format.header)
format.header--;
for(int i = 0; i < GetColumns(); i++) {
CellInfo& cf = ci[rowi][i];
if(!cf.valid && cf.master.x == i)
cell[cf.master.y][cf.master.x].vspan--;
}
cell.Remove(rowi);
}
void RichTable::RemoveColumn0(int column)
{
for(int i = 0; i < cell.GetCount(); i++) {
CellInfo& cf = ci[i][column];
if(!cf.valid && cf.master.y == i)
cell[cf.master.y][cf.master.x].hspan--;
cell[i].Remove(column);
}
format.column.Remove(column);
}
void RichTable::Normalize()
{
Normalize0();
int i = 0;
while(i < GetRows())
if(IsRowEmpty(i)) {
Array<RichCell> r(cell[i], 1);
RemoveRow0(i);
for(int j = 0; j < GetColumns(); j++)
if(ci[i][j].valid) {
cell[i][j] <<= r[j];
cell[i][j].vspan--;
}
Normalize0();
}
else
i++;
int j = 0;
while(j < GetColumns())
if(IsColumnEmpty(j)) {
Array<RichCell> r;
for(int i = 0; i < GetRows(); i++)
r.Add() <<= cell[i][j];
int c = format.column[j];
RemoveColumn0(j);
format.column[min(GetColumns() - 1, j)] += c;
for(int i = 0; i < GetRows(); i++)
if(ci[i][j].valid)
cell[i][j] <<= r[i];
Normalize0();
}
else
j++;
int sum = Sum0(format.column);
if(sum != 10000) {
r_row = -1;
if(format.column.GetCount()) {
if(format.column.GetCount() > 1) {
int q = 0;
for(int i = 0; i < format.column.GetCount() - 1; i++)
q += sum <= 0 ? (format.column[i] = 10000 / format.column.GetCount())
: (format.column[i] = format.column[i] * 10000 / sum);
format.column[format.column.GetCount() - 1] = 10000 - q;
}
else
format.column[0] = 10000;
}
}
}
int RichTable::GetLength() const
{
if(length < 0) {
length = 0;
for(int i = 0; i < cell.GetCount(); i++)
for(int j = 0; j < format.column.GetCount(); j++)
if(ci[i][j].valid)
length += cell[i][j].text.GetLength() + 1;
}
return length ? length - 1 : 0;
}
Point RichTable::FindCell(int& pos) const
{
for(int i = 0; i < cell.GetCount(); i++)
for(int j = 0; j < format.column.GetCount(); j++)
if(ci[i][j].valid) {
int l = cell[i][j].text.GetLength() + 1;
if(pos < l)
return Point(j, i);
pos -= l;
}
NEVER();
return Point();
}
int RichTable::GetCellPos(int ii, int jj) const
{
int pos = 0;
for(int i = 0; i < ii; i++)
for(int j = 0; j < format.column.GetCount(); j++)
if(ci[i][j].valid)
pos += cell[i][j].text.GetLength() + 1;
for(int j = 0; j < jj; j++)
if(ci[ii][j].valid)
pos += cell[ii][j].text.GetLength() + 1;
return pos;
}
Point RichTable::GetMasterCell(int i, int j) const
{
i = min(GetRows() - 1, i);
j = min(GetColumns() - 1, j);
const CellInfo& cf = ci[i][j];
return cf.valid ? Point(j, i) : cf.master;
}
const RichCell& RichTable::GetMaster(int i, int j) const
{
Point p = GetMasterCell(i, j);
return cell[p.y][p.x];
}
int RichTable::GetTableCount(int ii, int jj) const
{
int ti = 0;
for(int i = 0; i < ii; i++)
for(int j = 0; j < format.column.GetCount(); j++)
if(ci[i][j].valid)
ti += cell[i][j].text.GetTableCount();
for(int j = 0; j < jj; j++)
if(ci[ii][j].valid)
ti += cell[ii][j].text.GetTableCount();
return ti;
}
void RichTable::ClearSpelling()
{
for(int i = 0; i < cell.GetCount(); i++)
for(int j = 0; j < format.column.GetCount(); j++)
if(ci[i][j].valid)
cell[i][j].text.ClearSpelling();
}
int RichTable::GetTableCount() const
{
if(tabcount < 0) {
tabcount = 0;
for(int i = 0; i < cell.GetCount(); i++) {
for(int j = 0; j < format.column.GetCount(); j++)
if(ci[i][j].valid)
tabcount += cell[i][j].text.GetTableCount();
}
}
return tabcount;
}
void RichTable::Validate()
{
r_row = -2;
}
int RichTable::GetInvalid(PageY& top, PageY& bottom, RichContext rc) const
{
if(r_row == -2)
return -1;
const TabLayout& tab = Realize(rc);
if(r_row >= 0 && r_page == rc.page
&& r_py == rc.py && tab[min(GetRows() - 1, r_row + cell[r_row][r_column].vspan)].pyy == r_pyy) {
const PaintRow& pr = tab[r_row];
const RichCell& cl = cell[r_row][r_column];
top = pr.py;
bottom = tab[min(cell.GetCount() - 1, r_row + cl.vspan)].pyy;
return 0;
}
return 1;
}
void RichTable::AddColumn(int cx)
{
format.column.Add(cx);
}
void RichTable::SetPick(int i, int j, pick_ RichTxt& text)
{
cell.At(i).At(j).text = text;
}
RichTxt RichTable::GetPick(int i, int j)
{
return cell[i][j].text;
}
void RichTable::SetQTF(int i, int j, const char *qtf)
{
SetPick(i, j, ParseQTF(qtf));
}
void RichTable::SetFormat(int i, int j, const RichCell::Format& fmt)
{
cell.At(i).At(j).format = fmt;
}
void RichTable::SetSpan(int i, int j, int vspan, int hspan)
{
RichCell& c = cell.At(i).At(j);
c.vspan = vspan;
c.hspan = hspan;
}
Size RichTable::GetSpan(int i, int j) const
{
const RichCell& c = cell[i][j];
return Size(c.hspan, c.vspan);
}
void RichTable::SetFormat(const Format& fmt)
{
format = fmt;
}
RichTable RichTable::Copy(const Rect& sel) const
{
RichTable r;
r.format = format;
r.format.header = max(0, format.header - sel.top);
r.format.column.Remove(0, sel.left);
r.format.column.SetCount(sel.right - sel.left + 1);
for(int i = sel.top; i <= sel.bottom; i++)
for(int j = sel.left; j <= sel.right; j++)
r.cell.At(i - sel.top).At(j - sel.left) <<= cell[i][j];
r.Normalize();
return r;
}
void RichTable::RemoveRow(int rowi)
{
RemoveRow0(rowi);
Normalize();
}
void RichTable::InsertRow(int rowi, const RichStyles& style)
{
if(rowi < format.header)
format.header++;
int si;
if(rowi < GetRows()) {
for(int i = 0; i < GetColumns(); i++) {
CellInfo& cf = ci[rowi][i];
if(!cf.valid && cf.master.x == i)
cell[cf.master.y][cf.master.x].vspan++;
}
si = rowi + 1;
}
else
si = rowi - 1;
cell.Insert(rowi).SetCount(GetColumns());
if(si >= 0)
for(int i = 0; i < GetColumns(); i++) {
RichCell& c = cell[rowi][i];
const RichCell& sc = cell[si][i];
c.format = sc.format;
DUMP(sc.hspan);
c.hspan = sc.hspan;
c.ClearText(sc.text.GetFirstFormat(style), style);
}
Normalize();
}
void RichTable::RemoveColumn(int column)
{
RemoveColumn0(column);
Normalize();
}
void RichTable::InsertColumn(int column, const RichStyles& style)
{
int sci = column < GetColumns() ? column + 1 : column - 1;
for(int i = 0; i < cell.GetCount(); i++) {
CellInfo& cf = ci[i][column];
if(!cf.valid && cf.master.y == i)
cell[cf.master.y][cf.master.x].hspan++;
RichCell& c = cell[i].Insert(column);
if(sci >= 0) {
const RichCell& sc = cell[i][sci];
c.format = sc.format;
c.vspan = sc.vspan;
c.ClearText(sc.text.GetFirstFormat(style), style);
}
}
int c = format.column[min(column, GetColumns() - 1)];
format.column.Insert(column, c);
Normalize();
}
void RichTable::SplitCell(Point cl, Size sz, const RichStyles& style)
{
const RichCell& sc = cell[cl.y][cl.x];
int ext = sz.cy - cell[cl.y][cl.x].vspan - 1;
if(ext > 0) {
cell.InsertN(cl.y + 1, ext);
if(cl.y < format.header)
format.header += ext;
for(int i = 0; i < ext; i++) {
cell[cl.y + 1 + i].SetCount(GetColumns());
for(int j = 0; j < GetColumns(); j++) {
RichCell& c = cell[cl.y + 1 + i][j];
const RichCell& sc = cell[cl.y][j];
c.format = sc.format;
c.hspan = sc.hspan;
c.ClearText(sc.text.GetFirstFormat(style), style);
}
}
for(int i = 0; i < GetColumns(); i++) {
CellInfo& cf = ci[cl.y][i];
if(cf.valid)
cell[cl.y][i].vspan += ext;
else
if(cf.master.x == i)
cell[cf.master.y][cf.master.x].vspan += ext;
}
}
cell[cl.y][cl.x].vspan = 0;
if(ext < 0)
cell[cl.y + sz.cy - 1][cl.x].vspan = -ext;
for(int i = 1; i < sz.cy; i++) {
RichCell& c = cell[cl.y + i][cl.x];
c.format = sc.format;
c.hspan = sc.hspan;
c.ClearText(sc.text.GetFirstFormat(style), style);
}
Normalize0();
ext = sz.cx - cell[cl.y][cl.x].hspan - 1;
if(ext > 0) {
int clx = 0;
for(int i = 0; i <= cell[cl.y][cl.x].hspan; i++)
clx += format.column[cl.x + i];
format.column.InsertN(cl.x, ext);
int q = clx / sz.cx;
for(int i = 1; i < sz.cx; i++)
format.column[cl.x + i] = q;
format.column[cl.x] = clx - (sz.cx - 1) * q;
for(int i = 0; i < cell.GetCount(); i++) {
cell[i].InsertN(cl.x + 1, ext);
for(int q = 0; q < ext; q++) {
RichCell& c = cell[i][cl.x + 1 + q];
const RichCell& sc = cell[i][cl.x];
c.format = sc.format;
c.vspan = sc.vspan;
c.ClearText(sc.text.GetFirstFormat(style), style);
}
CellInfo& cf = ci[i][cl.x];
if(cf.valid)
cell[i][cl.x].hspan += ext;
else
if(cf.master.y == i)
cell[cf.master.y][cf.master.x].hspan += ext;
}
}
for(int i = 0; i < sz.cy; i++)
for(int j = 0; j < sz.cx; j++) {
RichCell& c = cell[cl.y + i][cl.x + j];
if(j < sz.cx - 1)
c.hspan = 0;
if(j) {
const RichCell& sc = cell[cl.y + i][cl.x];
c.format = sc.format;
c.vspan = sc.vspan;
c.ClearText(sc.text.GetFirstFormat(style), style);
}
}
Normalize();
}
void sMatchRect(Rect& t, const Rect& s)
{
if(t.left != s.left)
t.left = Null;
if(t.top != s.top)
t.top = Null;
if(t.right != s.right)
t.right = Null;
if(t.bottom != s.bottom)
t.bottom = Null;
}
RichCell::Format RichTable::GetCellFormat(const Rect& sel) const
{
RichCell::Format fmt;
for(int i = sel.top; i <= sel.bottom; i++)
for(int j = sel.left; j <= sel.right; j++)
if(i == sel.top && j == sel.left)
fmt = cell[i][j].format;
else
if(ci[i][j].valid) {
const RichCell::Format& f = cell[i][j].format;
sMatchRect(fmt.border, f.border);
sMatchRect(fmt.margin, f.margin);
if(fmt.align != f.align)
fmt.align = Null;
if(fmt.color != f.color)
fmt.color = Null;
if(fmt.bordercolor != f.bordercolor)
fmt.bordercolor = Null;
}
return fmt;
}
void sSetRect(Rect& t, const Rect& s)
{
if(!IsNull(s.left))
t.left = s.left;
if(!IsNull(s.top))
t.top = s.top;
if(!IsNull(s.right))
t.right = s.right;
if(!IsNull(s.bottom))
t.bottom = s.bottom;
}
void RichTable::SetCellFormat(const Rect& sel, const RichCell::Format& fmt, bool setkeep)
{
for(int i = sel.top; i <= sel.bottom; i++)
for(int j = sel.left; j <= sel.right; j++)
if(ci[i][j].valid) {
RichCell::Format& f = cell[i][j].format;
sSetRect(f.border, fmt.border);
sSetRect(f.margin, fmt.margin);
if(!IsNull(fmt.align))
f.align = fmt.align;
if(!IsNull(fmt.color))
f.color = fmt.color;
if(!IsNull(fmt.bordercolor))
f.bordercolor = fmt.bordercolor;
if(!IsNull(fmt.minheight))
f.minheight = fmt.minheight;
if(setkeep)
f.keep = fmt.keep;
}
Normalize();
}
void RichTable::Paste(Point pos, const RichTable& tab)
{
for(int i = 0; i < tab.GetRows(); i++)
for(int j = 0; j < min(GetColumns() - pos.x, tab.GetColumns()); j++)
cell.At(i + pos.y, cell[cell.GetCount() - 1]).At(j + pos.x) <<= tab[i][j];
Normalize();
}
void RichTable::AdjustSel(Rect& sel) const
{
again:
for(int i = sel.top; i <= sel.bottom; i++)
for(int j = sel.left; j <= sel.right; j++) {
Point p = GetMasterCell(i, j);
const RichCell& c = cell[p.y][p.x];
Point pp = p + Point(c.hspan, c.vspan);
if(p.x < sel.left) {
sel.left = p.x;
goto again;
}
if(pp.x > sel.right) {
sel.right = pp.x;
goto again;
}
if(p.y < sel.top) {
sel.top = p.y;
goto again;
}
if(pp.y > sel.bottom) {
sel.bottom = pp.y;
goto again;
}
}
}
RichTable::RichTable(const RichTable& src, int)
{
format = src.format;
cell <<= src.cell;
r_row = -1;
Normalize();
}
RichTable::RichTable()
{
cpy.page = -1;
r_row = -1;
Invalidate();
}
END_UPP_NAMESPACE

View file

@ -0,0 +1,176 @@
#include "RichText.h"
NAMESPACE_UPP
bool RichTable::Reduce(RichContext& rc) const
{
Rect br = rc.page;
rc.page.left += format.lm;
rc.page.right -= format.rm;
rc.page.Deflate(format.frame);
if(rc.page.IsEmpty())
rc.page = br;
return !rc.page.IsEmpty();
}
const RichTable::TabLayout& RichTable::Realize(RichContext rc) const
{
if(rc.py != cpy || rc.page != cpage) {
rc.py.y += format.before;
if(rc.py.y > rc.page.bottom) {
rc.py.y = rc.page.top;
rc.py.page++;
}
cpage = rc.page;
cpy = rc.py;
Reduce(rc);
clayout.page = rc.page;
clayout.hasheader = false;
clayout.sz = GetSize();
if(format.header && cell.GetCount()) {
int hy = min(format.header, cell.GetCount());
RichContext nrc = rc;
nrc.py.page = 0;
nrc.py.y = clayout.page.top;
clayout.header = Realize(nrc, hy);
if(clayout.header[0].py.page == clayout.header[hy - 1].pyy.page) {
Layout x = Realize(rc, cell.GetCount());
if(cell.GetCount() > hy && rc.py.page != x[hy].py.page) {
rc.py.page++;
rc.py.y = rc.page.top;
}
clayout.hasheader = true;
rc.page.top = clayout.page.top = clayout.header[hy - 1].pyy.y + format.grid;
}
}
clayout.page0 = rc.py.page;
(Layout&)clayout = Realize(rc, cell.GetCount());
if(format.keep && cell.GetCount()) {
if(clayout[0].py.page != clayout[cell.GetCount() - 1].pyy.page) {
rc.py.page++;
rc.py.y = rc.page.top;
}
clayout.page0 = rc.py.page;
(Layout&)clayout = Realize(rc, cell.GetCount());
}
}
return clayout;
}
RichTable::Layout RichTable::Realize(RichContext rc, int ny) const
{
Layout tab;
int nx = format.column.GetCount();
tab.row.Alloc(ny);
for(int i = 0; i < ny; i++)
tab[i].cell.Alloc(nx);
tab.col.Alloc(nx);
int sum = 0;
for(int i = 0; i < nx; i++)
sum += format.column[i];
int x = 0;
int xx = rc.page.left;
int dcx = rc.page.Width();
for(int i = 0; i < nx; i++) {
Rect& cp = tab.col[i];
cp = rc.page;
cp.left = xx;
x += format.column[i];
xx = cp.right = x * dcx / sum + rc.page.left;
}
int f2 = format.grid / 2;
int ff2 = format.grid - f2;
rc.py.y += format.frame;
for(int i = 0; i < ny; i++) {
const Array<RichCell>& row = cell[i];
PaintRow& pr = tab[i];
pr.first = i == 0;
pr.gpy = rc.py;
if(i)
rc.py.y += format.grid;
for(int j = 0; j < nx;) {
PaintCell& pc = pr[j];
const RichCell& cell = row[j];
if(pc.top) {
pc.page = tab.col[j];
pc.page.right = tab.col[min(nx - 1, j + cell.hspan)].right;
pc.bottom = false;
int ms = min(ny - 1, i + cell.vspan);
for(int k = i + 1; k <= ms; k++) {
PaintCell& pc = tab[k][j];
pc.top = pc.bottom = false;
}
tab[ms][j].bottom = true;
pc.left = pc.page.left;
pc.right = pc.page.right;
if(j)
pc.page.left += f2;
if(j + cell.hspan < nx - 1)
pc.page.right -= ff2;
}
j += cell.hspan + 1;
}
bool keep = i < format.header || format.keep;
for(int j = 0; j < nx;) {
const RichCell& cell = row[j];
if(pr[j].top && cell.format.keep) {
keep = true;
break;
}
j += cell.hspan + 1;
}
bool span = false;
for(int j = 0; j < nx;) {
const RichCell& cell = row[j];
if(!pr[j].top) {
span = true;
break;
}
j += cell.hspan + 1;
}
if(!span)
for(int j = 0; j < nx;) {
const RichCell& cell = row[j];
PaintCell& pc = pr[j];
if(pc.top) {
rc.page = pc.page;
PageY ty = cell.GetTop(rc);
PageY ky = rc.py;
if(keep)
ky = cell.GetHeight(rc);
if(ty.page != rc.py.page || ky.page != rc.py.page) {
rc.Page();
pr.gpy = rc.py;
pr.first = true;
break;
}
}
j += cell.hspan + 1;
}
pr.py = rc.py;
for(int j = 0; j < nx;) {
const RichCell& cell = row[j];
PaintCell& pc = pr[j];
rc.page = pc.page;
if(pc.top)
tab[min(ny - 1, i + cell.vspan)][j].hy = cell.GetHeight(rc);
j += cell.hspan + 1;
}
for(int j = 0; j < nx;) {
const RichCell& cell = row[j];
if(pr[j].bottom)
rc.py = max(pr[j].hy, rc.py);
j += cell.hspan + 1;
}
tab.pyy = pr.pyy = rc.py;
}
return tab;
}
END_UPP_NAMESPACE

View file

@ -0,0 +1,372 @@
#include "RichText.h"
NAMESPACE_UPP
RichTable::Format::Format()
{
grid = 4;
gridcolor = Black;
frame = 10;
framecolor = Black;
before = after = lm = rm = 0;
header = 0;
keep = false;
}
#include "RichText.h"
void RichTable::ExpandFrr(VectorMap<int, Rect>& frr, int pi, int l, int r, int t, int b)
{
Rect& fr = frr.GetAdd(pi, Rect(INT_MAX, INT_MAX, INT_MIN, INT_MIN));
fr.left = min(fr.left, l);
fr.right = max(fr.right, r);
fr.top = min(fr.top, t);
fr.bottom = max(fr.bottom, b);
}
bool RichTable::RowPaint(PageDraw& pw, const RichStyles& st, const Layout& tab,
int i, int ny, const Rect& pg, VectorMap<int, Rect>& frr,
PaintInfo& pi, int pd, bool sel) const
{
RichContext rc(st);
const Array<RichCell>& row = cell[i];
const PaintRow& pr = tab[i];
rc.py = pr.py;
rc.py.page += pd;
int gridln = LineZoom(pi.zoom, format.grid);
int ff2ln = gridln - gridln / 2;
Color gc = format.gridcolor;
if(gridln == 0 && !IsNull(pi.showcodes)) {
gridln = 1;
gc = pi.showcodes;
}
for(int j = 0; j < format.column.GetCount();) {
const RichCell& cell = row[j];
const PaintCell& pc = pr[j];
if(pc.top) {
PageY pyy = tab[min(ny - 1, i + cell.vspan)].pyy;
pyy.page += pd;
bool paint = pyy > pi.top;
rc.page = pr[j].page;
Rect xpg = pg;
int y;
int ny = pi.zoom * pyy.y;
y = pi.zoom * pr.gpy.y;
if(j) {
xpg.left = pi.zoom * pc.left - ff2ln;
if(pyy.page == rc.py.page)
pw.Page(rc.py.page).DrawRect(xpg.left, y, gridln, ny - y, gc);
else {
pw.Page(rc.py.page).DrawRect(xpg.left, y, gridln, pg.bottom - y, gc);
for(int i = rc.py.page + 1; i < pyy.page; i++)
pw.Page(i).DrawRect(xpg.left, pg.top, gridln, pg.bottom - pg.top, gc);
pw.Page(pyy.page).DrawRect(xpg.left, pg.top, gridln, ny - pg.top, gc);
}
xpg.left += gridln;
}
if(j + cell.hspan < format.column.GetCount() - 1)
xpg.right = pi.zoom * pc.right - ff2ln;
if(!pr.first) {
y += gridln;
if(paint)
pw.Page(rc.py.page).DrawRect(xpg.left, y - gridln, xpg.Width(), gridln, gc);
}
if(paint)
row[j].Paint(pw, rc, pyy, xpg, y, ny, pi,
sel && j >= pi.cells.left && i >= pi.cells.top &&
j + cell.hspan <= pi.cells.right && i + cell.vspan <= pi.cells.bottom);
if(pyy.page == rc.py.page)
ExpandFrr(frr, pyy.page, xpg.left, xpg.right, y, ny);
else {
ExpandFrr(frr, rc.py.page, xpg.left, xpg.right, y, xpg.bottom);
for(int i = rc.py.page + 1; i < pyy.page; i++)
ExpandFrr(frr, i, xpg.left, xpg.right, xpg.top, xpg.bottom);
ExpandFrr(frr, pyy.page, xpg.left, xpg.right, xpg.top, ny);
}
int l = cell.text.GetLength() + 1;
pi.sell -= l;
pi.selh -= l;
pi.tablesel -= cell.text.GetTableCount();
}
j += cell.hspan + 1;
}
return rc.py >= pi.bottom;
}
void RichTable::Paint(PageDraw& pw, RichContext rc, const PaintInfo& _pi) const
{
const TabLayout& tab = Realize(rc);
if(tab.page.IsEmpty())
return;
Rect p = tab.page;
PaintInfo pi = _pi;
int frameln = LineZoom(pi.zoom, format.frame);
int gridln = LineZoom(pi.zoom, format.grid);
Rect pg = rc.page;
pg.left += format.lm;
pg.right -= format.rm;
pg.left = pi.zoom * pg.left;
pg.right = pi.zoom * pg.right;
pg.top = pi.zoom * pg.top;
pg.bottom = pi.zoom * pg.bottom;
pg.Deflate(frameln);
int hy = min(format.header, cell.GetCount());
Rect hpg = pg;
if(tab.hasheader) {
hpg.bottom = pi.zoom * tab.header[hy - 1].pyy.y;
pg.top = hpg.bottom + gridln;
}
bool allsel = false;
if(pi.sell < 0 && pi.selh >= 0) {
pi.sell = pi.selh = 0;
allsel = true;
}
bool sel = pi.tablesel == 0;
int ny = cell.GetCount();
VectorMap<int, Rect> frr;
for(int i = 0; i < ny; i++)
if(RowPaint(pw, rc.styles, tab, i, ny, pg, frr, pi, 0, sel))
break;
Color gc = format.gridcolor;
Color fc = format.framecolor;
int fl = frameln;
if(!IsNull(pi.showcodes)) {
if(fl == 0 && !IsNull(pi.showcodes)) {
fl = 1;
fc = pi.showcodes;
}
if(gridln == 0) {
gridln = 1;
gc = pi.showcodes;
}
}
for(int i = 0; i < frr.GetCount(); i++) {
PaintInfo _pi = pi;
pi.tablesel = 0;
pi.sell = pi.selh = -1;
int pgi = frr.GetKey(i);
Draw& w = pw.Page(pgi);
if(pgi > tab.page0 && tab.hasheader)
for(int i = 0; i < hy; i++) {
RowPaint(pw, rc.styles, tab.header, i, hy, hpg, frr, pi, pgi, false);
w.DrawRect(pg.left, hpg.bottom, pg.Width(), gridln, format.gridcolor);
}
Rect r = frr[i].Inflated(frameln);
if(!r.IsEmpty()) {
DrawFatFrame(w, r, fc, fl);
if(allsel)
w.DrawRect(r, InvertColor);
}
}
}
PageY RichTable::GetHeight(RichContext rc) const
{
PageY pyy = Realize(rc).pyy;
pyy.y += format.frame;
pyy.y += format.after;
if(pyy.y > rc.page.bottom) {
pyy.y = rc.page.top;
pyy.page++;
}
return pyy;
}
PageY RichTable::GetTop(RichContext rc) const
{
if(cell.GetCount() == 0)
return rc.py;
rc.py = Realize(rc)[0].py;
rc.py.y -= format.frame;
return rc.py;
}
RichCaret RichTable::GetCaret(int pos, RichContext rc) const
{
ASSERT(pos >= 0);
int nx = format.column.GetCount();
int ny = cell.GetCount();
int ti = 0;
const TabLayout& tab = Realize(rc);
for(int i = 0; i < ny; i++) {
const PaintRow& pr = tab[i];
rc.py = pr.py;
PageY pyy;
for(int j = 0; j < nx; j++) {
if(ci[i][j].valid) {
const RichCell& cl = cell[i][j];
pyy = tab[min(ny - 1, i + cl.vspan)].pyy;
int l = cl.text.GetLength() + 1;
if(pos < l) {
rc.page = pr[j].page;
return cl.GetCaret(pos, rc, pyy);
}
ti += cl.text.GetTableCount();
pos -= l;
}
}
}
NEVER();
return RichCaret();
}
int RichTable::GetPos(int x, PageY y, RichContext rc) const
{
int nx = format.column.GetCount();
int ny = cell.GetCount();
const TabLayout& tab = Realize(rc);
int pos = 0;
for(int i = 0; i < ny; i++) {
const PaintRow& pr = tab[i];
rc.py = pr.py;
for(int j = 0; j < nx; j++)
if(ci[i][j].valid) {
const RichCell& cl = cell[i][j];
const PaintCell& pc = pr[j];
PageY pyy = tab[min(ny - 1, i + cl.vspan)].pyy;
if(y < pyy
&& (j == 0 || x >= pc.page.left - format.grid)
&& (j == nx - 1 || x < pc.page.right)) {
rc.page = pc.page;
return cl.GetPos(x, y, rc, pyy) + pos;
}
pos += cl.text.GetLength() + 1;
}
}
return pos ? pos - 1 : 0;
}
RichHotPos RichTable::GetHotPos(int x, PageY y, int tolerance, RichContext rc) const
{
RichHotPos hp;
hp.textleft = rc.page.left;
hp.textcx = rc.page.Width();
int nx = format.column.GetCount();
int ny = cell.GetCount();
const TabLayout& tab = Realize(rc);
if(abs(x - tab.page.left) <= tolerance) {
hp.table = 0;
hp.column = RICHHOT_LM;
hp.delta = x - tab.page.left;
return hp;
}
if(abs(x - tab.page.right) <= tolerance) {
hp.table = 0;
hp.column = RICHHOT_RM;
hp.delta = x - tab.page.right;
return hp;
}
int ti = 0;
for(int i = 0; i < ny; i++) {
const PaintRow& pr = tab[i];
rc.py = pr.py;
for(int j = 0; j < nx; j++) {
if(ci[i][j].valid) {
const RichCell& cl = cell[i][j];
const PaintCell& pc = pr[j];
PageY pyy = tab[min(ny - 1, i + cl.vspan)].pyy;
if(y < pyy) {
if(j < nx - 1 && abs(x - pc.page.right) <= tolerance) {
hp.table = 0;
hp.column = j + cl.hspan;
hp.delta = x - pc.page.right;
hp.left = tab.page.left;
hp.cx = tab.page.Width();
return hp;
}
if((j == 0 || x >= pc.page.left - format.grid) && (j == nx - 1 || x < pc.page.right)) {
rc.page = pc.page;
hp = cl.GetHotPos(x, y, tolerance, rc, pyy);
hp.table += ti;
return hp;
}
}
ti += cl.text.GetTableCount();
}
}
}
return RichHotPos();
}
int RichTable::GetVertMove(int pos, int gx, RichContext rc, int dir) const
{
if(cell.GetCount() == 0)
return -1;
int nx = format.column.GetCount();
int ny = cell.GetCount();
const TabLayout& tab = Realize(rc);
Point cp;
if(pos >= 0)
cp = FindCell(pos);
else {
cp.y = dir > 0 ? 0 : cell.GetCount() - 1;
cp.x = 0;
const PaintRow& pr = tab[cp.y];
for(int j = 0; j < nx; j++)
if(ci[cp.y][cp.x].valid && gx < pr[j].page.right) {
cp.x = j;
break;
}
pos = -1;
}
for(;;) {
rc.page = tab[cp.y][cp.x].page;
const RichCell& c = cell[cp.y][cp.x];
RichContext rc1 = rc;
if(c.Reduce(rc1)) {
int q = cell[cp.y][cp.x].text.GetVertMove(pos, gx, rc1, dir);
if(q >= 0)
return q + GetCellPos(cp);
}
pos = -1;
cp.y += dir;
if(cp.y < 0 || cp.y >= ny)
return -1;
}
}
void RichTable::GatherValPos(Vector<RichValPos>& f, RichContext rc, int pos, int type) const
{
ASSERT(pos >= 0);
int nx = format.column.GetCount();
int ny = cell.GetCount();
const TabLayout& tab = Realize(rc);
for(int i = 0; i < ny; i++) {
const PaintRow& pr = tab[i];
rc.py = pr.py;
for(int j = 0; j < nx; j++)
if(ci[i][j].valid) {
const RichCell& cl = cell[i][j];
rc.page = pr[j].page;
cl.GatherValPos(f, rc, tab[min(ny - 1, i + cl.vspan)].pyy, pos, type);
pos += cl.text.GetLength() + 1;
}
}
}
void RichTable::ApplyZoom(Zoom z, const RichStyles& ostyle, const RichStyles& zstyle)
{
Invalidate();
r_row = -1;
int nx = format.column.GetCount();
int ny = cell.GetCount();
format.frame = LineZoom(z, format.frame);
format.grid = LineZoom(z, format.grid);
format.before *= z;
format.lm *= z;
format.rm *= z;
format.after *= z;
for(int i = 0; i < ny; i++)
for(int j = 0; j < nx; j++)
if(ci[i][j].valid) {
RichCell& c = cell[i][j];
c.format.border *= z;
c.format.margin *= z;
c.format.minheight *= z;
c.text.ApplyZoom(z, ostyle, zstyle);
}
}
END_UPP_NAMESPACE

135
uppdev/RichTextP/Text.h Normal file
View file

@ -0,0 +1,135 @@
class RichText : public RichTxt, public DeepCopyOption<RichText> {
RichStyles style;
String footer; // ugly hack
bool nolinks;
void Init();
struct StyleChangeOp;
struct SetStylesOp;
struct RemoveStyleOp;
struct MergeStylesOp;
friend struct MergeStylesOp;
struct OverrideStylesOp;
public:
void Clear();
int GetStyleCount() const { return style.GetCount(); }
Uuid GetStyleId(int i) const { return style.GetKey(i); }
Uuid GetStyleId(const String& name) const;
const RichStyle& GetStyle(int i) const { return style[i]; }
const RichStyle& GetStyle(const Uuid& id) const { return UPP::GetStyle(style, id); }
void SetStyle(const Uuid& id, const RichStyle& _style);
bool HasStyle(const Uuid& id) { return style.Find(id) >= 0; }
void RemoveStyle(const Uuid& id);
const RichStyles& GetStyles() const { return style; }
void SetStyles(const RichStyles& styles);
void OverrideStyles(const RichStyles& masterstyles,
bool matchname = true, bool addmissing = true);
void MergeStyles(const RichText& text);
RichPara Get(int i) const { return RichTxt::Get(i, style); }
void Cat(const RichPara& p) { RichTxt::Cat(p, style); }
void CatPick(pick_ RichText& p);
using RichTxt::CatPick;
RichContext Context(const Rect& page) const;
RichPos GetRichPos(int pos, int maxlevel = INT_MAX) const;
int operator[](int pos) const { return GetRichPos(pos).chr; }
void ApplyZoom(Zoom z);
PageY GetHeight(PageY py, const Rect& page) const;
PageY GetHeight(const Rect& page) const;
void Paint(PageDraw& w, PageY py, const Rect& page, const PaintInfo& pi) const;
void Paint(PageDraw& w, const Rect& page, const PaintInfo& pi) const;
RichCaret GetCaret(int pos, const Rect& page) const;
int GetPos(int x, PageY y, const Rect& page) const;
RichHotPos GetHotPos(int x, PageY y, int tolerance, const Rect& page) const;
int GetVertMove(int pos, int gx, const Rect& page, int dir) const;
int GetWidth() const;
int GetHeight(int cx) const;
int GetHeight(Zoom zoom, int cx) const;
void Paint(Draw& w, int x, int y, int cx, const PaintInfo& pi) const;
void Paint(Zoom zoom, Draw& w, int x, int y, int cx) const;
void Paint(Draw& w, int x, int y, int cx) const;
Vector<RichValPos> GetValPos(const Rect& page, int type) const;
int AdjustCursor(int anchor, int cursor) const;
void Remove(int pos, int count);
void Insert(int pos, const RichText& p);
RichText Copy(int pos, int count) const;
FormatInfo GetFormatInfo(int pos, int count) const;
void ApplyFormatInfo(int pos, const FormatInfo& fi, int count);
void ReStyle(int pos, const Uuid& id);
Formating SaveFormat(int pos, int count) const;
void RestoreFormat(int pos, const Formating& info);
RichTable::Format GetTableFormat(int table) const;
void SetTableFormat(int table, const RichTable::Format& fmt);
int SetTable(int pos, const RichTable& table);
void DestroyTable(int table);
RichTable CopyTable(int table) const;
void ReplaceTable(int table, const RichTable& tab);
void RemoveParaSpecial(int table, bool before);
bool CanRemoveParaSpecial(int table, bool before);
void InsertParaSpecial(int table, bool before, const RichPara::Format& fmt);
bool ShouldInsertParaSpecial(int table, bool before);
RichTable CopyTable(int table, const Rect& sel) const;
void ClearTable(int table, const Rect& sel);
void PasteTable(int table, Point pos, const RichTable& tab);
void InsertTableRow(int table, int row);
void RemoveTableRow(int table, int row);
void InsertTableColumn(int table, int column);
void RemoveTableColumn(int table, int column);
Point GetMasterCell(int table, int row, int column);
Point GetMasterCell(int table, Point p) { return GetMasterCell(table, p.y, p.x); }
void SplitCell(int table, Point cell, Size sz);
void JoinCell(int table, const Rect& sel);
RichCell::Format GetCellFormat(int table, const Rect& sel) const;
void SetCellFormat(int table, const Rect& sel, const RichCell::Format& fmt, bool setkeep);
FormatInfo GetTableFormatInfo(int table, const Rect& sel) const;
void ApplyTableFormatInfo(int table, const Rect& sel, const RichText::FormatInfo& fi);
void AdjustTableSel(int table, Rect& sel) const { return GetConstTable(table).AdjustSel(sel); }
bool Iterate(Iterator& r) const { return RichTxt::Iterate(r, 0, style); }
bool Iterate(UpdateIterator& r) { return RichTxt::Iterate(r, 0, style); }
bool EvaluateFields(VectorMap<String, Value>& vars) { return RichTxt::EvaluateFields(style, vars); }
void InvalidateAll() { r_type = ALL; }
void Validate();
bool GetInvalid(PageY& top, PageY& bottom, const Rect& page,
int sell, int selh, int osell, int oselh) const;
struct ClipboardType {
ClipboardType();
virtual ~ClipboardType();
virtual int Level();
virtual RichText ReadClipboard(const RichPara::Format& f) = 0;
virtual void WriteClipboard(const RichText& text) = 0;
};
static void Register(ClipboardType& type);
//Ugly hacks
void SetFooter(const String& s) { footer = s; }
String GetFooter() const { return footer; }
void PrintNoLinks(bool b = true) { nolinks = b; }
bool IsPrintNoLinks() const { return nolinks; }
RichText() { Init(); }
RichText(const RichText& x, int);
RichText(pick_ RichTxt& x, pick_ RichStyles& st);
};

View file

@ -0,0 +1,332 @@
#include "RichText.h"
NAMESPACE_UPP
void RichText::CatPick(pick_ RichText& p)
{
MergeStyles(p);
int c = part.GetCount();
part.AppendPick(p.part);
for(int i = c; i < part.GetCount(); i++)
if(IsPara(i))
part[i].Get<Para>().cx = -1;
RefreshAll();
}
RichPos::RichPos()
{
tabtextparti = tabtextpartcount = tabposintabtext = tabtextlen = table = tablen = posintab =
celllen = posincell = parai = partcount = posinpara = paralen = 0;
parenttab = Null;
tabsize = Size(0, 0);
cell = Point(0, 0);
chr = '?';
}
RichPos RichText::GetRichPos(int pos, int maxlevel) const
{
RichPos rp;
rp.level = 0;
RichTxt::GetRichPos(pos, rp, 0, maxlevel, style);
if(IsNull(rp.parenttab))
rp.parenttab = 0;
return rp;
}
int RichText::AdjustCursor(int anchor, int cursor) const
{
int d = anchor;
const RichTxt& txt = GetConstText(anchor);
d -= anchor;
if(!(cursor == txt.GetLength() && !txt.IsTable(txt.GetPartCount() - 1)))
cursor = minmax(cursor - d, 0, txt.GetLength());
int c = cursor;
int pi = txt.FindPart(c);
if(txt.IsTable(pi)) {
if(cursor < anchor) {
while(--pi >= 0)
if(txt.IsPara(pi))
return d + txt.GetPartPos(pi) + txt.GetPartLength(pi);
while(++pi < txt.GetPartCount())
if(txt.IsPara(pi))
return d + txt.GetPartPos(pi);
return d + anchor;
}
else {
while(++pi < txt.GetPartCount())
if(txt.IsPara(pi))
return d + txt.GetPartPos(pi);
while(--pi >= 0)
if(txt.IsPara(pi))
return d + txt.GetPartPos(pi) + txt.GetPartLength(pi);
return d + anchor;
}
}
return d + cursor;
}
void RichText::Remove(int pos, int count)
{
GetLength();
int p = pos;
int l = GetConstText(p).GetLength();
count = min(l - p, count);
RichTxt& txt = GetUpdateText(pos);
int pos2 = pos + count;
int pi = txt.FindPart(pos);
int pi2 = txt.FindPart(pos2);
if(pi == pi2) {
RichPara pa, pa1;
pa = txt.Get(pi, style);
pa1 <<= pa;
pa.Trim(pos);
pa1.Mid(pos2);
pa.Append(pa1);
txt.Put(pi, pa, style);
}
else {
RichPara pa2 = txt.Get(pi2, style);
RichPara pa = txt.Get(pi, pa2.format.styleid, style);
txt.part.Remove(pi, pi2 - pi);
pa.Trim(pos);
pa2.Mid(pos2);
pa.Append(pa2);
pa.format = pa2.format;
txt.Put(pi, pa, style);
txt.SetRefreshFrom(pi);
}
}
void RichText::Insert(int pos, const RichText& p)
{
MergeStyles(p);
if(p.GetLength() == 0)
return;
ASSERT(pos >= 0 && pos <= GetLength());
RichTxt& txt = GetUpdateText(pos);
int pi = txt.FindPart(pos);
int n = p.part.GetCount() - 1;
if(n) {
txt.part.Insert(pi + 1, p.part, 1, n);
RichPara pa1, pa2;
pa1 = txt.Get(pi, style);
pa2 = txt.Get(pi + n, pa1.format.styleid, style);
pa1.Mid(pos);
pa2.Append(pa1);
pa2.format = pa1.format;
txt.Put(pi + n, pa2, style);
pa2 = p.RichTxt::Get(0, p.GetStyle(p.GetParaStyle(0)));
pa1 = txt.Get(pi, pa2.format.styleid, style);
pa1.Trim(pos);
pa1.Append(pa2);
pa1.format = pa2.format;
txt.Put(pi, pa1, style);
txt.SetRefreshFrom(pi);
}
else {
RichPara pa0, pa2;
pa0 = txt.Get(pi, style);
pa2 <<= pa0;
pa0.Trim(pos);
pa2.Mid(pos);
pa0.Append(p.RichTxt::Get(0, p.GetStyle(pa0.format.styleid)));
pa0.Append(pa2);
txt.Put(pi, pa0, style);
}
}
RichText RichText::Copy(int pos, int count) const
{
RichText r;
r.SetStyles(style);
const RichTxt& txt = GetConstText(pos);
bool addp = false;
if(count > txt.GetLength() - pos) {
count = txt.GetLength() - pos;
addp = true;
}
int pos2 = pos + count;
int pi = txt.FindPart(pos);
int pi2 = txt.FindPart(pos2);
if(pi == pi2) {
RichPara pa = txt.Get(pi, style);
pa.Trim(pos2);
pa.Mid(pos);
r.Cat(pa);
}
else {
RichPara pa = txt.Get(pi++, style);
pa.Mid(pos);
r.Cat(pa);
while(pi < pi2) {
if(txt.IsPara(pi))
r.Cat(txt.Get(pi, style));
else {
RichTable tab(txt.GetTable(pi), 1);
r.CatPick(tab);
}
pi++;
}
pa = txt.Get(pi2, style);
pa.Trim(pos2);
r.Cat(pa);
}
if(addp)
r.Cat(RichPara());
return r;
}
RichText::FormatInfo RichText::GetFormatInfo(int pos, int count) const
{
const RichTxt& txt = GetConstText(pos);
count = min(txt.GetLength() - pos, count);
int pos2 = pos + count;
int pi = txt.FindPart(pos);
int pi2 = txt.FindPart(pos2);
FormatInfo fi;
RichPara::Format fmt;
RichPara pa = txt.Get(pi, style);
fmt = pa.format;
int i = pa.FindPart(pos);
if(i < pa.GetCount())
(RichPara::CharFormat&)fmt = pa[i].format;
fi.Set(fmt);
i++;
if(pi == pi2) {
int i2 = pa.FindPart(pos2);
while(i < i2)
fi.Combine(pa[i++].format);
if(pos2 && i2 < pa.GetCount())
fi.Combine(pa[i2].format);
}
else {
while(i < pa.GetCount())
fi.Combine(pa[i++].format);
fi.Combine(pa.format);
pi++;
bool first = false;
txt.CombineFormat(fi, pi, pi2, first, style);
pa = txt.Get(pi2, style);
int i2 = pa.FindPart(pos2);
for(i = 0; i < i2; i++)
fi.Combine(pa[i].format);
if(pos2 && i2 < pa.GetCount())
fi.Combine(pa[i2].format);
}
return fi;
}
void RichText::ApplyFormatInfo(int pos, const FormatInfo& fi, int count)
{
RichTxt& txt = GetUpdateText(pos);
int pos2 = min(txt.GetLength(), pos + count);
int pi = txt.FindPart(pos);
int pi2 = txt.FindPart(pos2);
ASSERT(txt.IsPara(pi) && txt.IsPara(pi2));
if(pi == pi2) {
RichPara pa, pa1, pa2;
pa = txt.Get(pi, style);
ApplyStyle(fi, pa, style);
pa1 <<= pa;
pa2 <<= pa;
pa.Trim(pos);
pa2.Mid(pos2);
pa1.Trim(pos2);
pa1.Mid(pos);
Apply(fi, pa1, style);
pa.Append(pa1);
pa.Append(pa2);
fi.ApplyTo(pa.format);
txt.Put(pi, pa, style);
}
else {
RichPara pa, pa1;
// if(fi.paravalid & RichText::STYLE)
// pa = txt.Get(pi, fi.styleid, style);
// else
pa = txt.Get(pi, style);
ApplyStyle(fi, pa, style);
pa1 <<= pa;
pa.Trim(pos);
pa1.Mid(pos);
Apply(fi, pa1, style);
fi.ApplyTo(pa.format);
pa.Append(pa1);
txt.Put(pi, pa, style);
pi++;
txt.ApplyFormat(fi, pi, pi2, style);
// if(fi.paravalid & RichText::STYLE)
// pa = txt.Get(pi2, fi.styleid, style);
// else
pa = txt.Get(pi2, style);
ApplyStyle(fi, pa, style);
pa1 <<= pa;
pa.Trim(pos2);
pa1.Mid(pos2);
Apply(fi, pa, style);
pa.Append(pa1);
txt.Put(pi2, pa, style);
}
}
void RichText::ReStyle(int pos, const Uuid& id)
{
int p = FindPart(pos);
RichPara pa = Get(p);
pa.format.styleid = id;
Put(p, pa, style);
}
RichText::Formating RichText::SaveFormat(int pos, int count) const
{
const RichTxt& txt = GetConstText(pos);
count += pos;
Formating r;
txt.SaveFormat(r, txt.FindPart(pos), txt.FindPart(count), style);
return r;
}
void RichText::RestoreFormat(int pos, const RichText::Formating& info)
{
RichTxt& txt = GetUpdateText(pos);
int ii = 0;
txt.RestoreFormat(txt.FindPart(pos), info, ii, style);
}
void RichText::Init()
{
RichTxt::Init();
RichStyle& s = style.Add(RichStyle::GetDefaultId());
s.name = "Default";
nolinks = false;
}
void RichText::Clear()
{
RichTxt::Clear();
style.Clear();
Init();
}
RichText::RichText(const RichText& x, int)
: RichTxt(x, 1), style(x.style, 1)
{
nolinks = x.nolinks;
}
RichText::RichText(pick_ RichTxt& x, pick_ RichStyles& st)
: RichTxt(x), style(st)
{
nolinks = false;
}
END_UPP_NAMESPACE

View file

@ -0,0 +1,183 @@
#include "RichText.h"
NAMESPACE_UPP
RichContext RichText::Context(const Rect& page) const
{
RichContext c(style);
c.page = page;
c.py = PageY(0, page.top);
return c;
}
PageY RichText::GetHeight(const Rect& page) const
{
return RichTxt::GetHeight(Context(page));
}
PageY RichText::GetHeight(PageY py, const Rect& page) const
{
RichContext ctx = Context(page);
ctx.py = py;
return RichTxt::GetHeight(ctx);
}
int RichText::GetWidth() const
{
return RichTxt::GetWidth(style);
}
void RichText::Paint(PageDraw& w, PageY py, const Rect& page, const PaintInfo& pi) const
{
RichContext ctx = Context(page);
ctx.py = py;
RichTxt::Paint(w, ctx, pi);
}
void RichText::Paint(PageDraw& w, const Rect& page, const PaintInfo& pi) const
{
RichTxt::Paint(w, Context(page), pi);
}
RichCaret RichText::GetCaret(int pos, const Rect& page) const
{
return RichTxt::GetCaret(pos, Context(page));
}
int RichText::GetPos(int x, PageY y, const Rect& page) const
{
return RichTxt::GetPos(x, y, Context(page));
}
int RichText::GetVertMove(int pos, int gx, const Rect& page, int dir) const
{
return RichTxt::GetVertMove(pos, gx, Context(page), dir);
}
RichHotPos RichText::GetHotPos(int x, PageY y, int tolerance, const Rect& page) const
{
RichHotPos p = RichTxt::GetHotPos(x, y, tolerance, Context(page));
if(p.column < -2)
p.table = 0;
return p;
}
Vector<RichValPos> RichText::GetValPos(const Rect& page, int type) const
{
Vector<RichValPos> f;
GatherValPos(f, Context(page), 0, type);
return f;
}
void RichText::Validate()
{
r_type = NONE;
for(int i = 0; i < part.GetCount(); i++)
if(IsTable(i))
part[i].Get<RichTable>().Validate();
}
bool RichText::GetInvalid(PageY& top, PageY& bottom, const Rect& page,
int sell, int selh, int osell, int oselh) const
{
int spi;
int rtype = r_type;
if(sell != selh || osell != oselh) {
if(sell != osell) {
if(rtype == NONE) {
spi = FindPart(sell);
rtype = spi == FindPart(osell) ? SPARA : ALL;
}
else
rtype = ALL;
}
if(selh != oselh) {
if(rtype == NONE) {
spi = FindPart(selh);
rtype = spi == FindPart(oselh) ? SPARA : ALL;
}
else
rtype = ALL;
}
}
bottom = top = PageY(0, page.top);
if(rtype == NONE) {
bottom = top;
return false;
}
if(rtype == ALL) {
bottom = GetHeight(page);
return true;
}
RichContext rc = Context(page);
if(rtype == SPARA) {
rc.py = top = GetPartPageY(spi, rc);
bottom = GetNextPageY(spi, rc);
return true;
}
rc.py = top = GetPartPageY(r_parti, rc);
if(rtype == PARA) {
if(IsTable(r_parti))
switch(GetTable(r_parti).GetInvalid(top, bottom, rc)) {
case -1: return false;
case 0: return true;
default:
bottom = GetHeight(page);
return true;
}
else {
Sync(r_parti, rc);
const Para& pp = part[r_parti].Get<Para>();
if(r_paraocx == pp.cx &&
r_paraocy == Sum(pp.linecy, 0) + pp.ruler + pp.before + pp.after &&
r_keep == pp.keep &&
r_keepnext == pp.keepnext &&
r_newpage == pp.newpage) {
bottom = GetNextPageY(r_parti, rc);
return true;
}
}
}
bottom = GetHeight(page);
return true;
}
int RichText::GetHeight(Zoom zoom, int cx) const
{
int lwd = cx / zoom;
return GetHeight(Size(lwd, 0xFFFFFFF)).y * zoom;
}
int RichText::GetHeight(int cx) const
{
return GetHeight(Size(cx, 0xFFFFFFF)).y;
}
void RichText::Paint(Draw& w, int x, int y, int cx, const PaintInfo& pinit) const
{
SimplePageDraw pw(w);
PaintInfo pi(pinit);
pi.top = PageY(0, 0);
pi.bottom = PageY(0, INT_MAX);
pi.usecache = true;
pi.sizetracking = false;
pi.highlight = Null;
w.Offset(x, y);
Paint(pw, Size(cx / pi.zoom, INT_MAX), pi);
w.End();
}
void RichText::Paint(Zoom zoom, Draw& w, int x, int y, int cx) const
{
PaintInfo pi;
pi.highlightpara = false;
pi.zoom = zoom;
Paint(w, x, y, cx, pi);
}
void RichText::Paint(Draw& w, int x, int y, int cx) const
{
Paint(Zoom(1, 1), w, x, y, cx);
}
END_UPP_NAMESPACE

View file

@ -0,0 +1,153 @@
#include "RichText.h"
NAMESPACE_UPP
const RichStyle& RichStyle::GetDefault()
{
return Single<RichStyle>();
}
Uuid RichStyle::GetDefaultId()
{
Uuid id;
id.a = 0;
id.b = 0;
id.c = 0;
id.d = 0;
return id;
}
const RichStyle& GetStyle(const RichStyles& s, const Uuid& id)
{
return s.Get(id, RichStyle::GetDefault());
}
int FindStyleWithName(const RichStyles& style, const String& name)
{
for(int j = 0; j < style.GetCount(); j++)
if(style[j].name == name)
return j;
return -1;
}
struct RichText::StyleChangeOp : RichTxt::ParaOp {
Uuid id, nid;
virtual bool operator()(RichTxt::Para& p) {
if(p.styleid == id) {
p.styleid = nid;
p.cx = -1;
return true;
}
return false;
}
};
void RichText::SetStyle(const Uuid& id, const RichStyle& _style)
{
Invalidate();
RichStyle& s = style.GetAdd(id);
s = _style;
s.format.styleid = id;
s.format.language = 0;
s.format.newpage = false;
StyleChangeOp op;
op.nid = op.id = id;
Update(op);
}
struct RichText::SetStylesOp : RichTxt::ParaOp {
RichStyles *style;
virtual bool operator()(RichTxt::Para& p) {
p.cx = -1;
if(style->Find(p.styleid) < 0)
p.styleid = RichStyle::GetDefaultId();
return true;
}
};
void RichText::SetStyles(const RichStyles& _style)
{
Invalidate();
style <<= _style;
SetStylesOp op;
op.style = &style;
Update(op);
}
Uuid RichText::GetStyleId(const String& name) const
{
int i = FindStyleWithName(style, name);
return i >= 0 ? style.GetKey(i) : RichStyle::GetDefaultId();
}
void RichText::RemoveStyle(const Uuid& id)
{
ASSERT(id != RichStyle::GetDefaultId());
Invalidate();
StyleChangeOp op;
op.id = id;
op.nid = RichStyle::GetDefaultId();
Update(op);
style.RemoveKey(id);
}
struct RichText::MergeStylesOp : RichTxt::ParaOp {
RichText *text;
const RichText *stxt;
virtual bool operator()(RichTxt::Para& p) {
if(text->style.Find(p.styleid) < 0) {
RichStyle& s = text->style.GetAdd(p.styleid);
s = stxt->GetStyle(p.styleid);
s.format.styleid = p.styleid;
}
return false;
}
};
void RichText::MergeStyles(const RichText& text)
{
Invalidate();
MergeStylesOp op;
op.stxt = &text;
op.text = this;
const_cast<RichText&>(text).Update(op);
}
struct RichText::OverrideStylesOp : RichTxt::ParaOp {
VectorMap<Uuid, Uuid> cs;
virtual bool operator()(RichTxt::Para& p) {
p.styleid = cs.Get(p.styleid, RichStyle::GetDefaultId());
p.cx = -1;
return true;
}
};
void RichText::OverrideStyles(const RichStyles& ms, bool matchname, bool addmissing)
{
Invalidate();
RichStyles orig = style;
style <<= ms;
OverrideStylesOp op;
for(int i = 0; i < orig.GetCount(); i++) {
Uuid pid = orig.GetKey(i);
int q;
if(ms.Find(pid) >= 0)
op.cs.Add(pid, pid);
else
if(matchname && (q = FindStyleWithName(style, orig[i].name)) >= 0)
op.cs.Add(pid, style.GetKey(q));
else
if(addmissing) {
SetStyle(pid, orig[i]);
op.cs.Add(pid, pid);
}
}
Update(op);
}
END_UPP_NAMESPACE

View file

@ -0,0 +1,225 @@
#include "RichText.h"
NAMESPACE_UPP
RichTable::Format RichText::GetTableFormat(int table) const
{
return GetConstTable(table).GetFormat();
}
void RichText::SetTableFormat(int table, const RichTable::Format& fmt)
{
RichTable& tab = GetUpdateTable(table);
tab.SetFormat(fmt);
tab.Normalize();
}
int RichText::SetTable(int pos, const RichTable& table)
{
RefreshAll();
RichPos p = GetRichPos(pos);
int bpos = pos;
RichTxt& txt = GetUpdateText(pos);
int pi = txt.FindPart(pos);
ASSERT(pos == 0 && txt.GetPartLength(pi) == 0 && txt.IsPara(pi));
RichTable pt(table, 1);
txt.SetPick(pi, pt);
return GetRichPos(bpos).table;
}
RichTable RichText::CopyTable(int table) const
{
RichTable tab(GetConstTable(table), 1);
return tab;
}
void RichText::ReplaceTable(int table, const RichTable& tab)
{
(GetUpdateTable(table) <<= tab).Normalize();
RefreshAll();
}
void RichText::DestroyTable(int table)
{
int pi;
RichTxt& txt = GetTableUpdateText(table, style, pi);
RichPara p;
txt.Set(pi, p, style);
RefreshAll();
}
void RichText::RemoveParaSpecial(int table, bool before)
{
int pi;
RichTxt& txt = GetTableUpdateText(table, style, pi);
if(before)
pi--;
else
pi++;
ASSERT(txt.IsPara(pi) && txt.GetPartLength(pi) == 0);
txt.part.Remove(pi);
RefreshAll();
}
bool RichText::CanRemoveParaSpecial(int table, bool before)
{
int pi;
if(!table)
return false;
RichTxt& txt = GetTableUpdateText(table, style, pi);
if(before)
pi--;
else
pi++;
return pi >= 0 && pi < txt.GetPartCount() && txt.IsPara(pi) && txt.GetPartLength(pi) == 0;
}
bool RichText::ShouldInsertParaSpecial(int table, bool before)
{
int pi;
RichTxt& txt = GetTableUpdateText(table, style, pi);
if(!before)
pi++;
return pi == 0 || pi >= txt.GetPartCount() || txt.IsTable(pi);
}
void RichText::InsertParaSpecial(int table, bool before, const RichPara::Format& fmt)
{
int pi;
RichTxt& txt = GetTableUpdateText(table, style, pi);
if(!before)
pi++;
txt.RefreshAll();
txt.part.Insert(pi);
RichPara p;
p.format = fmt;
txt.Set(pi, p, style);
RefreshAll();
}
RichTable RichText::CopyTable(int table, const Rect& sel) const
{
return GetConstTable(table).Copy(sel);
}
Point RichText::GetMasterCell(int table, int row, int column)
{
return GetConstTable(table).GetMasterCell(row, column);
}
void RichText::PasteTable(int table, Point pos, const RichTable& tab)
{
GetUpdateTable(table).Paste(pos, tab);
RefreshAll();
}
void RichText::InsertTableRow(int table, int row)
{
GetUpdateTable(table).InsertRow(row, style);
RefreshAll();
}
void RichText::RemoveTableRow(int table, int row)
{
GetUpdateTable(table).RemoveRow(row);
RefreshAll();
}
void RichText::InsertTableColumn(int table, int column)
{
GetUpdateTable(table).InsertColumn(column, style);
RefreshAll();
}
void RichText::RemoveTableColumn(int table, int column)
{
GetUpdateTable(table).RemoveColumn(column);
RefreshAll();
}
void RichText::SplitCell(int table, Point cell, Size sz)
{
GetUpdateTable(table).SplitCell(cell, sz, style);
RefreshAll();
}
void RichText::JoinCell(int table, const Rect& sel)
{
RichTable& tab = GetUpdateTable(table);
RichCell& cell = tab[sel.top][sel.left];
cell.vspan = sel.bottom - sel.top;
cell.hspan = sel.right - sel.left;
for(int i = sel.top; i <= sel.bottom; i++)
for(int j = sel.left; j <= sel.right; j++) {
if(tab(i, j) && (i != sel.top || j != sel.left)) {
RichTxt& t = tab[i][j].text;
for(int pi = 0; pi < t.GetPartCount(); pi++)
if(t.IsTable(pi))
cell.text.CatPick(t.part[pi].Get<RichTable>());
else
if(pi < t.GetPartCount() - 1 || t.GetPartLength(pi))
cell.text.Cat(t.Get(pi, style), style);
tab[i][j].ClearText();
}
}
tab.Normalize();
RefreshAll();
}
RichCell::Format RichText::GetCellFormat(int table, const Rect& sel) const
{
return GetConstTable(table).GetCellFormat(sel);
}
void RichText::SetCellFormat(int table, const Rect& sel, const RichCell::Format& fmt, bool setkeep)
{
GetUpdateTable(table).SetCellFormat(sel, fmt, setkeep);
RefreshAll();
}
void RichText::ClearTable(int table, const Rect& sel)
{
RichTable& tab = GetUpdateTable(table);
for(int i = sel.top; i <= sel.bottom; i++)
for(int j = sel.left; j <= sel.right; j++) {
if(tab(i, j)) {
tab.InvalidateRefresh(i, j);
tab[i][j].ClearText(tab[i][j].text.GetFirstFormat(style), style);
}
}
tab.Normalize();
RefreshAll();
}
RichText::FormatInfo RichText::GetTableFormatInfo(int table, const Rect& sel) const
{
const RichTable& tab = GetConstTable(table);
bool first = true;
FormatInfo fi;
for(int i = sel.top; i <= sel.bottom; i++)
for(int j = sel.left; j <= sel.right; j++) {
if(tab(i, j)) {
const RichTxt& txt = tab[i][j].text;
txt.CombineFormat(fi, 0, txt.GetPartCount(), first, style);
}
}
return fi;
}
void RichText::ApplyTableFormatInfo(int table, const Rect& sel, const RichText::FormatInfo& fi)
{
RichTable& tab = GetUpdateTable(table);
for(int i = sel.top; i <= sel.bottom; i++)
for(int j = sel.left; j <= sel.right; j++) {
if(tab(i, j)) {
tab.InvalidateRefresh(i, j);
RichTxt& txt = tab[i][j].text;
txt.ApplyFormat(fi, 0, txt.GetPartCount(), style);
}
}
tab.Normalize();
RefreshAll();
}
END_UPP_NAMESPACE

247
uppdev/RichTextP/Txt.h Normal file
View file

@ -0,0 +1,247 @@
class RichTxt : DeepCopyOption<RichTxt> {
public:
enum {
BOLD = 0x00000001,
ITALIC = 0x00000002,
UNDERLINE = 0x00000004,
FACE = 0x00000008,
HEIGHT = 0x00000010,
LANGUAGE = 0x00000020,
INK = 0x00000040,
PAPER = 0x00000080,
LINK = 0x00000100,
SSCRIPT = 0x00000200,
CAPITALS = 0x00000400,
STRIKEOUT = 0x00000800,
LANG = 0x00001000,
INDEXENTRY = 0x00002000,
DASHED = 0x00004000,
NOAA = 0x00008000,
};
enum {
ALIGN = 0x80000000,
BEFORE = 0x40000000,
LM = 0x20000000,
INDENT = 0x10000000,
RM = 0x08000000,
AFTER = 0x04000000,
TABSIZE = 0x02000000,
BULLET = 0x01000000,
NEWPAGE = 0x00800000,
KEEP = 0x00400000,
TABS = 0x00200000,
STYLE = 0x00100000,
LABEL = 0x00080000,
KEEPNEXT = 0x00040000,
ORPHAN = 0x00020000,
NUMBERING = 0x00010000,
SPACING = 0x00008000,
RULER = 0x00004000,
RULERINK = 0x00002000,
};
struct FormatInfo : RichPara::Format {
dword charvalid;
dword paravalid;
void Set(const RichPara::Format& fmt);
void Set(const RichPara::CharFormat& fmt);
void Combine(const RichPara::CharFormat& fmt);
void Combine(const RichPara::Format& fmt);
void Combine(const FormatInfo& fmt);
void ApplyTo(RichPara::CharFormat& fmt) const;
void ApplyTo(RichPara::Format& fmt) const;
};
class Formating {
Vector<Uuid> styleid;
Vector<String> format;
friend class RichText;
friend class RichTxt;
};
protected:
struct Para : DeepCopyOption<Para> {
Uuid styleid;
int length;
String content;
Array<RichObject> object;
mutable int cx;
mutable int cy;
mutable int ruler;
mutable int before;
mutable Vector<int> linecy;
mutable int after;
mutable bool newpage;
mutable bool keep;
mutable bool keepnext;
mutable bool orphan;
mutable int numbering;
mutable Bits spellerrors;
mutable bool checked;
mutable bool haspos;
One<RichPara::NumberFormat> number;
Para(const Para& src, int);
Para() { length = 0; cx = -1; numbering = -1; checked = false; haspos = false; }
};
struct Part : MoveableAndDeepCopyOption< Part, Any> {
Part(const Part& src, int);
Part();
};
Vector<Part> part;
mutable int length;
mutable int tabcount;
mutable Rect rect;
mutable Vector<PageY> py;
enum {
NONE, SPARA, PARA, FROM, ALL
};
int r_type;
int r_parti;
int r_paraocx;
int r_paraocy;
bool r_keep;
bool r_keepnext;
bool r_newpage;
void Init();
void Invalidate();
void SetRefresh(int parai);
void SetRefreshFrom(int parai);
void RefreshAll() { SetRefreshFrom(0); }
void ParaRemove(int parai, int pos, int count);
void ParaInsert(int parai, int pos, const RichPara& p);
RichPara ParaCopy(int parai, int pos, int count) const;
void Put(int i, const RichPara& p, const RichStyle& s);
void Put(int i, const RichPara& p, const RichStyles& s);
void Sync0(const Para& pp, int parti, const RichContext& rc) const;
inline void Sync(int parti, const RichContext& rc) const {
int cx = rc.page.Width();
ASSERT(part[parti].Is<Para>());
const Para& pp = part[parti].Get<Para>();
if(pp.cx == cx) return;
Sync0(pp, parti, rc);
}
bool BreaksPage(PageY py, const Para& pp, int i, const Rect& page) const;
PageY GetNextPageY(int parti, const RichContext& rc) const;
PageY GetPartPageY(int parti, RichContext rc) const;
struct ParaOp {
virtual bool operator()(RichTxt::Para& p) = 0;
virtual ~ParaOp() {}
};
bool Update(ParaOp& op);
RichTxt& GetText0(int& pos, bool update);
RichTxt& GetUpdateText(int& pos);
const RichTxt& GetConstText(int& pos) const;
RichTable& GetTable0(int table, bool update);
RichTable& GetUpdateTable(int table);
const RichTable& GetConstTable(int table) const;
RichTxt& GetTableUpdateText(int table, const RichStyles& style, int& pi);
void CombineFormat(FormatInfo& f, int pi, int pi2, bool& first, const RichStyles& style) const;
static void ApplyStyle(const FormatInfo& fi, RichPara& pa, const RichStyles& style);
static void Apply(const FormatInfo& fi, RichPara& pa, const RichStyles& style);
void ApplyFormat(const FormatInfo& f, int pi, int pi2, const RichStyles& style);
void SaveFormat(Formating& f, int p1, int p2, const RichStyles& style) const;
void RestoreFormat(int pi, const Formating& info, int& ii, const RichStyles& style);
void GetAllLanguages(Index<int>& all) const;
friend class RichTable;
friend class RichText;
friend class RichCell;
int ComputeLength() const;
void GetRichPos(int pos, RichPos& rp, int ti, int maxlevel, const RichStyles& st) const;
RichPara::Format GetFirstFormat(const RichStyles& st) const;
PageY GetTop(RichContext rc) const;
PageY GetHeight(RichContext rc) const;
int GetWidth(const RichStyles& st) const;
void Paint(PageDraw& w, RichContext rc, const PaintInfo& pi) const;
RichCaret GetCaret(int pos, RichContext rc) const;
int GetPos(int x, PageY y, RichContext rc) const;
int GetVertMove(int pos, int gx, RichContext rc, int dir) const;
RichHotPos GetHotPos(int x, PageY y, int tolerance, RichContext rc) const;
void GatherValPos(Vector<RichValPos>& f, RichContext rc, int pos, int type) const;
bool EvaluateFields(const RichStyles& s, VectorMap<String, Value>& vars);
void ApplyZoom(Zoom z, const RichStyles& ostyle, const RichStyles& zstyle);
public:
enum ValPosType { LABELS, INDEXENTRIES };
int GetPartCount() const { return part.GetCount(); }
bool IsPara(int i) const { return part[i].Is<Para>(); }
bool IsTable(int i) const;
int GetPartLength(int pi) const;
int FindPart(int& pos) const;
int GetPartPos(int pi) const;
RichPara Get(int i, const RichStyles& s) const;
RichPara Get(int i, const Uuid& styleid, const RichStyles& s) const;
RichPara Get(int i, const RichStyle& style) const;
Uuid GetParaStyle(int i) const { return part[i].Get<Para>().styleid; }
void SetParaStyle(int i, const Uuid& si);
const RichTable& GetTable(int i) const;
int GetLength() const;
int GetTableCount() const;
bool IsEmpty() const;
RichCellPos GetCellPos(int table, int row, int column) const;
RichCellPos GetCellPos(int table, Point p) const;
void Clear();
void ClearSpelling();
void SetPick(int parti, pick_ RichTable& table);
void CatPick(pick_ RichTable& table) { SetPick(GetPartCount(), table); }
void Set(int parai, const RichPara& p, const RichStyles& s);
void Insert(int parai, const RichPara& p, const RichStyles& s);
void Cat(const RichPara& p, const RichStyles& s) { Set(GetPartCount(), p, s); }
void RemovePart(int parti);
void Normalize();
Vector<int> GetAllLanguages() const;
WString GetPlainText() const;
struct UpdateIterator {
enum { CONTINUE = 0, STOP = 1, UPDATE = 2 };
virtual int operator()(int pos, RichPara& para) = 0;
virtual ~UpdateIterator() {}
};
bool Iterate(UpdateIterator& r, int gpos, const RichStyles& s);
struct Iterator {
virtual bool operator()(int pos, const RichPara& para) = 0;
virtual ~Iterator() {}
};
bool Iterate(Iterator& r, int gpos, const RichStyles& s) const;
RichTxt(const RichTxt& src, int);
RichTxt();
#ifdef _DEBUG
void Dump();
#endif
};

View file

@ -0,0 +1,472 @@
#include "RichText.h"
NAMESPACE_UPP
RichTxt::Para::Para(const Para& src, int)
: object(src.object, 1)
{
length = src.length;
styleid = src.styleid;
content = src.content;
haspos = src.haspos;
if(src.number)
number = new RichPara::NumberFormat(*src.number);
cx = -1;
checked = false;
}
RichTxt::Part::Part(const Part& src, int) {
if(src.Is<Para>())
Create<Para>() <<= src.Get<Para>();
else
Create<RichTable>() <<= src.Get<RichTable>();
}
RichTxt::Part::Part() {}
void RichTxt::Invalidate()
{
length = -1;
tabcount = -1;
py.Clear();
}
int RichTxt::GetPartLength(int pi) const
{
return part[pi].Is<RichTable>() ? part[pi].Get<RichTable>().GetLength() : part[pi].Get<Para>().length;
}
bool RichTxt::IsTable(int i) const { return part[i].Is<RichTable>(); }
const RichTable& RichTxt::GetTable(int i) const { return part[i].Get<RichTable>(); }
int RichTxt::FindPart(int& pos) const
{
int pi = 0;
while(pi < part.GetCount()) {
int l = GetPartLength(pi) + 1;
if(pos < l)
break;
pos -= l;
pi++;
}
if(pi >= part.GetCount())
pos = 0;
return pi;
}
int RichTxt::GetPartPos(int pi) const
{
int pos = 0;
for(int i = 0; i < pi; i++)
pos += GetPartLength(i) + 1;
return pos;
}
void RichTxt::SetRefresh(int parti)
{
switch(r_type) {
case NONE:
r_parti = parti;
r_type = PARA;
if(IsPara(parti)) {
Para& pp = part[parti].Get<Para>();
if(pp.cx >= 0) {
r_paraocx = pp.cx;
r_paraocy = Sum(pp.linecy, 0) + pp.before + pp.after;
r_keep = pp.keep;
r_keepnext = pp.keepnext;
r_newpage = pp.newpage;
break;
}
else
r_type = FROM;
}
break;
case PARA:
if(parti == r_parti) break;
case FROM:
r_parti = min(parti, r_parti);
r_type = FROM;
break;
}
}
void RichTxt::SetRefreshFrom(int parti)
{
r_type = FROM;
if(r_type == NONE)
r_parti = parti;
else
r_parti = min(parti, r_parti);
}
void RichTxt::Put(int i, const RichPara& p, const RichStyle& s)
{
if(i >= part.GetCount() || !IsPara(i))
part.At(i).Create<Para>();
Para& pp = part[i].Get<Para>();
int numbering = p.format.GetNumberLevel();
if(pp.numbering != numbering)
SetRefreshFrom(i);
else
SetRefresh(i);
pp.number.Clear();
pp.content = p.Pack(s.format, pp.object);
pp.cx = -1;
pp.checked = false;
pp.styleid = p.format.styleid;
pp.length = p.GetLength();
pp.numbering = numbering;
pp.spellerrors.Clear();
pp.haspos = p.HasPos();
if(numbering >= 0 || p.format.reset_number) {
pp.number = new RichPara::NumberFormat;
*pp.number = p.format;
}
}
void RichTxt::Put(int i, const RichPara& p, const RichStyles& s)
{
Put(i, p, GetStyle(s, p.format.styleid));
}
void RichTxt::Set(int i, const RichPara& p, const RichStyles& s)
{
Put(i, p, s);
Invalidate();
}
void RichTxt::Insert(int i, const RichPara& p, const RichStyles& s)
{
part.Insert(i);
Set(i, p, s);
}
void RichTxt::RemovePart(int parti)
{
part.Remove(parti);
Invalidate();
}
void RichTxt::SetPick(int i, pick_ RichTable& p)
{
const_cast<RichTable&>(p).Normalize();
part.At(i).Create<RichTable>() = p;
Invalidate();
SetRefresh(i);
}
RichPara RichTxt::Get(int parai, const RichStyle& style) const
{
ASSERT(part[parai].Is<Para>());
const Para& pp = part[parai].Get<Para>();
RichPara p;
p.Unpack(pp.content, pp.object, style.format);
return p;
}
RichPara RichTxt::Get(int parai, const Uuid& styleid, const RichStyles& s) const
{
RichPara p = Get(parai, GetStyle(s, styleid));
p.format.styleid = styleid;
return p;
}
RichPara RichTxt::Get(int parti, const RichStyles& s) const
{
return Get(parti, part[parti].Get<Para>().styleid, s);
}
bool RichTxt::IsEmpty() const
{
return part.IsEmpty() || part.GetCount() == 1 && ComputeLength() == 0;
}
int RichTxt::ComputeLength() const
{
int length = part.GetCount() - 1;
for(int i = 0; i < part.GetCount(); i++)
length += GetPartLength(i);
return length;
}
int RichTxt::GetLength() const
{
if(length < 0)
length = ComputeLength();
return length;
}
int RichTxt::GetTableCount() const
{
if(tabcount < 0) {
tabcount = 0;
for(int i = 0; i < part.GetCount(); i++)
if(IsTable(i))
tabcount += GetTable(i).GetTableCount() + 1;
}
return tabcount;
}
bool RichTxt::EvaluateFields(const RichStyles& s, VectorMap<String, Value>& vars)
{
bool b = false;
for(int i = 0; i < part.GetCount(); i++)
if(IsTable(i)) {
RichTable& tab = part[i].Get<RichTable>();
for(int i = 0; i < tab.GetRows(); i++)
for(int j = 0; j < tab.GetColumns(); j++)
if(tab(i, j) && tab[i][j].text.EvaluateFields(s, vars)) {
tab.InvalidateRefresh(i, j);
b = true;
}
}
else {
RichPara p = Get(i, s);
if(p.EvaluateFields(vars)) {
b = true;
Set(i, p, s);
}
}
return b;
}
void RichTxt::ClearSpelling()
{
for(int i = 0; i < part.GetCount(); i++) {
if(IsTable(i)) {
RichTable& tab = part[i].Get<RichTable>();
for(int i = 0; i < tab.GetRows(); i++)
for(int j = 0; j < tab.GetColumns(); j++)
if(tab(i, j)) {
tab[i][j].text.ClearSpelling();
tab.InvalidateRefresh(i, j);
}
}
else {
Para& p = part[i].Get<Para>();
p.spellerrors.Clear();
p.checked = false;
}
}
}
void RichTxt::SetParaStyle(int i, const Uuid& id)
{
ASSERT(IsPara(i));
Para& p = part[i].Get<Para>();
p.styleid = id;
p.cx = -1;
SetRefreshFrom(i);
}
void RichTxt::GetRichPos(int pos, RichPos& rp, int ti, int maxlevel, const RichStyles& st) const
{
int p = pos;
int pti = ti;
for(int i = 0; i < part.GetCount(); i++) {
int l = GetPartLength(i) + 1;
if(pos < l) {
if(IsTable(i)) {
const RichTable& tab = GetTable(i);
rp.level++;
rp.tabtextparti = i;
rp.tabtextpartcount = part.GetCount();
rp.tabtextlen = GetLength();
rp.tabposintabtext = p - pos;
rp.posintab = pos;
rp.cell = tab.FindCell(pos);
rp.posincell = pos;
rp.tabsize = tab.GetSize();
rp.tablen = tab.GetLength();
const RichTxt& ct = tab[rp.cell].text;
rp.celllen = ct.GetLength();
rp.parenttab = pti;
rp.table = ti + 1;
if(rp.level < maxlevel)
ct.GetRichPos(pos, rp, ti + 1 + tab.GetTableCount(rp.cell), maxlevel, st);
return;
}
else {
rp.posinpara = pos;
rp.parai = i;
rp.partcount = part.GetCount();
rp.paralen = l - 1;
Get(i, st).GetRichPos(rp, pos);
return;
}
}
pos -= l;
if(IsTable(i))
ti += 1 + GetTable(i).GetTableCount();
}
rp.parai = part.GetCount();
rp.posinpara = 0;
rp.partcount = part.GetCount();
rp.paralen = 0;
}
RichPara::Format RichTxt::GetFirstFormat(const RichStyles& style) const
{
if(IsTable(0)) {
const RichTable& tab = GetTable(0);
return tab[0][0].text.GetFirstFormat(style);
}
RichPos rp;
Get(0, style).GetRichPos(rp, 0);
return rp.format;
}
RichCellPos RichTxt::GetCellPos(int table, int row, int column) const
{
int pos = 0;
for(int i = 0;; i++) {
if(IsTable(i)) {
table--;
const RichTable& tab = part[i].Get<RichTable>();
if(table <= tab.GetTableCount()) {
if(table == 0) {
RichCellPos p;
p.tabsize = tab.GetSize();
p.tablen = tab.GetLength();
p.cellpos = tab.GetCellPos(row, column);
p.pos = p.tabpos = pos;
p.pos += p.cellpos;
p.textlen = GetLength();
p.level = 1;
return p;
}
for(int i = 0; i < tab.GetRows(); i++)
for(int j = 0; j < tab.GetColumns(); j++)
if(tab(i, j)) {
const RichTxt& txt = tab[i][j].text;
if(table <= txt.GetTableCount()) {
RichCellPos p = txt.GetCellPos(table, row, column);
p.pos += pos + tab.GetCellPos(i, j);
p.level++;
return p;
}
table -= txt.GetTableCount();
}
NEVER();
}
else
table -= tab.GetTableCount();
}
pos += GetPartLength(i) + 1;
}
NEVER();
return RichCellPos();
}
RichCellPos RichTxt::GetCellPos(int table, Point p) const
{
return GetCellPos(table, p.y, p.x);
}
bool RichTxt::Iterate(UpdateIterator& r, int gpos, const RichStyles& s)
{
for(int pi = 0; pi < part.GetCount(); pi++)
if(IsTable(pi)) {
RichTable& tab = part[pi].Get<RichTable>();
for(int i = 0; i < tab.GetRows(); i++)
for(int j = 0; j < tab.GetColumns(); j++)
if(tab(i, j)) {
if(tab[i][j].text.Iterate(r, gpos, s))
return true;
gpos += tab[i][j].text.GetLength() + 1;
}
}
else {
RichPara p = Get(pi, s);
int q = r(gpos, p);
if(q & UpdateIterator::UPDATE)
Set(pi, p, s);
if(q & UpdateIterator::STOP)
return true;
gpos += GetPartLength(pi) + 1;
}
return false;
}
struct sIter__ : RichTxt::UpdateIterator {
RichTxt::Iterator *iter;
virtual int operator()(int pos, RichPara& para) {
return iter->operator()(pos, para) ? STOP : CONTINUE;
}
};
bool RichTxt::Iterate(Iterator& r, int gpos, const RichStyles& s) const
{
sIter__ it;
it.iter = &r;
return const_cast<RichTxt *>(this)->Iterate(it, gpos, s);
}
void RichTxt::Init()
{
r_type = ALL;
r_parti = 0;
tabcount = length = 0;
}
void RichTxt::Clear()
{
part.Clear();
Init();
}
RichTxt::RichTxt()
{
Init();
}
RichTxt::RichTxt(const RichTxt& src, int)
{
Init();
part <<= src.part;
length = src.length;
tabcount = src.tabcount;
py.Clear();
}
#ifdef _DEBUG
#define DMP(x) s << #x << "=" << x << ", "
String RichPos::ToString() const
{
String s;
DMP(tabtextparti);
DMP(tabtextpartcount);
DMP(tabposintabtext);
DMP(tabtextlen);
DMP(table);
DMP(tabsize);
DMP(cell);
DMP(tablen);
DMP(posintab);
DMP(celllen);
DMP(posincell);
DMP(parai);
DMP(partcount);
DMP(posinpara);
DMP(paralen);
DMP(level);
DMP(parenttab);
s << "char: " << (char)chr;
return s;
}
String RichCellPos::ToString() const
{
String s;
s << "pos: " << pos << ", textlen: " << textlen << ", size: " << tabsize << ", tabpos: " << tabpos
<< ", tablen: " << tablen << ", cellpos: " << cellpos << ", celllen: " << celllen << ", level: " << level;
return s;
}
#endif
END_UPP_NAMESPACE

358
uppdev/RichTextP/TxtOp.cpp Normal file
View file

@ -0,0 +1,358 @@
#include "RichText.h"
NAMESPACE_UPP
void RichTxt::GetAllLanguages(Index<int>& all) const
{
for(int i = 0; i < part.GetCount(); i++) {
if(IsTable(i)) {
const RichTable& tab = part[i].Get<RichTable>();
for(int i = 0; i < tab.GetRows(); i++)
for(int j = 0; j < tab.GetColumns(); j++)
if(tab(i, j))
tab[i][j].text.GetAllLanguages(all);
}
else {
RichPara p = Get(i, RichStyle::GetDefault());
all.FindAdd(p.format.language);
for(int i = 0; i < p.GetCount(); i++)
all.FindAdd(p[i].format.language);
}
}
}
Vector<int> RichTxt::GetAllLanguages() const
{
Index<int> all;
GetAllLanguages(all);
return all.PickKeys();
}
bool RichTxt::Update(ParaOp& op)
{
bool val = false;
for(int i = 0; i < part.GetCount(); i++)
if(IsTable(i)) {
RichTable& tab = part[i].Get<RichTable>();
for(int i = 0; i < tab.GetRows(); i++)
for(int j = 0; j < tab.GetColumns(); j++)
if(tab(i, j))
if(tab[i][j].text.Update(op)) {
tab.InvalidateRefresh(i, j);
val = true;
}
}
else
if(op(part[i].Get<Para>()))
val = true;
RefreshAll();
return val;
}
RichTxt& RichTxt::GetText0(int& pos, bool update)
{
if(update)
Invalidate();
int p = pos;
int pi = FindPart(p);
if(IsTable(pi)) {
RichTable& tab = part[pi].Get<RichTable>();
Point cl = tab.FindCell(p);
if(update) {
tab.InvalidateRefresh(cl);
SetRefresh(pi);
}
pos = p;
return tab[cl].text.GetText0(pos, update);
}
return *this;
}
RichTxt& RichTxt::GetUpdateText(int& pos)
{
return GetText0(pos, true);
}
const RichTxt& RichTxt::GetConstText(int& pos) const
{
return const_cast<RichTxt *>(this)->GetText0(pos, false);
}
RichTable& RichTxt::GetTable0(int table, bool update)
{
if(update)
Invalidate();
for(int i = 0;; i++)
if(IsTable(i)) {
table--;
RichTable& tab = part[i].Get<RichTable>();
if(table <= tab.GetTableCount()) {
if(update)
SetRefresh(i);
if(table == 0)
return tab;
for(int i = 0; i < tab.GetRows(); i++)
for(int j = 0; j < tab.GetColumns(); j++)
if(tab(i, j)) {
RichTxt& txt = tab[i][j].text;
if(table <= txt.GetTableCount()) {
if(update)
tab.InvalidateRefresh(i, j);
return txt.GetTable0(table, update);
}
table -= txt.GetTableCount();
}
NEVER();
}
else
table -= tab.GetTableCount();
}
}
RichTable& RichTxt::GetUpdateTable(int table)
{
return GetTable0(table, true);
}
const RichTable& RichTxt::GetConstTable(int table) const {
return const_cast<RichTxt *>(this)->GetTable0(table, false);
}
void RichTxt::CombineFormat(FormatInfo& fi, int pi, int pi2, bool& first, const RichStyles& style) const
{
while(pi < pi2) {
if(IsTable(pi)) {
const RichTable& tab = part[pi].Get<RichTable>();
for(int i = 0; i < tab.GetRows(); i++)
for(int j = 0; j < tab.GetColumns(); j++)
if(tab(i, j)) {
const RichTxt& txt = tab[i][j].text;
txt.CombineFormat(fi, 0, txt.GetPartCount(), first, style);
}
}
else {
RichPara pa = Get(pi, style);
if(first) {
fi.Set(pa.format);
if(pa.GetCount())
fi.Set(pa[0].format);
first = false;
}
else
fi.Combine(pa.format);
for(int i = first; i < pa.GetCount(); i++)
fi.Combine(pa[i].format);
}
pi++;
}
}
void RichTxt::ApplyStyle(const RichText::FormatInfo& fi, RichPara& pa, const RichStyles& style)
{
if(fi.paravalid & STYLE) {
int q = style.Find(fi.styleid);
if(q >= 0) {
pa.ApplyStyle(style[q].format);
pa.format.styleid = fi.styleid;
}
}
}
void RichTxt::Apply(const RichText::FormatInfo& fi, RichPara& pa, const RichStyles& style)
{
ApplyStyle(fi, pa, style);
for(int i = 0; i < pa.GetCount(); i++)
fi.ApplyTo(pa[i].format);
fi.ApplyTo(pa.format);
}
void RichTxt::ApplyFormat(const FormatInfo& fi, int pi, int pi2, const RichStyles& style)
{
while(pi < pi2) {
if(IsTable(pi)) {
RichTable& tab = part[pi].Get<RichTable>();
for(int i = 0; i < tab.GetRows(); i++)
for(int j = 0; j < tab.GetColumns(); j++)
if(tab(i, j)) {
RichTxt& txt = tab[i][j].text;
tab.InvalidateRefresh(i, j);
txt.ApplyFormat(fi, 0, txt.GetPartCount(), style);
}
}
else {
RichPara pa;
if(fi.paravalid & RichText::STYLE)
pa = RichTxt::Get(pi, fi.styleid, style);
else
pa = Get(pi, style);
Apply(fi, pa, style);
Put(pi, pa, style);
}
pi++;
}
}
void RichTxt::SaveFormat(Formating& r, int p1, int p2, const RichStyles& style) const
{
Array<RichObject> dummy;
for(int i = p1; i <= p2; i++)
if(IsTable(i)) {
const RichTable& tab = part[i].Get<RichTable>();
for(int i = 0; i < tab.GetRows(); i++)
for(int j = 0; j < tab.GetColumns(); j++)
if(tab(i, j)) {
const RichTxt& txt = tab[i][j].text;
txt.SaveFormat(r, 0, txt.GetPartCount() - 1, style);
}
}
else {
RichPara pa = Get(i, style);
for(int i = 0; i < pa.GetCount(); i++) {
RichPara::Part& p = pa[i];
int q = p.GetLength();
p.field = Id();
p.object = RichObject();
WString h;
while(q) {
int c = min(q, 50000);
h.Cat(c + 32);
q -= c;
}
p.text = h;
}
r.styleid.Add(pa.format.styleid);
r.format.Add(pa.Pack(GetStyle(style, pa.format.styleid).format, dummy));
}
}
void RichTxt::RestoreFormat(int pi, const Formating& info, int& ii, const RichStyles& style)
{
Array<RichObject> dummy;
while(ii < info.format.GetCount() && pi < GetPartCount()) {
if(IsTable(pi)) {
RichTable& tab = part[pi].Get<RichTable>();
for(int i = 0; i < tab.GetRows(); i++)
for(int j = 0; j < tab.GetColumns(); j++) {
if(tab(i, j)) {
if(ii >= info.format.GetCount())
return;
tab.InvalidateRefresh(i, j);
tab[i][j].text.RestoreFormat(0, info, ii, style);
}
}
pi++;
}
else {
RichPara pa = Get(pi, style);
RichPara pf;
pf.Unpack(info.format[ii], dummy, GetStyle(style, info.styleid[ii]).format);
RichPara t;
t.format = pf.format;
int si = 0;
int sp = 0;
for(int j = 0; j < pf.GetCount(); j++) {
const RichPara::Part& q = pf[j];
for(int k = 0; k < q.text.GetLength(); k++) {
int len = q.text[k] - 32;
t.part.Add().format = q.format;
while(len) {
const RichPara::Part& p = pa[si];
if(p.IsText()) {
int l = min(len, p.GetLength() - sp);
t.part.Top().text.Cat(p.text.Mid(sp, l));
sp += l;
len -= l;
ASSERT(sp <= p.GetLength());
if(sp >= p.GetLength()) {
sp = 0;
si++;
}
}
else {
ASSERT(sp == 0);
(t.part.Add() = pa[si++]).format = q.format;
len--;
sp = 0;
}
}
}
}
ASSERT(si == pa.GetCount() && sp == 0);
Put(pi, t, style);
ii++;
pi++;
}
}
}
WString RichTxt::GetPlainText() const {
WString clip;
for(int pi = 0; pi < GetPartCount(); pi++) {
if(pi) {
clip.Cat('\r');
clip.Cat('\n');
}
if(IsTable(pi)) {
const RichTable& tab = part[pi].Get<RichTable>();
for(int i = 0; i < tab.GetRows(); i++)
for(int j = 0; j < tab.GetColumns(); j++)
if(tab(i, j)) {
if(i || j) {
clip.Cat('\r');
clip.Cat('\n');
}
clip << tab[i][j].text.GetPlainText();
}
}
else
clip.Cat(Get(pi, RichStyle::GetDefault()).GetText());
}
return clip;
}
RichTxt& RichTxt::GetTableUpdateText(int table, const RichStyles& style, int& pi)
{
Invalidate();
for(int i = 0;; i++)
if(IsTable(i)) {
table--;
RichTable& tab = part[i].Get<RichTable>();
if(table <= tab.GetTableCount()) {
SetRefresh(i);
if(table == 0) {
pi = i;
return *this;
}
for(int i = 0; i < tab.GetRows(); i++)
for(int j = 0; j < tab.GetColumns(); j++)
if(tab(i, j)) {
RichTxt& txt = tab[i][j].text;
if(table <= txt.GetTableCount()) {
tab.InvalidateRefresh(i, j);
return txt.GetTableUpdateText(table, style, pi);
}
table -= txt.GetTableCount();
}
NEVER();
}
else
table -= tab.GetTableCount();
}
NEVER();
}
void RichTxt::Normalize()
{
RichPara pa;
if(GetPartCount() && IsTable(0)) {
part.Insert(0);
Put(0, pa, RichStyle::GetDefault());
Invalidate();
}
if(GetPartCount() == 0 || IsTable(GetPartCount() - 1)) {
Put(GetPartCount(), pa, RichStyle::GetDefault());
Invalidate();
}
}
END_UPP_NAMESPACE

View file

@ -0,0 +1,377 @@
#include "RichText.h"
NAMESPACE_UPP
int RichTxt::GetWidth(const RichStyles& st) const
{
int cx = 0;
for(int i = 0; i < part.GetCount(); i++) {
if(IsPara(i)) {
RichPara p = Get(i, st);
RichPara::Lines pl = p.FormatLines(INT_MAX);
int ccx = 0;
Sum(ccx, ~pl.width, ~pl.width + pl.clen);
cx = max(cx, ccx);
}
else
return 10000;
}
return cx;
}
void RichTxt::Sync0(const Para& pp, int parti, const RichContext& rc) const
{
int cx = rc.page.Width();
pp.cx = cx;
RichPara p = Get(parti, rc.styles);
RichPara::Lines pl = p.FormatLines(cx);
pp.ruler = p.format.ruler;
pp.before = p.format.before;
pp.linecy.Clear();
pp.linecy.SetCount(pl.GetCount());
for(int i = 0; i < pl.GetCount(); i++)
pp.linecy[i] = pl[i].Sum();
pp.cy = Sum0(pp.linecy);
pp.after = p.format.after;
pp.newpage = p.format.newpage;
pp.keep = p.format.keep;
pp.keepnext = p.format.keepnext;
pp.orphan = p.format.orphan;
}
inline
bool RichTxt::BreaksPage(PageY py, const Para& pp, int i, const Rect& page) const
{
int linecy = pp.linecy[i];
if(linecy >= page.Height()) return false;
if(linecy + py.y > page.bottom)
return true;
if(pp.orphan || pp.linecy.GetCount() < 2) return false;
if((i == 0 || i == pp.linecy.GetCount() - 2) &&
py.y + linecy + pp.linecy[i + 1] > page.bottom)
return true;
return false;
}
PageY RichTxt::GetNextPageY(int parti, const RichContext& rc) const
{
if(part[parti].Is<RichTable>())
return GetTable(parti).GetHeight(rc);
else {
Sync(parti, rc);
const Para& pp = part[parti].Get<Para>();
int cy = pp.before + pp.ruler;
if(pp.keep || pp.keepnext)
cy += pp.cy;
else
cy += pp.linecy[0];
PageY py = rc.py;
if(rc.page.Height() < 30000) {
int nbefore = 0;
int nline = 0;
if(pp.keepnext && parti + 1 < part.GetCount() && part[parti + 1].Is<Para>()) {
Sync(parti + 1, rc);
const Para& p = part[parti + 1].Get<Para>();
nbefore = p.before + p.ruler;
nline = p.linecy[0];
}
if(pp.newpage || py.y + cy + nbefore + nline > rc.page.bottom && cy < rc.page.Height()) {
py.page++;
py.y = rc.page.top;
}
py.y += pp.before;
if(py.y + pp.cy < rc.page.bottom)
py.y += pp.cy;
else
for(int lni = 0; lni < pp.linecy.GetCount(); lni++) {
if(BreaksPage(py, pp, lni, rc.page)) {
py.y = rc.page.top;
py.page++;
}
py.y += pp.linecy[lni];
}
py.y += pp.after;
if(py.y > rc.page.bottom) {
py.y = rc.page.top;
py.page++;
}
}
else
py.y += pp.before + pp.cy + pp.after;
return py;
}
}
PageY RichTxt::GetPartPageY(int parti, RichContext rc) const
{
for(int i = 0; i < parti; i++)
rc.py = GetNextPageY(i, rc);
return rc.py;
}
bool IsPainting(PageDraw& pw, Zoom z, const Rect& page, PageY top, PageY bottom)
{
int t = top.y;
for(int pi = top.page; pi < bottom.page; pi++) {
if(pw.Page(pi).IsPainting(Rect(z * page.left, z * top.y, z * page.right, z * page.bottom)))
return true;
t = page.top;
}
return pw.Page(bottom.page).IsPainting(Rect(z * page.left, z * t, z * page.right, z * bottom.y));
}
void RichTxt::Paint(PageDraw& pw, RichContext rc, const PaintInfo& _pi) const
{
PaintInfo pi = _pi;
int parti = 0;
int pos = 0;
RichPara::Number n;
while(rc.py < pi.bottom && parti < part.GetCount()) {
if(part[parti].Is<RichTable>()) {
pi.tablesel--;
const RichTable& tab = GetTable(parti);
tab.Paint(pw, rc, pi);
rc.py = tab.GetHeight(rc);
pi.tablesel -= tab.GetTableCount();
}
else {
const Para& pp = part[parti].Get<Para>();
if(pp.number) {
n.TestReset(*pp.number);
n.Next(*pp.number);
}
PageY next = GetNextPageY(parti, rc);
if(next >= pi.top) {
int nbefore = 0;
int nline = 0;
if(pp.keepnext && parti + 1 < part.GetCount() && part[parti + 1].Is<Para>()) {
Sync(parti + 1, rc);
const Para& pp = part[parti + 1].Get<Para>();
nbefore = pp.before;
nline = pp.linecy[0];
}
RichPara p = Get(parti, rc.styles);
if(pi.spellingchecker) {
if(!pp.checked) {
pp.spellerrors = (*pi.spellingchecker)(p);
pp.checked = true;
}
}
else {
pp.checked = false;
pp.spellerrors.Clear();
}
if(IsPainting(pw, pi.zoom, rc.page, rc.py, next))
p.Paint(pw, rc.page, rc.py, pi, n, pp.spellerrors, nbefore, nline);
}
rc.py = next;
}
int l = GetPartLength(parti) + 1;
pi.highlightpara -= l;
pi.sell -= l;
pi.selh -= l;
pos += l;
++parti;
}
}
RichCaret RichTxt::GetCaret(int pos, RichContext rc) const
{
int parti = 0;
if(pos > GetLength())
pos = GetLength();
while(parti < part.GetCount()) {
int l = GetPartLength(parti) + 1;
if(pos < l)
if(IsTable(parti))
return GetTable(parti).GetCaret(pos, rc);
else {
const Para& p = part[parti].Get<Para>();
int nbefore = 0;
int nline = 0;
if(p.keepnext && parti + 1 < part.GetCount() && part[parti + 1].Is<Para>()) {
Sync(parti + 1, rc);
const Para& pp = part[parti + 1].Get<Para>();
nbefore = pp.before;
nline = pp.linecy[0];
}
RichCaret tp = Get(parti, rc.styles).GetCaret(pos, rc.page, rc.py, nbefore, nline);
tp.textpage = rc.page;
return tp;
}
pos -= l;
rc.py = GetNextPageY(parti++, rc);
}
return RichCaret();
}
int RichTxt::GetPos(int x, PageY y, RichContext rc) const
{
int parti = 0;
int pos = 0;
if(part.GetCount()) {
PageY nnext = GetNextPageY(parti, rc);
while(parti < part.GetCount()) {
PageY next = nnext;
if(parti + 1 < part.GetCount()) {
RichContext nrc = rc;
nrc.py = next;
nnext = GetNextPageY(parti + 1, nrc);
}
if(y < next || y.page < next.page) {
if(IsTable(parti))
return GetTable(parti).GetPos(x, y, rc) + pos;
else {
int nbefore = 0;
int nline = 0;
if(part[parti].Get<Para>().keepnext && parti + 1 < part.GetCount() && IsPara(parti + 1)) {
Sync(parti + 1, rc);
const Para& pp = part[parti + 1].Get<Para>();
nbefore = pp.before;
nline = pp.linecy[0];
}
return Get(parti, rc.styles).GetPos(x, y, rc.page, rc.py, nbefore, nline) + pos;
}
}
pos += GetPartLength(parti) + 1;
parti++;
rc.py = next;
}
}
return pos - 1;
}
RichHotPos RichTxt::GetHotPos(int x, PageY y, int tolerance, RichContext rc) const
{
int parti = 0;
int pos = 0;
int ti = 0;
if(part.GetCount()) {
PageY nnext = GetNextPageY(parti, rc);
while(parti < part.GetCount()) {
PageY next = nnext;
if(parti + 1 < part.GetCount()) {
RichContext nrc = rc;
nrc.py = next;
nnext = GetNextPageY(parti + 1, nrc);
}
if(y < next || y.page < next.page) {
if(IsTable(parti)) {
RichHotPos pos = GetTable(parti).GetHotPos(x, y, tolerance, rc);
pos.table += ti + 1;
return pos;
}
else
break;
}
if(IsTable(parti))
ti += 1 + GetTable(parti).GetTableCount();
pos += GetPartLength(parti) + 1;
parti++;
rc.py = next;
}
}
return RichHotPos();
}
int RichTxt::GetVertMove(int pos, int gx, RichContext rc, int dir) const
{
ASSERT(dir == -1 || dir == 1);
if(GetPartCount() == 0)
return -1;
int pi;
int p = pos;
if(pos >= 0) {
pi = FindPart(p);
pos -= p;
}
else {
pi = dir > 0 ? 0 : GetPartCount() - 1;
p = -1;
pos = 0;
}
while(pi < GetPartCount()) {
int q = IsTable(pi) ? GetTable(pi).GetVertMove(p, gx, rc, dir)
: Get(pi, rc.styles).GetVertMove(p, gx, rc.page, dir);
if(q >= 0)
return q + pos;
if(dir > 0)
pos += GetPartLength(pi) + 1;
p = -1;
pi += dir;
if(pi < 0)
break;
if(dir < 0)
pos -= GetPartLength(pi) + 1;
}
return -1;
}
void RichTxt::GatherValPos(Vector<RichValPos>& f, RichContext rc, int pos, int type) const
{
int parti = 0;
while(parti < part.GetCount()) {
if(part[parti].Is<RichTable>())
GetTable(parti).GatherValPos(f, rc, pos, type);
else {
int nbefore = 0;
int nline = 0;
const Para& p = part[parti].Get<Para>();
if(p.keepnext && parti + 1 < part.GetCount() && IsPara(parti + 1)) {
Sync(parti + 1, rc);
const Para& pp = part[parti + 1].Get<Para>();
nbefore = pp.before;
nline = pp.linecy[0];
}
if(p.haspos)
if(type == LABELS)
Get(parti, rc.styles).GatherLabels(f, rc.page, rc.py, pos, nbefore, nline);
else
Get(parti, rc.styles).GatherIndexes(f, rc.page, rc.py, pos, nbefore, nline);
}
pos += GetPartLength(parti) + 1;
rc.py = GetNextPageY(parti++, rc);
}
}
PageY RichTxt::GetHeight(RichContext rc) const
{
for(int i = 0; i < GetPartCount(); i++)
rc.py = GetNextPageY(i, rc);
return rc.py;
}
PageY RichTxt::GetTop(RichContext rc) const
{
if(part.GetCount() == 0)
return rc.py;
if(part[0].Is<RichTable>())
return GetTable(0).GetTop(rc);
else {
Sync(0, rc);
const Para& pp = part[0].Get<Para>();
rc.py.y += pp.before;
if(BreaksPage(rc.py, pp, 0, rc.page))
rc.Page();
return rc.py;
}
}
void RichTxt::ApplyZoom(Zoom z, const RichStyles& ostyle, const RichStyles& zstyle)
{
for(int i = 0; i < GetPartCount(); i++)
if(IsTable(i))
part[i].Get<RichTable>().ApplyZoom(z, ostyle, zstyle);
else {
RichPara p = Get(i, ostyle);
p.ApplyZoom(z);
Set(i, p, zstyle);
}
}
END_UPP_NAMESPACE

123
uppdev/RichTextP/Util.cpp Normal file
View file

@ -0,0 +1,123 @@
#include "RichText.h"
NAMESPACE_UPP
Draw& SimplePageDraw::Info()
{
return w;
}
Draw& SimplePageDraw::Page(int)
{
return w;
}
void RichText::ApplyZoom(Zoom z)
{
RichStyles ostyle(style, 1);
for(int i = 0; i < style.GetCount(); i++)
style[i].format *= z;
RichTxt::ApplyZoom(z, ostyle, style);
RefreshAll();
}
Zoom GetRichTextStdScreenZoom()
{
return Zoom(Ctrl::HorzLayoutZoom(96), 600);
}
struct QTFDisplayCls : Display {
virtual void Paint(Draw& w, const Rect& r, const Value& q,
Color ink, Color paper, dword style) const;
virtual Size GetStdSize(const Value& q) const;
virtual Size RatioSize(const Value& q, int cx, int cy) const;
};
Size QTFDisplayCls::GetStdSize(const Value& q) const
{
Size sz;
RichText txt = ParseQTF((String)q);
txt.ApplyZoom(GetRichTextStdScreenZoom());
sz.cx = txt.GetWidth();
sz.cy = txt.GetHeight(Zoom(1, 1), sz.cx);
return sz;
}
Size QTFDisplayCls::RatioSize(const Value& q, int cx, int cy) const
{
if(cy == 0 && cx > 0) {
RichText txt = ParseQTF((String)q);
return Size(cx, txt.GetHeight(Zoom(1, 1), cx));
}
return GetStdSize(q);
}
void QTFDisplayCls::Paint(Draw& draw, const Rect& r, const Value& v, Color ink, Color paper, dword style) const
{
String s;
s << "[@(" << ink.GetR() << "." << ink.GetG() << "." << ink.GetB() << ") " << v;
RichText rtext = ParseQTF(s);
rtext.ApplyZoom(GetRichTextStdScreenZoom());
draw.DrawRect(r, paper);
draw.Clipoff(r);
rtext.Paint(Zoom(1, 1), draw, 0, 0, r.Width());
draw.End();
}
const Display& QTFDisplay()
{
return Single<QTFDisplayCls>();
}
struct QTFDisplayCCls : QTFDisplayCls {
virtual void Paint(Draw& w, const Rect& r, const Value& q,
Color ink, Color paper, dword style) const;
};
void QTFDisplayCCls::Paint(Draw& draw, const Rect& r, const Value& v, Color ink, Color paper, dword style) const
{
String s;
s << "[@(" << ink.GetR() << "." << ink.GetG() << "." << ink.GetB() << ") " << v;
RichText rtext = ParseQTF(s);
rtext.ApplyZoom(GetRichTextStdScreenZoom());
draw.DrawRect(r, paper);
draw.Clipoff(r);
int cy = rtext.GetHeight(Zoom(1, 1), r.Width());
rtext.Paint(Zoom(1, 1), draw, 0, max(0, (r.Height() - cy) / 2), r.Width());
draw.End();
}
const Display& QTFDisplayVCenter()
{
return Single<QTFDisplayCCls>();
}
RichText AsRichText(const wchar *s, const RichPara::Format& f)
{
RichText clip;
RichPara p;
p.format = f;
p.part.Add().format = f;
RichStyle cs;
cs.format = f;
cs.format.sscript = 0;
cs.format.link.Clear();
cs.format.indexentry.Clear();
cs.format.language = LNG_ENGLISH;
cs.format.label.Clear();
clip.SetStyle(f.styleid, cs);
WString& part = p.part.Top().text;
while(*s) {
if(*s == '\n') {
clip.Cat(p);
part.Clear();
}
if(*s >= 32 || *s == '\t')
part.Cat(*s);
s++;
}
clip.Cat(p);
return clip;
}
END_UPP_NAMESPACE

8
uppdev/RichTextP/init Normal file
View file

@ -0,0 +1,8 @@
#ifndef _RichTextP_icpp_init_stub
#define _RichTextP_icpp_init_stub
#include "CtrlCore/init"
#include "plugin\png/init"
#define BLITZ_INDEX__ F70234807CBDCCBF7C7FC03C2E97EA2EC
#include "RichImage.icpp"
#undef BLITZ_INDEX__
#endif

View file

@ -0,0 +1,705 @@
topic "QTF";
[2 $$0,0#00000000000000000000000000000000:Default]
[@(128.0.255)2 $$1,0#65874547464505293575048467215454:QTF Chr]
[*/+117 $$2,0#07143242482611002448121871408047:title]
[*C@3+75 $$3,3#36268203433472503231438721581057:code]
[{_}%EN-US
[s0;= [*8 QTF]&]
[s0; &]
[s0; QTF is the native format of Ultimate`+`+ rich texts (formatted
texts).&]
[s0; &]
[s0; It is byte oriented format. Bytes with values 2`-31 are ignored.
Other are interpreted as characters or formatting commands.&]
[s0; &]
[s0; Letters ([@4 a]`-[@4 zA]`-[@4 Z]), numbers ([@4 0]`-[@4 9]), space (32)
and characters&]
[s0; &]
[s0; [*@4 . , ; ! ? % ( ) / < > #]&]
[s0; &]
[s0; and bytes greater than 127 are guaranteed to be never used as
command characters (not even in future versions of QTF). Other
characters should be prefixed with escape character `` (reverse
apostrophe). Group of characters can be escaped using byte 1.
Example:&]
[s0; &]
[s3; `"`\1a`[x`]`\1`[`* bold`]`"&]
[s0; &]
[s0; Byte 0 represents the end of input sequence.&]
[s0; &]
[s0; Dimension units of QTF are dots `- one dot is defined as 1/600
of inch.&]
[s0; &]
[s0; Colors are described as either number [@(128.0.255) 0]`-[@(128.0.255) 9],
with meaning&]
[s0; &]
[ {{1000:1000:1000:1000:1000:1000:1000:1000:1000:1000<96;>96;f4; [s0;%- [* 0]]
:: [s0;%- [* 1]]
:: [s0;%- [* 2]]
:: [s0;%- [* 3]]
:: [s0;%- [* 4]]
:: [s0;%- [* 5]]
:: [s0;%- [* 6]]
:: [s0;%- [* 7]]
:: [s0;%- [* 8]]
:: [s0;%- [* 9]]
::l/0r/0t/0b/0@0 [s0; ]
::@1 [s0; ]
::@2 [s0; ]
::@3 [s0; ]
::@4 [s0; ]
::@5 [s0; ]
::@6 [s0; ]
::@7 [s0; ]
::@8 [s0; ]
::@9 [s0; ]
::l/25r/25t/15b/15@2 [s0;%- [1 Black]]
:: [s0; [1 LtGray]]
:: [s0; [1 White]]
:: [s0;%- [1 Red]]
:: [s0;%- [1 Green]]
:: [s0;%- [1 Blue]]
:: [s0;%- [1 LtRed]]
:: [s0;%- [1 WhiteGray]]
:: [s0;%- [1 LtCyan]]
:: [s0;%- [1 Yellow]]}}&]
[s0; &]
[s0; or letters&]
[s0; &]
[ {{1109:1109:1109:1109:1109:1109:1109:1109:1128<96;>96;f4; [s0;%- [*C@(128.0.255) b]]
:: [s0;%- [*C@(128.0.255) c]]
:: [s0;%- [*C@(128.0.255) g]]
:: [s0;%- [*C@(128.0.255) k]]
:: [s0;%- [*C@(128.0.255) l]]
:: [s0;%- [*C@(128.0.255) m]]
:: [s0;%- [*C@(128.0.255) o]]
:: [s0;%- [*C@(128.0.255) r]]
:: [s0;%- [*C@(128.0.255) y]]
::l/0r/0t/0b/0@5 [s0; ]
::@(0.128.128) [s0; ]
::@4 [s0; ]
::@0 [s0; ]
::@1 [s0; ]
::@(128.0.255) [s0; ]
::@(128.128.0) [s0; ]
::@3 [s0; ]
::@9 [s0; ]
::l/25r/25t/15b/15@2 [s0;%- [1 Blue]]
:: [s0;%- [1 Cyan]]
:: [s0;%- [1 Green]]
:: [s0;%- [1 Black]]
:: [s0;%- [1 LtGray]]
:: [s0;%- [1 Magenta]]
:: [s0;%- [1 Brown]]
:: [s0;%- [1 Red]]
:: [s0;%- [1 Yellow]]}}&]
[s0; &]
[ {{1109:1109:1109:1109:1109:1109:1109:1109:1128<96;>96;f4; [s0;%- [*@(128.0.255) B]]
:: [s0;%- [*@(128.0.255) C]]
:: [s0;%- [*@(128.0.255) G]]
:: [s0;%- [*@(128.0.255) K]]
:: [s0;%- [*@(128.0.255) L]]
:: [s0;%- [*@(128.0.255) M]]
:: [s0;%- [*@(128.0.255) W]]
:: [s0;%- [*@(128.0.255) R]]
:: [s0;%- [*@(128.0.255) Y]]
::l/0r/0t/0b/0@(0.0.255) [s0; ]
::@8 [s0; ]
::@(0.255.0) [s0; ]
::@(128) [s0; ]
::@(238) [s0; ]
::@(255.0.255) [s0; ]
::@2 [s0; ]
::@6 [s0; ]
::@(255.255.180) [s0; ]
::l/25r/25t/15b/15@2 [s0;%- [1 LtBlue]]
:: [s0;%- [1 LtCyan]]
:: [s0;%- [1 LtGreen]]
:: [s0;%- [1 Gray]]
:: [s0;%- [1 WhiteGray]]
:: [s0;%- [1 LtMagenta]]
:: [s0;%- [1 White]]
:: [s0;%- [1 LtRed]]
:: [s0;%- [1 LtYellow]]}}&]
[s0; &]
[s0; or as the RGB value in form&]
[s0; &]
[s0; [@(128.0.255) (][/@(0.0.255) number][@(128.0.255) .][/@(0.0.255) number][@(128.0.255) .][/@(0.0.255) n
umber][@(128.0.255) )]&]
[s0;@(128.0.255) &]
[s0; where [/@(0.0.255) number] is 0`-255.&]
[s0; &]
[s0; Form with single [/@(0.0.255) number]&]
[s0; &]
[s0; [@(128.0.255) (][/@(0.0.255) number][@(128.0.255) )]&]
[s0;@(128.0.255) &]
[s0; specifies grays.&]
[s0; &]
[s0; Letter&]
[s0; &]
[s0; [@(128.0.255) N]&]
[s0;@(128.0.255) &]
[s0; used in place of color designates transparent color.&]
[s0; &]
[s0; &]
[s2; Basic QTF codes&]
[s0; &]
[s0; &]
[ {{2003:7997<96;>96; [s0; [C@(128.0.255) `_]]
:: [s0; Hard`-space `- space that cannot be divided at the end of line.]
:: [s0; [C@(128.0.255) `&]]
:: [s0; New paragraph.]
:: [s0; [C@(128.0.255) `-`|]]
:: [s0; Tabulator]
:: [s0;%- [%%C@(128.0.255) `@`$][%%*C@(0.0.255) hex][C@(128.0.255) ;]]
:: [s0; Unicode character as hexadecimal number.]}}&]
[s0; &]
[s0; &]
[s2; Character and paragraph formatting&]
[s0; &]
[s0; Character and paragraph formatting starts with&]
[s0;@(128.0.255) &]
[s0; [@(128.0.255) `[]&]
[s0;@(128.0.255) &]
[s0; character followed by [*/ character/paragraph formating][/ sequence]
ended with single space character and applies to the text until
matching&]
[s0; &]
[s0; [@(128.0.255) `]]&]
[s0;@(128.0.255) &]
[s0; is encountered.&]
[s0; &]
[ {{1879:8121^@(229.229.248)-1 [s0; [*/ Character/paragraph formating sequence]]
::=@2 [s0;%- ]
::^ [s0;%- [C@(128.0.255) /]]
::= [s0; Italic.]
::^ [s0;%- [C@(128.0.255) `*]]
::= [s0; Bold.]
::^ [s0;%- [C@(128.0.255) `_]]
::= [s0; Underline.]
::^ [s0;%- [C@(128.0.255) `-]]
::= [s0; Strikeout.]
::^ [s0;%- [C@(128.0.255) c]]
::= [s0; Capitals.]
::^ [s0;%- [C@(128.0.255) ``]]
::= [s0; Superscript.]
::^ [s0;%- [C@(128.0.255) ,]]
::= [s0; Subscript.]
::^ [s0;%- [C@(128.0.255) d]]
::= [s0; Dashed underline.]
::^ [s0;%- [C@(128.0.255) T]]
::= [s0; Non anti aliased font.]
::^ [s0;%- [C@(128.0.255) `^][/C@(0.0.255) text][C@(128.0.255) `^]]
::= [s0; Hyperlink.]
::^ [s0;%- [C@(128.0.255) I][/C@(0.0.255) text][C@(128.0.255) ;]]
::= [s0; Index entry.]
::^ [s0;%- [C@(128.0.255) `+][/C@(0.0.255) number]]
::= [s0; Font height in dots.]
::^ [s0;%- [C@(128.0.255) 0]]
::= [s0; Font height 50 dots (6 points).]
::^ [s0;%- [C@(128.0.255) 1]]
::= [s0; Font height 67 dots (8 points).]
::^ [s0;%- [C@(128.0.255) 2]]
::= [s0; Font height 84 dots (10 points).]
::^ [s0;%- [C@(128.0.255) 3]]
::= [s0; Font height 100 dots (12 points).]
::^ [s0;%- [C@(128.0.255) 4]]
::= [s0; Font height 134 dots (16 points).]
::^ [s0;%- [C@(128.0.255) 5]]
::= [s0; Font height 167 dots (20 points).]
::^ [s0;%- [C@(128.0.255) 6]]
::= [s0; Font height 200 dots (24 points).]
::^ [s0;%- [C@(128.0.255) 7]]
::= [s0; Font height 234 dots (28 points).]
::^ [s0;%- [C@(128.0.255) 8]]
::= [s0; Font height 300 dots (36 points).]
::^ [s0;%- [C@(128.0.255) 9]]
::= [s0; Font height 400 dots (48 points).]
::^ [s0;%- [C@(128.0.255) `@][/C@(0.0.255) color]]
::= [s0; Text color.]
::^ [s0;%- [C@(128.0.255) `$][/C@(0.0.255) color]]
::= [s0; Text background color.]
::^ [s0;%- [C@(128.0.255) A]]
::= [s0; Arial font.]
::^ [s0;%- [C@(128.0.255) R]]
::= [s0; Times New Roman font.]
::^ [s0;%- [C@(128.0.255) C]]
::= [s0; Courier font.]
::^ [s0;%- [C@(128.0.255) G]]
::= [s0; Standard GUI font.]
::^ [s0;%- [C@(128.0.255) S]]
::= [s0; Symbol font.]
::^ [s0;%- [C@(128.0.255) .][/C@(0.0.255) number]]
::= [s0; Font with specified font [/@(0.0.255) number].]
::^ [s0;%- [C@(128.0.255) !][/C@(0.0.255) text][C@(128.0.255) !]]
::= [s0; Font with face name equal to [/@(0.0.255) text]. If such font
does not exist on system, Arial is used.]
::^ [s1;%- [C `{][/C@(0.0.255) charset][C `}]&]
[s0; ]
::= [s0; Character set. It can be defined as either single character&]
[s0; &]
[ {{1840:8160<330;>1757;f4;h1; [s0; [C@(128.0.255) `_]]
:: [s0; utf`-8]
:: [s0; [C@(128.0.255) 0]]
:: [s0; windows`-1250]
:: [s0; [C@(128.0.255) 1]]
:: [s0; windows`-1251]
:: [s0; [C@(128.0.255) 2]]
:: [s0; windows`-1252]
:: [s0; [C@(128.0.255) 3]]
:: [s0; windows`-1253]
:: [s0; [C@(128.0.255) 4]]
:: [s0; windows`-1254]
:: [s0; [C@(128.0.255) 5]]
:: [s0; windows`-1255]
:: [s0; [C@(128.0.255) 6]]
:: [s0; windows`-1256]
:: [s0; [C@(128.0.255) 7]]
:: [s0; windows`-1257]
:: [s0; [C@(128.0.255) A]]
:: [s0; iso`-8859`-1]
:: [s0; [C@(128.0.255) B]]
:: [s0; iso`-8859`-2]
:: [s0; [C@(128.0.255) C]]
:: [s0; iso`-8859`-3]
:: [s0; [C@(128.0.255) D]]
:: [s0; iso`-8859`-4]
:: [s0; [C@(128.0.255) E]]
:: [s0; iso`-8859`-5]
:: [s0; [C@(128.0.255) F]]
:: [s0; iso`-8859`-6]
:: [s0; [C@(128.0.255) G]]
:: [s0; iso`-8859`-7]
:: [s0; [C@(128.0.255) H]]
:: [s0; iso`-8859`-8]
:: [s0; [C@(128.0.255) I]]
:: [s0; iso`-8859`-9]
:: [s0; [C@(128.0.255) J]]
:: [s0; iso`-8859`-10]}}&]
[s0; &]
[s0; or as the string designating character set (example: [*C@3 `"`[`{`_`}_...`]`"][* ,
][*C@3 `"`[`{windows`-1250`}_...`]`"]).]
::^ [s0;%- [C@(128.0.255) %][/C@(0.0.255) lang]]
::= [s0; Language. It is defined in form [@(0.0.255) XX]`-[@(0.0.255) YY],
according to ISO 639 and ISO 3166 standards. (example: [*C@3 `"`[%EN`-US_...`]`"]).
[*C@3 `"`[%00`-00_`"] represents `"none`" language. As special
optimization, [*@(128.0.255) %`-] is equivalent to [@(128.0.255) %][@(0.0.255) 00`-00]
(no language) and&]
[s0; [@(128.0.255) %%] is equivalent to [@(128.0.255) %][@(0.0.255) EN`-US].]
::^ [s0;%- [C@(128.0.255) :][/C@(0.0.255) text][C@(128.0.255) :]]
::= [s0; Paragraph label.]
::^ [s0;%- [C@(128.0.255) <]]
::= [s0; Align paragraph left.]
::^ [s0;%- [C@(128.0.255) `=]]
::= [s0; Center paragraph.]
::^ [s0;%- [C@(128.0.255) >]]
::= [s0; Align paragraph right.]
::^ [s0;%- [C@(128.0.255) #]]
::= [s0; Justify paragraph.]
::^ [s0;%- [C@(128.0.255) l][/C@(0.0.255) number]]
::= [s0; Left margin in dots.]
::^ [s0;%- [C@(128.0.255) r][/C@(0.0.255) number]]
::= [s0; Right margin in dots.]
::^ [s0;%- [C@(128.0.255) i][/C@(0.0.255) number]]
::= [s0; Indent in dots.]
::^ [s0;%- [C@(128.0.255) pn]]
::= [s0; Line spacing 1.0.]
::^ [s0;%- [C@(128.0.255) ph]]
::= [s0; Line spacing 1.5.]
::^ [s0;%- [C@(128.0.255) pd]]
::= [s0; Line spacing 2.0.]
::^ [s0;%- [C@(128.0.255) H][/C@(0.0.255) number]]
::= [s0; Horizontal ruler height (if zero, there is no ruler).]
::^ [s0;%- [C@(128.0.255) h][/C@(0.0.255) color]]
::= [s0; Color of horizontal ruler (default is black).]
::^ [s0;%- [C@(128.0.255) b][/C@(0.0.255) number]]
::= [s0; Space before paragraph in dots.]
::^ [s0;%- [C@(128.0.255) a][/C@(0.0.255) number]]
::= [s0; Space after paragraph in dots.]
::^ [s0;%- [C@(128.0.255) P]]
::= [s0; Page break before paragraph.]
::^ [s0;%- [C@(128.0.255) k]]
::= [s0; Keep paragraph on single page.]
::^ [s0;%- [C@(128.0.255) K]]
::= [s0; Keep paragraph on same page as next one.]
::^ [s0;%- [C@(128.0.255) Q]]
::= [s0; Orphan control.]
::^ [s0;%- [C@(128.0.255) n][/C@(0.0.255) text][C@(128.0.255) ;]]
::= [s0; Text to insert before paragraph number.]
::^ [s0;%- [C@(128.0.255) m][/C@(0.0.255) text][C@(128.0.255) ;]]
::= [s0; Text to insert after paragraph number.]
::^ [s0;%- [C@(128.0.255) N]]
::= [s0; Numbering. It is followed by up to 8 characters defining numbering
style of each level&]
[s0; &]
[ {{864:9136<342;>861;f4; [s0; [C@(128.0.255) `-]]
:: [s0; Level is not used.]
:: [s0; [C@(128.0.255) 1]]
:: [s0; Numbers, starting with 1.]
:: [s0; [C@(128.0.255) 0]]
:: [s0; Numbers, starting with 0.]
:: [s0; [C@(128.0.255) a]]
:: [s0; Lowercase letters, starting with a.]
:: [s0; [C@(128.0.255) A]]
:: [s0; Uppercase letters, starting with A.]
:: [s0; [C@(128.0.255) i]]
:: [s0; Lowercase roman numbers, starting with i.]
:: [s0; [C@(128.0.255) I]]
:: [s0; Uppercase roman numbers, starting with I]}}&]
[s0; ]
::^ [s0;%- [C@(128.0.255) o]]
::= [s0; Bullet style.]
::^ [s0;%- [C@(128.0.255) O`_]]
::= [s0; No bullet.]
::^ [s0;%- [C@(128.0.255) O0]]
::= [s0; Bullet style.]
::^ [s0;%- [C@(128.0.255) O1]]
::= [s0; Bullet style.]
::^ [s0;%- [C@(128.0.255) O2]]
::= [s0; Bullet style.]
::^ [s0;%- [C@(128.0.255) O3]]
::= [s0; Bullet style.]
::^ [s0;%- [C@(128.0.255) O9]]
::= [s0; Text bullet style.]
::^ [s0;%- [C@(128.0.255) t][/C@(0.0.255) number]]
::= [s0; Default tab size.]
::^ [s0;%- [C@(128.0.255) `~]]
::= [s0; Tabulator setting. Can be followed by character designating
type of tabulation&]
[s0; &]
[ {{864:9136<342;>861;f4; [s0; [C@(128.0.255) >]]
:: [s0; Normal tabulation.]
:: [s0; [C@(128.0.255) <]]
:: [s0; Left tabulation.]
:: [s0; [C@(128.0.255) `=]]
:: [s0; Centered tabulation.]}}&]
[s0; &]
[s0; (default is normal) and by filler character &]
[s0; &]
[ {{3312:3436:3252<342;>861;f4; [s0; [C@(128.0.255) .]]
:: [s0; [C@(128.0.255) `-]]
:: [s0; [C@(128.0.255) `_]]}}&]
[s0; &]
[s0; and must be followed by number specifying tabulator position
in dots.&]
[s0; &]
[s0; When followed by [C@(128.0.255) `~] ([*C@3 `"`~`~`"]), clears all
current tab settings (including those inherited from paragraph
style).]
::^ [s0;%- [C@(128.0.255) ;]]
::= [s0; NOP separator. In some cases it is needed to separate command
code. Example: [*C@3 `"`[l200;4 `"]]
::^ [s1; [%-C s][/C@(0.0.255) number]&]
[s0; [%-C@(128.0.255) s][/C@(0.0.255) `"text`"]]
:: [s0; Paragraph style, either defined by style number, or style name.]}}&]
[s0;3 &]
[s0;3 &]
[s2; Styles&]
[s0; &]
[s0; Paragraph styles are defined using normal character/paragraph
formatting sequence with&]
[s0; &]
[s0; [@(128.0.255) `$`$][@(0.0.255) number][@(128.0.255) ,][@(0.0.255) nnumber][@(128.0.255) #][@(0.0.255) u
uid][@(128.0.255) :][@(0.0.255) name]&]
[s0; &]
[s0; instead of text, where&]
[s0; &]
[ {{1879:8121^ [s0;%- [@(0.0.255) number]]
:: [s0; Number of style `- can be used with [@(128.0.255) s] paragraph
format command code.]
:: [s0;%- [@(0.0.255) nnumber]]
:: [s0; Number of style of next paragraph `- used by RichText editor
when inserting paragraphs.]
:: [s0;%- [@(0.0.255) uuid]]
:: [s0; 32 digit unique hexadecimal identifier of style.]
:: [s0;%- [@(0.0.255) name]]
:: [s0; Name of style, displayed by editors. Can also be used with [@(128.0.255) s]
paragraph format command code.]}}&]
[s0; &]
[s0; Style with [@(0.0.255) number] `= 0 and [@(0.0.255) uuid `= ]00000000000000000000000
000000000 is [*/ default] style.&]
[s0; &]
[s0; Example:&]
[s0; &]
[s0; [C@3 `"`[`*/`+117 `$`$2,0#07143242482611002448121871408047:title`]`"]&]
[s0;@(0.0.255) &]
[s0;@(0.0.255) &]
[s2; Objects&]
[s0;@(0.0.255) &]
[s0; Object plays the role of the single character and is displayed
according to its type. It is started with a header in the form&]
[s0; &]
[s0; [@(128.0.255) `@`@][@(0.0.255) format][@(128.0.255) :][@(0.0.255) cx][@(128.0.255) `&][@(0.0.255) c
y]&]
[s0;@(0.0.255) &]
[s0;%- where&]
[s0; &]
[ {{1879:8121^ [s0; [@(0.0.255) format]]
:: [s0; Format of objects. This format must be recognized by the application.
By default, RichText recognizes the PNG format.]
:: [s0; [@(0.0.255) cx]]
:: [s0; Width of object in dots.]
:: [s0; [@(0.0.255) cy]]
:: [s0; Height of object in dots.]}}&]
[s0;@(0.0.255) &]
[s0; Header is followed by binary data of object, encoded in 7 bit
format. Bit 7 of data bytes is always 1, so that actual data
bytes are in range 128`-255. First byte in range 32`-127 ends
data sequence.&]
[s0; &]
[s0; Data are encoded in 7 byte groups, which corresponds to 8 bytes
of encoded format. First byte of this 8 bytes block always contains
eight bits of following bytes, LSB (that is bit 0) being the
eight bit for first byte in block.&]
[s0;@(0.0.255) &]
[s0;@(0.0.255) &]
[s2; Tables&]
[s0; &]
[s0; Table definition starts with&]
[s0;3 &]
[s0; [@(128.0.255) `{`{]&]
[s0;@(128.0.255) &]
[s0; pair, followed by set of numbers separated with&]
[s0; &]
[s0; [@(128.0.255) :]&]
[s0;@(128.0.255) &]
[s0; Numbers represent ratios of column widths; count of numbers
is equivalent to count of columns. Next there is [/ table/cell
formatting sequence] ended with single space character. Cells
are separated with&]
[s0; &]
[s0; [@(128.0.255) `::]&]
[s0;@(128.0.255) &]
[s0; characters and another table/cell formating sequence (to setup
format for each individual cell). Formating of cells is inherited
from previous cells. Table ends with&]
[s0; &]
[s0; [@(128.0.255) `}`}]&]
[s0;@(128.0.255) &]
[s0; pair.&]
[s0; &]
[ {{1993:8007^@(229.229.248)-1 [s0; [*/ Table/cell formating sequence]]
::=@2 [s0;%- ]
::^ [s0;%- [C@(128.0.255) <][/C@(0.0.255) number]]
:: [s0; Left margin of table in dots.]
:: [s0;%- [C@(128.0.255) >][/C@(0.0.255) number]]
:: [s0; Right margin of table in dots.]
:: [s0;%- [C@(128.0.255) B][/C@(0.0.255) number]]
:: [s0; Space before table in dots.]
:: [s0;%- [C@(128.0.255) A][/C@(0.0.255) number]]
:: [s0; Space after table in dots.]
:: [s0;%- [C@(128.0.255) f][/C@(0.0.255) number]]
:: [s0; Frame thickness in dots. Frame is outer border of table. Default
value is 10.]
:: [s0;%- [C@(128.0.255) F][/C@(0.0.255) color]]
:: [s0; Color of the frame.]
:: [s0; [%-C@(128.0.255) g][/C@(0.0.255) number]]
:: [s0; Grid thickness in dots. Grid are lines dividing cells inside
table. Default value is 4.]
:: [s0;%- [C@(128.0.255) G][/C@(0.0.255) color]]
:: [s0; Color of the grid.]
:: [s0;%- [C@(128.0.255) k]]
:: [s0; Keep the cell on single page.]
:: [s0;%- [C@(128.0.255) K]]
:: [s0; Keep the table on single page.]
:: [s0;%- [C@(128.0.255) `~]]
:: [s0; Sets grid and frame thickness to zero. Useful when using tables
to organize text.]
:: [s0; [%-C@(128.0.255) h][/C@(0.0.255) number]]
:: [s0; Number of header rows. Header rows are repeated at the beginning
of every page.]
:: [s0;%- [C@(128.0.255) `^]]
:: [s0; Cell aligns to top. Default.]
:: [s0;%- [C@(128.0.255) `=]]
:: [s0; Cell aligns to center (vertical).]
:: [s0;%- [C@(128.0.255) v]]
:: [s0; Cell aligns to bottom.]
:: [s1; [%-C l][/C@(0.0.255) number/number]&]
[s0; [%-C@(128.0.255) l][/C@(0.0.255) number]&]
[s0; [%-C@(128.0.255) l][/C@(0.0.255) /number]]
:: [s0; Sets left cell border (first [/@(0.0.255) number]) and margin
in dots. If any of numbers is missing, sets only the one present.
Default is border: 0, margin: 25.]
:: [s1; [C r][/C@(0.0.255) number/number]&]
[s0; [C@(128.0.255) r][/C@(0.0.255) number]&]
[s0; [C@(128.0.255) r][/C@(0.0.255) /number]]
:: [s0; Sets right cell border (first [/@(0.0.255) number]) and margin
in dots. If any of numbers is missing, sets only the one present.
Default is border: 0, margin: 25.]
:: [s1; [C t][/C@(0.0.255) number/number]&]
[s0; [C@(128.0.255) t][/C@(0.0.255) number]&]
[s0; [C@(128.0.255) t][/C@(0.0.255) /number]]
:: [s0; Sets top cell border (first [/@(0.0.255) number]) and margin in
dots. If any of numbers is missing, sets only the one present.
Default is border: 0, margin: 15.]
:: [s1; [C b][/C@(0.0.255) number/number]&]
[s0; [C@(128.0.255) b][/C@(0.0.255) number]&]
[s0; [C@(128.0.255) b][/C@(0.0.255) /number]]
:: [s0; Sets bottom cell border (first [/@(0.0.255) number]) and margin
in dots. If any of numbers is missing, sets only the one present.
Default is border: 0, margin: 15.]
:: [s1; [C a][/C@(0.0.255) number/number]&]
[s0; [C@(128.0.255) a][/C@(0.0.255) number]&]
[s0; [C@(128.0.255) a][/C@(0.0.255) /number]]
:: [s0; Sets all cell borders (first [/@(0.0.255) number]) and margins
in dots. If any of numbers is missing, sets only the one present.]
:: [s0; [C@(128.0.255) `@][/C@(0.0.255) color]]
:: [s0; Cell background color. Default is White.]
:: [s0; [C@(128.0.255) R][/C@(0.0.255) color]]
:: [s0; Cell border color. Default is Black.]
:: [s0; [C@(128.0.255) !]]
:: [s0; Resets cell formatting to default values.]
:: [s0; [C@(128.0.255) H][/C@(0.0.255) number]]
:: [s0; Sets the minimal height of cell (and therefore also of row)
in dots.]
:: [s0; [C@(128.0.255) `-][/C@(0.0.255) number]]
:: [s0; Horizontal cell span.]
:: [s0; [C@(128.0.255) `|][/C@(0.0.255) number]]
:: [s0; Vertical cell span.]
:: [s0; [C@(128.0.255) ;]]
::= [s0; NOP separator. In some cases it helps to separate command code.]}}&]
[s0;3 &]
[s0; Note: There is also legacy support for old table format (from
previous QTF version) that is based on [@(128.0.255) `+`+ ]pair
as table start/stop and [@(128.0.255) `|`| `-`-] to divide cells/lines.
&]
[s0;3 &]
[s0;3 &]
[s2; [3 Examples]&]
[s0; &]
[ {{10000 [s0; [*C@3;1 `"Normal `[`* bold`] `[/ italic`] `[`_ underline`] `[``
superscript`] `[, subscript`]`"]]
:: [s0; Normal [* bold] [/ italic] [_ underline] [` superscript] [, subscript]]}}&]
[s0; &]
[ {{10000 [s0; [*C@3;1 `"```[ ```] `\1`[escaped`]`\1 `[`* bold`]`"]]
:: [s0; `[ `] `[escaped`] [* bold]]}}&]
[s0; &]
[ {{10000 [s0; [*C@3;1 `"`[A Arial (Sans`-Serif)`] `[R Times New Roman (Serif)`]
`[C Courier (Monospace)`]`"]]
:: [s0; Arial (Sans`-Serif) [R Times New Roman (Serif)] [C Courier (Monospace)]]}}&]
[s0; &]
[ {{10000 [s0; [*C@3;1 `"`[0 6pt `]`[1 8pt `]`[2 10pt `]`[3 12pt `]`[4 16pt `]`[5
20pt `]`[6 24pt `]`[7 28pt `]`[8 36pt `]`[9 48pt `]`"]]
:: [s0; [0 6pt ][1 8pt ]10pt [3 12pt] [4 16pt ][5 20pt ][6 24pt ][7 28pt ][8 36pt ][9 48pt
]]}}&]
[s0; &]
[ {{10000 [s0; [*C@3;1 `"`[!Tahoma! Tahoma`]`"]]
:: [s0; Tahoma]}}&]
[s0; &]
[ {{10000 [s0; [*C@3;1 `"`[`+500 500dots`]`"]]
:: [s0; [+500 500dots]]}}&]
[s0; &]
[ {{10000 [s0; [*C@3;1 `"`[`@4 Green text`] `[`$(255.220.200) Pink background`]`"]]
:: [s0; [@4 Green text] [$(255.220.200) Pink background]]}}&]
[s0; &]
[ {{10000 [s0; [*C@3;1 `"`[%EN`-US English language`] `[%CS`-CZ Czech language`]`"]]
:: [s0;%CS-CZ [%% English language ]Czech language]}}&]
[s0; &]
[ {{10000 [s0; [*C@3;1 `"`[`^upp.sf.net`^ Hyperlink`] `[Icompiler, linker; Index
entry`]`"]]
:: [s0; [^upp`.sf`.net^ Hyperlink] [Icompiler`, linker; Index entry]]}}&]
[s0; &]
[ {{10000 [s0; [*C@3;1 `"`[:label: Labeled paragraph`]`"]]
:: [s0; Labeled paragraph]}}&]
[s0; &]
[ {{10000 [s0; [*C@3;1 `"`[< Left paragraph alignment`]`"]]
:: [s0; Left paragraph alignment]}}&]
[s0; &]
[ {{10000 [s0; [*C@3;1 `"`[`= Center paragraph alignment`]`"]]
:: [s0; Center paragraph alignment]}}&]
[s0; &]
[ {{10000 [s0; [*C@3;1 `"`[> Right paragraph alignment`]`"]]
:: [s0; Right paragraph alignment]}}&]
[s0; &]
[ {{10000 [s0; [*C@3;1 `"`[# Justify alignment. Just some text to demosntrate
it... Just some text to demonstrate it... Just some text to demonstrate
it...`]`"]]
:: [s0; Justify alignment. Just some text to demosntrate it... Just
some text to demonstrate it... Just some text to demonstrate
it...]}}&]
[s0; &]
[ {{10000 [s0; [*C@3;1 `"`[l1000 Left margin 1000dots`]`"]]
:: [s0; Left margin 1000dots]}}&]
[s0; &]
[ {{10000 [s0; [*C@3;1 `"`[i1000 Indent 1000 dots.Just some text to demonstrate
it... Just some text to demonstrate it...`]`"]]
:: [s0; Indent 1000 dots.Just some text to demonstrate it... Just some
text to demonstrate it...]}}&]
[s0; &]
[ {{10000 [s0; [*C@3;1 `"`[r1000 Right margin 1000 dots.Just some text to demonstrate
it... Just some text to demonstrate it...`]`"]]
:: [s0; Right margin 1000 dots.Just some text to demonstrate it... Just
some text to demonstrate it...]}}&]
[s0; &]
[ {{10000 [s0; [*C@3;1 `"Paragraph`&`[b200 Before 200dots`]`"]]
:: [s0; Paragraph&]
[s0; Before 200dots]}}&]
[s0; &]
[ {{10000 [s0; [*C@3;1 `"`[a200 After 200dots`]`&Paragraph`"]]
:: [s0;a200; After 200dots&]
[s0; Paragraph]}}&]
[s0; &]
[ {{10000 [s0; [*C@3;1 `"`[i200 `[O0 bullet`&`]`[O1 bullet`&`]`[O2 bullet`&`]`[O3
bullet`]`]`"]]
:: [s0;i200;O0; bullet&]
[s0;i200;O1; bullet&]
[s0;i200;O2; bullet&]
[s0; bullet]}}&]
[s0; &]
[ {{10000 [s0; [*C@3;1 `"`[O9i500 text bullet`-`|Just some text to demonstrate
it... Just some text to demonstrate it...Just some text to demonstrate
it... Just some text to demonstrate it...`]`"]]
:: [s0; text bullet-|Just some text to demonstrate it... Just some text
to demonstrate it...Just some text to demonstrate it... Just
some text to demonstrate it...]}}&]
[s0; &]
[ {{10000 [s0; [*C@3;1 `"`[O9i200 `[N1m.; `-`|level 1`&`]`[N1a `-`|level 2`&`]`[N1a
`-`|level 2`&`]`[N1 `-`|level 1`&`]`[N1a `-`|level 2`]`]`"]]
:: [s0;i200;O9;m`.;N1; -|level 1&]
[s0;i200;O9;N1a; -|level 2&]
[s0;i200;O9;N1a; -|level 2&]
[s0;i200;O9;N1; -|level 1&]
[s0; -|level 2]}}&]
[s0; &]
[ {{10000 [s0; [*C@3;1 `"`[`~300`~`=.2000`~>`-3000 `-`|Normal tab`-`|Centered
tab`-`|Right tab`]`"]]
:: [s0; -|Normal tab-|Centered tab-|Right tab]}}&]
[s0; &]
[ {{10000 [s0; [*C@3;1 `"`{`{1:2 A1]]
:: [s0; [*C@3;1 A2]]
:: [s0; [*C@3;1 B1]]
:: [s0; [*C@3;1 B2`}`}`"]]
:: [ {{3333:6667 [s0; A1]
:: [s0; A2]
:: [s0; B1]
:: [s0; B2]}}]}}&]
[s0; &]
[ {{10000 [s0; [*C@3;1 `"`{`{2:1G4g100F5f50 A1`:: A2`:: B1`:: B2`}`}`"]]
:: [ {{6666:3334f50;F5g100;G4 [s0; A1]
:: [s0; A2]
:: [s0; B1]
:: [s0; B2]}}]}}&]
[s0; &]
[ {{10000 [s0; [*C@3;1 `"`{`{1:2 A1`::l40/60R6`@3 A2`::! B1`:: B2`}`}`"]]
:: [ {{3333:6667 [s0; A1]
::l40/60@3R6 [s0; A2]
::l0/25@2R0 [s0; B1]
:: [s0; B2]}}]}}&]
[s0; &]
[ {{10000 [s0; [*C@3;1 `"`{`{1:1:1`|2 A1`::`-2 A2`:: A3`:: B1`:: B2`:: B3`}`}`"]]
:: [ {{3333:3333:3334|1 [s0; A1]
::-1 [s0; A2]
:: [s0;%- ]
:: [s0;%- ]
:: [s0; B2]
:: [s0; B3]}}]}}&]
[s0; &]
[ {{10000 [s0; [*C@3;1 `"`{`{1:2 A1`:: A2`:: B1`:: `{`{1:2 a1`:: a2`:: a1`:: a2`}`}`}`}`"]]
:: [ {{3333:6667 [s0; A1]
:: [s0; A2]
:: [s0; B1]
:: [ {{3333:6667 [s0; a1]
:: [s0; a2]
:: [s0; a1]
:: [s0; a2]}}]}}]}}&]
[s0; ]

View file

@ -1,18 +1,35 @@
#ifndef _SyntaxHighlight_test_h_
#define _SyntaxHighlight_test_h_
#include <Core/Core.h>
#include <vector>
#include "Common.h"
using namespace Upp;
using namespace std;
class XXX {
typedef XXX yyy;
public:
private:
namespace Upp {
template<> void Xmlize(XmlIO xml, vector<int>& data) {
if(xml.IsStoring())
for(int i = 0; i < (int)data.size(); i++)
Xmlize(xml.Add("item"), data[i]);
else {
data.clear();
for(int i = 0; i < xml->GetCount(); i++)
if(xml->Node(i).IsTag("item")) {
data.push_back(0);
Xmlize(xml.At(i), data.back());
}
}
}
};
struct Y {
};
#endif
CONSOLE_APP_MAIN
{
vector<int> x;
x.push_back(1);
x.push_back(2);
x.push_back(3);
String s = StoreAsXML(x, "std-test");
DUMP(s);
vector<int> y;
LoadFromXML(y, s);
for(int i = 0; i < (int)y.size(); i++)
DUMP(y[i]);
}

View file

@ -0,0 +1,8 @@
#include <Core/Core.h>
using namespace Upp;
CONSOLE_APP_MAIN
{
SaveFile("z:/zaci/5-2007-2.xml", ZDecompress(LoadFile("z:/zaci/5-2007-2.zml")));
}

View file

@ -0,0 +1,9 @@
uses
Core;
file
uncompress.cpp;
mainconfig
"" = "";