tesseract v5.3.3.20231005
scrollview.cpp
Go to the documentation of this file.
1
2// File: scrollview.cpp
3// Description: ScrollView
4// Author: Joern Wanke
5//
6// (C) Copyright 2007, Google Inc.
7// Licensed under the Apache License, Version 2.0 (the "License");
8// you may not use this file except in compliance with the License.
9// You may obtain a copy of the License at
10// http://www.apache.org/licenses/LICENSE-2.0
11// Unless required by applicable law or agreed to in writing, software
12// distributed under the License is distributed on an "AS IS" BASIS,
13// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14// See the License for the specific language governing permissions and
15// limitations under the License.
16//
18//
19
20// Include automatically generated configuration file if running autoconf.
21#ifdef HAVE_CONFIG_H
22# include "config_auto.h"
23#endif
24
25#include "scrollview.h"
26
27#include "svutil.h" // for SVNetwork
28
29#include <allheaders.h>
30
31#include <algorithm>
32#include <climits>
33#include <cstdarg>
34#include <cstring>
35#include <map>
36#include <memory> // for std::unique_ptr
37#include <mutex> // for std::mutex
38#include <string>
39#include <thread> // for std::thread
40#include <utility>
41#include <vector>
42
43namespace tesseract {
44
45const int kSvPort = 8461;
46const int kMaxMsgSize = 4096;
47const int kMaxIntPairSize = 45; // Holds %d,%d, for up to 64 bit.
48
50 bool empty; // Independent indicator to allow SendMsg to call SendPolygon.
51 std::vector<int> xcoords;
52 std::vector<int> ycoords;
53};
54
55// A map between the window IDs and their corresponding pointers.
56static std::map<int, ScrollView *> svmap;
57static std::mutex *svmap_mu;
58// A map of all semaphores waiting for a specific event on a specific window.
59static std::map<std::pair<ScrollView *, SVEventType>,
60 std::pair<SVSemaphore *, std::unique_ptr<SVEvent>>> waiting_for_events;
61static std::mutex *waiting_for_events_mu;
62
63std::unique_ptr<SVEvent> SVEvent::copy() const {
64 auto any = std::unique_ptr<SVEvent>(new SVEvent);
65 any->command_id = command_id;
66 any->counter = counter;
67 any->parameter = new char[strlen(parameter) + 1];
68 strcpy(any->parameter, parameter);
69 any->type = type;
70 any->x = x;
71 any->y = y;
72 any->x_size = x_size;
73 any->y_size = y_size;
74 any->window = window;
75 return any;
76}
77
78// Destructor.
79// It is defined here, so the compiler can create a single vtable
80// instead of weak vtables in every compilation unit.
82
83#ifndef GRAPHICS_DISABLED
88void ScrollView::MessageReceiver() {
89 int counter_event_id = 0; // ongoing counter
90 char *message = nullptr;
91 // Wait until a new message appears in the input stream_.
92 do {
93 message = ScrollView::GetStream()->Receive();
94 } while (message == nullptr);
95
96 // This is the main loop which iterates until the server is dead (strlen =
97 // -1). It basically parses for 3 different messagetypes and then distributes
98 // the events accordingly.
99 while (true) {
100 // The new event we create.
101 std::unique_ptr<SVEvent> cur(new SVEvent);
102 // The ID of the corresponding window.
103 int window_id;
104
105 int ev_type;
106
107 int n;
108 // Fill the new SVEvent properly.
109 sscanf(message, "%d,%d,%d,%d,%d,%d,%d,%n", &window_id, &ev_type, &cur->x, &cur->y, &cur->x_size,
110 &cur->y_size, &cur->command_id, &n);
111 char *p = (message + n);
112
113 svmap_mu->lock();
114 cur->window = svmap[window_id];
115
116 if (cur->window != nullptr) {
117 auto length = strlen(p);
118 cur->parameter = new char[length + 1];
119 strcpy(cur->parameter, p);
120 if (length > 0) { // remove the last \n
121 cur->parameter[length - 1] = '\0';
122 }
123 cur->type = static_cast<SVEventType>(ev_type);
124 // Correct selection coordinates so x,y is the min pt and size is +ve.
125 if (cur->x_size > 0) {
126 cur->x -= cur->x_size;
127 } else {
128 cur->x_size = -cur->x_size;
129 }
130 if (cur->y_size > 0) {
131 cur->y -= cur->y_size;
132 } else {
133 cur->y_size = -cur->y_size;
134 }
135 // Returned y will be the bottom-left if y is reversed.
136 if (cur->window->y_axis_is_reversed_) {
137 cur->y = cur->window->TranslateYCoordinate(cur->y + cur->y_size);
138 }
139 cur->counter = counter_event_id;
140 // Increase by 2 since we will also create an SVET_ANY event from cur,
141 // which will have a counter_id of cur + 1 (and thus gets processed
142 // after cur).
143 counter_event_id += 2;
144
145 // In case of an SVET_EXIT event, quit the whole application.
146 if (ev_type == SVET_EXIT) {
147 SendRawMessage("svmain:exit()");
148 break;
149 }
150
151 // Place two copies of it in the table for the window.
152 cur->window->SetEvent(cur.get());
153
154 // Check if any of the threads currently waiting want it.
155 std::pair<ScrollView *, SVEventType> awaiting_list(cur->window, cur->type);
156 std::pair<ScrollView *, SVEventType> awaiting_list_any(cur->window, SVET_ANY);
157 std::pair<ScrollView *, SVEventType> awaiting_list_any_window((ScrollView *)nullptr,
158 SVET_ANY);
159 waiting_for_events_mu->lock();
160 if (waiting_for_events.count(awaiting_list) > 0) {
161 waiting_for_events[awaiting_list].second = std::move(cur);
162 waiting_for_events[awaiting_list].first->Signal();
163 } else if (waiting_for_events.count(awaiting_list_any) > 0) {
164 waiting_for_events[awaiting_list_any].second = std::move(cur);
165 waiting_for_events[awaiting_list_any].first->Signal();
166 } else if (waiting_for_events.count(awaiting_list_any_window) > 0) {
167 waiting_for_events[awaiting_list_any_window].second = std::move(cur);
168 waiting_for_events[awaiting_list_any_window].first->Signal();
169 }
170 waiting_for_events_mu->unlock();
171 // Signal the corresponding semaphore twice (for both copies).
172 ScrollView *sv = svmap[window_id];
173 if (sv != nullptr) {
174 sv->Signal();
175 sv->Signal();
176 }
177 }
178 svmap_mu->unlock();
179
180 // Wait until a new message appears in the input stream_.
181 do {
182 message = ScrollView::GetStream()->Receive();
183 } while (message == nullptr);
184 }
185}
186
187// Table to implement the color index values in the old system.
188static const uint8_t table_colors[ScrollView::GREEN_YELLOW + 1][4] = {
189 {0, 0, 0, 0}, // NONE (transparent)
190 {0, 0, 0, 255}, // BLACK.
191 {255, 255, 255, 255}, // WHITE.
192 {255, 0, 0, 255}, // RED.
193 {255, 255, 0, 255}, // YELLOW.
194 {0, 255, 0, 255}, // GREEN.
195 {0, 255, 255, 255}, // CYAN.
196 {0, 0, 255, 255}, // BLUE.
197 {255, 0, 255, 255}, // MAGENTA.
198 {0, 128, 255, 255}, // AQUAMARINE.
199 {0, 0, 64, 255}, // DARK_SLATE_BLUE.
200 {128, 128, 255, 255}, // LIGHT_BLUE.
201 {64, 64, 255, 255}, // MEDIUM_BLUE.
202 {0, 0, 32, 255}, // MIDNIGHT_BLUE.
203 {0, 0, 128, 255}, // NAVY_BLUE.
204 {192, 192, 255, 255}, // SKY_BLUE.
205 {64, 64, 128, 255}, // SLATE_BLUE.
206 {32, 32, 64, 255}, // STEEL_BLUE.
207 {255, 128, 128, 255}, // CORAL.
208 {128, 64, 0, 255}, // BROWN.
209 {128, 128, 0, 255}, // SANDY_BROWN.
210 {192, 192, 0, 255}, // GOLD.
211 {192, 192, 128, 255}, // GOLDENROD.
212 {0, 64, 0, 255}, // DARK_GREEN.
213 {32, 64, 0, 255}, // DARK_OLIVE_GREEN.
214 {64, 128, 0, 255}, // FOREST_GREEN.
215 {128, 255, 0, 255}, // LIME_GREEN.
216 {192, 255, 192, 255}, // PALE_GREEN.
217 {192, 255, 0, 255}, // YELLOW_GREEN.
218 {192, 192, 192, 255}, // LIGHT_GREY.
219 {64, 64, 128, 255}, // DARK_SLATE_GREY.
220 {64, 64, 64, 255}, // DIM_GREY.
221 {128, 128, 128, 255}, // GREY.
222 {64, 192, 0, 255}, // KHAKI.
223 {255, 0, 192, 255}, // MAROON.
224 {255, 128, 0, 255}, // ORANGE.
225 {255, 128, 64, 255}, // ORCHID.
226 {255, 192, 192, 255}, // PINK.
227 {128, 0, 128, 255}, // PLUM.
228 {255, 0, 64, 255}, // INDIAN_RED.
229 {255, 64, 0, 255}, // ORANGE_RED.
230 {255, 0, 192, 255}, // VIOLET_RED.
231 {255, 192, 128, 255}, // SALMON.
232 {128, 128, 0, 255}, // TAN.
233 {0, 255, 255, 255}, // TURQUOISE.
234 {0, 128, 128, 255}, // DARK_TURQUOISE.
235 {192, 0, 255, 255}, // VIOLET.
236 {128, 128, 0, 255}, // WHEAT.
237 {128, 255, 0, 255} // GREEN_YELLOW
238};
239
240/*******************************************************************************
241 * Scrollview implementation.
242 *******************************************************************************/
243
244SVNetwork *ScrollView::stream_ = nullptr;
245int ScrollView::nr_created_windows_ = 0;
246int ScrollView::image_index_ = 0;
247
249ScrollView::ScrollView(const char *name, int x_pos, int y_pos, int x_size, int y_size,
250 int x_canvas_size, int y_canvas_size, bool y_axis_reversed,
251 const char *server_name) {
252 Initialize(name, x_pos, y_pos, x_size, y_size, x_canvas_size, y_canvas_size, y_axis_reversed,
253 server_name);
254}
255
257ScrollView::ScrollView(const char *name, int x_pos, int y_pos, int x_size, int y_size,
258 int x_canvas_size, int y_canvas_size, bool y_axis_reversed) {
259 Initialize(name, x_pos, y_pos, x_size, y_size, x_canvas_size, y_canvas_size, y_axis_reversed,
260 "localhost");
261}
262
264ScrollView::ScrollView(const char *name, int x_pos, int y_pos, int x_size, int y_size,
265 int x_canvas_size, int y_canvas_size) {
266 Initialize(name, x_pos, y_pos, x_size, y_size, x_canvas_size, y_canvas_size, false, "localhost");
267}
268
270void ScrollView::Initialize(const char *name, int x_pos, int y_pos, int x_size, int y_size,
271 int x_canvas_size, int y_canvas_size, bool y_axis_reversed,
272 const char *server_name) {
273 // If this is the first ScrollView Window which gets created, there is no
274 // network connection yet and we have to set it up in a different thread.
275 if (stream_ == nullptr) {
276 nr_created_windows_ = 0;
277 stream_ = new SVNetwork(server_name, kSvPort);
278 waiting_for_events_mu = new std::mutex();
279 svmap_mu = new std::mutex();
280 SendRawMessage("svmain = luajava.bindClass('com.google.scrollview.ScrollView')\n");
281 std::thread t(&ScrollView::MessageReceiver);
282 t.detach();
283 }
284
285 // Set up the variables on the clientside.
286 nr_created_windows_++;
287 event_handler_ = nullptr;
288 event_handler_ended_ = false;
289 y_axis_is_reversed_ = y_axis_reversed;
290 y_size_ = y_canvas_size;
291 window_name_ = name;
292 window_id_ = nr_created_windows_;
293 // Set up polygon buffering.
294 points_ = new SVPolyLineBuffer;
295 points_->empty = true;
296
297 svmap_mu->lock();
298 svmap[window_id_] = this;
299 svmap_mu->unlock();
300
301 for (auto &i : event_table_) {
302 i = nullptr;
303 }
304
305 semaphore_ = new SVSemaphore();
306
307 // Set up an actual Window on the client side.
308 char message[kMaxMsgSize];
309 snprintf(message, sizeof(message),
310 "w%u = luajava.newInstance('com.google.scrollview.ui"
311 ".SVWindow','%s',%u,%u,%u,%u,%u,%u,%u)\n",
312 window_id_, window_name_, window_id_, x_pos, y_pos, x_size, y_size, x_canvas_size,
313 y_canvas_size);
315
316 std::thread t(&ScrollView::StartEventHandler, this);
317 t.detach();
318}
319
321void ScrollView::StartEventHandler() {
322 for (;;) {
323 stream_->Flush();
324 semaphore_->Wait();
325 int serial = -1;
326 int k = -1;
327 mutex_.lock();
328 // Check every table entry if it is valid and not already processed.
329
330 for (int i = 0; i < SVET_COUNT; i++) {
331 if (event_table_[i] != nullptr && (serial < 0 || event_table_[i]->counter < serial)) {
332 serial = event_table_[i]->counter;
333 k = i;
334 }
335 }
336 // If we didn't find anything we had an old alarm and just sleep again.
337 if (k != -1) {
338 auto new_event = std::move(event_table_[k]);
339 mutex_.unlock();
340 if (event_handler_ != nullptr) {
341 event_handler_->Notify(new_event.get());
342 }
343 if (new_event->type == SVET_DESTROY) {
344 // Signal the destructor that it is safe to terminate.
345 event_handler_ended_ = true;
346 return;
347 }
348 } else {
349 mutex_.unlock();
350 }
351 // The thread should run as long as its associated window is alive.
352 }
353}
354#endif // !GRAPHICS_DISABLED
355
357#ifndef GRAPHICS_DISABLED
358 svmap_mu->lock();
359 if (svmap[window_id_] != nullptr) {
360 svmap_mu->unlock();
361 // So the event handling thread can quit.
362 SendMsg("destroy()");
363
365 svmap_mu->lock();
366 svmap[window_id_] = nullptr;
367 svmap_mu->unlock();
368 // The event handler thread for this window *must* receive the
369 // destroy event and set its pointer to this to nullptr before we allow
370 // the destructor to exit.
371 while (!event_handler_ended_) {
372 Update();
373 }
374 } else {
375 svmap_mu->unlock();
376 }
377 delete semaphore_;
378 delete points_;
379#endif // !GRAPHICS_DISABLED
380}
381
382#ifndef GRAPHICS_DISABLED
384void ScrollView::SendMsg(const char *format, ...) {
385 if (!points_->empty) {
386 SendPolygon();
387 }
388 va_list args;
389 char message[kMaxMsgSize - 4];
390
391 va_start(args, format); // variable list
392 vsnprintf(message, sizeof(message), format, args);
393 va_end(args);
394
395 char form[kMaxMsgSize];
396 snprintf(form, sizeof(form), "w%u:%s\n", window_id_, message);
397
398 stream_->Send(form);
399}
400
403void ScrollView::SendRawMessage(const char *msg) {
404 stream_->Send(msg);
405}
406
409 event_handler_ = listener;
410}
411
412void ScrollView::Signal() {
413 semaphore_->Signal();
414}
415
416void ScrollView::SetEvent(const SVEvent *svevent) {
417 // Copy event
418 auto any = svevent->copy();
419 auto specific = svevent->copy();
420 any->counter = specific->counter + 1;
421
422 // Place both events into the queue.
423 std::lock_guard<std::mutex> guard(mutex_);
424
425 event_table_[specific->type] = std::move(specific);
426 event_table_[SVET_ANY] = std::move(any);
427}
428
432std::unique_ptr<SVEvent> ScrollView::AwaitEvent(SVEventType type) {
433 // Initialize the waiting semaphore.
434 auto *sem = new SVSemaphore();
435 std::pair<ScrollView *, SVEventType> ea(this, type);
436 waiting_for_events_mu->lock();
437 waiting_for_events[ea] = {sem, nullptr};
438 waiting_for_events_mu->unlock();
439 // Wait on it, but first flush.
440 stream_->Flush();
441 sem->Wait();
442 // Process the event we got woken up for (its in waiting_for_events pair).
443 waiting_for_events_mu->lock();
444 auto ret = std::move(waiting_for_events[ea].second);
445 waiting_for_events.erase(ea);
446 delete sem;
447 waiting_for_events_mu->unlock();
448 return ret;
449}
450
451// Send the current buffered polygon (if any) and clear it.
452void ScrollView::SendPolygon() {
453 if (!points_->empty) {
454 points_->empty = true; // Allows us to use SendMsg.
455 int length = points_->xcoords.size();
456 // length == 1 corresponds to 2 SetCursors in a row and only the
457 // last setCursor has any effect.
458 if (length == 2) {
459 // An isolated line!
460 SendMsg("drawLine(%d,%d,%d,%d)", points_->xcoords[0], points_->ycoords[0],
461 points_->xcoords[1], points_->ycoords[1]);
462 } else if (length > 2) {
463 // A polyline.
464 SendMsg("createPolyline(%d)", length);
465 char coordpair[kMaxIntPairSize];
466 std::string decimal_coords;
467 for (int i = 0; i < length; ++i) {
468 snprintf(coordpair, kMaxIntPairSize, "%d,%d,", points_->xcoords[i], points_->ycoords[i]);
469 decimal_coords += coordpair;
470 }
471 decimal_coords += '\n';
472 SendRawMessage(decimal_coords.c_str());
473 SendMsg("drawPolyline()");
474 }
475 points_->xcoords.clear();
476 points_->ycoords.clear();
477 }
478}
479
480/*******************************************************************************
481 * LUA "API" functions.
482 *******************************************************************************/
483
484// Sets the position from which to draw to (x,y).
485void ScrollView::SetCursor(int x, int y) {
486 SendPolygon();
487 DrawTo(x, y);
488}
489
490// Draws from the current position to (x,y) and sets the new position to it.
491void ScrollView::DrawTo(int x, int y) {
492 points_->xcoords.push_back(x);
493 points_->ycoords.push_back(TranslateYCoordinate(y));
494 points_->empty = false;
495}
496
497// Draw a line using the current pen color.
498void ScrollView::Line(int x1, int y1, int x2, int y2) {
499 if (!points_->xcoords.empty() && x1 == points_->xcoords.back() &&
500 TranslateYCoordinate(y1) == points_->ycoords.back()) {
501 // We are already at x1, y1, so just draw to x2, y2.
502 DrawTo(x2, y2);
503 } else if (!points_->xcoords.empty() && x2 == points_->xcoords.back() &&
504 TranslateYCoordinate(y2) == points_->ycoords.back()) {
505 // We are already at x2, y2, so just draw to x1, y1.
506 DrawTo(x1, y1);
507 } else {
508 // This is a new line.
509 SetCursor(x1, y1);
510 DrawTo(x2, y2);
511 }
512}
513
514// Set the visibility of the window.
515void ScrollView::SetVisible(bool visible) {
516 if (visible) {
517 SendMsg("setVisible(true)");
518 } else {
519 SendMsg("setVisible(false)");
520 }
521}
522
523// Set the alwaysOnTop flag.
525 if (b) {
526 SendMsg("setAlwaysOnTop(true)");
527 } else {
528 SendMsg("setAlwaysOnTop(false)");
529 }
530}
531
532// Adds a message entry to the message box.
534 char form[kMaxMsgSize];
535 snprintf(form, sizeof(form), "w%u:%s", window_id_, message);
536
537 char *esc = AddEscapeChars(form);
538 SendMsg("addMessage(\"%s\")", esc);
539 delete[] esc;
540}
541
542void ScrollView::AddMessageF(const char *format, ...) {
543 va_list args;
544 char message[kMaxMsgSize - 4];
545
546 va_start(args, format); // variable list
547 vsnprintf(message, sizeof(message), format, args);
548 va_end(args);
549
551}
552
553// Set a messagebox.
555 SendMsg("addMessageBox()");
556}
557
558// Exit the client completely (and notify the server of it).
560 SendRawMessage("svmain:exit()");
561 exit(0);
562}
563
564// Clear the canvas.
566 SendMsg("clear()");
567}
568
569// Set the stroke width.
570void ScrollView::Stroke(float width) {
571 SendMsg("setStrokeWidth(%f)", width);
572}
573
574// Draw a rectangle using the current pen color.
575// The rectangle is filled with the current brush color.
576void ScrollView::Rectangle(int x1, int y1, int x2, int y2) {
577 if (x1 == x2 && y1 == y2) {
578 return; // Scrollviewer locks up.
579 }
580 SendMsg("drawRectangle(%d,%d,%d,%d)", x1, TranslateYCoordinate(y1), x2, TranslateYCoordinate(y2));
581}
582
583// Draw an ellipse using the current pen color.
584// The ellipse is filled with the current brush color.
585void ScrollView::Ellipse(int x1, int y1, int width, int height) {
586 SendMsg("drawEllipse(%d,%d,%u,%u)", x1, TranslateYCoordinate(y1), width, height);
587}
588
589// Set the pen color to the given RGB values.
590void ScrollView::Pen(int red, int green, int blue) {
591 SendMsg("pen(%d,%d,%d)", red, green, blue);
592}
593
594// Set the pen color to the given RGB values.
595void ScrollView::Pen(int red, int green, int blue, int alpha) {
596 SendMsg("pen(%d,%d,%d,%d)", red, green, blue, alpha);
597}
598
599// Set the brush color to the given RGB values.
600void ScrollView::Brush(int red, int green, int blue) {
601 SendMsg("brush(%d,%d,%d)", red, green, blue);
602}
603
604// Set the brush color to the given RGB values.
605void ScrollView::Brush(int red, int green, int blue, int alpha) {
606 SendMsg("brush(%d,%d,%d,%d)", red, green, blue, alpha);
607}
608
609// Set the attributes for future Text(..) calls.
610void ScrollView::TextAttributes(const char *font, int pixel_size, bool bold, bool italic,
611 bool underlined) {
612 const char *b;
613 const char *i;
614 const char *u;
615
616 if (bold) {
617 b = "true";
618 } else {
619 b = "false";
620 }
621 if (italic) {
622 i = "true";
623 } else {
624 i = "false";
625 }
626 if (underlined) {
627 u = "true";
628 } else {
629 u = "false";
630 }
631 SendMsg("textAttributes('%s',%u,%s,%s,%s)", font, pixel_size, b, i, u);
632}
633
634// Draw text at the given coordinates.
635void ScrollView::Text(int x, int y, const char *mystring) {
636 SendMsg("drawText(%d,%d,'%s')", x, TranslateYCoordinate(y), mystring);
637}
638
639// Open and draw an image given a name at (x,y).
640void ScrollView::Draw(const char *image, int x_pos, int y_pos) {
641 SendMsg("openImage('%s')", image);
642 SendMsg("drawImage('%s',%d,%d)", image, x_pos, TranslateYCoordinate(y_pos));
643}
644
645// Add new checkboxmenuentry to menubar.
646void ScrollView::MenuItem(const char *parent, const char *name, int cmdEvent, bool flag) {
647 if (parent == nullptr) {
648 parent = "";
649 }
650 if (flag) {
651 SendMsg("addMenuBarItem('%s','%s',%d,true)", parent, name, cmdEvent);
652 } else {
653 SendMsg("addMenuBarItem('%s','%s',%d,false)", parent, name, cmdEvent);
654 }
655}
656
657// Add new menuentry to menubar.
658void ScrollView::MenuItem(const char *parent, const char *name, int cmdEvent) {
659 if (parent == nullptr) {
660 parent = "";
661 }
662 SendMsg("addMenuBarItem('%s','%s',%d)", parent, name, cmdEvent);
663}
664
665// Add new submenu to menubar.
666void ScrollView::MenuItem(const char *parent, const char *name) {
667 if (parent == nullptr) {
668 parent = "";
669 }
670 SendMsg("addMenuBarItem('%s','%s')", parent, name);
671}
672
673// Add new submenu to popupmenu.
674void ScrollView::PopupItem(const char *parent, const char *name) {
675 if (parent == nullptr) {
676 parent = "";
677 }
678 SendMsg("addPopupMenuItem('%s','%s')", parent, name);
679}
680
681// Add new submenuentry to popupmenu.
682void ScrollView::PopupItem(const char *parent, const char *name, int cmdEvent, const char *value,
683 const char *desc) {
684 if (parent == nullptr) {
685 parent = "";
686 }
687 char *esc = AddEscapeChars(value);
688 char *esc2 = AddEscapeChars(desc);
689 SendMsg("addPopupMenuItem('%s','%s',%d,'%s','%s')", parent, name, cmdEvent, esc, esc2);
690 delete[] esc;
691 delete[] esc2;
692}
693
694// Send an update message for a single window.
696 SendMsg("update()");
697}
698
699// Note: this is an update to all windows
701 std::lock_guard<std::mutex> guard(*svmap_mu);
702 for (auto &iter : svmap) {
703 if (iter.second != nullptr) {
704 iter.second->UpdateWindow();
705 }
706 }
707}
708
709// Set the pen color, using an enum value (e.g. ScrollView::ORANGE)
711 Pen(table_colors[color][0], table_colors[color][1], table_colors[color][2],
712 table_colors[color][3]);
713}
714
715// Set the brush color, using an enum value (e.g. ScrollView::ORANGE)
717 Brush(table_colors[color][0], table_colors[color][1], table_colors[color][2],
718 table_colors[color][3]);
719}
720
721// Shows a modal Input Dialog which can return any kind of String
722char *ScrollView::ShowInputDialog(const char *msg) {
723 SendMsg("showInputDialog(\"%s\")", msg);
724 // wait till an input event (all others are thrown away)
725 auto ev = AwaitEvent(SVET_INPUT);
726 char *p = new char[strlen(ev->parameter) + 1];
727 strcpy(p, ev->parameter);
728 return p;
729}
730
731// Shows a modal Yes/No Dialog which will return 'y' or 'n'
732int ScrollView::ShowYesNoDialog(const char *msg) {
733 SendMsg("showYesNoDialog(\"%s\")", msg);
734 // Wait till an input event (all others are thrown away)
735 auto ev = AwaitEvent(SVET_INPUT);
736 int a = ev->parameter[0];
737 return a;
738}
739
740// Zoom the window to the rectangle given upper left corner and
741// lower right corner.
742void ScrollView::ZoomToRectangle(int x1, int y1, int x2, int y2) {
743 y1 = TranslateYCoordinate(y1);
744 y2 = TranslateYCoordinate(y2);
745 SendMsg("zoomRectangle(%d,%d,%d,%d)", std::min(x1, x2), std::min(y1, y2), std::max(x1, x2),
746 std::max(y1, y2));
747}
748
749// Send an image of type Pix.
750void ScrollView::Draw(Image image, int x_pos, int y_pos) {
751 l_uint8 *data;
752 size_t size;
753 pixWriteMem(&data, &size, image, IFF_PNG);
754 int base64_len = (size + 2) / 3 * 4;
755 y_pos = TranslateYCoordinate(y_pos);
756 SendMsg("readImage(%d,%d,%d)", x_pos, y_pos, base64_len);
757 // Base64 encode the data.
758 const char kBase64Table[64] = {
759 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
760 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
761 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
762 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/',
763 };
764 char *base64 = new char[base64_len + 1];
765 memset(base64, '=', base64_len);
766 base64[base64_len] = '\0';
767 int remainder = 0;
768 int bits_left = 0;
769 int code_len = 0;
770 for (size_t i = 0; i < size; ++i) {
771 int code = (data[i] >> (bits_left + 2)) | remainder;
772 base64[code_len++] = kBase64Table[code & 63];
773 bits_left += 2;
774 remainder = data[i] << (6 - bits_left);
775 if (bits_left == 6) {
776 base64[code_len++] = kBase64Table[remainder & 63];
777 bits_left = 0;
778 remainder = 0;
779 }
780 }
781 if (bits_left > 0) {
782 base64[code_len++] = kBase64Table[remainder & 63];
783 }
784 SendRawMessage(base64);
785 delete[] base64;
786 lept_free(data);
787}
788
789// Escapes the ' character with a \, so it can be processed by LUA.
790// Note: The caller will have to make sure it deletes the newly allocated item.
791char *ScrollView::AddEscapeChars(const char *input) {
792 const char *nextptr = strchr(input, '\'');
793 const char *lastptr = input;
794 char *message = new char[kMaxMsgSize];
795 int pos = 0;
796 while (nextptr != nullptr) {
797 strncpy(message + pos, lastptr, nextptr - lastptr);
798 pos += nextptr - lastptr;
799 message[pos] = '\\';
800 pos += 1;
801 lastptr = nextptr;
802 nextptr = strchr(nextptr + 1, '\'');
803 }
804 strcpy(message + pos, lastptr);
805 return message;
806}
807
808// Inverse the Y axis if the coordinates are actually inversed.
810 if (!y_axis_is_reversed_) {
811 return y;
812 } else {
813 return y_size_ - y;
814 }
815}
816
818 // Wait till an input or click event (all others are thrown away)
819 char ret = '\0';
820 SVEventType ev_type = SVET_ANY;
821 do {
822 std::unique_ptr<SVEvent> ev(AwaitEvent(SVET_ANY));
823 ev_type = ev->type;
824 if (ev_type == SVET_INPUT) {
825 ret = ev->parameter[0];
826 }
827 } while (ev_type != SVET_INPUT && ev_type != SVET_CLICK);
828 return ret;
829}
830
831#endif // !GRAPHICS_DISABLED
832
833} // namespace tesseract
int value
const double y
const char * p
const int kMaxMsgSize
Definition: scrollview.cpp:46
const int kMaxIntPairSize
Definition: scrollview.cpp:47
@ SVET_COUNT
Definition: scrollview.h:66
@ SVET_DESTROY
Definition: scrollview.h:54
@ SVET_CLICK
Definition: scrollview.h:56
@ SVET_INPUT
Definition: scrollview.h:58
const int kSvPort
Definition: scrollview.cpp:45
type
Definition: upload.py:458
std::vector< int > xcoords
Definition: scrollview.cpp:51
std::vector< int > ycoords
Definition: scrollview.cpp:52
std::unique_ptr< SVEvent > copy() const
Definition: scrollview.cpp:63
SVEventType type
Definition: scrollview.h:74
ScrollView * window
Definition: scrollview.h:75
virtual void Notify(const SVEvent *sve)
Definition: scrollview.h:98
void Line(int x1, int y1, int x2, int y2)
Definition: scrollview.cpp:498
char * ShowInputDialog(const char *msg)
Definition: scrollview.cpp:722
void PopupItem(const char *parent, const char *name)
Definition: scrollview.cpp:674
void AddMessage(const char *message)
Definition: scrollview.cpp:533
std::unique_ptr< SVEvent > AwaitEvent(SVEventType type)
Definition: scrollview.cpp:432
void TextAttributes(const char *font, int pixel_size, bool bold, bool italic, bool underlined)
Definition: scrollview.cpp:610
void AlwaysOnTop(bool b)
Definition: scrollview.cpp:524
void static void SendRawMessage(const char *msg)
Definition: scrollview.cpp:403
ScrollView(const char *name, int x_pos, int y_pos, int x_size, int y_size, int x_canvas_size, int y_canvas_size)
Calls Initialize with default argument for server_name_ & y_axis_reversed.
Definition: scrollview.cpp:264
void Text(int x, int y, const char *mystring)
Definition: scrollview.cpp:635
void Draw(Image image, int x_pos, int y_pos)
Definition: scrollview.cpp:750
void Stroke(float width)
Definition: scrollview.cpp:570
void SetVisible(bool visible)
Definition: scrollview.cpp:515
void void ZoomToRectangle(int x1, int y1, int x2, int y2)
Definition: scrollview.cpp:742
void Pen(Color color)
Definition: scrollview.cpp:710
static void Update()
Definition: scrollview.cpp:700
void AddEventHandler(SVEventHandler *listener)
Add an Event Listener to this ScrollView Window.
Definition: scrollview.cpp:408
void Brush(Color color)
Definition: scrollview.cpp:716
static void Exit()
Definition: scrollview.cpp:559
void Rectangle(int x1, int y1, int x2, int y2)
Definition: scrollview.cpp:576
void SetCursor(int x, int y)
Definition: scrollview.cpp:485
void Ellipse(int x, int y, int width, int height)
Definition: scrollview.cpp:585
int TranslateYCoordinate(int y)
Definition: scrollview.cpp:809
void MenuItem(const char *parent, const char *name)
Definition: scrollview.cpp:666
void DrawTo(int x, int y)
Definition: scrollview.cpp:491
int ShowYesNoDialog(const char *msg)
Definition: scrollview.cpp:732
void AddMessageF(const char *format,...) __attribute__((format(gnu_printf
Definition: scrollview.cpp:542
void SendMsg(const char *msg,...) __attribute__((format(gnu_printf
Send a message to the server, attaching the window id.
Definition: scrollview.cpp:384
void Signal()
Signal a semaphore.
Definition: svutil.cpp:143
void Wait()
Wait on a semaphore.
Definition: svutil.cpp:153
void Flush()
Flush the buffer.
Definition: svutil.cpp:170
void Send(const char *msg)
Put a message in the messagebuffer to the server and try to send it.
Definition: svutil.cpp:164