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