tesseract
3.03
|
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