Example #1
0
func finishNewTable(b *tablebase, ty reflect.Type) Table {
	widget := C.gtk_tree_view_new()
	t := &table{
		scroller:  newScroller(widget, true, true, false), // natively scrollable; has a border; no overlay
		tablebase: b,
		treeview:  (*C.GtkTreeView)(unsafe.Pointer(widget)),
		crtocol:   make(map[*C.GtkCellRendererToggle]int),
		selected:  newEvent(),
	}
	model := C.newTableModel(unsafe.Pointer(t))
	t.model = model
	t.modelgtk = (*C.GtkTreeModel)(unsafe.Pointer(model))
	t.selection = C.gtk_tree_view_get_selection(t.treeview)
	g_signal_connect(
		C.gpointer(unsafe.Pointer(t.selection)),
		"changed",
		C.GCallback(C.tableSelectionChanged),
		C.gpointer(unsafe.Pointer(t)))
	C.gtk_tree_view_set_model(t.treeview, t.modelgtk)
	for i := 0; i < ty.NumField(); i++ {
		colname := ty.Field(i).Tag.Get("uicolumn")
		if colname == "" {
			colname = ty.Field(i).Name
		}
		cname := togstr(colname)
		switch {
		case ty.Field(i).Type == reflect.TypeOf((*image.RGBA)(nil)):
			// can't use GDK_TYPE_PIXBUF here because it's a macro that expands to a function and cgo hates that
			t.types = append(t.types, C.gdk_pixbuf_get_type())
			C.tableAppendColumn(t.treeview, C.gint(i), cname,
				C.gtk_cell_renderer_pixbuf_new(), attribPixbuf)
		case ty.Field(i).Type.Kind() == reflect.Bool:
			t.types = append(t.types, C.G_TYPE_BOOLEAN)
			cr := C.gtk_cell_renderer_toggle_new()
			crt := (*C.GtkCellRendererToggle)(unsafe.Pointer(cr))
			t.crtocol[crt] = i
			g_signal_connect(C.gpointer(unsafe.Pointer(cr)),
				"toggled",
				C.GCallback(C.goTableModel_toggled),
				C.gpointer(unsafe.Pointer(t)))
			C.tableAppendColumn(t.treeview, C.gint(i), cname,
				cr, attribActive)
		default:
			t.types = append(t.types, C.G_TYPE_STRING)
			C.tableAppendColumn(t.treeview, C.gint(i), cname,
				C.gtk_cell_renderer_text_new(), attribText)
		}
		freegstr(cname) // free now (not deferred) to conserve memory
	}
	// and for some GtkTreeModel boilerplate
	t.nColumns = C.gint(ty.NumField())
	return t
}
Example #2
0
func newWindow(title string, width int, height int, control Control) *window {
	widget := C.gtk_window_new(C.GTK_WINDOW_TOPLEVEL)
	ctitle := togstr(title)
	defer freegstr(ctitle)
	w := &window{
		widget:  widget,
		wc:      (*C.GtkContainer)(unsafe.Pointer(widget)),
		bin:     (*C.GtkBin)(unsafe.Pointer(widget)),
		window:  (*C.GtkWindow)(unsafe.Pointer(widget)),
		closing: newEvent(),
	}
	C.gtk_window_set_title(w.window, ctitle)
	g_signal_connect(
		C.gpointer(unsafe.Pointer(w.window)),
		"delete-event",
		C.GCallback(C.windowClosing),
		C.gpointer(unsafe.Pointer(w)))
	C.gtk_window_resize(w.window, C.gint(width), C.gint(height))
	w.container = newContainer(control)
	w.container.setParent(&controlParent{w.wc})
	// for dialogs; otherwise, they will be modal to all windows, not just this one
	w.group = C.gtk_window_group_new()
	C.gtk_window_group_add_window(w.group, w.window)
	return w
}
Example #3
0
func startNewTextField() *textfield {
	widget := C.gtk_entry_new()
	t := &textfield{
		_widget: widget,
		entry:   (*C.GtkEntry)(unsafe.Pointer(widget)),
		changed: newEvent(),
	}
	g_signal_connect(
		C.gpointer(unsafe.Pointer(t._widget)),
		"changed",
		C.GCallback(C.textfieldChanged),
		C.gpointer(unsafe.Pointer(t)))
	return t
}
Example #4
0
func startNewTextField() *textfield {
	widget := C.gtk_entry_new()
	t := &textfield{
		controlSingleWidget: newControlSingleWidget(widget),
		editable:            (*C.GtkEditable)(unsafe.Pointer(widget)),
		entry:               (*C.GtkEntry)(unsafe.Pointer(widget)),
		changed:             newEvent(),
	}
	g_signal_connect(
		C.gpointer(unsafe.Pointer(t.widget)),
		"changed",
		C.GCallback(C.textfieldChanged),
		C.gpointer(unsafe.Pointer(t)))
	return t
}
Example #5
0
func (w *window) openFile(f func(filename string)) {
	widget := C.newOpenFileDialog(w.window)
	window := (*C.GtkWindow)(unsafe.Pointer(widget))
	dialog := (*C.GtkDialog)(unsafe.Pointer(widget))
	fc := (*C.GtkFileChooser)(unsafe.Pointer(widget))
	C.gtk_file_chooser_set_local_only(fc, C.FALSE)
	C.gtk_file_chooser_set_select_multiple(fc, C.FALSE)
	C.gtk_file_chooser_set_show_hidden(fc, C.TRUE)
	C.gtk_window_set_modal(window, C.TRUE)
	g_signal_connect(
		C.gpointer(unsafe.Pointer(dialog)),
		"response",
		C.GCallback(C.our_openfile_response_callback),
		C.gpointer(unsafe.Pointer(&f)))
	C.gtk_widget_show_all(widget)
}
Example #6
0
// shared code for setting up buttons, check boxes, etc.
func newButton(text string) *button {
	ctext := togstr(text)
	defer freegstr(ctext)
	widget := C.gtk_button_new_with_label(ctext)
	b := &button{
		controlSingleWidget: newControlSingleWidget(widget),
		button:              (*C.GtkButton)(unsafe.Pointer(widget)),
		clicked:             newEvent(),
	}
	g_signal_connect(
		C.gpointer(unsafe.Pointer(b.button)),
		"clicked",
		C.GCallback(C.buttonClicked),
		C.gpointer(unsafe.Pointer(b)))
	return b
}
Example #7
0
func (w *window) openFile(f func(filename string)) {
	widget := C.newOpenFileDialog(w.window)
	window := (*C.GtkWindow)(unsafe.Pointer(widget))
	dialog := (*C.GtkDialog)(unsafe.Pointer(widget))
	fc := (*C.GtkFileChooser)(unsafe.Pointer(widget))
	// non-local filenames are relevant mainly to GIO where we can open *anything*, not to Go os.File; see https://twitter.com/braket/status/506142849654870016
	C.gtk_file_chooser_set_local_only(fc, C.TRUE)
	C.gtk_file_chooser_set_select_multiple(fc, C.FALSE)
	C.gtk_file_chooser_set_show_hidden(fc, C.TRUE)
	C.gtk_window_set_modal(window, C.TRUE)
	g_signal_connect(
		C.gpointer(unsafe.Pointer(dialog)),
		"response",
		C.GCallback(C.our_openfile_response_callback),
		C.gpointer(unsafe.Pointer(&f)))
	C.gtk_widget_show_all(widget)
}
Example #8
0
func newCheckbox(text string) *checkbox {
	ctext := togstr(text)
	defer freegstr(ctext)
	widget := C.gtk_check_button_new_with_label(ctext)
	c := &checkbox{
		_widget:  widget,
		button:   (*C.GtkButton)(unsafe.Pointer(widget)),
		toggle:   (*C.GtkToggleButton)(unsafe.Pointer(widget)),
		checkbox: (*C.GtkCheckButton)(unsafe.Pointer(widget)),
		toggled:  newEvent(),
	}
	g_signal_connect(
		C.gpointer(unsafe.Pointer(c.checkbox)),
		"toggled",
		C.GCallback(C.checkboxToggled),
		C.gpointer(unsafe.Pointer(c)))
	return c
}
Example #9
0
func newSpinbox(min int, max int) Spinbox {
	// gtk_spin_button_new_with_range() initially sets its value to the minimum value
	widget := C.gtk_spin_button_new_with_range(C.gdouble(min), C.gdouble(max), 1)
	s := &spinbox{
		controlSingleWidget: newControlSingleWidget(widget),
		spinbutton:          (*C.GtkSpinButton)(unsafe.Pointer(widget)),
		changed:             newEvent(),
	}
	C.gtk_spin_button_set_digits(s.spinbutton, 0)       // integers
	C.gtk_spin_button_set_numeric(s.spinbutton, C.TRUE) // digits only
	// this isn't specifically documented as the signal to connect to until 3.14
	// it has existed as far back as 3.4, though, if not earlier
	// there's also ::change-value which is for keyboard changing
	g_signal_connect(
		C.gpointer(unsafe.Pointer(s.spinbutton)),
		"value-changed",
		C.GCallback(C.spinboxChanged),
		C.gpointer(unsafe.Pointer(s)))
	return s
}
Example #10
0
func gdk_threads_add_idle(idleop *gtkIdleOp) {
	C.gdk_threads_add_idle(C.GCallback(C.our_idle_callback),
		C.gpointer(unsafe.Pointer(idleop)))
}
Example #11
0
// extern gboolean our_window_configure_event_callback(GtkWidget *, GdkEvent *, gpointer);
// extern void our_button_clicked_callback(GtkButton *, gpointer);
// extern gboolean our_idle_callback(gpointer);
// /* because cgo is flaky with macros; static inline because we have //exports */
// static inline void gSignalConnect(GtkWidget *widget, char *signal, GCallback callback, void *data) { g_signal_connect(widget, signal, callback, data); }
import "C"

