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