diff options
Diffstat (limited to 'test')
| -rw-r--r-- | test/Makefile | 15 | ||||
| -rw-r--r-- | test/demo.cxx | 12 | ||||
| -rw-r--r-- | test/demo.menu | 6 | ||||
| -rw-r--r-- | test/dnd-test.cxx | 75 | ||||
| -rw-r--r-- | test/fonts.cxx | 27 | ||||
| -rw-r--r-- | test/mcast_launcher.cxx | 164 | ||||
| -rw-r--r-- | test/mcast_rx.cxx | 160 | ||||
| -rw-r--r-- | test/mcast_tx.cxx | 144 | ||||
| -rw-r--r-- | test/utf8.cxx | 624 |
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 */ + |
