builder.go 58 KB

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