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