Author: LakeFox
Email: [email protected]
Date: Fri, 16 Aug 2024 19:42:12 -0600
docs/cstyle/plugins/flex/index.html
wokring improvement. Don't use
Commits
ae78990ed5b06e02833bd8e578a3af1df49adc00 ae742fdbda42322f4fa1d30761f516bf1ad45a70 1ae1fe418977632fafe3e61c5f02e87f0cad6c87 099527773e9bc03b40b9ce5d8a492ebbcdebcf32 b6acff3a27a7c66e35ab7ea5ffe48f1a69efaf11 07144afe32b8dd752fc4d80efd81529e2df9e4e5 ca735fa2c136dd5f35a5ccf2ffe2133b906c7f94 e2ea9c897ee1e89f89cd5c043632326348191b3a 10f4ce166028ee8ff926170d4d9e17d54e63a4a4 4bd704181610864a1fc4ebe65f20220ea1f1c00b 1c468e139a0f87655e4222b8512c38bec429d067 d8d6cadd2741b05c7a121ccb6753c5a48b8ad1b4 4c0529a8475408ee41d4e4dbd9c969db14594d37 ed8180f077d294d1e2f347f6c30d2977e8670b42 9113424c26a247352fe7b111fff39d1562f6c342 f783d5cacccf047368f8f20fc687bf5ad8f6f66a 66084134570c2a3d87e1336a2ab2ca50341b93b2 031df3b2fd4851345dd6f4c443057141d5b9e65b baf5d8cc1ccf27d14e4e58edcc4c170bba6445df e9c8f7961cf8b188938535b318b50397a76268ba 29572e238d6ba3f401717032bd12a2f409bf1ea9 d6025b04ef9516745adae85a478cbf9f98433597 476d6415583067674f395660961e33b9b40c3e66 906dd99de66ad7df92011a52fb19e0319224741e 4c44132d28d06548d2c90c2f8ca72dd3047fa52d 79e4c754771ba514b29a36e96a7570f266de3c41 36aaa13c4ea4d1235c64febfe9a8fd797037bbb2 6d4b83918686647193953a59c166baf7455b4996 c6a1e4a5102e9a3b5045957c22a0a73ac1a7ca4c db934f090648cdcd96e2f5f12a9bad762c60bfcd 7af8fc3f425ca3814ce1088fbd8a7f82513a1bb2 1c650539c11b715b14ee9013ad7d7faa8f733a7a 717ed8747f4df855c63e13ff95dcab720b8713cd 1c786f0d0efe1a47c285564824c9503881bef393 af527f354d956456e2e71a7f81f1470e74888e69 94ded12a3e3953459ccfbec2f225cecb43b47c73 c0081dc2f877de951fd8b0cd37136568a7ebb586 cbc825d6b458d50debc5913c6b5ed442138d7462 0a3baa3c4708754c79d023ad0addb4cbfb2844c2 a07b34e07b359327e413ccb7ea2dcdf1a91504de 4bf00213a866402775b162fb6f4b7b0bc37a8af7 1b690fa946047f4b897b417d8bc3b02c54cfdb2d 83b05e82a5f28bbe288565ae8a65943ba681cb4a 37d58d4f9de6af12611dada7ba5ae42d51ef05c6 8bbfc0ded0504595111765963d396a4574773e05 81049efedf0b3b521fb2949d8eb03d5ba681b0a5 6dcb369a2fa2bb69f94598fb4224a1349a80db6c c3e4d0cb62570c56ef5bc530f57eeea613f083fc 82d0fbb470daae4091bf30fb57707d66bd193992 166ec9ab6f4a3af0fe522a7dbe166951d2b39b31 992895a8842900d9a0803e7099611d650aba257d 4904b0b2812f9f0f45a59f2efacae89dabe9fe7c 36beac951788f5fb7ab2eeb3381300b07993bfe8 541818a92a5be6442879cd9b3420e1ef27f6e663 43ac3a1bbe6e727869a26ab8697c035eb60577fa d2afd27150a869ff41b8e100e82f20af54146105 0374f24d4685954662fa9db05939a8cbcd492b1c ed04d15b29d4df0329e8a4725c1a371a5cb0a20e 39fc4123096b04a4584b48d6efbb1acd5acacbf9 18315df2eb529bab6c5c79607ecb94626b170ae6 c519a195b90ad689d60d85365252e433b7488eaf d0d2839012c26032488bfe657797b4b590f926c7 8e0cb82ccac15fbc3e08bb53b148563e62437a44 d4413acd4dbad43507018f24e0456a9bc432d156 0dc05886b3ae0c59667f03a245e0728ab094f130 c9a3652d779d9700d9a9d797fd0c58d349a58de1 76425d002c70c3d853c117389a3b407efc53c7c2 fb409ef93b05cd4268e83c7201da73b6b29d482a da1cce88d00f7f7c373df1ce66b18e26e3a2d6e9 fa74cd48bb8959855c9d6b874f874671611611f7 610079be424f3a72ad02aa62e1c89607481750e0 60fda643c807730c3774beaa10a0910a31a4278a 6d2bcdcad816fd2b31c612fe45d3fd5a2fb14f98 b2d960e7d263bee55badbca47dc5d4d4f2d61084 f2ba1e3a96dd571d142c5a37c462743a21148e5f 25cbd33758fdb18f79aa1cf6500d1c1c024ee516 cde2d71846d1f69e5f386d354006465d61a4d19c cf708c22c45491dbdbbdbbb4450b08969f2e33bc 7bda495fbc9ea2c3aa87ac73a5cf4881eecf1482 9499d6967b394b70a22d9be34f47ee1b7a3fc55e 3aa3e67cd8ab769bc2c12b46fc77b11be2b1a0dd abed4927dc46e3e952fd21472f7ae4150ee16044 73953118e02b4c2d8159279624810dddd75e9100 031e4b18d91d825b56ef1e9eda5f1638bcd26629 fa3e1c57efa140ea58f56c6abf1f5f12f9bf2c7d a9b1b82a40fa6c462a9919b2832a89eb6bb47784 a8bf5e2504bdbe257686d48c2bfcaf061abfc95d e2830e4a6650ca8a1c53116a6d86f2975951dbbf 4a48b4c6905999527a7fc8d32e53d8c347c9ac74 9cfdb8c7ddce3a1b34a6590d8872f820601c2c53 128fad8298e89eadafa5feea43ca94f5115b9090 95d4595418fa814d47707441f2dc98d07eac12d6 5e35f7131d999b406eaeafc689374e3426845e6d 3402992fd25a64838e7acecfba3fad645c6c2511 8fcabdf5a34e7d80de988c10426c27adb0622087 1884dd57148595841cfb324f5b812d8640964978 6008cc8c3444f86d729ae5a81ae26919da1bb516 03d40c0d7e8feda38add1d89e3805df74997d915 810685c4aac0a651beaecd0488443a3b293b315d a666abc115c6693b355d5a8ef9cdfc3d77a088ca bcd3619f96c4157ee5b6450bc2bd1f23f27c9d81 9c428f6ab674582e022ea469ef2ac1e3f7ccb933 6e99df4296470d349da01f2e29698dbb34692a0f ed739dfaeb1ca5da10b2c75236faee40bacaf851 006a9351f3320662bff0b96d5d27daa1ba4e52e4 d6b38763cf83ad275aed0450151a97098f48859a 4ea031466d93057705a52caf2dfa21929b215730 a1bead3d96a11f4badedbd5a6eb984473c1cd309 7aa36472009f43cad843b465f67d2927f3428fdf 5f875adcd63ebd9ac9dfaef3ea16e6a6d3735503 4c0cc347e5e52d8ed99e84d42b309c4541d9280c c3de867fbbc27aaefba7aa88f97b5b1406c7c58e 00754639948b6612016ed5c434e97f44e7c65ed6 ffe16b1e768209b1c2021301a142b7fcd9a35a4b 800e568c600187f7228b228874ad20fb57f35166 d36b349e0eea73e99253b64fae3afeb5c4c276ca a7d8eff776e4e28a85e7835ee7ff6d50775748e7 bd0bd280c89d5d742e0ef13673c854436657466f 42da0bb422cdca21c8491af40ca9631206d8e964 e81415f70bedf456983b18692b4ae04355f15283 09c0a9a40ca6d8a8b6eaa6f06ce3f8c2440f7ee1 26eaa5b9c8cc2a84f9de04e17e01f201c122989e 649f49d0618e3c8cb940c4d259a536dfcc66020f 27ec987a8e8a9bc645f6cd38d9f8d5d52e7dbedb eb566ec8284ba205d27699a9bf465e26158b5098 4bdf14d6decad2ef14a77c108227273dd700e9a3 5598cb31dc238e16f58da2f793a1e2f7f5768dba 0bfe812e3d1f25756efcf92162961f5d55c3a5d8 9f96c81ba868d6269f3698c64ca8a83e74b0510f d5f01925db8323eeabbc43ec1b72a685da00dd6b f09195ec50a24c35947cb52feca1978ac5599871 0a10380275edaffc88632ef444a15b15c47ec17e 3f08ca6c77812c1d39f2949d2bab7416c77cc4ca af784841593347b2fd440fb78872fe9ac0fe1c09 9aa492880457b6fc20968f5d036cb6fe912e8964 c622cc4a0d279b98570b0af11fc67278e3355556 4d5dead4c4d3b3e34198e59e6ee0f6b3ca7c64b1 2191ceb040dd58a0794250e9e6c795a509b9fad5 775c1d3bc761967ff2f0a83e345c951117a5e9aa ace03eee6a19e6a12ad12c25e310ac3d223d2d48 f10dbc643cb334dc70657a086a38aadb59b59e29 ea63ec4d6f32b8a652d495d9c66d777313271e4a 038178b09b92d678107449519b75a977a08f45e9 f9cdbbb9ebfc1db9261b430427aa719be56a53c1 0a200674c645cf59ae69f25a25440db0b89c0c30 2e7189bb5db8a803c0ade25613a50bfcc264746a e6ca3edcf724fb8f2457423d9261ab73faf1f5da 6ff2d4a7c2fbc14ea856eb891f019c7978905834 72fac5e32be9bbf531dc8e324f2b865eb265ec4f 351cd2077d369fc0a9b9ec8675ede29288d41f35 061dd2a2659df35d1edd4ba74d67e6e72b531bf7 3c32ab918568bf4f59b0a8b393020de888dc2c3e 08fa11670d73b4f71226541761e09a99fc8a17c9 9d94e556f3eb471fd312af194ca7c4b82b67da6c db70db80c56513ebad6b95b66273e623198c5f44 e666311a274481b4af90702c916004ccbf9b6d8a 9780e12fa7acfb3a5be7d4171068c8c100858c53 baee9c1074cbf844b7c4a3c837ebb17f7861d075 0aae4ce623c90bfd7ea6c4f20967bf50001dc22f c8b42e81407d55a6444986deb435fa8144822c49 9e9967bb87524a82ae9411ca974d3b081ec52c53 3eac611da268444f07e1f718ffd18c7f47bc2a4c fbb2b3a689be07c57cde471e651ba06d7ecf7316 28d61bf3fae304b22ce0380c93a6f997e8c77e32 992c464588845b09ff2b4a61b5de719b9cdaf356 716fff934be2016bc00b2fcf17e19bc0ecfdeeb0 69a2005824c09fa33828ec5ffa24b9df8cd5bcc0 4fa6810e9e944c7d0c4ff06bed6a534e33869034 8dbbcec096317e9016c2f3478be4d458dbb34ad8 2c7c01be15245ae8997185fee247c00106cc81db 5af9b8d40ec97f5741d9a69161ef4aa10c879724 c9851e1b750de6c324c749b4bff5725d79e2b610 0a9f5a297bb97486fc23bb3a0bb39cb8b5b8cc27 aa4bda96b90fab60bf383c255d60b9580b5b6a31 cd8a892d7f6ca71c5d591d4282d98083462d77fe 98cc1a202fd2dbf27e87378c1588edc5eb1c3d60 d3068f5500a98d2a2b71d4c01d5296477224b743 1b28153bff1449200899115d4a1d9f612fac716c d992717d5df7bf68a5907446f9b31c78b5a01f51 497033c40c559bceb5c7980c8d48bd1d935188e3 d967a66b91fd990264e5a4b134385d80e5980c57 a397e9dda8244b6977adb9daeb5ab5ddff6e6140 60b804dc01593469962dae00a1e4004f0a8d7c53 a7b240cf9199d727e494b97ad2d9b65440a9ef1c 2458e3538eef44deb6f3d6a4831aef19414fd0ed c19139b782f5124ea86fc1610fe13ea85f77a279 c67f095bcad89fc6e6b635792a96ed0ed295e1a8 9ecebc8512dbb2a0ed61df1901eafd3832893bf8 95a551f86f299d7f8b424c26da3ff77400368fed ae5c8d61d8c75ed4b01dac60edd37859bc8f9d8f e54f11cae13b053a44afe10cdb47b65f535caca9 9b4fcfd0bee437354defe7e0f431857ff21c0edb ee5c2a995e1b9affef5a8e12f23cff8b0813d2ab 034c3e1601aaa0cba81118030a849485eea2b7ea 0cce165ede3a66867a863d5cb86afff5db406587 375b4fd6eca2d9d63959f9c755de6f8c5d89d302 8bec92a21036bedb734571d443f7b1a14daaa6eb 14d0b11516cd8bbdea84a3fa6cf53cff9619d902 c1e77a9311a8679328d0dc1337dd940682296927 6ab614d3e218d4c5cb3f69001a71350d3d7c65ec 77f6db23a5b65257959cc55e03eff09ee8f25cfc 64b7a40bb5620ec0522d9609fc961cff9cafe68a 62dca0c033d444aa579970c4c871b802c2a82d60 21f5480d3441d7c918a817368172bc14d714a3e8 3fc038d8db20f298b843a7eeeb31f25abf5a2788 492236c84ca4cfc3d8aea9d32d75b6a65a2fe52a 759a12b81483024d52d7b2055f66d675c05ea372 50580213060d8392a2da78eec0b8f08adddeba62 6374e3bb760d470dacdadfc14ef7cb824d9e194c 964b76fe981ab840a2cbc8a807789abae92ae660 b30861536f72d0ffc97c8780b62759fb764ed40b 5edb09e6ea1ba70cdac64a2196481b1f038301c2 34eeb6773589a95ecf66484b999cf443e57632d0 4ee9c48fa4b6f983c03acf77e8d04720fe43e1a6 88ebb8d8af483c96640f7df804e87fca20284c4d ce9fadbe2bd8bac62b475a387a8577f8a806fd52 9e7eb5f80cde5398270e1c4c85258118e22fe8ef a19227e38c38ceb21695ac14ea7754002980cf55 4277bc56f4490533734b1ed78fb5a9c8575f7afb 424479529f31e00ff3263795d42218a026fa528a 91c0289a560e3f3860d7b39549010adf917b8d1b 62a80750f59f92786acc48b18c3365d021bc5590 c0de5849434d88dd115eac9e5bc8eafcd0a0fa76 f869b8a4d7f88ac88437c9f3cfb4416784990e98 ee80bb3fe9cdd54af1ce4aba7f5e2fd136a2499c 8563a689d5957e4fd3ff9fecfbf97def28de4bff de8179675f9250b28678671addf56e33e5829e79 43b815a08101d267bc5d937d0b003a419bb2abd9 9e4164f6b3f847f371351a324905def648ea1747 1f26e1cc07a0de2edb516769b74e99b965b6d75d c36c0e51aad0f40f3f61406e786ba198ab6d90f9 c727bae4cb644789b0a975ec665c8b02652d4651 a61b91abb5ba8128c1438cc59b2f054c71f28d2a 2e1cecf0bba482b9976f3d8f274611195b0cf2f8 707ef18dccda6b917e1b421291e47e658555b3d2 b456956bfd85041b5b70b50d5fb2eaf3c9de64f2 f39d14d001e3dd0e73c4f8200f4132b47ebb40d3 9f0bcb8f5d1922199afb7bc8f8bb57bb10d0fe12 e877036f029a0198d9da39775443c8ac2132309b 2391f2f3881dbdabf96ca33c931e9cd5f42cedc9 82189594b7e20243f5ece31c6f7b804d6b83b0d7 5abd3260994cc77992f5c6437bdcdf45c32d9867 2519053ee4c5b2ce1c2851fee0d47d612d27aa1f 05584371da7da40cdab309ea2809c51c02069384 b61c8342cee8a0942ce276c2d2de773347ab4dcd c7b80824ade46956377b955838b73325d6fbe4d9 9866874e4701f30f1a293a7fd2e5d242bbf82c4f 2308aecbde415948894a55e53201c5abb7184039 e8b44094228f41fa5996788b977d07072fcf87a6 2facd93337f682bd8aa1222805c46720a53edc99 2d9288cec441356241f7d59d120de06ee7b97fdd
Diff


    
        
        
        
        
        GRIM UI 
        
        
        
        
    
    
        
        

