Tesseract  3.02
tesseract-ocr/viewer/scrollview.cpp
Go to the documentation of this file.
00001 
00002 // File:        scrollview.cc
00003 // Description: ScrollView
00004 // Author:      Joern Wanke
00005 // Created:     Thu Nov 29 2007
00006 //
00007 // (C) Copyright 2007, Google Inc.
00008 // Licensed under the Apache License, Version 2.0 (the "License");
00009 // you may not use this file except in compliance with the License.
00010 // You may obtain a copy of the License at
00011 // http://www.apache.org/licenses/LICENSE-2.0
00012 // Unless required by applicable law or agreed to in writing, software
00013 // distributed under the License is distributed on an "AS IS" BASIS,
00014 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00015 // See the License for the specific language governing permissions and
00016 // limitations under the License.
00017 //
00019 //
00020 
00021 #include <stdarg.h>
00022 #include <limits.h>
00023 #include <string.h>
00024 #include <map>
00025 #include <utility>
00026 #include <algorithm>
00027 #include <vector>
00028 #include <string>
00029 #include <cstring>
00030 #include <climits>
00031 
00032 // Include automatically generated configuration file if running autoconf.
00033 #ifdef HAVE_CONFIG_H
00034 #include "config_auto.h"
00035 #endif
00036 
00037 #ifndef GRAPHICS_DISABLED
00038 // This class contains the main ScrollView-logic,
00039 // e.g. parsing & sending messages, images etc.
00040 #ifdef _MSC_VER
00041 #pragma warning(disable:4786)  // Don't give stupid warnings for stl
00042 #pragma warning(disable:4018)  // signed/unsigned warnings
00043 #pragma warning(disable:4530)  // exception warnings
00044 #endif
00045 
00046 const int kSvPort = 8461;
00047 const int kMaxMsgSize = 4096;
00048 const int kMaxIntPairSize = 45;  // Holds %d,%d, for upto 64 bit.
00049 
00050 #include "scrollview.h"
00051 #include "svutil.h"
00052 
00053 #include "allheaders.h"
00054 
00055 struct SVPolyLineBuffer {
00056   bool empty;  // Independent indicator to allow SendMsg to call SendPolygon.
00057   std::vector<int> xcoords;
00058   std::vector<int> ycoords;
00059 };
00060 
00061 // A map between the window IDs and their corresponding pointers.
00062 static std::map<int, ScrollView*> svmap;
00063 static SVMutex* svmap_mu;
00064 // A map of all semaphores waiting for a specific event on a specific window.
00065 static std::map<std::pair<ScrollView*, SVEventType>,
00066                 std::pair<SVSemaphore*, SVEvent*> > waiting_for_events;
00067 static SVMutex* waiting_for_events_mu;
00068 
00069 SVEvent* SVEvent::copy() {
00070   SVEvent* any = new SVEvent;
00071   any->command_id = command_id;
00072   any->counter = counter;
00073   any->parameter = new char[strlen(parameter) + 1];
00074   strncpy(any->parameter, parameter, strlen(parameter));
00075   any->parameter[strlen(parameter)] = '\0';
00076   any->type = type;
00077   any->x = x;
00078   any->y = y;
00079   any->x_size = x_size;
00080   any->y_size = y_size;
00081   any->window = window;
00082   return any;
00083 }
00084 
00089 void* ScrollView::MessageReceiver(void* a) {
00090   int counter_event_id = 0;  // ongoing counter
00091   char* message = NULL;
00092   // Wait until a new message appears in the input stream_.
00093   do {
00094     message = ScrollView::GetStream()->Receive();
00095   } while (message == NULL);
00096 
00097 // This is the main loop which iterates until the server is dead (strlen = -1).
00098 // It basically parses for 3 different messagetypes and then distributes the
00099 // events accordingly.
00100   while (strlen(message) != -1) {
00101       // The new event we create.
00102       SVEvent* cur = new SVEvent;
00103       // The ID of the corresponding window.
00104       int window_id;
00105 
00106       int ev_type;
00107 
00108       int n;
00109       // Fill the new SVEvent properly.
00110       sscanf(message, "%d,%d,%d,%d,%d,%d,%d,%n", &window_id, &ev_type, &cur->x,
00111              &cur->y, &cur->x_size, &cur->y_size, &cur->command_id, &n);
00112       char* p = (message + n);
00113 
00114       svmap_mu->Lock();
00115       cur->window = svmap[window_id];
00116 
00117       if (cur->window != NULL) {
00118         cur->parameter = new char[strlen(p) + 1];
00119         strncpy(cur->parameter, p, strlen(p) + 1);
00120         if (strlen(p) > 0) {  // remove the last \n
00121           cur->parameter[strlen(p)] = '\0';
00122         }
00123         cur->type = static_cast<SVEventType>(ev_type);
00124         // Correct selection coordinates so x,y is the min pt and size is +ve.
00125         if (cur->x_size > 0)
00126           cur->x -= cur->x_size;
00127         else
00128           cur->x_size = -cur->x_size;
00129         if (cur->y_size > 0)
00130           cur->y -= cur->y_size;
00131         else
00132           cur->y_size = -cur->y_size;
00133         // Returned y will be the bottom-left if y is reversed.
00134         if (cur->window->y_axis_is_reversed_)
00135           cur->y = cur->window->TranslateYCoordinate(cur->y + cur->y_size);
00136         cur->counter = counter_event_id;
00137         // Increase by 2 since we will also create an SVET_ANY event from cur,
00138         // which will have a counter_id of cur + 1 (and thus gets processed
00139         // after cur).
00140         counter_event_id += 2;
00141 
00142         // In case of an SVET_EXIT event, quit the whole application.
00143         if (ev_type == SVET_EXIT) { ScrollView::Exit(); }
00144 
00145         // Place two copies of it in the table for the window.
00146         cur->window->SetEvent(cur);
00147 
00148         // Check if any of the threads currently waiting want it.
00149         std::pair<ScrollView*, SVEventType> awaiting_list(cur->window,
00150                                                           cur->type);
00151         std::pair<ScrollView*, SVEventType> awaiting_list_any(cur->window,
00152                                                               SVET_ANY);
00153         std::pair<ScrollView*, SVEventType> awaiting_list_any_window((ScrollView*)0,
00154                                                               SVET_ANY);
00155         waiting_for_events_mu->Lock();
00156         if (waiting_for_events.count(awaiting_list) > 0) {
00157           waiting_for_events[awaiting_list].second = cur;
00158           waiting_for_events[awaiting_list].first->Signal();
00159         } else if (waiting_for_events.count(awaiting_list_any) > 0) {
00160           waiting_for_events[awaiting_list_any].second = cur;
00161           waiting_for_events[awaiting_list_any].first->Signal();
00162         } else if (waiting_for_events.count(awaiting_list_any_window) > 0) {
00163           waiting_for_events[awaiting_list_any_window].second = cur;
00164           waiting_for_events[awaiting_list_any_window].first->Signal();
00165         } else {
00166           // No one wanted it, so delete it.
00167           delete cur;
00168         }
00169         waiting_for_events_mu->Unlock();
00170         // Signal the corresponding semaphore twice (for both copies).
00171         ScrollView* sv = svmap[window_id];
00172         if (sv != NULL) {
00173           sv->Signal();
00174           sv->Signal();
00175         }
00176       }
00177       svmap_mu->Unlock();
00178 
00179       // Wait until a new message appears in the input stream_.
00180       do {
00181         message = ScrollView::GetStream()->Receive();
00182       } while (message == NULL);
00183     }
00184   return 0;
00185 }
00186 
00187 // Table to implement the color index values in the old system.
00188 int table_colors[ScrollView::GREEN_YELLOW+1][4]= {
00189   {0, 0, 0, 0},        // NONE (transparent)
00190   {0, 0, 0, 255},        // BLACK.
00191   {255, 255, 255, 255},  // WHITE.
00192   {255, 0, 0, 255},      // RED.
00193   {255, 255, 0, 255},    // YELLOW.
00194   {0, 255, 0, 255},      // GREEN.
00195   {0, 255, 255, 255},    // CYAN.
00196   {0, 0, 255, 255},      // BLUE.
00197   {255, 0, 255, 255},    // MAGENTA.
00198   {0, 128, 255, 255},    // AQUAMARINE.
00199   {0, 0, 64, 255},       // DARK_SLATE_BLUE.
00200   {128, 128, 255, 255},  // LIGHT_BLUE.
00201   {64, 64, 255, 255},    // MEDIUM_BLUE.
00202   {0, 0, 32, 255},       // MIDNIGHT_BLUE.
00203   {0, 0, 128, 255},      // NAVY_BLUE.
00204   {192, 192, 255, 255},  // SKY_BLUE.
00205   {64, 64, 128, 255},    // SLATE_BLUE.
00206   {32, 32, 64, 255},     // STEEL_BLUE.
00207   {255, 128, 128, 255},  // CORAL.
00208   {128, 64, 0, 255},     // BROWN.
00209   {128, 128, 0, 255},    // SANDY_BROWN.
00210   {192, 192, 0, 255},    // GOLD.
00211   {192, 192, 128, 255},  // GOLDENROD.
00212   {0, 64, 0, 255},       // DARK_GREEN.
00213   {32, 64, 0, 255},      // DARK_OLIVE_GREEN.
00214   {64, 128, 0, 255},     // FOREST_GREEN.
00215   {128, 255, 0, 255},    // LIME_GREEN.
00216   {192, 255, 192, 255},  // PALE_GREEN.
00217   {192, 255, 0, 255},    // YELLOW_GREEN.
00218   {192, 192, 192, 255},  // LIGHT_GREY.
00219   {64, 64, 128, 255},    // DARK_SLATE_GREY.
00220   {64, 64, 64, 255},     // DIM_GREY.
00221   {128, 128, 128, 255},  // GREY.
00222   {64, 192, 0, 255},     // KHAKI.
00223   {255, 0, 192, 255},    // MAROON.
00224   {255, 128, 0, 255},    // ORANGE.
00225   {255, 128, 64, 255},   // ORCHID.
00226   {255, 192, 192, 255},  // PINK.
00227   {128, 0, 128, 255},    // PLUM.
00228   {255, 0, 64, 255},     // INDIAN_RED.
00229   {255, 64, 0, 255},     // ORANGE_RED.
00230   {255, 0, 192, 255},    // VIOLET_RED.
00231   {255, 192, 128, 255},  // SALMON.
00232   {128, 128, 0, 255},    // TAN.
00233   {0, 255, 255, 255},    // TURQUOISE.
00234   {0, 128, 128, 255},    // DARK_TURQUOISE.
00235   {192, 0, 255, 255},    // VIOLET.
00236   {128, 128, 0, 255},    // WHEAT.
00237   {128, 255, 0, 255}     // GREEN_YELLOW
00238 };
00239 
00240 
00241 /*******************************************************************************
00242 * Scrollview implementation.
00243 *******************************************************************************/
00244 
00245 SVNetwork* ScrollView::stream_ = NULL;
00246 int ScrollView::nr_created_windows_ = 0;
00247 int ScrollView::image_index_ = 0;
00248 
00250 ScrollView::ScrollView(const char* name, int x_pos, int y_pos, int x_size,
00251                        int y_size, int x_canvas_size, int y_canvas_size,
00252                        bool y_axis_reversed, const char* server_name) {
00253   Initialize(name, x_pos, y_pos, x_size, y_size, x_canvas_size, y_canvas_size,
00254              y_axis_reversed, server_name);}
00255 
00257 ScrollView::ScrollView(const char* name, int x_pos, int y_pos, int x_size,
00258                        int y_size, int x_canvas_size, int y_canvas_size,
00259                        bool y_axis_reversed) {
00260   Initialize(name, x_pos, y_pos, x_size, y_size, x_canvas_size, y_canvas_size,
00261              y_axis_reversed, "localhost");
00262 }
00263 
00265 ScrollView::ScrollView(const char* name, int x_pos, int y_pos, int x_size,
00266                        int y_size, int x_canvas_size, int y_canvas_size) {
00267   Initialize(name, x_pos, y_pos, x_size, y_size, x_canvas_size, y_canvas_size,
00268              false, "localhost");
00269 }
00270 
00272 void ScrollView::Initialize(const char* name, int x_pos, int y_pos, int x_size,
00273                             int y_size, int x_canvas_size, int y_canvas_size,
00274                             bool y_axis_reversed, const char* server_name) {
00275   // If this is the first ScrollView Window which gets created, there is no
00276   // network connection yet and we have to set it up in a different thread.
00277   if (stream_ == NULL) {
00278     nr_created_windows_ = 0;
00279     stream_ = new SVNetwork(server_name, kSvPort);
00280     waiting_for_events_mu = new SVMutex();
00281     svmap_mu = new SVMutex();
00282     SendRawMessage(
00283         "svmain = luajava.bindClass('com.google.scrollview.ScrollView')\n");
00284     SVSync::StartThread(MessageReceiver, NULL);
00285   }
00286 
00287   // Set up the variables on the clientside.
00288   nr_created_windows_++;
00289   event_handler_ = NULL;
00290   event_handler_ended_ = false;
00291   y_axis_is_reversed_ = y_axis_reversed;
00292   y_size_ = y_canvas_size;
00293   window_name_ = name;
00294   window_id_ = nr_created_windows_;
00295   // Set up polygon buffering.
00296   points_ = new SVPolyLineBuffer;
00297   points_->empty = true;
00298 
00299   svmap_mu->Lock();
00300   svmap[window_id_] = this;
00301   svmap_mu->Unlock();
00302 
00303   for (int i = 0; i < SVET_COUNT; i++) {
00304     event_table_[i] = NULL;
00305   }
00306 
00307   mutex_ = new SVMutex();
00308   semaphore_ = new SVSemaphore();
00309 
00310   // Set up an actual Window on the client side.
00311   char message[kMaxMsgSize];
00312   snprintf(message, sizeof(message),
00313            "w%u = luajava.newInstance('com.google.scrollview.ui"
00314            ".SVWindow','%s',%u,%u,%u,%u,%u,%u,%u)\n",
00315            window_id_, window_name_, window_id_,
00316            x_pos, y_pos, x_size, y_size, x_canvas_size, y_canvas_size);
00317   SendRawMessage(message);
00318 
00319   SVSync::StartThread(StartEventHandler, this);
00320 }
00321 
00323 void* ScrollView::StartEventHandler(void* a) {
00324   ScrollView* sv = reinterpret_cast<ScrollView*>(a);
00325   SVEvent* new_event;
00326 
00327   do {
00328     stream_->Flush();
00329     sv->semaphore_->Wait();
00330     new_event = NULL;
00331     int serial = -1;
00332     int k = -1;
00333     sv->mutex_->Lock();
00334     // Check every table entry if he is is valid and not already processed.
00335 
00336     for (int i = 0; i < SVET_COUNT; i++) {
00337       if (sv->event_table_[i] != NULL &&
00338           (serial < 0 || sv->event_table_[i]->counter < serial)) {
00339         new_event = sv->event_table_[i];
00340         serial = sv->event_table_[i]->counter;
00341         k = i;
00342       }
00343     }
00344     // If we didnt find anything we had an old alarm and just sleep again.
00345     if (new_event != NULL) {
00346       sv->event_table_[k] = NULL;
00347       sv->mutex_->Unlock();
00348       if (sv->event_handler_ != NULL) { sv->event_handler_->Notify(new_event); }
00349       if (new_event->type == SVET_DESTROY) {
00350         // Signal the destructor that it is safe to terminate.
00351         sv->event_handler_ended_ = true;
00352         sv = NULL;
00353       }
00354       delete new_event;  // Delete the pointer after it has been processed.
00355     } else { sv->mutex_->Unlock(); }
00356   // The thread should run as long as its associated window is alive.
00357   } while (sv != NULL);
00358   return 0;
00359 }
00360 
00361 ScrollView::~ScrollView() {
00362   svmap_mu->Lock();
00363   if (svmap[window_id_] != NULL) {
00364     svmap_mu->Unlock();
00365     // So the event handling thread can quit.
00366     SendMsg("destroy()");
00367 
00368     SVEvent* sve = AwaitEvent(SVET_DESTROY);
00369     delete sve;
00370     svmap_mu->Lock();
00371     svmap[window_id_] = NULL;
00372     svmap_mu->Unlock();
00373     // The event handler thread for this window *must* receive the
00374     // destroy event and set its pointer to this to NULL before we allow
00375     // the destructor to exit.
00376     while (!event_handler_ended_)
00377       Update();
00378   } else {
00379     svmap_mu->Unlock();
00380   }
00381   delete mutex_;
00382   delete semaphore_;
00383   delete points_;
00384 }
00385 
00387 void ScrollView::SendMsg(const char* format, ...) {
00388   if (!points_->empty)
00389     SendPolygon();
00390   va_list args;
00391   char message[kMaxMsgSize];
00392 
00393   va_start(args, format);  // variable list
00394   vsnprintf(message, kMaxMsgSize, format, args);
00395   va_end(args);
00396 
00397   char form[kMaxMsgSize];
00398   snprintf(form, kMaxMsgSize, "w%u:%s\n", window_id_, message);
00399 
00400   stream_->Send(form);
00401 }
00402 
00405 void ScrollView::SendRawMessage(const char* msg) {
00406   stream_->Send(msg);
00407 }
00408 
00410 void ScrollView::AddEventHandler(SVEventHandler* listener) {
00411   event_handler_ = listener;
00412 }
00413 
00414 void ScrollView::Signal() {
00415   semaphore_->Signal();
00416 }
00417 
00418 void ScrollView::SetEvent(SVEvent* svevent) {
00419 // Copy event
00420   SVEvent* any = svevent->copy();
00421   SVEvent* specific = svevent->copy();
00422   any->counter = specific->counter + 1;
00423 
00424 // Place both events into the queue.
00425   mutex_->Lock();
00426   // Delete the old objects..
00427   if (event_table_[specific->type] != NULL) {
00428     delete event_table_[specific->type]; }
00429   if (event_table_[SVET_ANY] != NULL) {
00430     delete event_table_[SVET_ANY]; }
00431   // ...and put the new ones in the table.
00432   event_table_[specific->type] = specific;
00433   event_table_[SVET_ANY] = any;
00434   mutex_->Unlock();
00435 }
00436 
00437 
00441 SVEvent* ScrollView::AwaitEvent(SVEventType type) {
00442   // Initialize the waiting semaphore.
00443   SVSemaphore* sem = new SVSemaphore();
00444   std::pair<ScrollView*, SVEventType> ea(this, type);
00445   waiting_for_events_mu->Lock();
00446   waiting_for_events[ea] = std::pair<SVSemaphore*, SVEvent*> (sem, (SVEvent*)0);
00447   waiting_for_events_mu->Unlock();
00448   // Wait on it, but first flush.
00449   stream_->Flush();
00450   sem->Wait();
00451   // Process the event we got woken up for (its in waiting_for_events pair).
00452   waiting_for_events_mu->Lock();
00453   SVEvent* ret = waiting_for_events[ea].second;
00454   waiting_for_events.erase(ea);
00455   delete sem;
00456   waiting_for_events_mu->Unlock();
00457   return ret;
00458 }
00459 
00460 // Block until any event on any window is received.
00461 // No event is returned here!
00462 SVEvent* ScrollView::AwaitEventAnyWindow() {
00463   // Initialize the waiting semaphore.
00464   SVSemaphore* sem = new SVSemaphore();
00465   std::pair<ScrollView*, SVEventType> ea((ScrollView*)0, SVET_ANY);
00466   waiting_for_events_mu->Lock();
00467   waiting_for_events[ea] = std::pair<SVSemaphore*, SVEvent*> (sem, (SVEvent*)0);
00468   waiting_for_events_mu->Unlock();
00469   // Wait on it.
00470   stream_->Flush();
00471   sem->Wait();
00472   // Process the event we got woken up for (its in waiting_for_events pair).
00473   waiting_for_events_mu->Lock();
00474   SVEvent* ret = waiting_for_events[ea].second;
00475   waiting_for_events.erase(ea);
00476   waiting_for_events_mu->Unlock();
00477   return ret;
00478 }
00479 
00480 // Send the current buffered polygon (if any) and clear it.
00481 void ScrollView::SendPolygon() {
00482   if (!points_->empty) {
00483     points_->empty = true;  // Allows us to use SendMsg.
00484     int length = points_->xcoords.size();
00485     // length == 1 corresponds to 2 SetCursors in a row and only the
00486     // last setCursor has any effect.
00487     if (length == 2) {
00488       // An isolated line!
00489       SendMsg("drawLine(%d,%d,%d,%d)",
00490               points_->xcoords[0], points_->ycoords[0],
00491               points_->xcoords[1], points_->ycoords[1]);
00492     } else if (length > 2) {
00493       // A polyline.
00494       SendMsg("createPolyline(%d)", length);
00495       char coordpair[kMaxIntPairSize];
00496       std::string decimal_coords;
00497       for (int i = 0; i < length; ++i) {
00498         snprintf(coordpair, kMaxIntPairSize, "%d,%d,",
00499                  points_->xcoords[i], points_->ycoords[i]);
00500         decimal_coords += coordpair;
00501       }
00502       decimal_coords += '\n';
00503       SendRawMessage(decimal_coords.c_str());
00504       SendMsg("drawPolyline()");
00505     }
00506     points_->xcoords.clear();
00507     points_->ycoords.clear();
00508   }
00509 }
00510 
00511 
00512 /*******************************************************************************
00513 * LUA "API" functions.
00514 *******************************************************************************/
00515 
00516 // Sets the position from which to draw to (x,y).
00517 void ScrollView::SetCursor(int x, int y) {
00518   SendPolygon();
00519   DrawTo(x, y);
00520 }
00521 
00522 // Draws from the current position to (x,y) and sets the new position to it.
00523 void ScrollView::DrawTo(int x, int y) {
00524   points_->xcoords.push_back(x);
00525   points_->ycoords.push_back(TranslateYCoordinate(y));
00526   points_->empty = false;
00527 }
00528 
00529 // Draw a line using the current pen color.
00530 void ScrollView::Line(int x1, int y1, int x2, int y2) {
00531   if (!points_->xcoords.empty() && x1 == points_->xcoords.back() &&
00532       TranslateYCoordinate(y1) == points_->ycoords.back()) {
00533     // We are already at x1, y1, so just draw to x2, y2.
00534     DrawTo(x2, y2);
00535   } else if (!points_->xcoords.empty() && x2 == points_->xcoords.back() &&
00536       TranslateYCoordinate(y2) == points_->ycoords.back()) {
00537     // We are already at x2, y2, so just draw to x1, y1.
00538     DrawTo(x1, y1);
00539   } else {
00540     // This is a new line.
00541     SetCursor(x1, y1);
00542     DrawTo(x2, y2);
00543   }
00544 }
00545 
00546 // Set the visibility of the window.
00547 void ScrollView::SetVisible(bool visible) {
00548   if (visible) { SendMsg("setVisible(true)");
00549   } else { SendMsg("setVisible(false)"); }
00550 }
00551 
00552 // Set the alwaysOnTop flag.
00553 void ScrollView::AlwaysOnTop(bool b) {
00554   if (b) { SendMsg("setAlwaysOnTop(true)");
00555   } else { SendMsg("setAlwaysOnTop(false)"); }
00556 }
00557 
00558 // Adds a message entry to the message box.
00559 void ScrollView::AddMessage(const char* format, ...) {
00560   va_list args;
00561   char message[kMaxMsgSize];
00562   char form[kMaxMsgSize];
00563 
00564   va_start(args, format);  // variable list
00565   vsnprintf(message, kMaxMsgSize, format, args);
00566   va_end(args);
00567 
00568   snprintf(form, kMaxMsgSize, "w%u:%s", window_id_, message);
00569 
00570   char* esc = AddEscapeChars(form);
00571   SendMsg("addMessage(\"%s\")", esc);
00572   delete[] esc;
00573 }
00574 
00575 // Set a messagebox.
00576 void ScrollView::AddMessageBox() {
00577   SendMsg("addMessageBox()");
00578 }
00579 
00580 // Exit the client completely (and notify the server of it).
00581 void ScrollView::Exit() {
00582   SendRawMessage("svmain:exit()");
00583   exit(0);
00584 }
00585 
00586 // Clear the canvas.
00587 void ScrollView::Clear() {
00588   SendMsg("clear()");
00589 }
00590 
00591 // Set the stroke width.
00592 void ScrollView::Stroke(float width) {
00593   SendMsg("setStrokeWidth(%f)", width);
00594 }
00595 
00596 // Draw a rectangle using the current pen color.
00597 // The rectangle is filled with the current brush color.
00598 void ScrollView::Rectangle(int x1, int y1, int x2, int y2) {
00599   if (x1 == x2 && y1 == y2)
00600     return;  // Scrollviewer locks up.
00601   SendMsg("drawRectangle(%d,%d,%d,%d)",
00602     x1, TranslateYCoordinate(y1), x2, TranslateYCoordinate(y2));
00603 }
00604 
00605 // Draw an ellipse using the current pen color.
00606 // The ellipse is filled with the current brush color.
00607 void ScrollView::Ellipse(int x1, int y1, int width, int height) {
00608   SendMsg("drawEllipse(%d,%d,%u,%u)",
00609     x1, TranslateYCoordinate(y1), width, height);
00610 }
00611 
00612 // Set the pen color to the given RGB values.
00613 void ScrollView::Pen(int red, int green, int blue) {
00614   SendMsg("pen(%d,%d,%d)", red, green, blue);
00615 }
00616 
00617 // Set the pen color to the given RGB values.
00618 void ScrollView::Pen(int red, int green, int blue, int alpha) {
00619   SendMsg("pen(%d,%d,%d,%d)", red, green, blue, alpha);
00620 }
00621 
00622 // Set the brush color to the given RGB values.
00623 void ScrollView::Brush(int red, int green, int blue) {
00624   SendMsg("brush(%d,%d,%d)", red, green, blue);
00625 }
00626 
00627 // Set the brush color to the given RGB values.
00628 void ScrollView::Brush(int red, int green, int blue, int alpha) {
00629   SendMsg("brush(%d,%d,%d,%d)", red, green, blue, alpha);
00630 }
00631 
00632 // Set the attributes for future Text(..) calls.
00633 void ScrollView::TextAttributes(const char* font, int pixel_size,
00634                                 bool bold, bool italic, bool underlined) {
00635   const char* b;
00636   const char* i;
00637   const char* u;
00638 
00639   if (bold) { b = "true";
00640   } else { b = "false"; }
00641   if (italic) { i = "true";
00642   } else { i = "false"; }
00643   if (underlined) { u = "true";
00644   } else { u = "false"; }
00645   SendMsg("textAttributes('%s',%u,%s,%s,%s)", font, pixel_size,
00646     b, i, u);
00647 }
00648 
00649 // Draw text at the given coordinates.
00650 void ScrollView::Text(int x, int y, const char* mystring) {
00651   SendMsg("drawText(%d,%d,'%s')", x, TranslateYCoordinate(y), mystring);
00652 }
00653 
00654 // Open and draw an image given a name at (x,y).
00655 void ScrollView::Image(const char* image, int x_pos, int y_pos) {
00656   SendMsg("openImage('%s')", image);
00657   SendMsg("drawImage('%s',%d,%d)",
00658                 image, x_pos, TranslateYCoordinate(y_pos));
00659 }
00660 
00661 // Add new checkboxmenuentry to menubar.
00662 void ScrollView::MenuItem(const char* parent, const char* name,
00663                           int cmdEvent, bool flag) {
00664   if (parent == NULL) { parent = ""; }
00665   if (flag) { SendMsg("addMenuBarItem('%s','%s',%d,true)",
00666                       parent, name, cmdEvent);
00667   } else { SendMsg("addMenuBarItem('%s','%s',%d,false)",
00668                    parent, name, cmdEvent); }
00669 }
00670 
00671 // Add new menuentry to menubar.
00672 void ScrollView::MenuItem(const char* parent, const char* name, int cmdEvent) {
00673   if (parent == NULL) { parent = ""; }
00674   SendMsg("addMenuBarItem('%s','%s',%d)", parent, name, cmdEvent);
00675 }
00676 
00677 // Add new submenu to menubar.
00678 void ScrollView::MenuItem(const char* parent, const char* name) {
00679   if (parent == NULL) { parent = ""; }
00680   SendMsg("addMenuBarItem('%s','%s')", parent, name);
00681 }
00682 
00683 // Add new submenu to popupmenu.
00684 void ScrollView::PopupItem(const char* parent, const char* name) {
00685   if (parent == NULL) { parent = ""; }
00686   SendMsg("addPopupMenuItem('%s','%s')", parent, name);
00687 }
00688 
00689 // Add new submenuentry to popupmenu.
00690 void ScrollView::PopupItem(const char* parent, const char* name,
00691                            int cmdEvent, const char* value, const char* desc) {
00692   if (parent == NULL) { parent = ""; }
00693   char* esc = AddEscapeChars(value);
00694   char* esc2 = AddEscapeChars(desc);
00695   SendMsg("addPopupMenuItem('%s','%s',%d,'%s','%s')", parent, name,
00696           cmdEvent, esc, esc2);
00697   delete[] esc;
00698   delete[] esc2;
00699 }
00700 
00701 // Send an update message for a single window.
00702 void ScrollView::UpdateWindow() {
00703   SendMsg("update()");
00704 }
00705 
00706 // Note: this is an update to all windows
00707 void ScrollView::Update() {
00708   svmap_mu->Lock();
00709   for (std::map<int, ScrollView*>::iterator iter = svmap.begin();
00710       iter != svmap.end(); ++iter) {
00711     if (iter->second != NULL)
00712       iter->second->UpdateWindow();
00713   }
00714   svmap_mu->Unlock();
00715 }
00716 
00717 // Set the pen color, using an enum value (e.g. ScrollView::ORANGE)
00718 void ScrollView::Pen(Color color) {
00719   Pen(table_colors[color][0], table_colors[color][1],
00720       table_colors[color][2], table_colors[color][3]);
00721 }
00722 
00723 // Set the brush color, using an enum value (e.g. ScrollView::ORANGE)
00724 void ScrollView::Brush(Color color) {
00725   Brush(table_colors[color][0],
00726         table_colors[color][1],
00727         table_colors[color][2],
00728         table_colors[color][3]);
00729 }
00730 
00731 // Shows a modal Input Dialog which can return any kind of String
00732 char* ScrollView::ShowInputDialog(const char* msg) {
00733   SendMsg("showInputDialog(\"%s\")", msg);
00734   SVEvent* ev;
00735   // wait till an input event (all others are thrown away)
00736   ev = AwaitEvent(SVET_INPUT);
00737   char* p = new char[strlen(ev->parameter) + 1];
00738   strncpy(p, ev->parameter, strlen(ev->parameter));
00739   p[strlen(ev->parameter)] = '\0';
00740   delete ev;
00741   return p;
00742 }
00743 
00744 // Shows a modal Yes/No Dialog which will return 'y' or 'n'
00745 int ScrollView::ShowYesNoDialog(const char* msg) {
00746   SendMsg("showYesNoDialog(\"%s\")", msg);
00747   SVEvent* ev;
00748   // Wait till an input event (all others are thrown away)
00749   ev = AwaitEvent(SVET_INPUT);
00750   int a = ev->parameter[0];
00751   delete ev;
00752   return a;
00753 }
00754 
00755 // Zoom the window to the rectangle given upper left corner and
00756 // lower right corner.
00757 void ScrollView::ZoomToRectangle(int x1, int y1, int x2, int y2) {
00758   y1 = TranslateYCoordinate(y1);
00759   y2 = TranslateYCoordinate(y2);
00760   SendMsg("zoomRectangle(%d,%d,%d,%d)",
00761           MIN(x1, x2), MIN(y1, y2), MAX(x1, x2), MAX(y1, y2));
00762 }
00763 
00764 // Send an image of type Pix.
00765 void ScrollView::Image(struct Pix* image, int x_pos, int y_pos) {
00766   int width = image->w;
00767   int height = image->h;
00768   l_uint32 bpp = image->d;
00769   ++image_index_;
00770   // PIX* do not have a unique identifier/name associated, so name them "lept".
00771   SendMsg("createImage('lept%d',%d,%d,%d)", image_index_, width, height, bpp);
00772 
00773   if (bpp == 32) {
00774     Transfer32bppImage(image);
00775   } else if (bpp == 8) {
00776     TransferGrayImage(image);
00777   } else if (bpp == 1) {
00778     TransferBinaryImage(image);
00779   }
00780   // PIX* do not have a unique identifier/name associated, so name them "lept".
00781   SendMsg("drawImage('lept%d',%d,%d)", image_index_, x_pos, y_pos);
00782 }
00783 
00784 // Sends each pixel as hex value like html, e.g. #00FF00 for green.
00785 void ScrollView::Transfer32bppImage(PIX* image) {
00786   int ppL = pixGetWidth(image);
00787   int h = pixGetHeight(image);
00788   int wpl = pixGetWpl(image);
00789   int transfer_size= ppL * 7 + 2;
00790   char* pixel_data = new char[transfer_size];
00791   for (int y = 0; y < h; ++y) {
00792     l_uint32* data = pixGetData(image) + y*wpl;
00793     for (int x = 0; x < ppL; ++x, ++data) {
00794       snprintf(&pixel_data[x*7], 7, "#%.2x%.2x%.2x",
00795                GET_DATA_BYTE(data, COLOR_RED),
00796                GET_DATA_BYTE(data, COLOR_GREEN),
00797                GET_DATA_BYTE(data, COLOR_BLUE));
00798     }
00799     pixel_data[transfer_size - 2] = '\n';
00800     pixel_data[transfer_size - 1] = '\0';
00801     SendRawMessage(pixel_data);
00802   }
00803   delete[] pixel_data;
00804 }
00805 
00806 // Sends for each pixel either '1' or '0'.
00807 void ScrollView::TransferGrayImage(PIX* image) {
00808   char* pixel_data = new char[image->w * 2 + 2];
00809   for (int y = 0; y < image->h; y++) {
00810     l_uint32* data = pixGetData(image) + y * pixGetWpl(image);
00811     for (int x = 0; x < image->w; x++) {
00812       snprintf(&pixel_data[x*2], 2, "%.2x", (GET_DATA_BYTE(data, x)));
00813       pixel_data[image->w * 2] = '\n';
00814       pixel_data[image->w * 2 + 1] = '\0';
00815       SendRawMessage(pixel_data);
00816     }
00817   }
00818   delete [] pixel_data;
00819 }
00820 
00821 // Sends for each pixel either '1' or '0'.
00822 void ScrollView::TransferBinaryImage(PIX* image) {
00823   char* pixel_data = new char[image->w + 2];
00824   for (int y = 0; y < image->h; y++) {
00825     l_uint32* data = pixGetData(image) + y * pixGetWpl(image);
00826     for (int x = 0; x < image->w; x++) {
00827       if (GET_DATA_BIT(data, x))
00828         pixel_data[x] = '1';
00829       else
00830         pixel_data[x] = '0';
00831     }
00832     pixel_data[image->w] = '\n';
00833     pixel_data[image->w + 1] = '\0';
00834     SendRawMessage(pixel_data);
00835   }
00836   delete [] pixel_data;
00837 }
00838 
00839 // Escapes the ' character with a \, so it can be processed by LUA.
00840 // Note: The caller will have to make sure he deletes the newly allocated item.
00841 char* ScrollView::AddEscapeChars(const char* input) {
00842   const char* nextptr = strchr(input, '\'');
00843   const char* lastptr = input;
00844   char* message = new char[kMaxMsgSize];
00845   int pos = 0;
00846   while (nextptr != NULL) {
00847     strncpy(message+pos, lastptr, nextptr-lastptr);
00848     pos += nextptr - lastptr;
00849     message[pos] = '\\';
00850     pos += 1;
00851     lastptr = nextptr;
00852     nextptr = strchr(nextptr+1, '\'');
00853   }
00854   strncpy(message+pos, lastptr, strlen(lastptr));
00855   message[pos+strlen(lastptr)] = '\0';
00856   return message;
00857 }
00858 
00859 // Inverse the Y axis if the coordinates are actually inversed.
00860 int ScrollView::TranslateYCoordinate(int y) {
00861   if (!y_axis_is_reversed_) { return y;
00862   } else { return y_size_ - y; }
00863 }
00864 
00865 #endif  // GRAPHICS_DISABLED