1 /*
2  * Copyright (C) 2004-2010 Geometer Plus <contact@geometerplus.com>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17  * 02110-1301, USA.
18  */
19 
20 #include <ZLOptionsDialog.h>
21 #include <ZLApplication.h>
22 #include <ZLOptionEntry.h>
23 
24 #include <optionEntries/ZLSimpleOptionEntry.h>
25 #include <optionEntries/ZLSimpleKeyOptionEntry.h>
26 
27 #include "ReadingOptionsDialog.h"
28 
29 #include "../../fbreader/FBReader.h"
30 #include "../../fbreader/FBReaderActions.h"
31 
32 class KeyboardControlEntry : public ZLSimpleBooleanOptionEntry {
33 
34 public:
35 	KeyboardControlEntry();
36 	void onStateChanged(bool state);
37 };
38 
KeyboardControlEntry()39 KeyboardControlEntry::KeyboardControlEntry() : ZLSimpleBooleanOptionEntry(FBReader::Instance().KeyboardControlOption) {
40 }
41 
onStateChanged(bool state)42 void KeyboardControlEntry::onStateChanged(bool state) {
43 	ZLSimpleBooleanOptionEntry::onStateChanged(state);
44 	FBReader::Instance().grabAllKeys(state);
45 }
46 
47 class SingleKeyOptionEntry : public ZLSimpleKeyOptionEntry {
48 
49 public:
50 	SingleKeyOptionEntry(const CodeIndexBimap &bimap, ZLKeyBindings &bindings);
51 	const CodeIndexBimap &codeIndexBimap() const;
52 
53 private:
54 	const CodeIndexBimap &myBimap;
55 };
56 
SingleKeyOptionEntry(const CodeIndexBimap & bimap,ZLKeyBindings & bindings)57 SingleKeyOptionEntry::SingleKeyOptionEntry(const CodeIndexBimap &bimap, ZLKeyBindings &bindings) : ZLSimpleKeyOptionEntry(bindings), myBimap(bimap) {
58 }
59 
codeIndexBimap() const60 const ZLSimpleKeyOptionEntry::CodeIndexBimap &SingleKeyOptionEntry::codeIndexBimap() const {
61 	return myBimap;
62 }
63 
64 class MultiKeyOptionEntry : public ZLKeyOptionEntry {
65 
66 public:
67 	MultiKeyOptionEntry(const ZLResource &resource);
68 	void onAccept();
69 	int actionIndex(const std::string &key);
70 	void onValueChanged(const std::string &key, int index);
71 	void onKeySelected(const std::string &key);
72 
73 	void setOrientation(ZLView::Angle);
74 	void setExitOnCancelEntry(ZLOptionEntry *exitOnCancelEntry);
75 
76 private:
77 	void addAction(const std::string &actionId);
78 
79 private:
80 	const ZLResource &myResource;
81 	ZLSimpleKeyOptionEntry::CodeIndexBimap myBimap;
82 
83 	SingleKeyOptionEntry myEntry0;
84 	SingleKeyOptionEntry myEntry90;
85 	SingleKeyOptionEntry myEntry180;
86 	SingleKeyOptionEntry myEntry270;
87 	SingleKeyOptionEntry *myCurrentEntry;
88 	ZLOptionEntry *myExitOnCancelEntry;
89 };
90 
addAction(const std::string & actionId)91 void MultiKeyOptionEntry::addAction(const std::string &actionId) {
92 	myBimap.insert(actionId);
93 	addActionName(myResource[ZLResourceKey(actionId)].value());
94 }
95 
MultiKeyOptionEntry(const ZLResource & resource)96 MultiKeyOptionEntry::MultiKeyOptionEntry(const ZLResource &resource) :
97 	ZLKeyOptionEntry(),
98 	myResource(resource),
99 	myEntry0(myBimap, *FBReader::Instance().keyBindings(ZLView::DEGREES0)),
100 	myEntry90(myBimap, *FBReader::Instance().keyBindings(ZLView::DEGREES90)),
101 	myEntry180(myBimap, *FBReader::Instance().keyBindings(ZLView::DEGREES180)),
102 	myEntry270(myBimap, *FBReader::Instance().keyBindings(ZLView::DEGREES270)),
103 	myCurrentEntry(&myEntry0),
104 	myExitOnCancelEntry(0) {
105 	addAction(ZLApplication::NoAction);
106 
107 	// switch view
108 	addAction(ActionCode::SHOW_LIBRARY);
109 	addAction(ActionCode::SHOW_NETWORK_LIBRARY);
110 	addAction(ActionCode::OPEN_PREVIOUS_BOOK);
111 	addAction(ActionCode::SHOW_TOC);
112 
113 	// navigation
114 	addAction(ActionCode::SCROLL_TO_HOME);
115 	addAction(ActionCode::SCROLL_TO_START_OF_TEXT);
116 	addAction(ActionCode::SCROLL_TO_END_OF_TEXT);
117 	addAction(ActionCode::GOTO_NEXT_TOC_SECTION);
118 	addAction(ActionCode::GOTO_PREVIOUS_TOC_SECTION);
119 	addAction(ActionCode::PAGE_SCROLL_FORWARD);
120 	addAction(ActionCode::PAGE_SCROLL_BACKWARD);
121 	addAction(ActionCode::LINE_SCROLL_FORWARD);
122 	addAction(ActionCode::LINE_SCROLL_BACKWARD);
123 	addAction(ActionCode::UNDO);
124 	addAction(ActionCode::REDO);
125 
126 	// selection
127 	addAction(ActionCode::COPY_SELECTED_TEXT_TO_CLIPBOARD);
128 	addAction(ActionCode::OPEN_SELECTED_TEXT_IN_DICTIONARY);
129 	addAction(ActionCode::CLEAR_SELECTION);
130 
131 	// search
132 	addAction(ActionCode::SEARCH);
133 	addAction(ActionCode::FIND_PREVIOUS);
134 	addAction(ActionCode::FIND_NEXT);
135 
136 	// look
137 	addAction(ActionCode::INCREASE_FONT);
138 	addAction(ActionCode::DECREASE_FONT);
139 	addAction(ActionCode::SHOW_HIDE_POSITION_INDICATOR);
140 	addAction(ActionCode::TOGGLE_FULLSCREEN);
141 	addAction(ActionCode::ROTATE_SCREEN);
142 
143 	// dialogs
144 	addAction(ActionCode::SHOW_OPTIONS_DIALOG);
145 	addAction(ActionCode::SHOW_BOOK_INFO_DIALOG);
146 	addAction(ActionCode::ADD_BOOK);
147 
148 	// quit
149 	addAction(ActionCode::CANCEL);
150 	addAction(ActionCode::QUIT);
151 }
152 
setOrientation(ZLView::Angle angle)153 void MultiKeyOptionEntry::setOrientation(ZLView::Angle angle) {
154 	switch (angle) {
155 		case ZLView::DEGREES0:
156 			myCurrentEntry = &myEntry0;
157 			break;
158 		case ZLView::DEGREES90:
159 			myCurrentEntry = &myEntry90;
160 			break;
161 		case ZLView::DEGREES180:
162 			myCurrentEntry = &myEntry180;
163 			break;
164 		case ZLView::DEGREES270:
165 			myCurrentEntry = &myEntry270;
166 			break;
167 	}
168 	resetView();
169 }
170 
onAccept()171 void MultiKeyOptionEntry::onAccept() {
172 	myEntry0.onAccept();
173 	myEntry90.onAccept();
174 	myEntry180.onAccept();
175 	myEntry270.onAccept();
176 }
177 
actionIndex(const std::string & key)178 int MultiKeyOptionEntry::actionIndex(const std::string &key) {
179 	return myCurrentEntry->actionIndex(key);
180 }
181 
onValueChanged(const std::string & key,int index)182 void MultiKeyOptionEntry::onValueChanged(const std::string &key, int index) {
183 	myCurrentEntry->onValueChanged(key, index);
184 	if (myExitOnCancelEntry != 0) {
185 		myExitOnCancelEntry->setVisible(myBimap.codeByIndex(index) == ActionCode::CANCEL);
186 	}
187 }
188 
setExitOnCancelEntry(ZLOptionEntry * exitOnCancelEntry)189 void MultiKeyOptionEntry::setExitOnCancelEntry(ZLOptionEntry *exitOnCancelEntry) {
190 	myExitOnCancelEntry = exitOnCancelEntry;
191 }
192 
onKeySelected(const std::string & key)193 void MultiKeyOptionEntry::onKeySelected(const std::string &key) {
194 	if (myExitOnCancelEntry != 0) {
195 		myExitOnCancelEntry->setVisible(myBimap.codeByIndex(myCurrentEntry->actionIndex(key)) == ActionCode::CANCEL);
196 	}
197 }
198 
199 class OrientationEntry : public ZLComboOptionEntry {
200 
201 public:
202 	OrientationEntry(MultiKeyOptionEntry &keyEntry, const ZLResource &resource);
203 	const std::string &initialValue() const;
204 	const std::vector<std::string> &values() const;
205 	void onValueSelected(int index);
206 	void onAccept(const std::string &value);
207 
208 private:
209 	MultiKeyOptionEntry &myKeyEntry;
210 	const ZLResource &myResource;
211 };
212 
OrientationEntry(MultiKeyOptionEntry & keyEntry,const ZLResource & resource)213 OrientationEntry::OrientationEntry(MultiKeyOptionEntry &keyEntry, const ZLResource &resource) : myKeyEntry(keyEntry), myResource(resource) {
214 }
215 
initialValue() const216 const std::string &OrientationEntry::initialValue() const {
217 	return values()[0];
218 }
219 
values() const220 const std::vector<std::string> &OrientationEntry::values() const {
221 	static std::vector<std::string> _values;
222 	if (_values.empty()) {
223 		_values.push_back(myResource["degrees0"].value());
224 		_values.push_back(myResource["degrees90ccw"].value());
225 		_values.push_back(myResource["degrees180"].value());
226 		_values.push_back(myResource["degrees90cw"].value());
227 	}
228 	return _values;
229 }
230 
onValueSelected(int index)231 void OrientationEntry::onValueSelected(int index) {
232 	static ZLView::Angle angles[] = {
233 		ZLView::DEGREES0,
234 		ZLView::DEGREES90,
235 		ZLView::DEGREES180,
236 		ZLView::DEGREES270
237 	};
238 	myKeyEntry.setOrientation(angles[index]);
239 }
240 
onAccept(const std::string &)241 void OrientationEntry::onAccept(const std::string&) {
242 }
243 
244 class UseSeparateOptionsEntry : public ZLSimpleBooleanOptionEntry {
245 
246 public:
247 	UseSeparateOptionsEntry(ZLOptionEntry &keyEntry, OrientationEntry &orientationEntry);
248 	void onStateChanged(bool state);
249 
250 private:
251 	ZLOptionEntry &myKeyEntry;
252 	OrientationEntry &myOrientationEntry;
253 };
254 
UseSeparateOptionsEntry(ZLOptionEntry & keyEntry,OrientationEntry & orientationEntry)255 UseSeparateOptionsEntry::UseSeparateOptionsEntry(ZLOptionEntry &keyEntry, OrientationEntry &orientationEntry) : ZLSimpleBooleanOptionEntry(FBReader::Instance().UseSeparateBindingsOption), myKeyEntry(keyEntry), myOrientationEntry(orientationEntry) {
256 }
257 
onStateChanged(bool state)258 void UseSeparateOptionsEntry::onStateChanged(bool state) {
259 	ZLSimpleBooleanOptionEntry::onStateChanged(state);
260 	myOrientationEntry.setVisible(state);
261 	myKeyEntry.resetView();
262 }
263 
264 
createKeyBindingsTab()265 void ReadingOptionsDialog::createKeyBindingsTab() {
266 	ZLDialogContent &dialogTab = dialog().createTab(ZLResourceKey("Keys"));
267 	FBReader &fbreader = FBReader::Instance();
268 	if (ZLBooleanOption(ZLCategoryKey::EMPTY, ZLOption::PLATFORM_GROUP, ZLOption::FULL_KEYBOARD_CONTROL, false).value()) {
269 		dialogTab.addOption(ZLResourceKey("grabSystemKeys"), new KeyboardControlEntry());
270 	}
271 	ZLResourceKey actionKey("action");
272 	ZLResourceKey separateKey("separate");
273 	ZLResourceKey orientationKey("orientation");
274 	MultiKeyOptionEntry *keyEntry = new MultiKeyOptionEntry(dialogTab.resource(actionKey));
275 	OrientationEntry *orientationEntry = new OrientationEntry(*keyEntry, dialogTab.resource(orientationKey));
276 	ZLBooleanOptionEntry *useSeparateBindingsEntry = new UseSeparateOptionsEntry(*keyEntry, *orientationEntry);
277 	dialogTab.addOption(separateKey, useSeparateBindingsEntry);
278 	dialogTab.addOption(orientationKey, orientationEntry);
279 	dialogTab.addOption("", "", keyEntry);
280 	ZLOptionEntry *exitOnCancelEntry = new ZLSimpleBooleanOptionEntry(fbreader.QuitOnCancelOption);
281 	keyEntry->setExitOnCancelEntry(exitOnCancelEntry);
282 	dialogTab.addOption(ZLResourceKey("quitOnCancel"), exitOnCancelEntry);
283 	exitOnCancelEntry->setVisible(false);
284 	useSeparateBindingsEntry->onStateChanged(useSeparateBindingsEntry->initialState());
285 	dialogTab.addOption(ZLResourceKey("keyDelay"), new ZLSimpleSpinOptionEntry(fbreader.KeyDelayOption, 50));
286 }
287