Flexbox

Flexbox is a high level positioning plugin that allows for dynamic positioning of elements based apon container sizing. To learn more about flexbox refer to this MDN article, in this document we will go into the impleamentation of flexbox rather than the usage of it.

"display": "flex", "justify-content": "*", "align-content": "*", "align-items": "*", "flex-wrap": "*", "flex-direction": "*",

# Flex Properties

justify-content align-content align-items flex-wrap flex-direction
normal normal normal nowrap row
center center center wrap column
flex-start flex-start flex-start row-reverse
flex-end flex-end flex-end column-reverse
space-between space-between stretch
space-around space-around baseline
space-evenly stretch

# order?(go)

asd

   1package flex
   2
   3import (
   4	"gui/cstyle"
   5	"gui/cstyle/plugins/inline"
   6	"gui/element"
   7	"gui/utils"
   8	"sort"
   9	"strings"
  10)
  11
  12func Init() cstyle.Plugin {
  13	return cstyle.Plugin{
  14		Selector: func(n *element.Node) bool {
  15			styles := map[string]string{
  16				"display": "flex",
  17			}
  18			matches := true
  19			for name, value := range styles {
  20				if (n.Style[name] != value || n.Style[name] == "") && !(value == "*") {
  21					matches = false
  22				}
  23			}
  24			return matches
  25		},
  26		Level: 3,
  27		Handler: func(n *element.Node, state *map[string]element.State) {
  28			s := *state
  29			self := s[n.Properties.Id]
  30
  31			verbs := strings.Split(n.Style["flex-direction"], "-")
  32			flexDirection := verbs[0]
  33			if flexDirection == "" {
  34				flexDirection = "row"
  35			}
  36			flexReversed := false
  37			if len(verbs) > 1 {
  38				flexReversed = true
  39			}
  40
  41			var flexWrapped bool
  42			if n.Style["flex-wrap"] == "wrap" {
  43				flexWrapped = true
  44			} else {
  45				flexWrapped = false
  46			}
  47
  48			alignContent := n.Style["align-content"]
  49			if alignContent == "" {
  50				alignContent = "normal"
  51			}
  52			alignItems := n.Style["align-items"]
  53			if alignItems == "" {
  54				alignItems = "normal"
  55			}
  56			justifyItems := n.Style["justify-items"]
  57			if justifyItems == "" {
  58				justifyItems = "normal"
  59			}
  60
  61			justifyContent := n.Style["justify-content"]
  62			if justifyContent == "" {
  63				justifyContent = "normal"
  64			}
  65			// fmt.Println(flexDirection, flexReversed, flexWrapped, alignItems, alignContent, justifyItems, justifyContent)
  66			rows := [][]int{}
  67			maxH := float32(0)
  68			// maxW := float32(0)
  69
  70			// Get inital sizing
  71			textTotal := 0
  72			textCounts := []int{}
  73			widths := []float32{}
  74			// heights := []float32{}
  75			innerSizes := [][]float32{}
  76			minWidths := []float32{}
  77			minHeights := []float32{}
  78			maxWidths := []float32{}
  79			// maxHeights := []float32{}
  80			for _, v := range n.Children {
  81				count := countText(v)
  82				textTotal += count
  83				textCounts = append(textCounts, count)
  84
  85				minw := getMinWidth(v, state)
  86				minWidths = append(minWidths, minw)
  87
  88				maxw := getMaxWidth(v, state)
  89				maxWidths = append(maxWidths, maxw)
  90
  91				w, h := getInnerSize(v, state)
  92
  93				minh := getMinHeight(v, state)
  94				minHeights = append(minHeights, minh)
  95
  96				// maxh := getMaxHeight(&v, state)
  97				// maxHeights = append(maxHeights, maxh)
  98				innerSizes = append(innerSizes, []float32{w, h})
  99			}
 100			selfWidth := (self.Width - self.Padding.Left) - self.Padding.Right
 101			selfHeight := (self.Height - self.Padding.Top) - self.Padding.Bottom
 102
 103			if flexDirection == "row" {
 104				// if the elements are less than the size of the parent, don't change widths. Just set mins
 105				if !flexWrapped {
 106					if add2d(innerSizes, 0) < selfWidth {
 107						for i := range innerSizes {
 108							// for i, _ := range n.Children {
 109							// vState := s[v.Properties.Id]
 110
 111							w := innerSizes[i][0]
 112							// w -= vState.Margin.Left + vState.Margin.Right + (vState.Border.Width * 2)
 113							widths = append(widths, w)
 114						}
 115					} else {
 116						// Modifiy the widths so they aren't under the mins
 117						for i, v := range n.Children {
 118							vState := s[v.Properties.Id]
 119
 120							w := ((selfWidth / float32(textTotal)) * float32(textCounts[i]))
 121							w -= vState.Margin.Left + vState.Margin.Right + (vState.Border.Left.Width + vState.Border.Right.Width)
 122
 123							if w < minWidths[i] {
 124								selfWidth -= minWidths[i] + vState.Margin.Left + vState.Margin.Right + (vState.Border.Left.Width + vState.Border.Right.Width)
 125								textTotal -= textCounts[i]
 126								textCounts[i] = 0
 127							}
 128
 129						}
 130						for i, v := range n.Children {
 131							vState := s[v.Properties.Id]
 132
 133							w := ((selfWidth / float32(textTotal)) * float32(textCounts[i]))
 134							w -= vState.Margin.Left + vState.Margin.Right + (vState.Border.Left.Width + vState.Border.Right.Width)
 135							// (w!=w) is of NaN
 136							if w < minWidths[i] || (w != w) {
 137								w = minWidths[i]
 138							}
 139							widths = append(widths, w)
 140						}
 141					}
 142					// Apply the new widths
 143					fState := s[n.Children[0].Properties.Id]
 144					for i, v := range n.Children {
 145						vState := s[v.Properties.Id]
 146
 147						vState.Width = widths[i]
 148						xStore := vState.X
 149						if i > 0 {
 150							sState := s[n.Children[i-1].Properties.Id]
 151							vState.X = sState.X + sState.Width + sState.Margin.Right + vState.Margin.Left + vState.Border.Left.Width + vState.Border.Right.Width
 152							propagateOffsets(v, xStore, vState.Y, vState.X, fState.Y+vState.Margin.Top, state)
 153						}
 154
 155						vState.Y = fState.Y + vState.Margin.Top
 156
 157						(*state)[v.Properties.Id] = vState
 158						deInline(v, state)
 159						applyInline(v, state)
 160						applyBlock(v, state)
 161						_, h := getInnerSize(v, state)
 162						h = utils.Max(h, vState.Height)
 163						maxH = utils.Max(maxH, h)
 164					}
 165					// When not wrapping everything will be on the same row
 166					rows = append(rows, []int{0, len(n.Children), int(maxH)})
 167				} else {
 168					// Flex Wrapped
 169					sum := innerSizes[0][0]
 170					for i := 0; i < len(n.Children); i++ {
 171						v := n.Children[i]
 172						vState := s[v.Properties.Id]
 173
 174						// if the next plus current will break then
 175						w := innerSizes[i][0]
 176						if i > 0 {
 177							sib := s[n.Children[i-1].Properties.Id]
 178							if maxWidths[i] > selfWidth {
 179								w = selfWidth - vState.Margin.Left - vState.Margin.Right - (vState.Border.Left.Width + vState.Border.Right.Width)
 180							}
 181							if w+sum > selfWidth {
 182								sum = w + vState.Margin.Left + vState.Margin.Right + (vState.Border.Left.Width + vState.Border.Right.Width)
 183							} else {
 184								propagateOffsets(v, vState.X, vState.Y, vState.X, sib.Y, state)
 185								vState.Y = sib.Y
 186								(*state)[v.Properties.Id] = vState
 187								sum += w + vState.Margin.Left + vState.Margin.Right + (vState.Border.Left.Width + vState.Border.Right.Width)
 188							}
 189						}
 190
 191						widths = append(widths, w)
 192					}
 193
 194					// Move the elements into the correct position
 195					start := 0
 196					var prevOffset float32
 197					for i := 0; i < len(n.Children); i++ {
 198						v := n.Children[i]
 199						vState := s[v.Properties.Id]
 200
 201						vState.Width = widths[i]
 202						xStore := vState.X
 203						yStore := vState.Y
 204
 205						if i > 0 {
 206							sib := s[n.Children[i-1].Properties.Id]
 207							if vState.Y+prevOffset == sib.Y {
 208								yStore += prevOffset
 209
 210								if vState.Height < sib.Height {
 211									vState.Height = minHeight(v, state, sib.Height)
 212								}
 213								// Shift right if on a row with sibling
 214								xStore = sib.X + sib.Width + sib.Margin.Right + sib.Border.Left.Width + vState.Margin.Left + vState.Border.Left.Width
 215							} else {
 216								// Shift under sibling
 217								yStore = sib.Y + sib.Height + sib.Margin.Top + sib.Margin.Bottom + sib.Border.Top.Width + sib.Border.Bottom.Width
 218								prevOffset = yStore - vState.Y
 219								rows = append(rows, []int{start, i, int(maxH)})
 220								start = i
 221								maxH = 0
 222							}
 223							propagateOffsets(v, vState.X, vState.Y, xStore, yStore, state)
 224						}
 225						vState.X = xStore
 226						vState.Y = yStore
 227
 228						(*state)[v.Properties.Id] = vState
 229						deInline(v, state)
 230						applyInline(v, state)
 231						applyBlock(v, state)
 232						_, h := getInnerSize(v, state)
 233						h = utils.Max(h, vState.Height)
 234						maxH = utils.Max(maxH, h)
 235						vState.Height = minHeight(v, state, h)
 236						(*state)[v.Properties.Id] = vState
 237					}
 238					if start < len(n.Children) {
 239						rows = append(rows, []int{start, len(n.Children), int(maxH)})
 240					}
 241				}
 242
 243				var totalHeight float32
 244
 245				for _, v := range rows {
 246					totalHeight += float32(v[2])
 247					for i := v[0]; i < v[1]; i++ {
 248						vState := s[n.Children[i].Properties.Id]
 249						if vState.Height == float32(v[2]) {
 250							totalHeight += vState.Margin.Top + vState.Margin.Bottom
 251							v[2] += int(vState.Margin.Top + vState.Margin.Bottom + (vState.Border.Top.Width + vState.Border.Bottom.Width))
 252						}
 253					}
 254				}
 255				var yOffset float32
 256				for _, v := range rows {
 257					for i := v[0]; i < v[1]; i++ {
 258						vState := s[n.Children[i].Properties.Id]
 259						// height := float32(v[2])
 260						if n.Children[i].Style["height"] == "" && n.Children[i].Style["min-height"] == "" && !flexWrapped {
 261							height := self.Height - self.Padding.Top - self.Padding.Bottom - vState.Margin.Top - vState.Margin.Bottom - (vState.Border.Top.Width + vState.Border.Bottom.Width)
 262							vState.Height = minHeight(n.Children[i], state, height)
 263						} else if flexWrapped && (n.Style["height"] != "" || n.Style["min-height"] != "") {
 264							height := ((selfHeight / totalHeight) * float32(v[2])) - (vState.Margin.Top + vState.Margin.Bottom + (vState.Border.Top.Width + vState.Border.Bottom.Width))
 265							vState.Height = minHeight(n.Children[i], state, height)
 266							yStore := vState.Y
 267							vState.Y = self.Y + self.Padding.Top + yOffset + vState.Margin.Top + vState.Border.Top.Width
 268							propagateOffsets(n.Children[i], vState.X, yStore, vState.X, vState.Y, state)
 269						} else if flexWrapped {
 270							if vState.Height+vState.Margin.Top+vState.Margin.Bottom+(vState.Border.Top.Width+vState.Border.Bottom.Width) != float32(v[2]) {
 271								height := vState.Height - (vState.Margin.Top + vState.Margin.Bottom + (vState.Border.Top.Width + vState.Border.Bottom.Width))
 272								vState.Height = minHeight(n.Children[i], state, height)
 273							}
 274							yStore := vState.Y
 275							vState.Y = self.Y + self.Padding.Top + yOffset + vState.Margin.Top + vState.Border.Top.Width
 276							propagateOffsets(n.Children[i], vState.X, yStore, vState.X, vState.Y, state)
 277						}
 278						(*state)[n.Children[i].Properties.Id] = vState
 279					}
 280					if flexWrapped && (n.Style["height"] != "" || n.Style["min-height"] != "") {
 281						yOffset += ((selfHeight / totalHeight) * float32(v[2]))
 282					} else if flexWrapped {
 283						yOffset += float32(v[2])
 284					}
 285				}
 286				// Reverse elements
 287				if flexReversed {
 288					rowReverse(rows, n, state)
 289				}
 290
 291				if justifyContent != "" && justifyContent != "normal" {
 292					justifyRow(rows, n, state, justifyContent, flexReversed)
 293				}
 294
 295				if alignContent != "normal" || alignItems != "normal" {
 296					alignRow(rows, n, state, alignItems, alignContent)
 297				}
 298
 299			}
 300
 301			if flexDirection == "column" {
 302				if !flexWrapped {
 303					// if the container has a size restriction
 304					var totalHeight, maxH float32
 305					var fixedHeightElements int
 306					for i, v := range n.Children {
 307						vState := s[v.Properties.Id]
 308						if v.Style["min-height"] != "" {
 309							selfHeight -= vState.Height + vState.Margin.Top + vState.Margin.Bottom + (vState.Border.Top.Width + vState.Border.Bottom.Width)
 310							fixedHeightElements++
 311							maxH = utils.Max(maxH, vState.Height)
 312						} else {
 313							// accoutn for element min height
 314							totalHeight += minHeights[i] + vState.Margin.Top + vState.Margin.Bottom + (vState.Border.Top.Width + vState.Border.Bottom.Width)
 315							maxH = utils.Max(maxH, minHeights[i])
 316						}
 317					}
 318
 319					heightDelta := selfHeight - totalHeight
 320					if heightDelta < 0 {
 321						heightDelta = -heightDelta
 322					}
 323					heightAdj := heightDelta / float32(len(n.Children)-fixedHeightElements)
 324					if heightAdj < 0 {
 325						heightAdj = -heightAdj
 326					}
 327					// We are calculating the amount a element needs to shrink because of its siblings
 328					for i, v := range n.Children {
 329						vState := s[v.Properties.Id]
 330						yStore := vState.Y
 331						vState.Height = setHeight(v, state, minHeights[i]-heightAdj)
 332						if i > 0 {
 333							sib := s[n.Children[i-1].Properties.Id]
 334
 335							vState.Y = sib.Y + sib.Height + sib.Margin.Bottom + sib.Border.Top.Width + vState.Margin.Top + vState.Border.Top.Width
 336						}
 337						propagateOffsets(v, vState.X, yStore, vState.X, vState.Y, state)
 338
 339						(*state)[v.Properties.Id] = vState
 340					}
 341
 342					rows = append(rows, []int{0, len(n.Children) - 1, int(maxH)})
 343
 344				} else {
 345					// need to redo this, with col wrap make each row the width of the longest element unless set otherwise (width, max-width) get width with min-width
 346					var colHeight float32
 347					var colIndex int
 348					cols := [][][]float32{}
 349
 350					// Map elements to columns
 351					for i, v := range n.Children {
 352						vState := s[v.Properties.Id]
 353						height := vState.Height + vState.Margin.Top + vState.Margin.Bottom + (vState.Border.Top.Width + vState.Border.Bottom.Width)
 354						if colHeight+height > selfHeight {
 355							colHeight = height
 356							colIndex++
 357							width := innerSizes[i][0]
 358							if colIndex >= len(cols) {
 359								cols = append(cols, [][]float32{})
 360							}
 361							cols[colIndex] = append(cols[colIndex], []float32{float32(i), height, width})
 362						} else {
 363							colHeight += height
 364							width := innerSizes[i][0]
 365							if colIndex >= len(cols) {
 366								cols = append(cols, [][]float32{})
 367							}
 368							cols[colIndex] = append(cols[colIndex], []float32{float32(i), height, width})
 369						}
 370					}
 371
 372					// Find the max total width of all columns
 373					var totalMaxWidth float32
 374					maxWidths := []float32{}
 375					for _, col := range cols {
 376						var maxWidth, maxHeight float32
 377						for _, element := range col {
 378							maxHeight = utils.Max(utils.Max(element[1], minHeights[int(element[0])]), maxHeight)
 379							maxWidth = utils.Max(element[2], maxWidth)
 380						}
 381						rows = append(rows, []int{int(col[0][0]), int(col[len(col)-1][0]), int(maxHeight)})
 382						totalMaxWidth += maxWidth
 383						maxWidths = append(maxWidths, maxWidth)
 384					}
 385					// Move the elements into the correct position
 386					var xOffset float32
 387					var index int
 388					for i, col := range cols {
 389						// Move the elements into the correct position
 390						yOffset := self.Y + self.Border.Top.Width + self.Padding.Top
 391						var marginOffset float32
 392						for _, element := range col {
 393							v := n.Children[int(element[0])]
 394							vState := s[v.Properties.Id]
 395							xStore := vState.X
 396							yStore := vState.Y
 397							vState.X = self.X + self.Padding.Left + self.Border.Left.Width + xOffset + vState.Margin.Left + vState.Border.Left.Width
 398							vState.Y = yOffset + vState.Margin.Top + vState.Border.Top.Width
 399							propagateOffsets(v, xStore, yStore, vState.X, vState.Y, state)
 400							if innerSizes[index][0] == maxWidths[i] {
 401								marginOffset = vState.Margin.Right + vState.Margin.Left + (vState.Border.Left.Width + vState.Border.Right.Width)
 402							}
 403							vState.Width = setWidth(v, state, maxWidths[i])
 404							yOffset += vState.Margin.Top + vState.Border.Top.Width + vState.Height + vState.Margin.Bottom + vState.Border.Bottom.Width
 405							(*state)[v.Properties.Id] = vState
 406							index++
 407						}
 408						xOffset += maxWidths[i] + marginOffset
 409					}
 410
 411				}
 412
 413				if flexReversed {
 414					colReverse(rows, n, state)
 415				}
 416
 417				if justifyContent != "normal" {
 418					justifyCols(rows, n, state, justifyContent, flexReversed)
 419				}
 420				if alignContent != "normal" || alignItems != "normal" {
 421					alignCols(rows, n, state, alignItems, alignContent, innerSizes)
 422				}
 423			}
 424			if n.Style["height"] == "" && n.Style["min-height"] == "" {
 425				_, h := getInnerSize(n, state)
 426				self.Height = h
 427			}
 428			(*state)[n.Properties.Id] = self
 429		},
 430	}
 431}
 432
 433func applyBlock(n *element.Node, state *map[string]element.State) {
 434	if len(n.Children) > 0 {
 435		accum := float32(0)
 436		inlineOffset := float32(0)
 437		s := *state
 438		lastHeight := float32(0)
 439		baseY := s[n.Children[0].Properties.Id].Y
 440		for i := 0; i < len(n.Children); i++ {
 441			v := n.Children[i]
 442			vState := s[v.Properties.Id]
 443
 444			if v.Style["display"] != "block" {
 445				vState.Y += inlineOffset
 446				accum = (vState.Y - baseY)
 447				lastHeight = vState.Height
 448			} else if v.Style["position"] != "absolute" {
 449				vState.Y += accum
 450				inlineOffset += (vState.Height + (vState.Border.Top.Width + vState.Border.Bottom.Width) + vState.Margin.Top + vState.Margin.Bottom + vState.Padding.Top + vState.Padding.Bottom) + lastHeight
 451			}
 452			(*state)[v.Properties.Id] = vState
 453		}
 454	}
 455}
 456
 457func deInline(n *element.Node, state *map[string]element.State) {
 458	s := *state
 459	// self := s[n.Properties.Id]
 460	baseX := float32(-1)
 461	baseY := float32(-1)
 462	for _, v := range n.Children {
 463		vState := s[v.Properties.Id]
 464
 465		if v.Style["display"] == "inline" {
 466			if baseX < 0 && baseY < 0 {
 467				baseX = vState.X
 468				baseY = vState.Y
 469			} else {
 470				vState.X = baseX
 471				vState.Y = baseY
 472				(*state)[v.Properties.Id] = vState
 473
 474			}
 475		} else {
 476			baseX = float32(-1)
 477			baseY = float32(-1)
 478		}
 479
 480		if len(v.Children) > 0 {
 481			deInline(v, state)
 482		}
 483	}
 484
 485}
 486
 487func applyInline(n *element.Node, state *map[string]element.State) {
 488	pl := inline.Init()
 489	for i := 0; i < len(n.Children); i++ {
 490		v := n.Children[i]
 491
 492		if len(v.Children) > 0 {
 493			applyInline(v, state)
 494		}
 495
 496		if pl.Selector(v) {
 497			pl.Handler(v, state)
 498		}
 499	}
 500}
 501
 502func propagateOffsets(n *element.Node, prevx, prevy, newx, newy float32, state *map[string]element.State) {
 503	s := *state
 504	for _, v := range n.Children {
 505		vState := s[v.Properties.Id]
 506		xStore := (vState.X - prevx) + newx
 507		yStore := (vState.Y - prevy) + newy
 508
 509		if len(v.Children) > 0 {
 510			propagateOffsets(v, vState.X, vState.Y, xStore, yStore, state)
 511		}
 512		vState.X = xStore
 513		vState.Y = yStore
 514		(*state)[v.Properties.Id] = vState
 515	}
 516
 517}
 518
 519func countText(n *element.Node) int {
 520	count := 0
 521	groups := []int{}
 522	for _, v := range n.Children {
 523		if v.TagName == "notaspan" {
 524			count += 1
 525		}
 526		if v.Style["display"] == "block" {
 527			groups = append(groups, count)
 528			count = 0
 529		}
 530		if len(v.Children) > 0 {
 531			count += countText(v)
 532		}
 533	}
 534	groups = append(groups, count)
 535
 536	sort.Slice(groups, func(i, j int) bool {
 537		return groups[i] > groups[j]
 538	})
 539	return groups[0]
 540}
 541
 542func minHeight(n *element.Node, state *map[string]element.State, prev float32) float32 {
 543	s := *state
 544	self := s[n.Properties.Id]
 545	if n.Style["min-height"] != "" {
 546		mw := utils.ConvertToPixels(n.Style["min-height"], self.EM, s[n.Parent.Properties.Id].Width)
 547		return utils.Max(prev, mw)
 548	} else {
 549		return prev
 550	}
 551
 552}
 553
 554func getMinHeight(n *element.Node, state *map[string]element.State) float32 {
 555	s := *state
 556	self := s[n.Properties.Id]
 557	selfHeight := float32(0)
 558
 559	if len(n.Children) > 0 {
 560		for _, v := range n.Children {
 561			selfHeight = utils.Max(selfHeight, getNodeHeight(v, state))
 562		}
 563	} else {
 564		selfHeight = self.Height
 565	}
 566	if n.Style["min-height"] != "" {
 567		mh := utils.ConvertToPixels(n.Style["min-height"], self.EM, s[n.Parent.Properties.Id].Width)
 568		selfHeight = utils.Max(mh, selfHeight)
 569	}
 570
 571	selfHeight += self.Padding.Top + self.Padding.Bottom
 572	return selfHeight
 573}
 574
 575func getMinWidth(n *element.Node, state *map[string]element.State) float32 {
 576	s := *state
 577	self := s[n.Properties.Id]
 578	selfWidth := float32(0)
 579
 580	if len(n.Children) > 0 {
 581		for _, v := range n.Children {
 582			selfWidth = utils.Max(selfWidth, getNodeWidth(v, state))
 583		}
 584	} else {
 585		selfWidth = self.Width
 586	}
 587	if n.Style["min-width"] != "" {
 588		mw := utils.ConvertToPixels(n.Style["min-width"], self.EM, s[n.Parent.Properties.Id].Width)
 589		selfWidth = utils.Max(mw, selfWidth)
 590	}
 591
 592	selfWidth += self.Padding.Left + self.Padding.Right
 593	return selfWidth
 594}
 595func getMaxWidth(n *element.Node, state *map[string]element.State) float32 {
 596	s := *state
 597	self := s[n.Properties.Id]
 598	selfWidth := float32(0)
 599
 600	if len(n.Children) > 0 {
 601		var maxRowWidth, rowWidth float32
 602
 603		for _, v := range n.Children {
 604			rowWidth += getNodeWidth(v, state)
 605			if v.Style["display"] != "inline" {
 606				maxRowWidth = utils.Max(rowWidth, maxRowWidth)
 607				rowWidth = 0
 608			}
 609		}
 610		selfWidth = utils.Max(rowWidth, maxRowWidth)
 611	} else {
 612		selfWidth = self.Width
 613	}
 614
 615	selfWidth += self.Padding.Left + self.Padding.Right
 616	return selfWidth
 617}
 618
 619func getNodeWidth(n *element.Node, state *map[string]element.State) float32 {
 620	s := *state
 621	self := s[n.Properties.Id]
 622	w := float32(0)
 623	w += self.Padding.Left
 624	w += self.Padding.Right
 625
 626	w += self.Margin.Left
 627	w += self.Margin.Right
 628
 629	w += self.Width
 630
 631	w += self.Border.Left.Width + self.Border.Right.Width
 632
 633	for _, v := range n.Children {
 634		w = utils.Max(w, getNodeWidth(v, state))
 635	}
 636
 637	return w
 638}
 639
 640func setWidth(n *element.Node, state *map[string]element.State, width float32) float32 {
 641	s := *state
 642	self := s[n.Properties.Id]
 643
 644	if n.Style["width"] != "" {
 645		return utils.ConvertToPixels(n.Style["width"], self.EM, s[n.Parent.Properties.Id].Width) + self.Padding.Left + self.Padding.Right
 646	}
 647
 648	var maxWidth, minWidth float32
 649	maxWidth = 10e9
 650	if n.Style["min-width"] != "" {
 651		minWidth = utils.ConvertToPixels(n.Style["min-width"], self.EM, s[n.Parent.Properties.Id].Width)
 652		minWidth += self.Padding.Left + self.Padding.Right
 653	}
 654	if n.Style["max-width"] != "" {
 655		maxWidth = utils.ConvertToPixels(n.Style["min-width"], self.EM, s[n.Parent.Properties.Id].Width)
 656		maxWidth += self.Padding.Left + self.Padding.Right
 657	}
 658
 659	return utils.Max(minWidth, utils.Min(width, maxWidth))
 660}
 661
 662func setHeight(n *element.Node, state *map[string]element.State, height float32) float32 {
 663	s := *state
 664	self := s[n.Properties.Id]
 665
 666	if n.Style["height"] != "" {
 667		return utils.ConvertToPixels(n.Style["height"], self.EM, s[n.Parent.Properties.Id].Height)
 668	}
 669
 670	var maxHeight, minHeight float32
 671	maxHeight = 10e9
 672	if n.Style["min-height"] != "" {
 673		minHeight = utils.ConvertToPixels(n.Style["min-height"], self.EM, s[n.Parent.Properties.Id].Height)
 674	}
 675	if n.Style["max-height"] != "" {
 676		maxHeight = utils.ConvertToPixels(n.Style["min-height"], self.EM, s[n.Parent.Properties.Id].Height)
 677	}
 678
 679	return utils.Max(minHeight, utils.Min(height, maxHeight))
 680}
 681
 682func getNodeHeight(n *element.Node, state *map[string]element.State) float32 {
 683	s := *state
 684	self := s[n.Properties.Id]
 685	h := float32(0)
 686	h += self.Padding.Top
 687	h += self.Padding.Bottom
 688
 689	h += self.Margin.Top
 690	h += self.Margin.Bottom
 691
 692	h += self.Height
 693
 694	h += self.Border.Top.Width + self.Border.Bottom.Width
 695
 696	for _, v := range n.Children {
 697		h = utils.Max(h, getNodeHeight(v, state))
 698	}
 699
 700	return h
 701}
 702
 703func getInnerSize(n *element.Node, state *map[string]element.State) (float32, float32) {
 704	s := *state
 705	self := s[n.Properties.Id]
 706
 707	minx := float32(10e10)
 708	maxw := float32(0)
 709	miny := float32(10e10)
 710	maxh := float32(0)
 711	for _, v := range n.Children {
 712		vState := s[v.Properties.Id]
 713		minx = utils.Min(vState.X, minx)
 714		miny = utils.Min(vState.Y-vState.Margin.Top, miny)
 715		// Don't add the top or left because the x&y values already take that into account
 716		hOffset := (vState.Border.Bottom.Width) + vState.Margin.Bottom
 717		wOffset := (vState.Border.Right.Width) + vState.Margin.Right
 718		maxw = utils.Max(vState.X+vState.Width+wOffset, maxw)
 719		maxh = utils.Max(vState.Y+vState.Height+hOffset, maxh)
 720	}
 721	w := maxw - minx
 722	h := maxh - miny
 723
 724	w += self.Padding.Left + self.Padding.Right
 725	h += self.Padding.Top + self.Padding.Bottom
 726	if n.Style["width"] != "" {
 727		w = self.Width
 728	}
 729	if n.Style["height"] != "" {
 730		h = self.Height
 731	}
 732
 733	return w, h
 734}
 735
 736func add2d(arr [][]float32, index int) float32 {
 737	var sum float32
 738	if len(arr) == 0 {
 739		return sum
 740	}
 741
 742	for i := 0; i < len(arr); i++ {
 743		if len(arr[i]) <= index {
 744			return sum
 745		}
 746		sum += arr[i][index]
 747	}
 748
 749	return sum
 750}
 751
 752func colReverse(cols [][]int, n *element.Node, state *map[string]element.State) {
 753	s := *state
 754	for _, col := range cols {
 755		tempNodes := []*element.Node{}
 756		tempStates := []element.State{}
 757
 758		for i := col[1]; i >= col[0]; i-- {
 759			tempNodes = append(tempNodes, n.Children[i])
 760			tempStates = append(tempStates, s[n.Children[i].Properties.Id])
 761		}
 762
 763		for i := 0; i < len(tempStates); i++ {
 764			e := col[0] + i
 765			vState := s[n.Children[e].Properties.Id]
 766			propagateOffsets(n.Children[e], vState.X, vState.Y, tempStates[i].X, tempStates[i].Y, state)
 767			vState.Y = tempStates[i].Y
 768			(*state)[n.Children[e].Properties.Id] = vState
 769		}
 770		for i := 0; i < len(tempStates); i++ {
 771			e := col[0] + i
 772			n.Children[e] = tempNodes[i]
 773		}
 774	}
 775}
 776
 777func rowReverse(rows [][]int, n *element.Node, state *map[string]element.State) {
 778	s := *state
 779	for _, row := range rows {
 780		tempNodes := []*element.Node{}
 781		tempStates := []element.State{}
 782
 783		for i := row[1] - 1; i >= row[0]; i-- {
 784			tempNodes = append(tempNodes, n.Children[i])
 785			tempStates = append(tempStates, s[n.Children[i].Properties.Id])
 786		}
 787
 788		for i := 0; i < len(tempStates); i++ {
 789			e := row[0] + i
 790			vState := s[n.Children[e].Properties.Id]
 791			propagateOffsets(n.Children[e], vState.X, vState.Y, tempStates[i].X, tempStates[i].Y, state)
 792			vState.X = tempStates[i].X
 793			(*state)[n.Children[e].Properties.Id] = vState
 794		}
 795		for i := 0; i < len(tempStates); i++ {
 796			e := row[0] + i
 797			n.Children[e] = tempNodes[i]
 798		}
 799
 800		for i := row[1] - 1; i >= row[0]; i-- {
 801			vState := s[n.Children[i].Properties.Id]
 802			var xChng float32
 803			if i < row[1]-1 {
 804				sib := s[n.Children[i+1].Properties.Id]
 805				xChng = sib.X - (sib.Border.Left.Width + sib.Margin.Left + vState.Margin.Right + vState.Border.Right.Width + vState.Width)
 806			} else {
 807				parent := s[n.Properties.Id]
 808				xChng = ((((parent.X + parent.Width) - parent.Padding.Right) - vState.Width) - vState.Margin.Right) - (vState.Border.Right.Width)
 809
 810			}
 811			propagateOffsets(n.Children[i], vState.X, vState.Y, xChng, vState.Y, state)
 812			vState.X = xChng
 813			(*state)[n.Children[i].Properties.Id] = vState
 814		}
 815	}
 816}
 817
 818func justifyRow(rows [][]int, n *element.Node, state *map[string]element.State, justify string, reversed bool) {
 819	s := *state
 820	for _, row := range rows {
 821
 822		if (justify == "flex-end" || justify == "end" || justify == "right") && !reversed {
 823			for i := row[1] - 1; i >= row[0]; i-- {
 824				vState := s[n.Children[i].Properties.Id]
 825				var xChng float32
 826				if i < row[1]-1 {
 827					sib := s[n.Children[i+1].Properties.Id]
 828					xChng = sib.X - (sib.Border.Left.Width + sib.Margin.Left + vState.Margin.Right + vState.Border.Left.Width + vState.Width)
 829				} else {
 830					parent := s[n.Properties.Id]
 831					xChng = ((((parent.X + parent.Width) - parent.Padding.Right) - vState.Width) - vState.Margin.Right) - (vState.Border.Right.Width)
 832
 833				}
 834				propagateOffsets(n.Children[i], vState.X, vState.Y, xChng, vState.Y, state)
 835				vState.X = xChng
 836				(*state)[n.Children[i].Properties.Id] = vState
 837			}
 838		} else if (justify == "flex-end" || justify == "start" || justify == "left" || justify == "normal") && reversed {
 839			for i := row[0]; i < row[1]; i++ {
 840				vState := s[n.Children[i].Properties.Id]
 841				var xChng float32
 842				if i > row[0] {
 843					sib := s[n.Children[i-1].Properties.Id]
 844					xChng = sib.X + sib.Width + (sib.Border.Left.Width + sib.Border.Right.Width) + sib.Margin.Right + vState.Margin.Left + vState.Border.Left.Width
 845				} else {
 846					parent := s[n.Properties.Id]
 847					xChng = parent.X + parent.Padding.Right + vState.Margin.Left + vState.Border.Left.Width + parent.Border.Right.Width
 848
 849				}
 850				propagateOffsets(n.Children[i], vState.X, vState.Y, xChng, vState.Y, state)
 851				vState.X = xChng
 852				(*state)[n.Children[i].Properties.Id] = vState
 853			}
 854		} else if justify == "center" {
 855			// get width of row then center (by getting last x + w + mr + b)
 856			f := s[n.Children[row[0]].Properties.Id]
 857			l := s[n.Children[row[1]-1].Properties.Id]
 858			parent := s[n.Properties.Id]
 859			po := parent.X + parent.Border.Left.Width
 860			// ?
 861			offset := (parent.Width - ((f.X - po) + (l.X - po) + l.Width + f.Border.Left.Width + l.Border.Right.Width)) / 2
 862
 863			for i := row[0]; i < row[1]; i++ {
 864				vState := s[n.Children[i].Properties.Id]
 865
 866				if !reversed {
 867					propagateOffsets(n.Children[i], vState.X, vState.Y, vState.X+offset, vState.Y, state)
 868					vState.X += offset
 869				} else {
 870					propagateOffsets(n.Children[i], vState.X, vState.Y, vState.X-offset, vState.Y, state)
 871					vState.X -= offset
 872				}
 873				(*state)[n.Children[i].Properties.Id] = vState
 874			}
 875
 876		} else if justify == "space-between" {
 877			// get width of row then center (by getting last x + w + mr + b)
 878			f := s[n.Children[row[0]].Properties.Id]
 879			l := s[n.Children[row[1]-1].Properties.Id]
 880			parent := s[n.Properties.Id]
 881			po := parent.Border.Left.Width + parent.Width
 882			po -= parent.Padding.Left + parent.Padding.Right
 883
 884			// make po repersent the total space between elements
 885			for i := row[0]; i < row[1]; i++ {
 886				vState := s[n.Children[i].Properties.Id]
 887				po -= vState.Width + vState.Margin.Left + vState.Margin.Right + (vState.Border.Left.Width + vState.Border.Right.Width)
 888			}
 889
 890			po /= float32(((row[1]) - row[0]) - 1)
 891
 892			if (row[1]-1)-row[0] > 0 {
 893				for i := row[0]; i < row[1]; i++ {
 894					vState := s[n.Children[i].Properties.Id]
 895					var offset float32
 896					if i == row[0] {
 897						offset = parent.X + parent.Padding.Left + f.Margin.Left + f.Border.Left.Width
 898					} else if i == row[1]-1 {
 899						offset = (parent.X + parent.Width) - (l.Margin.Right + l.Border.Left.Width + l.Width + parent.Padding.Right)
 900					} else {
 901						if !reversed {
 902							offset = vState.X + (po * float32(i-row[0]))
 903						} else {
 904							offset = vState.X - (po * float32(((row[1]-1)-row[0])-(i-row[0])))
 905						}
 906
 907					}
 908
 909					propagateOffsets(n.Children[i], vState.X, vState.Y, offset, vState.Y, state)
 910					vState.X = offset
 911					(*state)[n.Children[i].Properties.Id] = vState
 912				}
 913			}
 914			//  else {
 915
 916			// this is/was causing issues, removed and it fixed its self
 917
 918			// if there is one element move left
 919			// vState := s[n.Children[(row[1]-1)-row[0]].Properties.Id]
 920			// var offset float32
 921
 922			// if !reversed {
 923			// 	offset = parent.X + parent.Padding.Left + f.Margin.Left + f.Border.Width
 924			// 	propagateOffsets(&n.Children[(row[1]-1)-row[0]], vState.X, vState.Y, offset, vState.Y, state)
 925			// 	vState.X = offset
 926
 927			// 	(*state)[n.Children[(row[1]-1)-row[0]].Properties.Id] = vState
 928			// }
 929
 930			// }
 931
 932		} else if justify == "space-evenly" {
 933			// get width of row then center (by getting last x + w + mr + b)
 934			parent := s[n.Properties.Id]
 935			po := parent.Border.Left.Width + parent.Width
 936			po -= parent.Padding.Left + parent.Padding.Right
 937
 938			// make po repersent the total space between elements
 939			for i := row[0]; i < row[1]; i++ {
 940				vState := s[n.Children[i].Properties.Id]
 941				po -= vState.Width + vState.Margin.Left + vState.Margin.Right + (vState.Border.Left.Width + vState.Border.Right.Width)
 942			}
 943
 944			po /= float32(((row[1]) - row[0]) + 1)
 945
 946			// get width of row then center (by getting last x + w + mr + b)
 947
 948			for i := row[0]; i < row[1]; i++ {
 949				vState := s[n.Children[i].Properties.Id]
 950
 951				if !reversed {
 952					offset := po * (float32(i-row[0]) + 1)
 953					propagateOffsets(n.Children[i], vState.X, vState.Y, vState.X+offset, vState.Y, state)
 954					vState.X += offset
 955				} else {
 956					offset := po * float32(((row[1]-1)-row[0])-((i-row[0])-1))
 957
 958					propagateOffsets(n.Children[i], vState.X, vState.Y, vState.X-offset, vState.Y, state)
 959					vState.X -= offset
 960				}
 961				(*state)[n.Children[i].Properties.Id] = vState
 962			}
 963
 964		} else if justify == "space-around" {
 965			// get width of row then center (by getting last x + w + mr + b)
 966			parent := s[n.Properties.Id]
 967			po := parent.Border.Left.Width + parent.Width
 968			po -= parent.Padding.Left + parent.Padding.Right
 969
 970			// make po repersent the total space between elements
 971			for i := row[0]; i < row[1]; i++ {
 972				vState := s[n.Children[i].Properties.Id]
 973				po -= vState.Width + vState.Margin.Left + vState.Margin.Right + (vState.Border.Left.Width + vState.Border.Right.Width)
 974			}
 975
 976			po /= float32(((row[1]) - row[0]))
 977
 978			// get width of row then center (by getting last x + w + mr + b)
 979
 980			for i := row[0]; i < row[1]; i++ {
 981				vState := s[n.Children[i].Properties.Id]
 982
 983				if !reversed {
 984					m := (float32(i-row[0]) + 1)
 985					if i-row[0] == 0 {
 986						m = 0.5
 987					} else {
 988						m -= 0.5
 989					}
 990					offset := po * m
 991					propagateOffsets(n.Children[i], vState.X, vState.Y, vState.X+offset, vState.Y, state)
 992					vState.X += offset
 993				} else {
 994					m := float32(((row[1] - 1) - row[0]) - ((i - row[0]) - 1))
 995					m -= 0.5
 996					offset := po * m
 997
 998					propagateOffsets(n.Children[i], vState.X, vState.Y, vState.X-offset, vState.Y, state)
 999					vState.X -= offset
1000				}
1001				(*state)[n.Children[i].Properties.Id] = vState
1002			}
1003
1004		}
1005
1006	}
1007}
1008
1009func alignRow(rows [][]int, n *element.Node, state *map[string]element.State, align, content string) {
1010	// !ISSUE: Baseline isn't properly impleamented
1011	s := *state
1012	self := s[n.Properties.Id]
1013
1014	maxes := []float32{}
1015	var maxesTotal float32
1016	for _, row := range rows {
1017		var maxH float32
1018		for i := row[0]; i < row[1]; i++ {
1019			v := n.Children[i]
1020			vState := s[v.Properties.Id]
1021			_, h := getInnerSize(v, state)
1022			h = minHeight(v, state, h)
1023			h = setHeight(v, state, h)
1024			vState.Height = h
1025			h += vState.Margin.Top + vState.Margin.Bottom + (vState.Border.Top.Width + vState.Border.Bottom.Width)
1026			maxH = utils.Max(maxH, h)
1027			(*state)[v.Properties.Id] = vState
1028		}
1029		maxes = append(maxes, maxH)
1030		maxesTotal += maxH
1031	}
1032
1033	os := ((self.Height - (self.Padding.Top + self.Padding.Bottom + (self.Border.Top.Width + self.Border.Bottom.Width))) - maxesTotal) / float32(len(rows))
1034	if os < 0 || content != "normal" {
1035		os = 0
1036	}
1037
1038	var contentOffset float32
1039
1040	if content == "center" {
1041		contentOffset = ((self.Height - (self.Padding.Top + self.Padding.Bottom + (self.Border.Top.Width + self.Border.Bottom.Width))) - maxesTotal) / 2
1042	} else if content == "end" || content == "flex-end" {
1043		contentOffset = ((self.Height - (self.Padding.Top + self.Padding.Bottom + (self.Border.Top.Width + self.Border.Bottom.Width))) - maxesTotal)
1044	} else if content == "start" || content == "flex-start" || content == "baseline" {
1045		// This is redundent but it helps keep track
1046		contentOffset = 0
1047	} else if content == "space-between" {
1048		os = ((self.Height - (self.Padding.Top + self.Padding.Bottom + (self.Border.Top.Width + self.Border.Bottom.Width))) - maxesTotal) / float32(len(rows)-1)
1049	} else if content == "space-around" {
1050		os = ((self.Height - (self.Padding.Top + self.Padding.Bottom + (self.Border.Top.Width + self.Border.Bottom.Width))) - maxesTotal) / float32(len(rows))
1051		contentOffset = os / 2
1052	} else if content == "space-evenly" {
1053		os = ((self.Height - (self.Padding.Top + self.Padding.Bottom + (self.Border.Top.Width + self.Border.Bottom.Width))) - maxesTotal) / float32(len(rows)+1)
1054		contentOffset = os
1055	}
1056
1057	for c, row := range rows {
1058		maxH := maxes[c]
1059		var sum float32
1060		for i := 0; i < c; i++ {
1061			sum += maxes[i]
1062		}
1063		if align == "start" || align == "flex-start" || align == "self-start" || align == "normal" {
1064			for i := row[0]; i < row[1]; i++ {
1065				vState := s[n.Children[i].Properties.Id]
1066
1067				offset := sum + self.Y + self.Padding.Top + vState.Margin.Top + contentOffset
1068
1069				if n.Style["height"] != "" || n.Style["min-height"] != "" {
1070					offset += ((os) * float32(c))
1071				}
1072
1073				propagateOffsets(n.Children[i], vState.X, vState.Y, vState.X, offset, state)
1074				vState.Y = offset
1075				(*state)[n.Children[i].Properties.Id] = vState
1076			}
1077		} else if align == "center" {
1078			for i := row[0]; i < row[1]; i++ {
1079				vState := s[n.Children[i].Properties.Id]
1080
1081				offset := sum + self.Y + self.Padding.Top + vState.Margin.Top + contentOffset
1082
1083				if n.Style["height"] != "" || n.Style["min-height"] != "" {
1084					offset += (os * float32(c+1)) - (os / 2)
1085				}
1086
1087				if vState.Height+vState.Margin.Top+vState.Margin.Bottom+(vState.Border.Top.Width+vState.Border.Bottom.Width) < maxH {
1088					offset += (maxH - (vState.Height + vState.Margin.Top + vState.Margin.Bottom + (vState.Border.Top.Width + vState.Border.Bottom.Width))) / 2
1089				}
1090				propagateOffsets(n.Children[i], vState.X, vState.Y, vState.X, offset, state)
1091				vState.Y = offset
1092				(*state)[n.Children[i].Properties.Id] = vState
1093			}
1094		} else if align == "end" || align == "flex-end" || align == "self-end" {
1095			for i := row[0]; i < row[1]; i++ {
1096				vState := s[n.Children[i].Properties.Id]
1097
1098				offset := sum + self.Y + self.Padding.Top + vState.Margin.Top + contentOffset
1099
1100				if n.Style["height"] != "" || n.Style["min-height"] != "" {
1101					offset += os * float32(c+1)
1102				}
1103
1104				if vState.Height+vState.Margin.Top+vState.Margin.Bottom+(vState.Border.Top.Width+vState.Border.Bottom.Width) < maxH {
1105					offset += (maxH - (vState.Height + vState.Margin.Top + vState.Margin.Bottom + (vState.Border.Top.Width + vState.Border.Bottom.Width)))
1106				}
1107				propagateOffsets(n.Children[i], vState.X, vState.Y, vState.X, offset, state)
1108				vState.Y = offset
1109				(*state)[n.Children[i].Properties.Id] = vState
1110
1111			}
1112		} else if align == "stretch" {
1113			for i := row[0]; i < row[1]; i++ {
1114				vState := s[n.Children[i].Properties.Id]
1115
1116				offset := sum + self.Y + self.Padding.Top + vState.Margin.Top
1117
1118				if n.Style["height"] != "" || n.Style["min-height"] != "" {
1119					offset += ((os) * float32(c))
1120				}
1121
1122				propagateOffsets(n.Children[i], vState.X, vState.Y, vState.X, offset, state)
1123				vState.Y = offset
1124				vState.Height = maxH - (vState.Margin.Top + vState.Margin.Bottom + (vState.Border.Top.Width + vState.Border.Bottom.Width))
1125				(*state)[n.Children[i].Properties.Id] = vState
1126
1127			}
1128		}
1129	}
1130}
1131
1132func justifyCols(cols [][]int, n *element.Node, state *map[string]element.State, justify string, reversed bool) {
1133	s := *state
1134	self := s[n.Properties.Id]
1135
1136	selfHeight := (self.Height) - (self.Padding.Top + self.Padding.Bottom)
1137	for _, col := range cols {
1138		yCollect := self.Y + self.Padding.Top
1139		var colHeight float32
1140		for i := col[0]; i <= col[1]; i++ {
1141			v := n.Children[i]
1142			vState := s[v.Properties.Id]
1143			colHeight += vState.Height + vState.Margin.Top + vState.Margin.Bottom + (vState.Border.Top.Width + vState.Border.Bottom.Width)
1144		}
1145
1146		if justify == "center" {
1147			offset := ((selfHeight - colHeight) / 2)
1148			yCollect += offset
1149			for i := col[0]; i <= col[1]; i++ {
1150				v := n.Children[i]
1151				vState := s[v.Properties.Id]
1152				yStore := vState.Y
1153				vState.Y = yCollect + vState.Margin.Top
1154				yCollect += vState.Height + vState.Margin.Bottom + vState.Margin.Top + vState.Border.Top.Width + vState.Border.Bottom.Width
1155				propagateOffsets(n.Children[i], vState.X, yStore, vState.X, vState.Y, state)
1156				(*state)[v.Properties.Id] = vState
1157			}
1158		}
1159
1160		if justify == "end" || justify == "flex-end" {
1161			offset := (selfHeight - colHeight)
1162			yCollect += offset
1163			for i := col[0]; i <= col[1]; i++ {
1164				v := n.Children[i]
1165				vState := s[v.Properties.Id]
1166				yStore := vState.Y
1167				vState.Y = yCollect + vState.Border.Top.Width + vState.Margin.Top
1168				yCollect += vState.Height + vState.Margin.Bottom + vState.Border.Top.Width + vState.Margin.Top + vState.Border.Bottom.Width
1169				propagateOffsets(n.Children[i], vState.X, yStore, vState.X, vState.Y, state)
1170				(*state)[v.Properties.Id] = vState
1171			}
1172		}
1173
1174		if justify == "space-evenly" {
1175			offset := (selfHeight - colHeight) / (float32(col[1]-col[0]) + 2)
1176			for i := col[0]; i <= col[1]; i++ {
1177				v := n.Children[i]
1178				vState := s[v.Properties.Id]
1179				yStore := vState.Y
1180				vState.Y = yCollect + vState.Border.Top.Width + vState.Margin.Top + offset
1181				yCollect += vState.Height + vState.Margin.Bottom + vState.Border.Top.Width + vState.Margin.Top + vState.Border.Bottom.Width + offset
1182				propagateOffsets(n.Children[i], vState.X, yStore, vState.X, vState.Y, state)
1183				(*state)[v.Properties.Id] = vState
1184			}
1185		}
1186
1187		if justify == "space-between" {
1188			offset := (selfHeight - colHeight) / (float32(col[1] - col[0]))
1189			for i := col[0]; i <= col[1]; i++ {
1190				v := n.Children[i]
1191				vState := s[v.Properties.Id]
1192				yStore := vState.Y
1193				vState.Y = yCollect + vState.Border.Top.Width + vState.Margin.Top
1194				if col[1]-col[0] != 0 {
1195					vState.Y += offset * float32(i-col[0])
1196				} else if reversed {
1197					vState.Y += selfHeight - (vState.Height + vState.Margin.Bottom + vState.Border.Top.Width + vState.Margin.Top + vState.Border.Bottom.Width)
1198				}
1199				yCollect += vState.Height + vState.Margin.Bottom + vState.Border.Top.Width + vState.Margin.Top + vState.Border.Bottom.Width
1200				propagateOffsets(n.Children[i], vState.X, yStore, vState.X, vState.Y, state)
1201				(*state)[v.Properties.Id] = vState
1202			}
1203		}
1204		if justify == "space-around" {
1205			offset := (selfHeight - colHeight) / (float32(col[1]-col[0]) + 1)
1206			for i := col[0]; i <= col[1]; i++ {
1207				v := n.Children[i]
1208				vState := s[v.Properties.Id]
1209				yStore := vState.Y
1210				vState.Y = yCollect + vState.Border.Top.Width + vState.Margin.Top
1211				if col[1]-col[0] == 0 {
1212					vState.Y += offset / 2
1213				} else {
1214					vState.Y += (offset * float32(i-col[0])) + (offset / 2)
1215				}
1216				yCollect += vState.Height + vState.Margin.Bottom + vState.Border.Top.Width + vState.Margin.Top + vState.Border.Bottom.Width
1217				propagateOffsets(n.Children[i], vState.X, yStore, vState.X, vState.Y, state)
1218				(*state)[v.Properties.Id] = vState
1219			}
1220		}
1221	}
1222}
1223
1224func alignCols(cols [][]int, n *element.Node, state *map[string]element.State, align, content string, minWidths [][]float32) {
1225	s := *state
1226	self := s[n.Properties.Id]
1227
1228	if (align == "stretch" && content == "stretch") || (align == "stretch" && content == "normal") || (align == "normal" && content == "stretch") {
1229		return
1230	}
1231
1232	selfWidth := (self.Width - self.Padding.Left) - self.Padding.Right
1233
1234	var rowWidth float32
1235	colWidths := []float32{}
1236	for _, col := range cols {
1237		var maxWidth float32
1238		for i := col[0]; i <= col[1]; i++ {
1239			v := n.Children[i]
1240			vState := s[v.Properties.Id]
1241			vState.Width = setWidth(v, state, minWidths[i][0])
1242			maxWidth = utils.Max(maxWidth, vState.Width+vState.Margin.Left+vState.Margin.Right+(vState.Border.Left.Width+vState.Border.Right.Width))
1243			(*state)[v.Properties.Id] = vState
1244		}
1245		colWidths = append(colWidths, maxWidth)
1246		rowWidth += maxWidth
1247	}
1248	var xOffset float32
1249	for c, col := range cols {
1250
1251		if align != "normal" {
1252			// var offset float32
1253			for i := col[0]; i <= col[1]; i++ {
1254				v := n.Children[i]
1255				vState := s[v.Properties.Id]
1256				xStore := vState.X
1257				vState.X = self.X + self.Padding.Left + self.Border.Left.Width + xOffset + vState.Margin.Left + vState.Border.Right.Width
1258				if align == "center" {
1259					vState.X += ((colWidths[c] - (vState.Width + vState.Margin.Left + vState.Margin.Right + (vState.Border.Left.Width + vState.Border.Right.Width))) / 2)
1260				} else if align == "end" || align == "flex-end" || align == "self-end" {
1261					vState.X += (colWidths[c] - (vState.Width + vState.Margin.Left + vState.Margin.Right + (vState.Border.Left.Width + vState.Border.Right.Width)))
1262				} else if align == "stretch" {
1263					vState.Width = (colWidths[c] - (vState.Margin.Left + vState.Margin.Right + (vState.Border.Left.Width + vState.Border.Right.Width)))
1264				}
1265				propagateOffsets(n.Children[i], xStore, vState.Y, vState.X, vState.Y, state)
1266				(*state)[v.Properties.Id] = vState
1267			}
1268			xOffset += colWidths[c]
1269		} else {
1270			// if align is set to normal then make the elements the size of the column
1271			// the size of the column is
1272			for i := col[0]; i <= col[1]; i++ {
1273				v := n.Children[i]
1274				vState := s[v.Properties.Id]
1275				vState.Width = setWidth(v, state, colWidths[c]-(vState.Margin.Left+vState.Margin.Right+(vState.Border.Left.Width+vState.Border.Right.Width)))
1276				(*state)[v.Properties.Id] = vState
1277			}
1278		}
1279	}
1280
1281	var offset float32
1282	if selfWidth < rowWidth {
1283		selfWidth = rowWidth
1284	}
1285	if content == "center" {
1286		offset = ((selfWidth - rowWidth) / 2)
1287	}
1288	if content == "end" || content == "flex-end" {
1289		offset = (selfWidth - rowWidth)
1290	}
1291	if content == "space-evenly" {
1292		offset = (selfWidth - rowWidth) / (float32(len(cols) + 1))
1293	}
1294	if content == "space-between" {
1295		offset = (selfWidth - rowWidth) / (float32(len(cols) - 1))
1296	}
1297	if content == "space-around" {
1298		offset = (selfWidth - rowWidth) / (float32(len(cols)))
1299	}
1300	if content == "normal" || content == "stretch" {
1301		if align == "start" || align == "end" || content == "flex-end" {
1302			offset = (selfWidth - rowWidth) / (float32(len(cols)))
1303		}
1304		if align == "center" {
1305			offset = ((selfWidth - rowWidth) / (float32(len(cols))))
1306		}
1307	}
1308	for c, col := range cols {
1309
1310		for i := col[0]; i <= col[1]; i++ {
1311			v := n.Children[i]
1312			vState := s[v.Properties.Id]
1313			xStore := vState.X
1314			if content == "center" || content == "end" || content == "flex-end" {
1315				vState.X += offset
1316			} else if content == "space-evenly" {
1317				vState.X += offset * float32(c+1)
1318			} else if content == "space-between" {
1319				vState.X += offset * float32(c)
1320			} else if content == "space-around" {
1321				if c == 0 {
1322					vState.X += offset / 2
1323				} else {
1324					vState.X += (offset * float32(c)) + (offset / 2)
1325				}
1326			} else if content == "normal" || content == "stretch" {
1327				if align == "start" {
1328					vState.X += offset * float32(c)
1329				}
1330				if align == "end" || content == "flex-end" {
1331					vState.X += offset * float32(c+1)
1332				}
1333				if align == "center" {
1334					if c == 0 {
1335						vState.X += offset / 2
1336					} else {
1337						vState.X += (offset * float32(c)) + (offset / 2)
1338					}
1339				}
1340			}
1341			propagateOffsets(n.Children[i], xStore, vState.Y, vState.X, vState.Y, state)
1342			(*state)[v.Properties.Id] = vState
1343		}
1344	}
1345}