tesseract  4.1.1
scrollview.cpp
Go to the documentation of this file.
1 // File: scrollview.cpp
3 // Description: ScrollView
4 // Author: Joern Wanke
5 // Created: Thu Nov 29 2007
6 //
7 // (C) Copyright 2007, Google Inc.
8 // Licensed under the Apache License, Version 2.0 (the "License");
9 // you may not use this file except in compliance with the License.
10 // You may obtain a copy of the License at
11 // http://www.apache.org/licenses/LICENSE-2.0
12 // Unless required by applicable law or agreed to in writing, software
13 // distributed under the License is distributed on an "AS IS" BASIS,
14 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 // See the License for the specific language governing permissions and
16 // limitations under the License.
17 //
19 //
20 
21 #include <algorithm>
22 #include <climits>
23 #include <cstdarg>
24 #include <cstring>
25 #include <map>
26 #include <string>
27 #include <utility>
28 #include <vector>
29 
30 // Include automatically generated configuration file if running autoconf.
31 #ifdef HAVE_CONFIG_H
32 #include "config_auto.h"
33 #endif
34 
35 #include "scrollview.h"
36 
37 const int kSvPort = 8461;
38 const int kMaxMsgSize = 4096;
39 const int kMaxIntPairSize = 45; // Holds %d,%d, for up to 64 bit.
40 
41 #include "svutil.h"
42 
43 #include "allheaders.h"
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 SVMutex* 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 SVMutex* 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(void* a) {
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  return nullptr;
182 }
183 
184 // Table to implement the color index values in the old system.
185 static const uint8_t table_colors[ScrollView::GREEN_YELLOW+1][4]= {
186  {0, 0, 0, 0}, // NONE (transparent)
187  {0, 0, 0, 255}, // BLACK.
188  {255, 255, 255, 255}, // WHITE.
189  {255, 0, 0, 255}, // RED.
190  {255, 255, 0, 255}, // YELLOW.
191  {0, 255, 0, 255}, // GREEN.
192  {0, 255, 255, 255}, // CYAN.
193  {0, 0, 255, 255}, // BLUE.
194  {255, 0, 255, 255}, // MAGENTA.
195  {0, 128, 255, 255}, // AQUAMARINE.
196  {0, 0, 64, 255}, // DARK_SLATE_BLUE.
197  {128, 128, 255, 255}, // LIGHT_BLUE.
198  {64, 64, 255, 255}, // MEDIUM_BLUE.
199  {0, 0, 32, 255}, // MIDNIGHT_BLUE.
200  {0, 0, 128, 255}, // NAVY_BLUE.
201  {192, 192, 255, 255}, // SKY_BLUE.
202  {64, 64, 128, 255}, // SLATE_BLUE.
203  {32, 32, 64, 255}, // STEEL_BLUE.
204  {255, 128, 128, 255}, // CORAL.
205  {128, 64, 0, 255}, // BROWN.
206  {128, 128, 0, 255}, // SANDY_BROWN.
207  {192, 192, 0, 255}, // GOLD.
208  {192, 192, 128, 255}, // GOLDENROD.
209  {0, 64, 0, 255}, // DARK_GREEN.
210  {32, 64, 0, 255}, // DARK_OLIVE_GREEN.
211  {64, 128, 0, 255}, // FOREST_GREEN.
212  {128, 255, 0, 255}, // LIME_GREEN.
213  {192, 255, 192, 255}, // PALE_GREEN.
214  {192, 255, 0, 255}, // YELLOW_GREEN.
215  {192, 192, 192, 255}, // LIGHT_GREY.
216  {64, 64, 128, 255}, // DARK_SLATE_GREY.
217  {64, 64, 64, 255}, // DIM_GREY.
218  {128, 128, 128, 255}, // GREY.
219  {64, 192, 0, 255}, // KHAKI.
220  {255, 0, 192, 255}, // MAROON.
221  {255, 128, 0, 255}, // ORANGE.
222  {255, 128, 64, 255}, // ORCHID.
223  {255, 192, 192, 255}, // PINK.
224  {128, 0, 128, 255}, // PLUM.
225  {255, 0, 64, 255}, // INDIAN_RED.
226  {255, 64, 0, 255}, // ORANGE_RED.
227  {255, 0, 192, 255}, // VIOLET_RED.
228  {255, 192, 128, 255}, // SALMON.
229  {128, 128, 0, 255}, // TAN.
230  {0, 255, 255, 255}, // TURQUOISE.
231  {0, 128, 128, 255}, // DARK_TURQUOISE.
232  {192, 0, 255, 255}, // VIOLET.
233  {128, 128, 0, 255}, // WHEAT.
234  {128, 255, 0, 255} // GREEN_YELLOW
235 };
236 
237 
238 /*******************************************************************************
239 * Scrollview implementation.
240 *******************************************************************************/
241 
242 SVNetwork* ScrollView::stream_ = nullptr;
243 int ScrollView::nr_created_windows_ = 0;
244 int ScrollView::image_index_ = 0;
245 
247 ScrollView::ScrollView(const char* name, int x_pos, int y_pos, int x_size,
248  int y_size, int x_canvas_size, int y_canvas_size,
249  bool y_axis_reversed, const char* server_name) {
250  Initialize(name, x_pos, y_pos, x_size, y_size, x_canvas_size, y_canvas_size,
251  y_axis_reversed, server_name);}
252 
254 ScrollView::ScrollView(const char* name, int x_pos, int y_pos, int x_size,
255  int y_size, int x_canvas_size, int y_canvas_size,
256  bool y_axis_reversed) {
257  Initialize(name, x_pos, y_pos, x_size, y_size, x_canvas_size, y_canvas_size,
258  y_axis_reversed, "localhost");
259 }
260 
262 ScrollView::ScrollView(const char* name, int x_pos, int y_pos, int x_size,
263  int y_size, int x_canvas_size, int y_canvas_size) {
264  Initialize(name, x_pos, y_pos, x_size, y_size, x_canvas_size, y_canvas_size,
265  false, "localhost");
266 }
267 
269 void ScrollView::Initialize(const char* name, int x_pos, int y_pos, int x_size,
270  int y_size, int x_canvas_size, int y_canvas_size,
271  bool y_axis_reversed, const char* server_name) {
272  // If this is the first ScrollView Window which gets created, there is no
273  // network connection yet and we have to set it up in a different thread.
274  if (stream_ == nullptr) {
275  nr_created_windows_ = 0;
276  stream_ = new SVNetwork(server_name, kSvPort);
277  waiting_for_events_mu = new SVMutex();
278  svmap_mu = new SVMutex();
280  "svmain = luajava.bindClass('com.google.scrollview.ScrollView')\n");
281  SVSync::StartThread(MessageReceiver, nullptr);
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 SVMutex();
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  SVSync::StartThread(StartEventHandler, this);
317 }
318 
320 void* ScrollView::StartEventHandler(void* a) {
321  auto* sv = static_cast<ScrollView*>(a);
322  SVEvent* new_event;
323 
324  do {
325  stream_->Flush();
326  sv->semaphore_->Wait();
327  new_event = nullptr;
328  int serial = -1;
329  int k = -1;
330  sv->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 (sv->event_table_[i] != nullptr &&
335  (serial < 0 || sv->event_table_[i]->counter < serial)) {
336  new_event = sv->event_table_[i];
337  serial = sv->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  sv->event_table_[k] = nullptr;
344  sv->mutex_->Unlock();
345  if (sv->event_handler_ != nullptr) { sv->event_handler_->Notify(new_event); }
346  if (new_event->type == SVET_DESTROY) {
347  // Signal the destructor that it is safe to terminate.
348  sv->event_handler_ended_ = true;
349  sv = nullptr;
350  }
351  delete new_event; // Delete the pointer after it has been processed.
352  } else { sv->mutex_->Unlock(); }
353  // The thread should run as long as its associated window is alive.
354  } while (sv != nullptr);
355  return nullptr;
356 }
357 #endif // GRAPHICS_DISABLED
358 
360  #ifndef GRAPHICS_DISABLED
361  svmap_mu->Lock();
362  if (svmap[window_id_] != nullptr) {
363  svmap_mu->Unlock();
364  // So the event handling thread can quit.
365  SendMsg("destroy()");
366 
368  delete sve;
369  svmap_mu->Lock();
370  svmap[window_id_] = nullptr;
371  svmap_mu->Unlock();
372  // The event handler thread for this window *must* receive the
373  // destroy event and set its pointer to this to nullptr before we allow
374  // the destructor to exit.
375  while (!event_handler_ended_)
376  Update();
377  } else {
378  svmap_mu->Unlock();
379  }
380  delete mutex_;
381  delete semaphore_;
382  delete points_;
383  for (auto & i : event_table_) {
384  delete i;
385  }
386  #endif // GRAPHICS_DISABLED
387 }
388 
389 #ifndef GRAPHICS_DISABLED
390 void ScrollView::SendMsg(const char* format, ...) {
392  if (!points_->empty)
393  SendPolygon();
394  va_list args;
395  char message[kMaxMsgSize - 4];
396 
397  va_start(args, format); // variable list
398  vsnprintf(message, sizeof(message), format, args);
399  va_end(args);
400 
401  char form[kMaxMsgSize];
402  snprintf(form, sizeof(form), "w%u:%s\n", window_id_, message);
403 
404  stream_->Send(form);
405 }
406 
409 void ScrollView::SendRawMessage(const char* msg) {
410  stream_->Send(msg);
411 }
412 
415  event_handler_ = listener;
416 }
417 
418 void ScrollView::Signal() {
419  semaphore_->Signal();
420 }
421 
422 void ScrollView::SetEvent(SVEvent* svevent) {
423 // Copy event
424  SVEvent* any = svevent->copy();
425  SVEvent* specific = svevent->copy();
426  any->counter = specific->counter + 1;
427 
428 // Place both events into the queue.
429  mutex_->Lock();
430  // Delete the old objects..
431  delete event_table_[specific->type];
432  delete event_table_[SVET_ANY];
433  // ...and put the new ones in the table.
434  event_table_[specific->type] = specific;
435  event_table_[SVET_ANY] = any;
436  mutex_->Unlock();
437 }
438 
439 
444  // Initialize the waiting semaphore.
445  auto* sem = new SVSemaphore();
446  std::pair<ScrollView*, SVEventType> ea(this, type);
447  waiting_for_events_mu->Lock();
448  waiting_for_events[ea] = std::pair<SVSemaphore*, SVEvent*> (sem, (SVEvent*)nullptr);
449  waiting_for_events_mu->Unlock();
450  // Wait on it, but first flush.
451  stream_->Flush();
452  sem->Wait();
453  // Process the event we got woken up for (its in waiting_for_events pair).
454  waiting_for_events_mu->Lock();
455  SVEvent* ret = waiting_for_events[ea].second;
456  waiting_for_events.erase(ea);
457  delete sem;
458  waiting_for_events_mu->Unlock();
459  return ret;
460 }
461 
462 // Block until any event on any window is received.
463 // No event is returned here!
465  // Initialize the waiting semaphore.
466  auto* sem = new SVSemaphore();
467  std::pair<ScrollView*, SVEventType> ea((ScrollView*)nullptr, SVET_ANY);
468  waiting_for_events_mu->Lock();
469  waiting_for_events[ea] = std::pair<SVSemaphore*, SVEvent*> (sem, (SVEvent*)nullptr);
470  waiting_for_events_mu->Unlock();
471  // Wait on it.
472  stream_->Flush();
473  sem->Wait();
474  // Process the event we got woken up for (its in waiting_for_events pair).
475  waiting_for_events_mu->Lock();
476  SVEvent* ret = waiting_for_events[ea].second;
477  waiting_for_events.erase(ea);
478  waiting_for_events_mu->Unlock();
479  return ret;
480 }
481 
482 // Send the current buffered polygon (if any) and clear it.
483 void ScrollView::SendPolygon() {
484  if (!points_->empty) {
485  points_->empty = true; // Allows us to use SendMsg.
486  int length = points_->xcoords.size();
487  // length == 1 corresponds to 2 SetCursors in a row and only the
488  // last setCursor has any effect.
489  if (length == 2) {
490  // An isolated line!
491  SendMsg("drawLine(%d,%d,%d,%d)",
492  points_->xcoords[0], points_->ycoords[0],
493  points_->xcoords[1], points_->ycoords[1]);
494  } else if (length > 2) {
495  // A polyline.
496  SendMsg("createPolyline(%d)", length);
497  char coordpair[kMaxIntPairSize];
498  std::string decimal_coords;
499  for (int i = 0; i < length; ++i) {
500  snprintf(coordpair, kMaxIntPairSize, "%d,%d,",
501  points_->xcoords[i], points_->ycoords[i]);
502  decimal_coords += coordpair;
503  }
504  decimal_coords += '\n';
505  SendRawMessage(decimal_coords.c_str());
506  SendMsg("drawPolyline()");
507  }
508  points_->xcoords.clear();
509  points_->ycoords.clear();
510  }
511 }
512 
513 
514 /*******************************************************************************
515 * LUA "API" functions.
516 *******************************************************************************/
517 
518 // Sets the position from which to draw to (x,y).
519 void ScrollView::SetCursor(int x, int y) {
520  SendPolygon();
521  DrawTo(x, y);
522 }
523 
524 // Draws from the current position to (x,y) and sets the new position to it.
525 void ScrollView::DrawTo(int x, int y) {
526  points_->xcoords.push_back(x);
527  points_->ycoords.push_back(TranslateYCoordinate(y));
528  points_->empty = false;
529 }
530 
531 // Draw a line using the current pen color.
532 void ScrollView::Line(int x1, int y1, int x2, int y2) {
533  if (!points_->xcoords.empty() && x1 == points_->xcoords.back() &&
534  TranslateYCoordinate(y1) == points_->ycoords.back()) {
535  // We are already at x1, y1, so just draw to x2, y2.
536  DrawTo(x2, y2);
537  } else if (!points_->xcoords.empty() && x2 == points_->xcoords.back() &&
538  TranslateYCoordinate(y2) == points_->ycoords.back()) {
539  // We are already at x2, y2, so just draw to x1, y1.
540  DrawTo(x1, y1);
541  } else {
542  // This is a new line.
543  SetCursor(x1, y1);
544  DrawTo(x2, y2);
545  }
546 }
547 
548 // Set the visibility of the window.
549 void ScrollView::SetVisible(bool visible) {
550  if (visible) { SendMsg("setVisible(true)");
551  } else { SendMsg("setVisible(false)"); }
552 }
553 
554 // Set the alwaysOnTop flag.
556  if (b) { SendMsg("setAlwaysOnTop(true)");
557  } else { SendMsg("setAlwaysOnTop(false)"); }
558 }
559 
560 // Adds a message entry to the message box.
561 void ScrollView::AddMessage(const char* format, ...) {
562  va_list args;
563  char message[kMaxMsgSize - 4];
564 
565  va_start(args, format); // variable list
566  vsnprintf(message, sizeof(message), format, args);
567  va_end(args);
568 
569  char form[kMaxMsgSize];
570  snprintf(form, sizeof(form), "w%u:%s", window_id_, message);
571 
572  char* esc = AddEscapeChars(form);
573  SendMsg("addMessage(\"%s\")", esc);
574  delete[] esc;
575 }
576 
577 // Set a messagebox.
579  SendMsg("addMessageBox()");
580 }
581 
582 // Exit the client completely (and notify the server of it).
584  SendRawMessage("svmain:exit()");
585  exit(0);
586 }
587 
588 // Clear the canvas.
590  SendMsg("clear()");
591 }
592 
593 // Set the stroke width.
594 void ScrollView::Stroke(float width) {
595  SendMsg("setStrokeWidth(%f)", width);
596 }
597 
598 // Draw a rectangle using the current pen color.
599 // The rectangle is filled with the current brush color.
600 void ScrollView::Rectangle(int x1, int y1, int x2, int y2) {
601  if (x1 == x2 && y1 == y2)
602  return; // Scrollviewer locks up.
603  SendMsg("drawRectangle(%d,%d,%d,%d)",
604  x1, TranslateYCoordinate(y1), x2, TranslateYCoordinate(y2));
605 }
606 
607 // Draw an ellipse using the current pen color.
608 // The ellipse is filled with the current brush color.
609 void ScrollView::Ellipse(int x1, int y1, int width, int height) {
610  SendMsg("drawEllipse(%d,%d,%u,%u)",
611  x1, TranslateYCoordinate(y1), width, height);
612 }
613 
614 // Set the pen color to the given RGB values.
615 void ScrollView::Pen(int red, int green, int blue) {
616  SendMsg("pen(%d,%d,%d)", red, green, blue);
617 }
618 
619 // Set the pen color to the given RGB values.
620 void ScrollView::Pen(int red, int green, int blue, int alpha) {
621  SendMsg("pen(%d,%d,%d,%d)", red, green, blue, alpha);
622 }
623 
624 // Set the brush color to the given RGB values.
625 void ScrollView::Brush(int red, int green, int blue) {
626  SendMsg("brush(%d,%d,%d)", red, green, blue);
627 }
628 
629 // Set the brush color to the given RGB values.
630 void ScrollView::Brush(int red, int green, int blue, int alpha) {
631  SendMsg("brush(%d,%d,%d,%d)", red, green, blue, alpha);
632 }
633 
634 // Set the attributes for future Text(..) calls.
635 void ScrollView::TextAttributes(const char* font, int pixel_size,
636  bool bold, bool italic, bool underlined) {
637  const char* b;
638  const char* i;
639  const char* u;
640 
641  if (bold) { b = "true";
642  } else { b = "false"; }
643  if (italic) { i = "true";
644  } else { i = "false"; }
645  if (underlined) { u = "true";
646  } else { u = "false"; }
647  SendMsg("textAttributes('%s',%u,%s,%s,%s)", font, pixel_size,
648  b, i, u);
649 }
650 
651 // Draw text at the given coordinates.
652 void ScrollView::Text(int x, int y, const char* mystring) {
653  SendMsg("drawText(%d,%d,'%s')", x, TranslateYCoordinate(y), mystring);
654 }
655 
656 // Open and draw an image given a name at (x,y).
657 void ScrollView::Image(const char* image, int x_pos, int y_pos) {
658  SendMsg("openImage('%s')", image);
659  SendMsg("drawImage('%s',%d,%d)",
660  image, x_pos, TranslateYCoordinate(y_pos));
661 }
662 
663 // Add new checkboxmenuentry to menubar.
664 void ScrollView::MenuItem(const char* parent, const char* name,
665  int cmdEvent, bool flag) {
666  if (parent == nullptr) { parent = ""; }
667  if (flag) { SendMsg("addMenuBarItem('%s','%s',%d,true)",
668  parent, name, cmdEvent);
669  } else { SendMsg("addMenuBarItem('%s','%s',%d,false)",
670  parent, name, cmdEvent); }
671 }
672 
673 // Add new menuentry to menubar.
674 void ScrollView::MenuItem(const char* parent, const char* name, int cmdEvent) {
675  if (parent == nullptr) { parent = ""; }
676  SendMsg("addMenuBarItem('%s','%s',%d)", parent, name, cmdEvent);
677 }
678 
679 // Add new submenu to menubar.
680 void ScrollView::MenuItem(const char* parent, const char* name) {
681  if (parent == nullptr) { parent = ""; }
682  SendMsg("addMenuBarItem('%s','%s')", parent, name);
683 }
684 
685 // Add new submenu to popupmenu.
686 void ScrollView::PopupItem(const char* parent, const char* name) {
687  if (parent == nullptr) { parent = ""; }
688  SendMsg("addPopupMenuItem('%s','%s')", parent, name);
689 }
690 
691 // Add new submenuentry to popupmenu.
692 void ScrollView::PopupItem(const char* parent, const char* name,
693  int cmdEvent, const char* value, const char* desc) {
694  if (parent == nullptr) { parent = ""; }
695  char* esc = AddEscapeChars(value);
696  char* esc2 = AddEscapeChars(desc);
697  SendMsg("addPopupMenuItem('%s','%s',%d,'%s','%s')", parent, name,
698  cmdEvent, esc, esc2);
699  delete[] esc;
700  delete[] esc2;
701 }
702 
703 // Send an update message for a single window.
705  SendMsg("update()");
706 }
707 
708 // Note: this is an update to all windows
710  svmap_mu->Lock();
711  for (auto & iter : svmap) {
712  if (iter.second != nullptr)
713  iter.second->UpdateWindow();
714  }
715  svmap_mu->Unlock();
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)
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
void PopupItem(const char *parent, const char *name)
Definition: scrollview.cpp:686
void Rectangle(int x1, int y1, int x2, int y2)
Definition: scrollview.cpp:600
void AddMessageBox()
Definition: scrollview.cpp:578
Definition: svutil.h:68
void UpdateWindow()
Definition: scrollview.cpp:704
static void Update()
Definition: scrollview.cpp:709
void Lock()
Locks on a mutex.
Definition: svutil.cpp:64
SVEventType
Definition: scrollview.h:45
void Unlock()
Unlocks on a mutex.
Definition: svutil.cpp:72
void ZoomToRectangle(int x1, int y1, int x2, int y2)
Definition: scrollview.cpp:757
void Brush(Color color)
Definition: scrollview.cpp:725
int x_size
Definition: scrollview.h:69
SVEvent()=default
SVEvent * AwaitEvent(SVEventType type)
Definition: scrollview.cpp:443
char * ShowInputDialog(const char *msg)
Definition: scrollview.cpp:733
SVEvent * AwaitEventAnyWindow()
Definition: scrollview.cpp:464
SVEvent * copy()
Definition: scrollview.cpp:59
int y_size
Definition: scrollview.h:70
void SetVisible(bool visible)
Definition: scrollview.cpp:549
const int kMaxMsgSize
Definition: scrollview.cpp:38
static void SendRawMessage(const char *msg)
Definition: scrollview.cpp:409
int x
Definition: scrollview.h:67
void Signal()
Signal a semaphore.
Definition: svutil.cpp:182
void Stroke(float width)
Definition: scrollview.cpp:594
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:262
void DrawTo(int x, int y)
Definition: scrollview.cpp:525
char * parameter
Definition: scrollview.h:66
int ShowYesNoDialog(const char *msg)
Definition: scrollview.cpp:745
std::vector< int > ycoords
Definition: scrollview.cpp:48
static void Exit()
Definition: scrollview.cpp:583
void MenuItem(const char *parent, const char *name)
Definition: scrollview.cpp:680
void Flush()
Flush the buffer.
Definition: svutil.cpp:210
void Line(int x1, int y1, int x2, int y2)
Definition: scrollview.cpp:532
char * Receive()
Definition: svutil.cpp:221
static void StartThread(void *(*func)(void *), void *arg)
Create new thread.
Definition: svutil.cpp:81
const int kSvPort
Definition: scrollview.cpp:37
void Image(struct Pix *image, int x_pos, int y_pos)
Definition: scrollview.cpp:765
void Ellipse(int x, int y, int width, int height)
Definition: scrollview.cpp:609
void AddMessage(const char *format,...)
Definition: scrollview.cpp:561
void Wait()
Wait on a semaphore.
Definition: svutil.cpp:192
ScrollView * window
Definition: scrollview.h:65
virtual void Notify(const SVEvent *sve)
Definition: scrollview.h:88
void TextAttributes(const char *font, int pixel_size, bool bold, bool italic, bool underlined)
Definition: scrollview.cpp:635
void AddEventHandler(SVEventHandler *listener)
Add an Event Listener to this ScrollView Window.
Definition: scrollview.cpp:414
void Clear()
Definition: scrollview.cpp:589
const int kMaxIntPairSize
Definition: scrollview.cpp:39
SVEventType type
Definition: scrollview.h:64
virtual ~SVEventHandler()
void AlwaysOnTop(bool b)
Definition: scrollview.cpp:555
void SendMsg(const char *msg,...)
Send a message to the server, attaching the window id.
Definition: scrollview.cpp:391
int TranslateYCoordinate(int y)
Definition: scrollview.cpp:827
int command_id
Definition: scrollview.h:71
void Text(int x, int y, const char *mystring)
Definition: scrollview.cpp:652
std::vector< int > xcoords
Definition: scrollview.cpp:47
void Pen(Color color)
Definition: scrollview.cpp:719
int counter
Definition: scrollview.h:72
int y
Definition: scrollview.h:68
void SetCursor(int x, int y)
Definition: scrollview.cpp:519
void Send(const char *msg)
Put a message in the messagebuffer to the server and try to send it.
Definition: svutil.cpp:203