Added Area.OpenTextFieldAt() and implemented it on GTK+.

This commit is contained in:
Pietro Gagliardi 2014-08-22 11:29:44 -04:00
parent 20a65d96df
commit a48126cec7
3 changed files with 99 additions and 2 deletions

View File

@ -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 {

View File

@ -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

View File

@ -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() {