//export our_window_delete_event_callback
func our_window_delete_event_callback(widget *C.GtkWidget, event *C.GdkEvent, what C.gpointer) C.gboolean {
	// called when the user tries to close the window
	s := (*sysData)(unsafe.Pointer(what))
	s.signal()
	return C.TRUE // do not close the window
}

var window_delete_event_callback = C.GCallback(C.our_window_delete_event_callback)

//export our_window_configure_event_callback
func our_window_configure_event_callback(widget *C.GtkWidget, event *C.GdkEvent, what C.gpointer) C.gboolean {
	// called when the window is resized
	s := (*sysData)(unsafe.Pointer(what))
	if s.container != nil && s.allocate != nil { // wait for init
		width, height := gtk_window_get_size(s.widget)
		// top-left is (0,0) here
		s.resizeWindow(width, height)
	}
	// no need to manually redraw everything: since we use gtk_widget_set_size_request(), that queues both resize and redraw for us (thanks Company in irc.gimp.net/#gtk+)
	return C.FALSE // continue the event chain
}

var window_configure_event_callback = C.GCallback(C.our_window_configure_event_callback)
Example #12
0
	C.cairo_surface_flush(surface)
	toARGB(i, uintptr(unsafe.Pointer(C.cairo_image_surface_get_data(surface))),
		int(C.cairo_image_surface_get_stride(surface)))
	C.cairo_surface_mark_dirty(surface)
	C.cairo_set_source_surface(cr,
		surface,
		0, 0) // origin of the surface
	// that just set the brush that cairo uses: we have to actually draw now
	// (via https://developer.gnome.org/gtkmm-tutorial/stable/sec-draw-images.html.en)
	C.cairo_rectangle(cr, x0, y0, x1, y1) // breaking the nrom here since we have the coordinates as a C double already
	C.cairo_fill(cr)
	C.cairo_surface_destroy(surface) // free surface
	return C.FALSE                   // signals handled without stopping the event chain (thanks to desrt again)
}

