29#include <allheaders.h>
56static std::map<int, ScrollView *> svmap;
57static std::mutex *svmap_mu;
59static std::map<std::pair<ScrollView *, SVEventType>, std::pair<SVSemaphore *, SVEvent *>>
61static std::mutex *waiting_for_events_mu;
67 any->parameter =
new char[strlen(
parameter) + 1];
83#ifndef GRAPHICS_DISABLED
88void ScrollView::MessageReceiver() {
89 int counter_event_id = 0;
90 char *message =
nullptr;
93 message = ScrollView::GetStream()->Receive();
94 }
while (message ==
nullptr);
101 std::unique_ptr<SVEvent> cur(
new SVEvent);
109 sscanf(message,
"%d,%d,%d,%d,%d,%d,%d,%n", &window_id, &ev_type, &cur->x, &cur->y, &cur->x_size,
110 &cur->y_size, &cur->command_id, &n);
111 char *p = (message + n);
114 cur->window = svmap[window_id];
116 if (cur->window !=
nullptr) {
117 auto length = strlen(p);
118 cur->parameter =
new char[length + 1];
119 strcpy(cur->parameter, p);
121 cur->parameter[length - 1] =
'\0';
125 if (cur->x_size > 0) {
126 cur->x -= cur->x_size;
128 cur->x_size = -cur->x_size;
130 if (cur->y_size > 0) {
131 cur->y -= cur->y_size;
133 cur->y_size = -cur->y_size;
136 if (cur->window->y_axis_is_reversed_) {
137 cur->y = cur->window->TranslateYCoordinate(cur->y + cur->y_size);
139 cur->counter = counter_event_id;
143 counter_event_id += 2;
152 cur->window->SetEvent(cur.get());
155 std::pair<ScrollView *, SVEventType> awaiting_list(cur->window, cur->type);
156 std::pair<ScrollView *, SVEventType> awaiting_list_any(cur->window,
SVET_ANY);
157 std::pair<ScrollView *, SVEventType> awaiting_list_any_window((ScrollView *)
nullptr,
159 waiting_for_events_mu->lock();
160 if (waiting_for_events.count(awaiting_list) > 0) {
161 waiting_for_events[awaiting_list].second = cur.get();
162 waiting_for_events[awaiting_list].first->Signal();
163 }
else if (waiting_for_events.count(awaiting_list_any) > 0) {
164 waiting_for_events[awaiting_list_any].second = cur.get();
165 waiting_for_events[awaiting_list_any].first->Signal();
166 }
else if (waiting_for_events.count(awaiting_list_any_window) > 0) {
167 waiting_for_events[awaiting_list_any_window].second = cur.get();
168 waiting_for_events[awaiting_list_any_window].first->Signal();
170 waiting_for_events_mu->unlock();
182 message = ScrollView::GetStream()->Receive();
183 }
while (message ==
nullptr);
191 {255, 255, 255, 255},
200 {128, 128, 255, 255},
204 {192, 192, 255, 255},
207 {255, 128, 128, 255},
211 {192, 192, 128, 255},
216 {192, 255, 192, 255},
218 {192, 192, 192, 255},
221 {128, 128, 128, 255},
226 {255, 192, 192, 255},
231 {255, 192, 128, 255},
244SVNetwork *ScrollView::stream_ =
nullptr;
245int ScrollView::nr_created_windows_ = 0;
246int ScrollView::image_index_ = 0;
250 int x_canvas_size,
int y_canvas_size,
bool y_axis_reversed,
251 const char *server_name) {
252 Initialize(name, x_pos, y_pos, x_size, y_size, x_canvas_size, y_canvas_size, y_axis_reversed,
258 int x_canvas_size,
int y_canvas_size,
bool y_axis_reversed) {
259 Initialize(name, x_pos, y_pos, x_size, y_size, x_canvas_size, y_canvas_size, y_axis_reversed,
265 int x_canvas_size,
int y_canvas_size) {
266 Initialize(name, x_pos, y_pos, x_size, y_size, x_canvas_size, y_canvas_size,
false,
"localhost");
270void ScrollView::Initialize(
const char *name,
int x_pos,
int y_pos,
int x_size,
int y_size,
271 int x_canvas_size,
int y_canvas_size,
bool y_axis_reversed,
272 const char *server_name) {
275 if (stream_ ==
nullptr) {
276 nr_created_windows_ = 0;
278 waiting_for_events_mu =
new std::mutex();
279 svmap_mu =
new std::mutex();
280 SendRawMessage(
"svmain = luajava.bindClass('com.google.scrollview.ScrollView')\n");
281 std::thread t(&ScrollView::MessageReceiver);
286 nr_created_windows_++;
287 event_handler_ =
nullptr;
288 event_handler_ended_ =
false;
289 y_axis_is_reversed_ = y_axis_reversed;
290 y_size_ = y_canvas_size;
292 window_id_ = nr_created_windows_;
294 points_ =
new SVPolyLineBuffer;
295 points_->
empty =
true;
298 svmap[window_id_] =
this;
301 for (
auto &i : event_table_) {
305 semaphore_ =
new SVSemaphore();
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_, x_pos, y_pos, x_size, y_size, x_canvas_size,
316 std::thread t(&ScrollView::StartEventHandler,
this);
321void ScrollView::StartEventHandler() {
334 if (event_table_[i] !=
nullptr && (serial < 0 || event_table_[i]->counter < serial)) {
335 new_event = event_table_[i];
336 serial = event_table_[i]->counter;
341 if (new_event !=
nullptr) {
342 event_table_[k] =
nullptr;
344 if (event_handler_ !=
nullptr) {
345 event_handler_->
Notify(new_event);
349 event_handler_ended_ =
true;
363#ifndef GRAPHICS_DISABLED
365 if (svmap[window_id_] !=
nullptr) {
373 svmap[window_id_] =
nullptr;
378 while (!event_handler_ended_) {
386 for (
auto &i : event_table_) {
392#ifndef GRAPHICS_DISABLED
395 if (!points_->
empty) {
401 va_start(args, format);
402 vsnprintf(message,
sizeof(message), format, args);
406 snprintf(form,
sizeof(form),
"w%u:%s\n", window_id_, message);
419 event_handler_ = listener;
422void ScrollView::Signal() {
426void ScrollView::SetEvent(
const SVEvent *svevent) {
428 SVEvent *any = svevent->copy();
429 SVEvent *specific = svevent->copy();
430 any->counter = specific->counter + 1;
433 std::lock_guard<std::mutex> guard(mutex_);
435 delete event_table_[specific->type];
438 event_table_[specific->type] = specific;
448 std::pair<ScrollView *, SVEventType> ea(
this, type);
449 waiting_for_events_mu->lock();
450 waiting_for_events[ea] = std::pair<SVSemaphore *, SVEvent *>(sem, (
SVEvent *)
nullptr);
451 waiting_for_events_mu->unlock();
456 waiting_for_events_mu->lock();
457 SVEvent *ret = waiting_for_events[ea].second;
458 waiting_for_events.erase(ea);
460 waiting_for_events_mu->unlock();
465void ScrollView::SendPolygon() {
466 if (!points_->
empty) {
467 points_->
empty =
true;
468 int length = points_->
xcoords.size();
475 }
else if (length > 2) {
477 SendMsg(
"createPolyline(%d)", length);
479 std::string decimal_coords;
480 for (
int i = 0; i < length; ++i) {
482 decimal_coords += coordpair;
484 decimal_coords +=
'\n';
507 points_->
empty =
false;
516 }
else if (!points_->
xcoords.empty() && x2 == points_->
xcoords.back() &&
539 SendMsg(
"setAlwaysOnTop(true)");
541 SendMsg(
"setAlwaysOnTop(false)");
548 snprintf(form,
sizeof(form),
"w%u:%s", window_id_, message);
550 char *esc = AddEscapeChars(form);
551 SendMsg(
"addMessage(\"%s\")", esc);
559 va_start(args, format);
560 vsnprintf(message,
sizeof(message), format, args);
584 SendMsg(
"setStrokeWidth(%f)", width);
590 if (x1 == x2 && y1 == y2) {
604 SendMsg(
"pen(%d,%d,%d)", red, green, blue);
609 SendMsg(
"pen(%d,%d,%d,%d)", red, green, blue, alpha);
614 SendMsg(
"brush(%d,%d,%d)", red, green, blue);
619 SendMsg(
"brush(%d,%d,%d,%d)", red, green, blue, alpha);
644 SendMsg(
"textAttributes('%s',%u,%s,%s,%s)", font, pixel_size, b, i, u);
654 SendMsg(
"openImage('%s')", image);
660 if (parent ==
nullptr) {
664 SendMsg(
"addMenuBarItem('%s','%s',%d,true)", parent, name, cmdEvent);
666 SendMsg(
"addMenuBarItem('%s','%s',%d,false)", parent, name, cmdEvent);
672 if (parent ==
nullptr) {
675 SendMsg(
"addMenuBarItem('%s','%s',%d)", parent, name, cmdEvent);
680 if (parent ==
nullptr) {
683 SendMsg(
"addMenuBarItem('%s','%s')", parent, name);
688 if (parent ==
nullptr) {
691 SendMsg(
"addPopupMenuItem('%s','%s')", parent, name);
697 if (parent ==
nullptr) {
700 char *esc = AddEscapeChars(value);
701 char *esc2 = AddEscapeChars(desc);
702 SendMsg(
"addPopupMenuItem('%s','%s',%d,'%s','%s')", parent, name, cmdEvent, esc, esc2);
714 std::lock_guard<std::mutex> guard(*svmap_mu);
715 for (
auto &iter : svmap) {
716 if (iter.second !=
nullptr) {
717 iter.second->UpdateWindow();
724 Pen(table_colors[color][0], table_colors[color][1], table_colors[color][2],
725 table_colors[color][3]);
730 Brush(table_colors[color][0], table_colors[color][1], table_colors[color][2],
731 table_colors[color][3]);
736 SendMsg(
"showInputDialog(\"%s\")", msg);
740 char *p =
new char[strlen(ev->
parameter) + 1];
748 SendMsg(
"showYesNoDialog(\"%s\")", msg);
762 SendMsg(
"zoomRectangle(%d,%d,%d,%d)", std::min(x1, x2), std::min(y1, y2), std::max(x1, x2),
770 pixWriteMem(&data, &size, image, IFF_PNG);
771 int base64_len = (size + 2) / 3 * 4;
773 SendMsg(
"readImage(%d,%d,%d)", x_pos, y_pos, base64_len);
775 const char kBase64Table[64] = {
776 'A',
'B',
'C',
'D',
'E',
'F',
'G',
'H',
'I',
'J',
'K',
'L',
'M',
'N',
'O',
'P',
777 'Q',
'R',
'S',
'T',
'U',
'V',
'W',
'X',
'Y',
'Z',
'a',
'b',
'c',
'd',
'e',
'f',
778 'g',
'h',
'i',
'j',
'k',
'l',
'm',
'n',
'o',
'p',
'q',
'r',
's',
't',
'u',
'v',
779 'w',
'x',
'y',
'z',
'0',
'1',
'2',
'3',
'4',
'5',
'6',
'7',
'8',
'9',
'+',
'/',
781 char *base64 =
new char[base64_len + 1];
782 memset(base64,
'=', base64_len);
783 base64[base64_len] =
'\0';
787 for (
size_t i = 0; i < size; ++i) {
788 int code = (data[i] >> (bits_left + 2)) | remainder;
789 base64[code_len++] = kBase64Table[code & 63];
791 remainder = data[i] << (6 - bits_left);
792 if (bits_left == 6) {
793 base64[code_len++] = kBase64Table[remainder & 63];
799 base64[code_len++] = kBase64Table[remainder & 63];
808char *ScrollView::AddEscapeChars(
const char *input) {
809 const char *nextptr = strchr(input,
'\'');
810 const char *lastptr = input;
813 while (nextptr !=
nullptr) {
814 strncpy(message + pos, lastptr, nextptr - lastptr);
815 pos += nextptr - lastptr;
819 nextptr = strchr(nextptr + 1,
'\'');
821 strcpy(message + pos, lastptr);
827 if (!y_axis_is_reversed_) {
842 ret = ev->parameter[0];
const int kMaxIntPairSize
std::vector< int > xcoords
std::vector< int > ycoords
virtual void Notify(const SVEvent *sve)
virtual ~SVEventHandler()
void Line(int x1, int y1, int x2, int y2)
char * ShowInputDialog(const char *msg)
void PopupItem(const char *parent, const char *name)
void AddMessage(const char *message)
void TextAttributes(const char *font, int pixel_size, bool bold, bool italic, bool underlined)
void AddMessageF(const char *format,...) __attribute__((format(printf
void static void SendRawMessage(const char *msg)
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 Text(int x, int y, const char *mystring)
void Draw(Image image, int x_pos, int y_pos)
void SetVisible(bool visible)
void void ZoomToRectangle(int x1, int y1, int x2, int y2)
void AddEventHandler(SVEventHandler *listener)
Add an Event Listener to this ScrollView Window.
void Rectangle(int x1, int y1, int x2, int y2)
void SetCursor(int x, int y)
void Ellipse(int x, int y, int width, int height)
int TranslateYCoordinate(int y)
void MenuItem(const char *parent, const char *name)
void DrawTo(int x, int y)
SVEvent * AwaitEvent(SVEventType type)
int ShowYesNoDialog(const char *msg)
void SendMsg(const char *msg,...) __attribute__((format(printf
Send a message to the server, attaching the window id.
void Signal()
Signal a semaphore.
void Wait()
Wait on a semaphore.
void Flush()
Flush the buffer.
void Send(const char *msg)
Put a message in the messagebuffer to the server and try to send it.