├── .gitignore
├── src
├── examples
│ ├── .gitignore
│ ├── Makefile
│ ├── hello.go
│ └── text.go
├── .gitignore
├── layoutcalc.go
├── texteditor.go
├── window.go
├── group.go
├── input.go
├── Makefile
├── widget.go
├── fltk.h
├── fltk.go
└── fltk.cxx
├── Makefile
├── .project
├── LICENSE
└── README.md
/.gitignore:
--------------------------------------------------------------------------------
1 | bin
2 | *~
3 |
--------------------------------------------------------------------------------
/src/examples/.gitignore:
--------------------------------------------------------------------------------
1 | hello
2 | text
3 |
--------------------------------------------------------------------------------
/src/.gitignore:
--------------------------------------------------------------------------------
1 | 8.out
2 | .#*
3 | [#]*#
4 | *.o
5 | *.8
6 | *.c
7 | *.so
8 | *.cgo1.go
9 | *~
10 | _cgo_gotypes.go
11 | _obj
12 | fltk-2.0.x-r7725/*
13 | fltk-2.0.x-r7725.tar.bz2
14 |
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | all:
2 | cd src && $(MAKE) $(MFLAGS) all
3 |
4 | install:
5 | cd src && $(MAKE) $(MFLAGS) install
6 |
7 | examples:
8 | cd src && $(MAKE) $(MFLAGS) examples
9 |
10 | clean:
11 | cd src && $(MAKE) $(MFLAGS) clean
12 |
--------------------------------------------------------------------------------
/src/examples/Makefile:
--------------------------------------------------------------------------------
1 | BINS = text hello
2 | pkgdir=$(GOROOT)/pkg/$(GOOS)_$(GOARCH)
3 |
4 | all: $(BINS)
5 |
6 | text hello : % : %.go $(pkgdir)/cgo_fltk.so $(pkgdir)/fltk.a
7 | 8g $@.go && 8l -o $@ $@.8
8 |
9 | clean:
10 | rm -f $(BINS) *.8
11 |
--------------------------------------------------------------------------------
/.project:
--------------------------------------------------------------------------------
1 |
2 |
3 | fltk-go
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/src/layoutcalc.go:
--------------------------------------------------------------------------------
1 | package fltk
2 |
3 | type LayoutCalc struct {
4 | X, Y, W, H int
5 | }
6 |
7 | func NewLayoutCalc(w Widgety) *LayoutCalc {
8 | return &LayoutCalc{0, 0, w.GetWidget().W(), w.GetWidget().H()}
9 | }
10 | // add a widget of h height
11 | func (l *LayoutCalc) Add(w Widgety) {
12 | l.Y += w.GetWidget().H()
13 | l.H -= w.GetWidget().H()
14 | }
15 |
--------------------------------------------------------------------------------
/src/examples/hello.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import "fltk"
4 |
5 | func main() {
6 | w := fltk.NewWindow(300, 180)
7 | w.Begin()
8 | b := fltk.NewWidget(20, 40, 260, 100, "Hello there!")
9 | b.Box(fltk.UP_BOX)
10 | b.LabelFont(fltk.HELVETICA_BOLD_ITALIC)
11 | b.LabelSize(36)
12 | b.LabelType(fltk.SHADOW_LABEL)
13 | w.End()
14 | w.Show([]string{})
15 | fltk.Run(func() bool {return true})
16 | }
17 |
--------------------------------------------------------------------------------
/src/texteditor.go:
--------------------------------------------------------------------------------
1 | package fltk
2 |
3 | /*
4 | #include "fltk.h"
5 | */
6 | import "C"
7 | import "unsafe"
8 |
9 | type TextEditor struct {
10 | Widget
11 | }
12 |
13 | func NewTextEditor(x, y, w, h int, text... string) *TextEditor {
14 | i := &TextEditor{}
15 | initWidget(i, unsafe.Pointer(C.go_fltk_new_TextEditor(C.int(x), C.int(y), C.int(w), C.int(h), cStringOpt(text))))
16 | return i
17 | }
18 |
--------------------------------------------------------------------------------
/src/window.go:
--------------------------------------------------------------------------------
1 | package fltk
2 |
3 | /*
4 | #include "fltk.h"
5 | */
6 | import "C"
7 | import "unsafe"
8 |
9 | type Window struct {
10 | Group
11 | }
12 |
13 | func NewWindow(w, h int) *Window {
14 | win := &Window{}
15 | initWidget(win, unsafe.Pointer(C.go_fltk_new_Window(C.int(w), C.int(h))))
16 | return win
17 | }
18 | func (w *Window) Destroy() {C.go_fltk_Window_destroy(w.ptr)}
19 | func (w *Window) Show(args []string) {C.go_fltk_Window_show(w.ptr, C.int(0), unsafe.Pointer(uintptr(0)))}
20 | func (w *Window) SetLabel(label string) {C.go_fltk_Window_set_label(w.ptr, C.CString(label))}
21 |
--------------------------------------------------------------------------------
/src/group.go:
--------------------------------------------------------------------------------
1 | package fltk
2 |
3 | /*
4 | #include "fltk.h"
5 | */
6 | import "C"
7 | import "unsafe"
8 |
9 | type Group struct {
10 | Widget
11 | }
12 |
13 | func NewPackedGroup(x, y, w, h int) *Group {
14 | win := &Group{}
15 | initWidget(win, unsafe.Pointer(C.go_fltk_new_PackedGroup(C.int(x), C.int(y), C.int(w), C.int(h))))
16 | return win
17 | }
18 |
19 | func (g *Group) Begin() {C.go_fltk_Group_begin(g.ptr)}
20 | func (g *Group) End() {C.go_fltk_Group_end(g.ptr)}
21 | func (g *Group) Add(w Widgety) {C.go_fltk_Group_add(g.ptr, w.GetWidget().ptr)}
22 | func (g *Group) Resizable(w Widgety) {C.go_fltk_Group_resizable(g.ptr, w.GetWidget().ptr)}
23 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | This software is licensed under the ZLIB license:
2 |
3 | Copyright (c) 2010 Bill Burdick
4 |
5 | This software is provided 'as-is', without any express or implied
6 | warranty. In no event will the authors be held liable for any damages
7 | arising from the use of this software.
8 |
9 | Permission is granted to anyone to use this software for any purpose,
10 | including commercial applications, and to alter it and redistribute it
11 | freely, subject to the following restrictions:
12 |
13 | 1. The origin of this software must not be misrepresented; you must not
14 | claim that you wrote the original software. If you use this software
15 | in a product, an acknowledgment in the product documentation would be
16 | appreciated but is not required.
17 |
18 | 2. Altered source versions must be plainly marked as such, and must not be
19 | misrepresented as being the original software.
20 |
21 | 3. This notice may not be removed or altered from any source
22 | distribution.
23 |
--------------------------------------------------------------------------------
/src/input.go:
--------------------------------------------------------------------------------
1 | package fltk
2 |
3 | /*
4 | #include "fltk.h"
5 | */
6 | import "C"
7 | import "unsafe"
8 |
9 | type Input struct {
10 | Widget
11 | }
12 |
13 | func NewInput(x, y, w, h int, text... string) *Input {
14 | i := &Input{}
15 | initWidget(i, unsafe.Pointer(C.go_fltk_new_Input(C.int(x), C.int(y), C.int(w), C.int(h), cStringOpt(text))))
16 | return i
17 | }
18 |
19 | //func (i *Input) GetText() string {return string(uintptr(unsafe.Pointer(C.go_fltk_Input_get_text(i.ptr))))}
20 | func (i *Input) GetText() string {return C.GoString(C.go_fltk_Input_get_text(i.ptr))}
21 | func (i *Input) SetText(text string) bool {return C.go_fltk_Input_set_text(i.ptr, C.CString(text)) != C.int(0)}
22 | func (i *Input) MousePosition() int {return int(C.go_fltk_Input_mouse_position(i.ptr))}
23 | func (i *Input) GetPosition() int {return int(C.go_fltk_Input_get_position(i.ptr))}
24 | func (i *Input) GetMark() int {return int(C.go_fltk_Input_get_mark(i.ptr))}
25 | func (i *Input) SetPosition(p int, m int) {C.go_fltk_Input_set_position(i.ptr, C.int(p), C.int(m))}
26 |
--------------------------------------------------------------------------------
/src/examples/text.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import "fltk"
4 | import "fmt"
5 | import "strconv"
6 |
7 | func main() {
8 | exit := false
9 | window := fltk.NewWindow(300, 180)
10 | l := fltk.NewLayoutCalc(window)
11 | window.SetCallback(func(){exit = true; println("CLOSED"); window.Destroy()})
12 | window.Begin()
13 | i := fltk.NewInput(l.X, l.Y, l.W, 30)
14 | l.Add(i)
15 | i.StealEvents(fltk.PUSH_MASK | fltk.DRAG_MASK | fltk.PASTE_MASK)
16 | i.SetEventHandler(func(e *fltk.Event) {
17 | if (e.Stolen) {
18 | fmt.Println("STOLE EVENT:", strconv.Itoa(e.Event), "widget:", e.Widget, "push: ", fltk.PUSH)
19 | if (e.Event == fltk.PUSH) {
20 | fmt.Println("\nMouse Position:", i.MousePosition(), "\n")
21 | }
22 | if (e.Event != fltk.PUSH && e.Event != fltk.RELEASE && e.Event != fltk.PASTE) || e.Button == 1 {
23 | fmt.Println("CONTINUING EVENT:", strconv.Itoa(e.Event), "widget:", e.Widget, "push: ", fltk.PUSH)
24 | e.Continue()
25 | }
26 | }
27 | })
28 | fmt.Println("Editor at y: ", l.Y)
29 | e := fltk.NewTextEditor(l.X, l.Y, l.W, l.H)
30 | window.Resizable(e)
31 | window.End()
32 | window.Show([]string{})
33 | fltk.Run(func() bool {return !exit})
34 | }
35 |
--------------------------------------------------------------------------------
/src/Makefile:
--------------------------------------------------------------------------------
1 | FLTK=fltk-2.0.x-r7725
2 | FLTK_DIST=$(FLTK).tar.bz2
3 | FLTK_URL=http://ftp.funet.fi/pub/mirrors/ftp.easysw.com/pub/fltk/snapshots/$(FLTK).tar.bz2
4 | FLTK_LIB=$(FLTK)/lib/libfltk2.a
5 |
6 | examples: install
7 | (cd examples; make)
8 |
9 | # uncomment the next line to have 'make clean' remove the fltk-dist
10 | #clean: clean-fltk
11 |
12 | include $(GOROOT)/src/Make.inc
13 |
14 | TARG=fltk
15 | GOFILES=\
16 | layoutcalc.go
17 | CGOFILES=\
18 | fltk.go \
19 | widget.go \
20 | group.go \
21 | input.go \
22 | texteditor.go \
23 | window.go
24 | CGO_DEPS=fltk.o
25 |
26 | CGO_LDFLAGS=fltk.o $(FLTK_LIB) -lXext -lXinerama -lXft -lX11 -lXi -lm
27 |
28 | include $(GOROOT)/src/Make.pkg
29 |
30 | fltk.o: fltk.h fltk.cxx $(FLTK_LIB)
31 | g++ -I$(FLTK) -c fltk.cxx
32 |
33 | $(CGOTARG).so: $(GCC_OFILES) $(CGO_DEPS) $(FLTK_LIB)
34 | g++ $(_CGO_CFLAGS_$(GOARCH)) -o $@ $(GCC_OFILES) $(CGO_LDFLAGS) $(_CGO_LDFLAGS_$(GOOS))
35 |
36 | $(FLTK_LIB): $(FLTK)/config.status
37 | cd $(FLTK) && make DIRS="src $(LOCALIMAGES) images"
38 |
39 | $(FLTK)/config.status:
40 | rm -rf $(FLTK_DIST) $(FLTK)
41 | wget $(FLTK_URL) && tar xjf $(FLTK_DIST) && cd $(FLTK) && ./configure --disable-gl --disable-shared
42 |
43 | clean-fltk:
44 | rm -rf $(FLTK)
45 |
46 | clean: clean-local
47 |
48 | clean-local:
49 | (cd examples; make clean)
50 | rm -f *~
51 |
--------------------------------------------------------------------------------
/src/widget.go:
--------------------------------------------------------------------------------
1 | package fltk
2 |
3 | /*
4 | #include "fltk.h"
5 | */
6 | import "C"
7 | import "unsafe"
8 | import "fmt"
9 |
10 | type Widget struct {
11 | ptr *C.Widget
12 | callback func()
13 | eventHandler func(*Event)
14 | }
15 |
16 | func emptyCallback() {}
17 | func emptyHandler(*Event) {}
18 |
19 | func NewWidget(x, y, w, h int, text... string) *Widget {
20 | return initWidget(&Widget{}, unsafe.Pointer(C.go_fltk_new_Widget(C.int(x), C.int(y), C.int(w), C.int(h), cStringOpt(text))))
21 | }
22 | func (w *Widget) String() string {return fmt.Sprintf("Widget: %q", unsafe.Pointer(w.ptr))}
23 | func (w *Widget) SetCallback(f func()) {
24 | w.callback = f
25 | C.go_fltk_Widget_callback(w.ptr)
26 | }
27 | func (w *Widget) GetWidget() *Widget {return w}
28 | func (w *Widget) StealEvents(etypes int) {C.go_fltk_Widget_steal_events(w.ptr, C.int(etypes))}
29 | func (w *Widget) Box(box *C.Box) {C.go_fltk_Widget_box(w.ptr, box)}
30 | func (w *Widget) LabelFont(font *C.Font) {C.go_fltk_Widget_labelfont(w.ptr, font)}
31 | func (w *Widget) LabelSize(size int) {C.go_fltk_Widget_labelsize(w.ptr, C.int(size))}
32 | func (w *Widget) LabelType(ltype *C.LabelType) {C.go_fltk_Widget_labeltype(w.ptr, ltype)}
33 | func (w *Widget) SetEventHandler(f func(*Event)) {w.eventHandler = f}
34 | func (w *Widget) HandleCallback() {w.callback()}
35 | func (w *Widget) HandleEvent(e *Event) {w.eventHandler(e)}
36 | func (w *Widget) X() int {return int(C.go_fltk_Widget_x(w.ptr))}
37 | func (w *Widget) Y() int {return int(C.go_fltk_Widget_y(w.ptr))}
38 | func (w *Widget) W() int {return int(C.go_fltk_Widget_w(w.ptr))}
39 | func (w *Widget) H() int {return int(C.go_fltk_Widget_h(w.ptr))}
40 | func (w *Widget) ThrowFocus() {C.go_fltk_Widget_throw_focus(w.ptr)}
41 |
--------------------------------------------------------------------------------
/src/fltk.h:
--------------------------------------------------------------------------------
1 | #ifdef __cplusplus
2 | #define TYPEDEF(type) typedef fltk::type type
3 | extern "C" {
4 | #else
5 | #define TYPEDEF(type) typedef struct type type
6 | enum {
7 | CTRL = 0x00040000, /*!< Either ctrl key held down */
8 | ALT = 0x00080000, /*!< Either alt key held down */
9 | META = 0x00400000, /*!< "Windows" or the "Apple" keys held down */
10 | #if defined(__APPLE__)
11 | ACCELERATOR = CTRL,
12 | OPTION = ALT,
13 | COMMAND = META
14 | #else
15 | ACCELERATOR = ALT, //!< ALT on Windows/Linux, CTRL on OS/X, use for menu accelerators
16 | COMMAND = CTRL, //!< CTRL on Windows/Linux, META on OS/X, use for menu shortcuts
17 | OPTION = ALT|META //!< ALT|META on Windows/Linux, just ALT on OS/X, use as a drag modifier
18 | #endif
19 | };
20 | #endif
21 |
22 | TYPEDEF(Box);
23 | TYPEDEF(Font);
24 | TYPEDEF(LabelType);
25 | TYPEDEF(Widget);
26 | TYPEDEF(Group);
27 | TYPEDEF(PackedGroup);
28 | TYPEDEF(Window);
29 | TYPEDEF(Input);
30 | TYPEDEF(TextEditor);
31 |
32 | extern Widget *go_fltk_callback_widget;
33 | extern int go_fltk_event;
34 | extern Widget *go_fltk_event_widget;
35 | extern int go_fltk_event_state;
36 | extern int go_fltk_event_button;
37 | extern int go_fltk_event_clicks;
38 | extern int go_fltk_event_dx;
39 | extern int go_fltk_event_dy;
40 | extern int go_fltk_event_key;
41 | extern int go_fltk_event_x;
42 | extern int go_fltk_event_y;
43 | extern int go_fltk_event_x_root;
44 | extern int go_fltk_event_y_root;
45 | extern int go_fltk_event_stolen;
46 | extern int go_fltk_event_return;
47 |
48 | extern void free(void *ptr);
49 | static inline void free_string(char* s) { free(s); }
50 | static inline char* to_char_ptr(void *ptr) {return (char *)ptr;}
51 |
52 | extern Box *go_fltk_get_UP_BOX();
53 | extern Font *go_fltk_get_HELVETICA_BOLD_ITALIC();
54 | extern LabelType *go_fltk_get_SHADOW_LABEL();
55 | extern Window *go_fltk_new_Window(int w, int h);
56 | extern PackedGroup *go_fltk_new_PackedGroup(int x, int y, int w, int h);
57 | extern Widget *go_fltk_new_Widget(int x, int y, int w, int h, const char *text);
58 | extern Input *go_fltk_new_Input(int x, int y, int w, int h, const char *text);
59 | extern TextEditor *go_fltk_new_TextEditor(int x, int y, int w, int h, const char *text);
60 | extern void go_fltk_Widget_steal_events(Widget *w, int events);
61 | extern void go_fltk_Event_continue();
62 | extern void go_fltk_Group_begin(Group *g);
63 | extern void go_fltk_Group_end(Group *g);
64 | extern void go_fltk_Group_add(Group *g, Widget *w);
65 | extern void go_fltk_Group_resizable(Group *g, Widget *w);
66 | extern void go_fltk_Widget_box(Widget *w, Box *box);
67 | extern void go_fltk_Widget_labelfont(Widget *w, Font *font);
68 | extern void go_fltk_Widget_labelsize(Widget *w, int size);
69 | extern void go_fltk_Widget_labeltype(Widget *w, LabelType *type);
70 | extern void go_fltk_Widget_callback(Widget *w);
71 | extern void go_fltk_Window_destroy(Window *w);
72 | extern void go_fltk_Window_show(Window *w, int argc, void *argv);
73 | extern void go_fltk_Window_set_label(Window *w, const char *label);
74 | extern int go_fltk_Widget_x(Widget *w);
75 | extern int go_fltk_Widget_y(Widget *w);
76 | extern int go_fltk_Widget_w(Widget *w);
77 | extern int go_fltk_Widget_h(Widget *w);
78 | extern void go_fltk_Widget_throw_focus(Widget *w);
79 | extern const char *go_fltk_Input_get_text(Input *in);
80 | extern int go_fltk_Input_set_text(Input *in, const char *text);
81 | extern int go_fltk_Input_mouse_position(Input *in);
82 | extern int go_fltk_Input_get_position(Input *in);
83 | extern int go_fltk_Input_get_mark(Input *in);
84 | extern void go_fltk_Input_set_position(Input *in, int p, int m);
85 | extern void go_fltk_run();
86 | extern void go_fltk_get_event();
87 | extern void go_fltk_continue_event(int i);
88 |
89 | #ifdef __cplusplus
90 | }
91 | #endif
92 |
--------------------------------------------------------------------------------
/src/fltk.go:
--------------------------------------------------------------------------------
1 | package fltk
2 |
3 | /*
4 | #include "fltk.h"
5 | */
6 | import "C"
7 | import "unsafe"
8 | //import "fmt"
9 |
10 | var UP_BOX *C.Box
11 | var HELVETICA_BOLD_ITALIC *C.Font
12 | var SHADOW_LABEL *C.LabelType
13 |
14 | const (
15 | NO_EVENT = iota
16 | PUSH
17 | RELEASE
18 | ENTER
19 | LEAVE
20 | DRAG
21 | FOCUS
22 | UNFOCUS
23 | KEY
24 | KEYUP
25 | FOCUS_CHANGE
26 | MOVE
27 | SHORTCUT
28 | DEACTIVATE
29 | ACTIVATE
30 | HIDE
31 | SHOW
32 | PASTE
33 | TIMEOUT
34 | MOUSEWHEEL
35 | DND_ENTER
36 | DND_DRAG
37 | DND_LEAVE
38 | DND_RELEASE
39 | TOOLTIP
40 | )
41 | const (
42 | NO_EVENT_MASK = 1 << iota
43 | PUSH_MASK
44 | RELEASE_MASK
45 | ENTER_MASK
46 | LEAVE_MASK
47 | DRAG_MASK
48 | FOCUS_MASK
49 | UNFOCUS_MASK
50 | KEY_MASK
51 | KEYUP_MASK
52 | FOCUS_CHAN_MASKGE
53 | MOVE_MASK
54 | SHORTCUT_MASK
55 | DEACTIVATE_MASK
56 | ACTIVATE_MASK
57 | HIDE_MASK
58 | SHOW_MASK
59 | PASTE_MASK
60 | TIMEOUT_MASK
61 | MOUSEWHEEL_MASK
62 | DND_ENTER_MASK
63 | DND_DRAG_MASK
64 | DND_LEAVE_MASK
65 | DND_RELEASE_MASK
66 | TOOLTIP_MASK
67 | )
68 |
69 | /*! Flags returned by event_state(), and used as the high 16 bits
70 | of Widget::add_shortcut() values (the low 16 bits are all zero, so these
71 | may be or'd with key values).
72 |
73 | The inline function BUTTON(n) will turn n (1-8) into the flag for a
74 | mouse button.
75 | */
76 | const (
77 | SHIFT = 1 << 16 * iota // 0x00010000, /*!< Either shift key held down */
78 | CAPSLOCK // 0x00020000, /*!< Caps lock is toggled on */
79 | CTRL // 0x00040000, /*!< Either ctrl key held down */
80 | ALT // 0x00080000, /*!< Either alt key held down */
81 | NUMLOCK // 0x00100000, /*!< Num Lock turned on */
82 | _
83 | META // 0x00400000, /*!< "Windows" or the "Apple" keys held down */
84 | SCROLLLOCK // 0x00800000, /*!< Scroll Lock turned on */
85 | BUTTON1 // 0x01000000, /*!< Left mouse button held down */
86 | BUTTON2 // 0x02000000, /*!< Middle mouse button held down */
87 | BUTTON3 // 0x04000000, /*!< Right mouse button held down */
88 | ANY_BUTTON = 0x7f000000 // 0x7f000000, /*!< Any mouse button (up to 8) */
89 | ACCELERATOR = C.ACCELERATOR //!< ALT on Windows/Linux, CTRL on OS/X, use for menu accelerators
90 | OPTION = C.OPTION //!< ALT|META on Windows/Linux, just ALT on OS/X, use as a drag modifier
91 | COMMAND = C.COMMAND //!< CTRL on Windows/Linux, META on OS/X, use for menu shortcuts
92 | )
93 |
94 | type Event struct {
95 | Callback Widgety
96 | Widget Widgety
97 | Event int
98 | State int
99 | Button int
100 | Clicks int
101 | Dx int
102 | Dy int
103 | Key int
104 | X int
105 | Y int
106 | XRoot int
107 | YRoot int
108 | Stolen bool
109 | Return int
110 | // TimeElapsed int
111 | }
112 |
113 | func (*Event) Continue() bool{
114 | if C.go_fltk_event_stolen != 0 {
115 | C.go_fltk_Event_continue()
116 | return true
117 | }
118 | return false
119 | }
120 |
121 | var widgets map[*C.Widget]Widgety
122 |
123 | type Widgety interface {
124 | GetWidget() *Widget
125 | String() string
126 | }
127 |
128 | func debug(args... interface{}) {}
129 | //func debug(args... interface{}) {fmt.Println(args...)}
130 |
131 | func cStringOpt(s []string) *C.char {
132 | if len(s) == 0 {
133 | return (*C.char)(unsafe.Pointer(uintptr(0)))
134 | }
135 | return C.CString(s[0])
136 | }
137 |
138 | func init() {
139 | UP_BOX = C.go_fltk_get_UP_BOX()
140 | HELVETICA_BOLD_ITALIC = C.go_fltk_get_HELVETICA_BOLD_ITALIC()
141 | SHADOW_LABEL = C.go_fltk_get_SHADOW_LABEL()
142 | widgets = map[*C.Widget]Widgety{}
143 | Start()
144 | }
145 | func initWidget(w Widgety, p unsafe.Pointer) *Widget {
146 | w.GetWidget().ptr = (*C.Widget)(p)
147 | w.GetWidget().callback = emptyCallback
148 | w.GetWidget().eventHandler = emptyHandler
149 | widgets[w.GetWidget().ptr] = w
150 | return w.GetWidget()
151 | }
152 | func Start() {
153 | debug("started")
154 | go func() {
155 | C.go_fltk_run()
156 | debug("FLTK DONE")
157 | }()
158 | }
159 | func ReadEvent() *Event {
160 | debug("GO WAITING FOR EVENT FROM FLTK")
161 | C.go_fltk_get_event()
162 | debug("GO GOT EVENT FROM FLTK")
163 | return &Event{
164 | widgets[C.go_fltk_callback_widget],
165 | widgets[C.go_fltk_event_widget],
166 | int(C.go_fltk_event),
167 | int(C.go_fltk_event_state),
168 | int(C.go_fltk_event_button),
169 | int(C.go_fltk_event_clicks),
170 | int(C.go_fltk_event_dx),
171 | int(C.go_fltk_event_dy),
172 | int(C.go_fltk_event_key),
173 | int(C.go_fltk_event_x),
174 | int(C.go_fltk_event_y),
175 | int(C.go_fltk_event_x_root),
176 | int(C.go_fltk_event_y_root),
177 | int(C.go_fltk_event_stolen) != 0,
178 | int(C.go_fltk_event_return),
179 | }
180 | }
181 | func ContinueEvent(used int) {
182 | debug("GO CONTINUING FLTK")
183 | C.go_fltk_continue_event(C.int(used))
184 | }
185 | func Handle(event *Event) int {
186 | if event.Callback != nil {
187 | debug("CALLBACK")
188 | event.Callback.GetWidget().HandleCallback()
189 | } else if event.Widget != nil {
190 | debug("-- widget:", event.Widget, "event:", event.Event)
191 | event.Widget.GetWidget().HandleEvent(event)
192 | debug("-- event returned: ", event.Return)
193 | }
194 | return event.Return
195 | }
196 | func Run(while func() bool) {
197 | for (while()) {ContinueEvent(Handle(ReadEvent()))}
198 | }
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | [Go FLTK](http://github.com/zot/go-fltk)
2 | ========================================
3 |
4 | This is a simple go wrapper for [FLTK2](http://www.fltk.org/doc-2.0/html/index.html), which I did to support my Go version of Ober (based on Acme), [Gober](http://github.com/zot/Gober). It's very small and should be fairly easy to extend to support whatever other widgets and functionality you need. Please contribute changes you make. The code is licensed under the very permissive ZLIB license. FLTK2 is only somewhat supported, but I like its mouse-text behavior better than FLTK 1.3's.
5 |
6 |
7 | GOALS
8 | =====
9 | * *Good integration with Go* -- the way this binding processes events lends itself well to Go programs (I think). since there is not call-in from C to Go, only call-out from Go to C, this runs FLTK in a separate thread in order to allow Go to intercept every event. Go FLTK operations are protected so that they are safe to use in goroutines.
10 | * *Simplicity* -- I'm trying to keep the code small, mostly in Go, generic (multipurpose, but not fat), easy to modify, and easy to extend
11 | * *Small and relatively stand-alone* -- I wanted a toolkit that only depended on basic X functionality and was relatively small so I could statially link it into the Go package. At this point, fltk.a is 121K and cgo_fltk.so is 312K. Yes, I'm sitting here with a straight face and claiming that this is "small." Widget kits are usually several megabytes, so this is small. Maybe someday this will even be a service instead of a library.
12 |
13 |
14 | LIMITED FUNCTIONALITY
15 | =====================
16 | This wrapper is far from complete, and I'm only planning on supporting what I need to do Gober, but I welcome additions to it. In fact, at this point it hardly does anything. I'll flesh things out as I need them for Gober.
17 |
18 |
19 | USING Go FLTK
20 | =============
21 | * fltk.Run(while func() bool) runs FLTK until while() returns false. Run() is defined like this:
22 | for (while()) {ContinueEvent(Handle(ReadEvent()))}
23 | * fltk.ReadEvent() returns the next *Event structure read
24 | * fltk.Handle(event *Event) runs the widget's event handler (if there is one) and returns what the handler returned (1 means the widget used the event, 0 means it did not)
25 | * fltk.ContinueEvent(status int) allows FLTK to continue processing. If you do not call this, the GUI will hang.
26 |
27 | By default, widgets have empty handlers, so you can treat fltk as an event stream if you like, instead of using event handlers (wait for an event, process the event yourself), which may lend itself well to using Go channels, since Go FLTK operations are safe to use in goroutines. That boils down to four ways you can deal with events:
28 |
29 | case 1, process an event after the widget handles it:
30 |
31 | user event --> widget --> go event handler
32 |
33 | case 2, process an event before the widget handles it (event stealing):
34 |
35 | user event --> go event handler [optionally: --> widget]
36 |
37 | case 3, roll your own, with default widget behavior (without an event handler):
38 |
39 | user event --> widget --> roll your own with the current event
40 |
41 | case 4, roll your own, with no default widget behavior (stealing without an event handler):
42 |
43 | user event --> roll your own with the current event [optionally: --> widget]
44 |
45 | You can install an event handler with widget.SetEventHandler() like this:
46 |
47 | input.SetEventHandler(func(e fltk.Event){println(e.Event)}
48 |
49 | Normally, the widget processes the event before Wait returns but you can "steal" events so that your event handler will get the event before the widget has a chance to process it. If you want to steal events, call widget.StealEvents() with a bit mask for the FLTK event types. There are constants for the event types and masks for them by appending _MASK to the name, like PUSH_MASK, which is just 1 << PUSH. You call StealEvents() like this:
50 |
51 | input.StealEvents((1 << PUSH_MASK) | (1 << DRAG_MASK))
52 |
53 | There is a bool field in Event, called "Stolen" to tell you whether the event was stolen. If you want the widget to process the stolen event, just call widget.ContinueEvent(). Here is an example of an event handler that prints a message for stolen push and drag events and then continues them:
54 |
55 | i.StealEvents(fltk.PUSH_MASK | fltk.DRAG_MASK)
56 | i.SetEventHandler(func(e fltk.Event) {
57 | if (e.Stolen) {
58 | println("CONTINUING EVENT: " + strconv.Itoa(e.Event))
59 | i.ContinueEvent()
60 | }
61 | })
62 |
63 | There is an example program, test.go, in the "examples" directory, that steals events from a text field, like this.
64 |
65 |
66 | DEPENDENCIES
67 | ============
68 | The make file SHOULD auto-download and unpack FLTK2 for you. When it builds the Go library, it statically links FLTK into the library so that the only dependencies are -lXext -lXinerama -lXft -lX11 -lXi -lm.
69 |
70 | This only runs under X, because of the way I build it, but FLTK purports to run on windows and macs, so if you can test that and help with the Makefile, I'd appreciate it.
71 |
72 |
73 | BUILDING
74 | ========
75 | To build, run "make" in the top-level directory. This assumes you have g++ installed, because FLTK is written in C++ and you need to use g++ to link the library so it can resolve mangled names.
76 |
77 | To install the library, run "make install".
78 |
79 | To build the examples, run "make examples".
80 |
81 | If you want to eliminate the fltk-library from your directory, you can run "make clean-fltk".
82 |
83 |
84 | EXAMPLES
85 | ========
86 | There are two examples: hello and text. Hello is the Hello World program from the [FLTK docs](http://www.fltk.org/doc-2.0/html/example1.html) and text is a window with a text field in it that steals the PUSH and DRAG events, printing a message and continuing the events.
87 |
--------------------------------------------------------------------------------
/src/fltk.cxx:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 | #include
6 | #include
7 | #include
8 | #include
9 | #include "fltk.h"
10 | //#include
11 |
12 | //#define debugf printf
13 | #define debugf(...)
14 | #define MAX_EVENT_TYPES 25
15 |
16 | Widget *go_fltk_callback_widget = 0;
17 | Widget *go_fltk_event_widget;
18 | int go_fltk_event;
19 | int go_fltk_event_state;
20 | int go_fltk_event_button;
21 | int go_fltk_event_clicks;
22 | int go_fltk_event_dx;
23 | int go_fltk_event_dy;
24 | int go_fltk_event_key;
25 | int go_fltk_event_x;
26 | int go_fltk_event_y;
27 | int go_fltk_event_x_root;
28 | int go_fltk_event_y_root;
29 | int go_fltk_event_stolen;
30 | int go_fltk_event_return;
31 |
32 | void set_event_fields(int evt) {
33 | go_fltk_event_widget = fltk::belowmouse();
34 | go_fltk_event = evt;
35 | go_fltk_event_state = fltk::event_state();
36 | go_fltk_event_button = fltk::event_button();
37 | go_fltk_event_clicks = fltk::event_clicks();
38 | go_fltk_event_dx = fltk::event_dx();
39 | go_fltk_event_dy = fltk::event_dy();
40 | go_fltk_event_key = fltk::event_key();
41 | go_fltk_event_x = fltk::event_x();
42 | go_fltk_event_y = fltk::event_y();
43 | go_fltk_event_x_root = fltk::event_x_root();
44 | go_fltk_event_y_root = fltk::event_y_root();
45 | }
46 |
47 | static void respond(int event);
48 |
49 | static void lock() {
50 | fltk::lock();
51 | }
52 |
53 | static void unlock() {
54 | fltk::awake();
55 | fltk::unlock();
56 | }
57 |
58 | class EventThief {
59 | public:
60 | int stealEvents;
61 | int event;
62 | virtual int continue_event(int event) = 0;
63 | int handle(int evt) {
64 | event = evt;
65 |
66 | if (fltk::belowmouse() == dynamic_cast(this)) {
67 | bool stolen = (stealEvents & (1 << evt)) != 0;
68 |
69 | debugf("widget: %x belowmouse: %x, event:%d\n", (unsigned int)dynamic_cast(this), (unsigned int)fltk::belowmouse(), evt);
70 | if (stolen) {
71 | go_fltk_event_stolen = 1;
72 | respond(evt);
73 | return (go_fltk_event_stolen == 0 ? continue_event(evt) : go_fltk_event_return);
74 | }
75 | go_fltk_event_return = continue_event(evt);
76 | respond(evt);
77 | return go_fltk_event_return;
78 | }
79 | return continue_event(evt);
80 | }
81 | };
82 |
83 | class GWidget : public EventThief, public fltk::Widget {
84 | public:
85 | GWidget(int x, int y, int w, int h, const char *label) : fltk::Widget(x, y, w, h, label) {}
86 | int handle(int event) {return EventThief::handle(event);}
87 | int continue_event(int event) {return fltk::Widget::handle(event);}
88 | };
89 |
90 | class GInput : public EventThief, public fltk::Input {
91 | public:
92 | int mouse_pos;
93 |
94 | GInput(int x, int y, int w, int h, const char *label) : fltk::Input(x, y, w, h, label) {}
95 | int handle(int event) {
96 | if (event == fltk::PUSH) {
97 | mouse_pos = mouse_position(*this);
98 | }
99 | return EventThief::handle(event);
100 | }
101 | int continue_event(int event) {return fltk::Input::handle(event);}
102 | };
103 |
104 | class GTextEditor : public EventThief, public fltk::TextEditor {
105 | public:
106 | int evt;
107 | GTextEditor(int x, int y, int w, int h, const char *label) : fltk::TextEditor(x, y, w, h, label) {}
108 | int handle(int event) {return EventThief::handle(event);}
109 | int continue_event(int event) {return fltk::TextEditor::handle(event);}
110 | };
111 |
112 | static void notify_callback(Widget *w, void *data) {
113 | go_fltk_callback_widget = w;
114 | respond(fltk::NO_EVENT);
115 | }
116 | #define LOCK(code) fltk::lock(); debugf("API LOCKED\n"); code; fltk::awake(); fltk::unlock(); debugf("API UNLOCKED\n");
117 |
118 | Box *go_fltk_get_UP_BOX() {LOCK(Box *b = fltk::UP_BOX;) return b;}
119 | Font *go_fltk_get_HELVETICA_BOLD_ITALIC() {LOCK(Font *f = fltk::HELVETICA_BOLD_ITALIC;) return f;}
120 | LabelType *go_fltk_get_SHADOW_LABEL() {LOCK(LabelType *t = fltk::SHADOW_LABEL;) return t;}
121 | //void go_fltk_run() {LOCK(fltk::run();)}
122 | Window *go_fltk_new_Window(int w, int h) {LOCK(Window *win = new Window(w, h);) return win;}
123 | PackedGroup *go_fltk_new_PackedGroup(int x, int y, int w, int h) {LOCK(PackedGroup *g = new PackedGroup(x, y, w, h);) return g;}
124 | Widget *go_fltk_new_Widget(int x, int y, int w, int h, const char *text) {LOCK(Widget *wid = new GWidget(x, y, w, h, text);) return wid;}
125 | Input *go_fltk_new_Input(int x, int y, int w, int h, const char *text) {LOCK(Input *i = new GInput(x, y, w, h, text);) return i;}
126 | TextEditor *go_fltk_new_TextEditor(int x, int y, int w, int h, const char *text) {LOCK(TextEditor *te = new GTextEditor(x, y, w, h, text);) return te;}
127 | //TextEditor *go_fltk_new_TextEditor(int x, int y, int w, int h, const char *text) {LOCK(TextEditor *te = new TextEditor(x, y, w, h, text);) return te;}
128 | void go_fltk_Widget_steal_events(Widget *w, int events) {LOCK(dynamic_cast(w)->stealEvents = events;)}
129 | void go_fltk_Event_continue() {LOCK(go_fltk_event_stolen = 0;)}
130 | void go_fltk_Group_begin(Group *g) {LOCK(g->begin();)}
131 | void go_fltk_Group_end(Group *g) {LOCK(g->end();)}
132 | void go_fltk_Group_add(Group *g, Widget *w) {LOCK(g->add(w);)}
133 | void go_fltk_Group_resizable(Group *g, Widget *w) {LOCK(g->resizable(w);)}
134 | void go_fltk_Window_destroy(Window *w) {LOCK(w->destroy();)}
135 | void go_fltk_Window_show(Window *w, int argc, void *argv) {LOCK(w->show(argc, (char **)argv);)}
136 | void go_fltk_Window_set_label(Window *w, const char *label) {LOCK(w->label(label);)}
137 | void go_fltk_Widget_box(Widget *w, Box *box) {LOCK(w->box(box);)}
138 | void go_fltk_Widget_callback(Widget *w) {LOCK(w->callback(notify_callback);)}
139 | void go_fltk_Widget_labelfont(Widget *w, Font *font) {LOCK(w->labelfont(font);)}
140 | void go_fltk_Widget_labelsize(Widget *w, int size) {LOCK(w->labelsize(size);)}
141 | void go_fltk_Widget_labeltype(Widget *w, LabelType *type) {LOCK(w->labeltype(type);)}
142 | int go_fltk_Widget_x(Widget *w) {LOCK(int i = w->x();) return i;}
143 | int go_fltk_Widget_y(Widget *w) {LOCK(int i = w->y();) return i;}
144 | int go_fltk_Widget_w(Widget *w) {LOCK(int i = w->w();) return i;}
145 | int go_fltk_Widget_h(Widget *w) {LOCK(int i = w->h();) return i;}
146 | void go_fltk_Widget_throw_focus(Widget *w) {LOCK(w->throw_focus());}
147 | const char *go_fltk_Input_get_text(Input *in) {LOCK(const char *t = in->text();); return t;}
148 | int go_fltk_Input_set_text(Input *in, const char *t) {LOCK(int b = in->text(t);); return b;}
149 | int go_fltk_Input_mouse_position(Input *in) {LOCK(int pos = dynamic_cast(in)->mouse_pos); return pos;}
150 | int go_fltk_Input_get_position(Input *in) {LOCK(int pos = in->position();); return pos;}
151 | int go_fltk_Input_get_mark(Input *in) {LOCK(int pos = in->mark();); return pos;}
152 | void go_fltk_Input_set_position(Input *in, int p, int m) {LOCK(in->position(p, m));}
153 | ////////////////
154 | /// CHANNELS ///
155 | ////////////////
156 |
157 | static fltk::SignalMutex eventMutex, continueMutex;
158 | static bool eventFlag = false, continueFlag = false;
159 | static bool running = false;
160 |
161 | static void respond(int evt) {
162 | if (running) {
163 | set_event_fields(evt);
164 | debugf("FLTK SENDING EVENT TO GO, UNLOCKING\n");
165 | unlock();
166 | eventFlag = true;
167 | eventMutex.signal();
168 | debugf("FLTK WAITING FOR CONTINUE FROM GO\n");
169 | while (!continueFlag) {continueMutex.wait();}
170 | continueFlag = false;
171 | debugf("FLTK GOT EVENT FROM GO, LOCKING\n");
172 | lock();
173 | debugf("FLTK LOCKED\n");
174 | }
175 | }
176 |
177 | //void *go_fltk_run(void *data) {
178 | void go_fltk_run() {
179 | lock();
180 | running = true;
181 | for (;;) {
182 | debugf("FLTK WAITING FOR EVENT\n");
183 | fltk::wait();
184 | }
185 | }
186 |
187 | void go_fltk_get_event() {
188 | while (!eventFlag) {eventMutex.wait();}
189 | eventFlag = false;
190 | }
191 | void go_fltk_continue_event(int i) {
192 | lock();
193 | continueFlag = true;
194 | go_fltk_event_widget = 0;
195 | go_fltk_callback_widget = 0;
196 | go_fltk_event_return = i;
197 | unlock();
198 | continueMutex.signal();
199 | }
200 |
--------------------------------------------------------------------------------