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() {}