gio-plugins icon indicating copy to clipboard operation
gio-plugins copied to clipboard

Can pop-up plug-ins be supported?

Open Esword618 opened this issue 3 years ago • 7 comments

Can pop-up plug-ins be supported?

Esword618 avatar Nov 10 '22 09:11 Esword618

I'm not sure if I understand exactly. What kind of "pop-up" are you looking for? Can you give some native API examples (for Windows, Android, iOS...)?

My idea of "pop-up" is "Dialog-Box", for Windows it's https://learn.microsoft.com/en-us/windows/win32/dlgbox/dialog-boxes. I'm not sure if that is what you want.

Personally, I don't have plans to add any "native message dialog". Maybe one very basic (just for "hello world" demo) might be added.

inkeliz avatar Nov 11 '22 03:11 inkeliz

Yes, that's what you said

Esword618 avatar Nov 11 '22 03:11 Esword618

https://github.com/planetdecred/godcr/issues/909 The first photo of this link shows a dialog box. I just want to implement the dialog box in the middle.

Esword618 avatar Nov 11 '22 03:11 Esword618

In that specific case, sounds like a Gio-designed dialog, not the native dialog from the OS. I'm not sure if you are intended to replace it to native OS dialog (something similar to https://learn.microsoft.com/en-us/windows/win32/controls/use-a-single-line--edit-control).

Currently, gio-plugins is intended to integrate with external components, instead of in-gio draws (which may fits gio-x better).

I'll update this thread with some example of how you can do it using op.Defer.

inkeliz avatar Nov 17 '22 13:11 inkeliz

OK, I see. I'm looking forward to your updating the use of op.Defer

Esword618 avatar Nov 17 '22 13:11 Esword618

I think that is a simple example:

package main

import (
	"gioui.org/app"
	"gioui.org/font/gofont"
	"gioui.org/io/pointer"
	"gioui.org/io/system"
	"gioui.org/layout"
	"gioui.org/op"
	"gioui.org/op/clip"
	"gioui.org/op/paint"
	"gioui.org/text"
	"gioui.org/widget"
	"image"
	"image/color"
)

var shaper = text.NewCache(gofont.Collection())

func main() {
	w := app.NewWindow()
	ops := new(op.Ops)
	page := new(Page)

	go func() {
		for e := range w.Events() {
			switch evt := e.(type) {
			case system.FrameEvent:
				gtx := layout.NewContext(ops, evt)
				page.Layout(gtx)
				evt.Frame(gtx.Ops)
			case system.DestroyEvent:
				return
			}
		}
	}()

	app.Main()
}

type Page struct {
	dialog      layout.Widget
	dialogCover widget.Clickable

	submit widget.Clickable
}

func (p *Page) Layout(gtx layout.Context) layout.Dimensions {
	// if click on "Open Dialog:
	if p.submit.Clicked() {
    
                 // Your dialog: 
		p.dialog = func(gtx layout.Context) layout.Dimensions {
			gtx.Constraints.Max.X /= 5
			gtx.Constraints.Max.Y = gtx.Dp(200)

			defer clip.UniformRRect(image.Rectangle{Max: gtx.Constraints.Max}, 10).Push(gtx.Ops).Pop()
			paint.ColorOp{Color: color.NRGBA{255, 255, 255, 255}}.Add(gtx.Ops)
			paint.PaintOp{}.Add(gtx.Ops)
			// Click blocker:
			pointer.InputOp{Tag: &p, Types: pointer.Press | pointer.Release}.Add(gtx.Ops)

			gtx.Constraints.Min = gtx.Constraints.Max
			return layout.Center.Layout(gtx, func(gtx layout.Context) layout.Dimensions {
				gtx.Constraints.Min.Y = 0
				paint.ColorOp{Color: color.NRGBA{0, 0, 0, 255}}.Add(gtx.Ops)
				return widget.Label{}.Layout(gtx, shaper, text.Font{}, 12, "Text on dialog")
			})
		}
	}

	// if click on the background, close the dialog
	if p.dialogCover.Clicked() {
		p.dialog = nil // Remove the dialog
	}

	// overlay dialog
	if p.dialog != nil {
		// get size of the dialog  widget
		dialogRec := op.Record(gtx.Ops)
		dims := p.dialog(gtx)
		dialogCall := dialogRec.Stop()

		// add padding and background opacity
		overlay := op.Record(gtx.Ops)

		p.dialogCover.Layout(gtx, func(gtx layout.Context) layout.Dimensions {
			paint.ColorOp{Color: color.NRGBA{0, 0, 0, 128}}.Add(gtx.Ops)
			paint.PaintOp{}.Add(gtx.Ops)
			return layout.Dimensions{Size: gtx.Constraints.Max}
		})

		offset := op.Offset(image.Point{
			X: (gtx.Constraints.Max.X - dims.Size.X) / 2,
			Y: (gtx.Constraints.Max.Y - dims.Size.Y) / 2,
		}).Push(gtx.Ops)
		dialogCall.Add(gtx.Ops)
		offset.Pop()

		overlayCall := overlay.Stop()

		op.Defer(gtx.Ops, overlayCall)
	}

	// main page
	{
		gtx := gtx // copy
		gtx.Constraints.Max.X /= 2
		gtx.Constraints.Min = gtx.Constraints.Max

		// left
		layout.Center.Layout(gtx, func(gtx layout.Context) layout.Dimensions {
			return widget.Label{Alignment: text.Middle}.Layout(gtx, shaper, text.Font{}, 14, "Some sidebar text here")
		})

		// right
		right := op.Offset(image.Pt(gtx.Constraints.Max.X, 0)).Push(gtx.Ops)
		layout.Center.Layout(gtx, func(gtx layout.Context) layout.Dimensions {
			return layout.Flex{}.Layout(gtx,
				layout.Rigid(func(gtx layout.Context) layout.Dimensions {
					return p.submit.Layout(gtx, func(gtx layout.Context) layout.Dimensions {
						gtx.Constraints.Max.Y = gtx.Dp(30)
						gtx.Constraints.Min.Y = gtx.Constraints.Max.Y

						defer clip.Rect{Max: gtx.Constraints.Max}.Push(gtx.Ops).Pop()
						paint.ColorOp{Color: color.NRGBA{255, 0, 0, 255}}.Add(gtx.Ops)
						paint.PaintOp{}.Add(gtx.Ops)

						return layout.Center.Layout(gtx, func(gtx layout.Context) layout.Dimensions {
							gtx.Constraints.Min.Y = 0
							paint.ColorOp{Color: color.NRGBA{0, 0, 0, 255}}.Add(gtx.Ops)
							return widget.Label{}.Layout(gtx, shaper, text.Font{}, 14, "Open Dialog")
						})
					})
				}),
			)
		})
		right.Pop()
	}

	return layout.Dimensions{Size: gtx.Constraints.Max}
}

That is a page with one button, once clicked it opens one dialog. When click one the "background of the dialog" it will close.

The issue here is who is responsible to show the dialog, because you may have multiple pages and so on. Another topic is pop-up relative to specific position, that is harder to do.

inkeliz avatar Nov 18 '22 16:11 inkeliz

Ok,thanks.This has solved my long-standing confusion. Thank you very much. I will study hard next.

Esword618 avatar Nov 18 '22 17:11 Esword618