summaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
Diffstat (limited to 'test')
-rw-r--r--test/Makefile15
-rw-r--r--test/demo.cxx12
-rw-r--r--test/demo.menu6
-rw-r--r--test/dnd-test.cxx75
-rw-r--r--test/fonts.cxx27
-rw-r--r--test/mcast_launcher.cxx164
-rw-r--r--test/mcast_rx.cxx160
-rw-r--r--test/mcast_tx.cxx144
-rw-r--r--test/utf8.cxx624
9 files changed, 1212 insertions, 15 deletions
diff --git a/test/Makefile b/test/Makefile
index 6cf454542..2692ef1da 100644
--- a/test/Makefile
+++ b/test/Makefile
@@ -48,6 +48,7 @@ CPPFILES =\
cursor.cxx \
curve.cxx \
demo.cxx \
+ dnd-test.cxx \
doublebuffer.cxx \
editor.cxx \
fast_slow.cxx \
@@ -92,7 +93,11 @@ CPPFILES =\
threads.cxx \
tile.cxx \
tiled_image.cxx \
- valuators.cxx
+ valuators.cxx \
+ utf8.cxx \
+ mcast_launcher.cxx \
+ mcast_tx.cxx \
+ mcast_rx.cxx
ALL = \
unittests$(EXEEXT) \
@@ -112,6 +117,7 @@ ALL = \
cursor$(EXEEXT) \
curve$(EXEEXT) \
demo$(EXEEXT) \
+ dnd-test$(EXEEXT) \
doublebuffer$(EXEEXT) \
editor$(EXEEXT) \
fast_slow$(EXEEXT) \
@@ -151,7 +157,12 @@ ALL = \
$(THREADS) \
tile$(EXEEXT) \
tiled_image$(EXEEXT) \
- valuators$(EXEEXT)
+ valuators$(EXEEXT) \
+ utf8$(EXEEXT) \
+ mcast_launcher$(EXEEXT) \
+ mcast_tx$(EXEEXT) \
+ mcast_rx$(EXEEXT)
+
GLALL = \
cube$(EXEEXT) \
diff --git a/test/demo.cxx b/test/demo.cxx
index 5d03d547c..38a12525a 100644
--- a/test/demo.cxx
+++ b/test/demo.cxx
@@ -274,7 +274,17 @@ void dobut(Fl_Widget *, long arg)
delete[] command;
delete[] copy_of_icommand;
-
+
+#elif defined USING_XCODE
+
+ int icommand_length = strlen(menus[men].icommand[bn]);
+ char* command = new char[icommand_length+24]; // extraspace for 'open ../../(name).app &\0'
+
+ sprintf(command, "open ../../../%s.app &", menus[men].icommand[bn]);
+ system(command);
+
+ delete[] command;
+
#else // NON WIN32 systems.
int icommand_length = strlen(menus[men].icommand[bn]);
diff --git a/test/demo.menu b/test/demo.menu
index be4e8dbd7..f0b1e2628 100644
--- a/test/demo.menu
+++ b/test/demo.menu
@@ -50,6 +50,8 @@
@u:keyboard:keyboard
@u:fast && slow widgets:fast_slow
@u:inactive:inactive
+# @u:Drag Drop:dnd-test
+# @u:add_fd():mcast_launcher
@main:Fluid\n(UI design tool):../fluid/fluid valuators.fl
@@ -65,7 +67,9 @@
@main:Other\nTests:@o
@o:Color Choosers:color_chooser r
@o:File Chooser:file_chooser
- @o:Fonts:fonts
+ @o:Font Tests:@of
+ @of:Fonts:fonts
+ @of:UTF-8:utf8
@o:HelpDialog:help
@o:Input Choice:input_choice
@o:Preferences:preferences
diff --git a/test/dnd-test.cxx b/test/dnd-test.cxx
new file mode 100644
index 000000000..f19873300
--- /dev/null
+++ b/test/dnd-test.cxx
@@ -0,0 +1,75 @@
+/* Drag and Drop test demo. */
+#include <stdio.h>
+#include <FL/Fl.H>
+#include <FL/Fl_Window.H>
+#include <FL/Fl_Box.H>
+
+static Fl_Window *win_a;
+static Fl_Window *win_b;
+
+class Sender : public Fl_Box {
+public:
+ Sender(int x,int y,int w,int h) : Fl_Box(x,y,w,h) { }
+
+ int handle(int event) {
+ int ret = Fl_Box::handle(event);
+ switch ( event ) {
+ case FL_PUSH:
+ Fl::copy("message",7,0);
+ Fl::dnd();
+ return(1);
+ }
+ return(ret);
+ }
+};
+
+class Receiver : public Fl_Box {
+public:
+ Receiver(int x,int y,int w,int h) : Fl_Box(x,y,w,h) { }
+
+ int handle(int event) {
+ int ret = Fl_Box::handle(event);
+ switch ( event ) {
+ case FL_DND_ENTER:
+ case FL_DND_DRAG:
+ case FL_DND_RELEASE:
+ return(1);
+ case FL_PASTE:
+ label(Fl::event_text());
+ fprintf(stderr, "PASTE: %s\n", Fl::event_text());
+ fflush(stderr);
+ return(1);
+ }
+ return(ret);
+ }
+};
+//
+// Demonstrate DND (drag+drop) from red sender to green receiver
+//
+
+static Sender *Tx;
+static Receiver *Rx;
+
+int main(int argc, char **argv) {
+ win_a = new Fl_Window(40, 40, 200,100);
+ win_a->begin();
+ Tx = new Sender(5,5,90,90);
+ Tx->box(FL_UP_BOX);
+ Tx->label("Drag from here");
+ Tx->align(FL_ALIGN_WRAP);
+ Tx->color(FL_RED);
+ win_a->end();
+ win_a->show(argc, argv);
+
+ win_b = new Fl_Window (350, 40, 200,100,"Receiver");
+ win_b->begin();
+ Rx = new Receiver(105,5,90,90);
+ Rx->box(FL_FLAT_BOX);
+ Rx->label("to here");
+ Rx->color(FL_GREEN);
+ win_b->end();
+ win_b->show();
+
+ return Fl::run();
+}
+/* End of File */
diff --git a/test/fonts.cxx b/test/fonts.cxx
index 0e6a6e1e7..2c38b3e6d 100644
--- a/test/fonts.cxx
+++ b/test/fonts.cxx
@@ -26,7 +26,7 @@
//
#include <FL/Fl.H>
-#include <FL/Fl_Window.H>
+#include <FL/Fl_Double_Window.H>
#include <FL/Fl_Hold_Browser.H>
#include <FL/fl_draw.H>
#include <FL/Fl_Box.H>
@@ -34,7 +34,7 @@
#include <stdlib.h>
#include <string.h>
-Fl_Window *form;
+Fl_Double_Window *form;
class FontDisplay : public Fl_Widget {
void draw();
@@ -102,21 +102,23 @@ void size_cb(Fl_Widget *, long) {
textobj->redraw();
}
-char label[400];
+char label[0x1000];
void create_the_forms() {
- form = new Fl_Window(550,370);
+ int n = 0;
+ form = new Fl_Double_Window(550,370);
strcpy(label, "Hello, world!\n");
int i = strlen(label);
- uchar c;
+ ulong c;
for (c = ' '+1; c < 127; c++) {
- if (!(c&0x1f)) label[i++]='\n';
+ if (!(c&0x1f)) label[i++]='\n';
if (c=='@') label[i++]=c;
label[i++]=c;
}
label[i++] = '\n';
- for (c = 0xA1; c; c++) {if (!(c&0x1f)) label[i++]='\n'; label[i++]=c;}
+ for (c = 0xA1; c < 0x600; c += 9) {if (!(++n&(0x1f))) label[i++]='\n';
+ i += fl_utf8encode((unsigned int)c, label + i);}
label[i] = 0;
textobj = new FontDisplay(FL_FRAME_BOX,10,10,530,170,label);
@@ -141,11 +143,13 @@ int main(int argc, char **argv) {
Fl::args(argc, argv);
Fl::get_system_colors();
create_the_forms();
-#ifdef __APPLE__
+
+// For the Unicode test, get all fonts...
+//#ifdef __APPLE__
int i = 0;
-#else
- int i = fl_choice("Which fonts:","-*","iso8859","All");
-#endif
+//#else
+// int i = fl_choice("Which fonts:","-*","iso8859","All");
+//#endif
int k = Fl::set_fonts(i ? (i>1 ? "*" : 0) : "-*");
sizes = new int*[k];
numsizes = new int[k];
@@ -157,6 +161,7 @@ int main(int argc, char **argv) {
char *p = buffer;
if (t & FL_BOLD) {*p++ = '@'; *p++ = 'b';}
if (t & FL_ITALIC) {*p++ = '@'; *p++ = 'i';}
+ *p++ = '@'; *p++ = '.'; // Suppress subsequent formatting - some MS fonts have '@' in their name
strcpy(p,name);
name = buffer;
}
diff --git a/test/mcast_launcher.cxx b/test/mcast_launcher.cxx
new file mode 100644
index 000000000..f2601262e
--- /dev/null
+++ b/test/mcast_launcher.cxx
@@ -0,0 +1,164 @@
+/* This is just a simple wrapper app that launches two independent processes then exits...
+ * I use it because the fltk test/demo program launches one process per button, and I wanted
+ * to launch several in my multicast/Fl::add_fd() test harness.
+ *
+ * This code also shows how to find the "home" directory for any executable in a cross-platform
+ * way, which can be handy for finding resources or help files.
+ */
+#ifdef WIN32
+#include <windows.h> /* GetModuleFileName */
+#endif /* WIN32 */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#ifdef __APPLE__ /* assume this is OSX */
+#include <sys/param.h>
+#include <mach-o/dyld.h> /* _NSGetExecutablePath : must add -framework CoreFoundation to link line */
+#include <string.h>
+# ifndef PATH_MAX
+# define PATH_MAX MAXPATHLEN
+# endif
+#endif /* APPLE */
+
+#ifndef PATH_MAX
+# define PATH_MAX 2048
+#endif
+/*******************************************************************************************/
+static int get_app_path (char *pname, size_t pathsize)
+{
+ long result;
+
+#if defined (WIN32)
+ result = GetModuleFileName(NULL, pname, pathsize);
+ if (result > 0) {
+ /* fix up the dir slashes... */
+ int len = strlen(pname);
+ int idx;
+ for (idx = 0; idx < len; idx++) {
+ if (pname[idx] == '\\') pname[idx] = '/';
+ }
+ if ((access(pname, 0) == 0)) {
+ return 0; /* file exists, return OK */
+ }
+ /*else name doesn't seem to exist, return FAIL (falls through) */
+ }
+
+#elif defined (SOLARIS) // we used to set this for our all our Sun builds - I wonder what Sun set...?
+ char *p = getexecname();
+ if (p) {
+ /* According to the Sun manpages, getexecname will "normally" return an */
+ /* absolute path - BUT might not... AND that IF it is not, pre-pending */
+ /* getcwd() will "usually" be the correct thing... Urgh! */
+
+ /* check pathname is absolute (begins with a / ) */
+ if (p[0] == '/') { /* assume this means we have an absolute path */
+ strncpy(pname, p, pathsize);
+ if ((access(pname, 0) == 0))
+ return 0; /* file exists, return OK */
+ } else { /* if not, prepend getcwd() then check if file exists */
+ getcwd(pname, pathsize);
+ result = strlen(pname);
+ strncat(pname, "/", (pathsize - result));
+ result ++;
+ strncat(pname, p, (pathsize - result));
+
+ if ((access(pname, 0) == 0))
+ return 0; /* file exists, return OK */
+ /*else name doesn't seem to exist, return FAIL (falls through) */
+ }
+ }
+
+#elif defined (__APPLE__) /* assume this is OSX */
+/* extern int _NSGetExecutablePath(char *buf, unsigned long *bufsize);
+
+ _NSGetExecutablePath copies the path of the executable
+ into the buffer and returns 0 if the path was successfully
+ copied in the provided buffer. If the buffer is not large
+ enough, -1 is returned and the expected buffer size is
+ copied in *bufsize. Note that _NSGetExecutablePath will
+ return "a path" to the executable not a "real path" to the
+ executable. That is the path may be a symbolic link and
+ not the real file. And with deep directories the total
+ bufsize needed could be more than MAXPATHLEN.
+*/
+ int status = -1;
+ char *given_path = (char *)malloc(MAXPATHLEN * 2);
+ if (!given_path) return status;
+
+ pathsize = MAXPATHLEN * 2;
+ result = _NSGetExecutablePath(given_path, (uint32_t *)&pathsize);
+ if (result == 0) { /* OK, we got something - now try and resolve the real path... */
+ if (realpath(given_path, pname) != NULL) {
+ if ((access(pname, 0) == 0)) {
+ status = 0; /* file exists, return OK */
+ }
+ }
+ }
+ free (given_path);
+ return status;
+
+#else // just assume this is linux for now - not valid - what about BSD's etc...?
+ /* Oddly, the readlink(2) man page says no NULL is appended. */
+ /* So you have to do it yourself, based on the return value: */
+ pathsize --; /* Preserve a space to add the trailing NULL */
+ result = readlink("/proc/self/exe", pname, pathsize);
+
+ if (result > 0) {
+ pname[result] = 0; /* add a terminating NULL */
+
+ if ((access(pname, 0) == 0)) {
+ return 0; /* file exists, return OK */
+ }
+ /*else name doesn't seem to exist, return FAIL (falls through) */
+ }
+#endif /* LINUX (assumed!) */
+
+ return -1; /* Path Lookup Failed */
+} // get_app_path
+
+/*******************************************************************************************/
+static void app_launch(const char *cmd)
+{
+#ifdef WIN32
+ // Under win32 you can't just use "system" and background the process to easily launch
+ // another executable - so we use spawn instead...
+ _spawnl(_P_NOWAIT, cmd, cmd, NULL);
+#else
+ // On other systems, just use system to launch the executable
+ char buf[PATH_MAX];
+ snprintf(buf, PATH_MAX, "%s &", cmd);
+ system(buf);
+#endif
+} // app_launch
+
+/*******************************************************************************************/
+int main(int argc, char *argv[])
+{
+ char launcher_path[PATH_MAX];
+ char exe_path[PATH_MAX];
+ // Find where the launcher app lives - we assume the test executables are in the same location
+ int fail = get_app_path (launcher_path, PATH_MAX);
+ if (fail) // couldn't get a valid path...
+ return -1;
+
+ // not all supported platfoms provide a dirname function - do a simplified version here
+ strncpy(exe_path, launcher_path, PATH_MAX);
+ // find the last dir sep (note that get_app_path uses '/' on win32 also)
+ char *dirp = strrchr(exe_path, '/');
+ dirp ++; // first char after the dir slash
+ *dirp = 0; // terminate the path, removing the executables basename
+
+ strncat(exe_path, "mcast_tx", PATH_MAX);
+ app_launch(exe_path); // launch the sender
+
+ *dirp = 0; // terminate the path - again
+ strncat(exe_path, "mcast_rx", PATH_MAX);
+ app_launch(exe_path); // launch the receiver
+
+ return 0;
+}
+
+/* end of file */
diff --git a/test/mcast_rx.cxx b/test/mcast_rx.cxx
new file mode 100644
index 000000000..d346d845a
--- /dev/null
+++ b/test/mcast_rx.cxx
@@ -0,0 +1,160 @@
+/* Test multicast operation and Fl::add_fd functionality */
+/* This file is the multicast Receiver - there can be multiple instances
+ * of this running during the test. A minimum of one is good...! */
+
+#ifdef WIN32
+# include <windows.h>
+# include <winsock2.h>
+# include <ws2tcpip.h>
+# define CLOSESKT closesocket
+#else
+# include <sys/socket.h>
+# include <netinet/in.h>
+# include <arpa/inet.h>
+# include <netdb.h>
+# define CLOSESKT close
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/types.h>
+
+#include <FL/Fl.H>
+#include <FL/Fl_Double_Window.H>
+#include <FL/Fl_Browser.H>
+#include <FL/Fl_Button.H>
+#include <FL/Fl_Round_Button.H>
+
+// define an arbitrary multicast address with organisation-local scope
+static char madrs[] = "239.192.34.56";
+#define SERVER_PORT 5678
+#define MAX_MSG 100
+
+static Fl_Double_Window *rx_win;
+static Fl_Browser *rx_brws;
+static Fl_Button *exit_bt;
+static Fl_Round_Button *wait_bt;
+
+/*******************************************************************************************/
+static void cb_exit_bt(Fl_Button*, void*) {
+ rx_win->hide();
+}
+
+/*******************************************************************************************/
+static void led_flash(void*) {
+ static int led = 0;
+ led = led ^ 1;
+ wait_bt->value(led);
+ Fl::repeat_timeout(0.4, led_flash);
+}
+
+/*******************************************************************************************/
+static void skt_cb(int skt, void*) {
+ struct sockaddr_in cliAddr;
+ char msg[MAX_MSG];
+ socklen_t cliLen = sizeof (cliAddr);
+ int n = recvfrom (skt, msg, MAX_MSG, 0, (struct sockaddr *)&cliAddr, &cliLen);
+ if (n < 0) return;
+ rx_brws->add(msg);
+ int last = rx_brws->size();
+ rx_brws->bottomline(last);
+}
+
+/*******************************************************************************************/
+int main (int argc, char *argv[])
+{
+ // First, create the socket layer
+ int skt, res;
+ struct ip_mreq mreq;
+ struct sockaddr_in servAddr;
+ struct in_addr mcastAddr;
+ struct hostent *h;
+
+#ifdef WIN32
+ // On win32, make sure the winsock layer is started
+ WSADATA WSAData;
+ WSAStartup (MAKEWORD (1, 1), &WSAData);
+#endif
+
+ /* set mcast address to listen to */
+ h = gethostbyname(madrs);
+ if (h == NULL) {
+ exit (-1);
+ }
+
+ memcpy(&mcastAddr, h->h_addr_list[0], h->h_length);
+
+ /* create the socket */
+ skt = socket (AF_INET, SOCK_DGRAM, 0);
+ if (skt < 0) {
+ fprintf (stderr, "cannot create socket\n");
+ exit (-1);
+ }
+
+ /* set socket to allow re-use of local address before bind() - this should allow us to have
+ * multiple receiver instances all running at once. */
+ int bReUse = 1;
+ setsockopt(skt, SOL_SOCKET, SO_REUSEADDR, (char *)&bReUse, sizeof(bReUse));
+
+ // Populate the servAddr struct
+ servAddr.sin_family = AF_INET;
+ servAddr.sin_addr.s_addr = htonl (INADDR_ANY);
+ servAddr.sin_port = htons (SERVER_PORT);
+
+ /* bind port */
+ if (bind (skt, (struct sockaddr *) &servAddr, sizeof (servAddr)) < 0) {
+ fprintf(stderr, "cannot bind port %d \n", SERVER_PORT);
+ exit (-1);
+ }
+
+ /* join multicast group */
+ mreq.imr_multiaddr.s_addr = mcastAddr.s_addr;
+ mreq.imr_interface.s_addr = htonl (INADDR_ANY);
+
+ res = setsockopt(skt, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *)&mreq, sizeof(mreq));
+ if (res != 0) {
+ fprintf(stderr, "cannot join multicast group '%s'", inet_ntoa(mcastAddr));
+ exit (-1);
+ }
+
+ // Now create the fltk display window
+ rx_win = new Fl_Double_Window(600, 100, 447, 338, "Receiver");
+ rx_win->begin();
+
+ // A browser to display the rx'd text in
+ rx_brws = new Fl_Browser(10, 10, 285, 310);
+ rx_brws->when(FL_WHEN_NEVER);
+
+ // quit button
+ exit_bt = new Fl_Button(360, 290, 64, 30, "Quit");
+ exit_bt->box(FL_THIN_UP_BOX);
+ exit_bt->callback((Fl_Callback*)cb_exit_bt);
+
+ // flashing red "waiting" led...
+ wait_bt = new Fl_Round_Button(320, 20, 69, 30, "Waiting");
+ wait_bt->selection_color(FL_RED);
+ wait_bt->when(FL_WHEN_NEVER);
+ wait_bt->clear_visible_focus();
+
+ rx_win->end();
+
+ // display the Rx window
+ rx_win->show(argc, argv);
+
+ // Start the "waiting led" flashing
+ Fl::add_timeout(0.4, led_flash);
+
+ // Add the socket to the add_fd check list
+ Fl::add_fd(skt, skt_cb);
+
+ // run the fltk core
+ res = Fl::run();
+
+ /* close socket and exit */
+ CLOSESKT(skt);
+ return res;
+}
+
+/* End of File */
diff --git a/test/mcast_tx.cxx b/test/mcast_tx.cxx
new file mode 100644
index 000000000..11bd5a7eb
--- /dev/null
+++ b/test/mcast_tx.cxx
@@ -0,0 +1,144 @@
+/* Test multicast operation and Fl::add_fd functionality */
+/* This file is the multicast Transmitter - there should be one instance
+ * of this running during the test. */
+
+#ifdef WIN32
+# include <winsock2.h>
+# include <ws2tcpip.h>
+# define CLOSESKT closesocket
+#else
+# include <sys/socket.h>
+# include <netinet/in.h>
+# include <arpa/inet.h>
+# include <netdb.h>
+# define CLOSESKT close
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/types.h>
+
+#include <FL/Fl.H>
+#include <FL/Fl_Double_Window.H>
+#include <FL/Fl_Button.H>
+#include <FL/Fl_Round_Button.H>
+
+// define an arbitrary multicast address with organisation-local scope
+static char madrs[] = "239.192.34.56";
+#define SERVER_PORT 5678
+
+static Fl_Double_Window *tx_win;
+static Fl_Button *send_bt;
+static Fl_Button *exit_bt;
+static Fl_Round_Button *ready_bt;
+
+static int skt;
+static struct sockaddr_in servAddr;
+
+/*******************************************************************************************/
+static void cb_exit_bt(Fl_Button*, void*) {
+ tx_win->hide();
+}
+
+/*******************************************************************************************/
+static void led_flash(void*) {
+ static int led = 0;
+ led = led ^ 1;
+ ready_bt->value(led);
+ Fl::repeat_timeout(0.4, led_flash);
+}
+
+/*******************************************************************************************/
+static void send_cb(Fl_Button*, void*) { /* send some data */
+ static int msg_idx = 0;
+ char msg[128];
+ for (int i = 0; i < 3; i++)
+ {
+ sprintf(msg, "Message text %d", msg_idx);
+ msg_idx++;
+ sendto(skt, msg, strlen(msg) + 1, 0, (struct sockaddr *)&servAddr, sizeof(servAddr));
+ } /* end for */
+}
+
+/*******************************************************************************************/
+int main (int argc, char *argv[])
+{
+ // First prepare the socket layer code
+ struct sockaddr_in cliAddr;
+ struct hostent *h;
+
+#ifdef WIN32
+ // On win32, make sure the winsock layer is started
+ WSADATA WSAData;
+ WSAStartup (MAKEWORD (1, 1), &WSAData);
+#endif
+
+ h = gethostbyname(madrs);
+ if (h == NULL) {
+ exit (-1);
+ }
+
+ // Populate the servAddr struct with the requested values
+ servAddr.sin_family = h->h_addrtype;
+ memcpy ((char *) &servAddr.sin_addr.s_addr, h->h_addr_list[0], h->h_length);
+ servAddr.sin_port = htons (SERVER_PORT);
+
+ /* create the socket */
+ skt = socket (AF_INET, SOCK_DGRAM, 0);
+ if (skt < 0) {
+ fprintf(stderr, "cannot open socket\n");
+ exit (-1);
+ }
+
+ /* bind port number */
+ cliAddr.sin_family = AF_INET;
+ cliAddr.sin_addr.s_addr = htonl(INADDR_ANY); // assume default eth_if is fine
+ cliAddr.sin_port = htons (0);
+ if (bind(skt, (struct sockaddr *)&cliAddr, sizeof(cliAddr)) < 0) {
+ fprintf(stderr, "cannot bind port %d \n", SERVER_PORT);
+ exit (-1);
+ }
+
+ /* set the IP TTL to 1, so our multicast datagrams can not get off the local network */
+ char ttl = 1;
+ setsockopt (skt, IPPROTO_IP, IP_MULTICAST_TTL, &ttl, sizeof(ttl));
+
+ // Now create the fltk window
+ tx_win = new Fl_Double_Window(100, 100, 447, 338, "Sender");
+ tx_win->begin();
+
+ // msg send button
+ send_bt = new Fl_Button(100, 100, 100, 50, "SEND");
+ send_bt->box(FL_THIN_UP_BOX);
+ send_bt->callback((Fl_Callback*)send_cb);
+
+ // quit button
+ exit_bt = new Fl_Button(360, 290, 64, 30, "Quit");
+ exit_bt->box(FL_THIN_UP_BOX);
+ exit_bt->callback((Fl_Callback*)cb_exit_bt);
+
+ // flashing green "ready" led...
+ ready_bt = new Fl_Round_Button(320, 20, 69, 30, "Ready");
+ ready_bt->selection_color(FL_GREEN);
+ ready_bt->when(FL_WHEN_NEVER);
+ ready_bt->clear_visible_focus();
+
+ tx_win->end();
+
+ // display the Tx window
+ tx_win->show(argc, argv);
+
+ // Start the "ready led" flashing
+ Fl::add_timeout(0.4, led_flash);
+
+ // run the fltk core
+ int res = Fl::run();
+
+ /* close socket and exit */
+ CLOSESKT(skt);
+ return res;
+}
+
+/* End of File */
diff --git a/test/utf8.cxx b/test/utf8.cxx
new file mode 100644
index 000000000..6047aba58
--- /dev/null
+++ b/test/utf8.cxx
@@ -0,0 +1,624 @@
+//
+//
+// UTF-8 test program for the Fast Light Tool Kit (FLTK).
+//
+// Copyright 1998-2003 by Bill Spitzak and others.
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Library General Public
+// License as published by the Free Software Foundation; either
+// version 2 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Library General Public License for more details.
+//
+// You should have received a copy of the GNU Library General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+// USA.
+//
+// Please report all bugs and problems to "fltk-bugs@fltk.org".
+//
+
+#include <FL/Fl.H>
+#include <FL/Fl_Window.H>
+#include <FL/Fl_Double_Window.H>
+#include <FL/Fl_Scroll.H>
+#include <FL/Fl_Choice.H>
+#include <FL/Fl_Input.H>
+#include <FL/Fl_Box.H>
+#include <FL/Fl_Hold_Browser.H>
+#include <FL/Fl_Value_Output.H>
+#include <FL/Fl_Button.H>
+#include <FL/Fl_Check_Button.H>
+#include <FL/Fl_Output.H>
+#include <FL/fl_draw.H>
+#include <FL/fl_utf8.H>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+
+//
+// Font chooser widget for the Fast Light Tool Kit(FLTK).
+//
+
+/********************************************************************************************/
+#define DEF_SIZE 16 // default value for the font size picker
+
+/********************************************************************************************/
+static Fl_Double_Window *fnt_chooser_win;
+static Fl_Hold_Browser *fontobj;
+static Fl_Hold_Browser *sizeobj;
+
+static Fl_Value_Output *fnt_cnt;
+static Fl_Button *refresh_btn;
+static Fl_Button *choose_btn;
+static Fl_Output *fix_prop;
+static Fl_Check_Button *own_face;
+
+static int **sizes = NULL;
+static int *numsizes = NULL;
+static int pickedsize = DEF_SIZE;
+static char label[1000];
+
+static Fl_Double_Window *main_win;
+static Fl_Scroll *thescroll;
+static Fl_Font extra_font;
+
+static int font_count = 0;
+static int first_free = 0;
+
+/********************************************************************************************/
+class FontDisplay : public Fl_Widget
+{
+ void draw(void);
+
+public:
+ int font, size;
+
+ int test_fixed_pitch(void);
+
+ FontDisplay(Fl_Boxtype B, int X, int Y, int W, int H, const char *L = 0) : Fl_Widget(X, Y, W, H, L)
+ {
+ box(B);
+ font = 0;
+ size = DEF_SIZE;
+ }
+};
+
+/********************************************************************************************/
+void FontDisplay::draw(void)
+{
+ draw_box();
+ fl_font((Fl_Font)font, size);
+ fl_color(FL_BLACK);
+ fl_draw(label(), x() + 3, y() + 3, w() - 6, h() - 6, align());
+}
+/********************************************************************************************/
+int FontDisplay::test_fixed_pitch(void)
+{
+ int w1, w2;
+ int h1, h2;
+
+ w1 = w2 = 0;
+ h1 = h2 = 0;
+
+ fl_font((Fl_Font)font, size);
+
+ fl_measure("MHMHWWMHMHMHM###WWX__--HUW", w1, h1, 0);
+ fl_measure("iiiiiiiiiiiiiiiiiiiiiiiiii", w2, h2, 0);
+
+ if (w1 == w2) return 1; // exact match - fixed pitch
+
+ // Is the font "nearly" fixed pitch? If it is within 5%, say it is...
+ double f1 = (double)w1;
+ double f2 = (double)w2;
+ double delta = fabs(f1 - f2) * 5.0;
+ if (delta <= f1) return 2; // nearly fixed pitch...
+
+ return 0; // NOT fixed pitch
+}
+
+/********************************************************************************************/
+static FontDisplay *textobj;
+
+/********************************************************************************************/
+static void size_cb(Fl_Widget *, long)
+{
+ int size_idx = sizeobj->value();
+
+ if (!size_idx) return;
+
+ const char *c = sizeobj->text(size_idx);
+
+ while (*c < '0' || *c > '9') c++; // find the first numeric char
+ pickedsize = atoi(c); // convert the number string to a value
+
+ // Now set the font view to the selected size and redraw it.
+ textobj->size = pickedsize;
+ textobj->redraw();
+}
+/********************************************************************************************/
+static void font_cb(Fl_Widget *, long)
+{
+ int font_idx = fontobj->value() + first_free;
+
+ if (!font_idx) return;
+ font_idx--;
+
+ textobj->font = font_idx;
+ sizeobj->clear();
+
+ int size_count = numsizes[font_idx-first_free];
+ int *size_array = sizes[font_idx-first_free];
+ if (!size_count)
+ {
+ // no preferred sizes - probably TT fonts etc...
+ }
+ else if (size_array[0] == 0)
+ {
+ // many sizes, probably a scaleable font with preferred sizes
+ int j = 1;
+ for (int i = 1; i <= 64 || i < size_array[size_count - 1]; i++)
+ {
+ char buf[16];
+ if (j < size_count && i == size_array[j])
+ {
+ sprintf(buf, "@b%d", i);
+ j++;
+ }
+ else
+ sprintf(buf, "%d", i);
+ sizeobj->add(buf);
+ }
+ sizeobj->value(pickedsize);
+ }
+ else
+ {
+ // some sizes, probably a font with a few fixed sizes available
+ int w = 0;
+ for (int i = 0; i < size_count; i++)
+ {
+ // find the nearest available size to the current picked size
+ if (size_array[i] <= pickedsize) w = i;
+
+ char buf[16];
+ sprintf(buf, "@b%d", size_array[i]);
+ sizeobj->add(buf);
+ }
+ sizeobj->value(w + 1);
+ }
+ size_cb(sizeobj, 0); // force selection of nearest valid size, then redraw
+
+ // Now check to see if the font looks like a fixed pitch font or not...
+ int looks_fixed = textobj->test_fixed_pitch();
+ if(looks_fixed)
+ {
+ if (looks_fixed > 1)
+ fix_prop->value("near");
+ else
+ fix_prop->value("fixed");
+ }
+ else
+ {
+ fix_prop->value("prop");
+ }
+}
+
+/********************************************************************************************/
+static void choose_cb(Fl_Widget *, long)
+{
+ int font_idx = fontobj->value() + first_free;
+ if (!font_idx)
+ {
+ puts("No font chosen");
+ }
+ else
+ {
+ int font_type;
+ font_idx -= 1;
+ const char *name = Fl::get_font_name((Fl_Font)font_idx, &font_type);
+ printf("idx %d\nUser name :%s:\n", font_idx, name);
+ printf("FLTK name :%s:\n", Fl::get_font((Fl_Font)font_idx));
+
+ Fl::set_font(extra_font, (Fl_Font)font_idx);
+// Fl::set_font(extra_font, Fl::get_font((Fl_Font)font_idx));
+ }
+
+ int size_idx = sizeobj->value();
+ if (!size_idx)
+ {
+ puts("No size selected");
+ }
+ else
+ {
+ const char *c = sizeobj->text(size_idx);
+ while (*c < '0' || *c > '9') c++; // find the first numeric char
+ int pickedsize = atoi(c); // convert the number string to a value
+
+ printf("size %d\n\n", pickedsize);
+ }
+
+ fflush(stdout);
+ main_win->redraw();
+}
+/********************************************************************************************/
+static void refresh_cb(Fl_Widget *, long)
+{
+ main_win->redraw();
+}
+
+/********************************************************************************************/
+static void own_face_cb(Fl_Widget *, void *)
+{
+ int font_idx;
+ int cursor_restore = 0;
+ static int i_was = -1; // used to keep track of where we were in the list...
+
+ if (i_was < 0) { // not been here before
+ i_was = 1;
+ } else {
+ i_was = fontobj->topline(); // record which was the topmost visible line
+ fontobj->clear();
+ // Populating the font widget can be slower than an old dog with three legs
+ // on a bad day, show a wait cursor
+ fnt_chooser_win->cursor(FL_CURSOR_WAIT);
+ cursor_restore = 1;
+ }
+
+
+ // Populate the font list with the names of the fonts found
+ for (font_idx = first_free; font_idx < font_count; font_idx++)
+ {
+ int font_type;
+ const char *name = Fl::get_font_name((Fl_Font)font_idx, &font_type);
+ char buffer[128];
+
+ if(own_face->value() == 0) {
+ char *p = buffer;
+ if (font_type & FL_BOLD) { // if the font is BOLD, set the bold attribute in the list
+ *p++ = '@';
+ *p++ = 'b';
+ }
+ if (font_type & FL_ITALIC) { // ditto for italic fonts
+ *p++ = '@';
+ *p++ = 'i';
+ }
+ // Suppress subsequent formatting - some MS fonts have '@' in their name
+ *p++ = '@';
+ *p++ = '.';
+ strcpy(p, name);
+ } else { // Show font in its own face
+ /* this is neat, but really slow on some systems: uses each font to display its own name */
+ sprintf (buffer, "@F%d@.%s", font_idx, name);
+ }
+ fontobj->add(buffer);
+ }
+ // now put the browser position back the way it was... more or less
+ fontobj->topline(i_was);
+ // restore the cursor
+ if(cursor_restore) fnt_chooser_win->cursor(FL_CURSOR_DEFAULT);
+}
+
+/********************************************************************************************/
+static void create_font_widget()
+{
+ fnt_chooser_win = new Fl_Double_Window(380, 420, "Font Selector");
+
+ strcpy(label, "Font Sample\n");
+ int i = 12; // strlen(label);
+ int n = 0;
+ ulong c;
+ for (c = ' '+1; c < 127; c++) {
+ if (!(c&0x1f)) label[i++]='\n';
+ if (c=='@') label[i++]=c;
+ label[i++]=c;
+ }
+ label[i++] = '\n';
+ for (c = 0xA1; c < 0x600; c += 9) {if (!(++n&(0x1f))) label[i++]='\n';
+ i += fl_utf8encode((unsigned int)c, label + i);}
+ label[i] = 0;
+
+ textobj = new FontDisplay(FL_FRAME_BOX, 10, 10, 360, 90, label);
+ textobj->align(FL_ALIGN_TOP | FL_ALIGN_LEFT | FL_ALIGN_INSIDE | FL_ALIGN_CLIP);
+ textobj->color(53, 3);
+
+ fontobj = new Fl_Hold_Browser(10, 110, 290, 270);
+ fontobj->box(FL_FRAME_BOX);
+ fontobj->color(53, 3);
+ fontobj->callback(font_cb);
+ fnt_chooser_win->resizable(fontobj);
+
+ sizeobj = new Fl_Hold_Browser(310, 110, 60, 270);
+ sizeobj->box(FL_FRAME_BOX);
+ sizeobj->color(53, 3);
+ sizeobj->callback(size_cb);
+
+// Create the status bar
+ Fl_Group * stat_bar = new Fl_Group (10, 385, 380, 30);
+ stat_bar->begin();
+
+ fnt_cnt = new Fl_Value_Output(10, 390, 40, 20);
+ fnt_cnt->label("fonts");
+ fnt_cnt->align(FL_ALIGN_RIGHT);
+
+ fix_prop = new Fl_Output(100, 390, 40, 20);
+ fix_prop->color(FL_BACKGROUND_COLOR);
+ fix_prop->value("prop");
+ fix_prop->clear_visible_focus();
+
+ own_face = new Fl_Check_Button(150, 390, 40, 20, "Self");
+ own_face->value(0);
+ own_face->type(FL_TOGGLE_BUTTON);
+ own_face->clear_visible_focus();
+ own_face->callback(own_face_cb);
+ own_face->tooltip("Display font names in their own face");
+
+ Fl_Box * dummy = new Fl_Box(220, 390, 1, 1);
+
+ choose_btn = new Fl_Button(240, 385, 60, 30);
+ choose_btn->label("Select");
+ choose_btn->callback(choose_cb);
+
+ refresh_btn = new Fl_Button(310, 385, 60, 30);
+ refresh_btn->label("Refresh");
+ refresh_btn->callback(refresh_cb);
+
+ stat_bar->end();
+ stat_bar->resizable (dummy);
+
+ fnt_chooser_win->end();
+}
+
+/********************************************************************************************/
+int make_font_chooser(void)
+{
+ int font_idx;
+
+ // create the widget frame
+ create_font_widget();
+
+ // Load the systems available fonts - ask for everything
+// font_count = Fl::set_fonts("*");
+#ifdef _WIN32
+ font_count = Fl::set_fonts("*");
+#elif __APPLE__
+ font_count = Fl::set_fonts("*");
+#else
+ // Load the systems available fonts - ask for everything that claims to be iso10646 compatible
+ font_count = Fl::set_fonts("-*-*-*-*-*-*-*-*-*-*-*-*-iso10646-1");
+#endif
+
+ // allocate space for the sizes and numsizes array, now we know how many entries it needs
+ sizes = new int*[font_count];
+ numsizes = new int[font_count];
+
+ // Populate the font list with the names of the fonts found
+ first_free = FL_FREE_FONT;
+ for (font_idx = first_free; font_idx < font_count; font_idx++)
+ {
+ // Find out how many sizes are supported for each font face
+ int *size_array;
+ int size_count = Fl::get_font_sizes((Fl_Font)font_idx, size_array);
+ numsizes[font_idx-first_free] = size_count;
+ if (size_count) // if the font has multiple sizes, populate the 2-D sizes array
+ {
+ sizes[font_idx-first_free] = new int[size_count];
+ for (int j = 0; j < size_count; j++)
+ sizes[font_idx-first_free][j] = size_array[j];
+ }
+ } // end of font list filling loop
+
+ // Call this once to get the font browser loaded up
+ own_face_cb(NULL, 0);
+
+ fontobj->value(1);
+// fontobj->textfont(261); // optional hard-coded font for testing - do not use!
+
+ font_cb(fontobj, 0);
+
+ fnt_cnt->value(font_count);
+
+ return font_count;
+
+} // make_font_chooser
+
+/* End of Font Chooser Widget code */
+/********************************************************************************************/
+/* Unicode Font display widget */
+
+void box_cb(Fl_Widget* o, void*) {
+ thescroll->box(((Fl_Button*)o)->value() ? FL_DOWN_FRAME : FL_NO_BOX);
+ thescroll->redraw();
+}
+
+class right_left_input : public Fl_Input
+{
+public:
+ right_left_input (int x, int y, int w, int h) : Fl_Input(x, y, w, h) {};
+ void draw() {
+ if (type() == FL_HIDDEN_INPUT) return;
+ Fl_Boxtype b = box();
+ if (damage() & FL_DAMAGE_ALL) draw_box(b, color());
+ drawtext(x()+Fl::box_dx(b)+3, y()+Fl::box_dy(b),
+ w()-Fl::box_dw(b)-6, h()-Fl::box_dh(b));
+ }
+ void drawtext(int X, int Y, int W, int H) {
+ fl_color(textcolor());
+ fl_font(textfont(), textsize());
+ fl_rtl_draw(value(), strlen(value()),
+ X + W, Y + fl_height() -fl_descent());
+ }
+};
+
+
+void i7_cb(Fl_Widget *w, void *d)
+{
+ int i = 0;
+ char nb[] = "01234567";
+ Fl_Input *i7 = (Fl_Input*)w;
+ Fl_Input *i8 = (Fl_Input*)d;
+ static char buf[1024];
+ const char *ptr = i7->value();
+ while (ptr && *ptr) {
+ if (*ptr < ' ' || *ptr > 126) {
+ buf[i++] = '\\';
+ buf[i++] = nb[((*ptr >> 6) & 0x3)];
+ buf[i++] = nb[((*ptr >> 3) & 0x7)];
+ buf[i++] = nb[(*ptr & 0x7)];
+ } else {
+ if (*ptr == '\\') buf[i++] = '\\';
+ buf[i++] = *ptr;
+ }
+ ptr++;
+ }
+ buf[i] = 0;
+ i8->value(buf);
+}
+
+/********************************************************************************************/
+int main(int argc, char** argv)
+{
+ int l;
+/* If this file is saved as a UTF-8, the latin1 text in the comment
+ * below doesn't look right any more!
+ * Store the specific latin-1 byte values here... this should be equivalent to:
+ * char *latin1 = "ABCabcàèéïâîöüã123"; */
+ char *latin1 = "\x41\x42\x43\x61\x62\x63\xe0\xe8\xe9\xef\xe2\xee\xf6\xfc\xe3\x31\x32\x33";
+ char *utf8 = (char*) malloc(strlen(latin1) * 5 + 1);
+ l = 0;
+// l = fl_latin12utf((const unsigned char*)latin1, strlen(latin1), utf8);
+ l = fl_utf8froma(utf8, (strlen(latin1) * 5 + 1), latin1, strlen(latin1));
+
+ make_font_chooser();
+ extra_font = FL_TIMES_BOLD_ITALIC;
+
+ /* setup the extra font */
+ Fl::set_font(extra_font,
+#ifdef _WIN32
+ " Arial Unicode MS"
+#elif __APPLE__
+ "Monaco"
+#else
+ "-*-*-*-*-*-*-*-*-*-*-*-*-iso10646-1"
+#endif
+ );
+
+ main_win = new Fl_Double_Window (200 + 5*75, 400, "Unicode Display Test");
+ main_win->begin();
+
+ Fl_Input i1(5, 5, 190, 25);
+ utf8[l] = '\0';
+ i1.value(utf8);
+ Fl_Scroll scroll(200,0,5 * 75,400);
+
+ int off = 2;
+ if (argc > 1) {
+ off = (int)strtoul(argv[1], NULL, 0);
+ off /= 16;
+ }
+ argc = 1;
+ for (long y=off; y< 0x10000 / 16; y++) {
+ int o = 0;
+ char bu[25];
+ char buf[16*6];
+ int i = 16 * y;
+ for (int x=0; x<16; x++) {
+ int l;
+ l = fl_utf8encode(i, buf + o);
+ if (l < 1) l = 1;
+ o += l;
+ i++;
+ }
+ buf[o] = '\0';
+ sprintf(bu, "0x%04lX", y * 16);
+ Fl_Input* b = new Fl_Input(200,(y-off)*25,60,25);
+ b->value(strdup(bu));
+ b = new Fl_Input(260,(y-off)*25,400,25);
+ b->textfont(extra_font);
+ b->value(strdup(buf));
+ }
+ main_win->resizable(scroll);
+ scroll.end();
+
+ thescroll = &scroll;
+
+ char *utf8l = (char*) malloc(strlen(utf8) * 3 + 1);
+ Fl_Input i2(5, 35, 190, 25);
+ l = fl_utf_tolower((const unsigned char*)utf8, l, utf8l);
+ utf8l[l] = '\0';
+ i2.value(utf8l);
+
+ char *utf8u = (char*) malloc(strlen(utf8l) * 3 + 1);
+ Fl_Input i3(5, 65, 190, 25);
+ l = fl_utf_toupper((const unsigned char*)utf8l, l, utf8u);
+ utf8u[l] = '\0';
+ i3.value(utf8u);
+
+ char *ltr_txt = "\\->e\xCC\x82=\xC3\xAA";
+ Fl_Input i4(5, 90, 190, 25);
+ i4.value(ltr_txt);
+ i4.textfont(extra_font);
+
+ wchar_t r_to_l_txt[] ={/*8238,*/ 1610, 1608, 1606, 1604, 1603, 1608, 1583, 0};
+
+ char abuf[40];
+// l = fl_unicode2utf(r_to_l_txt, 8, abuf);
+ l = fl_utf8fromwc(abuf, 40, r_to_l_txt, 8);
+ abuf[l] = 0;
+
+ right_left_input i5(5, 115, 190, 50);
+ i5.textfont(extra_font);
+ i5.textsize(30);
+ i5.value(abuf);
+
+ Fl_Input i7(5, 230, 190, 25);
+ Fl_Input i8(5, 260, 190, 25);
+ i7.callback(i7_cb, &i8);
+ i7.textsize(20);
+ i7.value(abuf);
+ i7.when(FL_WHEN_CHANGED);
+
+ wchar_t r_to_l_txt1[] ={/*8238,*/ 1610, 0x20, 1608, 0x20, 1606, 0x20, 1604, 0x20, 1603, 0x20, 1608, 0x20, 1583, 0};
+
+// l = fl_unicode2utf(r_to_l_txt1, 14, abuf);
+ l = fl_utf8fromwc(abuf, 40, r_to_l_txt1, 14);
+ abuf[l] = 0;
+ right_left_input i6(5, 175, 190, 50);
+ i6.textfont(extra_font);
+ i6.textsize(30);
+ i6.value(abuf);
+
+ // Now try Greg Ercolano's Japanese test sequence
+ // SOME JAPANESE UTF8 TEXT
+ char *utfstr = "\xe4\xbd\x95\xe3\x82\x82\xe8\xa1"
+ "\x8c\xe3\x82\x8b\xe3\x80\x82"; // 何も行る。
+
+ Fl_Output o9(5, 330, 190, 45);
+ o9.textfont(extra_font);
+ o9.textsize(30);
+ o9.value(utfstr);
+
+
+ main_win->end();
+ fl_set_status(0, 370, 100, 30);
+
+ main_win->show(argc,argv);
+
+ fnt_chooser_win->show();
+
+ int ret = Fl::run();
+
+ // Free up the sizes arrays we allocated
+ if(numsizes) {delete [] numsizes;}
+ if(sizes) {delete [] sizes;}
+
+ return ret;
+}
+
+/* end of file */
+