1 //
2 // C++ Implementation: TOC dialog
3 //
4 // Description:
5 // Shows table of contents, and allows to input page number to go
6 //
7 // Author: Vadim Lopatin <vadim.lopatin@coolreader.org>, (C) 2008
8 //
9 // Copyright: See COPYING file that comes with this distribution
10 //
11 // tocdlg.cpp
12
13 #include "tocdlg.h"
14 #include <cri18n.h>
15
limitTextWidth(lString16 s,int width,LVFontRef font)16 lString16 limitTextWidth( lString16 s, int width, LVFontRef font )
17 {
18
19 int w = font->getTextWidth(s.c_str(), s.length());
20 if ( w<width )
21 return s;
22 lString16 sss("...");
23 int www = font->getTextWidth(sss.c_str(), sss.length());
24 while (s.length()>0) {
25 s.erase(s.length()-1, 1);
26 int w = font->getTextWidth(s.c_str(), s.length());
27 if ( w+www<=width )
28 return s+sss;
29 }
30 return lString16(".");
31 }
32
draw()33 void CRTOCDialog::draw()
34 {
35 CRGUIWindowBase::draw();
36 CRRectSkinRef clientSkin = _skin->getClientSkin();
37 CRRectSkinRef normalItemSkin = _skin->getItemSkin();
38 CRRectSkinRef valueSkin = _skin->getValueSkin();
39 CRRectSkinRef selItemSkin = _skin->getSelItemSkin();
40 if ( normalItemSkin.isNull() )
41 normalItemSkin = clientSkin;
42 if ( valueSkin.isNull() )
43 valueSkin = clientSkin;
44 if ( selItemSkin.isNull() )
45 selItemSkin = clientSkin;
46 lvRect borders = clientSkin->getBorderWidths();
47 LVRef<LVDrawBuf> drawbuf = _wm->getScreen()->getCanvas();
48 lvRect tocRect;
49 getClientRect( tocRect );
50 tocRect.shrinkBy(borders);
51 int curPage = _docview->getCurPage();
52 // draw toc
53 for (int i=0; i < _pageItems && i + _topItem < _items.length(); i++) {
54 LVTocItem * item = _items[ i + _topItem];
55 LVTocItem * nextitem = (i+_topItem+1) < _items.length()
56 ? _items[ i + _topItem + 1] : NULL;
57
58 //lvRect margins( 10, 10, 10, 10 );
59 lvRect itemRect = tocRect;
60 bool isSelected = true;
61
62 if ( curPage < item->getPage() )
63 isSelected = false;
64 else if ( nextitem!=NULL && curPage >= nextitem->getPage() &&
65 curPage > item->getPage() )
66 isSelected = false;
67 CRRectSkinRef itemSkin = isSelected ? selItemSkin : normalItemSkin;
68 //itemRect.shrinkBy( margins );
69 itemRect.top = i * _itemHeight + tocRect.top;
70 itemRect.bottom = itemRect.top + _itemHeight;
71
72
73
74 lString16 titleString = item->getName();
75 lString16 pageString = lString16::itoa( item->getPage() + 1 );
76 int pageNumWidth = valueSkin->getFont()->getTextWidth( pageString.c_str(), pageString.length() );
77 int titleWidth = itemSkin->getFont()->getTextWidth( titleString.c_str(), titleString.length() );
78 int level = item->getLevel();
79 int levelMargin = 32; // TODO: get better value
80 itemSkin->draw( *drawbuf, itemRect );
81 itemRect.left += (level - 1) * levelMargin;
82 lvRect pageNumRect = itemRect;
83 pageNumRect.left = pageNumRect.right - pageNumWidth - valueSkin->getBorderWidths().left - valueSkin->getBorderWidths().right;
84 itemRect.right = pageNumRect.left;
85 if ( !itemRect.isEmpty() ) {
86 lvRect rc = itemRect;
87 //rc.extendBy( borders );
88 lString16 s = limitTextWidth( titleString, rc.width()-borders.left-borders.right, itemSkin->getFont() );
89 itemSkin->drawText( *drawbuf, rc, s );
90 }
91 if ( !pageNumRect.isEmpty() ) {
92 lvRect rc = pageNumRect;
93 //rc.extendBy( borders );
94 valueSkin->drawText( *drawbuf, rc, pageString );
95 }
96 if ( itemRect.left + titleWidth < itemRect.right + 5 ) {
97 itemRect.left = itemRect.left + titleWidth + itemSkin->getBorderWidths().left;
98 itemRect.left = (itemRect.left + 3) & (~3);
99 itemRect.right &= (~3);
100 lUInt32 cl = clientSkin->getTextColor();
101 if ( !itemRect.isEmpty() ) {
102 // draw line of points
103 for ( int i = itemRect.left; i < itemRect.right; i += 4 ) {
104 int y = itemRect.bottom - itemSkin->getFontSize()/5;
105 drawbuf->FillRect( i, y, i+1, y+1, cl );
106 }
107 }
108
109 }
110 }
111 }
112
CRTOCDialog(CRGUIWindowManager * wm,lString16 title,int resultCmd,int pageCount,LVDocView * docview)113 CRTOCDialog::CRTOCDialog( CRGUIWindowManager * wm, lString16 title, int resultCmd, int pageCount, LVDocView * docview )
114 : CRNumberEditDialog( wm, title, lString16::empty_str, resultCmd, 1, pageCount )
115 ,_docview(docview)
116 {
117 docview->getFlatToc( _items );
118 _skinName = "#toc";
119 _skin = _wm->getSkin()->getMenuSkin(_skinName.c_str());
120 CRRectSkinRef clientSkin = _skin->getClientSkin();
121 CRRectSkinRef itemSkin = _skin->getItemSkin();
122 CRRectSkinRef valueSkin = _skin->getValueSkin();
123 CRRectSkinRef selItemSkin = _skin->getSelItemSkin();
124 if ( itemSkin.isNull() )
125 itemSkin = clientSkin;
126 if ( valueSkin.isNull() )
127 valueSkin = clientSkin;
128 if ( selItemSkin.isNull() )
129 selItemSkin = clientSkin;
130
131 lvRect borders = clientSkin->getBorderWidths();
132 CRScrollSkinRef sskin = _skin->getScrollSkin();
133 _font = itemSkin->getFont();
134 _fullscreen = true;
135 _rect = _wm->getScreen()->getRect();
136 _caption = title;
137 lvRect clientRect = _skin->getClientRect( _rect );
138 lvRect tocRect;
139 getClientRect( tocRect );
140 tocRect.shrinkBy(borders);
141 lvRect itemBorders = itemSkin->getBorderWidths();
142 _itemHeight = _font->getHeight() + itemBorders.top + itemBorders.bottom;
143 _pageItems = tocRect.height() / _itemHeight;
144 int curItem = getCurItemIndex();
145 _topItem = curItem>=0 ? curItem / _pageItems * _pageItems : 0;
146 _page = _topItem / _pageItems + 1;
147 _pages = (_items.length() + (_pageItems - 1)) / _pageItems;
148 int curPage = _docview->getCurPage();
149 int docPages = _docview->getPageCount();
150 lString16 pageString(_("Current page: $1 of $2\n"));
151 pageString.replaceIntParam(1, curPage+1);
152 pageString.replaceIntParam(2, docPages);
153 _statusText = pageString + lString16(_("Enter page number:"));
154 _inputText = "_";
155 }
156
digitEntered(lChar16 c)157 bool CRTOCDialog::digitEntered( lChar16 c )
158 {
159 lString16 v = _value;
160 v << c;
161 int n = v.atoi();
162 if ( n<=_maxvalue ) {
163 _value = v;
164 _inputText = _value + "_";
165 setDirty();
166 return true;
167 }
168 return false;
169 }
170
171 /// returns index of first item for current page, -1 if not found
getCurItemIndex()172 int CRTOCDialog::getCurItemIndex()
173 {
174 int curPage = _docview->getCurPage();
175 for ( int i=0; i<_items.length(); i++ ) {
176 LVTocItem * item = _items[ i ];
177 LVTocItem * nextitem = (i+1) < _items.length()
178 ? _items[ i + 1] : NULL;
179 bool isSelected = true;
180 if ( curPage < item->getPage() )
181 isSelected = false;
182 else if ( nextitem!=NULL && curPage >= nextitem->getPage() &&
183 curPage > item->getPage() )
184 isSelected = false;
185 if ( isSelected )
186 return i;
187 }
188 return -1;
189 }
190
191 /// returns true if command is processed
onCommand(int command,int params)192 bool CRTOCDialog::onCommand( int command, int params )
193 {
194 if ( _value.empty() ) {
195 if ( command == MCMD_SELECT_0 )
196 command = MCMD_SCROLL_FORWARD;
197 if ( command == MCMD_SELECT_0_LONG )
198 command = MCMD_SCROLL_FORWARD_LONG;
199 }
200 switch ( command ) {
201 case MCMD_CANCEL:
202 if ( _value.length()>0 ) {
203 _value.erase( _value.length()-1, 1 );
204 _inputText = _value + "_";
205 setDirty();
206 } else {
207 _wm->closeWindow( this );
208 }
209 return true;
210 case MCMD_OK:
211 {
212 int n = _value.atoi();
213 if ( n>=_minvalue && n<=_maxvalue ) {
214 _wm->postCommand( _resultCmd, n );
215 _wm->closeWindow( this );
216 return true;
217 }
218 _wm->closeWindow( this );
219 return true;
220 }
221 case MCMD_SCROLL_FORWARD:
222 case MCMD_SCROLL_FORWARD_LONG:
223 {
224 int step = command == MCMD_SCROLL_FORWARD_LONG ? 10 : 1;
225 _topItem = _topItem + _pageItems * step;
226 int maxpos = (_items.length()-1) / _pageItems * _pageItems;
227 if ( _topItem > maxpos )
228 _topItem = maxpos;
229 if ( _topItem < 0 )
230 _topItem = 0;
231 _page = _topItem / _pageItems + 1;
232 _pages = (_items.length()+(_pageItems-1))/ _pageItems;
233 setDirty();
234 }
235 break;
236 case MCMD_SCROLL_BACK:
237 case MCMD_SCROLL_BACK_LONG:
238 {
239 int step = command == MCMD_SCROLL_BACK_LONG ? 10 : 1;
240 _topItem = _topItem - _pageItems * step;
241 int maxpos = (_items.length()-1) / _pageItems * _pageItems;
242 if ( _topItem > maxpos )
243 _topItem = maxpos;
244 if ( _topItem < 0 )
245 _topItem = 0;
246 _page = _topItem / _pageItems + 1;
247 _pages = (_items.length()+(_pageItems-1))/ _pageItems;
248 setDirty();
249 }
250 break;
251 case MCMD_SELECT_0:
252 case MCMD_SELECT_1:
253 case MCMD_SELECT_2:
254 case MCMD_SELECT_3:
255 case MCMD_SELECT_4:
256 case MCMD_SELECT_5:
257 case MCMD_SELECT_6:
258 case MCMD_SELECT_7:
259 case MCMD_SELECT_8:
260 case MCMD_SELECT_9:
261 digitEntered( '0' + (command - MCMD_SELECT_0) );
262 break;
263 default:
264 return true;
265 }
266 return true;
267 }
268