basic.go 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489
  1. package widget
  2. import "fmt"
  3. import . "gitlab.com/beoran/ebsgo/zori/types"
  4. import "gitlab.com/beoran/ebsgo/zori/backend"
  5. import "gitlab.com/beoran/ebsgo/zori/state"
  6. import "gitlab.com/beoran/ebsgo/zori/style"
  7. import "gitlab.com/beoran/ebsgo/zori/event"
  8. import "gitlab.com/beoran/ebsgo/monolog"
  9. var LastID = 0
  10. type ActionCallback func (w Widget, data ... interface{}) event.Result
  11. type Basic struct {
  12. Be backend.Backend
  13. ID int
  14. MyRoot RootWidget
  15. Box
  16. Outer Box
  17. Inner Box
  18. Z int
  19. style.BasicTheme
  20. MyParent Widget
  21. MyChildren []Widget
  22. state.Flag
  23. Result interface{}
  24. ActionCallback
  25. }
  26. func (b * Basic) SetBounds(bounds * Box) {
  27. b.Box.X = bounds.X
  28. b.Box.Y = bounds.Y
  29. b.Box.W = bounds.W
  30. b.Box.H = bounds.H
  31. b.Outer = b.Box
  32. b.Inner = b.Box
  33. }
  34. func NewBasicWithTheme(parent Widget, bounds * Box, theme * style.Theme, cb ActionCallback) * Basic {
  35. b := &Basic{}
  36. LastID++
  37. b.ID = LastID
  38. if parent != nil {
  39. b.Be = parent.Backend()
  40. if parent.Theme() != nil {
  41. b.MyTheme = * parent.Theme()
  42. }
  43. if root, ok := parent.(RootWidget) ; ok {
  44. b.MyRoot = root
  45. } else {
  46. b.MyRoot = parent.Root()
  47. }
  48. b.MyParent = parent
  49. box := Bounds(parent.Top(), parent.Left(), parent.Width(), parent.Height())
  50. b.SetBounds(&box)
  51. }
  52. if bounds != nil {
  53. b.SetBounds(bounds)
  54. }
  55. if theme != nil {
  56. b.MyTheme = *theme
  57. }
  58. if cb != nil {
  59. b.ActionCallback = cb
  60. }
  61. return b;
  62. }
  63. func NewBasic(parent Widget, bounds * Box, cb ActionCallback) * Basic {
  64. return NewBasicWithTheme(parent, bounds, nil, cb)
  65. }
  66. func NewBasicWidgetWithTheme(parent Widget, bounds * Box, theme * style.Theme, cb ActionCallback) Widget {
  67. return Widget(NewBasicWidgetWithTheme(parent, bounds, theme, cb));
  68. }
  69. func NewBasicWidget(parent Widget, bounds * Box, cb ActionCallback) Widget {
  70. return Widget(NewBasicWidget(parent, bounds, cb));
  71. }
  72. func (b Basic) Backend() backend.Backend {
  73. return b.Be
  74. }
  75. func (b Basic) Parent() Widget {
  76. return b.MyParent
  77. }
  78. func (b Basic) Root() RootWidget {
  79. return b.MyRoot
  80. }
  81. func (b Basic) Children() []Widget {
  82. return b.MyChildren
  83. }
  84. func (b * Basic) AddChild(widget Widget) Widget {
  85. b.MyChildren = append(b.MyChildren, widget)
  86. return widget
  87. }
  88. func (bw *Basic) Action(ev event.Action) event.Result {
  89. monolog.Info("Action");
  90. if bw.ActionCallback != nil {
  91. return bw.ActionCallback(bw, ev.Data)
  92. }
  93. return event.Pass;
  94. }
  95. func (bw *Basic) Update(ev event.Update) event.Result { monolog.Info("Update"); return event.Pass; }
  96. func (bw *Basic) Draw(ev event.Draw) event.Result { monolog.Info("Draw"); return event.Pass; }
  97. func (bw *Basic) Resize(ev event.Resize) event.Result { monolog.Info("Resize"); return event.Pass; }
  98. func (bw *Basic) Destroy(ev event.Destroy) event.Result { monolog.Info("Destroy"); return event.Pass; }
  99. func (bw *Basic) Close(ev event.Close) event.Result { monolog.Info("Close"); return event.Pass; }
  100. func (bw *Basic) NewChild(ev event.NewChild) event.Result { monolog.Info("Child"); return event.Pass; }
  101. func (bw *Basic) JoystickButtonPress(ev event.Joystick) event.Result { monolog.Info("JBP"); return event.Pass; }
  102. func (bw *Basic) JoystickButtonRelease(ev event.Joystick) event.Result { monolog.Info("JBR"); return event.Pass; }
  103. func (bw *Basic) JoystickAxis(ev event.Joystick) event.Result { monolog.Info("JAX"); return event.Pass; }
  104. func (bw *Basic) KeyPress(ev event.Key) event.Result { monolog.Info("KEP"); return event.Pass; }
  105. func (bw *Basic) KeyRelease(ev event.Key) event.Result { monolog.Info("KER"); return event.Pass; }
  106. func (bw *Basic) MouseAxes(ev event.Mouse) event.Result { monolog.Info("MAX"); return event.Pass; }
  107. func (bw *Basic) MouseWarped(ev event.Mouse) event.Result { monolog.Info("MWA"); return event.Pass; }
  108. func (bw *Basic) MouseButtonPress(ev event.Mouse) event.Result { monolog.Info("MBP"); return event.Pass; }
  109. func (bw *Basic) MouseButtonRelease(ev event.Mouse) event.Result { monolog.Info("MBR"); return event.Pass; }
  110. func (bw *Basic) MouseEnterDisplay(ev event.Mouse) event.Result { monolog.Info("MED"); return event.Pass; }
  111. func (bw *Basic) MouseLeaveDisplay(ev event.Mouse) event.Result { monolog.Info("MLD"); return event.Pass; }
  112. func (bw *Basic) TouchBegin(ev event.Touch) event.Result { monolog.Info("TB"); return event.Pass; }
  113. func (bw *Basic) TouchEnd(ev event.Touch) event.Result { monolog.Info("TE"); return event.Pass; }
  114. func (bw *Basic) TouchMove(ev event.Touch) event.Result { monolog.Info("TM"); return event.Pass; }
  115. func (bw *Basic) TouchCancel(ev event.Touch) event.Result { monolog.Info("TC"); return event.Pass; }
  116. func (bw *Basic) Default(ev event.Event) event.Result {
  117. monolog.Warning("Warning using default event handler for type %d %s!", ev.Type(), event.String(ev));
  118. return event.Pass;
  119. }
  120. func (bw *Basic) KeyChar(kc event.Key) event.Result {
  121. monolog.Info("KeyChar of Basic")
  122. return event.Done
  123. }
  124. // Checks if the coordinates are inside the main rectange of the widget.
  125. func (bw *Basic) IsInside(x, y int) bool {
  126. return (x >= bw.X) && (x <= bw.X + bw.W) && (y >= bw.Y) && (y <= (bw.Y + bw.H))
  127. }
  128. func (bw * Basic) String() string {
  129. return fmt.Sprintf("widget %d", bw.ID)
  130. }
  131. func DispatchRecursive(bw Widget, ev event.Event) event.Result {
  132. res := event.Dispatch(ev, bw)
  133. dlev := "INFO"
  134. switch ev.(type) {
  135. case event.Draw: dlev = "DEBUG"
  136. case event.Update: dlev = "DEBUG"
  137. case event.Mouse: if ev.Type() == event.TypeMouseAxes { dlev = "DEBUG" ; }
  138. default: break
  139. }
  140. monolog.Log(dlev, "Parent dispatch: %s -> %s", event.String(ev), bw.String())
  141. if event.Done != res {
  142. one_ok := false
  143. for _ , child := range bw.Children() {
  144. monolog.Log(dlev, "Child dispatch: %v -> %s", child, event.String(ev))
  145. res := event.Dispatch(ev, child)
  146. if res == event.Done {
  147. one_ok = true
  148. }
  149. }
  150. if one_ok {
  151. return event.Done
  152. } else {
  153. return event.Pass
  154. }
  155. } else {
  156. return event.Done
  157. }
  158. }
  159. func (bw * Basic) Dispatch(ev event.Event) event.Result {
  160. return DispatchRecursive(bw, ev)
  161. }
  162. /** Returns whether or not a widget will even handle an event in the first place.
  163. * For example, a hidden widget won't draw, and a disabled widget won't
  164. * accept any system events, and a NULL widget doesn't accept events at all.. */
  165. func (bw * Basic) AcceptsEvent(ev event.Event) bool {
  166. switch ev.(type) {
  167. case event.Draw: return bw.Visible()
  168. default: return bw.Active()
  169. }
  170. }
  171. func (bw * Basic) Priority() int {
  172. return bw.Z
  173. }
  174. func (bw * Basic) Compare(w Widget) int {
  175. return (w.Priority() - bw.Priority())
  176. }
  177. /* Gets the theme to use for a marked widget. Looks up a root widget and then
  178. * looks for the cursor to determine this. */
  179. func (bw * Basic) MarkedTheme() style.Theme {
  180. return bw.Root().MarkedTheme()
  181. }
  182. /* Gets the style to use for a hovered widget. Looks up a screen widget and then
  183. * looks for the cursor t determine this. */
  184. func (bw * Basic) HoveredTheme() style.Theme {
  185. return bw.Root().HoveredTheme()
  186. }
  187. /* Sets the widget's margins */
  188. func (bw * Basic) SetMargins(left, top, right, bottom int) * Basic {
  189. bw.Outer = bw.Box
  190. bw.Outer.X -= left
  191. bw.Outer.Y -= top
  192. bw.Outer.W += (left+ right)
  193. bw.Outer.H += (top + bottom)
  194. return bw
  195. }
  196. /* Sets the widget's margins, all equal */
  197. func (bw * Basic) SetMargin(size int) * Basic {
  198. return bw.SetMargins(size, size, size, size)
  199. }
  200. /* Sets the widget's paddins */
  201. func (bw * Basic) SetPaddings(left, top, right, bottom int) * Basic {
  202. bw.Inner = bw.Box
  203. bw.Inner.X += left
  204. bw.Inner.Y += top
  205. bw.Inner.W -= (left+ right)
  206. bw.Inner.H -= (top + bottom)
  207. return bw
  208. }
  209. /* Sets the widget's paddings, all equal */
  210. func (bw * Basic) SetPadding(size int) * Basic {
  211. return bw.SetPaddings(size, size, size, size)
  212. }
  213. /* Draws a widget's frame based on it's style. If the background bitmap is set
  214. * then that is used, otherwise, the background color is used, including a border
  215. * if needed. */
  216. func (bw * Basic) DrawBackground() {
  217. be := bw.Backend()
  218. dx := bw.X
  219. dy := bw.Y
  220. dw := bw.W
  221. dh := bw.H
  222. theme := bw.MyTheme
  223. if bw.Hovered() {
  224. theme = bw.HoveredTheme()
  225. } else if bw.Marked() {
  226. theme = bw.MarkedTheme()
  227. }
  228. if theme.Background.Bitmap != nil {
  229. bmp := theme.Background.Bitmap
  230. sw := bmp.Width()
  231. sh := bmp.Height()
  232. // XXX should use draw9 algorithm here
  233. be.DrawScaledBitmap(0,0,sw,sh,dx,dy,dw,dh, bmp)
  234. } else {
  235. fillcol := theme.Background.Color
  236. bordcol := theme.Border.Color
  237. thick := theme.Border.Size
  238. rad := theme.Border.Radius
  239. be.DrawRoundedSlab(dx, dy, dw, dh, rad, rad, fillcol)
  240. be.DrawRoundedRectangle(dx, dy, dw, dh, rad, rad, bordcol, thick)
  241. }
  242. }
  243. func (bw * Basic) SetState(flag state.Flag, set bool) bool {
  244. if set {
  245. bw.Flag |= flag
  246. } else {
  247. bw.Flag &= (^flag)
  248. }
  249. return bw.IsState(flag)
  250. }
  251. func (bw * Basic) IsState(flag state.Flag) bool {
  252. return ((bw.Flag & flag) == flag)
  253. }
  254. func (bw * Basic) Visible() bool {
  255. return bw != nil && ((bw.Flag & state.HIDDEN) != state.HIDDEN)
  256. }
  257. func (bw * Basic) Active() bool {
  258. return bw != nil && ((bw.Flag & state.DISABLED) != state.DISABLED )
  259. }
  260. func (bw * Basic) Hovered() bool {
  261. return bw != nil && bw.IsState(state.HOVERED)
  262. }
  263. func (bw * Basic) Marked() bool {
  264. return bw != nil && bw.IsState(state.MARKED)
  265. }
  266. func (bw * Basic) SetHovered(set bool) bool {
  267. return bw.SetState(state.HOVERED, set)
  268. }
  269. func (bw * Basic) SetMarked(set bool) bool {
  270. return bw.SetState(state.MARKED, set)
  271. }
  272. func (bw * Basic) SetActive(set bool) bool {
  273. bw.SetState(state.DISABLED, !set)
  274. return bw.Active()
  275. }
  276. func (bw * Basic) SetVisible(set bool) bool {
  277. bw.SetState(state.HIDDEN, !set)
  278. return bw.Visible()
  279. }
  280. /** Get active and visible */
  281. func (bw * Basic) Live() bool {
  282. return bw.Active() && bw.Visible()
  283. }
  284. /** Set active and visible */
  285. func (bw * Basic) SetLive(live bool) {
  286. bw.SetActive(live)
  287. bw.SetVisible(live)
  288. }
  289. func (bw * Basic) FindParent(predicate func (wi Widget) bool) Widget {
  290. for parent := bw.Parent() ; parent != nil ; parent = parent.Parent() {
  291. if predicate(parent) {
  292. return parent
  293. }
  294. }
  295. return nil
  296. }
  297. func (bw * Basic) Mark() event.Result {
  298. root := bw.Root().(*Root)
  299. root.Cursors.Keyjoy.Point = bw.Box.Point
  300. return event.Done
  301. }
  302. /* Moves the widget by the offset (dx, dy). Does not move it's children. */
  303. func (bw * Basic) MoveSelfBy(dx, dy int) {
  304. bw.Box.X += dx
  305. bw.Box.Y += dy
  306. bw.Inner.X += dx
  307. bw.Inner.Y += dy
  308. bw.Outer.X += dx
  309. bw.Outer.Y += dy
  310. }
  311. /* Resizes the widget by the offset (dw, dh). Does not move it's children. */
  312. func (bw * Basic) ResizeSelfBy(dw, dh int) {
  313. bw.Box.W += dw
  314. bw.Box.H += dh
  315. bw.Inner.W += dw
  316. bw.Inner.H += dh
  317. bw.Outer.W += dw
  318. bw.Outer.H += dh
  319. }
  320. /* Moves the widget by the offset (dx, dy). It's children will be moved as well recursively
  321. * keeping the offset */
  322. func (bw * Basic) MoveBy(dx, dy int) {
  323. bw.MoveSelfBy(dx, dy)
  324. for _, child := range bw.MyChildren {
  325. child.MoveBy(dx, dy)
  326. }
  327. }
  328. /* Moves the widget to (x, y). It's children will be moved as well recursively
  329. * keeping the offset */
  330. func (bw * Basic) MoveTo(x, y int) {
  331. dx := bw.Box.X - x
  332. dy := bw.Box.Y - y
  333. bw.MoveBy(dx, dy)
  334. }
  335. /* Moves the widget to (x, y). Doesn't move children. */
  336. func (bw * Basic) MoveSelfTo(x, y int) {
  337. dx := bw.Box.X - x
  338. dy := bw.Box.Y - y
  339. bw.MoveSelfBy(dx, dy)
  340. }
  341. /* Resizes the widget to (w, h). Doesn't resize children. Margins and padding will be
  342. * resized accordingly. */
  343. func (bw * Basic) ResizeSelfTo(w, h int) {
  344. dx := bw.Box.W - w
  345. dy := bw.Box.H - h
  346. bw.ResizeSelfBy(dx, dy)
  347. }
  348. /* Makes the widget fit itself to all direct children.
  349. * Does not resize nor move the children.
  350. */
  351. func (bw * Basic) FitToChildren(w, h int) {
  352. min_x := 640
  353. min_y := 480
  354. min_w := 0
  355. min_h := 0
  356. be := bw.Backend()
  357. if be.Display() != nil {
  358. min_x = be.Display().Width()
  359. min_y = be.Display().Height()
  360. }
  361. for _,child := range bw.MyChildren {
  362. if child.Left() < min_x {
  363. min_x = child.Left()
  364. }
  365. if child.Top() < min_y {
  366. min_y = child.Top()
  367. }
  368. if child.Width() > min_w {
  369. min_w = child.Width()
  370. }
  371. if child.Height() > min_h {
  372. min_w = child.Height()
  373. }
  374. }
  375. bw.MoveSelfTo(min_x, min_y)
  376. bw.ResizeSelfTo(min_w, min_h)
  377. }
  378. /* Style getters for ease of use. */
  379. func (bw * Basic) TextFont() Font {
  380. theme := bw.MyTheme
  381. if (theme.Text.Font != nil) {
  382. return theme.Text.Font
  383. }
  384. if bw.MyParent != nil {
  385. return bw.Root().Theme().Text.Font
  386. }
  387. return nil
  388. }
  389. func (bw * Basic) TextColor() Color {
  390. theme := bw.MyTheme
  391. return theme.Text.Color
  392. }
  393. func (bw * Basic) BackgroundColor() Color {
  394. theme := bw.MyTheme
  395. return theme.Background.Color
  396. }