Compare commits

...

1046 Commits

Author SHA1 Message Date
Tigran Aivazian a4fa231b00 Merge pull request #631 from chrox/cacheclaim
cleanup: use current_memsize instead of counting cache sizes
12 years ago
Tigran Aivazian 74741a7a8f Merge pull request #630 from chrox/koptconfig-default
add koptconfig defaults in defaults.lua and some cleanups
12 years ago
chrox 31a61a995b add koptconfig defaults in defaults.lua 12 years ago
chrox 10b4804d2e cleanup: use current_memsize instead of counting cache sizes 12 years ago
Tigran Aivazian 328a1a853f Merge pull request #627 from chrox/kopt-writecache
bugfix: write cache before new reflows && fix memory leak
12 years ago
{Qingping,Dave} Hou f41d56d397 Merge pull request #626 from chrox/kopt-cache
bugfix: calculate current cache size and free oldest cache if needed
12 years ago
chrox 1b1b0e423f bugfix: destroying attr objects immediately after pthread_create 12 years ago
{Qingping,Dave} Hou f27ee2f5fa Merge pull request #628 from tigran123/highlights
Fix deleting highlights via Shift-N + cleanup of battery logging.
12 years ago
{Qingping,Dave} Hou 1b95b4b874 Merge pull request #624 from tigran123/history
Re-sort Last Documents list on closing the document and remove unneeded page redraw
12 years ago
chrox f5b45aa253 bugfix: reclaim thread stack explicitly by using detached threads
Otherwise the VmData size will keep increasing in multi-threads mode.
Although the increasing VmData size doesn't mean there is enormous
memory leak, it does show that the thread stack is not handled properly
when threads exit.
12 years ago
Tigran Aivazian f047084320 Cleanups of battery logging
1. No need to pass the header through string.format()
2. Check for G_battery_logging value inside logBatteryLevel() function
to simply the code in the callers thereof.
12 years ago
Tigran Aivazian fa0c08cb56 Fix deleting highlights via Shift-N
When deleting highlights the tables pointing to a highlight's page
number and sequential number within that page must be rebuilt.
The present implementation illustrates the typical use of local
functions in Lua, i.e. for this situation the lexical scope feature of
Lua's local functions is ideally suited.
12 years ago
chrox ff267ee735 bugfix: get rid of memory leak in koptreader
Memory leak came from the master bitmap that is reused in each reflow. But the bitmap
width and height were not set to zero when bitmap was freed. When the master bitmap was
enlarged in some cases the size of the master bitmap would increase monotonically.
This patch fixes this issue by setting master bitmap width and height to zero at the
beginning of each reflow. And a memeory usage logger is added in koptreader.
12 years ago
chrox 9583a477fe bugfix: write cache before a new reflow
Reflowed bitmap should be written to cache before a new reflow is
started because all reflowing processes share the same masterinfo in
libk2pdfopt which contains the data of reflowed bitmap. If a new reflow
is started before a priviously reflowed bitmap is written, the
priviously reflowed bitmap will be corrupted which may cause
segmentation fault when it is written into cache finally.
12 years ago
chrox 0603dc8a38 bugfix: calculate current cache size and free oldest cache if needed
Cache ttl should not be decreased only when there is no free slot for
new cache but decreased when claiming new cache each time. Otherwise
caches will be freed altogether which obviously is not the purpose of
the cache system. This patch only free the oldest caches and make just
enough free slots for the new one.
12 years ago
Tigran Aivazian 4bc9f37b49 Two trivial optimizations
1. Comment out re-calculation of parameters to adjust for the case when
the user changed screen orientation, because we force portrait mode on
document close. I left a comment explaining this, so we can uncomment
this code if we choose to not force portrait mode on document close in
thefuture.
2. Don't re-sort the list if the file does not exist.
This predicts the most likely scenario, namely that the user
will choose to delete this stale history entry.
And even if he chooses NOT to delete it, placing a stale entry
to the top of the list contradicts our logic because the
non-existent file was never opened.
12 years ago
Tigran Aivazian 722ddc96f9 Redraw current page on return from highlight mode
When returning from highlight mode there is no need to :goto() to the
current page (and force dummy pre-cache) --- all that is needed is the
redraw of the current page.
12 years ago
Tigran Aivazian 6a73dad4f5 Re-sort the history list on closing document
The "Last Documents" list is re-sorted on operations that modify it,
such as deleting an entry. But opening/closing a document is also one
such operation and, therefore, requires re-sorting.
12 years ago
Tigran Aivazian 7cfc505d21 Remove unneeded redraw of the current page.
The function UniReader:showHighLight() internally handles all cases
where page redraw is necessary. Therefore, there is no need to redraw
the current page (much less to :goto() to it) on return from it.
12 years ago
{Qingping,Dave} Hou 13f67822a1 Merge pull request #622 from tigran123/ext-all
Restore full File Manager functionality to KPV
12 years ago
{Qingping,Dave} Hou c2ab146203 Merge pull request #621 from tigran123/home
Unify Home and Alt-Back commands for UniReader
12 years ago
{Qingping,Dave} Hou b74fa0e0e2 Merge pull request #620 from tigran123/delete-bookmarks-crengine
Support deleting bookmarks in crengine
12 years ago
{Qingping,Dave} Hou 7c1cf60438 Merge pull request #618 from tigran123/rotation-mode
Cleanup the forcing of portrait mode and make FileChooser work in landscape mode
12 years ago
{Qingping,Dave} Hou 5a6ffc5582 Merge pull request #617 from tigran123/bookmarks
Added InfoMessage:drawTopMsg() method
12 years ago
Tigran Aivazian 6c036b4933 Use empty string as default extension
For treating document settings it is better to use empty string ""
rather than "txt" as a default extension type.
12 years ago
Tigran Aivazian 4ae40aa1ed Don't crash on files with no extension 12 years ago
Tigran Aivazian 7d61ea20fd Don't crash in fileinfo on files with no extension
Treat a file with no extension as crengine-supported txt file.
12 years ago
Tigran Aivazian 65e9f2fed3 Restore full filemanager functionality
Prior to introduction of the reader-chooser infrastructure we had a very
useful feature of browsing (and therefore
copying/moving/deleting/renaming/creating) filesystem tree accessing
arbitrary files if the user privilege mode is set to any value higher
than BEGINNER.
This patch restores this functionality by checking the privilege levels
in readerchooser and returning CREReader for any file type if there is
no other reader associated with it (including files with no extension).
12 years ago
Tigran Aivazian bb6480e458 Bugfix: prevent crash in openFile()
The code which determines file type in openFile() is actually unused, so
it can be safely removed. Moreover, if the filename passed to openFile()
happens to have no extension then this would crash openFile(). The
reason this was not noticed before is because no such filename was
passed to openFile() ever, but will be after the next few commits that
are coming...
12 years ago
Tigran Aivazian 72e0a314fb Unify Home and Alt-Back commands for UniReader
The command handlers for Home and Alt-Back commands currently perform
exactly the same function (of closing the document) despite the help page
and even the Lua code suggesting otherwise, so it makes sense to merge
them into a single command handler.
12 years ago
Tigran Aivazian 630d3f1002 Add support for deleting bookmarks for crengine
The function CREReader:showBookMarks() can have the same logic present
also in its UniReader counterpart, except the goto has to deal with
"xpointers".
Also, I added the number of bookmarks shown in the title of bookmarks
list dialog, just like I did for UniReader:showBookMarks() previously.
12 years ago
Tigran Aivazian 7e5712946a Make bm_menu in UniReader:showBookMarks() local
We should not overwrite a global bm_menu (if it exists).
12 years ago
Tigran Aivazian f0edb9fc55 Make FileChooser:choose() work in landscape
Although we are forcing portrait mode upon closing a document and also
start up FileChooser in portrait mode, it is best to not rely on this
fact within the FileChooser itself.
Therefore, I have enhanced FileChooser:choose() method to handle both
landscape and portrait modes by removing the assumption that the global
variables G_width and G_height will maintain the value they had
upon the entry to this function.
This supercedes the fix in PR 616 which actually introduced a memory
corruption bug by using the stale values of G_height/G_width in some
contexts and refreshed value(s) in others.
12 years ago
Tigran Aivazian eb45c49fd6 Cleanup FileChooser:choose() method.
1. Remove the unnecessary parameters from FileChooser:choose() method.
2. Save frequently used expression G_width - 2*self.margin_H in a local
variable.
3. Replace the calls to fb.bb:getWidth() and fb.bb:getHeight() with the
locally saved copies of G_width and G_height respectively.
12 years ago
Tigran Aivazian f2c161d45d Cleanup the forcing of portrait mode
1. Move the setting of G_width/G_height inside the function
Screen:setRotationMode()
2. Don't call self:clearCache() twice on closing the document (once is enough).
3. Get rid of UniReader:setRotationMode() method because
Screen:setRotationMode() is enough, as there is nothing reader- or
document-specific in this function.
12 years ago
Tigran Aivazian 93a0db59a1 Added InfoMessage:drawTopMsg() method
Displaying a pop-up window for operations like adding a bookmark seems a
bit of an overkill for simple messages like "Bookmark added" or
"Bookmark already exists". Therefore, based on the suggestion by
@dracodoc I have implemented an InfoMessage:drawTopMsg() for this
purpose which just renders the text in the top left corner on a gray
background of auto-calculated appropriate width.
12 years ago
{Qingping,Dave} Hou d3b0be1bf4 Merge pull request #616 from kai771/fc_bugfix
bugfix: FileChooser crashes when closing landscape document
12 years ago
kai771 6919e40db2 bugfix: FileChooser crashes when closing landscape document
Yes, we already fixed that forcing portrait mode on KPV start, and
document close. However, this is a fix that will prevent the crash if
we don't force portrait. I'm not suggesting that we stop forcing portrait -
I think we all agreed that FileChooser in landscape mode on K3 is not
very usable. But, this might be handy on Touch or KPW (we'll see about that
later), so it should be usable should we need it. To test this, you need to
comment out self:setRotationMode(0) line in UniReader:inputLoop() in
unireader.lua, thus removing forcing of portrait on document close
.
12 years ago
Tigran Aivazian c4246b3134 Merge pull request #614 from chrox/master
bugfix: remove koptreflow.o in make clean
12 years ago
chrox 0b2a03b8fe remove koptreflow.o in make clean 12 years ago
{Qingping,Dave} Hou 7c7e2af4eb Merge pull request #613 from kai771/jumps_bugfix
bugfix: incorrectly positioned jumps
12 years ago
{Qingping,Dave} Hou d631445636 Merge pull request #612 from tigran123/droid
Use the font DroidSansFallbackFull.ttf and mkdir history and clipboard for the emu
12 years ago
Tigran Aivazian 8fd76e243f Create history and clipboard dirs for the emulator 12 years ago
kai771 c50b53b604 bugfix: incorrectly positioned jumps
1. In a document with different even/odd bbox, when jumping from odd to even
page, page would be incorrectly positioned.
2. When closing document in fit-to-content-width and 2-column-mode,
and opening it again, the page would not be positioned correctly if you
were not at the beginning of the page when closing.
12 years ago
Tigran Aivazian e7c264c576 Use the font DroidSansFallbackFull.ttf 12 years ago
Tigran Aivazian d350c6005a Merge pull request #610 from kai771/bbox_bugfix2
correction for #608. I added the line in the wrong place
12 years ago
kai771 f9be17ecad correction for #608. I added the line in the wrong place 12 years ago
Tigran Aivazian 4b197ad382 Merge pull request #607 from kai771/SS_bugfix
bugfix: Screen Saver not working if Help page is displayed
12 years ago
Tigran Aivazian bf4d548aef Merge pull request #608 from kai771/bbox_bugfix
bugfix: using bbox of previous document
12 years ago
kai771 ba90e9e97c bugfix: using bbox of previous document
If you open a document, manually set bbox, then close it and open
another one without bbox, manually set bbox of the previous bbox is
used, which is annoying. This fixes it.
12 years ago
kai771 c06f01ee21 bugfix: Screen Saver not working if Help page is displayed 12 years ago
Tigran Aivazian 8ae678ae5b Merge pull request #605 from kai771/help_bugfix
bugfix: help message too long
12 years ago
Tigran Aivazian d1b6339f63 Merge pull request #604 from kai771/overlap_bugfix2
overlap bugfixes (again)
12 years ago
kai771 c049f26b52 bugfix: help message too long 12 years ago
kai771 dc3478f1e8 links, goto, jump history, search should also reset overlap 12 years ago
kai771 326b9065de another fixes to overlap in 2 column mode (this time with fw left/right) 12 years ago
kai771 7adb096c4d overlap bugfixes (again)
1. Fixes showing overlap when it shouldn't in 2 column mode
2. number jumps (10%, 20% etc) should reset overlap
3. jumps from TOC should reset overlap
12 years ago
Tigran Aivazian 20fe6e9af9 Merge pull request #603 from chrox/k2pdfopt-v1.62
remove unused function dprintf
12 years ago
chrox 38abe95ad3 remove unused function dprintf 12 years ago
Tigran Aivazian 07ff1474a3 Merge pull request #596 from kai771/emu_rotate
Implements Kindle screen rotate on emulator and forces portrait mode on doc close
12 years ago
{Qingping,Dave} Hou a100014c47 Merge pull request #602 from chrox/k2pdfopt-v1.62
cleanup unused variables in libk2pdfopt
12 years ago
chrox e38e889e6d cleanup unused variables 12 years ago
{Qingping,Dave} Hou bafcea0d33 Merge pull request #601 from chrox/k2pdfopt-v1.62
bugfix: fixed missing words in last line
12 years ago
kai771 9f68c07b5a force portrait mode on KPV start too 12 years ago
chrox b60566bfe2 cleanup: comment out unnecessary debugs 12 years ago
chrox ffd49835af bugfix: fixed missing words in last line 12 years ago
Tigran Aivazian f3f193c69b Merge pull request #600 from chrox/k2pdfopt-v1.62
update k2pdfopt to version 1.62
12 years ago
chrox f792eeb227 cleanup: don't log reflow duration to file 12 years ago
chrox 31e4f6ba89 update k2pdfopt to version 1.62 12 years ago
Tigran Aivazian 7f3256511d Merge pull request #599 from kai771/bugfix_overlap
fixes a bug that dracodoc reported in #597. I missed it :(
12 years ago
kai771 fc604057b6 fixes a bug that dracodoc reported in #597. I missed it :( 12 years ago
kai771 eafeb2fce3 force portrait mode after closing document 12 years ago
kai771 3f6bea1220 Implements Kindle screen rotate on emulator 12 years ago
Tigran Aivazian b681967243 Merge pull request #594 from kai771/overlap_fix
Overlap on/off improvement
12 years ago
kai771 47fd08a3a3 fixes and changes suggested by tigran123 12 years ago
kai771 2382d46c66 deleted call to :inform() 12 years ago
kai771 2b5e161575 things I missed 1 12 years ago
kai771 427f1c6a10 Overlap on/off improvement
Turning off overlap was instantly visible, but turning it back on was visible only on the next view. This makes both turning on/off overlap instantly visible. Since the result of a keypress is immediately visible, I commented out the inform message, since it's not needed anymore.
12 years ago
Tigran Aivazian ccea393775 Merge pull request #593 from kai771/shift-s_bugfix
bugfix: bottom of bbox should be respected in fit-to-content-width mode
12 years ago
kai771 4c3f9fdeb7 bugfix: bottom of bbox should be respected in fit-to-content-width mode 12 years ago
Tigran Aivazian 4dc1d479bc Merge pull request #590 from tigran123/inform2
Cleanup InfoMessage:inform() API and its usage
12 years ago
Tigran Aivazian 609089629c Cleanup InfoMessage:inform() API and its usage
This patch changes the second argument of InfoMessage:inform() function
to be either DINFO_DELAY or DINFO_NODELAY with the following
semantics:

DINFO_DELAY - display the message and delay DINFO_DELAY ms before
returning. Save and restore the screen content.

DINFO_NODELAY - display the message and return immediately without
saving/restoring the screen content.

Also, tidy up the call to modBBox() from Shift-X command handler, it
should be unireader:modBBox() and not self:modBBox(unireader) --- there
is no need to pass the reader object to the :modBBox() method.
12 years ago
Tigran Aivazian 81b3da5bd8 Merge pull request #588 from chrox/modbbox-method
refactoring: move function in "Shift+X" command into the modBBox method
12 years ago
Tigran Aivazian e6559f158e Merge pull request #589 from chrox/kopt-reflowlog
add function to log page reflow duration
12 years ago
chrox 2d0659f33a add function to log page reflow duration 12 years ago
chrox 974a6dd066 refactoring: move function in "Shift+X" command into the modBBox method
So that other modules like koptconfig could reuse the code to have the
fuctionality of modifying the page bbox.
12 years ago
Tigran Aivazian d7d718fc53 Merge pull request #586 from chrox/master
bugfix: change the default word spacing for koptreader
12 years ago
chrox 3945ab232b bugfix: change the default word spacing for koptreader
Because in most Chinese docs there is very small spacing between
characters compared to the word spacing in English docs. The previous
default is ideal for English documents but is too large for
Chinese docs so that it will be impossible to read reflowed
Chinese pages without changing in to a smaller value. I decrease the
default value a little in this patch so that both English and Chinese
documents will have a satisfatory reflow by default although it's better
to switch it to large for English doc and change it to small for Chinese
doc.
12 years ago
Tigran Aivazian 95be75c87e Merge pull request #585 from tigran123/fast1
Bugfix: toggle popup windows don't disappear
12 years ago
Tigran Aivazian fd0120ad69 Bugfix: toggle popup windows don't disappear
Thanks to kai771's idea of setting the value of DINFO_TIMEOUT_FAST=1
(in defaults.lua) we can still have the same behaviour of calls to
InfoMessage:inform(..DINFO_TIMEOUT_FAST..) on both the emulator and the
Kindle without the need to manually refresh the page after the call.
Also, now we don't need to set pagedirty=true in filechooser when
displaying a popup window with DINFO_TIMEOUT_FAST flag.
Also, add space to the end of the text messages passed to :inform() for
symmetry.
12 years ago
Tigran Aivazian 4e74b70b9f Revert "Bugfix: need page redraw after DINFO_TIMEOUT_FAST"
This reverts commit 3393a4a9ea5fd41d0a97cb9e6ae2ebd00b9f03b1.
12 years ago
Tigran Aivazian 3268e487f0 Bugfix: need page redraw after DINFO_TIMEOUT_FAST
I have removed the calls to self:redrawPage() recently after the calls
to InfoMessage:inform() with DINFO_TIMEOUT_FAST because on the emulator
the screen was refreshed automatically. But not so on the real Kindle
hardware --- we have to refresh the page explicitly, otherwise the popup
window stays until one forces manual refresh via Space or turns the page
(or causes a refresh by some other way, e.g. pressing Menu twice).
This patch restores those calls to self:redrawCurrentPage().
Also, it adds space to the end of some messages for symmetry and
switches Alt-Z toggle to DINFO_TIMEOUT_FAST mode as well.
12 years ago
Tigran Aivazian 8aa7530782 Merge pull request #583 from chrox/kopt-threads
bugfix: wait only when the bgthread is running
12 years ago
Tigran Aivazian ca12b469dc Merge pull request #580 from kai771/zip_in_pdfreader
Adds zip ext to PDFReader and makes extensions accesible through defaults.lua
12 years ago
kai771 5a3eca91d2 moved comment about pdb from readerchooser.lua to defaults.lua 12 years ago
chrox 8d0a6f6ee2 bugfix: wait only when the bgthread is running
When the bgthread has finished, do the fgthread's reflow.
12 years ago
kai771 01331ed4d1 explicitly require defaults in readerchooser.lua 12 years ago
kai771 b14d79d225 Adds zip ext to PDFReader and makes extensions accesible through defaults.lua
A lot of manga comes as .zip, and not .cbz (for all intents and purposes, it
is the same thing, just the extension is different). This allows the user to
choose the reader to open her zip files - PDFReader or CREReader, in the same
way she can choose to use PDFReader or PDFReflow for pdf files. I also moved
the list of supported extensions to defaults.lua.
12 years ago
Tigran Aivazian af463cd993 Merge pull request #578 from tigran123/goto-page
Optimize UniReader:redrawCurrentPage()
12 years ago
Tigran Aivazian 3fd89106bd Merge pull request #577 from tigran123/link-jumps
Add any link jump to the history.
12 years ago
Tigran Aivazian f3c5670016 Merge pull request #571 from tigran123/bbox-fix
Don't slow down :inform() when modifying bbox (and other very minor fixes)
12 years ago
Tigran Aivazian 348a496f8c Merge pull request #579 from chrox/kopt-threads
bugfix: save one reflow when switching between multi-threads on and off
12 years ago
chrox 5ca6c8728c cleanup: change drawToCache method name to writeToCache
It will be more reasonable to fit in the read(reflow) - write(cache) -
draw(blit) system.
12 years ago
chrox 7faeece952 bugfix: save one reflow when switching between multi-threads on and off
The multi_threads variable should be excluded from the hash as cache
from the multi-threads procedure is valid for non-multi-threads
procedure and vice versa.
12 years ago
Tigran Aivazian 96da77ba96 Make the code more compact. 12 years ago
Tigran Aivazian edb2a1f678 Optimize UniReader:redrawCurrentPage()
1. There is no need to call the :goto() method which does the extra work
of adding to jump history and (most importantly) pre-caching, which is
not relevant for the simple task of redrawing the current page.
2. The page goto "G" function can now be optimized to avoid pre-caching if
the page has not actually changed.
12 years ago
Tigran Aivazian 12e713b285 Add any link jump to the history.
Previously, if you follow a local link in the PDF file which points to a
place only one page away from the current page and then press Back it
will bring you to some random location (depending on the previous jump
history). But normally you would expect to be returned to the link's
location, regardless of its distance from the target page. This commit
fixes this problem, also raised as an issue 575.
12 years ago
Tigran Aivazian b67dcf8668 Don't slow down "Opening document..." on emulator
If we try to slow down this message then on the emulator we would need
to press an extra key when opening the file via "Last file" mode
(corresponding to Shift-P-P on Kindle).
12 years ago
Tigran Aivazian 8f28fe8825 Merge pull request #574 from kai771/fcw_bugfix
bugfixes for fit-to-content-width zoom mode for documents with pages of ...
12 years ago
kai771 77558cadd7 G_height -> height 12 years ago
kai771 1b5075ba51 clean-up 12 years ago
kai771 0f945dd9cd bugfixes for fit-to-content-width zoom mode for documents with pages of different size 12 years ago
Tigran Aivazian d87c3050fb More accurate wording in the comments. 12 years ago
Tigran Aivazian b0f4614308 Merge pull request #570 from chrox/kopt-threads
add multi-threaded precache in koptreaders
12 years ago
Tigran Aivazian 56d29d5588 Don't slow down :inform() when modifying bbox. 12 years ago
chrox cd21b9f041 bugfix: sorry. I forgot to change the configurable defaluts. 12 years ago
chrox c95b2a1dc5 disable multi-threaded precache by default 12 years ago
chrox 262acbed09 bigfix: fix screen freeze when changing from threaded mode
to non-threaded mode.
12 years ago
chrox 49d4b5ff1e inform the user when turning page while bgthread has not finished yet 12 years ago
chrox 0ef75c65f0 change default max columns to 2 12 years ago
chrox 9594895b26 add options to disable multi-thread precache 12 years ago
Tigran Aivazian f549450898 Use tabs to indent. 12 years ago
Tigran Aivazian 7d52e65828 Don't slow down :inform() when modifying bbox.
1. We shouldn't delay the calls to :inform() when modifying bbox
(Shift-X) on the emulator. Otherwise, the popup window will disappear
after a very short delay.
2. Document the 'msec' parameter of :inform() method in the comments
above it in dialog.lua.
3. Get rid of some of the "polite" alternative voice messages in cases
where the default one will do perfectly.
4. Get rid of the useless "Scanning folder..." message as this operation
is fast enough to not deserve any such message.
5. Explain the reason why a directory cannot be deleted instead of just
stating this as a fact. (and get rid of those exclamation marks, no need
for shouting, the world is a noisy enough place as it is :)
12 years ago
chrox 5022609bc2 save one page reflow in occasional cases
when the page reflow is not finished from the bgthread but the main
thread ask to draw the page immediately. We will stay here to wait for
the bgthread.
12 years ago
chrox f2835d7a86 add precache and bmp src in koptcontext 12 years ago
chrox 1d018ee5bf add multi-threaded precache
Because the lua reader is single threaded on which both user inputloop
and background page rendering is processed. Although there is a pretty
good precache system to save user's time spending on waiting for the
rendering when going to the next page, user input is indeed blocked when
running the precache thing. The situation is even worse in koptreader as
reflowing on page would usually take several second, in this period
users cannot move to the next page view even it's already in the cache.
This patch will let precache run in the background in a seperate thread
so that the koptreader is still responsive when precaching the next
page. Now it only just works. Welcome to find out bugs in it.
12 years ago
Tigran Aivazian 756bab8a9c Merge pull request #568 from kai771/info_timeout3
speeds up info messages of toggles etc. in emulator
12 years ago
kai771 ea98061c61 speeds up info messages of toggles etc. in emulator 12 years ago
{Qingping,Dave} Hou 38e75c230e Merge pull request #566 from tigran123/libjpeg
Bugfix: link with the static libjpeg.a from mupdf/thirdparty
12 years ago
{Qingping,Dave} Hou 82221fa420 Merge pull request #565 from tigran123/tts
Tidy up TTS
12 years ago
Tigran Aivazian d1a72f6f95 Merge pull request #567 from kai771/info_timeout2
info_timeout2 - fixes issues reported by tigran123 in #560
12 years ago
kai771 c12a02f236 DINFO_TIMEOUT_SLOW set to 1500 12 years ago
kai771 9c6ad7387a info_timeout2 - fixes issues reported by tigran123 in #560 12 years ago
Tigran Aivazian d2cde652b7 Bugfix: link with the static libjpeg.a
We should explicitly link with the libjpeg.a from mupdf/thirdparty and not with the
shared libjpeg.so that may happen to be installed on the system.
12 years ago
Tigran Aivazian a81fe952fd Tidy up TTS
1. Describe the 'message_importance' parameter correctly in the comments
above :inform() function.
2. Use more appropriate menu titles for event notification dialog.
3. bugfix: save/restore configured event notifications methods in the
settings.
12 years ago
Tigran Aivazian 4514e828b5 Merge pull request #564 from chrox/kopt-manbbox
bugfix: reflowed page should be at the top of the screen
12 years ago
chrox 6df1a05264 bugfix: reflowed page should be at the top of the screen
when reflowed page has a height less than screen height. This bug was
initially found by @tigran123 in #452. I'm sorry that I didn't fix it
until now.
12 years ago
Tigran Aivazian a209ed3549 Merge pull request #562 from chrox/kopt-manbbox
bugfix: update cur_bbox with correct page number when doing precache
12 years ago
Tigran Aivazian 20e0d3aef1 Merge pull request #563 from kai771/comics_overlap2
enable overlap in comics mode 2
12 years ago
kai771 c13fe3c517 Remove unneeded page redraws by tigran123 12 years ago
chrox f4eb9e7982 bugfix: update cur_bbox with correct page number when doing precache
Otherwise with the wrong pagehash the precache will be invalid and page
need to be reflowed twice.
12 years ago
kai771 12974cffbe enable overlap in comics_mode 12 years ago
Tigran Aivazian b949cec1aa Merge pull request #559 from chrox/kopt-manbbox
add bbox modification inside of koptreader
12 years ago
Tigran Aivazian 8374aff5b7 Merge pull request #560 from kai771/info_timeout
Info_timeout in emulator and defaults.lua clean-up
12 years ago
chrox fc3ba20ab7 change default white margin size to 0 12 years ago
kai771 39eb6e5e29 Info_timeout in emulator and defaults.lua clean-up 12 years ago
chrox ad19673bd7 add bbox modification inside of koptreader
The modification code is copied directly from unireader as I haven't
find a more elegant way yet.
12 years ago
Dobrica Pavlinušić 2a7912aa05 Merge pull request #558 from kai771/bugfix1
Fixes bugs with viewport mode reported by tigran123 in #555
12 years ago
kai771 9e9ffab969 Fixes bugs with viewport mode reported by tigran123 in #555 12 years ago
Tigran Aivazian 6a53c2f864 Merge pull request #556 from chrox/koptreader-bbox
feature: add bbox support in koptreader
12 years ago
Tigran Aivazian e8750d641a Merge pull request #557 from chrox/master
bugfix: readerchooser dialog should not be visible when opening a file
12 years ago
chrox 31f384255c bugfix: readerchooser dialog should not be visible when opening a file
when select a reader to open a document the readerchooser dialog is
overlayed with opening file notification window. The overlayed three
windows(file chooser, reader chooser and notification window) will make
users feel unconfortable easpecially when opening in koptreader which
usually freezes the screen for several seconds.

With this patch the reader chooser dialog is closed before the opening
file noticifation is shown up.
12 years ago
Dobrica Pavlinušić 22b3e9749c Merge pull request #555 from kai771/page_mode
Implements page mode as a toggle
12 years ago
chrox 0f8b56b795 use -O3 option in compiling libk2pdfopt
Probably we should use fomit-frame-pointer explicitly even though
fomit-frame-pointer is included by default with -O2 and -O3 just like
the Linux kernel guys doing. I found append -O3 directly to `CFLAGES`
will do the trick. So I removed the KOPT_CFLAGS variable.
12 years ago
chrox 68a0f34a19 add -fno-finite-math-only in KOPT_CFLAGS
In some compilation platform if finite-math-only option is turned
on, math functions like exp and sqrt will be dynamically linked to
finite versions which cannot be located in Kindle's GLIBC. In my
toolchain the symbol __exp_finite cannot be found in GLIBC_2.4 so
gcc just use __exp_finite in GLIBC_2.15, which will cause a run time
error in Kindle saying "version GLIBC_2.15 not found"
12 years ago
chrox 0a427cc02f -fomit-frame-pointer is enabled at level -O, -O2, -O3 12 years ago
chrox 5c93a3a271 no need to mark source page 12 years ago
chrox 7a75742bab add libk2pdfopt.so.1 in customupdate 12 years ago
chrox 84aec5067b adjust gamma in k2pdfopt 12 years ago
chrox 4248194e14 use -O3 option in k2pdfopt compilation
Koptreader will gain 20% performance boost.
12 years ago
chrox f157b604c1 bugfix: no need to use crop boxes 12 years ago
chrox 9cb906f031 update libk2pdfopt 12 years ago
chrox d0878f00a9 build libk2pdfopt as a shared library 12 years ago
chrox cd9b6cc770 some UI tweaks and default changes 12 years ago
chrox 505f59fc87 Pulled update to libk2pdfopt 12 years ago
chrox 73f796a13c feature: add bbox support in koptreader
Reflow can be configured to use bbox which could remove
side comments and defects in the margin and get much better reflowed
page in some documents. Currently the bbox is only set in PDFReader or
DJVUReader reader. But eventually there will be bbox setting routines in
KOPTReader.
Thirdparty should be cleaned and refetched and remake to get
this feature in operation.
12 years ago
kai771 3293acd3a3 Implements page mode as a toggle 12 years ago
{Qingping,Dave} Hou 0b7fb32280 Merge pull request #554 from chrox/libk2pdfopt
move k2pdfopt source to submodules
12 years ago
chrox e9217caa9c include k2pdfopt header in pdf.c and djvu.c and koptcontext.h 12 years ago
chrox 0d5249e75c move k2pdfopt source to a submodule libk2pdfopt
Currently libk2pdfopt is staticly linked to kpdfview.
12 years ago
Tigran Aivazian 7ba5d4a2bb Merge pull request #553 from chrox/kopt-association
bugfix: redefine reader association policy
12 years ago
chrox 2126166233 bugfix: reader chooser dialog is shown properly
When there are reader preferences table but preference for the file type
of which the file is to be opened is not available, reader chooser
should show up.
I changed `last_reader` and `default_reader` to `reader_association` and
`reader_preferences` respectively for clearness.
12 years ago
chrox af13491b6c bugfix: redefine reader association policy
Users can still use default reader for specific type. The "Remember
this file" option will add exception to the predefined reader
preference. And exception for a document can be made with the "Alt+C"
command after opening the doc. This patch fixed the bug reported on
issue #480 by @dracodoc.
12 years ago
{Qingping,Dave} Hou 2a43323ecd Merge pull request #551 from chrox/kopt-config
bugfix: automatic preview of new configuration is disabled
12 years ago
chrox ab407c896c bugfix: automatic preview of new configuration is disabled
Configuration for koptreader doesn't take effect unless FW_PRESS
is pressed or Aa dialog is closed.
12 years ago
{Qingping,Dave} Hou 1bbd353d95 Merge pull request #549 from tigran123/batop
Make battery logging optional, disabled by default
12 years ago
{Qingping,Dave} Hou befad6bb1e Merge pull request #548 from tigran123/batopt
Allow anyone to set event notifications.
12 years ago
Tigran Aivazian 27817d66d8 Cleanup: ReturnKey and InQuotes are not methods
The functions ReturnKey() and InQuotes() are generic utility functions
and there is no reason whatsoever for them to be object methods of
FileChooser object (and in fact they are used elsewhere). We should
clearly delineate the common utility functions from object's methods
so that eventually the former could be moved to other source modules
while the latter stay close to their object's definitions.
12 years ago
Tigran Aivazian dae7b95753 Set the message timeout for battery logging to nil.
This was set to 1 second during the testing and I forgot to reset it to
nil for the commit.
12 years ago
Tigran Aivazian 15aee5f4f2 Make battery logging optional, disabled by default
The key that toggles the battery logging is ALT+KEY_DOT and it works
both in the readers and filechooser.
12 years ago
Tigran Aivazian 4bc095122c Unrestrict other TTS functions too. 12 years ago
Tigran Aivazian 60d667db63 Allow anyone to set event notifications.
1. Choosing the level of event notifications shouldn't be restricted.
2. It should sit on key E standing for "configure Event notifications"
rather than the very lengthy "change the way to Inform about events".
12 years ago
Tigran Aivazian 8c43d8226f Merge pull request #544 from chrox/koptcontext
update K2pdfopt to the latest version 1.60
12 years ago
{Qingping,Dave} Hou fd095706c4 Merge pull request #545 from tigran123/battery-log
Battery log
12 years ago
Tigran Aivazian 47fd12f3d2 Merge branch 'master' into battery-log
Conflicts:
	Makefile
12 years ago
{Qingping,Dave} Hou 1d277d3009 Merge pull request #541 from tigran123/luajit
Get rid of LD_LIBRARY_PATH, LUALIBCOMPAT and package defaults.lua
12 years ago
chrox 65bd523d4c use koptcontext to keep dozons of parameters for k2pdfopt 12 years ago
Tigran Aivazian bade79138d No need to cat crash.log on crash.
One cannot start kpdf.sh from a terminal anyway (try it and you will see
that keyboard handling doesn't work), so there is no need to cat the
content of crash.log (to a non-existent terminal) if reader.lua fails.
12 years ago
Tigran Aivazian 69d58ae6f5 Add battery level logging. 12 years ago
Tigran Aivazian 1ca3bf3592 Package defaults.lua and symlink libluajit-5.1.so
1. The file defaults.lua needs to be mentioned in LUA_FILES in order to
be packaged by "make customupdate".
2. The problem with the linker not finding libluajit-5.1.so.2 can be
fixed without specifying the shared library in the list of objects (and
static libraries), simply by making a symbolic link. No need to copy a
duplicate.
12 years ago
Tigran Aivazian 3a1e65a570 No need to set LD_LIBRARY_PATH
As we use -Wl,-rpath=$(LIBDIR)/ the RPATH is hardcoded in the kpdfview
binary and so there is no need to help the linker find our libraries.
12 years ago
Tigran Aivazian 3ca9d510e5 Merge pull request #533 from hwhw/hwhw-master
LuaJIT update (+shared library), MuPDF update
12 years ago
Tigran Aivazian 4afe0bc3be Merge pull request #537 from kai771/separate_config
separates configurable options from the code
12 years ago
kai771 84aa00bbe4 adds DBACKGROUND_COLOR to defaults 12 years ago
kai771 255aa6c761 fixes suggested by tigran123 12 years ago
kai771 57ce4b201f separates configurable options from the code 12 years ago
HW 618c218969 Fixed initialization/update of mupdf's submodules, build "release" version of build helpers 12 years ago
{Qingping,Dave} Hou 7a627836bb Merge pull request #532 from tigran123/cleanup
cleanup: one-line call to :inform() for ON/OFF
12 years ago
HW ec26c4cec1 work around luajit library name confusion 12 years ago
HW a04823528b moved luajit-2.0 and mupdf to latest version - now really 12 years ago
HW 613ccb1955 Merge remote-tracking branch 'origin/master' into hwhw-master 12 years ago
HW 5c1090866f disabled patching of libjpeg, restructured everything for mupdf subrepos 12 years ago
Tigran Aivazian e8840e6059 cleanup: one-line call to :inform() for ON/OFF 12 years ago
Tigran Aivazian aeb6248424 Merge pull request #515 from kai771/rtl_mode
implements rtl_mode
12 years ago
chrox 0e042c0ff1 change default value of render quality option 12 years ago
{Qingping,Dave} Hou 959ddad864 Merge pull request #529 from tigran123/pdfattach-author
Add "-a author" option to pdfattach utility
12 years ago
{Qingping,Dave} Hou 850db0475b Merge pull request #528 from tigran123/rotate-quiet
Rotate pages quietly and cleanup toggle calls
12 years ago
chrox 3c197ccd78 add trim page option 12 years ago
HW f2e228f17f changes due to mupdf updates (third party libraries) 12 years ago
HW 5e51dd9f86 updated mupdf to latest version 12 years ago
chrox 1e639cc97d update K2pdfopt to the latest version 1.60 12 years ago
HW eb7e15cfb2 Switched LuaJIT to shared library instead of static 12 years ago
chrox 655f2bb19b add defect size option 12 years ago
chrox 3bedc59287 add render quality option
Many users complained that the reflowing process is too slow. This is
rather a speed-quality dilemma. Trade-off can be made by decreasing the
dpi of source page. And by default quality is prefered.
12 years ago
Tigran Aivazian 504954433e Add "-a author" option
This option is useful when creating a PDF file with embedded collection
by the same author. Then one can specify the author on the command line
and it will be shown correctly instead of the email address in Amazon's
Personal Documents area.
12 years ago
Tigran Aivazian 3cf606ec81 Merge pull request #525 from houqp/master
update djvulibre target dependence for LIBDIR
12 years ago
Tigran Aivazian 108737f88e Rotate pages quietly and cleanup toggle calls
1. There is no need to inform the user about the rotation being in
progress because it never takes long enough to cause concerns.
2. Shorten the calls to InfoMessage:inform() in ON/OFF toggle
situations.
12 years ago
chrox c5ebd6c6a6 more flexible configuration dialog
Each option can be configured to show or not and the height of the
config dialog is updated accordingly. By default the page margin and
line spacing is not drawn to save dialog space. Because these two
options just make minorest differences to the view of reflowed pages and
the default medium values should work in most case. Even so users can
still change the visibility of these two options by editing this file.
12 years ago
Qingping Hou fddcc51b72 update djvulibre target dependence for LIBDIR 12 years ago
kai771 cb1b0cdfb0 enables rtl_mode for picviewer too 12 years ago
kai771 692f5ec454 sets pan_margin back to 5, and restores "+ margin" for y in setzoom 12 years ago
Dobrica Pavlinušić 5d34c16493 Merge pull request #524 from tigran123/libdir
Link against libraries in libs and libs-emu
12 years ago
Dobrica Pavlinušić 770c76c33b Merge pull request #523 from tigran123/clipboard
Mkdir clipboard at build, not runtime
12 years ago
Tigran Aivazian 4b5f3c7d4d Link against libraries in libs and libs-emu
Instead of linking against the location inside the original build tree
we should link against the copy in a single place. This makes the build
code cleaner and more compact even now and will do even more so when we
build more libraries as shared (which is what I am going to attempt
next).
12 years ago
Tigran Aivazian 60af1862ba Mkdir clipboard at build, not runtime 12 years ago
kai771 3f1c052024 Includes dpavlin's fixes from #507 and various bug fixes 12 years ago
{Qingping,Dave} Hou 7d62cad1ef Merge pull request #521 from chrox/kopt-indent
add indentation option in koptconfig
12 years ago
kai771 c83b8b3c88 changes shortcut Alt-R to U 12 years ago
kai771 424e29e7e4 changes shortcut R to Alt-R 12 years ago
chrox a8354db6ca add indentation option in koptconfig
By default the indentaion detection is enabled in K2pdfopt. This will
sometimes generate very poor reflowed page when there are sidenotes on
the page which would be treated as indentation. Disabling indentaion
detection will rescue the reflowed page from this situation.
12 years ago
{Qingping,Dave} Hou 5f00ab1f2a Merge pull request #518 from tigran123/meminfo
Add simple memory usage indicator.
12 years ago
{Qingping,Dave} Hou f0a391fd66 Merge pull request #519 from tigran123/libs-make
build: mkdir libs if does not exist
12 years ago
Tigran Aivazian a907643279 build: mkdir libs if does not exist
Since we are doing this for emulator we might as well do this for normal
build too.
12 years ago
Tigran Aivazian 694459df64 Check for failure of io.open() 12 years ago
Tigran Aivazian bef40656a6 Use file:lines() instead of io.lines(filename) API
This is due to a very strange quirk in Lua. If we use io.lines(filename)
API like this:

for line in io.lines(filename) do
  ....
  if something then break end
end

Then the file descriptor table is growing infinitely because the
descriptor is not closed on breaking out of io.lines() loop. So we have
to use the ordinary file api like this:

local file = io.open(filename, "r")
for line in file:lines() do
  ....
  if something then break end
end
file:close()

This way there is no file descriptor leak.
12 years ago
Tigran Aivazian 83fb0cd69b Add simple memory usage indicator.
The function memUsage() parses the file "/proc/self/status" and extracts
the sizes (in KB) of RSS, Data, Stack, Lib and TotalVM.
These are displayed when Menu button is pressed inside readers.
12 years ago
Dobrica Pavlinušić a4844cfba8 Merge pull request #516 from houqp/master
fix makefile for building libdjvu in emu mode
12 years ago
Qingping Hou e6d459970a build: create libs-emu dir if not found 12 years ago
{Qingping,Dave} Hou 795199d84a Merge pull request #511 from tigran123/shared-djvulibre
Build djvulibre as a shared library
12 years ago
kai771 a127ec2c47 implements rtl_mode 12 years ago
Tigran Aivazian 06f32ee5dd Build djvulibre as a shared library 12 years ago
Dobrica Pavlinušić 1f1151391d Merge pull request #505 from tigran123/page
Shorten "Page " -> "p." to give more space to the section title
12 years ago
Tigran Aivazian a4da5e8445 Give more space to the section title
1. Shorten "Page " to "p." in the bookmarks list and menu info display
to give more space to the section title that follows
2. Show the total number of pages in the Goto Page dialog, as it is
often useful to know and currently one has to press Menu to find out.
12 years ago
{Qingping,Dave} Hou 9f07996413 Merge pull request #502 from chrox/kopt-config
bugfix: don't refresh markers when page is dirty
12 years ago
{Qingping,Dave} Hou df327b9fe1 Merge pull request #501 from chrox/koptreader
bugfix: save offset_y in doc settings
12 years ago
chrox a06051932f bugfix: don't refresh markers when page is dirty
Otherwise markers will show up before other elements are drawn which is
annoying
12 years ago
Tigran Aivazian 4bea524f7c Merge pull request #500 from kai771/1pg_pdf_bugfix
Fixes a bug with tall, 1 page pdf files.
12 years ago
chrox 349d00c9b8 bugfix: avoid looping at the first page when keep pressing KEY_PGBCK 12 years ago
chrox 3c3fe9b0ef bugfix: save offset_y in doc settings
And keep offset_y at min_offset_y in next view at the last page
otherwise it will loop at the last page.
12 years ago
kai771 c64d07ff0a optimization in UniReader:nextView() as suggested by tigran123 12 years ago
kai771 969b26890e Fixes a bug with tall, 1 page pdf files. 12 years ago
Tigran Aivazian 76987355a5 Merge pull request #498 from kai771/comics_mode
Implements "comics mode"
12 years ago
kai771 aada329165 :show() optimizations, as suggested by tigran123 12 years ago
kai771 0d05db3a4b removes comics mode from koptreader, because it doesn't make sense there 12 years ago
kai771 a4322e44b9 fixes :setDefaults for other readers 12 years ago
kai771 2d09659e86 Implements "comics mode" 12 years ago
Dobrica Pavlinušić 8cc757503b Merge pull request #497 from chrox/kopt-config
save koptconfig in doc settings and disable precache in koptconfig
12 years ago
chrox 47da06a29e add screen rotation in koptconfig 12 years ago
chrox 2f0cc5b827 when changing options in koptconfig dialog precache is disabled
Once koptconfig is finished the next page is cached immediately. This
will make the configuration process more responsive.
12 years ago
chrox 389177bd51 save koptconfig in doc settings and remove previously used zoom and
gamma variables
12 years ago
Dobrica Pavlinušić c8f5009b98 Merge pull request #496 from chrox/kopt-config
More options in koptconfig dialog
12 years ago
chrox 6c46977074 add default item in auto straighten 12 years ago
chrox cc9a47daa8 add auto straighten option for scanned pages 12 years ago
chrox 7557dbe05e add column detection in koptconfig 12 years ago
chrox 138f9facf3 add font size option in koptconfig dialog 12 years ago
chrox f2d03daac4 cleanup: dst_justify is assigned according to both justification and
full_just
12 years ago
chrox ce631f4827 merge justification and full justification to one option 12 years ago
Dobrica Pavlinušić 75638663dc Merge pull request #495 from chrox/kopt-config
add more configurable options in koptconfig
12 years ago
chrox 83cc0ea24b add justification option in koptconfig dialog 12 years ago
chrox f3f5d0a920 default dst_mar in k2pdfopt should be 0.06 12 years ago
chrox f4a2b5f3a0 add page margin and text wrap and contrast option in koptconfig 12 years ago
Dobrica Pavlinušić 2621474916 Merge pull request #494 from chrox/kopt-config
some UI tweaks on koptconfig and readerchooser to accommodate DXG screen
12 years ago
chrox 496591730f align option name to right and option item to left 12 years ago
chrox 251f002ee0 use fixed width and height window to get better UI in DXG 12 years ago
chrox 472e669670 bugfix: make option names and items default to dirty at each call
Otherwise when call Koptconfig again option names and items will not be
drawn. And some variables' name are changed from 'value' to 'item' which
are consistent across this module now.
12 years ago
Dobrica Pavlinušić ac218923d3 Merge pull request #493 from chrox/kopt-config
add config dialog for koptreader
12 years ago
chrox c240f88b8d add koptconfig.lua in Makefile 12 years ago
chrox b4417c73de add config dialog for koptreader
For now only line spaceing and word spaceing are configurable with
'F'/'Aa' commands. And device size are passed to k2pdfopt in place of
the hard-coded default width and height(via @dpavlin).
12 years ago
Dobrica Pavlinušić a7b396b3b1 Merge pull request #491 from tigran123/master
fix to Makefile: extr depends on MUPDFLIBS and THIRDPARTYLIBS
12 years ago
Tigran Aivazian 84571c315c Makefile: extr depends on MUPDFLIBS/THIRDPARTYLIBS 12 years ago
Dobrica Pavlinušić 0f34ca7398 Merge pull request #490 from tigran123/cleanup
Cleanups to extr.c and pdfattach
12 years ago
Tigran Aivazian 17726663b2 Adjust the error message as well. 12 years ago
Tigran Aivazian 85a97a641b Cleanups to extr.c and pdfattach
1. In extr.c the error message should use the correct full pathname, not
the base filename.
2. In pdfattach the check for existence of input files should be
replaced with the check for read access to them.
12 years ago
Dobrica Pavlinušić b16f33f8f8 Merge pull request #488 from tigran123/pdf-extract
Extract attachments from PDF file via Alt-S
12 years ago
Tigran Aivazian 47d507c406 Escape ampersand & in the filename also.
I am amazed what stupid filenames some people come up with, instead of
abiding by old good [a-zA-Z0-9] character set and 8.3 filename length...
12 years ago
Tigran Aivazian 90376422d9 More enhancements to pdfattach
1. Emit the list of attached files first and then emit each individual
attachment one per page.
2. Use hyperlinks in the list of attached files so one can jump directly
to the file which he wants to extract.
12 years ago
Tigran Aivazian c2bc496d35 Merge pull request #489 from chrox/kopt-isolated
bugfix: isolate doc settings of koptreader from pdfreader/djvureader and feedback zoom value used by page reflow
12 years ago
Tigran Aivazian 9ad3577be8 Enhance pdfattach script
1. Set the page size to 9x12cm as appropriate for Kindle 3
2. Together with each attachment print its base filename and file size
in bytes.
3. Print the total size of all attachments (so one can estimate whether
it is safe to extract the attachments or not).
12 years ago
chrox e05366f464 bugfix: dpi should be multiplied by shrink_factor not zoom 12 years ago
Tigran Aivazian be1996d0a0 Use tabs not spaces for indenting. 12 years ago
Tigran Aivazian 3eb1e83002 Make the pdfattach utility more robust
1. Handle filenames with spaces
2. Check if pdflatex and attachfile packages are installed before trying
to use them.
3. Use a more intuitive interface "pdfattach -o file.pdf file1.djvu
[file2.djvu]..." instead of forcing the user to specify "-i" option for
every input file.
12 years ago
chrox 564f73d035 feedback zoom value used by page reflow
So that when zoom value exceed the upper limit of reflowable page size
user will notice that zoom value cannot be increased.
12 years ago
Tigran Aivazian 1264adcda1 Utility for attaching files inside PDF
This utility creates a PDF file containing specified files embedded into
it as attachments. The attachments can be extracted from the PDF file by
using extr utility.
I placed this in a separate "utils" directory to signify that this is
NOT intended to run on a Kindle (it requires pdfLaTeX to generate the
PDF file) but only on the desktop Linux workstation.
12 years ago
Tigran Aivazian 0feb47335f Handle absolute attachment pathnames
We must use only the basename part of the embedded attachment filename,
because the directories used in the path on the machine where the
attachments were created may not even exist on the machine where they
are extracted.
12 years ago
chrox 88fb136376 isolate doc settings of koptreader from pdfreader/djvureader 12 years ago
Tigran Aivazian cbada0f8ef Correct the comment.
The global variable "doc" is actually shared by ALL functions, so the
old comment was incorrect.
12 years ago
Tigran Aivazian ff96c601f1 Support for extracting attachments from PDF file
This commit adds Alt-S command which invokes the external utility "extr"
passing it the full pathname of the open PDF file and the current page
number. The utility extracts all attachments on this page (if there are
any) and saves them in the same directory as the PDF file. The file
names given to attachments are decoded from within the PDF file itself,
i.e. they are the same as the original file names of the files embedded
in the PDF.
12 years ago
Tigran Aivazian bb94c20bcf Make Space in FileChooser refresh the file list
The Space command in FileChooser should actually re-read the directory
and not just redraw the current (possibly stale) data. This is
especially useful in two situations:
1. You have extracted some attachments in the current directory
2. You wish to see the current state of the Last Documents list.
12 years ago
Tigran Aivazian 772dda7e57 Make file info more resilient
We shouldn't crash the whole KPV application just because for some
reason we can't obtain the valid unpacked size of the zip archive.
12 years ago
Dobrica Pavlinušić 6311ff40e5 Merge pull request #484 from tigran123/selectmenu-jump
Add ability to jump to any location in SelectMenu
12 years ago
Dobrica Pavlinušić cdd2eddca9 Merge pull request #483 from tigran123/selectmenu-home
Use only Back not Home to exit dialogs
12 years ago
Tigran Aivazian 47302a339a Merge pull request #485 from chrox/readerchooser
using local variable optbar_T instead of self.options_bar_T
12 years ago
chrox d870d1c905 using local variable optbar_T instead of self.options_bar_T 12 years ago
Tigran Aivazian 3305021115 Merge pull request #480 from chrox/readerchooser
add readerchooser to prompt users to select alternative readers
12 years ago
chrox 76844ec996 shorten info messages 12 years ago
chrox 5ad0805410 use PDFReflow and DJVUReflow to differentiate between KOPTReader and
PDFReader/DJVUReader
12 years ago
Tigran Aivazian d20ee50f10 Add ability to jump to any location in SelectMenu
For large SelectMenu lists (e.g. Encyclopedias/Dictionaries with huge
TOC) it is very awkward to navigate the menu one page at a time.
Therefore, this patch implements the jump to 10%,20%,... locations.
12 years ago
Tigran Aivazian 357656f79d Don't use HOME key to exit manual bbox dialog 12 years ago
chrox f48a87bfdf disable exiting readerchooser dialog with Home key 12 years ago
Tigran Aivazian c3ded9f8fe Don't use Home for exiting InputBox dialog 12 years ago
Tigran Aivazian d82e7ca4d2 Use only Back not Home to exit select menu
It is not a good idea to use the key that exits the whole application
for exiting a dialog, because accidentally pressing that key twice will
exit the application and annoy the user.
12 years ago
chrox 84971cd941 bugfix: return the first reader found 12 years ago
chrox 067be63258 add option of remembering default reader for certain file type 12 years ago
chrox c3be6ef214 Cleanup: using length operator 12 years ago
chrox 1c72becc71 reader cleanup 12 years ago
chrox 34d8c32e26 bugfix: close docsetting so that changes take effects 12 years ago
chrox 2fd933abc9 remove extension.lua and implement getReaderByType in readerchooser.lua 12 years ago
chrox e5e99e3d7f bugfix: fix inconsistency in variable name 12 years ago
chrox 46b6000cb1 bugfix: refresh cache when switching between standard reader and
koptreader
12 years ago
chrox e42403bb85 add readerchooser to prompt users to select alternative readers 12 years ago
Dobrica Pavlinušić a4e79be0b8 Merge pull request #482 from tigran123/symlink
Two bugfixes for link shortcuts
12 years ago
Dobrica Pavlinušić 9acea2e0ac Merge pull request #481 from tigran123/cleanup-part2
Bugfix: support opening the specified file again
12 years ago
Tigran Aivazian 791aee86c6 Bugfix: use the correct number of shortcuts
Instead of using the hardcoded number 30 we calculate the number of
shortcuts and store it in a variable with the proper scope.
12 years ago
Tigran Aivazian 686cad7965 Two bugfixes for link shortcuts
1. We can't use "/" shortcuts for links because KEY_SLASH key is not
present on Kindle 3 but we might want to read files on Kindle 3 with
many links on the page.

2. When I fixed "last select menu item shortcut not reachable on Kindle"
issue #467 bug I switched "/" and "Sym" positions, so the link shortcuts
code needs to be made aware of the new values.
12 years ago
Tigran Aivazian 6d018da7ca Support opening the specified file
My cleanup change broke the case of "reader.lua -d file.pdf". Fixed now.
12 years ago
Dobrica Pavlinušić d62c721bab Merge pull request #478 from tigran123/reader-cleanup
KPV Cleanup.
12 years ago
Tigran Aivazian 73057bb8bc Remove alt_getopt.lua module altogether. 12 years ago
Tigran Aivazian c8e7b638fe Comment out computationally-intensive debug code
The debug statements which do not just print something but make calls to
other functions and perform calculations should be uncommented only
during debugging.
12 years ago
Tigran Aivazian 4f2c452365 Remove unused code from reader.lua
Making the program as simple as possible is the absolutely essential
pre-requisite for the ability to add more features.
12 years ago
Tigran Aivazian 525e1bdfd9 Merge pull request #476 from chrox/master
remove unused variable reflow_mode_enable in pagehash
12 years ago
chrox e2a4a0d3b6 remove unused variable reflow_mode_enable in pagehash 12 years ago
Dobrica Pavlinušić 8bb8f7860f Merge pull request #474 from tigran123/kopt-r-switch
Alt-R command to switch between STANDARD and KOPTReader
12 years ago
Tigran Aivazian 5c165a23ab Merge pull request #471 from chrox/kopt-memleak
add page size limit in reading pdf/djvu files
12 years ago
Tigran Aivazian 2c1fbbc712 Kill debug print() 12 years ago
Tigran Aivazian 29762d02fe Cleanup: use "if x" instead of "if x == true". 12 years ago
Tigran Aivazian 9bd6a4c63a Delete Alt-R command in picviewer and crereader 12 years ago
Tigran Aivazian e97770d8ae Alt-R to switch between STANDARD and KOPTReader
Currently it closes the file and drops you back to the filemanager,
so you have to re-open it manually.
12 years ago
Dobrica Pavlinušić 1be32e99a9 Merge pull request #472 from tigran123/distclean
LuaJIT: make distclean -> make clean
12 years ago
Tigran Aivazian 08e9240f10 LuaJIT: make distclean -> make clean
Two reasons for this change:

1. The latest LuaJIT has no "distclean" target
2. The "distclean" is MUCH slower
12 years ago
chrox e0a9548975 add page size limit in reading pdf/djvu files 12 years ago
{Qingping,Dave} Hou 5c4790af0e Merge pull request #467 from tigran123/menu-shortcuts
Make the last menu item keyboard shortcut work
12 years ago
{Qingping,Dave} Hou d7b6ff45aa Merge pull request #466 from tigran123/shutup
Comment out the illustration of method selection
12 years ago
Tigran Aivazian 3b0fc4b659 Merge pull request #468 from chrox/koptreader
Bugfix: guess and update offset_y after changing globalzoom
12 years ago
chrox a6f83fb856 Bugfix: guess and update offset_y after changing globalzoom 12 years ago
Tigran Aivazian 2fe8ea12eb Make the last menu item keyboard shorcut work
On Kindle 3 the last menu item's keyboard shortcut should be "Sym" and
not "/" as there is no "/" key on Kindle 3 (but there is one on DXG).
Tested to work on both Kindle 3 and Kindle DXG (and on emulator where
"Sym" is the right Shift key).
12 years ago
Tigran Aivazian 0e6b099647 Comment out the illustration of method selection
It is especially annoying when TTS is enabled.
12 years ago
{Qingping,Dave} Hou d5f64aba91 Merge pull request #462 from tigran123/kopt-cmd
Delete "< >" command group in koptreader
12 years ago
Tigran Aivazian 5cd3cec652 Delete "< >" command group in koptreader
This command group is identical to the one created in unireader.lua, so
there is no need for it.
12 years ago
{Qingping,Dave} Hou d8de1b66b1 Merge pull request #461 from tigran123/page-indicator
Minor optimization of UniReader:drawOrCache()
12 years ago
Tigran Aivazian 1a7e805e4b Minor optimization of UniReader:drawOrCache()
Cut down one access to a global, call to C level getPages() and a
division per call to UniReader:drawOrCache() function, i.e. on each page
draw including panning.
12 years ago
{Qingping,Dave} Hou 8c0e6a53a4 Merge pull request #460 from chrox/koptreader
Koptreader: just another pdf/djvu reader with reflow support
12 years ago
chrox 6b79310bb1 add koptreader.lua file in customupdate 12 years ago
chrox f7e4a548c7 add DJVU reflow 12 years ago
chrox afd97e0d43 Testing: index field 'commands' (a nil value) bug 12 years ago
chrox 0695d9155e Testing: index field 'commands' (a nil value) bug 12 years ago
chrox a53fa980f8 Cleanup: disable showing links by default 12 years ago
Dobrica Pavlinušić b15eedeaaf Merge pull request #458 from tigran123/djvu-overlap
Bugfix: initialize show_overlap_enable flag
12 years ago
Tigran Aivazian e57730b128 Bugfix: initialize show_overlap_enable flag
We must initialize show_overlap_enable to true in
DJVUReader:setDefaults() method, otherwise it will be uninitialized on
the first open of a DjVu file (i.e. with no history file).
12 years ago
chrox f1977a470c Cleanup: pass globalzoom to reflow in dc 12 years ago
chrox 717c2aec48 Delete all 'A''D''F''Z''X''N''L' commands in reflow mode 12 years ago
chrox 46b7b23a25 Cleanup: use one line assignment 12 years ago
chrox fb53035484 add zoom in/out in reflow mode && PGBCK/PGFWD now work as expect 12 years ago
{Qingping,Dave} Hou bda58e1364 Merge pull request #455 from tigran123/pic-cleanup
Get rid of unused variable in getCacheSize()
12 years ago
Tigran Aivazian d76eb27fa3 Get rid of unused variable in getCacheSize() 12 years ago
{Qingping,Dave} Hou e97f009320 Merge pull request #451 from tigran123/cre-cmd-delete
Delete the correct command group and use correct keys in crereader
12 years ago
chrox d2dcbff4bb add pdf page reflow 12 years ago
Tigran Aivazian ffaa770434 Switch crengine to Alt-K/L keys.
I have switched unireader from Alt-Up/Down to Alt-K/L but forgot to do
the same for crengine.
12 years ago
Tigran Aivazian e0777b6ed2 Cleanup: use local variable bm. 12 years ago
Tigran Aivazian 19fa375a1e Delete the correct command group
By mistake I deleted the Alt-K/L (bookmark cycling) command group
instead of Alt-H/J (TOC cycling) group.
12 years ago
Dobrica Pavlinušić 8a902d104b Merge pull request #450 from tigran123/altm-help
Set the header for Alt-M dialog
12 years ago
Dobrica Pavlinušić 98ceb7dc60 Merge pull request #449 from tigran123/bm-cycle-cleanup
Fixes to bookmarks and TOC cycling features
12 years ago
Tigran Aivazian cd5324c141 Use Alt-H/J and Alt-K/L instead of Alt-fiveway
On Kindle (unlike the emulator) the Alt + fiveway keys don't work, so I
have substituted them with Alt-H/J and Alt-K/L.
12 years ago
Tigran Aivazian d6a8d3be73 Set the header for Alt-M dialog
I have changed the help for this but forgot to change the actual header
drawn at the top of this dialog.
12 years ago
Tigran Aivazian 9fd7e36b07 Minor cleanups to bookmarks cycle feature
1. Use local variable bm in the command handler
2. Delete the correct command group in picture viewer module
12 years ago
Dobrica Pavlinušić 85d3ec3704 Merge pull request #448 from tigran123/help-cleanup
Explain the Alt-M command better in the help.
12 years ago
Dobrica Pavlinušić b6960ce274 Merge pull request #447 from tigran123/bigger-maxrcountmax
Increase the max value of rcountmax to 200
12 years ago
Dobrica Pavlinušić 6911b0b0fe Merge pull request #445 from tigran123/readme-emu
Mention SDL/SDL-devel requirement on Fedora
12 years ago
Dobrica Pavlinušić 9d9fdf3ce2 Merge pull request #444 from tigran123/toc-cycle
Add TOC entry cycle via Alt-Left/Alt-Right keys.
12 years ago
Dobrica Pavlinušić 9fa47dcd2a Merge pull request #439 from houqp/master
add bookmark jumping feature
12 years ago
Tigran Aivazian 751eaefe05 Describe Alt-M function better. 12 years ago
Tigran Aivazian d58b9aa4e8 Increase the max value of rcountmax to 200
On user's request increasing the maximum value for the number of pages
before a full refresh to 200.
12 years ago
Tigran Aivazian 22614a4ade Explain the Alt-M command better in the help.
Since this setting affects not only the file manager but other parts of
KPV (e.g. access to TTS features) it would be better to describe it as
"set user privilege level".
12 years ago
Tigran Aivazian 2d999e8c87 Mention SDL/SDL-devel requirement on Fedora 12 years ago
Tigran Aivazian e63a6cb8fe Use MOD_ALT modifier when deleting a group 12 years ago
Tigran Aivazian 50d7594d7f Add TOC cycling via Alt-Left/Alt-Right
When pressing Alt-Left/Alt-Right keys the jump is made to the
previous/next TOC entry respectively.
The jump is NOT recorded in the jump history.
12 years ago
Tigran Aivazian ce19393d0e Make self.toc_curitem a local variable. 12 years ago
Qingping Hou 857cd74ad3 don't treat bookmark cycling as random browsing
refer to discussion in #439, in short, don't add
jump target to jump history when using bookmark
jumping feature
12 years ago
{Qingping,Dave} Hou e629ff2960 Merge pull request #443 from tigran123/readme
Update README to mention other formats than PDF.
12 years ago
Tigran Aivazian 45c0f7efb6 Update README to mention other formats than PDF.
Mention support for DjVu (djvulibre), ebooks (crengine)
and JPEG images (libjpeg).
12 years ago
Qingping Hou cfbe9456ba change bookmark jumping key binding to Alt-UP/DOWN 12 years ago
Qingping Hou b2d1302b85 remove redundant vars in bookmark jumping feature 12 years ago
Dobrica Pavlinušić 042823d56c Merge pull request #441 from tigran123/space-cmd
Fix KEY_SPACE (manual screen refresh) command.
12 years ago
Tigran Aivazian 4cc3e570e3 Fix KEY_SPACE (manual screen refresh) command.
The eInk controller will ignore screen refresh if nothing has changed on
the screen, so we have to fake a change in order for manual screen
refresh to work properly.
12 years ago
Qingping Hou 4634c8e165 remove bookmark jumping shortcut in picviewer 12 years ago
Qingping Hou a360cfbb17 add bookmark jumping shortcuts 12 years ago
Dobrica Pavlinušić 4df2eabf27 Merge pull request #437 from dpavlin/cre-bugfix
fix getCurrentPageLinks segfault on links without target
12 years ago
Dobrica Pavlinusic 5e1a6b3101 use DEBUG_CRENGINE from enviroment if available
This allows to specify DEBUG_CRENGINE=1 while compiling without editing
source code
12 years ago
Dobrica Pavlinusic 534b8dc114 fix getCurrentPageLinks segfault on links without target 12 years ago
Dobrica Pavlinušić 53b6f9b7b3 Merge pull request #436 from dpavlin/cre-bugfix
fixes and cleanup for crengine links
12 years ago
Dobrica Pavlinusic 7b6ab1a486 getSelections can be 0
This depends on visible selections and not on content of file. So if we
have search results on screen this will be more than 0, but if we don't
we won't get any link shortcuts
12 years ago
Dobrica Pavlinusic 08f2c2e2f2 use CRLog::debug instead of printf, removed unused code 12 years ago
Dobrica Pavlinušić 6ab8e21375 Merge pull request #423 from dpavlin/cre-links-cleanup
crengine link support
12 years ago
Dobrica Pavlinušić 333360af0b Merge pull request #434 from tigran123/settings-part2
Provide :setDefaults() for overriding defaults
12 years ago
Dobrica Pavlinušić 3a774380a4 Merge pull request #435 from tigran123/pic-cmd
Delete commands which make no sense for PICViewer
12 years ago
Tigran Aivazian 59cfb63ea4 Disable 10-deg rotation and history commands
At the moment PICViewer does not support rotation by arbitrary angle
(only 90 degrees), so the commands Shift-J/Shift-K should be disabled.
Also, jump history (Back/Shift-Back) commands are disabled.
12 years ago
Dobrica Pavlinusic d64a4fb7a1 remove SHift+L binding since crengine always draws links 12 years ago
Tigran Aivazian d2a350eca8 Delete commands which make no sense for PICViewer 12 years ago
Tigran Aivazian dfd12100f4 Clarify the purpose of :setDefaults() method 12 years ago
Dobrica Pavlinusic 17bf58b062 getSelections can return empty ldomXRangeList 12 years ago
Tigran Aivazian 5b2ffc7a53 Provide :setDefaults() for overriding defaults
Because we re-use the same instance of UniReader object (i.e. PDFReader,
DJVUReader, CREReader and PICViewer) we have to re-initialize the
defaults on closing the document. The clean way to do this which allows
to keep the default values in a single place is in a :setDefaults()
method which this commit provides, together with the example of usage in
DJVUReader and PICViewer.
12 years ago
Dobrica Pavlinusic e52910a81f when following links store origin location in history for back 12 years ago
Dobrica Pavlinušić 7277149edb Merge pull request #433 from tigran123/pic-cleanup
PICViewer cleanup
12 years ago
Tigran Aivazian 56946f7393 Cleanup of pic.c
1. Report the true size of the document cache (0).
2. Cut down the number of pointer dereferences in drawPage().
12 years ago
Tigran Aivazian 081172a2ae Cleanup Menu info for images.
1. Don't show document cache as there is no such thing for PICViewer
2. Show the image size (in K) in brackets next to the resolution as that
is where it logically belongs.
12 years ago
{Qingping,Dave} Hou f5d3db0341 Merge pull request #432 from tigran123/settings
Settings etc
12 years ago
Tigran Aivazian 4ff751d2f1 Remove unneeded page redraw from showToc()
This is a leftover from the days of "Retrieving TOC..." message, so it
is no longer needed.
12 years ago
Tigran Aivazian 7d53f8d34c Set show_links_enable=false by default for DjVu 12 years ago
Tigran Aivazian dc52f81ec6 Update the message in the help screen for Shift-L 12 years ago
Tigran Aivazian f5ac464369 Override some of UniReader's defaults in PICViewer
For the picture viewer we want to disable showing grey boxes on page
overlaps and underlining of the links (because there aren't any).
12 years ago
Tigran Aivazian a354d96ab8 Two bugfixes and a cleanup
1. When loading boolean settings we have to explicitly check for the
return of nil from the self.settings:readSetting() function and only
modify the default if the return value is NOT nil.

2. When closing the document we have to reset the settings to defaults,
otherwise their values are re-used on the next open.

3. The messages "Links on page ON/OFF" changed to
"Link underlines ON/OFF" because the old version gave two false
impressions: a) as if the action is pertinent only to the current page
(but in fact it is global for the entire document) and b) that we are
disabling the links whereas we are only disabling the show of underlines
under the links. The new message addresses both issues.
12 years ago
Dobrica Pavlinušić 78c9223897 Merge pull request #428 from tigran123/pic-fmt
Factor out JPEG support into a module
12 years ago
Dobrica Pavlinušić f58de262a6 Merge pull request #430 from tigran123/clipboard
Bugfix for the issue #429
12 years ago
Tigran Aivazian daeb7ae7c8 Comment out [currently] unused variables. 12 years ago
Tigran Aivazian 8953cc89f6 Bugfix for the issue #429
The function FileChooser:FullFileName() was calculating the position of
the item incorrectly, i.e. would work only on the first page in
filechooser. This would break copying/moving files to clipboard and also
renaming files from the second page and subsequent ones.
12 years ago
Tigran Aivazian aa2b21aa23 Recognize the files with ".jpeg" extension 12 years ago
Tigran Aivazian a1f9068d5b Factor out JPEG support into a module
This is to make adding support for new formats easier.
See the file pic_jpeg.h for the description of the interface that each
image format must support.
12 years ago
{Qingping,Dave} Hou b6218b30a3 Merge pull request #424 from tigran123/wrong-dotdot
Two bugfixes: issues #419 and #420
12 years ago
{Qingping,Dave} Hou 0c4f94dd19 Merge pull request #426 from tigran123/colour-jpeg
Free raw_image if it is unsupported.
12 years ago
Tigran Aivazian 2ca5c028c1 Initialize doc->image in openDocument
This is needed to protect against double free() in closeDocument().
12 years ago
Tigran Aivazian b63edfca1f Free raw_image if it is unsupported.
If the number of colour components is neither 1 nor 3 we should remember
to free the buffer holding the raw decoded image before returning the
error to Lua.
12 years ago
{Qingping,Dave} Hou 127a20146b Merge pull request #425 from tigran123/colour-jpeg
Add support for colour JPEG images.
12 years ago
Tigran Aivazian 669d84df18 Show the number of colour components via Menu. 12 years ago
Tigran Aivazian f0511ff22c Make closeDocument() re-entrant. 12 years ago
Tigran Aivazian 5823ab0c44 Slight tidy-up of the code. 12 years ago
Tigran Aivazian 2d2e2b6216 Add support for colour JPEG images.
I used the luminance match algorithm for converting RGB colour images to
grayscale as it gives the best visual results (but at the cost of speed).
12 years ago
Tigran Aivazian 4f16f1d97e Tidy up a comment to be consistent. 12 years ago
Tigran Aivazian 51b3d70165 Two bugfixes: issues #419 and #420
1. Rewritten the function FileChooser:setPath() to handle returning to
the parent directory via ".." entry correctly. Issue #419

2. Fixed the crash when moving the last file from a directory to the
clipboard via Shift-X and then pressing Shift-X on the phantom entry
that is left. Issue #420
12 years ago
Dobrica Pavlinusic 7bf9fadebe restore variable font size for link shortcut, smarter refresh 12 years ago
Dobrica Pavlinusic 3c755cbc2e added clearSelection used by crengine 12 years ago
Dobrica Pavlinusic 9d02f32b4c no *page* links 12 years ago
Dobrica Pavlinusic bbb5ec00a5 return section separate from url and fix highlight 12 years ago
Dobrica Pavlinusic 1d4dc8f280 added clearSelection 12 years ago
Dobrica Pavlinusic eb450f262f take into account just section links 12 years ago
Dobrica Pavlinusic 99cf95c96f added gotoLink 12 years ago
Dobrica Pavlinusic e8ac31e07c draw shotcuts 12 years ago
Dobrica Pavlinusic 60e01c8636 getPageLinks implementation for crengine formats 12 years ago
{Qingping,Dave} Hou 5f1ce0e82d Merge pull request #421 from tigran123/pdf-cleanup
Commented out debug-only function readable_fs().
12 years ago
Tigran Aivazian d86944cce0 Commented out debug-only function readable_fs(). 12 years ago
{Qingping,Dave} Hou b74347afae Merge pull request #418 from tigran123/shell
Force the use of bash in the Makefile.
12 years ago
{Qingping,Dave} Hou 6bb497cfae Merge pull request #415 from tigran123/git-ignore
Add git-rev file to .gitignore
12 years ago
{Qingping,Dave} Hou fe62c577b0 Merge pull request #412 from tigran123/djvu-gwidth
Use the local copy of the global G_width variable.
12 years ago
Tigran Aivazian 8ab0e7fcb8 Force the use of bash.
On some distributions (e.g. Ubuntu) the shell used for scripts is dash,
not bash and we explicitly rely on bash's features in the Makefile, so
we must guarantee that we are running with bash (not dash or anything
else).
12 years ago
Tigran Aivazian f2c17ed435 Merge pull request #416 from kai771/show_links_enable
Implements a toggle that allows enabling/disabling links underlining
12 years ago
kai771 286f7caf2d "page links" -> "page links shortcut keys" 12 years ago
Tigran Aivazian a5cd590e39 Add git-rev file. 12 years ago
kai771 bb899cfad2 Implements a toggle that allows enabling/disabling links underlining 12 years ago
Dobrica Pavlinušić cdbacebd06 Merge pull request #411 from tigran123/picviewer
Picture viewer (currently supports only grayscale JPEG files)
12 years ago
Tigran Aivazian 148d92037e Revert "Undo some of my changes to rendertext.lua"
This reverts commit edd347eb55.
12 years ago
Tigran Aivazian 98898dabda Merge branch 'master' into picviewer 12 years ago
Tigran Aivazian 2b04e5ee86 Merge pull request #414 from hwhw/hwhw-master
Fix for blitbuffer.c / boundary checking
12 years ago
HW b5bc152c3d Merge remote-tracking branch 'origin/master' into hwhw-master 12 years ago
HW 10806074b8 factored out blitting constraints check in a seperate function
the checking of the boundaries when blitting was incomplete
for the addblitToBuffer() function when compared with the
blitToBuffer() function. Factored out the redundant checking
procedure into a new function.

Should fix another bug leading to issue #401 and probably
more cases for specifying boundary boxes.
12 years ago
Dobrica Pavlinušić 31c10f09e7 Merge pull request #413 from hwhw/hwhw-master
added framework to check the involved pointers in blitbuffer operations
12 years ago
HW 4810eded5c added framework to check the involved pointers in blitbuffer operations
blitbuffer operations in 4bpp can be a nasty experience, easy to
get the pointers wrong. so a macro can check them now.
12 years ago
Tigran Aivazian 4705ec60ad Use the local copy of the global G_width variable. 12 years ago
Tigran Aivazian ba84bb56d3 Use the local copy of the global G_width variable. 12 years ago
Tigran Aivazian a68407a770 Add image info to the Menu status top bar. 12 years ago
Tigran Aivazian 13646a3d51 Support only grayscale images for now. 12 years ago
Tigran Aivazian aa3bfb8439 Add simple scaling support. 12 years ago
Tigran Aivazian afc89beb80 Merge branch 'djvu-crash' into picviewer 12 years ago
Tigran Aivazian edd347eb55 Undo some of my changes to rendertext.lua
My fixes to kerning logic check in sizeUtf8Text(), renderUtf8Text() and
renderUtf8TextWidth() functions either caused or triggered a memory
corruption easily observable with DjVu files.
Undoing these changes fixes the corruption... or does it just make it
unnoticeable? Please review these changes to find out the answer.
12 years ago
Tigran Aivazian c64da132c5 Merge pull request #387 from dpavlin/variable_link_font_size
recalculate font size for each link
12 years ago
{Qingping,Dave} Hou f4f29bb12b Merge pull request #410 from tigran123/mode-refresh
Fix for the issue #404 no page redraw after setting mode from readers.
12 years ago
{Qingping,Dave} Hou fd27ba693b Merge pull request #409 from tigran123/long-msg
Allow two decimal digits point for gamma/zoom
12 years ago
{Qingping,Dave} Hou 78301d98ff Merge pull request #408 from tigran123/crash-fix
Possible fix for the memory corruption issue #401
12 years ago
Tigran Aivazian 82831f4312 Get rid of comments showing bad practice. 12 years ago
Tigran Aivazian 832a36c624 Allow two decimal digits point for gamma/zoom
Allowing only one digit seems insufficient, especially for zoom.
12 years ago
Tigran Aivazian 1dec3def12 Fix for the memory corruption issue #401
In the function renderUtf8Text() I added a variable buffer_width which
was intended to be local but I forgot the keyword "local" in front of
it. This overwrote whatever global "buffer_width" there might be and
caused a serious memory corruption described in issue #401. Although
grepping our *.lua sources did not reveal any "buffer_width" variable I
assume that there is one elsewhere (i.e. Lua's own internal namespace is
"pollutable" by user's code) because this little change definitely does
make an awful amount of difference...
12 years ago
{Qingping,Dave} Hou 83874931f5 Merge pull request #406 from tigran123/long-msg
Restrict the value of gamma in the window message.
12 years ago
{Qingping,Dave} Hou 80bdcd6cf6 Merge pull request #397 from tigran123/djvu-validate
Validate DjVu magic string before opening.
12 years ago
Tigran Aivazian ef4d0a2ae4 Merge branch 'master' into picviewer 12 years ago
Tigran Aivazian 339bda372a Restrict the value gamma in the window message.
In order to make sure that the message is always visible we should not
show all the decimal places --- one is more than enough. Otherwise the
whole thing is invisible, often enough to be irritating...
12 years ago
Tigran Aivazian 4d1945d0de Merge pull request #405 from hwhw/hwhw-master
changed page number reading
12 years ago
HW 723362e469 changed page number reading
this is far from complete since in fact, we read page references
which follow a more complex syntax. while specifying page numbers
is one option for them, they might also specify page names. we
currently do not yet have code for this case and we will return
"-1" for all page references we can not parse.
12 years ago
Tigran Aivazian da3e336de5 Page redraw when pressing Alt-M and I in readers 12 years ago
Dobrica Pavlinušić 495a24b972 Merge pull request #398 from tigran123/showzoom
Show current zoom value when changing it.
12 years ago
Dobrica Pavlinušić 224327406c Merge pull request #399 from tigran123/djvu-zoom
Show zoom factor in DjVu info.
12 years ago
Dobrica Pavlinušić 7d5b2e6962 Merge pull request #400 from tigran123/djvu-memset
Optimize DjVu drawPage() function
12 years ago
Tigran Aivazian 4a727c8595 Optimize DjVu drawPage() function
We only need to fill the image buffer with white colour if DjVu page
rendering function did not fill it in with page data.
12 years ago
Tigran Aivazian 30415e8e3b Show zoom factor in DjVu info.
It is useful to know which zoom factor the page is shown at, right after
showing the physical dimensions of the page.
12 years ago
Tigran Aivazian 62b2261555 Show current zoom value when changing it. 12 years ago
Tigran Aivazian 55532b0cd6 Add picviewer.lua to LUA_FILES
We need to do this in order for picviewer.lua to be included when doing
"make customupdate".
12 years ago
Tigran Aivazian 0e84f27512 Fix the leftover from the old name jpg.h 12 years ago
Tigran Aivazian 8d88aa8901 Fix the "upside down mirror image" problem. 12 years ago
Tigran Aivazian 76d91a9ec4 Render grayscale images. 12 years ago
Tigran Aivazian 64b6ef4afd Validate DjVu magic string before opening.
While browsing libdjvu sources I remembered that I always validated DjVu
magic string before passing the file to djvulibre. This is because
forcing djvulibre errors on open is a bad idea --- it can lead to
very strange side effects, such as refusing to open the next (valid!)
DjVu file.
So, I have now implemented the same in KPV --- check DjVu magic string
before passing it to the proper DjVu :openDocument() method.
I timed the difference between opening with and without validation and
it was absolutely negligible (i.e. by far most of the time is spent in DjVu
document decoding anyway).
12 years ago
Tigran Aivazian b2b9f425dd Decode the JPEG's dimensions. 12 years ago
Dobrica Pavlinušić 08ef1e3666 Merge pull request #396 from tigran123/djvu-cleanup
Cleanup of getUsedBBox() function.
12 years ago
Tigran Aivazian 7177f71c55 Cleanup of getUsedBBox() function.
The function getUsedBBox() does not need to perform any operations on
the DjvuPage structure, so there is no need to obtain it from Lua.
12 years ago
Tigran Aivazian 30de5e0a23 Initial commit of picviewer. 12 years ago
Dobrica Pavlinušić fe77be4830 Merge pull request #395 from tigran123/dim-overlap
Add dim_overlap configurable
12 years ago
Tigran Aivazian 0de624a7ea Rename dim_overlap -> show_overlap_enable
The new name is more intuitive.
12 years ago
Tigran Aivazian 3dd2fba241 Merge branch 'master' into dim-overlap 12 years ago
Dobrica Pavlinušić 436d738b43 Merge pull request #394 from tigran123/dirinfo
Bugfix: count books like BOOK.PDF and BOOK.DJVU
12 years ago
Dobrica Pavlinusic d14d0ba137 use visible_links for selected link 12 years ago
Dobrica Pavlinusic 905a7e704d invert all four sides of link rectangle
this helps with huge areas (Linux Journal comes to mind) for which
is somewhat hard to figure out which shortcut corresponds to which
link area
12 years ago
Dobrica Pavlinusic 4a331ab8e8 recalculate font size for each link
This fixes problems with pages full of links where first link
is so big that rest of link shotcuts overlap on page
and size of link shortcuts under different zoom #385
12 years ago
Tigran Aivazian cd48bc4d8b Add dim_overlap configurable
On request of users (dracodoc, kai771 et al.) I have added a new command
`O` which toggles the display (via dimmed box) of the page overlap
areas. This setting is saved on a per-book basis, i.e. is specific to
the book, which is the desired behaviour as one wants dimming on some
books (math, physics, etc) but not others (fiction).
12 years ago
Dobrica Pavlinušić 5608759e0f Merge pull request #393 from tigran123/bookmark-refresh
No need for page redraw in UniReader:addBookmark()
12 years ago
Dobrica Pavlinušić 621b787a85 Merge pull request #392 from tigran123/refresh-help
Explain Shift-R function in the help better
12 years ago
Tigran Aivazian c115127e1c Bugfix: count books like BOOK.PDF and BOOK.DJVU
In the function FileInfo:getFolderContent() we need to lowercase the
extension before deciding if it is a book or not --- otherwise files
like BOOK.PDF and BOOK.DJVU are not counted as books.
12 years ago
Tigran Aivazian e06069c147 Comment out a Debug() for page jumping.
All those functions get called even if Debug() itself is a do-nothing,
so this type of Debug()s should only be uncommented when needed.
12 years ago
Tigran Aivazian a63140e9c8 Add "manual full screen refresh" on pressing Space
Overloading the function "set full screen refresh count" (Shift-R) with
forcing screen refresh is rather counter-intuitive and inconvenient in
practice, because the InputBox dialog obscures the large part of the
page and when it disappears it is not obvious whether the full page
redraw occurred or not.
Therefore, it is more convenient to have a separate function (bound to
KEY_SPACE as in KPV's filemanager, K3Chess and in most other readers)
that does the full screen refresh.
12 years ago
Tigran Aivazian aeb8bcf729 No need for page redraw in UniReader:addBookmark()
The call to self:redrawCurrentPage() in UniReader:addBookmark() comes
from the days when this function was causing a "Retrieving TOC..."
message via getTocTitleByPage()->fillToc() codepath. Now that message is
gone so we should kill the redraw as well.
12 years ago
Tigran Aivazian 33768b50a7 Explain Shift-R function in the help better
1. Explain the purpose of `Shift-R` function better in the help screen.
2. Show the range of valid values when the user presses `Shift-R`.
12 years ago
Dobrica Pavlinušić 5ce6bf87ca Merge pull request #386 from tigran123/rendertext-part2
Fix the kerning check in renderUtf8TextWidth()
12 years ago
Tigran Aivazian cb25029ddd Fix the kerning check in renderUtf8TextWidth()
This is a completion of my fixes that went into PR \#383.
In the function renderUtf8TextWidth() the check for kerning was
meaningless (always true).
12 years ago
Dobrica Pavlinušić 36486d0697 Merge pull request #383 from tigran123/rendertext
Fixes to text rendering functions and their callers.
12 years ago
Dobrica Pavlinušić 239c3bbcbc Merge pull request #384 from tigran123/show-version
Show the program version in the Help header.
12 years ago
Tigran Aivazian 7fe288ace3 No need for the local variable 'title' 12 years ago
Tigran Aivazian e9913dce40 Generate git-rev file at compile time.
The file git-rev containing the program's version should be generated at
kpdfview compile time rather than package generation time.
12 years ago
Dobrica Pavlinušić c1827b1d9a Merge pull request #381 from tigran123/selectmenu-nokerning
Don't use kerning for monospaced fonts.
12 years ago
Tigran Aivazian ba0e4460d7 Merge branch 'master' into show-version 12 years ago
Tigran Aivazian cf557bdaf8 Merge pull request #372 from dpavlin/screen_offset
Screen offset fixes
12 years ago
Tigran Aivazian 87712cf0e4 Show the program version in the Help header.
1. On startup read the file git-rev if exists and initialize a new global
G_program_version.
2. In filechooser's help page's header show the version.
This helps to easily identify what version the user is running without
asking him to cat git-rev file manually.
12 years ago
Tigran Aivazian c7b4cf71f8 Fix the kerning logic in text size/rendering.
1. Fix the functions sizeUtf8Text(), renderUtf8Text() and
renderUtf8TextWidth() to have a meaningful test whether to kern or not
(the current code is meaningless as it contains the `else` clause that is never
executed).
2. Whitespace changes to filechooser.lua
12 years ago
Dobrica Pavlinusic fea2eea7a4 create shortcuts just for visible links 12 years ago
Dobrica Pavlinusic 6ab06cb584 reset screen offsets after pre-cache
Code which tried to restore offsets didn't do anything since old and
self point to same values
12 years ago
Dobrica Pavlinusic cceae8ad0a add negative x,y checking in dimRect 12 years ago
Dobrica Pavlinusic d6bbf5d1ef paintRect should support negative x and y
without this page, highlights which land outside of page in negative
direction will core-dump reader
12 years ago
Tigran Aivazian 379cba7b68 Pass the boolean `kerning` to renderUtf8Text()
The last argument of renderUtf8Text() accepts only boolean values of
`kerning`.
12 years ago
Tigran Aivazian ea92f8c1fc Don't use kerning for monospaced fonts.
If you happened to have a word like "HISTORY" in the book's TOC you will know
how ugly it looks when kerning is enabled. Since we use monospaced font
(by default) for selectmenu, it makes sense to disable kerning for the
actual items (but leave it on for shortcuts and "..." etc).
12 years ago
Dobrica Pavlinušić 1ced4ceb17 Merge pull request #376 from tigran123/nupogodi-inform
Switch to new InfoMessage API (from NuPogodi).
12 years ago
{Qingping,Dave} Hou d916c55a87 Merge pull request #380 from tigran123/master
TTS in EMU and PDF/DjVu info cleanup.
12 years ago
Tigran Aivazian e541a378a2 Flush the time/battery info to the right for PDF
Do the same for PDF that I have done for DjVu, to be consistent.
12 years ago
Tigran Aivazian ca5be5c0e6 Merge branch 'djvu-info' 12 years ago
Tigran Aivazian 4945994516 Flush the date/time and battery info to the right.
Because it looks nicer that way.
12 years ago
Tigran Aivazian 1dccc29c7d Show the current rendering mode in DjVu info
Although the current rendering mode can also be ascertained by pressing
"R" and noting the current position in the menu, it is convenient to
show it alongside the page type in the Menu status info.
12 years ago
Tigran Aivazian 5eeda016a9 Mention patch in the pre-requisites for building.
On FC17 patch(1) command is not installed by default.
12 years ago
Tigran Aivazian 683ec7570c Enable TTS for the emulator.
On the PC in the EMU mode we can run espeak command which has the same interface as say
on Kindle.
12 years ago
{Qingping,Dave} Hou d1d6cdb056 Merge pull request #379 from tigran123/master
Use only Back (not Home) for exiting from Help screens
12 years ago
Tigran Aivazian a5032046d3 Don't use Home to exit Help page.
It is a bad idea to use too many keys for the same function and also do
this non-uniformly (i.e. not in all contexts). The info at the bottom of
Help screen says "Back to close this page", so only KEY_BACK (but not
KEY_HOME) should serve this purpose. And if the user pressed Home twice
then the whole application would exit, so using Home here is a bad idea.
12 years ago
Dobrica Pavlinušić 4716321b0a Merge pull request #377 from tigran123/nupogodi-filesearcher
Improvements to filesearcher from NuPogodi
12 years ago
NuPogodi 5a493c141f Improvements to filesearcher from NuPogodi
1. Initialize self.commands only once
2. Corrections to hotkeys: added fast jumps to item at position 0%,
10%, ... 100% by Alt+Q, W, ... P
3. Added fast jump to page entered via inputbox (by G)
4. Cleanup of function descriptions and to hotkeys.
5. Added a function deleteFoundFile(full_filename) used by KEY_DEL
handler.
12 years ago
NuPogodi 81cb3a1f25 Switch unireader.lua to new InfoMessage:inform() 12 years ago
NuPogodi 55f4c278b7 Switch to new InfoMessage API from NuPogodi.
Convert the three files crereader.lua filehistory.lua fileinfo.lua to
use the new InfoMessage:inform() API.
12 years ago
{Qingping,Dave} Hou f7040b30af Merge pull request #375 from tigran123/nupogodi
Fixed search in history with empty pattern (from NuPogodi).
12 years ago
NuPogodi 10592c68b0 Fixed search with empty pattern (from NuPogodi). 12 years ago
{Qingping,Dave} Hou 17acaa27b5 Merge pull request #374 from tigran123/djvu-menu-info
Display DjVu info in the status line.
12 years ago
Tigran Aivazian 77273a84a7 Decrease the step for gamma to 10%.
The current step of 25% forward and 20% backward is too big and does not
let us come close enough to the design value of 2.2 for most djvu files.
With 10% step we can get much closer.
12 years ago
Tigran Aivazian 057c461e7d Display DjVu info in the status line.
The DjVu info shown in the status line includes:
1. Physical page dimensions.
2. Current value of gamma and (in square brackets) the value of the
display for which the page was designed.
3. Page resolution (in dpi).
4. Page type.
For the end-user probably the most useful bit is the page type as it
helps him decide which rendering mode to choose for this page (and also
explains why he can't see anything on the page --- e.g. when rendering
some COMPOUND or PHOTO pages in B&W mode). For the developer the
physical page dimensions are also interesting as they allow to estimate
the amount of time needed for page decoding and cache efficiency.
12 years ago
Tigran Aivazian c7b82f938a First stage of improving the DjVu status info. 12 years ago
Dobrica Pavlinušić 20e4b55965 Merge pull request #371 from tigran123/master
Prevent crash when opening a stale history entry
12 years ago
Tigran Aivazian 723be220ac Tidy up the previous commit.
I didn't realize that the voice message is optional, so the last
argument can be deleted, i.e. in this case the voice message can be the
same as the text one.
12 years ago
Tigran Aivazian c13a1553f4 Prevent crash when opening stale history entry.
This fixes the issue #370 raised by dracodoc.
When the user removes or renames the book which was previously opened
and tries to open it again via (now stale) history entry we are passing
the filename of a non-existent file to the format-specific
:openDocument() method and the behaviour depends on the format. For PDF
and DjVu files it is okay --- they just return an error, but for the
crengine files (ebooks) we get a coredump.
Anyway, the proper solution is to not attempt to open a non-existent
file but give a more meaningful message (than, for example:
"ddjvu: **Unrecognized DjVu Me" for DjVu case) which informs the user
that the history entry is stale. If he has valuable data in it (such as
highlights, etc) he can save them, otherwise he can delete the history
entry there and then.
12 years ago
Dobrica Pavlinušić 48fba48206 Merge pull request #369 from tigran123/master
Small typo that wasted millions of instructions...
12 years ago
Tigran Aivazian a2970bafad Change print() to Debug for "Unknown direction!" message. 12 years ago
Tigran Aivazian 8f68227c3c Small typo that wasted millions of instructions.
Now that #define CRENGINE_DEBUG is handled correctly, all those pesky
messages from crengine are gone and so the performance of crereader
should be much better --- remember that under some circumstances
crengine generates literally THOUSANDS of debug messages per second
(e.g. when complaining about corrupt TOC nodes and there are _plenty_ of
fb2 files out there which have an invalid structure).
12 years ago
{Qingping,Dave} Hou d3c6ac816b Merge pull request #368 from tigran123/master
Kill "Retrieving TOC..." message and simplify code.
12 years ago
Tigran Aivazian f2443a7d33 Kill "Retrieving TOC..." message and simplify code.
After some consideration I believe that it is best to get rid of
"Retrieving TOC..." message altogether on the following grounds:
1. The code in unireader.lua/crereader.lua that has to deal with this
specifically can be removed.
2. The fillToc() is a data manipulation function and ought not to touch
graphical state.
3. The files for which retrieving TOC can take a long time are
_exceptionally_ rare (only two are known to me --- both are my own
editions with detailed morphological tags which require massive
hierarchical TOC for quick navigation)
4. Users are going to be confused when they press Menu for the first
time and see "Retrieving TOC..." staying on the screen until they press
Menu again.
12 years ago
{Qingping,Dave} Hou f011bdc358 Merge pull request #366 from tigran123/master
Kill getDiskSizeInfo() function and make only Back (not Home) return from Search.
12 years ago
Tigran Aivazian d1d955f3a4 Make only Back (not Home) return from Search Results.
It is best to restrict Home to only exit from the application (or
perhaps also for closing the document, though even this is doubtful) and
not use it in any other context, because otherwise pressing Home too
many times may inadvertently exit the application and annoy the user.
It is a bad practice to let user try various keys in different contexts
and hope that one of them may work.
12 years ago
Tigran Aivazian f3306d5512 Kill getDiskSizeInfo() function.
Instead of making an extra function call, packing return values in key'd
values of a table and then use two table indexing operations, just call
util.df(".") directly from FileInfo:formatDiskSizeInfo() and use its two
return values appropriately.
12 years ago
{Qingping,Dave} Hou 8308ce0218 Merge pull request #363 from NiLuJe/master
Bunch of Makefile fixes
12 years ago
{Qingping,Dave} Hou 6e9b809238 Merge pull request #364 from tigran123/master
Small fixes to "Last Documents" dialog.
12 years ago
Tigran Aivazian 8107d84e9e Cleanup crereader fonts initialization.
Don't try to register the two fonts Dingbats.cff and StandardSymL.cff
with crengine because it will reject them anyway. But we cannot simply
remove these two fonts because they are used internally by mupdf to
emulate "builtin" fonts which are mandated by Adobe PDF specification to
be present in every valid implementation.
12 years ago
Tigran Aivazian 37099d81f1 Fixes to "Last Documents" dialog.
1. Remove ".." entry as unnecessary waste of (rather limited) space.
Pressing KEY_BACK returns the user from this dialog, so there is no need
for the ".." entry.
2. Simplify FileHistory:init() function as it does not really need the
argument --- our history location is fixed and hardcoded.
3. Remove KEY_HOME quit key from history command handlers. Pressing Home
key too many times would cause the application to exit, which is
very annoying.
4. Show the number of items in the header next to "Last Documents".
12 years ago
NiLuJe fab4b29502 More comments on the whole unaligned access mess on FW 2.x. Don't even
think about setting the alignment trap to a mode that includes warn,
that simply kills the performance because of the storm of faults the
syslog gets...
12 years ago
NiLuJe 9cc3438fd2 Yep, -mno-unaligned-access is definitely needed with a GCC 4.7
ToolChain, the kernel used on FW 2.x is too old to handle unaligned
accesses properly.
12 years ago
NiLuJe 1f2b85e0de It's a spaaaaace! 12 years ago
NiLuJe aa68e5250a Quote that to avoid potential issues... 12 years ago
NiLuJe ef94d27084 We don't need you, either, in EMU... 12 years ago
NiLuJe 1606cc195d We don't need those two in EMU ;). 12 years ago
NiLuJe 566d081503 Slightly nicer fix for building mupdf's .host stuff with CFLAGS in the env. 12 years ago
NiLuJe c38c6dbea4 Add a note about -mno-unaligned-access (check my x-compile.sh script for
more details, I'll revisit this once Linaro 2012.10 comes out).
12 years ago
NiLuJe 2d5c952749 Split the backward compat stuff between CFLAGS/CXXFLAGS 12 years ago
NiLuJe bd306da170 Don't use the backward compat flags on the host. Move to a dedicated
variable, with a few comments to explain ;).
12 years ago
NiLuJe c312eaabf1 Add -fno-finite-math-only (after -ffast-math) to the ARM flags to avoid
MG 2012.03 pulling GLIBC_2.15 symbols from libm (because -ffast-math asks
for it).
I didn't see this on my own TC because it's using a much older glibc version (2.9).
12 years ago
NiLuJe 50386743ec revert the whole 'let's use ld' thing. It's useless, and might wreak
havoc on EMU builds picking up system libs instead of the bundled ones.
12 years ago
NiLuJe 29878a0a90 Make sure we're always building luajit statically, so ld doesn't pick a
shared version. Of course that explained the size difference :D.
12 years ago
NiLuJe a79d29fd17 Fix the luajit clean fix (forgot to quote *_*).
Let ld do its job when linking, don't pass the static libs as object
files (we end up with a smaller native binary).
12 years ago
NiLuJe f817437660 Mention open_noshell in the README 12 years ago
NiLuJe 36d4b5e22a Make sure we're building for the softfp float ABI, and not in Thumb.
Might fix #359
12 years ago
NiLuJe bf032e5c6a Honor toplevel settings re: CC/FLAGS when building libdjvu. Define
_GNU_SOURCE to fix build with CS/MG TC. Fixes #341
12 years ago
NiLuJe 392f29f522 Let's do a distclean, actually. Less noise in git status that way. 12 years ago
NiLuJe d4782d05e8 Don't require a cross-tc for cleanthirdparty (still confuzzled about why
luajit needs CFLAGS for a clean target, but, hey!). Fixes #357
12 years ago
Tigran Aivazian 28e9f06727 Merge pull request #360 from houqp/master
revert commit 9127d1c
12 years ago
{Qingping,Dave} Hou bfe3c605be Merge pull request #356 from tigran123/master
Various cleanups.
12 years ago
Qingping Hou 269de90598 Merge branch 'master' of github.com:hwhw/kindlepdfviewer 12 years ago
Qingping Hou 14fdb90f58 revert commit 9127d1c9a1
As NiLuJe points out, that line is not needed, clean
stage of the popen Makefile will take care of it.
12 years ago
Tigran Aivazian fe20d8a899 Tiny optimization of UniReader:goto()
Save the value of self.doc:getPages() in a local variable instead of
calling it twice (the number of pages in a document is not going to
change).
12 years ago
Tigran Aivazian 35c423328e Fix two crashes on the emulator.
When running on the emulator don't attempt to perform any of the TTS
function as this will crash the application.
12 years ago
Tigran Aivazian 4da5138bbe Merge pull request #353 from houqp/master
set full screen refresh on every page turn
12 years ago
Tigran Aivazian b5f1ec08d0 Merge pull request #355 from tigran123/master
Mention svn as a dependency.
12 years ago
Tigran Aivazian da766c09ce Mention dependency on svn as required for popen_noshell.c
When we run make fetchthirdparty it does svn co of popen-noshell
12 years ago
Qingping Hou 3623ad9afb Merge branch 'master' of github.com:hwhw/kindlepdfviewer 12 years ago
{Qingping,Dave} Hou e5a2ac4344 Merge pull request #354 from NiLuJe/master
Misc kpdf.sh fixes after #348 & #352
12 years ago
Qingping Hou 44a4e32c93 add HOSTAR for emu mode complie 12 years ago
Qingping Hou 9127d1c9a1 add popennslib to cleanthirdparty 12 years ago
NiLuJe a3be10bb96 Reimplement kpdf.sh changes from PR#348 after the PR#352 merge, and fix
customupdate to actually bundle kpdf.sh in the new location
12 years ago
Qingping Hou f37d6a647f Merge branch 'master' of github.com:hwhw/kindlepdfviewer 12 years ago
{Qingping,Dave} Hou c628100958 Merge pull request #348 from NiLuJe/input-close-fix
Fix input.closeAll & don't leave zombie lipc-wait-event processes
12 years ago
{Qingping,Dave} Hou e846f2089b Merge pull request #352 from hwhw/NuPogodi-InfoMessages
New InfoMessage Concept
12 years ago
{Qingping,Dave} Hou ab93d91056 Merge pull request #350 from dpavlin/debug_only_page_indicator
show reneding page_indicator only in debug mode
12 years ago
Qingping Hou d2a1033baf set full screen refresh on every page turn 12 years ago
NiLuJe c7fa11e7e9 Slight syntax tweak 12 years ago
NiLuJe 9acdedcaeb Forgot to revert that too, useless now :). 12 years ago
NiLuJe a2ce5dd101 Hello, tiny stupid typo! 12 years ago
NiLuJe 3c181ead77 Actually, no that's wrong, it's not the parent process, it's a fork. 12 years ago
NiLuJe 8b45833e2d Kill a bit of cruft, explain the reasonning behind the kill/traps, and
fix a potential buffering issue eating the first slider event
12 years ago
NuPogodi 00c1f2ec9c New InfoMessage Concept
Part I (still no unireader, crereader, filesearcher & fileinfo)
12 years ago
NiLuJe 7bc80277e4 Don't checkout popen_noshell twice (it reverts parts of our patch) 12 years ago
NiLuJe 4356622186 Don't patch popen-noshell twice 12 years ago
NiLuJe 9cc106995d Properly fix the luajit *FLAGS mess 12 years ago
Dobrica Pavlinusic ccff5c899d show reneding page_indicator only in debug mode
This addresses performance degradation because of two e-ink refreshes
introduced by this feature #349
12 years ago
NiLuJe ffe7be7085 Merge remote-tracking branch 'upstream/master' 12 years ago
NiLuJe 76714c453a Restore Makefiles tweaks 12 years ago
NiLuJe 4522b062cc Merge branch 'input-close-fix' 12 years ago
NiLuJe d0573049c9 Ignore untracked popen_noshell stuff 12 years ago
NiLuJe 5c76ef0f78 Fetch popen_noshell during fetchthirdparty, don't bundle it in our repo 12 years ago
Dobrica Pavlinusic 53a60495b5 use git describe to generate version
Last release had git annotate tag (added with git -a) so this is
now much better alternative to just git sha1
12 years ago
Dobrica Pavlinusic 6325183dc3 Revert "don't preCache in two column mode"
This reverts commit 4d187aad4e.
12 years ago
NiLuJe 4e861715e3 Fix a stupid typo 12 years ago
NiLuJe 3f5fe1e991 Use popen_noshell as a static lib instead of an object file. Use CHOST
instead of HOST (and allow it to be set from the env), use $(MAKE)
instead of make to allow using the jobserver properly, and remove the
dash from commands where we do care about the return code (or inhibit
errors the usual way: rm -f instead of -rm)
12 years ago
NiLuJe 8e7f4ba989 Add a small makefile to build popen_noshell as a static lib 12 years ago
NiLuJe 44f69b55cd Revert Makefile changes potentially unsuitable for upstream 12 years ago
NiLuJe 6b245b9c80 Update the standalone testcase, too. 12 years ago
NiLuJe 9fab02e33f Kill debug printf 12 years ago
NiLuJe d27f20d696 Fix input device closing, and fix lipc-wait-event handling (using
popen-noshell from http://code.google.com/p/popen-noshell/)
12 years ago
NiLuJe 1a746d6e8f Makefile tweaks for my TC 12 years ago
{Qingping,Dave} Hou 3bd8c5c9f4 Merge pull request #345 from tigran123/master
Build optimizations.
12 years ago
Tigran Aivazian 0c1eb1109e Be minimalistic wrt LDFLAGS
Passing CFLAGS and LDFLAGS to kpdfview link stage has no effect in our
particular case, so I ripped it out, leaving it only for the crengine.
12 years ago
Tigran Aivazian b6936f9dc5 Merge remote-tracking branch 'upstream/master' 12 years ago
Tigran Aivazian 13d686f438 Merge pull request #347 from dpavlin/last_globalzoom_mode_invalidation
reset last_globalzoom_mode on setglobalzoom_mode #346
12 years ago
Dobrica Pavlinusic 2fc0cb2ddd reset last_globalzoom_mode on setglobalzoom_mode #346 12 years ago
Tigran Aivazian 2fefc96b79 Enable LTO for kpdfview and crengine
Enaling link time optimizations for kpdfview binary and crengine library
causes another slight performance increase --- almost negligible (1-2ms
per page) but still noticeable by precise measurements.
12 years ago
Tigran Aivazian d2e3558add ARM-specific optimizations
Thanks to NiLuJe who pointed out that our generic -march=armv6 can be
replaced (for K2/K3/DX/DXG) with a more specific optimization:
-march=armv6j -mtune=arm1136jf-s -mfpu=vfp. This I have now done and
also passed ARM_CFLAGS value to CXXFLAGS which is then passed to
crengine build. Tested, works fine. The performance improvement is
negligible (a few ms per page, but seems to be consistently better, i.e.
not just plus/minus fluctuations).
12 years ago
Tigran Aivazian 5459cb18ae Build mupdf in release mode, not debug.
Thanks to NiLuJe who pointed out that we are building mupdf in debug
mode. Switching to "release" build reduced the size of the kpdfview
binary and did not cause any performance degradation (but no noticeable
improvement either --- the page handling times seem to be exactly the
same, i.e. fluctuating a couple of ms in both directions).
12 years ago
{Qingping,Dave} Hou 69e43d1c4d Merge pull request #343 from dpavlin/preCache
don't preCache in two column mode
12 years ago
{Qingping,Dave} Hou fcecd1425a Merge pull request #344 from tigran123/master
Restrict the values of rcountmax to the range 0 to 10.
12 years ago
Tigran Aivazian 72f669ff3c Don't allow floating point values for rcountmax
This is a better version of the previous commit, which:
a) makes the code more readable
b) disallows rcountmax values like "6.05", i.e. restricts to integers
only.
12 years ago
Tigran Aivazian 79c1dd44ca Restrict the values of rcountmax to the range 0-10
Currently the user can enter any value like -10 and it is accepted and
saved in the settings file(s).
12 years ago
Dobrica Pavlinusic 4d187aad4e don't preCache in two column mode
This also cleanups code to make it easier to follow chaning logic
a bit to generate useful Debug messages
12 years ago
Tigran Aivazian 72b064fa9a Merge remote-tracking branch 'upstream/master' 12 years ago
{Qingping,Dave} Hou a8197950d0 Merge pull request #342 from dpavlin/ZOOM_FIT_TO_CONTENT_WIDTH_PAN
ZOOM_FIT_TO_CONTENT_WIDTH_PAN pan centers page
12 years ago
Dobrica Pavlinusic 12e9930975 ZOOM_FIT_TO_CONTENT_WIDTH_PAN pan centers page
When we start panning up in fit to width mode, we shouldn't
center page vertically on screen.
12 years ago
Tigran Aivazian 051926637b Merge remote-tracking branch 'upstream/master' 12 years ago
Tigran Aivazian b4c0162a40 Merge remote-tracking branch 'upstream/master' 12 years ago
{Qingping,Dave} Hou c3b0c343c9 Merge pull request #340 from tigran123/master
Two fixes from NuPogodi
12 years ago
Tigran Aivazian 1a3371c5bf Two fixes from NuPogodi
1. ATM, the footers in selectmenu.lua & helppage.lua are left-adjusted,
these also contain the prompt for users how to call help
(selectmenu.lua) and how to go back (helppage.lua). By minor correction
to function DrawFooter() in filechooser.lua, one may readily make the
rest footers to look in a similar way.
2. When writing the code of inputbox.lua, I (NuPogodi) left the wrong
command to delete the 1st entry in the math function list
(called in calculator mode by pressing Alt-M).
12 years ago
Dobrica Pavlinušić 00bdcd7f14 Merge pull request #339 from tigran123/master
Typo: --disable-largefiles -> --disable-largefile
Optimize compilation of cre.cpp
Comment out debug printf() in pdf.c
12 years ago
Tigran Aivazian 5959c56937 Remove "-d" switch from reader.lua invocation. 12 years ago
Tigran Aivazian 24e9d77a37 Comment out debug printf() in pdf.c
The printf() about the number of links on a page is very useful, but
only for debugging. As other instances of debugging printf() in djvu.c
and pdf.c are commented out, it seemed consistent to do the same with
this one.
12 years ago
Tigran Aivazian db077b2f34 Optimize compilation of cre.cpp
1. Remove unused "-lsdtc++" from the compilation stage as no linking is
done then.
2. Add our standard CFLAGS to the compilation of cre.cpp which brings in
-O3 -march=armv6 which enables optimizations.
It seemed strange that we compile a cpp file with gcc (as opposed to
g++), but I left it as is for now.
12 years ago
Tigran Aivazian f77a201e0b Typo: --disable-largefiles -> --disable-largefile
As a result of a simple typo we were continuing to include LFS
support unnecessarily...
12 years ago
{Qingping,Dave} Hou a416e35555 Merge pull request #337 from tigran123/master
The fix for the issue #336
12 years ago
Tigran Aivazian 93e946b0a4 Undoing previous commit to crereader.lua by NuPogodi
The subject says it all (undoing accidental commit by a fellow
collaborator).
12 years ago
Dobrica Pavlinušić a6a4380d41 Merge pull request #335 from tigran123/master
Fix from NuPogodi: initialize scfont face properly.
12 years ago
NuPogodi f872473604 Replace outdated messages by InfoMessage:inform() 12 years ago
Tigran Aivazian f3b52f269c Tidy up "git status" output a bit.
Added settings.reader.lua, cr3cache, history, crash.log, .vimrc, data,
fonts to .gitignore.
12 years ago
Tigran Aivazian 90971a7bf7 Fix from NuPogodi --- initialize scfont face properly.
This fixes the bug of non-persistency of user's setting of scfont.
12 years ago
{Qingping,Dave} Hou 33bb760576 Merge pull request #332 from tigran123/master
Jump history in crereader loses the last position.
12 years ago
Tigran Aivazian 496fcc089f Merge remote-tracking branch 'upstream/master'
Conflicts:
	unireader.lua
12 years ago
Tigran Aivazian 58d19ea7fd Merge pull request #327 from dpavlin/two-column-recalculate-pan
recalculate pan offsets on page change #275
12 years ago
Dobrica Pavlinusic 7b983ee7e6 fix fiveway pan to right-bottom of previous page 12 years ago
Dobrica Pavlinusic 01a57b2fb9 recalculate pan offsets on page change
Store last globalzoom_mode in self.pan_by_page so we can restore it
to force offsets recalculation on page change

This wasn't quite enough to trigger correct re-panning for page
changes when using fiveway to move in two-column mode, issue #275

I considered adding callback to goto method and than transfering
it through function calls, but this approach (allthough very
questionable) seemed to provide simplier code.
12 years ago
Tigran Aivazian 850a777760 On pressing Back crereader loses last position
This fix makes the behaviour of Back command handler in crereader
identical with that in unireader, i.e. the last position is saved in
Jump History when pressing Back, so you can return to it by pressing
Shift-Back enough times.
Also, with this change we would need to handle the need for redrawing
the current page because the :addJump() method can force the call to
fillToc() (if TOC is not already present) and this will display
"Retrieving TOC..." message which will need clearing away.
12 years ago
Tigran Aivazian 68c95e4bb2 Merge remote-tracking branch 'dpavlin/two-column-recalculate-pan' into dpavlin-twocolumn 12 years ago
{Qingping,Dave} Hou cc1ab45b1c Merge pull request #329 from dpavlin/fit-content-pan
remember last zoom mode when panning #236
12 years ago
{Qingping,Dave} Hou 8588b08761 Merge pull request #326 from dpavlin/invertRect-negative
invertRect should handle negative x or y values
12 years ago
Dobrica Pavlinušić d4ee7f2c53 Merge pull request #328 from tigran123/master
Mixed up unireader.toc with self.toc in the command handler.
12 years ago
Dobrica Pavlinusic 7ba8d6f877 remember last zoom mode when panning #236
This tries to address issue #236 so that previous and next keys don't
change meaning when user go into panning mode by pressing fiveway.
12 years ago
Tigran Aivazian a7b22ba0d4 Mixed up unireader.toc with self.toc, sorry. 12 years ago
Dobrica Pavlinusic fe2517ecd2 recalculate pan offsets on page change
Store last globalzoom_mode in self.pan_by_page so we can restore it
to force offsets recalculation on page change

This wasn't quite enough to trigger correct re-panning for page
changes when using fiveway to move in two-column mode, issue #275

I considered adding callback to goto method and than transfering
it through function calls, but this approach (allthough very
questionable) seemed to provide simplier code.
12 years ago
Dobrica Pavlinusic c8b3a0d486 invertRect should handle negative x or y values
two-column mode combined with showing links in pdf files triggers this bug
12 years ago
Dobrica Pavlinušić 44bb4d18f2 Merge pull request #325 from tigran123/master
Various fixes.
12 years ago
Tigran Aivazian 5d82ffe984 Redraw current page if necessary on pressing Back
For PDF and DjVu files (but not for crereader) the command handler for
"Back" key can call addJump() in order to avoid losing the top of the
jump history on return. This (addJump()) can cause the TOC to be
retrieved and the message "Retrieving TOC..." to be displayed.
If this happens then we need to redraw the current page after displaying
our own "Already first jump!" message.
12 years ago
Tigran Aivazian 0987c2826e Don't crash on pressing Del in History
After deleting all the entries from History we should guard against
pressing Del to try to delete a non-existent entry.
12 years ago
Tigran Aivazian 819efb55aa Tidy up Screen:fb2bmp() function
1. Remove unused assert() around io.open of the input device. The failure
to open input device is already guarded by the "if inputf" code.
2. Remove unneeded assert() around io.open of the output device. This is
unneeded because we should not crash the whole application just because
we cannot write screen dump (e.g. because filesystem is full, etc) ---
rather we should exit gracefully.
12 years ago
Tigran Aivazian 6710aa132f Merge pull request #318 from tigran123/master
Show real time, not cpu time when making screenshots.
12 years ago
Tigran Aivazian 9e134ce976 Merge remote-tracking branch 'upstream/master' 12 years ago
Tigran Aivazian 3cdb57ccc7 Merge pull request #309 from dpavlin/pdf-links
show pdf links using L key
12 years ago
Dobrica Pavlinusic 929334c00c shortcut_offset should be added directly to shortcut_map 12 years ago
Dobrica Pavlinusic 51e2a0c13b use shortcut_map to track page links 12 years ago
Dobrica Pavlinusic 771901d56e use all shortcuts, skipping uri links 12 years ago
Tigran Aivazian a0cfcba266 Merge remote-tracking branch 'upstream/master' 12 years ago
{Qingping,Dave} Hou 3fd3ff3680 Merge pull request #319 from dpavlin/crengine-upstream
bump crengine version to cr3.0.57-15
12 years ago
Dobrica Pavlinusic a9bff12d8e version: cr3.0.57-15
This might help fix #316 since upstream has cache changes
12 years ago
Dobrica Pavlinusic d936f86f04 fix shortcuts beyond last one 12 years ago
Dobrica Pavlinusic 88828fd478 check if there is at least one page link before drawing shortcuts 12 years ago
Dobrica Pavlinusic ee7b0ca41e ignore all non-page links 12 years ago
Dobrica Pavlinusic fc22f5ed93 check if getPageLinks returned links before use 12 years ago
Tigran Aivazian df65245e70 Bug in CREReader:ZipContentExt().
Even after restoring to the previous version, this function had a slight
bug that would cause a crash on valid .zip files (e.g.
mupdf-thirdparty.zip in kindlepdfviewer make tree). The reason is
because the value of s may be not nil, but the string.match() would
return nil and so string.lower() would get nil as an argument and crash.
So, we have to guard against this carefully.
12 years ago
Tigran Aivazian bc3c3f6a38 Oops, left the pointer to emulator binary, sorry. 12 years ago
Tigran Aivazian 96ac2bef8d Simplify the calling of filechooser.
The FileChooser:choose() method returns only a single argument,
so we can get rid of the second return value in reader.lua and
simplify the code a bit.
12 years ago
Tigran Aivazian 67efe2d4ca Use util.isEmulated for screenshot. 12 years ago
Tigran Aivazian 9e3ebe9496 Show the real time, not the cpu usage spent on making screenshot. 12 years ago
Tigran Aivazian 37dc2d9530 Get rid of the compilation warning. 12 years ago
Dobrica Pavlinusic 16c5171432 removed refresh which will be called after anyway 12 years ago
Dobrica Pavlinusic 01b1f5ba66 move 30 link shortcuts around using fireway 12 years ago
Dobrica Pavlinušić 4d09763224 Merge pull request #315 from tigran123/master
Pulling bits from kpdfdjview branch (plus other fixes)
12 years ago
Dobrica Pavlinusic cc222c6525 fix DOT and SYM bindings, added ENTER 12 years ago
Tigran Aivazian 1a119660ea Display better messages on failing to open a file.
1. Usually the error messages from the :open() method are too
long (except for crereader files) and won't be shown.
So, I extract the first 30 bytes from the error message (if there is
one) and show that. But if there is no error message then just display
the generic "Error opening document ". Otherwise, as was currently the
case, the error message is present but is too long and so we get
absolutely nothing, not even a generic one. But in the Debug output we
can show the entire error message as there is no restriction on the
length.
2. Use showInfoMsgWithDelay() instead of InfoMessage:show() followed by
util.sleep().
3. Remove the dependency on keys.lua. This was needed when we were
detecting emulation by comparing the physical value of some KEY_ but now
we use util.isEmulated() so there is no need for it anymore.
12 years ago
Tigran Aivazian 416c62ca61 Tidy up debug support.
1. Make "-d" switch passed to reader.lua enable all debugging
2. Enable debugging for now (development stage) to preserve the current
behaviour. But for the production release I advise to: a) disable it by
not passing "-d" and b) redirect standard output (not just standard
error) of reader.lua to crash.log in kpdf.sh
3. Comment out debug printf()s in pdf.c
12 years ago
Tigran Aivazian 385f74222a Create static directories at build, not runtime.
Instead of calling lfs.mkdir() to create "./history" and "./screenshots"
at runtime it is easier to create them at package build time.
I hesitated whether to add "./clipboard" to this list but decided
against it as we can perhaps change current directory and then
all the code manipulating clipboard would break, so I left it as is.
12 years ago
Tigran Aivazian ba1e739543 Guard against trying to see "Unpacked size" for corrupt zip files.
Print "Invalid" in the "Unpacked" field for corrupt zip files.
More generally, the FormatSize() function returns the string "Invalid"
if whatever passed to it is not a number.
12 years ago
Tigran Aivazian b297ee2c71 Use generic FileExists()
This change should have been in the previous commit, sorry.
12 years ago
Tigran Aivazian 2fdecb7b40 Don't assert() around io.popen() and use generic FileExists(). 12 years ago
Tigran Aivazian ac46f7237f Fix a typo "Q to E" -> "Q to P" in Active Keys helppage. 12 years ago
Tigran Aivazian 504425cd89 Fix for the issue #314 introduced by a commit in #310
When I rewrote the function CREReader:ZipContentExt() I lost
the code path leading to "Error unzipping file." message.
This was now restored, plus two required changes:
1. There is no need to surround io.popen() with assert() as it
never fails, not even if the command is non-existent. Besides,
even if it did, crashing the whole viewer just because for
some reason we can't unzip the file is not a good idea.
2. The "while tmp" after tmp=assert() assignment is meaningless.
Even after removing assert() it is still meaningless because io.popen()
can never return nil, oddly enough.
12 years ago
Tigran Aivazian 864be87fc2 Tidy up BatteryLevel() function.
1. Remove assert() around io.popen() as this function never fails, even
when opening a pipe to a non-existent program.
2. Remove the second assert() as well, because it is not wise to fail the whole
application just because we don't know or cannot ascertain the battery
level.
3. Guard against the failure of gasgauge-info (e.g. on emulator where it
does not exist, so, effectively "fails") by checking what we read from
the pipe and return "?" if need be.
12 years ago
Tigran Aivazian 06a0b27664 Allow clearing both internal and document caches via Menu
Bind the key "C" in Menu to clear internal tile cache and key "D" to
clear the document cache.
12 years ago
Tigran Aivazian 16623b5b08 Cleanup of djvu.c
1. Use the proper <string.h> header.
2. Typo fixes and whitespace changes.
3. Comment out debug printf() about cache size.
4. Remove obsolete comment(s).
12 years ago
Tigran Aivazian 4b5c33d4cd Optimize building djvulibre.
1. Don't build xmltools in the emulator
2. Remove duplicate --disable-desktopfiles
3. Don't build LFS support. The largest DjVu file I have ever published
was a highres facsimile edition of the London Walton Polyglot (1657)
which was a "mere" 1GB in size and I don't think anyone produced
anything bigger. Besides, storing DjVu files >2GB in size (even if
they existed, which I doubt) on a Kindle with only 3GB total storage
space is _exceedingly_ unlikely.
12 years ago
Dobrica Pavlinušić cee63d6078 Merge pull request #313 from NuPogodi/master
removed two self:redrawCurrentPage() functions
12 years ago
NuPogodi 9403d1c120 remove self:redrawCurrentPage() in CREReader:gotoTocEntry(entry) 12 years ago
NuPogodi d542982778 remove self:redrawCurrentPage() in UniReader:addJump(pageno) 12 years ago
Dobrica Pavlinusic ac14ac4a21 show only page links 12 years ago
Dobrica Pavlinusic 8a7f2bd562 go only to page links 12 years ago
Dobrica Pavlinusic a3f5de9e7a fix size of fonts according to globalzoom
And a few of one pixel up, one pixel down adjustemts, so that all
underlines get dimmed.
12 years ago
Dobrica Pavlinusic 1916f5038b draw links on page as underline 12 years ago
{Qingping,Dave} Hou d1a4399170 Merge pull request #310 from tigran123/master
Fix a crash in getDiskSizeInfo() (in emulator) and use util.df function.
12 years ago
Tigran Aivazian 1e2429b3be Fix for the issue #311.
Children nodes that have no [apparent] parent should be adopted
by the "_HEAD" i.e. the root of the whole tree.
12 years ago
Tigran Aivazian 47b056861b Slightly shorter and more Lua-idiomatic way of reading lines. 12 years ago
Tigran Aivazian 43cbcbf319 Rewrite CREReader:ZipContentExt() function.
Technically, the only serious problem in this function was the code:
 local tmp = assert(io.popen('unzip -l \"'..fname..'\"', "r"))
 while tmp do
         s = tmp:read("*line")
         if i > 3 then tmp:close(); break; end
         i = i + 1
 end
It is meaningless to evaluate the truth of the return value of assert()
and the above code gives the impression that it relies on the
(undocumented and unreliable) fact that after tmp:close() tmp will be
nil, even though in actual fact it does because it breaks out of the
loop.
However, having looked at the function I saw that the whole thing
can be rewritten in a much simpler way:

 local tmp = assert(io.popen('unzip -l \"'..fname..'\" | head -4 | tail -1', "r"))
 s = tmp:read("*line")
 tmp:close()
12 years ago
Tigran Aivazian 6e0f0aef26 Fix a crash in getDiskSizeInfo() and use util.df function
1. When executed in the emulator the viewer will crash if you press
Right on any zip file in the filechooser. This is because the assertion
on "df /mnt/us | tail -1" will fail as "/mnt/us" is normally
non-existent.
2. The proper (faster, reliable, portable) way of obtaining the number
of total and free bytes on a filesystem is by using the statvfs(2)
system call via util.df Lua interface, see util.c.
3. Removed the "used" field in the function's return as unused and
unneeded.
12 years ago
Dobrica Pavlinusic f2eeca73aa overlay keyboard shortcuts on top of links
This is example of user interface discussed in #309
12 years ago
Dobrica Pavlinusic 2774350ec6 transform coordinates to on-screen values 12 years ago
Dobrica Pavlinusic 0828468b12 try to draw inverted rectangles over links
This commit nicely shows that we need to translate link coordinates
12 years ago
Dobrica Pavlinusic 46afa82b52 add LF to end of debug message 12 years ago
Dobrica Pavlinusic 71ff602cd5 getPageLinks implementation for mupdf #72
This is rough first draft, and provides just dump of all links
available on pdf page. Binding to Shift+L is temporary and just for
debugging!
12 years ago
Dobrica Pavlinusic e1fc748faf fix indenting to tabs 12 years ago
{Qingping,Dave} Hou 73719e7b2e Merge pull request #307 from NuPogodi/master
Added: Folder Info; fixed: crash in getUnpackedZipSize(); etc.
12 years ago
{Qingping,Dave} Hou 43b0dce322 Merge pull request #308 from dpavlin/git-rev
include git-rev in distribution zip
12 years ago
NuPogodi 6a2b0d044d filechooser: added support for calling folder info 12 years ago
NuPogodi 59c212971f fixed crash in function getUnpackedZipSize()...
applied to zips which filenames contain spaces; added support for showing information about folders (size, subfolders, files, books)
12 years ago
NuPogodi 7b7ba80f6e crereader: piping in function ZipContentExt(...)
Avoid writing/reading from/to temporary file
12 years ago
Dobrica Pavlinušić 6f0ea100ce Merge pull request #306 from tigran123/master
Don't write to temporary file on the flash device.
12 years ago
Tigran Aivazian d338eff00d Don't write to temporary file on the flash device.
Instead of writing to (and reading from) the temporary file
"history/.history.txt" create a pipe to the appropriate process
and read from it.
12 years ago
{Qingping,Dave} Hou 52d4b09d6b Merge pull request #304 from tigran123/master
TOC and crash when pressing C in Menu in crereader + Active Hotkeys in SelectMenu
12 years ago
Tigran Aivazian 2c021d9d4e Corrected the showMenu() function to belong to the right object!
UniReader -> CREReader in crereader.lua.
12 years ago
Tigran Aivazian 8b2143561e Avoid printing long messages in the SelectMenu footer.
Bind Alt-H to show the help page with all the active hotkeys.
Thanks to NuPogodi for the suggestion.
12 years ago
Tigran Aivazian de5cf52255 Merge remote-tracking branch 'upstream/master' 12 years ago
NuPogodi f7779d7c2a Merge pull request #305 from NuPogodi/master
avoid rendering infomessages with monospaced font
12 years ago
NuPogodi e621e006b9 Avoid rendering infomessages with the 'infont' used in user-inputbox (i.e. monospaced font hardly suitable for messages)
BTW, I've fixed it already the 3rd time and, let me hope, the last one.
12 years ago
Tigran Aivazian a9f4dd3b1f The second part of the TOC/crereader fix.
Redraw the current page when selecting a TOC entry.
Otherwise the correct page is shown only after the next Menu press
or anything else that does current page redraw, e.g. Shift-R.
12 years ago
Tigran Aivazian de96f30eff Prove CREReader:showMenu() method because the generic
UniReader:showMenu() method invokes :cleanCache() method which is
non-existent for CREReader object and causes a crash if you press C
after pressing Menu while viewing any of crereader-handled files (fb2,
epub, etc.)
12 years ago
Tigran Aivazian 3056bf440c Fix for TOC breakage for crengine-related files.
In UniReader:showToc() function we cannot use goto() by page number
but have to use self:gotoTocEntry() because crereader defines its own
CREReader:gotoTocEntry() method which uses "xpointer" field of the TOC
entry for this purpose.
With this fix the TOC navigation in crengine-related files works
correctly, BUT after each jump you have to press Menu to refresh the
page for some reason (adding explicit self:redrawCurrentPage() in the
code before gotoTocEntry() doesn't help). This seems to be an unrelated
problem to do with cr3 caching or something else. I will try to
investigate it as well, but for now I am committing the fix for the TOC side
of the problem.
12 years ago
Dobrica Pavlinusic 238e25e743 include git rev in distribution zip 12 years ago
Dobrica Pavlinušić 940408fc51 Merge pull request #300 from tigran123/master
Bugfix for deleting an empty directory.
12 years ago
Tigran Aivazian 6cd66a3e79 No need to set self.items after deleting a directory as it is
recalculated in self:setPath() anyway.
12 years ago
Tigran Aivazian b2f4d358ae Bugfix for deleting a directory:
After a directory is deleted it is still shown in the filemanager
list, so you can accidentally delete another directory as all the
pointers after the previously deleted entry are wrong (shifted by one).
12 years ago
{Qingping,Dave} Hou d77801d9a0 Merge pull request #299 from tigran123/master
Fix for the crash mentioned in issue #295
12 years ago
Tigran Aivazian b3f8ddf67d Be consistent with the case: "Last Read" -> "Last read". 12 years ago
Tigran Aivazian b8e29b77bc File Info tidy up:
1. Fix the "Created" field in file info to say "Status changed" as the ctime has nothing to do with creation of a file but with the time of the last modification to its inode (e.g. owner, group, link count, mode, etc.)
2. Added the field "Accessed" which shows the atime.
12 years ago
Tigran Aivazian e5c859059d Fix for the crash when deleting highlights, see issue #295. 12 years ago
{Qingping,Dave} Hou f7c0166fb2 Merge pull request #298 from tigran123/master
Report the amount of free disk space in file info.
12 years ago
Tigran Aivazian 8496ccb073 Disk free space reporting:
1. Enhance FileInfo:FileSize() to handle gigabytes and rename it to FileInfo:FormatSize() as it is not just for file sizes.
2. Add "Free space" field to file info because it is useful to see it when deciding whether to remove this file or not.
12 years ago
Tigran Aivazian 69ac04500a Indicate in the help page that "Home" is the key to be used for exiting the application. 12 years ago
{Qingping,Dave} Hou 720687648e Merge pull request #296 from tigran123/master
Simple cleanups...
12 years ago
Tigran Aivazian f11a006775 1. Fix deleting highlights when there is more than one (previously it would delete not only the current highlight but some or all of the later ones)
2. Support deleting highlights from within "show all highlights" function (Shift-N). It is much easier to delete multiple highlights than having to position the cursor on them and press Del.
3. Fix the bug whereby the first press of Menu would overlay the info on top of the book's text.
4. Show the number of bookmarks and highlights in their respective lists.
5. Fix the incorrect section title shown in Menu when the file contains TOC with external links.
6. Rename "start highlight mode" -> "enter highlight mode".
7. Rename "display all highlights" -> "show all highlights".
12 years ago
Tigran Aivazian eb002540a2 Don't crash on user pressing ENTER in empty history --- just display an appropriate message. 12 years ago
Tigran Aivazian f5f5040f20 Change "Updating HighLight data..." message to Debug() as this operation
cannot possibly hang and it conveys no useful info to the end user.
12 years ago
Tigran Aivazian d2b2d8b18f Make the info messages about highlight short enough to be visible.
Also, shorten the delay from 2s to 1s.
12 years ago
Tigran Aivazian c57c319656 When user presses BACK in the filemanager it should NOT exit the program, only HOME should do so.
Otherwise too many times one accidentally exits from KPV.
12 years ago
{Qingping,Dave} Hou 35695e2fe0 Merge pull request #293 from tigran123/master
Cleanup: use util.isEmulated() == 1 instead of looking at KEY_FW_DOWN value.
12 years ago
Tigran Aivazian 4b9cf4eaf5 Use os.remove() instead of os.execute("rm...") because it is less expensive
as it uses remove(3) C library function rather than fork/exec-ing a new process.
12 years ago
Tigran Aivazian 456136ef71 Fix the calculation of the total unpacked size of the content of a zip file when it contains multiple entries.
Also, don't write to temporary files in the physical filesystem --- use pipes instead.
12 years ago
Tigran Aivazian c43fb549d3 Avoid writing to files when obtaining the battery level --- use pipes instead. 12 years ago
Tigran Aivazian a2cb1745d6 Merge remote branch 'upstream/master' 12 years ago
Tigran Aivazian c9c89ef56d Use the proper way to detect emulation. 12 years ago
Dobrica Pavlinušić 781bab1e40 Merge pull request #291 from houqp/master
fix typo in makefile
12 years ago
Qingping Hou 5e6a0c82c9 fix typo in Makefile 12 years ago
Dobrica Pavlinušić 55bd3f1bd3 Merge pull request #290 from dpavlin/master
use README.md in distribution zip
12 years ago
Dobrica Pavlinusic 263ab789c8 use README.md in distribution zip 12 years ago
Dobrica Pavlinušić 3a8707a645 Merge pull request #288 from tigran123/master
TOC cleanup.
12 years ago
Tigran Aivazian 75bd54657b Cleanup of the TOC support code: remove unnecessary initializations. 12 years ago
Qingping Hou 1d703f9fb6 delete README.TXT 12 years ago
{Qingping,Dave} Hou 16a8b2099b Merge pull request #286 from tigran123/master
Stop writing battery info messages to crash.log every few seconds.
12 years ago
Tigran Aivazian 1694fc5b0a Stop filling up crash.log with INFO messages about battery charge every couple of seconds.
Every write to a flash device shortens its life.
12 years ago
Dobrica Pavlinušić a4260c6fc0 Merge pull request #285 from houqp/master
Update readme
12 years ago
Qingping Hou 8c994ee0bc remove leading tab in command in README 12 years ago
Qingping Hou 686a823629 rename README.TXT to README.md
for better rendering in Github
12 years ago
Qingping Hou 1b3e1db0d2 update readme 12 years ago
Qingping Hou ea325146d3 move -l argument to the end of GCC call 12 years ago
{Qingping,Dave} Hou a34696d96c Merge pull request #283 from tigran123/master
Fix for calculating TOC position.
12 years ago
Tigran Aivazian 51ccc20845 Save a few table indexing operations since we already have the page number. 12 years ago
Tigran Aivazian 56f4ac42bd Better fix for the external links in TOC problem: instead of returning
to the current page display a message "External links unsupported" and
remain in the TOC menu. The reason for this decision is that if the
user chose invalid TOC entry she is more likely to wish to stay in the
TOC menu and choose another entry rather than return to reading immediately.
12 years ago
Tigran Aivazian 680866d4ad Merge remote branch 'upstream/master' 12 years ago
Tigran Aivazian cc5abd3b87 Use the value of self.doc:getPages() stored in a local variable instead of calling it for each TOC entry. 12 years ago
Tigran Aivazian 853f34b488 Fix for calculating the current position in the case of TOC containing links to external files:
when walking the TOC we should check if the destination page is within the range of the current document.
12 years ago
Tigran Aivazian dac88587bf Fix for the case when TOC contains a link to external file: we should redraw the current page and not just quietly return from UniReader:goto(). 12 years ago
Tigran Aivazian 42d9583319 In the Search Results show the actual pattern entered, not the uppercased version thereof. 12 years ago
Tigran Aivazian 527421eb86 Make file search function completely case-insensitive. 12 years ago
Tigran Aivazian 3048311dd5 Show the number of hits in Search Results. 12 years ago
{Qingping,Dave} Hou 31fd466425 Merge pull request #281 from tigran123/master
Minor changes to djvu and filesearcher.
12 years ago
Tigran Aivazian 284ab49db4 Shorten the message to make it visible. 12 years ago
Tigran Aivazian 28ba1c7e37 1. It is customary to call DjVu context by the name of the program.
2. When changing DjVu page rendering mode there is no need to clear DjVu cache, only our own tile cache.
12 years ago
Dobrica Pavlinušić a99f429afc Merge pull request #280 from tigran123/master
Cleanup of cleanUpTocTitle()
12 years ago
Tigran Aivazian 29b1ef5dde Cleanup of expandAllTOCSubItems(). 12 years ago
Tigran Aivazian 922b53ac60 Cleanup of cleanUpTocTitle() function: (f(x)) is a more elegant way of forcing
the return of a single value than the use of a dummy variable.
12 years ago
Dobrica Pavlinušić 657bcee7d0 Merge pull request #276 from houqp/master
roll back to use DroidSansFallback as default cfont font face
12 years ago
{Qingping,Dave} Hou b96edf3693 Merge pull request #279 from tigran123/master
Calculator: make it more robust.
12 years ago
Tigran Aivazian 4f2be7a7e8 Calculator: make it more robust. Previously it was very easy to crash
the application by entering invalid input into calculator, for example
things like these: ")(", "inf/0", "f()", etc.
By using Lua pcall() function to execute not only the construction of
the expression, but also the calculation of the final result, the calculator
is made more robust and safe-guarded from such crashes.
12 years ago
Tigran Aivazian da296e2e95 Slight cleanup of the previous commit: save one arithmetical operation. 12 years ago
Tigran Aivazian b6a429a1d4 Calculator: calculate the cursor position correctly when the output contains more characters than input. 12 years ago
Tigran Aivazian dc473e85a9 Calculator: on exit from help page refresh the screen properly (i.e. fully) 12 years ago
Tigran Aivazian b0febe2d9b Calculator: don't crash when pressing Enter or FW-select buttons. 12 years ago
{Qingping,Dave} Hou 98b8399692 Merge pull request #278 from tigran123/master
Stop calculator from crashing on empty input.
12 years ago
Tigran Aivazian 3984355c1c Part of the previous commit, i.e. "expand all subitems" in TOC. 12 years ago
Tigran Aivazian 8312ad83c5 Add "expand all" command attached to Shift-Right key in the menu which recursively expands all subitems of a given item. 12 years ago
Tigran Aivazian e35a828fb0 Generate expandable TOC only if there really is something to expand in the TOC. 12 years ago
Qingping Hou 2f847e6a5e use DroidSansFallback as cfont
DroidSansFallback supports more characters
12 years ago
{Qingping,Dave} Hou f9b8ee0513 Merge pull request #272 from tigran123/master
The fix for the bug issue #269.
12 years ago
Tigran Aivazian 49a76330ac Bugfix for the issue #269 and also fixed findTOCpos() function to correctly calculate the position in TOC
for the case when the current page is before the first page with a TOC entry.
12 years ago
Tigran Aivazian 1c32a24450 1. Shorten the "No TOC" message to be displayable.
2. Get rid of the calls to self:fillToc() from the places in the code which cannot affect TOC.
I assume the reason for these calls is that they are needed in the original CoolReader application
(because there the TOC displays the virtual "page numbers") and were brought over to our crengine.lua
during the port.
12 years ago
Dobrica Pavlinušić 44d9daf07a Merge pull request #271 from tigran123/master
TOC cleanup in crengine.lua
12 years ago
{Qingping,Dave} Hou 75d286257f Merge pull request #270 from tigran123/master
When renaming a file no need to initialize oldname TWICE.
12 years ago
Tigran Aivazian 253a0829ff No need to initialize oldname = self:FullFileName() twice when renaming a file --- one initialization is enough.
(and, while at it, replaced references to a non-existent word "extention" with the proper English "extension")
12 years ago
Dobrica Pavlinušić bfc369062e Merge pull request #268 from houqp/master
set crengine cache size in lua code
12 years ago
Qingping Hou 1eb7162796 set crengine cache size in lua code 12 years ago
{Qingping,Dave} Hou 275e94c7a3 Merge pull request #267 from dpavlin/crengine_64Mb_cache
use 64Mb for on disk DOM cache for crengine
12 years ago
Dobrica Pavlinusic 880374f5db use 64Mb for on disk DOM cache for crengine
Previously we had cache size limit of 100 bytes, so crengine would erase
all on-disk cache on each file open as described in #206
12 years ago
{Qingping,Dave} Hou 4cdbcac458 Merge pull request #266 from tigran123/master
Shorten the message about opening the document.
12 years ago
Tigran Aivazian 47556b5562 Shorten the message about opening the document, otherwise it is not displayed at all. 12 years ago
Dobrica Pavlinusic 397d3aa037 Merge branch 'gamma_speedup' 12 years ago
Dobrica Pavlinusic 2332691bb0 replaced showInfoMsgWithDelay with InfoMessage:show in crereader 12 years ago
{Qingping,Dave} Hou 0100f33128 Merge pull request #264 from dpavlin/gamma_speedup
showInfoMsgWithDelay would delay gamma change for 1s #165
12 years ago
{Qingping,Dave} Hou 79a304bb5d Merge pull request #262 from dpavlin/render_indicator
added page_indicator to show document position and rendering
12 years ago
Dobrica Pavlinusic b27b665a97 showInfoMsgWithDelay would delay gamma change for 1s #165 12 years ago
Dobrica Pavlinušić b75470365b Merge pull request #263 from tigran123/master
Allow deleting bookmarks as requested in issue #256
12 years ago
Tigran Aivazian 4242cc9686 Allow deleting bookmarks. 12 years ago
Dobrica Pavlinusic 4e1586fc81 added page_indicator to show document position and rendering
idea is simple: when starting long operation (page renedering) invert
box on top of screen which has relative width of this page.

This allows easy overview where in document user is, along with
indication that something is still happending.

Perfect use-case are glossy magazines pdfs which have first two
pages in hi-res graphics, so this indicator is very useful to see
that something is still happending and that reader didn't die
12 years ago
{Qingping,Dave} Hou af53a78291 Merge pull request #260 from tigran123/master
Slight tidy up to the fix for \#257
12 years ago
Tigran Aivazian 2c6dfae807 Shorten various messages --- otherwise they are NOT SHOWN at all.
Also, mark pagedirty in all cases when deleting the file, to cause the screen refresh --
otherwise the message "Press 'Y' to confirm" stays there indefinitely.
12 years ago
Tigran Aivazian f1e197cbfd For documents without TOC we need to redraw current page after showing the "No Table of Contents" message,
otherwise the message "Retrieving TOC..." will stay on the screen indefinitely.
12 years ago
{Qingping,Dave} Hou 329132d3df Merge pull request #259 from dpavlin/fileinfo_duplication
fileinfo doesn't reset results
12 years ago
{Qingping,Dave} Hou 7e20d120db Merge pull request #258 from dpavlin/cr_cache
use ldomDocCache::init to cache crengine DOM
12 years ago
Dobrica Pavlinušić 4c5f488151 Merge pull request #257 from dpavlin/master
fix crash on documents without TOC
12 years ago
Dobrica Pavlinusic d3aa98abb9 fileinfo doesn't reset results
This affects multiple entry into fileinfo which just accumulate
information, eventually scrolling off screen
12 years ago
Dobrica Pavlinusic 3fe518979c use ldomDocCache::init to cache crengine DOM
This should improve performance of crengine #206
12 years ago
Dobrica Pavlinusic acc61e7c07 fix crash on documents without TOC
Showing TOC on documents without one results in following error:

lua config error: ./unireader.lua:1742: attempt to get length of a nil value
12 years ago
{Qingping,Dave} Hou 9c0b59c79e Merge pull request #255 from tigran123/master
Multi-level TOC support.
12 years ago
Qingping Hou 6a1de042f4 initialize fileinfo.commands to nil 12 years ago
Tigran Aivazian 27340db68b cleanup: get rid of the variable that is no longer needed. 12 years ago
Tigran Aivazian 44df8027f7 Fix the function cleanUpTocTitle() to return a single string, so that
it can be passed as a second argument to table.insert().
12 years ago
Tigran Aivazian e2a3f1de64 Multi-level TOC support, see issue #235 on github. 12 years ago
Tigran Aivazian e824fb24da Correct the comment (the existing text was referring to a different file). 12 years ago
{Qingping,Dave} Hou aa93a8f078 Merge pull request #254 from dpavlin/master
fallback to default fonts when loading reader configuration
12 years ago
Dobrica Pavlinusic 406f3d72da fallback to default fonts when loading reader configuration
Since we are adding and renaming fonts, we need to make sure that
all fonts which reader uses are defined. This allows us to add fonts
and not break when users load old configuration files

close #252
12 years ago
NuPogodi a5496b83c6 Update helppage.lua
Fixed crash of heplpage 'cause of typo: tfont > tface
12 years ago
Qingping Hou 6c9fb8b023 fix typo in getFace 12 years ago
Qingping Hou 4199ac8e3c add missing ")" 12 years ago
{Qingping,Dave} Hou f03e198573 Merge pull request #251 from NuPogodi/master
New menu to change font faces; new parameter to handle files; etc
12 years ago
NuPogodi d1ae0f3999 Enter filemanager modes for beginners & advanced users
1. Added parameter that tells filemanager the way how to manage files. Those who prefer 'safe' method (default) should not select any other mode except for BEGINNERS_MODE in new menu called by Alt+M. Actually, 'safe mode' is our old version (the files are filtered on the extention-basis; one may rename the filenames, but not their extentions). The tigran's corrections de0f40ce9c
are easy to switch on by selecting mode for advanced users who understand potential danger (mostly, crashes of crereader 'cause of improper input files) and accept it.
2. New menu Font:chooseFonts() to change font faces
3. Removed duplicated code of 'make screenshot'
4. The hotkeys (Back & Home) to exit FileChooser are moved down
5. Removed outdated comments
12 years ago
NuPogodi dddbea89df Restored proper separation of cre-documents
The decision whether ext:getReader(ftype) returns CREReader or nil for documents with improper file extentions now depends on the new parameter FileChooser.filemanager_expert_mode. Improper files are now related to CREReader only for advances users.
12 years ago
NuPogodi b052e3207c Add global parameter filemanager_expert_mode
In order to switch between safe and advanced way for filechooser to manage files, I've introduced special parameter 'filemanager_expert_mode':
i) 'safe' means that filemanager shows only files with the reader-related extentions; make safe renaming (i.e. the extention remains the same)
ii) 'advanced': all files are available (no filtering); any renaming is allowed;
TODO: to add also 'expert' mode & use it for unstable or dangerous functions
12 years ago
NuPogodi 92545a0cc2 Message font: "cfont" > "infofont"
1. Removed useless parameter self.face
2. Changed font face from "cfont" to "infofont"
12 years ago
NuPogodi 4196d98323 Replaced: font-related 'self' parameters > local
1. Made few (font-related) self parameters to be local > now updating font faces in Font:chooseFonts() properly changes these font faces
3. Removed outdated comments; minor code cleanup: to make it more readable
12 years ago
NuPogodi 8a792d2f31 Replaced: font selection menu (new version), etc
1. New menu Font:chooseFonts() to change font faces
2. Removed duplicate of 'make screenshot'
3. Hotkeys (Back & Home) to exit are moved down, to the end of hotkey list
4. Removed outdated comments & not informative comments
12 years ago
NuPogodi dc2fcc8654 Replace old 'Font menu'-function by new, improved version
1. Replace old function to change 'cfont' by new, improved version capable to change all font faces.
2. Remove 'make screenshot'; already added in commands.lua
2. Moved exit hotkeys (Back & Home) to the end of the hotkey list
3. Remove some outdated comments and clean a bit the code (just cosmetics to make it more readable)
12 years ago
NuPogodi 5e6a93191a Clear the code from not used parameters
1. Remove a lot of unused self parameters & commands (including 'make screenshot') 
2. Make sure adding commands only once
3. Add function to change font faces for any items enumerated in Fonts.fontmap and modify the code to recalculate the width of left column that depends on the selected font face => lface
4. Remove most of outdated comments
12 years ago
NuPogodi cfa4afe35a Improved the method to define font face to render menu items
1. Add parameter own_glyph that defines how to render menu items:
default own_glyph = 0,	-- render menu items with default "cfont"
own_glyph = 1 => own glyphs for items like "Droid/DroidSans.ttf"
own_glyph = 2 => own glyphs for Font.fontmap._index like "ffont", "tfont", etc.
Now own font face may be used to render both types of menu items called from Font:chooseFonts() 
2. Delete some outdated comments
12 years ago
NuPogodi bd0c180c81 Add functions to change font face for all items in Font.fontmap
1. Excluded pgfont from Font.fontmap-items; it was used in helppage.lua to render footer and just duplicated ffont
2. Fixed typo: self.cfont > "cfont" in Font:getFace()
3. 3 small functions to change font face for any member of Font.fontmap
12 years ago
NuPogodi d58fa93285 Next tigran's requests
1. Finally, removed infomessage about redrawing page in new zoom mode
2. Prevented potentially wrong user's input of non-integer values for page numbers in the 'go to page' input box
3. Removed duplicated code to make screenshot; already included in commands.lua
12 years ago
NuPogodi fe5d39821f Added: command 'make screenshot'
Now one may gradually remove 'make screenshot'-duplicates from other Lua-modules.
TODO: Since Shift+P is in use in inputbox to enter char 'P', one should discuss replacing Shift+P by something else, that is still free. Just an info: inputbox uses all buttons without modifiers => small characters; all buttons with Shift => CAPITALS; Alt+Q..P = digits (0..9) and etc.
12 years ago
{Qingping,Dave} Hou 093f99aaa7 Merge pull request #250 from NuPogodi/master
fix: to prevent crashes at opening wrong zips or zips with not crengine-related documents
12 years ago
NuPogodi 676a4610cf Following requests...
1. Replace hotkeys Alt+<> & Shift+<> (houpq's request)
2. Restrict maximum X/Y-panning steps by G_width/G_height, respectively.
3. Remove warning out about redrawing in new zoom mode (tigran's request)
12 years ago
NuPogodi a1c85affd1 if the document cannot be opened, function openFile(filename) shows a warning with specified error 12 years ago
NuPogodi fe2363b29f fix: to prevent crash opening wrong zips and zips with improper content
if the file with zip-extention is not valid zip or it contains the improper entry (not crengine-related files), function CREReader:open(filename) return false, "the error description"
12 years ago
Dobrica Pavlinušić a52ce4d22a Merge pull request #247 from NuPogodi/master
unireader: storing rcountmax; user-configurable zoom step & pan steps, etc
12 years ago
NuPogodi 1f89704b90 storing rcountmax; user-configurable zoom step & pan steps, etc
1. In order to close issue #59, I've introduced user-configurable values for panning steps - for X- & Y-axis, separately. Now panning is called by pressing fiveway without mod_keys. When one presses Shift+FW, he/she changes panning steps in the following way - Shift-Left/Right = decrease / increase X-panning step (divide or multiply on factor 2), Shift-Up/Down = increase / decrease Y-panning step. The lowest value for panning steps is set 1. Both parameters, shift_x & shift_y, are saved to local settings (i.e. history file).

2. Manual zoom step was also made user-configurable. So, instead of two old zooming functions (with fixed 10% and 20%-steps), I made one function to zoom (Shift+<>), while the other (Alt+<>) changes the zoom step downto minimum 1%. 

3. Fresh introduced function to change parameter rcountmax was added by storing rcountmax to both setting files - global settings & local ones (i.e. history file) - so that the rcountmax-priority (from low to high) is the following: default rcountmax=5 < its value in global settings < rcountmax stored for each concrete document.

3. Dirty, the extention-based hack to avoid reading not crengine-related parameters stored in history files. TODO: one has to finally introduce loadSpecialSettings() & readSpecialSettings() for PDFReader & DJVUReader and to store therein the reader-specific parameters (like globalgamma, bbox, globalzoom, globalzoom_mode; render_mode = for djvu-files only, etc.)

4. Some lua-code cosmetics (to make code more readable); for example: "self.pan_margin = settings:readSetting("pan_margin") or self.pan_margin" instead of 
"local pan_margin = settings:readSetting("pan_margin")
if pan_margin then
		self.pan_margin = pan_margin
	end"

5. Fix for the today's tigran123 fix: issue #246 (details are included). Added InfoMessage:show() to inform most impatient users that the reader tries to redraw new zoo mode.

6. The fontface for the reading info (called by 'Menu') is restored to be in accordance with original intentions and with the same fontface in crereader.lua - namely, Font:getFace("rifont", 20)

7. Moved the exit hotkeys (Alt+Back & Home) to the end of hotkey list.
12 years ago
{Qingping,Dave} Hou f85614f1c7 Merge pull request #246 from tigran123/master
Bugfix: screen refresh needed on exit from zoom mode menu.
12 years ago
Tigran Aivazian b70865286c Remove Debug() --- I keep forgetting to remove them before commit :) 12 years ago
Tigran Aivazian df18cae233 Bugfix: In zoom mode menu selection we need to redraw the screen even if the selected mode is the same as the current one,
otherwise it gives an impression that the program hangs (unless the user presses Next page or does anything else that causes
screen refresh, e.g. manual screen refresh).
12 years ago
{Qingping,Dave} Hou c9dcf5bdd2 Merge pull request #244 from tigran123/master
Minor optimization of DjVu drawPage() and set dither bits to 4 to match Kindle's screen.
12 years ago
Tigran Aivazian af37e9f14d Comment out the setting of dithering bits because djvulibre ignores anything less than 8 bits anyway. 12 years ago
Tigran Aivazian 524c8209c0 Improve customupdate target to only include the _real_ LUA source files, not
the garbage settings.*.lua or any other small test/experimental *.lua files
that happen to be in the current directory.
12 years ago
Tigran Aivazian 95be71c1e1 Small optimization in djvu.c:drawPage() --- there is no need to create and destroy
djvu pixel format on each redraw of the page as this can be done once on open and close
of the document. Also, set dither bits to 4 to help djvulibre choose the most
optimal dithering algorithm for the Kindle. Also, make coding style of "if(" -> "if ("
consistent (both instances were used, but "if (" was more frequent).
12 years ago
{Qingping,Dave} Hou 1e45c06689 Merge pull request #243 from tigran123/master
Bugfix: moving files to/from clipboard works now.
12 years ago
Tigran Aivazian b96f4f509f Remove the Debug() call I added when debugging the previous issue. 12 years ago
Tigran Aivazian 6f1dea294c Merge remote branch 'upstream/master' 12 years ago
Tigran Aivazian 2d4189fc84 Bugfix: moving files to/from clipboard works now. 12 years ago
Dobrica Pavlinušić a56e49c3f3 Merge pull request #240 from tigran123/master
DjVu rendering mode and other changes.
12 years ago
Tigran Aivazian b2e0ecb7b0 Add description of MASK ONLY djvu page rendering mode. 12 years ago
Tigran Aivazian 3b1da21cfd Merge remote branch 'upstream/master'
Conflicts:
	djvureader.lua
	unireader.lua
12 years ago
{Qingping,Dave} Hou 45d9b10aa6 Merge pull request #239 from NuPogodi/master
Restored: partial screen refresh; Moved: djvu render mode to djvureader; Added: menu with zoom-modes
12 years ago
NuPogodi 4bb8ef7f45 unireader: refresh frequency; zoommode-menu, etc.
1. Restored default value rcountmax=5; the function to make manual full screen refresh is no more silent; at first, it asks user to set a number of partial refreshes (rcountmax) and then performs full refresh. TODO: saving parameter 'rcountmax' in the global reader settings (or separately, for each document). 
2. The hotkey 'R' and the respective function toggle_render_mode() for djvu-documents are moved to djvureader.
3. Added hotkey 'M' and the respective function that calls menu with zoom-modes. Probably, one needs to remove unappropriate items, like "Fit zoom to page" and, less probably, the hotkeys (A, S, D, F and ^A, ^S, ^D, ^F) to set zoom-mode directly.
12 years ago
NuPogodi c9e20704a4 djvureader: moved render-mode functions
Since parameter 'render_mode' is related to djvu-documents only, the hotkey 'R' and the respective function to toggle 'render_mode' are moved from unireader to djvureader.
12 years ago
NuPogodi a2f7f62a3d crereader: remove not crengine-related 'M'-hotkey
Since I've added new unireader-hotkey that calls menu with zoom-modes, one has to remove it from crereader.lua. Done...
12 years ago
Tigran Aivazian 10a23e81d6 Merge remote branch 'upstream/master' 12 years ago
{Qingping,Dave} Hou ee83b6e043 Merge pull request #238 from NuPogodi/master
crereader
12 years ago
Tigran Aivazian 711cee787e Merge remote branch 'upstream/master' 12 years ago
NuPogodi 4d6b03052a crereader: some corrections
1. Improved the method to restore position in document after rescaling font face, size, weight, interline spacing,  etc.
2. Fixed rotation functions inherited from unireader.lua
3. Removed hotkey for the function of manual cropping inherited from unireader.lua; reason: not crengine-related
4. Added fast navigation functions via Shift+fiveway: jump to previous / next TOC-entry; scroll 10 pages backwards / forward
12 years ago
Tigran Aivazian 60b87b4b95 Update the name of the function cycle_render_mode() -> select_render_mode() in the comment. 12 years ago
Tigran Aivazian 9a22a022bf Tidy up the help text on the 'R' command. 12 years ago
Qingping Hou 461c135c5d patch for #234 by Nupogoddi
refresh screen if no input from search highlight.

close #234
12 years ago
Tigran Aivazian 2e0876a4ae Merge remote branch 'upstream/master' 12 years ago
NuPogodi 25edd3101f TOC position on current place in the tree #235 12 years ago
NuPogodi 20fae9369e Update rendertext.lua
Minor modification in function renderUtf8Multiline(...) to solve Issue #214
12 years ago
Tigran Aivazian c6a1d22bc9 Redraw the page even if the user did not select any rendering mode, otherwise nothing is displayed (except menu). 12 years ago
Tigran Aivazian b0b0b85ca1 Re-implement the interface for setting DjVu page rendering mode as a menu.
Thanks to NuPogodi for showing how to do this.
12 years ago
Tigran Aivazian 3fd33805c5 Save/restore the setting of render_mode. 12 years ago
Dobrica Pavlinusic d577ed9b00 show search results as inverted block 12 years ago
Tigran Aivazian 32333ca1d6 Make the function cycle_render_mode() slightly more readable. 12 years ago
Tigran Aivazian 7000f349c0 Allow renaming the whole file, including "extension". 12 years ago
Tigran Aivazian 42491bfefd Merge remote branch 'upstream/master' 12 years ago
Tigran Aivazian 2d5a936480 Remove the local variable render_mode from drawPage() (although it would be optimized away by gcc anyway). 12 years ago
Tigran Aivazian 824e9d139e Move render_mode support out of unireader.lua into djvureader.lua as it is djvu-specific.
Also added support for all other rendering modes handled by djvulibre.
Also made the message print a human-readable description of the mode rather than just the number.
12 years ago
Dobrica Pavlinusic 989016ece5 disable DEBUG_CRENGINE 12 years ago
Dobrica Pavlinušić cd3f72136e Merge pull request #231 from dpavlin/cre-search
coolreader search highlight
12 years ago
NuPogodi bfe8a5d84f added calculator to filechooser
closes #232
12 years ago
Dobrica Pavlinušić ebe6b87587 Merge pull request #233 from hwhw/nupogodi-inputbox
Nupogodi inputbox
12 years ago
NuPogodi 282d8e693e improvements to rename if file browser
closes #219
12 years ago
NuPogodi 63e1c4b66c a lot of inputbox improvements
closes #194, closes #218

1. Lowercase layout is default
2. Uppercase chars by pressing Shift+Key; it will probably require us to
   remap some old MOD_SHIFT-commands to MOD_ALT (not the upper raw that is
   responsible for digits: Alt-Q = 1, etc.)
3. New 'documentation' functions
   - usual helppage with active hotkeys (Alt+H)
   - list of available math functions (Alt+M, active in the calculator
     mode)
4. Added two small functions to move cursor to the first/last position
   in inputbox (Shift+FW-left/FW-right)
5. Some minor rearrangement for layouts (mostly for convenient work with
   calculator)
6. Keeping initial "d_text" in InputBox:input(... d_text, is_hint) when
   is_hint is not true (say, for minor changing of long filenames #219, etc.)
   or incremental search.

Added: calculator with a proper documentation of available math
functions
12 years ago
NuPogodi 3f410bdb6b To allow arbitrary header title 12 years ago
Dobrica Pavlinusic bc0a911e7e showInfoMsgWithDelay with number of results 12 years ago
Dobrica Pavlinusic f0476ab481 hide inputbox after entry 12 years ago
Dobrica Pavlinusic 7d10a636e7 correctly return first search position and refresh screen 12 years ago
Dobrica Pavlinusic adf0b42e5b coolreader search highlight
This is rough port of Android code, but seems to work
12 years ago
Dobrica Pavlinusic 5a897fba77 Revert "Set up to compile with arm-kindle-linux-x-tools-glibc2.5-gcc4.2.4.tar.gz toolchain."
This reverts commit 2650faa000
as described in #229
12 years ago
Tigran Aivazian 5c9a8fbec6 DjVu enhancements: a) add support for switching the rendering mode between B&W (default, 1) and COLOUR (0) values. b) handle the gamma values correctly. 12 years ago
Tigran Aivazian 0a4e11d4af In the status line shorten "Memory:" -> "M:" and "Section:" -> "Sec:" and also show the battery level. 12 years ago
Tigran Aivazian 424a6a895b Refresh the screen completely on every page, not every 5th. 12 years ago
Tigran Aivazian c4833b7557 Make sure the function that deletes history entry does NOT delete the physical file.
This is normal/expected behaviour, as in CoolReader and all other viewers I looked at.
12 years ago
Tigran Aivazian 8a583311c8 Trivial grammatical changes. 12 years ago
Tigran Aivazian b605536567 Fix the "rename" function to include the file extension. 12 years ago
Tigran Aivazian 601b7b9d69 Memory leak in DrawFileItem(), found by NuPogodi. 12 years ago
Tigran Aivazian 5576890263 Fix the Makefile to use freetype-2.4.10 and kpvcrlib/CMakeLists.txt to do the same and also zlib 1.2.5->1.2.7 and libjpeg 8d->9. 12 years ago
Tigran Aivazian de0f40ce9c 1. Disable filtering by file extension so that the program can be used as a proper filemanager.
2. Pass all files to crengine except those handled by PDF and DjVu modules.
12 years ago
Tigran Aivazian 2650faa000 Set up to compile with arm-kindle-linux-x-tools-glibc2.5-gcc4.2.4.tar.gz toolchain. 12 years ago
{Qingping,Dave} Hou d952fff3f3 Merge pull request #228 from dpavlin/1c6421dc3f
naive implementation of search highlight
12 years ago
Dobrica Pavlinusic 1c6421dc3f correctly show default value in inputbox 12 years ago
Dobrica Pavlinusic 2dfee0a2fb remember last search so it's incremental now 12 years ago
Dobrica Pavlinusic d827301639 search through whole document 12 years ago
Dobrica Pavlinusic eb38dfedd4 show search highlight until next page refresh 12 years ago
Dobrica Pavlinusic e8ab2381c3 extract code into new function UniReader:searchHighLight(search) 12 years ago
Dobrica Pavlinusic ed59adecea naive implementation of search highlight issue #75 12 years ago
Dobrica Pavlinušić 2a24f5a13a Merge pull request #227 from houqp/master
integrate bmp and pgm support patch from NuPogodi
12 years ago
Qingping Hou 5be38246f5 fix comment in screen.lua
set default to no pack on bmp image
12 years ago
Qingping Hou 7a3de8b6b7 move battery info file to /tmp 12 years ago
NuPogodi c06605e86c Update master 12 years ago
NuPogodi 333537dfd6 to save screenshots as bmp (4bpp, 166dpi > fast) or pgm (8bpp, slow) 12 years ago
NuPogodi 17585c2bf4 Update master for comment on image size 12 years ago
NuPogodi 2e975fa18d Update master 12 years ago
NuPogodi ead3355a2b Update master 12 years ago
NuPogodi 13ac163c51 save screenshots to bmp (or pgm) 12 years ago
NuPogodi e580a7c278 Update master: fixes for BMP method 12 years ago
NuPogodi f996a69568 add BMP and PGM methods. Use BMP in screenshot method
Update master
Conflicts:
	screen.lua
12 years ago
{Qingping,Dave} Hou a505cdaf34 Merge pull request #209 from dpavlin/master
fix path to lua for lua.h include
12 years ago
Dobrica Pavlinusic 2fd5c28007 fix lua include path 12 years ago
{Qingping,Dave} Hou 692b06fdcb Merge pull request #208 from dpavlin/master
make on-screen keyboard lower case by default
12 years ago
Dobrica Pavlinusic 89fd8d22d6 make on-screen keyboard lower case by default
close #194
12 years ago
HW ee7472be96 Merge pull request #202 from tchaikov/mac-fixes
fixes for mac
12 years ago
HW a853dbbb1d Merge pull request #201 from tchaikov/remove-dependency
remove dependency on <linux/input.h>
12 years ago
Kefu Chai 896c435840 remove dependency on <linux/input.h>
* and kill a warning
12 years ago
Kefu Chai 1ecab97c6f fixes for mac
* per http://luajit.org/install.html, otherwise LuaJIT always fails
  to get desired memory chunk from mmap(2)
* kill a warning of clang
12 years ago
HW 4fb745a0df Merge pull request #198 from tchaikov/remove-dependency
remove dependency on <linux/fb.h>
12 years ago
Kefu Chai 0e561c610a remove dependency on <linux/fb.h> 12 years ago
Qingping Hou 794e9188fc update building section in Makefile 12 years ago
Qingping Hou 1e3d72df70 update README, for emulator example 12 years ago
Qingping Hou ad7a8d044c update self.items and self.current after file deletion 12 years ago
{Qingping,Dave} Hou 9b263ca23a Merge pull request #197 from tchaikov/remove-position-saved
stay at current page after deletion
12 years ago
Kefu Chai 8665a7567f stay at current page after deletion
* prefer os.remove() to 'os.execute("rm "...)'
12 years ago
Dobrica Pavlinušić 388d4fb2ac Merge pull request #196 from houqp/master
fix for #127
12 years ago
Qingping Hou 0558a5ec5a reread current directory files after unplug from PC 12 years ago
Qingping Hou 2485a552eb first try to fix #127 12 years ago
Dobrica Pavlinušić 9b0cb24200 Merge pull request #195 from houqp/master
add usb charging events
12 years ago
Qingping Hou 7ab59e9a5c add usb charging events
for issue #127
12 years ago
Dobrica Pavlinušić b46a4f5dbb Merge pull request #192 from houqp/master
build environment & bookmark navi bug fix
12 years ago
Qingping Hou 2dfbf3177f revert shift+page turn bindings
previously, they are overwritten by mistakes
12 years ago
Qingping Hou dec86586e8 bug fix in CREReader:prevBookMarkedPage
handle two more corner situations
12 years ago
Qingping Hou 8ef6eb8b73 bug fix in CREReader:prevBookMarkedPage 12 years ago
Qingping Hou 772a298d48 fix CC for luajit compilation 12 years ago
HW 454611afb7 Merge pull request #191 from houqp/master
three changes
12 years ago
Qingping Hou d0e7f2240d add bookmark navigation function to crereader 12 years ago
Qingping Hou d04370464b add getPosFromXPointer in cre.cpp 12 years ago
Qingping Hou 763e2223d2 sort bookmark table after addition 12 years ago
Qingping Hou b76be2b87d add bookmark navigation functions in unireader.lua 12 years ago
Qingping Hou e2e3f12463 fix cleanthirdparty target 12 years ago
Qingping Hou 25e943cb84 bump crengine version to 3.0.57-15 12 years ago
HW 4660781c84 removed local config file 12 years ago
HW 906a5bd48c removed debugging cruft 12 years ago
HW a0b538affd update to freetype-2.4.9 12 years ago
HW 0d12ff70cd rename debug() to Debug() to stop clashing with the debug submodule from Lua 12 years ago
HW ccd91b58e3 Merge branch 'luajit' 12 years ago
Qingping Hou eb0c6b3619 fix #187 12 years ago
HW 942ab0d3d4 fixed issue that made CREngine default font working after restart only
in the earlier version, the static crereader.default_font wasn't
changed, so a new default font only got used after a restart
12 years ago
HW 978fd9313a added compilation for ARM (Kindle device) with LuaJIT 12 years ago
HW e35339a398 fixed wrong escape sequences in strings
again, LuaJIT will choke on these, Lua-5.1.n did just ignore them
12 years ago
HW b07470535f fixed missing return values
those did not trigger problems with Lua-5.1.x, but they do with LuaJIT
12 years ago
HW 7952220b41 switch to LuaJIT-2.0
LuaJIT is a JIT compiler for Lua code. It's phenomenal work, and
you can read about it here: http://luajit.org/
12 years ago
HW 054c63704c Added code for KEY_LPGFWD to KDX key list for K2 compatibility 12 years ago
HW 22ce736e11 added jump-to-percent dialog for CREngine reader 12 years ago
HW e2af463bac enable key repeat in SDL emulation mode 12 years ago
HW 02c40b6078 configurable default font for CREngine
when in CREngine mode, the current font can be made the default
document font by pressing Shift-F

in order to store this setting, the reader_settings variable was
promoted to the declared global G_reader_settings

close #184
12 years ago
HW 4d2036fa7b bugfix for #185, close #185 12 years ago
HW 202b6fc039 Merge pull request #178 from dpavlin/master
NuPogodi code drop from 2012-05-27
12 years ago
HW 497e1d89de added shortcuts for Kite
as per suggestion from NuPogodi:
http://www.mobileread.com/forums/showpost.php?p=2090800&postcount=465
12 years ago
HW ab400b97ac faster refresh path for the cursor 12 years ago
Dobrica Pavlinusic ae9be768ab use lfs.currentdir to specify clipboard directory
This will make clipboard usable on emulator
12 years ago
NuPogodi 944a3b5b05 NuPogodi code drop from 2012-05-27
- zip files don't require double extensions any more
- filechooser has 'H' shortcut to display keys
- new function for files and folders (^ == shift)
	^N - new folder
	Del - delete document/folder
	^C - copy file into clipboard
	^X - cut (move) file to clipboard
	^V - paste files from clipboard
	^R - rename file
- configurable keyboard for input box
12 years ago
{Qingping,Dave} Hou 78efdc77e3 Merge pull request #174 from dpavlin/NuPogodi_push
NuPogodi filechooser changes
12 years ago
NuPogodi 1831004da5 Add the new function ZipContentExt(zipfilename) which reads the content of zipfile and returns the extention of the first entry. 12 years ago
NuPogodi cccdf42892 use new input handling to enable help page 12 years ago
Dobrica Pavlinušić b1486ee4bd Merge pull request #173 from houqp/master
fix for djvu getPageText API changes
12 years ago
Qingping Hou d2d8ad84ed handle djvu getPageText API changes. 12 years ago
{Qingping,Dave} Hou 763b97744b Merge pull request #170 from dpavlin/NuPogodi
NuPogodi patch 19.05.2012
12 years ago
Dobrica Pavlinusic f55654f03e implement settings version #120 and migration #134
Latest changes for history support move configuration files into
history directory to keep them as timestamp for last read. This code
also adds reading of old configuration files (but does not remove them)
12 years ago
Dobrica Pavlinusic 9de055eb5d fix glymp caching name
With recent changes in font selector, we where hitting
glyphcache_max_memsize so glyphcache[k].glyph.bb:free() got
invoked and crashed reader.
12 years ago
Dobrica Pavlinusic d678510d9a return to file list with fiveway left
It's nice and symetrical to show info (fiveway right) so you don't have
to move hands from fiveway while having long names lookup
12 years ago
Dobrica Pavlinusic a08c35a52c added Screen:screenshot() 12 years ago
NuPogodi 86513c3793 added cr3.css for files without one 12 years ago
NuPogodi 3a76ec91fd integrate rest of @NuPogodi changes #166
- long lines (filenames in 'Document Info') are now splitted in more
  human-readable way (by spaces, dots, slashes or some other characters
- see screenshot)
- the selection of fonts in filemanager (key 'F' or 'Aa') looks now more
  user-friendly
- fixed too long strings in most menues (TOC, Bookmarks, Fonts...) and
  in the popup with the reading progress (called by key 'Menu')
- the position inside the cr-documents (epub, mobi...) now remain nearly
  the same after rescaling the document (i.e. changing the font face,
  size, boldface and interline distance)
- when you open TOC-menu or Fonts Menu, it highlights the current item
  (i.e. current chapter and current fontface).
- i've a bit changed the way to read the battery level values, it might
  now work even without Amazon Kindle framework.
12 years ago
NuPogodi f595d42431 change default title font to DroidSansBold 12 years ago
Qingping Hou 6f5bf4a3b8 bump crengine to version v3.0.57-14
This version also fixes segfault when
reading the Real Analysis - Maths.chm.

The test file is provided by medwatt
from mobileread.
12 years ago
{Qingping,Dave} Hou c43a312725 Merge pull request #169 from dpavlin/master
added Registering fonts dialog on startup
12 years ago
Dobrica Pavlinusic 28161ae3d0 added Registering fonts dialog on startup
This operation can take some time on device
12 years ago
NuPogodi 93b5da0d8d Update crereader.lua 12 years ago
NuPogodi 773a4d69b6 + added: saving & restoring the font size (new parameter > font_zoom)
+ fixed: too long strings in _drawReadingInfo() (called by key 'Menu')
+ fixed: floating the text when the font (face, size or boldface) and/or interline spacing modify the document height
12 years ago
NuPogodi cd046a0637 Update rendertext.lua 12 years ago
{Qingping,Dave} Hou eaaff0d9bc Merge pull request #162 from dpavlin/master
few more tweaks for manual crop rouler
12 years ago
Dobrica Pavlinusic 54657bb74c use hpkfont for ruler, increase size and fix aligment #35
This is maximum font size which allows vertical ruler to have
spacing between vertical letters.
12 years ago
Dobrica Pavlinusic bca64dd4ef use showInfoMsgWithDelay for new bbox and redraw page #153 12 years ago
Qingping Hou 121f154313 bump crengine to version v3.0.57-14
This version also fixes segfault when
reading the Real Analysis - Maths.chm.

The test file is provided by medwatt
from mobileread.
12 years ago
Dobrica Pavlinusic ba19ab7029 added .prc as alternative extension for mobi
This was reported by @valex in post at forum:
http://www.mobileread.com/forums/showpost.php?p=2064360&postcount=340
12 years ago
Dobrica Pavlinušić e73803603b Merge pull request #159 from houqp/master
bump crengine version.
12 years ago
Qingping Hou c2cb95f8e8 remove patch in cre.cpp since it is accepted by upstream 12 years ago
Qingping Hou 84eb0e338f bump crengine to version v3.0.57-14
This version also fixes segfault when
reading the Real Analysis - Maths.chm.

The test file is provided by medwatt
from mobileread.
12 years ago
Dobrica Pavlinušić 7e885198ec Merge pull request #157 from houqp/master
rewrite getpagtext for djvu module
12 years ago
Qingping Hou a73d9a5a52 Merge branch 'master' of github.com:hwhw/kindlepdfviewer 12 years ago
Qingping Hou a672cf4ee0 unified coordinates system in djvrereader
fix bug in showing manual corp area.
this also fixes #132.
12 years ago
Dobrica Pavlinušić 89f9a8c711 Merge pull request #156 from houqp/master
bug fix in jump history
12 years ago
Qingping Hou d21ea032e5 Merge branch 'master' of github.com:hwhw/kindlepdfviewer 12 years ago
Qingping Hou c275862ffe fix bug in jump_history
record current page when jump_history.cur points to
empty head.
12 years ago
Dobrica Pavlinušić 0d4d7e7fb9 Merge pull request #154 from houqp/master
Two bug fixes & patches from NuPogodi
12 years ago
Qingping Hou c818d7e90e screenshot shorcut patch by NuPogodi@mobileread 12 years ago
Qingping Hou 381b34cc04 detect file type in zip file, patched by NuPogodi@mobileread 12 years ago
Qingping Hou eb1fbebc5b change default font face for crereader, reported by NuPogodi@mobileread.
changed to Droid Sans Fallback
12 years ago
Qingping Hou 1e36018021 fix bug in inputbox
Redundant code in character deleting
12 years ago
{Qingping,Dave} Hou dad5b32331 Merge pull request #153 from dpavlin/issue_35_manual_crop
second try to implement ruler idea by @eLiNK2gl in #35
12 years ago
Dobrica Pavlinusic 55cdb26823 force next full refresh 12 years ago
Dobrica Pavlinusic de12c6aac0 second try to implement rouler idea by y @eLiNK2gl in #35 12 years ago
{Qingping,Dave} Hou 246619b9c4 Merge pull request #151 from dpavlin/issue_35_manual_crop
manually select page bounding box
12 years ago
Dobrica Pavlinusic 90b8860ed5 always use partial refresh 12 years ago
Dobrica Pavlinusic 31108d536c manually select page bounding box
I hope we can finally close #35 with this.
12 years ago

23
.gitignore vendored

@ -2,9 +2,18 @@
lua
lua-*
.reader.kpdfview.lua
settings.reader.lua
mupdf-thirdparty.zip
djvulibre*
cr3cache
history
crash.log
.vimrc
git-rev
data
fonts
kpdfview
slider_watcher
*.o
kindlepdfviewer-*.zip
@ -17,3 +26,17 @@ kpvcrlib/CMakeCache.txt
kpvcrlib/CMakeFiles/
kpvcrlib/cmake_install.cmake
kpvcrlib/Makefile
popen-noshell/libpopen_noshell.a
popen-noshell/*.o
popen-noshell/.svn/
popen-noshell/CREDITS
popen-noshell/Makefile
popen-noshell/README
popen-noshell/performance_tests/
popen-noshell/popen_noshell.c
popen-noshell/popen_noshell.h
popen-noshell/popen_noshell_examples.c
popen-noshell/popen_noshell_tests.c
popen-noshell/popen_noshell_tests.cpp

6
.gitmodules vendored

@ -10,3 +10,9 @@
[submodule "kpvcrlib/crengine"]
path = kpvcrlib/crengine
url = git://crengine.git.sourceforge.net/gitroot/crengine/crengine
[submodule "luajit-2.0"]
path = luajit-2.0
url = http://luajit.org/git/luajit-2.0.git
[submodule "libk2pdfopt"]
path = libk2pdfopt
url = git://github.com/chrox/libk2pdfopt.git

@ -1,38 +1,55 @@
# you can probably leave these settings alone:
LUADIR=lua
LUADIR=luajit-2.0
MUPDFDIR=mupdf
MUPDFTARGET=build/debug
MUPDFTARGET=build/release
MUPDFLIBDIR=$(MUPDFDIR)/$(MUPDFTARGET)
DJVUDIR=djvulibre
KPVCRLIGDIR=kpvcrlib
CRENGINEDIR=$(KPVCRLIGDIR)/crengine
KPVCRLIBDIR=kpvcrlib
CRENGINEDIR=$(KPVCRLIBDIR)/crengine
FREETYPEDIR=$(MUPDFDIR)/thirdparty/freetype-2.4.8
FREETYPEDIR=$(MUPDFDIR)/thirdparty/freetype
JPEGDIR=$(MUPDFDIR)/thirdparty/jpeg
LFSDIR=luafilesystem
POPENNSDIR=popen-noshell
K2PDFOPTLIBDIR=libk2pdfopt
# must point to directory with *.ttf fonts for crengine
TTF_FONTS_DIR=$(MUPDFDIR)/fonts
# set this to your ARM cross compiler:
HOST:=arm-none-linux-gnueabi
CC:=$(HOST)-gcc
CXX:=$(HOST)-g++
STRIP:=$(HOST)-strip
SHELL:=/bin/bash
CHOST?=arm-none-linux-gnueabi
CC:=$(CHOST)-gcc
CXX:=$(CHOST)-g++
STRIP:=$(CHOST)-strip
AR:=$(CHOST)-ar
ifdef SBOX_UNAME_MACHINE
CC:=gcc
CXX:=g++
endif
HOSTCC:=gcc
HOSTCXX:=g++
CFLAGS:=-O3 $(SYSROOT)
CXXFLAGS:=-O3 $(SYSROOT)
LDFLAGS:= $(SYSROOT)
ARM_CFLAGS:=-march=armv6
# use this for debugging:
#CFLAGS:=-O0 -g
HOSTAR:=ar
# Base CFLAGS, without arch. We'll need it for luajit, because its Makefiles do some tricky stuff to differentiate HOST/TARGET
BASE_CFLAGS:=-O2 -ffast-math -pipe -fomit-frame-pointer
# Use this for debugging:
#BASE_CFLAGS:=-O0 -g
# Misc GCC tricks to ensure backward compatibility with the K2, even when using a fairly recent TC (Linaro/MG).
# NOTE: -mno-unaligned-access is needed for TC based on Linaro 4.6/4.7 or GCC 4.7, or weird crap happens on FW 2.x. We unfortunately can't set it by default, since it's a new flag.
# A possible workaround would be to set the alignment trap to fixup (echo 2 > /proc/cpu/alignment) in the launch script, but that's terribly ugly, and might severly nerf performance...
# That said, MG 2012.03 is still using GCC 4.6.3, so we're good ;).
ARM_BACKWARD_COMPAT_CFLAGS:=-fno-stack-protector -U_FORTIFY_SOURCE -D_GNU_SOURCE -fno-finite-math-only
ARM_BACKWARD_COMPAT_CXXFLAGS:=-fno-use-cxa-atexit
ARM_ARCH:=-march=armv6j -mtune=arm1136jf-s -mfpu=vfp -mfloat-abi=softfp -marm
HOST_ARCH:=-march=native
HOSTCFLAGS:=$(HOST_ARCH) $(BASE_CFLAGS)
CFLAGS:=$(BASE_CFLAGS)
CXXFLAGS:=$(BASE_CFLAGS)
LDFLAGS:=-Wl,-O1 -Wl,--as-needed
DYNAMICLIBSTDCPP:=-lstdc++
ifdef STATICLIBSTDCPP
@ -46,6 +63,7 @@ endif
ifdef EMULATE_READER
CC:=$(HOSTCC) -g
CXX:=$(HOSTCXX)
AR:=$(HOSTAR)
EMULATE_READER_W?=824
EMULATE_READER_H?=1200
EMU_CFLAGS?=$(shell sdl-config --cflags)
@ -53,12 +71,21 @@ ifdef EMULATE_READER
-DEMULATE_READER_W=$(EMULATE_READER_W) \
-DEMULATE_READER_H=$(EMULATE_READER_H)
EMU_LDFLAGS?=$(shell sdl-config --libs)
ifeq "$(shell uname -s -m)" "Darwin x86_64"
EMU_LDFLAGS += -pagezero_size 10000 -image_base 100000000
endif
CFLAGS+= $(HOST_ARCH)
CXXFLAGS+= $(HOST_ARCH)
LIBDIR=libs-emu
else
CFLAGS+= $(ARM_CFLAGS)
CFLAGS+= $(ARM_ARCH) $(ARM_BACKWARD_COMPAT_CFLAGS)
CXXFLAGS+= $(ARM_ARCH) $(ARM_BACKWARD_COMPAT_CFLAGS) $(ARM_BACKWARD_COMPAT_CXXFLAGS)
LIBDIR=libs
endif
# standard includes
KPDFREADER_CFLAGS=$(CFLAGS) -I$(LUADIR)/src -I$(MUPDFDIR)/
K2PDFOPT_CFLAGS=-I$(K2PDFOPTLIBDIR)/willuslib -I$(K2PDFOPTLIBDIR)/k2pdfoptlib -I$(K2PDFOPTLIBDIR)/
# enable tracing output:
@ -67,7 +94,10 @@ KPDFREADER_CFLAGS=$(CFLAGS) -I$(LUADIR)/src -I$(MUPDFDIR)/
# for now, all dependencies except for the libc are compiled into the final binary:
MUPDFLIBS := $(MUPDFLIBDIR)/libfitz.a
DJVULIBS := $(DJVUDIR)/build/libdjvu/.libs/libdjvulibre.a
DJVULIBS := $(DJVUDIR)/build/libdjvu/.libs/libdjvulibre.so \
$(LIBDIR)/libdjvulibre.so
DJVULIB := $(LIBDIR)/libdjvulibre.so.21
DJVULIBDIR := $(DJVUDIR)/build/libdjvu/.libs/
CRENGINELIBS := $(CRENGINEDIR)/crengine/libcrengine.a \
$(CRENGINEDIR)/thirdparty/chmlib/libchmlib.a \
$(CRENGINEDIR)/thirdparty/libpng/libpng.a \
@ -82,144 +112,191 @@ THIRDPARTYLIBS := $(MUPDFLIBDIR)/libfreetype.a \
#$(MUPDFLIBDIR)/libjpeg.a \
#$(CRENGINEDIR)/thirdparty/libjpeg/libjpeg.a \
LUALIB := $(LUADIR)/src/liblua.a
LUALIB := $(LIBDIR)/libluajit-5.1.so.2
POPENNSLIB := $(POPENNSDIR)/libpopen_noshell.a
all:kpdfview
K2PDFOPTLIB := $(LIBDIR)/libk2pdfopt.so.1
kpdfview: kpdfview.o einkfb.o pdf.o blitbuffer.o drawcontext.o input.o util.o ft.o lfs.o mupdfimg.o $(MUPDFLIBS) $(THIRDPARTYLIBS) $(LUALIB) djvu.o $(DJVULIBS) cre.o $(CRENGINELIBS)
$(CC) -lm -ldl -lpthread $(EMU_LDFLAGS) $(DYNAMICLIBSTDCPP) \
all: kpdfview extr
VERSION?=$(shell git describe HEAD)
kpdfview: kpdfview.o einkfb.o pdf.o blitbuffer.o drawcontext.o koptcontext.o input.o $(POPENNSLIB) util.o ft.o lfs.o mupdfimg.o $(MUPDFLIBS) $(THIRDPARTYLIBS) $(LUALIB) djvu.o $(DJVULIBS) cre.o $(CRENGINELIBS) pic.o pic_jpeg.o
echo $(VERSION) > git-rev
$(CC) \
$(CFLAGS) \
kpdfview.o \
einkfb.o \
pdf.o \
blitbuffer.o \
drawcontext.o \
koptcontext.o \
input.o \
$(POPENNSLIB) \
util.o \
ft.o \
lfs.o \
mupdfimg.o \
pic.o \
pic_jpeg.o \
$(MUPDFLIBS) \
$(THIRDPARTYLIBS) \
$(LUALIB) \
djvu.o \
$(DJVULIBS) \
cre.o \
$(CRENGINELIBS) \
$(STATICLIBSTDCPP) \
-o kpdfview
$(LDFLAGS) \
-Wl,-rpath=$(LIBDIR)/ \
-o $@ \
-lm -ldl -lpthread -lk2pdfopt -ldjvulibre -lluajit-5.1 -L$(MUPDFLIBDIR) -L$(LIBDIR)\
$(EMU_LDFLAGS) \
$(DYNAMICLIBSTDCPP)
extr: extr.o $(MUPDFLIBS) $(THIRDPARTYLIBS)
$(CC) $(CFLAGS) extr.o $(MUPDFLIBS) $(THIRDPARTYLIBS) -lm -o extr
slider_watcher: slider_watcher.c
$(CC) $(CFLAGS) $< -o $@
extr.o: %.o: %.c
$(CC) -c -I$(MUPDFDIR)/pdf -I$(MUPDFDIR)/fitz $< -o $@
ft.o: %.o: %.c
slider_watcher.o: %.o: %.c
$(CC) -c $(CFLAGS) $< -o $@
slider_watcher: slider_watcher.o $(POPENNSLIB)
$(CC) $(CFLAGS) slider_watcher.o $(POPENNSLIB) -o $@
ft.o: %.o: %.c $(THIRDPARTYLIBS)
$(CC) -c $(KPDFREADER_CFLAGS) -I$(FREETYPEDIR)/include -I$(MUPDFDIR)/fitz $< -o $@
kpdfview.o pdf.o blitbuffer.o util.o drawcontext.o einkfb.o input.o mupdfimg.o: %.o: %.c
blitbuffer.o util.o drawcontext.o einkfb.o input.o mupdfimg.o: %.o: %.c
$(CC) -c $(KPDFREADER_CFLAGS) $(EMU_CFLAGS) -I$(LFSDIR)/src $< -o $@
kpdfview.o koptcontext.o pdf.o: %.o: %.c
$(CC) -c $(KPDFREADER_CFLAGS) $(K2PDFOPT_CFLAGS) $(EMU_CFLAGS) -I$(LFSDIR)/src $< -o $@
djvu.o: %.o: %.c
$(CC) -c $(KPDFREADER_CFLAGS) -I$(DJVUDIR)/ $< -o $@
$(CC) -c $(KPDFREADER_CFLAGS) $(K2PDFOPT_CFLAGS) -I$(DJVUDIR)/ $< -o $@
pic.o: %.o: %.c
$(CC) -c $(KPDFREADER_CFLAGS) $< -o $@
pic_jpeg.o: %.o: %.c
$(CC) -c $(KPDFREADER_CFLAGS) -I$(JPEGDIR)/ -I$(MUPDFDIR)/scripts/ $< -o $@
cre.o: %.o: %.cpp
$(CC) -c -I$(CRENGINEDIR)/crengine/include/ -Ilua/src $< -o $@ -lstdc++
$(CC) -c $(CFLAGS) -I$(CRENGINEDIR)/crengine/include/ -I$(LUADIR)/src $< -o $@
lfs.o: $(LFSDIR)/src/lfs.c
$(CC) -c $(CFLAGS) -I$(LUADIR)/src -I$(LFSDIR)/src $(LFSDIR)/src/lfs.c -o $@
fetchthirdparty:
-rm -Rf lua lua-5.1.4
-rm -Rf mupdf/thirdparty
rm -rf mupdf/thirdparty
test -d mupdf && (cd mupdf; git checkout .) || echo warn: mupdf folder not found
test -d $(LUADIR) && (cd $(LUADIR); git checkout .) || echo warn: $(LUADIR) folder not found
git submodule init
git submodule update
cd mupdf && (git submodule init; git submodule update)
ln -sf kpvcrlib/crengine/cr3gui/data data
test -e data/cr3.css || ln kpvcrlib/cr3.css data/
test -d fonts || ln -sf $(TTF_FONTS_DIR) fonts
test -d history || mkdir history
test -d clipboard || mkdir clipboard
# CREngine patch: disable fontconfig
grep USE_FONTCONFIG $(CRENGINEDIR)/crengine/include/crsetup.h && grep -v USE_FONTCONFIG $(CRENGINEDIR)/crengine/include/crsetup.h > /tmp/new && mv /tmp/new $(CRENGINEDIR)/crengine/include/crsetup.h || echo "USE_FONTCONFIG already disabled"
test -f mupdf-thirdparty.zip || wget http://www.mupdf.com/download/mupdf-thirdparty.zip
# CREngine patch: change child nodes' type face
# @TODO replace this dirty hack 24.04 2012 (houqp)
cd kpvcrlib/crengine/crengine/src && \
patch -N -p0 < ../../../lvrend_node_type_face.patch || true
unzip mupdf-thirdparty.zip -d mupdf
# dirty patch in MuPDF's thirdparty liby for CREngine
cd mupdf/thirdparty/jpeg-*/ && \
patch -N -p0 < ../../../kpvcrlib/jpeg_compress_struct_size.patch &&\
patch -N -p0 < ../../../kpvcrlib/jpeg_decompress_struct_size.patch
patch -N -p0 < ../../../lvrend_node_type_face.patch && \
patch -N -p3 < ../../../lvdocview-getCurrentPageLinks.patch || true
# MuPDF patch: use external fonts
cd mupdf && patch -N -p1 < ../mupdf.patch
test -f lua-5.1.4.tar.gz || wget http://www.lua.org/ftp/lua-5.1.4.tar.gz
tar xvzf lua-5.1.4.tar.gz && ln -s lua-5.1.4 lua
test -f popen-noshell/popen_noshell.c || svn co http://popen-noshell.googlecode.com/svn/trunk/ popen-noshell
# popen_noshell patch: Make it build on recent TCs, and implement a simple Makefile for building it as a static lib
cd popen-noshell && test -f Makefile || patch -N -p0 < popen_noshell-buildfix.patch
clean:
-rm -f *.o kpdfview slider_watcher
rm -f *.o kpdfview slider_watcher extr
cleanthirdparty:
make -C $(LUADIR) clean
make -C $(MUPDFDIR) clean
#make -C $(CRENGINEDIR)/thirdparty/antiword clean
test -d $(CRENGINEDIR)/thirdparty/chmlib && make -C $(CRENGINEDIR)/thirdparty/chmlib clean || echo warn: chmlib folder not found
test -d $(CRENGINEDIR)/thirdparty/libpng && (make -C $(CRENGINEDIR)/thirdparty/libpng clean) || echo warn: chmlib folder not found
test -d $(CRENGINEDIR)/crengine && (make -C $(CRENGINEDIR)/crengine clean) || echo warn: chmlib folder not found
test -d $(KPVCRLIGDIR) && (make -C $(KPVCRLIGDIR) clean) || echo warn: chmlib folder not found
-rm -rf $(DJVUDIR)/build
-rm -f $(MUPDFDIR)/fontdump.host
-rm -f $(MUPDFDIR)/cmapdump.host
$(MUPDFDIR)/fontdump.host:
make -C mupdf CC="$(HOSTCC)" $(MUPDFTARGET)/fontdump
cp -a $(MUPDFLIBDIR)/fontdump $(MUPDFDIR)/fontdump.host
make -C mupdf clean
$(MUPDFDIR)/cmapdump.host:
make -C mupdf CC="$(HOSTCC)" $(MUPDFTARGET)/cmapdump
cp -a $(MUPDFLIBDIR)/cmapdump $(MUPDFDIR)/cmapdump.host
make -C mupdf clean
$(MUPDFLIBS) $(THIRDPARTYLIBS): $(MUPDFDIR)/cmapdump.host $(MUPDFDIR)/fontdump.host
rm -rf $(LIBDIR) ; mkdir $(LIBDIR)
$(MAKE) -C $(LUADIR) CC="$(HOSTCC)" CFLAGS="$(BASE_CFLAGS)" clean
$(MAKE) -C $(MUPDFDIR) build="release" clean
$(MAKE) -C $(CRENGINEDIR)/thirdparty/antiword clean
test -d $(CRENGINEDIR)/thirdparty/chmlib && $(MAKE) -C $(CRENGINEDIR)/thirdparty/chmlib clean || echo warn: chmlib folder not found
test -d $(CRENGINEDIR)/thirdparty/libpng && ($(MAKE) -C $(CRENGINEDIR)/thirdparty/libpng clean) || echo warn: chmlib folder not found
test -d $(CRENGINEDIR)/crengine && ($(MAKE) -C $(CRENGINEDIR)/crengine clean) || echo warn: chmlib folder not found
test -d $(KPVCRLIBDIR) && ($(MAKE) -C $(KPVCRLIBDIR) clean) || echo warn: chmlib folder not found
rm -rf $(DJVUDIR)/build
$(MAKE) -C $(POPENNSDIR) clean
$(MAKE) -C $(K2PDFOPTLIBDIR) clean
$(MUPDFLIBS) $(THIRDPARTYLIBS):
# build only thirdparty libs, libfitz and pdf utils, which will care for libmupdf.a being built
CFLAGS="$(CFLAGS) -DNOBUILTINFONT" make -C mupdf CC="$(CC)" CMAPDUMP=cmapdump.host FONTDUMP=fontdump.host MUPDF= MU_APPS= BUSY_APP= XPS_APPS= verbose=1
ifdef EMULATE_READER
$(MAKE) -C mupdf XCFLAGS="$(CFLAGS) -DNOBUILTINFONT" build="release" CC="$(CC)" MUPDF= MU_APPS= BUSY_APP= XPS_APPS= verbose=1 NOX11=yes
else
# generate data headers
$(MAKE) -C mupdf generate build="release"
$(MAKE) -C mupdf XCFLAGS="$(CFLAGS) -DNOBUILTINFONT" build="release" CC="$(CC)" MUPDF= MU_APPS= BUSY_APP= XPS_APPS= verbose=1 NOX11=yes CROSSCOMPILE=yes OS=Kindle
endif
$(DJVULIBS):
-mkdir $(DJVUDIR)/build
mkdir -p $(DJVUDIR)/build
ifdef EMULATE_READER
cd $(DJVUDIR)/build && ../configure --disable-desktopfiles --disable-shared --enable-static
cd $(DJVUDIR)/build && CC="$(HOSTCC)" CXX="$(HOSTCXX)" CFLAGS="$(HOSTCFLAGS)" CXXFLAGS="$(HOSTCFLAGS)" LDFLAGS="$(LDFLAGS)" ../configure --disable-desktopfiles --disable-static --enable-shared --disable-xmltools --disable-largefile
else
cd $(DJVUDIR)/build && ../configure --disable-desktopfiles --disable-shared --enable-static --host=$(HOST) --disable-xmltools --disable-desktopfiles
cd $(DJVUDIR)/build && CC="$(CC)" CXX="$(CXX)" CFLAGS="$(CFLAGS)" CXXFLAGS="$(CXXFLAGS)" LDFLAGS="$(LDFLAGS)" ../configure --disable-desktopfiles --disable-static --enable-shared --host=$(CHOST) --disable-xmltools --disable-largefile
endif
make -C $(DJVUDIR)/build
$(MAKE) -C $(DJVUDIR)/build
test -d $(LIBDIR) || mkdir $(LIBDIR)
cp -a $(DJVULIBDIR)/libdjvulibre.so* $(LIBDIR)
$(CRENGINELIBS):
cd $(KPVCRLIGDIR) && rm -rf CMakeCache.txt CMakeFiles && \
CFLAGS="$(CFLAGS)" CC="$(CC)" CXX="$(CXX)" cmake . && \
make
cd $(KPVCRLIBDIR) && rm -rf CMakeCache.txt CMakeFiles && \
CFLAGS="$(CFLAGS)" CXXFLAGS="$(CXXFLAGS)" CC="$(CC)" CXX="$(CXX)" LDFLAGS="$(LDFLAGS)" cmake . && \
$(MAKE)
$(LUALIB):
make -C lua/src CC="$(CC)" CFLAGS="$(CFLAGS)" MYCFLAGS=-DLUA_USE_LINUX MYLIBS="-Wl,-E" liblua.a
ifdef EMULATE_READER
$(MAKE) -C $(LUADIR) BUILDMODE=shared
else
# To recap: build its TARGET_CC from CROSS+CC, so we need HOSTCC in CC. Build its HOST/TARGET_CFLAGS based on CFLAGS, so we need a neutral CFLAGS without arch
$(MAKE) -C $(LUADIR) BUILDMODE=shared CC="$(HOSTCC)" HOST_CC="$(HOSTCC) -m32" CFLAGS="$(BASE_CFLAGS)" HOST_CFLAGS="$(HOSTCFLAGS)" TARGET_CFLAGS="$(CFLAGS)" CROSS="$(CHOST)-" TARGET_FLAGS="-DLUAJIT_NO_LOG2 -DLUAJIT_NO_EXP2"
endif
test -d $(LIBDIR) || mkdir $(LIBDIR)
cp -a $(LUADIR)/src/libluajit.so* $(LUALIB)
ln -s libluajit-5.1.so.2 $(LIBDIR)/libluajit-5.1.so
$(POPENNSLIB):
$(MAKE) -C $(POPENNSDIR) CC="$(CC)" AR="$(AR)"
$(K2PDFOPTLIB):
$(MAKE) -C $(K2PDFOPTLIBDIR) BUILDMODE=shared CC="$(CC)" CFLAGS="$(CFLAGS) -O3" AR="$(AR)" all
test -d $(LIBDIR) || mkdir $(LIBDIR)
cp -a $(K2PDFOPTLIBDIR)/libk2pdfopt.so* $(LIBDIR)
thirdparty: $(MUPDFLIBS) $(THIRDPARTYLIBS) $(LUALIB) $(DJVULIBS) $(CRENGINELIBS)
thirdparty: $(MUPDFLIBS) $(THIRDPARTYLIBS) $(LUALIB) $(DJVULIBS) $(CRENGINELIBS) $(POPENNSLIB) $(K2PDFOPTLIB)
INSTALL_DIR=kindlepdfviewer
install:
# install to kindle using USB networking
scp kpdfview *.lua root@192.168.2.2:/mnt/us/$(INSTALL_DIR)/
scp launchpad/* root@192.168.2.2:/mnt/us/launchpad/
LUA_FILES=battery.lua commands.lua crereader.lua defaults.lua dialog.lua djvureader.lua readerchooser.lua filechooser.lua filehistory.lua fileinfo.lua filesearcher.lua font.lua graphics.lua helppage.lua image.lua inputbox.lua keys.lua pdfreader.lua koptconfig.lua koptreader.lua picviewer.lua reader.lua rendertext.lua screen.lua selectmenu.lua settings.lua unireader.lua widget.lua
VERSION?=$(shell git rev-parse --short HEAD)
customupdate: all
# ensure that build binary is for ARM
# ensure that the binaries were built for ARM
file kpdfview | grep ARM || exit 1
$(STRIP) --strip-unneeded kpdfview
-rm kindlepdfviewer-$(VERSION).zip
rm -Rf $(INSTALL_DIR)
mkdir $(INSTALL_DIR)
cp -p README.TXT COPYING kpdfview *.lua $(INSTALL_DIR)
file extr | grep ARM || exit 1
$(STRIP) --strip-unneeded kpdfview extr
rm -f kindlepdfviewer-$(VERSION).zip
rm -rf $(INSTALL_DIR)
mkdir -p $(INSTALL_DIR)/{history,screenshots,clipboard,libs}
cp -p README.md COPYING kpdfview extr kpdf.sh $(LUA_FILES) $(INSTALL_DIR)
mkdir $(INSTALL_DIR)/data
cp -L $(DJVULIB) $(LUALIB) $(K2PDFOPTLIB) $(INSTALL_DIR)/libs
$(STRIP) --strip-unneeded $(INSTALL_DIR)/libs/*
cp -rpL data/*.css $(INSTALL_DIR)/data
cp -rpL fonts $(INSTALL_DIR)
cp -r resources $(INSTALL_DIR)
rm $(INSTALL_DIR)/fonts/droid/DroidSansFallback.ttf
cp -r git-rev resources $(INSTALL_DIR)
mkdir $(INSTALL_DIR)/fonts/host
zip -9 -r kindlepdfviewer-$(VERSION).zip $(INSTALL_DIR) launchpad/
rm -Rf $(INSTALL_DIR)
zip -9 -r kindlepdfviewer-$(VERSION).zip $(INSTALL_DIR) launchpad/ kite/
rm -rf $(INSTALL_DIR)
@echo "copy kindlepdfviewer-$(VERSION).zip to /mnt/us/customupdates and install with shift+shift+I"

@ -1,69 +0,0 @@
KindlePDFViewer
===============
This is a PDF viewer application, created for usage on the Kindle e-ink reader.
It is currently restricted to 4bpp inverse grayscale displays. It's using the
muPDF library (see http://mupdf.com/) and its UI is scripted using Lua (see
http://www.lua.org/).
The application is licensed under the GPLv3 (see COPYING file).
Building
========
Follow these steps:
- install muPDF sources into subfolder "mupdf"
- install muPDF third-party sources (see muPDF homepage) into a new subfolder
"mupdf/thirdparty"
- install Lua sources into subfolder "lua"
=> note that there's a make target to do this. You need wget, unzip and git
installed. Then just run "make fetchthirdparty".
- adapt Makefile to your needs
- run "make thirdparty". This will build MuPDF (plus the libraries it depends
on) and Lua.
- run "make". This will build the kpdfview application
Running
=======
The user interface (or what's there yet) is scripted in Lua. See "reader.lua".
It uses the Linux feature to run scripts by using a corresponding line at its
start.
So you might just call that script. Note that the script and the kpdfview
binary currently must be in the same directory.
You would then just call reader.lua, giving the document file path as its first
argument. Run reader.lua without arguments to see usage notes.
The reader.lua script can also show a file chooser: it will do this when you
call it with a directory (instead of a file) as first argument.
Device emulation
================
The code also features a device emulation. You need SDL headers and library
for this. It allows to develop on a standard PC and saves precious development
time. It might also compose the most unfriendly desktop PDF reader, depending
on your view.
To build in "emulation mode", you need to run make like this:
make clean cleanthirdparty
EMULATE_READER=1 make thirdparty kpdfview
The reader.lua script needs a device argument in order to cope with some
slight differences between actual readers and the emulation. Run it like
this:
./reader.lua -d emu /PATH/TO/PDF.pdf
By default emulation will provide DXG resolution of 824*1200. It can be
specified at compile time, this is example for Kindle 3:
EMULATE_READER_W=600 EMULATE_READER_H=800 EMULATE_READER=1 make kpdfview

@ -0,0 +1,88 @@
KindlePDFViewer
===============
This is a document viewer application, created for usage on the Kindle e-ink reader.
It is currently restricted to 4bpp inverse grayscale displays. For PDF files
it is using the muPDF library (see http://mupdf.com/), for DjVu files djvulibre library
and for ebooks (fb2, mobi, ePub, etc) crengine. It can also read JPEG images using
libjpeg library. The user interface is scripted using Lua (see http://www.lua.org/).
The application is licensed under the GPLv3 (see COPYING file).
Building
========
Follow these steps:
* fetch thirdparty sources
* manually fetch all the thirdparty sources:
* install muPDF sources into subfolder "mupdf"
* install muPDF third-party sources (see muPDF homepage) into a new
subfolder "mupdf/thirdparty"
* install libDjvuLibre sources into subfolder "djvulibre"
* install CREngine sources into subfolder "kpvcrlib/crengine"
* install LuaJit sources into subfolder "luajit-2.0"
* install popen_noshell sources into subfolder "popen-noshell"
* automatically fetch thirdparty sources with Makefile:
* make sure you have patch, wget, unzip, git and svn installed
* run `make fetchthirdparty`.
* adapt Makefile to your needs
* run `make thirdparty`. This will build MuPDF (plus the libraries it depends
on), libDjvuLibre, CREngine and Lua.
* run `make`. This will build the kpdfview application
Running
=======
The user interface (or what's there yet) is scripted in Lua. See "reader.lua".
It uses the Linux feature to run scripts by using a corresponding line at its
start.
So you might just call that script. Note that the script and the kpdfview
binary currently must be in the same directory.
You would then just call reader.lua, giving the document file path, or any
directory path, as its first argument. Run reader.lua without arguments to see
usage notes. The reader.lua script can also show a file chooser: it will do
this when you call it with a directory (instead of a file) as first argument.
Device emulation
================
The code also features a device emulation. You need SDL headers and library
for this. It allows to develop on a standard PC and saves precious development
time. It might also compose the most unfriendly desktop PDF reader, depending
on your view.
If you are using Fedora Core Linux, do `yum install SDL SDL-devel`.
If you are using Ubuntu, install `libsdl-dev1.2` package.
To build in "emulation mode", you need to run make like this:
make clean cleanthirdparty
EMULATE_READER=1 make thirdparty kpdfview
And run the emulator like this:
```
./reader.lua /PATH/TO/PDF.pdf
```
or:
```
./reader.lua /ANY/PATH
```
By default emulation will provide DXG resolution of 824*1200. It can be
specified at compile time, this is example for Kindle 3:
```
EMULATE_READER_W=600 EMULATE_READER_H=800 EMULATE_READER=1 make kpdfview
```

@ -1,166 +0,0 @@
-- Copyright (c) 2009 Aleksey Cheusov <vle@gmx.net>
--
-- Permission is hereby granted, free of charge, to any person obtaining
-- a copy of this software and associated documentation files (the
-- "Software"), to deal in the Software without restriction, including
-- without limitation the rights to use, copy, modify, merge, publish,
-- distribute, sublicense, and/or sell copies of the Software, and to
-- permit persons to whom the Software is furnished to do so, subject to
-- the following conditions:
--
-- The above copyright notice and this permission notice shall be
-- included in all copies or substantial portions of the Software.
--
-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-- EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-- MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-- NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
-- LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
-- OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
-- WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
local type, pairs, ipairs, io, os = type, pairs, ipairs, io, os
module ("alt_getopt")
local function convert_short2long (opts)
local i = 1
local len = #opts
local ret = {}
for short_opt, accept_arg in opts:gmatch("(%w)(:?)") do
ret[short_opt]=#accept_arg
end
return ret
end
local function exit_with_error (msg, exit_status)
io.stderr:write (msg)
os.exit (exit_status)
end
local function err_unknown_opt (opt)
exit_with_error ("Unknown option `-" ..
(#opt > 1 and "-" or "") .. opt .. "'\n", 1)
end
local function canonize (options, opt)
if not options [opt] then
err_unknown_opt (opt)
end
while type (options [opt]) == "string" do
opt = options [opt]
if not options [opt] then
err_unknown_opt (opt)
end
end
return opt
end
function get_ordered_opts (arg, sh_opts, long_opts)
local i = 1
local count = 1
local opts = {}
local optarg = {}
local options = convert_short2long (sh_opts)
for k,v in pairs (long_opts) do
options [k] = v
end
while i <= #arg do
local a = arg [i]
if a == "--" then
i = i + 1
break
elseif a == "-" then
break
elseif a:sub (1, 2) == "--" then
local pos = a:find ("=", 1, true)
if pos then
local opt = a:sub (3, pos-1)
opt = canonize (options, opt)
if options [opt] == 0 then
exit_with_error ("Bad usage of option `" .. a .. "'\n", 1)
end
optarg [count] = a:sub (pos+1)
opts [count] = opt
else
local opt = a:sub (3)
opt = canonize (options, opt)
if options [opt] == 0 then
opts [count] = opt
else
if i == #arg then
exit_with_error ("Missed value for option `" .. a .. "'\n", 1)
end
optarg [count] = arg [i+1]
opts [count] = opt
i = i + 1
end
end
count = count + 1
elseif a:sub (1, 1) == "-" then
local j
for j=2,a:len () do
local opt = canonize (options, a:sub (j, j))
if options [opt] == 0 then
opts [count] = opt
count = count + 1
elseif a:len () == j then
if i == #arg then
exit_with_error ("Missed value for option `-" .. opt .. "'\n", 1)
end
optarg [count] = arg [i+1]
opts [count] = opt
i = i + 1
count = count + 1
break
else
optarg [count] = a:sub (j+1)
opts [count] = opt
count = count + 1
break
end
end
else
break
end
i = i + 1
end
return opts,i,optarg
end
function get_opts (arg, sh_opts, long_opts)
local ret = {}
local opts,optind,optarg = get_ordered_opts (arg, sh_opts, long_opts)
for i,v in ipairs (opts) do
if optarg [i] then
ret [v] = optarg [i]
else
ret [v] = 1
end
end
return ret,optind
end

@ -0,0 +1,24 @@
-- return the current battery level
function BatteryLevel()
local p = io.popen("gasgauge-info -s 2> /dev/null", "r") -- io.popen() _never_ fails!
local battery = p:read("*a") or "?"
if battery == "" then battery = "?" end
p:close()
return string.gsub(battery, "[\n\r]+", "")
end
-- log battery level in "batlog.txt" file, blevent can be any string
function logBatteryLevel(blevent)
if not G_battery_logging then return end
local file = io.open("batlog.txt", "a+")
if file then
if file:seek("end") == 0 then -- write the header only once
file:write("DATE\t\tTIME\t\tBATTERY\tEVENT\n")
end
file:write(string.format("%s\t%s\t%s\t%s\n",
os.date("%d-%b-%y"), os.date("%T"),
BatteryLevel(), blevent or "RUNNING"))
file:close()
end
end

@ -20,9 +20,19 @@
#include <string.h>
#include "blitbuffer.h"
/* debugging statements, switch as needed */
#ifdef DEBUG
#define ASSERT_BLITBUFFER_BOUNDARIES(bb,bb_ptr) \
if((bb_ptr < bb->data) || (bb_ptr >= (bb->data + bb->pitch * bb->h))) { \
fprintf(stderr, "violated blitbuffer constraints in file %s, line %d!\r\n", __FILE__, __LINE__); exit(1); \
}
#else // DEBUG
#define ASSERT_BLITBUFFER_BOUNDARIES(bb,bb_ptr) {}
#endif // DEBUG
inline int setPixel(BlitBuffer *bb, int x, int y, int c) {
uint8_t *dstptr = (uint8_t*)(bb->data) + (y * bb->pitch) + (x / 2);
ASSERT_BLITBUFFER_BOUNDARIES(bb, dstptr);
if(x % 2 == 0) {
*dstptr &= 0x0F;
@ -95,69 +105,80 @@ static int blitFullToBuffer(lua_State *L) {
return 0;
}
static int blitToBuffer(lua_State *L) {
BlitBuffer *dst = (BlitBuffer*) luaL_checkudata(L, 1, "blitbuffer");
BlitBuffer *src = (BlitBuffer*) luaL_checkudata(L, 2, "blitbuffer");
int xdest = luaL_checkint(L, 3);
int ydest = luaL_checkint(L, 4);
int xoffs = luaL_checkint(L, 5);
int yoffs = luaL_checkint(L, 6);
int w = luaL_checkint(L, 7);
int h = luaL_checkint(L, 8);
int x, y;
/**
* check/adapt boundaries for blitting operations
*
* @return 0 if no blitting is needed, 1 otherwise
*/
int fitBlitBufferBoundaries(BlitBuffer* src, BlitBuffer* dst, int* xdest, int* ydest, int* xoffs, int* yoffs, int* w, int* h) {
// check bounds
if(ydest < 0) {
if(*ydest < 0) {
// negative ydest, try to compensate
if(ydest + h > 0) {
if(*ydest + *h > 0) {
// shrink h by negative dest offset
h += ydest;
*h += *ydest;
// extend source offset
yoffs += -ydest;
ydest = 0;
*yoffs += -(*ydest);
*ydest = 0;
} else {
// effectively no height
return 0;
}
} else if(ydest >= dst->h) {
} else if(*ydest >= dst->h) {
// we're told to paint to off-bound target coords
return 0;
}
if(ydest + h > dst->h) {
if(*ydest + *h > dst->h) {
// clamp height if too large for target size
h = dst->h - ydest;
*h = dst->h - *ydest;
}
if(yoffs >= src->h) {
if(*yoffs >= src->h) {
// recalculated source offset is out of bounds
return 0;
} else if(yoffs + h > src->h) {
} else if(*yoffs + *h > src->h) {
// clamp height if too large for source size
h = src->h - yoffs;
*h = src->h - *yoffs;
}
// same stuff for x coords:
if(xdest < 0) {
if(xdest + w > 0) {
w += xdest;
xoffs += -xdest;
xdest = 0;
if(*xdest < 0) {
if(*xdest + *w > 0) {
*w += *xdest;
*xoffs += -(*xdest);
*xdest = 0;
} else {
return 0;
}
} else if(xdest >= dst->w) {
} else if(*xdest >= dst->w) {
return 0;
}
if(xdest + w > dst->w) {
w = dst->w - xdest;
if(*xdest + *w > dst->w) {
*w = dst->w - *xdest;
}
if(xoffs >= src->w) {
if(*xoffs >= src->w) {
return 0;
} else if(xoffs + w > src->w) {
w = src->w - xoffs;
} else if(*xoffs + *w > src->w) {
*w = src->w - *xoffs;
}
return 1; // continue processing
}
static int blitToBuffer(lua_State *L) {
BlitBuffer *dst = (BlitBuffer*) luaL_checkudata(L, 1, "blitbuffer");
BlitBuffer *src = (BlitBuffer*) luaL_checkudata(L, 2, "blitbuffer");
int xdest = luaL_checkint(L, 3);
int ydest = luaL_checkint(L, 4);
int xoffs = luaL_checkint(L, 5);
int yoffs = luaL_checkint(L, 6);
int w = luaL_checkint(L, 7);
int h = luaL_checkint(L, 8);
int x, y;
uint8_t *dstptr;
uint8_t *srcptr;
if(!fitBlitBufferBoundaries(src, dst, &xdest, &ydest, &xoffs, &yoffs, &w, &h))
return 0;
if(xdest & 1) {
/* this will render the leftmost column */
dstptr = (uint8_t*)(dst->data +
@ -168,6 +189,8 @@ static int blitToBuffer(lua_State *L) {
xoffs / 2 );
if(xoffs & 1) {
for(y = 0; y < h; y++) {
ASSERT_BLITBUFFER_BOUNDARIES(dst, dstptr);
ASSERT_BLITBUFFER_BOUNDARIES(src, srcptr);
*dstptr &= 0xF0;
*dstptr |= *srcptr & 0x0F;
dstptr += dst->pitch;
@ -175,6 +198,8 @@ static int blitToBuffer(lua_State *L) {
}
} else {
for(y = 0; y < h; y++) {
ASSERT_BLITBUFFER_BOUNDARIES(dst, dstptr);
ASSERT_BLITBUFFER_BOUNDARIES(src, srcptr);
*dstptr &= 0xF0;
*dstptr |= *srcptr >> 4;
dstptr += dst->pitch;
@ -195,6 +220,8 @@ static int blitToBuffer(lua_State *L) {
if(xoffs & 1) {
for(y = 0; y < h; y++) {
ASSERT_BLITBUFFER_BOUNDARIES(dst, dstptr);
ASSERT_BLITBUFFER_BOUNDARIES(src, srcptr);
for(x = 0; x < (w / 2); x++) {
dstptr[x] = (srcptr[x] << 4) | (srcptr[x+1] >> 4);
}
@ -207,6 +234,8 @@ static int blitToBuffer(lua_State *L) {
}
} else {
for(y = 0; y < h; y++) {
ASSERT_BLITBUFFER_BOUNDARIES(dst, dstptr);
ASSERT_BLITBUFFER_BOUNDARIES(src, srcptr);
memcpy(dstptr, srcptr, w / 2);
if(w & 1) {
dstptr[w/2] &= 0x0F;
@ -230,31 +259,12 @@ static int addblitToBuffer(lua_State *L) {
int h = luaL_checkint(L, 8);
int x, y;
// check bounds
if(yoffs >= src->h) {
return 0;
} else if(yoffs + h > src->h) {
h = src->h - yoffs;
}
if(ydest >= dst->h) {
return 0;
} else if(ydest + h > dst->h) {
h = dst->h - ydest;
}
if(xoffs >= src->w) {
return 0;
} else if(xoffs + w > src->w) {
w = src->w - xoffs;
}
if(xdest >= dst->w) {
return 0;
} else if(xdest + w > dst->w) {
w = dst->w - xdest;
}
uint8_t *dstptr;
uint8_t *srcptr;
if(!fitBlitBufferBoundaries(src, dst, &xdest, &ydest, &xoffs, &yoffs, &w, &h))
return 0;
if(xdest & 1) {
/* this will render the leftmost column */
dstptr = (uint8_t*)(dst->data +
@ -265,6 +275,8 @@ static int addblitToBuffer(lua_State *L) {
xoffs / 2 );
if(xoffs & 1) {
for(y = 0; y < h; y++) {
ASSERT_BLITBUFFER_BOUNDARIES(dst, dstptr);
ASSERT_BLITBUFFER_BOUNDARIES(src, srcptr);
uint8_t v = (*dstptr & 0x0F) + (*srcptr & 0x0F);
*dstptr = (*dstptr & 0xF0) | (v < 0x0F ? v : 0x0F);
dstptr += dst->pitch;
@ -272,6 +284,8 @@ static int addblitToBuffer(lua_State *L) {
}
} else {
for(y = 0; y < h; y++) {
ASSERT_BLITBUFFER_BOUNDARIES(dst, dstptr);
ASSERT_BLITBUFFER_BOUNDARIES(src, srcptr);
uint8_t v = (*dstptr & 0x0F) + (*srcptr >> 4);
*dstptr = (*dstptr & 0xF0) | (v < 0x0F ? v : 0x0F);
dstptr += dst->pitch;
@ -293,11 +307,15 @@ static int addblitToBuffer(lua_State *L) {
if(xoffs & 1) {
for(y = 0; y < h; y++) {
for(x = 0; x < (w / 2); x++) {
ASSERT_BLITBUFFER_BOUNDARIES(dst, dstptr);
ASSERT_BLITBUFFER_BOUNDARIES(src, srcptr);
uint16_t v1 = (dstptr[x] & 0xF0) + ((srcptr[x] & 0x0F) << 4);
uint8_t v2 = (dstptr[x] & 0x0F) + (srcptr[x+1] >> 4);
dstptr[x] = (v1 < 0xF0 ? v1 : 0xF0) | (v2 < 0x0F ? v2 : 0x0F);
}
if(w & 1) {
ASSERT_BLITBUFFER_BOUNDARIES(dst, dstptr);
ASSERT_BLITBUFFER_BOUNDARIES(src, srcptr);
uint16_t v1 = (dstptr[x] & 0xF0) + ((srcptr[x] & 0x0F) << 4);
dstptr[x] = (dstptr[x] & 0x0F) | (v1 < 0xF0 ? v1 : 0xF0);
}
@ -307,11 +325,15 @@ static int addblitToBuffer(lua_State *L) {
} else {
for(y = 0; y < h; y++) {
for(x = 0; x < (w / 2); x++) {
ASSERT_BLITBUFFER_BOUNDARIES(dst, dstptr);
ASSERT_BLITBUFFER_BOUNDARIES(src, srcptr);
uint16_t v1 = (dstptr[x] & 0xF0) + (srcptr[x] & 0xF0);
uint8_t v2 = (dstptr[x] & 0x0F) + (srcptr[x] & 0x0F);
dstptr[x] = (v1 < 0xF0 ? v1 : 0xF0) | (v2 < 0x0F ? v2 : 0x0F);
}
if(w & 1) {
ASSERT_BLITBUFFER_BOUNDARIES(dst, dstptr);
ASSERT_BLITBUFFER_BOUNDARIES(src, srcptr);
uint16_t v1 = (dstptr[x] & 0xF0) + (srcptr[x] & 0xF0);
dstptr[x] = (dstptr[x] & 0x0F) | (v1 < 0xF0 ? v1 : 0xF0);
}
@ -332,9 +354,25 @@ static int paintRect(lua_State *L) {
uint8_t *dstptr;
int cy;
if(w <= 0 || h <= 0 || x >= dst->w || y >= dst->h) {
return 0;
if(x < 0) {
if (x+w > 0) {
w += x;
x = 0;
} else {
return 0;
}
}
if(y < 0) {
if (y+h > 0) {
h += y;
y = 0;
} else {
return 0;
}
}
if(x + w > dst->w) {
w = dst->w - x;
}
@ -342,6 +380,10 @@ static int paintRect(lua_State *L) {
h = dst->h - y;
}
if(w <= 0 || h <= 0 || x >= dst->w || y >= dst->h) {
return 0;
}
if(x & 1) {
/* This will render the leftmost column
* in the case when x is odd. After this,
@ -350,6 +392,7 @@ static int paintRect(lua_State *L) {
y * dst->pitch +
x / 2);
for(cy = 0; cy < h; cy++) {
ASSERT_BLITBUFFER_BOUNDARIES(dst, dstptr);
*dstptr &= 0xF0;
*dstptr |= c;
dstptr += dst->pitch;
@ -361,6 +404,7 @@ static int paintRect(lua_State *L) {
y * dst->pitch +
x / 2);
for(cy = 0; cy < h; cy++) {
ASSERT_BLITBUFFER_BOUNDARIES(dst, dstptr);
memset(dstptr, c | (c << 4), w / 2);
dstptr += dst->pitch;
}
@ -372,6 +416,7 @@ static int paintRect(lua_State *L) {
y * dst->pitch +
(x + w) / 2);
for(cy = 0; cy < h; cy++) {
ASSERT_BLITBUFFER_BOUNDARIES(dst, dstptr);
*dstptr &= 0x0F;
*dstptr |= (c << 4);
dstptr += dst->pitch;
@ -389,6 +434,29 @@ static int invertRect(lua_State *L) {
uint8_t *dstptr;
int cy, cx;
//printf("## invertRect x=%d y=%d w=%d h=%d\n",x,y,w,h);
if (x < 0) {
if ( x + w > 0 ) {
w = w + x;
x = 0;
} else {
//printf("## invertRect x out of bound\n");
return 0;
}
}
if (y < 0) {
if ( y + h > 0 ) {
h = h + y;
y = 0;
} else {
//printf("## invertRect y out of bound\n");
return 0;
}
}
if(w <= 0 || h <= 0 || x >= dst->w || y >= dst->h) {
return 0;
}
@ -407,6 +475,7 @@ static int invertRect(lua_State *L) {
y * dst->pitch +
x / 2);
for(cy = 0; cy < h; cy++) {
ASSERT_BLITBUFFER_BOUNDARIES(dst, dstptr);
*dstptr ^= 0x0F;
dstptr += dst->pitch;
}
@ -418,6 +487,7 @@ static int invertRect(lua_State *L) {
x / 2);
for(cy = 0; cy < h; cy++) {
for(cx = 0; cx < w/2; cx++) {
ASSERT_BLITBUFFER_BOUNDARIES(dst, (dstptr+cx));
*(dstptr+cx) ^= 0xFF;
}
dstptr += dst->pitch;
@ -430,6 +500,7 @@ static int invertRect(lua_State *L) {
y * dst->pitch +
(x + w) / 2);
for(cy = 0; cy < h; cy++) {
ASSERT_BLITBUFFER_BOUNDARIES(dst, dstptr);
*dstptr ^= 0xF0;
dstptr += dst->pitch;
}
@ -446,6 +517,27 @@ static int dimRect(lua_State *L) {
uint8_t *dstptr;
int cy, cx;
if (x < 0) {
if ( x + w > 0 ) {
w = w + x;
x = 0;
} else {
//printf("## invertRect x out of bound\n");
return 0;
}
}
if (y < 0) {
if ( y + h > 0 ) {
h = h + y;
y = 0;
} else {
//printf("## invertRect y out of bound\n");
return 0;
}
}
if(w <= 0 || h <= 0 || x >= dst->w || y >= dst->h) {
return 0;
}
@ -464,6 +556,7 @@ static int dimRect(lua_State *L) {
y * dst->pitch +
x / 2);
for(cy = 0; cy < h; cy++) {
ASSERT_BLITBUFFER_BOUNDARIES(dst, dstptr);
int px = *dstptr & 0x0F;
*dstptr &= 0xF0 | px >> 1;
dstptr += dst->pitch;
@ -476,6 +569,7 @@ static int dimRect(lua_State *L) {
x / 2);
for(cy = 0; cy < h; cy++) {
for(cx = 0; cx < w/2; cx++) {
ASSERT_BLITBUFFER_BOUNDARIES(dst, (dstptr+cx));
*(dstptr+cx) =
( *(dstptr+cx) >> 1 ) & 0xF0 |
( *(dstptr+cx) & 0x0F ) >> 1;
@ -490,6 +584,7 @@ static int dimRect(lua_State *L) {
y * dst->pitch +
(x + w) / 2);
for(cy = 0; cy < h; cy++) {
ASSERT_BLITBUFFER_BOUNDARIES(dst, dstptr);
int px = *dstptr & 0xF0;
*dstptr &= 0x0F | ( px >> 1 & 0xF0 );
dstptr += dst->pitch;

@ -1,4 +1,5 @@
require "keys"
require "battery"
Keydef = {
keycode = nil,
@ -56,7 +57,7 @@ function Command:new(keydef, func, help, keygroup, order)
obj.help = help
obj.keygroup = keygroup
obj.order = order
--debug("creating command: ["..tostring(keydef).."] keygroup:["..(keygroup or "").."] help:"..help)
--Debug("creating command: ["..tostring(keydef).."] keygroup:["..(keygroup or "").."] help:"..help)
return obj
end
@ -165,22 +166,73 @@ function Commands:new(obj)
obj:add(KEY_INTO_SCREEN_SAVER, nil, "Slider",
"toggle screen saver",
function()
Screen:saveCurrentBB()
InfoMessage:show("Going into screensaver... ", 0)
Screen.kpv_rotation_mode = Screen.cur_rotation_mode
fb:setOrientation(Screen.native_rotation_mode)
util.sleep(1)
os.execute("killall -cont cvm")
--os.execute("echo 'screensaver in' >> /mnt/us/event_test.txt")
if G_charging_mode == false and G_screen_saver_mode == false then
logBatteryLevel("SLEEP")
Screen:saveCurrentBB()
InfoMessage:inform("Going into screensaver... ", DINFO_NODELAY, 0, MSG_AUX)
Screen.kpv_rotation_mode = Screen.cur_rotation_mode
fb:setOrientation(Screen.native_rotation_mode)
util.sleep(1)
os.execute("killall -cont cvm")
G_screen_saver_mode = true
end
end
)
obj:add(KEY_OUTOF_SCREEN_SAVER, nil, "Slider",
"toggle screen saver",
function()
util.usleep(1500000)
os.execute("killall -stop cvm")
fb:setOrientation(Screen.kpv_rotation_mode)
Screen:restoreFromSavedBB()
fb:refresh(0)
--os.execute("echo 'screensaver out' >> /mnt/us/event_test.txt")
if G_screen_saver_mode == true and G_charging_mode == false then
logBatteryLevel("WAKEUP")
util.usleep(1500000)
os.execute("killall -stop cvm")
fb:setOrientation(Screen.kpv_rotation_mode)
Screen:restoreFromSavedBB()
fb:refresh(0)
end
G_screen_saver_mode = false
end
)
obj:add(KEY_CHARGING, nil, "plugin/out usb",
"toggle usb drive mode",
function()
--os.execute("echo 'usb in' >> /mnt/us/event_test.txt")
if G_charging_mode == false and G_screen_saver_mode == false then
logBatteryLevel("USB PLUG")
Screen:saveCurrentBB()
Screen.kpv_rotation_mode = Screen.cur_rotation_mode
fb:setOrientation(Screen.native_rotation_mode)
InfoMessage:inform("Going into USB mode... ", DINFO_NODELAY, 0, MSG_AUX)
util.sleep(1)
os.execute("killall -cont cvm")
end
G_charging_mode = true
end
)
obj:add(KEY_NOT_CHARGING, nil, "plugin/out usb",
"toggle usb drive mode",
function()
--os.execute("echo 'usb out' >> /mnt/us/event_test.txt")
if G_charging_mode == true and G_screen_saver_mode == false then
util.usleep(1500000)
os.execute("killall -stop cvm")
fb:setOrientation(Screen.kpv_rotation_mode)
Screen:restoreFromSavedBB()
fb:refresh(0)
logBatteryLevel("USB UNPLUG")
end
FileChooser:setPath(FileChooser.path)
FileChooser.pagedirty = true
G_charging_mode = false
end
)
-- Shift+P would be overwritten in inputbox by entering char 'P'
-- I suggest one should probably change the hotkey to, say, Alt+Space
obj:add(KEY_P, MOD_SHIFT, "P", "make screenshot",
function()
logBatteryLevel("SCREENSHOT")
Screen:screenshot()
end
)
return obj

@ -17,6 +17,9 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef DEBUG_CRENGINE
#define DEBUG_CRENGINE 0
#endif
extern "C" {
#include "blitbuffer.h"
@ -32,6 +35,13 @@ typedef struct CreDocument {
ldomDocument *dom_doc;
} CreDocument;
static int initCache(lua_State *L) {
int cache_size = luaL_optint(L, 1, (2 << 20) * 64); // 64Mb on disk cache for DOM
ldomDocCache::init(lString16("./cr3cache"), cache_size);
return 0;
}
static int openDocument(lua_State *L) {
const char *file_name = luaL_checkstring(L, 1);
@ -117,28 +127,29 @@ static int getPageFromXPointer(lua_State *L) {
return 1;
}
static int getCurrentPos(lua_State *L) {
static int getPosFromXPointer(lua_State *L) {
CreDocument *doc = (CreDocument*) luaL_checkudata(L, 1, "credocument");
const char *xpointer_str = luaL_checkstring(L, 2);
lua_pushinteger(L, doc->text_view->GetPos());
int pos = 0;
ldomXPointer xp = doc->dom_doc->createXPointer(lString16(xpointer_str));
lvPoint pt = xp.toPoint();
if (pt.y > 0) {
pos = pt.y;
}
lua_pushinteger(L, pos);
return 1;
}
//static int getPosFromXPointer(lua_State *L) {
//CreDocument *doc = (CreDocument*) luaL_checkudata(L, 1, "credocument");
//const char *xpointer_str = luaL_checkstring(L, 2);
//lvRect rc;
//int pos;
static int getCurrentPos(lua_State *L) {
CreDocument *doc = (CreDocument*) luaL_checkudata(L, 1, "credocument");
//ldomXPointer *xp = NULL;
//xp = doc->dom_doc->createXPointer(lString16(xpointer_str));
//getCursorDocRect(*xp, rc);
//pos =
lua_pushinteger(L, doc->text_view->GetPos());
//return 1;
//}
return 1;
}
static int getCurrentPercent(lua_State *L) {
CreDocument *doc = (CreDocument*) luaL_checkudata(L, 1, "credocument");
@ -308,10 +319,6 @@ static int gotoXPointer(lua_State *L) {
ldomXPointer xp = doc->dom_doc->createXPointer(lString16(xpointer_str));
doc->text_view->goToBookmark(xp);
/* CREngine does not call checkPos() immediately after goToBookmark,
* so I have to manually update the pos in order to get a correct
* return from GetPos() call. */
doc->text_view->SetPos(xp.toPoint().y);
return 0;
}
@ -385,6 +392,91 @@ static int cursorRight(lua_State *L) {
return 0;
}
static int getPageLinks(lua_State *L) {
CreDocument *doc = (CreDocument*) luaL_checkudata(L, 1, "credocument");
lua_newtable(L); // all links
ldomXRangeList links;
ldomXRangeList & sel = doc->text_view->getDocument()->getSelections();
doc->text_view->getCurrentPageLinks( links );
int linkCount = links.length();
if ( linkCount ) {
sel.clear();
for ( int i=0; i<linkCount; i++ ) {
lString16 txt = links[i]->getRangeText();
lString8 txt8 = UnicodeToLocal( txt );
lString16 link = links[i]->getHRef();
lString8 link8 = UnicodeToLocal( link );
ldomXRange currSel;
currSel = *links[i];
lvPoint start_pt ( currSel.getStart().toPoint() );
lvPoint end_pt ( currSel.getEnd().toPoint() );
CRLog::debug("# link %d start %d %d end %d %d '%s' %s\n", i,
start_pt.x, start_pt.y, end_pt.x, end_pt.y,
txt8.c_str(), link8.c_str()
);
lua_newtable(L); // new link
lua_pushstring(L, "start_x");
lua_pushinteger(L, start_pt.x);
lua_settable(L, -3);
lua_pushstring(L, "start_y");
lua_pushinteger(L, start_pt.y);
lua_settable(L, -3);
lua_pushstring(L, "end_x");
lua_pushinteger(L, end_pt.x);
lua_settable(L, -3);
lua_pushstring(L, "end_y");
lua_pushinteger(L, end_pt.y);
lua_settable(L, -3);
const char * link_to = link8.c_str();
if ( link_to[0] == '#' ) {
lua_pushstring(L, "section");
lua_pushstring(L, link_to);
lua_settable(L, -3);
sel.add( new ldomXRange(*links[i]) ); // highlight
} else {
lua_pushstring(L, "uri");
lua_pushstring(L, link_to);
lua_settable(L, -3);
}
lua_rawseti(L, -2, i + 1);
}
doc->text_view->updateSelections();
}
return 1;
}
static int gotoLink(lua_State *L) {
CreDocument *doc = (CreDocument*) luaL_checkudata(L, 1, "credocument");
const char *pos = luaL_checkstring(L, 2);
doc->text_view->goLink(lString16(pos), true);
return 0;
}
static int clearSelection(lua_State *L) {
CreDocument *doc = (CreDocument*) luaL_checkudata(L, 1, "credocument");
doc->text_view->clearSelection();
return 0;
}
static int drawCurrentPage(lua_State *L) {
CreDocument *doc = (CreDocument*) luaL_checkudata(L, 1, "credocument");
DrawContext *dc = (DrawContext*) luaL_checkudata(L, 2, "drawcontext");
@ -427,7 +519,75 @@ static int registerFont(lua_State *L) {
return 0;
}
// ported from Android UI kpvcrlib/crengine/android/jni/docview.cpp
static int findText(lua_State *L) {
CreDocument *doc = (CreDocument*) luaL_checkudata(L, 1, "credocument");
const char *l_pattern = luaL_checkstring(L, 2);
lString16 pattern = lString16(l_pattern);
int origin = luaL_checkint(L, 3);
bool reverse = luaL_checkint(L, 4);
bool caseInsensitive = luaL_checkint(L, 5);
if ( pattern.empty() )
return 0;
LVArray<ldomWord> words;
lvRect rc;
doc->text_view->GetPos( rc );
int pageHeight = rc.height();
int start = -1;
int end = -1;
if ( reverse ) {
// reverse
if ( origin == 0 ) {
// from end current page to first page
end = rc.bottom;
} else if ( origin == -1 ) {
// from last page to end of current page
start = rc.bottom;
} else { // origin == 1
// from prev page to first page
end = rc.top;
}
} else {
// forward
if ( origin == 0 ) {
// from current page to last page
start = rc.top;
} else if ( origin == -1 ) {
// from first page to current page
end = rc.top;
} else { // origin == 1
// from next page to last
start = rc.bottom;
}
}
CRLog::debug("CRViewDialog::findText: Current page: %d .. %d", rc.top, rc.bottom);
CRLog::debug("CRViewDialog::findText: searching for text '%s' from %d to %d origin %d", LCSTR(pattern), start, end, origin );
if ( doc->text_view->getDocument()->findText( pattern, caseInsensitive, reverse, start, end, words, 200, pageHeight ) ) {
CRLog::debug("CRViewDialog::findText: pattern found");
doc->text_view->clearSelection();
doc->text_view->selectWords( words );
ldomMarkedRangeList * ranges = doc->text_view->getMarkedRanges();
if ( ranges ) {
if ( ranges->length()>0 ) {
int pos = ranges->get(0)->start.y;
//doc->text_view->SetPos(pos); // commented out not to mask lua code which does the same
CRLog::debug("# SetPos = %d", pos);
lua_pushinteger(L, ranges->length()); // results found
lua_pushinteger(L, pos);
return 2;
}
}
return 0;
}
CRLog::debug("CRViewDialog::findText: pattern not found");
return 0;
}
static const struct luaL_Reg cre_func[] = {
{"initCache", initCache},
{"openDocument", openDocument},
{"getFontFaces", getFontFaces},
{"getGammaIndex", getGammaIndex},
@ -441,6 +601,7 @@ static const struct luaL_Reg credocument_meth[] = {
{"getPages", getNumberOfPages},
{"getCurrentPage", getCurrentPage},
{"getPageFromXPointer", getPageFromXPointer},
{"getPosFromXPointer", getPosFromXPointer},
{"getCurrentPos", getCurrentPos},
{"getCurrentPercent", getCurrentPercent},
{"getXPointer", getXPointer},
@ -461,6 +622,10 @@ static const struct luaL_Reg credocument_meth[] = {
//{"cursorLeft", cursorLeft},
//{"cursorRight", cursorRight},
{"drawCurrentPage", drawCurrentPage},
{"findText", findText},
{"getPageLinks", getPageLinks},
{"gotoLink", gotoLink},
{"clearSelection", clearSelection},
{"close", closeDocument},
{"__gc", closeDocument},
{NULL, NULL}
@ -479,7 +644,7 @@ int luaopen_cre(lua_State *L) {
/* initialize font manager for CREngine */
InitFontManager(lString8());
#ifdef DEBUG_CRENGINE
#if DEBUG_CRENGINE
CRLog::setStdoutLogger();
CRLog::setLogLevel(CRLog::LL_DEBUG);
#endif

@ -2,6 +2,7 @@ require "font"
require "unireader"
require "inputbox"
require "selectmenu"
require "dialog"
CREReader = UniReader:new{
pos = nil,
@ -9,6 +10,8 @@ CREReader = UniReader:new{
gamma_index = 15,
font_face = nil,
default_font = "Droid Sans",
font_zoom = 0,
line_space_percent = 100,
}
@ -16,33 +19,74 @@ CREReader = UniReader:new{
function CREReader:init()
self:addAllCommands()
self:adjustCreReaderCommands()
-- initialize cache
cre.initCache(1024*1024*64)
-- we need to initialize the CRE font list
local fonts = Font:getFontList()
for _k, _v in ipairs(fonts) do
local ok, err = pcall(cre.registerFont, Font.fontdir..'/'.._v)
if not ok then
debug(err)
if _v ~= "Dingbats.cff" and _v ~= "StandardSymL.cff" then
local ok, err = pcall(cre.registerFont, Font.fontdir..'/'.._v)
if not ok then
Debug(err)
end
end
end
local default_font = G_reader_settings:readSetting("cre_font")
if default_font then
self.default_font = default_font
end
end
-- inspect the zipfile content
function CREReader:ZipContentExt(fname)
local i, s = 1
local tmp = io.popen('unzip -l \"'..fname..'\"', "r")
while true do
s = tmp:read("*line")
if i > 3 then tmp:close(); break; end
i = i + 1
end
if s then
local ext = string.match(s, ".+%.([^.]+)")
if ext then
ext = string.lower(ext)
return ext
end
end
return nil
end
-- open a CREngine supported file and its settings store
function CREReader:open(filename)
local ok
local file_type = string.lower(string.match(filename, ".+%.([^.]+)"))
local file_type = string.lower(string.match(filename, ".+%.([^.]+)") or "")
-- check zips for potential problems - wrong zip & wrong content
if file_type == "zip" then
file_type = self:ZipContentExt(filename)
end
if not file_type then
return false, "Error unzipping file. "
end
-- if the zip entry is not cre-document
if ReaderChooser:getReaderByType(file_type) ~= CREReader then
return false, "Zip contains improper content. "
end
-- these two format use the same css file
if file_type == "html" then
file_type = "htm"
end
-- if native css-file doesn't exist, one needs to use default cr3.css
if not io.open("./data/"..file_type..".css") then
file_type = "cr3"
end
local style_sheet = "./data/"..file_type..".css"
ok, self.doc = pcall(cre.openDocument, filename, style_sheet,
G_width, G_height)
ok, self.doc = pcall(cre.openDocument, filename, style_sheet, G_width, G_height)
if not ok then
return false, self.doc -- will contain error message
return false, "Error opening cre-document. " -- self.doc, will contain error message
end
self.doc:setDefaultInterlineSpace(self.line_space_percent)
return true
end
@ -51,7 +95,10 @@ end
----------------------------------------------------
function CREReader:loadSpecialSettings()
local font_face = self.settings:readSetting("font_face")
self.font_face = font_face or "FreeSerif"
if not font_face then
font_face = self.default_font
end
self.font_face = font_face
self.doc:setFontFace(self.font_face)
local gamma_index = self.settings:readSetting("gamma_index")
@ -60,10 +107,20 @@ function CREReader:loadSpecialSettings()
local line_space_percent = self.settings:readSetting("line_space_percent")
self.line_space_percent = line_space_percent or self.line_space_percent
self.font_zoom = self.settings:readSetting("font_zoom") or 0
if self.font_zoom ~= 0 then
local i = math.abs(self.font_zoom)
local step = self.font_zoom / i
while i>0 do
self.doc:zoomFont(step)
i=i-1
end
end
end
function CREReader:getLastPageOrPos()
local last_percent = self.settings:readSetting("last_percent")
local last_percent = self.settings:readSetting("last_percent")
if last_percent then
return math.floor((last_percent * self.doc:getFullHeight()) / 10000)
else
@ -75,6 +132,7 @@ function CREReader:saveSpecialSettings()
self.settings:saveSetting("font_face", self.font_face)
self.settings:saveSetting("gamma_index", self.gamma_index)
self.settings:saveSetting("line_space_percent", self.line_space_percent)
self.settings:saveSetting("font_zoom", self.font_zoom)
end
function CREReader:saveLastPageOrPos()
@ -104,42 +162,43 @@ end
function CREReader:goto(pos, is_ignore_jump, pos_type)
local prev_xpointer = self.doc:getXPointer()
local width, height = G_width, G_height
if pos_type == "xpointer" then
self.doc:gotoXPointer(pos)
pos = self.doc:getCurrentPos()
elseif pos_type == "link" then
self.doc:gotoLink(pos)
pos = self.doc:getCurrentPos()
else -- pos_type is position within document
pos = math.min(pos, self.doc:getFullHeight() - height)
pos = math.max(pos, 0)
self.doc:gotoPos(pos)
end
-- add to jump history, distinguish jump from normal page turn
-- NOTE:
-- even though we have called gotoPos() or gotoXPointer() previously,
-- even though we have called gotoPos() or gotoXPointer() previously,
-- self.pos hasn't been updated yet here, so we can still make use of it.
if not is_ignore_jump then
if self.pos and math.abs(self.pos - pos) > height then
self:addJump(prev_xpointer)
end
end
self.doc:drawCurrentPage(self.nulldc, fb.bb)
debug("## self.show_overlap "..self.show_overlap)
if self.show_overlap < 0 then
Debug("## self.show_overlap "..self.show_overlap)
if self.show_overlap < 0 and self.show_overlap_enable then
fb.bb:dimRect(0,0, width, -self.show_overlap)
elseif self.show_overlap > 0 then
elseif self.show_overlap > 0 and self.show_overlap_enable then
fb.bb:dimRect(0,height - self.show_overlap, width, self.show_overlap)
end
self.show_overlap = 0
if self.rcount >= self.rcountmax then
debug("full refresh")
Debug("full refresh")
self.rcount = 0
fb:refresh(0)
else
debug("partial refresh")
Debug("partial refresh")
self.rcount = self.rcount + 1
fb:refresh(1)
end
@ -188,8 +247,7 @@ function CREReader:showJumpHist()
end
if #menu_items == 0 then
showInfoMsgWithDelay(
"No jump history found.", 2000, 1)
InfoMessage:inform("No jump history found ", DINFO_DELAY, 1, MSG_WARN)
else
-- if cur points to head, draw entry for current page
if self.jump_history.cur > #self.jump_history then
@ -201,7 +259,7 @@ function CREReader:showJumpHist()
menu_title = "Jump History",
item_array = menu_items,
}
item_no = jump_menu:choose(0, fb.bb:getHeight())
item_no = jump_menu:choose(0, G_height)
if item_no and item_no <= #self.jump_history then
local jump_item = self.jump_history[item_no]
self.jump_history.cur = item_no
@ -215,8 +273,38 @@ end
----------------------------------------------------
-- bookmarks related methods
----------------------------------------------------
function CREReader:isBookmarkInSequence(a, b)
return self.doc:getPosFromXPointer(a.page) < self.doc:getPosFromXPointer(b.page)
end
function CREReader:nextBookMarkedPage()
for k,v in ipairs(self.bookmarks) do
if self.pos < self.doc:getPosFromXPointer(v.page) then
return v
end
end
return nil
end
function CREReader:prevBookMarkedPage()
local pre_item = nil
for k,v in ipairs(self.bookmarks) do
if self.pos <= self.doc:getPosFromXPointer(v.page) then
if not pre_item then
break
elseif self.doc:getPosFromXPointer(pre_item.page) < self.pos then
return pre_item
end
end
pre_item = v
end
return pre_item
end
function CREReader:showBookMarks()
local menu_items = {}
local ret_code, item_no = -1, -1
-- build menu items
for k,v in ipairs(self.bookmarks) do
table.insert(menu_items,
@ -224,23 +312,29 @@ function CREReader:showBookMarks()
.." "..v.notes.." @ "..v.datetime)
end
if #menu_items == 0 then
showInfoMsgWithDelay(
"No bookmark found.", 2000, 1)
else
toc_menu = SelectMenu:new{
menu_title = "Bookmarks",
return InfoMessage:inform("No bookmark found ", DINFO_DELAY, 1, MSG_WARN)
end
while true do
local bkmk_menu = SelectMenu:new{
menu_title = "Bookmarks ("..tostring(#menu_items).." items)",
item_array = menu_items,
deletable = true,
}
item_no = toc_menu:choose(0, fb.bb:getHeight())
if item_no then
self:goto(self.bookmarks[item_no].page, nil, "xpointer")
else
self:redrawCurrentPage()
ret_code, item_no = bkmk_menu:choose(0, G_height)
if ret_code then -- normal item selection
return self:goto(self.bookmarks[ret_code].page, nil, "xpointer")
elseif item_no then -- delete item
table.remove(menu_items, item_no)
table.remove(self.bookmarks, item_no)
if #menu_items == 0 then
return self:redrawCurrentPage()
end
else -- return via Back
return self:redrawCurrentPage()
end
end
end
----------------------------------------------------
-- TOC related methods
----------------------------------------------------
@ -259,36 +353,100 @@ function CREReader:getTocTitleOfCurrentPage()
return self:getTocTitleByPage(self.doc:getXPointer())
end
--[[ function to scroll chapters without calling TOC-menu,
direction is either +1 (next chapter) or -1 (previous one).
Jump over several chapters is principally possible when direction > 1 ]]
function CREReader:gotoPrevNextTocEntry(direction)
if not self.toc then
self:fillToc()
end
if #self.toc == 0 then
InfoMessage:inform("No Table of Contents ", DINFO_DELAY, 1, MSG_WARN)
return
end
-- search for current TOC-entry
local item_no = 0
for k,v in ipairs(self.toc) do
if v.page <= self.pageno then
item_no = item_no + 1
else
break
end
end
-- minor correction when current page is not the page opening current chapter
if self.pageno > self.toc[item_no].page and direction < 0 then
direction = direction + 1
end
-- define the jump target
item_no = item_no + direction
if item_no > #self.toc then -- jump to last page
self:goto(self.doc:getFullHeight()-G_height)
elseif item_no > 0 then
self:gotoTocEntry(self.toc[item_no])
else
self:goto(0) -- jump to first page
end
end
----------------------------------------------------
-- menu related methods
----------------------------------------------------
-- used in CREReader:showMenu()
function CREReader:_drawReadingInfo()
local ypos = G_height - 50
local width = G_width
local load_percent = self.percent/100
fb.bb:paintRect(0, ypos, G_width, 50, 0)
local rss, data, stack, lib, totalvm = memUsage()
local face = Font:getFace("rifont", 20)
-- display page number, date and memory stats at the top
fb.bb:paintRect(0, 0, width, 40+6*2, 0)
renderUtf8Text(fb.bb, 10, 15+6, face, "p."..self.pageno.."/"..self.doc:getPages(), true)
local txt = os.date("%a %d %b %Y %T").." ["..BatteryLevel().."]"
local w = sizeUtf8Text(0, width, face, txt, true).x
renderUtf8Text(fb.bb, width - w - 10, 15+6, face, txt, true)
renderUtf8Text(fb.bb, 10, 15+6+22, face,
"RSS:"..rss.." DAT:"..data.." STK:"..stack.." LIB:"..lib.." TOT:"..totalvm.."k", true)
-- display reading progress at the bottom
local ypos = G_height - 50
fb.bb:paintRect(0, ypos, width, 50, 0)
ypos = ypos + 15
local face = Font:getFace("rifont", 22)
local cur_section = self:getTocTitleOfCurrentPage()
if cur_section ~= "" then
cur_section = "Section: "..cur_section
cur_section = " Sec: "..cur_section
end
local footer = load_percent.."%"..cur_section
if sizeUtf8Text(10, fb.bb:getWidth(), face, footer, true).x < (fb.bb:getWidth() - 20) then
renderUtf8Text(fb.bb, 10, ypos+6, face, footer, true)
else
local gapx = sizeUtf8Text(10, fb.bb:getWidth(), face, "...", true).x
gapx = 10 + renderUtf8TextWidth(fb.bb, 10, ypos+6, face, footer, true, fb.bb:getWidth() - 30 - gapx).x
renderUtf8Text(fb.bb, gapx, ypos+6, face, "...", true)
end
renderUtf8Text(fb.bb, 10, ypos+6, face,
"Position: "..load_percent.."%".." "..cur_section, true)
ypos = ypos + 15
blitbuffer.progressBar(fb.bb, 10, ypos, G_width - 20, 15,
5, 4, load_percent/100, 8)
blitbuffer.progressBar(fb.bb, 10, ypos, width - 20, 15, 5, 4, load_percent/100, 8)
end
function CREReader:showMenu()
self:_drawReadingInfo()
fb:refresh(1)
while true do
local ev = input.saveWaitForEvent()
ev.code = adjustKeyEvents(ev)
if ev.type == EV_KEY and ev.value == EVENT_VALUE_KEY_PRESS then
if ev.code == KEY_BACK or ev.code == KEY_MENU then
return
end
end
end
end
function CREReader:adjustCreReaderCommands()
-- delete commands
self.commands:delGroup("[joypad]")
self.commands:delGroup(MOD_ALT.."H/J")
self.commands:del(KEY_G, nil, "G")
self.commands:del(KEY_J, MOD_SHIFT, "J")
self.commands:del(KEY_K, MOD_SHIFT, "K")
@ -307,25 +465,79 @@ function CREReader:adjustCreReaderCommands()
self.commands:del(KEY_X, nil, "X")
self.commands:del(KEY_F, MOD_SHIFT, "F")
self.commands:del(KEY_F, MOD_ALT, "F")
self.commands:del(KEY_N, nil, "N") -- highlight
self.commands:del(KEY_N, MOD_SHIFT, "N") -- show highlights
-- overwrite commands
self.commands:del(KEY_N, nil, "N")
self.commands:del(KEY_N, MOD_SHIFT, "N")
self.commands:del(KEY_X, MOD_SHIFT, "X")
self.commands:del(KEY_L, MOD_SHIFT, "L")
self.commands:del(KEY_M, nil, "M")
self.commands:del(KEY_U, nil,"U")
self.commands:del(KEY_C, nil, "C")
self.commands:del(KEY_P, nil, "P")
-- CCW-rotation
self.commands:add(KEY_K, nil, "K",
"rotate screen counterclockwise",
function(self)
local prev_xpointer = self.doc:getXPointer()
Screen:screenRotate("anticlockwise")
G_width, G_height = fb:getSize()
self:goto(prev_xpointer, nil, "xpointer")
self.pos = self.doc:getCurrentPos()
end
)
-- CW-rotation
self.commands:add(KEY_J, nil, "J",
"rotate screen clockwise",
function(self)
local prev_xpointer = self.doc:getXPointer()
Screen:screenRotate("clockwise")
G_width, G_height = fb:getSize()
self:goto(prev_xpointer, nil, "xpointer")
self.pos = self.doc:getCurrentPos()
end
)
-- navigate between chapters by Shift+Up & Shift-Down
self.commands:addGroup(MOD_SHIFT.."up/down",{
Keydef:new(KEY_FW_UP,MOD_SHIFT), Keydef:new(KEY_FW_DOWN,MOD_SHIFT)},
"scroll to previous/next chapter",
function(self)
if keydef.keycode == KEY_FW_UP then
self:gotoPrevNextTocEntry(-1)
else
self:gotoPrevNextTocEntry(1)
end
end
)
-- fast navigation by Shift+Left & Shift-Right
local scrollpages = 10
self.commands:addGroup(MOD_SHIFT.."left/right",
{Keydef:new(KEY_FW_LEFT,MOD_SHIFT),Keydef:new(KEY_FW_RIGHT,MOD_SHIFT)},
"scroll "..scrollpages.." pages backwards/forward",
function(self)
if keydef.keycode == KEY_FW_LEFT then
self:goto(math.max(0, self.pos - scrollpages*G_height))
else
self:goto(math.min(self.pos + scrollpages*G_height, self.doc:getFullHeight()-G_height))
end
end
)
self.commands:addGroup(MOD_SHIFT.."< >",{
Keydef:new(KEY_PGBCK,MOD_SHIFT),Keydef:new(KEY_PGFWD,MOD_SHIFT),
Keydef:new(KEY_LPGBCK,MOD_SHIFT),Keydef:new(KEY_LPGFWD,MOD_SHIFT)},
"increase/decrease font size",
function(self)
local delta = 1
local change = "increase"
local change = "Increasing"
if keydef.keycode == KEY_PGBCK or keydef.keycode == KEY_LPGBCK then
delta = -1
change = "decrease"
change = "Decreasing"
end
InfoMessage:show(change.." font size", 0)
self.font_zoom = self.font_zoom + delta
InfoMessage:inform(change.." font size to "..self.font_zoom..". ", DINFO_NODELAY, 1, MSG_AUX)
Debug("font zoomed to", self.font_zoom)
local prev_xpointer = self.doc:getXPointer()
self.doc:zoomFont(delta)
self:redrawCurrentPage()
self:goto(prev_xpointer, nil, "xpointer")
end
)
self.commands:addGroup(MOD_ALT.."< >",{
@ -335,62 +547,87 @@ function CREReader:adjustCreReaderCommands()
function(self)
if keydef.keycode == KEY_PGBCK or keydef.keycode == KEY_LPGBCK then
self.line_space_percent = self.line_space_percent - 10
if self.line_space_percent < 100 then
self.line_space_percent = 100
end
self.line_space_percent = math.max(self.line_space_percent, 80)
else
self.line_space_percent = self.line_space_percent + 10
if self.line_space_percent > 200 then
self.line_space_percent = 200
end
self.line_space_percent = math.min(self.line_space_percent, 200)
end
InfoMessage:show("line spacing "..self.line_space_percent.."%", 0)
debug("line spacing set to", self.line_space_percent)
InfoMessage:inform("Changing line space to "..self.line_space_percent.."% ", DINFO_NODELAY, 1, MSG_AUX)
Debug("line spacing set to", self.line_space_percent)
local prev_xpointer = self.doc:getXPointer()
self.doc:setDefaultInterlineSpace(self.line_space_percent)
self:redrawCurrentPage()
self:goto(prev_xpointer, nil, "xpointer")
end
)
local numeric_keydefs = {}
for i=1,10 do
numeric_keydefs[i]=Keydef:new(KEY_1+i-1, nil, tostring(i%10))
for i=1,10 do
numeric_keydefs[i]=Keydef:new(KEY_1+i-1, nil, tostring(i%10))
end
self.commands:addGroup("[1..0]", numeric_keydefs,
"jump to <key>*10% of document",
self.commands:addGroup("[1, 2 .. 9, 0]",numeric_keydefs,
"jump to 0%, 10% .. 90%, 100% of document",
function(self, keydef)
debug('jump to position: '..
Debug('jump to position: '..
math.floor(self.doc:getFullHeight()*(keydef.keycode-KEY_1)/9)..
'/'..self.doc:getFullHeight())
self:goto(math.floor(self.doc:getFullHeight()*(keydef.keycode-KEY_1)/9))
end
)
self.commands:add(KEY_F, nil, "F",
self.commands:add(KEY_G,nil,"G",
"open 'go to position' input box",
function(unireader)
local height = self.doc:getFullHeight()
local position = NumInputBox:input(G_height-100, 100,
"Position in percent:", "current: "..math.floor((self.pos / height)*100), true)
-- convert string to number
if position and pcall(function () position = position + 0 end) then
if position >= 0 and position <= 100 then
self:goto(math.floor(height * position / 100))
return
end
end
self:redrawCurrentPage()
end
)
self.commands:add({KEY_F, KEY_AA}, nil, "F",
"change document font",
function(self)
Screen:saveCurrentBB()
local face_list = cre.getFontFaces()
-- define the current font in face_list
local item_no = 0
while face_list[item_no] ~= self.font_face and item_no < #face_list do
item_no = item_no + 1
end
local fonts_menu = SelectMenu:new{
menu_title = "Fonts Menu",
item_array = face_list,
menu_title = "Fonts Menu ",
item_array = face_list,
current_entry = item_no - 1,
}
local item_no = fonts_menu:choose(0, G_height)
debug(face_list[item_no])
item_no = fonts_menu:choose(0, G_height)
local prev_xpointer = self.doc:getXPointer()
if item_no then
Screen:restoreFromSavedBB()
Debug(face_list[item_no])
InfoMessage:inform("Redrawing with "..face_list[item_no].." ", DINFO_NODELAY, 1, MSG_AUX)
self.doc:setFontFace(face_list[item_no])
self.font_face = face_list[item_no]
InfoMessage:show("Redrawing with "..face_list[item_no], 0)
end
self:redrawCurrentPage()
self:goto(prev_xpointer, nil, "xpointer")
end
)
self.commands:add(KEY_F, MOD_SHIFT, "F",
"use document font as default font",
function(self)
self.default_font = self.font_face
G_reader_settings:saveSetting("cre_font", self.font_face)
InfoMessage:inform("Default document font set ", DINFO_DELAY, 1, MSG_WARN)
end
)
self.commands:add(KEY_F, MOD_ALT, "F",
"Toggle font bolder attribute",
"toggle font-weight: bold <> normal",
function(self)
InfoMessage:inform("Changing font-weight...", DINFO_NODELAY, 1, MSG_AUX)
local prev_xpointer = self.doc:getXPointer()
self.doc:toggleFontBolder()
self:redrawCurrentPage()
self:goto(prev_xpointer, nil, "xpointer")
end
)
self.commands:add(KEY_B, MOD_ALT, "B",
@ -398,21 +635,41 @@ function CREReader:adjustCreReaderCommands()
function(self)
ok = self:addBookmark(self.doc:getXPointer())
if not ok then
showInfoMsgWithDelay("Page already marked!", 2000, 1)
InfoMessage:drawTopMsg("Bookmark already exists")
else
showInfoMsgWithDelay("Page marked.", 2000, 1)
InfoMessage:drawTopMsg("Bookmark added")
end
end
)
self.commands:addGroup(MOD_ALT.."K/L",{
Keydef:new(KEY_K,MOD_ALT), Keydef:new(KEY_L,MOD_ALT)},
"Jump between bookmarks",
function(unireader,keydef)
local bm = nil
if keydef.keycode == KEY_K then
bm = self:prevBookMarkedPage()
else
bm = self:nextBookMarkedPage()
end
if bm then self:goto(bm.page, true, "xpointer") end
end)
self.commands:add(KEY_BACK, nil, "Back",
"go backward in jump history",
function(self)
local prev_jump_no = self.jump_history.cur - 1
local prev_jump_no = 0
if self.jump_history.cur > #self.jump_history then
-- if cur points to head, put current page in history
self:addJump(self.doc:getXPointer())
prev_jump_no = self.jump_history.cur - 2
else
prev_jump_no = self.jump_history.cur - 1
end
if prev_jump_no >= 1 then
self.jump_history.cur = prev_jump_no
self:goto(self.jump_history[prev_jump_no].page, true, "xpointer")
else
showInfoMsgWithDelay("Already first jump!", 2000, 1)
InfoMessage:inform("Already first jump ", DINFO_DELAY, 1, MSG_WARN)
end
end
)
@ -424,7 +681,7 @@ function CREReader:adjustCreReaderCommands()
self.jump_history.cur = next_jump_no
self:goto(self.jump_history[next_jump_no].page, true, "xpointer")
else
showInfoMsgWithDelay("Already last jump!", 2000, 1)
InfoMessage:inform("Already last jump ", DINFO_DELAY, 1, MSG_WARN)
end
end
)
@ -438,6 +695,7 @@ function CREReader:adjustCreReaderCommands()
end
cre.setGammaIndex(self.gamma_index+delta)
self.gamma_index = cre.getGammaIndex()
InfoMessage:inform("Changing gamma to "..self.gamma_index..". ", DINFO_NODELAY, 1, MSG_AUX)
self:redrawCurrentPage()
end
)
@ -454,3 +712,52 @@ function CREReader:adjustCreReaderCommands()
end
)
end
----------------------------------------------------
--- search
----------------------------------------------------
function CREReader:searchHighLight(search)
Debug("FIXME CreReader::searchHighLight", search)
if self.last_search == nil or self.last_search.search == nil then
self.last_search = {
search = "",
}
end
local origin = 0 -- 0=current 1=next-last -1=first-current
if self.last_search.search == search then
origin = 1
end
local found, pos = self.doc:findText(
search,
origin,
0, -- reverse: boolean
1 -- caseInsensitive: boolean
)
if found then
self.pos = pos -- first metch position
self:redrawCurrentPage()
InfoMessage:inform( found.." hits '"..search.."' pos "..pos, DINFO_DELAY, 1, MSG_WARN)
else
InfoMessage:inform( "'"..search.."' not found in document ", DINFO_DELAY, 1, MSG_WARN)
end
self.last_search.search = search
end
----------------------------------------------------
--- page links
----------------------------------------------------
function CREReader:getPageLinks()
local links = self.doc:getPageLinks()
Debug("getPageLinks", links)
return links
end
function CREReader:clearSelection()
Debug("clearSelection")
self.doc:clearSelection()
end

@ -0,0 +1,94 @@
-- framebuffer update policy state:
DRCOUNT = 5
-- default to full refresh on every page turn
DRCOUNTMAX = 0
-- zoom state:
DGLOBALZOOM = 1.0
DGLOBALZOOM_ORIG = 1.0
DGLOBALZOOM_MODE = -1 -- ZOOM_FIT_TO_PAGE
DGLOBALROTATE = 0
-- gamma setting:
DGLOBALGAMMA = 1.0 -- GAMMA_NO_GAMMA
-- DjVu page rendering mode (used in djvu.c:drawPage())
-- See comments in djvureader.lua:DJVUReader:select_render_mode()
DRENDER_MODE = 0 -- COLOUR
-- set panning distance
DSHIFT_X = 100
DSHIFT_Y = 50
-- step to change zoom manually, default = 16%
DSTEP_MANUAL_ZOOM = 16
DPAN_BY_PAGE = false -- using shift_[xy] or width/height
DPAN_MARGIN = 5 -- horizontal margin for two-column zoom (in pixels)
DPAN_OVERLAP_VERTICAL = 30
-- tile cache configuration:
DCACHE_MAX_MEMSIZE = 1024*1024*5 -- 5MB tile cache
DCACHE_MAX_TTL = 20 -- time to live
-- renderer cache size
DCACHE_DOCUMENT_SIZE = 1024*1024*8 -- FIXME random, needs testing
-- default value for battery level logging
DBATTERY_LOGGING = false
-- background colour: 8 = gray, 0 = white, 15 = black
DBACKGROUND_COLOR = 8
-- delay for info messages in ms
DINFO_NODELAY=0
DINFO_DELAY=1500
-- toggle defaults
DUNIREADER_SHOW_OVERLAP_ENABLE = true
DUNIREADER_SHOW_LINKS_ENABLE = true
DUNIREADER_COMICS_MODE_ENABLE = true
DUNIREADER_RTL_MODE_ENABLE = false
DUNIREADER_PAGE_MODE_ENABLE = false
DDJVUREADER_SHOW_OVERLAP_ENABLE = true
DDJVUREADER_SHOW_LINKS_ENABLE = false
DDJVUREADER_COMICS_MODE_ENABLE = true
DDJVUREADER_RTL_MODE_ENABLE = false
DDJVUREADER_PAGE_MODE_ENABLE = false
DKOPTREADER_SHOW_OVERLAP_ENABLE = true
DKOPTREADER_SHOW_LINKS_ENABLE = false
DKOPTREADER_COMICS_MODE_ENABLE = false
DKOPTREADER_RTL_MODE_ENABLE = false
DKOPTREADER_PAGE_MODE_ENABLE = false
DPICVIEWER_SHOW_OVERLAP_ENABLE = false
DPICVIEWER_SHOW_LINKS_ENABLE = false
DPICVIEWER_COMICS_MODE_ENABLE = true
DPICVIEWER_RTL_MODE_ENABLE = false
DPICVIEWER_PAGE_MODE_ENABLE = false
-- koptreader config defaults
DKOPTREADER_CONFIG_FONT_SIZE = 1.0 -- range from 0.1 to 3.0
DKOPTREADER_CONFIG_TEXT_WRAP = 1 -- 1 = on, 0 = off
DKOPTREADER_CONFIG_TRIM_PAGE = 1 -- 1 = auto, 0 = manual
DKOPTREADER_CONFIG_DETECT_INDENT = 1 -- 1 = enable, 0 = disable
DKOPTREADER_CONFIG_DEFECT_SIZE = 1.0 -- range from 0.0 to 3.0
DKOPTREADER_CONFIG_PAGE_MARGIN = 0.06 -- range from 0.0 to 1.0
DKOPTREADER_CONFIG_LINE_SPACING = 1.2 -- range from 0.5 to 2.0
DKOPTREADER_CONFIG_WORD_SAPCING = 0.15 -- range from 0.05 to 0.5
DKOPTREADER_CONFIG_MULTI_THREADS = 1 -- 1 = on, 0 = off
DKOPTREADER_CONFIG_RENDER_QUALITY = 1.0 -- range from 0.5 to 1.0
DKOPTREADER_CONFIG_AUTO_STRAIGHTEN = 0 -- range from 0 to 10
DKOPTREADER_CONFIG_JUSTIFICATION = -1 -- -1 = auto, 0 = left, 1 = center, 2 = right, 3 = full
DKOPTREADER_CONFIG_MAX_COLUMNS = 2 -- range from 1 to 4
DKOPTREADER_CONFIG_CONTRAST = 1.0 -- range from 0.2 to 2.0
DKOPTREADER_CONFIG_SCREEN_ROTATION = 0 -- 0, 90, 180, 270 degrees
-- supported extensions
DPDFREADER_EXT = ";pdf;xps;cbz;zip;"
DDJVUREADER_EXT = ";djvu;"
DPDFREFLOW_EXT = ";pdf;"
DDJVUREFLOW_EXT = ";djvu;"
DCREREADER_EXT = ";epub;txt;rtf;htm;html;mobi;prc;azw;fb2;chm;pdb;doc;tcr;zip;" -- seems to accept pdb-files for PalmDoc only
DPICVIEWER_EXT = ";jpg;jpeg;"

@ -1,12 +1,47 @@
require "widget"
require "font"
-- some definitions for developers
MSG_AUX = 1
MSG_WARN = 2
MSG_ERROR = 3
MSG_CONFIRM = 4
MSG_BUG = 5
InfoMessage = {
face = Font:getFace("infofont", 25)
InfoMethod = { --[[
The items define how to inform user about various types of events, the values should be 0..3:
the lowest bit is responcible for showing popup windows,
while the 2nd bit allows using TTS-voice messages.
The current default values {1,1,1,1,1} correspond to previous kpdfviewer-settings
when every message is shown in popup window. ]]
1, -- auxiliary messages = 0 or 2 (nothing or TTS)
1, -- warnings = 1 or 2 (popup or TTS)
1, -- errors = 1 or 3 (popup or popup & TTS)
1, -- confirmations (must not be silent!) = 1 or 3 (popup or popup & TTS)
1, -- bugs (must not be silent!) = 1 or 3 (popup or popup & TTS)
},
-- images for various message types
Images = {
"resources/info-aux.png",
"resources/info-warn.png",
"resources/info-error.png",
"resources/info-confirm.png",
"resources/info-bug.png",
},
ImageFile = "resources/info-warn.png",
-- TTS-related parameters
TTSspeed = nil,
SoundVolume = nil,
--[[ as Kindle3-volume has nonlinear scale, one need to define the 'VolumeLevels'-values
TODO: test whether VolumeLevels are different for other sound-equipped Kindle models (K2, KDX)
by running self.VolumeLevels = self:getVolumeLevels() ]]
VolumeLevels = { 0, 1, 2, 4, 6, 7, 14, 21, 28, 35, 42, 49, 56, 63, 70, 77}
}
function InfoMessage:show(text,refresh_mode)
debug("# InfoMessage ", text, refresh_mode)
Debug("# InfoMessage ", text, refresh_mode)
local dialog = CenterContainer:new({
dimen = { w = G_width, h = G_height },
FrameContainer:new({
@ -15,14 +50,14 @@ function InfoMessage:show(text,refresh_mode)
HorizontalGroup:new({
align = "center",
ImageWidget:new({
file = "resources/info-i.png"
file = self.ImageFile
}),
Widget:new({
dimen = { w = 10, h = 0 }
}),
TextWidget:new({
text = text,
face = Font:getFace("cfont", 30)
face = Font:getFace("infofont", 30)
})
})
})
@ -55,3 +90,182 @@ function showInfoMsgWithDelay(text, msec, refresh_mode)
Screen:restoreFromSavedBB()
fb:refresh(refresh_mode)
end
--[[
Brief description of the function parameters
-- text : is the text message for visual and (if 'alternative_voice_message' isn't defined) voice notification
-- delay : parameter to define visual notification method
DINFO_NODELAY: display the message and return immediately (screen content not restored)
DINFO_DELAY: display the message and return after a delay (screen content restored)
-- msgtype : parameter separating various messages on
MSG_AUX - not obligatory messages that might be readily avoided
MSG_WARN - warnings (important messages)
MSG_ERROR - errors
MSG_CONFIRM - confirmations
MSG_BUG - bugs
-- tts_text: not obligatory parameter that allows to send longer messages to TTS-engine
if not defined, the default 'text' will be TTS-voiced
]]
function InfoMessage:inform(text, delay, refresh_mode, msgtype, tts_text)
local popup, voice = InfoMessage:getMethodForEvent(msgtype)
if voice then
say(tts_text or text)
end
if not popup then return end
self.ImageFile = self.Images[msgtype]
if delay == DINFO_NODELAY then
InfoMessage:show(text, refresh_mode)
if util.isEmulated() == 1 then util.usleep(500000) end
elseif delay == DINFO_DELAY then
showInfoMsgWithDelay(text, delay, refresh_mode)
else
Debug("InfoMessage:inform(), unrecognized delay=", delay)
end
end
function InfoMessage:getMethodForEvent(event)
local popup, voice = true, true
if self.InfoMethod[event] %2 == 0 then popup = false end
if self.InfoMethod[event] < 2 then voice = false end
return popup, voice
end
-- GUI-methods for user to choose the way to inform about various events --
function InfoMessage:chooseMethodForEvent(event)
local popup, voice = self:getMethodForEvent(event)
local items_menu = SelectMenu:new{
menu_title = "Event notifications",
item_array = {"Avoid any notifications",
"Show popup window",
"Use TTS-voice",
"Popup window and TTS-voice",
},
current_entry = (popup and 1 or 0) + (voice and 1 or 0) * 2,
}
local item_no = items_menu:choose(0, fb.bb:getHeight())
if item_no then
self.InfoMethod[event] = item_no - 1
-- just to illustrate the way how the selected method works; might be removed
-- self:inform("Event = "..event..", Method = "..self.InfoMethod[event], -1500, 1, event,
-- "You have chosen the method number "..self.InfoMethod[event].." for the event item number "..event)
end
end
function InfoMessage:chooseEventForMethod(event)
event = event or 0
local item_no = 0
local event_list = {
"Messages (e.g. 'Battery logging on')",
"Warnings (e.g. 'Already first jump!')",
"Errors (e.g. 'Zip contains improper content!')",
"Confirmations (e.g. 'Press Y to confirm')",
"Bugs",
}
while item_no ~= event and item_no < #event_list do
item_no = item_no + 1
end
local event_menu = SelectMenu:new{
menu_title = "Select the event type",
item_array = event_list,
current_entry = item_no - 1,
}
item_no = event_menu:choose(0, G_height)
return item_no
end
function InfoMessage:chooseNotificatonMethods()
local event = 1 -- default: auxiliary messages
while event do
event = self:chooseEventForMethod(event)
if event then self:chooseMethodForEvent(event) end
end
end
---------------- audio-related functions ----------------
function InfoMessage:incrTTSspeed(direction) -- either +1 or -1
-- make sure new TTS-speed is within reasonable range
self.TTSspeed = math.max(self.TTSspeed + direction * 20, 40) -- min = 40%
self.TTSspeed = math.min(self.TTSspeed, 200) -- max = 200%
-- set new value & give an example for more convenient tuning
os.execute('lipc-set-prop com.lab126.tts TtsISpeed '..self.TTSspeed)
say("The current voice speed is "..self.TTSspeed.." percent.")
end
function InfoMessage:getTTSspeed()
if util.isEmulated() == 1 then
return 0
end
local tmp = io.popen('lipc-get-prop com.lab126.tts TtsISpeed', "r")
local speed = tmp:read("*number")
tmp:close()
return speed or 100 -- nominal TTS-speed
end
function InfoMessage:incrSoundVolume(direction) -- either +1 or -1
-- make sure that new volume is within reasonable range
self.SoundVolume = math.max(self.SoundVolume + direction, 1)
self.SoundVolume = math.min(self.SoundVolume, #self.VolumeLevels)
-- set new value & give an example for more convenient tuning
os.execute('lipc-set-prop com.lab126.audio Volume '..(self.SoundVolume-1))
-- that is not exactly the volume percents, but more conventional values,
-- than abstract units returned by 'lipc-get-prop com.lab126.audio Volume'
local percents = math.floor(100*self.VolumeLevels[self.SoundVolume]/self.VolumeLevels[#self.VolumeLevels])
say("The current sound volume is "..percents.." percent.")
end
function InfoMessage:getSoundVolume()
if util.isEmulated() == 1 then
return 0
end
local tmp = io.popen('lipc-get-prop com.lab126.audio Volume', "r")
local volume = tmp:read("*number")
tmp:close()
local i = 1
while self.VolumeLevels[i] < volume and i < #self.VolumeLevels do
i = i + 1
end
return i or 16 -- maximum volume
end
--[[ -- to determine self.VolumeLevels in various Kindle-models
function InfoMessage:getVolumeLevels()
local levels, v, i = {}, 0, 0
while i < 16 do -- proper K3-range 0..15 might be different for other models
os.execute('lipc-set-prop com.lab126.audio Volume '..i)
v = self:getSoundVolume()
table.insert(levels, v)
i = i + 1
end
return levels
end ]]
function say(text)
if util.isEmulated() == 1 then
os.execute("espeak \""..text.."\"")
else
os.execute("say \""..text.."\"")
end
end
function InfoMessage:initInfoMessageSettings()
self.InfoMethod = G_reader_settings:readSetting("info_message_methods") or self.InfoMethod
self.TTSspeed = G_reader_settings:readSetting("tts_speed") or self:getTTSspeed()
self.SoundVolume = G_reader_settings:readSetting("sound_volume") or self:getSoundVolume()
end
function InfoMessage:saveInfoMessageSettings()
G_reader_settings:saveSetting("info_message_methods", self.InfoMethod)
G_reader_settings:saveSetting("sound_volume", self.SoundVolume-1)
G_reader_settings:saveSetting("tts_speed", self.TTSspeed)
end
function InfoMessage:drawTopMsg(msg)
local face = Font:getFace("rifont", 18)
local len = sizeUtf8Text(0, G_width, face, msg, true).x + 20
fb.bb:paintRect(0, 0, len, 15+6*2, 4)
renderUtf8Text(fb.bb, 10, 15+6, face, msg, true)
fb:refresh(1)
end

377
djvu.c

@ -15,22 +15,26 @@
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <math.h>
#include <string.h>
#include <errno.h>
#include <pthread.h>
#include <libdjvu/miniexp.h>
#include <libdjvu/ddjvuapi.h>
#include "string.h"
#include "blitbuffer.h"
#include "drawcontext.h"
#include "koptcontext.h"
#include "k2pdfopt.h"
#include "djvu.h"
#define MIN(a, b) ((a) < (b) ? (a) : (b))
#define MAX(a, b) ((a) > (b) ? (a) : (b))
/*@TODO check all the close method, ensure memories are freed 03.03 2012*/
typedef struct DjvuDocument {
ddjvu_context_t *context;
ddjvu_document_t *doc_ref;
ddjvu_format_t *pixelformat;
} DjvuDocument;
typedef struct DjvuPage {
@ -40,12 +44,11 @@ typedef struct DjvuPage {
DjvuDocument *doc;
} DjvuPage;
static int handle(lua_State *L, ddjvu_context_t *ctx, int wait)
{
const ddjvu_message_t *msg;
if (!ctx)
return;
return -1;
if (wait)
msg = ddjvu_message_wait(ctx);
while ((msg = ddjvu_message_peek(ctx)))
@ -54,8 +57,8 @@ static int handle(lua_State *L, ddjvu_context_t *ctx, int wait)
{
case DDJVU_ERROR:
if (msg->m_error.filename) {
return luaL_error(L, "ddjvu: %s\nddjvu: '%s:%d'\n",
msg->m_error.message, msg->m_error.filename,
return luaL_error(L, "ddjvu: %s\nddjvu: '%s:%d'\n",
msg->m_error.message, msg->m_error.filename,
msg->m_error.lineno);
} else {
return luaL_error(L, "ddjvu: %s\n", msg->m_error.message);
@ -77,20 +80,28 @@ static int openDocument(lua_State *L) {
luaL_getmetatable(L, "djvudocument");
lua_setmetatable(L, -2);
doc->context = ddjvu_context_create("DJVUReader");
doc->context = ddjvu_context_create("kindlepdfviewer");
if (! doc->context) {
return luaL_error(L, "cannot create context.");
return luaL_error(L, "cannot create context");
}
printf("## cache_size = %d\n", cache_size);
//printf("## cache_size = %d\n", cache_size);
ddjvu_cache_set_size(doc->context, (unsigned long)cache_size);
doc->doc_ref = ddjvu_document_create_by_filename_utf8(doc->context, filename, TRUE);
if (! doc->doc_ref)
return luaL_error(L, "cannot open DjVu file <%s>", filename);
while (! ddjvu_document_decoding_done(doc->doc_ref))
handle(L, doc->context, True);
if (! doc->doc_ref) {
return luaL_error(L, "cannot open DJVU file <%s>", filename);
doc->pixelformat = ddjvu_format_create(DDJVU_FORMAT_GREY8, 0, NULL);
if (! doc->pixelformat) {
return luaL_error(L, "cannot create DjVu pixelformat for <%s>", filename);
}
ddjvu_format_set_row_order(doc->pixelformat, 1);
ddjvu_format_set_y_direction(doc->pixelformat, 1);
/* dithering bits <8 are ignored by djvulibre */
/* ddjvu_format_set_ditherbits(doc->pixelformat, 4); */
return 1;
}
@ -98,15 +109,19 @@ static int openDocument(lua_State *L) {
static int closeDocument(lua_State *L) {
DjvuDocument *doc = (DjvuDocument*) luaL_checkudata(L, 1, "djvudocument");
// should be save if called twice
if(doc->doc_ref != NULL) {
// should be safe if called twice
if (doc->doc_ref != NULL) {
ddjvu_document_release(doc->doc_ref);
doc->doc_ref = NULL;
}
if(doc->context != NULL) {
if (doc->context != NULL) {
ddjvu_context_release(doc->context);
doc->context = NULL;
}
if (doc->pixelformat != NULL) {
ddjvu_format_release(doc->pixelformat);
doc->pixelformat = NULL;
}
return 0;
}
@ -123,21 +138,32 @@ static int walkTableOfContent(lua_State *L, miniexp_t r, int *count, int depth)
int length = miniexp_length(r);
int counter = 0;
char page_number[6];
const char* page_name;
int page_number;
while(counter < length-1) {
lua_pushnumber(L, *count);
lua_newtable(L);
lua_pushstring(L, "page");
strcpy(page_number,miniexp_to_str(miniexp_car(miniexp_cdr(miniexp_nth(counter, lista)))));
/* page numbers appear as #11, set # to 0 so strtol works */
page_number[0]= '0';
lua_pushnumber(L, strtol(page_number, NULL, 10));
page_name = miniexp_to_str(miniexp_car(miniexp_cdr(miniexp_nth(counter, lista))));
if(page_name != NULL && page_name[0] == '#') {
errno = 0;
page_number = strtol(page_name + 1, NULL, 10);
if(!errno) {
lua_pushnumber(L, page_number);
} else {
/* we can not parse this as a number, TODO: parse page names */
lua_pushnumber(L, -1);
}
} else {
/* something we did not expect here */
lua_pushnumber(L, -1);
}
lua_settable(L, -3);
lua_pushstring(L, "depth");
lua_pushnumber(L, depth);
lua_pushnumber(L, depth);
lua_settable(L, -3);
lua_pushstring(L, "title");
@ -156,7 +182,6 @@ static int walkTableOfContent(lua_State *L, miniexp_t r, int *count, int depth)
return 0;
}
static int getTableOfContent(lua_State *L) {
DjvuDocument *doc = (DjvuDocument*) luaL_checkudata(L, 1, "djvudocument");
miniexp_t r;
@ -178,7 +203,7 @@ static int openPage(lua_State *L) {
DjvuDocument *doc = (DjvuDocument*) luaL_checkudata(L, 1, "djvudocument");
int pageno = luaL_checkint(L, 2);
if(pageno < 1 || pageno > ddjvu_document_get_pagenum(doc->doc_ref)) {
if (pageno < 1 || pageno > ddjvu_document_get_pagenum(doc->doc_ref)) {
return luaL_error(L, "cannot open page #%d, out of range (1-%d)", pageno, ddjvu_document_get_pagenum(doc->doc_ref));
}
@ -186,19 +211,18 @@ static int openPage(lua_State *L) {
luaL_getmetatable(L, "djvupage");
lua_setmetatable(L, -2);
/* djvulibre counts page starts form 0 */
/* djvulibre counts page starts from 0 */
page->page_ref = ddjvu_page_create_by_pageno(doc->doc_ref, pageno - 1);
if (! page->page_ref)
return luaL_error(L, "cannot open page #%d", pageno);
while (! ddjvu_page_decoding_done(page->page_ref))
handle(L, doc->context, TRUE);
if(! page->page_ref) {
return luaL_error(L, "cannot open page #%d", pageno);
}
page->doc = doc;
page->num = pageno;
/* djvulibre counts page starts form 0 */
while((r=ddjvu_document_get_pageinfo(doc->doc_ref, pageno - 1,
/* djvulibre counts page starts from 0 */
while((r=ddjvu_document_get_pageinfo(doc->doc_ref, pageno - 1,
&(page->info)))<DDJVU_JOB_OK)
handle(L, doc->context, TRUE);
if (r>=DDJVU_JOB_FAILED)
@ -220,22 +244,93 @@ static int getPageSize(lua_State *L) {
/* unsupported so fake it */
static int getUsedBBox(lua_State *L) {
DjvuPage *page = (DjvuPage*) luaL_checkudata(L, 1, "djvupage");
lua_pushnumber(L, (double)0.01);
lua_pushnumber(L, (double)0.01);
lua_pushnumber(L, (double)-0.01);
lua_pushnumber(L, (double)-0.01);
return 4;
}
static int getOriginalPageSize(lua_State *L) {
DjvuDocument *doc = (DjvuDocument*) luaL_checkudata(L, 1, "djvudocument");
int pageno = luaL_checkint(L, 2);
ddjvu_status_t r;
ddjvu_pageinfo_t info;
while ((r=ddjvu_document_get_pageinfo(
doc->doc_ref, pageno-1, &info))<DDJVU_JOB_OK) {
handle(L, doc->context, TRUE);
}
lua_pushnumber(L, info.width);
lua_pushnumber(L, info.height);
return 2;
}
static int getPageInfo(lua_State *L) {
DjvuDocument *doc = (DjvuDocument*) luaL_checkudata(L, 1, "djvudocument");
int pageno = luaL_checkint(L, 2);
ddjvu_page_t *djvu_page;
int page_width, page_height, page_dpi;
double page_gamma;
ddjvu_page_type_t page_type;
char *page_type_str;
djvu_page = ddjvu_page_create_by_pageno(doc->doc_ref, pageno - 1);
if (! djvu_page)
return luaL_error(L, "cannot create djvu_page #%d", pageno);
while (! ddjvu_page_decoding_done(djvu_page))
handle(L, doc->context, TRUE);
page_width = ddjvu_page_get_width(djvu_page);
lua_pushnumber(L, page_width);
page_height = ddjvu_page_get_height(djvu_page);
lua_pushnumber(L, page_height);
page_dpi = ddjvu_page_get_resolution(djvu_page);
lua_pushnumber(L, page_dpi);
page_gamma = ddjvu_page_get_gamma(djvu_page);
lua_pushnumber(L, page_gamma);
page_type = ddjvu_page_get_type(djvu_page);
switch (page_type) {
case DDJVU_PAGETYPE_UNKNOWN:
page_type_str = "UNKNOWN";
break;
case DDJVU_PAGETYPE_BITONAL:
page_type_str = "BITONAL";
break;
case DDJVU_PAGETYPE_PHOTO:
page_type_str = "PHOTO";
break;
case DDJVU_PAGETYPE_COMPOUND:
page_type_str = "COMPOUND";
break;
default:
page_type_str = "INVALID";
break;
}
lua_pushstring(L, page_type_str);
ddjvu_page_release(djvu_page);
return 5;
}
/*
* Return a table like following:
* {
* -- a line entry
* 1 = {
* 1 = {
* 1 = {word="This", x0=377, y0=4857, x1=2427, y1=5089},
* 2 = {word="is", x0=377, y0=4857, x1=2427, y1=5089},
* 3 = {word="Word", x0=377, y0=4857, x1=2427, y1=5089},
@ -244,7 +339,7 @@ static int getUsedBBox(lua_State *L) {
* },
*
* -- an other line entry
* 2 = {
* 2 = {
* 1 = {word="This", x0=377, y0=4857, x1=2427, y1=5089},
* 2 = {word="is", x0=377, y0=4857, x1=2427, y1=5089},
* x0 = 377, y0 = 4857, x1 = 2427, y1 = 5089,
@ -255,6 +350,17 @@ static int getPageText(lua_State *L) {
DjvuDocument *doc = (DjvuDocument*) luaL_checkudata(L, 1, "djvudocument");
int pageno = luaL_checkint(L, 2);
/* get page height for coordinates transform */
ddjvu_pageinfo_t info;
ddjvu_status_t r;
while ((r=ddjvu_document_get_pageinfo(
doc->doc_ref, pageno-1, &info))<DDJVU_JOB_OK) {
handle(L, doc->context, TRUE);
}
if (r>=DDJVU_JOB_FAILED)
return luaL_error(L, "cannot get page #%d information", pageno);
/* start retrieving page text */
miniexp_t sexp, se_line, se_word;
int i = 1, j = 1, counter_l = 1, counter_w=1,
nr_line = 0, nr_word = 0;
@ -278,7 +384,7 @@ static int getPageText(lua_State *L) {
/* retrive one line entry */
se_line = miniexp_nth(i, sexp);
nr_word = miniexp_length(se_line);
if(nr_word == 0) {
if (nr_word == 0) {
continue;
}
@ -292,16 +398,18 @@ static int getPageText(lua_State *L) {
lua_pushnumber(L, miniexp_to_int(miniexp_nth(1, se_line)));
lua_settable(L, -3);
lua_pushstring(L, "y0");
lua_pushnumber(L, miniexp_to_int(miniexp_nth(2, se_line)));
lua_pushstring(L, "y1");
lua_pushnumber(L,
info.height - miniexp_to_int(miniexp_nth(2, se_line)));
lua_settable(L, -3);
lua_pushstring(L, "x1");
lua_pushnumber(L, miniexp_to_int(miniexp_nth(3, se_line)));
lua_settable(L, -3);
lua_pushstring(L, "y1");
lua_pushnumber(L, miniexp_to_int(miniexp_nth(4, se_line)));
lua_pushstring(L, "y0");
lua_pushnumber(L,
info.height - miniexp_to_int(miniexp_nth(4, se_line)));
lua_settable(L, -3);
/* now loop through each word in the line */
@ -325,16 +433,18 @@ static int getPageText(lua_State *L) {
lua_pushnumber(L, miniexp_to_int(miniexp_nth(1, se_word)));
lua_settable(L, -3);
lua_pushstring(L, "y0");
lua_pushnumber(L, miniexp_to_int(miniexp_nth(2, se_word)));
lua_pushstring(L, "y1");
lua_pushnumber(L,
info.height - miniexp_to_int(miniexp_nth(2, se_word)));
lua_settable(L, -3);
lua_pushstring(L, "x1");
lua_pushnumber(L, miniexp_to_int(miniexp_nth(3, se_word)));
lua_settable(L, -3);
lua_pushstring(L, "y1");
lua_pushnumber(L, miniexp_to_int(miniexp_nth(4, se_word)));
lua_pushstring(L, "y0");
lua_pushnumber(L,
info.height - miniexp_to_int(miniexp_nth(4, se_word)));
lua_settable(L, -3);
lua_pushstring(L, "word");
@ -355,32 +465,122 @@ static int getPageText(lua_State *L) {
static int closePage(lua_State *L) {
DjvuPage *page = (DjvuPage*) luaL_checkudata(L, 1, "djvupage");
// should be save if called twice
if(page->page_ref != NULL) {
// should be safe if called twice
if (page->page_ref != NULL) {
ddjvu_page_release(page->page_ref);
page->page_ref = NULL;
}
return 0;
}
static int drawPage(lua_State *L) {
static int reflowPage(lua_State *L) {
DjvuPage *page = (DjvuPage*) luaL_checkudata(L, 1, "djvupage");
DrawContext *dc = (DrawContext*) luaL_checkudata(L, 2, "drawcontext");
KOPTContext *kctx = (KOPTContext*) luaL_checkudata(L, 2, "koptcontext");
ddjvu_render_mode_t mode = (int) luaL_checkint(L, 3);
ddjvu_rect_t prect;
ddjvu_rect_t rrect;
int px, py, pw, ph, rx, ry, rw, rh, idpi, status;
double zoom = kctx->zoom;
double dpi = 250*zoom;
px = 0;
py = 0;
pw = ddjvu_page_get_width(page->page_ref);
ph = ddjvu_page_get_height(page->page_ref);
idpi = ddjvu_page_get_resolution(page->page_ref);
prect.x = px;
prect.y = py;
rx = (int)kctx->bbox.x0;
ry = (int)kctx->bbox.y0;
rw = (int)(kctx->bbox.x1 - kctx->bbox.x0);
rh = (int)(kctx->bbox.y1 - kctx->bbox.y0);
do {
prect.w = pw * dpi / idpi;
prect.h = ph * dpi / idpi;
rrect.x = rx * dpi / idpi;
rrect.y = ry * dpi / idpi;
rrect.w = rw * dpi / idpi;
rrect.h = rh * dpi / idpi;
printf("rendering page:%d,%d,%d,%d dpi:%.0f idpi:%.0d\n",rrect.x,rrect.y,rrect.w,rrect.h,dpi,idpi);
kctx->zoom = zoom;
zoom *= kctx->shrink_factor;
dpi *= kctx->shrink_factor;
} while (rrect.w > kctx->read_max_width | rrect.h > kctx->read_max_height);
WILLUSBITMAP *src = malloc(sizeof(WILLUSBITMAP));
bmp_init(src);
src->width = rrect.w;
src->height = rrect.h;
src->bpp = 8;
bmp_alloc(src);
if (src->bpp == 8) {
int ii;
for (ii = 0; ii < 256; ii++)
src->red[ii] = src->blue[ii] = src->green[ii] = ii;
}
ddjvu_format_set_row_order(page->doc->pixelformat, 1);
status = ddjvu_page_render(page->page_ref, mode, &prect, &rrect, page->doc->pixelformat,
bmp_bytewidth(src), (char *) src->data);
kctx->src = src;
if (kctx->precache) {
pthread_t rf_thread;
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
pthread_create(&rf_thread, &attr, k2pdfopt_reflow_bmp, (void*) kctx);
pthread_attr_destroy(&attr);
} else {
k2pdfopt_reflow_bmp(kctx);
}
return 0;
}
static int drawReflowedPage(lua_State *L) {
DjvuPage *page = (DjvuPage*) luaL_checkudata(L, 1, "djvupage");
KOPTContext *kc = (KOPTContext*) luaL_checkudata(L, 2, "koptcontext");
BlitBuffer *bb = (BlitBuffer*) luaL_checkudata(L, 3, "blitbuffer");
ddjvu_format_t *pixelformat;
ddjvu_rect_t pagerect, renderrect;
uint8_t *imagebuffer = NULL;
uint8_t *koptr = kc->data;
uint8_t *bbptr = bb->data;
int x_offset = 0;
int y_offset = 0;
bbptr += bb->pitch * y_offset;
int x, y;
for(y = y_offset; y < bb->h; y++) {
for(x = x_offset/2; x < (bb->w/2); x++) {
int p = x*2 - x_offset;
bbptr[x] = (((koptr[p + 1] & 0xF0) >> 4) | (koptr[p] & 0xF0)) ^ 0xFF;
}
bbptr += bb->pitch;
koptr += bb->w;
if (bb->w & 1) {
bbptr[x] = 255 - (koptr[x*2] & 0xF0);
}
}
imagebuffer = malloc((bb->w)*(bb->h)+1);
/* fill pixel map with white color */
memset(imagebuffer, 0xFF, (bb->w)*(bb->h)+1);
return 0;
}
pixelformat = ddjvu_format_create(DDJVU_FORMAT_GREY8, 0, NULL);
ddjvu_format_set_row_order(pixelformat, 1);
ddjvu_format_set_y_direction(pixelformat, 1);
ddjvu_format_set_gamma(pixelformat, dc->gamma);
/*ddjvu_format_set_ditherbits(dc->pixelformat, 2);*/
static int drawPage(lua_State *L) {
DjvuPage *page = (DjvuPage*) luaL_checkudata(L, 1, "djvupage");
DrawContext *dc = (DrawContext*) luaL_checkudata(L, 2, "drawcontext");
BlitBuffer *bb = (BlitBuffer*) luaL_checkudata(L, 3, "blitbuffer");
ddjvu_render_mode_t djvu_render_mode = (int) luaL_checkint(L, 6);
unsigned char adjusted_low[16], adjusted_high[16];
int i, adjust_pixels = 0;
ddjvu_rect_t pagerect, renderrect;
int bbsize = (bb->w)*(bb->h)+1;
uint8_t *imagebuffer = malloc(bbsize);
/*printf("@page %d, @@zoom:%f, offset: (%d, %d)\n", page->num, dc->zoom, dc->offset_x, dc->offset_y);*/
@ -394,16 +594,15 @@ static int drawPage(lua_State *L) {
/*printf("--pagerect--- (x: %d, y: %d), w: %d, h: %d.\n", 0, 0, pagerect.w, pagerect.h);*/
/* copy pixels area from pagerect specified by renderrect.
* ddjvulibre library does not support negative offset, positive offset
*
* ddjvulibre library does not support negative offset, positive offset
* means moving towards right and down.
*
* However, djvureader.lua handles offset differently. It use negative
* offset to move right and down while positive offset to move left
* and up. So we need to handle positive offset manually when copying
* imagebuffer to blitbuffer (framebuffer).
* However, djvureader.lua handles offset differently. It uses negative
* offset to move right and down while positive offset to move left
* and up. So we need to handle positive offset manually when copying
* imagebuffer to blitbuffer (framebuffer).
*/
renderrect.x = MAX(-dc->offset_x, 0);
renderrect.y = MAX(-dc->offset_y, 0);
@ -412,34 +611,43 @@ static int drawPage(lua_State *L) {
/*printf("--renderrect--- (%d, %d), w:%d, h:%d\n", renderrect.x, renderrect.y, renderrect.w, renderrect.h);*/
/* ddjvulibre library only supports rotation of 0, 90, 180 and 270 degrees.
* This four kinds of rotations can already be achieved by native system.
/* ddjvulibre library only supports rotation of 0, 90, 180 and 270 degrees.
* These four kinds of rotations can already be achieved by native system.
* So we don't set rotation here.
*/
ddjvu_page_render(page->page_ref,
DDJVU_RENDER_COLOR,
&pagerect,
&renderrect,
pixelformat,
bb->w,
imagebuffer);
if (!ddjvu_page_render(page->page_ref, djvu_render_mode, &pagerect, &renderrect, page->doc->pixelformat, bb->w, imagebuffer))
memset(imagebuffer, 0xFF, bbsize);
uint8_t *bbptr = (uint8_t*)bb->data;
uint8_t *pmptr = (uint8_t*)imagebuffer;
uint8_t *bbptr = bb->data;
uint8_t *pmptr = imagebuffer;
int x, y;
/* if offset is positive, we are moving towards up and left. */
int x_offset = MAX(0, dc->offset_x);
int y_offset = MAX(0, dc->offset_y);
/* prepare the tables for adjusting the intensity of pixels */
if (dc->gamma != -1.0) {
for (i=0; i<16; i++) {
adjusted_low[i] = MIN(15, (unsigned char)floorf(dc->gamma * (float)i));
adjusted_high[i] = adjusted_low[i] << 4;
}
adjust_pixels = 1;
}
bbptr += bb->pitch * y_offset;
for(y = y_offset; y < bb->h; y++) {
/* bbptr's line width is half of pmptr's */
for(x = x_offset/2; x < (bb->w / 2); x++) {
bbptr[x] = 255 - (((pmptr[x*2 + 1 - x_offset] & 0xF0) >> 4) |
(pmptr[x*2 - x_offset] & 0xF0));
int p = x*2 - x_offset;
unsigned char low = 15 - (pmptr[p + 1] >> 4);
unsigned char high = 15 - (pmptr[p] >> 4);
if (adjust_pixels)
bbptr[x] = adjusted_high[high] | adjusted_low[low];
else
bbptr[x] = (high << 4) | low;
}
if(bb->w & 1) {
if (bb->w & 1) {
bbptr[x] = 255 - (pmptr[x*2] & 0xF0);
}
/* go to next line */
@ -448,23 +656,20 @@ static int drawPage(lua_State *L) {
}
free(imagebuffer);
pmptr = imagebuffer = NULL;
ddjvu_format_release(pixelformat);
return 0;
}
static int getCacheSize(lua_State *L) {
DjvuDocument *doc = (DjvuDocument*) luaL_checkudata(L, 1, "djvudocument");
unsigned long size = ddjvu_cache_get_size(doc->context);
printf("## ddjvu_cache_get_size = %d\n", size);
//printf("## ddjvu_cache_get_size = %d\n", (int)size);
lua_pushnumber(L, size);
return 1;
}
static int cleanCache(lua_State *L) {
DjvuDocument *doc = (DjvuDocument*) luaL_checkudata(L, 1, "djvudocument");
printf("## ddjvu_cache_clear\n");
//printf("## ddjvu_cache_clear\n");
ddjvu_cache_clear(doc->context);
return 0;
}
@ -479,6 +684,8 @@ static const struct luaL_Reg djvudocument_meth[] = {
{"getPages", getNumberOfPages},
{"getToc", getTableOfContent},
{"getPageText", getPageText},
{"getOriginalPageSize", getOriginalPageSize},
{"getPageInfo", getPageInfo},
{"close", closeDocument},
{"getCacheSize", getCacheSize},
{"cleanCache", cleanCache},
@ -491,6 +698,8 @@ static const struct luaL_Reg djvupage_meth[] = {
{"getUsedBBox", getUsedBBox},
{"close", closePage},
{"__gc", closePage},
{"reflow", reflowPage},
{"rfdraw", drawReflowedPage},
{"draw", drawPage},
{NULL, NULL}
};

@ -2,9 +2,31 @@ require "unireader"
DJVUReader = UniReader:new{}
function DJVUReader:setDefaults()
self.show_overlap_enable = DDJVUREADER_SHOW_OVERLAP_ENABLE
self.show_links_enable = DDJVUREADER_SHOW_LINKS_ENABLE
self.comics_mode_enable = DDJVUREADER_COMICS_MODE_ENABLE
self.rtl_mode_enable = DDJVUREADER_RTL_MODE_ENABLE
self.page_mode_enable = DDJVUREADER_PAGE_MODE_ENABLE
end
-- check DjVu magic string to validate
function validDJVUFile(filename)
f = io.open(filename, "r")
if not f then return false end
local magic = f:read(8)
f:close()
if not magic or magic ~= "AT&TFORM" then return false end
return true
end
-- open a DJVU file and its settings store
-- DJVU does not support password yet
function DJVUReader:open(filename)
if not validDJVUFile(filename) then
return false, "Not a valid DjVu file"
end
local ok
ok, self.doc = pcall(djvu.openDocument, filename, self.cache_document_size)
if not ok then
@ -21,8 +43,36 @@ end
function DJVUReader:adjustDjvuReaderCommand()
self.commands:del(KEY_J, MOD_SHIFT, "J")
self.commands:del(KEY_K, MOD_SHIFT, "K")
self.commands:add(KEY_R, nil, "R",
"select djvu page rendering mode",
function(self)
self:select_render_mode()
end)
end
-- select the rendering mode from those supported by djvulibre.
-- Note that if the values in the definition of ddjvu_render_mode_t in djvulibre/libdjvu/ddjvuapi.h change,
-- then we should update our values here also. This is a bit risky, but these values never change, so it should be ok :)
function DJVUReader:select_render_mode()
local mode_menu = SelectMenu:new{
menu_title = "Select DjVu page rendering mode",
item_array = {
"COLOUR (works for both colour and b&w pages)", -- 0 (colour page or stencil)
"BLACK & WHITE (for b&w pages only, much faster)", -- 1 (stencil or colour page)
"COLOUR ONLY (slightly faster than COLOUR)", -- 2 (colour page or fail)
"MASK ONLY (for b&w pages only)", -- 3 (stencil or fail)
"COLOUR BACKGROUND (show only background)", -- 4 (colour background layer)
"COLOUR FOREGROUND (show only foreground)" -- 5 (colour foreground layer)
},
current_entry = self.render_mode,
}
local mode = mode_menu:choose(0, fb.bb:getHeight())
if mode then
self.render_mode = mode - 1
self:clearCache()
end
self:redrawCurrentPage()
end
----------------------------------------------------
-- highlight support
@ -31,68 +81,73 @@ function DJVUReader:getText(pageno)
return self.doc:getPageText(pageno)
end
----------------------------------------------------
-- In djvulibre library, some coordinates starts from
-- lower left conner, i.e. y is upside down in kpv's
-- coordinate. So y0 should be taken with special care.
----------------------------------------------------
function DJVUReader:zoomedRectCoordTransform(x0, y0, x1, y1)
local x,y = self:screenOffset()
return
x0 * self.globalzoom + x,
self.cur_full_height - (y1 * self.globalzoom) + y,
(x1 - x0) * self.globalzoom,
(y1 - y0) * self.globalzoom
end
-- make sure at least part of the box can be seen in next/previous view
-- @FIXME only works in FIT_TO_CONTENT_WIDTH mode 21.04 2012 (houqp)
-- @TODO use zoomedRectCoordTransform in unireader, no need to overwrite
-- it in here.
function DJVUReader:_isBoxInNextView(box)
return self.cur_full_height - (box.y0 * self.globalzoom) > -self.offset_y + G_height
end
function DJVUReader:_isBoxInPrevView(box)
return self.cur_full_height - (box.y1 * self.globalzoom) < -self.offset_y
end
-- y axel in djvulibre starts from bottom
function DJVUReader:_isEntireWordInScreenHeightRange(w)
return (w ~= nil) and
(self.cur_full_height - (w.y1 * self.globalzoom) >=
-self.offset_y) and
(self.cur_full_height - (w.y0 * self.globalzoom) <=
-self.offset_y + G_height)
-- for incompatible API fixing
function DJVUReader:invertTextYAxel(pageno, text_table)
local _, height = self.doc:getOriginalPageSize(pageno)
for _,text in pairs(text_table) do
for _,line in ipairs(text) do
line.y0, line.y1 = (height - line.y1), (height - line.y0)
end
end
return text_table
end
-- y axel in djvulibre starts from bottom
function DJVUReader:_isEntireLineInScreenHeightRange(l)
return (l ~= nil) and
(self.cur_full_height - (l.y1 * self.globalzoom) >=
-self.offset_y) and
(self.cur_full_height - (l.y0 * self.globalzoom) <=
-self.offset_y + G_height)
function render_mode_string(rm)
if (rm == 0) then
return "COLOUR"
elseif (rm == 1) then
return "B&W"
elseif (rm == 2) then
return "COLOUR ONLY"
elseif (rm == 3) then
return "MASK ONLY"
elseif (rm == 4) then
return "COLOUR BG"
elseif (rm == 5) then
return "COLOUR FG"
else
return "UNKNOWN"
end
end
-- y axel in djvulibre starts from bottom
function DJVUReader:_isWordInScreenRange(w)
if not w then
return false
function DJVUReader:_drawReadingInfo()
local width, height = G_width, G_height
local numpages = self.doc:getPages()
local load_percent = self.pageno/numpages
local face = Font:getFace("rifont", 20)
local rss, data, stack, lib, totalvm = memUsage()
local page_width, page_height, page_dpi, page_gamma, page_type = self.doc:getPageInfo(self.pageno)
-- display memory, time, battery and DjVu info on top of page
fb.bb:paintRect(0, 0, width, 60+6*2, 0)
renderUtf8Text(fb.bb, 10, 15+6, face,
"M: "..
math.ceil( self.cache_current_memsize / 1024 ).."/"..math.ceil( self.cache_max_memsize / 1024 ).."k "..
math.ceil( self.doc:getCacheSize() / 1024 ).."/"..math.ceil( self.cache_document_size / 1024 ).."k", true)
local txt = os.date("%a %d %b %Y %T").." ["..BatteryLevel().."]"
local w = sizeUtf8Text(0, width, face, txt, true).x
renderUtf8Text(fb.bb, width - w - 10, 15+6, face, txt, true)
renderUtf8Text(fb.bb, 10, 15+6+22, face,
"RSS:"..rss.." DAT:"..data.." STK:"..stack.." LIB:"..lib.." TOT:"..totalvm.."k", true)
renderUtf8Text(fb.bb, 10, 15+6+44, face,
"Gm:"..string.format("%.1f",self.globalgamma).." ["..tostring(page_gamma).."], "..
tostring(page_width).."x"..tostring(page_height)..", "..
string.format("%.1fx, ", self.globalzoom)..
tostring(page_dpi).."dpi, "..page_type..", "..
render_mode_string(self.render_mode), true)
-- display reading progress on bottom of page
local ypos = height - 50
fb.bb:paintRect(0, ypos, width, 50, 0)
ypos = ypos + 15
local cur_section = self:getTocTitleOfCurrentPage()
if cur_section ~= "" then
cur_section = "Sec: "..cur_section
end
renderUtf8Text(fb.bb, 10, ypos+6, face,
"p."..self.pageno.."/"..numpages.." "..cur_section, true)
is_entire_word_out_of_screen_height =
(self.cur_full_height - (w.y0 * self.globalzoom) <=
-self.offset_y)
or (self.cur_full_height - (w.y1 * self.globalzoom) >=
-self.offset_y + G_height)
is_entire_word_out_of_screen_width =
(w.x0 * self.globalzoom >= -self.offset_x + G_width
or w.x1 * self.globalzoom <= -self.offset_x)
return (not is_entire_word_out_of_screen_height) and
(not is_entire_word_out_of_screen_width)
ypos = ypos + 15
blitbuffer.progressBar(fb.bb, 10, ypos, width-20, 15,
5, 4, load_percent, 8)
end

@ -23,6 +23,11 @@
#include "einkfb.h"
#ifdef EMULATE_READER
int emu_w = EMULATE_READER_W;
int emu_h = EMULATE_READER_H;
#endif
static int openFrameBuffer(lua_State *L) {
const char *fb_device = luaL_checkstring(L, 1);
FBInfo *fb = (FBInfo*) lua_newuserdata(L, sizeof(FBInfo));
@ -83,34 +88,27 @@ static int openFrameBuffer(lua_State *L) {
if(fb->buf->data == MAP_FAILED) {
return luaL_error(L, "cannot mmap framebuffer");
}
memset(fb->buf->data, 0, fb->finfo.smem_len);
fb->buf->pitch = fb->finfo.line_length;
#else
if(SDL_Init(SDL_INIT_VIDEO) < 0) {
return luaL_error(L, "cannot initialize SDL.");
}
if(!(fb->screen = SDL_SetVideoMode(EMULATE_READER_W, EMULATE_READER_H, 32, SDL_HWSURFACE))) {
if(!(fb->screen = SDL_SetVideoMode(emu_w, emu_h, 32, SDL_HWSURFACE))) {
return luaL_error(L, "can't get video surface %dx%d for 32bpp.",
EMULATE_READER_W, EMULATE_READER_H);
emu_w, emu_h);
}
memset(&fb->finfo, 0, sizeof(fb->finfo));
memset(&fb->vinfo, 0, sizeof(fb->vinfo));
fb->vinfo.xres = EMULATE_READER_W;
fb->vinfo.yres = EMULATE_READER_H;
fb->vinfo.grayscale = 1;
fb->vinfo.bits_per_pixel = 4;
fb->finfo.smem_len = ((EMULATE_READER_W + 1) / 2) * EMULATE_READER_H;
fb->finfo.line_length = (EMULATE_READER_W + 1) / 2;
fb->finfo.type = FB_TYPE_PACKED_PIXELS;
fb->buf->data = malloc(fb->finfo.smem_len);
fb->vinfo.xres = emu_w;
fb->vinfo.yres = emu_h;
fb->buf->pitch = (emu_w + 1) / 2;
fb->buf->data = calloc(fb->buf->pitch * emu_h, sizeof(char));
if(fb->buf->data == NULL) {
return luaL_error(L, "cannot get framebuffer emu memory");
}
#endif
memset(fb->buf->data, 0, fb->finfo.smem_len);
fb->buf->w = fb->vinfo.xres;
fb->buf->h = fb->vinfo.yres;
fb->buf->pitch = fb->finfo.line_length;
fb->buf->allocated = 0;
return 1;
}
@ -198,7 +196,6 @@ static int einkUpdate(lua_State *L) {
/* NOTICE!!! You must close and reopen framebuffer after called this method.
* Otherwise, screen resolution will not be updated! */
static int einkSetOrientation(lua_State *L) {
#ifndef EMULATE_READER
FBInfo *fb = (FBInfo*) luaL_checkudata(L, 1, "einkfb");
int mode = luaL_optint(L, 2, 0);
@ -206,6 +203,7 @@ static int einkSetOrientation(lua_State *L) {
return luaL_error(L, "Wrong rotation mode %d given!", mode);
}
#ifndef EMULATE_READER
/* ioctl has a different definition for rotation mode. */
if (mode == 1)
mode = 2;
@ -213,6 +211,15 @@ static int einkSetOrientation(lua_State *L) {
mode = 1;
ioctl(fb->fd, FBIO_EINK_SET_DISPLAY_ORIENTATION, mode);
#else
if (mode == 0 || mode == 2) {
emu_w = EMULATE_READER_W;
emu_h = EMULATE_READER_H;
}
else if (mode == 1 || mode == 3) {
emu_w = EMULATE_READER_H;
emu_h = EMULATE_READER_W;
}
#endif
return 0;
}

@ -18,10 +18,14 @@
#ifndef _PDF_EINKFB_H
#define _PDF_EINKFB_H
#include <linux/fb.h>
#ifdef EMULATE_READER
#include <SDL.h>
struct fb_var_screeninfo {
uint32_t xres;
uint32_t yres;
};
#else
#include <linux/fb.h>
#include "include/einkfb.h"
#endif
@ -34,11 +38,12 @@
typedef struct FBInfo {
int fd;
BlitBuffer *buf;
struct fb_fix_screeninfo finfo;
struct fb_var_screeninfo vinfo;
#ifdef EMULATE_READER
SDL_Surface *screen;
#else
struct fb_fix_screeninfo finfo;
#endif
struct fb_var_screeninfo vinfo;
} FBInfo;
int luaopen_einkfb(lua_State *L);

105
extr.c

@ -0,0 +1,105 @@
/*
extr: Extract attachments from PDF file
Usage: extr /dir/file.pdf pageno
Returns 0 if one or more attachments saved, otherwise returns non-zero.
Prints the number of saved attachments on stdout.
Attachments are saved in /dir directory with the appropriate filenames.
Copyright (C) 2012 Tigran Aivazian <tigran@bibles.org.uk>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "mupdf-internal.h"
#include <libgen.h>
static pdf_document *doc;
void dump_stream(int i, FILE *fout)
{
fz_stream *stm = pdf_open_stream(doc, i, 0);
static unsigned char buf[8192];
while (1) {
int n = fz_read(stm, buf, sizeof buf);
if (n == 0) break;
fwrite(buf, 1, n, fout);
}
fz_close(stm);
}
/* returns the number of attachments saved */
int save_attachments(int pageno, char *targetdir)
{
pdf_page *page = pdf_load_page(doc, pageno-1);
pdf_annot *annot;
int saved_count = 0;
for (annot = page->annots; annot ; annot = annot->next) {
pdf_obj *fs_obj = pdf_dict_gets(annot->obj, "FS");
if (fs_obj) {
pdf_obj *ef_obj;
char *name = basename(strdup(pdf_to_str_buf(pdf_dict_gets(fs_obj, "F"))));
ef_obj = pdf_dict_gets(fs_obj, "EF");
if (ef_obj) {
pdf_obj *f_obj = pdf_dict_gets(ef_obj, "F");
if (f_obj && pdf_is_indirect(f_obj)) {
static char pathname[PATH_MAX];
sprintf(pathname, "%s/%s", targetdir, name);
FILE *fout = fopen(pathname, "w");
if (!fout) {
fprintf(stderr, "extr: cannot write to file %s\n", pathname);
exit(1);
}
dump_stream(pdf_to_num(f_obj), fout);
fclose(fout);
saved_count++;
}
}
}
}
return saved_count;
}
int main(int argc, char *argv[])
{
int saved = 0;
if (argc != 3) {
printf("Usage: extr file.pdf pageno\n");
exit(1);
}
char *filename = strdup(argv[1]);
char *dir = dirname(strdup(filename));
int pageno = atoi(argv[2]);
fz_context *ctx = fz_new_context(NULL, NULL, FZ_STORE_UNLIMITED);
if (!ctx) {
fprintf(stderr, "extr: cannot create context\n");
exit(1);
}
fz_var(doc);
fz_try(ctx) {
doc = pdf_open_document(ctx, filename);
saved = save_attachments(pageno, dir);
}
fz_catch(ctx)
{
}
printf("%d\n", saved);
return 0;
}

@ -3,14 +3,19 @@ require "keys"
require "graphics"
require "font"
require "filesearcher"
require "filehistory"
require "fileinfo"
require "inputbox"
require "selectmenu"
require "dialog"
require "readerchooser"
require "battery"
FileChooser = {
-- Class vars:
-- spacing between lines
spacing = 40,
title_H = 40, -- title height
spacing = 36, -- spacing between lines
foot_H = 28, -- foot height
margin_H = 10, -- horisontal margin
-- state buffer
dirs = nil,
@ -20,9 +25,83 @@ FileChooser = {
page = 1,
current = 1,
oldcurrent = 0,
exception_message = nil
exception_message = nil,
pagedirty = true,
markerdirty = false,
perpage,
clipboard = lfs.currentdir() .. "/clipboard", -- NO finishing slash
before_clipboard, -- NuPogodi, 30.09.12: to store the path where jump to clipboard was made from
-- modes that configures the filechoser for users with various purposes & skills
filemanager_expert_mode, -- default value is defined in reader.lua
-- the definitions
BEGINNERS_MODE = 1, -- the filemanager content is restricted by files with reader-related extensions; safe renaming (no extension)
ADVANCED_MODE = 2, -- no extension-based filtering; renaming with extensions; appreciable danger to crash crengine by improper docs
ROOT_MODE = 3, -- TODO: all functions (including non-stable and dangerous)
}
-- NuPogodi, 29.09.12: simplified the code
function getProperTitleLength(txt, font_face, max_width)
while sizeUtf8Text(0, G_width, font_face, txt, true).x > max_width do
txt = txt:sub(2, -1)
end
return txt
end
-- NuPogodi, 29.09.12: avoid using widgets
function DrawTitle(text, lmargin, y, height, color, font_face)
local r = 6 -- radius for round corners
color = 3 -- redefine to ignore the input for background color
fb.bb:paintRect(1, 1, G_width-2, height - r, color)
blitbuffer.paintBorder(fb.bb, 1, height/2, G_width-2, height/2, height/2, color, r)
local t = BatteryLevel() .. os.date(" %H:%M")
r = sizeUtf8Text(0, G_width, font_face, t, true).x
renderUtf8Text(fb.bb, G_width-r-lmargin, height-10, font_face, t, true)
r = G_width - r - 2 * lmargin - 10 -- let's leave small gap
if sizeUtf8Text(0, G_width, font_face, text, true).x <= r then
renderUtf8Text(fb.bb, lmargin, height-10, font_face, text, true)
else
t = renderUtf8Text(fb.bb, lmargin, height-10, font_face, "...", true)
text = getProperTitleLength(text, font_face, r-t)
renderUtf8Text(fb.bb, lmargin+t, height-10, font_face, text, true)
end
end
function DrawFooter(text,font_face,h)
local y = G_height - 7
-- just dirty fix to have the same footer everywhere
local x = FileChooser.margin_H --(G_width / 2) - 50
renderUtf8Text(fb.bb, x, y, font_face, text.." - Press H for help", true)
end
function DrawFileItem(name,x,y,image)
-- define icon file for
if name == ".." then image = "upfolder" end
local fn = "./resources/"..image..".png"
-- check whether the icon file exists or not
if not io.open(fn, "r") then fn = "./resources/other.png" end
local iw = ImageWidget:new({ file = fn })
iw:paintTo(fb.bb, x, y - iw:getSize().h + 1)
-- then drawing filenames
local cface = Font:getFace("cfont", 22)
local xleft = x + iw:getSize().w + 9 -- the gap between icon & filename
local width = G_width - xleft - x
-- now printing the name
if sizeUtf8Text(xleft, G_width - x, cface, name, true).x < width then
renderUtf8Text(fb.bb, xleft, y, cface, name, true)
else
local lgap = sizeUtf8Text(0, width, cface, " ...", true).x
local handle = renderUtf8TextWidth(fb.bb, xleft, y, cface, name, true, width - lgap - x)
renderUtf8Text(fb.bb, handle.x + lgap + x, y, cface, " ...", true)
end
iw:free()
end
function getAbsolutePath(aPath)
local abs_path
if not aPath then
@ -40,7 +119,7 @@ function getAbsolutePath(aPath)
abs_path = lfs.currentdir()
lfs.chdir(curr_dir)
end
--debug("rel: '"..aPath.."' abs:'"..abs_path.."'")
--Debug("rel: '"..aPath.."' abs:'"..abs_path.."'")
end
return abs_path
end
@ -49,195 +128,590 @@ function FileChooser:readDir()
self.dirs = {}
self.files = {}
for f in lfs.dir(self.path) do
if lfs.attributes(self.path.."/"..f, "mode") == "directory" and f ~= "." and not (f==".." and self.path=="/") and not string.match(f, "^%.[^.]") then
--debug(self.path.." -> adding: '"..f.."'")
table.insert(self.dirs, f)
else
if lfs.attributes(self.path.."/"..f, "mode") == "directory" and f ~= "." and f~=".."
and not string.match(f, "^%.[^.]") then
table.insert(self.dirs, f)
elseif lfs.attributes(self.path.."/"..f, "mode") == "file"
and not string.match(f, "^%.[^.]") then
local file_type = string.lower(string.match(f, ".+%.([^.]+)") or "")
if file_type == "djvu"
or file_type == "pdf" or file_type == "xps" or file_type == "cbz"
or file_type == "epub" or file_type == "txt" or file_type == "rtf"
or file_type == "htm" or file_type == "html" or file_type == "mobi"
or file_type == "fb2" or file_type == "chm" or file_type == "doc"
or file_type == "zip" then
if ReaderChooser:getReaderByType(file_type) then
table.insert(self.files, f)
end
end
end
--@TODO make sure .. is sortted to the first item 16.02 2012
table.sort(self.dirs)
if self.path~="/" then table.insert(self.dirs,1,"..") end
table.sort(self.files)
end
function FileChooser:setPath(newPath)
local curr_path = self.path
local oldPath = self.path
local search_position = false
-- We only need to re-scan the directory for the correct
-- position if we are entering it via ".." entry.
-- Unfortunately, ".." reaches us in the form of an absolute path,
-- but we can use the following trick: if we are traversing via "..",
-- then the new pathname will always be shorter than the old pathname.
if oldPath ~= "" and #newPath < #oldPath then
search_position = true
end
-- treat ".." entry in the clipboard as
-- a special case, namely return to the directory saved
-- in self.before_clipboard
if self.before_clipboard then
newPath = self.before_clipboard
self.before_clipboard = nil
end
-- convert to the absolute path so that we can
-- traverse up to the parent via ".."
self.path = getAbsolutePath(newPath)
local readdir_ok, exc = pcall(self.readDir,self)
if(not readdir_ok) then
debug("readDir error: "..tostring(exc))
self.exception_message = exc
return self:setPath(curr_path)
-- read the whole self.path directory
-- the error message is stored for display in the header.
local ret, msg = pcall(self.readDir, self)
if not ret then
self.exception_message = msg
return self:setPath(oldPath)
else
self.items = #self.dirs + #self.files
if self.items == 0 then
return nil
-- Dijkstra will hate me for this...
if newPath == oldPath then
return
end
self.page = 1
self.current = 1
return true
end
end
function FileChooser:choose(ypos, height)
local perpage = math.floor(height / self.spacing) - 2
local pagedirty = true
local markerdirty = false
if search_position then
-- extract the base part of oldPath, i.e. the actual directory name
local pos, _, oldPathBase = string.find(oldPath, "^.*/(.*)$")
local prevItem = function ()
if self.current == 1 then
if self.page > 1 then
self.current = perpage
self.page = self.page - 1
pagedirty = true
-- now search for the base part of oldPath among self.dirs[]
for k, v in ipairs(self.dirs) do
if v == oldPathBase then
self.current, self.page = gotoTargetItem(k, self.items, self.current, self.page, self.perpage)
break
end
end
else
self.current = self.current - 1
markerdirty = true
-- point the current position to ".." entry
self.page = 1
self.current = 1
end
end
end
local nextItem = function ()
if self.current == perpage then
if self.page < (self.items / perpage) then
self.current = 1
self.page = self.page + 1
pagedirty = true
end
else
if self.page ~= math.floor(self.items / perpage) + 1
or self.current + (self.page-1)*perpage < self.items then
self.current = self.current + 1
markerdirty = true
end
end
end
function FileChooser:choose()
local ypos = 0
self.pagedirty = true
self.markerdirty = false
self:addAllCommands()
while true do
local cface = Font:getFace("cfont", 25)
local tface = Font:getFace("tfont", 25)
local fface = Font:getFace("ffont", 16)
local cface = Font:getFace("cfont", 22)
local wlen = G_width - 2*self.margin_H
self.perpage = math.floor(G_height / self.spacing) - 2
if pagedirty then
fb.bb:paintRect(0, ypos, fb.bb:getWidth(), height, 0)
if self.pagedirty then
fb.bb:paintRect(0, ypos, G_width, G_height, 0)
local c
for c = 1, perpage do
local i = (self.page - 1) * perpage + c
for c = 1, self.perpage do
local i = (self.page - 1) * self.perpage + c
if i <= #self.dirs then
-- resembles display in midnight commander: adds "/" prefix for directories
renderUtf8Text(fb.bb, 39, ypos + self.spacing*c, cface, "/", true)
renderUtf8Text(fb.bb, 50, ypos + self.spacing*c, cface, self.dirs[i], true)
DrawFileItem(self.dirs[i],self.margin_H,ypos+self.title_H+self.spacing*c,"folder")
elseif i <= self.items then
renderUtf8Text(fb.bb, 50, ypos + self.spacing*c, cface, self.files[i-#self.dirs], true)
local file_type = string.lower(string.match(self.files[i-#self.dirs], ".+%.([^.]+)") or "")
DrawFileItem(self.files[i-#self.dirs],self.margin_H,ypos+self.title_H+self.spacing*c,file_type)
end
end
all_page = math.ceil(self.items/perpage)
renderUtf8Text(fb.bb, 5, ypos + self.spacing * perpage + 42, fface,
"Page "..self.page.." of "..all_page, true)
local msg = self.exception_message and self.exception_message:match("[^%:]+:%d+: (.*)") or "Path: "..self.path
-- draw footer
all_page = math.ceil(self.items/self.perpage)
DrawFooter("Page "..self.page.." of "..all_page,fface,self.foot_H)
-- draw menu title
local msg = self.exception_message and self.exception_message:match("[^%:]+:%d+: (.*)") or self.path
self.exception_message = nil
renderUtf8Text(fb.bb, 5, ypos + self.spacing * (perpage+1) + 27, fface, msg, true)
markerdirty = true
-- draw header
DrawTitle(msg,self.margin_H,ypos,self.title_H,3,tface)
self.markerdirty = true
end
if markerdirty then
if not pagedirty then
if self.markerdirty then
local ymarker = ypos + 8 + self.title_H
if not self.pagedirty then
if self.oldcurrent > 0 then
fb.bb:paintRect(30, ypos + self.spacing*self.oldcurrent + 10, fb.bb:getWidth() - 60, 3, 0)
fb:refresh(1, 30, ypos + self.spacing*self.oldcurrent + 10, fb.bb:getWidth() - 60, 3)
fb.bb:paintRect(self.margin_H, ymarker+self.spacing*self.oldcurrent, wlen, 3, 0)
fb:refresh(1, self.margin_H, ymarker+self.spacing*self.oldcurrent, wlen, 3)
end
end
fb.bb:paintRect(30, ypos + self.spacing*self.current + 10, fb.bb:getWidth() - 60, 3, 15)
if not pagedirty then
fb:refresh(1, 30, ypos + self.spacing*self.current + 10, fb.bb:getWidth() - 60, 3)
fb.bb:paintRect(self.margin_H, ymarker+self.spacing*self.current, wlen, 3, 15)
if not self.pagedirty then
fb:refresh(1, self.margin_H, ymarker+self.spacing*self.current, wlen, 3)
end
self.oldcurrent = self.current
markerdirty = false
self.markerdirty = false
end
if pagedirty then
fb:refresh(0, 0, ypos, fb.bb:getWidth(), height)
pagedirty = false
if self.pagedirty then
fb:refresh(0, 0, ypos, G_width, G_height)
self.pagedirty = false
end
local ev = input.saveWaitForEvent()
--debug("key code:"..ev.code)
--Debug("key code:"..ev.code)
ev.code = adjustKeyEvents(ev)
if ev.type == EV_KEY and ev.value ~= EVENT_VALUE_KEY_RELEASE then
if ev.code == KEY_FW_UP then
prevItem()
elseif ev.code == KEY_FW_DOWN then
nextItem()
elseif ev.code == KEY_F then -- invoke fontchooser menu
local fonts_menu = SelectMenu:new{
menu_title = "Fonts Menu",
item_array = Font:getFontList(),
}
local re, font = fonts_menu:choose(0, height)
if re then
Font.fontmap["cfont"] = font
Font:update()
end
pagedirty = true
elseif ev.code == KEY_S then -- invoke search input
keywords = InputBox:input(height-100, 100, "Search:")
if keywords then
-- call FileSearcher
--[[
This might looks a little bit dirty for using callback.
But I cannot come up with a better solution for renewing
the height argument according to screen rotation mode.
The callback might also be useful for calling system
settings menu in the future.
--]]
return nil, function()
InfoMessage:show("Searching...",0)
FileSearcher:init( self.path )
FileSearcher:choose(keywords)
end
end
pagedirty = true
elseif ev.code == KEY_PGFWD or ev.code == KEY_LPGFWD then
if self.page < (self.items / perpage) then
if self.current + self.page*perpage > self.items then
self.current = self.items - self.page*perpage
end
keydef = Keydef:new(ev.code, getKeyModifier())
Debug("key pressed: "..tostring(keydef))
command = self.commands:getByKeydef(keydef)
if command ~= nil then
Debug("command to execute: "..tostring(command))
ret_code = command.func(self, keydef)
else
Debug("command not found: "..tostring(command))
end
if ret_code == "break" then break end
if self.selected_item ~= nil then
Debug("# selected "..self.selected_item)
return self.selected_item
end
end -- if ev.type ==
end -- while
end
-- add available commands
function FileChooser:addAllCommands()
self.commands = Commands:new{}
self.commands:add(KEY_SPACE, nil, "Space",
"refresh file list",
function(self)
self:setPath(self.path)
self.pagedirty = true
end
)
self.commands:add(KEY_FW_DOWN, nil, "joypad down",
"next item",
function(self)
if self.current == self.perpage then
if self.page < (self.items / self.perpage) then
self.current = 1
self.page = self.page + 1
pagedirty = true
else
self.current = self.items - (self.page-1)*perpage
markerdirty = true
self.pagedirty = true
end
elseif ev.code == KEY_PGBCK or ev.code == KEY_LPGBCK then
else
if self.page ~= math.floor(self.items / self.perpage) + 1
or self.current + (self.page-1)*self.perpage < self.items then
self.current = self.current + 1
self.markerdirty = true
end
end
end
)
self.commands:add(KEY_FW_UP, nil, "joypad up",
"previous item",
function(self)
if self.current == 1 then
if self.page > 1 then
self.current = self.perpage
self.page = self.page - 1
pagedirty = true
self.pagedirty = true
end
else
self.current = self.current - 1
self.markerdirty = true
end
end
)
-- NuPogodi, 01.10.12: fast jumps to items at positions 10, 20, .. 90, 0% within the list
local numeric_keydefs, i = {}
for i=1, 10 do numeric_keydefs[i]=Keydef:new(KEY_1+i-1, nil, tostring(i%10)) end
self.commands:addGroup("[1, 2 .. 9, 0]", numeric_keydefs,
"item at position 0%, 10% .. 90%, 100%",
function(self)
local target_item = math.ceil(self.items * (keydef.keycode-KEY_1) / 9)
self.current, self.page, self.markerdirty, self.pagedirty =
gotoTargetItem(target_item, self.items, self.current, self.page, self.perpage)
end
)
self.commands:add({KEY_PGFWD, KEY_LPGFWD}, nil, ">",
"next page",
function(self)
if self.page < (self.items / self.perpage) then
if self.current + self.page*self.perpage > self.items then
self.current = self.items - self.page*self.perpage
end
self.page = self.page + 1
self.pagedirty = true
else
self.current = self.items - (self.page-1)*self.perpage
self.markerdirty = true
end
end
)
self.commands:add({KEY_PGBCK, KEY_LPGBCK}, nil, "<",
"previous page",
function(self)
if self.page > 1 then
self.page = self.page - 1
self.pagedirty = true
else
self.current = 1
self.markerdirty = true
end
end
)
self.commands:add(KEY_G, nil, "G", -- NuPogodi, 01.10.12: goto page No.
"goto page",
function(self)
local n = math.ceil(self.items / self.perpage)
local page = NumInputBox:input(G_height-100, 100, "Page:", "current page "..self.page.." of "..n, true)
if pcall(function () page = math.floor(page) end) -- convert string to number
and page ~= self.page and page > 0 and page <= n then
self.page = page
if self.current + (page-1)*self.perpage > self.items then
self.current = self.items - (page-1)*self.perpage
end
end
self.pagedirty = true
end
)
self.commands:add(KEY_FW_RIGHT, nil, "joypad right",
"show document information",
function(self)
local folder = self.dirs[self.perpage*(self.page-1)+self.current]
if folder then
if folder == ".." then
warningUnsupportedFunction()
else
self.current = 1
markerdirty = true
folder = self.path.."/"..folder
if FileInfo:show(folder) == "goto" then
self:setPath(folder)
end
end
elseif ev.code == KEY_ENTER or ev.code == KEY_FW_PRESS then
local newdir = self.dirs[perpage*(self.page-1)+self.current]
if newdir == ".." then
local path = string.gsub(self.path, "(.*)/[^/]+/?$", "%1")
self:setPath(path)
elseif newdir then
local path = self.path.."/"..newdir
self:setPath(path)
else -- file info
FileInfo:show(self.path, self.files[self.perpage*(self.page-1)+self.current-#self.dirs])
end
self.pagedirty = true
end
)
self.commands:add({KEY_ENTER, KEY_FW_PRESS}, nil, "Enter",
"open document / goto folder",
function(self)
local newdir = self.dirs[self.perpage*(self.page-1)+self.current]
if newdir == ".." then
local path = string.gsub(self.path, "(.*)/[^/]+/?$", "%1")
self:setPath(path)
elseif newdir then
self:setPath(self.path.."/"..newdir)
else
self.pathfile = self.path.."/"..self.files[self.perpage*(self.page-1)+self.current - #self.dirs]
openFile(self.pathfile)
end
self.pagedirty = true
end
)
-- modified to delete both files and empty folders
self.commands:add(KEY_DEL, nil, "Del",
"delete selected item",
function(self)
local pos = self.perpage*(self.page-1)+self.current
if pos > #self.dirs then -- file
if InfoMessage.InfoMethod[MSG_CONFIRM] == 0 then -- silent regime
self:deleteFileAtPosition(pos)
else
return self.path.."/"..self.files[perpage*(self.page-1)+self.current - #self.dirs]
InfoMessage:inform("Press 'Y' to confirm ", DINFO_NODELAY, 0, MSG_CONFIRM)
if ReturnKey() == KEY_Y then self:deleteFileAtPosition(pos) end
end
elseif self.dirs[pos] == ".." then
warningUnsupportedFunction()
else -- other folders
if InfoMessage.InfoMethod[MSG_CONFIRM] == 0 then -- silent regime
self:deleteFolderAtPosition(pos)
else
InfoMessage:inform("Press 'Y' to confirm ", DINFO_NODELAY, 0, MSG_CONFIRM)
if ReturnKey() == KEY_Y then self:deleteFolderAtPosition(pos) end
end
end
self.pagedirty = true
end -- function
)
-- make renaming flexible: it either keeps old extension (BEGINNERS_MODE) or
-- allows to rename the whole filename including the extension
self.commands:add(KEY_R, MOD_SHIFT, "R",
"rename file",
function(self)
local oldname = self:FullFileName()
if oldname then
-- NuPogodi, 04.09.2012: safe mode (keep old extensions)
-- Tigran, 18/08/12: corrected the rename operation to include extension.)
local name_we = self.files[self.perpage*(self.page-1)+self.current-#self.dirs]
local ext = ""
if self.filemanager_expert_mode <= self.BEGINNERS_MODE then
ext = "."..string.lower(string.match(oldname, ".+%.([^.]+)") or "")
name_we = string.sub(name_we, 1, -1-string.len(ext))
end
local newname = InputBox:input(0, 0, "New filename:", name_we)
if newname then
newname = self.path.."/"..newname..ext
os.rename(oldname, newname)
os.rename(DocToHistory(oldname), DocToHistory(newname))
self:setPath(self.path)
end
self.pagedirty = true
end
end
)
self.commands:add(KEY_M, MOD_ALT, "M",
"set user privilege level",
function(self)
self:changeFileChooserMode()
end
)
self.commands:add(KEY_E, nil, "E",
"configure event notifications",
function(self)
InfoMessage:chooseNotificatonMethods()
self.pagedirty = true
end
)
self.commands:addGroup("Vol-/+", {Keydef:new(KEY_VPLUS,nil), Keydef:new(KEY_VMINUS,nil)},
"decrease/increase sound volume",
function(self)
InfoMessage:incrSoundVolume(keydef.keycode == KEY_VPLUS and 1 or -1)
end
)
self.commands:addGroup(MOD_SHIFT.."Vol-/+", {Keydef:new(KEY_VPLUS,MOD_SHIFT), Keydef:new(KEY_VMINUS,MOD_SHIFT)},
"decrease/increase TTS-engine speed",
function(self)
InfoMessage:incrTTSspeed(keydef.keycode == KEY_VPLUS and 1 or -1)
end
)
self.commands:add({KEY_F, KEY_AA}, nil, "F, Aa",
"change font faces",
function(self)
Font:chooseFonts()
self.pagedirty = true
end
)
self.commands:add(KEY_H,nil,"H",
"show help page",
function(self)
HelpPage:show(0, G_height, self.commands, "Hotkeys "..G_program_version)
self.pagedirty = true
end
)
self.commands:add(KEY_L, nil, "L",
"show last documents",
function(self)
FileHistory:init()
FileHistory:choose("")
self.pagedirty = true
return nil
end
)
self.commands:add(KEY_S, nil, "S",
"search files (single space matches all)",
function(self)
local keywords = InputBox:input(0, 0, "Search:")
if keywords then
InfoMessage:inform("Searching... ", DINFO_NODELAY, 1, MSG_AUX)
FileSearcher:init( self.path )
FileSearcher:choose(keywords)
end
self.pagedirty = true
end
)
self.commands:add(KEY_C, MOD_SHIFT, "C",
"copy file to 'clipboard'",
function(self)
local file = self:FullFileName()
if file then
os.execute("cp "..InQuotes(file).." "..self.clipboard)
local fn = self.files[self.perpage*(self.page-1)+self.current - #self.dirs]
os.execute("cp "..InQuotes(DocToHistory(file)).." "
..InQuotes(DocToHistory(self.clipboard.."/"..fn)) )
InfoMessage:inform("File copied to clipboard ", DINFO_DELAY, 1, MSG_WARN)
end
end
)
self.commands:add(KEY_X, MOD_SHIFT, "X",
"move file to 'clipboard'",
function(self)
-- TODO (NuPogodi, 27.09.12): overwrite?
local file = self:FullFileName()
if file then
local fn = self.files[self.perpage*(self.page-1)+self.current - #self.dirs]
os.rename(file, self.clipboard.."/"..fn)
os.rename(DocToHistory(file), DocToHistory(self.clipboard.."/"..fn))
InfoMessage:inform("File moved to clipboard ", DINFO_DELAY, 0, MSG_WARN)
local pos = self.perpage*(self.page-1)+self.current
table.remove(self.files, pos-#self.dirs)
self.items = self.items - 1
self.current, self.page = gotoTargetItem(pos, self.items, pos, self.page, self.perpage)
self.pagedirty = true
end
end
)
self.commands:add(KEY_V, MOD_SHIFT, "V",
"paste file(s) from 'clipboard'",
function(self)
-- TODO (NuPogodi, 27.09.12): first test whether the clipboard is empty & answer respectively
-- TODO (NuPogodi, 27.09.12): overwrite?
InfoMessage:inform("Moving files from clipboard...", DINFO_NODELAY, 0, MSG_AUX)
for f in lfs.dir(self.clipboard) do
if lfs.attributes(self.clipboard.."/"..f, "mode") == "file" then
os.rename(self.clipboard.."/"..f, self.path.."/"..f)
os.rename(DocToHistory(self.clipboard.."/"..f), DocToHistory(self.path.."/"..f))
end
pagedirty = true
elseif ev.code == KEY_BACK or ev.code == KEY_HOME then
return nil
end
self:setPath(self.path)
self.pagedirty = true
end
)
self.commands:add(KEY_DOT, MOD_ALT, ".",
"toggle battery level logging",
function(self)
G_battery_logging = not G_battery_logging
InfoMessage:inform("Battery logging "..(G_battery_logging and "on " or "off "), DINFO_DELAY, 1, MSG_AUX)
G_reader_settings:saveSetting("G_battery_logging", G_battery_logging)
end
)
self.commands:add(KEY_B, MOD_SHIFT, "B",
"show content of 'clipboard'",
function(self)
-- save the current directory in order to
-- return from clipboard via ".." entry
local current_path = self.path
if self.clipboard ~= self.path then
self:setPath(self.clipboard)
self.before_clipboard = current_path
end
self.pagedirty = true
end
)
self.commands:add(KEY_N, MOD_SHIFT, "N",
"make new folder",
function(self)
local folder = InputBox:input(0, 0, "New Folder:")
if folder then
if lfs.mkdir(self.path.."/"..folder) then
self:setPath(self.path)
end
end
self.pagedirty = true
end
)
self.commands:add(KEY_K, MOD_SHIFT, "K",
"run calculator",
function(self)
local CalcBox = InputBox:new{ inputmode = MODE_CALC }
CalcBox:input(0, 0, "Calc ")
self.pagedirty = true
end
)
self.commands:addGroup("Home, Alt + Back", { Keydef:new(KEY_HOME, nil),Keydef:new(KEY_BACK, MOD_ALT)}, "exit",
function(self)
return "break"
end
)
end
-- returns full filename or nil (if folder)
function FileChooser:FullFileName()
local pos = self.current + self.perpage*(self.page-1) - #self.dirs
return pos > 0 and self.path.."/"..self.files[pos] or warningUnsupportedFunction()
end
-- returns the keycode of released key
function ReturnKey()
while true do
ev = input.saveWaitForEvent()
ev.code = adjustKeyEvents(ev)
if ev.type == EV_KEY and ev.value ~= EVENT_VALUE_KEY_RELEASE then
break
end
end
return ev.code
end
function InQuotes(text)
return "\""..text.."\""
end
--[[ NuPogodi, 04.09.2012: to make it more easy for users with various purposes and skills.
ATM, one may leave only silent toggling between BEGINNERS_MODE <> ADVANCED_MODE
-- But, in future, one more (the so called ROOT_MODE) might also be rather useful.
Switching this mode on should allow developers & beta-testers to use some unstable
and/or dangerous functions able to crash the reader. ]]
function FileChooser:changeFileChooserMode()
local face_list = { "Safe mode for beginners", "Advanced mode for experienced users", "Expert mode for beta-testers & developers" }
local modes_menu = SelectMenu:new{
menu_title = "Set user privilege level",
item_array = face_list,
current_entry = self.filemanager_expert_mode - 1,
}
local m = modes_menu:choose(0, G_height)
if m and m ~= self.filemanager_expert_mode then
if (self.filemanager_expert_mode == self.BEGINNERS_MODE and m > self.BEGINNERS_MODE)
or (m == self.BEGINNERS_MODE and self.filemanager_expert_mode > self.BEGINNERS_MODE) then
self.filemanager_expert_mode = m -- make sure that new mode is set before...
self:setPath(self.path) -- refreshing the folder content
else
self.filemanager_expert_mode = m
end
G_reader_settings:saveSetting("filemanager_expert_mode", self.filemanager_expert_mode)
end
-- NuPogodi, 26.09.2012: temporary place; when properly tested, might be commented / deleted the following line
InfoMessage:initInfoMessageSettings()
self.pagedirty = true
end
-- NuPogodi, 28.09.12: two following functions are extracted just to make the code more compact
function FileChooser:deleteFolderAtPosition(pos)
if lfs.rmdir(self.path.."/"..self.dirs[pos]) then
table.remove(self.dirs, pos) -- to avoid showing just deleted file
self.items = #self.dirs + #self.files
self.current, self.page = gotoTargetItem(pos, self.items, pos, self.page, self.perpage)
else
InfoMessage:inform("Directory not empty ", DINFO_DELAY, 1, MSG_ERROR)
end
end
function FileChooser:deleteFileAtPosition(pos)
local fullpath = self.path.."/"..self.files[pos-#self.dirs]
os.remove(fullpath) -- delete the file itself
os.remove(DocToHistory(fullpath)) -- and its history file, if any
table.remove(self.files, pos-#self.dirs) -- to avoid showing just deleted file
self.items = self.items - 1
self.current, self.page = gotoTargetItem(pos, self.items, pos, self.page, self.perpage)
end
-- NuPogodi, 01.10.12: jump to defined item in the itemlist
function gotoTargetItem(target_item, all_items, current_item, current_page, perpage)
target_item = math.max(math.min(target_item, all_items), 1)
local target_page = math.ceil(target_item/perpage)
local target_curr = (target_item -1) % perpage + 1
local pagedirty, markerdirty = false, false
if target_page ~= current_page then
current_page = target_page
pagedirty = true
markerdirty = true
elseif target_curr ~= current_item then
markerdirty = true
end
return target_curr, current_page, markerdirty, pagedirty
end
function warningUnsupportedFunction()
InfoMessage:inform("Unsupported function ", DINFO_DELAY, 1, MSG_WARN)
return nil
end

@ -0,0 +1,374 @@
require "rendertext"
require "keys"
require "graphics"
require "font"
require "inputbox"
require "dialog"
require "filesearcher"
require "settings"
require "dialog"
FileHistory = {
title_H = 40, -- title height
spacing = 36, -- spacing between lines
foot_H = 28, -- foot height
margin_H = 10, -- horisontal margin
-- state buffer
history_files = {},
files = {},
result = {},
items = 0,
page = 0,
current = 1,
oldcurrent = 1,
commands = nil,
}
function FileHistory:init(history_path)
self:setPath("history")
-- to initialize only once
if not self.commands then self:addAllCommands() end
end
function FileHistory:setPath(newPath)
self.path = newPath
self:readDir("-c ")
self.items = #self.files
if self.items == 1 then
return nil
end
self.page = 1
self.current = 1
return true
end
function FileHistory:readDir(order_criteria)
self.history_files = {}
self.files = {}
local p = io.popen("ls "..order_criteria.."-1 "..self.path)
for f in p:lines() do
-- insert history files
table.insert(self.history_files, {dir=self.path, name=f})
-- and corresponding path & file items
table.insert(self.files, {dir=HistoryToPath(f), name=HistoryToName(f)})
end
p:close()
end
function FileHistory:setSearchResult(keywords)
self.result = {}
if keywords == "" or keywords == " " then
-- show all history
self.result = self.files
else
-- select history files with keywords in the filename
for __,f in pairs(self.files) do
if string.find(string.lower(f.name), keywords) then
table.insert(self.result,f)
end
end
end
self.keywords = keywords
self.items = #self.result
self.page = 1
self.current = 1
return self.items
end
function FileHistory:prevItem()
if self.current == 1 then
if self.page > 1 then
self.current = self.perpage
self.page = self.page - 1
self.pagedirty = true
end
else
self.current = self.current - 1
self.markerdirty = true
end
end
function FileHistory:nextItem()
if self.current == self.perpage then
if self.page < (self.items / self.perpage) then
self.current = 1
self.page = self.page + 1
self.pagedirty = true
end
else
if self.page ~= math.floor(self.items / self.perpage) + 1
or self.current + (self.page-1)*self.perpage < self.items then
self.current = self.current + 1
self.markerdirty = true
end
end
end
function FileHistory:addAllCommands()
self.commands = Commands:new{}
self.commands:add(KEY_H, nil, "H",
"show help page",
function(self)
HelpPage:show(0, G_height, self.commands)
self.pagedirty = true
end
)
self.commands:add(KEY_FW_UP, nil, "joypad up",
"previous item",
function(self)
self:prevItem()
end
)
self.commands:add(KEY_FW_DOWN, nil, "joypad down",
"next item",
function(self)
self:nextItem()
end
)
-- NuPogodi, 01.10.12: fast jumps to items at positions 10, 20, .. 90, 0% within the list
local numeric_keydefs, i = {}
for i=1, 10 do numeric_keydefs[i]=Keydef:new(KEY_1+i-1, nil, tostring(i%10)) end
self.commands:addGroup("[1, 2 .. 9, 0]", numeric_keydefs,
"item at position 0%, 10% .. 90%, 100%",
function(self)
local target_item = math.ceil(self.items * (keydef.keycode-KEY_1) / 9)
self.current, self.page, self.markerdirty, self.pagedirty =
gotoTargetItem(target_item, self.items, self.current, self.page, self.perpage)
end
)
self.commands:add({KEY_PGFWD, KEY_LPGFWD}, nil, ">",
"next page",
function(self)
if self.page < (self.items / self.perpage) then
if self.current + self.page*self.perpage > self.items then
self.current = self.items - self.page*self.perpage
end
self.page = self.page + 1
self.pagedirty = true
else
self.current = self.items - (self.page-1)*self.perpage
self.markerdirty = true
end
end
)
self.commands:add({KEY_PGBCK, KEY_LPGBCK}, nil, "<",
"previous page",
function(self)
if self.page > 1 then
self.page = self.page - 1
self.pagedirty = true
else
self.current = 1
self.markerdirty = true
end
end
)
self.commands:add(KEY_G, nil, "G", -- NuPogodi, 01.10.12: goto page No.
"goto page",
function(self)
local n = math.ceil(self.items / self.perpage)
local page = NumInputBox:input(G_height-100, 100, "Page:", "current page "..self.page.." of "..n, true)
if pcall(function () page = math.floor(page) end) -- convert string to number
and page ~= self.page and page > 0 and page <= n then
self.page = page
if self.current + (page-1)*self.perpage > self.items then
self.current = self.items - (page-1)*self.perpage
end
end
self.pagedirty = true
end
)
self.commands:add(KEY_FW_RIGHT, nil, "joypad right",
"document details",
function(self)
local file_entry = self.result[self.perpage*(self.page-1)+self.current]
if file_entry.name == ".." then
warningUnsupportedFunction()
return
end -- do not show details
FileInfo:show(file_entry.dir,file_entry.name)
self.pagedirty = true
end
)
self.commands:add(KEY_S, nil, "S",
"invoke search inputbox",
function(self)
-- NuPogodi, 30.09.12: be sure that something is found
local old_keywords = self.keywords
local old_data = self.result
local old_page, old_current = self.page, self.current
self.keywords = InputBox:input(G_height - 100, 100, "Search:", old_keywords)
if self.keywords then
self:setSearchResult(self.keywords)
else
self.keywords = old_keywords
end
if #self.result < 1 then
InfoMessage:inform("No search hits ", DINFO_DELAY, 1, MSG_WARN)
-- restoring the original data
self.result = old_data
self.items = #self.result
self.keywords = old_keywords
self.page = old_page
self.current = old_current
end
self.pagedirty = true
end
)
self.commands:add({KEY_F, KEY_AA}, nil, "F, Aa",
"change font faces",
function(self)
Font:chooseFonts()
self.pagedirty = true
end
)
self.commands:add({KEY_ENTER, KEY_FW_PRESS}, nil, "Enter",
"open selected document",
function(self)
local file_entry = self.result[self.perpage*(self.page-1)+self.current]
file_full_path = file_entry.dir .. "/" .. file_entry.name
if FileExists(file_full_path) then
openFile(file_full_path)
--[[
-- reset height and item index if screen has been rotated
-- not needed because we force portrait mode on document close
local item_no = self.perpage * (self.page - 1) + self.current
self.perpage = math.floor(G_height / self.spacing) - 2
self.current = item_no % self.perpage
self.page = math.floor(item_no / self.perpage) + 1
--]]
self:init()
self:setSearchResult(self.keywords)
self.pagedirty = true
else
InfoMessage:inform("File does not exist ", DINFO_DELAY, 1, MSG_ERROR)
end
end
)
self.commands:add(KEY_DEL, nil, "Del",
"delete history entry",
function(self)
local file_entry = self.result[self.perpage*(self.page-1)+self.current]
local file_to_del = file_entry.dir .. "/" .. file_entry.name
if InfoMessage.InfoMethod[MSG_CONFIRM] == 0 then -- silent regime
os.remove(DocToHistory(file_to_del))
self:init()
self:setSearchResult(self.keywords)
else
InfoMessage:inform("Press 'Y' to confirm ", DINFO_NODELAY, 0, MSG_CONFIRM)
if ReturnKey() == KEY_Y then
os.remove(DocToHistory(file_to_del))
self:init()
self:setSearchResult(self.keywords)
end
end
self.pagedirty = true
if self.items == 0 then
return "break"
end
end
)
self.commands:add(KEY_SPACE, nil, "Space",
"refresh page manually",
function(self)
self.pagedirty = true
end
)
self.commands:add(KEY_BACK, nil, "Back",
"back",
function(self)
return "break"
end
)
end
function FileHistory:choose(keywords)
self.perpage = math.floor(G_height / self.spacing) - 2
self.pagedirty = true
self.markerdirty = false
-- NuPogodi, 30.09.12: immediate quit (no redraw), if empty
if self:setSearchResult(keywords) < 1 then
InfoMessage:inform("No reading history ", DINFO_DELAY, 1, MSG_WARN)
return nil
end
while true do
local cface = Font:getFace("cfont", 22)
local tface = Font:getFace("tfont", 25)
local fface = Font:getFace("ffont", 16)
if self.pagedirty then
self.markerdirty = true
fb.bb:paintRect(0, 0, G_width, G_height, 0)
-- draw header
local header = "Last Documents ("..tostring(self.items).." items)"
if self.keywords ~= "" and self.keywords ~= " " then
--header = header .. " (filter: \'" .. string.upper(self.keywords) .. "\')"
header = "Search Results for \'"..string.upper(self.keywords).."\'"
end
DrawTitle(header,self.margin_H,0,self.title_H,3,tface)
-- draw found results
for c = 1, self.perpage do
local i = (self.page - 1) * self.perpage + c
if i <= self.items then
y = self.title_H + (self.spacing * c) + 4
local ftype = string.lower(string.match(self.result[i].name, ".+%.([^.]+)") or "")
DrawFileItem(self.result[i].name,self.margin_H,y,ftype)
end
end
-- draw footer
all_page = math.ceil(self.items/self.perpage)
DrawFooter("Page "..self.page.." of "..all_page,fface,self.foot_H)
end
if self.markerdirty then
if not self.pagedirty then
if self.oldcurrent > 0 then
y = self.title_H + (self.spacing * self.oldcurrent) + 12
fb.bb:paintRect(self.margin_H, y, G_width - 2 * self.margin_H, 3, 0)
fb:refresh(1, self.margin_H, y, G_width - 2 * self.margin_H, 3)
end
end
-- draw new marker line
y = self.title_H + (self.spacing * self.current) + 12
fb.bb:paintRect(self.margin_H, y, G_width - 2 * self.margin_H, 3, 15)
if not self.pagedirty then
fb:refresh(1, self.margin_H, y, G_width - 2 * self.margin_H, 3)
end
self.oldcurrent = self.current
self.markerdirty = false
end
if self.pagedirty then
fb:refresh(0)
self.pagedirty = false
end
local ev = input.saveWaitForEvent()
ev.code = adjustKeyEvents(ev)
if ev.type == EV_KEY and ev.value ~= EVENT_VALUE_KEY_RELEASE then
keydef = Keydef:new(ev.code, getKeyModifier())
Debug("key pressed: "..tostring(keydef))
command = self.commands:getByKeydef(keydef)
if command ~= nil then
Debug("command to execute: "..tostring(command))
ret_code = command.func(self, keydef)
else
Debug("command not found: "..tostring(command))
end
if ret_code == "break" then
break
end
if self.selected_item ~= nil then
Debug("# selected "..self.selected_item)
return self.selected_item
end
end -- if
end -- while true
return nil
end

@ -0,0 +1,252 @@
require "rendertext"
require "keys"
require "graphics"
require "font"
require "inputbox"
require "dialog"
require "settings"
require "readerchooser"
FileInfo = {
title_H = 40, -- title height
spacing = 36, -- spacing between lines
foot_H = 28, -- foot height
margin_H = 10, -- horisontal margin
-- state buffer
pagedirty = true,
result = {},
commands = nil,
items = 0,
pathfile = "",
}
function FileInfo:FileCreated(fname, attr)
return os.date("%d %b %Y, %H:%M:%S", lfs.attributes(fname,attr))
end
function FileInfo:FormatSize(size)
if not tonumber(size) then
return "Invalid"
elseif size < 1024 then
return size.." Bytes"
elseif size < 2^20 then
return string.format("%.2f", size/2^10).."KB ("..size.." Bytes)"
elseif size < 2^30 then
return string.format("%.2f", size/2^20).."MB ("..size.." Bytes)"
else
return string.format("%.2f", size/2^30).."GB ("..size.." Bytes)"
end
end
function FileExists(path)
local f = io.open(path, "r")
if f then
f:close()
return true
else
return false
end
end
function getUnpackedZipSize(zipfile)
-- adding quotes allows us to avoid crash on zips which filename contains space(s)
local cmd='unzip -l \"'..zipfile..'\" | tail -1 | sed -e "s/^ *\\([0-9][0-9]*\\) *.*/\\1/"'
local p = io.popen(cmd, "r")
local res = p:read("*a")
p:close()
res = string.gsub(res, "[\n\r]+", "")
return tonumber(res)
end
function FileInfo:formatDiskSizeInfo()
local t, f = util.df(".")
return self:FormatSize(f)..string.format(", %.2f", 100*f/t).."%"
end
function FileInfo:getFolderContent()
local tmp = io.popen('du -a \"'..self.pathfile..'\"', "r")
local dirs, files, books, size, name, output, ftype, j = -1, 0, 0, 0
for output in tmp:lines() do
j = output:find("/")
name = output:sub(j, -1)
size = tonumber(output:sub(1, j-1)) -- in kB
j = lfs.attributes(name, "mode")
if j == "file" then
files = files + 1
ftype = string.match(name, ".+%.([^.]+)")
if ftype and ReaderChooser:getReaderByType(string.lower(ftype)) then
books = books + 1
end
elseif j == "directory" then
dirs = dirs + 1
end
end
tmp:close()
-- add 2 entries; might be joined / splitted
table.insert(self.result, {dir = "Contents", name = dirs.." sub-folder(s) / "..files.." file(s) / "..books.." book(s)"})
table.insert(self.result, {dir = "Size", name = self:FormatSize(size*1024)})
end
function FileInfo:init(path, fname)
-- add commands only once
if not self.commands then
self:addAllCommands()
end
if fname then
self.pathfile = path.."/"..fname
table.insert(self.result, {dir = "Name", name = fname} )
self.commands:add({KEY_ENTER, KEY_FW_PRESS}, nil, "Enter",
"open document",
function(self)
openFile(self.pathfile)
self.pagedirty = true
end)
else
self.pathfile = path.."/"
-- extracting folder name
local i, j = 0, 0
while true do
i = string.find(path, "/", i+1)
if i == nil then break else j=i end
end
table.insert(self.result, {dir = "Name", name = path:sub(j+1,-1) } )
table.insert(self.result, {dir = "Path", name = path:sub(1,j) } )
self.commands:add({KEY_ENTER, KEY_FW_PRESS}, nil, "Enter",
"goto folder",
function(self)
return "goto"
end)
end
local tmp, output
if fname then -- file info
table.insert(self.result, {dir = "Path", name = path.."/"} )
table.insert(self.result, {dir = "Size", name = self:FormatSize(lfs.attributes(self.pathfile, "size"))} )
-- total size of all unzipped entries for zips
local match = string.match(fname, ".+%.([^.]+)")
if match and string.lower(match) == "zip" then
table.insert(self.result, {dir = "Unpacked", name = self:FormatSize(getUnpackedZipSize(self.pathfile))} )
end
else -- folder info
self:getFolderContent()
end
table.insert(self.result, {dir = "Free space", name = self:formatDiskSizeInfo()})
table.insert(self.result, {dir = "Status changed", name = self:FileCreated(self.pathfile, "change")})
table.insert(self.result, {dir = "Modified", name = self:FileCreated(self.pathfile, "modification")})
table.insert(self.result, {dir = "Accessed", name = self:FileCreated(self.pathfile, "access")})
if fname then
-- if the document was already opened
local history = DocToHistory(self.pathfile)
if not FileExists(history) then
table.insert(self.result, {dir = "Last read", name = "Never"})
else
table.insert(self.result, {dir = "Last read", name = self:FileCreated(history, "change")})
local ext = string.match(self.pathfile, ".+%.([^.]+)")
local file_type = ext and ext:lower() or "txt"
local to_search, add, factor = "[\"last_percent\"]", "%", 100
if ReaderChooser:getReaderByType(file_type) ~= CREReader then
to_search = "[\"last_page\"]"
add = " pages"
factor = 1
end
for line in io.lines(history) do
if string.match(line, "%b[]") == to_search then
local cdc = tonumber(string.match(line, "%d+")) / factor
table.insert(self.result, {dir = "Completed", name = string.format("%d", cdc)..add })
end
end
end
end
self.items = #self.result
end
function FileInfo:show(path, name)
-- at first, one has to test whether the file still exists or not: necessary for last documents
if name and not FileExists(path.."/"..name) then return nil end
-- then goto main functions
self:init(path,name)
-- local variables
local cface, lface, tface, fface, width, xrcol, c, dy, ev, keydef, ret_code
while true do
if self.pagedirty then
-- refresh the fonts, if not yet defined or updated via 'F'
cface = Font:getFace("cfont", 22)
lface = Font:getFace("tfont", 22)
tface = Font:getFace("tfont", 25)
fface = Font:getFace("ffont", 16)
-- drawing
fb.bb:paintRect(0, 0, G_width, G_height, 0)
DrawTitle(name and "Document Information" or "Folder Information", self.margin_H, 0, self.title_H, 3, tface)
-- now calculating xrcol-position for the right column
width = 0
for c = 1, self.items do
width = math.max(sizeUtf8Text(0, G_width, lface, self.result[c].dir, true).x, width)
end
xrcol = self.margin_H + width + 25
dy = 5 -- to store the y-position correction 'cause of the multiline drawing
for c = 1, self.items do
y = self.title_H + self.spacing * c + dy
renderUtf8Text(fb.bb, self.margin_H, y, lface, self.result[c].dir, true)
dy = dy + renderUtf8Multiline(fb.bb, xrcol, y, cface, self.result[c].name, true,
G_width - self.margin_H - xrcol, 1.65).y - y
end
-- NuPogodi, 29.09.12: restored footer > to see 'Press H for help'
DrawFooter("Page 1 of 1",fface,self.foot_H)
fb:refresh(0)
self.pagedirty = false
end
-- waiting for user's commands
ev = input.saveWaitForEvent()
ev.code = adjustKeyEvents(ev)
if ev.type == EV_KEY and ev.value ~= EVENT_VALUE_KEY_RELEASE then
keydef = Keydef:new(ev.code, getKeyModifier())
command = self.commands:getByKeydef(keydef)
if command ~= nil then ret_code = command.func(self, keydef) end
if ret_code == "break" or ret_code == "goto" then break end
end -- if ev.type
end -- while true
self.pagedirty = true
self.result = {}
return ret_code
end
function FileInfo:addAllCommands()
self.commands = Commands:new{}
self.commands:add(KEY_SPACE, nil, "Space",
"refresh page manually",
function(self)
self.pagedirty = true
end
)
self.commands:add(KEY_H,nil,"H",
"show help page",
function(self)
HelpPage:show(0, G_height, self.commands)
self.pagedirty = true
end
)
self.commands:add({KEY_F, KEY_AA}, nil, "F, Aa",
"change font faces",
function(self)
Font:chooseFonts()
self.pagedirty = true
end
)
self.commands:add(KEY_L, nil, "L",
"last documents",
function(self)
FileHistory:init()
FileHistory:choose("")
self.pagedirty = true
end
)
self.commands:add({KEY_BACK, KEY_FW_LEFT}, nil, "Back, FW-Left",
"back",
function(self)
return "break"
end
)
end

@ -2,14 +2,15 @@ require "rendertext"
require "keys"
require "graphics"
require "font"
require "inputbox"
require "dialog"
require "readerchooser"
FileSearcher = {
-- title height
title_H = 45,
-- spacing between lines
spacing = 40,
-- foot height
foot_H = 27,
title_H = 40, -- title height
spacing = 36, -- spacing between lines
foot_H = 28, -- foot height
margin_H = 10, -- horisontal margin
-- state buffer
dirs = {},
@ -19,6 +20,7 @@ FileSearcher = {
page = 0,
current = 1,
oldcurrent = 1,
commands = nil,
}
function FileSearcher:readDir()
@ -31,19 +33,12 @@ function FileSearcher:readDir()
-- handle files in d
for f in lfs.dir(d) do
local file_type = string.lower(string.match(f, ".+%.([^.]+)") or "")
if lfs.attributes(d.."/"..f, "mode") == "directory"
and f ~= "." and f~= ".." and not string.match(f, "^%.[^.]") then
if lfs.attributes(d.."/"..f, "mode") == "directory" and f ~= "." and f~= ".." then
table.insert(new_dirs, d.."/"..f)
elseif file_type == "djvu" or file_type == "pdf"
or file_type == "xps" or file_type == "cbz"
or file_type == "epub" or file_type == "txt"
or file_type == "rtf" or file_type == "htm"
or file_type == "html" or file_type == "mobi"
or file_type == "fb2" or file_type == "chm"
or file_type == "doc" or file_type == "zip" then
elseif ReaderChooser:getReaderByType(file_type) then
file_entry = {dir=d, name=f,}
table.insert(self.files, file_entry)
--debug("file:"..d.."/"..f)
--Debug("file:"..d.."/"..f)
end
end
end
@ -70,7 +65,7 @@ function FileSearcher:setSearchResult(keywords)
self.result = self.files
else
for __,f in pairs(self.files) do
if string.find(string.lower(f.name), keywords) then
if string.find(string.lower(f.name), string.lower(keywords)) then
table.insert(self.result, f)
end
end
@ -82,12 +77,9 @@ function FileSearcher:setSearchResult(keywords)
end
function FileSearcher:init(search_path)
if search_path then
self:setPath(search_path)
else
self:setPath("/mnt/us/documents")
end
self:setPath(search_path or "/mnt/us/documents")
self:addAllCommands()
if not self.commands then self:addAllCommands() end
end
function FileSearcher:prevItem()
@ -121,19 +113,29 @@ end
function FileSearcher:addAllCommands()
self.commands = Commands:new{}
self.commands:add(KEY_FW_UP, nil, "joypad up",
"goto previous item",
"previous item",
function(self)
self:prevItem()
end
)
self.commands:add(KEY_FW_DOWN, nil, "joypad down",
"goto next item",
"next item",
function(self)
self:nextItem()
end
)
-- NuPogodi, 01.10.12: fast jumps to items at positions 10, 20, .. 90, 0% within the list
local numeric_keydefs, i = {}
for i=1, 10 do numeric_keydefs[i]=Keydef:new(KEY_1+i-1, nil, tostring(i%10)) end
self.commands:addGroup("[1, 2 .. 9, 0]", numeric_keydefs,
"item at position 0%, 10% .. 90%, 100%",
function(self)
local target_item = math.ceil(self.items * (keydef.keycode-KEY_1) / 9)
self.current, self.page, self.markerdirty, self.pagedirty =
gotoTargetItem(target_item, self.items, self.current, self.page, self.perpage)
end
)
self.commands:add({KEY_PGFWD, KEY_LPGFWD}, nil, ">",
"next page",
function(self)
@ -161,39 +163,79 @@ function FileSearcher:addAllCommands()
end
end
)
self.commands:add(KEY_G, nil, "G",
"goto page",
function(self)
local n = math.ceil(self.items / self.perpage)
local page = NumInputBox:input(G_height-100, 100, "Page:", "current page "..self.page.." of "..n, true)
if pcall(function () page = math.floor(page) end) -- convert string to number
and page ~= self.page and page > 0 and page <= n then
self.page = page
if self.current + (page-1)*self.perpage > self.items then
self.current = self.items - (page-1)*self.perpage
end
end
self.pagedirty = true
end
)
self.commands:add(KEY_L, nil, "L",
"last documents",
function(self)
FileHistory:init()
FileHistory:choose("")
self.pagedirty = true
end
)
self.commands:add(KEY_H, nil, "H",
"show help page",
function(self)
HelpPage:show(0, G_height, self.commands)
self.pagedirty = true
end
)
self.commands:add(KEY_FW_RIGHT, nil, "joypad right",
"document details",
function(self)
local file_entry = self.result[self.perpage*(self.page-1)+self.current]
FileInfo:show(file_entry.dir,file_entry.name)
self.pagedirty = true
end
)
self.commands:add(KEY_S, nil, "S",
"invoke search inputbox",
function(self)
old_keywords = self.keywords
self.keywords = InputBox:input(G_height - 100, 100,
"Search:", old_keywords)
local old_keywords = self.keywords
self.keywords = InputBox:input(G_height - 100, 100, "Search:", old_keywords)
if self.keywords then
local old_data = self.result -- be sure that something is found, otherwise restore
local old_page, old_current = self.page, self.current
self:setSearchResult(self.keywords)
if #self.result < 1 then
InfoMessage:inform("No search hits ", DINFO_DELAY, 1, MSG_WARN)
-- restoring the original data
self.result = old_data
self.items = #self.result
self.page = old_page
self.current = old_current
self.keywords = old_keywords
end
else
self.keywords = old_keywords
end
self.pagedirty = true
end
)
self.commands:add(KEY_F, nil, "F",
"font menu",
self.commands:add({KEY_F, KEY_AA}, nil, "F, Aa",
"change font faces",
function(self)
local fonts_menu = SelectMenu:new{
menu_title = "Fonts Menu",
item_array = Font:getFontList(),
}
local re, font = fonts_menu:choose(0, G_height)
if re then
Font.fontmap["cfont"] = font
Font:update()
end
Font:chooseFonts()
self.pagedirty = true
end
)
self.commands:add({KEY_ENTER, KEY_FW_PRESS}, nil, "",
"select item",
self.commands:add({KEY_ENTER, KEY_FW_PRESS}, nil, "Enter",
"open selected item",
function(self)
file_entry = self.result[self.perpage*(self.page-1)+self.current]
local file_entry = self.result[self.perpage*(self.page-1)+self.current]
file_full_path = file_entry.dir .. "/" .. file_entry.name
openFile(file_full_path)
@ -206,8 +248,31 @@ function FileSearcher:addAllCommands()
self.pagedirty = true
end
)
self.commands:add({KEY_BACK, KEY_HOME}, nil, "",
"back to file browser",
self.commands:add(KEY_DEL, nil, "Del",
"delete document",
function(self)
local pos = self.perpage*(self.page-1)+self.current
local file_entry = self.result[pos]
local file_to_del = file_entry.dir .. "/" .. file_entry.name
if InfoMessage.InfoMethod[MSG_CONFIRM] == 0 then -- silent regime
self:deleteFoundFile(file_to_del)
else
InfoMessage:inform("Press 'Y' to confirm ", DINFO_NODELAY, 0, MSG_CONFIRM)
if ReturnKey() == KEY_Y then
self:deleteFoundFile(file_to_del)
end
self.pagedirty = true
end
end
)
self.commands:add(KEY_SPACE, nil, "Space",
"refresh page manually",
function(self)
self.pagedirty = true
end
)
self.commands:add(KEY_BACK, nil, "Back",
"back",
function(self)
return "break"
end
@ -219,12 +284,16 @@ function FileSearcher:choose(keywords)
self.pagedirty = true
self.markerdirty = false
-- if given keywords, set new result according to keywords.
-- Otherwise, display the previous search result.
if keywords then
self:setSearchResult(keywords)
end
-- NuPogodi, 30.09.12: immediate quit (no redraw), if empty -- there is nothing to do in empty list anyway
if #self.result < 1 then
InfoMessage:inform("No search hits found ", DINFO_DELAY, 1, MSG_WARN)
return nil
end
while true do
local cface = Font:getFace("cfont", 22)
@ -235,51 +304,35 @@ function FileSearcher:choose(keywords)
self.markerdirty = true
fb.bb:paintRect(0, 0, G_width, G_height, 0)
-- draw menu title
renderUtf8Text(fb.bb, 30, 0 + self.title_H, tface,
"Search Result for: "..self.keywords, true)
DrawTitle("Search Results for \'"..self.keywords.."\'".." ("..tostring(self.items).." hits)",self.margin_H,0,self.title_H,3,tface)
-- draw results
local c
if self.items == 0 then -- nothing found
y = self.title_H + self.spacing * 2
renderUtf8Text(fb.bb, 20, y, cface,
"Sorry, no match found.", true)
renderUtf8Text(fb.bb, 20, y + self.spacing, cface,
"Please try a different keyword.", true)
self.markerdirty = false
else -- found something, draw it
for c = 1, self.perpage do
local i = (self.page - 1) * self.perpage + c
if i <= self.items then
y = self.title_H + (self.spacing * c)
renderUtf8Text(fb.bb, 50, y, cface,
self.result[i].name, true)
end
for c = 1, self.perpage do
local i = (self.page - 1) * self.perpage + c
if i <= self.items then
y = self.title_H + (self.spacing * c) + 4
local ftype = string.lower(string.match(self.result[i].name, ".+%.([^.]+)") or "")
DrawFileItem(self.result[i].name,self.margin_H,y,ftype)
end
end
-- draw footer
y = self.title_H + (self.spacing * self.perpage) + self.foot_H
x = (G_width / 2) - 50
all_page = math.ceil(self.items/self.perpage)
renderUtf8Text(fb.bb, x, y, fface,
"Page "..self.page.." of "..all_page, true)
DrawFooter("Page "..self.page.." of "..all_page,fface,self.foot_H)
end
if self.markerdirty then
if not self.pagedirty then
if self.oldcurrent > 0 then
y = self.title_H + (self.spacing * self.oldcurrent) + 10
fb.bb:paintRect(30, y, G_width - 60, 3, 0)
fb:refresh(1, 30, y, G_width - 60, 3)
y = self.title_H + (self.spacing * self.oldcurrent) + 12
fb.bb:paintRect(self.margin_H, y, G_width - 2 * self.margin_H, 3, 0)
fb:refresh(1, self.margin_H, y, G_width - 2 * self.margin_H, 3)
end
end
-- draw new marker line
y = self.title_H + (self.spacing * self.current) + 10
fb.bb:paintRect(30, y, G_width - 60, 3, 15)
y = self.title_H + (self.spacing * self.current) + 12
fb.bb:paintRect(self.margin_H, y, G_width - 2 * self.margin_H, 3, 15)
if not self.pagedirty then
fb:refresh(1, 30, y, G_width - 60, 3)
fb:refresh(1, self.margin_H, y, G_width - 2 * self.margin_H, 3)
end
self.oldcurrent = self.current
self.markerdirty = false
@ -294,14 +347,14 @@ function FileSearcher:choose(keywords)
ev.code = adjustKeyEvents(ev)
if ev.type == EV_KEY and ev.value ~= EVENT_VALUE_KEY_RELEASE then
keydef = Keydef:new(ev.code, getKeyModifier())
debug("key pressed: "..tostring(keydef))
Debug("key pressed: "..tostring(keydef))
command = self.commands:getByKeydef(keydef)
if command ~= nil then
debug("command to execute: "..tostring(command))
Debug("command to execute: "..tostring(command))
ret_code = command.func(self, keydef)
else
debug("command not found: "..tostring(command))
Debug("command not found: "..tostring(command))
end
if ret_code == "break" then
@ -309,10 +362,27 @@ function FileSearcher:choose(keywords)
end
if self.selected_item ~= nil then
debug("# selected "..self.selected_item)
Debug("# selected "..self.selected_item)
return self.selected_item
end
end -- if
end -- while true
return nil
end
function FileSearcher:deleteFoundFile(file_to_del)
os.remove(file_to_del)
os.remove(DocToHistory(file_to_del))
-- NuPogodi, 02.10.12: remove file from self.files WITHOUT rescanning folders
local i = 1
while i <= #self.files and self.files[i].dir.."/"..self.files[i].name ~= file_to_del do
i = i + 1
end
if i <= #self.files then
table.remove(self.files, i)
self.items = #self.files
end
i = self.current - 1 + (self.page-1)*self.perpage
self.page = math.ceil(i/self.perpage)
self.current = i - (self.page-1)*self.perpage
end

@ -1,37 +1,16 @@
Font = {
fontmap = {
-- default font for menu contents
cfont = "droid/DroidSans.ttf",
-- default font for title
tfont = "NimbusSanL-BoldItal.cff",
-- default font for footer
ffont = "droid/DroidSans.ttf",
-- default font for reading position info
rifont = "droid/DroidSans.ttf",
-- default font for pagination display
pgfont = "droid/DroidSans.ttf",
-- selectmenu: font for item shortcut
scfont = "droid/DroidSansMono.ttf",
-- help page: font for displaying keys
hpkfont = "droid/DroidSansMono.ttf",
-- font for displaying help messages
hfont = "droid/DroidSans.ttf",
-- font for displaying input content
-- we have to use mono here for better distance controlling
infont = "droid/DroidSansMono.ttf",
-- font for info messages
infofont = "droid/DroidSans.ttf",
cfont = "droid/DroidSansFallbackFull.ttf", -- filemanager: for menu contents
tfont = "droid/DroidSans.ttf", -- filemanager: for title
ffont = "droid/DroidSans.ttf", -- filemanager: for footer
infofont = "droid/DroidSans.ttf", -- info messages
rifont = "droid/DroidSans.ttf", -- readers: for reading position info
scfont = "droid/DroidSansMono.ttf", -- selectmenu: font for item shortcut
hpkfont = "droid/DroidSansMono.ttf", -- help page: font for displaying keys
hfont = "droid/DroidSans.ttf", -- help page: font for displaying help messages
infont = "droid/DroidSansMono.ttf", -- inputbox: use mono for better distance controlling
},
fontdir = os.getenv("FONTDIR") or "./fonts",
-- face table
faces = {},
}
@ -40,7 +19,7 @@ Font = {
function Font:getFace(font, size)
if not font then
-- default to content font
font = self.cfont
font = "cfont"
end
local face = self.faces[font..size]
@ -53,11 +32,11 @@ function Font:getFace(font, size)
realname = self.fontdir.."/"..realname
ok, face = pcall(freetype.newFace, realname, size)
if not ok then
debug("#! Font "..font.." ("..realname..") not supported: "..face)
Debug("#! Font "..font.." ("..realname..") not supported: "..face)
return nil
end
self.faces[font..size] = face
--debug("getFace, found: "..realname.." size:"..size)
--Debug("getFace, found: "..realname.." size:"..size)
end
return { size = size, ftface = face, hash = font..size }
end
@ -89,3 +68,81 @@ function Font:update()
self.faces = {}
clearGlyphCache()
end
-- NuPogodi, 05.09.12: added function to change fontface for ANY item in Font.fontmap
-- choose the Fonts.fontmap-item that has to be changed
function Font:chooseItemForFont(initial)
local items_list = {}
local item_no, item_found = 1, false
local description -- additional info to display in menu
-- define auxilary function
function add_element(_index)
if _index == "cfont" then description = "filemanager: menu contents"
elseif _index == "tfont" then description = "filemanager: header title"
elseif _index == "ffont" then description = "filemanager: footer"
elseif _index == "rifont" then description = "readers: reading position info"
elseif _index == "scfont" then description = "selectmenu: item shortcuts"
elseif _index == "hpkfont" then description = "help page: hotkeys"
elseif _index == "hfont" then description = "help page: description"
elseif _index == "infont" then description = "inputbox: on-screen keyboard & user input"
elseif _index == "infofont" then description = "info messages"
else --[[ not included in Font.fontmap ]] description = "nothing; not used anymore"
end
-- then, search for number of initial item in the list Font.fontmap
if not item_found then
if _index ~= initial then
item_no = item_no + 1
else
item_found = true
end
end
table.insert(items_list, "[".._index.."] for "..description)
end
table.foreach(Font.fontmap, add_element)
-- goto menu to select the item which font should be changed
local items_menu = SelectMenu:new{
menu_title = "Select item to change",
item_array = items_list,
current_entry = item_no - 1,
own_glyph = 2, -- use Font.fontmap-values to render 'items_menu'-items
}
local ok, item_font = items_menu:choose(0, fb.bb:getHeight())
if not ok then
return nil
end
-- and selecting from the font index included in [...] from the whole string
return string.sub(string.match(item_font,"%b[]"), 2, -2)
end
-- choose font for the 'item_font' in Fonts.fontmap
function Font:chooseFontForItem(item_font)
item_font = item_font or "cfont"
local item_no = 0
local face_list = Font:getFontList()
while face_list[item_no] ~= Font.fontmap[item_font] and item_no < #face_list do
item_no = item_no + 1
end
local fonts_menu = SelectMenu:new{
menu_title = "Fonts Menu",
item_array = face_list,
current_entry = item_no - 1,
own_glyph = 1, -- use the item from item_array to render 'fonts_menu'-items
}
local re, font = fonts_menu:choose(0, G_height)
if re then
Font.fontmap[item_font] = font
Font:update()
end
end
-- to remain in menu with Font.fontmap-items until 'Back'
function Font:chooseFonts()
local item_font = "cfont" -- initial value
while item_font ~= nil do
item_font = self:chooseItemForFont(item_font)
if item_font then
self:chooseFontForItem(item_font)
end
end
end

@ -85,7 +85,7 @@ function Cursor:setHeight(h)
self.line_w = math.floor(self.h / self.line_width_factor)
end
function Cursor:_draw(x, y)
function Cursor:_draw(x, y, refresh)
local up_down_width = math.floor(self.line_w / 2)
local body_h = self.h - (up_down_width * 2)
-- paint upper horizontal line
@ -95,19 +95,23 @@ function Cursor:_draw(x, y)
self.line_w, body_h)
-- paint lower horizontal line
fb.bb:invertRect(x, y + body_h + up_down_width, self.w, up_down_width)
if refresh then
fb:refresh(1, x, y, self.w, body_h + up_down_width * 2)
end
end
function Cursor:draw()
function Cursor:draw(refresh)
if self.is_cleared then
self.is_cleared = false
self:_draw(self.x_pos, self.y_pos)
self:_draw(self.x_pos, self.y_pos, refresh)
end
end
function Cursor:clear()
function Cursor:clear(refresh)
if not self.is_cleared then
self.is_cleared = true
self:_draw(self.x_pos, self.y_pos)
self:_draw(self.x_pos, self.y_pos, refresh)
end
end

@ -8,38 +8,30 @@ require "commands"
HelpPage = {
-- Other Class vars:
-- spacing between lines
spacing = 25,
title_H = 40, -- title height
margin_H = 10, -- horisontal margin
foot_H = 28, -- foot height
bg_color = 3, -- background color
spacing = 25, -- spacing between lines
-- state buffer
commands = nil,
items = 0,
page = 1,
-- font for displaying keys
fsize = 20,
face = Font:getFace("hpkfont", 20),
-- font for displaying help messages
hfsize = 20,
hface = Font:getFace("hfont", 20),
-- font for paging display
ffsize = 15,
fface = Font:getFace("pgfont", 15)
}
-- Other Class vars:
function HelpPage:show(ypos, height, commands, title)
local face = Font:getFace("hpkfont", 20)
local hface = Font:getFace("hfont", 20)
local fface = Font:getFace("ffont", 16)
local tface = Font:getFace("tfont", 25)
function HelpPage:show(ypos, height, commands)
self.commands = {}
self.commands = Commands:new()
self.items = 0
local keys = {}
for k,v in pairs(commands.map) do
local key = v.keygroup or v.keydef:display()
--debug("order: "..v.order.." command: "..tostring(v.keydef).." - keygroup:"..(v.keygroup or "nil").." -keys[key]:"..(keys[key] or "nil"))
--Debug("order: "..v.order.." command: "..tostring(v.keydef).." - keygroup:"..(v.keygroup or "nil").." -keys[key]:"..(keys[key] or "nil"))
if keys[key] == nil then
keys[key] = 1
table.insert(self.commands,{shortcut=key,help=v.help,order=v.order})
@ -48,46 +40,49 @@ function HelpPage:show(ypos, height, commands)
end
table.sort(self.commands,function(w1,w2) return w1.order<w2.order end)
local face_height, face_ascender = self.face.ftface:getHeightAndAscender()
--local hface_height, hface_ascender = self.hface.ftface:getHeightAndAscender()
local fface_height, fface_ascender = self.fface.ftface:getHeightAndAscender()
--debug(face_height.."-"..face_ascender)
--debug(fface_height.."-"..fface_ascender)
local face_height, face_ascender = face.ftface:getHeightAndAscender()
--local hface_height, hface_ascender = hface.ftface:getHeightAndAscender()
local fface_height, fface_ascender = fface.ftface:getHeightAndAscender()
--Debug(face_height.."-"..face_ascender)
--Debug(fface_height.."-"..fface_ascender)
face_height = math.ceil(face_height)
face_ascender = math.ceil(face_ascender)
fface_height = math.ceil(fface_height)
fface_ascender = math.ceil(fface_ascender)
local spacing = face_height + 5
local vert_S = self.title_H + 3
local perpage = math.floor( (height - ypos - 1 * (fface_height + 5)) / spacing )
local perpage = math.floor( (height - ypos - 1 * (fface_height + 5) - vert_S) / spacing )
self.page = 1
local is_pagedirty = true
while true do
if is_pagedirty then
fb.bb:paintRect(0, ypos, fb.bb:getWidth(), height, 0)
DrawTitle(title or "Active Hotkeys",self.margin_H,0,self.title_H,self.bg_color,tface)
local c
local max_x = 0
for c = 1, perpage do
local x = 5
local x = self.margin_H
local i = (self.page - 1) * perpage + c
if i <= self.items then
local key = self.commands[i].shortcut
for _k,aMod in pairs(MOD_TABLE) do
local modStart, modEnd = key:find(aMod.v)
debug("key:"..key.." v:"..aMod.v.." d:"..aMod.d.." modstart:"..(modStart or "nil"))
Debug("key:"..key.." v:"..aMod.v.." d:"..aMod.d.." modstart:"..(modStart or "nil"))
if(modStart ~= nil) then
key = key:sub(1,modStart-1)..key:sub(modEnd+1)
local box = sizeUtf8Text( x, fb.bb:getWidth(), self.face, aMod.d, true)
fb.bb:paintRect(x, ypos + spacing*c - box.y_top, box.x, box.y_top + box.y_bottom, 4)
local pen_x = renderUtf8Text(fb.bb, x, ypos + spacing*c, self.face, aMod.d.." + ", true)
local box = sizeUtf8Text( x, fb.bb:getWidth(), face, aMod.d, true)
fb.bb:paintRect(x, ypos + spacing*c - box.y_top + vert_S, box.x + self.title_H, box.y_top + box.y_bottom, self.bg_color)
local pen_x = renderUtf8Text(fb.bb, x, ypos + spacing*c + vert_S, face, aMod.d.." + ", true)
x = x + pen_x
max_x = math.max(max_x, pen_x)
end
end
debug("key:"..key)
local box = sizeUtf8Text( x, fb.bb:getWidth(), self.face, key , true)
fb.bb:paintRect(x, ypos + spacing*c - box.y_top, box.x, box.y_top + box.y_bottom, 4)
local pen_x = renderUtf8Text(fb.bb, x, ypos + spacing*c, self.face, key, true)
Debug("key:"..key)
local box = sizeUtf8Text( x, fb.bb:getWidth(), face, key , true)
fb.bb:paintRect(x, ypos + spacing*c - box.y_top + vert_S, box.x, box.y_top + box.y_bottom, self.bg_color)
local pen_x = renderUtf8Text(fb.bb, x, ypos + spacing*c + vert_S, face, key, true)
x = x + pen_x
max_x = math.max(max_x, x)
end
@ -95,11 +90,12 @@ function HelpPage:show(ypos, height, commands)
for c = 1, perpage do
local i = (self.page - 1) * perpage + c
if i <= self.items then
renderUtf8Text(fb.bb, max_x + 20, ypos + spacing*c, self.hface, self.commands[i].help, true)
renderUtf8Text(fb.bb, max_x + 20, ypos + spacing*c + vert_S, hface, self.commands[i].help, true)
end
end
renderUtf8Text(fb.bb, 5, height - fface_height + fface_ascender - 5, self.fface,
"Page "..self.page.." of "..math.ceil(self.items / perpage).." - Back to close this page", true)
-- draw footer
local footer = "Page "..self.page.." of "..math.ceil(self.items / perpage).." - Back to close this page"
renderUtf8Text(fb.bb, self.margin_H, height-7, fface, footer, true)
end
if is_pagedirty then
fb:refresh(0, 0, ypos, fb.bb:getWidth(), height)
@ -107,7 +103,7 @@ function HelpPage:show(ypos, height, commands)
end
local ev = input.saveWaitForEvent()
--debug("key code:"..ev.code)
--Debug("key code:"..ev.code)
ev.code = adjustKeyEvents(ev)
if ev.type == EV_KEY and ev.value == EVENT_VALUE_KEY_PRESS then
if ev.code == KEY_PGFWD or ev.code == KEY_LPGFWD then
@ -120,9 +116,15 @@ function HelpPage:show(ypos, height, commands)
self.page = self.page - 1
is_pagedirty = true
end
elseif ev.code == KEY_BACK or ev.code == KEY_HOME then
elseif ev.code == KEY_BACK then
return nil
elseif ev.code == KEY_INTO_SCREEN_SAVER or ev.code == KEY_OUTOF_SCREEN_SAVER then
command = self.commands:get(ev.code, nil)
ret_code = command.func(self)
if ret_code == "break" then
break;
end
end
end
end
end -- ev.type == EV_KEY...
end -- while
end

@ -15,24 +15,47 @@
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "popen-noshell/popen_noshell.h"
#include <err.h>
#include <stdio.h>
#include <signal.h>
#include <fcntl.h>
#include <errno.h>
#include <unistd.h>
#include <stdlib.h>
#ifdef EMULATE_READER
#include <SDL.h>
#define EV_KEY 0x01
#else
#include <linux/input.h>
#endif
#include "input.h"
#include <sys/types.h>
#include <sys/wait.h>
#include <signal.h>
#define OUTPUT_SIZE 21
#define CODE_IN_SAVER 10000
#define CODE_OUT_SAVER 10001
#define CODE_IN_SAVER 10000
#define CODE_OUT_SAVER 10001
#define CODE_USB_PLUG_IN 10010
#define CODE_USB_PLUG_OUT 10011
#define CODE_CHARGING 10020
#define CODE_NOT_CHARGING 10021
#define NUM_FDS 4
int inputfds[4] = { -1, -1, -1, -1 };
int slider_pid = -1;
#ifndef EMULATE_READER
pid_t slider_pid = -1;
struct popen_noshell_pass_to_pclose pclose_arg;
void slider_handler(int sig)
{
/* Kill lipc-wait-event properly on exit */
if(pclose_arg.pid != 0) {
// Be a little more gracious, lipc seems to handle SIGINT properly
kill(pclose_arg.pid, SIGINT);
}
}
#endif
int findFreeFdSlot() {
int i;
@ -64,10 +87,13 @@ static int openInputDevice(lua_State *L) {
return luaL_error(L, "cannot fork() slider event listener");
}
if(childpid == 0) {
// We send a SIGTERM to this child on exit, trap it to kill lipc properly.
signal(SIGTERM, slider_handler);
FILE *fp;
char std_out[OUTPUT_SIZE] = "";
char std_out[256];
int status;
struct input_event ev;
int ret;
__u16 key_code = 10000;
close(pipefd[0]);
@ -76,17 +102,34 @@ static int openInputDevice(lua_State *L) {
ev.code = key_code;
ev.value = 1;
/* listen power slider events */
while(1) {
fp = popen("exec lipc-wait-event com.lab126.powerd goingToScreenSaver,outOfScreenSaver", "r");
if(fgets(std_out, OUTPUT_SIZE, fp) == NULL) {
break;
}
pclose(fp);
/* listen power slider events (listen for ever for multiple events) */
char *argv[] = {"lipc-wait-event", "-m", "-s", "0", "com.lab126.powerd", "goingToScreenSaver,outOfScreenSaver,charging,notCharging", (char *) NULL};
/* @TODO 07.06 2012 (houqp)
* plugin and out event can only be watched by:
lipc-wait-event com.lab126.hal usbPlugOut,usbPlugIn
*/
fp = popen_noshell("lipc-wait-event", (const char * const *)argv, "r", &pclose_arg, 0);
if (!fp) {
err(EXIT_FAILURE, "popen_noshell()");
}
/* Flush to get rid of buffering issues? */
fflush(fp);
while(fgets(std_out, sizeof(std_out)-1, fp)) {
if(std_out[0] == 'g') {
ev.code = CODE_IN_SAVER;
} else if(std_out[0] == 'o') {
ev.code = CODE_OUT_SAVER;
} else if((std_out[0] == 'u') && (std_out[7] == 'I')) {
ev.code = CODE_USB_PLUG_IN;
} else if((std_out[0] == 'u') && (std_out[7] == 'O')) {
ev.code = CODE_USB_PLUG_OUT;
} else if(std_out[0] == 'c') {
ev.code = CODE_CHARGING;
} else if(std_out[0] == 'n') {
ev.code = CODE_NOT_CHARGING;
} else {
printf("Unrecognized event.\n");
}
@ -95,10 +138,26 @@ static int openInputDevice(lua_State *L) {
/* generate event */
if(write(pipefd[1], &ev, sizeof(struct input_event)) == -1) {
break;
printf("Failed to generate event.\n");
}
}
exit(0); /* cannot be reached?! */
status = pclose_noshell(&pclose_arg);
if (status == -1) {
err(EXIT_FAILURE, "pclose_noshell()");
} else {
printf("lipc-wait-event exited with status %d.\n", status);
if WIFEXITED(status) {
printf("lipc-wait-event exited normally with status: %d.\n", WEXITSTATUS(status));
}
if WIFSIGNALED(status) {
printf("lipc-wait-event terminated by signal: %d.\n", WTERMSIG(status));
}
}
// We're done, go away :).
_exit(EXIT_SUCCESS);
} else {
close(pipefd[1]);
inputfds[fd] = pipefd[0];
@ -117,16 +176,18 @@ static int openInputDevice(lua_State *L) {
if(SDL_Init(SDL_INIT_VIDEO) < 0) {
return luaL_error(L, "cannot initialize SDL.");
}
SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL);
return 0;
#endif
}
static int closeInputDevices(lua_State *L) {
#ifndef EMULATE_READER
int i;
for(i=0; i<NUM_FDS; i++) {
if(inputfds[i] != -1) {
ioctl(inputfds[i], EVIOCGRAB, 0);
close(i);
close(inputfds[i]);
}
}
if(slider_pid != -1) {
@ -135,6 +196,9 @@ static int closeInputDevices(lua_State *L) {
waitpid(-1, NULL, 0);
}
return 0;
#else
return 0;
#endif
}
static int waitForInput(lua_State *L) {
@ -197,7 +261,7 @@ static int waitForInput(lua_State *L) {
SDL_WaitEvent(&event);
else {
while (SDL_GetTicks()-ticks <= usecs/1000) {
if (SDL_PollEvent(&event)) break;
if (SDL_PollEvent(&event)) break;
SDL_Delay(10);
}
if (SDL_GetTicks()-ticks > usecs/1000)

@ -18,10 +18,6 @@
#ifndef _PDF_INPUT_H
#define _PDF_INPUT_H
#ifdef EMULATE_READER
#include <SDL.h>
#endif
#include <lua.h>
#include <lualib.h>
#include <lauxlib.h>

@ -3,26 +3,22 @@ require "rendertext"
require "keys"
require "graphics"
MODE_CALC = 1
MODE_TERM = 2
----------------------------------------------------
-- General inputbox
----------------------------------------------------
InputBox = {
-- Class vars:
h = 100,
input_slot_w = nil,
input_start_x = 145,
input_start_x = nil,
input_start_y = nil,
input_cur_x = nil, -- points to the start of next input pos
input_bg = 0,
input_string = "",
shiftmode = false,
altmode = false,
cursor = nil,
-- font for displaying input content
@ -31,7 +27,21 @@ InputBox = {
fheight = 25,
fwidth = 15,
commands = nil,
initialized = false,
vk_bg = 3,
charlist = {}, -- table to store input string
charpos = 1,
INPUT_KEYS = {}, -- table to store layouts
-- values to control layouts: min & max
min_layout = 2,
max_layout = 9,
layout = 3,
-- now bits to toggle the layout mode
shiftmode = true, -- toggle chars <-> capitals, lowest bit in (layout-2)
symbolmode = false, -- toggle chars <-> symbols, middle bit in (layout-2)
utf8mode = false, -- toggle english <-> national, highest bit in (layout-2)
inputmode, -- define mode: input <> calculator <> terminal
calcfunctions = nil, -- math functions for calculator helppage
}
function InputBox:new(o)
@ -41,162 +51,135 @@ function InputBox:new(o)
return o
end
function InputBox:init()
if not self.initialized then
self:addAllCommands()
self.initialized = true
end
end
function InputBox:refreshText()
-- clear previous painted text
fb.bb:paintRect(140, self.input_start_y-19,
self.input_slot_w, self.fheight, self.input_bg)
fb.bb:paintRect(self.input_start_x-5, self.input_start_y-19, self.input_slot_w, self.fheight, self.input_bg)
-- paint new text
renderUtf8Text(fb.bb, self.input_start_x, self.input_start_y,
self.face,
self.input_string, 0)
renderUtf8Text(fb.bb, self.input_start_x, self.input_start_y, self.face, self.input_string, true)
end
function InputBox:addChar(char)
self.cursor:clear()
-- draw new text
local cur_index = (self.cursor.x_pos + 3 - self.input_start_x)
/ self.fwidth
self.input_string = self.input_string:sub(1, cur_index)..char..
self.input_string:sub(cur_index+1)
local cur_index = (self.cursor.x_pos + 3 - self.input_start_x) / self.fwidth
table.insert(self.charlist, self.charpos, char)
self.charpos = self.charpos + 1
self.input_string = self:CharlistToString()
self:refreshText()
self.input_cur_x = self.input_cur_x + self.fwidth
-- draw new cursor
self.cursor:moveHorizontal(self.fwidth)
self.cursor:draw()
fb:refresh(1, self.input_start_x-5, self.input_start_y-25,
self.input_slot_w, self.h-25)
fb:refresh(1, self.input_start_x-5, self.input_start_y-25, self.input_slot_w, self.h-25)
end
function InputBox:delChar()
if self.input_start_x == self.input_cur_x then
return
end
local cur_index = (self.cursor.x_pos + 3 - self.input_start_x)
/ self.fwidth
if self.input_start_x == self.input_cur_x then return end
local cur_index = (self.cursor.x_pos + 3 - self.input_start_x) / self.fwidth
if cur_index == 0 then return end
self.cursor:clear()
-- draw new text
self.input_string = self.input_string:sub(1, cur_index-1)..
self.input_string:sub(cur_index+1, -1)
self.charpos = self.charpos - 1
table.remove(self.charlist, self.charpos)
self.input_string = self:CharlistToString()
self:refreshText()
self.input_cur_x = self.input_cur_x - self.fwidth
--fill last character with blank rectangle
fb.bb:paintRect(self.input_cur_x, self.input_start_y-19,
self.fwidth, self.fheight, self.input_bg)
-- fill last character with blank rectangle
fb.bb:paintRect(self.input_cur_x, self.input_start_y-19, self.fwidth, self.fheight, self.input_bg)
fb:refresh(1, self.input_cur_x, self.input_start_y-19, self.fwidth, self.fheight)
self.input_string = self.input_string:sub(0,-2)
-- draw new cursor
self.cursor:moveHorizontal(-self.fwidth)
self.cursor:draw()
fb:refresh(1, self.input_start_x-5, self.input_start_y-25,
self.input_slot_w, self.h-25)
fb:refresh(1, self.input_start_x-5, self.input_start_y-25, self.input_slot_w, self.h-25)
end
function InputBox:clearText()
self.cursor:clear()
self.input_string = ""
self.charlist = {}
self.charpos = 1
self:refreshText()
self.cursor.x_pos = self.input_start_x - 3
self.cursor:draw()
fb:refresh(1, self.input_start_x-5, self.input_start_y-25,
self.input_slot_w, self.h-25)
end
function InputBox:drawHelpMsg(ypos, w, h)
return
fb:refresh(1, self.input_start_x-5, self.input_start_y-25, self.input_slot_w, self.h-25)
end
function InputBox:drawBox(ypos, w, h, title)
-- draw input border
fb.bb:paintRect(20, ypos, w, h, 5)
-- draw input slot
fb.bb:paintRect(140, ypos + 10, w - 130, h - 20, self.input_bg)
local r = 6 -- round corners
fb.bb:paintRect(1, ypos+r, w, h - r, self.vk_bg)
blitbuffer.paintBorder(fb.bb, 1, ypos, fb.bb:getWidth() - 2, r, r, self.vk_bg, r)
-- draw input title
renderUtf8Text(fb.bb, 35, self.input_start_y, self.face,
title, true)
self.input_start_y = ypos + 37
-- draw the box title > estimate the start point for future text & the text slot width
self.input_start_x = 25 + renderUtf8Text(fb.bb, 15, self.input_start_y, self.face, title, true)
self.input_slot_w = fb.bb:getWidth() - self.input_start_x - 5
-- draw input slot
fb.bb:paintRect(self.input_start_x - 5, ypos + 10, self.input_slot_w, h - 20, self.input_bg)
end
----------------------------------------------------------------------
-- InputBox:input()
--
-- @title: input prompt for the box
-- @d_text: default to nil (used to set default text in input slot)
-- @is_hint: if this arg is true, default text will be used as hint
-- message for input
-- @is_hint: if this arg is true, default text will be used as hint
-- message for input
----------------------------------------------------------------------
function InputBox:input(ypos, height, title, d_text, is_hint)
self:init()
-- To avoid confusion with old ypos & height parameters, I'd better define
-- my own position, at the bottom screen edge
ypos = fb.bb:getHeight() - 165
-- some corrections for calculator mode
if self.inputmode == MODE_CALC then
self:setCalcMode()
end
-- at first, draw titled box and content
local h, w = 55, fb.bb:getWidth() - 2
self:drawBox(ypos, w, h, title)
-- do some initilization
self.ypos = ypos
self.h = height
self.input_start_y = ypos + 35
self.h = 100
self.input_cur_x = self.input_start_x
self.input_slot_w = fb.bb:getWidth() - 170
self:addAllCommands()
self.cursor = Cursor:new {
x_pos = self.input_start_x - 3,
y_pos = ypos + 13,
h = 30,
}
-- draw box and content
w = fb.bb:getWidth() - 40
h = height - 45
self:drawHelpMsg(ypos, w, h)
self:drawBox(ypos, w, h, title)
if d_text then
if is_hint then
-- print hint text
fb.bb:paintRect(140, self.input_start_y-19,
self.input_slot_w, self.fheight, self.input_bg)
renderUtf8Text(fb.bb, self.input_start_x+5, self.input_start_y,
self.face,
d_text, 0)
fb.bb:dimRect(140, self.input_start_y-19,
self.input_slot_w, self.fheight, self.input_bg)
fb.bb:paintRect(self.input_start_x-5, self.input_start_y-19, self.input_slot_w, self.fheight, self.input_bg)
renderUtf8Text(fb.bb, self.input_start_x+5, self.input_start_y, self.face, d_text, 0)
fb.bb:dimRect(self.input_start_x-5, self.input_start_y-19, self.input_slot_w, self.fheight, self.input_bg)
else
self.input_string = d_text
self.input_cur_x = self.input_cur_x + (self.fwidth * d_text:len())
self.cursor.x_pos = self.cursor.x_pos + (self.fwidth * d_text:len())
-- add text to input_string
self:StringToCharlist(d_text)
self.input_cur_x = self.input_cur_x + (self.fwidth * #self.charlist)
self.cursor.x_pos = self.cursor.x_pos + (self.fwidth * #self.charlist)
self:refreshText()
end
end
self.cursor:draw()
fb:refresh(1, 20, ypos, w, h)
fb:refresh(1, 1, ypos, w, h)
local ev, keydef, command, ret_code
while true do
local ev = input.saveWaitForEvent()
ev = input.saveWaitForEvent()
ev.code = adjustKeyEvents(ev)
if ev.type == EV_KEY and ev.value ~= EVENT_VALUE_KEY_RELEASE then
keydef = Keydef:new(ev.code, getKeyModifier())
debug("key pressed: "..tostring(keydef))
Debug("key pressed: "..tostring(keydef))
command = self.commands:getByKeydef(keydef)
if command ~= nil then
debug("command to execute: "..tostring(command))
Debug("command to execute: "..tostring(command))
ret_code = command.func(self, keydef)
else
debug("command not found: "..tostring(command))
Debug("command not found: "..tostring(command))
end
if ret_code == "break" then
ret_code = nil
break
@ -204,199 +187,474 @@ function InputBox:input(ypos, height, title, d_text, is_hint)
end -- if
end -- while
local return_str = self.input_string
local output = self.input_string
self.input_string = ""
return return_str
self.charlist = {}
self.charpos = 1
return output
end
function InputBox:addAllCommands()
if self.commands then
-- we only initialize once
return
end
self.commands = Commands:new{}
INPUT_KEYS = {
{KEY_Q, "q"}, {KEY_W, "w"}, {KEY_E, "e"}, {KEY_R, "r"}, {KEY_T, "t"},
{KEY_Y, "y"}, {KEY_U, "u"}, {KEY_I, "i"}, {KEY_O, "o"}, {KEY_P, "p"},
function InputBox:setLayoutsTable()
-- trying to read the layout from the user-defined file
local ok, stored = pcall(dofile, lfs.currentdir() .. "/mykeyboard.lua")
if ok then
self.INPUT_KEYS = stored
else -- if an error happens, we use the default layout
self.INPUT_KEYS = {
{ KEY_Q, "Q", "q", "1", "!", "Я", "я", "1", "!", },
{ KEY_W, "W", "w", "2", "?", "Ж", "ж", "2", "?", },
{ KEY_E, "E", "e", "3", "|", "Е", "е", "3", "«", },
{ KEY_R, "R", "r", "4", "#", "Р", "р", "4", "»", },
{ KEY_T, "T", "t", "5", "@", "Т", "т", "5", ":", },
{ KEY_Y, "Y", "y", "6", "", "Ы", "ы", "6", ";", },
{ KEY_U, "U", "u", "7", "'", "У", "у", "7", "~", },
{ KEY_I, "I", "i", "8", "`", "И", "и", "8", "(",},
{ KEY_O, "O", "o", "9", ":", "О", "о", "9", ")",},
{ KEY_P, "P", "p", "0", ";", "П", "п", "0", "=", },
-- middle raw
{ KEY_A, "A", "a", "+", "", "А", "а", "Ш", "ш", },
{ KEY_S, "S", "s", "-", "_", "С", "с", "Ѕ", "ѕ", },
{ KEY_D, "D", "d", "*", "=", "Д", "д", "Э", "э", },
{ KEY_F, "F", "f", "/", "\\", "Ф", "ф", "Ю", "ю", },
{ KEY_G, "G", "g", "%", "", "Г", "г", "Ґ", "ґ", },
{ KEY_H, "H", "h", "^", "", "Ч", "ч", "Ј", "ј", },
{ KEY_J, "J", "j", "<", "", "Й", "й", "І", "і", },
{ KEY_K, "K", "k", "=", "\"", "К", "к", "Ќ", "ќ", },
{ KEY_L, "L", "l", ">", "~", "Л", "л", "Љ", "љ", },
-- lowest raw
{ KEY_Z, "Z", "z", "(", "$", "З", "з", "Щ", "щ", },
{ KEY_X, "X", "x", ")", "", "Х", "х", "", "@", },
{ KEY_C, "C", "c", "&", "¥", "Ц", "ц", "Џ", "џ", },
{ KEY_V, "V", "v", ":", "£", "В", "в", "Ў", "ў", },
{ KEY_B, "B", "b", "π", "", "Б", "б", "Ћ", "ћ", },
{ KEY_N, "N", "n", "е", "", "Н", "н", "Њ", "њ", },
{ KEY_M, "M", "m", "~", "", "М", "м", "Ї", "ї", },
{ KEY_DOT, ",", ".", ".", ",", ",", ".", "Є", "є", },
-- Let us make key 'Space' the same for all layouts
{ KEY_SPACE," ", " ", " ", " ", " ", " ", " ", " ", },
-- Simultaneous pressing Alt + Q..P should also work properly everywhere
{ KEY_1, "1", "1", "1", "1", "1", "1", "1", "1", },
{ KEY_2, "2", "2", "2", "2", "2", "2", "2", "2", },
{ KEY_3, "3", "3", "3", "3", "3", "3", "3", "3", },
{ KEY_4, "4", "4", "4", "4", "4", "4", "4", "4", },
{ KEY_5, "5", "5", "5", "5", "5", "5", "5", "5", },
{ KEY_6, "6", "6", "6", "6", "6", "6", "6", "6", },
{ KEY_7, "7", "7", "7", "7", "7", "7", "7", "7", },
{ KEY_8, "8", "8", "8", "8", "8", "8", "8", "8", },
{ KEY_9, "9", "9", "9", "9", "9", "9", "9", "9", },
{ KEY_0, "0", "0", "0", "0", "0", "0", "0", "0", },
-- DXG keys
{ KEY_SLASH,"/", "\\", "/", "\\", "/", "\\", "/", "\\", },
}
end -- if ok
end
{KEY_A, "a"}, {KEY_S, "s"}, {KEY_D, "d"}, {KEY_F, "f"}, {KEY_G, "g"},
{KEY_H, "h"}, {KEY_J, "j"}, {KEY_K, "k"}, {KEY_L, "l"},
function InputBox:DrawVKey(key,x,y,face,rx,ry,t,c)
blitbuffer.paintBorder(fb.bb, x-11, y-ry-8, rx, ry, t, c, ry)
renderUtf8Text(fb.bb, x, y, face, key, true)
end
{KEY_Z, "z"}, {KEY_X, "x"}, {KEY_C, "c"}, {KEY_V, "v"}, {KEY_B, "b"},
{KEY_N, "n"}, {KEY_M, "m"},
-- this function is designed for K3 keyboard, portrait mode
-- TODO: support for other Kindle models & orientations?
function InputBox:DrawVirtualKeyboard()
local vy = fb.bb:getHeight()-15
-- dx, dy = xy-distance between the button rows
-- lx - position of left button column
-- r, c, t = radius, color and thickness of circles around chars
-- h = y-correction to adjust cicles & chars
local dx, dy, lx, r, c, bg, t = 51, 36, 20, 17, 6, self.vk_bg, 2
fb.bb:paintRect(1, fb.bb:getHeight()-120, fb.bb:getWidth()-2, 120, bg)
-- font to draw characters - MUST have UTF8-support
local vkfont = Font:getFace("infont", 22)
for k,v in ipairs(self.INPUT_KEYS) do
if v[1] >= KEY_Q and v[1] <= KEY_P then -- upper raw
self:DrawVKey(v[self.layout], lx+(v[1]-KEY_Q)*dx, vy-2*dy, vkfont, r, r, t, c)
elseif v[1] >= KEY_A and v[1] <= KEY_L then -- middle raw
self:DrawVKey(v[self.layout], lx+(v[1]-KEY_A)*dx, vy-dy, vkfont, r, r, t, c)
elseif v[1] >= KEY_Z and v[1] <= KEY_M then -- lower raw
self:DrawVKey(v[self.layout], lx+(v[1]-KEY_Z)*dx, vy, vkfont, r, r, t, c)
elseif v[1] == KEY_DOT then
self:DrawVKey(v[self.layout], lx + 7*dx, vy, vkfont, r, r, t, c)
end
end
-- the rest symbols (manually)
local smfont = Font:getFace("infont", 14)
-- Del
blitbuffer.paintBorder(fb.bb, lx+9*dx-10, vy-dy-r-8, r, r, t, c, r)
renderUtf8Text(fb.bb, lx-5+9*dx, vy-dy-3, smfont, "Del", true)
-- Sym
blitbuffer.paintBorder(fb.bb, lx+8*dx-10, vy-r-8, r, r, t + (r-t)*self:num(self.symbolmode), c, r)
renderUtf8Text(fb.bb, lx-5+8*dx, vy-3, smfont, "Sym", true)
-- Enter
blitbuffer.paintBorder(fb.bb, lx+9*dx-10, vy-r-8, r, r, t, c, r)
renderUtf8Text(fb.bb, lx+9*dx, vy-2, vkfont, "«", true)
-- Menu
blitbuffer.paintBorder(fb.bb, lx+10*dx-8, vy-2*dy-r-8, r+50, r, t+(r-t)*self:num(self.utf8mode), c, r)
renderUtf8Text(fb.bb, lx+10*dx+11, vy-2*dy-3, smfont, "Menu", true)
-- fiveway
local h=dy+2*r-2
blitbuffer.paintBorder(fb.bb, lx+10*dx-8, vy-dy-r-6, h, h, 9, c, r)
renderUtf8Text(fb.bb, lx+10*dx+22, vy-20, smfont, (self.layout-1), true)
fb:refresh(1, 1, fb.bb:getHeight()-120, fb.bb:getWidth()-2, 120)
end
{KEY_1, "1"}, {KEY_2, "2"}, {KEY_3, "3"}, {KEY_4, "4"}, {KEY_5, "5"},
{KEY_6, "6"}, {KEY_7, "7"}, {KEY_8, "8"}, {KEY_9, "9"}, {KEY_0, "0"},
function InputBox:num(bool)
return bool and 1 or 0
end
{KEY_SPACE, " "},
function InputBox:VKLayout(b1, b2, b3)
return 2 + self:num(b1) + 2 * self:num(b2) + 4 * self:num(b3)
end
-- DXG keys
{KEY_DOT, "."}, {KEY_SLASH, "/"},
}
for k,v in ipairs(INPUT_KEYS) do
self.commands:add(v[1], nil, "",
"input "..v[2],
function InputBox:addCharCommands(layout)
-- at first, let's define self.layout and extract separate bits as layout modes
if layout then
-- to be sure layout is selected properly
layout = math.max(layout, self.min_layout)
layout = math.min(layout, self.max_layout)
self.layout = layout
-- fill the layout modes
layout = (layout - 2) % 4
self.shiftmode = (layout == 1 or layout == 3)
self.symbolmode = (layout == 2 or layout == 4)
self.utf8mode = (self.layout > 5)
else -- or, without input parameter, restore layout from current layout modes
self.layout = self:VKLayout(self.shiftmode, self.symbolmode, self.utf8mode)
end
-- let's define layout called by Shift+Key (to type capitalized chars being in low-case layout)
local shift_layout = self:VKLayout(not self.shiftmode, self.symbolmode, self.utf8mode)
-- adding the commands
for k,v in ipairs(self.INPUT_KEYS) do
-- just redefining existing
self.commands:add(v[1], nil, "A..Z", "enter character from virtual keyboard (VK)",
function(self)
self:addChar(v[self.layout])
end
)
-- and commands for chars pressed with Shift
self.commands:add(v[1], MOD_SHIFT, "A..Z", "enter capitalized VK-character",
function(self)
self:addChar(v[2])
self:addChar(v[shift_layout])
end
)
end
self:DrawVirtualKeyboard()
end
self.commands:add(KEY_FW_LEFT, nil, "",
function InputBox:StringToCharlist(text)
if text == nill then return end
-- clear
self.charlist = {}
self.charpos = 1
local prevcharcode, charcode = 0
for uchar in string.gfind(text, "([%z\1-\127\194-\244][\128-\191]*)") do
charcode = util.utf8charcode(uchar)
if prevcharcode then -- utf8
self.charlist[#self.charlist+1] = uchar
end
prevcharcode = charcode
end
self.input_string = self:CharlistToString()
self.charpos = #self.charlist+1
end
function InputBox:CharlistToString()
local s, i = ""
for i=1, #self.charlist do
s = s .. self.charlist[i]
end
return s
end
function InputBox:addAllCommands()
-- if already initialized, we (re)define only inputmode-dependent commands
if self.commands then
self:ModeDependentCommands()
self:DrawVirtualKeyboard()
return
end
self:setLayoutsTable()
self.commands = Commands:new{}
-- adding character commands
self:addCharCommands(self.layout)
-- adding the rest commands (independent of the selected layout)
self.commands:add(KEY_H, MOD_ALT, "H",
"show help page",
function(self)
self:showHelpPage(self.commands)
end
)
self.commands:add(KEY_FW_LEFT, nil, "joypad left",
"move cursor left",
function(self)
if (self.cursor.x_pos + 3) > self.input_start_x then
self.cursor:moveHorizontalAndDraw(-self.fwidth)
fb:refresh(1, self.input_start_x-5, self.ypos,
self.input_slot_w, self.h)
self.charpos = self.charpos - 1
fb:refresh(1, self.input_start_x-5, self.ypos, self.input_slot_w, self.h)
end
end
)
self.commands:add(KEY_FW_LEFT, MOD_SHIFT, "left",
"move cursor to the first position",
function(self)
if (self.cursor.x_pos + 3) > self.input_start_x then
self.cursor:moveHorizontalAndDraw(-self.fwidth*(self.charpos-1))
self.charpos = 1
fb:refresh(1, self.input_start_x-5, self.ypos, self.input_slot_w, self.h)
end
end
)
self.commands:add(KEY_FW_RIGHT, nil, "",
self.commands:add(KEY_FW_RIGHT, nil, "joypad right",
"move cursor right",
function(self)
if (self.cursor.x_pos + 3) < self.input_cur_x then
self.cursor:moveHorizontalAndDraw(self.fwidth)
fb:refresh(1, self.input_start_x-5, self.ypos,
self.input_slot_w, self.h)
self.charpos = self.charpos + 1
fb:refresh(1, self.input_start_x-5, self.ypos, self.input_slot_w, self.h)
end
end
)
self.commands:add({KEY_ENTER, KEY_FW_PRESS}, nil, "",
"submit input content",
self.commands:add(KEY_FW_RIGHT, MOD_SHIFT, "right",
"move cursor to the last position",
function(self)
if self.input_string == "" then
self.input_string = nil
if (self.cursor.x_pos + 3) < self.input_cur_x then
self.cursor:moveHorizontalAndDraw(self.fwidth*(#self.charlist+1-self.charpos))
self.charpos = #self.charlist + 1
fb:refresh(1, self.input_start_x-5, self.ypos, self.input_slot_w, self.h)
end
return "break"
end
)
self.commands:add(KEY_DEL, nil, "",
self.commands:add(KEY_DEL, nil, "Del",
"delete one character",
function(self)
self:delChar()
end
)
self.commands:add(KEY_DEL, MOD_SHIFT, "",
"empty inputbox",
self.commands:add(KEY_DEL, MOD_SHIFT, "Del",
"delete all characters (empty inputbox)",
function(self)
self:clearText()
end
)
self.commands:add({KEY_BACK, KEY_HOME}, nil, "",
"cancel inputbox",
function(self)
self.input_string = nil
return "break"
end
)
end
----------------------------------------------------
-- Inputbox for numbers only
-- Designed by eLiNK
----------------------------------------------------
NumInputBox = InputBox:new{
initialized = false,
commands = Commands:new{},
}
function NumInputBox:addAllCommands()
self.commands = Commands:new{}
INPUT_NUM_KEYS = {
{KEY_Q, "1"}, {KEY_W, "2"}, {KEY_E, "3"}, {KEY_R, "4"}, {KEY_T, "5"},
{KEY_Y, "6"}, {KEY_U, "7"}, {KEY_I, "8"}, {KEY_O, "9"}, {KEY_P, "0"},
{KEY_1, "1"}, {KEY_2, "2"}, {KEY_3, "3"}, {KEY_4, "4"}, {KEY_5, "5"},
{KEY_6, "6"}, {KEY_7, "7"}, {KEY_8, "8"}, {KEY_9, "9"}, {KEY_0, "0"},
}
for k,v in ipairs(INPUT_NUM_KEYS) do
self.commands:add(v[1], nil, "",
"input "..v[2],
function(self)
self:addChar(v[2])
end
)
end -- for
self.commands:add(KEY_FW_LEFT, nil, "",
"move cursor left",
self.commands:addGroup("up/down", { Keydef:new(KEY_FW_DOWN, nil), Keydef:new(KEY_FW_UP, nil) },
"previous/next VK-layout",
function(self)
if (self.cursor.x_pos + 3) > self.input_start_x then
self.cursor:moveHorizontalAndDraw(-self.fwidth)
fb:refresh(1, self.input_start_x-5, self.ypos,
self.input_slot_w, self.h)
if keydef.keycode == KEY_FW_DOWN then
if self.layout == self.max_layout then self:addCharCommands(self.min_layout)
else self:addCharCommands(self.layout+1) end
else -- KEY_FW_UP
if self.layout == self.min_layout then self:addCharCommands(self.max_layout)
else self:addCharCommands(self.layout-1) end
end
end
)
self.commands:add(KEY_FW_RIGHT, nil, "",
"move cursor right",
self.commands:add(KEY_AA, nil, "Aa",
"toggle VK-layout: chars <> CHARS",
function(self)
if (self.cursor.x_pos + 3) < self.input_cur_x then
self.cursor:moveHorizontalAndDraw(self.fwidth)
fb:refresh(1, self.input_start_x-5, self.ypos,
self.input_slot_w, self.h)
end
self.shiftmode = not self.shiftmode
self:addCharCommands()
end
)
self.commands:add({KEY_ENTER, KEY_FW_PRESS}, nil, "",
"submit input content",
self.commands:add(KEY_SYM, nil, "Sym",
"toggle VK-layout: chars <> symbols",
function(self)
if self.input_string == "" then
self.input_string = nil
end
return "break"
self.symbolmode = not self.symbolmode
self:addCharCommands()
end
)
self.commands:add(KEY_DEL, nil, "",
"delete one character",
self.commands:add(KEY_MENU, nil, "Menu",
"toggle VK-layout: english <> national",
function(self)
self:delChar()
self.utf8mode = not self.utf8mode
self:addCharCommands()
end
)
self.commands:add(KEY_DEL, MOD_SHIFT, "",
"empty inputbox",
function(self)
self:clearText()
end
)
self.commands:add({KEY_BACK, KEY_HOME}, nil, "",
"cancel inputbox",
-- NuPogodi, 02.06.12: inputmode-dependent commands are collected
self:ModeDependentCommands() -- here
self.commands:add(KEY_BACK, nil, "Back",
"back",
function(self)
self.input_string = nil
return "break"
end
)
end
-----------------------------------------------------------------
-- NuPogodi, 02.06.12: Some Help- & Calculator-related functions
-----------------------------------------------------------------
function InputBox:defineCalcFunctions() -- for the calculator documentation
-- to initialize only once
if self.calcfunctions then return end
self.calcfunctions = Commands:new{}
-- remove initially added commands
self.calcfunctions:del(KEY_INTO_SCREEN_SAVER, nil, "Slider")
self.calcfunctions:del(KEY_OUTOF_SCREEN_SAVER, nil, "Slider")
self.calcfunctions:del(KEY_CHARGING, nil, "plugin/out usb")
self.calcfunctions:del(KEY_NOT_CHARGING, nil, "plugin/out usb")
self.calcfunctions:del(KEY_P, MOD_SHIFT, "P")
local s = " " -- space for function groups
local a = 100 -- arithmetic functions
self.calcfunctions:add(a-1, nil, s:rep(1), string.upper("Ariphmetic operators"))
self.calcfunctions:add(a, nil, "+ -", "addition: 1+2=3; substraction: 3-2=1")
self.calcfunctions:add(a+1, nil, "* /", "multiplication: 2*2=4; division: 4/2=2")
self.calcfunctions:add(a+3, nil, "%", "modulo (remainder): 5.2%2=1.2, π-π%0.01=3.14")
local r = 200 -- relations
self.calcfunctions:add(r-1, nil, s:rep(2), string.upper("Relational operators"))
self.calcfunctions:add(r, nil, "< >", "less: (2<3)=true; more: (2>3)=false")
self.calcfunctions:add(r+1, nil, "<=", "less or equal: (3≤3)=true, (2≤1)=false")
self.calcfunctions:add(r+2, nil, ">=", "more or equal: (3≥3)=true, (1≥2)=false")
self.calcfunctions:add(r+3, nil, "==", "equal: (3==3)=true, (1==2)=false")
self.calcfunctions:add(r+4, nil, "~=", "not equal: (6~=8)=true, (3~=3)=false")
local l = 300 -- logical
self.calcfunctions:add(l-1, nil, s:rep(3), string.upper("Logical operators"))
self.calcfunctions:add(l+0, nil, "and, &", "= logical 'and': (4 and 5)=5, (nil & 5)=nil")
self.calcfunctions:add(l+1, nil, "or, |", "= logical 'or': (4 or 5)=4, (false | 5)=5")
local c = 400 -- constants
self.calcfunctions:add(c-1, nil, s:rep(4), string.upper("Some constants"))
self.calcfunctions:add(c, nil, "pi, π", "= 3.14159…; sin(π/2)=1, cos(π/2)=0")
self.calcfunctions:add(c+1, nil, "е, exp(1)", "= 2.71828…; log(е)=1")
local m = 500 -- mathematical
self.calcfunctions:add(m-1, nil, s:rep(5), string.upper("Mathematic functions"))
self.calcfunctions:add(m, nil, "abs(x)", "absolute value of x: abs(1)=1, abs(-2)=2")
self.calcfunctions:add(m+1, nil, "ceil(x)", "round to integer no less than x: ceil(0.4)=1")
self.calcfunctions:add(m+2, nil, "floor(x)", "round to integer no greater than x: floor(0.4)=0")
self.calcfunctions:add(m+3, nil, "^, pow(x,y)","= power: 2^10=1024, pow(4,0.5)=2")
self.calcfunctions:add(m+4, nil, "exp(x), e^x","= exponent: exp(1)=2.71828…")
self.calcfunctions:add(m+5, nil, "log(x)", "the natural logarithm: log(e)=1")
self.calcfunctions:add(m+6, nil, "log10(x)", "the base 10 logarithm: log10(10)=1")
self.calcfunctions:add(m+7, nil, "max(x,…)", "return maximal value: max(0,-1,2,1)=2")
self.calcfunctions:add(m+8, nil, "min(x,…)", "return minimal value: min(0,-1,2,1)=-1")
self.calcfunctions:add(m+9, nil, "sqrt(x)", "return square root: sqrt(4)=2")
local t = 600 -- trigonometrical
self.calcfunctions:add(t, nil, s:rep(6), string.upper("Trigonometric functions"))
self.calcfunctions:add(t+1, nil, "deg(x)", "convert radians to degrees: deg(π/2)=90")
self.calcfunctions:add(t+2, nil, "rad(x)", "convert degrees to radians: rad(180)=3.14159…")
self.calcfunctions:add(t+3, nil, "sin(x)", "sine for x given in radians: sin(π/2)=1")
self.calcfunctions:add(t+4, nil, "cos(x)", "cosine for x given in radians: cos(π)=-1")
self.calcfunctions:add(t+5, nil, "tan(x)", "tangent for x given in radians: tan(π/4)=1")
self.calcfunctions:add(t+6, nil, "asin(x)", "inverse sine (in radians): asin(1)/π=0.5")
self.calcfunctions:add(t+7, nil, "acos(x)", "inverse cosine (in radians): acos(0)/π=0.5")
self.calcfunctions:add(t+8, nil, "atan(x)", "inverse tangent (in radians): atan(1)/π=0.25")
self.calcfunctions:add(t+9, nil, "atan2(x,y)", "inverse tangent of two args: = atan(x/y)")
local h = 700 -- hyperbolical
self.calcfunctions:add(h, nil, s:rep(7), string.upper("Hyperbolic functions"))
self.calcfunctions:add(h+1, nil, "sinh(x)", "hyperbolic sine, (exp(x)-exp(-x))/2")
self.calcfunctions:add(h+2, nil, "cosh(x)", "hyperbolic cosine, (exp(x)+exp(-x))/2")
self.calcfunctions:add(h+3, nil, "tanh(x)", "hyperbolic tangent, sinh(x)/cosh(x)")
-- not yet documented > "fmod", "frexp", "huge", "ldexp", "modf", "randomseed", "random"
end
function NumInputBox:drawHelpMsg(ypos, w, h)
local w = 415
local y = ypos - 60
local x = (G_width - w) / 2
local h = 50
local bw = 2
local face = Font:getFace("scfont", 22)
fb.bb:paintRect(x, y, w, h, 15)
fb.bb:paintRect(x+bw, y+bw, w-2*bw, h-2*bw, 0)
local font_y = y + 22
local font_x = x + 22
INPUT_NUM_KEYS = {
{"Q", "1"}, {"W", "2"}, {"E", "3"}, {"R", "4"}, {"T", "5"},
{"Y", "6"}, {"U", "7"}, {"I", "8"}, {"O", "9"}, {"P", "0"},
}
for k,v in ipairs(INPUT_NUM_KEYS) do
renderUtf8Text(fb.bb, font_x, font_y, face,
v[1], true)
renderUtf8Text(fb.bb, font_x, font_y + 22, face,
v[2], true)
font_x = font_x + 40
function InputBox:showHelpPage(list, title)
-- make inactive input slot
self.cursor:clear() -- hide cursor
fb.bb:dimRect(self.input_start_x-5, self.input_start_y-19, self.input_slot_w, self.fheight, self.input_bg)
fb:refresh(1, self.input_start_x-5, self.ypos, self.input_slot_w, self.h)
HelpPage:show(0, fb.bb:getHeight()-165, list, title)
-- on the help page-exit, making inactive helpage
fb.bb:dimRect(0, 40, fb.bb:getWidth(), fb.bb:getHeight()-205, self.input_bg)
-- and active input slot
self:refreshText()
self.cursor:draw() -- show cursor = ready to input
fb:refresh(1)
end
function InputBox:setCalcMode()
--clear previous input
self.input_string = ""
self.charlist = {}
self.charpos = 1
-- set proper layouts
self.layout = 4 -- digits
self.min_layout = 3
self.max_layout = 4
end
function InputBox:PrepareStringToCalc()
local s = string.lower(self.input_string)
-- continue interpreting the input
local mathe = { "abs", "acos", "asin", "atan2", "atan", "ceil", "cosh", "cos",
"deg", "exp", "floor", "fmod", "frexp", "huge", "ldexp", "log10", "log",
"max", "min", "modf", "pi", "pow", "rad", "randomseed", "random",
"sinh", "sin", "sqrt", "tanh", "tan", }
-- to avoid any ambiguities (like sin & sinh), one has to replace by capitals
for i=1, #mathe do
s = string.gsub(s, mathe[i], string.upper("math."..mathe[i]))
end
-- some acronyms for constants & functions
s = string.gsub(s, "π", " math.pi ")
s = string.gsub(s, "е", " math.exp(1) ")
s = string.gsub(s, "&", " and ")
s = string.gsub(s, "|", " or ")
-- return the whole string in lowercase and eventually replace double "math."
return string.gsub(string.lower(s), "math.math.", "math.")
end
fb:refresh(1, x, y, w, h)
-- define whether we need to calculate the result or to return 'self.input_string'
function InputBox:ModeDependentCommands()
if self.inputmode == MODE_CALC then
-- define what to do with the input_string
self.commands:add({KEY_FW_PRESS, KEY_ENTER}, nil, "Enter",
"calculate the result",
function(self)
if #self.input_string == 0 then
InfoMessage:inform("No user input ", DINFO_DELAY, 1, MSG_WARN)
else
local s = self:PrepareStringToCalc()
if pcall(function () f = assert(loadstring("r = tostring("..s..")")) end) and pcall(f) then
self:clearText()
self.cursor:clear()
for i=1, string.len(r) do
table.insert(self.charlist, string.sub(r,i,i))
end
self.charpos = #self.charlist + 1
self.input_cur_x = self.input_start_x + #self.charlist * self.fwidth
self.input_string = r
self:refreshText()
self.cursor:moveHorizontal(#self.charlist*self.fwidth)
self.cursor:draw()
fb:refresh(1, self.input_start_x-5, self.input_start_y-25, self.input_slot_w, self.h-25)
else
InfoMessage:inform("Invalid user input ", DINFO_DELAY, 1, MSG_WARN)
end -- if pcall
end
end -- function
)
-- add the calculator help (short list of available functions)
-- or, might be better, to make some help document and open it in reader ??
self.commands:add(KEY_M, MOD_ALT, "M",
"math functions available in calculator",
function(self)
self:defineCalcFunctions()
self:showHelpPage(self.calcfunctions, "Math Functions for Calculator")
end
)
else -- return input_string & close input box
self.commands:add({KEY_FW_PRESS, KEY_ENTER}, nil, "Enter",
"submit input content",
function(self)
if self.input_string == "" then
self.input_string = nil
end
return "break"
end
)
-- delete calculator-specific help
self.commands:del(KEY_M, MOD_ALT, "M")
end -- if self.inputmode
end
----------------------------------------------------
-- Inputbox for numbers only
-- Designed by eLiNK
----------------------------------------------------
NumInputBox = InputBox:new{
layout = 4,
charlist = {},
}

@ -87,8 +87,15 @@ KEY_FW_UP = 122
KEY_FW_DOWN = 123
KEY_FW_PRESS = 92
-- this is for the K2 - it won't hurt on the KDX
KEY_LPGFWD = 104
KEY_INTO_SCREEN_SAVER = 10000
KEY_OUTOF_SCREEN_SAVER = 10001
KEY_USB_PLUG_IN = 10010
KEY_USB_PLUG_OUT = 10011
KEY_CHARGING = 10020
KEY_NOT_CHARGING = 10021
-- constants from <linux/input.h>
EV_KEY = 1
@ -254,7 +261,7 @@ function adjustKeyEvents(ev)
end
end
-- This should not happen.
debug("# Unrecognizable rotation mode "..Screen.cur_rotation_mode.."!")
Debug("# Unrecognizable rotation mode "..Screen.cur_rotation_mode.."!")
return nil
end
@ -264,7 +271,7 @@ function input.saveWaitForEvent(timeout)
while retry do
local ok, ev = pcall(input.waitForEvent, timeout)
if not ok then
debug("got error waiting for events:", ev)
Debug("got error waiting for events:", ev)
if ev == "Waiting for input failed: 4\n" then
-- EINTR, we got interrupted. Try and restart
retry = true

@ -0,0 +1,3 @@
#!/bin/sh
/mnt/us/kindlepdfviewer/kpdf.sh

@ -0,0 +1,3 @@
#!/bin/sh
/mnt/us/kindlepdfviewer/kpdf.sh /mnt/us/documents

@ -0,0 +1,470 @@
require "font"
require "keys"
require "settings"
require "defaults"
KOPTOptions = {
{
name="font_size",
option_text="",
items_text={"Aa","Aa","Aa","Aa","Aa","Aa","Aa","Aa","Aa","Aa"},
text_font_size={14,16,20,23,26,30,34,38,42,46},
current_item=nil,
text_dirty=true,
marker_dirty={true, true, true, true, true, true, true, true, true, true},
values={0.2, 0.3, 0.4, 0.6, 0.8, 1.0, 1.2, 1.6, 2.2, 2.8},
default_value=DKOPTREADER_CONFIG_FONT_SIZE,
show = true,
draw_index = nil,},
{
name="text_wrap",
option_text="Reflow",
items_text={"on","off"},
current_item=nil,
text_dirty=true,
marker_dirty={true, true},
values={1, 0},
default_value=DKOPTREADER_CONFIG_TEXT_WRAP,
show = true,
draw_index = nil,},
{
name="trim_page",
option_text="Trim Page",
items_text={"auto","manual"},
current_item=nil,
text_dirty=true,
marker_dirty={true, true},
values={1, 0},
default_value=DKOPTREADER_CONFIG_TRIM_PAGE,
show = true,
draw_index = nil,},
{
name="detect_indent",
option_text="Indentation",
items_text={"enable","disable"},
current_item=nil,
text_dirty=true,
marker_dirty={true, true},
values={1, 0},
default_value=DKOPTREADER_CONFIG_DETECT_INDENT,
show = false,
draw_index = nil,},
{
name="defect_size",
option_text="Defect Size",
items_text={"small","medium","large"},
current_item=nil,
text_dirty=true,
marker_dirty={true, true, true},
values={0.5, 1.0, 2.0},
default_value=DKOPTREADER_CONFIG_DEFECT_SIZE,
show = true,
draw_index = nil,},
{
name="page_margin",
option_text="Page Margin",
items_text={"small","medium","large"},
current_item=nil,
text_dirty=true,
marker_dirty={true, true, true},
values={0.02, 0.06, 0.10},
default_value=DKOPTREADER_CONFIG_PAGE_MARGIN,
show = true,
draw_index = nil,},
{
name="line_spacing",
option_text="Line Spacing",
items_text={"small","medium","large"},
current_item=nil,
text_dirty=true,
marker_dirty={true, true, true},
values={1.0, 1.2, 1.4},
default_value=DKOPTREADER_CONFIG_LINE_SPACING,
show = true,
draw_index = nil,},
{
name="word_spacing",
option_text="Word Spacing",
items_text={"small","medium","large"},
current_item=nil,
text_dirty=true,
marker_dirty={true, true, true},
values={0.05, 0.15, 0.375},
default_value=DKOPTREADER_CONFIG_WORD_SAPCING,
show = true,
draw_index = nil,},
{
name="multi_threads",
option_text="Multi Threads",
items_text={"on","off"},
current_item=nil,
text_dirty=true,
marker_dirty={true, true},
values={1, 0},
default_value=DKOPTREADER_CONFIG_MULTI_THREADS,
show = true,
draw_index = nil,},
{
name="quality",
option_text="Render Quality",
items_text={"low","medium","high"},
current_item=nil,
text_dirty=true,
marker_dirty={true, true, true},
values={0.5, 0.8, 1.0},
default_value=DKOPTREADER_CONFIG_RENDER_QUALITY,
show = true,
draw_index = nil,},
{
name="auto_straighten",
option_text="Auto Straighten",
items_text={"0","5","10"},
current_item=nil,
text_dirty=true,
marker_dirty={true, true, true},
values={0, 5, 10},
default_value=DKOPTREADER_CONFIG_AUTO_STRAIGHTEN,
show = true,
draw_index = nil,},
{
name="justification",
option_text="Justification",
items_text={"auto","left","center","right","full"},
current_item=nil,
text_dirty=true,
marker_dirty={true, true, true, true, true},
values={-1,0,1,2,3},
default_value=DKOPTREADER_CONFIG_JUSTIFICATION,
show = true,
draw_index = nil,},
{
name="max_columns",
option_text="Columns",
items_text={"1","2","3","4"},
current_item=nil,
text_dirty=true,
marker_dirty={true, true, true, true},
values={1,2,3,4},
default_value=DKOPTREADER_CONFIG_MAX_COLUMNS,
show = true,
draw_index = nil,},
{
name="contrast",
option_text="Contrast",
items_text={"lightest","lighter","default","darker","darkest"},
current_item=nil,
text_dirty=true,
marker_dirty={true, true, true, true, true},
values={2.0, 1.5, 1.0, 0.5, 0.2},
default_value=DKOPTREADER_CONFIG_CONTRAST,
show = true,
draw_index = nil,},
{
name="screen_rotation",
option_text="Screen Rotation",
items_text={"0","90","180","270"},
current_item=nil,
text_dirty=true,
marker_dirty={true, true, true, true},
values={0, 90, 180, 270},
default_value=DKOPTREADER_CONFIG_SCREEN_ROTATION,
show = true,
draw_index = nil,},
}
KOPTConfig = {
-- UI constants
WIDTH = 550, -- width
HEIGHT = nil, -- height, updated in run time
MARGIN_BOTTOM = 25, -- window bottom margin
OPTION_PADDING_T = 60, -- option top padding
OPTION_PADDING_H = 70, -- option horizontal padding
OPTION_SPACING_V = 30, -- options vertical spacing
NAME_ALIGN_RIGHT = 0.28, -- align name right to the window width
ITEM_ALIGN_LEFT = 0.30, -- align item left to the window width
ITEM_SPACING_H = 10, -- items horisontal spacing
OPT_NAME_FONT_SIZE = 20, -- option name font size
OPT_ITEM_FONT_SIZE = 16, -- option item font size
-- last pos text is drawn
text_pos = 0,
-- current selected option
current_option = 1,
-- config change
config_change = false,
confirm_change = false,
-- reader object
koptreader = nil
}
function KOPTConfig:drawBox(xpos, ypos, width, hight, bgcolor, bdcolor)
-- draw dialog border
local r = 6 -- round corners
fb.bb:paintRect(xpos, ypos+r, width, hight - 2*r, bgcolor)
blitbuffer.paintBorder(fb.bb, xpos, ypos, width, r, r, bgcolor, r)
blitbuffer.paintBorder(fb.bb, xpos, ypos+hight-2*r, width, r, r, bgcolor, r)
end
function KOPTConfig:drawOptionName(xpos, ypos, option_index, text, font_face, redraw)
local width = self.WIDTH
local xpos, ypos = xpos+self.OPTION_PADDING_H+self.NAME_ALIGN_RIGHT*(width-2*self.OPTION_PADDING_H), ypos+self.OPTION_PADDING_T
if KOPTOptions[option_index].text_dirty or redraw then
--Debug("drawing option name:", KOPTOptions[option_index].option_text)
local text_len = sizeUtf8Text(0, G_width, font_face, text, true).x
local draw_index = KOPTOptions[option_index].draw_index
renderUtf8Text(fb.bb, xpos-text_len, ypos+self.OPTION_SPACING_V*(draw_index-1), font_face, text, true)
end
end
function KOPTConfig:drawOptionItem(xpos, ypos, option_index, item_index, text, font_face, redraw, refresh)
self.text_pos = (item_index == 1) and 0 or self.text_pos
local width = self.WIDTH
local offset = self.OPTION_PADDING_H+self.ITEM_ALIGN_LEFT*(width-2*self.OPTION_PADDING_H)
local item_x_offset = (KOPTOptions[option_index].option_text == "") and self.OPTION_PADDING_H or offset
local draw_index = KOPTOptions[option_index].draw_index
local xpos = xpos+item_x_offset+self.ITEM_SPACING_H*(item_index-1)+self.text_pos
local ypos = ypos+self.OPTION_PADDING_T+self.OPTION_SPACING_V*(draw_index-1)
if KOPTOptions[option_index].text_font_size then
font_face = Font:getFace("cfont", KOPTOptions[option_index].text_font_size[item_index])
end
if KOPTOptions[option_index].text_dirty or redraw then
--Debug("drawing option:", KOPTOptions[option_index].option_text, "item:", text)
renderUtf8Text(fb.bb, xpos, ypos, font_face, text, true)
end
local text_len = sizeUtf8Text(0, G_width, font_face, text, true).x
self.text_pos = self.text_pos + text_len
if KOPTOptions[option_index].marker_dirty[item_index] or redraw then
--Debug("drawing option:", KOPTOptions[option_index].option_text, "marker:", text)
if item_index == KOPTOptions[option_index].current_item then
fb.bb:paintRect(xpos, ypos+5, text_len, 3,(option_index == self.current_option) and 15 or 6)
if refresh then
fb:refresh(1, xpos, ypos+5, text_len, 3)
end
else
fb.bb:paintRect(xpos, ypos+5, text_len, 3, 3)
if refresh then
fb:refresh(1, xpos, ypos+5, text_len, 3)
end
end
KOPTOptions[option_index].marker_dirty[item_index] = false
end
end
function KOPTConfig:drawOptions(xpos, ypos, name_font, item_font, redraw, refresh)
local width, height = self.WIDTH, self.HEIGHT
for i=1,#KOPTOptions do
if KOPTOptions[i].show then
self:drawOptionName(xpos, ypos, i, KOPTOptions[i].option_text, name_font, redraw)
for j=1,#KOPTOptions[i].items_text do
self:drawOptionItem(xpos, ypos, i, j, KOPTOptions[i].items_text[j], item_font, redraw, refresh)
end
KOPTOptions[i].text_dirty = false
end
end
end
function KOPTConfig:makeDefault(configurable)
local draw_index = 1
self.HEIGHT = self.OPTION_PADDING_T
self.current_option = 1
for i=1,#KOPTOptions do
-- update draw index of each option in run time
if KOPTOptions[i].show then
KOPTOptions[i].draw_index = draw_index
draw_index = draw_index + 1
end
-- update window height
if KOPTOptions[i].show then
self.HEIGHT = self.HEIGHT + self.OPTION_SPACING_V
end
-- make each option and marker dirty
KOPTOptions[i].text_dirty = true
for j=1,#KOPTOptions[i].items_text do
KOPTOptions[i].marker_dirty[j] = true
end
-- make current index according to configurable table
local option = KOPTOptions[i].name
local val = configurable[option]
local min_diff = math.abs(val - KOPTOptions[i].values[1])
KOPTOptions[i].current_item = 1
for index, val_ in pairs(KOPTOptions[i].values) do
if val == val_ then
KOPTOptions[i].current_item = index
break
else
diff = math.abs(val - val_)
if diff <= min_diff then
min_diff = diff
KOPTOptions[i].current_item = index
end
end
end -- for index
end -- for i
end
function KOPTConfig:reconfigure(configurable)
for i=1,#KOPTOptions do
option = KOPTOptions[i].name
configurable[option] = KOPTOptions[i].values[KOPTOptions[i].current_item]
end
end
function KOPTConfig:config(reader)
self.koptreader = reader
self:makeDefault(self.koptreader.configurable)
self:addAllCommands()
local name_font = Font:getFace("tfont", self.OPT_NAME_FONT_SIZE)
local item_font = Font:getFace("cfont", self.OPT_ITEM_FONT_SIZE)
-- base window coordinates
local width, height = self.WIDTH, self.HEIGHT
local topleft_x, topleft_y = (fb.bb:getWidth()-width)/2, fb.bb:getHeight()-self.MARGIN_BOTTOM-height
local botleft_x, botleft_y = topleft_x, topleft_y+height
self:drawBox(topleft_x, topleft_y, width, height, 3, 15)
self:drawOptions(topleft_x, topleft_y, name_font, item_font, true, false)
fb:refresh(1, topleft_x, topleft_y, width, height)
local ev, keydef, command, ret_code
while true do
self:reconfigure(self.koptreader.configurable)
if self.config_change and self.confirm_change then
self.koptreader:redrawWithoutPrecache()
self:drawBox(topleft_x, topleft_y, width, height, 3, 15)
self:drawOptions(topleft_x, topleft_y, name_font, item_font, true, false)
fb:refresh(1, topleft_x, topleft_y, width, height)
self.config_change = false
self.confirm_change = false
end
self:drawOptions(topleft_x, topleft_y, name_font, item_font, false, true)
ev = input.saveWaitForEvent()
ev.code = adjustKeyEvents(ev)
if ev.type == EV_KEY and ev.value ~= EVENT_VALUE_KEY_RELEASE then
keydef = Keydef:new(ev.code, getKeyModifier())
Debug("key pressed: "..tostring(keydef))
command = self.commands:getByKeydef(keydef)
if command ~= nil then
Debug("command to execute: "..tostring(command))
ret_code = command.func(self, keydef)
else
Debug("command not found: "..tostring(command))
end
if ret_code == "break" then
ret_code = nil
return nil
end
end -- if
end -- while
end
-- add available commands
function KOPTConfig:addAllCommands()
self.commands = Commands:new{}
self.commands:add(KEY_FW_DOWN, nil, "joypad down",
"next item",
function(self)
local last_option = self.current_option
repeat
self.current_option = (self.current_option + #KOPTOptions + 1)%#KOPTOptions
self.current_option = (self.current_option == 0) and #KOPTOptions or self.current_option
until KOPTOptions[self.current_option].show
last_option_item = KOPTOptions[last_option].current_item
KOPTOptions[last_option].marker_dirty[last_option_item] = true
current_option_item = KOPTOptions[self.current_option].current_item
KOPTOptions[self.current_option].marker_dirty[current_option_item] = true
end
)
self.commands:add(KEY_FW_UP, nil, "joypad up",
"previous item",
function(self)
local last_option = self.current_option
repeat
self.current_option = (self.current_option + #KOPTOptions - 1)%#KOPTOptions
self.current_option = (self.current_option == 0) and #KOPTOptions or self.current_option
until KOPTOptions[self.current_option].show
last_option_item = KOPTOptions[last_option].current_item
KOPTOptions[last_option].marker_dirty[last_option_item] = true
current_option_item = KOPTOptions[self.current_option].current_item
KOPTOptions[self.current_option].marker_dirty[current_option_item] = true
end
)
self.commands:add(KEY_FW_LEFT, nil, "joypad left",
"last item",
function(self)
local last_item = KOPTOptions[self.current_option].current_item
local item_count = #KOPTOptions[self.current_option].items_text
local current_item = (KOPTOptions[self.current_option].current_item + item_count - 1)%item_count
current_item = (current_item == 0) and item_count or current_item
KOPTOptions[self.current_option].current_item = current_item
KOPTOptions[self.current_option].marker_dirty[last_item] = true
KOPTOptions[self.current_option].marker_dirty[current_item] = true
self.config_change = true
end
)
self.commands:add(KEY_FW_RIGHT, nil, "joypad right",
"next item",
function(self)
local last_item = KOPTOptions[self.current_option].current_item
local item_count = #KOPTOptions[self.current_option].items_text
local current_item = (KOPTOptions[self.current_option].current_item + item_count + 1)%item_count
current_item = (current_item == 0) and item_count or current_item
KOPTOptions[self.current_option].current_item = current_item
KOPTOptions[self.current_option].marker_dirty[last_item] = true
KOPTOptions[self.current_option].marker_dirty[current_item] = true
self.config_change = true
end
)
self.commands:add({KEY_F,KEY_AA,KEY_BACK}, nil, "Back",
"back",
function(self)
return "break"
end
)
self.commands:add(KEY_FW_PRESS, nil, "joypad press",
"preview",
function(self)
self.confirm_change = true
if KOPTOptions[self.current_option].name == "trim_page" then
local option = KOPTOptions[self.current_option]
local trim_mode = option.current_item
if option.items_text[trim_mode] == 'manual' then
self:modBBox(self.koptreader)
self.config_change = true
end
end
end
)
end
function KOPTConfig:modBBox(koptreader)
-- save variables that will be changed in modBBox
local orig_globalzoom = koptreader.globalzoom
local orig_dest_x = koptreader.dest_x
local orig_dest_y = koptreader.dest_y
local orig_offset_x = koptreader.offset_x
local orig_offset_y = koptreader.offset_y
koptreader:showOrigPage()
koptreader:modBBox()
-- restore variables changed in modBBox
koptreader.globalzoom = orig_globalzoom
koptreader.dest_x = orig_dest_x
koptreader.dest_y = orig_dest_y
koptreader.offset_x = orig_offset_x
koptreader.offset_y = orig_offset_y
end

@ -0,0 +1,278 @@
/*
KindlePDFViewer: a KOPTContext abstraction
Copyright (C) 2012 Huang Xin <chrox.huang@gmail.com>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "koptcontext.h"
static int newKOPTContext(lua_State *L) {
int trim = 1;
int wrap = 1;
int indent = 1;
int rotate = 0;
int columns = 2;
int offset_x = 0;
int offset_y = 0;
int dev_width = 600;
int dev_height = 800;
int page_width = 600;
int page_height = 800;
int straighten = 0;
int justification = -1;
int read_max_width = 3000;
int read_max_height = 4000;
double zoom = 1.0;
double margin = 0.06;
double quality = 1.0;
double contrast = 1.0;
double defect_size = 1.0;
double line_spacing = 1.2;
double word_spacing = 1.375;
double shrink_factor = 0.9;
uint8_t *data = NULL;
BBox bbox = {0, 0, 0, 0};
WILLUSBITMAP *src;
int precache = 0;
KOPTContext *kc = (KOPTContext*) lua_newuserdata(L, sizeof(KOPTContext));
kc->trim = trim;
kc->wrap = wrap;
kc->indent = indent;
kc->rotate = rotate;
kc->columns = columns;
kc->offset_x = offset_x;
kc->offset_y = offset_y;
kc->dev_width = dev_width;
kc->dev_height = dev_height;
kc->page_width = page_width;
kc->page_height = page_height;
kc->straighten = straighten;
kc->justification = justification;
kc->read_max_width = read_max_width;
kc->read_max_height = read_max_height;
kc->zoom = zoom;
kc->margin = margin;
kc->quality = quality;
kc->contrast = contrast;
kc->defect_size = defect_size;
kc->line_spacing = line_spacing;
kc->word_spacing = word_spacing;
kc->shrink_factor = shrink_factor;
kc->data = data;
kc->bbox = bbox;
kc->src = src;
kc->precache = precache;
luaL_getmetatable(L, "koptcontext");
lua_setmetatable(L, -2);
return 1;
}
static int kcSetBBox(lua_State *L) {
KOPTContext *kc = (KOPTContext*) luaL_checkudata(L, 1, "koptcontext");
kc->bbox.x0 = luaL_checknumber(L, 2);
kc->bbox.y0 = luaL_checknumber(L, 3);
kc->bbox.x1 = luaL_checknumber(L, 4);
kc->bbox.y1 = luaL_checknumber(L, 5);
return 0;
}
static int kcSetTrim(lua_State *L) {
KOPTContext *kc = (KOPTContext*) luaL_checkudata(L, 1, "koptcontext");
kc->trim = luaL_checkint(L, 2);
return 0;
}
static int kcGetTrim(lua_State *L) {
KOPTContext *kc = (KOPTContext*) luaL_checkudata(L, 1, "koptcontext");
lua_pushinteger(L, kc->trim);
return 1;
}
static int kcSetWrap(lua_State *L) {
KOPTContext *kc = (KOPTContext*) luaL_checkudata(L, 1, "koptcontext");
kc->wrap = luaL_checkint(L, 2);
return 0;
}
static int kcSetIndent(lua_State *L) {
KOPTContext *kc = (KOPTContext*) luaL_checkudata(L, 1, "koptcontext");
kc->indent = luaL_checkint(L, 2);
return 0;
}
static int kcSetRotate(lua_State *L) {
KOPTContext *kc = (KOPTContext*) luaL_checkudata(L, 1, "koptcontext");
kc->rotate = luaL_checkint(L, 2);
return 0;
}
static int kcSetColumns(lua_State *L) {
KOPTContext *kc = (KOPTContext*) luaL_checkudata(L, 1, "koptcontext");
kc->columns = luaL_checkint(L, 2);
return 0;
}
static int kcSetOffset(lua_State *L) {
KOPTContext *kc = (KOPTContext*) luaL_checkudata(L, 1, "koptcontext");
kc->offset_x = luaL_checkint(L, 2);
kc->offset_y = luaL_checkint(L, 3);
return 0;
}
static int kcGetOffset(lua_State *L) {
KOPTContext *kc = (KOPTContext*) luaL_checkudata(L, 1, "koptcontext");
lua_pushinteger(L, kc->offset_x);
lua_pushinteger(L, kc->offset_y);
return 2;
}
static int kcSetDeviceDim(lua_State *L) {
KOPTContext *kc = (KOPTContext*) luaL_checkudata(L, 1, "koptcontext");
kc->dev_width = luaL_checkint(L, 2);
kc->dev_height = luaL_checkint(L, 3);
return 0;
}
static int kcGetPageDim(lua_State *L) {
KOPTContext *kc = (KOPTContext*) luaL_checkudata(L, 1, "koptcontext");
lua_pushinteger(L, kc->page_width);
lua_pushinteger(L, kc->page_height);
return 2;
}
static int kcSetStraighten(lua_State *L) {
KOPTContext *kc = (KOPTContext*) luaL_checkudata(L, 1, "koptcontext");
kc->straighten = luaL_checkint(L, 2);
return 0;
}
static int kcSetJustification(lua_State *L) {
KOPTContext *kc = (KOPTContext*) luaL_checkudata(L, 1, "koptcontext");
kc->justification = luaL_checkint(L, 2);
return 0;
}
static int kcSetZoom(lua_State *L) {
KOPTContext *kc = (KOPTContext*) luaL_checkudata(L, 1, "koptcontext");
kc->zoom = luaL_checknumber(L, 2);
return 0;
}
static int kcGetZoom(lua_State *L) {
KOPTContext *kc = (KOPTContext*) luaL_checkudata(L, 1, "koptcontext");
lua_pushnumber(L, kc->zoom);
return 1;
}
static int kcSetMargin(lua_State *L) {
KOPTContext *kc = (KOPTContext*) luaL_checkudata(L, 1, "koptcontext");
kc->margin = luaL_checknumber(L, 2);
return 0;
}
static int kcSetQuality(lua_State *L) {
KOPTContext *kc = (KOPTContext*) luaL_checkudata(L, 1, "koptcontext");
kc->quality = luaL_checknumber(L, 2);
return 0;
}
static int kcSetContrast(lua_State *L) {
KOPTContext *kc = (KOPTContext*) luaL_checkudata(L, 1, "koptcontext");
kc->contrast = luaL_checknumber(L, 2);
return 0;
}
static int kcSetDefectSize(lua_State *L) {
KOPTContext *kc = (KOPTContext*) luaL_checkudata(L, 1, "koptcontext");
kc->defect_size = luaL_checknumber(L, 2);
return 0;
}
static int kcSetLineSpacing(lua_State *L) {
KOPTContext *kc = (KOPTContext*) luaL_checkudata(L, 1, "koptcontext");
kc->line_spacing = luaL_checknumber(L, 2);
return 0;
}
static int kcSetWordSpacing(lua_State *L) {
KOPTContext *kc = (KOPTContext*) luaL_checkudata(L, 1, "koptcontext");
kc->word_spacing = luaL_checknumber(L, 2);
return 0;
}
static int kcSetPreCache(lua_State *L) {
KOPTContext *kc = (KOPTContext*) luaL_checkudata(L, 1, "koptcontext");
kc->precache = 1;
return 0;
}
static int kcIsPreCache(lua_State *L) {
KOPTContext *kc = (KOPTContext*) luaL_checkudata(L, 1, "koptcontext");
lua_pushinteger(L, kc->precache);
return 1;
}
static const struct luaL_Reg koptcontext_meth[] = {
{"setBBox", kcSetBBox},
{"setTrim", kcSetTrim},
{"getTrim", kcGetTrim},
{"setWrap", kcSetWrap},
{"setIndent", kcSetIndent},
{"setRotate", kcSetRotate},
{"setColumns", kcSetColumns},
{"setOffset", kcSetOffset},
{"getOffset", kcGetOffset},
{"setDeviceDim", kcSetDeviceDim},
{"getPageDim", kcGetPageDim},
{"setStraighten", kcSetStraighten},
{"setJustification", kcSetJustification},
{"setZoom", kcSetZoom},
{"getZoom", kcGetZoom},
{"setMargin", kcSetMargin},
{"setQuality", kcSetQuality},
{"setContrast", kcSetContrast},
{"setDefectSize", kcSetDefectSize},
{"setLineSpacing", kcSetLineSpacing},
{"setWordSpacing", kcSetWordSpacing},
{"setPreCache", kcSetPreCache},
{"isPreCache", kcIsPreCache},
{NULL, NULL}
};
static const struct luaL_Reg koptcontext_func[] = {
{"new", newKOPTContext},
{NULL, NULL}
};
int luaopen_koptcontext(lua_State *L) {
luaL_newmetatable(L, "koptcontext");
lua_pushstring(L, "__index");
lua_pushvalue(L, -2);
lua_settable(L, -3);
luaL_register(L, NULL, koptcontext_meth);
lua_pop(L, 1);
luaL_register(L, "KOPTContext", koptcontext_func);
return 1;
}

@ -0,0 +1,27 @@
/*
KindlePDFViewer: a KOPTContext abstraction
Copyright (C) 2012 Huang Xin <chrox.huang@gmail.com>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _KOPTCONTEXT_H
#define _KOPTCONTEXT_H
#include <lua.h>
#include <lualib.h>
#include <lauxlib.h>
#include "koptreflow.h"
int luaopen_koptcontext(lua_State *L);
#endif

@ -0,0 +1,614 @@
require "unireader"
require "inputbox"
require "koptconfig"
Configurable = {}
function Configurable:hash(sep)
local hash = ""
local excluded = {multi_threads = true,}
for key,value in pairs(self) do
if type(value) == "number" and not excluded[key] then
hash = hash..sep..value
end
end
return hash
end
function Configurable:loadDefaults()
for i=1,#KOPTOptions do
local key = KOPTOptions[i].name
self[key] = KOPTOptions[i].default_value
end
end
function Configurable:loadSettings(settings, prefix)
for key,value in pairs(self) do
if type(value) == "number" then
saved_value = settings:readSetting(prefix..key)
self[key] = (saved_value == nil) and self[key] or saved_value
--Debug("Configurable:loadSettings", "key", key, "saved value", saved_value,"Configurable.key", self[key])
end
end
--Debug("loaded config:", dump(Configurable))
end
function Configurable:saveSettings(settings, prefix)
for key,value in pairs(self) do
if type(value) == "number" then
settings:saveSetting(prefix..key, value)
end
end
end
KOPTReader = UniReader:new{
configurable = {}
}
function KOPTReader:makeContext()
local kc = KOPTContext.new()
kc:setTrim(self.configurable.trim_page)
kc:setWrap(self.configurable.text_wrap)
kc:setIndent(self.configurable.detect_indent)
kc:setRotate(self.configurable.screen_rotation)
kc:setColumns(self.configurable.max_columns)
kc:setDeviceDim(G_width, G_height)
kc:setStraighten(self.configurable.auto_straighten)
kc:setJustification(self.configurable.justification)
kc:setZoom(self.configurable.font_size)
kc:setMargin(self.configurable.page_margin)
kc:setQuality(self.configurable.quality)
kc:setContrast(self.configurable.contrast)
kc:setDefectSize(self.configurable.defect_size)
kc:setLineSpacing(self.configurable.line_spacing)
kc:setWordSpacing(self.configurable.word_spacing)
return kc
end
-- open a PDF/DJVU file and its settings store
function KOPTReader:open(filename)
-- muPDF manages its own cache, set second parameter
-- to the maximum size you want it to grow
self.filename = filename
local file_type = string.lower(string.match(filename, ".+%.([^.]+)") or "")
if file_type == "pdf" then
local ok
ok, self.doc = pcall(pdf.openDocument, filename, self.cache_document_size)
if not ok then
return false, self.doc -- will contain error message
end
if self.doc:needsPassword() then
local password = InputBox:input(G_height-100, 100, "Pass:")
if not password or not self.doc:authenticatePassword(password) then
self.doc:close()
self.doc = nil
return false, "wrong or missing password"
end
-- password wrong or not entered
end
local ok, err = pcall(self.doc.getPages, self.doc)
if not ok then
-- for PDFs, they might trigger errors later when accessing page tree
self.doc:close()
self.doc = nil
return false, "damaged page tree"
end
return true
elseif file_type == "djvu" then
if not validDJVUFile(filename) then
return false, "Not a valid DjVu file"
end
local ok
ok, self.doc = pcall(djvu.openDocument, filename, self.cache_document_size)
if not ok then
return ok, self.doc -- this will be the error message instead
end
return ok
end
end
-- draw original page
function KOPTReader:showOrigPage()
local no = self.pageno
local ok, page = pcall(self.doc.openPage, self.doc, no)
local width, height = G_width, G_height
local pwidth, pheight = page:getSize(self.nulldc)
if not ok then
-- TODO: error handling
return nil
end
local dc = DrawContext.new()
self.globalzoom = width / pwidth
if height / pheight < self.globalzoom then
self.globalzoom = height / pheight
end
dc:setZoom(self.globalzoom)
self.offset_x = 0
self.offset_y = 0
local pagehash = no..'_orig_full_page'
if self.cache[pagehash] ~= nil then
page:close()
local bb = self.cache[pagehash].bb
self.dest_x = 0
self.dest_y = 0
if bb:getWidth() < width then
self.dest_x = (width - (bb:getWidth())) / 2
end
if bb:getHeight() < height then
self.dest_y = (height - (bb:getHeight())) / 2
end
if self.dest_x or self.dest_y then
fb.bb:paintRect(0, 0, width, height, DBACKGROUND_COLOR)
end
fb.bb:blitFrom(self.cache[pagehash].bb, self.dest_x, self.dest_y, 0, 0, width, height)
fb:refresh(1)
return
end
local tile = { x = 0, y = 0, w = width, h = height }
-- can we cache the full page?
local max_cache = self.cache_max_memsize
local fullwidth, fullheight = page:getSize(dc)
if (fullwidth * fullheight / 2) <= max_cache then
-- yes we can, so do this with offset 0, 0
tile.x = 0
tile.y = 0
tile.w = fullwidth
tile.h = fullheight
else
Debug("ERROR not enough memory in cache left, probably a bug.")
return nil
end
self:cacheClaim(tile.w * tile.h / 2);
self.cache[pagehash] = {
x = tile.x,
y = tile.y,
w = tile.w,
h = tile.h,
ttl = self.cache_max_ttl,
size = tile.w * tile.h / 2,
bb = Blitbuffer.new(tile.w, tile.h)
}
--debug ("# new biltbuffer:"..dump(self.cache[pagehash]))
dc:setOffset(-tile.x, -tile.y)
Debug("rendering page", no)
page:draw(dc, self.cache[pagehash].bb, 0, 0, self.render_mode)
page:close()
local bb = self.cache[pagehash].bb
self.dest_x = 0
self.dest_y = 0
if bb:getWidth() < width then
self.dest_x = (width - (bb:getWidth())) / 2
end
if bb:getHeight() < height then
self.dest_y = (height - (bb:getHeight())) / 2
end
if self.dest_x or self.dest_y then
fb.bb:paintRect(0, 0, width, height, DBACKGROUND_COLOR)
end
fb.bb:blitFrom(bb, self.dest_x, self.dest_y, 0, 0, width, height)
fb:refresh(1)
end
function KOPTReader:drawOrCache(no, preCache)
-- our general caching strategy is as follows:
-- #1 goal: we must render the needed area.
-- #2 goal: we render as much of the requested page as we can
-- #3 goal: we render the full page
-- #4 goal: we render next page, too. (TODO)
-- ideally, this should be factored out and only be called when needed (TODO)
local ok, page = pcall(self.doc.openPage, self.doc, no)
local width, height = G_width, G_height
if not ok then
-- TODO: error handling
return nil
end
local kc = self:getContext(page, no, preCache)
self.globalzoom_mode = self.ZOOM_FIT_TO_CONTENT_WIDTH_PAN
-- check if we have relevant cache contents
local bbox = self.cur_bbox
local pagehash = no..self.configurable:hash('_')..'_'..bbox.x0..'_'..bbox.y0..'_'..bbox.x1..'_'..bbox.y1
Debug('page hash', pagehash)
if self.cache[pagehash] ~= nil then
-- we have something in cache
-- requested part is within cached tile
-- ...so properly clean page
page:close()
self.min_offset_x = fb.bb:getWidth() - self.cache[pagehash].w
self.min_offset_y = fb.bb:getHeight() - self.cache[pagehash].h
if(self.min_offset_x > 0) then
self.min_offset_x = 0
end
if(self.min_offset_y > 0) then
self.min_offset_y = 0
end
if self.offset_y <= -201253 then
self.offset_y = self.min_offset_y
end
-- offset_x_in_page & offset_y_in_page is the offset within zoomed page
-- they are always positive.
-- you can see self.offset_x_& self.offset_y as the offset within
-- draw space, which includes the page. So it can be negative and positive.
local offset_x_in_page = -self.offset_x
local offset_y_in_page = -self.offset_y
if offset_x_in_page < 0 then offset_x_in_page = 0 end
if offset_y_in_page < 0 then offset_y_in_page = 0 end
Debug("cached page offset_x",self.offset_x,"offset_y",self.offset_y,"min_offset_x",self.min_offset_x,"min_offset_y",self.min_offset_y)
-- ...and give it more time to live (ttl), except if we're precaching
if not preCache then
self.cache[pagehash].ttl = self.cache_max_ttl
end
-- ...and return blitbuffer plus offset into it
self.cached_pagehash = pagehash
self.cached_offset_x = offset_x_in_page - self.cache[pagehash].x
self.cached_offset_y = offset_y_in_page - self.cache[pagehash].y
return pagehash,
offset_x_in_page - self.cache[pagehash].x,
offset_y_in_page - self.cache[pagehash].y
end
-- okay, we do not have it in cache yet.
-- so render now.
-- start off with the requested area
local use_threads = self.configurable.multi_threads == 1 and true or false
if use_threads and preCache then
Debug("start precache on page", no)
if self.precache_kc ~= nil then
if self.precache_kc:isPreCache() == 1 then
Debug("waiting threaded precache to finish.")
return nil
else
Debug("threaded preCache is finished.")
Debug("current pagehash", pagehash)
Debug("precache pagehash", self.precache_pagehash)
if self.precache_pagehash == pagehash then
Debug("write cache ", self.precache_pagehash)
return self:writeToCache(self.precache_kc, page, self.precache_pagehash, true)
else
self.precache_kc = nil
self.precache_pagehash = nil
Debug("discard cache ", self.precache_pagehash)
return nil
end
end
else
self.precache_kc = kc
self.precache_pagehash = pagehash
self.precache_kc:setPreCache()
page:reflow(self.precache_kc, self.render_mode)
Debug("threaded preCache is returned.")
end
else
if use_threads and self.precache_kc ~= nil then
if self.precache_kc:isPreCache() == 1 and self.cache[self.cached_pagehash] then
InfoMessage:inform("Rendering in background...", DINFO_DELAY, 1, MSG_WARN)
return self.cached_pagehash, self.cached_offset_x, self.cached_offset_y
elseif self.precache_kc:isPreCache() == 0 then -- cache is ready to be written
Debug("write cache", self.precache_pagehash)
self:writeToCache(self.precache_kc, page, self.precache_pagehash, true)
Debug("reflow page", pagehash)
local ok, page = pcall(self.doc.openPage, self.doc, no) -- reopen current page
kc = self:getContext(page, no, true)
page:reflow(kc, self.render_mode)
return self:writeToCache(kc, page, pagehash, false)
else
Debug("ERROR something wrong happens .. why cached page is missing?")
return nil
end
else
--local secs, usecs = util.gettime()
Debug("reflow page", pagehash)
page:reflow(kc, self.render_mode)
--local nsecs, nusecs = util.gettime()
--local dur = (nsecs - secs) * 1000000 + nusecs - usecs
--Debug("Reflow duration:", dur)
--self:logReflowDuration(no, dur)
return self:writeToCache(kc, page, pagehash, false)
end
end
end
function KOPTReader:logReflowDuration(pageno, dur)
local file = io.open("reflowlog.txt", "a+")
if file then
if file:seek("end") == 0 then -- write the header only once
file:write("FILE\tPAGE\tDUR\n")
end
file:write(string.format("%s\t%s\t%s\n", self.filename, pageno, dur))
file:close()
end
end
function KOPTReader:logMemoryUsage(pageno)
local status_file = io.open("/proc/self/status", "r")
local log_file = io.open("reflow_mem_log.txt", "a+")
local data = -1
if status_file then
for line in status_file:lines() do
local s, n
s, n = line:gsub("VmData:%s-(%d+) kB", "%1")
if n ~= 0 then data = tonumber(s) end
if data ~= -1 then break end
end
status_file:close()
end
if log_file then
if log_file:seek("end") == 0 then -- write the header only once
log_file:write("PAGE\tMEM\n")
end
log_file:write(string.format("%s\t%s\n", pageno, data))
log_file:close()
end
end
function KOPTReader:writeToCache(kc, page, pagehash, preCache)
--self:logMemoryUsage(self.pageno)
local tile = { x = 0, y = 0, w = G_width, h = G_height }
-- can we cache the full page?
local max_cache = self.cache_max_memsize
local fullwidth, fullheight = kc:getPageDim()
self.reflow_zoom = kc:getZoom()
Debug("page::reflowPage:", "fullwidth:", fullwidth, "fullheight:", fullheight)
if (fullwidth * fullheight / 2) <= max_cache then
-- yes we can, so do this with offset 0, 0
tile.x = 0
tile.y = 0
tile.w = fullwidth
tile.h = fullheight
else
Debug("ERROR not enough memory in cache left, reflowed page is too large.")
return nil
end
Debug("cache capacity", max_cache, "cache claim", tile.w * tile.h / 2, "cache current", self.cache_current_memsize)
if not self:cacheClaim(tile.w * tile.h / 2) then
Debug("ERROR not enough memory in cache left, cache claim failed.")
return nil
else
Debug("Cache claim succeed.")
end
self.cache[pagehash] = {
x = tile.x,
y = tile.y,
w = tile.w,
h = tile.h,
ttl = self.cache_max_ttl,
size = tile.w * tile.h / 2,
bb = Blitbuffer.new(tile.w, tile.h)
}
--Debug ("new biltbuffer:"..dump(self.cache[pagehash]))
Debug("page::drawReflowedPage", "width:", self.cache[pagehash].w, "height:", self.cache[pagehash].h)
page:rfdraw(kc, self.cache[pagehash].bb)
page:close()
if preCache then
self.precache_kc = nil
end
self.min_offset_x = fb.bb:getWidth() - self.cache[pagehash].w
self.min_offset_y = fb.bb:getHeight() - self.cache[pagehash].h
if(self.min_offset_x > 0) then
self.min_offset_x = 0
end
if(self.min_offset_y > 0) then
self.min_offset_y = 0
end
if self.offset_y <= -201253 then
self.offset_y = self.min_offset_y
end
local offset_x_in_page = -self.offset_x
local offset_y_in_page = -self.offset_y
if offset_x_in_page < 0 then offset_x_in_page = 0 end
if offset_y_in_page < 0 then offset_y_in_page = 0 end
-- return hash and offset within blitbuffer
return pagehash,
offset_x_in_page - tile.x,
offset_y_in_page - tile.y
end
-- get reflow context
function KOPTReader:getContext(page, pnumber, preCache)
local kc = self:makeContext()
local pwidth, pheight = page:getSize(self.nulldc)
local width, height = G_width, G_height
-- rounds down pwidth and pheight to 2 decimals, because page:getUsedBBox() returns only 2 decimals.
-- without it, later check whether to use margins will fail for some documents
pwidth = math.floor(pwidth * 100) / 100
pheight = math.floor(pheight * 100) / 100
Debug("Context preCache:", preCache and "true" or "false")
Debug("Context page::getSize",pwidth,pheight)
local x0, y0, x1, y1 = page:getUsedBBox()
if x0 == 0.01 and y0 == 0.01 and x1 == -0.01 and y1 == -0.01 then
x0 = 0
y0 = 0
x1 = pwidth
y1 = pheight
end
if x1 == 0 then x1 = pwidth end
if y1 == 0 then y1 = pheight end
-- clamp to page BBox
if x0 < 0 then x0 = 0 end
if x1 > pwidth then x1 = pwidth end
if y0 < 0 then y0 = 0 end
if y1 > pheight then y1 = pheight end
if self.bbox.enabled then
Debug("ORIGINAL page::getUsedBBox", x0,y0, x1,y1 )
local bbox = self.bbox[pnumber] -- exact
local oddEven = self:oddEven(pnumber)
if bbox ~= nil then
Debug("bbox from", pnumber)
else
bbox = self.bbox[oddEven] -- odd/even
end
if bbox ~= nil then -- last used up to this page
Debug("bbox from", oddEven)
else
for i = 0,pnumber do
bbox = self.bbox[ pnumber - i ]
if bbox ~= nil then
Debug("bbox from", pnumber - i)
break
end
end
end
if bbox ~= nil then
x0 = bbox["x0"]
y0 = bbox["y0"]
x1 = bbox["x1"]
y1 = bbox["y1"]
end
end
Debug("Context page::getUsedBBox", x0, y0, x1, y1 )
if kc:getTrim() == 1 then
kc:setBBox(0, 0, pwidth, pheight)
else
kc:setBBox(x0, y0, x1, y1)
end
self.cur_bbox = {
["x0"] = x0,
["y0"] = y0,
["x1"] = x1,
["y1"] = y1,
}
Debug("Context cur_bbox", self.cur_bbox)
return kc
end
function KOPTReader:nextView()
local pageno = self.pageno
Debug("nextView offset_y", self.offset_y, "min_offset_y", self.min_offset_y)
if self.offset_y <= self.min_offset_y then
-- hit content bottom, turn to next page top
local numpages = self.doc:getPages()
if pageno < numpages then
self.offset_x = 0
self.offset_y = 0
end
pageno = pageno + 1
else
-- goto next view of current page
self.offset_y = self.offset_y - G_height + self.pan_overlap_vertical
end
return pageno
end
function KOPTReader:prevView()
local pageno = self.pageno
Debug("preView offset_y", self.offset_y, "min_offset_y", self.min_offset_y)
if self.offset_y >= 0 then
-- hit content top, turn to previous page bottom
if pageno > 1 then
self.offset_x = 0
self.offset_y = -2012534
end
pageno = pageno - 1
else
-- goto previous view of current page
self.offset_y = self.offset_y + G_height - self.pan_overlap_vertical
end
return pageno
end
function KOPTReader:setDefaults()
self.show_overlap_enable = DKOPTREADER_SHOW_OVERLAP_ENABLE
self.show_links_enable = DKOPTREADER_SHOW_LINKS_ENABLE
self.comics_mode_enable = DKOPTREADER_COMICS_MODE_ENABLE
self.rtl_mode_enable = DKOPTREADER_RTL_MODE_ENABLE
self.page_mode_enable = DKOPTREADER_PAGE_MODE_ENABLE
end
-- backup global variables from UniReader
function KOPTReader:loadSettings(filename)
UniReader.loadSettings(self,filename)
self.offset_y = self.settings:readSetting("kopt_offset_y") or 0
self.configurable = Configurable
self.configurable:loadDefaults()
--Debug("default configurable:", dump(self.configurable))
self.configurable:loadSettings(self.settings, 'kopt_')
--Debug("loaded configurable:", dump(self.configurable))
-- backup global variable that may be changed in koptreader
self.orig_globalzoom_mode = self.settings:readSetting("globalzoom_mode") or -1
self.orig_dbackground_color = DBACKGROUND_COLOR
DBACKGROUND_COLOR = 0
end
function KOPTReader:saveSpecialSettings()
self.settings:saveSetting("kopt_offset_y", self.offset_y)
self.configurable:saveSettings(self.settings, 'kopt_')
--Debug("saved configurable:", dump(self.configurable))
-- restore global variable from backups
self.settings:saveSetting("globalzoom_mode", self.orig_globalzoom_mode)
DBACKGROUND_COLOR = self.orig_dbackground_color
end
function KOPTReader:init()
self:addAllCommands()
self:adjustCommands()
end
function KOPTReader:redrawWithoutPrecache()
self:show(self.pageno)
end
function KOPTReader:adjustCommands()
self.commands:del(KEY_A, nil,"A")
self.commands:del(KEY_A, MOD_SHIFT, "A")
self.commands:del(KEY_C, nil,"C")
self.commands:del(KEY_U, nil,"U")
self.commands:del(KEY_D, nil,"D")
self.commands:del(KEY_D, MOD_SHIFT, "D")
self.commands:del(KEY_S, nil,"S")
self.commands:del(KEY_S, MOD_SHIFT, "S")
self.commands:del(KEY_F, nil,"F")
self.commands:del(KEY_F, MOD_SHIFT, "F")
self.commands:del(KEY_Z, nil,"Z")
self.commands:del(KEY_Z, MOD_ALT, "Z")
self.commands:del(KEY_Z, MOD_SHIFT, "Z")
self.commands:del(KEY_X, nil,"X")
self.commands:del(KEY_X, MOD_SHIFT, "X")
self.commands:del(KEY_N, nil,"N")
self.commands:del(KEY_N, MOD_SHIFT, "N")
self.commands:del(KEY_L, nil, "L")
self.commands:del(KEY_L, MOD_SHIFT, "L")
self.commands:del(KEY_M, nil, "M")
self.commands:delGroup(MOD_ALT.."< >")
self.commands:delGroup(MOD_SHIFT.."< >")
self.commands:delGroup("vol-/+")
self.commands:del(KEY_P, nil, "P")
self.commands:add({KEY_F,KEY_AA}, nil, "F",
"change koptreader configuration",
function(self)
KOPTConfig:config(self)
self:redrawCurrentPage()
end
)
end

@ -22,7 +22,7 @@ fi
killall -stop cvm
# finally call reader
./reader.lua "$1" 2> /mnt/us/kindlepdfviewer/crash.log || cat /mnt/us/kindlepdfviewer/crash.log
./reader.lua "$1" 2> crash.log
# unmount system fonts
if grep /mnt/us/kindlepdfviewer/fonts/host /proc/mounts; then
@ -31,7 +31,3 @@ fi
# always try to continue cvm
killall -cont cvm || /etc/init.d/framework start
# cleanup hanging process
killall lipc-wait-event

@ -25,9 +25,11 @@
#include "blitbuffer.h"
#include "drawcontext.h"
#include "koptcontext.h"
#include "pdf.h"
#include "mupdfimg.h"
#include "djvu.h"
#include "pic.h"
#include "cre.h"
#include "einkfb.h"
#include "input.h"
@ -39,7 +41,7 @@
lua_State *L;
int main(int argc, char **argv) {
int i, err;
int i;
if(argc < 2) {
fprintf(stderr, "needs config file as first argument.\n");
@ -53,9 +55,11 @@ int main(int argc, char **argv) {
luaopen_blitbuffer(L);
luaopen_drawcontext(L);
luaopen_koptcontext(L);
luaopen_einkfb(L);
luaopen_pdf(L);
luaopen_djvu(L);
luaopen_pic(L);
luaopen_cre(L);
luaopen_input(L);
luaopen_util(L);

@ -9,14 +9,14 @@ SET(CR_3RDPARTY_DIR crengine/thirdparty)
SET(CR3_PNG 1)
#SET(CR3_JPEG 1)
SET(FREETYPE_INCLUDE_DIRS ${MUPDF_3RDPARTY_DIR}/freetype-2.4.8/include)
SET(FREETYPE_INCLUDE_DIRS ${MUPDF_3RDPARTY_DIR}/freetype/include)
#SET(FREETYPE_INCLUDE_DIRS ${CR_3RDPARTY_DIR}/freetype/include)
SET(ANTIWORD_INCLUDE_DIR ${CR_3RDPARTY_DIR}/antiword)
SET(CHM_INCLUDE_DIRS ${CR_3RDPARTY_DIR}/chmlib)
SET(PNG_INCLUDE_DIR ${CR_3RDPARTY_DIR}/libpng)
SET(ZLIB_INCLUDE_DIR ${MUPDF_3RDPARTY_DIR}/zlib-1.2.5)
SET(ZLIB_INCLUDE_DIR ${MUPDF_3RDPARTY_DIR}/zlib)
#SET(ZLIB_INCLUDE_DIR ${CR_3RDPARTY_DIR}/zlib)
SET(JPEGLIB_INCLUDE_DIR ${MUPDF_3RDPARTY_DIR}/jpeg-8d)
SET(JPEGLIB_INCLUDE_DIR ${MUPDF_3RDPARTY_DIR}/jpeg)
#SET(JPEGLIB_INCLUDE_DIR ${CR_3RDPARTY_DIR}/libjpeg)
SET(JCONFIG_INCLUDE_DIR ${MUPDF_DIR}/scripts)

@ -0,0 +1,74 @@
body { text-align: left; text-indent: 0px }
p { text-align: justify; text-indent: 2em; margin-top:0em; margin-bottom: 0em }
empty-line { height: 1em }
hr { height: 1px; /* background-color: #808080; */ margin-top: 0.5em; margin-bottom: 0.5em }
sub { vertical-align: sub; font-size: 70% }
sup { vertical-align: super; font-size: 70% }
strong, b { font-weight: bold }
emphasis, i { font-style: italic }
a { text-decoration: underline }
a[type="note"] { vertical-align: super; font-size: 70%; text-decoration: none }
image { text-align: center; text-indent: 0px }
p image { display: inline }
title p, subtitle p, h1 p, h2 p, h3 p, h4 p, h5 p, h6 p { text-align: center; text-indent: 0px }
cite p, epigraph p { text-align: left; text-indent: 0px }
v { text-align: left; text-indent: 0px }
stanza + stanza { margin-top: 1em; }
stanza { margin-left: 30%; text-align: left; font-style: italic }
poem { margin-top: 1em; margin-bottom: 1em; text-indent: 0px }
text-author { font-weight: bold; font-style: italic; margin-left: 5%}
epigraph { margin-left: 25%; margin-right: 1em; text-align: left; text-indent:
1px; font-style: italic; margin-top: 15px; margin-bottom: 25px }
cite { font-style: italic; margin-left: 5%; margin-right: 5%; text-align: justify;
margin-top: 20px; margin-bottom: 20px }
title, h1, h2 { text-align: center; text-indent: 0px; font-weight: bold; hyphenate: none;
page-break-before: always; page-break-inside: avoid; page-break-after: avoid; }
subtitle, h3, h4, h5, h6 { text-align: center; text-indent: 0px; font-weight: bold;
hyphenate: none; page-break-inside: avoid; page-break-after: avoid; }
title { font-size: 110%; margin-top: 0.7em; margin-bottom: 0.5em }
subtitle { font-style: italic; margin-top: 0.3em; margin-bottom: 0.3em }
h1 { font-size: 150% }
h2 { font-size: 140% }
h3 { font-size: 130% }
h4 { font-size: 120% }
h5 { font-size: 110% }
table { font-size: 80% }
td, th { text-indent: 0px; padding: 3px }
th { font-weight: bold; /* background-color: #DDD */ }
table > caption { text-indent: 0px; padding: 4px; /* background-color: #EEE */ }
code, pre { display: block; white-space: pre; text-align: left;
font-family: "Droid Sans Mono", monospace; text-align: left }
body[name="notes"] { font-size: 70%; }
body[name="notes"] section title { display: run-in; text-align: left; font-size: 110%;
font-weight: bold; page-break-before: auto; page-break-inside: auto;
page-break-after: auto; }
body[name="notes"] section title p { display: inline }
description { display: block; }
title-info { display: block; }
annotation { margin-left: 5%; margin-right: 5%; font-size: 80%; font-style: italic;
text-align: justify; text-indent: 2em }
date { display: block; font-size: 80%; font-style: italic; text-align: center }
genre { display: none; }
author { display: none; }
book-title { display: none; }
keywords { display: none; }
lang { display: none; }
src-lang { display: none; }
translator { display: none; }
document-info { display: none; }
publish-info { display: none; }
custom-info { display: none; }
coverpage { display: none }

@ -1 +1 @@
Subproject commit 7a73d1666538fe9dd7d84d7e18135b03c21be2ca
Subproject commit a9516b455e811b9f57f2805d6c08b6744f797083

@ -1,15 +0,0 @@
--- jcapimin.c 2012-04-04 00:02:30.000000000 +0800
+++ jcapimin-patched.c 2012-04-04 00:02:26.000000000 +0800
@@ -36,9 +36,9 @@
cinfo->mem = NULL; /* so jpeg_destroy knows mem mgr not called */
if (version != JPEG_LIB_VERSION)
ERREXIT2(cinfo, JERR_BAD_LIB_VERSION, JPEG_LIB_VERSION, version);
- if (structsize != SIZEOF(struct jpeg_compress_struct))
- ERREXIT2(cinfo, JERR_BAD_STRUCT_SIZE,
- (int) SIZEOF(struct jpeg_compress_struct), (int) structsize);
+ /*if (structsize != SIZEOF(struct jpeg_compress_struct))*/
+ /*ERREXIT2(cinfo, JERR_BAD_STRUCT_SIZE, */
+ /*(int) SIZEOF(struct jpeg_compress_struct), (int) structsize);*/
/* For debugging purposes, we zero the whole master structure.
* But the application has already set the err pointer, and may have set

@ -1,15 +0,0 @@
--- jdapimin.c 2012-04-04 01:09:00.000000000 +0800
+++ jdapimin-patched.c 2012-04-04 01:42:44.000000000 +0800
@@ -36,9 +36,9 @@
cinfo->mem = NULL; /* so jpeg_destroy knows mem mgr not called */
if (version != JPEG_LIB_VERSION)
ERREXIT2(cinfo, JERR_BAD_LIB_VERSION, JPEG_LIB_VERSION, version);
- if (structsize != SIZEOF(struct jpeg_decompress_struct))
- ERREXIT2(cinfo, JERR_BAD_STRUCT_SIZE,
- (int) SIZEOF(struct jpeg_decompress_struct), (int) structsize);
+ /*if (structsize != SIZEOF(struct jpeg_decompress_struct))*/
+ /*ERREXIT2(cinfo, JERR_BAD_STRUCT_SIZE, */
+ /*(int) SIZEOF(struct jpeg_decompress_struct), (int) structsize);*/
/* For debugging purposes, we zero the whole master structure.
* But the application has already set the err pointer, and may have set

@ -0,0 +1,14 @@
diff --git a/crengine/src/lvdocview.cpp b/crengine/src/lvdocview.cpp
index e7a355a..e1178de 100755
--- a/crengine/src/lvdocview.cpp
+++ b/crengine/src/lvdocview.cpp
@@ -4539,7 +4539,8 @@ void LVDocView::getCurrentPageLinks(ldomXRangeList & list) {
if (_list[i]->getStart().getNode() == elem)
return true; // don't add, duplicate found!
}
- _list.add(new ldomXRange(elem->getChildNode(0)));
+ ldomNode * node = elem->getChildNode(0);
+ if ( node ) _list.add(new ldomXRange(node));
}
return true;
}

@ -1,11 +1,11 @@
[Actions]
# start kindlepdfviewer with filebrowser in /mnt/us/documents
P D = !/mnt/us/launchpad/kpdf.sh /mnt/us/documents
P D = !/mnt/us/kindlepdfviewer/kpdf.sh /mnt/us/documents
# start kindlepdfviewer with last document
P P = !/mnt/us/launchpad/kpdf.sh
P P = !/mnt/us/kindlepdfviewer/kpdf.sh
# start kindlepdfviewer without framework in /mnt/us/documents
P K = !/mnt/us/launchpad/kpdf.sh --framework_stop /mnt/us/documents
P K = !/mnt/us/kindlepdfviewer/kpdf.sh --framework_stop /mnt/us/documents
# start kindlepdfviewer without framework on last read document
P L = !/mnt/us/launchpad/kpdf.sh --framework_stop
P L = !/mnt/us/kindlepdfviewer/kpdf.sh --framework_stop
# restart amazon framework - when it got irritated
P R = !/etc/init.d/framework restart

@ -0,0 +1 @@
Subproject commit d9ed4f0b5d9212cdcc97fa432b83ba46eab21d09

@ -0,0 +1 @@
Subproject commit eb6f890ebd01ee4cf4f31a66d8a946bc8dccd885

@ -1 +1 @@
Subproject commit bdb6b688a238df56b2cf47fa17a08a4dd4b7a122
Subproject commit 05219d086a5136ee19f643cf062bd5c0d3aef5d3

@ -1,62 +1,60 @@
diff --git a/pdf/pdf_font.c b/pdf/pdf_font.c
index 5e54e0b..38bd1d8 100644
index 33a1a65..c2fdee3 100644
--- a/pdf/pdf_font.c
+++ b/pdf/pdf_font.c
@@ -182,8 +182,13 @@ pdf_load_builtin_font(fz_context *ctx, pdf_font_desc *fontdesc, char *fontname)
@@ -185,7 +185,12 @@ pdf_load_builtin_font(fz_context *ctx, pdf_font_desc *fontdesc, char *fontname)
if (!data)
fz_throw(ctx, "cannot find builtin font: '%s'", fontname);
+#ifndef NOBUILTINFONT
fontdesc->font = fz_new_font_from_memory(ctx, data, len, 0, 1);
/* RJW: "cannot load freetype font from memory" */
fontdesc->font = fz_new_font_from_memory(ctx, fontname, data, len, 0, 1);
+#else
+ fontdesc->font = fz_new_font_from_file(ctx, data, 0, 1);
+ fontdesc->font = fz_new_font_from_file(ctx, fontname, data, 0, 1);
+ free(data);
+#endif
if (!strcmp(fontname, "Symbol") || !strcmp(fontname, "ZapfDingbats"))
fontdesc->flags |= PDF_FD_SYMBOLIC;
@@ -199,8 +204,13 @@ pdf_load_substitute_font(fz_context *ctx, pdf_font_desc *fontdesc, int mono, int
@@ -201,7 +206,12 @@ pdf_load_substitute_font(fz_context *ctx, pdf_font_desc *fontdesc, char *fontnam
if (!data)
fz_throw(ctx, "cannot find substitute font");
+#ifndef NOBUILTINFONT
fontdesc->font = fz_new_font_from_memory(ctx, data, len, 0, 1);
/* RJW: "cannot load freetype font from memory" */
fontdesc->font = fz_new_font_from_memory(ctx, fontname, data, len, 0, 1);
+#else
+ fontdesc->font = fz_new_font_from_file(ctx, data, 0, 1);
+ fontdesc->font = fz_new_font_from_file(ctx, fontname, data, 0, 1);
+ free(data);
+#endif
fontdesc->font->ft_substitute = 1;
fontdesc->font->ft_bold = bold && !ft_is_bold(fontdesc->font->ft_face);
@@ -218,7 +228,12 @@ pdf_load_substitute_cjk_font(fz_context *ctx, pdf_font_desc *fontdesc, int ros,
@@ -219,7 +229,12 @@ pdf_load_substitute_cjk_font(fz_context *ctx, pdf_font_desc *fontdesc, char *fon
fz_throw(ctx, "cannot find builtin CJK font");
/* a glyph bbox cache is too big for droid sans fallback (51k glyphs!) */
+#ifndef NOBUILTINFONT
fontdesc->font = fz_new_font_from_memory(ctx, data, len, 0, 0);
fontdesc->font = fz_new_font_from_memory(ctx, fontname, data, len, 0, 0);
+#else
+ fontdesc->font = fz_new_font_from_file(ctx, data, 0, 0);
+ fontdesc->font = fz_new_font_from_file(ctx, fontname, data, 0, 1);
+ free(data);
+#endif
/* RJW: "cannot load builtin CJK font" */
fontdesc->font->ft_substitute = 1;
}
diff --git a/pdf/pdf_fontfile.c b/pdf/pdf_fontfile.c
index 543ce76..a076033 100644
index 99565da..a91380f 100644
--- a/pdf/pdf_fontfile.c
+++ b/pdf/pdf_fontfile.c
@@ -1,6 +1,8 @@
#include "fitz.h"
#include "mupdf.h"
@@ -15,6 +15,8 @@
Set NODROIDFONT to use the base 14 fonts as substitute fonts.
*/
+#ifndef NOBUILTINFONT
+
#ifdef NOCJK
#define NOCJKFONT
#endif
@@ -129,3 +131,112 @@ pdf_find_substitute_cjk_font(int ros, int serif, unsigned int *len)
@@ -152,3 +154,112 @@ pdf_lookup_substitute_cjk_font(int ros, int serif, unsigned int *len)
return NULL;
#endif
}

@ -53,6 +53,7 @@ static int loadPNGData(lua_State *L) {
fz_catch(img->context) {
return luaL_error(L, "cannot load PNG data");
}
return 0;
}
static int loadJPEGData(lua_State *L) {
@ -65,6 +66,7 @@ static int loadJPEGData(lua_State *L) {
fz_catch(img->context) {
return luaL_error(L, "cannot open JPEG data");
}
return 0;
}
static int toBlitBuffer(lua_State *L) {

226
pdf.c

@ -15,15 +15,18 @@
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <fitz/fitz-internal.h>
#include "blitbuffer.h"
#include "drawcontext.h"
#include "pdf.h"
#include <stdio.h>
#include <math.h>
#include <stddef.h>
#include <pthread.h>
#include <fitz/fitz-internal.h>
#include "blitbuffer.h"
#include "drawcontext.h"
#include "koptcontext.h"
#include "k2pdfopt.h"
#include "pdf.h"
typedef struct PdfDocument {
fz_document *xref;
@ -58,6 +61,7 @@ static size_t msize_min;
static size_t msize_iniz;
static int is_realloc=0;
#if 0
char* readable_fs(double size/*in bytes*/, char *buf) {
int i = 0;
const char* units[] = {"B", "kB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"};
@ -68,6 +72,7 @@ char* readable_fs(double size/*in bytes*/, char *buf) {
sprintf(buf, "%.*f %s", i, size, units[i]);
return buf;
}
#endif
static void resetMsize(){
msize_iniz = msize;
@ -78,7 +83,7 @@ static void resetMsize(){
static void showMsize(){
char buf[15],buf2[15],buf3[15],buf4[15];
printf("§§§ now: %s was: %s - min: %s - max: %s\n",readable_fs(msize,buf),readable_fs(msize_iniz,buf2),readable_fs(msize_min,buf3),readable_fs(msize_max,buf4));
//printf("§§§ now: %s was: %s - min: %s - max: %s\n",readable_fs(msize,buf),readable_fs(msize_iniz,buf2),readable_fs(msize_min,buf3),readable_fs(msize_max,buf4));
resetMsize();
}
@ -89,7 +94,7 @@ static void log_size(char *funcName){
msize_min = msize;
if(1==0 && abs(msize-msize_prev)>msize_prev*LOG_TRESHOLD_PERC){
char buf[15],buf2[15];
printf("§§§ %s - total: %s (was %s)\n",funcName, readable_fs(msize,buf),readable_fs(msize_prev,buf2));
//printf("§§§ %s - total: %s (was %s)\n",funcName, readable_fs(msize,buf),readable_fs(msize_prev,buf2));
msize_prev = msize;
}
}
@ -133,7 +138,7 @@ my_realloc_default(void *opaque, void *old, unsigned int size)
} else {
struct header * h = ((struct header *)old) - 1;
if (h -> magic != MAGIC) { // Not allocated by my_malloc_default
printf("§§§ warn: not allocated by my_malloc_default, new size: %i\n",size);
//printf("§§§ warn: not allocated by my_malloc_default, new size: %i\n",size);
newp = realloc(old,size);
} else { // malloc + free
is_realloc = 1;
@ -166,7 +171,7 @@ static int openDocument(lua_State *L) {
char *filename = strdup(luaL_checkstring(L, 1));
int cache_size = luaL_optint(L, 2, 64 << 20); // 64 MB limit default
char buf[15];
printf("## cache_size: %s\n",readable_fs(cache_size,buf));
//printf("## cache_size: %s\n",readable_fs(cache_size,buf));
PdfDocument *doc = (PdfDocument*) lua_newuserdata(L, sizeof(PdfDocument));
@ -492,9 +497,9 @@ static int getUsedBBox(lua_State *L) {
return luaL_error(L, "cannot calculate bbox for page");
}
lua_pushnumber(L, ((double)result.x0)/100);
lua_pushnumber(L, ((double)result.x0)/100);
lua_pushnumber(L, ((double)result.y0)/100);
lua_pushnumber(L, ((double)result.x1)/100);
lua_pushnumber(L, ((double)result.x1)/100);
lua_pushnumber(L, ((double)result.y1)/100);
return 4;
@ -509,6 +514,147 @@ static int closePage(lua_State *L) {
return 0;
}
/* bmpmupdf.c from willuslib */
static int bmpmupdf_pixmap_to_bmp(WILLUSBITMAP *bmp, fz_context *ctx, fz_pixmap *pixmap) {
unsigned char *p;
int ncomp, i, row, col;
bmp->width = fz_pixmap_width(ctx, pixmap);
bmp->height = fz_pixmap_height(ctx, pixmap);
ncomp = fz_pixmap_components(ctx, pixmap);
/* Has to be 8-bit or RGB */
if (ncomp != 2 && ncomp != 4)
return (-1);
bmp->bpp = (ncomp == 2) ? 8 : 24;
bmp_alloc(bmp);
if (ncomp == 2)
for (i = 0; i < 256; i++)
bmp->red[i] = bmp->green[i] = bmp->blue[i] = i;
p = fz_pixmap_samples(ctx, pixmap);
if (ncomp == 1)
for (row = 0; row < bmp->height; row++) {
unsigned char *dest;
dest = bmp_rowptr_from_top(bmp, row);
memcpy(dest, p, bmp->width);
p += bmp->width;
}
else if (ncomp == 2)
for (row = 0; row < bmp->height; row++) {
unsigned char *dest;
dest = bmp_rowptr_from_top(bmp, row);
for (col = 0; col < bmp->width; col++, dest++, p += 2)
dest[0] = p[0];
}
else
for (row = 0; row < bmp->height; row++) {
unsigned char *dest;
dest = bmp_rowptr_from_top(bmp, row);
for (col = 0; col < bmp->width;
col++, dest += ncomp - 1, p += ncomp)
memcpy(dest, p, ncomp - 1);
}
return (0);
}
static int reflowPage(lua_State *L) {
PdfPage *page = (PdfPage*) luaL_checkudata(L, 1, "pdfpage");
KOPTContext *kctx = (KOPTContext*) luaL_checkudata(L, 2, "koptcontext");
fz_device *dev;
fz_pixmap *pix;
fz_rect bounds,bounds2;
fz_matrix ctm;
fz_bbox bbox;
pix = NULL;
fz_var(pix);
bounds.x0 = kctx->bbox.x0;
bounds.y0 = kctx->bbox.y0;
bounds.x1 = kctx->bbox.x1;
bounds.y1 = kctx->bbox.y1;
double dpp,zoom;
zoom = kctx->zoom;
double dpi = 250*zoom*kctx->quality;
do {
dpp = dpi / 72.;
ctm = fz_scale(dpp, dpp);
// ctm=fz_concat(ctm,fz_rotate(rotation));
bounds2 = fz_transform_rect(ctm, bounds);
bbox = fz_round_rect(bounds2);
printf("reading page:%d,%d,%d,%d zoom:%.2f dpi:%.0f\n",bbox.x0,bbox.y0,bbox.x1,bbox.y1,zoom,dpi);
kctx->zoom = zoom;
zoom *= kctx->shrink_factor;
dpi *= kctx->shrink_factor;
} while (bbox.x1 > kctx->read_max_width | bbox.y1 > kctx->read_max_height);
pix = fz_new_pixmap_with_bbox(page->doc->context, fz_device_gray, bbox);
fz_clear_pixmap_with_value(page->doc->context, pix, 0xff);
dev = fz_new_draw_device(page->doc->context, pix);
#ifdef MUPDF_TRACE
fz_device *tdev;
fz_try(page->doc->context) {
tdev = fz_new_trace_device(page->doc->context);
fz_run_page(page->doc->xref, page->page, tdev, ctm, NULL);
}
fz_always(page->doc->context) {
fz_free_device(tdev);
}
#endif
fz_run_page(page->doc->xref, page->page, dev, ctm, NULL);
fz_free_device(dev);
WILLUSBITMAP *src = malloc(sizeof(WILLUSBITMAP));
bmp_init(src);
int status = bmpmupdf_pixmap_to_bmp(src, page->doc->context, pix);
fz_drop_pixmap(page->doc->context, pix);
kctx->src = src;
if (kctx->precache) {
pthread_t rf_thread;
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
pthread_create( &rf_thread, &attr, k2pdfopt_reflow_bmp, (void*) kctx);
pthread_attr_destroy(&attr);
} else {
k2pdfopt_reflow_bmp(kctx);
}
return 0;
}
static int drawReflowedPage(lua_State *L) {
PdfPage *page = (PdfPage*) luaL_checkudata(L, 1, "pdfpage");
KOPTContext *kc = (KOPTContext*) luaL_checkudata(L, 2, "koptcontext");
BlitBuffer *bb = (BlitBuffer*) luaL_checkudata(L, 3, "blitbuffer");
uint8_t *koptr = kc->data;
uint8_t *bbptr = bb->data;
int x_offset = 0;
int y_offset = 0;
bbptr += bb->pitch * y_offset;
int x, y;
for(y = y_offset; y < bb->h; y++) {
for(x = x_offset/2; x < (bb->w/2); x++) {
int p = x*2 - x_offset;
bbptr[x] = (((koptr[p + 1] & 0xF0) >> 4) | (koptr[p] & 0xF0)) ^ 0xFF;
}
bbptr += bb->pitch;
koptr += bb->w;
if (bb->w & 1) {
bbptr[x] = 255 - (koptr[x*2] & 0xF0);
}
}
return 0;
}
static int drawPage(lua_State *L) {
fz_pixmap *pix;
fz_device *dev;
@ -567,16 +713,69 @@ static int drawPage(lua_State *L) {
}
static int getCacheSize(lua_State *L) {
printf("## mupdf getCacheSize = %d\n", msize);
//printf("## mupdf getCacheSize = %zu\n", msize);
lua_pushnumber(L, msize);
return 1;
}
static int cleanCache(lua_State *L) {
printf("## mupdf cleanCache NOP\n");
//printf("## mupdf cleanCache NOP\n");
return 0;
}
static int getPageLinks(lua_State *L) {
fz_link *page_links;
fz_link *link;
int link_count;
PdfPage *page = (PdfPage*) luaL_checkudata(L, 1, "pdfpage");
page_links = fz_load_links(page->doc->xref, page->page); // page->doc->xref?
lua_newtable(L); // all links
link_count = 0;
for (link = page_links; link; link = link->next) {
lua_newtable(L); // new link
lua_pushstring(L, "x0");
lua_pushinteger(L, link->rect.x0);
lua_settable(L, -3);
lua_pushstring(L, "y0");
lua_pushinteger(L, link->rect.y0);
lua_settable(L, -3);
lua_pushstring(L, "x1");
lua_pushinteger(L, link->rect.x1);
lua_settable(L, -3);
lua_pushstring(L, "y1");
lua_pushinteger(L, link->rect.y1);
lua_settable(L, -3);
if (link->dest.kind == FZ_LINK_URI) {
lua_pushstring(L, "uri");
lua_pushstring(L, link->dest.ld.uri.uri);
lua_settable(L, -3);
} else if (link->dest.kind == FZ_LINK_GOTO) {
lua_pushstring(L, "page");
lua_pushinteger(L, link->dest.ld.gotor.page); // FIXME page+1?
lua_settable(L, -3);
} else {
printf("ERROR: unkown link kind: %x", link->dest.kind);
}
lua_rawseti(L, -2, ++link_count);
}
//printf("## getPageLinks found %d links in document\n", link_count);
fz_drop_link(page->doc->context, page_links);
return 1;
}
static const struct luaL_Reg pdf_func[] = {
{"openDocument", openDocument},
{NULL, NULL}
@ -599,8 +798,11 @@ static const struct luaL_Reg pdfpage_meth[] = {
{"getSize", getPageSize},
{"getUsedBBox", getUsedBBox},
{"getPageText", getPageText},
{"getPageLinks", getPageLinks},
{"close", closePage},
{"__gc", closePage},
{"reflow", reflowPage},
{"rfdraw", drawReflowedPage},
{"draw", drawPage},
{NULL, NULL}
};

@ -1,7 +1,9 @@
require "unireader"
require "inputbox"
PDFReader = UniReader:new{}
PDFReader = UniReader:new{
filename -- stores the absolute pathname of the open file
}
-- open a PDF file and its settings store
function PDFReader:open(filename)
@ -28,6 +30,7 @@ function PDFReader:open(filename)
self.doc = nil
return false, "damaged page tree"
end
self.filename = filename
return true
end
@ -41,7 +44,55 @@ function PDFReader:getText(pageno)
return nil
end
local text = page:getPageText()
--debug("## page:getPageText "..dump(text)) -- performance impact on device
--Debug("## page:getPageText "..dump(text)) -- performance impact on device
page:close()
return text
end
function PDFReader:getPageLinks(pageno)
local ok, page = pcall(self.doc.openPage, self.doc, pageno)
if not ok then
-- TODO: error handling
return nil
end
local links = page:getPageLinks()
Debug("## page:getPageLinks ", links)
page:close()
return links
end
function PDFReader:init()
self:addAllCommands()
self:adjustCommands()
end
function PDFReader:adjustCommands()
self.commands:add(KEY_S, MOD_ALT, "S",
"save all attachments on this page",
function(self)
self:saveAttachments()
end)
end
-- saves all attachments on the current page in the same directory
-- as the file itself (see extr.c utility)
function PDFReader:saveAttachments()
InfoMessage:inform("Saving attachments...", DINFO_NODELAY, 1, MSG_AUX)
local p = io.popen('./extr "'..self.filename..'" '..tostring(self.pageno), "r")
local count = p:read("*a")
p:close()
if count ~= "" then
-- double braces are needed because string.gsub() returns more than one value
count = tonumber((string.gsub(count, "[\n\r]+", "")))
if count == 0 then
InfoMessage:inform("No attachments found ", DINFO_DELAY, 1, MSG_WARN)
else
InfoMessage:inform(count.." attachment"..(count > 1 and "s" or "").." saved ",
DINFO_DELAY, 1, MSG_AUX)
end
else
InfoMessage:inform("Failed to save attachments ", DINFO_DELAY, 1, MSG_WARN)
end
-- needed because of inform(..DINFO_NODELAY..) above
self:redrawCurrentPage()
end

280
pic.c

@ -0,0 +1,280 @@
/*
KindlePDFViewer: Picture viewer abstraction for Lua
Copyright (C) 2012 Tigran Aivazian <tigran@bibles.org.uk>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <math.h>
#include "blitbuffer.h"
#include "drawcontext.h"
#include "pic.h"
#include "pic_jpeg.h"
#define MIN(a, b) ((a) < (b) ? (a) : (b))
#define MAX(a, b) ((a) > (b) ? (a) : (b))
typedef struct PicDocument {
int width;
int height;
int components;
uint8_t *image;
} PicDocument;
typedef struct PicPage {
int width;
int height;
uint8_t *image;
PicDocument *doc;
} PicPage;
/* Uses luminance match for approximating the human perception of colour,
* as per http://en.wikipedia.org/wiki/Grayscale#Converting_color_to_grayscale
* L = 0.299*Red + 0.587*Green + 0.114*Blue */
static uint8_t *rgbToGrayscale(uint8_t *image, int width, int height)
{
int x, y;
uint8_t *buf = malloc(width*height+1);
if (!buf) return NULL;
for (x=0; x<width; x++)
for (y=0; y<height; y++) {
int pos = 3*(x+y*width);
buf[x+y*width] = (uint8_t)(0.299*((double)image[pos]) + 0.587*((double)image[pos+1]) + 0.114*((double)image[pos+2]));
}
return buf;
}
static int openDocument(lua_State *L) {
int width, height, components;
const char *filename = luaL_checkstring(L, 1);
PicDocument *doc = (PicDocument*) lua_newuserdata(L, sizeof(PicDocument));
luaL_getmetatable(L, "picdocument");
lua_setmetatable(L, -2);
uint8_t *raw_image = jpegLoadFile(filename, &width, &height, &components);
if (!raw_image)
return luaL_error(L, "Cannot open jpeg file");
doc->image = NULL;
if (components == 1)
doc->image = raw_image;
else if (components == 3) {
uint8_t *gray_image = rgbToGrayscale(raw_image, width, height);
free(raw_image);
if (!gray_image)
return luaL_error(L, "Cannot convert to grayscale");
else
doc->image = gray_image;
} else {
free(raw_image);
return luaL_error(L, "Unsupported image format");
}
doc->width = width;
doc->height = height;
doc->components = components;
return 1;
}
static int openPage(lua_State *L) {
PicDocument *doc = (PicDocument*) luaL_checkudata(L, 1, "picdocument");
PicPage *page = (PicPage*) lua_newuserdata(L, sizeof(PicPage));
luaL_getmetatable(L, "picpage");
lua_setmetatable(L, -2);
page->width = doc->width;
page->height = doc->height;
page->image = doc->image;
page->doc = doc;
return 1;
}
static int getNumberOfPages(lua_State *L) {
lua_pushinteger(L, 1);
return 1;
}
static int getOriginalPageSize(lua_State *L) {
PicDocument *doc = (PicDocument*) luaL_checkudata(L, 1, "picdocument");
lua_pushnumber(L, doc->width);
lua_pushnumber(L, doc->height);
lua_pushnumber(L, doc->components);
return 3;
}
/* re-entrant */
static int closeDocument(lua_State *L) {
PicDocument *doc = (PicDocument*) luaL_checkudata(L, 1, "picdocument");
if (doc->image != NULL) {
free(doc->image);
doc->image = NULL;
}
return 0;
}
/* uses very simple nearest neighbour scaling */
static void scaleImage(uint8_t *result, uint8_t *image, int width, int height, int new_width, int new_height)
{
int x, y;
for (x=0; x<new_width; x++)
for (y=0; y<new_height; y++)
result[x+y*new_width] = image[(x*width/new_width) + (y*height/new_height)*width];
}
static int drawPage(lua_State *L) {
PicPage *page = (PicPage*) luaL_checkudata(L, 1, "picpage");
DrawContext *dc = (DrawContext*) luaL_checkudata(L, 2, "drawcontext");
BlitBuffer *bb = (BlitBuffer*) luaL_checkudata(L, 3, "blitbuffer");
int x_offset = MAX(0, dc->offset_x);
int y_offset = MAX(0, dc->offset_y);
int x, y;
int img_width = page->width;
int img_height = page->height;
int img_new_width = bb->w;
int img_new_height = bb->h;
unsigned char adjusted_low[16], adjusted_high[16];
int i, adjust_pixels = 0;
/* prepare the tables for adjusting the intensity of pixels */
if (dc->gamma != -1.0) {
for (i=0; i<16; i++) {
adjusted_low[i] = MIN(15, (unsigned char)floorf(dc->gamma * (float)i));
adjusted_high[i] = adjusted_low[i] << 4;
}
adjust_pixels = 1;
}
uint8_t *scaled_image = malloc(img_new_width*img_new_height+1);
if (!scaled_image)
return 0;
scaleImage(scaled_image, page->image, img_width, img_height, img_new_width, img_new_height);
uint8_t *bbptr = bb->data;
uint8_t *pmptr = scaled_image;
bbptr += bb->pitch * y_offset;
for(y = y_offset; y < img_new_height; y++) {
for(x = x_offset/2; x < (img_new_width / 2); x++) {
int p = x*2 - x_offset;
unsigned char low = 15 - (pmptr[p + 1] >> 4);
unsigned char high = 15 - (pmptr[p] >> 4);
if (adjust_pixels)
bbptr[x] = adjusted_high[high] | adjusted_low[low];
else
bbptr[x] = (high << 4) | low;
}
if (img_new_width & 1)
bbptr[x] = 255 - (pmptr[x*2] & 0xF0);
bbptr += bb->pitch;
pmptr += img_new_width;
}
free(scaled_image);
return 0;
}
static int getCacheSize(lua_State *L) {
lua_pushnumber(L, 0);
return 1;
}
static int cleanCache(lua_State *L) {
return 0;
}
static int getPageSize(lua_State *L) {
PicPage *page = (PicPage*) luaL_checkudata(L, 1, "picpage");
DrawContext *dc = (DrawContext*) luaL_checkudata(L, 2, "drawcontext");
lua_pushnumber(L, dc->zoom * page->width);
lua_pushnumber(L, dc->zoom * page->height);
return 2;
}
static int closePage(lua_State *L) {
return 0;
}
/* unsupported so fake it */
static int getUsedBBox(lua_State *L) {
lua_pushnumber(L, (double)0.01);
lua_pushnumber(L, (double)0.01);
lua_pushnumber(L, (double)-0.01);
lua_pushnumber(L, (double)-0.01);
return 4;
}
static int getTableOfContent(lua_State *L) {
lua_newtable(L);
return 1;
}
static const struct luaL_Reg pic_func[] = {
{"openDocument", openDocument},
{NULL, NULL}
};
static const struct luaL_Reg picdocument_meth[] = {
{"openPage", openPage},
{"getPages", getNumberOfPages},
{"getToc", getTableOfContent},
{"getOriginalPageSize", getOriginalPageSize},
{"getCacheSize", getCacheSize},
{"close", closeDocument},
{"cleanCache", cleanCache},
{"__gc", closeDocument},
{NULL, NULL}
};
static const struct luaL_Reg picpage_meth[] = {
{"getSize", getPageSize},
{"getUsedBBox", getUsedBBox},
{"close", closePage},
{"__gc", closePage},
{"draw", drawPage},
{NULL, NULL}
};
int luaopen_pic(lua_State *L) {
luaL_newmetatable(L, "picdocument");
lua_pushstring(L, "__index");
lua_pushvalue(L, -2);
lua_settable(L, -3);
luaL_register(L, NULL, picdocument_meth);
lua_pop(L, 1);
luaL_newmetatable(L, "picpage");
lua_pushstring(L, "__index");
lua_pushvalue(L, -2);
lua_settable(L, -3);
luaL_register(L, NULL, picpage_meth);
lua_pop(L, 1);
luaL_register(L, "pic", pic_func);
return 1;
}

27
pic.h

@ -0,0 +1,27 @@
/*
KindlePDFViewer: JPEG Picture viewer abstraction for Lua
Copyright (C) 2012 Tigran Aivazian <tigran@bibles.org.uk>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _PIC_H
#define _PIC_H
#include <lua.h>
#include <lualib.h>
#include <lauxlib.h>
int luaopen_pic(lua_State *L);
#endif

@ -0,0 +1,84 @@
/*
KindlePDFViewer: JPEG support for Picture Viewer module
Copyright (C) 2012 Tigran Aivazian <tigran@bibles.org.uk>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdint.h>
#include <string.h>
#include <setjmp.h>
#include <stdio.h>
#include "jpeglib.h"
struct my_error_mgr {
struct jpeg_error_mgr pub;
jmp_buf setjmp_buffer;
};
typedef struct my_error_mgr *my_error_ptr;
METHODDEF(void) my_error_exit(j_common_ptr cinfo)
{
my_error_ptr myerr = (my_error_ptr) cinfo->err;
(*cinfo->err->output_message) (cinfo);
longjmp(myerr->setjmp_buffer, 1);
}
uint8_t *jpegLoadFile(const char *fname, int *width, int *height, int *components)
{
struct jpeg_decompress_struct cinfo;
struct my_error_mgr jerr;
FILE *infile;
JSAMPARRAY buffer;
int row_stride;
long cont;
JSAMPLE *image_buffer;
if ((infile = fopen(fname, "r")) == NULL) return NULL;
cinfo.err = jpeg_std_error(&jerr.pub);
jerr.pub.error_exit = my_error_exit;
if (setjmp(jerr.setjmp_buffer)) {
jpeg_destroy_decompress(&cinfo);
fclose(infile);
return NULL;
}
jpeg_create_decompress(&cinfo);
jpeg_stdio_src(&cinfo, infile);
(void) jpeg_read_header(&cinfo, TRUE);
(void) jpeg_start_decompress(&cinfo);
row_stride = cinfo.output_width * cinfo.output_components;
buffer = (*cinfo.mem->alloc_sarray)
((j_common_ptr) & cinfo, JPOOL_IMAGE, row_stride, 1);
image_buffer = (JSAMPLE *) malloc(cinfo.image_width*cinfo.image_height*cinfo.output_components);
if (image_buffer == NULL) return NULL;
*width = cinfo.image_width;
*height = cinfo.image_height;
//cont = cinfo.output_height - 1;
cont = 0;
while (cinfo.output_scanline < cinfo.output_height) {
(void) jpeg_read_scanlines(&cinfo, buffer, 1);
memcpy(image_buffer + cinfo.image_width * cinfo.output_components * cont, buffer[0], row_stride);
cont++;
}
(void) jpeg_finish_decompress(&cinfo);
jpeg_destroy_decompress(&cinfo);
fclose(infile);
*components = cinfo.output_components;
return (uint8_t *)image_buffer;
}

@ -0,0 +1,30 @@
/*
KindlePDFViewer: Interface to JPEG module for picture viewer
Copyright (C) 2012 Tigran Aivazian <tigran@bibles.org.uk>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _PIC_JPEG_H
#define _PIC_JPEG_H
/* each new image format must provide fmtLoadFile() function which
* performs the following:
* 1. Opens the file 'filename'
* 2. Reads the image data from it into a buffer allocated with malloc()
* 3. Fills in the image *width, *height and *components (number of bytes per pixel)
* 4. Closes the file
* 5. Returns the pointer to the image data
*/
extern uint8_t *jpegLoadFile(const char *fname, int *width, int *height, int *components);
#endif

@ -0,0 +1,69 @@
require "unireader"
PICViewer = UniReader:new{}
function PICViewer:setDefaults()
self.show_overlap_enable = DPICVIEWER_SHOW_OVERLAP_ENABLE
self.show_links_enable = DPICVIEWER_SHOW_LINKS_ENABLE
self.comics_mode_enable = DPICVIEWER_COMICS_MODE_ENABLE
self.rtl_mode_enable = DPICVIEWER_RTL_MODE_ENABLE
self.page_mode_enable = DPICVIEWER_PAGE_MODE_ENABLE
end
function PICViewer:open(filename)
ok, self.doc = pcall(pic.openDocument, filename)
if not ok then
return ok, self.doc
end
return ok
end
function PICViewer:_drawReadingInfo()
local width = G_width
local face = Font:getFace("rifont", 20)
local rss, data, stack, lib, totalvm = memUsage()
local page_width, page_height, page_components = self.doc:getOriginalPageSize()
-- display memory, time, battery and image info on top of page
fb.bb:paintRect(0, 0, width, 60+6*2, 0)
renderUtf8Text(fb.bb, 10, 15+6, face,
"M: "..
math.ceil( self.cache_current_memsize / 1024 ).."/"..math.ceil( self.cache_max_memsize / 1024 ).."k", true)
local txt = os.date("%a %d %b %Y %T").." ["..BatteryLevel().."]"
local w = sizeUtf8Text(0, width, face, txt, true).x
renderUtf8Text(fb.bb, width - w - 10, 15+6, face, txt, true)
renderUtf8Text(fb.bb, 10, 15+6+22, face,
"Gm:"..string.format("%.1f",self.globalgamma)..", "..
tostring(page_width).."x"..tostring(page_height).."x"..tostring(page_components)..
" ("..tostring(math.ceil(page_width*page_height*page_components/1024)).."k), "..
string.format("%.1fx", self.globalzoom), true)
renderUtf8Text(fb.bb, 10, 15+6+44, face,
"RSS:"..rss.." DAT:"..data.." STK:"..stack.." LIB:"..lib.." TOT:"..totalvm.."k", true)
end
function PICViewer:init()
self:addAllCommands()
self:adjustCommands()
end
function PICViewer:adjustCommands()
self.commands:del(KEY_G, nil, "G")
self.commands:del(KEY_T, nil, "T")
self.commands:del(KEY_B, nil, "B")
self.commands:del(KEY_B, MOD_ALT, "B")
self.commands:del(KEY_B, MOD_SHIFT, "B")
self.commands:del(KEY_R, MOD_SHIFT, "R")
self.commands:del(KEY_DOT, nil, ".")
self.commands:del(KEY_N, nil, "N")
self.commands:del(KEY_L, nil, "L")
self.commands:del(KEY_L, MOD_SHIFT, "L")
self.commands:del(KEY_N, MOD_SHIFT, "N")
self.commands:del(KEY_J, MOD_SHIFT,"J")
self.commands:del(KEY_K, MOD_SHIFT,"K")
self.commands:del(KEY_BACK, nil,"Back")
self.commands:del(KEY_BACK, MOD_SHIFT,"Back")
self.commands:delGroup("[1, 2 .. 9, 0]")
self.commands:delGroup(MOD_ALT.."H/J")
self.commands:delGroup(MOD_ALT.."K/L")
self.commands:del(KEY_P, nil, "P")
end

@ -0,0 +1,86 @@
Index: CREDITS
===================================================================
--- CREDITS (revision 0)
+++ CREDITS (working copy)
@@ -0,0 +1 @@
+Taken from http://code.google.com/p/popen-noshell/
Property changes on: CREDITS
___________________________________________________________________
Added: svn:keywords
## -0,0 +1 ##
+Id
\ No newline at end of property
Index: Makefile
===================================================================
--- Makefile (revision 0)
+++ Makefile (working copy)
@@ -0,0 +1,17 @@
+SRCS=popen_noshell.c
+
+OBJS:=$(SRCS:%.c=%.o)
+
+%.o: %.c
+ $(CC) $(CPPFLAGS) $(CFLAGS) -o $@ -c $<
+
+all: libpopen_noshell.a
+
+libpopen_noshell.a: $(OBJS)
+ $(AR) rcs $@ $(OBJS)
+
+clean:
+ rm -rf *.o
+ rm -rf libpopen_noshell.a
+
+.PHONY: clean
Property changes on: Makefile
___________________________________________________________________
Added: svn:keywords
## -0,0 +1 ##
+Id
\ No newline at end of property
Index: popen_noshell.c
===================================================================
--- popen_noshell.c (revision 8)
+++ popen_noshell.c (working copy)
@@ -16,6 +16,10 @@
* along with this program. If not, see <http://www.gnu.org/licenses>.
*/
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE
+#endif
+
#include "popen_noshell.h"
#include <errno.h>
#include <unistd.h>
@@ -28,10 +32,6 @@
#include <sys/wait.h>
#include <stdlib.h>
#include <inttypes.h>
-
-#ifndef _GNU_SOURCE
-#define _GNU_SOURCE
-#endif
#include <sched.h>
/*
@@ -249,7 +249,7 @@
* The above malloc() + align implementation is taken from:
* http://stackoverflow.com/questions/227897/solve-the-memory-alignment-in-c-interview-question-that-stumped-me
*/
-
+
#ifndef POPEN_NOSHELL_VALGRIND_DEBUG
pid = clone(fn, stack_aligned, CLONE_VM | SIGCHLD, arg);
#else
@@ -358,7 +358,7 @@
pclose_arg->fp = fp;
pclose_arg->pid = pid;
-
+
return fp; // we should never end up here
}

@ -16,50 +16,38 @@
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
]]--
require "alt_getopt"
require "pdfreader"
require "djvureader"
require "koptreader"
require "picviewer"
require "crereader"
require "filechooser"
require "settings"
require "screen"
require "keys"
require "commands"
require "dialog"
-- option parsing:
longopts = {
password = "p",
goto = "g",
gamma = "G",
debug = "d",
help = "h"
}
require "readerchooser"
require "defaults"
function openFile(filename)
local file_type = string.lower(string.match(filename, ".+%.([^.]+)"))
local reader = nil
if file_type == "djvu" then
reader = DJVUReader
elseif file_type == "pdf" or file_type == "xps" or file_type == "cbz" then
reader = PDFReader
elseif file_type == "epub" or file_type == "txt" or file_type == "rtf" or file_type == "htm" or file_type == "html" or file_type == "fb2" or file_type == "chm" or file_type == "mobi" or file_type == "doc" or file_type == "zip" then
reader = CREReader
end
local reader = ReaderChooser:getReaderByName(filename)
if reader then
InfoMessage:show("Opening document, please wait... ", 0)
InfoMessage:inform("Opening document... ", DINFO_NODELAY, 0, MSG_AUX)
reader:preLoadSettings(filename)
local ok, err = reader:open(filename)
if ok then
reader:loadSettings(filename)
page_num = reader:getLastPageOrPos()
reader:goto(tonumber(page_num), true)
reader_settings:saveSetting("lastfile", filename)
G_reader_settings:saveSetting("lastfile", filename)
return reader:inputLoop()
else
InfoMessage:show("Error opening document.", 0)
util.sleep(2)
if err then
Debug("openFile(): "..err)
InfoMessage:inform(err:sub(1,30), DINFO_DELAY, 1, MSG_ERROR)
else
InfoMessage:inform("Error opening document ", DINFO_DELAY, 1, MSG_ERROR)
end
end
end
return true -- on failed attempts, we signal to keep running
@ -67,11 +55,8 @@ end
function showusage()
print("usage: ./reader.lua [OPTION] ... path")
print("Read PDFs and DJVUs on your E-Ink reader")
print("Read PDF/DjVu/ePub/MOBI/FB2/CHM/HTML/TXT/DOC/RTF/JPEG on your E-Ink reader")
print("")
print("-p, --password=PASSWORD set password for reading PDF document")
print("-g, --goto=page start reading on page")
print("-G, --gamma=GAMMA set gamma correction")
print("-d, --debug start in debug mode")
print(" (floating point notation, e.g. \"1.5\")")
print("-h, --help show this usage help")
@ -86,17 +71,26 @@ function showusage()
return
end
optarg, optind = alt_getopt.get_opts(ARGV, "p:g:G:hg:dg:", longopts)
if optarg["h"] then
if ARGV[1] == "-h" then
return showusage()
end
if not optarg["d"] then
local argidx = 1
if ARGV[1] == "-d" then
argidx = argidx + 1
else
Debug = function() end
dump = function() end
debug = function() end
end
if optarg["G"] ~= nil then
globalgamma = optarg["G"]
local vfile = io.open("git-rev", "r")
if vfile then
G_program_version = vfile:read("*a") or "?"
G_program_version = G_program_version:gsub("[\n\r]+", "")
vfile.close()
else
G_program_version = "(unknown version)"
end
if util.isEmulated()==1 then
@ -109,64 +103,72 @@ else
input.open("/dev/input/event1")
-- check if we are running on Kindle 3 (additional volume input)
local f=lfs.attributes("/dev/input/event2")
if f then
print("Auto-detected Kindle 3")
if FileExists("/dev/input/event2") then
Debug("Auto-detected Kindle 3")
input.open("/dev/input/event2")
setK3Keycodes()
end
end
G_screen_saver_mode = false
G_charging_mode = false
fb = einkfb.open("/dev/fb0")
G_width, G_height = fb:getSize()
-- read current rotation mode
Screen:updateRotationMode()
Screen.native_rotation_mode = Screen.cur_rotation_mode
-- force portrait mode
Screen:setRotationMode(0)
-- set up reader's setting: font
reader_settings = DocSettings:open(".reader")
fontmap = reader_settings:readSetting("fontmap")
G_reader_settings = DocSettings:open(".reader")
fontmap = G_reader_settings:readSetting("fontmap")
if fontmap ~= nil then
Font.fontmap = fontmap
-- we need to iterate over all fonts used in reader to support upgrade from older configuration
for name,path in pairs(fontmap) do
if Font.fontmap[name] then
Font.fontmap[name] = path
else
Debug("missing "..name.." in user configuration, using default font "..path)
end
end
end
-- set up the mode to manage files
FileChooser.filemanager_expert_mode = G_reader_settings:readSetting("filemanager_expert_mode") or 1
InfoMessage:initInfoMessageSettings()
local tmp = G_reader_settings:readSetting("G_battery_logging")
if tmp ~= nil then
G_battery_logging = tmp
else
G_battery_logging = DBATTERY_LOGGING
end
-- initialize global settings shared among all readers
UniReader:initGlobalSettings(reader_settings)
-- initialize specific readers
UniReader:initGlobalSettings(G_reader_settings)
PDFReader:init()
DJVUReader:init()
KOPTReader:init()
PICViewer:init()
CREReader:init()
-- display directory or open file
local patharg = reader_settings:readSetting("lastfile")
if ARGV[optind] and lfs.attributes(ARGV[optind], "mode") == "directory" then
local running = true
FileChooser:setPath(ARGV[optind])
while running do
local file, callback = FileChooser:choose(0, G_height)
if callback then
callback()
else
if file ~= nil then
running = openFile(file)
print(file)
else
running = false
end
end
end
elseif ARGV[optind] and lfs.attributes(ARGV[optind], "mode") == "file" then
openFile(ARGV[optind], optarg["p"])
local patharg = G_reader_settings:readSetting("lastfile")
if ARGV[argidx] and lfs.attributes(ARGV[argidx], "mode") == "directory" then
FileChooser:setPath(ARGV[argidx])
FileChooser:choose()
elseif ARGV[argidx] and lfs.attributes(ARGV[argidx], "mode") == "file" then
openFile(ARGV[argidx])
elseif patharg and lfs.attributes(patharg, "mode") == "file" then
openFile(patharg, optarg["p"])
openFile(patharg)
else
return showusage()
end
-- save reader settings
reader_settings:saveSetting("fontmap", Font.fontmap)
reader_settings:close()
G_reader_settings:saveSetting("fontmap", Font.fontmap)
InfoMessage:saveInfoMessageSettings()
G_reader_settings:close()
-- @TODO dirty workaround, find a way to force native system poll
-- screen orientation and upside down mode 09.03 2012

@ -0,0 +1,306 @@
require "font"
require "keys"
require "settings"
require "screen"
require "pdfreader"
require "djvureader"
require "koptreader"
require "picviewer"
require "crereader"
require "defaults"
registry = {
-- registry format:
-- reader_name = {reader_object, supported_formats, priority}
PDFReader = {PDFReader, DPDFREADER_EXT, 1},
DJVUReader = {DJVUReader, DDJVUREADER_EXT, 1},
PDFReflow = {KOPTReader, DPDFREFLOW_EXT, 2},
DJVUReflow = {KOPTReader, DDJVUREFLOW_EXT, 2},
CREReader = {CREReader, DCREREADER_EXT, 2},
PICViewer = {PICViewer, DPICVIEWER_EXT, 1},
}
ReaderChooser = {
-- UI constants
title_H = 35, -- title height
title_bar_H = 15, -- title bar height
options_H = 35, -- options height
options_bar_T = 2, -- options bar thickness
spacing = 35, -- spacing between lines
WIDTH = 380, -- window width
HEIGHT = 220, -- window height
margin_I = 50, -- reader item margin
margin_O = 10, -- option margin
title_font_size = 23, -- title font size
item_font_size = 20, -- reader item font size
option_font_size = 17, -- option font size
-- title text
TITLE = "Complete action using",
-- options text
OPTION_TYPE = "Remember this type(T)",
OPTION_FILE = "Remember this file(F)",
-- data variables
readers = {},
final_choice = nil,
last_item = 0,
current_item = 1,
-- state variables
dialogdirty = true,
markerdirty = false,
optiondirty = true,
remember_preference = false,
remember_association = false,
}
function GetRegisteredReaders(ftype)
local s = ";"
local readers = {}
for key,value in pairs(registry) do
if string.find(value[2],s..ftype..s) then
table.insert(readers,key)
end
end
table.sort(readers, function(a,b) return registry[a][3]<registry[b][3] end)
return readers
end
-- find the first reader registered with this file type
function ReaderChooser:getReaderByType(ftype)
local readers = GetRegisteredReaders(ftype)
if #readers >= 1 then
return registry[readers[1]][1]
else
if FileChooser.filemanager_expert_mode > FileChooser.BEGINNERS_MODE then
return CREReader
else
return nil
end
end
end
function ReaderChooser:getReaderByName(filename)
local ext = string.match(filename, ".+%.([^.]+)")
local file_type = ext and ext:lower() or "txt"
local readers = GetRegisteredReaders(file_type)
if #readers > 1 then -- more than one reader are registered with this file type
local file_settings = DocSettings:open(filename)
local reader_association = file_settings:readSetting("reader_association")
local reader_preferences = G_reader_settings:readSetting("reader_preferences")
Debug("Reading saved association:", reader_association)
if reader_association and reader_association ~= "N/A" then
file_settings:close()
return registry[reader_association][1]
elseif reader_preferences and reader_association ~= "N/A" then
default_reader = reader_preferences[file_type]
if default_reader then
return registry[default_reader][1]
end
end
-- need to choose reader
Screen:saveCurrentBB()
local name = self:choose(readers)
if name then
if self.remember_preference then
if not reader_preferences then
reader_preferences = {}
end
reader_preferences[file_type] = name
G_reader_settings:saveSetting("reader_preferences", reader_preferences)
file_settings:delSetting("reader_association") --override reader association
end
if self.remember_association then
Debug("Saving last reader:", name)
file_settings:saveSetting("reader_association", name)
end
file_settings:close()
Screen:restoreFromSavedBB()
return registry[name][1]
else
file_settings:close()
return nil
end
elseif #readers == 1 then
return registry[readers[1]][1]
else
if FileChooser.filemanager_expert_mode > FileChooser.BEGINNERS_MODE then
return CREReader
else
return nil
end
end
end
function ReaderChooser:drawBox(xpos, ypos, w, h, bgcolor, bdcolor)
-- draw dialog border
local r = 6 -- round corners
fb.bb:paintRect(xpos, ypos+r, w, h - r, bgcolor)
blitbuffer.paintBorder(fb.bb, xpos, ypos, w, r, r, bdcolor, r)
blitbuffer.paintBorder(fb.bb, xpos+2, ypos + 2, w - 4, r, r, bdcolor, r)
end
function ReaderChooser:drawTitle(text, xpos, ypos, w, font_face)
-- draw title text
renderUtf8Text(fb.bb, xpos+10, ypos+self.title_H, font_face, text, true)
-- draw title bar
fb.bb:paintRect(xpos, ypos+self.title_H+self.title_bar_H, w, 3, 5)
end
function ReaderChooser:drawReaderItem(name, xpos, ypos, font_face)
-- draw reader name
renderUtf8Text(fb.bb, xpos+self.margin_I, ypos, font_face, name, true)
return sizeUtf8Text(0, G_width, font_face, name, true).x
end
function ReaderChooser:drawOptions(xpos, ypos, barcolor, bgcolor, font_face)
local width, height = self.WIDTH, self.HEIGHT
local optbar_T = self.options_bar_T
-- draw option border
fb.bb:paintRect(xpos, ypos, width, optbar_T, barcolor)
fb.bb:paintRect(xpos+(width-optbar_T)/2, ypos, optbar_T, self.options_H, barcolor)
-- draw option cell
fb.bb:paintRect(xpos, ypos+optbar_T, (width-optbar_T)/2, self.options_H-optbar_T, bgcolor+3*(self.remember_preference and 1 or 0))
fb.bb:paintRect(xpos+(width+optbar_T)/2, ypos+optbar_T, (width-optbar_T)/2, self.options_H-optbar_T, bgcolor+3*(self.remember_association and 1 or 0))
-- draw option text
renderUtf8Text(fb.bb, xpos+self.margin_O, ypos+self.options_H/2+8, font_face, self.OPTION_TYPE, true)
renderUtf8Text(fb.bb, xpos+width/2+self.margin_O, ypos+self.options_H/2+8, font_face, self.OPTION_FILE, true)
fb:refresh(1, xpos, ypos, width, self.options_H-optbar_T)
end
function ReaderChooser:choose(readers)
self.readers = {}
self.final_choice = nil
self.readers = readers
self.dialogdirty = true
self.markerdirty = false
self.optiondirty = true
self:addAllCommands()
local tface = Font:getFace("tfont", self.title_font_size)
local cface = Font:getFace("cfont", self.item_font_size)
local fface = Font:getFace("ffont", self.option_font_size)
local width, height = self.WIDTH, self.HEIGHT
local topleft_x, topleft_y = (fb.bb:getWidth()-width)/2, (fb.bb:getHeight()-height)/2
local botleft_x, botleft_y = topleft_x, topleft_y+height
Debug("Drawing box")
self:drawBox(topleft_x, topleft_y, width, height, 3, 3)
Debug("Drawing title")
self:drawTitle(self.TITLE, topleft_x, topleft_y, width, tface)
local reader_text_width = {}
for index,name in ipairs(self.readers) do
Debug("Drawing reader:",index,name)
reader_text_width[index] = self:drawReaderItem(name, topleft_x, topleft_y+self.title_H+self.spacing*index+10, cface)
end
fb:refresh(1, topleft_x, topleft_y, width, height)
-- paint first reader marker
local xmarker = topleft_x + self.margin_I
local ymarker = topleft_y + self.title_H + self.title_bar_H
fb.bb:paintRect(xmarker, ymarker+self.spacing*self.current_item, reader_text_width[self.current_item], 3, 15)
fb:refresh(1, xmarker, ymarker+self.spacing*self.current_item, reader_text_width[self.current_item], 3)
local ev, keydef, command, ret_code
while true do
if self.markerdirty then
fb.bb:paintRect(xmarker, ymarker+self.spacing*self.last_item, reader_text_width[self.last_item], 3, 3)
fb:refresh(1, xmarker, ymarker+self.spacing*self.last_item, reader_text_width[self.last_item], 3)
fb.bb:paintRect(xmarker, ymarker+self.spacing*self.current_item, reader_text_width[self.current_item], 3, 15)
fb:refresh(1, xmarker, ymarker+self.spacing*self.current_item, reader_text_width[self.current_item], 3)
self.markerdirty = false
end
if self.optiondirty then
self:drawOptions(botleft_x, botleft_y-self.options_H, 5, 3, fface)
self.optiondirty = false
end
ev = input.saveWaitForEvent()
ev.code = adjustKeyEvents(ev)
if ev.type == EV_KEY and ev.value ~= EVENT_VALUE_KEY_RELEASE then
keydef = Keydef:new(ev.code, getKeyModifier())
Debug("key pressed: "..tostring(keydef))
command = self.commands:getByKeydef(keydef)
if command ~= nil then
Debug("command to execute: "..tostring(command))
ret_code = command.func(self, keydef)
else
Debug("command not found: "..tostring(command))
end
if ret_code == "break" then
ret_code = nil
if self.final_choice then
return self.readers[self.final_choice]
else
return nil
end
end
end -- if
end -- while
end
-- add available commands
function ReaderChooser:addAllCommands()
self.commands = Commands:new{}
self.commands:add(KEY_FW_DOWN, nil, "joypad down",
"next item",
function(self)
self.last_item = self.current_item
self.current_item = (self.current_item + #self.readers + 1)%#self.readers
if self.current_item == 0 then
self.current_item = self.current_item + #self.readers
end
Debug("Last item:", self.last_item, "Current item:", self.current_item, "N items:", #self.readers)
self.markerdirty = true
end
)
self.commands:add(KEY_FW_UP, nil, "joypad up",
"previous item",
function(self)
self.last_item = self.current_item
self.current_item = (self.current_item + #self.readers - 1)%#self.readers
if self.current_item == 0 then
self.current_item = self.current_item + #self.readers
end
Debug("Last item:", self.last_item, "Current item:", self.current_item, "N items:", #self.readers)
self.markerdirty = true
end
)
self.commands:add(KEY_T, nil, "T",
"remember reader choice for this type",
function(self)
self.remember_preference = not self.remember_preference
self.optiondirty = true
end
)
self.commands:add(KEY_F, nil, "F",
"remember reader choice for this file",
function(self)
self.remember_association = not self.remember_association
self.optiondirty = true
end
)
self.commands:add({KEY_ENTER, KEY_FW_PRESS}, nil, "Enter",
"choose reader",
function(self)
self.final_choice = self.current_item
return "break"
end
)
self.commands:add(KEY_BACK, nil, "Back",
"back",
function(self)
return "break"
end
)
end

@ -1,12 +1,14 @@
glyphcache_max_memsize = 256*1024 -- 256kB glyphcache
glyphcache_current_memsize = 0
glyphcache = {}
glyphcache_max_age = 4096
glyphcache_max_age = 4
function glyphCacheClaim(size)
if(size > glyphcache_max_memsize) then
error("too much memory claimed")
return false
end
while glyphcache_current_memsize + size > glyphcache_max_memsize do
for k, _ in pairs(glyphcache) do
if glyphcache[k].age > 0 then
@ -15,14 +17,18 @@ function glyphCacheClaim(size)
glyphcache_current_memsize = glyphcache_current_memsize - glyphcache[k].size
glyphcache[k].glyph.bb:free()
glyphcache[k] = nil
break -- leave loop and check again if we have enough free space now
end
end
end
glyphcache_current_memsize = glyphcache_current_memsize + size
return true
end
function getGlyph(face, charcode)
local hash = glyphCacheHash(face.hash, charcode)
if glyphcache[hash] == nil then
local glyph = face.ftface:renderGlyph(charcode)
local size = glyph.bb:getWidth() * glyph.bb:getHeight() / 2 + 32
@ -30,25 +36,30 @@ function getGlyph(face, charcode)
glyphcache[hash] = {
age = glyphcache_max_age,
size = size,
g = glyph
glyph = glyph
}
else
glyphcache[hash].age = glyphcache_max_age
end
return glyphcache[hash].g
return glyphcache[hash].glyph
end
function glyphCacheHash(face, charcode)
return face..'_'..charcode;
end
function clearGlyphCache()
glyphcache = {}
glyphcache_current_memsize = 0
end
function sizeUtf8Text(x, width, face, text, kerning)
if text == nil then
debug("sizeUtf8Text called without text");
if not text then
Debug("sizeUtf8Text called without text");
return
end
-- may still need more adaptive pen placement when kerning,
-- see: http://freetype.org/freetype2/docs/glyphs/glyphs-4.html
local pen_x = 0
@ -59,48 +70,118 @@ function sizeUtf8Text(x, width, face, text, kerning)
if pen_x < (width - x) then
local charcode = util.utf8charcode(uchar)
local glyph = getGlyph(face, charcode)
if kerning and prevcharcode then
local kern = face.ftface:getKerning(prevcharcode, charcode)
pen_x = pen_x + kern
--debug("prev:"..string.char(prevcharcode).." curr:"..string.char(charcode).." kern:"..kern)
else
--debug("curr:"..string.char(charcode))
if kerning and (prevcharcode ~= 0) then
pen_x = pen_x + face.ftface:getKerning(prevcharcode, charcode)
end
pen_x = pen_x + glyph.ax
pen_y_top = math.max(pen_y_top, glyph.t)
pen_y_bottom = math.max(pen_y_bottom, glyph.bb:getHeight() - glyph.t)
--debug("ax:"..glyph.ax.." t:"..glyph.t.." r:"..glyph.r.." h:"..glyph.bb:getHeight().." w:"..glyph.bb:getWidth().." yt:"..pen_y_top.." yb:"..pen_y_bottom)
--Debug("ax:"..glyph.ax.." t:"..glyph.t.." r:"..glyph.r.." h:"..glyph.bb:getHeight().." w:"..glyph.bb:getWidth().." yt:"..pen_y_top.." yb:"..pen_y_bottom)
prevcharcode = charcode
end
end
end -- if pen_x < (width -x)
end -- for uchar
return { x = pen_x, y_top = pen_y_top, y_bottom = pen_y_bottom}
end
function renderUtf8Text(buffer, x, y, face, text, kerning)
if text == nil then
debug("renderUtf8Text called without text");
if not text then
Debug("renderUtf8Text called without text");
return 0
end
-- may still need more adaptive pen placement when kerning,
-- see: http://freetype.org/freetype2/docs/glyphs/glyphs-4.html
local pen_x = 0
local prevcharcode = 0
local buffer_width = buffer:getWidth()
for uchar in string.gfind(text, "([%z\1-\127\194-\244][\128-\191]*)") do
if pen_x < buffer:getWidth() then
if pen_x < buffer_width then
local charcode = util.utf8charcode(uchar)
local glyph = getGlyph(face, charcode)
if kerning and prevcharcode then
local kern = face.ftface:getKerning(prevcharcode, charcode)
pen_x = pen_x + kern
--debug("prev:"..string.char(prevcharcode).." curr:"..string.char(charcode).." pen_x:"..pen_x.." kern:"..kern)
buffer:addblitFrom(glyph.bb, x + pen_x + glyph.l, y - glyph.t, 0, 0, glyph.bb:getWidth(), glyph.bb:getHeight())
else
--debug(" curr:"..string.char(charcode))
buffer:blitFrom(glyph.bb, x + pen_x + glyph.l, y - glyph.t, 0, 0, glyph.bb:getWidth(), glyph.bb:getHeight())
if kerning and (prevcharcode ~= 0) then
pen_x = pen_x + face.ftface:getKerning(prevcharcode, charcode)
end
buffer:addblitFrom(glyph.bb, x + pen_x + glyph.l, y - glyph.t, 0, 0, glyph.bb:getWidth(), glyph.bb:getHeight())
pen_x = pen_x + glyph.ax
prevcharcode = charcode
end -- if pen_x < buffer_width
end -- for uchar
return pen_x
end
-- render UTF8 text restricted by width 'w'
function renderUtf8TextWidth(buffer, x, y, face, text, kerning, w)
if not text then
Debug("renderUtf8Text called without text");
return nil
end
local prevcharcode, pen_x, rest = 0, 0, ""
for uchar in string.gfind(text, "([%z\1-\127\194-\244][\128-\191]*)") do
if pen_x < w then
local charcode = util.utf8charcode(uchar)
local glyph = getGlyph(face, charcode)
if kerning and (prevcharcode ~= 0) then
pen_x = pen_x + face.ftface:getKerning(prevcharcode, charcode)
end
buffer:addblitFrom(glyph.bb, x + pen_x + glyph.l, y - glyph.t, 0, 0, glyph.bb:getWidth(), glyph.bb:getHeight())
pen_x = pen_x + glyph.ax
prevcharcode = charcode
else
-- accumulating the rest of text here
rest = rest .. uchar
end
end
return pen_x
return { left = rest, x = pen_x, y = y }
end
function SplitString(text)
local words = {}
local word = ""
for uchar in string.gfind(text, "([%z\1-\127\194-\244][\128-\191]*)") do
if uchar == "/" or uchar == " " or uchar == "-" or uchar == "_" or uchar == "." then
words[#words+1] = word .. uchar
word = ""
else
word = word .. uchar
end
end
-- add the rest of string as the last word
words[#words+1] = word
return words
end
function renderUtf8Multiline(buffer, x, y, face, text, kerning, w, line_spacing)
local words = SplitString(text)
-- test whether it is inside of reasonable values 1.0 < line_spacing < 5.0 or given in pixels (>5)
-- default value is 1.75 ; getGlyph(face, 65).t = height of char 'A'
local gl = getGlyph(face, 65)
if line_spacing<1 then line_spacing=gl.t -- single = minimum
elseif line_spacing < 5 then line_spacing=math.ceil(gl.t * line_spacing)
-- if line_spacing>5 then it seems to be defined in pixels
elseif line_spacing>=5 then line_spacing=line_spacing
-- and, just for a case, default value
else line_spacing = math.ceil(gl.t * 1.75)
end
-- NuPogodi, 17.07.2012: minor modification to solve issue #214
local lx, render = x
for i = 1, #words do
if sizeUtf8Text(lx, buffer:getWidth(), face, words[i], kerning).x < (w - lx + x) then
lx = lx + renderUtf8TextWidth(buffer, lx, y, face, words[i], kerning, w - lx + x).x
else -- shift down if it's not the first word in the current line
if lx > x then
y = y + line_spacing
end
lx = x -- move lx to the line start and draw next word until the last char
render = renderUtf8TextWidth(buffer, lx, y, face, words[i], kerning, w-gl.ax)
while render.left ~= "" do
y = y + line_spacing
render = renderUtf8TextWidth(buffer, lx, y, face, render.left, kerning, w-gl.ax)
end
lx = lx + render.x
end -- if
end --for
return { x = x, y = y }
end

Binary file not shown.

After

Width:  |  Height:  |  Size: 259 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 288 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 321 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 237 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 249 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 191 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 326 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 311 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 858 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 950 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 844 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 268 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 276 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 269 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 266 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 276 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 304 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 292 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 334 B

@ -18,7 +18,7 @@
--[[
Codes for rotation modes:
1 for no rotation,
1 for no rotation,
2 for landscape with bottom on the right side of screen, etc.
2
@ -26,8 +26,8 @@ Codes for rotation modes:
| +----------+ |
| | | |
| | Freedom! | |
| | | |
| | | |
| | | |
| | | |
3 | | | | 1
| | | |
| | | |
@ -38,7 +38,6 @@ Codes for rotation modes:
0
--]]
Screen = {
cur_rotation_mode = 0,
-- these two variabls are used to help switching from framework to reader
@ -48,6 +47,20 @@ Screen = {
saved_bb = nil,
}
function Screen:setRotationMode(mode)
if mode < 0 or mode > 3 then
Debug("Illegal mode parameter to Screen:setRotatonMode()!")
return
end
self.cur_rotation_mode = mode
-- you have to reopen framebuffer after rotate
fb:setOrientation(self.cur_rotation_mode)
fb:close()
fb = einkfb.open("/dev/fb0")
G_width, G_height = fb:getSize()
end
-- @orien: 1 for clockwise rotate, -1 for anti-clockwise
-- Remember to reread screen resolution after this function call
function Screen:screenRotate(orien)
@ -67,7 +80,7 @@ function Screen:screenRotate(orien)
end
function Screen:updateRotationMode()
if KEY_FW_DOWN == 116 then -- in EMU mode always set to 0
if util.isEmulated() == 1 then -- in EMU mode always set to 0
self.cur_rotation_mode = 0
else
orie_fd = assert(io.open("/sys/module/eink_fb_hal_broads/parameters/bs_orientation", "r"))
@ -103,6 +116,121 @@ function Screen:restoreFromBB(bb)
if bb then
fb.bb:blitFullFrom(bb)
else
debug("Got nil bb in restoreFromSavedBB!")
Debug("Got nil bb in restoreFromSavedBB!")
end
end
function Screen:screenshot()
if util.isEmulated() == 1 then
return
end
local secs, usecs = util.gettime()
self:fb2bmp("/dev/fb0", lfs.currentdir().."/screenshots/"..os.date("%Y%m%d%H%M%S")..".bmp", true, nil)
local nsecs, nusecs = util.gettime()
local diff = nsecs - secs + (nusecs - usecs)/1000000
--self:fb2bmp("/dev/fb0", lfs.currentdir().."/screenshots/"..os.date("%Y%m%d%H%M%S")..".bmp", true, "bzip2 ")
--self:fb2pgm("/dev/fb0", lfs.currentdir().."/screenshots/"..os.date("%Y%m%d%H%M%S")..".pgm", "bzip2 ", 4)
local msg = "Screenshot is ready in "
InfoMessage:inform(msg..string.format("%.2fs ", diff), DINFO_DELAY, 1, MSG_WARN, msg..math.ceil(diff*1000).." milliseconds")
end
-- NuPogodi (02.07.2012): added the functions to save the fb-content in common graphic files - bmp & pgm.
-- ToDo: png, gif ?
function Screen:LE(x) -- converts positive upto 32bit-number to a little-endian for bmp-header
local s, n = "", 4
if x<0x10000 then
s = string.char(0,0)
n = 2
end
x = math.floor(x)
for i = 1,n do
s = s..string.char(x%256)
x = math.floor(x/256)
end
return s
end
--[[ This function saves the 4bpp framebuffer as 4bpp BMP and, if necessary, packes the output by command os.execute(pack..fn).
Since framebuffer enumerates the lines from top to bottom and the bmp-file does it in the inversed order, the process includes
a vertical flip that makes it a bit slower, namely,
~0.16(s) @ Kindle3 & Kindle2 (600x800) ~0.02s @ without v-flip
~0.36(s) @ Kindle DX (824x1200)
NB: needs free memory of G_width*G_height/2 bytes to manupulate the fb-content! ]]
function Screen:fb2bmp(fin, fout, vflip, pack) -- atm, for 4bpp framebuffers only
local inputf = io.open(fin,"rb")
if inputf then
local outputf, size = io.open(fout,"wb")
if outputf then
-- writing bmp-header
outputf:write(string.char(0x42,0x4D,0xF6,0xA9,3,0,0,0,0,0,0x76,0,0,0,40,0),
self:LE(G_width), self:LE(G_height), -- width & height: 4 chars each
string.char(0,0,1,0,4,0,0,0,0,0),
self:LE(G_height*G_width/2), -- raw bytes in image
string.char(0x87,0x19,0,0,0x87,0x19,0,0), -- 6536 pixel/m = 166 dpi for both x&y resolutions
string.char(16,0,0,0,0,0,0,0)) -- 16 colors
local line, i = G_width/2, 15
-- add palette to bmp-header
while i>=0 do
outputf:write(string.char(i*16+i):rep(3), string.char(0))
i=i-1
end
if vflip then -- flip image vertically to make it bmp-compliant
-- read the fb-content line-by-line & fill the content-table in the inversed order
local content = {}
for i=1, G_height do
table.insert(content, 1, inputf:read(line))
end
-- write the v-flipped bmp-data
for i=1, G_height do
outputf:write(content[i])
end
else -- without v-flip, it takes only 0.02s @ 600x800, 4bpp
outputf:write(inputf:read("*all"))
end
outputf:close()
-- here one may use either standard archivers (bzip2, gzip)
-- or standalone converters (bmp2png, bmp2gif)
if pack then os.execute(pack..fout) end
end -- if output f
inputf:close()
end -- if inputf
end
--[[ This function saves the fb-content (both 4bpp and 8bpp) as 8bpp PGM and pack it.
It's relatively slow for 4bpp devices such as
~2.5s @ K2 and K3 > 600x800, 4bpp
~5.0s @ KDX > 824x1200,
but should be very fast (<<0.1s) when no color conversion (4bpp>8bpp) is needed. ]]
--[[
function Screen:fb2pgm(fin, fout, pack, bpp)
local inputf = assert(io.open(fin,"rb"))
if inputf then
local outputf = assert(io.open(fout,"wb"))
outputf:write("P5\n# Created by kindlepdfviewer\n"..G_width.." "..G_height.."\n255\n")
if bpp == 8 then -- then needs free memory of G_width*G_height bytes, but extremely fast!
outputf:write(inputf:read("*all"))
else -- convert 4bpp to 8bpp; needs free memory just to store a block = G_width/2 bytes
local bpp8, block, i, j, line = {}, G_width/2
-- to accelerate a process, let us first create the convertion table: char (0..255) > 2 chars
for j=0, 255 do
i = j%16
bpp8[#bpp8+1] = string.char(255-j+i, 255-i*16)
end
-- now read, convert & write the fb-content by blocks
for i=1, G_height do
line = inputf:read(block)
for j=1, block do
outputf:write(bpp8[1+string.byte(line,j)])
end
end
end
inputf:close()
outputf:close()
if pack then os.execute(pack..fout) end
end
end
]]

@ -5,21 +5,15 @@ require "font"
require "commands"
SelectMenu = {
-- font for displaying item names
fsize = 22,
-- font for page title
tfsize = 25,
-- font for paging display
ffsize = 16,
-- font for item shortcut
sface = Font:getFace("scfont", 22),
fsize = 22, -- font for displaying item names
tfsize = 25, -- font for page title
ffsize = 16,-- font for paging display
-- title height
title_H = 40,
-- spacing between lines
spacing = 36,
-- foot height
foot_H = 27,
title_H = 40, -- title height
spacing = 36, -- spacing between lines
foot_H = 27, -- foot height
margin_H = 10, -- horisontal margin
current_entry = 0,
menu_title = "No Title",
no_item_msg = "No items found.",
@ -28,8 +22,8 @@ SelectMenu = {
item_shortcuts = {
"Q", "W", "E", "R", "T", "Y", "U", "I", "O", "P",
"A", "S", "D", "F", "G", "H", "J", "K", "L", "Del",
"Z", "X", "C", "V", "B", "N", "M", ".", "Sym", "Ent",
"A", "S", "D", "F", "G", "H", "J", "K", "L", "Sym",
"Z", "X", "C", "V", "B", "N", "M", ".", "/", "Ent",
},
last_shortcut = 0,
@ -40,6 +34,14 @@ SelectMenu = {
selected_item = nil,
commands = nil,
expandable = false, -- if true handle Right/Left FW selector keys
deletable = false, -- if true handle Del key as a request to delete item
-- note that currently expandable and deletable are mutually exclusive
-- NuPogodi, 30.08.12: define font to render menu items
own_glyph = 0, -- render menu items with default "cfont"
-- own_glyph = 1 => own glyphs for items like "Droid/DroidSans.ttf"
-- own_glyph = 2 => own glyphs for Font.fontmap._index like "ffont", "tfont", etc.
}
function SelectMenu:new(o)
@ -71,7 +73,18 @@ end
function SelectMenu:addAllCommands()
self.commands = Commands:new{}
self.commands:add(KEY_FW_UP, nil, "",
local numeric_keydefs, i = {}
for i=1, 10 do numeric_keydefs[i]=Keydef:new(KEY_1+i-1, nil, tostring(i%10)) end
self.commands:addGroup("[1, 2 .. 9, 0]", numeric_keydefs,
"item at position 0%, 10% .. 90%, 100%",
function(sm)
local target_item = math.ceil(sm.items * (keydef.keycode-KEY_1) / 9)
sm.current, sm.page, sm.markerdirty, sm.pagedirty =
gotoTargetItem(target_item, sm.items, sm.current, sm.page, sm.perpage)
end
)
self.commands:add(KEY_FW_UP, nil, "joypad up",
"previous item",
function(sm)
if sm.current == 1 then
@ -86,7 +99,7 @@ function SelectMenu:addAllCommands()
end
end
)
self.commands:add(KEY_FW_DOWN, nil, "",
self.commands:add(KEY_FW_DOWN, nil, "joypad down",
"next item",
function(sm)
if sm.current == sm.perpage then
@ -104,7 +117,7 @@ function SelectMenu:addAllCommands()
end
end
)
self.commands:add({KEY_PGFWD, KEY_LPGFWD}, nil, "",
self.commands:add({KEY_PGFWD, KEY_LPGFWD}, nil, ">",
"next page",
function(sm)
if sm.page < (sm.items / sm.perpage) then
@ -119,7 +132,7 @@ function SelectMenu:addAllCommands()
end
end
)
self.commands:add({KEY_PGBCK, KEY_LPGBCK}, nil, "",
self.commands:add({KEY_PGBCK, KEY_LPGBCK}, nil, "<",
"previous page",
function(sm)
if sm.page > 1 then
@ -131,8 +144,8 @@ function SelectMenu:addAllCommands()
end
end
)
self.commands:add(KEY_FW_PRESS, nil, "",
"select menu item",
self.commands:add(KEY_FW_PRESS, nil, "joypad center",
"select item",
function(sm)
if sm.items == 0 then
return "break"
@ -141,12 +154,44 @@ function SelectMenu:addAllCommands()
end
end
)
if self.deletable then
self.commands:add(KEY_DEL, nil, "Del",
"delete item",
function(sm)
self.selected_item = (sm.perpage * (sm.page - 1) + sm.current)
return "delete"
end
)
end
if self.expandable then
self.commands:add(KEY_FW_RIGHT, nil, "joypad right",
"expand item",
function(sm)
self.selected_item = (sm.perpage * (sm.page - 1) + sm.current)
return "expand"
end
)
self.commands:add(KEY_FW_LEFT, nil, "joypad left",
"collapse item",
function(sm)
self.selected_item = (sm.perpage * (sm.page - 1) + sm.current)
return "collapse"
end
)
self.commands:add(KEY_FW_RIGHT, MOD_SHIFT, "joypad right",
"expand all subitems",
function(sm)
self.selected_item = (sm.perpage * (sm.page - 1) + sm.current)
return "expand all"
end
)
end
local KEY_Q_to_P = {}
for i = KEY_Q, KEY_P do
table.insert(KEY_Q_to_P, Keydef:new(i, nil, ""))
end
self.commands:addGroup("Q to P", KEY_Q_to_P,
"Select menu item with Q to E key as shortcut",
"select item with Q to P key as shortcut",
function(sm, keydef)
sm.selected_item = sm:getItemIndexByShortCut(
sm.item_shortcuts[ keydef.keycode - KEY_Q + 1 ], sm.perpage)
@ -157,7 +202,7 @@ function SelectMenu:addAllCommands()
table.insert(KEY_A_to_L, Keydef:new(i, nil, ""))
end
self.commands:addGroup("A to L", KEY_A_to_L,
"Select menu item with A to L key as shortcut",
"select item with A to L key as shortcut",
function(sm, keydef)
sm.selected_item = sm:getItemIndexByShortCut(
sm.item_shortcuts[ keydef.keycode - KEY_A + 11 ], sm.perpage)
@ -168,39 +213,44 @@ function SelectMenu:addAllCommands()
table.insert(KEY_Z_to_M, Keydef:new(i, nil, ""))
end
self.commands:addGroup("Z to M", KEY_Z_to_M,
"Select menu item with Z to M key as shortcut",
"select item with Z to M key as shortcut",
function(sm, keydef)
sm.selected_item = sm:getItemIndexByShortCut(
sm.item_shortcuts[ keydef.keycode - KEY_Z + 21 ], sm.perpage)
end
)
self.commands:add(KEY_DEL, nil, "",
"Select menu item with del key as shortcut",
self.commands:add(KEY_SLASH, nil, "/",
"select item with / key as shortcut",
function(sm)
sm.selected_item = sm:getItemIndexByShortCut("Del", sm.perpage)
sm.selected_item = sm:getItemIndexByShortCut("/", sm.perpage)
end
)
self.commands:add(KEY_DOT, nil, "",
"Select menu item with dot key as shortcut",
self.commands:add(KEY_DOT, nil, ".",
"select item with dot key as shortcut",
function(sm)
sm.selected_item = sm:getItemIndexByShortCut(".", sm.perpage)
end
)
self.commands:add({KEY_SYM, KEY_SLASH}, nil, "",
"Select menu item with sym/slash key as shortcut",
self.commands:add(KEY_SYM, nil, "Sym",
"select item with Sym key as shortcut",
function(sm)
-- DXG has slash after dot
sm.selected_item = sm:getItemIndexByShortCut("Sym", sm.perpage)
end
)
self.commands:add(KEY_ENTER, nil, "",
"Select menu item with enter key as shortcut",
self.commands:add(KEY_ENTER, nil, "Enter",
"select item with Enter key as shortcut",
function(sm)
sm.selected_item = sm:getItemIndexByShortCut("Ent", sm.perpage)
end
)
self.commands:add(KEY_BACK, nil, "",
"Exit menu",
self.commands:add(KEY_H,MOD_ALT,"H",
"show help page",
function(sm)
HelpPage:show(0, G_height, sm.commands)
sm.pagedirty = true
end)
self.commands:add(KEY_BACK, nil, "Back",
"exit menu",
function(sm)
return "break"
end
@ -210,8 +260,8 @@ end
function SelectMenu:clearCommands()
self.commands = Commands:new{}
self.commands:add(KEY_BACK, nil, "",
"Exit menu",
self.commands:add(KEY_BACK, nil, "Back",
"exit menu",
function(sm)
return "break"
end)
@ -226,29 +276,37 @@ function SelectMenu:choose(ypos, height)
self.markerdirty = false
self.last_shortcut = 0
self.current_entry = math.min(self.current_entry,self.items)
-- now calculating the page & cursor
self.page = math.floor(self.current_entry / self.perpage) + 1
self.page = math.max(1, self.page)
self.current = self.current_entry - (self.page - 1) * self.perpage + 1
self.current = math.max(1, self.current)
local own_face
while true do
local cface = Font:getFace("cfont", 22)
local tface = Font:getFace("tfont", 25)
local fface = Font:getFace("ffont", 16)
local sface = Font:getFace("scfont", 22)
local lx = self.margin_H + 40
local fw = fb.bb:getWidth() - lx - self.margin_H
if self.pagedirty then
fb.bb:paintRect(0, ypos, fb.bb:getWidth(), height, 0)
self.markerdirty = true
-- draw menu title
fb.bb:paintRect(0, ypos, fb.bb:getWidth(), self.title_H + 10, 0)
fb.bb:paintRect(10, ypos + 10, fb.bb:getWidth() - 20, self.title_H, 5)
local x = 20
local y = ypos + self.title_H
renderUtf8Text(fb.bb, x, y, tface, self.menu_title, true)
DrawTitle(self.menu_title,self.margin_H,0,self.title_H,3,tface)
-- draw items
fb.bb:paintRect(0, ypos + self.title_H + 10, fb.bb:getWidth(), height - self.title_H, 0)
fb.bb:paintRect(0, ypos + self.title_H + self.margin_H, fb.bb:getWidth(), height - self.title_H, 0)
if self.items == 0 then
y = ypos + self.title_H + (self.spacing * 2)
renderUtf8Text(fb.bb, 30, y, cface,
renderUtf8Text(fb.bb, self.margin_H + 20, y, cface,
"Oops... Bad news for you:", true)
y = y + self.spacing
renderUtf8Text(fb.bb, 30, y, cface,
renderUtf8Text(fb.bb, self.margin_H + 20, y, cface,
self.no_item_msg, true)
self.markerdirty = false
self:clearCommands()
@ -257,54 +315,63 @@ function SelectMenu:choose(ypos, height)
for c = 1, self.perpage do
local i = (self.page - 1) * self.perpage + c
if i <= self.items then
y = ypos + self.title_H + (self.spacing * c)
y = ypos + self.title_H + (self.spacing * c) + 4
-- paint shortcut indications
if c <= 10 or c > 20 then
blitbuffer.paintBorder(fb.bb, 10, y-22, 29, 29, 2, 15)
blitbuffer.paintBorder(fb.bb, self.margin_H, y-22, 29, 29, 2, 15)
else
fb.bb:paintRect(10, y-22, 29, 29, 3)
fb.bb:paintRect(self.margin_H, y-22, 29, 29, 3)
end
if self.item_shortcuts[c] ~= nil and
string.len(self.item_shortcuts[c]) == 3 then
-- debug "Del", "Sym and "Ent"
renderUtf8Text(fb.bb, 13, y, fface,
renderUtf8Text(fb.bb, self.margin_H + 3, y, fface,
self.item_shortcuts[c], true)
else
renderUtf8Text(fb.bb, 18, y, self.sface,
renderUtf8Text(fb.bb, self.margin_H + 8, y, sface,
self.item_shortcuts[c], true)
end
self.last_shortcut = c
renderUtf8Text(fb.bb, 50, y, cface,
self.item_array[i], true)
-- NuPogodi, 30.08.12: improved method to use own fontface for each menu item
if self.own_glyph == 1 then -- Font.fontmap[_index], like "Droid/DroidSans.ttf"
own_face = Font:getFace(self.item_array[i], 22)
elseif self.own_glyph == 2 then -- Font.fontmap._index, like "[cfont] description"
own_face = Font:getFace(string.sub(string.match(self.item_array[i],"%b[]"), 2, -2), 22)
else
own_face = cface
end
-- rendering menu items
if sizeUtf8Text(lx,fb.bb:getWidth(),own_face,self.item_array[i],false).x < (fw - 10) then
renderUtf8Text(fb.bb,lx,y,own_face,self.item_array[i],false)
else
local gapx = sizeUtf8Text(0,fb.bb:getWidth(),own_face,"...", true).x
gapx = lx + renderUtf8TextWidth(fb.bb,lx,y,own_face,self.item_array[i],false,fw-gapx-15).x
renderUtf8Text(fb.bb,gapx,y,own_face,"...",true)
end
-- end of changes (NuPogodi)
end -- if i <= self.items
end -- for c=1, self.perpage
end -- if self.items == 0
-- draw footer
y = ypos + self.title_H + (self.spacing * self.perpage)
+ self.foot_H + 5
x = (fb.bb:getWidth() / 2) - 50
renderUtf8Text(fb.bb, x, y, fface,
"Page "..self.page.." of "..
(math.ceil(self.items / self.perpage)), true)
local footer = "Page "..self.page.." of "..(math.ceil(self.items / self.perpage)).." - Press Alt-H for help"
renderUtf8Text(fb.bb, self.margin_H, height-7, fface, footer, true)
end
if self.markerdirty then
if not self.pagedirty then
if self.oldcurrent > 0 then
y = ypos + self.title_H + (self.spacing * self.oldcurrent) + 8
fb.bb:paintRect(45, y, fb.bb:getWidth() - 60, 3, 0)
fb:refresh(1, 45, y, fb.bb:getWidth() - 60, 3)
y = ypos + self.title_H + (self.spacing * self.oldcurrent) + 12
fb.bb:paintRect( lx, y, fw, 3, 0)
fb:refresh(1, lx, y, fw, 3)
end
end
-- draw new marker line
y = ypos + self.title_H + (self.spacing * self.current) + 8
fb.bb:paintRect(45, y, fb.bb:getWidth() - 60, 3, 15)
y = ypos + self.title_H + (self.spacing * self.current) + 12
fb.bb:paintRect(lx, y, fw, 3, 15)
if not self.pagedirty then
fb:refresh(1, 45, y, fb.bb:getWidth() - 60, 3)
fb:refresh(1, lx, y, fw, 3)
end
self.oldcurrent = self.current
self.markerdirty = false
@ -319,14 +386,14 @@ function SelectMenu:choose(ypos, height)
ev.code = adjustKeyEvents(ev)
if ev.type == EV_KEY and ev.value ~= EVENT_VALUE_KEY_RELEASE then
keydef = Keydef:new(ev.code, getKeyModifier())
debug("key pressed: "..tostring(keydef))
Debug("key pressed: "..tostring(keydef))
command = self.commands:getByKeydef(keydef)
if command ~= nil then
debug("command to execute: "..tostring(command))
Debug("command to execute: "..tostring(command))
ret_code = command.func(self, keydef)
else
debug("command not found: "..tostring(command))
Debug("command not found: "..tostring(command))
end
if ret_code == "break" then
@ -334,7 +401,18 @@ function SelectMenu:choose(ypos, height)
end
if self.selected_item ~= nil then
debug("# selected "..self.selected_item)
if self.expandable then
if ret_code == "expand" then
return nil, self.selected_item
elseif ret_code == "collapse" then
return nil, -self.selected_item
elseif ret_code == "expand all" then
return nil, self.selected_item, "all"
end
elseif self.deletable and ret_code == "delete" then
return nil, self.selected_item
end
Debug("# selected "..self.selected_item)
return self.selected_item, self.item_array[self.selected_item]
end
end -- EOF if

@ -1,9 +1,71 @@
DocSettings = {}
DocSettings = {
}
function DocToHistory(fullname)
local i,j = 1,0
while i ~= nil do
i = string.find(fullname,"/",i+1)
if i==nil then break end
j = i
end
local f = string.sub(fullname,j+1,-1)
if j>0 then return "./history/["..string.gsub(string.sub(fullname,1,j),"/","#").."] "..f..".lua"
else return "./settings"..f..".lua" end
end
function HistoryToName(history)
-- at first, search for path length
local s = string.len(string.match(history,"%b[]"))
-- and return the rest of string without 4 last characters (".lua")
return string.sub(history, s+2, -5)
end
function HistoryToPath(history)
-- 1. select everything included in brackets
local s = string.match(history,"%b[]")
-- 2. crop the bracket-sign from both sides
-- 3. and finally replace decorative signs '#' to dir-char '/'
return string.gsub(string.sub(s,2,-3),"#","/")
end
function DocSettings:open(docfile)
local new = { file = docfile..".kpdfview.lua", data = {} }
-- history feature moves configuration files into history directory
local new = { file = DocToHistory(docfile), data = {} }
local ok, stored = pcall(dofile,new.file)
if not ok then
ok, stored = pcall(dofile,docfile..".kpdfview.lua")
end
if ok then
if stored.version == nil then
stored.version = 0
end
if stored.version < 2012.05 then
Debug("settings", docfile, stored)
if stored.jumpstack ~= nil then
stored.jump_history = stored.jumpstack
stored.jumpstack = nil
if not stored.jump_history.cur then
-- set up new history head
stored.jump_history.cur = #stored.jump_history + 1
end
end
-- update variable name
if stored.globalzoommode ~= nil then
stored.globalzoom_mode = stored.globalzoommode
stored.globalzoommode = nil
end
if stored.highlight ~= nil then
local file_type = string.lower(string.match(docfile, ".+%.([^.]+)") or "")
if file_type == "djvu" then
stored.highlight.to_fix = {"djvu invert y axle"}
end
end
stored.version = 2012.05
Debug("upgraded", stored)
end
new.data = stored
end
return setmetatable(new, { __index = DocSettings})
@ -27,8 +89,9 @@ function dump(data)
return table.concat(out)
end
function debug(...)
function Debug(...)
local line = ""
local arg = {...}
for i,v in ipairs(arg) do
if type(v) == "table" then
line = line .. " " .. dump(v)
@ -37,6 +100,7 @@ function debug(...)
end
end
print("#"..line)
return true -- debug enabled
end
-- simple serialization function, won't do uservalues, functions, loops

@ -16,8 +16,11 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdlib.h>
#include "popen-noshell/popen_noshell.h"
#include <err.h>
#include <stdio.h>
#include <signal.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
@ -25,18 +28,19 @@
#include <sys/stat.h>
#include <sys/types.h>
#include <errno.h>
#include <sys/wait.h>
#define OUTPUT_SIZE 21
#define EVENT_PIPE "/tmp/event_slider"
#define CODE_IN_SAVER 10000
#define CODE_OUT_SAVER 10001
int
main ( int argc, char *argv[] )
{
int fd, ret;
int fd;
FILE *fp;
char std_out[OUTPUT_SIZE] = "";
char std_out[256];
int status;
struct popen_noshell_pass_to_pclose pclose_arg;
struct input_event ev;
__u16 key_code = 10000;
@ -51,7 +55,7 @@ main ( int argc, char *argv[] )
/* open npipe for writing */
fd = open(argv[1], O_RDWR | O_NONBLOCK);
if(fd < 0) {
printf("Open %s falied: %s\n", argv[1], strerror(errno));
printf("Open %s failed: %s\n", argv[1], strerror(errno));
exit(EXIT_FAILURE);
}
@ -60,15 +64,18 @@ main ( int argc, char *argv[] )
ev.code = key_code;
ev.value = 1;
while(1) {
/* listen power slider events */
memset(std_out, 0, OUTPUT_SIZE);
fp = popen("lipc-wait-event -s 0 com.lab126.powerd goingToScreenSaver,outOfScreenSaver", "r");
ret = fread(std_out, OUTPUT_SIZE, 1, fp);
pclose(fp);
/* listen power slider events */
char *argv[] = {"lipc-wait-event", "-m", "-s", "0", "com.lab126.powerd", "goingToScreenSaver,outOfScreenSaver", (char *) NULL};
fp = popen_noshell("lipc-wait-event", (const char * const *)chargv, "r", &pclose_arg, 0);
if (!fp) {
err(EXIT_FAILURE, "popen_noshell()");
}
while(fgets(std_out, sizeof(std_out)-1, fp)) {
/* printf("Got line: %s", std_out); */
/* fill event struct */
gettimeofday(&ev.time, NULL);
if(std_out[0] == 'g') {
ev.code = CODE_IN_SAVER;
} else if(std_out[0] == 'o') {
@ -77,9 +84,29 @@ main ( int argc, char *argv[] )
printf("Unrecognized event.\n");
exit(EXIT_FAILURE);
}
/* fill event struct */
gettimeofday(&ev.time, NULL);
/* printf("Send event %d\n", ev.code); */
/* generate event */
ret = write(fd, &ev, sizeof(struct input_event));
if(write(fd, &ev, sizeof(struct input_event)) == -1) {
printf("Failed to generate event.\n");
}
}
status = pclose_noshell(&pclose_arg);
if (status == -1) {
err(EXIT_FAILURE, "pclose_noshell()");
} else {
printf("Power slider event listener child exited with status %d.\n", status);
if WIFEXITED(status) {
printf("Child exited normally with status: %d.\n", WEXITSTATUS(status));
}
if WIFSIGNALED(status) {
printf("Child terminated by signal: %d.\n", WTERMSIG(status));
}
}
close(fd);

File diff suppressed because it is too large Load Diff

@ -17,6 +17,7 @@
*/
#include <sys/time.h>
#include <sys/statvfs.h>
#include <unistd.h>
#include "util.h"
@ -41,10 +42,19 @@ static int util_usleep(lua_State *L) {
return 0;
}
static int util_df(lua_State *L) {
const char *path = luaL_checkstring(L, 1);
struct statvfs vfs;
statvfs(path, &vfs);
lua_pushnumber(L, (double)vfs.f_blocks * (double)vfs.f_bsize);
lua_pushnumber(L, (double)vfs.f_bfree * (double)vfs.f_bsize);
return 2;
}
/* Turn UTF-8 char code to Unicode */
static int utf8charcode(lua_State *L) {
size_t len;
const char* utf8char = luaL_checklstring(L, 1, &len);
const char *utf8char = luaL_checklstring(L, 1, &len);
int c;
if(len == 1) {
c = utf8char[0] & 0x7F; /* should not be needed */
@ -75,6 +85,7 @@ static const struct luaL_Reg util_func[] = {
{"usleep", util_usleep},
{"utf8charcode", utf8charcode},
{"isEmulated", isEmulated},
{"df", util_df},
{NULL, NULL}
};

@ -1,5 +1,5 @@
/*
KindlePDFViewer: buffer for blitting muPDF data to framebuffer (blitbuffer)
KindlePDFViewer: miscellaneous utility functions for Lua
Copyright (C) 2011 Hans-Werner Hilse <hilse@web.de>
This program is free software: you can redistribute it and/or modify

@ -0,0 +1,125 @@
#!/bin/bash
#
# pdfattach --- embed specified file(s) in a specified PDF file
# Requires pdfLaTeX and attachfile.sty package to run
# Returns 0 on success or >0 on error
#
# Written by Tigran Aivazian <tigran@bibles.org.uk>
#
progname=$(basename $0)
function escape_tex_specialchars()
{
local txt=$1
local res=$(echo "$txt" | sed -e "s%_%\\\_%g" -e "s%&%\\\&%g")
echo "$res"
}
function usage()
{
echo "Usage: $progname -o file.pdf [-a author] file1.djvu [file2.mp3] ..."
exit 1
}
if (! getopts ":o:" opt); then
echo "$progname: Missing options." >&2
usage
fi
if ! type pdflatex > /dev/null 2>&1 ; then
echo "$progname: pdfLaTeX program is required." >&2
exit 1
fi
if ! kpsewhich attachfile.sty > /dev/null 2>&1 ; then
echo "$progname: attachfile.sty package is required." >&2
exit 1
fi
declare outfile=""
declare -a infiles=()
declare -a infiles_texclean=()
declare -a infilesize=()
declare -i infcount=0 outfcount=0 totalsize=0
declare author=""
while getopts ":o:a:" opt; do
case $opt in
a)
author="$OPTARG"
;;
o)
outfile=$(readlink -f "$OPTARG")
((outfcount++))
;;
\?)
echo "$progname: Invalid option: -$OPTARG" >&2
usage
;;
:)
echo "$progname: Option -$OPTARG requires an argument." >&2
usage
;;
esac
done
shift $((OPTIND-1))
numargs=$#
for ((i=1 ; i <= $numargs ; i++))
do
fullname=$(readlink -f "$1")
if [ ! -r "$fullname" ] ; then
echo "$progname: cannot access the file \"$fullname\"" >&2
usage
fi
infiles[$infcount]="$fullname"
infiles_texclean[$infcount]=$(escape_tex_specialchars $(basename "${infiles[$infcount]}"))
infilesize[$infcount]=$(stat --print="%s" "$fullname")
((totalsize=totalsize+${infilesize[$infcount]}))
((infcount++))
shift
done
if ((infcount == 0)) ; then
echo "$progname: No input file(s) specified." >&2
usage
fi
if ((outfcount != 1)) ; then
echo "$progname: One (and only one) output file must be specified." >&2
usage
fi
workdir=$(mktemp --tmpdir -d pdfattach.XXXXXX)
cd $workdir
> tmp.tex
# emit TeX preamble
echo -E "\documentclass{book}" >> tmp.tex
echo -E "\usepackage[margin={1mm},papersize={9cm,12cm}]{geometry}" >> tmp.tex
echo -E "\usepackage{hyperref,attachfile}" >> tmp.tex
if [ ! -z "$author" ] ; then
echo -E "\AtBeginDocument{\hypersetup{pdfauthor={$author}}}" >> tmp.tex
fi
echo -E "\begin{document}" >> tmp.tex
echo -E "\tolerance=10000\pagestyle{empty}\fontsize{7}{13}\selectfont" >> tmp.tex
# emit the list of all files
for ((i = 0 ; i < ${#infiles[*]} ; i++));
do
echo -E "\noindent \hyperlink{L$i}{$((i+1))/${infcount}} \texttt{${infiles_texclean[$i]}} (${infilesize[$i]} bytes)" >> tmp.tex
echo >> tmp.tex
done
echo -E "\noindent Total size $totalsize bytes\newpage" >> tmp.tex
# now emit all the attachments, one per page
for ((i = 0 ; i < ${#infiles[*]} ; i++));
do
echo -E "\noindent\hypertarget{L$i}$((i+1))/${infcount}\\\\\texttt{${infiles_texclean[$i]}} (\textattachfile[color={0 0 0}]{${infiles[$i]}}{${infilesize[$i]} bytes})\newpage" >> tmp.tex
done
echo -E "\end{document}" >> tmp.tex
pdflatex -halt-on-error tmp.tex > /dev/null && mv tmp.pdf "$outfile"
cd - > /dev/null
rm -rf $workdir

@ -107,7 +107,7 @@ TextWidget = Widget:new({
function TextWidget:_render()
local h = self.face.size * 1.5
self._bb = Blitbuffer.new(self._maxlength, h)
self._length = renderUtf8Text(self._bb, 0, h*.7, self.face, self.text, self.color)
self._length = renderUtf8Text(self._bb, 0, h*.7, self.face, self.text, true)
end
function TextWidget:getSize()

Loading…
Cancel
Save