var area_draw_callback = C.GCallback(C.our_area_draw_callback)

func translateModifiers(state C.guint, window *C.GdkWindow) C.guint {
	// GDK doesn't initialize the modifier flags fully; we have to explicitly tell it to (thanks to Daniel_S and daniels (two different people) in irc.gimp.net/#gtk+)
	C.gdk_keymap_add_virtual_modifiers(
		C.gdk_keymap_get_for_display(C.gdk_window_get_display(window)),
		(*C.GdkModifierType)(unsafe.Pointer(&state)))
	return state
}

func makeModifiers(state C.guint) (m Modifiers) {
	if (state & C.GDK_CONTROL_MASK) != 0 {
		m |= Ctrl
	}
	if (state & C.GDK_META_MASK) != 0 { // TODO get equivalent for Alt
		m |= Alt
Example #13
0
}

//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_populate_popup_callback
func our_area_textfield_populate_popup_callback(entry *C.GtkEntry, menu *C.GtkMenu, data C.gpointer) {
	a := (*area)(unsafe.Pointer(data))
	a.inmenu = true
}

var area_textfield_populate_popup_callback = C.GCallback(C.our_area_textfield_populate_popup_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))
	if !a.inmenu {
		C.gtk_widget_hide(a.textfieldw)
		a.textfielddone.fire()
Example #14
0
		}()
		return
	}
	// otherwise just connect the delete signal
	g_signal_connect_pointer(box, "response", dialog_response_callback, unsafe.Pointer(d))
	C.gtk_widget_show_all(box)
}

//export our_dialog_response_callback
func our_dialog_response_callback(box *C.GtkDialog, res C.gint, data C.gpointer) {
	d := (*dialog)(unsafe.Pointer(data))
	d.cleanup((*C.GtkWidget)(unsafe.Pointer(box)))
	go d.send(res) // send on another goroutine, like everything else
}

var dialog_response_callback = C.GCallback(C.our_dialog_response_callback)

func (d *dialog) cleanup(box *C.GtkWidget) {
	// have to explicitly close the dialog box, otherwise wacky things will happen
	C.gtk_widget_destroy(box)
	if d.parent != dialogWindow {
		C.gtk_window_group_remove_window(d.newgroup, d.pwin)
		C.g_object_unref(C.gpointer(unsafe.Pointer(d.newgroup))) // free the group
		if d.prevgroup != nil {
			C.gtk_window_group_add_window(d.prevgroup, d.pwin)
		} // otherwise it'll go back into the default group on its own
	}
}

func (d *dialog) send(res C.gint) {
	// this is where processing would go