Tesseract
3.02
|
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