32 #include "config_auto.h"
43 #include "allheaders.h"
52 static std::map<int, ScrollView*> svmap;
55 static std::map<std::pair<ScrollView*, SVEventType>,
56 std::pair<SVSemaphore*, SVEvent*> > waiting_for_events;
57 static SVMutex* waiting_for_events_mu;
63 any->parameter =
new char[strlen(
parameter) + 1];
79 #ifndef GRAPHICS_DISABLED
84 void* ScrollView::MessageReceiver(
void* a) {
85 int counter_event_id = 0;
86 char* message =
nullptr;
89 message = ScrollView::GetStream()->
Receive();
90 }
while (message ==
nullptr);
105 sscanf(message,
"%d,%d,%d,%d,%d,%d,%d,%n", &window_id, &ev_type, &cur->x,
106 &cur->y, &cur->x_size, &cur->y_size, &cur->command_id, &n);
107 char* p = (message + n);
110 cur->window = svmap[window_id];
112 if (cur->window !=
nullptr) {
113 cur->parameter =
new char[strlen(p) + 1];
114 strcpy(cur->parameter, p);
116 cur->parameter[strlen(p)] =
'\0';
121 cur->x -= cur->x_size;
123 cur->x_size = -cur->x_size;
125 cur->y -= cur->y_size;
127 cur->y_size = -cur->y_size;
129 if (cur->window->y_axis_is_reversed_)
130 cur->y = cur->window->TranslateYCoordinate(cur->y + cur->y_size);
131 cur->counter = counter_event_id;
135 counter_event_id += 2;
141 cur->window->SetEvent(cur);
144 std::pair<ScrollView*, SVEventType> awaiting_list(cur->window,
146 std::pair<ScrollView*, SVEventType> awaiting_list_any(cur->window,
148 std::pair<ScrollView*, SVEventType> awaiting_list_any_window((
ScrollView*)
nullptr,
150 waiting_for_events_mu->
Lock();
151 if (waiting_for_events.count(awaiting_list) > 0) {
152 waiting_for_events[awaiting_list].second = cur;
153 waiting_for_events[awaiting_list].first->Signal();
154 }
else if (waiting_for_events.count(awaiting_list_any) > 0) {
155 waiting_for_events[awaiting_list_any].second = cur;
156 waiting_for_events[awaiting_list_any].first->Signal();
157 }
else if (waiting_for_events.count(awaiting_list_any_window) > 0) {
158 waiting_for_events[awaiting_list_any_window].second = cur;
159 waiting_for_events[awaiting_list_any_window].first->Signal();
164 waiting_for_events_mu->
Unlock();
178 message = ScrollView::GetStream()->
Receive();
179 }
while (message ==
nullptr);
188 {255, 255, 255, 255},
197 {128, 128, 255, 255},
201 {192, 192, 255, 255},
204 {255, 128, 128, 255},
208 {192, 192, 128, 255},
213 {192, 255, 192, 255},
215 {192, 192, 192, 255},
218 {128, 128, 128, 255},
223 {255, 192, 192, 255},
228 {255, 192, 128, 255},
242 SVNetwork* ScrollView::stream_ =
nullptr;
243 int ScrollView::nr_created_windows_ = 0;
244 int ScrollView::image_index_ = 0;
248 int y_size,
int x_canvas_size,
int y_canvas_size,
249 bool y_axis_reversed,
const char* server_name) {
250 Initialize(name, x_pos, y_pos, x_size, y_size, x_canvas_size, y_canvas_size,
251 y_axis_reversed, server_name);}
255 int y_size,
int x_canvas_size,
int y_canvas_size,
256 bool y_axis_reversed) {
257 Initialize(name, x_pos, y_pos, x_size, y_size, x_canvas_size, y_canvas_size,
258 y_axis_reversed,
"localhost");
263 int y_size,
int x_canvas_size,
int y_canvas_size) {
264 Initialize(name, x_pos, y_pos, x_size, y_size, x_canvas_size, y_canvas_size,
269 void ScrollView::Initialize(
const char* name,
int x_pos,
int y_pos,
int x_size,
270 int y_size,
int x_canvas_size,
int y_canvas_size,
271 bool y_axis_reversed,
const char* server_name) {
274 if (stream_ ==
nullptr) {
275 nr_created_windows_ = 0;
277 waiting_for_events_mu =
new SVMutex();
280 "svmain = luajava.bindClass('com.google.scrollview.ScrollView')\n");
285 nr_created_windows_++;
286 event_handler_ =
nullptr;
287 event_handler_ended_ =
false;
288 y_axis_is_reversed_ = y_axis_reversed;
289 y_size_ = y_canvas_size;
291 window_id_ = nr_created_windows_;
294 points_->
empty =
true;
297 svmap[window_id_] =
this;
300 for (
auto & i : event_table_) {
309 snprintf(message,
sizeof(message),
310 "w%u = luajava.newInstance('com.google.scrollview.ui"
311 ".SVWindow','%s',%u,%u,%u,%u,%u,%u,%u)\n",
312 window_id_, window_name_, window_id_,
313 x_pos, y_pos, x_size, y_size, x_canvas_size, y_canvas_size);
320 void* ScrollView::StartEventHandler(
void* a) {
326 sv->semaphore_->
Wait();
334 if (sv->event_table_[i] !=
nullptr &&
335 (serial < 0 || sv->event_table_[i]->counter < serial)) {
336 new_event = sv->event_table_[i];
337 serial = sv->event_table_[i]->
counter;
342 if (new_event !=
nullptr) {
343 sv->event_table_[k] =
nullptr;
345 if (sv->event_handler_ !=
nullptr) { sv->event_handler_->
Notify(new_event); }
348 sv->event_handler_ended_ =
true;
352 }
else { sv->mutex_->
Unlock(); }
354 }
while (sv !=
nullptr);
360 #ifndef GRAPHICS_DISABLED
362 if (svmap[window_id_] !=
nullptr) {
370 svmap[window_id_] =
nullptr;
375 while (!event_handler_ended_)
383 for (
auto & i : event_table_) {
389 #ifndef GRAPHICS_DISABLED
397 va_start(args, format);
398 vsnprintf(message,
sizeof(message), format, args);
402 snprintf(form,
sizeof(form),
"w%u:%s\n", window_id_, message);
415 event_handler_ = listener;
418 void ScrollView::Signal() {
422 void ScrollView::SetEvent(
SVEvent* svevent) {
431 delete event_table_[specific->
type];
434 event_table_[specific->
type] = specific;
446 std::pair<ScrollView*, SVEventType> ea(
this,
type);
447 waiting_for_events_mu->
Lock();
448 waiting_for_events[ea] = std::pair<SVSemaphore*, SVEvent*> (sem, (
SVEvent*)
nullptr);
449 waiting_for_events_mu->
Unlock();
454 waiting_for_events_mu->
Lock();
455 SVEvent* ret = waiting_for_events[ea].second;
456 waiting_for_events.erase(ea);
458 waiting_for_events_mu->
Unlock();
468 waiting_for_events_mu->
Lock();
469 waiting_for_events[ea] = std::pair<SVSemaphore*, SVEvent*> (sem, (
SVEvent*)
nullptr);
470 waiting_for_events_mu->
Unlock();
475 waiting_for_events_mu->
Lock();
476 SVEvent* ret = waiting_for_events[ea].second;
477 waiting_for_events.erase(ea);
478 waiting_for_events_mu->
Unlock();
483 void ScrollView::SendPolygon() {
484 if (!points_->
empty) {
485 points_->
empty =
true;
486 int length = points_->
xcoords.size();
491 SendMsg(
"drawLine(%d,%d,%d,%d)",
494 }
else if (length > 2) {
496 SendMsg(
"createPolyline(%d)", length);
498 std::string decimal_coords;
499 for (
int i = 0; i < length; ++i) {
502 decimal_coords += coordpair;
504 decimal_coords +=
'\n';
528 points_->
empty =
false;
537 }
else if (!points_->
xcoords.empty() && x2 == points_->
xcoords.back() &&
550 if (visible) {
SendMsg(
"setVisible(true)");
551 }
else {
SendMsg(
"setVisible(false)"); }
556 if (b) {
SendMsg(
"setAlwaysOnTop(true)");
557 }
else {
SendMsg(
"setAlwaysOnTop(false)"); }
565 va_start(args, format);
566 vsnprintf(message,
sizeof(message), format, args);
570 snprintf(form,
sizeof(form),
"w%u:%s", window_id_, message);
572 char* esc = AddEscapeChars(form);
573 SendMsg(
"addMessage(\"%s\")", esc);
595 SendMsg(
"setStrokeWidth(%f)", width);
601 if (x1 == x2 && y1 == y2)
603 SendMsg(
"drawRectangle(%d,%d,%d,%d)",
610 SendMsg(
"drawEllipse(%d,%d,%u,%u)",
616 SendMsg(
"pen(%d,%d,%d)", red, green, blue);
621 SendMsg(
"pen(%d,%d,%d,%d)", red, green, blue, alpha);
626 SendMsg(
"brush(%d,%d,%d)", red, green, blue);
631 SendMsg(
"brush(%d,%d,%d,%d)", red, green, blue, alpha);
636 bool bold,
bool italic,
bool underlined) {
641 if (bold) { b =
"true";
642 }
else { b =
"false"; }
643 if (italic) { i =
"true";
644 }
else { i =
"false"; }
645 if (underlined) { u =
"true";
646 }
else { u =
"false"; }
647 SendMsg(
"textAttributes('%s',%u,%s,%s,%s)", font, pixel_size,
658 SendMsg(
"openImage('%s')", image);
659 SendMsg(
"drawImage('%s',%d,%d)",
665 int cmdEvent,
bool flag) {
666 if (parent ==
nullptr) { parent =
""; }
667 if (flag) {
SendMsg(
"addMenuBarItem('%s','%s',%d,true)",
668 parent, name, cmdEvent);
669 }
else {
SendMsg(
"addMenuBarItem('%s','%s',%d,false)",
670 parent, name, cmdEvent); }
675 if (parent ==
nullptr) { parent =
""; }
676 SendMsg(
"addMenuBarItem('%s','%s',%d)", parent, name, cmdEvent);
681 if (parent ==
nullptr) { parent =
""; }
682 SendMsg(
"addMenuBarItem('%s','%s')", parent, name);
687 if (parent ==
nullptr) { parent =
""; }
688 SendMsg(
"addPopupMenuItem('%s','%s')", parent, name);
693 int cmdEvent,
const char* value,
const char* desc) {
694 if (parent ==
nullptr) { parent =
""; }
695 char* esc = AddEscapeChars(value);
696 char* esc2 = AddEscapeChars(desc);
697 SendMsg(
"addPopupMenuItem('%s','%s',%d,'%s','%s')", parent, name,
698 cmdEvent, esc, esc2);
711 for (
auto & iter : svmap) {
712 if (iter.second !=
nullptr)
713 iter.second->UpdateWindow();
720 Pen(table_colors[color][0], table_colors[color][1],
721 table_colors[color][2], table_colors[color][3]);
726 Brush(table_colors[color][0],
727 table_colors[color][1],
728 table_colors[color][2],
729 table_colors[color][3]);
734 SendMsg(
"showInputDialog(\"%s\")", msg);
738 char* p =
new char[strlen(ev->
parameter) + 1];
746 SendMsg(
"showYesNoDialog(\"%s\")", msg);
760 SendMsg(
"zoomRectangle(%d,%d,%d,%d)",
761 std::min(x1, x2), std::min(y1, y2), std::max(x1, x2), std::max(y1, y2));
768 pixWriteMem(&data, &size, image, IFF_PNG);
769 int base64_len = (size + 2) / 3 * 4;
771 SendMsg(
"readImage(%d,%d,%d)", x_pos, y_pos, base64_len);
773 const char kBase64Table[64] = {
774 'A',
'B',
'C',
'D',
'E',
'F',
'G',
'H',
775 'I',
'J',
'K',
'L',
'M',
'N',
'O',
'P',
776 'Q',
'R',
'S',
'T',
'U',
'V',
'W',
'X',
777 'Y',
'Z',
'a',
'b',
'c',
'd',
'e',
'f',
778 'g',
'h',
'i',
'j',
'k',
'l',
'm',
'n',
779 'o',
'p',
'q',
'r',
's',
't',
'u',
'v',
780 'w',
'x',
'y',
'z',
'0',
'1',
'2',
'3',
781 '4',
'5',
'6',
'7',
'8',
'9',
'+',
'/',
783 char* base64 =
new char[base64_len + 1];
784 memset(base64,
'=', base64_len);
785 base64[base64_len] =
'\0';
789 for (
size_t i = 0; i < size; ++i) {
790 int code = (data[i] >> (bits_left + 2)) | remainder;
791 base64[code_len++] = kBase64Table[code & 63];
793 remainder = data[i] << (6 - bits_left);
794 if (bits_left == 6) {
795 base64[code_len++] = kBase64Table[remainder & 63];
801 base64[code_len++] = kBase64Table[remainder & 63];
809 char* ScrollView::AddEscapeChars(
const char* input) {
810 const char* nextptr = strchr(input,
'\'');
811 const char* lastptr = input;
814 while (nextptr !=
nullptr) {
815 strncpy(message+pos, lastptr, nextptr-lastptr);
816 pos += nextptr - lastptr;
820 nextptr = strchr(nextptr+1,
'\'');
822 strcpy(message+pos, lastptr);
828 if (!y_axis_is_reversed_) {
return y;
829 }
else {
return y_size_ - y; }
const int kMaxIntPairSize
std::vector< int > xcoords
std::vector< int > ycoords
virtual void Notify(const SVEvent *sve)
virtual ~SVEventHandler()
ScrollView(const char *name, int x_pos, int y_pos, int x_size, int y_size, int x_canvas_size, int y_canvas_size)
Calls Initialize with default argument for server_name_ & y_axis_reversed.
void MenuItem(const char *parent, const char *name)
SVEvent * AwaitEvent(SVEventType type)
void DrawTo(int x, int y)
void PopupItem(const char *parent, const char *name)
void Line(int x1, int y1, int x2, int y2)
void Ellipse(int x, int y, int width, int height)
void TextAttributes(const char *font, int pixel_size, bool bold, bool italic, bool underlined)
void Image(struct Pix *image, int x_pos, int y_pos)
SVEvent * AwaitEventAnyWindow()
void Text(int x, int y, const char *mystring)
void AddEventHandler(SVEventHandler *listener)
Add an Event Listener to this ScrollView Window.
void ZoomToRectangle(int x1, int y1, int x2, int y2)
void SendMsg(const char *msg,...)
Send a message to the server, attaching the window id.
static void SendRawMessage(const char *msg)
void SetCursor(int x, int y)
int TranslateYCoordinate(int y)
void SetVisible(bool visible)
int ShowYesNoDialog(const char *msg)
void Rectangle(int x1, int y1, int x2, int y2)
char * ShowInputDialog(const char *msg)
void AddMessage(const char *format,...)
static void StartThread(void *(*func)(void *), void *arg)
Create new thread.
void Wait()
Wait on a semaphore.
void Signal()
Signal a semaphore.
void Unlock()
Unlocks on a mutex.
void Lock()
Locks on a mutex.
void Send(const char *msg)
Put a message in the messagebuffer to the server and try to send it.
void Flush()
Flush the buffer.