Added Area.OpenTextFieldAt() and implemented it on GTK+.
This commit is contained in:
parent
20a65d96df
commit
a48126cec7
16
redo/area.go
16
redo/area.go
|
@ -27,7 +27,7 @@ import (
|
||||||
// Character processing methods differ across operating
|
// Character processing methods differ across operating
|
||||||
// systems; trying ot recreate these yourself is only going
|
// systems; trying ot recreate these yourself is only going
|
||||||
// to lead to trouble.
|
// 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 {
|
type Area interface {
|
||||||
Control
|
Control
|
||||||
|
|
||||||
|
@ -44,6 +44,20 @@ type Area interface {
|
||||||
|
|
||||||
// RepaintAll marks the entirety of the Area as needing to be redrawn.
|
// RepaintAll marks the entirety of the Area as needing to be redrawn.
|
||||||
RepaintAll()
|
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 {
|
type areabase struct {
|
||||||
|
|
|
@ -11,6 +11,8 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
// #include "gtk_unix.h"
|
// #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_draw_callback(GtkWidget *, cairo_t *, gpointer);
|
||||||
// extern gboolean our_area_button_press_event_callback(GtkWidget *, GdkEvent *, gpointer);
|
// extern gboolean our_area_button_press_event_callback(GtkWidget *, GdkEvent *, gpointer);
|
||||||
// extern gboolean our_area_button_release_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
|
scroller *scroller
|
||||||
|
|
||||||
clickCounter *clickCounter
|
clickCounter *clickCounter
|
||||||
|
|
||||||
|
textfieldw *C.GtkWidget
|
||||||
|
textfield *C.GtkEntry
|
||||||
|
textfieldx int
|
||||||
|
textfieldy int
|
||||||
|
textfielddone *event
|
||||||
}
|
}
|
||||||
|
|
||||||
func newArea(ab *areabase) Area {
|
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)
|
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
|
// and we need to allow focusing on a GtkDrawingArea to enable keyboard events
|
||||||
C.gtk_widget_set_can_focus(widget, C.TRUE)
|
C.gtk_widget_set_can_focus(widget, C.TRUE)
|
||||||
|
textfieldw := C.gtk_entry_new()
|
||||||
a := &area{
|
a := &area{
|
||||||
areabase: ab,
|
areabase: ab,
|
||||||
_widget: widget,
|
_widget: widget,
|
||||||
drawingarea: (*C.GtkDrawingArea)(unsafe.Pointer(widget)),
|
drawingarea: (*C.GtkDrawingArea)(unsafe.Pointer(widget)),
|
||||||
scroller: newScroller(widget, false, false, true), // not natively scrollable; no border; have an overlay for OpenTextFieldAt()
|
scroller: newScroller(widget, false, false, true), // not natively scrollable; no border; have an overlay for OpenTextFieldAt()
|
||||||
clickCounter: new(clickCounter),
|
clickCounter: new(clickCounter),
|
||||||
|
textfieldw: textfieldw,
|
||||||
|
textfield: (*C.GtkEntry)(unsafe.Pointer(textfieldw)),
|
||||||
|
textfielddone: newEvent(),
|
||||||
}
|
}
|
||||||
for _, c := range areaCallbacks {
|
for _, c := range areaCallbacks {
|
||||||
g_signal_connect(
|
g_signal_connect(
|
||||||
|
@ -61,6 +73,19 @@ func newArea(ab *areabase) Area {
|
||||||
C.gpointer(unsafe.Pointer(a)))
|
C.gpointer(unsafe.Pointer(a)))
|
||||||
}
|
}
|
||||||
a.SetSize(a.width, a.height)
|
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
|
return a
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -83,6 +108,55 @@ func (a *area) RepaintAll() {
|
||||||
C.gtk_widget_queue_draw(a._widget)
|
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 {
|
var areaCallbacks = []struct {
|
||||||
name string
|
name string
|
||||||
callback C.GCallback
|
callback C.GCallback
|
||||||
|
|
|
@ -56,7 +56,16 @@ func (r *repainter) Paint(rect image.Rectangle) *image.RGBA {
|
||||||
return r.img.SubImage(rect).(*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) Key(ke KeyEvent) bool { return false }
|
||||||
|
|
||||||
func (r *repainter) setx() {
|
func (r *repainter) setx() {
|
||||||
|
|
Loading…
Reference in New Issue