mirror of
https://git.sr.ht/~eliasnaur/gio
synced 2026-07-01 15:45:38 +00:00
app/window,app/internal/window: allow min/max window size
The app.MinSize and app.MaxSize options restricts the window size: w := app.NewWindow( app.Size(unit.Dp(600), unit.Dp(596)), app.MinSize(unit.Dp(600), unit.Dp(596)), app.MaxSize(unit.Dp(600), unit.Dp(596)), app.Title(APPNAME), ) Signed-off-by: Jason <sourcehut@sweatyballs.es>
This commit is contained in:
@@ -41,7 +41,7 @@ __attribute__ ((visibility ("hidden"))) CFTypeRef gio_readClipboard(void);
|
||||
__attribute__ ((visibility ("hidden"))) void gio_writeClipboard(unichar *chars, NSUInteger length);
|
||||
__attribute__ ((visibility ("hidden"))) void gio_setNeedsDisplay(CFTypeRef viewRef);
|
||||
__attribute__ ((visibility ("hidden"))) void gio_appTerminate(void);
|
||||
__attribute__ ((visibility ("hidden"))) CFTypeRef gio_createWindow(CFTypeRef viewRef, const char *title, CGFloat width, CGFloat height);
|
||||
__attribute__ ((visibility ("hidden"))) CFTypeRef gio_createWindow(CFTypeRef viewRef, const char *title, CGFloat width, CGFloat height, CGFloat minWidth, CGFloat minHeight, CGFloat maxWidth, CGFloat maxHeight);
|
||||
__attribute__ ((visibility ("hidden"))) void gio_makeKeyAndOrderFront(CFTypeRef windowRef);
|
||||
__attribute__ ((visibility ("hidden"))) NSPoint gio_cascadeTopLeftFromPoint(CFTypeRef windowRef, NSPoint topLeft);
|
||||
__attribute__ ((visibility ("hidden"))) void gio_close(CFTypeRef windowRef);
|
||||
@@ -323,12 +323,21 @@ func NewWindow(win Callbacks, opts *Options) error {
|
||||
// Window sizes is in unscaled screen coordinates, not device pixels.
|
||||
width = int(float32(width) / screenScale)
|
||||
height = int(float32(height) / screenScale)
|
||||
minWidth := cfg.Px(opts.MinWidth)
|
||||
minHeight := cfg.Px(opts.MinHeight)
|
||||
minWidth = int(float32(minWidth) / screenScale)
|
||||
minHeight = int(float32(minHeight) / screenScale)
|
||||
maxWidth := cfg.Px(opts.MaxWidth)
|
||||
maxHeight := cfg.Px(opts.MaxHeight)
|
||||
maxWidth = int(float32(maxWidth) / screenScale)
|
||||
maxHeight = int(float32(maxHeight) / screenScale)
|
||||
title := C.CString(opts.Title)
|
||||
defer C.free(unsafe.Pointer(title))
|
||||
errch <- nil
|
||||
win.SetDriver(w)
|
||||
w.w = win
|
||||
w.window = C.gio_createWindow(w.view, title, C.CGFloat(width), C.CGFloat(height))
|
||||
w.window = C.gio_createWindow(w.view, title, C.CGFloat(width), C.CGFloat(height),
|
||||
C.CGFloat(minWidth), C.CGFloat(minHeight), C.CGFloat(maxWidth), C.CGFloat(maxHeight))
|
||||
if nextTopLeft.x == 0 && nextTopLeft.y == 0 {
|
||||
// cascadeTopLeftFromPoint treats (0, 0) as a no-op,
|
||||
// and just returns the offset we need for the first window.
|
||||
|
||||
@@ -124,7 +124,7 @@ void gio_makeKeyAndOrderFront(CFTypeRef windowRef) {
|
||||
[window makeKeyAndOrderFront:nil];
|
||||
}
|
||||
|
||||
CFTypeRef gio_createWindow(CFTypeRef viewRef, const char *title, CGFloat width, CGFloat height) {
|
||||
CFTypeRef gio_createWindow(CFTypeRef viewRef, const char *title, CGFloat width, CGFloat height, CGFloat minWidth, CGFloat minHeight, CGFloat maxWidth, CGFloat maxHeight) {
|
||||
@autoreleasepool {
|
||||
NSRect rect = NSMakeRect(0, 0, width, height);
|
||||
NSUInteger styleMask = NSTitledWindowMask |
|
||||
@@ -136,6 +136,12 @@ CFTypeRef gio_createWindow(CFTypeRef viewRef, const char *title, CGFloat width,
|
||||
styleMask:styleMask
|
||||
backing:NSBackingStoreBuffered
|
||||
defer:NO];
|
||||
if (minWidth > 0 || minHeight > 0) {
|
||||
window.contentMinSize = NSMakeSize(minWidth, minHeight);
|
||||
}
|
||||
if (maxWidth > 0 || maxHeight > 0) {
|
||||
window.contentMaxSize = NSMakeSize(maxWidth, maxHeight);
|
||||
}
|
||||
[window setAcceptsMouseMovedEvents:YES];
|
||||
window.title = [NSString stringWithUTF8String: title];
|
||||
NSView *view = (__bridge NSView *)viewRef;
|
||||
|
||||
@@ -27,6 +27,16 @@ import (
|
||||
"gioui.org/io/system"
|
||||
)
|
||||
|
||||
type winConstraints struct {
|
||||
minWidth, minHeight int32
|
||||
maxWidth, maxHeight int32
|
||||
}
|
||||
|
||||
type winDeltas struct {
|
||||
width int32
|
||||
height int32
|
||||
}
|
||||
|
||||
type window struct {
|
||||
hwnd syscall.Handle
|
||||
hdc syscall.Handle
|
||||
@@ -39,6 +49,10 @@ type window struct {
|
||||
|
||||
mu sync.Mutex
|
||||
animating bool
|
||||
|
||||
minmax winConstraints
|
||||
deltas winDeltas
|
||||
opts *Options
|
||||
}
|
||||
|
||||
const _WM_REDRAW = windows.WM_USER + 0
|
||||
@@ -137,6 +151,15 @@ func initResources() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func getWindowConstraints(cfg unit.Metric, opts *Options, d winDeltas) winConstraints {
|
||||
var minmax winConstraints
|
||||
minmax.minWidth = int32(cfg.Px(opts.MinWidth)) + d.width
|
||||
minmax.minHeight = int32(cfg.Px(opts.MinHeight)) + d.height
|
||||
minmax.maxWidth = int32(cfg.Px(opts.MaxWidth)) + d.width
|
||||
minmax.maxHeight = int32(cfg.Px(opts.MaxHeight)) + d.height
|
||||
return minmax
|
||||
}
|
||||
|
||||
func createNativeWindow(opts *Options) (*window, error) {
|
||||
var resErr error
|
||||
resources.once.Do(func() {
|
||||
@@ -152,7 +175,14 @@ func createNativeWindow(opts *Options) (*window, error) {
|
||||
}
|
||||
dwStyle := uint32(windows.WS_OVERLAPPEDWINDOW)
|
||||
dwExStyle := uint32(windows.WS_EX_APPWINDOW | windows.WS_EX_WINDOWEDGE)
|
||||
deltas := winDeltas{
|
||||
width: wr.Right,
|
||||
height: wr.Bottom,
|
||||
}
|
||||
windows.AdjustWindowRectEx(&wr, dwStyle, 0, dwExStyle)
|
||||
deltas.width = wr.Right - wr.Left - deltas.width
|
||||
deltas.height = wr.Bottom - wr.Top - deltas.height
|
||||
|
||||
hwnd, err := windows.CreateWindowEx(dwExStyle,
|
||||
resources.class,
|
||||
opts.Title,
|
||||
@@ -168,7 +198,10 @@ func createNativeWindow(opts *Options) (*window, error) {
|
||||
return nil, err
|
||||
}
|
||||
w := &window{
|
||||
hwnd: hwnd,
|
||||
hwnd: hwnd,
|
||||
minmax: getWindowConstraints(cfg, opts, deltas),
|
||||
deltas: deltas,
|
||||
opts: opts,
|
||||
}
|
||||
w.hdc, err = windows.GetDC(hwnd)
|
||||
if err != nil {
|
||||
@@ -251,6 +284,20 @@ func windowProc(hwnd syscall.Handle, msg uint32, wParam, lParam uintptr) uintptr
|
||||
case windows.SIZE_MAXIMIZED, windows.SIZE_RESTORED:
|
||||
w.setStage(system.StageRunning)
|
||||
}
|
||||
case windows.WM_GETMINMAXINFO:
|
||||
mm := (*windows.MinMaxInfo)(unsafe.Pointer(uintptr(lParam)))
|
||||
if w.minmax.minWidth > 0 || w.minmax.minHeight > 0 {
|
||||
mm.PtMinTrackSize = windows.Point{
|
||||
w.minmax.minWidth,
|
||||
w.minmax.minHeight,
|
||||
}
|
||||
}
|
||||
if w.minmax.maxWidth > 0 || w.minmax.maxHeight > 0 {
|
||||
mm.PtMaxTrackSize = windows.Point{
|
||||
w.minmax.maxWidth,
|
||||
w.minmax.maxHeight,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return windows.DefWindowProc(hwnd, msg, wParam, lParam)
|
||||
@@ -375,6 +422,7 @@ func (w *window) draw(sync bool) {
|
||||
return
|
||||
}
|
||||
cfg := configForDC()
|
||||
w.minmax = getWindowConstraints(cfg, w.opts, w.deltas)
|
||||
w.w.Event(FrameEvent{
|
||||
FrameEvent: system.FrameEvent{
|
||||
Now: time.Now(),
|
||||
|
||||
@@ -514,6 +514,21 @@ func newX11Window(gioWin Callbacks, opts *Options) error {
|
||||
hints.flags = C.InputHint
|
||||
C.XSetWMHints(dpy, win, &hints)
|
||||
|
||||
var shints C.XSizeHints
|
||||
if opts.MinWidth.V != 0 || opts.MinHeight.V != 0 {
|
||||
shints.min_width = C.int(cfg.Px(opts.MinWidth))
|
||||
shints.min_height = C.int(cfg.Px(opts.MinHeight))
|
||||
shints.flags = C.PMinSize
|
||||
}
|
||||
if opts.MaxWidth.V != 0 || opts.MaxHeight.V != 0 {
|
||||
shints.max_width = C.int(cfg.Px(opts.MaxWidth))
|
||||
shints.max_height = C.int(cfg.Px(opts.MaxHeight))
|
||||
shints.flags = shints.flags | C.PMaxSize
|
||||
}
|
||||
if shints.flags != 0 {
|
||||
C.XSetWMNormalHints(dpy, win, &shints)
|
||||
}
|
||||
|
||||
name := C.CString(filepath.Base(os.Args[0]))
|
||||
defer C.free(unsafe.Pointer(name))
|
||||
wmhints := C.XClassHint{name, name}
|
||||
|
||||
@@ -14,8 +14,10 @@ import (
|
||||
)
|
||||
|
||||
type Options struct {
|
||||
Width, Height unit.Value
|
||||
Title string
|
||||
Width, Height unit.Value
|
||||
MinWidth, MinHeight unit.Value
|
||||
MaxWidth, MaxHeight unit.Value
|
||||
Title string
|
||||
}
|
||||
|
||||
type FrameEvent struct {
|
||||
|
||||
@@ -46,6 +46,14 @@ type Point struct {
|
||||
X, Y int32
|
||||
}
|
||||
|
||||
type MinMaxInfo struct {
|
||||
PtReserved Point
|
||||
PtMaxSize Point
|
||||
PtMaxPosition Point
|
||||
PtMinTrackSize Point
|
||||
PtMaxTrackSize Point
|
||||
}
|
||||
|
||||
const (
|
||||
CS_HREDRAW = 0x0002
|
||||
CS_VREDRAW = 0x0001
|
||||
@@ -120,33 +128,34 @@ const (
|
||||
|
||||
UNICODE_NOCHAR = 65535
|
||||
|
||||
WM_CANCELMODE = 0x001F
|
||||
WM_CHAR = 0x0102
|
||||
WM_CREATE = 0x0001
|
||||
WM_DPICHANGED = 0x02E0
|
||||
WM_DESTROY = 0x0002
|
||||
WM_ERASEBKGND = 0x0014
|
||||
WM_KEYDOWN = 0x0100
|
||||
WM_KEYUP = 0x0101
|
||||
WM_LBUTTONDOWN = 0x0201
|
||||
WM_LBUTTONUP = 0x0202
|
||||
WM_MBUTTONDOWN = 0x0207
|
||||
WM_MBUTTONUP = 0x0208
|
||||
WM_MOUSEMOVE = 0x0200
|
||||
WM_MOUSEWHEEL = 0x020A
|
||||
WM_PAINT = 0x000F
|
||||
WM_CLOSE = 0x0010
|
||||
WM_QUIT = 0x0012
|
||||
WM_SETFOCUS = 0x0007
|
||||
WM_KILLFOCUS = 0x0008
|
||||
WM_SHOWWINDOW = 0x0018
|
||||
WM_SIZE = 0x0005
|
||||
WM_SYSKEYDOWN = 0x0104
|
||||
WM_RBUTTONDOWN = 0x0204
|
||||
WM_RBUTTONUP = 0x0205
|
||||
WM_TIMER = 0x0113
|
||||
WM_UNICHAR = 0x0109
|
||||
WM_USER = 0x0400
|
||||
WM_CANCELMODE = 0x001F
|
||||
WM_CHAR = 0x0102
|
||||
WM_CREATE = 0x0001
|
||||
WM_DPICHANGED = 0x02E0
|
||||
WM_DESTROY = 0x0002
|
||||
WM_ERASEBKGND = 0x0014
|
||||
WM_KEYDOWN = 0x0100
|
||||
WM_KEYUP = 0x0101
|
||||
WM_LBUTTONDOWN = 0x0201
|
||||
WM_LBUTTONUP = 0x0202
|
||||
WM_MBUTTONDOWN = 0x0207
|
||||
WM_MBUTTONUP = 0x0208
|
||||
WM_MOUSEMOVE = 0x0200
|
||||
WM_MOUSEWHEEL = 0x020A
|
||||
WM_PAINT = 0x000F
|
||||
WM_CLOSE = 0x0010
|
||||
WM_QUIT = 0x0012
|
||||
WM_SETFOCUS = 0x0007
|
||||
WM_KILLFOCUS = 0x0008
|
||||
WM_SHOWWINDOW = 0x0018
|
||||
WM_SIZE = 0x0005
|
||||
WM_SYSKEYDOWN = 0x0104
|
||||
WM_RBUTTONDOWN = 0x0204
|
||||
WM_RBUTTONUP = 0x0205
|
||||
WM_TIMER = 0x0113
|
||||
WM_UNICHAR = 0x0109
|
||||
WM_USER = 0x0400
|
||||
WM_GETMINMAXINFO = 0x0024
|
||||
|
||||
WS_CLIPCHILDREN = 0x00010000
|
||||
WS_CLIPSIBLINGS = 0x04000000
|
||||
|
||||
@@ -427,4 +427,32 @@ func Size(w, h unit.Value) Option {
|
||||
}
|
||||
}
|
||||
|
||||
// MaxSize sets the maximum size of the window.
|
||||
func MaxSize(w, h unit.Value) Option {
|
||||
if w.V <= 0 {
|
||||
panic("width must be larger than or equal to 0")
|
||||
}
|
||||
if h.V <= 0 {
|
||||
panic("height must be larger than or equal to 0")
|
||||
}
|
||||
return func(opts *window.Options) {
|
||||
opts.MaxWidth = w
|
||||
opts.MaxHeight = h
|
||||
}
|
||||
}
|
||||
|
||||
// MinSize sets the minimum size of the window.
|
||||
func MinSize(w, h unit.Value) Option {
|
||||
if w.V <= 0 {
|
||||
panic("width must be larger than or equal to 0")
|
||||
}
|
||||
if h.V <= 0 {
|
||||
panic("height must be larger than or equal to 0")
|
||||
}
|
||||
return func(opts *window.Options) {
|
||||
opts.MinWidth = w
|
||||
opts.MinHeight = h
|
||||
}
|
||||
}
|
||||
|
||||
func (driverEvent) ImplementsEvent() {}
|
||||
|
||||
Reference in New Issue
Block a user