22# include "config_auto.h"
29#include <allheaders.h>
56static std::map<int, ScrollView *> svmap;
57static std::mutex *svmap_mu;
59static std::map<std::pair<ScrollView *, SVEventType>,
60 std::pair<SVSemaphore *, std::unique_ptr<SVEvent>>> waiting_for_events;
61static std::mutex *waiting_for_events_mu;
64 auto any = std::unique_ptr<SVEvent>(
new SVEvent);
67 any->parameter =
new char[strlen(
parameter) + 1];
83#ifndef GRAPHICS_DISABLED
88void ScrollView::MessageReceiver() {
89 int counter_event_id = 0;
93 message = ScrollView::GetStream()->Receive();
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);
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 = std::move(cur);
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 = std::move(cur);
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 = std::move(cur);
168 waiting_for_events[awaiting_list_any_window].first->Signal();
170 waiting_for_events_mu->unlock();
182 message = ScrollView::GetStream()->Receive();
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();
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() {
331 if (event_table_[
i] !=
nullptr && (serial < 0 || event_table_[
i]->counter < serial)) {
332 serial = event_table_[
i]->counter;
338 auto new_event = std::move(event_table_[k]);
340 if (event_handler_ !=
nullptr) {
341 event_handler_->
Notify(new_event.get());
345 event_handler_ended_ =
true;
357#ifndef GRAPHICS_DISABLED
359 if (svmap[window_id_] !=
nullptr) {
366 svmap[window_id_] =
nullptr;
371 while (!event_handler_ended_) {
382#ifndef GRAPHICS_DISABLED
385 if (!points_->
empty) {
391 va_start(args, format);
396 snprintf(form,
sizeof(form),
"w%u:%s\n", window_id_,
message);
409 event_handler_ = listener;
412void ScrollView::Signal() {
416void ScrollView::SetEvent(
const SVEvent *svevent) {
418 auto any = svevent->copy();
419 auto specific = svevent->copy();
420 any->counter = specific->counter + 1;
423 std::lock_guard<std::mutex> guard(mutex_);
425 event_table_[specific->type] = std::move(specific);
426 event_table_[
SVET_ANY] = std::move(any);
435 std::pair<ScrollView *, SVEventType> ea(
this,
type);
436 waiting_for_events_mu->lock();
437 waiting_for_events[ea] = {sem,
nullptr};
438 waiting_for_events_mu->unlock();
443 waiting_for_events_mu->lock();
444 auto ret = std::move(waiting_for_events[ea].second);
445 waiting_for_events.erase(ea);
447 waiting_for_events_mu->unlock();
452void ScrollView::SendPolygon() {
453 if (!points_->
empty) {
454 points_->
empty =
true;
455 int length = points_->
xcoords.size();
462 }
else if (length > 2) {
464 SendMsg(
"createPolyline(%d)", length);
466 std::string decimal_coords;
467 for (
int i = 0;
i < length; ++
i) {
469 decimal_coords += coordpair;
471 decimal_coords +=
'\n';
494 points_->
empty =
false;
503 }
else if (!points_->
xcoords.empty() && x2 == points_->
xcoords.back() &&
526 SendMsg(
"setAlwaysOnTop(true)");
528 SendMsg(
"setAlwaysOnTop(false)");
535 snprintf(form,
sizeof(form),
"w%u:%s", window_id_,
message);
537 char *esc = AddEscapeChars(form);
538 SendMsg(
"addMessage(\"%s\")", esc);
546 va_start(args, format);
571 SendMsg(
"setStrokeWidth(%f)", width);
577 if (x1 == x2 && y1 == y2) {
591 SendMsg(
"pen(%d,%d,%d)", red, green, blue);
596 SendMsg(
"pen(%d,%d,%d,%d)", red, green, blue, alpha);
601 SendMsg(
"brush(%d,%d,%d)", red, green, blue);
606 SendMsg(
"brush(%d,%d,%d,%d)", red, green, blue, alpha);
631 SendMsg(
"textAttributes('%s',%u,%s,%s,%s)", font, pixel_size, b,
i, u);
641 SendMsg(
"openImage('%s')", image);
647 if (parent ==
nullptr) {
651 SendMsg(
"addMenuBarItem('%s','%s',%d,true)", parent, name, cmdEvent);
653 SendMsg(
"addMenuBarItem('%s','%s',%d,false)", parent, name, cmdEvent);
659 if (parent ==
nullptr) {
662 SendMsg(
"addMenuBarItem('%s','%s',%d)", parent, name, cmdEvent);
667 if (parent ==
nullptr) {
670 SendMsg(
"addMenuBarItem('%s','%s')", parent, name);
675 if (parent ==
nullptr) {
678 SendMsg(
"addPopupMenuItem('%s','%s')", parent, name);
684 if (parent ==
nullptr) {
687 char *esc = AddEscapeChars(
value);
688 char *esc2 = AddEscapeChars(desc);
689 SendMsg(
"addPopupMenuItem('%s','%s',%d,'%s','%s')", parent, name, cmdEvent, esc, esc2);
701 std::lock_guard<std::mutex> guard(*svmap_mu);
702 for (
auto &iter : svmap) {
703 if (iter.second !=
nullptr) {
704 iter.second->UpdateWindow();
711 Pen(table_colors[color][0], table_colors[color][1], table_colors[color][2],
712 table_colors[color][3]);
717 Brush(table_colors[color][0], table_colors[color][1], table_colors[color][2],
718 table_colors[color][3]);
723 SendMsg(
"showInputDialog(\"%s\")", msg);
726 char *
p =
new char[strlen(ev->parameter) + 1];
727 strcpy(
p, ev->parameter);
733 SendMsg(
"showYesNoDialog(\"%s\")", msg);
736 int a = ev->parameter[0];
745 SendMsg(
"zoomRectangle(%d,%d,%d,%d)", std::min(x1, x2), std::min(y1, y2), std::max(x1, x2),
753 pixWriteMem(&data, &size, image, IFF_PNG);
754 int base64_len = (size + 2) / 3 * 4;
756 SendMsg(
"readImage(%d,%d,%d)", x_pos, y_pos, base64_len);
758 const char kBase64Table[64] = {
759 'A',
'B',
'C',
'D',
'E',
'F',
'G',
'H',
'I',
'J',
'K',
'L',
'M',
'N',
'O',
'P',
760 'Q',
'R',
'S',
'T',
'U',
'V',
'W',
'X',
'Y',
'Z',
'a',
'b',
'c',
'd',
'e',
'f',
761 'g',
'h',
'i',
'j',
'k',
'l',
'm',
'n',
'o',
'p',
'q',
'r',
's',
't',
'u',
'v',
762 'w',
'x',
'y',
'z',
'0',
'1',
'2',
'3',
'4',
'5',
'6',
'7',
'8',
'9',
'+',
'/',
764 char *base64 =
new char[base64_len + 1];
765 memset(base64,
'=', base64_len);
766 base64[base64_len] =
'\0';
770 for (
size_t i = 0;
i < size; ++
i) {
771 int code = (data[
i] >> (bits_left + 2)) | remainder;
772 base64[code_len++] = kBase64Table[code & 63];
774 remainder = data[
i] << (6 - bits_left);
775 if (bits_left == 6) {
776 base64[code_len++] = kBase64Table[remainder & 63];
782 base64[code_len++] = kBase64Table[remainder & 63];
791char *ScrollView::AddEscapeChars(
const char *input) {
792 const char *nextptr = strchr(input,
'\'');
793 const char *lastptr = input;
796 while (nextptr !=
nullptr) {
797 strncpy(
message + pos, lastptr, nextptr - lastptr);
798 pos += nextptr - lastptr;
802 nextptr = strchr(nextptr + 1,
'\'');
804 strcpy(
message + pos, lastptr);
810 if (!y_axis_is_reversed_) {
825 ret = ev->parameter[0];
const int kMaxIntPairSize
std::vector< int > xcoords
std::vector< int > ycoords
std::unique_ptr< SVEvent > copy() const
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)
std::unique_ptr< SVEvent > AwaitEvent(SVEventType type)
void TextAttributes(const char *font, int pixel_size, bool bold, bool italic, bool underlined)
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)
int ShowYesNoDialog(const char *msg)
void AddMessageF(const char *format,...) __attribute__((format(gnu_printf
void SendMsg(const char *msg,...) __attribute__((format(gnu_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.