├── .github
└── workflows
│ └── build.yaml
├── .gitignore
├── DocumentViewer.hvif
├── DocumentViewerScreenshot.png
├── README.md
├── application
├── BaseEngine.cpp
├── BaseEngine.h
├── BookmarksView.cpp
├── BookmarksView.h
├── CircleMenuView.cpp
├── CircleMenuView.h
├── DJVUEngine.cpp
├── DJVUEngine.h
├── Debug.h
├── DocumentView.cpp
├── DocumentView.h
├── DocumentViewer.rdef
├── DocumentViewer_icon.png
├── Flags.h
├── Icons.rdef
├── ImageButton.cpp
├── ImageButton.h
├── ImagePopUp.cpp
├── ImagePopUp.h
├── ImageSpinner.cpp
├── ImageSpinner.h
├── ImageTabView.cpp
├── ImageTabView.h
├── MainApplication.h
├── MainWindow.cpp
├── MainWindow.h
├── MainWindowRB.cpp
├── MainWindowRB.h
├── Makefile
├── Messages.h
├── NumberControl.cpp
├── NumberControl.h
├── OutlineView.cpp
├── OutlineView.h
├── PDFEngine.cpp
├── PDFEngine.h
├── PDFFilter.cpp
├── PDFFilter.h
├── PageNavigationView.cpp
├── PageNavigationView.h
├── PasswordRequestWindow.cpp
├── PasswordRequestWindow.h
├── PreviewView.cpp
├── PreviewView.h
├── PrintPreviewView.cpp
├── PrintPreviewView.h
├── PrintingWindow.cpp
├── PrintingWindow.h
├── SearchView.cpp
├── SearchView.h
├── Settings.h
├── Timer.h
├── Tools.h
└── main.cpp
└── documentation
├── help.odt
└── help.pdf
/.github/workflows/build.yaml:
--------------------------------------------------------------------------------
1 | name: "haiku-ci"
2 | on: [push, pull_request]
3 |
4 | jobs:
5 | build-haiku:
6 | timeout-minutes: 60
7 | runs-on: ${{ matrix.config.runner }}
8 | name: build-${{ matrix.config.os }}-${{ matrix.config.version }}-${{ matrix.config.architecture }}
9 |
10 | strategy:
11 | fail-fast: false
12 | matrix:
13 | config:
14 | # The OS versions supported are specific to the version of the action
15 | # https://github.com/cross-platform-actions/action/blob/master/changelog.md
16 | - { os: haiku, version: 'r1beta5', runner: 'ubuntu-latest', architecture: 'x86-64' }
17 | - { os: haiku, version: 'r1beta5', runner: 'ubuntu-latest', architecture: 'x86' }
18 | - { os: haiku, version: 'nightly', runner: 'ubuntu-latest', architecture: 'x86-64' }
19 | - { os: haiku, version: 'nightly', runner: 'ubuntu-latest', architecture: 'x86' }
20 |
21 | steps:
22 | - uses: actions/checkout@v4
23 |
24 | - uses: korli/action@v0.25.0-haiku3
25 | with:
26 | operating_system: ${{ matrix.config.os }}
27 | version: ${{ matrix.config.version }}
28 | architecture: ${{ matrix.config.architecture }}
29 | run: |
30 | if [[ `uname -m` == BePC ]]; then
31 | ssh user@localhost "pkgman update -y haiku_x86_devel devel:libdjvulibre_x86 devel:libfreetype_x86 devel:libjbig2dec_x86 devel:libjpeg_x86 devel:libmupdf_x86 devel:libopenjp2_x86 devel:libz_x86 cmd:gcc_x86 gcc_x86_syslibs_devel cmd:as_x86" &&
32 | cd application && setarch x86 make
33 | else
34 | ssh user@localhost "pkgman update -y haiku_devel devel:libdjvulibre devel:libfreetype devel:libjbig2dec devel:libjpeg devel:libmupdf devel:libopenjp2 devel:libz cmd:gcc gcc_syslibs_devel cmd:as" &&
35 | cd application && make
36 | fi
37 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | objects*/
2 |
--------------------------------------------------------------------------------
/DocumentViewer.hvif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HaikuArchives/DocumentViewer/963d1176cdfe9aab945531633f01334eaac0a686/DocumentViewer.hvif
--------------------------------------------------------------------------------
/DocumentViewerScreenshot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HaikuArchives/DocumentViewer/963d1176cdfe9aab945531633f01334eaac0a686/DocumentViewerScreenshot.png
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | DocumentViewer
2 | =
3 |
4 | DocumentViewer is a viewer supporting PDF and DJVU files.
5 | It provides many features, making it easy to open and view documents.
6 |
7 |
8 |
9 | ## Features include:
10 | * Printing
11 | * A view panel
12 | * Zooming in and out
13 | * Fitting the page length or width
14 | * Thumbnails
15 | * Text search
16 | * A home panel giving access to more features
17 | * Offline user documentation
18 |
--------------------------------------------------------------------------------
/application/BaseEngine.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2011-2012 Haiku Inc. All rights reserved.
3 | * Distributed under the terms of the MIT License.
4 | *
5 | * Authors:
6 | * Ciprian Nedisan (cipri)
7 | *
8 | */
9 | #include "BaseEngine.h"
10 |
11 | #include "Flags.h"
12 | #include "Messages.h"
13 |
14 | using namespace std;
15 |
16 | pthread_mutex_t BaseEngine::gEngineStopMutex = PTHREAD_MUTEX_INITIALIZER;
17 | pthread_mutex_t BaseEngine::gTextSearchStopMutex = PTHREAD_MUTEX_INITIALIZER;
18 |
19 | BaseEngine::BaseEngine(void)
20 | :
21 | fStopThread(false),
22 | fZoomFactor(1),
23 | fPages(0),
24 | fRotation(0),
25 | fForwardCache(16),
26 | fBackwardCache(16),
27 | fCurrentPageNo(0),
28 | fSearchFlag(0),
29 | fDefaultRect(0, 0, 300, 500),
30 | fHighlightUnderText(false),
31 | fStopTextSearchThread(false)
32 | {
33 | fTextSearchThread = nullptr;
34 | fDrawingThread = nullptr;
35 | }
36 |
37 |
38 | BaseEngine::~BaseEngine()
39 | {
40 | StopTextSearch();
41 |
42 | for (std::pair< BBitmap*, bool> bitmap : fBitmap) {
43 | if (bitmap.first != nullptr) {
44 | delete bitmap.first;
45 | bitmap.first = nullptr;
46 | }
47 | }
48 | }
49 |
50 |
51 | void
52 | BaseEngine::Start(void)
53 | {
54 | fPages = PageCount();
55 |
56 | fBitmap.resize(fPages, std::pair((BBitmap*)nullptr, false));
57 |
58 | fMutex.resize(fPages);
59 | for (int i = 0; i < fPages; i++)
60 | pthread_mutex_init(&fMutex[i], NULL);
61 |
62 | pthread_create(&fDrawingThread, nullptr, _DrawingThread, (void*)(this));
63 | }
64 |
65 |
66 | void
67 | BaseEngine::Stop(void)
68 | {
69 | pthread_mutex_lock(&gEngineStopMutex);
70 | fStopThread = true;
71 | pthread_mutex_unlock(&gEngineStopMutex);
72 |
73 | while (true) {
74 | usleep(1000);
75 | pthread_mutex_lock(&gEngineStopMutex);
76 | if (fStopThread == false) {
77 | pthread_mutex_unlock(&gEngineStopMutex);
78 | break;
79 | }
80 | pthread_mutex_unlock(&gEngineStopMutex);
81 | }
82 | }
83 |
84 |
85 | void*
86 | BaseEngine::_DrawingThread(void* arg)
87 | {
88 | rename_thread(find_thread(NULL), "_DrawingThread");
89 |
90 | BaseEngine* engine =(BaseEngine*)arg;
91 | int& pages = engine->fPages;
92 | std::vector< std::pair >& bitmap = engine->fBitmap;
93 | std::vector< pthread_mutex_t >& mutex = engine->fMutex;
94 |
95 | int upperbound = -1;
96 | int lowerbound = -1;
97 | int pageFuture = -1;
98 | int pagePast = -1;
99 | int currentPage = -1;
100 | int deleteIndex = 0;
101 | bool forwardPriority = true;
102 |
103 | while(true) {
104 | pthread_mutex_lock(&gEngineStopMutex);
105 | if (engine->fStopThread) {
106 | engine->fStopThread = false;
107 | pthread_mutex_unlock(&gEngineStopMutex);
108 | return nullptr;
109 | }
110 | pthread_mutex_unlock(&gEngineStopMutex);
111 |
112 | if (currentPage != engine->fCurrentPageNo) {
113 | if (engine->fCurrentPageNo < currentPage)
114 | forwardPriority = false;
115 | else
116 | forwardPriority = true;
117 |
118 | deleteIndex = 0;
119 | currentPage = engine->fCurrentPageNo;
120 | pageFuture = pagePast = currentPage;
121 | lowerbound = currentPage - engine->fBackwardCache;
122 | upperbound = currentPage + engine->fForwardCache;
123 |
124 | if (lowerbound < 0) lowerbound = 0;
125 | if (upperbound >= pages) upperbound = pages - 1;
126 | } else {
127 | for (; deleteIndex < pages; ++deleteIndex) {
128 | pthread_mutex_lock(&mutex[deleteIndex]);
129 | if (bitmap[deleteIndex].first != nullptr
130 | && (deleteIndex < lowerbound || deleteIndex > upperbound)) {
131 | delete bitmap[deleteIndex].first;
132 | bitmap[deleteIndex].first = nullptr;
133 | pthread_mutex_unlock(&mutex[deleteIndex]);
134 | break;
135 | }
136 | pthread_mutex_unlock(&mutex[deleteIndex]);
137 | }
138 |
139 | if (forwardPriority) {
140 | if (pageFuture < upperbound) {
141 | ++pageFuture;
142 | pthread_mutex_lock(&mutex[pageFuture]);
143 | if (bitmap[pageFuture].first == nullptr) {
144 | bitmap[pageFuture] = engine->_RenderBitmap(pageFuture);
145 | } else if (bitmap[pageFuture].second == true) {
146 | delete bitmap[pageFuture].first;
147 | bitmap[pageFuture] = engine->_RenderBitmap(pageFuture);
148 | }
149 | pthread_mutex_unlock(&mutex[pageFuture]);
150 | } else if (pagePast > lowerbound) {
151 | --pagePast;
152 | pthread_mutex_lock(&mutex[pagePast]);
153 | if (bitmap[pagePast].first == nullptr) {
154 | bitmap[pagePast] = engine->_RenderBitmap(pagePast);
155 | } else if (bitmap[pageFuture].second == true) {
156 | delete bitmap[pageFuture].first;
157 | bitmap[pageFuture] = engine->_RenderBitmap(pageFuture);
158 | }
159 | pthread_mutex_unlock(&mutex[pagePast]);
160 | } else {
161 | usleep(1000);
162 | }
163 | } else {
164 | if (pagePast > lowerbound) {
165 | --pagePast;
166 | pthread_mutex_lock(&mutex[pagePast]);
167 | if (bitmap[pagePast].first == nullptr)
168 | bitmap[pagePast] = engine->_RenderBitmap(pagePast);
169 |
170 | pthread_mutex_unlock(&mutex[pagePast]);
171 | } else if (pageFuture < upperbound) {
172 | ++pageFuture;
173 | pthread_mutex_lock(&mutex[pageFuture]);
174 | if (bitmap[pageFuture].first == nullptr)
175 | bitmap[pageFuture] = engine->_RenderBitmap(pageFuture);
176 |
177 | pthread_mutex_unlock(&mutex[pageFuture]);
178 | } else {
179 | usleep(1000);
180 | }
181 | }
182 | }
183 | }
184 | return nullptr;
185 | }
186 |
187 |
188 | int const&
189 | BaseEngine::PageRotation(int pageNumber)
190 | {
191 | return fRotation;
192 | }
193 |
194 |
195 | void
196 | BaseEngine::SetZoom(float zoomFactor)
197 | {
198 | if (fZoomFactor == zoomFactor)
199 | return;
200 |
201 | fZoomFactor = zoomFactor;
202 | fDefaultRect.right = 300 * fZoomFactor;
203 | fDefaultRect.bottom = 500 * fZoomFactor;
204 |
205 | // Mark all existing bitmap as dirty as they need to be rendered again.
206 | for (int i = 0; i < fPages; ++i)
207 | if (fBitmap[i].first != nullptr)
208 | fBitmap[i].second = true;
209 | }
210 |
211 |
212 | BBitmap*
213 | BaseEngine::Page(int pageNumber)
214 | {
215 | if (pageNumber < 0)
216 | pageNumber = 0;
217 | else if (pageNumber >= fPages - 1)
218 | pageNumber = fPages - 1;
219 |
220 | pthread_mutex_lock(&fMutex[pageNumber]);
221 | if (fBitmap[pageNumber].first == nullptr) {
222 | fBitmap[pageNumber] = _RenderBitmap(pageNumber);
223 | } else if (fBitmap[pageNumber].second == true) {
224 | delete fBitmap[pageNumber].first;
225 | fBitmap[pageNumber] = _RenderBitmap(pageNumber);
226 | }
227 | pthread_mutex_unlock(&fMutex[pageNumber]);
228 | fCurrentPageNo = pageNumber;
229 |
230 | return fBitmap[pageNumber].first;
231 | }
232 |
233 |
234 | BRect
235 | BaseEngine::PageMediabox(int pageNumber)
236 | {
237 | BRect rect(0, 0, 1, 1);
238 |
239 | pthread_mutex_lock(&fMutex[pageNumber]);
240 | if (fBitmap[pageNumber].first != nullptr)
241 | rect = fBitmap[pageNumber].first->Bounds();
242 |
243 | pthread_mutex_unlock(&fMutex[pageNumber]);
244 |
245 | return rect;
246 | }
247 |
248 |
249 | BRect
250 | BaseEngine::PageContentBox(int pageNumber)
251 | {
252 | return PageMediabox(pageNumber);
253 | }
254 |
255 |
256 | BString
257 | BaseEngine::GetPageLabel(int pageNumber)
258 | {
259 | BString label;
260 | label << pageNumber;
261 |
262 | return label;
263 | }
264 |
265 |
266 | BString
267 | BaseEngine::FileName(void) const
268 | {
269 | return BString("");
270 | }
271 |
272 |
273 | int
274 | BaseEngine::GetPageByLabel(BString label)
275 | {
276 | return atoi(label.String());
277 | }
278 |
279 |
280 | BString
281 | BaseEngine::GetDecryptionKey(void) const
282 | {
283 | return BString("");
284 | }
285 |
286 |
287 | void
288 | BaseEngine::SetCacheSize(int forwardCache, int backwardCache)
289 | {
290 | fForwardCache = forwardCache;
291 | fBackwardCache = backwardCache;
292 | }
293 |
294 |
295 | void
296 | BaseEngine::MultiplyZoom(float factor)
297 | {
298 | SetZoom(fZoomFactor * factor);
299 | }
300 |
301 |
302 | void
303 | BaseEngine::WriteOutline(BOutlineListView* list)
304 | {
305 |
306 | }
307 |
308 | void
309 | BaseEngine::StopTextSearch(void)
310 | {
311 | if (fTextSearchThread != nullptr) {
312 | pthread_mutex_lock(&gTextSearchStopMutex);
313 | fStopTextSearchThread = true;
314 | pthread_mutex_unlock(&gTextSearchStopMutex);
315 | void* status;
316 | pthread_join(fTextSearchThread, &status);
317 | fTextSearchThread = nullptr;
318 | }
319 | }
320 |
321 | void
322 | BaseEngine::FindString(BString const& name, BLooper* looper, BHandler* handler, int32 flag)
323 | {
324 | StopTextSearch();
325 |
326 | if (name.Length() < 2)
327 | return;
328 |
329 | fSearchString = name;
330 | fSearchFlag = flag;
331 | fTargetLooper = looper;
332 | fSearchHandler = handler;
333 | fStopTextSearchThread = false;
334 | pthread_create(&fTextSearchThread, nullptr, _TextSearchThread, (void*)(this));
335 | }
336 |
337 |
338 | tuple< vector, vector >
339 | BaseEngine::_FindString(BString const& name, int const& page)
340 | {
341 | //empty
342 | return {};
343 | }
344 |
345 |
346 | void*
347 | BaseEngine::_TextSearchThread(void* arg)
348 | {
349 | rename_thread(find_thread(NULL), "_TextSearchThread");
350 |
351 | BaseEngine* engine =(BaseEngine*)arg;
352 | int& pages = engine->fPages;
353 |
354 | BString name = engine->fSearchString;
355 | for (int page = 0; page < pages; ++page) {
356 | pthread_mutex_lock(&gTextSearchStopMutex);
357 | if (engine->fStopTextSearchThread) {
358 | engine->fStopTextSearchThread = false;
359 | pthread_mutex_unlock(&gTextSearchStopMutex);
360 | break;
361 | //return nullptr;
362 | }
363 | pthread_mutex_unlock(&gTextSearchStopMutex);
364 |
365 | auto t = engine->_FindString(name, page);
366 |
367 | for (uint32 i = 0; i < get<0>(t).size(); ++i) {
368 | BMessage msg(MSG_SEARCH_RESULT);
369 | msg.AddInt32("page", page);
370 | msg.AddString("context", move(get<0>(t)[i]));
371 | msg.AddRect("rect", move(get<1>(t)[i]));
372 | engine->fTargetLooper->PostMessage(&msg, engine->fSearchHandler);
373 | }
374 | }
375 |
376 | return nullptr;
377 | }
378 |
379 |
380 | bool
381 | BaseEngine::HighlightUnderText(void)
382 | {
383 | return fHighlightUnderText;
384 | }
385 |
386 |
--------------------------------------------------------------------------------
/application/BaseEngine.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2011-2012 Haiku Inc. All rights reserved.
3 | * Distributed under the terms of the MIT License.
4 | *
5 | * Authors:
6 | * Ciprian Nedisan (cipri)
7 | *
8 | */
9 | #ifndef BASEENGINE_H
10 | #define BASEENGINE_H
11 |
12 | #include
13 | #include
14 | #include
15 | #include
16 |
17 | #include
18 | #include
19 | #include
20 | #include
21 | #include
22 | #include
23 |
24 | #include
25 | #include "Debug.h"
26 |
27 |
28 | class BaseEngine
29 | {
30 | public:
31 | BaseEngine(void);
32 | virtual ~BaseEngine();
33 |
34 | void Start(void);
35 | void Stop(void);
36 |
37 | void StopTextSearch(void);
38 |
39 | // the name of the file this engine handles
40 | virtual BString FileName(void) const;
41 | // number of pages the loaded document contains
42 | virtual int PageCount(void) const = 0;
43 |
44 | // the box containing the visible page content
45 | // (usually BRect(0, 0, pageWidth, pageHeight))
46 | virtual BRect PageMediabox(int pageNumber);
47 | // the box inside PageMediabox that actually contains any relevant content
48 | // (used for auto-cropping in Fit Content mode, can be PageMediabox)
49 | virtual BRect PageContentBox(int pageNumber);
50 |
51 | virtual void SetZoom(float zoomFactor);
52 |
53 | // the angle in degrees the given page is rotated natively (usually 0 deg)
54 | virtual int const& PageRotation(int pageNumber);
55 |
56 | virtual std::unique_ptr RenderBitmap(int const& pageNumber,uint32 const& width,
57 | uint32 const& height, int const& rotation = 0) = 0;
58 |
59 | virtual BBitmap* Page(int pageNumber);
60 |
61 | // access to various document properties (such as Author, Title, etc.)
62 | virtual BString GetProperty(BString name) { return BString(""); }
63 |
64 | virtual BString GetPageLabel(int pageNumber);
65 |
66 | // reverts GetPageLabel by returning the first page number
67 | // having the given label
68 | virtual int GetPageByLabel(BString label);
69 |
70 | // returns a string to remember when the user wants to save
71 | // a document's password (don't implement for document types
72 | // that don't support password protection)
73 | virtual BString GetDecryptionKey(void) const;
74 |
75 | virtual void SetCacheSize(int forwardCache, int backwardCache = 0);
76 | virtual void MultiplyZoom(float factor);
77 |
78 | virtual void WriteOutline(BOutlineListView* list);
79 |
80 | virtual void FindString(BString const& name, BLooper* looper, BHandler* handler,
81 | int32 flag = 0);
82 |
83 | bool HighlightUnderText(void);
84 |
85 | bool fStopThread;
86 |
87 | protected:
88 | virtual std::pair _RenderBitmap(int const& pageNumber) = 0;
89 | virtual std::tuple< std::vector, std::vector >
90 | _FindString(BString const& name, int const& page);
91 |
92 |
93 | static void* _DrawingThread(void* arg);
94 |
95 | pthread_t fDrawingThread;
96 |
97 | static pthread_mutex_t gEngineStopMutex;
98 |
99 |
100 | float fZoomFactor;
101 | int fPages;
102 | int fRotation;
103 | int fForwardCache;
104 | int fBackwardCache;
105 | int fCurrentPageNo;
106 |
107 | int32 fSearchFlag;
108 |
109 | std::vector > fBitmap;
110 | std::vector fMutex;
111 |
112 | BRect fDefaultRect;
113 | bool fHighlightUnderText;
114 |
115 | Debug out;
116 |
117 | private:
118 | static void* _TextSearchThread(void* arg);
119 |
120 | pthread_t fTextSearchThread;
121 |
122 | bool fStopTextSearchThread;
123 |
124 | static pthread_mutex_t gTextSearchStopMutex;
125 |
126 | BLooper* fTargetLooper;
127 | BHandler* fSearchHandler;
128 |
129 | BString fSearchString;
130 | };
131 |
132 | #endif
133 |
--------------------------------------------------------------------------------
/application/BookmarksView.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2011-2011 Haiku Inc. All rights reserved.
3 | * Distributed under the terms of the MIT License.
4 | *
5 | * Authors:
6 | * Ciprian Nedisan (cipri)
7 | *
8 | */
9 | #include "BookmarksView.h"
10 |
11 | #include
12 |
13 | #include "ImageButton.h"
14 | #include "Messages.h"
15 |
16 |
17 | BookmarkItem::BookmarkItem(const char* name)
18 | :
19 | BListItem(),
20 | fName(name)
21 | {
22 | }
23 |
24 |
25 | BookmarkItem::~BookmarkItem()
26 | {
27 | }
28 |
29 |
30 | void
31 | BookmarkItem::DrawItem(BView *owner, BRect itemRect, bool complete)
32 | {
33 | rgb_color kBlack = {0, 0, 0, 0};
34 | rgb_color kHighlight = {156, 154, 156, 0};
35 |
36 | if (IsSelected() || complete) {
37 | rgb_color color;
38 | if (IsSelected())
39 | color = kHighlight;
40 | else
41 | color = owner->ViewColor();
42 |
43 | owner->SetHighColor(color);
44 | owner->SetLowColor(color);
45 | owner->FillRect(itemRect);
46 | owner->SetHighColor(kBlack);
47 |
48 | } else {
49 | owner->SetLowColor(owner->ViewColor());
50 | }
51 |
52 | BFont font = be_plain_font;
53 | font_height finfo;
54 | font.GetHeight(&finfo);
55 |
56 | BPoint point = BPoint(itemRect.left + 5, itemRect.bottom - finfo.descent + 1);
57 |
58 | owner->SetHighColor(kBlack);
59 | owner->SetFont(be_plain_font);
60 | owner->MovePenTo(point);
61 |
62 | owner->MovePenTo(point);
63 | owner->DrawString(fName);
64 | }
65 |
66 |
67 | BookmarkListView::BookmarkListView(void)
68 | :
69 | BOutlineListView("bookmark_listview")
70 | {
71 |
72 | }
73 |
74 |
75 | BookmarksView::BookmarksView(void)
76 | :
77 | BGroupView("Bookmarks_view", B_VERTICAL, 0)
78 | {
79 | ImageButton* bookmarkDeleteButton = new ImageButton("quit",
80 | new BMessage(MSG_ZOOM_IN), 0.3, 1, "Delete bookmark");
81 | bookmarkDeleteButton->SetExplicitMinSize(BSize(20, 20));
82 | bookmarkDeleteButton->SetExplicitMaxSize(BSize(20, 20));
83 |
84 | ImageButton* bookmarkAddButton = new ImageButton("plus",
85 | new BMessage(MSG_ZOOM_OUT), 0.3, 1, "Add bookmark");
86 | bookmarkAddButton->SetExplicitMinSize(BSize(20, 20));
87 | bookmarkAddButton->SetExplicitMaxSize(BSize(20, 20));
88 |
89 | ImageButton* bookmarkEditButton = new ImageButton("edit",
90 | new BMessage(MSG_NO_FIT), 0.3, 1, "Edit bookmark");
91 | bookmarkEditButton->SetExplicitMinSize(BSize(20, 20));
92 | bookmarkEditButton->SetExplicitMaxSize(BSize(20, 20));
93 |
94 | BookmarkItem* item1 = new BookmarkItem("Test1");
95 | // item1->SetOutlineLevel(1);
96 | BookmarkItem* item2 = new BookmarkItem("Test2");
97 | //item2->SetOutlineLevel(0);
98 | BookmarkItem* item3 = new BookmarkItem("Test3");
99 | //item2->SetOutlineLevel(0);
100 | BookmarkItem* item4 = new BookmarkItem("Test4");
101 | BookmarkItem* item5 = new BookmarkItem("Test5");
102 |
103 | fBookmarkListView = new BookmarkListView();
104 | fBookmarkListView->AddItem(item1);
105 | fBookmarkListView->AddUnder(item3, item1);
106 | fBookmarkListView->AddUnder(item2, item1);
107 | fBookmarkListView->AddItem(item4);
108 | fBookmarkListView->AddItem(item5);
109 |
110 | fVScrollBar = new BScrollBar("v_scrollbar",
111 | fBookmarkListView, 0, 2000, B_VERTICAL);
112 | fHScrollBar = new BScrollBar("h_scrollbar",
113 | fBookmarkListView, 0, 2000, B_HORIZONTAL);
114 |
115 | fSearchTC = new BTextControl("", "", nullptr);
116 |
117 | BLayoutBuilder::Group<>(this)
118 | .AddGroup(B_HORIZONTAL, 0)
119 | .Add(bookmarkAddButton)
120 | .Add(bookmarkEditButton)
121 | .Add(bookmarkDeleteButton)
122 | .Add(fSearchTC)
123 | //.AddGlue(100)
124 | .End()
125 | .AddGroup(B_HORIZONTAL, 0)
126 | .Add(fBookmarkListView)
127 | .Add(fVScrollBar)
128 | .End()
129 | .Add(fHScrollBar)
130 | .End()
131 | ;
132 | }
133 |
--------------------------------------------------------------------------------
/application/BookmarksView.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2011-2011 Haiku Inc. All rights reserved.
3 | * Distributed under the terms of the MIT License.
4 | *
5 | * Authors:
6 | * Ciprian Nedisan (cipri)
7 | *
8 | */
9 | #ifndef BOOKMARKSVIEW_H
10 | #define BOOKMARKSVIEW_H
11 |
12 | #include
13 |
14 | extern "C" {
15 | #include
16 | }
17 |
18 | #include
19 | #include
20 | #include
21 | #include
22 | #include
23 | #include
24 |
25 | #include "Debug.h"
26 |
27 | class BookmarkItem : public BListItem
28 | {
29 | public:
30 | BookmarkItem(const char* name);
31 | ~BookmarkItem();
32 | virtual void DrawItem(BView* owner, BRect itemRect, bool = false);
33 | private:
34 | BString fName;
35 | };
36 |
37 |
38 | class BookmarkListView : public BOutlineListView
39 | {
40 | public:
41 | BookmarkListView(void);
42 |
43 | private:
44 |
45 | };
46 |
47 |
48 | class BookmarksView : public BGroupView
49 | {
50 | public:
51 | BookmarksView(void);
52 |
53 | private:
54 | BScrollBar* fVScrollBar;
55 | BScrollBar* fHScrollBar;
56 |
57 | BTextControl* fSearchTC;
58 | BookmarkListView* fBookmarkListView;
59 | };
60 |
61 | #endif
62 |
--------------------------------------------------------------------------------
/application/CircleMenuView.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2011-2011 Haiku Inc. All rights reserved.
3 | * Distributed under the terms of the MIT License.
4 | *
5 | * Authors:
6 | * Ciprian Nedisan (cipri)
7 | *
8 | */
9 |
10 | #include "CircleMenuView.h"
11 |
12 | #include
13 | #include
14 |
15 | using namespace std;
16 |
17 | CircleMenuView::CircleMenuView(BRect const& frame, int width, BString const& name)
18 | :
19 | BView(frame, name, B_FOLLOW_LEFT | B_FOLLOW_TOP,
20 | B_FULL_UPDATE_ON_RESIZE | B_WILL_DRAW | B_DRAW_ON_CHILDREN)
21 | {
22 | SetEventMask(EventMask() | B_FULL_POINTER_HISTORY);
23 | SetDrawingMode(B_OP_ALPHA);
24 | SetBlendingMode(B_PIXEL_ALPHA, B_ALPHA_OVERLAY);
25 | SetPenSize(3);
26 |
27 | fBgColor = make_color(180, 180, 255, 180);
28 | SetViewColor(fBgColor);
29 | fMarginColor = tint_color(fBgColor, B_DARKEN_4_TINT);
30 | /*
31 | m_nWidth = nWidth;
32 | m_cBounds = cFrame.Bounds();
33 |
34 | int nROut = static_cast< int >( m_cBounds.Width() / 2 );
35 | int nRIn = nROut - m_nWidth ;
36 |
37 | m_cCenter = IPoint( nROut, nROut );
38 |
39 | m_vRMiddle = nRIn + m_nWidth / 2;
40 |
41 | m_pcImage = DrawRing( nROut, nRIn, 0.0, 0.0, 0.0, 0.6 );
42 |
43 | Hide();
44 | */
45 | fCenterPoint = BPoint(frame.Width() / 2, frame.Height() / 2);
46 | fROut = std::min(frame.Width() / 2, frame.Height() / 2);
47 | fROut -= 10;
48 | fRIn = fROut- width;
49 | fRMiddle = (fROut + fRIn) / 2;
50 | if (IsHidden() == false)
51 | Hide();
52 | }
53 |
54 |
55 | void
56 | CircleMenuView::Draw(BRect updateRect)
57 | {
58 | SetHighColor(fBgColor);
59 | BPoint center(Bounds().Width()/2, Bounds().Height()/2);
60 | // FillEllipse(center, center.x, center.x - 10);
61 | FillArc(fCenterPoint, fROut, fROut, 0, 360);
62 | SetHighColor(B_TRANSPARENT_32_BIT);
63 | FillArc(fCenterPoint, fRIn, fRIn, 0, 360);
64 | SetHighColor(fMarginColor);
65 | StrokeArc(fCenterPoint, fROut, fROut, 0, 360);
66 | StrokeArc(fCenterPoint, fRIn, fRIn, 0, 360);
67 | }
68 |
69 |
70 | void
71 | CircleMenuView::MouseMoved(BPoint where, uint32 code, const BMessage* dragMessage)
72 | {
73 | BView::MouseMoved(where, code, dragMessage);
74 | if((pow((where.x - fCenterPoint.x),2) +
75 | pow((where.y - fCenterPoint.y),2)) >= pow(fROut,2)) {
76 | if (IsHidden() == false)
77 | Hide();
78 |
79 | Parent()->MakeFocus(true);
80 | }
81 | }
82 |
83 |
84 | void
85 | CircleMenuView::AddChild(BView* view)
86 | {
87 | BView::AddChild(view);
88 | AlignViews();
89 | }
90 |
91 |
92 | void
93 | CircleMenuView::RemoveChild(BView* view)
94 | {
95 |
96 |
97 | }
98 |
99 |
100 | void
101 | CircleMenuView::AlignViews(void)
102 | {
103 | if (Parent() == NULL)
104 | return;
105 |
106 | float children = CountChildren();
107 | float numberOfChild = 0;
108 | BView* child = ChildAt(0);
109 |
110 | while (child != NULL) {
111 | complex pos(polar(fRMiddle, static_cast< float >(M_PI/2) +
112 | numberOfChild*2* static_cast< float >(M_PI) / children));
113 |
114 | float width = child->Bounds().Width();
115 | float height = child->Bounds().Height();
116 |
117 | //rect.right = fCenterPoint.x + pos.real() + width/2;
118 | //rect.bottom = fCenterPoint.y - pos.imag() + height/2;
119 |
120 | child->MoveTo(fCenterPoint.x + pos.real() - width/2,
121 | fCenterPoint.y - pos.imag() - height/2);
122 | child->ResizeTo(49, 49);
123 | child->ResizeBy(1, 1);
124 | child->Invalidate();
125 | //child->Show();
126 | ++numberOfChild;
127 | child = child->NextSibling();
128 | }
129 |
130 | Invalidate();
131 | }
132 |
133 |
134 | void
135 | CircleMenuView::AttachedToWindow(void)
136 | {
137 | BView::AttachedToWindow();
138 |
139 | AlignViews();
140 | Invalidate();
141 | }
142 |
--------------------------------------------------------------------------------
/application/CircleMenuView.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2011-2011 Haiku Inc. All rights reserved.
3 | * Distributed under the terms of the MIT License.
4 | *
5 | * Authors:
6 | * Ciprian Nedisan (cipri)
7 | *
8 | */
9 |
10 | #ifndef CIRCLEMENUVIEW
11 | #define CIRCLEMENUVIEW
12 |
13 | #include
14 |
15 | #include
16 | #include
17 | #include
18 | #include
19 |
20 | #include "Debug.h"
21 |
22 | class CircleMenuView : public BView
23 | {
24 | public:
25 | CircleMenuView(BRect const& frame, int width = 60,
26 | BString const& name = "circle_menu");
27 |
28 | virtual void Draw(BRect updateRect);
29 | virtual void MouseMoved(BPoint where, uint32 code,
30 | const BMessage* dragMessage);
31 | virtual void AddChild(BView* view);
32 | virtual void RemoveChild(BView* view);
33 | virtual void AlignViews(void);
34 | virtual void AttachedToWindow(void);
35 |
36 | private:
37 | std::list fViewList;
38 | float fROut;
39 | float fRIn;
40 | float fRMiddle;
41 | BPoint fCenterPoint;
42 |
43 | rgb_color fBgColor;
44 | rgb_color fMarginColor;
45 |
46 | BGradientLinear fTransparentGradient;
47 | Debug out;
48 | };
49 |
50 | #endif
51 |
--------------------------------------------------------------------------------
/application/DJVUEngine.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2012-2012 Haiku Inc. All rights reserved.
3 | * Distributed under the terms of the MIT License.
4 | *
5 | * Authors:
6 | * Ciprian Nedisan (cipri)
7 | *
8 | */
9 | #include "DJVUEngine.h"
10 |
11 | #include
12 | #include
13 |
14 | #include "Flags.h"
15 | #include "Messages.h"
16 | #include "OutlineView.h"
17 | #include "PasswordRequestWindow.h"
18 |
19 | using namespace std;
20 |
21 | pthread_mutex_t DJVUEngine::gRendermutex;
22 |
23 | DJVUEngine::DJVUEngine(BString fileName, BString& password)
24 | :
25 | fFileName(fileName),
26 | fPassword(password)
27 | {
28 |
29 | fContext = ddjvu_context_create("DJVUEngine");
30 | ddjvu_cache_set_size(fContext, 30E6);
31 | fDocument = ddjvu_document_create_by_filename_utf8(fContext,
32 | fileName.String(), TRUE);
33 |
34 | while (!ddjvu_document_decoding_done(fDocument))
35 | _HandleDjvuMessages(fContext, true);
36 |
37 | if (ddjvu_document_decoding_error(fDocument))
38 | throw;
39 |
40 | Start();
41 | }
42 |
43 |
44 | DJVUEngine::~DJVUEngine()
45 | {
46 | Stop();
47 |
48 | ddjvu_document_release(fDocument);
49 | ddjvu_context_release(fContext);
50 |
51 | minilisp_finish();
52 | }
53 |
54 |
55 | void
56 | DJVUEngine::_HandleDjvuMessages(ddjvu_context_t *context, int wait)
57 | {
58 | if (wait)
59 | ddjvu_message_wait(context);
60 |
61 | const ddjvu_message_t *msg;
62 | while ((msg = ddjvu_message_peek(context))) {
63 | switch(msg->m_any.tag) {
64 | case DDJVU_ERROR:
65 | !out << "djvu-error: " << msg->m_error.message << endl;
66 | break;
67 |
68 | default:
69 | break;
70 | }
71 | ddjvu_message_pop(context);
72 | }
73 | }
74 |
75 |
76 | int
77 | DJVUEngine::PageCount(void) const
78 | {
79 | return ddjvu_document_get_pagenum(fDocument);
80 | }
81 |
82 |
83 | void
84 | DJVUEngine::WriteOutline(BOutlineListView* list)
85 | {
86 | std::function OutlineToList =
87 | [&OutlineToList](miniexp_t outline, BOutlineListView* list, BListItem* super, int level) {
88 | for (miniexp_t rest = outline; miniexp_consp(rest); rest = miniexp_cdr(rest)) {
89 | miniexp_t item = miniexp_car(rest);
90 | if (!miniexp_consp(item) || !miniexp_consp(miniexp_cdr(item)) ||
91 | !miniexp_stringp(miniexp_car(item)) || !miniexp_stringp(miniexp_cadr(item)))
92 | continue;
93 |
94 | BString link(miniexp_to_str(miniexp_cadr(item)));
95 | BString name(miniexp_to_str(miniexp_car(item)));
96 |
97 | link.RemoveAll("#");
98 | int pageNumber= atoi(link.String()) - 1;
99 | OutlineItem* listItem = new OutlineItem(name, pageNumber);
100 | list->AddUnder(listItem, super);
101 | OutlineToList(miniexp_cddr(item),list, listItem, level + 1);
102 | }
103 | };
104 |
105 | miniexp_t outline;
106 |
107 | while ((outline = ddjvu_document_get_outline(fDocument)) == miniexp_dummy)
108 | _HandleDjvuMessages(fContext);
109 |
110 | if (!miniexp_consp(outline) || miniexp_car(outline) != miniexp_symbol("bookmarks")) {
111 | ddjvu_miniexp_release(fDocument, outline);
112 | return;
113 | }
114 |
115 | OutlineToList(outline, list, nullptr, 0);
116 |
117 |
118 | ddjvu_miniexp_release(fDocument, outline);
119 | }
120 |
121 |
122 | BString
123 | DJVUEngine::GetProperty(BString name)
124 | {
125 | BString property;
126 |
127 | return property;
128 | }
129 |
130 |
131 | BString
132 | DJVUEngine::FileName(void) const
133 | {
134 | return fFileName;
135 | }
136 |
137 |
138 |
139 |
140 | unique_ptr
141 | DJVUEngine::RenderBitmap(int const& pageNumber,
142 | uint32 const& width, uint32 const& height, int const& rotation)
143 | {
144 | if (pageNumber < 0 || pageNumber >= fPages) {
145 | return unique_ptr(nullptr);
146 | }
147 |
148 | ddjvu_page_t *page = ddjvu_page_create_by_pageno(fDocument, pageNumber);
149 | if (!page)
150 | return unique_ptr(nullptr);
151 |
152 | while (!ddjvu_page_decoding_done(page))
153 | _HandleDjvuMessages(fContext);
154 |
155 | if (ddjvu_page_decoding_error(page))
156 | return unique_ptr(nullptr);
157 |
158 |
159 | ddjvu_rect_t prect = {0,0, width, height};
160 |
161 | if (prect.w <= 0) {
162 | if (prect.h <= 0)
163 | throw "DJVUEngine::RenderBitmap - illegal size";
164 |
165 | prect.w = prect.h * ddjvu_page_get_width(page) / ddjvu_page_get_height(page);
166 | } else if (prect.h <= 0) {
167 | prect.h = prect.w * ddjvu_page_get_height(page) / ddjvu_page_get_width(page);
168 | }
169 |
170 |
171 | ddjvu_rect_t rrect = prect;
172 |
173 | BBitmap* bitmap;
174 | ddjvu_render_mode_t mode;
175 | ddjvu_format_t *fmt;
176 |
177 | if (DDJVU_PAGETYPE_BITONAL == ddjvu_page_get_type(page)) {
178 | bitmap = new BBitmap(BRect(0, 0, prect.w - 1, prect.h - 1), B_GRAY8);
179 | fmt = ddjvu_format_create(DDJVU_FORMAT_GREY8, 0, NULL);
180 | mode = DDJVU_RENDER_MASKONLY;
181 | } else {
182 | bitmap = new BBitmap(BRect(0, 0, prect.w - 1, prect.h - 1), B_RGB24);
183 | fmt = ddjvu_format_create(DDJVU_FORMAT_BGR24, 0, NULL);
184 | mode = DDJVU_RENDER_COLOR;
185 | }
186 |
187 | ddjvu_format_set_row_order(fmt, TRUE);
188 |
189 | if (!ddjvu_page_render(page, mode, &prect, &rrect, fmt, bitmap->BytesPerRow(),
190 | (char*)bitmap->Bits()))
191 | return unique_ptr(nullptr);
192 |
193 | ddjvu_format_release(fmt);
194 | ddjvu_page_release(page);
195 |
196 | return unique_ptr(bitmap);
197 | }
198 |
199 |
200 | std::pair
201 | DJVUEngine::_RenderBitmap(int const& pageNumber)
202 | {
203 | pthread_mutex_lock(&gRendermutex);
204 |
205 | ddjvu_page_t *page = ddjvu_page_create_by_pageno(fDocument, pageNumber);
206 | if (!page) {
207 | pthread_mutex_unlock(&gRendermutex);
208 | return std::pair(new BBitmap(fDefaultRect, B_RGBA32), false);
209 | }
210 |
211 | while (!ddjvu_page_decoding_done(page))
212 | _HandleDjvuMessages(fContext);
213 |
214 | if (ddjvu_page_decoding_error(page)) {
215 | pthread_mutex_unlock(&gRendermutex);
216 | return std::pair(new BBitmap(fDefaultRect, B_RGBA32), false);
217 | }
218 |
219 | ddjvu_rect_t prect = {0, 0, 0, 0};
220 | prect.w = ddjvu_page_get_width(page) * fZoomFactor * 0.1;
221 | prect.h = ddjvu_page_get_height(page) * fZoomFactor * 0.1;
222 | ddjvu_rect_t rrect = prect;
223 |
224 | BBitmap* bitmap;
225 | ddjvu_render_mode_t mode;
226 | ddjvu_format_t *fmt;
227 |
228 | if (DDJVU_PAGETYPE_BITONAL == ddjvu_page_get_type(page)) {
229 | bitmap = new BBitmap(BRect(0, 0, prect.w - 1, prect.h - 1), B_GRAY8);
230 | fmt = ddjvu_format_create(DDJVU_FORMAT_GREY8, 0, NULL);
231 | mode = DDJVU_RENDER_MASKONLY;
232 | } else {
233 | bitmap = new BBitmap(BRect(0, 0, prect.w - 1, prect.h - 1), B_RGB24);
234 | fmt = ddjvu_format_create(DDJVU_FORMAT_BGR24, 0, NULL);
235 | mode = DDJVU_RENDER_COLOR;
236 | }
237 |
238 | ddjvu_format_set_row_order(fmt, /* top_to_bottom */ TRUE);
239 |
240 | if (!ddjvu_page_render(page, mode, &prect, &rrect, fmt, bitmap->BytesPerRow(),
241 | (char*)bitmap->Bits())) {
242 | pthread_mutex_unlock(&gRendermutex);
243 | return std::pair(new BBitmap(fDefaultRect, B_RGBA32), false);
244 | }
245 | ddjvu_format_release(fmt);
246 | ddjvu_page_release(page);
247 | pthread_mutex_unlock(&gRendermutex);
248 |
249 | return std::pair(bitmap, false);
250 | }
251 |
252 |
253 | tuple< vector, vector >
254 | DJVUEngine::_FindString(BString const& name, int const& page)
255 | {
256 | vector contextVec;
257 | vector rectVec;
258 |
259 | vector textVec;
260 |
261 | bool needWholeWord = false;
262 | if (GHasFlag(fSearchFlag, SEARCH_WHOLE_WORD))
263 | needWholeWord = true;
264 |
265 | bool needMatchCase = false;
266 | if (GHasFlag(fSearchFlag, SEARCH_MATCH_CASE))
267 | needMatchCase = true;
268 |
269 | float pageWidth = 1;
270 | float pageHeight = 1;
271 |
272 | function _SearchInExpression =
273 | [&](miniexp_t expression) {
274 | miniexp_t type = miniexp_car(expression);
275 | if (!miniexp_symbolp(type))
276 | return;
277 |
278 | expression = miniexp_cdr(expression);
279 | BRect rect;
280 |
281 | rect.left = miniexp_to_int(miniexp_car(expression));
282 | expression = miniexp_cdr(expression);
283 | rect.bottom = miniexp_to_int(miniexp_car(expression));
284 | expression = miniexp_cdr(expression);
285 | rect.right = miniexp_to_int(miniexp_car(expression));
286 | expression = miniexp_cdr(expression);
287 | rect.top = miniexp_to_int(miniexp_car(expression));
288 | expression = miniexp_cdr(expression);
289 | Debug out;
290 | miniexp_t str = miniexp_car(expression);
291 |
292 | if (miniexp_symbol("page") == type) {
293 | pageWidth = rect.Width();
294 | pageHeight = -rect.Height();
295 | }
296 |
297 |
298 | if (miniexp_stringp(str) && !miniexp_cdr(expression)) {
299 | BString tempStr = miniexp_to_str(str);
300 | bool foundMatch = false;
301 | if (needMatchCase) {
302 | if (tempStr.FindFirst(name) != B_ERROR) {
303 | if (needWholeWord) {
304 | if (tempStr.Length() == name.Length())
305 | foundMatch = true;
306 | } else {
307 | foundMatch = true;
308 | }
309 | }
310 | } else {
311 | if (tempStr.IFindFirst(name) != B_ERROR) {
312 | if (needWholeWord) {
313 | if (tempStr.Length() == name.Length())
314 | foundMatch = true;
315 | } else {
316 | foundMatch = true;
317 | }
318 | }
319 | }
320 |
321 | if (foundMatch) {
322 | rect.left = rect.left / pageWidth;
323 | rect.right = rect.right/ pageWidth;
324 | rect.top = (pageHeight - rect.top) / pageHeight;
325 | rect.bottom = (pageHeight - rect.bottom) / pageHeight;
326 | rectVec.push_back(rect);
327 | }
328 |
329 | textVec.push_back(move(tempStr));
330 | expression = miniexp_cdr(expression);
331 | }
332 |
333 | while (miniexp_consp(str)) {
334 | _SearchInExpression(str);
335 | expression = miniexp_cdr(expression);
336 | str = miniexp_car(expression);
337 | }
338 |
339 | return;
340 | };
341 |
342 | auto _SearchInPage = [&](int page) {
343 | miniexp_t pagetext;
344 | while ((pagetext = ddjvu_document_get_pagetext(fDocument, page, "word")) == miniexp_dummy)
345 | _HandleDjvuMessages(fContext, true);
346 |
347 | if (miniexp_nil == pagetext)
348 | return;
349 |
350 | _SearchInExpression(pagetext);
351 |
352 | ddjvu_miniexp_release(fDocument, pagetext);
353 | };
354 |
355 | _SearchInPage(page);
356 |
357 | int deltaIndexLeft = 4;
358 | int deltaIndexRight = 4;
359 |
360 | bool foundMatch = false;
361 |
362 | for (uint32 i = 0; i < textVec.size(); ++i) {
363 | foundMatch = false;
364 |
365 | if (needMatchCase) {
366 | if (textVec[i].FindFirst(name) != B_ERROR) {
367 | if (needWholeWord) {
368 | if (textVec[i].Length() == name.Length())
369 | foundMatch = true;
370 | } else {
371 | foundMatch = true;
372 | }
373 | }
374 | } else {
375 | if (textVec[i].IFindFirst(name) != B_ERROR) {
376 | if (needWholeWord) {
377 | if (textVec[i].Length() == name.Length())
378 | foundMatch = true;
379 | } else {
380 | foundMatch = true;
381 | }
382 | }
383 | }
384 |
385 | if (foundMatch == true) {
386 | int from = i - deltaIndexLeft;
387 | if (from < 0)
388 | from = 0;
389 |
390 | uint32 to = i + deltaIndexRight;
391 | if (to >= textVec.size())
392 | to = textVec.size() - 1;
393 |
394 | BString str;
395 | for (uint32 j = from; j < to; ++j) {
396 | str += textVec[j];
397 | str += " ";
398 | }
399 |
400 | str += textVec[to];
401 |
402 | contextVec.push_back(str);
403 | }
404 | }
405 |
406 | return make_tuple(contextVec, rectVec);
407 | }
408 |
--------------------------------------------------------------------------------
/application/DJVUEngine.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2012-2012 Haiku Inc. All rights reserved.
3 | * Distributed under the terms of the MIT License.
4 | *
5 | * Authors:
6 | * Ciprian Nedisan (cipri)
7 | *
8 | */
9 | #ifndef DJVUENGINE_H
10 | #define DJVUENGINE_H
11 |
12 | #include
13 |
14 | #include
15 |
16 | #include
17 | #include
18 |
19 | #include "BaseEngine.h"
20 | #include "Debug.h"
21 |
22 | class DJVUEngine : public BaseEngine
23 | {
24 | public:
25 | DJVUEngine(BString filename, BString& password);
26 |
27 | virtual ~DJVUEngine();
28 |
29 | virtual BString FileName(void) const;
30 | int PageCount(void) const;
31 |
32 | virtual BString GetProperty(BString name);
33 |
34 | virtual void WriteOutline(BOutlineListView* list);
35 |
36 | virtual std::unique_ptr RenderBitmap(int const& pageNumber,uint32 const& width,
37 | uint32 const& height, int const& rotation = 0);
38 |
39 | private:
40 | virtual std::pair _RenderBitmap(int const& pageNumber);
41 |
42 | virtual std::tuple< std::vector, std::vector >
43 | _FindString(BString const& name, int const& page);
44 |
45 | void _HandleDjvuMessages(ddjvu_context_t *context,
46 | int wait = false);
47 |
48 | BString fFileName;
49 | BString fPassword;
50 |
51 | ddjvu_context_t* fContext;
52 | ddjvu_document_t* fDocument;
53 |
54 | static pthread_mutex_t gRendermutex;
55 |
56 | Debug out;
57 | };
58 |
59 | #endif
60 |
--------------------------------------------------------------------------------
/application/Debug.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2011-2011 Haiku Inc. All rights reserved.
3 | * Distributed under the terms of the MIT License.
4 | *
5 | * Authors:
6 | * Ciprian Nedisan (cipri)
7 | *
8 | */
9 | #ifndef DEBUG_H
10 | #define DEBUG_H
11 |
12 | #include
13 | #include
14 | #include
15 |
16 | using std::endl;
17 |
18 | #if DEBUG == 1
19 |
20 | class Debug
21 | {
22 | public:
23 | Debug(void)
24 | :
25 | fStr(""),
26 | fState(true)
27 | {
28 |
29 | }
30 |
31 | Debug(BString str)
32 | :
33 | fStr(""),
34 | fState(true)
35 | {
36 | std::cout << str.String() << std::endl;
37 | }
38 |
39 |
40 | Debug& operator<<(std::ostream& (*f)(std::ostream&))
41 | {
42 | std::cout<
13 | #include
14 |
15 | #include
16 | #include
17 | #include
18 |
19 | #include "BaseEngine.h"
20 | #include "CircleMenuView.h"
21 | #include "Debug.h"
22 | #include "ImageButton.h"
23 |
24 |
25 | class BasicDocumentView : public BView
26 | {
27 | public:
28 | BasicDocumentView(BString filename, BString fileType,
29 | BString& password);
30 | ~BasicDocumentView();
31 |
32 | virtual void Draw(BRect updateRect);
33 | virtual void FrameResized(float newWidth, float newHeight);
34 | virtual void KeyDown(const char* bytes, int32 numBytes);
35 | virtual void MessageReceived(BMessage* message);
36 | virtual void MouseDown(BPoint where);
37 | virtual void MouseUp(BPoint where);
38 | virtual void MouseMoved(BPoint where, uint32 code,
39 | const BMessage* dragMessage);
40 | virtual void ScrollTo(BPoint where);
41 | virtual void AllAttached(void);
42 | virtual void Pulse();
43 |
44 | void SetFile(const BString& file, BString const& fileType,
45 | BString& password);
46 |
47 | friend class DocumentView;
48 |
49 | enum {
50 | M_INIT = 'ii01'
51 | };
52 |
53 | private:
54 | void _GoToPage(int32 pageNumber);
55 | void _NotifyPageChange(const int& pageNumber);
56 | void _SetScrollBarAtPage(int pageNumber);
57 | void _ShowPage(const int& pagenumber);
58 | void _ShowCurrentPage(void);
59 | void _AdaptScrollBarRange(void);
60 | void _AdaptCache(void);
61 | void _FitPageHeight(void);
62 | void _FitPageWidth(void);
63 | void _ScrollDownBigStep(void);
64 | void _ScrollDownSmallStep(void);
65 | void _ScrollUpBigStep(void);
66 | void _ScrollUpSmallStep(void);
67 |
68 | // BRect _PageFrame(const int& pageNumber);
69 | BRect _PageFrame(BBitmap* bitmap, const int& pageNumber);
70 |
71 | std::unique_ptr fEngine;
72 | CircleMenuView* fCircleMenu;
73 |
74 |
75 | BPoint fOldMousePos;
76 | uint32 fMouseButtons;
77 | uint32 fCurrentFit;
78 |
79 | float fZoomFactor;
80 | float fZoomStep;
81 | float fSmallScrollStep;
82 |
83 | int fCurrentPageNumber;
84 | bool fIsPanning;
85 | bool fIsHPanning;
86 | bool fIsVPanning;
87 | bool fNeedsResize;
88 | bool fIsPrinting;
89 | bool fHighlightUnderText;
90 |
91 | std::tuple fHighlightRect;
92 |
93 | Debug out;
94 | };
95 |
96 |
97 | class DocumentView : public BGroupView
98 | {
99 | public:
100 | DocumentView(BString filename, BString fileType, BString& password);
101 | virtual void MessageReceived(BMessage* message);
102 | virtual void FileChanged(const BString& file, BString const& fileType,
103 | BString& password);
104 |
105 | void Print(void);
106 | int PageCount(void);
107 |
108 | BBitmap* ImagePage(int const& pageNumber, float const& height = 500);
109 |
110 |
111 |
112 | std::unique_ptr
113 | Cover(float const& height = 500);
114 |
115 | virtual void MakeFocus(bool focus);
116 |
117 | const int& CurrentPageNumber(void);
118 |
119 | private:
120 | BasicDocumentView* fBasicDocumentView;
121 | BScrollBar* fVScrollBar;
122 | BScrollBar* fHScrollBar;
123 |
124 | Debug out;
125 | };
126 |
127 | #endif
128 |
--------------------------------------------------------------------------------
/application/DocumentViewer.rdef:
--------------------------------------------------------------------------------
1 | resource app_flags B_MULTIPLE_LAUNCH;
2 |
3 | resource app_version {
4 | major = 0,
5 | middle = 3,
6 | minor = 0,
7 |
8 | variety = B_APPV_ALPHA,
9 | internal = 1,
10 |
11 | short_info = "DocumentViewer",
12 | long_info = "DocumentViewer based on MuPDF DjVuLibre libCHM ebook-tools"
13 | };
14 |
15 | resource app_signature "application/x-vnd.documentviewer";
16 |
17 | resource file_types message {
18 | "types" = "application/x-pdf",
19 | "types" = "application/pdf",
20 | "types" = "application/x-djvu",
21 | "types" = "application/vnd.ms-xpsdocument"
22 | };
23 |
24 | resource vector_icon {
25 | $"6E6369661F03010000020016023CC7EE389BC0BA16573E39B04977C842ADC700"
26 | $"FFFFD3020016023C529D3753A2B8966F3D9D074B6044496AAF0047FFA0020016"
27 | $"02BC4E76BC411B3C90DABCA00D47587D4ABA850090FFD40200160238313C3B5C"
28 | $"F0BFCD963C7AAC4C13943FCAF901ECFFC3054B04016B020006033E2F99387F17"
29 | $"BA42DB3FF5B94A0E32482C90001D1E2C3D454658FF010101020006023879063B"
30 | $"8224BE2CC83B10DB4A1F6F49B89400242222FF9A9A9A020006033C69A6000000"
31 | $"0000003E186148800049800000D4CECE58F3F3F3FFD9D9D9038DFF0603FF0000"
32 | $"05FF05010200160338D2F73CD163BF82B23B84A94B88504870C900D6BDF5FFE6"
33 | $"020116023E49240000000000003CAAAA4940004A3000FFEA7CA3040192020016"
34 | $"023A55A6BAC2293F0DA33E958646C2EB47A1D60001FF9E035C020203FF050505"
35 | $"0104005305000200160338D2F73CD163BF82B23B84A94B88504870C900E7BDFF"
36 | $"FFEB0501020106023E49240000000000003CAAAA4940004A30007CFFC0C0FFF4"
37 | $"F4F4040192020016023A55A6BAC2293F0DA33E958646C2EB47A1D60001FF9E05"
38 | $"FF020006023B61A038E755B9F2003C4C154AC9623D6A0500FF6D6DFFDA1C1C02"
39 | $"00060239658D3E8928BDB2D1387A224A2B6346C66B6B06F8B7FF1467FF270000"
40 | $"00000A062228224A485E525252302C220A042228483852302C220A044838485E"
41 | $"525252300A042228224A485E48380A04453A45572446242C0A04B560C1592446"
42 | $"242CB569B8200A0445544557244626440A04453A45542644B569B8200A043826"
43 | $"3D234E28492C080438263D234E284E2E0A03492C4E284E2E0802425843C9830A"
44 | $"06486054606052CA1BC5B95C4D524800000206403B383A483C4E38523C4C3643"
45 | $"3E473A3E433E4B3A4B434B3B3D3E42BCBBBCD833353534B87EBC670A04B77BBB"
46 | $"B7B7E137B77BBC9CB722370A04B77BBBB7B7E137B77BBC9CB7223702044030C3"
47 | $"4530BC3A30304030BC3A30C3454050BC3A50C34550504050C34550BC3A000002"
48 | $"044030C34530BC3A30304030BC3A30C3454050BC3A50C34550504050C34550BC"
49 | $"3A0A04B722B9F9B609BB11B722BC43B854BB1E0606AE0BB40BBF4D33C3AEB75C"
50 | $"C172BDEFC606C13EC804CA27BD82C117B920C51BBB40BF06B8073AB6BC0605AE"
51 | $"02B57D3EB9B9C3EFB7BB44BBB751BD75C936CA8DC1B0402F0A093B593D5BBFCD"
52 | $"C93D455BC516C5F060465B435D4544510A045A425E3F5A3D5740080238333D2E"
53 | $"08023D36413208024139463408023A484A3708023E4B4E390802424E4F3F0606"
54 | $"F60F3E3022492444244D245A2255225A225A305A30553049324D3244320404B6"
55 | $"412E2745294526452C422B0604F649272E4E2C4E2F4E2C4E294EB71B4E260803"
56 | $"522E522756270802522B552B0A04283E3E4C50383A2E100A06010E000A00010B"
57 | $"1001178400040A04010A000A05010C000A0001021001178400040A010103000A"
58 | $"020104000A03020506000A070109000A080107000A090108000A0A010D1815FF"
59 | $"01178220040A0C020F09000A180121123F79990000000000003F7999C8240048"
60 | $"F40001178402040A1D0121023F79990000000000003F7999C8240048F4000A1C"
61 | $"04242223251A3F79990000000000003F7999C8240048F40015FF0117822204"
62 | };
63 |
--------------------------------------------------------------------------------
/application/DocumentViewer_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HaikuArchives/DocumentViewer/963d1176cdfe9aab945531633f01334eaac0a686/application/DocumentViewer_icon.png
--------------------------------------------------------------------------------
/application/Flags.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2012-2012 Haiku Inc. All rights reserved.
3 | * Distributed under the terms of the MIT License.
4 | *
5 | * Authors:
6 | * Ciprian Nedisan (cipri)
7 | *
8 | */
9 | #ifndef FLAGS_H
10 | #define FLAGS_H
11 |
12 | inline bool GHasFlag(int const& kValue, int const& kFlag)
13 | {
14 | return ((kValue & kFlag) == kFlag);
15 | }
16 |
17 | const int SEARCH_MATCH_CASE = 1 << 0 ;
18 | const int SEARCH_WHOLE_WORD = 1 << 1 ;
19 |
20 | #endif
21 |
--------------------------------------------------------------------------------
/application/ImageButton.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2011-2011 Haiku Inc. All rights reserved.
3 | * Distributed under the terms of the MIT License.
4 | *
5 | * Authors:
6 | * Ciprian Nedisan (cipri)
7 | *
8 | */
9 | #include "ImageButton.h"
10 |
11 | #include
12 |
13 | #include
14 |
15 | #include
16 | #include
17 | #include
18 | #include
19 |
20 | #include "Tools.h"
21 |
22 | using namespace std;
23 |
24 | ImageButton::ImageButton(BString imageName,BMessage *message,
25 | float marginProportion, int frameBehaviour,
26 | const char* tooltip, const char* name, uint32 flags)
27 | :
28 | BButton(name, "", message, flags),
29 | fImageName(imageName),
30 | fBitmap(nullptr),
31 | fMarginProportion(1 - marginProportion),
32 | fFrameBehaviour(frameBehaviour),
33 | fMouseState(MOUSE_OUTSIDE),
34 | fShowFrame(false),
35 | fLongPush(false),
36 | fLongPushLimit(500)
37 | {
38 | SetExplicitMaxSize(BSize(B_SIZE_UNLIMITED, B_SIZE_UNLIMITED));
39 | SetExplicitPreferredSize(BSize(50, 30));
40 |
41 | //SetViewColor(B_TRANSPARENT_32_BIT);
42 | SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR));
43 | SetDrawingMode(B_OP_ALPHA);
44 | SetBlendingMode(B_PIXEL_ALPHA, B_ALPHA_OVERLAY);
45 | /*
46 | BScreen screen;
47 |
48 | monitor_info info;
49 | screen.GetMonitorInfo(&info);
50 |
51 | !out << "Width: " << info.width << " Height " << info.height << std::endl;
52 | */
53 |
54 | fTimer = unique_ptr(new Timer);
55 |
56 | fGradientHighlight.SetStart(0, 0);
57 | fGradientPressed.SetStart(0, 0);
58 |
59 | if (tooltip != NULL)
60 | SetToolTip(tooltip);
61 | }
62 |
63 |
64 | void
65 | ImageButton::Draw(BRect updateRect)
66 | {
67 | switch (fFrameBehaviour) {
68 | case 0: case 1:
69 | break;
70 |
71 | case 2:
72 |
73 |
74 | break;
75 |
76 | default:
77 | break;
78 | }
79 |
80 |
81 | switch (fFrameBehaviour) {
82 | case 0:
83 | BButton::Draw(updateRect);
84 | break;
85 |
86 | case 1:
87 | if (fMouseState == MOUSE_OUTSIDE) {
88 | SetHighColor(Parent()->ViewColor());
89 | FillRect(Bounds());
90 | } else {
91 | BButton::Draw(updateRect);
92 | }
93 | break;
94 |
95 | case 2:
96 | switch (fMouseState) {
97 | case MOUSE_OUTSIDE:
98 | if (Parent()->ViewColor().alpha == 255) {
99 | SetHighColor(Parent()->ViewColor());
100 | FillRect(Bounds());
101 | }
102 | break;
103 |
104 | case MOUSE_INSIDE:
105 | FillEllipse(Bounds(), fGradientHighlight);
106 | break;
107 |
108 | case MOUSE_PRESSED:
109 | FillEllipse(Bounds(), fGradientPressed);
110 | SetHighColor(fMarginColor);
111 | StrokeEllipse(Bounds());
112 | break;
113 |
114 | default:
115 | break;
116 | }
117 | break;
118 |
119 | default:
120 | break;
121 | }
122 |
123 | if (fBitmap == nullptr)
124 | fBitmap = Tools::LoadBitmap(fImageName, fImageRect.Width());
125 |
126 | DrawBitmapAsync(fBitmap, fImageRect.LeftTop() + fOffset);
127 |
128 | Sync();
129 | }
130 |
131 |
132 | void
133 | ImageButton::AttachedToWindow(void)
134 | {
135 | BButton::AttachedToWindow();
136 | if (Parent() != nullptr)
137 | fBgColor = Parent()->ViewColor();
138 | else
139 | fBgColor = ViewColor();
140 |
141 | fGradientHighlight.AddColor(tint_color(fBgColor, B_LIGHTEN_1_TINT), 0);
142 | fGradientHighlight.AddColor(tint_color(fBgColor, B_DARKEN_3_TINT), 255);
143 |
144 | fGradientPressed.AddColor(tint_color(fBgColor, B_DARKEN_1_TINT), 0);
145 | fGradientPressed.AddColor(tint_color(fBgColor, B_DARKEN_4_TINT), 255);
146 |
147 | fMarginColor = tint_color(fBgColor, B_DARKEN_2_TINT);
148 | }
149 |
150 |
151 | void
152 | ImageButton::MouseMoved(BPoint where, uint32 code, const BMessage* dragMessage)
153 | {
154 |
155 | switch (code) {
156 | case B_EXITED_VIEW:
157 | MakeFocus(false);
158 | fMouseState = MOUSE_OUTSIDE;
159 | Invalidate();
160 | break;
161 |
162 | case B_ENTERED_VIEW:
163 | fMouseState = MOUSE_INSIDE;
164 | Invalidate();
165 | break;
166 |
167 | default:
168 | break;
169 | }
170 |
171 | BButton::MouseMoved(where, code, dragMessage);
172 | }
173 |
174 |
175 | void
176 | ImageButton::MouseUp(BPoint where)
177 | {
178 | if (fTimer->MS() > fLongPushLimit)
179 | fLongPush = true;
180 |
181 | fMouseState = MOUSE_INSIDE;
182 | fShowFrame = false;
183 | fOffset = BPoint(0, 0);
184 | Invalidate();
185 | BButton::MouseUp(where);
186 | }
187 |
188 |
189 | void
190 | ImageButton::MouseDown(BPoint where)
191 | {
192 | fTimer->Restart();
193 | fMouseState = MOUSE_PRESSED;
194 | fLongPush = false;
195 | fShowFrame = true;
196 | fOffset = BPoint(1, 1);
197 | Invalidate();
198 | BButton::MouseDown(where);
199 | }
200 |
201 |
202 | bool
203 | ImageButton::PushedLong(void)
204 | {
205 | return fLongPush;
206 | }
207 |
208 | void
209 | ImageButton::FrameResized(float newWidth, float newHeight)
210 | {
211 | BButton::FrameResized(newWidth, newHeight);
212 |
213 | int width = std::min(newWidth, newHeight) * fMarginProportion;
214 | fImageRect = BRect(0, 0, width, width);
215 |
216 | fImageRect.OffsetTo((newWidth - width)/2, (newHeight - width)/2);
217 |
218 | delete fBitmap;
219 | fBitmap = Tools::LoadBitmap(fImageName, fImageRect.Width());
220 | if (fBitmap == nullptr)
221 | !out << "Bitmap == nullptr" << std::endl;
222 | Invalidate();
223 |
224 | fGradientHighlight.SetEnd(0, newHeight);
225 | fGradientPressed.SetEnd(0, newHeight);
226 | }
227 |
228 |
229 | BBitmap*
230 | ImageButton::_RescaleBitmap(const BBitmap* src, int32 width, int32 height)
231 | {
232 | if (!src || !src->IsValid())
233 | return nullptr;
234 |
235 | BRect srcSize = src->Bounds();
236 |
237 | if (height < 0) {
238 | float srcProp = srcSize.Height()/srcSize.Width();
239 | height = (int32)(width * ceil(srcProp));
240 | }
241 |
242 | BBitmap* res = new BBitmap(BRect(0, 0, (float)width, (float)height),
243 | src->ColorSpace());
244 |
245 | float dx = (srcSize.Width() + 1)/(float)(width + 1);
246 | float dy = (srcSize.Height() + 1)/(float)(height + 1);
247 | uint8 bpp = (uint8)(src->BytesPerRow()/ceil(srcSize.Width()));
248 |
249 | int srcYOff = src->BytesPerRow();
250 | int dstYOff = res->BytesPerRow();
251 |
252 | void* dstData = res->Bits();
253 | void* srcData = src->Bits();
254 |
255 | for (int32 y = 0; y <= height; y++) {
256 | void* dstRow = (void*)((uintptr_t)dstData + (uintptr_t)(y * dstYOff));
257 | void* srcRow = (void*)((uintptr_t)srcData + ((uintptr_t)(y * dy) * srcYOff));
258 |
259 | for (int32 x = 0; x <= width; x++)
260 | memcpy((void*)((uintptr_t)dstRow + (x * bpp)), (void*)((uintptr_t)srcRow
261 | + ((uintptr_t)(x * dx) * bpp)), bpp);
262 | }
263 |
264 | return res;
265 | }
266 |
--------------------------------------------------------------------------------
/application/ImageButton.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2011-2012 Haiku Inc. All rights reserved.
3 | * Distributed under the terms of the MIT License.
4 | *
5 | * Authors:
6 | * Ciprian Nedisan (cipri)
7 | *
8 | */
9 | #ifndef IMAGEBUTTON_H
10 | #define IMAGEBUTTON_H
11 |
12 | #include
13 |
14 | #include
15 | #include
16 | #include
17 | #include
18 | #include
19 | #include
20 | #include
21 |
22 |
23 |
24 | #include "Debug.h"
25 | #include "Timer.h"
26 |
27 | class ImageButton : public BButton
28 | {
29 | public:
30 | ImageButton(BString imageName, BMessage *message = nullptr,
31 | float marginProportion = 0, int frameBehaviour = 0,
32 | const char* tooltip = NULL,
33 | const char* name = "im_button",
34 | uint32 flags = B_FRAME_EVENTS | B_WILL_DRAW
35 | | B_NAVIGABLE |B_FULL_UPDATE_ON_RESIZE
36 | | B_DRAW_ON_CHILDREN);
37 |
38 | virtual void Draw(BRect updateRect);
39 | virtual void AttachedToWindow(void);
40 | virtual void MouseMoved(BPoint where, uint32 code,
41 | const BMessage* dragMessage);
42 | virtual void MouseUp(BPoint where);
43 | virtual void MouseDown(BPoint where);
44 |
45 | virtual void FrameResized(float newWidth, float newHeight);
46 |
47 | bool PushedLong(void);
48 |
49 | private:
50 | BBitmap* _RescaleBitmap(const BBitmap* src, int32 width,
51 | int32 height);
52 |
53 | BString fImageName;
54 | BBitmap* fBitmap;
55 | BRect fImageRect;
56 | BPoint fOffset;
57 | float fMarginProportion;
58 | int fFrameBehaviour;
59 |
60 | BGradientLinear fGradientHighlight;
61 | BGradientLinear fGradientPressed;
62 |
63 | std::unique_ptr fTimer;
64 |
65 | rgb_color fBgColor;
66 | rgb_color fHighlightColor;
67 | rgb_color fButtonPressedColor;
68 | rgb_color fMarginColor;
69 |
70 | enum {
71 | MOUSE_OUTSIDE, MOUSE_INSIDE, MOUSE_PRESSED
72 | };
73 |
74 | int fMouseState;
75 | bool fShowFrame;
76 | bool fLongPush;
77 | double fLongPushLimit;
78 |
79 | Debug out;
80 | };
81 |
82 | #endif
83 |
--------------------------------------------------------------------------------
/application/ImagePopUp.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2011-2011 Haiku Inc. All rights reserved.
3 | * Distributed under the terms of the MIT License.
4 | *
5 | * Authors:
6 | * Ciprian Nedisan (cipri)
7 | *
8 | */
9 |
10 | #include "ImagePopUp.h"
11 |
12 | #include
13 |
14 | ImagePopUp::ImagePopUp(const char* name, const char* label, BMessage* message,
15 | uint32 flags)
16 | :
17 | BOptionControl(name, label, message, flags)
18 | {
19 |
20 | }
21 |
22 |
23 | ImagePopUp::~ImagePopUp()
24 | {
25 |
26 | }
27 |
28 |
29 | void
30 | ImagePopUp::Draw(BRect updateRect)
31 | {
32 | SetHighColor(255, 255, 255, 255);
33 | FillRect(Bounds());
34 | }
35 |
36 | void
37 | ImagePopUp::MessageReceived(BMessage* message)
38 | {
39 |
40 | }
41 |
42 |
43 | status_t
44 | ImagePopUp::AddOption(const char* name, int32 value)
45 | {
46 |
47 | return 0;
48 | }
49 |
50 |
51 | bool
52 | ImagePopUp::GetOptionAt(int32 index, const char** _name, int32* _value)
53 | {
54 |
55 | return true;
56 | }
57 |
58 |
59 | void
60 | ImagePopUp::RemoveOptionAt(int32 index)
61 | {
62 |
63 |
64 | }
65 |
66 |
67 | int32
68 | ImagePopUp::CountOptions() const
69 | {
70 |
71 | return 0;
72 | }
73 |
74 |
75 | status_t
76 | ImagePopUp::AddOptionAt(const char* name, int32 value, int32 index)
77 | {
78 |
79 | return 0;
80 | }
81 |
82 |
83 | int32
84 | ImagePopUp::SelectedOption(const char** name, int32* outValue) const
85 | {
86 |
87 | return 0;
88 | }
89 |
--------------------------------------------------------------------------------
/application/ImagePopUp.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2011-2011 Haiku Inc. All rights reserved.
3 | * Distributed under the terms of the MIT License.
4 | *
5 | * Authors:
6 | * Ciprian Nedisan (cipri)
7 | *
8 | */
9 | #ifndef IMAGEPOPUP_H
10 | #define IMAGEPOPUP_H
11 |
12 | #include
13 | #include
14 |
15 | class ImagePopUp : public BOptionControl
16 | {
17 | public:
18 | ImagePopUp(const char* name,
19 | const char* label, BMessage* message,
20 | uint32 flags = B_WILL_DRAW);
21 | virtual ~ImagePopUp();
22 |
23 | virtual void Draw(BRect updateRect);
24 |
25 | virtual void MessageReceived(BMessage* message);
26 |
27 | status_t AddOption(const char* name, int32 value);
28 | virtual bool GetOptionAt(int32 index, const char** _name,
29 | int32* _value);
30 | virtual void RemoveOptionAt(int32 index);
31 | virtual int32 CountOptions() const;
32 | virtual status_t AddOptionAt(const char* name, int32 value,
33 | int32 index);
34 | virtual int32 SelectedOption(const char** name = nullptr,
35 | int32* outValue = nullptr) const;
36 |
37 | private:
38 |
39 | };
40 |
41 |
42 | #endif
43 |
--------------------------------------------------------------------------------
/application/ImageSpinner.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2012-2012 Haiku Inc. All rights reserved.
3 | * Distributed under the terms of the MIT License.
4 | *
5 | * Authors:
6 | * Ciprian Nedisan (cipri)
7 | *
8 | */
9 | #include "ImageSpinner.h"
10 |
11 | #include
12 | #include
13 | #include
14 | #include
15 | #include
16 |
17 | #include
18 | #include
19 | #include
20 | #include
21 | #include
22 |
23 |
24 | #include
25 |
26 | #include "Messages.h"
27 | #include "Settings.h"
28 | #include "Tools.h"
29 |
30 |
31 | using namespace std;
32 |
33 | ImageSpinner::ImageSpinner(float const& imageHeight)
34 | :
35 | BGroupView("image_spinner", B_VERTICAL, 0),
36 | fImageHeight(imageHeight)
37 | {
38 |
39 | fBasicImageSpinner = new BasicImageSpinner;
40 | fBasicImageSpinner->SetExplicitMaxSize(BSize(B_SIZE_UNLIMITED, fImageHeight + 6));
41 | fBasicImageSpinner->SetExplicitMinSize(BSize(0, 0/*fImageHeight + 6*/));
42 |
43 | fDeleteButton = new ImageButton("quit",
44 | new BMessage(M_DELETE), 0.3, 1, "Remove document");
45 | fBackButton = new ImageButton("back",
46 | new BMessage(M_MOVE_LEFT), 0.3, 1, "Previous document");
47 | fNextButton = new ImageButton("next",
48 | new BMessage(M_MOVE_RIGHT), 0.3, 1, "Next document");
49 | fOpenButton = new ImageButton("open_document",
50 | new BMessage(MSG_OPEN_FILE_PANEL), 0.3, 1, "Open document");
51 |
52 |
53 | BGroupLayout* navigationLayout = BLayoutBuilder::Group<>(B_HORIZONTAL, 0)
54 | .Add(fDeleteButton)
55 | .Add(fBackButton)
56 | .Add(fNextButton)
57 | .Add(fOpenButton, 10)
58 | //.AddStrut(12)
59 | ;
60 |
61 | navigationLayout->SetExplicitMinSize(BSize(0, 20));
62 | navigationLayout->SetExplicitMaxSize(BSize(B_SIZE_UNLIMITED, 50));
63 |
64 | auto scrollbar = new BScrollBar("h_scrollbar",
65 | fBasicImageSpinner, 0, 0, B_HORIZONTAL);
66 | scrollbar->SetSteps(200, 200);
67 |
68 | BLayoutBuilder::Group<>(this)
69 | .Add(scrollbar)
70 | .AddGlue(0)
71 | .Add(fBasicImageSpinner)
72 | //.AddStrut(10)
73 | .AddGlue(0)
74 | .Add(navigationLayout)
75 | .End()
76 | ;
77 | }
78 |
79 |
80 | void
81 | ImageSpinner::AttachedToWindow(void)
82 | {
83 | fDeleteButton->SetTarget(this);
84 | fBackButton->SetTarget(this);
85 | fNextButton->SetTarget(this);
86 | fBasicImageSpinner->MakeFocus(true);
87 | BGroupView::AttachedToWindow();
88 | }
89 |
90 |
91 | void
92 | ImageSpinner::MakeFocus(bool focus)
93 | {
94 | BGroupView::MakeFocus(focus);
95 | fBasicImageSpinner->MakeFocus(focus);
96 | }
97 |
98 | void
99 | ImageSpinner::MessageReceived(BMessage* message)
100 | {
101 | switch (message->what) {
102 | case M_BACK:
103 | fBasicImageSpinner->Back();
104 | break;
105 |
106 | case M_NEXT:
107 | fBasicImageSpinner->Next();
108 | break;
109 |
110 | case M_DELETE:
111 | fBasicImageSpinner->RemoveSelectedItem();
112 | break;
113 |
114 | case M_MOVE_LEFT:
115 | fBasicImageSpinner->MoveLeftSelectedItem();
116 | break;
117 |
118 | case M_MOVE_RIGHT:
119 | fBasicImageSpinner->MoveRightSelectedItem();
120 | break;
121 |
122 | default:
123 | BGroupView::MessageReceived(message);
124 | break;
125 | }
126 | }
127 |
128 |
129 | void
130 | ImageSpinner::Add(BString const& str, std::unique_ptr&& bitmap)
131 | {
132 | if (bitmap->Bounds().Height() != fImageHeight) {
133 | auto res = Tools::RescaleBitmap(move(bitmap), 0, fImageHeight);
134 | fBasicImageSpinner->Add(str, move(res));
135 | } else {
136 | fBasicImageSpinner->Add(str, move(bitmap));
137 | }
138 | }
139 |
140 |
141 | bool
142 | ImageSpinner::NeedsFile(BString const& filePath)
143 | {
144 | return fBasicImageSpinner->NeedsFile(filePath);
145 | }
146 |
147 |
148 | float
149 | ImageSpinner::PreferredImageHeight(void)
150 | {
151 | return fImageHeight;
152 | }
153 |
154 |
155 | BasicImageSpinner::BasicImageSpinner(void)
156 | :
157 | BView(BRect(), "basic_image_view", B_FOLLOW_ALL,
158 | B_WILL_DRAW | B_FULL_UPDATE_ON_RESIZE | B_FRAME_EVENTS),
159 | fOldMousePos(0, 0),
160 | fMouseButtons(0),
161 | fSpace(5),
162 | fTotalWidth(fSpace),
163 | fIsPanning(false),
164 | fMaxItemsNumber(10),
165 | fCurrentIndex(0)
166 | {
167 | SetViewColor(B_TRANSPARENT_32_BIT);
168 | //SetDrawingMode(B_OP_ALPHA);
169 | //SetBlendingMode(B_PIXEL_ALPHA, B_ALPHA_OVERLAY);
170 |
171 |
172 | fSettingsPath = Tools::SettingsPath();
173 |
174 | _LoadSettings();
175 | }
176 |
177 |
178 | BasicImageSpinner::~BasicImageSpinner()
179 | {
180 | _SaveSettings();
181 | }
182 |
183 |
184 | void
185 | BasicImageSpinner::AttachedToWindow(void)
186 | {
187 | _AdaptScrollBarRange();
188 | BView::AttachedToWindow();
189 | }
190 |
191 |
192 | void
193 | BasicImageSpinner::Draw(BRect updateRect)
194 | {
195 | BRect bounds = Bounds();
196 | SetHighColor(ui_color(B_PANEL_BACKGROUND_COLOR));
197 | FillRect(bounds);
198 |
199 | if (fItems.empty())
200 | return;
201 |
202 | SetPenSize(2);
203 | SetHighColor(0, 0, 0, 255);
204 |
205 | float height = get<0>(fItems.front())->Bounds().Height();
206 |
207 | BPoint offset(fSpace, (bounds.Height() - height) / 2);
208 |
209 | if (offset.y < 0)
210 | offset.y = 0;
211 |
212 | bool hasDrawn = false;
213 | uint32 index = 0;
214 | for (auto it = fItems.begin(); it != fItems.end(); ++it, ++index) {
215 | BBitmap* bitmap = (BBitmap*)(&*get<0>(*it));
216 | auto rect = bitmap->Bounds().OffsetByCopy(offset);
217 | if (rect.Intersects(updateRect)) {
218 | hasDrawn = true;
219 | DrawBitmapAsync(bitmap, rect/*.LeftTop()*/);
220 | if (index == fCurrentIndex) {
221 | SetHighColor(0, 0, 255, 255);
222 | SetPenSize(3);
223 | StrokeRect(rect);
224 | SetPenSize(2);
225 | SetHighColor(0, 0, 0, 255);
226 | } else {
227 | StrokeRect(get<0>(*it)->Bounds().OffsetByCopy(offset));
228 | }
229 | } else if (hasDrawn) {
230 | break;
231 | }
232 | offset.x += get<0>(*it)->Bounds().Width() + fSpace;
233 | }
234 |
235 | Sync();
236 | BView::Draw(updateRect);
237 | }
238 |
239 |
240 |
241 | void
242 | BasicImageSpinner::KeyDown(const char* bytes, int32 numBytes)
243 | {
244 | if (numBytes == 1) {
245 | switch (bytes[0]) {
246 | case B_ENTER:
247 | _SelectIndex(fCurrentIndex);
248 | break;
249 |
250 | case B_DELETE:
251 | RemoveSelectedItem();
252 | break;
253 |
254 | case B_DOWN_ARROW: case B_RIGHT_ARROW:
255 | _Next();
256 | break;
257 |
258 | case B_UP_ARROW: case B_LEFT_ARROW:
259 | _Back();
260 | break;
261 |
262 | case B_PAGE_UP:
263 | break;
264 |
265 | case B_PAGE_DOWN:
266 | break;
267 |
268 | case B_HOME:
269 | _First();
270 | break;
271 |
272 | case B_END:
273 | _Last();
274 | break;
275 |
276 |
277 | default:
278 | BView::KeyDown(bytes, numBytes);
279 | break;
280 | }
281 | }
282 | }
283 |
284 |
285 |
286 | void
287 | BasicImageSpinner::FrameResized(float newWidth, float newHeight)
288 | {
289 |
290 | _AdaptScrollBarRange();
291 | BView::FrameResized(newWidth, newHeight);
292 | }
293 |
294 |
295 | void
296 | BasicImageSpinner::MessageReceived(BMessage* message)
297 | {
298 |
299 | BView::MessageReceived(message);
300 | }
301 |
302 |
303 | void
304 | BasicImageSpinner::MouseMoved(BPoint where, uint32 code,
305 | const BMessage* dragMessage)
306 | {
307 | switch (code) {
308 | case B_EXITED_VIEW:
309 | fIsPanning = false;
310 | break;
311 |
312 | default:
313 | break;
314 | }
315 |
316 | if (fIsPanning == true) {
317 | BPoint delta = fOldMousePos - where;
318 |
319 | ScrollBar(B_HORIZONTAL)->SetValue(
320 | ScrollBar(B_HORIZONTAL)->Value() + delta.x);
321 | }
322 |
323 | BView::MouseMoved(where, code, dragMessage);
324 | }
325 |
326 |
327 | void
328 | BasicImageSpinner::MouseDown(BPoint where)
329 | {
330 | MakeFocus(true);
331 | GetMouse(&fOldMousePos, &fMouseButtons);
332 |
333 | int32 clicks = 0;
334 | Window()->CurrentMessage()->FindInt32("clicks", &clicks);
335 |
336 | if (clicks == 2) {
337 | _Select(fOldMousePos);
338 | } else {
339 | _HighlightPosition(fOldMousePos);
340 | fIsPanning = true;
341 | }
342 |
343 | BView::MouseDown(where);
344 | }
345 |
346 |
347 | void
348 | BasicImageSpinner::MouseUp(BPoint where)
349 | {
350 | fIsPanning = false;
351 |
352 | BView::MouseUp(where);
353 | }
354 |
355 |
356 | bool
357 | BasicImageSpinner::NeedsFile(BString const& filePath)
358 | {
359 | for (auto it = fItems.begin(); it != fItems.end(); ++it) {
360 | if (filePath == get<1>(*it)) {
361 | auto temp = move(*it);
362 | fItems.remove(*it);
363 | fItems.push_front(move(temp));
364 | return false;
365 | }
366 | }
367 |
368 | return true;
369 | }
370 |
371 |
372 | void
373 | BasicImageSpinner::Add(BString const& filePath, std::unique_ptr&& bitmap)
374 | {
375 | uniform_int_distribution distribution(0, 999);
376 | mt19937 engine(time(NULL)); //Mersenn twister
377 | auto generate = bind(distribution, engine); // RNG
378 |
379 |
380 | int idNumber;
381 | bool isInvalid;
382 |
383 | // generate a random Number, and make sure it's unique.
384 | do {
385 | isInvalid = false;
386 | idNumber = generate();
387 | for (auto it = fItems.begin(); it != fItems.end(); ++it) {
388 | if (get<2>(*it) == idNumber) {
389 | isInvalid = true;
390 | break;
391 | }
392 | }
393 | } while (isInvalid);
394 |
395 | // save bitmap to disk
396 | BString settingsPath(Tools::SettingsPath());
397 | BString path(settingsPath);
398 | path << idNumber;
399 | Tools::ExportBitmap(bitmap.get(), path);
400 |
401 | _Add(filePath, move(bitmap), idNumber);
402 | }
403 |
404 |
405 | void
406 | BasicImageSpinner::_Add(BString const& filePath,
407 | std::unique_ptr&& bitmap, int const& bitmapID)
408 | {
409 | fItems.push_front(tuple, BString, int>
410 | (move(bitmap), filePath, bitmapID));
411 |
412 | fTotalWidth += get<0>(fItems.front())->Bounds().Width() + fSpace;
413 |
414 | if (fItems.size() > fMaxItemsNumber)
415 | RemoveBackItem();
416 |
417 | _AdaptScrollBarRange();
418 | }
419 |
420 |
421 | void
422 | BasicImageSpinner::MoveLeftSelectedItem(void)
423 | {
424 | if (fCurrentIndex < 1 || fItems.size() < 2)
425 | return;
426 |
427 |
428 |
429 | auto it = fItems.begin();
430 | for (uint32 i = 1; i < fCurrentIndex; ++i)
431 | ++it;
432 |
433 | auto left = it;
434 | ++it;
435 | swap(*left, *it);
436 | _Back();
437 | }
438 |
439 |
440 | void
441 | BasicImageSpinner::MoveRightSelectedItem(void)
442 | {
443 | if (fCurrentIndex > (fItems.size() - 2)
444 | || fItems.size() < 2)
445 | return;
446 |
447 | auto it = fItems.begin();
448 | for (uint32 i = 0; i < fCurrentIndex; ++i)
449 | ++it;
450 |
451 | auto left = it;
452 | ++it;
453 | swap(*left, *it);
454 |
455 | _Next();
456 | }
457 |
458 |
459 | void
460 | BasicImageSpinner::RemoveBackItem(void)
461 | {
462 | fTotalWidth -= (get<0>(fItems.back())->Bounds().Width() + fSpace);
463 |
464 | BString path(Tools::SettingsPath());
465 | path << get<2>(fItems.back());
466 | BEntry entry(path);
467 | entry.Remove();
468 | fItems.pop_back();
469 | _AdaptScrollBarRange();
470 | Invalidate();
471 | }
472 |
473 |
474 | void
475 | BasicImageSpinner::RemoveSelectedItem(void)
476 | {
477 | if (fItems.empty() || fCurrentIndex < 0)
478 | return;
479 |
480 | auto it = fItems.begin();
481 | for (uint32 i = 0; i < fCurrentIndex; ++i)
482 | ++it;
483 |
484 | fTotalWidth -= (get<0>(*it)->Bounds().Width() + fSpace);
485 |
486 | BString path(Tools::SettingsPath());
487 | path << get<2>(*it);
488 | BEntry entry(path);
489 | entry.Remove();
490 | fItems.remove(*it);
491 |
492 | --fCurrentIndex;
493 | if (fCurrentIndex < 0)
494 | fCurrentIndex = 0;
495 |
496 | _AdaptScrollBarRange();
497 | Invalidate();
498 | }
499 |
500 |
501 | void
502 | BasicImageSpinner::_Select(BPoint const& pos)
503 | {
504 | float temp = 0;
505 | for (auto it = fItems.begin(); it != fItems.end(); ++it) {
506 | temp += get<0>(*it)->Bounds().Width() + fSpace;
507 | if (temp < pos.x)
508 | continue;
509 |
510 | BMessage msg(MSG_OPEN_FILE);
511 | msg.AddString("file", get<1>(*it));
512 | Window()->PostMessage(&msg);
513 | _First();
514 | break;
515 | }
516 | }
517 |
518 |
519 | void
520 | BasicImageSpinner::_HighlightPosition(BPoint const& pos)
521 | {
522 | float temp = 0;
523 | int counter = 0;
524 | for (auto it = fItems.begin(); it != fItems.end(); ++it, ++counter) {
525 | temp += get<0>(*it)->Bounds().Width() + fSpace;
526 | if (temp >= pos.x)
527 | break;
528 | }
529 |
530 | fCurrentIndex = counter;
531 |
532 | if (fCurrentIndex >= fItems.size())
533 | fCurrentIndex = -1;
534 |
535 | Invalidate();
536 | }
537 |
538 |
539 | void
540 | BasicImageSpinner::_SelectIndex(int const& index)
541 | {
542 | int counter = 0;
543 | for (auto it = fItems.begin(); it != fItems.end(); ++it) {
544 | if (counter < index) {
545 | ++counter;
546 | continue;
547 | }
548 |
549 | BMessage msg(MSG_OPEN_FILE);
550 | msg.AddString("file", get<1>(*it));
551 | Window()->PostMessage(&msg);
552 | _First();
553 | break;
554 | }
555 | }
556 |
557 |
558 | void
559 | BasicImageSpinner::_SaveSettings(void)
560 | {
561 | #if 0 // This is known to crash DocumentViewer in some cases, see issue #2
562 | BString settingsPath(Tools::SettingsPath());
563 | BString path = settingsPath;
564 | path.Append("RecentlyOpened");
565 | BFile file(path, B_WRITE_ONLY | B_CREATE_FILE | B_ERASE_FILE);
566 |
567 | BString str;
568 | for (auto it = fItems.rbegin(); it != fItems.rend(); ++it) {
569 | str = get<1>(*it);
570 | str << "\t" << get<2>(*it) << "\n";
571 | file.Write(str, str.Length());
572 | }
573 | #endif
574 | }
575 |
576 |
577 | void
578 | BasicImageSpinner::_LoadSettings(void)
579 | {
580 | #if 0 // This is known to crash DocumentViewer in some cases, see issue #2
581 | BString settingsPath = Tools::SettingsPath();
582 | BString path = settingsPath;
583 | path.Append("RecentlyOpened");
584 |
585 | BFile file(path, B_READ_ONLY | B_CREATE_FILE);
586 | off_t size;
587 | file.GetSize(&size);
588 | char buffer[size];
589 | file.Read(&buffer, size);
590 |
591 | fItems.clear();
592 | BString str = "";
593 | for (int i = 0; i < size; ++i) {
594 | if (buffer[i] != '\n') {
595 | str += buffer[i];
596 | } else {
597 | auto vec = Tools::Split(str, '\t');
598 | str = "";
599 | if (vec.size() != 2)
600 | continue;
601 |
602 | path = settingsPath;
603 | path.Append(vec[1]);
604 | unique_ptr bitmap(BTranslationUtils::GetBitmap(path));
605 |
606 | if (bitmap == nullptr)
607 | return;
608 |
609 | stringstream ss;
610 | ss << vec[1];
611 | int idNumber;
612 | ss >>idNumber;
613 | _Add(vec[0], move(bitmap), idNumber);
614 |
615 | }
616 | }
617 | #endif
618 | }
619 |
620 |
621 | void
622 | BasicImageSpinner::_ScrollToSelection(void)
623 | {
624 | // ToDO : Not yet implemented
625 |
626 | Invalidate();
627 | }
628 |
629 |
630 | void
631 | BasicImageSpinner::Next(void)
632 | {
633 | _Next();
634 | }
635 |
636 |
637 | void
638 | BasicImageSpinner::_Next(void)
639 | {
640 | ++fCurrentIndex;
641 | if (fCurrentIndex < 0)
642 | fCurrentIndex = 0;
643 | else if (fCurrentIndex >= fItems.size())
644 | fCurrentIndex = fItems.size() - 1;
645 |
646 | float width = fSpace;
647 | auto it = fItems.begin();
648 | for (uint32 i = 0; i <= fCurrentIndex; ++i, ++it)
649 | width += get<0>(*it)->Bounds().Width() + fSpace;
650 |
651 | if (Bounds().right < width)
652 | ScrollTo(width - Bounds().Width(), 0);
653 |
654 | Invalidate();
655 | }
656 |
657 |
658 | void
659 | BasicImageSpinner::_Back(void)
660 | {
661 | --fCurrentIndex;
662 | if (fCurrentIndex < 0)
663 | fCurrentIndex = 0;
664 | else if (fCurrentIndex >= fItems.size())
665 | fCurrentIndex = fItems.size() - 1;
666 |
667 | float width = 0;
668 | auto it = fItems.begin();
669 | for (uint32 i = 0; i < fCurrentIndex; ++i, ++it)
670 | width += get<0>(*it)->Bounds().Width() + fSpace;
671 |
672 | if (Bounds().left > width)
673 | ScrollTo(width, 0);
674 |
675 | Invalidate();
676 | }
677 |
678 |
679 | void
680 | BasicImageSpinner::Back(void)
681 | {
682 | _Back();
683 | }
684 |
685 |
686 | void
687 | BasicImageSpinner::_First(void)
688 | {
689 | fCurrentIndex = 0;
690 | Invalidate();
691 | }
692 |
693 |
694 | void
695 | BasicImageSpinner::_Last(void)
696 | {
697 | fCurrentIndex = fItems.size() - 1;
698 | Invalidate();
699 | }
700 |
701 |
702 | void
703 | BasicImageSpinner::_AdaptScrollBarRange(void)
704 | {
705 | float width = -Bounds().Width();
706 | if (width > 0)
707 | return;
708 |
709 | width += fTotalWidth;
710 | auto scrollbar = ScrollBar(B_HORIZONTAL);
711 | scrollbar->SetRange(0, width);
712 | scrollbar->SetProportion(1 - width/fTotalWidth);
713 | }
714 |
715 |
716 | BString
717 | BasicImageSpinner::_RandomName(void)
718 | {
719 | uniform_int_distribution distribution(0,999);
720 | mt19937 engine(time(NULL)); //Mersenn twister
721 | auto random = bind(distribution, engine); // RNG
722 |
723 | BString str;
724 | str << random();
725 |
726 | return str;
727 | }
728 |
729 |
730 |
--------------------------------------------------------------------------------
/application/ImageSpinner.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2012-2012 Haiku Inc. All rights reserved.
3 | * Distributed under the terms of the MIT License.
4 | *
5 | * Authors:
6 | * Ciprian Nedisan (cipri)
7 | *
8 | */
9 | #ifndef IMAGESPINNER_H
10 | #define IMAGESPINNER_H
11 |
12 | #include
13 | #include
14 | #include
15 |
16 | #include
17 | #include
18 | #include
19 | #include
20 | #include
21 |
22 | #include "Debug.h"
23 | #include "ImageButton.h"
24 |
25 | class BasicImageSpinner : public BView
26 | {
27 | public:
28 | BasicImageSpinner(void);
29 | virtual ~BasicImageSpinner();
30 |
31 | virtual void AttachedToWindow(void);
32 | virtual void Draw(BRect updateRect);
33 | virtual void FrameResized(float newWidth, float newHeight);
34 | virtual void KeyDown(const char* bytes, int32 numBytes);
35 | virtual void MessageReceived(BMessage* message);
36 | virtual void MouseDown(BPoint where);
37 | virtual void MouseUp(BPoint where);
38 | virtual void MouseMoved(BPoint where, uint32 code,
39 | const BMessage* dragMessage);
40 |
41 | void Add(BString const& str, std::unique_ptr&& bitmap);
42 |
43 | void Next(void);
44 | void Back(void);
45 |
46 | bool NeedsFile(BString const& filePath);
47 |
48 | void RemoveBackItem(void);
49 | void RemoveSelectedItem(void);
50 |
51 | void MoveLeftSelectedItem(void);
52 | void MoveRightSelectedItem(void);
53 |
54 | private:
55 | void _AdaptScrollBarRange(void);
56 | void _Add(BString const& filePath,
57 | std::unique_ptr&& bitmap, int const& bitmapID);
58 | void _SaveSettings(void);
59 | void _LoadSettings(void);
60 | void _Last(void);
61 | void _Next(void);
62 | void _Back(void);
63 | void _First(void);
64 | void _HighlightPosition(BPoint const& pos);
65 | void _Select(BPoint const& pos);
66 | void _SelectIndex(int const& index);
67 | void _ScrollToSelection(void);
68 |
69 | BString _RandomName(void);
70 |
71 |
72 | std::list< std::tuple, BString, int> > fItems;
73 |
74 | BPoint fOldMousePos;
75 | uint32 fMouseButtons;
76 |
77 | float fSpace;
78 | float fTotalWidth;
79 | bool fIsPanning;
80 | uint32 fMaxItemsNumber;
81 | uint32 fCurrentIndex;
82 | BString fAppName;
83 | BString fSettingsPath;
84 |
85 |
86 | Debug out;
87 | };
88 |
89 | class ImageSpinner : public BGroupView
90 | {
91 | public:
92 | ImageSpinner(float const& imageHeight = 500);
93 | virtual void MakeFocus(bool focus);
94 | virtual void MessageReceived(BMessage* message);
95 | virtual void AttachedToWindow(void);
96 |
97 | void Add(BString const& filePath, std::unique_ptr&& bitmap);
98 |
99 | bool NeedsFile(BString const& filePath);
100 |
101 | float PreferredImageHeight(void);
102 |
103 | private:
104 |
105 | ImageButton* fDeleteButton;
106 | ImageButton* fBackButton;
107 | ImageButton* fNextButton;
108 | ImageButton* fOpenButton;
109 |
110 |
111 | BasicImageSpinner* fBasicImageSpinner;
112 |
113 | float fImageHeight;
114 |
115 | enum {
116 | M_BACK = 'ib01', M_NEXT = 'in01',
117 | M_MOVE_LEFT = 'im01', M_MOVE_RIGHT = 'im02',
118 | M_DELETE = 'id01'
119 | };
120 |
121 | };
122 |
123 | #endif // IMAGESPINNER_H
124 |
--------------------------------------------------------------------------------
/application/ImageTabView.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2011-2011 Haiku Inc. All rights reserved.
3 | * Distributed under the terms of the MIT License.
4 | *
5 | * Authors:
6 | * Ciprian Nedisan (cipri)
7 | *
8 | */
9 | #include "ImageTabView.h"
10 |
11 | #include
12 |
13 | #include
14 | #include
15 | #include
16 |
17 | #include "Tools.h"
18 |
19 | ImageTab::ImageTab(const char* imgName, BView* tabView)
20 | :
21 | BTab(tabView)
22 | {
23 | fBitmap = nullptr;
24 | fImageName.SetTo(imgName);
25 | }
26 |
27 |
28 | void
29 | ImageTab::DrawLabel(BView* owner, BRect frame)
30 | {
31 |
32 | int size = std::min(frame.Width(), frame.Height()) - 2;
33 |
34 | if (fBitmap == nullptr) {
35 | fBitmap = Tools::LoadBitmap(fImageName, size);
36 | } else if (fBitmap->Bounds().Height() != size) {
37 | delete fBitmap;
38 | fBitmap = Tools::LoadBitmap(fImageName, size);
39 | }
40 |
41 | owner->SetDrawingMode(B_OP_OVER);
42 |
43 | BPoint where;
44 | where.x = frame.left + (frame.Width() - fBitmap->Bounds().Width()) / 2;
45 | where.y = frame.top + (frame.Height() - fBitmap->Bounds().Height())/ 2;
46 |
47 | owner->DrawBitmap(fBitmap, where);
48 | }
49 |
50 |
51 | ImageTabView::ImageTabView(const char* name)
52 | :
53 | BTabView(name),
54 | fTabWidth(38)
55 | {
56 | SetTabHeight(26);
57 | }
58 |
59 |
60 | BRect
61 | ImageTabView::TabFrame(int32 index) const
62 | {
63 | if (index < 0 || index > CountTabs())
64 | return BRect();
65 |
66 | return BRect(index*fTabWidth, 0, (index + 1) * fTabWidth, TabHeight());
67 | }
68 |
69 | void
70 | ImageTabView::MouseMoved(BPoint where, uint32 code, const BMessage * dragMessage)
71 | {
72 | int32 numTabs = CountTabs();
73 | if (code == B_INSIDE_VIEW || code == B_ENTERED_VIEW) {
74 | for (int i = 0; i < numTabs; i++) {
75 | const BRect tabRect = TabFrame(i);
76 | if (tabRect.Contains(where)) {
77 | SetToolTip(TabAt(i)->Label());
78 | }
79 | }
80 | } else {
81 | SetToolTip("");
82 | }
83 |
84 | }
85 |
--------------------------------------------------------------------------------
/application/ImageTabView.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2011-2011 Haiku Inc. All rights reserved.
3 | * Distributed under the terms of the MIT License.
4 | *
5 | * Authors:
6 | * Ciprian Nedisan (cipri)
7 | *
8 | */
9 | #ifndef IMAGETAB_H
10 | #define IMAGETAB_H
11 |
12 | #include
13 | #include
14 | #include
15 | #include
16 | #include "Debug.h"
17 |
18 | class ImageTab : public BTab
19 | {
20 | public:
21 | ImageTab(const char* imageName, BView* tabView = nullptr);
22 | virtual void DrawLabel(BView* owner, BRect frame);
23 |
24 | private:
25 | BBitmap* fBitmap;
26 | Debug out;
27 | BString fImageName;
28 | };
29 |
30 |
31 | class ImageTabView : public BTabView
32 | {
33 | public:
34 | ImageTabView(const char* name = "im_tabview");
35 | virtual BRect TabFrame(int32 index) const;
36 | virtual void MouseMoved(BPoint where, uint32 code, const BMessage * dragMessage);
37 |
38 |
39 | private:
40 | float fTabWidth;
41 | };
42 |
43 | #endif
44 |
--------------------------------------------------------------------------------
/application/MainApplication.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2011-2011 Haiku Inc. All rights reserved.
3 | * Distributed under the terms of the MIT License.
4 | *
5 | * Authors:
6 | * Ciprian Nedisan (cipri)
7 | *
8 | */
9 | #ifndef MAINAPPLICATION_H
10 | #define MAINAPPLICATION_H
11 |
12 |
13 | #include
14 | #include
15 | #include
16 |
17 | #include "Debug.h"
18 | #include "MainWindow.h"
19 | #include "Messages.h"
20 | #include "PDFFilter.h"
21 |
22 | class MainApplication : public BApplication
23 | {
24 | public:
25 | MainApplication(void)
26 | :
27 | BApplication("application/x-vnd.documentviewer")
28 | {
29 | fFilePanel = nullptr;
30 | fMainWindow = nullptr;
31 | }
32 |
33 | virtual void ReadyToRun(void)
34 | {
35 | if (fMainWindow == nullptr)
36 | fMainWindow = new MainWindow();
37 | }
38 |
39 | virtual void RefsReceived(BMessage* msg)
40 | {
41 | uint32 type = 0;
42 | int32 count = 0;
43 |
44 | msg->GetInfo ("refs", &type, &count);
45 | if (type != B_REF_TYPE)
46 | return;
47 |
48 | if (fMainWindow == nullptr)
49 | fMainWindow = new MainWindow();
50 |
51 | entry_ref ref;
52 | for (int32 i = --count; i >= 0; --i)
53 | if (msg->FindRef("refs", i, &ref) == B_OK) {
54 | BEntry entry(&ref, true);
55 | BPath path;
56 | entry.GetPath(&path);
57 |
58 | int32 page = 0;
59 | msg->FindInt32("page", &page);
60 |
61 | BString password = "";
62 | msg->FindString("password", &password);
63 |
64 | BMessage message(MSG_OPEN_FILE);
65 | message.AddString("file", path.Path());
66 | message.AddString("password", password);
67 | message.AddInt32("page", page);
68 | fMainWindow->PostMessage(&message);
69 | }
70 | }
71 |
72 | virtual void ArgvReceived (int32 argc, char **argv)
73 | {
74 | // check command line
75 | if (!(argc == 2 || argc == 3 || argc == 4))
76 | exit(1);
77 |
78 | BString path = "";
79 | if (argc >= 2)
80 | path = argv[1];
81 |
82 | int page = 0;
83 | if (argc >= 3)
84 | page = atoi(argv[2]) - 1;
85 |
86 | BString password = "";
87 | if (argc == 4)
88 | password = argv[3];
89 |
90 | entry_ref ref;
91 | get_ref_for_path (path.String(), &ref);
92 |
93 | BMessage msg(B_REFS_RECEIVED);
94 | msg.AddRef("refs", &ref);
95 | msg.AddString("password", password);
96 | msg.AddInt32 ("page", page);
97 | PostMessage(&msg);
98 | }
99 |
100 | void MessageReceived(BMessage* msg)
101 | {
102 | switch (msg->what) {
103 | /* case B_CANCEL:
104 | if (fMainWindow == nullptr)
105 | PostMessage (B_QUIT_REQUESTED);
106 |
107 | break;
108 | */
109 | default:
110 | BApplication::MessageReceived(msg);
111 | }
112 | }
113 |
114 | void OpenFilePanel(void)
115 | {
116 | if (fFilePanel == nullptr)
117 | fFilePanel = new BFilePanel (B_OPEN_PANEL,
118 | nullptr, nullptr, B_FILE_NODE, true, nullptr, &fPDFFilter);
119 |
120 | fFilePanel->Show();
121 | }
122 |
123 | private:
124 | MainWindow* fMainWindow;
125 | BFilePanel* fFilePanel;
126 | bool fToOpenFilePanel;
127 | PDFFilter fPDFFilter;
128 |
129 | Debug out;
130 | };
131 |
132 | #endif
133 |
--------------------------------------------------------------------------------
/application/MainWindow.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2011-2011 Haiku Inc. All rights reserved.
3 | * Distributed under the terms of the MIT License.
4 | *
5 | * Authors:
6 | * Ciprian Nedisan (cipri)
7 | *
8 | */
9 | #include "MainWindow.h"
10 |
11 | #include
12 |
13 | #include
14 | #include
15 | #include
16 | #include
17 | #include
18 | #include
19 | #include
20 | #include
21 | #include
22 | #include
23 | #include
24 | #include
25 | #include
26 | #include
27 | #include
28 | #include
29 | #include
30 | #include
31 | #include
32 | #include
33 |
34 | #include "MainApplication.h"
35 | #include "Messages.h"
36 | #include "Settings.h"
37 | #include "Tools.h"
38 |
39 |
40 |
41 | MainWindow::MainWindow(void)
42 | :
43 | BWindow(BRect(), "DocumentViewer", B_DOCUMENT_WINDOW_LOOK,
44 | B_NORMAL_WINDOW_FEEL, B_ASYNCHRONOUS_CONTROLS
45 | | B_QUIT_ON_WINDOW_CLOSE),
46 | fFullscreenIsOn(false),
47 | fPassword("")
48 | {
49 | fTabView1 = new ImageTabView("tab_view1");
50 |
51 | fPreviewView = new PreviewView();
52 | ImageTab* previewViewTab = new ImageTab("preview");
53 | fTabView1->AddTab(fPreviewView, previewViewTab);
54 | previewViewTab->SetLabel("Preview");
55 |
56 |
57 | fOutlineView = new OutlineView();
58 | ImageTab* outlineViewTab = new ImageTab("outline");
59 | fTabView1->AddTab(fOutlineView, outlineViewTab);
60 | outlineViewTab->SetLabel("Outline");
61 |
62 | fSearchView = new SearchView();
63 | ImageTab* searchViewTab = new ImageTab("find");
64 | fTabView1->AddTab(fSearchView, searchViewTab);
65 | searchViewTab->SetLabel("Find");
66 |
67 | fTabView1->Select(0);
68 | fDocumentView = new DocumentView("", "", fPassword);
69 | fRibbon = new MainWindowRB();
70 |
71 | fDocumentLayout = BLayoutBuilder::Group<>(B_VERTICAL, 0)
72 | .AddSplit(B_HORIZONTAL, 0, 7).GetSplitView(&fSplitView1)
73 | .AddGroup(B_VERTICAL, 0, 1)
74 | .Add(fTabView1)
75 | .End()
76 | .AddSplit(B_VERTICAL, 0, 6).GetSplitView(&fSplitView2)
77 | .Add(fRibbon, 1)
78 | .AddGroup(B_VERTICAL, 0, 6)
79 | .Add(fDocumentView)
80 | .End()
81 | .End()
82 | .End()
83 | ;
84 |
85 | fImageSpinner = new ImageSpinner();
86 |
87 | fIntroLayout = BLayoutBuilder::Group<>(B_VERTICAL, 0)
88 | .Add(fImageSpinner)
89 | .AddGlue(0)
90 | ;
91 |
92 | fCardLayout = new BCardLayout();
93 |
94 | BLayoutBuilder::Group<>(this, B_VERTICAL, 0)
95 | .Add(fCardLayout)
96 | ;
97 |
98 | fCardLayout->AddItem(fIntroLayout);
99 | fCardLayout->AddItem(fDocumentLayout);
100 | fCardLayout->SetVisibleItem(fIntroLayout);
101 | _LoadSettings();
102 | ResizeTo(1200, 600); ///Show 3 documents and minimize empty space
103 | Show();
104 | }
105 |
106 |
107 | void
108 | MainWindow::MessageReceived(BMessage* message)
109 | {
110 | switch (message->what) {
111 | case MSG_NO_FIT:
112 | case MSG_NO_ZOOM:
113 | case MSG_FIT_PAGE_HEIGHT:
114 | case MSG_FIT_PAGE_WIDTH:
115 | case MSG_ZOOM_IN:
116 | case MSG_ZOOM_OUT:
117 | PostMessage(message, fDocumentView);
118 | break;
119 |
120 | case MSG_ACTIVE_PAGE:
121 | {
122 | PostMessage(message, fRibbon);
123 | int32 pageNumber = 0;
124 | message->FindInt32("info", &pageNumber);
125 | fPreviewView->SelectPage(pageNumber);
126 | break;
127 | }
128 |
129 | case MSG_GOTO_PAGE:
130 | {
131 | PostMessage(message, fDocumentView);
132 | PostMessage(message, fRibbon);
133 |
134 | int32 pageNumber = 0;
135 | message->FindInt32("info", &pageNumber);
136 | fPreviewView->SelectPage(pageNumber);
137 | break;
138 | }
139 |
140 | case MSG_FULLSCREEN:
141 | fFullscreenIsOn = !fFullscreenIsOn;
142 |
143 | if (fFullscreenIsOn) {
144 | fSavedFrame = Frame();
145 | BScreen screen(this);
146 | BRect rect(screen.Frame());
147 | MoveTo(rect.left, rect.top);
148 | ResizeTo(rect.Width(), rect.Height());
149 | } else {
150 | Hide();
151 | MoveTo(fSavedFrame.left, fSavedFrame.top);
152 | ResizeTo(fSavedFrame.Width(), fSavedFrame.Height());
153 | Show();
154 | }
155 | break;
156 |
157 | case MSG_APP_QUIT:
158 | {
159 | fCardLayout->SetVisibleItem((BLayoutItem*)fIntroLayout);
160 | fImageSpinner->MakeFocus(true);
161 | SetTitle("DocumentViewer");
162 | ResizeTo(1200, 600); //Show 3 documents and minimize empty space
163 | //be_app->PostMessage(B_QUIT_REQUESTED);
164 | break;
165 | }
166 |
167 | case MSG_HELP:
168 | {
169 | BPathFinder pathFinder;
170 | BPath path;
171 |
172 | pathFinder.FindPath(B_FIND_PATH_DOCUMENTATION_DIRECTORY,
173 | "packages/documentviewer/help.pdf", B_FIND_PATH_EXISTING_ONLY, path);
174 |
175 | _OpenFile(path.Path(), "pdf", "", 0);
176 | break;
177 | }
178 |
179 |
180 | case MSG_HIGHLIGHT_RECT:
181 | PostMessage(message, fDocumentView);
182 | break;
183 |
184 | case MSG_SUPPORT:
185 | {
186 | char const* args[] = {"http://haikuarchives.github.io/DocumentViewer/support.html", 0};
187 | be_roster->Launch("text/html", 1, args);
188 | break;
189 | }
190 |
191 | case MSG_PRINT_DOCUMENT:
192 | {
193 | fDocumentView->Print();
194 | break;
195 | }
196 |
197 |
198 | case MSG_SETUP_PRINTER:
199 | {
200 | BPrintJob job("document's name");
201 | job.ConfigPage();
202 | break;
203 | }
204 |
205 | case MSG_OPEN_FILE_PANEL:
206 | case M_OPEN_FILE_PANEL:
207 | ((MainApplication*)be_app)->OpenFilePanel();
208 | break;
209 |
210 | case MSG_OPEN_FILE:
211 | {
212 | BString file;
213 | message->FindString("file", &file);
214 | BString password = "";
215 | message->FindString("password", &password);
216 | int32 page = 0;
217 | message->FindInt32("page", &page);
218 | auto type = _FileType(file);
219 | _OpenFile(file, type, password, page);
220 | break;
221 | }
222 |
223 | case M_SHOW_DOCUMENT:
224 | fCardLayout->SetVisibleItem((BLayoutItem*)fDocumentLayout);
225 | break;
226 |
227 |
228 | default:
229 | BWindow::MessageReceived(message);
230 | break;
231 | }
232 | }
233 |
234 |
235 | BString
236 | MainWindow::_FileType(BString const& file)
237 | {
238 | entry_ref ref;
239 | BEntry(file).GetRef(&ref);
240 |
241 | BMimeType mime;
242 | BMimeType::GuessMimeType(&ref, &mime);
243 | BMessage msg;
244 | uint32 i=0;
245 | mime.GetFileExtensions(&msg);
246 |
247 | BString type;
248 | while (true) {
249 | if (msg.FindString("extensions", i++, &type) != B_OK)
250 | break;
251 |
252 | if (type == "djvu" || type == "pdf" || type == "xps")
253 | break;
254 | }
255 |
256 | // hack, delte later, after types are added to haiku
257 | if (type == "") {
258 | if (file.IFindLast("djvu") != B_ERROR)
259 | type = "djvu";
260 | if (file.IFindLast("xps") != B_ERROR)
261 | type = "xps";
262 | }
263 |
264 | return type;
265 | }
266 |
267 |
268 | void
269 | MainWindow::_OpenFile(BString const& path, BString const& fileType,
270 | BString password, int32 const& page)
271 | {
272 | SetTitle(path);
273 | try {
274 | fDocumentView->FileChanged(path, fileType, password);
275 | fPreviewView->FileChanged(path, fileType, password);
276 | } catch(...) {
277 | BAlert* alert = new BAlert("error", "Can't open the file!", "OK");
278 | alert->Go();
279 | return;
280 | }
281 | fOutlineView->EngineChanged(fPreviewView->Engine());
282 | fSearchView->EngineChanged(fPreviewView->Engine());
283 | fRibbon->SetDocumentPages(fDocumentView->PageCount());
284 |
285 | if (fImageSpinner->NeedsFile(path)) {
286 | auto height = fImageSpinner->PreferredImageHeight();
287 | fImageSpinner->Add(path, move(fDocumentView->Cover(height)));
288 | }
289 |
290 | BMessage msg(MSG_GOTO_PAGE);
291 | msg.AddInt32("info", page);
292 | PostMessage(&msg);
293 |
294 | fCardLayout->SetVisibleItem((BLayoutItem*)fDocumentLayout);
295 | fDocumentView->MakeFocus(true);
296 | }
297 |
298 |
299 | /*
300 | void
301 | MainWindow::_AddDocumentLayout
302 | {
303 | fDocumentLayout = BLayoutBuilder::Group<>(B_VERTICAL, 0)
304 | .AddSplit(B_HORIZONTAL, 0, 7).GetSplitView(&fSplitView1)
305 | .AddGroup(B_VERTICAL, 0, 6)
306 | .Add(fTabView1)
307 | .End()
308 | .AddSplit(B_VERTICAL, 0, 1).GetSplitView(&fSplitView2)
309 | .Add(fRibbon, 1)
310 | .AddGroup(B_VERTICAL, 0, 6)
311 | .Add(fDocumentView)
312 | .End()
313 | .End()
314 | .End()
315 | ;
316 | }
317 |
318 | */
319 |
320 | void
321 | MainWindow::_SaveSettings(void)
322 | {
323 | if (fFullscreenIsOn == false)
324 | fSavedFrame = Frame();
325 |
326 | Settings settings("MainWindow");
327 |
328 | settings << "SavedFrame" << fSavedFrame;
329 |
330 | if (fDocumentLayout != nullptr) {
331 | settings
332 | << "Split10" << fSplitView1->ItemWeight((int32)0)
333 | << "Split11" << fSplitView1->ItemWeight(1)
334 | << "Split20" << fSplitView2->ItemWeight((int32)0)
335 | << "Split21" << fSplitView2->ItemWeight(1)
336 | << "RibbonTab" << fRibbon->ActiveTab()
337 | << "SidebarTab" << fTabView1->Selection()
338 | << "Fullscreen" << (int32)fFullscreenIsOn
339 | << std::endl;
340 | }
341 | }
342 |
343 |
344 | void
345 | MainWindow::_LoadSettings()
346 | {
347 | Settings settings("MainWindow");
348 |
349 | settings << "SavedFrame" >> fSavedFrame;
350 |
351 | if (fSavedFrame == BRect()) {
352 | Zoom();
353 | } else {
354 | MoveTo(fSavedFrame.left, fSavedFrame.top);
355 | ResizeTo(fSavedFrame.Width(), fSavedFrame.Height());
356 | }
357 |
358 | if (fDocumentLayout == nullptr)
359 | return;
360 |
361 | float weight;
362 | weight = 1.0;
363 | settings << "Split10" >> weight;
364 | fSplitView1->SetItemWeight(0, weight, true);
365 | if (weight == 0)
366 | fSplitView1->SetItemCollapsed(0, false);
367 |
368 | weight = 5.0;
369 | settings << "Split11" >> weight;
370 | fSplitView1->SetItemWeight(1, weight, true);
371 | if (weight == 0)
372 | fSplitView1->SetItemCollapsed(1, false);
373 |
374 | weight = 1.0;
375 | settings << "Split20" >> weight;
376 | fSplitView2->SetItemWeight(0, weight, true);
377 | if (weight == 0)
378 | fSplitView2->SetItemCollapsed(0, false);
379 |
380 | weight = 6.0;
381 | settings << "Split21" >> weight;
382 | fSplitView2->SetItemWeight(1, weight, true);
383 | if (weight == 0)
384 | fSplitView2->SetItemCollapsed(1, false);
385 |
386 | int32 value;
387 | value = 0;
388 | settings << "RibbonTab" >> value;
389 | fRibbon->SetActiveTab(value);
390 | value = 0;
391 | settings << "SidebarTab" >> value;
392 | fTabView1->Select(value);
393 | value = 0;
394 | settings << "Fullscreen" >> value;
395 | if (value != 0)
396 | PostMessage(MSG_FULLSCREEN);
397 | }
398 |
399 |
400 | bool
401 | MainWindow::QuitRequested(void)
402 | {
403 | Hide();
404 | _SaveSettings();
405 | return true;
406 | }
407 |
--------------------------------------------------------------------------------
/application/MainWindow.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2011-2011 Haiku Inc. All rights reserved.
3 | * Distributed under the terms of the MIT License.
4 | *
5 | * Authors:
6 | * Ciprian Nedisan (cipri)
7 | *
8 | */
9 | #ifndef MAINWINDOW_H
10 | #define MAINWINDOW_H
11 |
12 | #include
13 |
14 | #include
15 | #include
16 | #include
17 | #include
18 | #include
19 | #include
20 | #include
21 | #include
22 |
23 |
24 | #include "BookmarksView.h"
25 | #include "Debug.h"
26 | #include "ImageSpinner.h"
27 | #include "ImageTabView.h"
28 | #include "MainWindowRB.h"
29 | #include "OutlineView.h"
30 | #include "DocumentView.h"
31 | #include "PreviewView.h"
32 | #include "SearchView.h"
33 |
34 | class MainWindow : public BWindow
35 | {
36 | public:
37 | MainWindow(void);
38 | virtual void MessageReceived(BMessage* message);
39 | virtual bool QuitRequested(void);
40 |
41 | const int& CurrentPageNumber(void)
42 | {
43 | return fDocumentView->CurrentPageNumber();
44 | }
45 |
46 |
47 | enum{ M_EXIT = 'ie01', M_OPEN_FILE = 'io01', M_OPEN_FILE_PANEL,
48 | M_SHOW_DOCUMENT = 'is01'
49 | };
50 |
51 | private:
52 | void _OpenFile(const BString& path, BString const& fileType,
53 | BString password, int32 const& page = 0);
54 | void _SaveSettings(void);
55 | void _LoadSettings(void);
56 |
57 | BString _FileType(BString const& file);
58 |
59 | BCardLayout* fCardLayout;
60 | BGroupLayout* fDocumentLayout;
61 | BGroupLayout* fIntroLayout;
62 |
63 | BSplitView* fSplitView1;
64 | BSplitView* fSplitView2;
65 | BSplitView* fSplitView3;
66 | BSplitView* fSplitView4;
67 |
68 | BButton* fButton;
69 |
70 | ImageTabView* fTabView1;
71 |
72 | DocumentView* fDocumentView;
73 | OutlineView* fOutlineView;
74 | PreviewView* fPreviewView;
75 | BookmarksView* fBookmarksView;
76 | SearchView* fSearchView;
77 | MainWindowRB* fRibbon;
78 |
79 | ImageSpinner* fImageSpinner;
80 |
81 | BRect fSavedFrame;
82 |
83 | bool fFullscreenIsOn;
84 |
85 | BString fPassword;
86 |
87 | Debug out;
88 | };
89 |
90 |
91 | #endif
92 |
--------------------------------------------------------------------------------
/application/MainWindowRB.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2011-2011 Haiku Inc. All rights reserved.
3 | * Distributed under the terms of the MIT License.
4 | *
5 | * Authors:
6 | * Ciprian Nedisan (cipri)
7 | *
8 | */
9 | #include "MainWindowRB.h"
10 |
11 | #include
12 | #include
13 |
14 | #include
15 | #include
16 | #include
17 | #include
18 | #include
19 | #include
20 |
21 | #include "Messages.h"
22 |
23 | using namespace std;
24 |
25 | MainWindowRB::MainWindowRB(void)
26 | :
27 | BGroupView("main_widow_ribbon", B_VERTICAL, 0),
28 | fPages(0),
29 | fMaxHeight(35),
30 | fAutohiding(false)
31 | {
32 | SetFlags(Flags() | B_FULL_POINTER_HISTORY);
33 |
34 | unique_ptr navigationMessage(new BMessage(M_PAGENUMBER));
35 | fPageNavigationView = new PageNavigationView(move(navigationMessage));
36 |
37 | ImageButton* printButton = new ImageButton("print",
38 | new BMessage(MSG_PRINT_DOCUMENT), 0.3, 1, "Print document");
39 | printButton->SetExplicitMinSize(BSize(fMaxHeight, fMaxHeight));
40 | printButton->SetExplicitMaxSize(BSize(fMaxHeight, fMaxHeight));
41 |
42 | fOpenFileButton = new ImageButton("open_document",
43 | new BMessage(MSG_OPEN_FILE_PANEL), 0.3, 1, "Open document");
44 | fOpenFileButton->SetExplicitMinSize(BSize(fMaxHeight, fMaxHeight));
45 | fOpenFileButton->SetExplicitMaxSize(BSize(fMaxHeight, fMaxHeight));
46 |
47 | fQuitButton = new ImageButton("quit", new BMessage(MSG_APP_QUIT),
48 | 0.3, 1, "Close document");
49 | fQuitButton->SetExplicitMinSize(BSize(fMaxHeight, 0));
50 | fQuitButton->SetExplicitMaxSize(BSize(fMaxHeight, fMaxHeight));
51 |
52 | // Home Tab
53 | BGroupLayout* homeLayout = BGroupLayoutBuilder(B_HORIZONTAL, 0)
54 | .SetInsets(2, 2, 2, 2)
55 | .Add(fPageNavigationView)
56 | .AddGlue(1000)
57 | .Add(printButton)
58 | .Add(fOpenFileButton)
59 | .Add(fQuitButton)
60 | .RootLayout()
61 | ;
62 |
63 | ImageButton* fullscreenButton = new ImageButton("fullscreen",
64 | new BMessage(MSG_FULLSCREEN) , 0.3, 1, "Fullscreen");
65 | fullscreenButton->SetExplicitMinSize(BSize(fMaxHeight, 0));
66 | fullscreenButton->SetExplicitMaxSize(BSize(fMaxHeight, fMaxHeight));
67 |
68 | ImageButton* fitPageHeight = new ImageButton("fit_page_height",
69 | new BMessage(MSG_FIT_PAGE_HEIGHT), 0.3, 1, "Fit to height");
70 | fitPageHeight->SetExplicitMinSize(BSize(fMaxHeight, fMaxHeight));
71 | fitPageHeight->SetExplicitMaxSize(BSize(fMaxHeight, fMaxHeight));
72 |
73 | ImageButton* fitPageWidth = new ImageButton("fit_page_width",
74 | new BMessage(MSG_FIT_PAGE_WIDTH), 0.3, 1, "Fit to width");
75 | fitPageWidth->SetExplicitMinSize(BSize(fMaxHeight, fMaxHeight));
76 | fitPageWidth->SetExplicitMaxSize(BSize(fMaxHeight, fMaxHeight));
77 |
78 | ImageButton* zoomOriginal = new ImageButton("zoom_original",
79 | new BMessage(MSG_NO_ZOOM), 0.3, 1, "Reset zoom");
80 | zoomOriginal->SetExplicitMinSize(BSize(fMaxHeight, fMaxHeight));
81 | zoomOriginal->SetExplicitMaxSize(BSize(fMaxHeight, fMaxHeight));
82 |
83 | ImageButton* zoomOut = new ImageButton("zoom_out",
84 | new BMessage(MSG_ZOOM_OUT), 0.3, 1, "Zoom out");
85 | zoomOut->SetExplicitMinSize(BSize(fMaxHeight, fMaxHeight));
86 | zoomOut->SetExplicitMaxSize(BSize(fMaxHeight, fMaxHeight));
87 |
88 | ImageButton* zoomIn = new ImageButton("zoom_in",
89 | new BMessage(MSG_ZOOM_IN), 0.3, 1, "Zoom in");
90 | zoomIn->SetExplicitMinSize(BSize(fMaxHeight, fMaxHeight));
91 | zoomIn->SetExplicitMaxSize(BSize(fMaxHeight, fMaxHeight));
92 |
93 | ImageButton* rotateLeftButton = new ImageButton("rotate_left", nullptr,
94 | 0.3, 1, "Rotate left");
95 | rotateLeftButton->SetExplicitMinSize(BSize(fMaxHeight, fMaxHeight));
96 | rotateLeftButton->SetExplicitMaxSize(BSize(fMaxHeight, fMaxHeight));
97 |
98 | ImageButton* rotateRightButton = new ImageButton("rotate_right", nullptr,
99 | 0.3, 1, "Rotate right");
100 | rotateRightButton->SetExplicitMinSize(BSize(fMaxHeight, fMaxHeight));
101 | rotateRightButton->SetExplicitMaxSize(BSize(fMaxHeight, fMaxHeight));
102 |
103 | // View Tab
104 | BGroupLayout* viewLayout = BGroupLayoutBuilder(B_HORIZONTAL, 0)
105 | .SetInsets(2, 2, 2, 2)
106 | .AddGroup(B_VERTICAL, 0, 0)
107 | .AddGroup(B_HORIZONTAL, 0, 0)
108 | .Add(fullscreenButton)
109 | .Add(new BSeparatorView(B_VERTICAL))
110 | .Add(fitPageHeight)
111 | .Add(fitPageWidth)
112 | .Add(new BSeparatorView(B_VERTICAL))
113 | .Add(zoomOriginal)
114 | .Add(zoomOut)
115 | .Add(zoomIn)
116 | .Add(new BSeparatorView(B_VERTICAL))
117 | .Add(rotateLeftButton)
118 | .Add(rotateRightButton)
119 | .AddGlue(0)
120 | .End()
121 | .End()
122 | .RootLayout()
123 | ;
124 |
125 | // Edit Tab
126 | BGroupLayout* editLayout = BGroupLayoutBuilder(B_VERTICAL, 0)
127 | .AddGlue(0)
128 | //.Add(new ImageButton("star_green", nullptr, 0.3))
129 | .AddGlue(0)
130 | .RootLayout()
131 | ;
132 |
133 |
134 | ImageButton* setupPrinterButton = new ImageButton("printer",
135 | new BMessage(MSG_SETUP_PRINTER), 0.3, 1, "Printer setup");
136 | setupPrinterButton->SetExplicitMinSize(BSize(fMaxHeight, fMaxHeight));
137 | setupPrinterButton->SetExplicitMaxSize(BSize(fMaxHeight, fMaxHeight));
138 |
139 | // Configure Tab
140 | BGroupLayout* configureLayout = BGroupLayoutBuilder(B_HORIZONTAL, 0)
141 | .Add(setupPrinterButton)
142 | .AddGlue(0)
143 | .RootLayout()
144 | ;
145 |
146 | ImageButton* helpButton = new ImageButton("help2",
147 | new BMessage(MSG_HELP), 0.3, 1, "Help");
148 | helpButton->SetExplicitMinSize(BSize(fMaxHeight, fMaxHeight));
149 | helpButton->SetExplicitMaxSize(BSize(fMaxHeight, fMaxHeight));
150 |
151 | ImageButton* supportButton = new ImageButton("support",
152 | new BMessage(MSG_SUPPORT), 0.3, 1, "Contribute");
153 | supportButton->SetExplicitMinSize(BSize(fMaxHeight, fMaxHeight));
154 | supportButton->SetExplicitMaxSize(BSize(fMaxHeight, fMaxHeight));
155 |
156 |
157 | // Configure Tab
158 | BGroupLayout* helpLayout = BGroupLayoutBuilder(B_HORIZONTAL, 0)
159 | .Add(helpButton)
160 | .AddGlue(1000)
161 | .Add(supportButton)
162 | //.AddGlue(0)
163 | .RootLayout()
164 | ;
165 |
166 | fTabView = new ImageTabView("tab_view");
167 | //fTabView->SetTabWidth(B_WIDTH_FROM_LABEL);
168 |
169 | fTabsVec.push_back(new ImageTab("home"));
170 | fTabView->AddTab(homeLayout->View(), fTabsVec.back());
171 | fTabsVec.back()->SetLabel("Home");
172 | fTabsVec.push_back(new ImageTab("zoom_fit_best"));
173 | fTabView->AddTab(viewLayout->View(), fTabsVec.back());
174 | fTabsVec.back()->SetLabel("View");
175 | fTabsVec.push_back(new ImageTab("marker"));
176 | fTabView->AddTab(editLayout->View(), fTabsVec.back());
177 | fTabsVec.back()->SetLabel("Edit");
178 | fTabsVec.push_back(new ImageTab("configure"));
179 | fTabView->AddTab(configureLayout->View(), fTabsVec.back());
180 | fTabsVec.back()->SetLabel("Configure");
181 | fTabsVec.push_back(new ImageTab("help"));
182 | fTabView->AddTab(helpLayout->View(), fTabsVec.back());
183 | fTabsVec.back()->SetLabel("Help");
184 |
185 | BLayoutBuilder::Group<>(this)
186 | .Add(fTabView)
187 | ;
188 | //fTabView->SetExplicitMaxSize(BSize(10000, 50));
189 | // fTabView->SetExplicitMinSize(BSize(0, 50));
190 | }
191 |
192 |
193 | void
194 | MainWindowRB::AttachedToWindow(void)
195 | {
196 | fPageNavigationView->SetTarget(this);
197 | //int size = fTabView->CountTabs();
198 |
199 | // for (int i = 0; i < size; ++i)
200 | // fTabView->ViewForTab(i)->SetViewColor(220,220,255,255);
201 | BGroupView::AttachedToWindow();
202 |
203 | }
204 |
205 |
206 | int32
207 | MainWindowRB::ActiveTab(void)
208 | {
209 | return fTabView->Selection();
210 | }
211 |
212 |
213 | void
214 | MainWindowRB::SetActiveTab(int32 tab)
215 | {
216 | fTabView->Select(tab);
217 | }
218 |
219 |
220 | inline void
221 | MainWindowRB::_GoToPage(int pageNumber)
222 | {
223 | BMessage msg(MSG_GOTO_PAGE);
224 | msg.AddInt32("info", pageNumber);
225 | Window()->PostMessage(&msg);
226 | }
227 |
228 |
229 | void
230 | MainWindowRB::SetDocumentPages(int pages)
231 | {
232 | fPages = pages;
233 | fPageNavigationView->SetMaxValue(pages);
234 | }
235 |
236 |
237 | void
238 | MainWindowRB::MessageReceived(BMessage* message)
239 | {
240 | switch (message->what) {
241 |
242 | case MSG_ACTIVE_PAGE:
243 | case MSG_GOTO_PAGE:
244 | {
245 | int32 value;
246 | message->FindInt32("info", &value);
247 | ++value;
248 | fPageNavigationView->SetValue(value);
249 |
250 | break;
251 | }
252 |
253 | case M_PAGENUMBER:
254 | _GoToPage(fPageNavigationView->Value() - 1);
255 | break;
256 |
257 | default:
258 | BGroupView::MessageReceived(message);
259 | }
260 | }
261 |
262 |
263 | void
264 | MainWindowRB::MouseMoved(BPoint where, uint32 code, const BMessage* dragMessage)
265 | {
266 | switch (code) {
267 | case B_EXITED_VIEW:
268 | // fMainGroup->SetVisible(false);
269 | break;
270 |
271 | case B_ENTERED_VIEW:
272 | if (fAutohiding) {
273 | fMainGroup->SetVisible(true);
274 | MakeFocus(true);
275 | }
276 | break;
277 |
278 | default:
279 | break;
280 | }
281 |
282 | BGroupView::MouseMoved(where, code, dragMessage);
283 | }
284 |
285 |
286 | void
287 | MainWindowRB::MakeFocus(bool focusState)
288 | {
289 | if (fAutohiding) {
290 | if (focusState == false)
291 | fMainGroup->SetVisible(false);
292 | }
293 |
294 | BGroupView::MakeFocus(focusState);
295 | }
296 |
297 |
298 | void
299 | MainWindowRB::SetAutohiding(bool autohiding)
300 | {
301 | fAutohiding = autohiding;
302 |
303 | if (fAutohiding)
304 | fMainGroup->SetVisible(false);
305 | else
306 | fMainGroup->SetVisible(true);
307 | }
308 |
--------------------------------------------------------------------------------
/application/MainWindowRB.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2011-2011 Haiku Inc. All rights reserved.
3 | * Distributed under the terms of the MIT License.
4 | *
5 | * Authors:
6 | * Ciprian Nedisan (cipri)
7 | *
8 | */
9 | #ifndef MAINWINDOWRB_H
10 | #define MAINWINDOWRB_H
11 |
12 | #include
13 |
14 | #include
15 | #include
16 | #include
17 |
18 | #include "Debug.h"
19 | #include "ImageButton.h"
20 | #include "ImagePopUp.h"
21 | #include "ImageTabView.h"
22 | #include "PageNavigationView.h"
23 |
24 | class MainWindowRB : public BGroupView
25 | {
26 | public:
27 | MainWindowRB(void);
28 | virtual void MouseMoved(BPoint where, uint32 code,
29 | const BMessage* dragMessage);
30 | virtual void AttachedToWindow(void);
31 | virtual void MessageReceived(BMessage* message);
32 | virtual void MakeFocus(bool focusState = true);
33 |
34 | void SetDocumentPages(int pages);
35 |
36 | void SetActiveTab(int32 tab);
37 | int32 ActiveTab(void);
38 |
39 | void SetAutohiding(bool autohiding = true);
40 | bool IsAutohiding(void) { return fAutohiding; }
41 |
42 | enum{ M_PAGENUMBER = 'ip01'
43 | };
44 |
45 | private:
46 | void _GoToPage(int pageNumber);
47 |
48 | ImageTabView* fTabView;
49 | std::vector fTabsVec;
50 |
51 | BGroupLayout* fMainGroup;
52 | PageNavigationView* fPageNavigationView;
53 |
54 | ImageButton* fOpenFileButton;
55 | ImageButton* fQuitButton;
56 | ImageButton* fSupportButton;
57 |
58 | int fPages;
59 | int fMaxHeight;
60 |
61 | bool fAutohiding;
62 |
63 | Debug out;
64 | };
65 |
66 | #endif // MAINWINDOWRB_H
67 |
--------------------------------------------------------------------------------
/application/Makefile:
--------------------------------------------------------------------------------
1 | ## Haiku Generic Makefile v2.6 ##
2 |
3 | ## Fill in this file to specify the project being created, and the referenced
4 | ## Makefile-Engine will do all of the hard work for you. This handles any
5 | ## architecture of Haiku.
6 |
7 | # The name of the binary.
8 | NAME = DocumentViewer
9 |
10 | # The type of binary, must be one of:
11 | # APP: Application
12 | # SHARED: Shared library or add-on
13 | # STATIC: Static library archive
14 | # DRIVER: Kernel driver
15 | TYPE = APP
16 |
17 | # If you plan to use localization, specify the application's MIME signature.
18 | APP_MIME_SIG =
19 |
20 | # The following lines tell Pe and Eddie where the SRCS, RDEFS, and RSRCS are
21 | # so that Pe and Eddie can fill them in for you.
22 | #%{
23 | # @src->@
24 |
25 | # Specify the source files to use. Full paths or paths relative to the
26 | # Makefile can be included. All files, regardless of directory, will have
27 | # their object files created in the common object directory. Note that this
28 | # means this Makefile will not work correctly if two source files with the
29 | # same name (source.c or source.cpp) are included from different directories.
30 | # Also note that spaces in folder names do not work well with this Makefile.
31 | SRCS = BaseEngine.cpp \
32 | BookmarksView.cpp \
33 | CircleMenuView.cpp \
34 | DJVUEngine.cpp \
35 | DocumentView.cpp \
36 | ImageButton.cpp \
37 | ImagePopUp.cpp \
38 | ImageSpinner.cpp \
39 | ImageTabView.cpp \
40 | main.cpp \
41 | MainWindow.cpp \
42 | MainWindowRB.cpp \
43 | NumberControl.cpp \
44 | OutlineView.cpp \
45 | PageNavigationView.cpp \
46 | PasswordRequestWindow.cpp \
47 | PDFEngine.cpp \
48 | PDFFilter.cpp \
49 | PreviewView.cpp \
50 | PrintingWindow.cpp \
51 | PrintPreviewView.cpp \
52 | SearchView.cpp
53 |
54 | # Specify the resource definition files to use. Full or relative paths can be
55 | # used.
56 | RDEFS = DocumentViewer.rdef Icons.rdef
57 |
58 | # Specify the resource files to use. Full or relative paths can be used.
59 | # Both RDEFS and RSRCS can be utilized in the same Makefile.
60 | RSRCS =
61 |
62 | # End Pe/Eddie support.
63 | # @<-src@
64 | #%}
65 |
66 | # Specify libraries to link against.
67 | # There are two acceptable forms of library specifications:
68 | # - if your library follows the naming pattern of libXXX.so or libXXX.a,
69 | # you can simply specify XXX for the library. (e.g. the entry for
70 | # "libtracker.so" would be "tracker")
71 | #
72 | # - for GCC-independent linking of standard C++ libraries, you can use
73 | # $(STDCPPLIBS) instead of the raw "stdc++[.r4] [supc++]" library names.
74 | #
75 | # - if your library does not follow the standard library naming scheme,
76 | # you need to specify the path to the library and it's name.
77 | # (e.g. for mylib.a, specify "mylib.a" or "path/mylib.a")
78 | LIBS = be $(STDCPPLIBS) columnlistview translation tracker \
79 | z freetype jpeg mupdf djvulibre
80 |
81 | # Specify additional paths to directories following the standard libXXX.so
82 | # or libXXX.a naming scheme. You can specify full paths or paths relative
83 | # to the Makefile. The paths included are not parsed recursively, so
84 | # include all of the paths where libraries must be found. Directories where
85 | # source files were specified are automatically included.
86 | LIBPATHS =
87 |
88 | # Additional paths to look for system headers. These use the form
89 | # "#include ". Directories that contain the files in SRCS are
90 | # NOT auto-included here.
91 | SYSTEM_INCLUDE_PATHS = /system/develop/headers/private/interface/
92 |
93 | # Additional paths paths to look for local headers. These use the form
94 | # #include "header". Directories that contain the files in SRCS are
95 | # automatically included.
96 | LOCAL_INCLUDE_PATHS =
97 |
98 | # Specify the level of optimization that you want. Specify either NONE (O0),
99 | # SOME (O1), FULL (O2), or leave blank (for the default optimization level).
100 | OPTIMIZE := SOME
101 |
102 | # Specify the codes for languages you are going to support in this
103 | # application. The default "en" one must be provided too. "make catkeys"
104 | # will recreate only the "locales/en.catkeys" file. Use it as a template
105 | # for creating catkeys for other languages. All localization files must be
106 | # placed in the "locales" subdirectory.
107 | LOCALES =
108 |
109 | # Specify all the preprocessor symbols to be defined. The symbols will not
110 | # have their values set automatically; you must supply the value (if any) to
111 | # use. For example, setting DEFINES to "DEBUG=1" will cause the compiler
112 | # option "-DDEBUG=1" to be used. Setting DEFINES to "DEBUG" would pass
113 | # "-DDEBUG" on the compiler's command line.
114 | DEFINES =
115 |
116 | # Specify the warning level. Either NONE (suppress all warnings),
117 | # ALL (enable all warnings), or leave blank (enable default warnings).
118 | WARNINGS = ALL
119 |
120 | # With image symbols, stack crawls in the debugger are meaningful.
121 | # If set to "TRUE", symbols will be created.
122 | SYMBOLS :=
123 |
124 | # Includes debug information, which allows the binary to be debugged easily.
125 | # If set to "TRUE", debug info will be created.
126 | DEBUGGER := TRUE
127 |
128 | # Specify any additional compiler flags to be used.
129 | COMPILER_FLAGS = -std=c++11
130 |
131 | # Specify any additional linker flags to be used.
132 | LINKER_FLAGS =
133 |
134 | # Specify the version of this binary. Example:
135 | # -app 3 4 0 d 0 -short 340 -long "340 "`echo -n -e '\302\251'`"1999 GNU GPL"
136 | # This may also be specified in a resource.
137 | APP_VERSION :=
138 |
139 | # (Only used when "TYPE" is "DRIVER"). Specify the desired driver install
140 | # location in the /dev hierarchy. Example:
141 | # DRIVER_PATH = video/usb
142 | # will instruct the "driverinstall" rule to place a symlink to your driver's
143 | # binary in ~/add-ons/kernel/drivers/dev/video/usb, so that your driver will
144 | # appear at /dev/video/usb when loaded. The default is "misc".
145 | DRIVER_PATH =
146 |
147 | ## Include the Makefile-Engine
148 | DEVEL_DIRECTORY := \
149 | $(shell findpaths -r "makefile_engine" B_FIND_PATH_DEVELOP_DIRECTORY)
150 | include $(DEVEL_DIRECTORY)/etc/makefile-engine
151 |
--------------------------------------------------------------------------------
/application/Messages.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2011-2011 Haiku Inc. All rights reserved.
3 | * Distributed under the terms of the MIT License.
4 | *
5 | * Authors:
6 | * Ciprian Nedisan (cipri)
7 | *
8 | */
9 | #ifndef MESSAGES_H
10 | #define MESSAGES_H
11 |
12 | enum
13 | {
14 | MSG_ACTIVE_PAGE = 'ga01' ,
15 | MSG_ANSWER_CURRENT_PAGENUMBER = 'ga02' ,
16 |
17 | MSG_APP_QUIT = 'gb01' ,
18 |
19 | MSG_FIT_PAGE_HEIGHT = 'gf01' ,
20 | MSG_FIT_PAGE_WIDTH = 'gf02' ,
21 | MSG_FULLSCREEN = 'gf03' ,
22 |
23 | MSG_GOTO_PAGE = 'gg01' ,
24 |
25 | MSG_HELP = 'gh01' ,
26 | MSG_HIGHLIGHT_RECT = 'gh02' ,
27 |
28 | MSG_NO_FIT = 'gn01' ,
29 | MSG_NO_ZOOM = 'ge02' ,
30 |
31 |
32 | MSG_OPEN_FILE = 'go01' ,
33 | MSG_OPEN_FILE_PANEL = 'go02' ,
34 |
35 | MSG_PRINT_DOCUMENT = 'gp01' ,
36 |
37 | MSG_SEARCH_RESULT = 'gS01' ,
38 | MSG_SETUP_PRINTER = 'gS02' ,
39 | MSG_SUPPORT = 'gS03' ,
40 |
41 | MSG_TELL_CURRENT_PAGENUMBER = 'gt01' ,
42 |
43 | // View-Menu
44 | MSG_VIEW_ALWAYSONTOP = 'gv01' ,
45 | MSG_ZOOM_IN = 'gz01' ,
46 |
47 | MSG_ZOOM_OUT = 'gz03'
48 | };
49 |
50 | #endif
51 |
--------------------------------------------------------------------------------
/application/NumberControl.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2012-2012 Haiku Inc. All rights reserved.
3 | * Distributed under the terms of the MIT License.
4 | *
5 | * Authors:
6 | * Ciprian Nedisan (cipri)
7 | *
8 | */
9 | #include "NumberControl.h"
10 |
11 | #include
12 |
13 | #include
14 | #include
15 |
16 | using namespace std;
17 |
18 | NumberControl::NumberControl(unique_ptr message)
19 | :
20 | BTextView("number_control"),
21 | BInvoker(message.release(), NULL, NULL)
22 | {
23 | BFont font;
24 | font.SetSize(16);
25 | font.SetFlags(Flags() | B_FORCE_ANTIALIASING);
26 | font.SetFace(B_CONDENSED_FACE | B_BOLD_FACE);
27 | rgb_color color = make_color(0, 0, 0, 255);
28 |
29 | SetFontAndColor(&font, B_FONT_ALL, &color);
30 |
31 | SetAlignment(B_ALIGN_HORIZONTAL_CENTER);
32 | //TODO:
33 | //SetWordWrap(false);
34 |
35 | font_height fontHeight;
36 | GetFontHeight(&fontHeight);
37 | auto height = fontHeight.ascent + fontHeight.descent + fontHeight.leading;
38 | height *= 1.35;
39 | SetExplicitMinSize(BSize(StringWidth("999999"), height));
40 | SetExplicitMaxSize(BSize(StringWidth("999999"), height));
41 | }
42 |
43 |
44 | void
45 | NumberControl::KeyDown(const char* bytes, int32 numBytes)
46 | {
47 | if (numBytes == 1) {
48 | auto value = bytes[0];
49 | switch (value) {
50 | case B_ENTER:
51 | SetValue(atoi(Text()));
52 | Invoke();
53 | MakeFocus(false);
54 | break;
55 |
56 | case B_DELETE:
57 | case B_INSERT:
58 | case B_BACKSPACE:
59 | BTextView::KeyDown(bytes, numBytes);
60 | break;
61 |
62 | default:
63 | if (value >= '0' && value <= '9' && TextLength() < 4)
64 | BTextView::KeyDown(bytes, numBytes);
65 |
66 | break;
67 | }
68 | }
69 | }
70 |
71 |
72 | float
73 | NumberControl::Value(void)
74 | {
75 | return fValue;
76 | }
77 |
78 |
79 | void
80 | NumberControl::SetValue(float const& value)
81 | {
82 | fValue = value;
83 | BString str;
84 | str << static_cast(fValue);
85 | SetText(str);
86 | }
87 |
--------------------------------------------------------------------------------
/application/NumberControl.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2012-2012 Haiku Inc. All rights reserved.
3 | * Distributed under the terms of the MIT License.
4 | *
5 | * Authors:
6 | * Ciprian Nedisan (cipri)
7 | *
8 | */
9 | #ifndef NUMBERCONTROL_H
10 | #define NUMBERCONTROL_H
11 |
12 | #include
13 |
14 | #include
15 | #include
16 | #include
17 |
18 | #include "Debug.h"
19 |
20 | class NumberControl : public BTextView, public BInvoker
21 | {
22 | public:
23 | NumberControl(std::unique_ptr message);
24 |
25 | virtual void KeyDown(const char* bytes, int32 numBytes);
26 | void SetValue(float const& value);
27 | float Value(void);
28 | private:
29 |
30 | float fValue;
31 | Debug out;
32 |
33 | };
34 |
35 | #endif
36 |
--------------------------------------------------------------------------------
/application/OutlineView.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2011-2011 Haiku Inc. All rights reserved.
3 | * Distributed under the terms of the MIT License.
4 | *
5 | * Authors:
6 | * Ciprian Nedisan (cipri)
7 | *
8 | */
9 | #include "OutlineView.h"
10 |
11 | #include
12 | #include
13 | #include
14 |
15 | #include "ImageButton.h"
16 | #include "MainWindow.h"
17 | #include "Messages.h"
18 |
19 | using namespace std;
20 |
21 |
22 | EditListItemWindow::EditListItemWindow(OutlineItem* item, const BString& name)
23 | :
24 | BWindow(BRect(0, 0, 300, 100), name, B_MODAL_WINDOW_LOOK,
25 | B_FLOATING_ALL_WINDOW_FEEL, B_ASYNCHRONOUS_CONTROLS
26 | | B_AUTO_UPDATE_SIZE_LIMITS | B_NOT_MINIMIZABLE | B_NOT_ZOOMABLE
27 | | B_NOT_CLOSABLE
28 | /*| B_OUTLINE_RESIZE*/
29 | /* | B_WILL_ACCEPT_FIRST_CLICK*/),
30 | fCode(0)
31 | {
32 | fNameTC = new BTextControl("Name ", "", nullptr);
33 | fNameTC->SetText(item->Name());
34 | fPageTC = new BTextControl("Page ", "", nullptr);
35 | BString str;
36 | str << item->PageNumber() + 1;
37 |
38 | fPageTC->SetText(str);
39 |
40 | BButton* okButton = new BButton("ok_button", "OK", new BMessage(M_OK));
41 | SetDefaultButton(okButton);
42 |
43 | fGoToPageCB = new BCheckBox("Go to page ");
44 | fGoToPageCB->SetValue(1);
45 |
46 | BGroupLayout* layout;
47 | layout = BLayoutBuilder::Group<>(B_VERTICAL, 0)
48 | .SetInsets(5, 5, 5, 5)
49 | .Add(fGoToPageCB)
50 | ;
51 |
52 | BBox* box1 = new BBox("box1");
53 | box1->SetBorder(B_FANCY_BORDER);
54 | box1->AddChild(layout->View());
55 |
56 |
57 | BLayoutBuilder::Group<>(this, B_VERTICAL, 10)
58 | .SetInsets(10, 10, 10, 10)
59 | .Add(fNameTC)
60 | .Add(fPageTC)
61 | //.Add(box1)
62 | .AddGlue(0)
63 | .AddGroup(B_HORIZONTAL, 0)
64 | .AddGlue(0)
65 | .Add(okButton)
66 | .End()
67 | .End();
68 |
69 | fNameTC->MakeFocus();
70 | fItem = item;
71 | }
72 |
73 |
74 | void
75 | EditListItemWindow::SetResponse(const int& code, BLooper* looper, BHandler* handler)
76 | {
77 | fTargetLooper = looper;
78 | fTargetHandler = handler;
79 | fCode = code;
80 | }
81 |
82 |
83 | void
84 | EditListItemWindow::MessageReceived(BMessage* message)
85 | {
86 | switch (message->what) {
87 | case M_OK:
88 | {
89 | fItem->SetName(fNameTC->Text());
90 | fItem->SetPageNumber(atoi(fPageTC->Text()) - 1);
91 | fTargetLooper->PostMessage(fCode, fTargetHandler);
92 | Close();
93 |
94 | break;
95 | }
96 |
97 |
98 | default:
99 | BWindow::MessageReceived(message);
100 | break;
101 | }
102 | }
103 |
104 |
105 | OutlineItem::OutlineItem(const BString& name, const int& pageNumber,
106 | uint32 outlineLevel, bool expanded)
107 | :
108 | BListItem(),
109 | fName(name),
110 | fPageNumber(pageNumber)
111 | {
112 | }
113 |
114 |
115 | OutlineItem::~OutlineItem()
116 | {
117 | }
118 |
119 |
120 | void
121 | OutlineItem::SetName(const BString& name)
122 | {
123 | fName = name;
124 | }
125 |
126 |
127 | void
128 | OutlineItem::DrawItem(BView *owner, BRect itemRect, bool complete)
129 | {
130 | rgb_color kBlack = {0, 0, 0, 0};
131 | rgb_color kHighlight = {156, 154, 156, 0};
132 |
133 | if (IsSelected() || complete) {
134 | rgb_color color;
135 | if (IsSelected())
136 | color = kHighlight;
137 | else
138 | color = owner->ViewColor();
139 |
140 | owner->SetHighColor(color);
141 | owner->SetLowColor(color);
142 | owner->FillRect(itemRect);
143 | owner->SetHighColor(kBlack);
144 |
145 | } else {
146 | owner->SetLowColor(owner->ViewColor());
147 | }
148 |
149 | BFont font = be_plain_font;
150 | font_height finfo;
151 | font.GetHeight(&finfo);
152 |
153 | BPoint point = BPoint(itemRect.left + 5, itemRect.bottom - finfo.descent + 1);
154 |
155 | owner->SetHighColor(kBlack);
156 | owner->SetFont(be_plain_font);
157 | owner->MovePenTo(point);
158 |
159 | owner->MovePenTo(point);
160 | owner->DrawString(fName);
161 | }
162 |
163 |
164 | OutlineListView::OutlineListView(void)
165 | :
166 | BOutlineListView("outline_list_view"),
167 | fStartSearchIndex(0)
168 | {
169 |
170 | }
171 |
172 |
173 | void
174 | OutlineListView::ReverseOrder(OutlineItem* super)
175 | {
176 | if (super == nullptr)
177 | return;
178 |
179 | int32 end = CountItemsUnder(super, true) - 1;
180 | if (end < 1)
181 | return;
182 |
183 | for (int start = 0; start < end; ++start, --end)
184 | SwapItems(FullListIndexOf(ItemUnderAt(super, true, start)),
185 | FullListIndexOf(ItemUnderAt(super, true, end)));
186 | }
187 |
188 |
189 | void
190 | OutlineListView::MoveFirstToEnd(OutlineItem* super)
191 | {
192 | // move the element fromt the front to the end of the list
193 | int32 transpositions = CountItemsUnder(super, true) - 1;
194 | for (int i = 0; i < transpositions; ++i)
195 | SwapItems(FullListIndexOf(ItemUnderAt(super, true, i)),
196 | FullListIndexOf(ItemUnderAt(super, true, i + 1)));
197 | }
198 |
199 | void
200 | OutlineListView::MouseDown(BPoint where)
201 | {
202 | int32 idx = CurrentSelection();
203 | BOutlineListView::MouseDown(where);
204 |
205 | if (CurrentSelection() == idx) {
206 | DeselectAll();
207 | }
208 | }
209 |
210 |
211 | void
212 | OutlineListView::SetEngine(BaseEngine* engine)
213 | {
214 | if (engine == nullptr)
215 | return;
216 |
217 | MakeEmpty();
218 | fEngine = engine;
219 | fEngine->WriteOutline(this);
220 | ReverseOrder();
221 | }
222 |
223 |
224 | void
225 | OutlineListView::ReverseOrder(void)
226 | {
227 | int32 size = FullListCountItems();
228 |
229 | for (int i = 0; i < size; ++i)
230 | ReverseOrder(static_cast(FullListItemAt(i)));
231 | }
232 |
233 |
234 | void
235 | OutlineListView::Find(const BString& name)
236 | {
237 | if (name.Length() == 0)
238 | return;
239 |
240 | if (name != fSearchString) {
241 | fStartSearchIndex = 0;
242 | fSearchString = name;
243 | }
244 |
245 | int32 size = FullListCountItems();
246 | OutlineItem* item;
247 |
248 | for (int j = 0; j < 2; ++j) {
249 | for (int i = fStartSearchIndex; i < size; ++i) {
250 | item = static_cast(FullListItemAt(i));
251 | if (item->Name().IFindFirst(name) != B_ERROR) {
252 | DeselectAll();
253 | Select(i, true);
254 | ScrollToSelection();
255 | fStartSearchIndex = (i + 1) % size;
256 | return;
257 | }
258 | }
259 | fStartSearchIndex = 0;
260 | }
261 | }
262 |
263 |
264 | OutlineItem*
265 | OutlineListView::_SelectedItem(void)
266 | {
267 | return static_cast< OutlineItem* >(FullListItemAt(CurrentSelection()));
268 | }
269 |
270 |
271 | inline void
272 | OutlineListView::_GoToPage(const int& pageNumber)
273 | {
274 | BMessage msg(MSG_GOTO_PAGE);
275 | msg.AddInt32("info", pageNumber);
276 | Window()->PostMessage(&msg);
277 | }
278 |
279 |
280 | status_t
281 | OutlineListView::Invoke(BMessage* message)
282 | {
283 | auto item = _SelectedItem();
284 | if (item)
285 | _GoToPage(item->PageNumber());
286 |
287 | BListView::Invoke(message);
288 |
289 | // added this return call to silence -Wreturn-type warning
290 | // should probably be replaced by real error handling
291 | return B_OK;
292 | }
293 |
294 |
295 | void
296 | OutlineListView::RemoveCurrentSelection(void)
297 | {
298 | int32 idx = FullListCurrentSelection();
299 | RemoveItem(idx);
300 | Select(idx - 1);
301 | }
302 |
303 |
304 | bool
305 | OutlineListView::InitiateDrag(BPoint point, int32 itemIndex, bool initialySelected)
306 | {
307 | !out << "DRAG" << endl;
308 | return BOutlineListView::InitiateDrag(point, itemIndex, initialySelected);
309 | }
310 |
311 |
312 |
313 | OutlineView::OutlineView(void)
314 | :
315 | BGroupView("outline", B_VERTICAL, 0)
316 | {
317 | const float iconHeight = 30;
318 | fDeleteItem = new ImageButton("quit",
319 | new BMessage(M_DELETE_ITEM), 0.3, 1, "Remove outline");
320 | fDeleteItem->SetExplicitMinSize(BSize(iconHeight, iconHeight));
321 | fDeleteItem->SetExplicitMaxSize(BSize(iconHeight, iconHeight));
322 |
323 | fAddItem = new ImageButton("plus",
324 | new BMessage(M_ADD_ITEM), 0.3, 1, "Add outline");
325 | fAddItem->SetExplicitMinSize(BSize(iconHeight, iconHeight));
326 | fAddItem->SetExplicitMaxSize(BSize(iconHeight, iconHeight));
327 |
328 | fEditItem = new ImageButton("edit",
329 | new BMessage(M_EDIT_ITEM), 0.3, 1, "Edit outline");
330 | fEditItem->SetExplicitMinSize(BSize(iconHeight, iconHeight));
331 | fEditItem->SetExplicitMaxSize(BSize(iconHeight, iconHeight));
332 |
333 | fFindNext = new ImageButton("find_next",
334 | new BMessage(M_FIND_NEXT), 0.3, 1, "Search outline");
335 | fFindNext->SetExplicitMinSize(BSize(iconHeight, iconHeight));
336 | fFindNext->SetExplicitMaxSize(BSize(iconHeight, iconHeight));
337 |
338 | fOutlineListView = new OutlineListView();
339 |
340 | fVScrollBar = new BScrollBar("v_scrollbar",
341 | fOutlineListView, 0, 100, B_VERTICAL);
342 | fHScrollBar = new BScrollBar("h_scrollbar",
343 | fOutlineListView, 0, 100, B_HORIZONTAL);
344 |
345 | fSearchTC = new BTextControl("", "", new BMessage(M_FIND_NEXT));
346 |
347 | BGroupLayout*
348 | controlsLayout = BLayoutBuilder::Group<>(B_VERTICAL, 0)
349 | .AddGroup(B_HORIZONTAL, 0)
350 | .Add(fAddItem)
351 | .Add(fEditItem)
352 | .Add(fDeleteItem)
353 | .Add(fSearchTC)
354 | .Add(fFindNext)
355 | .End()
356 | ;
357 |
358 | BBox* box1 = new BBox("box1");
359 | box1->SetBorder(B_FANCY_BORDER);
360 | box1->AddChild(controlsLayout->View());
361 |
362 | BGroupLayout*
363 | listLayout = BLayoutBuilder::Group<>(B_HORIZONTAL, 0)
364 | .Add(fOutlineListView)
365 | .Add(fVScrollBar)
366 | ;
367 |
368 | BBox* box2 = new BBox("box2");
369 | box2->SetBorder(B_FANCY_BORDER);
370 | box2->AddChild(listLayout->View());
371 |
372 | BLayoutBuilder::Group<>(this)
373 | .Add(box1)
374 | .Add(box2)
375 | .End()
376 | ;
377 | }
378 |
379 |
380 | void
381 | OutlineView::AttachedToWindow(void)
382 | {
383 | fDeleteItem->SetTarget(this);
384 | fAddItem->SetTarget(this);
385 | fEditItem->SetTarget(this);
386 | fSearchTC->SetTarget(this);
387 | fFindNext->SetTarget(this);
388 | BGroupView::AttachedToWindow();
389 | }
390 |
391 |
392 | void
393 | OutlineView::EngineChanged(BaseEngine* engine)
394 | {
395 | //ToDo: save outline
396 | fOutlineListView->SetEngine(engine);
397 | Invalidate();
398 | }
399 |
400 |
401 | void
402 | OutlineView::_ShowEditWindow(void)
403 | {
404 | int idx = fOutlineListView->CurrentSelection();
405 | if (idx < 0)
406 | return;
407 |
408 | OutlineItem* item = static_cast(fOutlineListView->FullListItemAt(idx));
409 | item->SetPageNumber(_CurrentPageNumber());
410 | auto temp = new EditListItemWindow(item);
411 | temp->SetResponse(M_ITEM_CHANGED, Window(), this);
412 | temp->CenterIn(Window()->Frame());
413 | temp->Show();
414 | }
415 |
416 |
417 | int
418 | OutlineView::_CurrentPageNumber(void)
419 | {
420 | return static_cast(Window())->CurrentPageNumber();
421 | }
422 |
423 |
424 | void
425 | OutlineView::MessageReceived(BMessage* message)
426 | {
427 | switch (message->what) {
428 | case M_DELETE_ITEM:
429 | fOutlineListView->RemoveCurrentSelection();
430 | break;
431 |
432 | case M_ADD_ITEM:
433 | {
434 | OutlineItem* item = new OutlineItem("", _CurrentPageNumber());
435 | OutlineItem* super = nullptr;
436 | int idx = fOutlineListView->CurrentSelection();
437 | if (idx < 0) {
438 | fOutlineListView->AddItem(item);
439 | } else {
440 | super = static_cast(fOutlineListView->FullListItemAt(idx));
441 | fOutlineListView->AddUnder(item, super);
442 | }
443 |
444 | fOutlineListView->MoveFirstToEnd(super);
445 |
446 | fOutlineListView->Select(fOutlineListView->IndexOf(item));
447 | fOutlineListView->Invalidate();
448 |
449 | _ShowEditWindow();
450 |
451 | break;
452 | }
453 |
454 | case M_EDIT_ITEM:
455 | _ShowEditWindow();
456 | break;
457 |
458 | case M_ITEM_CHANGED:
459 | {
460 | fOutlineListView->Invalidate();
461 | /*
462 | auto compare = [](const OutlineItem* i1, const OutlineItem* i2){
463 | return i1->PageNumber() - i2->PageNumber();
464 | };
465 |
466 | fOutlineListView->FullListSortItems(compare);
467 | */
468 | break;
469 | }
470 |
471 | case M_FIND_NEXT:
472 | fOutlineListView->Find(fSearchTC->Text());
473 | break;
474 |
475 | default:
476 | BGroupView::MessageReceived(message);
477 | break;
478 | }
479 | }
480 |
--------------------------------------------------------------------------------
/application/OutlineView.h:
--------------------------------------------------------------------------------
1 |
2 | /*
3 | * Copyright 2011-2011 Haiku Inc. All rights reserved.
4 | * Distributed under the terms of the MIT License.
5 | *
6 | * Authors:
7 | * Ciprian Nedisan (cipri)
8 | *
9 | */
10 | #ifndef OUTLINEVIEW_H
11 | #define OUTLINEVIEW_H
12 |
13 | #include
14 | #include
15 |
16 |
17 | extern "C" {
18 | #include
19 | }
20 |
21 |
22 | #include
23 | #include
24 | #include
25 | #include
26 | #include
27 | #include
28 | #include
29 | #include
30 |
31 | #include "BaseEngine.h"
32 | #include "Debug.h"
33 | #include "ImageButton.h"
34 |
35 |
36 | class OutlineItem : public BListItem
37 | {
38 | public:
39 | OutlineItem(const BString& name, const int& pageNumber = 0,
40 | uint32 outlineLevel = 0, bool expanded = true);
41 | ~OutlineItem();
42 | virtual void DrawItem(BView* owner, BRect itemRect, bool = false);
43 |
44 | void SetName(const BString& name);
45 | BString Name(void) { return fName; }
46 |
47 | const int& PageNumber(void) const
48 | {
49 | return fPageNumber;
50 | }
51 |
52 | void SetPageNumber(const int& pageNumber)
53 | {
54 | fPageNumber = pageNumber;
55 | }
56 |
57 | private:
58 | BString fName;
59 | int fPageNumber;
60 | };
61 |
62 |
63 | class OutlineListView : public BOutlineListView
64 | {
65 | public:
66 | OutlineListView(void);
67 | virtual status_t Invoke(BMessage* message = nullptr);
68 | virtual void MouseDown(BPoint where);
69 | virtual bool InitiateDrag(BPoint point, int32 itemIndex,
70 | bool initialySelected);
71 |
72 | void RemoveCurrentSelection(void);
73 | void SetEngine(BaseEngine* engine);
74 | void ReverseOrder(OutlineItem* super);
75 | void ReverseOrder(void);
76 | void MoveFirstToEnd(OutlineItem* super);
77 | void Find(const BString& name);
78 |
79 | private:
80 | OutlineItem* _SelectedItem(void);
81 | inline void _GoToPage(const int& pageNumber);
82 |
83 | BaseEngine* fEngine;
84 |
85 | BString fSearchString;
86 | int32 fStartSearchIndex;
87 |
88 | Debug out;
89 |
90 | };
91 |
92 |
93 | class EditListItemWindow : public BWindow
94 | {
95 | public:
96 | EditListItemWindow(OutlineItem* item, const BString& name = "Edit");
97 |
98 | virtual void MessageReceived(BMessage* message);
99 |
100 | void SetResponse(const int& code, BLooper* looper, BHandler* handler = nullptr);
101 |
102 | enum{ M_OK = 'io01'
103 |
104 | };
105 |
106 | private:
107 | BTextControl* fNameTC;
108 | BTextControl* fPageTC;
109 | BCheckBox* fGoToPageCB;
110 | OutlineItem * fItem;
111 | BLooper* fTargetLooper;
112 | BHandler* fTargetHandler;
113 | int fCode;
114 |
115 | Debug out;
116 |
117 | };
118 |
119 |
120 | class OutlineView : public BGroupView
121 | {
122 | public:
123 | OutlineView(void);
124 | virtual void MessageReceived(BMessage* message);
125 | virtual void AttachedToWindow(void);
126 |
127 | virtual void EngineChanged(BaseEngine* engine);
128 |
129 |
130 | enum{ M_ADD_ITEM = 'ic01', M_DELETE_ITEM = 'id01',
131 | M_EDIT_ITEM = 'ie01', M_FIND_NEXT = 'if01',
132 | M_ITEM_CHANGED = 'ii01'
133 | };
134 |
135 | private:
136 | int _CurrentPageNumber(void);
137 | void _ShowEditWindow(void);
138 |
139 | BScrollBar* fVScrollBar;
140 | BScrollBar* fHScrollBar;
141 |
142 | BTextControl* fSearchTC;
143 |
144 | ImageButton* fEditItem;
145 | ImageButton* fDeleteItem;
146 | ImageButton* fAddItem;
147 | ImageButton* fFindNext;
148 |
149 | OutlineListView* fOutlineListView;
150 | Debug out;
151 | };
152 |
153 | #endif
154 |
--------------------------------------------------------------------------------
/application/PDFEngine.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2011-2012 Haiku Inc. All rights reserved.
3 | * Distributed under the terms of the MIT License.
4 | *
5 | * Authors:
6 | * Ciprian Nedisan (cipri)
7 | *
8 | */
9 | #include "PDFEngine.h"
10 |
11 | #include
12 | #include
13 | #include
14 | #include
15 |
16 | #include "Flags.h"
17 | #include "Messages.h"
18 | #include "OutlineView.h"
19 | #include "PasswordRequestWindow.h"
20 |
21 | using namespace std;
22 |
23 |
24 | struct fz_lock_impl {
25 | fz_locks_context context;
26 |
27 | fz_lock_impl() {
28 | for (int i = 0; i < FZ_LOCK_MAX; i++)
29 | locks[i] = PTHREAD_MUTEX_INITIALIZER;
30 |
31 | context.user = this;
32 | context.lock = lock;
33 | context.unlock = unlock;
34 | }
35 |
36 | static void lock(void* user, int lock) {
37 | pthread_mutex_lock(&((fz_lock_impl*)user)->locks[lock]);
38 | }
39 | static void unlock(void* user, int lock) {
40 | pthread_mutex_unlock(&((fz_lock_impl*)user)->locks[lock]);
41 | }
42 |
43 | private:
44 | pthread_mutex_t locks[FZ_LOCK_MAX];
45 | };
46 |
47 |
48 | PDFEngine::PDFEngine(BString fileName, BString& password)
49 | :
50 | fFileName(fileName),
51 | fPassword(password)
52 | {
53 | fHighlightUnderText = true;
54 | fDocument = nullptr;
55 | fz_var(fDocument);
56 |
57 | fz_lock_impl* locks = new fz_lock_impl;
58 | fContext = fz_new_context(nullptr, &locks->context, FZ_STORE_DEFAULT);
59 | fz_register_document_handlers(fContext);
60 | // why bgr instead of rgb?
61 | fColorSpace = fz_device_bgr(fContext);
62 |
63 | if (!fContext) {
64 | !out << "cannot init context" << endl;
65 | exit(1);
66 | }
67 |
68 | fz_try(fContext) {
69 | fDocument = fz_open_document(fContext, fileName.String());
70 | } fz_catch(fContext) {
71 | !out << "can not open document" << endl;
72 | throw;
73 | }
74 |
75 | if (fz_needs_password(fContext, fDocument)) {
76 | if (password.Length() == 0) {
77 | while (true) {
78 | auto t = (new PasswordRequestWindow())->Go();
79 | if (std::get<1>(t) == false)
80 | throw "wrong password";
81 |
82 | if (fz_authenticate_password(fContext, fDocument, std::get<0>(t))) {
83 | password = std::get<0>(t);
84 | break;
85 | }
86 | }
87 | } else {
88 | int okay = fz_authenticate_password(fContext, fDocument,
89 | const_cast(password.String()));
90 |
91 | if (!okay)
92 | throw "wrong password";
93 | }
94 | }
95 |
96 | // Contexts for alternate threads
97 | fRenderContext = fz_clone_context(fContext);
98 |
99 | Start();
100 | }
101 |
102 |
103 | PDFEngine::~PDFEngine()
104 | {
105 | Stop();
106 |
107 | if (fDocument) {
108 | fz_drop_document(fContext, fDocument);
109 | }
110 |
111 | if (fContext) {
112 | fz_lock_impl* locks = static_cast(fContext->locks.user);
113 | fz_drop_context(fContext);
114 | delete locks;
115 | }
116 | }
117 |
118 |
119 | int
120 | PDFEngine::PageCount(void) const
121 | {
122 | int count = fz_count_pages(fContext, fDocument);
123 | return count;
124 | }
125 |
126 |
127 |
128 | void
129 | PDFEngine::WriteOutline(BOutlineListView* list)
130 | {
131 | auto outline = fz_load_outline(fContext, fDocument);
132 |
133 | std::function OutlineToList =
134 | [&OutlineToList](fz_context* ctx, fz_document* doc, fz_outline* outline, BOutlineListView* list, BListItem* super, int level) {
135 | OutlineItem* item;
136 | int page_number;
137 | while (outline) {
138 | page_number = fz_page_number_from_location(ctx, doc, outline->page);
139 | if (page_number > -1)
140 | item = new OutlineItem(outline->title, page_number);
141 | else
142 | item = new OutlineItem(outline->title, 0);
143 |
144 | list->AddUnder(item, super);
145 |
146 | if (outline->down)
147 | OutlineToList(ctx, doc, outline->down,list, item, level + 1);
148 |
149 | outline = outline->next;
150 | }
151 | };
152 |
153 | OutlineToList(fContext, fDocument, outline, list, nullptr, 0);
154 | fz_drop_outline(fContext, outline);
155 | }
156 |
157 |
158 | namespace std {
159 | // FIXME remove when the compiler supports this C++11 feature.
160 | template
161 | std::unique_ptr make_unique(Args&&... args)
162 | {
163 | return std::unique_ptr(new T(std::forward(args)...));
164 | }
165 | }
166 |
167 |
168 | std::tuple< std::vector, std::vector >
169 | PDFEngine::_FindString(BString const& name, int const& pageNumber)
170 | {
171 | vector contextVec;
172 | vector rectVec;
173 |
174 | bool needWholeWord = false;
175 | if (GHasFlag(fSearchFlag, SEARCH_WHOLE_WORD))
176 | needWholeWord = true;
177 |
178 | bool needMatchCase = false;
179 | if (GHasFlag(fSearchFlag, SEARCH_MATCH_CASE))
180 | needMatchCase = true;
181 |
182 | fz_page* page = nullptr;
183 | page = fz_load_page(fContext, fDocument, pageNumber);
184 |
185 | fz_device* dev = nullptr;
186 | fz_var(dev);
187 |
188 | fz_stext_page* text = nullptr;
189 | fz_var(text);
190 |
191 | fz_try(fContext) {
192 | text = fz_new_stext_page_from_page(fContext, page, NULL);
193 | dev = fz_new_stext_device(fContext, text, 0);
194 |
195 | // Load the text from the page
196 | fz_run_page(fContext, page, dev, fz_identity, NULL);
197 | fz_close_device(fContext, dev);
198 | fz_drop_device(fContext, dev);
199 | dev = nullptr;
200 |
201 | // Now actually get the boxes
202 | static const int MAX_SEARCHES = 500;
203 | fz_quad boxes[MAX_SEARCHES];
204 | // Keep track of the hit marks
205 | int hit_marks[MAX_SEARCHES];
206 | int count = fz_search_stext_page(fContext, text, name, hit_marks, boxes, MAX_SEARCHES);
207 |
208 | for (int i = 0; i < count; i++) {
209 | // Attempt to avoid duplicates
210 | if (hit_marks[i]) {
211 | fz_rect fr = fz_rect_from_quad(boxes[i]);
212 | BRect br;
213 | br.top = fr.y0;
214 | br.bottom = fr.y1;
215 | br.left = fr.x0;
216 | br.right = fr.x1;
217 |
218 | // Get some context: extract some text around the match by enlarging
219 | // the rect to cover a greater part of the text
220 | fr.x0 -= 1000;
221 | fr.x1 += 1000;
222 |
223 | BString context(fz_copy_rectangle(fContext, text, fr, false));
224 | int pos = context.FindFirst(name);
225 |
226 | // Check that we get a case match if requested
227 | if (needMatchCase && pos < 0)
228 | continue;
229 |
230 | // Filter out non-whole word results
231 | if (needWholeWord) {
232 | if (pos > 0 && isalpha(context[pos - 1]))
233 | continue;
234 | if (isalpha(context[pos + name.Length()]))
235 | continue;
236 | }
237 |
238 | rectVec.push_back(br);
239 | contextVec.push_back(context);
240 | }
241 | }
242 |
243 |
244 | } fz_catch(fContext) {
245 | fz_close_device(fContext, dev);
246 | fz_drop_device(fContext, dev);
247 | fz_drop_stext_page(fContext, text);
248 | fz_rethrow(fContext);
249 | }
250 |
251 | return make_tuple(contextVec, rectVec);
252 | }
253 |
254 |
255 | BString
256 | PDFEngine::GetProperty(BString name)
257 | {
258 | BString property;
259 |
260 | return property;
261 | }
262 |
263 |
264 | BString
265 | PDFEngine::FileName(void) const
266 | {
267 | return fFileName;
268 | }
269 |
270 |
271 | unique_ptr
272 | PDFEngine::RenderBitmap(int const& pageNumber,
273 | uint32 const& width, uint32 const& height, int const& rotation)
274 | {
275 | if (pageNumber < 0 || pageNumber >= fPages) {
276 | return unique_ptr(nullptr);
277 | }
278 |
279 | fz_page *page;
280 | fz_display_list *list = nullptr;
281 | fz_device *dev = nullptr;
282 |
283 | fz_var(list);
284 | fz_var(dev);
285 |
286 | pthread_mutex_lock(&fRendermutex);
287 |
288 | bool stop = false; // variable for avoiding return in fz_catch
289 | fz_try(fRenderContext) {
290 | page = fz_load_page(fRenderContext, fDocument, pageNumber);
291 | } fz_catch(fRenderContext) {
292 | pthread_mutex_unlock(&fRendermutex);
293 | stop = true;
294 | }
295 |
296 | if (stop)
297 | return std::make_unique(BRect(0, 0, width, height), B_RGBA32);
298 |
299 | fz_try(fRenderContext) {
300 | list = fz_new_display_list(fRenderContext, fz_empty_rect);
301 | dev = fz_new_list_device(fRenderContext, list);
302 | fz_run_page(fRenderContext, page, dev, fz_identity, nullptr);
303 | } fz_catch(fRenderContext) {
304 | fz_close_device(fRenderContext, dev);
305 | fz_drop_device(fRenderContext, dev);
306 | fz_drop_display_list(fRenderContext, list);
307 | fz_drop_page(fRenderContext, page);
308 | pthread_mutex_unlock(&fRendermutex);
309 | stop = true;
310 | }
311 |
312 | if (stop)
313 | return std::make_unique(BRect(0, 0, width, height), B_RGBA32);
314 |
315 | fz_close_device(fRenderContext, dev);
316 | fz_drop_device(fRenderContext, dev);
317 | dev = nullptr;
318 |
319 | fz_pixmap* image = nullptr;
320 | fz_var(image);
321 |
322 | fz_rect bounds = fz_bound_page(fRenderContext, page);
323 |
324 | float zoomFactor = 1;
325 |
326 | if (width <= 0) {
327 | zoomFactor = height / (bounds.y1 - bounds.y0);
328 | } else {
329 | zoomFactor = width / (bounds.x1 - bounds.x0);
330 | }
331 |
332 | fz_matrix ctm = fz_pre_scale(fz_rotate(fRotation), zoomFactor, zoomFactor);
333 | fz_irect pageBox = fz_round_rect(fz_transform_rect(bounds, ctm));
334 | fz_separations *seps = fz_page_separations(fContext, page);
335 |
336 | fz_try(fRenderContext) {
337 | image = fz_new_pixmap_with_bbox(fRenderContext, fColorSpace, pageBox, seps, 1);
338 |
339 | fz_clear_pixmap_with_value(fRenderContext, image, 255);
340 | dev = fz_new_draw_device(fRenderContext, fz_identity, image);
341 | if (list)
342 | fz_run_display_list(fRenderContext, list, dev, ctm, bounds, nullptr);
343 | else
344 | fz_run_page(fRenderContext, page, dev, ctm, nullptr);
345 |
346 | fz_close_device(fRenderContext, dev);
347 | fz_drop_device(fRenderContext, dev);
348 | dev = nullptr;
349 | } fz_catch(fRenderContext) {
350 | fz_close_device(fRenderContext, dev);
351 | fz_drop_device(fRenderContext, dev);
352 | fz_drop_pixmap(fRenderContext, image);
353 | fz_drop_display_list(fRenderContext, list);
354 | fz_drop_page(fRenderContext, page);
355 | pthread_mutex_unlock(&fRendermutex);
356 | stop = true;
357 | }
358 |
359 | if (stop)
360 | return std::make_unique(BRect(0, 0, width, height), B_RGBA32);
361 |
362 | fz_flush_warnings(fRenderContext);
363 |
364 | int imageWidth = pageBox.x1 - pageBox.x0;
365 | int imageHeight = pageBox.y1 - pageBox.y0;
366 |
367 |
368 | BBitmap* bitmap = new BBitmap(BRect(0, 0, imageWidth - 1, imageHeight - 1), B_RGBA32);
369 | bitmap->SetBits(fz_pixmap_samples(fRenderContext, image),
370 | imageWidth * imageHeight * fz_pixmap_components(fRenderContext, image), 0, B_RGBA32);
371 |
372 | fz_close_device(fRenderContext, dev);
373 | fz_drop_device(fRenderContext, dev);
374 | fz_drop_pixmap(fRenderContext, image);
375 | fz_drop_display_list(fRenderContext, list);
376 | fz_drop_page(fRenderContext, page);
377 |
378 | pthread_mutex_unlock(&fRendermutex);
379 | return unique_ptr(bitmap);
380 | }
381 |
382 |
383 | std::pair
384 | PDFEngine::_RenderBitmap(int const& pageNumber)
385 | {
386 | unique_ptr bitmap = RenderBitmap(pageNumber, fDefaultRect.Width(),
387 | fDefaultRect.Height(), 0);
388 |
389 | return std::pair(bitmap.release(), false);
390 | }
391 |
--------------------------------------------------------------------------------
/application/PDFEngine.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2011-2012 Haiku Inc. All rights reserved.
3 | * Distributed under the terms of the MIT License.
4 | *
5 | * Authors:
6 | * Ciprian Nedisan (cipri)
7 | *
8 | */
9 | #ifndef PDFENGINE_H
10 | #define PDFENGINE_H
11 |
12 | extern "C" {
13 | #include
14 | //#include
15 | }
16 |
17 |
18 | #include
19 |
20 | #include
21 |
22 | #include "BaseEngine.h"
23 | #include "Debug.h"
24 |
25 | class PDFEngine : public BaseEngine
26 | {
27 | public:
28 | PDFEngine(BString filename, BString& password);
29 |
30 | virtual ~PDFEngine();
31 |
32 | virtual BString FileName(void) const;
33 | int PageCount(void) const;
34 |
35 | virtual BString GetProperty(BString name);
36 |
37 | virtual void WriteOutline(BOutlineListView* list);
38 |
39 | virtual std::unique_ptr RenderBitmap(int const& pageNumber,uint32 const& width,
40 | uint32 const& height, int const& rotation = 0);
41 |
42 | private:
43 | virtual std::pair _RenderBitmap(int const& pageNumber);
44 | virtual std::tuple< std::vector, std::vector >
45 | _FindString(BString const& name, int const& page);
46 |
47 | fz_document* fDocument;
48 | fz_context* fContext;
49 | fz_context* fRenderContext;
50 |
51 | fz_page* fPage;
52 | fz_display_list* fList;
53 | fz_device* fDev;
54 |
55 | fz_colorspace* fColorSpace;
56 |
57 | BString fFileName;
58 | BString fPassword;
59 |
60 | pthread_mutex_t fRendermutex = PTHREAD_MUTEX_INITIALIZER;
61 |
62 | Debug out;
63 | };
64 |
65 | #endif
66 |
--------------------------------------------------------------------------------
/application/PDFFilter.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2011-2011 Haiku Inc. All rights reserved.
3 | * Distributed under the terms of the MIT License.
4 | *
5 | * Authors:
6 | * Ciprian Nedisan (cipri)
7 | *
8 | */
9 |
10 | #include "PDFFilter.h"
11 |
12 | #include
13 |
14 | #include
15 | #include
16 |
17 | static const char* valid_filetypes[] = {
18 | "application/pdf",
19 | "application/djvu",
20 | "application/xps",
21 | NULL
22 | };
23 |
24 | bool
25 | PDFFilter::Filter(const entry_ref* ref, BNode* node, struct stat_beos* st,
26 | const char* filetype)
27 | {
28 | BEntry entry(ref, true);
29 | if (entry.InitCheck() != B_OK)
30 | return false;
31 | if (entry.IsDirectory())
32 | return true;
33 |
34 | entry_ref linkedRef;
35 | if (entry.GetRef(&linkedRef) != B_OK)
36 | return false;
37 |
38 | BMimeType mimeType;
39 | if (BMimeType::GuessMimeType(&linkedRef, &mimeType) != B_OK)
40 | return false;
41 |
42 | for (int i = 0; valid_filetypes[i] != nullptr; i++)
43 | if (strcmp(mimeType.Type(), valid_filetypes[i]) == 0)
44 | return true;
45 |
46 | return false;
47 | }
48 |
--------------------------------------------------------------------------------
/application/PDFFilter.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2011-2011 Haiku Inc. All rights reserved.
3 | * Distributed under the terms of the MIT License.
4 | *
5 | * Authors:
6 | * Ciprian Nedisan (cipri)
7 | *
8 | */
9 | #ifndef PDF_FILTER_H
10 | #define PDF_FILTER_H
11 |
12 | #include
13 |
14 | class PDFFilter : public BRefFilter {
15 | public:
16 | bool Filter(const entry_ref* ref, BNode* node, struct stat_beos* st,
17 | const char* filetype);
18 | };
19 |
20 | #endif
21 |
--------------------------------------------------------------------------------
/application/PageNavigationView.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2012-2012 Haiku Inc. All rights reserved.
3 | * Distributed under the terms of the MIT License.
4 | *
5 | * Authors:
6 | * Ciprian Nedisan (cipri)
7 | *
8 | */
9 | #include "PageNavigationView.h"
10 |
11 | #include
12 |
13 | #include
14 | #include
15 | #include
16 |
17 | #include "ImageButton.h"
18 |
19 | using namespace std;
20 |
21 | PageNavigationView::PageNavigationView(unique_ptr message)
22 | :
23 | BGroupView("page_navigation_view", B_HORIZONTAL, 0),
24 | BInvoker(message.release(), NULL, NULL),
25 | fMaxValue(10000)
26 | {
27 | SetFlags(Flags() | B_FRAME_EVENTS);
28 | unique_ptr pageNumberMsg(new BMessage(M_GOTO_PAGE));
29 |
30 | fPageNC = new NumberControl(move(pageNumberMsg));
31 | fTotalPagesSV = new BStringView("pages_sv", "");
32 |
33 | BGroupLayout* layout1;
34 | layout1 = BLayoutBuilder::Group<>(B_HORIZONTAL, 0)
35 | .Add(fPageNC)
36 | .AddGroup(B_VERTICAL, 0)
37 | .AddGlue(0)
38 | .Add(fTotalPagesSV)
39 | .AddGlue(0)
40 | .End()
41 | ;
42 |
43 | BBox* box1 = new BBox("box1");
44 | box1->SetBorder(B_FANCY_BORDER);
45 | box1->AddChild(layout1->View());
46 |
47 | fBackButton = new ImageButton("back",
48 | new BMessage(M_GOTO_PREVIOUS_PAGE), 0.3, 1, "Previous page");
49 |
50 | fNextButton = new ImageButton("next",
51 | new BMessage(M_GOTO_NEXT_PAGE), 0.3, 1, "Next page");
52 |
53 | BLayoutBuilder::Group<>(this)
54 | .Add(fBackButton)
55 | .Add(box1)
56 | .Add(fNextButton)
57 | ;
58 | }
59 |
60 |
61 | void
62 | PageNavigationView::MessageReceived(BMessage* message)
63 | {
64 | switch (message->what) {
65 | case M_GOTO_PAGE:
66 | SetValue(fPageNC->Value());
67 | Invoke();
68 | break;
69 |
70 | case M_GOTO_NEXT_PAGE:
71 | if (fNextButton->PushedLong())
72 | SetValue(fMaxValue);
73 | else
74 | SetValue(fPageNC->Value() + 1);
75 |
76 | Invoke();
77 | break;
78 |
79 | case M_GOTO_PREVIOUS_PAGE:
80 | if (fBackButton->PushedLong())
81 | SetValue(1);
82 | else
83 | SetValue(fPageNC->Value() - 1);
84 |
85 | Invoke();
86 | break;
87 |
88 | default:
89 | BGroupView::MessageReceived(message);
90 | break;
91 | }
92 | }
93 |
94 |
95 | void
96 | PageNavigationView::AttachedToWindow(void)
97 | {
98 | fNextButton->SetTarget(this);
99 | fBackButton->SetTarget(this);
100 | fPageNC->SetTarget(this);
101 | BGroupView::AttachedToWindow();
102 | }
103 |
104 |
105 | void
106 | PageNavigationView::FrameResized(float newWidth, float newHeight)
107 | {
108 | fBackButton->SetExplicitMinSize(BSize(newHeight, newHeight));
109 | fBackButton->SetExplicitMaxSize(BSize(newHeight, newHeight));
110 | fNextButton->SetExplicitMinSize(BSize(newHeight, newHeight));
111 | fNextButton->SetExplicitMaxSize(BSize(newHeight, newHeight));
112 |
113 | BGroupView::FrameResized(newWidth, newHeight);
114 | }
115 |
116 |
117 | void
118 | PageNavigationView::MakeFocus(bool focus)
119 | {
120 | BGroupView::MakeFocus(focus);
121 | }
122 |
123 |
124 | void
125 | PageNavigationView::SetValue(int value)
126 | {
127 | if (value < 1)
128 | value = 1;
129 | else if (value > fMaxValue)
130 | value = fMaxValue;
131 |
132 | fPageNC->SetValue(value);
133 | }
134 |
135 | void
136 | PageNavigationView::SetMaxValue(int const& value)
137 | {
138 | fMaxValue = value;
139 | BString str = " / ";
140 | str << fMaxValue;
141 | fTotalPagesSV->SetText(str);
142 | }
143 |
144 |
145 | int
146 | PageNavigationView::Value(void)
147 | {
148 | return fPageNC->Value();
149 | }
150 |
--------------------------------------------------------------------------------
/application/PageNavigationView.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2012-2012 Haiku Inc. All rights reserved.
3 | * Distributed under the terms of the MIT License.
4 | *
5 | * Authors:
6 | * Ciprian Nedisan (cipri)
7 | *
8 | */
9 | #ifndef PAGENAVIGATIONVIEW_H
10 | #define PAGENAVIGATIONVIEW_H
11 |
12 | #include