builder.go 60 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431
  1. // Copyright 2016 The G3N Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style
  3. // license that can be found in the LICENSE file.
  4. package gui
  5. import (
  6. "fmt"
  7. "io/ioutil"
  8. "os"
  9. "path/filepath"
  10. "sort"
  11. "strconv"
  12. "strings"
  13. "github.com/g3n/engine/gui/assets/icon"
  14. "github.com/g3n/engine/math32"
  15. "github.com/g3n/engine/window"
  16. "gopkg.in/yaml.v2"
  17. )
  18. // Builder builds GUI objects from a declarative description in YAML format
  19. type Builder struct {
  20. am map[string]interface{} // parsed map with gui object atttributes
  21. imgpath string // base path for image panels files
  22. builders map[string]BuilderFunc // map of builder functions by type
  23. attribs map[string]AttribCheckFunc // map of attribute name with check functions
  24. layouts map[string]IBuilderLayout // map of layout type to layout builder
  25. }
  26. // IBuilderLayout is the interface for all layout builders
  27. type IBuilderLayout interface {
  28. BuildLayout(b *Builder, am map[string]interface{}) (ILayout, error)
  29. BuildParams(b *Builder, am map[string]interface{}) (interface{}, error)
  30. }
  31. // BuilderFunc is type for functions which build a gui object from an attribute map
  32. type BuilderFunc func(*Builder, map[string]interface{}) (IPanel, error)
  33. // BuilderFunc is type for functions which builds a layout object from an attribute map
  34. type LayoutFunc func(*Builder, map[string]interface{}) (ILayout, error)
  35. //// descLayout contains all layout attributes
  36. //type descLayout struct {
  37. // Type string // Type of the layout: HBox, VBox, Grid, Dock, others...
  38. // Cols int // Number of columns for Grid layout
  39. // Spacing float32 // Spacing in pixels for HBox and VBox
  40. // AlignH string // HBox group alignment type
  41. // AlignV string // VBox group alignment type
  42. // MinHeight bool // HBox, VBox minimum height flag
  43. // MinWidth bool // HBox, VBox minimum width flag
  44. // ExpandH bool // Grid
  45. // ExpandV bool // Grid
  46. //}
  47. //
  48. //// descLayoutParam describes all layout parameters types
  49. //type descLayoutParams struct {
  50. // Expand *float32 // HBox, VBox expand factor
  51. // ColSpan int // Grid layout colspan
  52. // AlignH string // horizontal alignment
  53. // AlignV string // vertical alignment
  54. // Edge string // Dock layout edge: top,right,bottom,left,center
  55. //}
  56. //// descPanel describes all panel attributes
  57. //type descPanel struct {
  58. // Type string // Gui object type: Panel, Label, Edit, etc ...
  59. // Name string // Optional name for identification
  60. // Position string // Optional position as: x y | x,y
  61. // Width *float32 // Optional width (default = 0)
  62. // Height *float32 // Optional height (default = 0)
  63. // AspectWidth *float32 // Optional aspectwidth (default = nil)
  64. // AspectHeight *float32 // Optional aspectwidth (default = nil)
  65. // Margins string // Optional margins as 1 or 4 float values
  66. // Borders string // Optional borders as 1 or 4 float values
  67. // BorderColor string // Optional border color as name or 3 or 4 float values
  68. // Paddings string // Optional paddings as 1 or 4 float values
  69. // Color string // Optional color as 1 or 4 float values
  70. // Enabled *bool // All:
  71. // Visible *bool // All:
  72. // Renderable *bool // All:
  73. // Imagefile string // For Panel, Button
  74. // Layout *descLayout // Optional pointer to layout
  75. // LayoutParams *descLayoutParams // Optional layout parameters
  76. // Text string // Label, Button
  77. // Icons string // Label
  78. // BgColor string // Label
  79. // FontColor string // Label
  80. // FontSize *float32 // Label
  81. // FontDPI *float32 // Label
  82. // LineSpacing *float32 // Label
  83. // PlaceHolder string // Edit
  84. // MaxLength *uint // Edit
  85. // Icon string // Button
  86. // Group string // RadioButton
  87. // Checked bool // CheckBox, RadioButton
  88. // ImageLabel *descPanel // DropDown
  89. // Items []*descPanel // Menu, MenuBar
  90. // Shortcut string // Menu
  91. // Value *float32 // Slider
  92. // ScaleFactor *float32 // Slider
  93. // Title string // Window
  94. // Resizable string // Window resizable borders
  95. // P0 *descPanel // Splitter panel 0
  96. // P1 *descPanel // Splitter panel 1
  97. // Split *float32 // Splitter split value
  98. // parent *descPanel // used internally
  99. //}
  100. // Panel and layout types
  101. const (
  102. TypePanel = "panel"
  103. TypeImagePanel = "imagepanel"
  104. TypeLabel = "label"
  105. TypeImageLabel = "imagelabel"
  106. TypeButton = "button"
  107. TypeCheckBox = "checkbox"
  108. TypeRadioButton = "radiobutton"
  109. TypeEdit = "edit"
  110. TypeVList = "vlist"
  111. TypeHList = "hlist"
  112. TypeDropDown = "dropdown"
  113. TypeHSlider = "hslider"
  114. TypeVSlider = "vslider"
  115. TypeHSplitter = "hsplitter"
  116. TypeVSplitter = "vsplitter"
  117. TypeSeparator = "separator"
  118. TypeTree = "tree"
  119. TypeTreeNode = "node"
  120. TypeMenuBar = "menubar"
  121. TypeMenu = "menu"
  122. TypeWindow = "window"
  123. TypeHBoxLayout = "hbox"
  124. TypeVBoxLayout = "vbox"
  125. TypeGridLayout = "grid"
  126. TypeDockLayout = "dock"
  127. )
  128. // Common attribute names
  129. const (
  130. AttribAlignv = "alignv" // Align
  131. AttribAlignh = "alignh" // Align
  132. AttribAspectHeight = "aspectheight" // float32
  133. AttribAspectWidth = "aspectwidth" // float32
  134. AttribBgColor = "bgcolor" // Color4
  135. AttribBorders = "borders" // BorderSizes
  136. AttribBorderColor = "bordercolor" // Color4
  137. AttribChecked = "checked" // bool
  138. AttribColor = "color" // Color4
  139. AttribCols = "cols" // Int
  140. AttribColSpan = "colspan" // Int
  141. AttribEdge = "edge" // int
  142. AttribEnabled = "enabled" // bool
  143. AttribExpand = "expand" // float32
  144. AttribExpandh = "expandh" // bool
  145. AttribExpandv = "expandv" // bool
  146. AttribFontColor = "fontcolor" // Color4
  147. AttribFontDPI = "fontdpi" // float32
  148. AttribFontSize = "fontsize" // float32
  149. AttribGroup = "group" // string
  150. AttribHeight = "height" // float32
  151. AttribIcon = "icon" // string
  152. AttribImageFile = "imagefile" // string
  153. AttribImageLabel = "imagelabel" // []map[string]interface{}
  154. AttribItems = "items" // []map[string]interface{}
  155. AttribLayout = "layout" // map[string]interface{}
  156. AttribLayoutParams = "layoutparams" // map[string]interface{}
  157. AttribLineSpacing = "linespacing" // float32
  158. AttribMinHeight = "minheight" // bool
  159. AttribMinWidth = "minwidth" // bool
  160. AttribMargins = "margins" // BorderSizes
  161. AttribName = "name" // string
  162. AttribPaddings = "paddings" // BorderSizes
  163. AttribPanel0 = "panel0" // map[string]interface{}
  164. AttribPanel1 = "panel1" // map[string]interface{}
  165. AttribParent_ = "parent_" // string (internal attribute)
  166. AttribPlaceHolder = "placeholder" // string
  167. AttribPosition = "position" // []float32
  168. AttribRender = "render" // bool
  169. AttribScaleFactor = "scalefactor" // float32
  170. AttribShortcut = "shortcut" // []int
  171. AttribSpacing = "spacing" // float32
  172. AttribText = "text" // string
  173. AttribType = "type" // string
  174. AttribWidth = "width" // float32
  175. AttribValue = "value" // float32
  176. AttribVisible = "visible" // bool
  177. )
  178. const (
  179. aPOS = 1 << iota // attribute position
  180. aSIZE = 1 << iota // attribute size
  181. aNAME = 1 << iota // attribute name
  182. aMARGINS = 1 << iota // attribute margins widths
  183. aBORDERS = 1 << iota // attribute borders widths
  184. aBORDERCOLOR = 1 << iota // attribute border color
  185. aPADDINGS = 1 << iota // attribute paddings widths
  186. aCOLOR = 1 << iota // attribute panel bgcolor
  187. aENABLED = 1 << iota // attribute enabled for events
  188. aRENDER = 1 << iota // attribute renderable
  189. aVISIBLE = 1 << iota // attribute visible
  190. asPANEL = 0xFF // attribute set for panels
  191. asWIDGET = aPOS | aNAME | aSIZE | aENABLED | aVISIBLE // attribute set for widgets
  192. )
  193. // maps align name with align parameter
  194. var mapAlignh = map[string]Align{
  195. "none": AlignNone,
  196. "left": AlignLeft,
  197. "right": AlignRight,
  198. "width": AlignWidth,
  199. "center": AlignCenter,
  200. }
  201. // maps align name with align parameter
  202. var mapAlignv = map[string]Align{
  203. "none": AlignNone,
  204. "top": AlignTop,
  205. "bottom": AlignBottom,
  206. "height": AlignHeight,
  207. "center": AlignCenter,
  208. }
  209. // maps edge name (dock layout) with edge parameter
  210. var mapEdgeName = map[string]int{
  211. "top": DockTop,
  212. "right": DockRight,
  213. "bottom": DockBottom,
  214. "left": DockLeft,
  215. "center": DockCenter,
  216. }
  217. // maps resize border name (window) with parameter value
  218. var mapResizable = map[string]Resizable{
  219. "top": ResizeTop,
  220. "right": ResizeRight,
  221. "bottom": ResizeBottom,
  222. "left": ResizeLeft,
  223. "all": ResizeAll,
  224. }
  225. type AttribCheckFunc func(b *Builder, am map[string]interface{}, fname string) error
  226. // NewBuilder creates and returns a pointer to a new gui Builder object
  227. func NewBuilder() *Builder {
  228. b := new(Builder)
  229. // Sets map of object type to builder function
  230. b.builders = map[string]BuilderFunc{
  231. TypePanel: buildPanel,
  232. TypeImagePanel: buildImagePanel,
  233. TypeLabel: buildLabel,
  234. TypeImageLabel: buildImageLabel,
  235. TypeButton: buildButton,
  236. TypeEdit: buildEdit,
  237. TypeCheckBox: buildCheckBox,
  238. TypeRadioButton: buildRadioButton,
  239. TypeVList: buildVList,
  240. TypeHList: buildHList,
  241. TypeDropDown: buildDropDown,
  242. TypeMenu: buildMenu,
  243. TypeMenuBar: buildMenu,
  244. TypeHSlider: buildSlider,
  245. TypeVSlider: buildSlider,
  246. TypeHSplitter: buildSplitter,
  247. TypeVSplitter: buildSplitter,
  248. TypeTree: buildTree,
  249. }
  250. // Sets map of layout type name to layout function
  251. b.layouts = map[string]IBuilderLayout{
  252. TypeHBoxLayout: &BuilderLayoutHBox{},
  253. TypeVBoxLayout: &BuilderLayoutVBox{},
  254. TypeGridLayout: &BuilderLayoutGrid{},
  255. TypeDockLayout: &BuilderLayoutDock{},
  256. }
  257. // Sets map of attribute name to check function
  258. b.attribs = map[string]AttribCheckFunc{
  259. AttribAlignv: AttribCheckAlign,
  260. AttribAlignh: AttribCheckAlign,
  261. AttribAspectWidth: AttribCheckFloat,
  262. AttribAspectHeight: AttribCheckFloat,
  263. AttribHeight: AttribCheckFloat,
  264. AttribMargins: AttribCheckBorderSizes,
  265. AttribBgColor: AttribCheckColor,
  266. AttribBorders: AttribCheckBorderSizes,
  267. AttribBorderColor: AttribCheckColor,
  268. AttribChecked: AttribCheckBool,
  269. AttribColor: AttribCheckColor,
  270. AttribCols: AttribCheckInt,
  271. AttribColSpan: AttribCheckInt,
  272. AttribEdge: AttribCheckEdge,
  273. AttribEnabled: AttribCheckBool,
  274. AttribExpand: AttribCheckFloat,
  275. AttribExpandh: AttribCheckBool,
  276. AttribExpandv: AttribCheckBool,
  277. AttribFontColor: AttribCheckColor,
  278. AttribFontDPI: AttribCheckFloat,
  279. AttribFontSize: AttribCheckFloat,
  280. AttribGroup: AttribCheckString,
  281. AttribIcon: AttribCheckIcons,
  282. AttribImageFile: AttribCheckString,
  283. AttribImageLabel: AttribCheckMap,
  284. AttribItems: AttribCheckListMap,
  285. AttribLayout: AttribCheckLayout,
  286. AttribLayoutParams: AttribCheckMap,
  287. AttribLineSpacing: AttribCheckFloat,
  288. AttribMinHeight: AttribCheckBool,
  289. AttribMinWidth: AttribCheckBool,
  290. AttribName: AttribCheckString,
  291. AttribPaddings: AttribCheckBorderSizes,
  292. AttribPanel0: AttribCheckMap,
  293. AttribPanel1: AttribCheckMap,
  294. AttribPlaceHolder: AttribCheckString,
  295. AttribPosition: AttribCheckPosition,
  296. AttribRender: AttribCheckBool,
  297. AttribScaleFactor: AttribCheckFloat,
  298. AttribShortcut: AttribCheckMenuShortcut,
  299. AttribSpacing: AttribCheckFloat,
  300. AttribText: AttribCheckString,
  301. AttribType: AttribCheckStringLower,
  302. AttribValue: AttribCheckFloat,
  303. AttribVisible: AttribCheckBool,
  304. AttribWidth: AttribCheckFloat,
  305. }
  306. return b
  307. }
  308. // ParseString parses a string with gui objects descriptions in YAML format
  309. // It there was a previously parsed description, it is cleared.
  310. func (b *Builder) ParseString(desc string) error {
  311. // Parses descriptor string in YAML format saving result in
  312. // a map of interface{} to interface{} as YAML allows numeric keys.
  313. var mii map[interface{}]interface{}
  314. err := yaml.Unmarshal([]byte(desc), &mii)
  315. if err != nil {
  316. return err
  317. }
  318. // If all the values of the top level map keys are other maps,
  319. // then it is a description of several objects, otherwise it is
  320. // a description of a single object.
  321. single := false
  322. for _, v := range mii {
  323. _, ok := v.(map[interface{}]interface{})
  324. if !ok {
  325. single = true
  326. break
  327. }
  328. }
  329. log.Error("single:%v", single)
  330. // Internal function which converts map[interface{}]interface{} to
  331. // map[string]interface{} recursively and lower case of all map keys.
  332. // It also sets a field named "parent_", which pointer to the parent map
  333. // This field causes a circular reference in the result map which prevents
  334. // the use of Go's Printf to print the result map.
  335. var visitor func(v, par interface{}) (interface{}, error)
  336. visitor = func(v, par interface{}) (interface{}, error) {
  337. switch vt := v.(type) {
  338. case []interface{}:
  339. ls := []interface{}{}
  340. for _, item := range vt {
  341. ci, err := visitor(item, par)
  342. if err != nil {
  343. return nil, err
  344. }
  345. ls = append(ls, ci)
  346. }
  347. return ls, nil
  348. case map[interface{}]interface{}:
  349. ms := make(map[string]interface{})
  350. for k, v := range vt {
  351. // Checks key
  352. ks, ok := k.(string)
  353. if !ok {
  354. return nil, fmt.Errorf("Keys must be strings")
  355. }
  356. ks = strings.ToLower(ks)
  357. // Checks value
  358. vi, err := visitor(v, ms)
  359. if err != nil {
  360. return nil, err
  361. }
  362. ms[ks] = vi
  363. // If has panel has parent or is a single top level panel, checks attributes
  364. if par != nil || single {
  365. // Get attribute check function
  366. acf, ok := b.attribs[ks]
  367. if !ok {
  368. return nil, fmt.Errorf("Invalid attribute:%s", ks)
  369. }
  370. // Checks attribute
  371. err = acf(b, ms, ks)
  372. if err != nil {
  373. return nil, err
  374. }
  375. }
  376. }
  377. if par != nil {
  378. ms[AttribParent_] = par
  379. }
  380. return ms, nil
  381. default:
  382. return v, nil
  383. }
  384. return nil, nil
  385. }
  386. // Get map[string]interface{} with lower case keys from parsed descritor
  387. res, err := visitor(mii, nil)
  388. if err != nil {
  389. return err
  390. }
  391. msi, ok := res.(map[string]interface{})
  392. if !ok {
  393. return fmt.Errorf("Parsed result is not a map")
  394. }
  395. b.am = msi
  396. //b.debugPrint(b.am, 1)
  397. return nil
  398. }
  399. // ParseFile parses a file with gui objects descriptions in YAML format
  400. // It there was a previously parsed description, it is cleared.
  401. func (b *Builder) ParseFile(filepath string) error {
  402. // Reads all file data
  403. f, err := os.Open(filepath)
  404. if err != nil {
  405. return err
  406. }
  407. data, err := ioutil.ReadAll(f)
  408. if err != nil {
  409. return err
  410. }
  411. err = f.Close()
  412. if err != nil {
  413. return err
  414. }
  415. // Parses file data
  416. return b.ParseString(string(data))
  417. }
  418. // Names returns a sorted list of names of top level previously parsed objects.
  419. // Only objects with defined types are returned.
  420. // If there is only a single object with no name, its name is returned
  421. // as an empty string
  422. func (b *Builder) Names() []string {
  423. var objs []string
  424. if b.am[AttribType] != nil {
  425. objs = append(objs, "")
  426. return objs
  427. }
  428. for name, _ := range b.am {
  429. objs = append(objs, name)
  430. }
  431. sort.Strings(objs)
  432. return objs
  433. }
  434. // Build builds a gui object and all its children recursively.
  435. // The specified name should be a top level name from a
  436. // from a previously parsed description
  437. // If the descriptions contains a single object with no name,
  438. // It should be specified the empty string to build this object.
  439. func (b *Builder) Build(name string) (IPanel, error) {
  440. // Only one object
  441. if name == "" {
  442. log.Error("TYPE:---------->%T", b.am)
  443. return b.build(b.am, nil)
  444. }
  445. // Map of gui objects
  446. am, ok := b.am[name]
  447. if !ok {
  448. return nil, fmt.Errorf("Object name:%s not found", name)
  449. }
  450. return b.build(am.(map[string]interface{}), nil)
  451. }
  452. // Sets the path for image panels relative image files
  453. func (b *Builder) SetImagepath(path string) {
  454. b.imgpath = path
  455. }
  456. func (b *Builder) AddBuilder(typename string, bf BuilderFunc) {
  457. b.builders[typename] = bf
  458. }
  459. // build builds the gui object from the specified description.
  460. // All its children are also built recursively
  461. // Returns the built object or an error
  462. func (b *Builder) build(am map[string]interface{}, iparent IPanel) (IPanel, error) {
  463. // Get panel type
  464. itype := am[AttribType]
  465. if itype == nil {
  466. return nil, fmt.Errorf("Type not specified")
  467. }
  468. typename := itype.(string)
  469. // Get builder function for this type name
  470. builder := b.builders[typename]
  471. if builder == nil {
  472. return nil, fmt.Errorf("Invalid type:%v", typename)
  473. }
  474. // Builds panel
  475. pan, err := builder(b, am)
  476. if err != nil {
  477. return nil, err
  478. }
  479. // Adds built panel to parent
  480. if iparent != nil {
  481. iparent.GetPanel().Add(pan)
  482. }
  483. return pan, nil
  484. }
  485. // buildPanel builds an object of type Panel
  486. func buildPanel(b *Builder, am map[string]interface{}) (IPanel, error) {
  487. pan := NewPanel(0, 0)
  488. err := b.setAttribs(am, pan, asPANEL)
  489. if err != nil {
  490. return nil, err
  491. }
  492. // Builds children recursively
  493. if am[AttribItems] != nil {
  494. items := am[AttribItems].([]map[string]interface{})
  495. for i := 0; i < len(items); i++ {
  496. item := items[i]
  497. child, err := b.build(item, pan)
  498. if err != nil {
  499. return nil, err
  500. }
  501. pan.Add(child)
  502. }
  503. }
  504. return pan, nil
  505. }
  506. // buildImagePanel builds a gui object of type ImagePanel
  507. func buildImagePanel(b *Builder, am map[string]interface{}) (IPanel, error) {
  508. // Checks imagefile attribute
  509. if am[AttribImageFile] == nil {
  510. return nil, b.err(am, AttribImageFile, "Must be supplied")
  511. }
  512. // If path is not absolute join with user supplied image base path
  513. imagefile := am[AttribImageFile].(string)
  514. if !filepath.IsAbs(imagefile) {
  515. imagefile = filepath.Join(b.imgpath, imagefile)
  516. }
  517. // Builds panel and set common attributes
  518. panel, err := NewImage(imagefile)
  519. if err != nil {
  520. return nil, err
  521. }
  522. err = b.setAttribs(am, panel, asPANEL)
  523. if err != nil {
  524. return nil, err
  525. }
  526. // Sets optional AspectWidth attribute
  527. if aw := am[AttribAspectWidth]; aw != nil {
  528. panel.SetContentAspectWidth(aw.(float32))
  529. }
  530. // Sets optional AspectHeight attribute
  531. if ah := am[AttribAspectHeight]; ah != nil {
  532. panel.SetContentAspectHeight(ah.(float32))
  533. }
  534. // Builds children recursively
  535. if am[AttribItems] != nil {
  536. items := am[AttribItems].([]map[string]interface{})
  537. for i := 0; i < len(items); i++ {
  538. item := items[i]
  539. child, err := b.build(item, panel)
  540. if err != nil {
  541. return nil, err
  542. }
  543. panel.Add(child)
  544. }
  545. }
  546. return panel, nil
  547. }
  548. // buildLabel builds a gui object of type Label
  549. func buildLabel(b *Builder, am map[string]interface{}) (IPanel, error) {
  550. var label *Label
  551. if am[AttribIcon] != nil {
  552. label = NewLabel(am[AttribIcon].(string), true)
  553. } else if am[AttribText] != nil {
  554. label = NewLabel(am[AttribText].(string))
  555. } else {
  556. label = NewLabel("")
  557. }
  558. // Sets common attributes
  559. err := b.setAttribs(am, label, asPANEL)
  560. if err != nil {
  561. return nil, err
  562. }
  563. // Set optional background color
  564. if bgc := am[AttribBgColor]; bgc != nil {
  565. label.SetBgColor4(bgc.(*math32.Color4))
  566. }
  567. // Set optional font color
  568. if fc := am[AttribFontColor]; fc != nil {
  569. label.SetColor4(fc.(*math32.Color4))
  570. }
  571. // Sets optional font size
  572. if fs := am[AttribFontSize]; fs != nil {
  573. label.SetFontSize(float64(fs.(float32)))
  574. }
  575. // Sets optional font dpi
  576. if fdpi := am[AttribFontDPI]; fdpi != nil {
  577. label.SetFontDPI(float64(fdpi.(float32)))
  578. }
  579. // Sets optional line spacing
  580. if ls := am[AttribLineSpacing]; ls != nil {
  581. label.SetLineSpacing(float64(ls.(float32)))
  582. }
  583. return label, nil
  584. }
  585. // buildImageLabel builds a gui object of type: ImageLabel
  586. func buildImageLabel(b *Builder, am map[string]interface{}) (IPanel, error) {
  587. // Builds image label and set common attributes
  588. var text string
  589. if am[AttribText] != nil {
  590. text = am[AttribText].(string)
  591. }
  592. imglabel := NewImageLabel(text)
  593. err := b.setAttribs(am, imglabel, asPANEL)
  594. if err != nil {
  595. return nil, err
  596. }
  597. // Sets optional icon(s)
  598. if icon := am[AttribIcon]; icon != nil {
  599. imglabel.SetIcon(icon.(string))
  600. }
  601. // Sets optional image from file
  602. // If path is not absolute join with user supplied image base path
  603. if imgf := am[AttribImageFile]; imgf != nil {
  604. path := imgf.(string)
  605. if !filepath.IsAbs(path) {
  606. path = filepath.Join(b.imgpath, path)
  607. }
  608. err := imglabel.SetImageFromFile(path)
  609. if err != nil {
  610. return nil, err
  611. }
  612. }
  613. return imglabel, nil
  614. }
  615. // buildButton builds a gui object of type: Button
  616. func buildButton(b *Builder, am map[string]interface{}) (IPanel, error) {
  617. // Builds button and set commont attributes
  618. var text string
  619. if am[AttribText] != nil {
  620. text = am[AttribText].(string)
  621. }
  622. button := NewButton(text)
  623. err := b.setAttribs(am, button, asWIDGET)
  624. if err != nil {
  625. return nil, err
  626. }
  627. // Sets optional icon(s)
  628. if icon := am[AttribIcon]; icon != nil {
  629. button.SetIcon(icon.(string))
  630. }
  631. // Sets optional image from file
  632. // If path is not absolute join with user supplied image base path
  633. if imgf := am[AttribImageFile]; imgf != nil {
  634. path := imgf.(string)
  635. if !filepath.IsAbs(path) {
  636. path = filepath.Join(b.imgpath, path)
  637. }
  638. err := button.SetImage(path)
  639. if err != nil {
  640. return nil, err
  641. }
  642. }
  643. return button, nil
  644. }
  645. // buildEdit builds a gui object of type: "Edit"
  646. func buildEdit(b *Builder, am map[string]interface{}) (IPanel, error) {
  647. // Builds button and set attributes
  648. var width float32
  649. var placeholder string
  650. if aw := am[AttribWidth]; aw != nil {
  651. width = aw.(float32)
  652. }
  653. if ph := am[AttribPlaceHolder]; ph != nil {
  654. placeholder = ph.(string)
  655. }
  656. edit := NewEdit(int(width), placeholder)
  657. err := b.setAttribs(am, edit, asWIDGET)
  658. if err != nil {
  659. return nil, err
  660. }
  661. return edit, nil
  662. }
  663. // buildCheckBox builds a gui object of type: CheckBox
  664. func buildCheckBox(b *Builder, am map[string]interface{}) (IPanel, error) {
  665. // Builds check box and set commont attributes
  666. var text string
  667. if am[AttribText] != nil {
  668. text = am[AttribText].(string)
  669. }
  670. cb := NewCheckBox(text)
  671. err := b.setAttribs(am, cb, asWIDGET)
  672. if err != nil {
  673. return nil, err
  674. }
  675. // Sets optional checked value
  676. if checked := am[AttribChecked]; checked != nil {
  677. cb.SetValue(checked.(bool))
  678. }
  679. return cb, nil
  680. }
  681. // buildRadioButton builds a gui object of type: RadioButton
  682. func buildRadioButton(b *Builder, am map[string]interface{}) (IPanel, error) {
  683. // Builds check box and set commont attributes
  684. var text string
  685. if am[AttribText] != nil {
  686. text = am[AttribText].(string)
  687. }
  688. rb := NewRadioButton(text)
  689. err := b.setAttribs(am, rb, asWIDGET)
  690. if err != nil {
  691. return nil, err
  692. }
  693. // Sets optional radio button group
  694. if gr := am[AttribGroup]; gr != nil {
  695. rb.SetGroup(gr.(string))
  696. }
  697. // Sets optional checked value
  698. if checked := am[AttribChecked]; checked != nil {
  699. rb.SetValue(checked.(bool))
  700. }
  701. return rb, nil
  702. }
  703. // buildVList builds a gui object of type: VList
  704. func buildVList(b *Builder, am map[string]interface{}) (IPanel, error) {
  705. // Builds list and set commont attributes
  706. list := NewVList(0, 0)
  707. err := b.setAttribs(am, list, asWIDGET)
  708. if err != nil {
  709. return nil, err
  710. }
  711. // Builds children
  712. if am[AttribItems] != nil {
  713. items := am[AttribItems].([]map[string]interface{})
  714. for i := 0; i < len(items); i++ {
  715. item := items[i]
  716. child, err := b.build(item, list)
  717. if err != nil {
  718. return nil, err
  719. }
  720. list.Add(child)
  721. }
  722. }
  723. return list, nil
  724. }
  725. // buildHList builds a gui object of type: VList
  726. func buildHList(b *Builder, am map[string]interface{}) (IPanel, error) {
  727. // Builds list and set commont attributes
  728. list := NewHList(0, 0)
  729. err := b.setAttribs(am, list, asWIDGET)
  730. if err != nil {
  731. return nil, err
  732. }
  733. // Builds children
  734. if am[AttribItems] != nil {
  735. items := am[AttribItems].([]map[string]interface{})
  736. for i := 0; i < len(items); i++ {
  737. item := items[i]
  738. child, err := b.build(item, list)
  739. if err != nil {
  740. return nil, err
  741. }
  742. list.Add(child)
  743. }
  744. }
  745. return list, nil
  746. }
  747. // buildDropDown builds a gui object of type: DropDown
  748. func buildDropDown(b *Builder, am map[string]interface{}) (IPanel, error) {
  749. // If image label attribute defined use it, otherwise
  750. // uses default value.
  751. var imglabel *ImageLabel
  752. if iv := am[AttribImageLabel]; iv != nil {
  753. imgl := iv.(map[string]interface{})
  754. imgl[AttribType] = TypeImageLabel
  755. ipan, err := b.build(imgl, nil)
  756. if err != nil {
  757. return nil, err
  758. }
  759. imglabel = ipan.(*ImageLabel)
  760. } else {
  761. imglabel = NewImageLabel("")
  762. }
  763. // Builds drop down and set common attributes
  764. dd := NewDropDown(0, imglabel)
  765. err := b.setAttribs(am, dd, asWIDGET)
  766. if err != nil {
  767. return nil, err
  768. }
  769. // Builds children
  770. if am[AttribItems] != nil {
  771. items := am[AttribItems].([]map[string]interface{})
  772. for i := 0; i < len(items); i++ {
  773. item := items[i]
  774. child, err := b.build(item, dd)
  775. if err != nil {
  776. return nil, err
  777. }
  778. dd.Add(child.(*ImageLabel))
  779. }
  780. }
  781. return dd, nil
  782. }
  783. // buildMenu builds a gui object of type: Menu or MenuBar from the
  784. // specified panel descriptor.
  785. func buildMenu(b *Builder, am map[string]interface{}) (IPanel, error) {
  786. // Builds menu bar or menu
  787. var menu *Menu
  788. if am[AttribType].(string) == TypeMenuBar {
  789. menu = NewMenuBar()
  790. } else {
  791. menu = NewMenu()
  792. }
  793. // Only sets attribs for top level menus
  794. if pi := am[AttribParent_]; pi != nil {
  795. par := pi.(map[string]interface{})
  796. ptype := ""
  797. if ti := par[AttribType]; ti != nil {
  798. ptype = ti.(string)
  799. }
  800. if ptype != TypeMenu && ptype != TypeMenuBar {
  801. err := b.setAttribs(am, menu, asWIDGET)
  802. if err != nil {
  803. return nil, err
  804. }
  805. }
  806. }
  807. // Builds and adds menu items
  808. if am[AttribItems] != nil {
  809. items := am[AttribItems].([]map[string]interface{})
  810. for i := 0; i < len(items); i++ {
  811. // Get the item optional type and text
  812. item := items[i]
  813. itype := ""
  814. itext := ""
  815. if iv := item[AttribType]; iv != nil {
  816. itype = iv.(string)
  817. }
  818. if iv := item[AttribText]; iv != nil {
  819. itext = iv.(string)
  820. }
  821. // Item is another menu
  822. if itype == TypeMenu {
  823. subm, err := buildMenu(b, item)
  824. if err != nil {
  825. return nil, err
  826. }
  827. menu.AddMenu(itext, subm.(*Menu))
  828. continue
  829. }
  830. // Item is a separator
  831. if itext == TypeSeparator {
  832. menu.AddSeparator()
  833. continue
  834. }
  835. // Item must be a menu option
  836. mi := menu.AddOption(itext)
  837. // Set item optional icon(s)
  838. if icon := item[AttribIcon]; icon != nil {
  839. mi.SetIcon(icon.(string))
  840. }
  841. // Sets optional menu item shortcut
  842. if sci := item[AttribShortcut]; sci != nil {
  843. sc := sci.([]int)
  844. mi.SetShortcut(window.ModifierKey(sc[0]), window.Key(sc[1]))
  845. }
  846. }
  847. }
  848. return menu, nil
  849. }
  850. // buildSlider builds a gui object of type: HSlider or VSlider
  851. func buildSlider(b *Builder, am map[string]interface{}) (IPanel, error) {
  852. // Builds horizontal or vertical slider
  853. var slider *Slider
  854. if am[AttribType].(string) == TypeHSlider {
  855. slider = NewHSlider(0, 0)
  856. } else {
  857. slider = NewVSlider(0, 0)
  858. }
  859. // Sets common attributes
  860. err := b.setAttribs(am, slider, asWIDGET)
  861. if err != nil {
  862. return nil, err
  863. }
  864. // Sets optional text
  865. if itext := am[AttribText]; itext != nil {
  866. slider.SetText(itext.(string))
  867. }
  868. // Sets optional scale factor
  869. if isf := am[AttribScaleFactor]; isf != nil {
  870. slider.SetScaleFactor(isf.(float32))
  871. }
  872. // Sets optional value
  873. if iv := am[AttribValue]; iv != nil {
  874. slider.SetValue(iv.(float32))
  875. }
  876. return slider, nil
  877. }
  878. // buildSplitter builds a gui object of type: HSplitterr or VSplitter
  879. func buildSplitter(b *Builder, am map[string]interface{}) (IPanel, error) {
  880. // Builds horizontal or vertical splitter
  881. var splitter *Splitter
  882. if am[AttribType].(string) == TypeHSplitter {
  883. splitter = NewHSplitter(0, 0)
  884. } else {
  885. splitter = NewVSplitter(0, 0)
  886. }
  887. // Sets common attributes
  888. err := b.setAttribs(am, splitter, asWIDGET)
  889. if err != nil {
  890. return nil, err
  891. }
  892. // Sets optional split value
  893. if iv := am[AttribValue]; iv != nil {
  894. splitter.SetSplit(iv.(float32))
  895. }
  896. // Internal function to set each of the splitter's panel attributes and items
  897. setpan := func(attrib string, pan *Panel) error {
  898. // Get internal panel attributes
  899. ipattribs := am[attrib]
  900. if ipattribs == nil {
  901. return nil
  902. }
  903. pattr := ipattribs.(map[string]interface{})
  904. // Set panel attributes
  905. err := b.setAttribs(pattr, pan, asPANEL)
  906. if err != nil {
  907. return nil
  908. }
  909. // Builds panel children
  910. if pattr[AttribItems] != nil {
  911. items := pattr[AttribItems].([]map[string]interface{})
  912. for i := 0; i < len(items); i++ {
  913. item := items[i]
  914. child, err := b.build(item, pan)
  915. if err != nil {
  916. return err
  917. }
  918. pan.Add(child)
  919. }
  920. }
  921. return nil
  922. }
  923. // Set optional splitter panel's attributes
  924. err = setpan(AttribPanel0, &splitter.P0)
  925. if err != nil {
  926. return nil, err
  927. }
  928. err = setpan(AttribPanel1, &splitter.P1)
  929. if err != nil {
  930. return nil, err
  931. }
  932. return splitter, nil
  933. }
  934. // buildTree builds a gui object of type: Tree
  935. func buildTree(b *Builder, am map[string]interface{}) (IPanel, error) {
  936. // Builds tree and sets its common attributes
  937. tree := NewTree(0, 0)
  938. err := b.setAttribs(am, tree, asWIDGET)
  939. if err != nil {
  940. return nil, err
  941. }
  942. // Internal function to build tree nodes recursively
  943. var buildItems func(am map[string]interface{}, pnode *TreeNode) error
  944. buildItems = func(am map[string]interface{}, pnode *TreeNode) error {
  945. v := am[AttribItems]
  946. if v == nil {
  947. return nil
  948. }
  949. items := v.([]map[string]interface{})
  950. for i := 0; i < len(items); i++ {
  951. // Get the item type
  952. item := items[i]
  953. itype := ""
  954. if v := item[AttribType]; v != nil {
  955. itype = v.(string)
  956. }
  957. itext := ""
  958. if v := item[AttribText]; v != nil {
  959. itext = v.(string)
  960. }
  961. // Item is a tree node
  962. if itype == "" || itype == TypeTreeNode {
  963. var node *TreeNode
  964. if pnode == nil {
  965. node = tree.AddNode(itext)
  966. } else {
  967. node = pnode.AddNode(itext)
  968. }
  969. err := buildItems(item, node)
  970. if err != nil {
  971. return err
  972. }
  973. continue
  974. }
  975. // Other controls
  976. ipan, err := b.build(item, nil)
  977. if err != nil {
  978. return err
  979. }
  980. if pnode == nil {
  981. tree.Add(ipan)
  982. } else {
  983. pnode.Add(ipan)
  984. }
  985. }
  986. return nil
  987. }
  988. // Build nodes
  989. err = buildItems(am, nil)
  990. if err != nil {
  991. return nil, err
  992. }
  993. return tree, nil
  994. }
  995. // setLayout sets the optional layout of the specified panel
  996. func (b *Builder) setLayout(am map[string]interface{}, ipan IPanel) error {
  997. // Get layout type
  998. lai := am[AttribLayout]
  999. if lai == nil {
  1000. return nil
  1001. }
  1002. lam := lai.(map[string]interface{})
  1003. ltype := lam[AttribType]
  1004. if ltype == nil {
  1005. return b.err(am, AttribType, "Layout must have a type")
  1006. }
  1007. // Get layout builder
  1008. lbuilder := b.layouts[ltype.(string)]
  1009. if lbuilder == nil {
  1010. return b.err(am, AttribType, "Invalid layout type")
  1011. }
  1012. // Builds layout builder and set to panel
  1013. layout, err := lbuilder.BuildLayout(b, lam)
  1014. if err != nil {
  1015. return err
  1016. }
  1017. ipan.SetLayout(layout)
  1018. return nil
  1019. }
  1020. func (b *Builder) setLayoutParams(am map[string]interface{}, ipan IPanel) error {
  1021. // Get layout params attributes
  1022. lpi := am[AttribLayoutParams]
  1023. if lpi == nil {
  1024. return nil
  1025. }
  1026. lp := lpi.(map[string]interface{})
  1027. // Get layout type from parent
  1028. pi := am[AttribParent_]
  1029. if pi == nil {
  1030. return b.err(am, AttribType, "Panel has no parent")
  1031. }
  1032. par := pi.(map[string]interface{})
  1033. v := par[AttribLayout]
  1034. if v == nil {
  1035. return nil
  1036. }
  1037. playout := v.(map[string]interface{})
  1038. pltype := playout[AttribType].(string)
  1039. // Get layout builder and builds layout params
  1040. lbuilder := b.layouts[pltype]
  1041. params, err := lbuilder.BuildParams(b, lp)
  1042. if err != nil {
  1043. return err
  1044. }
  1045. ipan.GetPanel().SetLayoutParams(params)
  1046. return nil
  1047. }
  1048. func AttribCheckEdge(b *Builder, am map[string]interface{}, fname string) error {
  1049. v := am[fname]
  1050. if v == nil {
  1051. return nil
  1052. }
  1053. vs, ok := v.(string)
  1054. if !ok {
  1055. return b.err(am, fname, "Invalid edge name")
  1056. }
  1057. edge, ok := mapEdgeName[vs]
  1058. if !ok {
  1059. return b.err(am, fname, "Invalid edge name")
  1060. }
  1061. am[fname] = edge
  1062. return nil
  1063. }
  1064. func AttribCheckLayout(b *Builder, am map[string]interface{}, fname string) error {
  1065. v := am[fname]
  1066. if v == nil {
  1067. return nil
  1068. }
  1069. msi, ok := v.(map[string]interface{})
  1070. if !ok {
  1071. return b.err(am, fname, "Not a map")
  1072. }
  1073. lti := msi[AttribType]
  1074. if lti == nil {
  1075. return b.err(am, fname, "Layout must have a type")
  1076. }
  1077. lfunc := b.layouts[lti.(string)]
  1078. if lfunc == nil {
  1079. return b.err(am, fname, "Invalid layout type")
  1080. }
  1081. return nil
  1082. }
  1083. func AttribCheckAlign(b *Builder, am map[string]interface{}, fname string) error {
  1084. v := am[fname]
  1085. if v == nil {
  1086. return nil
  1087. }
  1088. vs, ok := v.(string)
  1089. if !ok {
  1090. return b.err(am, fname, "Invalid alignment")
  1091. }
  1092. var align Align
  1093. if fname == AttribAlignh {
  1094. align, ok = mapAlignh[vs]
  1095. } else {
  1096. align, ok = mapAlignv[vs]
  1097. }
  1098. if !ok {
  1099. return b.err(am, fname, "Invalid alignment")
  1100. }
  1101. am[fname] = align
  1102. return nil
  1103. }
  1104. func AttribCheckMenuShortcut(b *Builder, am map[string]interface{}, fname string) error {
  1105. v := am[fname]
  1106. if v == nil {
  1107. return nil
  1108. }
  1109. vs, ok := v.(string)
  1110. if !ok {
  1111. return b.err(am, fname, "Not a string")
  1112. }
  1113. sc := strings.Trim(vs, " ")
  1114. if sc == "" {
  1115. return nil
  1116. }
  1117. parts := strings.Split(sc, "+")
  1118. var mods window.ModifierKey
  1119. for i := 0; i < len(parts)-1; i++ {
  1120. switch parts[i] {
  1121. case "Shift":
  1122. mods |= window.ModShift
  1123. case "Ctrl":
  1124. mods |= window.ModControl
  1125. case "Alt":
  1126. mods |= window.ModAlt
  1127. default:
  1128. return b.err(am, fname, "Invalid shortcut:"+sc)
  1129. }
  1130. }
  1131. // The last part must be a key
  1132. keyname := parts[len(parts)-1]
  1133. var keycode int
  1134. found := false
  1135. for kcode, kname := range mapKeyText {
  1136. if kname == keyname {
  1137. keycode = int(kcode)
  1138. found = true
  1139. break
  1140. }
  1141. }
  1142. if !found {
  1143. return b.err(am, fname, "Invalid shortcut:"+sc)
  1144. }
  1145. am[fname] = []int{int(mods), keycode}
  1146. return nil
  1147. }
  1148. func AttribCheckListMap(b *Builder, am map[string]interface{}, fname string) error {
  1149. v := am[fname]
  1150. if v == nil {
  1151. return nil
  1152. }
  1153. li, ok := v.([]interface{})
  1154. if !ok {
  1155. return b.err(am, fname, "Not a list")
  1156. }
  1157. lmsi := make([]map[string]interface{}, 0)
  1158. for i := 0; i < len(li); i++ {
  1159. item := li[i]
  1160. msi, ok := item.(map[string]interface{})
  1161. if !ok {
  1162. return b.err(am, fname, "Item is not a map")
  1163. }
  1164. lmsi = append(lmsi, msi)
  1165. }
  1166. am[fname] = lmsi
  1167. return nil
  1168. }
  1169. func AttribCheckMap(b *Builder, am map[string]interface{}, fname string) error {
  1170. v := am[fname]
  1171. if v == nil {
  1172. return nil
  1173. }
  1174. msi, ok := v.(map[string]interface{})
  1175. if !ok {
  1176. return b.err(am, fname, "Not a map")
  1177. }
  1178. am[fname] = msi
  1179. return nil
  1180. }
  1181. func AttribCheckIcons(b *Builder, am map[string]interface{}, fname string) error {
  1182. v := am[fname]
  1183. if v == nil {
  1184. return nil
  1185. }
  1186. fs, ok := v.(string)
  1187. if !ok {
  1188. return b.err(am, fname, "Not a string")
  1189. }
  1190. text := ""
  1191. parts := strings.Fields(fs)
  1192. for i := 0; i < len(parts); i++ {
  1193. // Try name first
  1194. cp := icon.Codepoint(parts[i])
  1195. if cp != "" {
  1196. text += string(cp)
  1197. continue
  1198. }
  1199. // Try to parse as hex value
  1200. val, err := strconv.ParseUint(parts[i], 16, 32)
  1201. if err != nil {
  1202. return b.err(am, fname, fmt.Sprintf("Invalid icon codepoint value/name:%v", parts[i]))
  1203. }
  1204. text += string(val)
  1205. }
  1206. am[fname] = text
  1207. return nil
  1208. }
  1209. func AttribCheckColor(b *Builder, am map[string]interface{}, fname string) error {
  1210. // Checks if field is nil
  1211. v := am[fname]
  1212. if v == nil {
  1213. return nil
  1214. }
  1215. // Converts to string
  1216. fs, ok := v.(string)
  1217. if !ok {
  1218. return b.err(am, fname, "Not a string")
  1219. }
  1220. // Checks if string field is empty
  1221. fs = strings.Trim(fs, " ")
  1222. if fs == "" {
  1223. return nil
  1224. }
  1225. // If string has 1 or 2 fields it must be a color name and optional alpha
  1226. parts := strings.Fields(fs)
  1227. if len(parts) == 1 || len(parts) == 2 {
  1228. // First part must be a color name
  1229. c, ok := math32.IsColorName(parts[0])
  1230. if !ok {
  1231. return b.err(am, fname, fmt.Sprintf("Invalid color name:%s", parts[0]))
  1232. }
  1233. c4 := math32.Color4{c.R, c.G, c.B, 1}
  1234. if len(parts) == 2 {
  1235. val, err := strconv.ParseFloat(parts[1], 32)
  1236. if err != nil {
  1237. return b.err(am, fname, fmt.Sprintf("Invalid float32 value:%s", parts[1]))
  1238. }
  1239. c4.A = float32(val)
  1240. }
  1241. am[fname] = &c4
  1242. return nil
  1243. }
  1244. // Accept 3 or 4 floats values
  1245. va, err := b.parseFloats(am, fname, 3, 4)
  1246. if err != nil {
  1247. return err
  1248. }
  1249. if len(va) == 3 {
  1250. am[fname] = &math32.Color4{va[0], va[1], va[2], 1}
  1251. return nil
  1252. }
  1253. am[fname] = &math32.Color4{va[0], va[1], va[2], va[3]}
  1254. return nil
  1255. }
  1256. func AttribCheckBorderSizes(b *Builder, am map[string]interface{}, fname string) error {
  1257. va, err := b.parseFloats(am, fname, 1, 4)
  1258. if err != nil {
  1259. return err
  1260. }
  1261. if va == nil {
  1262. return nil
  1263. }
  1264. if len(va) == 1 {
  1265. am[fname] = &BorderSizes{va[0], va[0], va[0], va[0]}
  1266. return nil
  1267. }
  1268. am[fname] = &BorderSizes{va[0], va[1], va[2], va[3]}
  1269. return nil
  1270. }
  1271. func AttribCheckPosition(b *Builder, am map[string]interface{}, fname string) error {
  1272. v := am[fname]
  1273. if v == nil {
  1274. return nil
  1275. }
  1276. af, err := b.parseFloats(am, fname, 2, 2)
  1277. if err != nil {
  1278. return err
  1279. }
  1280. am[fname] = af
  1281. return nil
  1282. }
  1283. func AttribCheckStringLower(b *Builder, am map[string]interface{}, fname string) error {
  1284. err := AttribCheckString(b, am, fname)
  1285. if err != nil {
  1286. return err
  1287. }
  1288. if v := am[fname]; v != nil {
  1289. am[fname] = strings.ToLower(v.(string))
  1290. }
  1291. return nil
  1292. }
  1293. func AttribCheckFloat(b *Builder, am map[string]interface{}, fname string) error {
  1294. v := am[fname]
  1295. if v == nil {
  1296. return nil
  1297. }
  1298. switch n := v.(type) {
  1299. case int:
  1300. am[fname] = float32(n)
  1301. return nil
  1302. case float64:
  1303. am[fname] = float32(n)
  1304. return nil
  1305. default:
  1306. return b.err(am, fname, fmt.Sprintf("Not a number:%T", v))
  1307. }
  1308. return nil
  1309. }
  1310. func AttribCheckInt(b *Builder, am map[string]interface{}, fname string) error {
  1311. v := am[fname]
  1312. if v == nil {
  1313. return nil
  1314. }
  1315. vint, ok := v.(int)
  1316. if !ok {
  1317. return b.err(am, fname, "Not an integer")
  1318. }
  1319. am[fname] = vint
  1320. return nil
  1321. }
  1322. func AttribCheckString(b *Builder, am map[string]interface{}, fname string) error {
  1323. v := am[fname]
  1324. if v == nil {
  1325. return nil
  1326. }
  1327. s, ok := v.(string)
  1328. if !ok {
  1329. return b.err(am, fname, "Not a string")
  1330. }
  1331. am[fname] = s
  1332. return nil
  1333. }
  1334. func AttribCheckBool(b *Builder, am map[string]interface{}, fname string) error {
  1335. v := am[fname]
  1336. if v == nil {
  1337. return nil
  1338. }
  1339. bv, ok := v.(bool)
  1340. if !ok {
  1341. return b.err(am, fname, "Not a bool")
  1342. }
  1343. am[fname] = bv
  1344. return nil
  1345. }
  1346. /***
  1347. // buildImageLabel builds a gui object of type: ImageLabel
  1348. func (b *Builder) buildImageLabel(pd *descPanel) (IPanel, error) {
  1349. // Builds image label and set common attributes
  1350. imglabel := NewImageLabel(pd.Text)
  1351. err := b.setAttribs(pd, imglabel, asPANEL)
  1352. if err != nil {
  1353. return nil, err
  1354. }
  1355. // Sets optional icon(s)
  1356. icons, err := b.parseIconNames("icons", pd.Icons)
  1357. if err != nil {
  1358. return nil, err
  1359. }
  1360. if icons != "" {
  1361. imglabel.SetIcon(icons)
  1362. }
  1363. // Sets optional image from file
  1364. // If path is not absolute join with user supplied image base path
  1365. if pd.Imagefile != "" {
  1366. path := pd.Imagefile
  1367. if !filepath.IsAbs(path) {
  1368. path = filepath.Join(b.imgpath, path)
  1369. }
  1370. err := imglabel.SetImageFromFile(path)
  1371. if err != nil {
  1372. return nil, err
  1373. }
  1374. }
  1375. return imglabel, nil
  1376. }
  1377. // buildButton builds a gui object of type: Button
  1378. func (b *Builder) buildButton(pd *descPanel) (IPanel, error) {
  1379. // Builds button and set commont attributes
  1380. button := NewButton(pd.Text)
  1381. err := b.setAttribs(pd, button, asBUTTON)
  1382. if err != nil {
  1383. return nil, err
  1384. }
  1385. // Sets optional icon
  1386. if pd.Icon != "" {
  1387. cp, err := b.parseIconName("icon", pd.Icon)
  1388. if err != nil {
  1389. return nil, err
  1390. }
  1391. button.SetIcon(cp)
  1392. }
  1393. // Sets optional image from file
  1394. // If path is not absolute join with user supplied image base path
  1395. if pd.Imagefile != "" {
  1396. path := pd.Imagefile
  1397. if !filepath.IsAbs(path) {
  1398. path = filepath.Join(b.imgpath, path)
  1399. }
  1400. err := button.SetImage(path)
  1401. if err != nil {
  1402. return nil, err
  1403. }
  1404. }
  1405. return button, nil
  1406. }
  1407. // buildCheckBox builds a gui object of type: CheckBox
  1408. func (b *Builder) buildCheckBox(pd *descPanel) (IPanel, error) {
  1409. // Builds check box and set commont attributes
  1410. cb := NewCheckBox(pd.Text)
  1411. err := b.setAttribs(pd, cb, asWIDGET)
  1412. if err != nil {
  1413. return nil, err
  1414. }
  1415. cb.SetValue(pd.Checked)
  1416. return cb, nil
  1417. }
  1418. // buildRadioButton builds a gui object of type: RadioButton
  1419. func (b *Builder) buildRadioButton(pd *descPanel) (IPanel, error) {
  1420. // Builds check box and set commont attributes
  1421. rb := NewRadioButton(pd.Text)
  1422. err := b.setAttribs(pd, rb, asWIDGET)
  1423. if err != nil {
  1424. return nil, err
  1425. }
  1426. // Sets optional radio button group
  1427. if pd.Group != "" {
  1428. rb.SetGroup(pd.Group)
  1429. }
  1430. rb.SetValue(pd.Checked)
  1431. return rb, nil
  1432. }
  1433. // buildEdit builds a gui object of type: "Edit"
  1434. func (b *Builder) buildEdit(dp *descPanel) (IPanel, error) {
  1435. // Builds button and set attributes
  1436. width, _ := b.size(dp)
  1437. edit := NewEdit(int(width), dp.PlaceHolder)
  1438. err := b.setAttribs(dp, edit, asWIDGET)
  1439. if err != nil {
  1440. return nil, err
  1441. }
  1442. edit.SetText(dp.Text)
  1443. return edit, nil
  1444. }
  1445. // buildVList builds a gui object of type: VList
  1446. func (b *Builder) buildVList(dp *descPanel) (IPanel, error) {
  1447. // Builds list and set commont attributes
  1448. width, height := b.size(dp)
  1449. list := NewVList(width, height)
  1450. err := b.setAttribs(dp, list, asWIDGET)
  1451. if err != nil {
  1452. return nil, err
  1453. }
  1454. // Builds list children
  1455. for i := 0; i < len(dp.Items); i++ {
  1456. item := dp.Items[i]
  1457. b.objpath.push(item.Name)
  1458. child, err := b.build(item, list)
  1459. b.objpath.pop()
  1460. if err != nil {
  1461. return nil, err
  1462. }
  1463. list.Add(child)
  1464. }
  1465. return list, nil
  1466. }
  1467. // buildHList builds a gui object of type: VList
  1468. func (b *Builder) buildHList(dp *descPanel) (IPanel, error) {
  1469. // Builds list and set commont attributes
  1470. width, height := b.size(dp)
  1471. list := NewHList(width, height)
  1472. err := b.setAttribs(dp, list, asWIDGET)
  1473. if err != nil {
  1474. return nil, err
  1475. }
  1476. // Builds list children
  1477. for i := 0; i < len(dp.Items); i++ {
  1478. item := dp.Items[i]
  1479. b.objpath.push(item.Name)
  1480. child, err := b.build(item, list)
  1481. b.objpath.pop()
  1482. if err != nil {
  1483. return nil, err
  1484. }
  1485. list.Add(child)
  1486. }
  1487. return list, nil
  1488. }
  1489. // buildDropDown builds a gui object of type: DropDown
  1490. func (b *Builder) buildDropDown(pd *descPanel) (IPanel, error) {
  1491. // If image label attribute defined use it, otherwise
  1492. // uses default value.
  1493. var imglabel *ImageLabel
  1494. if pd.ImageLabel != nil {
  1495. pd.ImageLabel.Type = descTypeImageLabel
  1496. ipan, err := b.build(pd.ImageLabel, nil)
  1497. if err != nil {
  1498. return nil, err
  1499. }
  1500. imglabel = ipan.(*ImageLabel)
  1501. } else {
  1502. imglabel = NewImageLabel("")
  1503. }
  1504. // Builds drop down and set common attributes
  1505. width, _ := b.size(pd)
  1506. dd := NewDropDown(width, imglabel)
  1507. err := b.setAttribs(pd, dd, asWIDGET)
  1508. if err != nil {
  1509. return nil, err
  1510. }
  1511. // Builds drop down children
  1512. for i := 0; i < len(pd.Items); i++ {
  1513. item := pd.Items[i]
  1514. item.Type = descTypeImageLabel
  1515. b.objpath.push(item.Name)
  1516. child, err := b.build(item, dd)
  1517. b.objpath.pop()
  1518. if err != nil {
  1519. return nil, err
  1520. }
  1521. dd.Add(child.(*ImageLabel))
  1522. }
  1523. return dd, nil
  1524. }
  1525. // buildSlider builds a gui object of type: HSlider or VSlider
  1526. func (b *Builder) buildSlider(pd *descPanel, horiz bool) (IPanel, error) {
  1527. // Builds slider and sets its position
  1528. width, height := b.size(pd)
  1529. var slider *Slider
  1530. if horiz {
  1531. slider = NewHSlider(width, height)
  1532. } else {
  1533. slider = NewVSlider(width, height)
  1534. }
  1535. err := b.setAttribs(pd, slider, asWIDGET)
  1536. if err != nil {
  1537. return nil, err
  1538. }
  1539. // Sets optional text
  1540. if pd.Text != "" {
  1541. slider.SetText(pd.Text)
  1542. }
  1543. // Sets optional scale factor
  1544. if pd.ScaleFactor != nil {
  1545. slider.SetScaleFactor(*pd.ScaleFactor)
  1546. }
  1547. // Sets optional value
  1548. if pd.Value != nil {
  1549. slider.SetValue(*pd.Value)
  1550. }
  1551. return slider, nil
  1552. }
  1553. // buildSplitter builds a gui object of type: HSplitterr or VSplitter
  1554. func (b *Builder) buildSplitter(pd *descPanel, horiz bool) (IPanel, error) {
  1555. // Builds splitter and sets its common attributes
  1556. width, height := b.size(pd)
  1557. var splitter *Splitter
  1558. if horiz {
  1559. splitter = NewHSplitter(width, height)
  1560. } else {
  1561. splitter = NewVSplitter(width, height)
  1562. }
  1563. err := b.setAttribs(pd, splitter, asWIDGET)
  1564. if err != nil {
  1565. return nil, err
  1566. }
  1567. // Optional split value
  1568. if pd.Split != nil {
  1569. splitter.SetSplit(*pd.Split)
  1570. }
  1571. // Splitter panel 0 attributes and items
  1572. if pd.P0 != nil {
  1573. err := b.setAttribs(pd.P0, &splitter.P0, asPANEL)
  1574. if err != nil {
  1575. return nil, err
  1576. }
  1577. err = b.addPanelItems(pd.P0, &splitter.P0)
  1578. if err != nil {
  1579. return nil, err
  1580. }
  1581. }
  1582. // Splitter panel 1 attributes and items
  1583. if pd.P1 != nil {
  1584. err := b.setAttribs(pd.P1, &splitter.P1, asPANEL)
  1585. if err != nil {
  1586. return nil, err
  1587. }
  1588. err = b.addPanelItems(pd.P1, &splitter.P1)
  1589. if err != nil {
  1590. return nil, err
  1591. }
  1592. }
  1593. return splitter, nil
  1594. }
  1595. // buildTree builds a gui object of type: Tree
  1596. func (b *Builder) buildTree(dp *descPanel) (IPanel, error) {
  1597. // Builds tree and sets its common attributes
  1598. width, height := b.size(dp)
  1599. tree := NewTree(width, height)
  1600. err := b.setAttribs(dp, tree, asWIDGET)
  1601. if err != nil {
  1602. return nil, err
  1603. }
  1604. // Internal function to build tree nodes recursively
  1605. var buildItems func(dp *descPanel, pnode *TreeNode) error
  1606. buildItems = func(dp *descPanel, pnode *TreeNode) error {
  1607. for i := 0; i < len(dp.Items); i++ {
  1608. item := dp.Items[i]
  1609. // Item is a tree node
  1610. if item.Type == "" || item.Type == descTypeTreeNode {
  1611. var node *TreeNode
  1612. if pnode == nil {
  1613. node = tree.AddNode(item.Text)
  1614. } else {
  1615. node = pnode.AddNode(item.Text)
  1616. }
  1617. err := buildItems(item, node)
  1618. if err != nil {
  1619. return err
  1620. }
  1621. continue
  1622. }
  1623. // Other controls
  1624. ipan, err := b.build(item, nil)
  1625. if err != nil {
  1626. return err
  1627. }
  1628. if pnode == nil {
  1629. tree.Add(ipan)
  1630. } else {
  1631. pnode.Add(ipan)
  1632. }
  1633. }
  1634. return nil
  1635. }
  1636. // Build nodes
  1637. err = buildItems(dp, nil)
  1638. if err != nil {
  1639. return nil, err
  1640. }
  1641. return tree, nil
  1642. }
  1643. // buildMenu builds a gui object of type: Menu or MenuBar from the
  1644. // specified panel descriptor.
  1645. func (b *Builder) buildMenu(pd *descPanel, child, bar bool) (IPanel, error) {
  1646. // Builds menu bar or menu
  1647. var menu *Menu
  1648. if bar {
  1649. menu = NewMenuBar()
  1650. } else {
  1651. menu = NewMenu()
  1652. }
  1653. // Only sets attribs for top level menus
  1654. if !child {
  1655. err := b.setAttribs(pd, menu, asWIDGET)
  1656. if err != nil {
  1657. return nil, err
  1658. }
  1659. }
  1660. // Builds and adds menu items
  1661. for i := 0; i < len(pd.Items); i++ {
  1662. item := pd.Items[i]
  1663. // Item is another menu
  1664. if item.Type == descTypeMenu {
  1665. subm, err := b.buildMenu(item, true, false)
  1666. if err != nil {
  1667. return nil, err
  1668. }
  1669. menu.AddMenu(item.Text, subm.(*Menu))
  1670. continue
  1671. }
  1672. // Item is a separator
  1673. if item.Type == "Separator" {
  1674. menu.AddSeparator()
  1675. continue
  1676. }
  1677. // Item must be a menu option
  1678. mi := menu.AddOption(item.Text)
  1679. // Set item optional icon(s)
  1680. icons, err := b.parseIconNames("icon", item.Icon)
  1681. if err != nil {
  1682. return nil, err
  1683. }
  1684. if icons != "" {
  1685. mi.SetIcon(string(icons))
  1686. }
  1687. // Sets optional menu item shortcut
  1688. err = b.setMenuShortcut(mi, "shortcut", item.Shortcut)
  1689. if err != nil {
  1690. return nil, err
  1691. }
  1692. }
  1693. return menu, nil
  1694. }
  1695. // buildWindow builds a gui object of type: Window from the
  1696. // specified panel descriptor.
  1697. func (b *Builder) buildWindow(dp *descPanel) (IPanel, error) {
  1698. // Builds window and sets its common attributes
  1699. width, height := b.size(dp)
  1700. win := NewWindow(width, height)
  1701. err := b.setAttribs(dp, win, asWIDGET)
  1702. if err != nil {
  1703. return nil, err
  1704. }
  1705. // Title attribute
  1706. win.SetTitle(dp.Title)
  1707. // Parse resizable borders
  1708. if dp.Resizable != "" {
  1709. parts := strings.Fields(dp.Resizable)
  1710. var res Resizable
  1711. for _, name := range parts {
  1712. v, ok := mapResizable[name]
  1713. if !ok {
  1714. return nil, b.err("resizable", "Invalid resizable name:"+name)
  1715. }
  1716. res |= v
  1717. }
  1718. win.SetResizable(res)
  1719. }
  1720. // Builds window client panel children recursively
  1721. for i := 0; i < len(dp.Items); i++ {
  1722. item := dp.Items[i]
  1723. b.objpath.push(item.Name)
  1724. child, err := b.build(item, win)
  1725. b.objpath.pop()
  1726. if err != nil {
  1727. return nil, err
  1728. }
  1729. win.Add(child)
  1730. }
  1731. return win, nil
  1732. }
  1733. // addPanelItems adds the items in the panel descriptor to the specified panel
  1734. func (b *Builder) addPanelItems(dp *descPanel, ipan IPanel) error {
  1735. pan := ipan.GetPanel()
  1736. for i := 0; i < len(dp.Items); i++ {
  1737. item := dp.Items[i]
  1738. b.objpath.push(item.Name)
  1739. child, err := b.build(item, pan)
  1740. b.objpath.pop()
  1741. if err != nil {
  1742. return err
  1743. }
  1744. pan.Add(child)
  1745. }
  1746. return nil
  1747. }
  1748. // setAttribs sets common attributes from the description to the specified panel
  1749. // The attributes which are set can be specified by the specified bitmask.
  1750. func (b *Builder) setAttribs(pd *descPanel, ipan IPanel, attr uint) error {
  1751. panel := ipan.GetPanel()
  1752. // Set optional position
  1753. if attr&aPOS != 0 && pd.Position != "" {
  1754. va, err := b.parseFloats("position", pd.Position, 2, 2)
  1755. if va == nil || err != nil {
  1756. return err
  1757. }
  1758. panel.SetPosition(va[0], va[1])
  1759. }
  1760. // Set optional size
  1761. if attr&aSIZE != 0 {
  1762. if pd.Width != nil {
  1763. panel.SetWidth(*pd.Width)
  1764. }
  1765. if pd.Height != nil {
  1766. panel.SetHeight(*pd.Height)
  1767. }
  1768. }
  1769. // Set optional margin sizes
  1770. if attr&aMARGINS != 0 {
  1771. bs, err := b.parseBorderSizes(fieldMargins, pd.Margins)
  1772. if err != nil {
  1773. return err
  1774. }
  1775. if bs != nil {
  1776. panel.SetMarginsFrom(bs)
  1777. }
  1778. }
  1779. // Set optional border sizes
  1780. if attr&aBORDERS != 0 {
  1781. bs, err := b.parseBorderSizes(fieldBorders, pd.Borders)
  1782. if err != nil {
  1783. return err
  1784. }
  1785. if bs != nil {
  1786. panel.SetBordersFrom(bs)
  1787. }
  1788. }
  1789. // Set optional border color
  1790. if attr&aBORDERCOLOR != 0 {
  1791. c, err := b.parseColor(fieldBorderColor, pd.BorderColor)
  1792. if err != nil {
  1793. return err
  1794. }
  1795. if c != nil {
  1796. panel.SetBordersColor4(c)
  1797. }
  1798. }
  1799. // Set optional paddings sizes
  1800. if attr&aPADDINGS != 0 {
  1801. bs, err := b.parseBorderSizes(fieldPaddings, pd.Paddings)
  1802. if err != nil {
  1803. return err
  1804. }
  1805. if bs != nil {
  1806. panel.SetPaddingsFrom(bs)
  1807. }
  1808. }
  1809. // Set optional color
  1810. if attr&aCOLOR != 0 {
  1811. c, err := b.parseColor(fieldColor, pd.Color)
  1812. if err != nil {
  1813. return err
  1814. }
  1815. if c != nil {
  1816. panel.SetColor4(c)
  1817. }
  1818. }
  1819. if attr&aNAME != 0 && pd.Name != "" {
  1820. panel.SetName(pd.Name)
  1821. }
  1822. if attr&aVISIBLE != 0 && pd.Visible != nil {
  1823. panel.SetVisible(*pd.Visible)
  1824. }
  1825. if attr&aENABLED != 0 && pd.Enabled != nil {
  1826. panel.SetEnabled(*pd.Enabled)
  1827. }
  1828. if attr&aRENDER != 0 && pd.Renderable != nil {
  1829. panel.SetRenderable(*pd.Renderable)
  1830. }
  1831. err := b.setLayoutParams(pd, ipan)
  1832. if err != nil {
  1833. return err
  1834. }
  1835. return b.setLayout(pd, ipan)
  1836. }
  1837. // setLayoutParams sets the optional layout params attribute for specified the panel
  1838. func (b *Builder) setLayoutParams(dp *descPanel, ipan IPanel) error {
  1839. // If layout params not declared, nothing to do
  1840. if dp.LayoutParams == nil {
  1841. return nil
  1842. }
  1843. // Get the parent layout
  1844. if dp.parent == nil {
  1845. return b.err("layoutparams", "No parent defined")
  1846. }
  1847. playout := dp.parent.Layout
  1848. if playout == nil {
  1849. return b.err("layoutparams", "Parent does not have layout")
  1850. }
  1851. panel := ipan.GetPanel()
  1852. dlp := dp.LayoutParams
  1853. // HBoxLayout parameters
  1854. if playout.Type == descTypeHBoxLayout {
  1855. // Creates layout parameter
  1856. params := HBoxLayoutParams{Expand: 0, AlignV: AlignTop}
  1857. // Sets optional expand parameter
  1858. if dlp.Expand != nil {
  1859. params.Expand = *dlp.Expand
  1860. }
  1861. // Sets optional align parameter
  1862. if dlp.AlignV != "" {
  1863. align, ok := mapAlignName[dlp.AlignV]
  1864. if !ok {
  1865. return b.err("align", "Invalid align name:"+dlp.AlignV)
  1866. }
  1867. params.AlignV = align
  1868. }
  1869. panel.SetLayoutParams(&params)
  1870. return nil
  1871. }
  1872. // VBoxLayout parameters
  1873. if playout.Type == descTypeVBoxLayout {
  1874. // Creates layout parameter
  1875. params := VBoxLayoutParams{Expand: 0, AlignH: AlignLeft}
  1876. // Sets optional expand parameter
  1877. if dlp.Expand != nil {
  1878. params.Expand = *dlp.Expand
  1879. }
  1880. // Sets optional align parameter
  1881. if dlp.AlignH != "" {
  1882. align, ok := mapAlignName[dlp.AlignH]
  1883. if !ok {
  1884. return b.err("align", "Invalid align name:"+dlp.AlignH)
  1885. }
  1886. params.AlignH = align
  1887. }
  1888. panel.SetLayoutParams(&params)
  1889. return nil
  1890. }
  1891. // GridLayout parameters
  1892. if playout.Type == descTypeGridLayout {
  1893. // Creates layout parameter
  1894. params := GridLayoutParams{
  1895. ColSpan: 0,
  1896. AlignH: AlignNone,
  1897. AlignV: AlignNone,
  1898. }
  1899. params.ColSpan = dlp.ColSpan
  1900. // Sets optional alignh parameter
  1901. if dlp.AlignH != "" {
  1902. align, ok := mapAlignName[dlp.AlignH]
  1903. if !ok {
  1904. return b.err("alignh", "Invalid align name:"+dlp.AlignH)
  1905. }
  1906. params.AlignH = align
  1907. }
  1908. // Sets optional alignv parameter
  1909. if dlp.AlignV != "" {
  1910. align, ok := mapAlignName[dlp.AlignV]
  1911. if !ok {
  1912. return b.err("alignv", "Invalid align name:"+dlp.AlignV)
  1913. }
  1914. params.AlignV = align
  1915. }
  1916. panel.SetLayoutParams(&params)
  1917. return nil
  1918. }
  1919. // DockLayout parameters
  1920. if playout.Type == descTypeDockLayout {
  1921. if dlp.Edge != "" {
  1922. edge, ok := mapEdgeName[dlp.Edge]
  1923. if !ok {
  1924. return b.err("edge", "Invalid edge name:"+dlp.Edge)
  1925. }
  1926. params := DockLayoutParams{Edge: edge}
  1927. panel.SetLayoutParams(&params)
  1928. return nil
  1929. }
  1930. }
  1931. return b.err("layoutparams", "Invalid parent layout:"+playout.Type)
  1932. }
  1933. // setLayout sets the optional panel layout and layout parameters
  1934. func (b *Builder) setLayout(dp *descPanel, ipan IPanel) error {
  1935. // If layout types not declared, nothing to do
  1936. if dp.Layout == nil {
  1937. return nil
  1938. }
  1939. dl := dp.Layout
  1940. // HBox layout
  1941. if dl.Type == descTypeHBoxLayout {
  1942. hbl := NewHBoxLayout()
  1943. hbl.SetSpacing(dl.Spacing)
  1944. if dl.AlignH != "" {
  1945. align, ok := mapAlignName[dl.AlignH]
  1946. if !ok {
  1947. return b.err("align", "Invalid align name:"+dl.AlignV)
  1948. }
  1949. hbl.SetAlignH(align)
  1950. }
  1951. hbl.SetMinHeight(dl.MinHeight)
  1952. hbl.SetMinWidth(dl.MinWidth)
  1953. ipan.SetLayout(hbl)
  1954. return nil
  1955. }
  1956. // VBox layout
  1957. if dl.Type == descTypeVBoxLayout {
  1958. vbl := NewVBoxLayout()
  1959. vbl.SetSpacing(dl.Spacing)
  1960. if dl.AlignV != "" {
  1961. align, ok := mapAlignName[dl.AlignV]
  1962. if !ok {
  1963. return b.err("align", "Invalid align name:"+dl.AlignV)
  1964. }
  1965. vbl.SetAlignV(align)
  1966. }
  1967. vbl.SetMinHeight(dl.MinHeight)
  1968. vbl.SetMinWidth(dl.MinWidth)
  1969. ipan.SetLayout(vbl)
  1970. return nil
  1971. }
  1972. // Grid layout
  1973. if dl.Type == descTypeGridLayout {
  1974. // Number of columns
  1975. if dl.Cols == 0 {
  1976. return b.err("cols", "Invalid number of columns:"+dl.AlignH)
  1977. }
  1978. grl := NewGridLayout(dl.Cols)
  1979. // Global horizontal alignment
  1980. if dl.AlignH != "" {
  1981. alignh, ok := mapAlignName[dl.AlignH]
  1982. if !ok {
  1983. return b.err("alignh", "Invalid horizontal align:"+dl.AlignH)
  1984. }
  1985. grl.SetAlignH(alignh)
  1986. }
  1987. // Global vertical alignment
  1988. if dl.AlignV != "" {
  1989. alignv, ok := mapAlignName[dl.AlignV]
  1990. if !ok {
  1991. return b.err("alignv", "Invalid vertical align:"+dl.AlignH)
  1992. }
  1993. grl.SetAlignV(alignv)
  1994. }
  1995. // Expansion flags
  1996. grl.SetExpandH(dl.ExpandH)
  1997. grl.SetExpandV(dl.ExpandV)
  1998. ipan.SetLayout(grl)
  1999. return nil
  2000. }
  2001. // Dock layout
  2002. if dl.Type == descTypeDockLayout {
  2003. dockl := NewDockLayout()
  2004. ipan.SetLayout(dockl)
  2005. return nil
  2006. }
  2007. return b.err("layout", "Invalid layout type:"+dl.Type)
  2008. }
  2009. ****/
  2010. // setAttribs sets common attributes from the description to the specified panel
  2011. // The attributes which are set can be specified by the specified bitmask.
  2012. func (b *Builder) setAttribs(am map[string]interface{}, ipan IPanel, attr uint) error {
  2013. panel := ipan.GetPanel()
  2014. // Set optional position
  2015. if attr&aPOS != 0 && am[AttribPosition] != nil {
  2016. va := am[AttribPosition].([]float32)
  2017. panel.SetPosition(va[0], va[1])
  2018. }
  2019. // Set optional panel width
  2020. if attr&aSIZE != 0 && am[AttribWidth] != nil {
  2021. panel.SetWidth(am[AttribWidth].(float32))
  2022. log.Error("set width:%v", am[AttribWidth])
  2023. }
  2024. // Sets optional panel height
  2025. if attr&aSIZE != 0 && am[AttribHeight] != nil {
  2026. panel.SetHeight(am[AttribHeight].(float32))
  2027. }
  2028. // Set optional margin sizes
  2029. if attr&aMARGINS != 0 && am[AttribMargins] != nil {
  2030. panel.SetMarginsFrom(am[AttribMargins].(*BorderSizes))
  2031. }
  2032. // Set optional border sizes
  2033. if attr&aBORDERS != 0 && am[AttribBorders] != nil {
  2034. panel.SetBordersFrom(am[AttribBorders].(*BorderSizes))
  2035. }
  2036. // Set optional border color
  2037. if attr&aBORDERCOLOR != 0 && am[AttribBorderColor] != nil {
  2038. panel.SetBordersColor4(am[AttribBorderColor].(*math32.Color4))
  2039. }
  2040. // Set optional paddings sizes
  2041. if attr&aPADDINGS != 0 && am[AttribPaddings] != nil {
  2042. panel.SetPaddingsFrom(am[AttribPaddings].(*BorderSizes))
  2043. }
  2044. // Set optional panel color
  2045. if attr&aCOLOR != 0 && am[AttribColor] != nil {
  2046. panel.SetColor4(am[AttribColor].(*math32.Color4))
  2047. }
  2048. if attr&aNAME != 0 && am[AttribName] != nil {
  2049. panel.SetName(am[AttribName].(string))
  2050. }
  2051. if attr&aVISIBLE != 0 && am[AttribVisible] != nil {
  2052. panel.SetVisible(am[AttribVisible].(bool))
  2053. }
  2054. if attr&aENABLED != 0 && am[AttribEnabled] != nil {
  2055. panel.SetEnabled(am[AttribEnabled].(bool))
  2056. }
  2057. if attr&aRENDER != 0 && am[AttribRender] != nil {
  2058. panel.SetRenderable(am[AttribRender].(bool))
  2059. }
  2060. // Sets optional layout
  2061. err := b.setLayout(am, panel)
  2062. if err != nil {
  2063. return nil
  2064. }
  2065. // Sets optional layout params
  2066. err = b.setLayoutParams(am, panel)
  2067. return err
  2068. }
  2069. //func (b *Builder) setMenuShortcut(mi *MenuItem, fname, field string) error {
  2070. //
  2071. // field = strings.Trim(field, " ")
  2072. // if field == "" {
  2073. // return nil
  2074. // }
  2075. // parts := strings.Split(field, "+")
  2076. // var mods window.ModifierKey
  2077. // for i := 0; i < len(parts)-1; i++ {
  2078. // switch parts[i] {
  2079. // case "Shift":
  2080. // mods |= window.ModShift
  2081. // case "Ctrl":
  2082. // mods |= window.ModControl
  2083. // case "Alt":
  2084. // mods |= window.ModAlt
  2085. // default:
  2086. // return b.err(am, fname, "Invalid shortcut:"+field)
  2087. // }
  2088. // }
  2089. // // The last part must be a key
  2090. // key := parts[len(parts)-1]
  2091. // for kcode, kname := range mapKeyText {
  2092. // if kname == key {
  2093. // mi.SetShortcut(mods, kcode)
  2094. // return nil
  2095. // }
  2096. // }
  2097. // return b.err(fname, "Invalid shortcut:"+field)
  2098. //}
  2099. // parseFloats parses a string with a list of floats with the specified size
  2100. // and returns a slice. The specified size is 0 any number of floats is allowed.
  2101. // The individual values can be separated by spaces or commas
  2102. func (b *Builder) parseFloats(am map[string]interface{}, fname string, min, max int) ([]float32, error) {
  2103. // Checks if field is empty
  2104. v := am[fname]
  2105. if v == nil {
  2106. return nil, nil
  2107. }
  2108. // If field has only one value, it is an int or a float64
  2109. switch ft := v.(type) {
  2110. case int:
  2111. return []float32{float32(ft)}, nil
  2112. case float64:
  2113. return []float32{float32(ft)}, nil
  2114. }
  2115. // Converts to string
  2116. fs, ok := v.(string)
  2117. if !ok {
  2118. return nil, b.err(am, fname, "Not a string")
  2119. }
  2120. // Checks if string field is empty
  2121. fs = strings.Trim(fs, " ")
  2122. if fs == "" {
  2123. return nil, nil
  2124. }
  2125. // Separate individual fields
  2126. var parts []string
  2127. if strings.Index(fs, ",") < 0 {
  2128. parts = strings.Fields(fs)
  2129. } else {
  2130. parts = strings.Split(fs, ",")
  2131. }
  2132. if len(parts) < min || len(parts) > max {
  2133. return nil, b.err(am, fname, "Invalid number of float32 values")
  2134. }
  2135. // Parse each field value and appends to slice
  2136. var values []float32
  2137. for i := 0; i < len(parts); i++ {
  2138. val, err := strconv.ParseFloat(strings.Trim(parts[i], " "), 32)
  2139. if err != nil {
  2140. return nil, b.err(am, fname, err.Error())
  2141. }
  2142. values = append(values, float32(val))
  2143. }
  2144. return values, nil
  2145. }
  2146. // err creates and returns an error for the current object, field name and with the specified message
  2147. func (b *Builder) err(am map[string]interface{}, fname, msg string) error {
  2148. return fmt.Errorf("Error in object:%s field:%s -> %s", am[AttribName], fname, msg)
  2149. }
  2150. // debugPrint prints the internal attribute map of the builder for debugging.
  2151. // This map cannot be printed by fmt.Printf() because it has cycles.
  2152. // A map contains a key: _parent, which pointer to is parent map, if any.
  2153. func (b *Builder) debugPrint(v interface{}, level int) {
  2154. switch vt := v.(type) {
  2155. case map[string]interface{}:
  2156. level += 3
  2157. fmt.Printf("\n")
  2158. for mk, mv := range vt {
  2159. if mk == AttribParent_ {
  2160. continue
  2161. }
  2162. fmt.Printf("%s%s:", strings.Repeat(" ", level), mk)
  2163. b.debugPrint(mv, level)
  2164. }
  2165. case []map[string]interface{}:
  2166. for _, v := range vt {
  2167. b.debugPrint(v, level)
  2168. }
  2169. default:
  2170. fmt.Printf(" %v (%T)\n", vt, vt)
  2171. }
  2172. }