Author: LakeFox
Email: [email protected]
Date: Sun, 30 Jun 2024 15:59:46 -0600
docs/cstyle/plugins/flex/index.html
not working
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
diff --git a/docs/cstyle/plugins/flex/index.html b/docs/cstyle/plugins/flex/index.html
index db7264f..6b2131b 100644
--- a/docs/cstyle/plugins/flex/index.html
+++ b/docs/cstyle/plugins/flex/index.html
@@ -466 +466 @@
- 367						width := w + vState.Margin.Left + vState.Margin.Right + (vState.Border.Width * 2)
+ 367						width := vState.Width + vState.Margin.Left + vState.Margin.Right + (vState.Border.Width * 2)


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