示例#1
0
文件: gtk.go 项目: jwilkins/pond
func (ui *GTKUI) handle(action interface{}) {
	switch action := action.(type) {
	case Reset:
		ui.widgets = make(map[string]gtk.WidgetLike)
		ui.entries = make(map[string]*gtk.GtkEntry)
		ui.textViews = make(map[string]*gtk.GtkTextView)
		ui.combos = make(map[string]*gtk.GtkComboBoxText)
		ui.radioGroups = make(map[string]int)
		ui.checks = make(map[string]*gtk.GtkCheckButton)
		ui.radioGroups = make(map[string]int)
		ui.calendars = make(map[string]*gtk.GtkCalendar)
		ui.spinButtons = make(map[string]*gtk.GtkSpinButton)

		if ui.topWidget != nil {
			ui.window.Remove(ui.topWidget)
			ui.topWidget = nil
		}
		ui.topWidget = ui.newWidget(action.root)
		ui.window.Add(ui.topWidget)
		ui.window.ShowAll()
	case Append:
		box := ui.getWidget(action.name).(gtk.BoxLike)
		for _, child := range action.children {
			widget := ui.newWidget(child)
			box.PackStart(widget, child.Expand(), child.Fill(), child.Padding())
		}
		ui.window.ShowAll()
	case AddToBox:
		box := ui.getWidget(action.box).(gtk.BoxLike)
		widget := ui.newWidget(action.child)
		box.PackStart(widget, action.child.Expand(), action.child.Fill(), action.child.Padding())
		box.ReorderChild(widget, action.pos)
		ui.window.ShowAll()
	case SetChild:
		bin := gtk.GtkBin{gtk.GtkContainer{gtk.GtkWidget{ui.getWidget(action.name).ToNative()}}}
		for _, child := range bin.GetChildren() {
			child.Destroy()
		}
		bin.Add(ui.newWidget(action.child))
		ui.window.ShowAll()
	case SetBoxContents:
		box := gtk.GtkBox{gtk.GtkContainer{gtk.GtkWidget{ui.getWidget(action.name).ToNative()}}}
		for _, child := range box.GetChildren() {
			child.Destroy()
		}
		child := action.child
		widget := ui.newWidget(child)
		box.PackStart(widget, child.Expand(), child.Fill(), child.Padding())
		ui.window.ShowAll()
	case SetBackground:
		widget := gtk.GtkWidget{ui.getWidget(action.name).ToNative()}
		widget.OverrideBackgroundColor(gtk.GTK_STATE_FLAG_NORMAL, toColor(action.color))
	case Sensitive:
		widget := gtk.GtkWidget{ui.getWidget(action.name).ToNative()}
		widget.SetSensitive(action.sensitive)
	case StartSpinner:
		widget := gtk.GtkSpinner{gtk.GtkWidget{ui.getWidget(action.name).ToNative()}}
		widget.Start()
	case StopSpinner:
		widget := gtk.GtkSpinner{gtk.GtkWidget{ui.getWidget(action.name).ToNative()}}
		widget.Stop()
	case SetText:
		widget := gtk.GtkLabel{gtk.GtkWidget{ui.getWidget(action.name).ToNative()}}
		widget.SetText(action.text)
	case SetButtonText:
		widget := gtk.GtkButton{gtk.GtkBin{gtk.GtkContainer{gtk.GtkWidget{ui.getWidget(action.name).ToNative()}}}}
		widget.SetLabel(action.text)
	case SetEntry:
		widget := ui.getWidget(action.name).(gtk.TextInputLike)
		widget.SetText(action.text)
	case SetTextView:
		widget := gtk.GtkTextView{gtk.GtkContainer{gtk.GtkWidget{ui.getWidget(action.name).ToNative()}}}
		buffer := gtk.TextBuffer(gtk.TextTagTable())
		buffer.SetText(action.text)
		widget.SetBuffer(buffer)
	case ScrollTextViewToEnd:
		widget := gtk.GtkTextView{gtk.GtkContainer{gtk.GtkWidget{ui.getWidget(action.name).ToNative()}}}
		mark := widget.GetBuffer().GetMark("insert")
		widget.ScrollToMark(mark, 0.0, true, 0, 1)
	case SetImage:
		widget := gtk.GtkImage{gtk.GtkWidget{ui.getWidget(action.name).ToNative()}}
		widget.SetFromPixbuf(action.image.Image())
	case SetFocus:
		widget := gtk.GtkWidget{ui.getWidget(action.name).ToNative()}
		widget.GrabFocus()
	case Destroy:
		widget := gtk.GtkWidget{ui.getWidget(action.name).ToNative()}
		widget.Destroy()
		delete(ui.widgets, action.name)
	case FileOpen:
		fileAction := gtk.GTK_FILE_CHOOSER_ACTION_OPEN
		button := gtk.GTK_STOCK_OPEN
		if action.save {
			fileAction = gtk.GTK_FILE_CHOOSER_ACTION_SAVE
			button = gtk.GTK_STOCK_SAVE
		}
		dialog := gtk.FileChooserDialog(action.title, ui.window, fileAction, gtk.GTK_STOCK_CANCEL, int(gtk.GTK_RESPONSE_CANCEL), button, int(gtk.GTK_RESPONSE_ACCEPT))
		if action.save {
			if len(action.filename) > 0 {
				dialog.SetCurrentName(action.filename)
			} else {
				panic("save dialog without filename")
			}
		}
		switch gtk.GtkResponseType(dialog.Run()) {
		case gtk.GTK_RESPONSE_ACCEPT:
			ui.events <- OpenResult{
				ok:   true,
				path: dialog.GetFilename(),
				arg:  action.arg,
			}
		default:
			ui.events <- OpenResult{arg: action.arg}
		}
		dialog.Destroy()
	case SetForeground:
		widget := gtk.GtkWidget{ui.getWidget(action.name).ToNative()}
		widget.OverrideColor(gtk.GTK_STATE_FLAG_NORMAL, toColor(action.foreground))
	case SetProgress:
		widget := gtk.GtkProgressBar{gtk.GtkWidget{ui.getWidget(action.name).ToNative()}}
		widget.SetFraction(action.fraction)
		widget.SetText(action.s)
	case SetTitle:
		ui.window.SetTitle(action.title)
	case InsertRow:
		grid := gtk.GtkGrid{gtk.GtkContainer{gtk.GtkWidget{ui.getWidget(action.name).ToNative()}}}
		x := 0
		for _, elem := range action.row {
			if elem.widget != nil {
				grid.Attach(ui.newWidget(elem.widget), x, action.pos, elem.width, elem.height)
			}
			x += elem.width
		}
		ui.window.ShowAll()
	case GridSet:
		grid := gtk.GtkGrid{gtk.GtkContainer{gtk.GtkWidget{ui.getWidget(action.name).ToNative()}}}
		grid.Attach(ui.newWidget(action.widget), action.col, action.row, 1, 1)
		ui.window.ShowAll()

	case UIError:
	case UIState:
		// for testing.
	default:
		panic("unknown action")
	}
}
示例#2
0
文件: gtk.go 项目: shpedoikal/pond
func (ui *GTKUI) handle(action interface{}) {
	switch action := action.(type) {
	case Reset:
		ui.widgets = make(map[string]gtk.WidgetLike)
		ui.entries = make(map[string]*gtk.GtkEntry)
		ui.textViews = make(map[string]*gtk.GtkTextView)
		ui.combos = make(map[string]*gtk.GtkComboBox)
		if ui.topWidget != nil {
			ui.window.Remove(ui.topWidget)
			ui.topWidget = nil
		}
		ui.topWidget = ui.newWidget(action.root)
		ui.window.Add(ui.topWidget)
		ui.window.ShowAll()
	case Append:
		box := ui.getWidget(action.name).(gtk.BoxLike)
		for _, child := range action.children {
			widget := ui.newWidget(child)
			box.PackStart(widget, child.Expand(), child.Fill(), child.Padding())
		}
		ui.window.ShowAll()
	case AddToBox:
		box := ui.getWidget(action.box).(gtk.BoxLike)
		widget := ui.newWidget(action.child)
		box.PackStart(widget, action.child.Expand(), action.child.Fill(), action.child.Padding())
		box.ReorderChild(widget, action.pos)
		ui.window.ShowAll()
	case SetChild:
		bin := gtk.GtkBin{gtk.GtkContainer{gtk.GtkWidget{ui.getWidget(action.name).ToNative()}}}
		for _, child := range bin.GetChildren() {
			child.Destroy()
		}
		bin.Add(ui.newWidget(action.child))
		ui.window.ShowAll()
	case SetBoxContents:
		box := gtk.GtkBox{gtk.GtkContainer{gtk.GtkWidget{ui.getWidget(action.name).ToNative()}}}
		for _, child := range box.GetChildren() {
			child.Destroy()
		}
		child := action.child
		widget := ui.newWidget(child)
		box.PackStart(widget, child.Expand(), child.Fill(), child.Padding())
		ui.window.ShowAll()
	case SetBackground:
		widget := gtk.GtkWidget{ui.getWidget(action.name).ToNative()}
		widget.ModifyBG(gtk.GTK_STATE_NORMAL, toColor(action.color))
	case Sensitive:
		widget := gtk.GtkWidget{ui.getWidget(action.name).ToNative()}
		widget.SetSensitive(action.sensitive)
	case StartSpinner:
		widget := gtk.GtkSpinner{gtk.GtkWidget{ui.getWidget(action.name).ToNative()}}
		widget.Start()
	case StopSpinner:
		widget := gtk.GtkSpinner{gtk.GtkWidget{ui.getWidget(action.name).ToNative()}}
		widget.Stop()
	case SetText:
		widget := gtk.GtkLabel{gtk.GtkWidget{ui.getWidget(action.name).ToNative()}}
		widget.SetText(action.text)
	case SetTextView:
		widget := gtk.GtkTextView{gtk.GtkContainer{gtk.GtkWidget{ui.getWidget(action.name).ToNative()}}}
		buffer := gtk.TextBuffer(gtk.TextTagTable())
		buffer.SetText(action.text)
		widget.SetBuffer(buffer)
	case SetImage:
		widget := gtk.GtkImage{gtk.GtkWidget{ui.getWidget(action.name).ToNative()}}
		widget.SetFromPixbuf(action.image.Image())
	case SetFocus:
		widget := gtk.GtkWidget{ui.getWidget(action.name).ToNative()}
		widget.GrabFocus()
	case Destroy:
		widget := gtk.GtkWidget{ui.getWidget(action.name).ToNative()}
		widget.Destroy()
	case FileOpen:
		fileAction := gtk.GTK_FILE_CHOOSER_ACTION_OPEN
		but := gtk.GTK_STOCK_OPEN
		if action.save {
			fileAction = gtk.GTK_FILE_CHOOSER_ACTION_SAVE
			but = gtk.GTK_STOCK_SAVE
		}
		dialog := gtk.FileChooserDialog(action.title, ui.window, fileAction, gtk.GTK_STOCK_CANCEL, int(gtk.GTK_RESPONSE_CANCEL), but, int(gtk.GTK_RESPONSE_ACCEPT))
		switch gtk.GtkResponseType(dialog.Run()) {
		case gtk.GTK_RESPONSE_ACCEPT:
			ui.events <- OpenResult{
				ok:   true,
				path: dialog.GetFilename(),
				arg:  action.arg,
			}
		default:
			ui.events <- OpenResult{arg: action.arg}
		}
		dialog.Destroy()
	case SetForeground:
		widget := gtk.GtkWidget{ui.getWidget(action.name).ToNative()}
		widget.ModifyFG(gtk.GTK_STATE_NORMAL, toColor(action.foreground))
	case UIError:
	case UIState:
		// for testing.
	default:
		panic("unknown action")
	}
}
示例#3
0
文件: gtk.go 项目: jwilkins/pond
func (ui *GTKUI) createWidget(v interface{}) gtk.WidgetLike {
	switch v := v.(type) {
	case VBox:
		vbox := gtk.Box(gtk.GTK_ORIENTATION_VERTICAL, v.spacing)
		for _, child := range v.children {
			widget := ui.newWidget(child)
			if child.PackEnd() {
				vbox.PackEnd(widget, child.Expand(), child.Fill(), child.Padding())
			} else {
				vbox.PackStart(widget, child.Expand(), child.Fill(), child.Padding())
			}
		}
		return vbox
	case HBox:
		hbox := gtk.Box(gtk.GTK_ORIENTATION_HORIZONTAL, v.spacing)
		for _, child := range v.children {
			widget := ui.newWidget(child)
			hbox.PackStart(widget, child.Expand(), child.Fill(), child.Padding())
		}
		return hbox
	case EventBox:
		box := gtk.EventBox()
		if v.child != nil {
			widget := ui.newWidget(v.child)
			box.Add(widget)
		}
		configureWidget(&box.GtkWidget, v.widgetBase)
		if len(v.name) > 0 {
			box.Connect("button-press-event", func(e interface{}) {
				ui.clicked(v.name)
			})
		}
		return box
	case Label:
		label := gtk.Label(v.text)
		if len(v.markup) > 0 {
			label.SetMarkup(v.markup)
		}
		label.SetAlignment(v.xAlign, v.yAlign)
		configureWidget(&label.GtkWidget, v.widgetBase)
		if v.wrap != 0 {
			label.SetSizeRequest(v.wrap, -1)
			label.SetLineWrap(true)
		}
		label.SetSelectable(v.selectable)
		return label
	case Entry:
		entry := gtk.Entry()
		entry.SetText(v.text)
		if v.width > 0 {
			entry.SetWidthChars(v.width)
		}
		if name := v.name; len(name) > 0 {
			ui.entries[name] = entry
			entry.Connect("destroy", func() {
				delete(ui.entries, name)
			})
			entry.Connect("activate", func() {
				ui.clicked(v.name)
			})
			if v.updateOnChange {
				entry.Connect("changed", func() {
					ui.updatedEntry(v.name)
				})
			}
		}
		if v.password {
			entry.SetVisibility(false)
		}
		configureWidget(&entry.GtkWidget, v.widgetBase)
		return entry
	case Button:
		var button *gtk.GtkButton
		if len(v.text) > 0 {
			button = gtk.ButtonWithLabel(v.text)
		} else {
			button = gtk.Button()
			if len(v.markup) > 0 {
				label := gtk.Label("")
				label.SetMarkup(v.markup)
				button.Add(label)
			}
		}
		if v.image != indicatorNone {
			image := gtk.ImageFromPixbuf(v.image.Image())
			button.Add(image)
		}
		button.Clicked(func() {
			ui.clicked(v.name)
		})
		configureWidget(&button.GtkWidget, v.widgetBase)
		return button
	case Spinner:
		spinner := gtk.Spinner()
		spinner.Start()
		return spinner
	case Paned:
		paned := gtk.Paned(gtk.GTK_ORIENTATION_HORIZONTAL)
		left := ui.newWidget(v.left)
		right := ui.newWidget(v.right)
		paned.Add1(left)
		paned.Add2(right)
		return paned
	case Scrolled:
		scrolled := gtk.ScrolledWindow(nil, nil)
		horizonalPolicy := gtk.GtkPolicyType(gtk.GTK_POLICY_NEVER)
		if v.horizontal {
			horizonalPolicy = gtk.GTK_POLICY_AUTOMATIC
		}
		scrolled.SetPolicy(horizonalPolicy, gtk.GTK_POLICY_AUTOMATIC)
		child := ui.newWidget(v.child)
		if v.viewport {
			scrolled.AddWithViewPort(child)
		} else {
			scrolled.Add(child)
		}
		return scrolled
	case TextView:
		view := gtk.TextView()
		view.SetBorderWidth(1)
		view.SetEditable(v.editable)
		if len(v.text) > 0 {
			buffer := gtk.TextBuffer(gtk.TextTagTable())
			buffer.SetText(v.text)
			view.SetBuffer(buffer)
		}
		if v.wrap {
			view.SetWrapMode(gtk.GTK_WRAP_WORD_CHAR)
		}
		if v.updateOnChange && len(v.name) > 0 {
			view.GetBuffer().Connect("changed", func() {
				ui.updated(v.name)
			})
		}
		if v.spellCheck {
			if _, err := gtkspell.New(view, ""); err != nil {
				panic(err)
			}
		}
		if name := v.name; len(name) > 0 {
			ui.textViews[name] = view
			view.Connect("destroy", func() {
				delete(ui.textViews, name)
			})
		}
		configureWidget(&view.GtkWidget, v.widgetBase)
		return view
	case Combo:
		combo := gtk.ComboBoxText()
		selectedIndex := -1
		for i, l := range v.labels {
			combo.AppendText(l)
			if len(v.preSelected) > 0 && l == v.preSelected {
				selectedIndex = i
			}
		}
		if selectedIndex >= 0 {
			combo.SetActive(selectedIndex)
		}
		if name := v.name; len(name) > 0 {
			ui.combos[name] = combo
			combo.Connect("destroy", func() {
				delete(ui.combos, name)
			})
			combo.Connect("changed", func() {
				ui.clicked(v.name)
			})
		}
		configureWidget(&combo.GtkWidget, v.widgetBase)
		return combo
	case Image:
		image := gtk.ImageFromPixbuf(v.image.Image())
		image.SetAlignment(v.xAlign, v.yAlign)
		configureWidget(&image.GtkWidget, v.widgetBase)
		return image
	case Frame:
		frame := gtk.Frame("")
		configureWidget(&frame.GtkWidget, v.widgetBase)
		if v.child != nil {
			widget := ui.newWidget(v.child)
			frame.Add(widget)
		}
		return frame
	case Progress:
		pro := gtk.ProgressBar()
		configureWidget(&pro.GtkWidget, v.widgetBase)
		return pro
	case Grid:
		grid := gtk.Grid()
		configureWidget(&grid.GtkWidget, v.widgetBase)
		for y, row := range v.rows {
			x := 0
			for _, elem := range row {
				if elem.widget != nil {
					grid.Attach(ui.newWidget(elem.widget), x, y, elem.width, elem.height)
				}
				x += elem.width
			}
		}
		if v.rowSpacing > 0 {
			grid.SetRowSpacing(v.rowSpacing)
		}
		if v.colSpacing > 0 {
			grid.SetColSpacing(v.colSpacing)
		}
		if v.rowHomogeneous {
			grid.SetRowHomogeneous(true)
		}
		if v.colHomogeneous {
			grid.SetColumnHomogeneous(true)
		}
		return grid
	case RadioGroup:
		hbox := gtk.Box(gtk.GTK_ORIENTATION_HORIZONTAL, 2)
		var last *gtk.GtkRadioButton
		for i, labelText := range v.labels {
			last = gtk.RadioButtonWithLabelFromWidget(last, labelText)
			i := i
			last.Connect("toggled", func() {
				ui.radioGroups[v.name] = i
				ui.clicked(v.name)
			})
			last.Connect("destroy", func() {
				delete(ui.radioGroups, v.name)
			})
			hbox.PackStart(last, false, true, 2)
		}
		return hbox
	case Calendar:
		cal := gtk.Calendar()
		configureWidget(&cal.GtkWidget, v.widgetBase)
		if len(v.name) > 0 {
			ui.calendars[v.name] = cal
			cal.Connect("destroy", func() {
				delete(ui.calendars, v.name)
			})
		}
		return cal
	case SpinButton:
		spin := gtk.SpinButtonWithRange(v.min, v.max, v.step)
		configureWidget(&spin.GtkWidget, v.widgetBase)
		if len(v.name) > 0 {
			ui.spinButtons[v.name] = spin
			spin.Connect("destroy", func() {
				delete(ui.spinButtons, v.name)
			})
		}
		return spin
	case CheckButton:
		check := gtk.CheckButtonWithLabel(v.text)
		configureWidget(&check.GtkWidget, v.widgetBase)
		check.SetActive(v.checked)
		if len(v.name) > 0 {
			check.Connect("toggled", func() {
				ui.clicked(v.name)
			})
			check.Connect("destroy", func() {
				delete(ui.checks, v.name)
			})
			ui.checks[v.name] = check
		}

		return check

	default:
		panic("unknown widget: " + fmt.Sprintf("%#v", v))
	}

	panic("forgot to return")
}
示例#4
0
文件: gtk.go 项目: shpedoikal/pond
func (ui *GTKUI) createWidget(v interface{}) gtk.WidgetLike {
	switch v := v.(type) {
	case VBox:
		vbox := gtk.VBox(v.homogeneous, v.spacing)
		for _, child := range v.children {
			widget := ui.newWidget(child)
			if child.PackEnd() {
				vbox.PackEnd(widget, child.Expand(), child.Fill(), child.Padding())
			} else {
				vbox.PackStart(widget, child.Expand(), child.Fill(), child.Padding())
			}
		}
		return vbox
	case HBox:
		hbox := gtk.HBox(v.homogeneous, v.spacing)
		for _, child := range v.children {
			widget := ui.newWidget(child)
			hbox.PackStart(widget, child.Expand(), child.Fill(), child.Padding())
		}
		return hbox
	case EventBox:
		box := gtk.EventBox()
		if v.child != nil {
			widget := ui.newWidget(v.child)
			box.Add(widget)
		}
		configureWidget(&box.GtkWidget, v.widgetBase)
		if len(v.name) > 0 {
			box.Connect("button-press-event", func(e interface{}) {
				ui.clicked(v.name)
			})
		}
		return box
	case Label:
		label := gtk.Label(v.text)
		label.SetAlignment(v.xAlign, v.yAlign)
		configureWidget(&label.GtkWidget, v.widgetBase)
		if v.wrap != 0 {
			label.SetSizeRequest(v.wrap, -1)
			label.SetLineWrap(true)
		}
		label.SetSelectable(v.selectable)
		return label
	case Entry:
		entry := gtk.Entry()
		entry.SetText(v.text)
		if v.width > 0 {
			entry.SetWidthChars(v.width)
		}
		if name := v.name; len(name) > 0 {
			ui.entries[name] = entry
			entry.Connect("destroy", func() {
				delete(ui.entries, name)
			})
			entry.Connect("activate", func() {
				ui.clicked(v.name)
			})
		}
		if v.password {
			entry.SetVisibility(false)
		}
		configureWidget(&entry.GtkWidget, v.widgetBase)
		return entry
	case Button:
		button := gtk.ButtonWithLabel(v.text)
		button.Clicked(func() {
			ui.clicked(v.name)
		})
		configureWidget(&button.GtkWidget, v.widgetBase)
		return button
	case Spinner:
		spinner := gtk.Spinner()
		spinner.Start()
		return spinner
	case Paned:
		paned := gtk.HPaned()
		left := ui.newWidget(v.left)
		right := ui.newWidget(v.right)
		paned.Add1(left)
		paned.Add2(right)
		return paned
	case Scrolled:
		scrolled := gtk.ScrolledWindow(nil, nil)
		horizonalPolicy := gtk.GtkPolicyType(gtk.GTK_POLICY_NEVER)
		if v.horizontal {
			horizonalPolicy = gtk.GTK_POLICY_AUTOMATIC
		}
		scrolled.SetPolicy(horizonalPolicy, gtk.GTK_POLICY_AUTOMATIC)
		child := ui.newWidget(v.child)
		if v.viewport {
			scrolled.AddWithViewPort(child)
		} else {
			scrolled.Add(child)
		}
		return scrolled
	case TextView:
		view := gtk.TextView()
		view.SetBorderWidth(1)
		view.SetEditable(v.editable)
		if len(v.text) > 0 {
			buffer := gtk.TextBuffer(gtk.TextTagTable())
			buffer.SetText(v.text)
			view.SetBuffer(buffer)
		}
		if v.wrap {
			view.SetWrapMode(gtk.GTK_WRAP_WORD_CHAR)
		}
		if v.updateOnChange && len(v.name) > 0 {
			view.GetBuffer().Connect("changed", func() {
				ui.updated(v.name)
			})
		}
		if v.spellCheck {
			if _, err := gtkspell.New(view, ""); err != nil {
				panic(err)
			}
		}
		if name := v.name; len(name) > 0 {
			ui.textViews[name] = view
			view.Connect("destroy", func() {
				delete(ui.textViews, name)
			})
		}
		configureWidget(&view.GtkWidget, v.widgetBase)
		return view
	case Combo:
		combo := gtk.ComboBoxNewText()
		selectedIndex := -1
		for i, l := range v.labels {
			combo.AppendText(l)
			if len(v.preSelected) > 0 && l == v.preSelected {
				selectedIndex = i
			}
		}
		if selectedIndex >= 0 {
			combo.SetActive(selectedIndex)
		}
		if name := v.name; len(name) > 0 {
			ui.combos[name] = combo
			combo.Connect("destroy", func() {
				delete(ui.combos, name)
			})
			combo.Connect("changed", func() {
				ui.clicked(v.name)
			})
		}
		configureWidget(&combo.GtkWidget, v.widgetBase)
		return combo
	case Image:
		image := gtk.ImageFromPixbuf(v.image.Image())
		image.SetAlignment(v.xAlign, v.yAlign)
		configureWidget(&image.GtkWidget, v.widgetBase)
		return image
	default:
		panic("unknown widget: " + fmt.Sprintf("%#v", v))
	}

	panic("forgot to return")
}