TUI: story detail page
[fanfix.git] / src / be / nikiroo / fanfix / reader / tui / TuiReaderStoryWindow.java
CommitLineData
16a81ef7 1package be.nikiroo.fanfix.reader.tui;
c1873e56 2
edfd3577 3import java.util.ArrayList;
6a26aa76 4import java.util.Arrays;
edfd3577
NR
5import java.util.List;
6
0861d62a 7import jexer.TAction;
0861d62a 8import jexer.TButton;
0861d62a 9import jexer.TLabel;
6a26aa76 10import jexer.TTable;
f63c4267 11import jexer.TText;
0861d62a 12import jexer.TWindow;
c1873e56 13import jexer.event.TResizeEvent;
4f66bfa8 14import jexer.event.TResizeEvent.Type;
c1873e56
NR
15import be.nikiroo.fanfix.data.Chapter;
16import be.nikiroo.fanfix.data.MetaData;
17import be.nikiroo.fanfix.data.Paragraph;
9293188f 18import be.nikiroo.fanfix.data.Paragraph.ParagraphType;
c1873e56 19import be.nikiroo.fanfix.data.Story;
e42573a0 20import be.nikiroo.fanfix.library.BasicLibrary;
c1873e56 21
6a26aa76
NR
22/**
23 * This window will contain the {@link Story} in a readable format, with a
24 * chapter browser.
25 *
26 * @author niki
27 */
5dd985cf 28class TuiReaderStoryWindow extends TWindow {
68e2c6d2 29 private BasicLibrary lib;
c1873e56
NR
30 private MetaData meta;
31 private Story story;
6a26aa76 32 private TLabel titleField;
f63c4267 33 private TText textField;
6a26aa76
NR
34 private TTable table;
35 private int chapter = -99; // invalid value
edfd3577 36 private List<TButton> navigationButtons;
5b00c122 37 private TLabel currentChapter;
c1873e56 38
6322ab64 39 // chapter: -1 for "none" (0 is desc)
5b00c122 40 public TuiReaderStoryWindow(TuiReaderApplication app, BasicLibrary lib,
68e2c6d2 41 MetaData meta, int chapter) {
c1873e56 42 super(app, desc(meta), 0, 0, 60, 18, CENTERED | RESIZABLE);
68e2c6d2 43
b0e88ebd 44 this.lib = lib;
c1873e56
NR
45 this.meta = meta;
46
5b00c122 47 app.setStatusBar(this, desc(meta));
c1873e56 48
6a26aa76
NR
49 // last = use window background
50 titleField = new TLabel(this, " Title", 0, 1, "tlabel", false);
51 textField = new TText(this, "", 0, 3, getWidth() - 2, getHeight() - 5);
52 table = new TTable(this, 0, 3, getWidth(), getHeight() - 4, null, null,
53 Arrays.asList("Key", "Value"), true);
edfd3577 54
0b7e3d78 55 navigationButtons = new ArrayList<TButton>(5);
edfd3577 56
396e924c 57 // -3 because 0-based and 2 for borders
edfd3577
NR
58 int row = getHeight() - 3;
59
6a26aa76
NR
60 // for bg colour when << button is pressed
61 navigationButtons.add(addButton(" ", 0, row, null));
0861d62a 62 navigationButtons.add(addButton("<< ", 0, row, new TAction() {
211f7ddb 63 @Override
396e924c 64 public void DO() {
6a26aa76 65 setChapter(-1);
396e924c 66 }
edfd3577 67 }));
0861d62a 68 navigationButtons.add(addButton("< ", 4, row, new TAction() {
211f7ddb 69 @Override
edfd3577
NR
70 public void DO() {
71 setChapter(TuiReaderStoryWindow.this.chapter - 1);
72 }
73 }));
0861d62a 74 navigationButtons.add(addButton("> ", 7, row, new TAction() {
211f7ddb 75 @Override
edfd3577
NR
76 public void DO() {
77 setChapter(TuiReaderStoryWindow.this.chapter + 1);
78 }
79 }));
0861d62a 80 navigationButtons.add(addButton(">> ", 10, row, new TAction() {
211f7ddb 81 @Override
edfd3577
NR
82 public void DO() {
83 setChapter(getStory().getChapters().size());
84 }
85 }));
b0e88ebd 86
8670a283
NR
87 navigationButtons.get(0).setEnabled(false);
88 navigationButtons.get(1).setEnabled(false);
89 navigationButtons.get(2).setEnabled(false);
edfd3577 90
5b00c122
NR
91 currentChapter = addLabel("", 14, row);
92 currentChapter.setWidth(getWidth() - 10);
6a26aa76 93
edfd3577 94 setChapter(chapter);
c1873e56
NR
95 }
96
97 @Override
98 public void onResize(TResizeEvent resize) {
99 super.onResize(resize);
100
4f66bfa8
NR
101 // Resize the text field TODO: why setW/setH/reflow not enough for the
102 // scrollbars?
103 textField.onResize(new TResizeEvent(Type.WIDGET, resize.getWidth() - 2,
6a26aa76
NR
104 resize.getHeight() - 5));
105
106 table.setWidth(getWidth());
107 table.setHeight(getHeight() - 4);
108 table.reflowData();
edfd3577
NR
109
110 // -3 because 0-based and 2 for borders
111 int row = getHeight() - 3;
112
5b00c122
NR
113 String name = currentChapter.getLabel();
114 while (name.length() < resize.getWidth() - currentChapter.getX()) {
edfd3577
NR
115 name += " ";
116 }
5b00c122
NR
117 currentChapter.setLabel(name);
118 currentChapter.setWidth(resize.getWidth() - 10);
119 currentChapter.setY(row);
edfd3577
NR
120
121 for (TButton button : navigationButtons) {
122 button.setY(row);
123 }
124 }
125
5b00c122
NR
126 /**
127 * Display the current chapter in the window, or the {@link Story} info
128 * page.
129 *
130 * @param chapter
131 * the chapter (including "0" which is the description) or "-1"
132 * to display the info page instead
133 */
edfd3577 134 private void setChapter(int chapter) {
edfd3577
NR
135 if (chapter > getStory().getChapters().size()) {
136 chapter = getStory().getChapters().size();
137 }
138
139 if (chapter != this.chapter) {
140 this.chapter = chapter;
b0e88ebd 141
8670a283 142 int max = getStory().getChapters().size();
5b00c122
NR
143 navigationButtons.get(0).setEnabled(chapter > -1);
144 navigationButtons.get(1).setEnabled(chapter > -1);
145 navigationButtons.get(2).setEnabled(chapter > -1);
8670a283
NR
146 navigationButtons.get(3).setEnabled(chapter < max);
147 navigationButtons.get(4).setEnabled(chapter < max);
b0e88ebd 148
5b00c122 149 if (chapter < 0) {
6a26aa76 150 displayInfoPage();
edfd3577 151 } else {
6a26aa76 152 displayChapterPage();
edfd3577 153 }
5b00c122
NR
154 }
155
156 setCurrentChapterText();
157 }
edfd3577 158
5b00c122
NR
159 /**
160 * Append the info page about the current {@link Story}.
161 *
162 * @param builder
163 * the builder to append to
164 */
6a26aa76
NR
165 private void displayInfoPage() {
166 textField.setVisible(false);
167 table.setVisible(true);
5b00c122 168
6a26aa76 169 MetaData meta = getStory().getMeta();
5b00c122 170
6a26aa76 171 setCurrentTitle(meta.getTitle());
5b00c122 172
6a26aa76
NR
173 table.setRowData(new String[][] { //
174 new String[] { "Author", meta.getAuthor() }, //
175 new String[] { "Publication date", meta.getDate() },
176 new String[] { "Word count", Long.toString(meta.getWords()) },
177 new String[] { "Source", meta.getSource() } //
178 });
179 table.setHeaders(Arrays.asList("key", "value"), false);
180 table.toTop();
5b00c122
NR
181 }
182
183 /**
184 * Append the current chapter.
185 *
186 * @param builder
187 * the builder to append to
188 */
6a26aa76
NR
189 private void displayChapterPage() {
190 table.setVisible(false);
191 textField.setVisible(true);
192
193 StringBuilder builder = new StringBuilder();
194
5b00c122
NR
195 Chapter chap = null;
196 if (chapter == 0) {
197 chap = getStory().getMeta().getResume();
198 } else if (chapter > 0) {
199 chap = getStory().getChapters().get(chapter - 1);
200 }
201
202 // TODO: i18n
203 String chapName = chap == null ? "[No RESUME]" : chap.getName();
6a26aa76 204 setCurrentTitle(String.format("Chapter %d: %s", chapter, chapName));
5b00c122
NR
205
206 if (chap != null) {
207 for (Paragraph para : chap) {
208 if (para.getType() == ParagraphType.BREAK) {
209 builder.append("\n");
210 }
211 builder.append(para.getContent()).append("\n");
212 if (para.getType() == ParagraphType.BREAK) {
213 builder.append("\n");
fdc55375 214 }
edfd3577 215 }
edfd3577 216 }
6a26aa76
NR
217
218 setText(builder.toString());
c1873e56
NR
219 }
220
221 private Story getStory() {
222 if (story == null) {
edfd3577 223 // TODO: progress bar?
b0e88ebd 224 story = lib.getStory(meta.getLuid(), null);
c1873e56
NR
225 }
226 return story;
227 }
228
5b00c122
NR
229 /**
230 * Display the given text on the window.
231 *
232 * @param text
233 * the text to display
234 */
235 private void setText(String text) {
236 textField.setText(text);
237 textField.reflowData();
238 textField.toTop();
239 }
240
241 /**
242 * Set the current chapter area to the correct value.
243 */
244 private void setCurrentChapterText() {
245 String name;
246 if (chapter < 0) {
247 name = " " + getStory().getMeta().getTitle();
248 } else if (chapter == 0) {
249 Chapter resume = getStory().getMeta().getResume();
250 if (resume != null) {
251 name = String.format(" %s", resume.getName());
252 } else {
253 // TODO: i18n
254 name = "[No RESUME]";
255 }
256 } else {
257 int max = getStory().getChapters().size();
258 Chapter chap = getStory().getChapters().get(chapter - 1);
259 name = String.format(" %d/%d: %s", chapter, max, chap.getName());
260 }
261
262 int width = getWidth() - currentChapter.getX();
263 while (name.length() < width) {
264 name += " ";
265 }
266
267 if (name.length() > width) {
268 name = name.substring(0, width);
269 }
270
271 currentChapter.setLabel(name);
c1873e56 272 }
5b00c122
NR
273
274 /**
6a26aa76 275 * Set the current title in-window.
5b00c122 276 *
5b00c122 277 * @param title
6a26aa76 278 * the new title
5b00c122 279 */
6a26aa76
NR
280 private void setCurrentTitle(String title) {
281 titleField.setWidth(title.length());
282 titleField.setLabel(title);
283 }
5b00c122 284
6a26aa76
NR
285 private static String desc(MetaData meta) {
286 return String.format("%s: %s", meta.getLuid(), meta.getTitle());
5b00c122 287 }
c1873e56 288}