summaryrefslogtreecommitdiff
path: root/redo
diff options
context:
space:
mode:
Diffstat (limited to 'redo')
-rw-r--r--redo/area.go16
-rw-r--r--redo/area_unix.go74
-rw-r--r--redo/yz_repaint_test.go11
3 files changed, 99 insertions, 2 deletions
diff --git a/redo/area.go b/redo/area.go
index 829fc33..cd7f3e1 100644
--- a/redo/area.go
+++ b/redo/area.go
@@ -27,7 +27,7 @@ import (
// Character processing methods differ across operating
// systems; trying ot recreate these yourself is only going
// to lead to trouble.
-// [FOR FUTURE PLANNING Use TextArea instead, providing a TextAreaHandler.]
+// If you absolutely need to enter text somehow, use OpenTextFieldAt() and its related methods.
type Area interface {
Control
@@ -44,6 +44,20 @@ type Area interface {
// RepaintAll marks the entirety of the Area as needing to be redrawn.
RepaintAll()
+
+ // OpenTextFieldAt opens a TextField with the top-left corner at the given coordinates of the Area.
+ // It panics if the coordinates fall outside the Area.
+ // Any text previously in the TextField is removed.
+ // The TextField receives the input focus so the user can type things; when the TextField loses the input focus, it hides itself and signals the event set by OnTextFieldDismissed.
+ // TODO escape key
+ OpenTextFieldAt(x int, y int)
+
+ // TextFieldText and TextFieldSetText get and set the OpenTextFieldAt TextField's text, respectively.
+ TextFieldText() string
+ SetTextFieldText(text string)
+
+ // OnTextFieldDismissed is an event that is fired when the OpenTextFieldAt TextField is dismissed.
+ OnTextFieldDismissed(f func())
}
type areabase struct {
diff --git a/redo/area_unix.go b/redo/area_unix.go
index 7cee97b..ed52beb 100644
--- a/redo/area_unix.go
+++ b/redo/area_unix.go
@@ -11,6 +11,8 @@ import (
)
// #include "gtk_unix.h"
+// extern gboolean our_area_get_child_position_callback(GtkOverlay *, GtkWidget *, GdkRectangle *, gpointer);
+// extern gboolean our_area_textfield_focus_out_event_callback(GtkWidget *, GdkEvent *, gpointer);
// extern gboolean our_area_draw_callback(GtkWidget *, cairo_t *, gpointer);
// extern gboolean our_area_button_press_event_callback(GtkWidget *, GdkEvent *, gpointer);
// extern gboolean our_area_button_release_event_callback(GtkWidget *, GdkEvent *, gpointer);
@@ -36,6 +38,12 @@ type area struct {
scroller *scroller
clickCounter *clickCounter
+
+ textfieldw *C.GtkWidget
+ textfield *C.GtkEntry
+ textfieldx int
+ textfieldy int
+ textfielddone *event
}
func newArea(ab *areabase) Area {
@@ -46,12 +54,16 @@ func newArea(ab *areabase) Area {
C.GDK_BUTTON_PRESS_MASK|C.GDK_BUTTON_RELEASE_MASK|C.GDK_POINTER_MOTION_MASK|C.GDK_BUTTON_MOTION_MASK|C.GDK_ENTER_NOTIFY_MASK|C.GDK_LEAVE_NOTIFY_MASK)
// and we need to allow focusing on a GtkDrawingArea to enable keyboard events
C.gtk_widget_set_can_focus(widget, C.TRUE)
+ textfieldw := C.gtk_entry_new()
a := &area{
areabase: ab,
_widget: widget,
drawingarea: (*C.GtkDrawingArea)(unsafe.Pointer(widget)),
scroller: newScroller(widget, false, false, true), // not natively scrollable; no border; have an overlay for OpenTextFieldAt()
clickCounter: new(clickCounter),
+ textfieldw: textfieldw,
+ textfield: (*C.GtkEntry)(unsafe.Pointer(textfieldw)),
+ textfielddone: newEvent(),
}
for _, c := range areaCallbacks {
g_signal_connect(
@@ -61,6 +73,19 @@ func newArea(ab *areabase) Area {
C.gpointer(unsafe.Pointer(a)))
}
a.SetSize(a.width, a.height)
+ C.gtk_overlay_add_overlay(a.scroller.overlay, a.textfieldw)
+ g_signal_connect(
+ C.gpointer(unsafe.Pointer(a.scroller.overlay)),
+ "get-child-position",
+ area_get_child_position_callback,
+ C.gpointer(unsafe.Pointer(a)))
+ g_signal_connect(
+ C.gpointer(unsafe.Pointer(a.textfield)),
+ "focus-out-event",
+ area_textfield_focus_out_event_callback,
+ C.gpointer(unsafe.Pointer(a)))
+ // the widget shows up initially
+ C.gtk_widget_hide(a.textfieldw)
return a
}
@@ -83,6 +108,55 @@ func (a *area) RepaintAll() {
C.gtk_widget_queue_draw(a._widget)
}
+func (a *area) OpenTextFieldAt(x, y int) {
+ if x < 0 || x >= a.width || y < 0 || y >= a.height {
+ panic(fmt.Errorf("point (%d,%d) outside Area in Area.OpenTextFieldAt()", x, y))
+ }
+ a.textfieldx = x
+ a.textfieldy = y
+ a.SetTextFieldText("")
+ C.gtk_widget_show_all(a.textfieldw)
+ C.gtk_widget_grab_focus(a.textfieldw)
+}
+
+func (a *area) TextFieldText() string {
+ return fromgstr(C.gtk_entry_get_text(a.textfield))
+}
+
+func (a *area) SetTextFieldText(text string) {
+ ctext := togstr(text)
+ defer freegstr(ctext)
+ C.gtk_entry_set_text(a.textfield, ctext)
+}
+
+func (a *area) OnTextFieldDismissed(f func()) {
+ a.textfielddone.set(f)
+}
+
+//export our_area_get_child_position_callback
+func our_area_get_child_position_callback(overlay *C.GtkOverlay, widget *C.GtkWidget, rect *C.GdkRectangle, data C.gpointer) C.gboolean {
+ var nat C.GtkRequisition
+
+ a := (*area)(unsafe.Pointer(data))
+ rect.x = C.int(a.textfieldx)
+ rect.y = C.int(a.textfieldy)
+ C.gtk_widget_get_preferred_size(a.textfieldw, nil, &nat)
+ rect.width = C.int(nat.width)
+ rect.height = C.int(nat.height)
+ return C.TRUE
+}
+
+var area_get_child_position_callback = C.GCallback(C.our_area_get_child_position_callback)
+
+//export our_area_textfield_focus_out_event_callback
+func our_area_textfield_focus_out_event_callback(widget *C.GtkWidget, event *C.GdkEvent, data C.gpointer) C.gboolean {
+ a := (*area)(unsafe.Pointer(data))
+ C.gtk_widget_hide(a.textfieldw)
+ return continueEventChain
+}
+
+var area_textfield_focus_out_event_callback = C.GCallback(C.our_area_textfield_focus_out_event_callback)
+
var areaCallbacks = []struct {
name string
callback C.GCallback
diff --git a/redo/yz_repaint_test.go b/redo/yz_repaint_test.go
index 254c079..5783bac 100644
--- a/redo/yz_repaint_test.go
+++ b/redo/yz_repaint_test.go
@@ -56,7 +56,16 @@ func (r *repainter) Paint(rect image.Rectangle) *image.RGBA {
return r.img.SubImage(rect).(*image.RGBA)
}
-func (r *repainter) Mouse(me MouseEvent) {}
+func (r *repainter) Mouse(me MouseEvent) {
+ if me.Up == 1 {
+ r.area.OpenTextFieldAt(me.Pos.X, me.Pos.Y)
+ }
+}
+
+func (r *repainter) tfdone() {
+ println(r.area.TextFieldText())
+}
+
func (r *repainter) Key(ke KeyEvent) bool { return false }
func (r *repainter) setx() {