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