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