func (s *Screen) drawWidgets() { if !s.visible { return } s.window.MakeContextCurrent() s.fbW, s.fbH = s.window.GetFramebufferSize() s.w, s.h = s.window.GetSize() gl.Viewport(0, 0, s.fbW, s.fbH) s.pixelRatio = float32(s.fbW) / float32(s.w) s.context.BeginFrame(s.w, s.h, s.pixelRatio) s.Draw(s, s.context) elapsed := GetTime() - s.lastInteraction if elapsed > 0.5 { // Draw tooltips widget := s.FindWidget(s, s.mousePosX, s.mousePosY) if widget != nil && widget.Tooltip() != "" { var tooltipWidth float32 = 150 ctx := s.context ctx.SetFontFace(s.theme.FontNormal) ctx.SetFontSize(15.0) ctx.SetTextAlign(nanovgo.AlignCenter | nanovgo.AlignTop) ctx.SetTextLineHeight(1.1) posX, posY := widget.AbsolutePosition() posX += widget.Width() / 2 posY += widget.Height() + 10 bounds := ctx.TextBoxBounds(float32(posX), float32(posY), tooltipWidth, widget.Tooltip()) ctx.SetGlobalAlpha(minF(1.0, 2*(elapsed-0.5)) * 0.8) ctx.BeginPath() ctx.SetFillColor(nanovgo.MONO(0, 255)) h := (bounds[2] - bounds[0]) / 2 ctx.RoundedRect(bounds[0]-4-h, bounds[1]-4, bounds[2]-bounds[0]+8, bounds[3]-bounds[1]+8, 3) px := (bounds[2]+bounds[0])/2 - h ctx.MoveTo(px, bounds[1]-10) ctx.LineTo(px+7, bounds[1]+1) ctx.LineTo(px-7, bounds[1]+1) ctx.Fill() ctx.SetFillColor(nanovgo.MONO(255, 255)) ctx.SetFontBlur(0.0) ctx.TextBox(float32(posX)-h, float32(posY), tooltipWidth, widget.Tooltip()) } } s.context.EndFrame() }
func newViewport(driver *driver, width, height int, title string, fullscreen bool) *viewport { v := &viewport{ fullscreen: fullscreen, scaling: 1, title: title, } glfw.DefaultWindowHints() glfw.WindowHint(glfw.Samples, 4) var monitor *glfw.Monitor if fullscreen { monitor = glfw.GetPrimaryMonitor() if width == 0 || height == 0 { vm := monitor.GetVideoMode() width, height = vm.Width, vm.Height } } wnd, err := glfw.CreateWindow(width, height, v.title, monitor, nil) if err != nil { panic(err) } width, height = wnd.GetSize() // At this time, width and height serve as a "hint" for glfw.CreateWindow, so get actual values from window. wnd.MakeContextCurrent() v.context = newContext() cursorPoint := func(x, y float64) math.Point { // HACK: xpos is off by 1 and ypos is off by 3 on OSX. // Compensate until real fix is found. x -= 1.0 y -= 3.0 return math.Point{X: int(x), Y: int(y)}.ScaleS(1 / v.scaling) } wnd.SetCloseCallback(func(*glfw.Window) { v.Close() }) wnd.SetPosCallback(func(w *glfw.Window, x, y int) { v.Lock() v.position = math.NewPoint(x, y) v.Unlock() }) wnd.SetSizeCallback(func(_ *glfw.Window, w, h int) { v.Lock() v.sizeDipsUnscaled = math.Size{W: w, H: h} v.sizeDips = v.sizeDipsUnscaled.ScaleS(1 / v.scaling) v.Unlock() v.onResize.Fire() }) wnd.SetFramebufferSizeCallback(func(_ *glfw.Window, w, h int) { v.Lock() v.sizePixels = math.Size{W: w, H: h} v.Unlock() gl.Viewport(0, 0, w, h) gl.ClearColor(kClearColorR, kClearColorG, kClearColorB, 1.0) gl.Clear(gl.COLOR_BUFFER_BIT) }) wnd.SetCursorPosCallback(func(w *glfw.Window, x, y float64) { p := cursorPoint(w.GetCursorPos()) v.Lock() if v.pendingMouseMoveEvent == nil { v.pendingMouseMoveEvent = &gxui.MouseEvent{} driver.Call(func() { v.Lock() ev := *v.pendingMouseMoveEvent v.pendingMouseMoveEvent = nil v.Unlock() v.onMouseMove.Fire(ev) }) } v.pendingMouseMoveEvent.Point = p v.pendingMouseMoveEvent.State = getMouseState(w) v.Unlock() }) wnd.SetCursorEnterCallback(func(w *glfw.Window, entered bool) { p := cursorPoint(w.GetCursorPos()) ev := gxui.MouseEvent{ Point: p, } ev.State = getMouseState(w) if entered { v.onMouseEnter.Fire(ev) } else { v.onMouseExit.Fire(ev) } }) wnd.SetScrollCallback(func(w *glfw.Window, xoff, yoff float64) { p := cursorPoint(w.GetCursorPos()) v.Lock() if v.pendingMouseScrollEvent == nil { v.pendingMouseScrollEvent = &gxui.MouseEvent{} driver.Call(func() { v.Lock() ev := *v.pendingMouseScrollEvent v.pendingMouseScrollEvent = nil ev.ScrollX, ev.ScrollY = int(v.scrollAccumX), int(v.scrollAccumY) if ev.ScrollX != 0 || ev.ScrollY != 0 { v.scrollAccumX -= float64(ev.ScrollX) v.scrollAccumY -= float64(ev.ScrollY) v.Unlock() v.onMouseScroll.Fire(ev) } else { v.Unlock() } }) } v.pendingMouseScrollEvent.Point = p v.scrollAccumX += xoff * platform.ScrollSpeed v.scrollAccumY += yoff * platform.ScrollSpeed v.pendingMouseScrollEvent.State = getMouseState(w) v.Unlock() }) wnd.SetMouseButtonCallback(func(w *glfw.Window, button glfw.MouseButton, action glfw.Action, mod glfw.ModifierKey) { p := cursorPoint(w.GetCursorPos()) ev := gxui.MouseEvent{ Point: p, Modifier: translateKeyboardModifier(mod), } ev.Button = translateMouseButton(button) ev.State = getMouseState(w) if action == glfw.Press { v.onMouseDown.Fire(ev) } else { v.onMouseUp.Fire(ev) } }) wnd.SetKeyCallback(func(w *glfw.Window, key glfw.Key, scancode int, action glfw.Action, mods glfw.ModifierKey) { ev := gxui.KeyboardEvent{ Key: translateKeyboardKey(key), Modifier: translateKeyboardModifier(mods), } switch action { case glfw.Press: v.onKeyDown.Fire(ev) case glfw.Release: v.onKeyUp.Fire(ev) case glfw.Repeat: v.onKeyRepeat.Fire(ev) } }) wnd.SetCharModsCallback(func(w *glfw.Window, char rune, mods glfw.ModifierKey) { if !unicode.IsControl(char) && !unicode.IsGraphic(char) && !unicode.IsLetter(char) && !unicode.IsMark(char) && !unicode.IsNumber(char) && !unicode.IsPunct(char) && !unicode.IsSpace(char) && !unicode.IsSymbol(char) { return // Weird unicode character. Ignore } ev := gxui.KeyStrokeEvent{ Character: char, Modifier: translateKeyboardModifier(mods), } v.onKeyStroke.Fire(ev) }) wnd.SetRefreshCallback(func(w *glfw.Window) { if v.canvas != nil { v.render() } }) fw, fh := wnd.GetFramebufferSize() posX, posY := wnd.GetPos() // Pre-multiplied alpha blending gl.BlendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA) gl.Enable(gl.BLEND) gl.Enable(gl.SCISSOR_TEST) gl.Viewport(0, 0, fw, fh) gl.Scissor(0, 0, int32(fw), int32(fh)) gl.ClearColor(kClearColorR, kClearColorG, kClearColorB, 1.0) gl.Clear(gl.COLOR_BUFFER_BIT) wnd.SwapBuffers() v.window = wnd v.driver = driver v.onClose = driver.createAppEvent(func() {}) v.onResize = driver.createAppEvent(func() {}) v.onMouseMove = gxui.CreateEvent(func(gxui.MouseEvent) {}) v.onMouseEnter = driver.createAppEvent(func(gxui.MouseEvent) {}) v.onMouseExit = driver.createAppEvent(func(gxui.MouseEvent) {}) v.onMouseDown = driver.createAppEvent(func(gxui.MouseEvent) {}) v.onMouseUp = driver.createAppEvent(func(gxui.MouseEvent) {}) v.onMouseScroll = gxui.CreateEvent(func(gxui.MouseEvent) {}) v.onKeyDown = driver.createAppEvent(func(gxui.KeyboardEvent) {}) v.onKeyUp = driver.createAppEvent(func(gxui.KeyboardEvent) {}) v.onKeyRepeat = driver.createAppEvent(func(gxui.KeyboardEvent) {}) v.onKeyStroke = driver.createAppEvent(func(gxui.KeyStrokeEvent) {}) v.onDestroy = driver.createDriverEvent(func() {}) v.sizeDipsUnscaled = math.Size{W: width, H: height} v.sizeDips = v.sizeDipsUnscaled.ScaleS(1 / v.scaling) v.sizePixels = math.Size{W: fw, H: fh} v.position = math.Point{X: posX, Y: posY} return v }
func main() { err := glfw.Init(gl.ContextWatcher) if err != nil { panic(err) } defer glfw.Terminate() glfw.WindowHint(glfw.StencilBits, 1) glfw.WindowHint(glfw.Samples, 4) window, err := glfw.CreateWindow(1000*0.6, 600*0.6, "NanoVGo", nil, nil) if err != nil { panic(err) } window.SetKeyCallback(key) window.MakeContextCurrent() ctx, err := nanovgo.NewContext(0) defer ctx.Delete() if err != nil { panic(err) } demoData := LoadDemo(ctx) glfw.SwapInterval(0) fps := perfgraph.NewPerfGraph("Frame Time", "sans") for !window.ShouldClose() { t, _ := fps.UpdateGraph() fbWidth, fbHeight := window.GetFramebufferSize() winWidth, winHeight := window.GetSize() mx, my := window.GetCursorPos() pixelRatio := float32(fbWidth) / float32(winWidth) gl.Viewport(0, 0, fbWidth, fbHeight) if premult { gl.ClearColor(0, 0, 0, 0) } else { gl.ClearColor(0.3, 0.3, 0.32, 1.0) } gl.Clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT | gl.STENCIL_BUFFER_BIT) gl.Enable(gl.BLEND) gl.BlendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA) gl.Enable(gl.CULL_FACE) gl.Disable(gl.DEPTH_TEST) ctx.BeginFrame(winWidth, winHeight, pixelRatio) demo.RenderDemo(ctx, float32(mx), float32(my), float32(winWidth), float32(winHeight), t, blowup, demoData) fps.RenderGraph(ctx, 5, 5) ctx.EndFrame() gl.Enable(gl.DEPTH_TEST) window.SwapBuffers() glfw.PollEvents() } demoData.FreeData(ctx) }
func main() { if err := glfw.Init(gl.ContextWatcher); err != nil { panic(err) } defer glfw.Terminate() window, err := glfw.CreateWindow(400, 400, "", nil, nil) if err != nil { panic(err) } window.MakeContextCurrent() glfw.SwapInterval(1) // Vsync. framebufferSizeCallback := func(w *glfw.Window, framebufferSize0, framebufferSize1 int) { gl.Viewport(0, 0, framebufferSize0, framebufferSize1) var windowSize [2]int windowSize[0], windowSize[1] = w.GetSize() _, _ = windowSize[0], windowSize[1] /*inputEvent := InputEvent{ Pointer: windowPointer, EventTypes: map[EventType]struct{}{AXIS_EVENT: struct{}{}}, InputId: 0, Buttons: nil, Sliders: nil, Axes: []float64{float64(windowSize[0]), float64(windowSize[1])}, } inputEventQueue = events.EnqueueInputEvent(inputEventQueue, inputEvent)*/ } { var framebufferSize [2]int framebufferSize[0], framebufferSize[1] = window.GetFramebufferSize() framebufferSizeCallback(window, framebufferSize[0], framebufferSize[1]) } window.SetFramebufferSizeCallback(framebufferSizeCallback) var inputEventQueue []events.InputEvent mousePointer = &events.Pointer{VirtualCategory: events.POINTING} keyboardPointer = &events.Pointer{VirtualCategory: events.TYPING} window.SetMouseMovementCallback(func(w *glfw.Window, xpos, ypos, xdelta, ydelta float64) { inputEvent := events.InputEvent{ Pointer: mousePointer, EventTypes: map[events.EventType]struct{}{events.SLIDER_EVENT: {}}, InputId: 0, Buttons: nil, Sliders: []float64{xdelta, ydelta}, } if w.GetInputMode(glfw.CursorMode) != glfw.CursorDisabled { inputEvent.EventTypes[events.AXIS_EVENT] = struct{}{} inputEvent.Axes = []float64{xpos, ypos} } inputEventQueue = events.EnqueueInputEvent(inputEventQueue, inputEvent) }) window.SetScrollCallback(func(w *glfw.Window, xoff float64, yoff float64) { inputEvent := events.InputEvent{ Pointer: mousePointer, EventTypes: map[events.EventType]struct{}{events.SLIDER_EVENT: {}}, InputId: 2, Buttons: nil, Sliders: []float64{yoff, xoff}, Axes: nil, } inputEventQueue = events.EnqueueInputEvent(inputEventQueue, inputEvent) }) window.SetMouseButtonCallback(func(w *glfw.Window, button glfw.MouseButton, action glfw.Action, mods glfw.ModifierKey) { inputEvent := events.InputEvent{ Pointer: mousePointer, EventTypes: map[events.EventType]struct{}{events.BUTTON_EVENT: {}}, InputId: uint16(button), Buttons: []bool{action != glfw.Release}, Sliders: nil, Axes: nil, ModifierKey: uint8(mods), } inputEventQueue = events.EnqueueInputEvent(inputEventQueue, inputEvent) }) window.SetKeyCallback(func(w *glfw.Window, key glfw.Key, scancode int, action glfw.Action, mods glfw.ModifierKey) { inputEvent := events.InputEvent{ Pointer: keyboardPointer, EventTypes: map[events.EventType]struct{}{events.BUTTON_EVENT: {}}, InputId: uint16(key), Buttons: []bool{action != glfw.Release}, Sliders: nil, Axes: nil, ModifierKey: uint8(mods), } inputEventQueue = events.EnqueueInputEvent(inputEventQueue, inputEvent) // HACK. switch { case key == glfw.Key1 && action == glfw.Press: window.SetInputMode(glfw.CursorMode, glfw.CursorNormal) case key == glfw.Key2 && action == glfw.Press: window.SetInputMode(glfw.CursorMode, glfw.CursorHidden) case key == glfw.Key3 && action == glfw.Press: window.SetInputMode(glfw.CursorMode, glfw.CursorDisabled) } }) window.SetCharCallback(func(w *glfw.Window, char rune) { inputEvent := events.InputEvent{ Pointer: keyboardPointer, EventTypes: map[events.EventType]struct{}{events.CHARACTER_EVENT: {}}, InputId: uint16(char), Buttons: nil, Sliders: nil, Axes: nil, } inputEventQueue = events.EnqueueInputEvent(inputEventQueue, inputEvent) }) gl.ClearColor(0.85, 0.85, 0.85, 1) for !window.ShouldClose() { glfw.PollEvents() // Process Input. inputEventQueue = processInputEventQueue(inputEventQueue) gl.Clear(gl.COLOR_BUFFER_BIT) mousePointer.Render() window.SwapBuffers() runtime.Gosched() } }
func NewScreen(width, height int, caption string, resizable, fullScreen bool) *Screen { screen := &Screen{ //cursor: glfw.CursorNormal, caption: caption, } if runtime.GOARCH == "js" { glfw.WindowHint(glfw.Hint(0x00021101), 1) // enable stencil for nanovgo } glfw.WindowHint(glfw.Samples, 4) //glfw.WindowHint(glfw.RedBits, 8) //glfw.WindowHint(glfw.GreenBits, 8) //glfw.WindowHint(glfw.BlueBits, 8) glfw.WindowHint(glfw.AlphaBits, 8) //glfw.WindowHint(glfw.StencilBits, 8) //glfw.WindowHint(glfw.DepthBits, 8) //glfw.WindowHint(glfw.Visible, 0) if resizable { //glfw.WindowHint(glfw.Resizable, 1) } else { //glfw.WindowHint(glfw.Resizable, 0) } var err error if fullScreen { monitor := glfw.GetPrimaryMonitor() mode := monitor.GetVideoMode() screen.window, err = glfw.CreateWindow(mode.Width, mode.Height, caption, monitor, nil) } else { screen.window, err = glfw.CreateWindow(width, height, caption, nil, nil) } if err != nil { panic(err) } screen.window.MakeContextCurrent() gl.Viewport(0, 0, screen.fbW, screen.fbH) gl.ClearColor(0, 0, 0, 1) gl.Clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT | gl.STENCIL_BUFFER_BIT) glfw.SwapInterval(0) screen.window.SwapBuffers() /* Poll for events once before starting a potentially lengthy loading process. This is needed to be classified as "interactive" by other software such as iTerm2 */ if runtime.GOOS == "darwin" { glfw.PollEvents() } screen.window.SetCursorPosCallback(func(w *glfw.Window, xpos, ypos float64) { if screen, ok := nanoguiScreens[w]; ok { screen.cursorPositionCallbackEvent(xpos, ypos) } }) screen.window.SetMouseButtonCallback(func(w *glfw.Window, button glfw.MouseButton, action glfw.Action, mods glfw.ModifierKey) { if screen, ok := nanoguiScreens[w]; ok { screen.mouseButtonCallbackEvent(button, action, mods) } }) screen.window.SetKeyCallback(func(w *glfw.Window, key glfw.Key, scanCode int, action glfw.Action, mods glfw.ModifierKey) { if screen, ok := nanoguiScreens[w]; ok { screen.keyCallbackEvent(key, scanCode, action, mods) } }) screen.window.SetCharCallback(func(w *glfw.Window, char rune) { if screen, ok := nanoguiScreens[w]; ok { screen.charCallbackEvent(char) } }) screen.window.SetPreeditCallback(func(w *glfw.Window, text []rune, blocks []int, focusedBlock int) { if screen, ok := nanoguiScreens[w]; ok { screen.preeditCallbackEvent(text, blocks, focusedBlock) } }) screen.window.SetIMEStatusCallback(func(w *glfw.Window) { if screen, ok := nanoguiScreens[w]; ok { screen.imeStatusCallbackEvent() } }) screen.window.SetDropCallback(func(w *glfw.Window, names []string) { if screen, ok := nanoguiScreens[w]; ok { screen.dropCallbackEvent(names) } }) screen.window.SetScrollCallback(func(w *glfw.Window, xoff float64, yoff float64) { if screen, ok := nanoguiScreens[w]; ok { screen.scrollCallbackEvent(float32(xoff), float32(yoff)) } }) screen.window.SetFramebufferSizeCallback(func(w *glfw.Window, width int, height int) { if screen, ok := nanoguiScreens[w]; ok { screen.resizeCallbackEvent(width, height) } }) screen.Initialize(screen.window, true) InitWidget(screen, nil) return screen }