gioui.org/ui@v0.0.0-20190926171558-ce74bc0cbaea/app/app.go (about)

     1  // SPDX-License-Identifier: Unlicense OR MIT
     2  
     3  package app
     4  
     5  import (
     6  	"errors"
     7  	"image"
     8  	"math"
     9  	"os"
    10  	"strings"
    11  	"time"
    12  
    13  	"gioui.org/ui"
    14  )
    15  
    16  // An UpdateEvent is generated when a Window's Update
    17  // method must be called.
    18  type UpdateEvent struct {
    19  	Config Config
    20  	// Size is the dimensions of the window.
    21  	Size image.Point
    22  	// Insets is the insets to apply.
    23  	Insets Insets
    24  	// Whether this draw is system generated
    25  	// and needs a complete frame before
    26  	// proceeding.
    27  	sync bool
    28  }
    29  
    30  // DestroyEvent is the last event sent through
    31  // a window event channel.
    32  type DestroyEvent struct {
    33  	// Err is nil for normal window closures. If a
    34  	// window is prematurely closed, Err is the cause.
    35  	Err error
    36  }
    37  
    38  // Insets is the space taken up by
    39  // system decoration such as translucent
    40  // system bars and software keyboards.
    41  type Insets struct {
    42  	Top, Bottom, Left, Right ui.Value
    43  }
    44  
    45  // A StageEvent is generated whenever the stage of a
    46  // Window changes.
    47  type StageEvent struct {
    48  	Stage Stage
    49  }
    50  
    51  // CommandEvent is a system event.
    52  type CommandEvent struct {
    53  	Type CommandType
    54  	// Suppress the default action of the command.
    55  	Cancel bool
    56  }
    57  
    58  // Stage of a Window.
    59  type Stage uint8
    60  
    61  // CommandType is the type of a CommandEvent.
    62  type CommandType uint8
    63  
    64  type windowRendezvous struct {
    65  	in   chan windowAndOptions
    66  	out  chan windowAndOptions
    67  	errs chan error
    68  }
    69  
    70  type windowAndOptions struct {
    71  	window *Window
    72  	opts   *windowOptions
    73  }
    74  
    75  const (
    76  	// StagePaused is the Stage for inactive Windows.
    77  	// Inactive Windows don't receive UpdateEvents.
    78  	StagePaused Stage = iota
    79  	// StateRunning is for active Windows.
    80  	StageRunning
    81  )
    82  
    83  const (
    84  	// CommandBack is the command for a back action
    85  	// such as the Android back button.
    86  	CommandBack CommandType = iota
    87  )
    88  
    89  const (
    90  	inchPrDp = 1.0 / 160
    91  	mmPrDp   = 25.4 / 160
    92  	// monitorScale is the extra scale applied to
    93  	// monitor outputs to compensate for the extra
    94  	// viewing distance compared to phone and tables.
    95  	monitorScale = 1.20
    96  	// minDensity is the minimum pixels per dp to
    97  	// ensure font and ui legibility on low-dpi
    98  	// screens.
    99  	minDensity = 1.25
   100  )
   101  
   102  // extraArgs contains extra arguments to append to
   103  // os.Args. The arguments are separated with |.
   104  // Useful for running programs on mobiles where the
   105  // command line is not available.
   106  // Set with the go linker flag -X.
   107  var extraArgs string
   108  
   109  func (l Stage) String() string {
   110  	switch l {
   111  	case StagePaused:
   112  		return "StagePaused"
   113  	case StageRunning:
   114  		return "StageRunning"
   115  	default:
   116  		panic("unexpected Stage value")
   117  	}
   118  }
   119  
   120  func init() {
   121  	if extraArgs != "" {
   122  		args := strings.Split(extraArgs, "|")
   123  		os.Args = append(os.Args, args...)
   124  	}
   125  }
   126  
   127  // DataDir returns a path to use for application-specific
   128  // configuration data.
   129  // On desktop systems, DataDir use os.UserConfigDir.
   130  // On iOS NSDocumentDirectory is queried.
   131  // For Android Context.getFilesDir is used.
   132  //
   133  // BUG: DataDir blocks on Android until init functions
   134  // have completed.
   135  func DataDir() (string, error) {
   136  	return dataDir()
   137  }
   138  
   139  // Main must be called from the a program's main function. It
   140  // blocks until there are no more windows active.
   141  //
   142  // Calling Main is necessary because some operating systems
   143  // require control of the main thread of the program for
   144  // running windows.
   145  func Main() {
   146  	main()
   147  }
   148  
   149  // Config implements the ui.Config interface.
   150  type Config struct {
   151  	// Device pixels per dp.
   152  	pxPerDp float32
   153  	// Device pixels per sp.
   154  	pxPerSp float32
   155  	now     time.Time
   156  }
   157  
   158  func (c *Config) Now() time.Time {
   159  	return c.now
   160  }
   161  
   162  func (c *Config) Px(v ui.Value) int {
   163  	var r float32
   164  	switch v.U {
   165  	case ui.UnitPx:
   166  		r = v.V
   167  	case ui.UnitDp:
   168  		r = c.pxPerDp * v.V
   169  	case ui.UnitSp:
   170  		r = c.pxPerSp * v.V
   171  	default:
   172  		panic("unknown unit")
   173  	}
   174  	return int(math.Round(float64(r)))
   175  }
   176  
   177  func newWindowRendezvous() *windowRendezvous {
   178  	wr := &windowRendezvous{
   179  		in:   make(chan windowAndOptions),
   180  		out:  make(chan windowAndOptions),
   181  		errs: make(chan error),
   182  	}
   183  	go func() {
   184  		var main windowAndOptions
   185  		var out chan windowAndOptions
   186  		for {
   187  			select {
   188  			case w := <-wr.in:
   189  				var err error
   190  				if main.window != nil {
   191  					err = errors.New("multiple windows are not supported")
   192  				}
   193  				wr.errs <- err
   194  				main = w
   195  				out = wr.out
   196  			case out <- main:
   197  			}
   198  		}
   199  	}()
   200  	return wr
   201  }
   202  
   203  func (_ UpdateEvent) ImplementsEvent()   {}
   204  func (_ StageEvent) ImplementsEvent()    {}
   205  func (_ *CommandEvent) ImplementsEvent() {}
   206  func (_ DestroyEvent) ImplementsEvent()  {}