JUCE Graphics Workshop w/ Harrison Consoles

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
good morning everybody welcome to our special one-day workshop on programming the graphics for audio software this event is I put on here at Belmont with Harrison consoles we have one of the developers from Harrison here today as our presenter - stunning Alessandro I'm sure some of you have met him before so he's gonna be taking us through a day of presentations and demonstrations and many projects for us to learn some more about graphics we will be recording this I've being a video recording so after the fact if you want to go back through and be able to see any of the things that will be publicly available will have several breaks throughout the day about an hour from now maybe around 10:30 and then we'll break for lunch get back together again afternoon we'll have pizza here for everybody if you want to just hang out obviously if you want to go and get some other food that's fine too I'll turn it over to Tony now and I'll let you take it away from here cool yeah so I think I've met a lot of you before from Eric's class but just reiterate I'm Tony Burke at Harrison I'm in charge of their plugins so it's a lot of C++ and juice and a lot of graphical stuff so I know Eric sent in email out the other day about the repo let's see how all of the materials are up here on my github that's lisandro aan and juice graphics workshop if you need to grab them and basically you will want to clone it myself here probably okay so you'll need to clone the repo if you don't have it already and you will need to clone juice as well which is on their github we are Rolly juice and you'll need to set this up in your home directory so whichever user you're logged in as it'll just be within that own folder does everyone have the producer needs to set that up or anything cool as long as you're the producer knows where your juice installation is you should be good it'll be in a bill of myself here yep so as long as the producer your global paths are set to be correct juice insulation all these examples are work for you cool so yeah today we're just going to be going over graphics in juice from the component kind of widget side of how you actually start laying out elements on screen to drawing with them to doing image buffers and like image caching and we also go over making your own themes and kind of being able to swap around themes for your application so the very first part of that is the components and this will be in the examples folder cool so we'll be working from the first examples folder the components in juice are basically just their base element class for any kind of UI widget so it's just a drawable element on screen it accepts user input so keyboard events Mouse events all those kind of things it has different elements to it basically like you can set its name you can set certain properties for it it has a visibility it's whether it's enabled or not and because they're on the screen they all have size and position information as well and they all maintain their own child hierarchy so once you start adding components to the screen it'll start out with a base component and you just add some components to that keep track of things that way jous includes quite a few default widgets we won't really be using them today ours kind of just goes over the basics more of like layout and some of the event handling is stuff like that but included in juice are they have their drawable classes which are kind of the most simple component they'll have like a drawable rectangle of drawable pads stuff like that and really it's mostly used in there SVG loading so you can like take a vector image and just tell juice to start rendering it but I use those sometimes when there's just simple elements you want to draw on the screen that you don't want to go in and like mess around with some whole giant paint function trying to put stuff in so those are probably the most simple ones um aside from the base class of component they include a lot of default widgets that are used for your application so the sliders buttons labels those all have callbacks so once you start actually interacting with them you can control the logic of what they actually do when the button is clicked when the sliders drag there's some more complex views usually the hierarchical views of like a tree view or a list view and those are interesting you kind of manage it in like a Model View way where the component itself doesn't do a whole lot and you have to attach a model with it that actually can controls when the component is looking for information the model will tell it here you know are the cells that you're going to show in your ListView and here's how you draw them here's what the names are so those are kind of split up a little bit and the rest are usually just containers and windows viewport is probably the main one I don't know if there are other containers but the viewport basically you just add some components to that and you can use it as like a scrolling view and zooming and all that good stuff cool so let me switch over to the first example this will be in the examples folder number one basics so if you have the pro juicer open when you click open I'll open if you select any of these header files that are in the examples they're all in juices Hiep format which basically just means there's a big comment at the top with a bunch of metadata on how to build a project so these will open up and when you go to this tab right here with the little wrench and screwdriver that is juices live build engine if it's not installed already there will be a button right here saying please install the lock build engine so you can just click that but this basically just runs clang behind the scenes and builds your Hubble project for you and once it's done building it will show all of the components that it found in a little list here cool so once it's done it'll show all the components obviously juice has a lot of them so it actually shows you the whole juice list of what's available but for our purposes we usually just only have a demo component and you can click play on that and it will pull it up into a little window and show you it and allow you to resize it so that's how we'll be running the examples for the day this first example basically just goes over I can't get that little bit that first example basically just goes over the kind of component basic API so as we said it you can set names you can set component IDs both of those are things that you can use either for drawing I like to set names and use them for drawing a lot component IDs are good if you want to be able to just have a bunch of different components of different types and be able to just reference them by the same name so every subclass of component you can access all of these properties just through that base interface yeah so if anyone has issues with the live builder that seems to be a juice problem for right now or a froze user problem but if you do have Xcode installed you can click on the little X code button up here or Visual Studio if you're on Windows and you can open it in the IDE and all of the errors will go away basically it's just within the live build engine there's a still a few problems yeah so here we gonna do what I'm going to before the actual paint routine of this component utilizes its name so we're not having to like save our own State and stuff like that for that components have enablement which I mentioned so here there's just a little commented off block of set enabled to false but if we change it to one our paint routine is checking whether or not were enabled so when we're not enabled it'll just draw in a red color instead rebuild so that's always useful for kind of conveying to a user the state of which a component can be interacted with or not for example in our plugins I think every single paint routine basically checks whether something is enabled or not to set colors darker take out any saturation basically just evoke the sense of like you can't click on this juice will do that for quite a few of the built-in components like of a slider buttons and stuff like that or not enabled they actually just draw them with a layer of transparency so it kind of gets the same effect of where you know something is different about it and the component looks darker and when you mouse over it nothing really changes you can't click on it all of that so your font larger and producer it should be I don't see where that would ya if not I might just open these you edit the color scheme area in space to put that there we go this long yeah the color okay for everyone that kind of washed out with the light or anything oh cool cool so yeah basically these just provide the base interface that you need to do anything UI related so enablement visibility all that kind of stuff here we also use every component has a property set which is basically just a big hash map so we set a property that we call greeting and we set it to the string hello world and then we can just use that later on from the paint method so down here we we grab the text of get our properties get the key that is called greeting and we make it a string and then we just concatenate all this together so the text is I am in the name with the greeting before that so we can change that take that out and now there's no more greeting so that's useful when and we'll get into this a little bit later when you're doing themes and stuff like that but you start using your own custom components if you want to still be able to access all this stuff without having to type cast back and forth all over the place the properties set is always there so you can just pass things around as long as you just use the same identifiers for everything so that's useful when you do the look and feel stuff and you're using custom components all you have to do is just say does this component have this property or not and if it does you can know that it's one of your custom components and that that property was actually set for it well like I mentioned every component has bounds this is covered in a later example but here we just set the size so our component is going to be at zero zero and since it's our root component you really won't ever have us a position for it if it's a window or something and you want to move it around on the screen you'll actually set a position or tell it where to go but for the main content that's going to be within your window usually that's just going to be at zero zero and just have a size and growth left and right so here we also do the visibility so when our components actually added to this window we can say set visible false and nothing will show up so when a component is visible that's when it will actually get painted and actually be able to receive events but if it's not visible it will not be allowed to do either those things and if it's not an able that usually won't be able to to receive events and yeah so our first paint routine is basically just that we check enabled we use that to set the background color we filled the entire bounds with this get local bounds which basically just returns that size to you with position of zero zero so that's really useful when you are painting a component or laying out a components children and you know that you're working within the relative balance of that component so you can just say we're only working within this rectangle so let's not take any position information just get local balance and then start manipulating the rectangle from there and that covers the basics of the component API we'll get into a lot more of the specifics a little bit later so component painting when juice is ready to paint things on the screen basically it just allocates a big buffer of the size that it actually needs whether that's your entire screen size or just you know one or two windows that you might have open it'll allocate that space and it'll start with the top level component usually a window or something placed directly on the desktop and we'll just traverse that child higher hierarchy of the components and start calling those paint methods and like I said each one has to be visible on the screen to actually be drawn and as it's drawn your components paint method will be called first and then the children will draw overtop of that but there's also methods to just be able to go over top of the children and kind of draw overlays or whatever you need to draw on there I use that sometimes when it's a little more cumbersome to like have extra components in the hierarchy like oh I want to draw this one little piece over top of these other things it's a little easier just to say okay I'm just gonna go and draw over the children rather than trying to like make another little component say pad on top so when you are actually painting you we trigger those events by calling the component repaint method and the most important thing to remember about the whole system since this is software rendering is that none of the painting happens synchronously so when you're actually telling a component to repaint it's really just giving a message to the operating system saying hey there is a rectangle you know this far long in this window and at some point it needs to be updated so the user can see what's going on and you can call that for just the base repaint if you call that will just repaint the whole component so the whole bounds on screen will be marked in the operating system but you can also just repaint sections of a component so if you have just little pieces that are moving around within a component and you don't need to redraw the whole thing you can just call repaint and give it a little rectangle that it has the paint basically all of these get coalesced by the operating system so at some point it will just have a big collection of rectangles that it knows are dirty and needs to be updated and it'll put all that together and say okay this is the minimum like screen size that I just need to refresh so it'll go through that and have everything draw again which in this case will tell juice hey this whole section needs to be read you're on juice we'll figure that out allocate that that pixel data for you and then request from your components you know repaint just in this region kind of thing so it's important to note too that if you start calling repaint a lot on components the OS is completely free to just DPI prioritize those calls and throw them away so if you are doing something like trying to draw some sort of dynamic display at like 60 frames a second which would be pretty common in audio software but if you're doing it on the software side of software rendering like this where it's not OpenGL not dealing with the GPU stuff like that the OS will very likely just throw away your rethink all if it knows it's getting too heavy and that there's like too much other stuff going on so and I've seen that a lot where basically if you are repainting regular regularly you will just see a huge FPS drop and if you're doing other stuff like repainting just in sections and it starts throwing stuff away for example if we had like a ball moving on screen and you wanted to repaint the old position and the new position so that it properly updates sometimes you will see one of those get thrown away so now suddenly there's a copy or three copies of that same little rectangle over because it didn't repaint the old section and it only repainted the new section so that's important to note and it's usually avoided if you use components instead of doing like one big component and trying to manage a bunch of repaint calls gets a little tricky but juice if you are using the component system handles it a little bit better but it's still something to be aware of if you're regularly repainting and that brings us to the second example Earnie question support yeah feel free to ask any questions in the slides during the examples that anytime basically it's smart enough I should be able to drag a file nope folder every phone and painting so in this example we basically just start out and you'll see this a lot in the examples we just make a component that's a square and it takes a color and when it's drawn to the screen it just fills its whole bounds with that color so we use that a lot for demos so as I mentioned paint it's called first then juice will traverse that child hierarchy and call things so here we give our size for our main component we set the color for the square here we just make it a red hue we add and make visible to the square so that's how you actually start using the child hierarchy is the components have add child add and make visible a couple different methods that basically just say I want to make this a child component and a lot of them let you do something else so in our case add and make visible we'll just always add the child set its visibility true since it starts out false and you'll have your component draw on the screen there are other ones like add and set component ID and stuff like that not used quite as much but still kind of handy when you need them so since our size is 500 by 500 we just after we add the square as a child we call center with size so it gets and calls its parent finds out what size it is finds the center of that and then just offsets it so our component square is 250 by 250 place directly in the center so here we will be drawing the background what Y is excuse me why is the center was size after that I had to make visible why would it be before that it actually has to be in that order because center would size relies on realize I'm really two things one component having a parent and to the parent having a size itself so usually in these demos I was making it like oh I'll just add all the components in the like set-asides at the end but there's a few quirks with if you just want to like set everything up from the get-go and do all the layout kind of there that sometimes you have to reorder stuff like in this case we have to set the parent size then add a child and then finally like actually start laying out the child if we want to use the center with size so it's like something you just kind of learn from the experience I mean or is it documented well it is documented oh okay usually they are pretty good about that so you should have this open volunteers in case so Center with size and there's also a set center position and stuff like that so we could have actually done that as well if we set the center position which would basically just be - 50 - 50 - you know half of our square size then that position would actually be the same once we've added it so then we could just say he's an ultimate way of doing is put that when they're fun if you want yeah exactly nicely so yeah it's all it and that's one thing to keep in mind too if especially if you do the layout like in the constructor of a component that's sometimes it's a little quirky and you like have to set up things beforehand or before everything is really on screen and and has sizes and positions but if you set a position for a component and it doesn't even have a parent and the parent doesn't even have a size the position will stay with that component once you actually added so you could just go through and set all positions up beforehand but some of them like center with size requires it to be within a parent and there's a few other ones actually that rely on kind of having that hierarchy set up already said Vallance Road - so yeah exactly yeah so if you set the bounds relatively you'll have to have a parent first and you'll want to make sure that that parent has a size because if it is the other way around and you have a lot of code there you might end up with like why is it my component showing on screen was there any visual glitch if because of it or doesn't actually have to wait until that's done before it displays or the ad the ad function should display it on the next frame right yeah and then so you have one one display and then the very next frame the change changes yeah I mean this do you see a flicker or any kind of it kind of depends um because we're setting this off in the constructor nothing ends up getting shown until the whole demo component is constructed and then juice in in our case uh when we actually click on lay okay it makes one and then it makes this whole other window around it so it makes we have a lot of components going on here like there's some extra buttons and stuff like that so the larger components are ordering these commands exactly yeah so and that's one good way to go about it usually is like do as much setup as you can within a constructor for that reason of when you want the in our case our demo component to actually be on the screen here is the state that you can expect it to have because the constructor had to go and run completely before juice was allowed to take that demo component and add it to a window or do anything else with it so sometimes like you said with the flickering and glitchyness thing sometimes you can run into that if you're doing a lot of these kind of layout or like visual changes at runtime so if you're like adding components around and doing stuff that way you can run into some weirdness I guess it depends on how much work you're doing if you're doing like a huge heavy load and you're like trying to add all these components to the screen and the OS is like we're not going to repaint that much of the screen you might run into some weirdness usually it's not too bad and using the components and not calling repaint kind of works out I haven't quite got to a point where there's been like too many things trying to be added to the screen at once that I see like weirdness of the OS starts like throwing away things and stuff like that cool so as I mentioned we basically go through we paint our main component with this blue and we use the same thing of get local bounds we reduced it a bit to just give it offset so it'll take 50 off from each side basically and then draw within that area so here we have our sky blue we have our Red Square component which is going to be drawn over that but we in our demo component override the paint over children method which basically just gives us free rein over the whole bounce of the demo component to draw overtop of the children so you can basically visualize it as like paint gets called there's an extra step like in the middle here where all of the children go through and like they get painted and their children get painted and all that and then after all that happens we can call paint over children so we paint and we draw our text over it and just shows up directly over top of the of the child and whether or not you need this really depends on what you're doing we think only use this in a couple cases where like in our multiband compressor we have an OpenGL component drawing some RTA's and some crazy stuff on the screen and it was a little cumbersome to be adding components to that so we actually use the paint over children to just align each section of the multiband compressor and draw our text over top of that so the one two three four labels and those kind of things that is me on that one I understand how we're drawing the blue rectangle and I can see where we're defining where we're gonna have our own square component but what I don't understand is where the paint happens for dice we're right so here in our square component we override the paint method and it basically ends up that we don't have to manually call paint for the child components so and I think we step through this in another example too but basically kind of wish we had debugging right here is it would be nice to show that but basically once we start drawing the demo components of the screen juice goes in and grabs us a chunk base of pixel data that's big enough to hold this and it first calls this paint function and if you were to look at the actual component code you can see the loop of like it calls paint and it passes off that context that is drawing into that that pixel data and then it just looks at every child component that that component has and it calls there's a method called paint entire component actually let me pull it up right here so this paint entire component if you were to call this it essentially does the same thing and this is what Joost calls under the hood to set everything off is that and even says you should very rarely use this method but it calls paint it has it in reverse order it says it calls paint paint over children and recursively calls but basically we start out with that paint call for our demo component then every child has this paint entire component cult and all of that is drawn on top of the original paint contents from the demo and after every child as painted its entire contents then we go in and call paint over children and we can draw over top of all of that so it's basically just a lot of layering of we start out with blue this first it's only child the square has paint entire component called and because the square doesn't have any children or anything all it has to draw the screen as a red square but if we were to add another on say we have like a square too and we make that color and if we add the square to to the square itself let's say it's 25 by 25 in the left corner you build oh no I'm not gonna like that visible visible I think I mistyped that almost every single time when I had too many eyes over them that's where it goes there we go so then we can just start adding and basically this second square this tiny little black square is only seen within that loop of the child for the paint entire component thing so it goes through Cole's paint entire components on the red square so it'll draw all of the red first and then because we're painting the entire component it needs to go through its own children and calls paint entire component for those as well so basically steps from main component paints itself we go to the first child this paints itself and I'll read go to the first child of that is faints itself and they don't have anything else to be drawn so we step all the way back out to the main component which has a paint over children method and we just drop the text over top and that goes over top of all the layers basically that we're in between that paint and paint over children method so the Adamek visible is where we are adding it to be a child of in the first case they're the main component yeah and the second case we're adding it to be a child that's weird is that exactly yeah understand that and sometimes these are all funny to read especially when you start having a lot of base classes that you're deriving from so here because we're just calling it within the constructor it's pretty much equivalent to if you said this and make visible and its people as supposed to be usually don't use like this or have like a self thing I know a lot of other languages do that it would make a lot more clearer actually if we did but basically yeah for the demo we say add the square to this and then make it visible and then later on we can just take the child we're already put in the demo and say hey square now you're gonna have a child as well that'll just be a little black square in that top-left corner I think I have Scrolls oh there any other questions about the painting loop and how all that gets called basically go into so this kind of just reiterates a lot of what we said components can have many children so you can add as many components I guess as much memory as you have there will be some sort of limit if you add you know 20 billion components or something like that but each compare each component should only have one parent at a time and that is enforced by juice so if you start adding a component sum to something else if I recall it either throws some insert assertion like it'll stop the program and tell you or it will just actually silently transfer that ownership so now it removes itself from its original parent adds it to the other parent and everything it's all good components normally cannot draw outside of their bounds and their parent bounds so when we say in our last example all of the square components basically just called fill all and that fill all was the same as if you were to say get local bounds we just grabbed the size and fill a rectangle of that size when a component is being painted the graphics context is only working within the balance of that component and will not draw outside of that and the same goes for the parent so and we cover this a little later too when you're stepping through for example in our in our blue and red square example that first region that the context is like restricted to is going to be the size of your demo and then it reduces that region to the size of the red square so when you're in the first paint call for the demo you cannot draw outside the bounds that that demo component has when you're in the second when you're in the second paint call of that Red Square you still can't draw outside the first bounce but you also can't draw outside of that red squares balance now there are some flags that you can actually just turn this off and be allowed to draw anywhere but you'll run into a lot of problems with that in regards to the repaint stuff I mentioned because when you call repaint on a component it'll still take its balance but if you disable all of this and you say like ok I'm gonna draw a square and I'm gonna draw some random thing out here outside the bounds and you repaint that random thing will not be updated so usually you just want to keep the default behavior and say every time we're drawing the code a component we are only drawing within the rectangle that encompasses that component size the other thing to note is that if you delete a component so say you keep allocate it and you just randomly call delete on it sometime later it will remove itself from the parent so you don't have to worry about like oh I deleted this component but I didn't like remove it from the parent and you know take it out of the hierarchy and everything a lot of the component stuff in juice is set up to either do this automatically for you something like you know I should remove myself from the parent if I'm being deleted or it uses reference counting so when you do delete a component there will be some sort of like weak pointer or something like that which usually you see in Java not quite as much as C++ until C++ 11 but uh usually it doesn't come down to any kind of like problem if you delete a component but like someone still is like looking at it unless you're using a row pointer basically just you know we have that square we take the address of the square and then we just hold on to that forever we don't we would have to either invalidate that pointer or something else to actually know that that is not allowed to be used anymore if we are deleting our square yeah usually you don't end up deleting components unless you have some sort of dynamic UI where there's a lot of things being added to screen that you know we're based off of some thing the user is doing like say we have a bunch of buttons that we add based on like how many tracks so user put on the timeline or something like that but even in some of the other components like the tree views and stuff that I mentioned those are dynamic but they actually don't require keep allocating a bunch of components so usually you don't have to worry too much about it unless you're you have to have some sort of dynamic setup that requires you to start allocating components for that one in this example is pretty short as well as I remember when a hierarchy one basically just goes over a little bit of what we had last time this time we have three squares same square setup as before and we have three of them red blue and green squares you set their colors same thing here we're calling center with size after we set up a size so we make the red square in the center with 250 250 we add the blue square at 125 by 125 size and 125 125 position and we add that to the Red Square so the Blue Square will be drawn within the Red Square Green Square is just a 50 by 50 thing at 0 0 and so kind of like I said we just have 3 squares if we make this Blue Square a lot bigger so suddenly this one is like 500 by 500 we do not see this rebuilds there's not gonna be any change basically because we're already offset at 120 525 you only have this much space to draw before we run into that graphics clipping thing that I mentioned before so once we're inside of this component we only have that much space to work with so if you try to draw some huge component you better either resize that smaller or make sure that it's in the right position it will just cut off the silent screen otherwise now as I mentioned before all the bounds are relative to this so this red component can be anywhere on the screen but when you were actually drawing this blue component that 125 125 will always be relative to the top left origin of its parent component and we can see that as I'm here where we take the the Green Square is normally added to the red square change this to 1 and we can see that it's added to the main component but because of 0 0 it jumps over to the actual top left of our window instead so yeah basically just to reiterate just everything is always relative to the parent so when you get into more complex layouts and stuff you just kind of always have to keep that in mind of if you want something to be shown in a specific spot on the screen everything will have to be set up in a way especially if you have like a deep hierarchy everything will have to be set up in a way that your final bounds that you're calling for example are like zero zero 50/50 bounds here you will need to make sure all the parents are in the right spot to actually get this to this specific spot within the window itself [Music] but yeah usually it doesn't come down to that sometimes in the audio realm it does a little bit a lot of they're like skeuomorphic interfaces where it just looks like an actual picture of the gear and stuff like that things are kind of in loose spots there's not like grids or any kind of that layout so sometimes you get into that where it's like everything is just one big parent and you just add stuff in and you just tweak it around until it looks like it's in the right spot on the screen and a lot of other layouts usually things are kind of grid based or have some sort of structure of like okay we're going to take this specific area split it into you know five sections and layout everything where the relative sizes and stuff like that we get into that a lot later too for now it's mostly just and positioning everything which you might run into if you are doing audio plugins that all kind of depends on the aesthetic really I guess iZotope for sure they use all kinds of crazy layout systems considering they have so much going on at screen and they have tabs and all kinds of navigation stuff there are many questions about parent hierarchies or positioning and that kind of stuff um yes if you I might actually have to check on that but I'm pretty positive that is the case where basically one you are calling delete and we can't do it here because since this is actually just allocated with that demo component it's not allocated on the heap so it wasn't made using new or anything like that but uh if we said this was like pointer to a square might have to change some stuff I think we can red square its new square [Music] it's my biggest annoyance with C++ is the arrow syntax I have to go and change every single dot to an arrow there we go so if we were to actually just run this right now we probably won't see anything because the producer doesn't have debugging but if we just close this window and let that Red Square just never be deleted juice will tell you and if you do call delete on it what ends up happening is since we're using the actual operator delete C++ the first thing that will get called is the destructor of square which in this case we don't have it would usually look something like this and we could say something you know like we're destroying the square you can do whatever you need to like actually clean up stuff but because this derives from component the destructor for the base classes it traverses back up so in the destructor of the base component class it will do any cleanup that it needs to actually handle that and I believe that it actually will not I don't think it can delete the components because it wouldn't know whether or not in our case we have the Red Square as a heap-allocated component and the rest of them are not evaluated so it won't call delete manually I'm sorry call delete automatically for you but if you were to delete the component it will handle you know not seg faulting and stuff like that like this demo component will not have a pointer laying around to the Red Square if all it had was you know we heap-allocated a square and we said I'd make visible that we delete it later the demo won't crash you know trying to paint a component that like was already deleted or something like that but the rest of it if you are keep allocating a bunch of components you will have to manage the lifetime of their memory so to speak which usually you can do with a lot of like Plus 11 and on like smart pointers like having you know unique pointers to something once that unique pointer is gone it will know to just clean up the object for you so a lot of times if people are doing dynamically allocated components like that they will just save they'll have some sort of array or just members within that parent component that they set manually that have the that smart reference to it so once those go out of scope and that parent is going away it will clean up all of his child components too and Guice offers some stuff like that to juice has been around since like 2004 so actually they have a lot of kind of redundancies with the with the C++ is more standard library so there is this own direct class that you can use if you do need the parent to actually be managing the lifetime of the children you can just have an own DeRay that every time you're adding a child you just also add it to this array and once this array goes out of scope aka the parent that has the array is deleted or goes out of scope this will go through and clean up all those objects for you but yeah just by default if you are deleting a component you will have to clean up components or any other kind of data members that you may have like EEP allocated along with it are there any other questions about that or questions about how the parent kind of manages children in that way I think this brings us to graphics so the second example folder well are there any example any cases tell me we're just using this standard classes as designed by Jews where you can end up with a memory leak just using it as design um absolutely there are actually a couple of cases that I found because there's some weirdness with how'd you lays out its API and a lot of like standard C++ stuff or I guess more modern c-plus well it's not necessarily the standard library but you will see stuff like if you are passing off an object to some sort of API or function you know me like not late finding but it will take the argument instead of just a pointer to some object will usually be like a unique pointer or like a shared pointer and they use that to basically tell you or invoke that when you're reading that documentation this is taking ownership of this object so when you hand over the pointer to you know a square or something like that our square component it is done under the knowledge that it is passing off a unique pointer so when that unique pointer is finally gone the object that you passed off will also be deleted and Guice does not do this so there's a few examples where like for example there's this positioner class with use components which really is not used that much at all but it under the hood uses kind of the same thing as a unique pointer I think it uses its own juice variety of it but when you set a positioner it will be if you have one there already it will be delete and if you just set one once and never worry about it again when that component goes away it will actually go in and delete that positioner as well but because they don't really because it was written so long ago before unique pointer and before a lot of the more modern C++ stuff it doesn't really tell you in the function signature itself that this is taking ownership of the object that you're handing off to it so this case it does and the only way that they tell you is by actually writing out on the documentation but there's other ones like this set look and feel when you send a look and feel the objects is not deleted by the component so it all kind of comes down to just having to read the documentation for every single method or crash and figure out oh something went wrong and then go through the documentation to find out what happened but usually juice will tell you as well like if you for example and I think this comes up later in our in one of our demos if you set a look and feel and you don't set the look and feel to null pointer when that component is going away so say you know our demo component we set some custom look and feel object which is not going to be owned by the component if we don't set that to null pointer when that component is being destructed juice actually just asserts on you and says like hey you shouldn't be like keeping around you know a reference to the look and feel and the components still you know being used and stuff like that there's a few quirks to it basically but it kind of comes down to just the API and whether or not they decided to make something owned or not but it does not tell you in the function signature so it's usually all up to reading the documentation so the positioner is one I believe there's a few examples like this component effect which the image effect filter class is basically just a thing that gets past an image and a graphics context and then you can just apply whatever you want to it so juice actually uses that for like drop shadow effects and doing like glow effects and stuff like that but uh when you set a component effect it takes a pointer again because it has to know like this is the one that I'm actually going to use and it doesn't make a copy of the image effect filter and it can't take a reference to it so it has to use a pointer but um it doesn't delete the object so you could have one image effect filter that's you know the global drop shadow or something and every component has a pointer to it but if you dynamically allocated that you better delete it when you're done because the components will not handle that for you so that's another one that does that but there is there's one more in here at least I know that set cached components at image will will be owned by the component so there's at least two or three cases in the component API where when you pass something in juice is deciding it will actually take ownership so it will delete that out from under you so it's just something to be aware of graphic side cool so as I mentioned highest level component that you can have is one that's directly on the desktop that will always be a window even if the window looks like it's a native window like a Mac also no kind of thing it is actually still a juice component and it just has a window that it's like controlling you can also place any kind of component directly on the desktop we can actually take the demo from before with the squares and stuff and just say stick this on the desktop and it won't have a window handle or anything it will just be the Blue Square and the Red Square just sitting right there on your desktop so as I mentioned before we go to the highest level one usually a window or something that's full screen or on the desktop paint gets called your vs. all the children paints over them if it needs to so what actually handles the buffer of pixel day that I mentioned before is the graphics context so when juice is ready to start drawing your user interface it will allocate some chunk of pixel data large enough to pull it all of it or it might even use just some buffer that already exists and it's just reusing it and what it does is passes you a graphics context that basically gives you an easy API to draw into that so all the juice graphics are vector graphics so when you're actually using all these draw calls and stuff you're working with in points of like I'm gonna draw a rectangle you know that said this position I'm gonna draw a path that draws a little squiggly line here and you don't have to go through and say you know set this pixel set this pixel and draw the whole thing out pixel by pixel you basically just pass in lists of points that get turned into path operations and way down in the graphic stack all of those paths get collected up and rasterized so juice will juice ends up doing it that way where it just goes through literally line by line and figures out okay where am i hitting a path where do I need to draw a rectangle and that's how it also handles the anti-aliasing so when it's going through line by line and you have like a smooth curve or something it knows okay I need to feather these edges out as I'm you know hitting into them so that the smooth curve is not super junky curve but actually looks smooth and continuous once it's on the screen and the important thing to note too is that juice handles their resolution aspects of your operating system for example I'm just running on like an older MacBook but the stuff that I worked on at work uses like a retina so you have a higher pixel density and the resolution is like way way bigger but all that you have to really deal with you don't really deal with pixel sizes but you just get coordinates and those coordinates and that size will map to be appropriate pixel density once it's actually going up on the screen so if I say you know draw 500 by 500 square that really means something different on my laptop versus any of these IMAX where the pixel density is like 2 or 4 times larger so the graphics class basically handles interfacing with all of that and the way it does that is the base is this juice low-level graphics context and that is the implementation specific it handles basically the implementation of doing all of that path collection rasterizing all of that putting that on the screen and you'll see them as like there's a low-level graphics context for there's the basic one which is the software renderer and that's what's used on Windows and Linux so when you're drawing on those you'll actually see the exact same image no matter what you ever take you know pixel density and resolution stuff but the same code that runs to draw graphics on Linux and juice also draws the same graphics on Windows on Mac OS you can toggle whether or not it's actually using core graphics which is Apple's own graphics class or graphics API and core graphics is basically the same way it's all just vector graphics it's a lot more powerful and a lot more expansive just because it's Apple's operating system library but um the low-level graphics context is what wraps over that so every time you're saying like draw a path and you're using core graphics it will just actually go through the low-level graphics context and that will tell core graphics hey I have a path here I need to draw on the screen it just passes it off in core cracks like those the rest for you some other implementations like you can basically do whatever you want once you have a low-level graphics context like there is one that handles really PostScript rendering or something along those lines and it's like kind of setting up vector graphics in the same way that a PDF is instructed I wrote a low-level graphics context thing that just maps back to SVG files so you can say like a draw a path then you know draw all this stuff and instead of drawing at the screen it actually just writes it out as like an SVG text document so you could like stick a one of the SVG low-level contexts in to you know some big complicated user interface that's already been designed and it'll spit out just a big SVG that is that exact thing and that was it's actually useful for we were using it a little bit at work for two things I was using it for a lot of the plugins that I started out working on reports so I would just make it look close enough to the old one and then I would actually just do the SVG thing and like tweak it around from there so it was a lot easier to design knowing that like I'm starting from this base I'm just gonna push this out and then like mess with it in Illustrator or something it's also great for screenshots if you instead of doing like a screenshot you could just have the SVG of your whole user interface and just have that in a browser or something like that but it's nice to say it's you can kind of do whatever once you have the low-level graphics context you can map all those graphic skulls to whatever you needed to actually do including them that's how juice accomplishes its OpenGL implementation as well we are in the second folder now cool so this first demo we have a square again but instead of drawing a consistent color we are going to take a random color so basically we just generate some random integers and make them un8 for the RGB values for the color and we fill an ellipse instead of a square this time so I'm actually not sure why I called it square ellipse this demo we it's basically goes over the repainting so there is a method in the component that easily lets you just toggle whether or not a component should repaint when you're doing Mouse events on it so if you enter exit the component if you click or double click on it and when you let go of the mouse if this set repaint some Mouse activity method has been set to true the component will know okay I'm going to redraw my entire contents and that's useful if it's like you don't want to go in and make you know a subclass that does all this and I should also know because it's mouse enter and mouse clicking all this this will have a lot of flashing colors so if you are sensitive to that do not go in and spam the mouse button probably should've put this on a timer actually that's like only every second nipple chain is not as fast as positive but it's basically goes over we'd roll in well okay that was strange we have found some sort of bug I wonder if that's because of my laptop being on the display or something oh that's weird but yeah basically every time you click you get a different color for both the important thing too is that if you are only clicking on the circle you will notice only the balance of this are being repainted in the circle and in the pairing so the circle only draws this ellipse but the parent is drawing the color behind there so once this component is being repainted it has to go to the parent and also say anything that is drawn behind me needs to be updated because you know in our case all of our corners are shown if you don't do that like for example if this was our regular square component and we were just filling the whole bounds obviously you can't see anything behind that component and to tell juice that that is the case you basically mark a component as opaque so if a component is opaque let's rebuild when a component is opaque you will notice that the corners are never being repainted because we are not filling these parts of the component we're only drawing that circle in the middle so it started out with the very initial color that it had which was this orange color and unless you go in and actually fill the whole mountains again that will always be there because it's just still sitting there on that screen buffer behind the scenes but if this if we were growing a square when the square itself repaints when that child componentry panes the parent doesn't have to go in and draw itself again so you'll notice this area that's behind the component doesn't have to be updated and this will actually save you a ton of work in CPU cycles basically if you are already drawing say like a meter or something where it's already a square and you can't see behind it anyway any component that that is the case for you should mark opaque simply because you don't want to be like redrawing all these background contents that you can't see anyway but yeah and that kind of exemplifies that hierarchy to where we have to go in and draw the background first then we go through the components and you're always learning our questions about that I think we were going to be moving away from component stuff now and more into the actual graphics context if anyone has any component questions or anything cool um so yeah next step is basically just moving from the component stage and kind of how the layouts are put together into the actual graphics context so as I mentioned before it's basically just a nice wrapper around drawing into a big pixel buffer using vector graphics only and it provides a lot of like helpful methods of drawing shapes so you may have seen some before like we were drawing rectangles or going to fill all drawing rectangles drawing ellipses that kind of stuff it basically gives you a bunch of those methods to just easily say I just want to show this shape on screen just set the color and like you know draw it to the screen and it provides a few like there's every fill method like fill ellipse fill square fill rounded rectangles that kind of stuff and those usually provide like an outline as well so when you're calling like fill rectangle obviously you're drawing the whole thing just within that balance there are other ones like draw rect we'll just draw an outline of a rectangle but it'll draw to those bounds so that the outline is like centered on it so if you're drawing like a 50 by 50 shape and you have like a 4 pixel wide outline it will actually stretch out to 52 and 48 since that outline is on the center so and we kind of get into that a little later when you're drawing outlines you like always have to account for that and it gets a little annoying because you always have to like shrink everything a little bit make it fit into the size and that kind of stuff the graphics class I should know it does not allow you to combine multiple shapes so um every time you're throwing a shape it's basically one graphics call drawl rect draw ellipse but you can't say like add a star a rectangle and a circle and then draw all of that at once this kind of thing and we'll get into that later it's actually the path class so example 2 2 from the folder sweet is growing the simple shapes and basically we just go through and it's just an example of everything that it has to offer so we get a nice little 80s looking kind of thing that just has in the background they have a checkerboard so if you just easily want to say like I just want you know 10 pixel wide checkers in dark gray and gray cross my whole component we didn't just do that with one call so you don't have to manually go in and say draw a rectangle here and then move over and draw one here move over again except the colors back and forth and it managed manages this through rectangle lists which is another juice glass we kind of go over these where juice has some geometry related classes like the rectangle point lines that kind of stuff rectangle list is one of them where you can just add a bunch of rectangles and make a complex shape out of it so if you add one and you have like rectangles that like stick out of the side or something it basically just has all of those and it will coalesce them and it'll know the full size that it takes to draw that but you can pass it off to the graphics context to say like I want to set red and like draw all of these rectangles at once and this checkerboard one is even more simple example of that where it's just just a big list of tiny little gray and dark grey squares that it girls over and over again so that basically just this has the examples of it we set our red color again and we fill this little rectangle at 50/50 and it's 50/50 size we fill an ellipse down here that's pale goldenrod color we draw a line from our top left to the bottom right of the main component so actually if you take the little resizer here and move it around this line will always be within you know from here all the way down to here is two struts diagonally across since we're repainting all the time and it's important to note that the graphics class is stateful so that any time you need to do stuff you have to set all this up beforehand and then make the call so here we are setting our color to red then drawing the rectangle so we're actually committing that rectangle to screen in the regular you can't necessarily do things where it's like I want to save some sort of shape and it has like all of these attributes like color and outline and font or anything like that it's always the case where you have to set up the graphic state right then and then make a call and your state is then preserved after that so if we were to take out you know this goldenrod color rebuild we basically just keep the same color until we actually call set color again yeah then we take we can draw arrows which there's a little arrow over here probably put in different colors it's hard to see so there's nice things like that where if you just want to draw an arrow and you know how big you want that arrow had to be and how long the arrow is and all that stuff you can just make one call pass off the line that you want and then pass off the size information and each of these you basically just have to will read the documentation for each sometimes gets into like this draw arrow one is a little long because we don't have named arguments or anything and C++ so usually I end up like writing comments or like other kind of stuff or something like that there are some where it's like I think when you're drawing like rounded rectangles that have an outline there's like ten arguments or something for the function so it's usually nice to set that up in like structs just make like some custom struts and use those so you can actually keep the names in line with the function and know each one is doing or comment and stuff like that cool so each one of these as I said before these first two are fill methods so we're actually gonna draw the full shape lines you can't really fill a line it's always gonna be an outline so that one's a draw call drawn line draw arrow is kinda the same way it's technically not you know it's filling that that triangle but down here we actually have the draw rectangle and draw ellipse goals and those will be just drawing the outlines so we draw this rectangle and it just draws it in a little thin outline we draw an ellipse it draws it with a two pixel wide outline that's that last argument here you can change it to something like 20 and we see this is larger but I should note again that the bounds of it will actually be like this will be aligned big year so the bottom of our rectangle and the sides of it will be within the outline so you always have to account for like how thick is the outline and how much do I need to inset something if I want to keep it within this rectangle instead of you know the actual one that we have are there any questions about that drawing shapes and stuff like that yeah so same kind of thing when we resize we will only it will only commit to screen what we actually have within the art club correct thing it's good Co although it is one more apparently so yeah and it actually will one thing I should note is that it will still draw the full shape it will not rasterize the full shape but it will make the call so if you have like some crazy compound complex shape that's going on over here it being outside of the region that we're actually drawing to doesn't save you from all that overhead of still making the shape and like sending it off and having it being up having the path being traversed and all of that but it will save you from the rasterized step but not entirely I think it still will go through and actually flatten that path out and figure out like here's the full shape that will be drawn to screen it just doesn't get drawn the screen so it's doing a lot of extra work for um Oh for nothing if he was that question was getting out the question was fully resizable windows what's stuck in my mind with juice was some examples online where was about three lines of code for each of your children and grandchildren and you can get your parents eyes and you could resize everything inside to match your parents size and have a quote truly resizable window including text if you just add these lines of code where the size of your your object or size of your text is multiplied by this number and this number is your current size over your parents eyes on x and y and anyway there were some examples of doing truly resize both windows like you'd expect and maybe a browse or something like that but you have to add you know three four lines of code from each of your children to do that exactly yeah can be done it ends up being and there's a few ways to go about it too but usually like for example the the line because it's always taking into account the bounds of life we got to get our top left which is always gonna be zero zero in this case in the bottom right that will always work but all the rest of these are hard-coded so if we wanted to say like okay we know our main window is always 500 by 500 that's our default size if we go lower than that say it's you know 250 250 we will want to take other positions and the sizes of all of these other objects and shrink that down so they actually fit within that know some easy easier ways to do that that we get into I've handled this in both of those ways because all of our plugins allow resizing not by dragging but there's like a little menu that you just go in and say smaller and it'll just shrink it by 10 20 percent or something like that but yeah it all comes down to whether or not you will have a static interface like I mentioned a lot of those scheme Orphic plugins where it's just like you know a big la-2a or something on the screen you usually can't resize resizing doesn't always work for every role and plugins I'll just put that out there right now because I ran into a lot of annoying things were like sometimes it'll work completely fine like and quite a few dolls it works ok like logic I've never had problems with play tools it actually does work but Pro Tools has I've had weird things were like the sides of the window or that like tool bar that Pro Tools puts in the plugin window for you like that will just turn black or like disappear for some reason so a lot of these dolls I guess they set them up to not expect like resizable windows and of course you get into something like Reaper is probably the worst because they have the container window and if you start moving that like it doesn't actually resize anything and if you do your own resizing that container window just goes crazy on you every time so usually when talking about plugins it's pretty static unless you go that route of like it's a menu option and you just shrink it by each size and if you're doing that actually then going through and just knowing your multiplier ahead of time it's really easy because you can just say like you know we shrunk it by half so now it's only half the size so we can just apply that to like all of our drawing operations with that number that we've already used for setting the size we have all of these examples I think it gets into it a little bit later of relative sizes and then later than that we go into like layouts and you can do affine transforms which will change the actual contents of the graphics context according to like a matrix anyone else have questions about graphics context that face level I think we're gonna get into the whole state setting thing next up switch back here so as I mentioned graphics context only lets you do simple shapes to do more complex shapes it boils down to using juices paths glass which is basically just points that all connect so you can connect them via lines they can be Bezier curves like a cubic curve or quadratic that kind of stuff and really everything induced boils down to using this so when you call Phil rect it will actually construct a path object for you that is a rectangle and then pass it along so those simple calls basically abstract over that where you want to draw a rectangle on the screen or an ellipse instead of making a path object setting you know adding an ellipse to it or adding a rectangle to it and then passing it off to the graphics context you can just do that all in one call but if you need to actually get into more complex shapes especially drawing like curves or anything like that you have to use the path context path class itself and start setting that whole layout out of here are my points here is how they get connected you know here are the control points for like my curves and stuff like that and it's important to note it can be allocated outside of the graphics context so you don't have to you just make a path class whenever since it's not tied to using a graphics context or using an image or anything like that so if you're doing like complex shapes you can save a lot of work by just having a path like inside of your class or allocated off somewhere set up the whole path beforehand and then just when you're ready to draw it to the screen just pass it off to the graphics context so you're not like creating a path every time creating this big list of points and like having to allocate those every single time and the path cut the path class actually works a little bit like juices array interface where you can ensure that it has a set amount of storage so you can say beforehand like I know I'm going to draw some crazy kind of FFT shape or something and it's gonna have like you know 2,000 points or something you can tell the graph you can tell this path class that it should ensure enough size to hold 2,000 points and then you can just start adding them instead of adding one you know adding a couple more the array suddenly realizes it's not big enough then it has to like allocate more data you run into that same thing again where it's like you keep adding them in a loop but the array doesn't know that you're actually one saying mm um so you can set up that mm beforehand and and then just run the loop and add them all in and keep that off line so you don't have to keep doing all of that work every time you're amazing the path also provides I guess not provides it's really just next to the path is a path stroke type class which really just has properties for defining how you want an outline to be drawn so the outline size is one thing but there's also the endcap style of once it gets to the end point is it stopping right there at the point is it drawing like a but to the point where there's it extends you know the size of the outline that much further away or is it rounded so it kind of rounds out at the point and then there's the joint types of like when there is a sharp curve or a sharp change in direction basically is it just going to be that sharp point will it be beveled off so it will hit that flatten out and then go back down or will be rounded so when you draw it it's just is a slightly rounding to give it nicer shape and usually I end up using rounded on everything it kind of just depends on what you need it for and what exactly you're drawing as to whether or not you have to deal with like the path stroke type stuff too often so in the next example here complex paths pretty much the same thing as before we're just drawing shapes but we make a path class at the start of our paint I've included all the links basically that point to like if you're drawing a type of shape like you want to draw a right triangle this is the exact method that is in the documentation for it so we go through and basically just add those kind of shapes so we have a triangle a star we draw our own little curve right here and we actually use the path to draw the background as well so our first use of the path is that we add this rectangle that's just this pink square a little bit reduced and we call fill path but we have to clear the path after we use it because we will be adding more points to it so if we were to not clear the path just comment it out basically and up with not what you want so it will actually still draw the outlines correctly because it knows where all the points are so we still have a rectangle we still have the lines we still have the star and everything but uh the fill of it it doesn't quite know what to do with because you have points that are like inside of this shape so is it supposed to draw like nothing in here or does it draw here in our case we actually fill it twice cuz yeah I guess we're still calling fill so it fills it once over with the pink and then it goes over again and it's like okay well I have a rectangle all the way here and some shapes inside so I'll just fill the whole rectangle with white so we see everything in white and then just only the outlines end up coming through since they don't overlap on top of each other but those fills we'll mess it up if you don't clear the path so I usually do that like if I'm going to be drawing a bunch of shapes that do use the paths I'll just make one path object at the top so I can just always say you know I'm using path that I don't have to have a bunch of variable names to remember it but anytime you start swapping around and changing shapes you're going to have to clear out the points that you are already using basically so we clear it out then we add a star here we go down and we add the triangle by actually just doing our own line segments so if you are going to go through and say like I want to draw some lines that you know encompass this area or something you have to start a sub path for that and that's essentially what we're missing when we were not calling clear going straight from the rectangle to other shapes it will start the sub path for you but it's going to all be within the same shape so we start a sub path over here and it's actually still part of the same path object as this star but because it started over here we don't have to connect any lines we don't have anything going on that's kind of weird like that if you were to not start the sub path and you said like made a bunch of line to calls down here and you drew some triangle here and then you said line two up to here it would actually connect that all the way across so you always have to start sub paths with where you want to start of that draw your shape and then close the sub path and a good example of not closing the sub path is in this curve right here we start our sub path at 200 200 and we right now we're using the quadratic curve which just has one control point so we have our starting path and we have like some control point over here and juice will do like a Bezier curve based on that control point so it'll round this out according to that but we don't actually close the sub path and as you can see the fill will actually go back and like figure out okay what was the path that what was the last point that I'm supposed to go back to so the fill will go back and draw that but if you don't close the sub path and start outlining things it will only outline from the points that you defined to the and points so if you're not closing your subpath you're gonna have like an open outline like on this as opposed to here where we closed it the whole shape fills in and the whole outline draws and obviously if you use any of the shape methods it'll do the whole sub mapping for you automatically so juice basically offers those two kind of Bezier curves so we have the quadratic two method which uses one control point and our cubic two method uses two so we have one control point that's like pulling this shape out here and another one that's like pulling it out this way so we can draw it through and basically you'll get into winding modes for the paths and which is how it determines its fill shape so here like the default is if you're crossing over we will fill it in this way and once you cross over its gonna go back over this way and you basically just have to end up knowing like if you want this to work out correctly you have to have your geometry correct for that or you get into using winding moments which determines basically just the algorithm of like how it figures out what is the filled in part of the shape versus what you know is everything else outside of that so we call fill path to draw our shapes in white and we have our path stroke type which always has to take arguments in its constructors I remember correctly and it just has the outline and like I mentioned before there's a joint style type that has which is either metered curved or bevel and the endcap style which is as I said before but square around it so yeah it always has to have some sort of argument so usually you're just constructing it with light but the thickness and then you can explicitly say like set joint style our joint style is curved set end style her in silence rounded change this another end style and probably will need to make this a lot bigger to actually see this genius cool so here we have the InStyle of but we go back to rounded over here miles you will see that this rounds out and it will extend pass to the end point so based on the size of your outline using the the square or the rounded end caps let's go back to the square will extend past it there we go so here our square will actually go past it so it will not end exactly on that point whereas the button one will have curved joint styles we can also use meter which basically you're just gonna have sharp edges to each kind of sharp joint and the other one was beveled which will cut them off basically so when we have our beveled edges it just chops off the points for the star so you really don't have like overshoot it's kind of like the butt end cap style but just for joint pads and you also see it works on the outside and star and on the inside of the star as well since we have the sharp joints going that thing there any questions about pads and all that kind of stuff as your curves and outlines [Music] to fill types this one's pretty straightforward you just have these methods of set kill type and the more simple ones of set colors that gradient fill or set tiled image fill so you're either filling something in with one solid color you're defining a color gradient which is just a list of colors and two points that get mapped out or an image which just gets tiled based on the size of the image and on top of the fill type you have the opacity of it so once you set a fill and you can set the opacity just for that fill so once you call graphics send opacity say we set the color to red and then we call this with 0.5 it's essentially the same as if you just called set color with red you know with alpha of 0.5 so that's really if you're using like tiled images or like gradients and you want to actually just apply that because otherwise you can just pass a color with an alpha the more useful thing is and Guice uses this as I mentioned before begin transparency layer and transparency layer and Juicy's is this for a lot of its built-in components like sliders and stuff when the component is disabled so it will actually just say if we're not enabled it'll begin some transparency layer then draw everything and then end it so that the disabled component appears lighter and appears like it's not able to be clicked on because it's semi-transparent and usually you'll see that a lot in more modern you guys because juice kind of goes along with that aesthetic works like minimal so we can just call like these layers of like just fade out the component a little bit to make it appear transparent and not clickable this example is super short basically just have two rectangles one of them we fill in with sky-blue color the other one we set up a gradient for as I mentioned the gradient is basically just a list of colors with two points so it will when you pass the gradient off to the graphics class those two points have to be relative to where you're working with so in our case we use the second rectangles top left and the bottom right to define where our gradient will start in it and then we just go through and add new colors ROYGBIV and we add it based on how many colors we're using which is 6 since you know we're starting at an offset of zero so we say red orange yellow green blue all of those are split up into equal parts and it will draw the gradient across the rectangle linearly and if you want it to be the case where it's drawing those as like rings of color you can change the radial property so it will actually just figure out the size and then draw ellipses using the colors so we can fade out a circle from red to yellow to orange green blue violet yeah we don't go over the image stuff in here because it's actually a bit later but that would be the other one is you could say fill an image tile say you have like some tiny image sets like that 50 by 50 it'll take the size of that and just figure out okay I need to place this many copies of the image you know to fit this rectangle but that is for later and all of these basically map out too there is the fill type class which really just wraps around this and this is how the graphics context like when its storing its state it uses the fill type itself because the fill type associates like this is a solid color fill or this is a gradient fill and that kind of stuff so it's not like keeping a copy of like we have a color we have a gradient we have an image that might be there it just has all of those saved in like a fill type it'll just save the fill type itself but you know usually you don't have to use the fill type you can use it if you want to transform it with an affine transform so if you have an image or you have a gradient you can apply some sort of transformation to the fill type and change it but usually you're just working with the methods I mentioned before of like you know set color set gradient fill or set tiled image fill yep brings us to text so in the most basic methods you can just give juice a string some sort of balance and some sort of justification setting which they have their own class to define those and it will draw the text on screen for you and how it ends up doing that is all based around the font the typeface that it's using it will take those typefaces figure out what the characters are that you're actually trying to draw convert them to paths and pass it all down to the low-level context to actually be rasterized and it'll do all that layout the kerning and figure out the actual placement of each glyph within the text so you don't really have to deal with that yourself you can if you want but I would not recommend it that is not fun at all but you should make sure that the area are drawing to will be big enough to fit into the text that will be wide enough if you're just using draw text or drawl fit in text and there's kind of methods there's also methods to draw multi-line text so you can just say like I'm going to draw a couple lines you know going outwards and down and you will have to make sure that then it's wide enough to fit your minimum line length of line width and tall enough to fit how many lines you're actually storing based on that font height so the font class basically just provides access to the site faces that I mentioned the typeface wraps around the operating system level of handling all of that so and every typeface really when you're using like OTF TTFN fonts and all that kind of stuff are already basically vector graphics so fonts are just the same kind of thing you're just defining these are the points and I'm gonna draw them out but yeah if you're making custom fonts you will have to pass off like your own typeface pointer so you're gonna be using create systems phase four which basically amounts to like within the producer you can just add the font object or the font file itself to the project and it will put it into binary data which really all that is is just it takes all of the bytes and writes them a giant array and then puts that in your actual source code so you can actually use that then to say like oh okay I want to make a new font of my own custom type when my application starts up I'm gonna have like a static typeface and it's gonna be created from you know binary data you know my font OTF and the pointer to that data and the size of the data and the typeface will be created if it can read that font obviously and then you can actually just start using that with a font class so you can make a font object if you have a typeface pointer or if you just have the name of the font or anything else that juice can resolve the actual connection with so usually it's using and our plugins we do the custom fonts so it's always a typeface and we basically just have a bunch of static fonts that like if you want the regular font of you know the Harrison font or whatever or the bold font you can just say like Harrison fonts regular and it's a static object so it'll always be there in your binary available to you but if you're gonna be using if you're doing something like a code editor or something which the producer offers and you're gonna be swapping out fonts you'll have to use chooses classes for actually reading what fonts are installed on the system and those will just be given to you as strings and if you want to change fonts you have to tell it the typeface name that you're trying to pick and it'll go and resolve that and figure out what actual font file has to read same thing with styles if you have like some sort of font and it has some style name attached with it or something you can change to that style by passing the style string which is also available from the font class itself yeah and it'll manage sighs so when you have a font you can like set the font height you can adjust the kerning of it you can set the typeface in style you can say whether it's bold or italicized or underlined and all that and once it's actually drawn to the screen is when all of that results and use will figure out what it needs to do to actually grow an underline or use the bolded version of the Fallen text with your all things laying out your own characters as I said don't do this it's a nightmare but if you absolutely have to for some reason the easiest is probably going to be if you're doing some sort of like multi font and color layout like say you have and we actually do this in the example to say you have some text that is like we're drawing here and it's in a certain font and then just in the middle of the sentence we switched to another font and switch to another color and a different style and everything you can do that with the attributed string pretty easily because it just Maps it all to methods where you're gonna say add some text add it with this color add it with this font and it just saves that range of text using that information and when it needs to actually get drawn to the screen then the attributed string in the text layout classes handle that for you where it's like okay we have this size area that we're working within and our first range of the text is a 12-point font it's in a white color it's not bold or anything it'll draw that moves on to the next range figures out like the actual placement and everything letting out your own characters is possible if you need to know how long your string is gonna be you can use get string with so if you need to basically find out the area that you're working with after you already have your text and your sides and set it the other way around then you can use get string with and like say when you're growing the text I'm gonna draw up with this width that definitely will encompass that do not use glyph arrangement it is a nightmare but if you absolutely have to that's how we did in hack audio UI library there's like kind of the latex style stuff where you can write math equations and it'll do like subscript and superscript and fractions and stuff and that is how that was achieved with the glyph arrangement over a very long time text laying out basically just going through the basic text stuff so we keep our bounds up at the top we fill our background since we're drawing white text we don't want it on a white background we get the local bounds and we're gonna say we are going to take chunks of 25 pixels tall to draw each line of text for now so it'll be the full width with just 25 play and we draw our first one white smoke color font size 24 we just draw some text we can say hello world we give it the bounds that we're working with and we say centered left is our justification and the justification class basically just offers it's just essentially an enum of you know left centered left top right any kind of positioning that you want to do justified you know bottom centre and all that kind of stuff it's just within that class and you just pass off these values so the graduates class knows how to do that layout so each time we draw the text we're going to translate the bounds a little bit so that we can just shift it downwards that's part of the rectangle class here we draw get processed crash segmentation fault that's not good so we draw some fitted text which is gonna be way too long and we're only working within 25 tall and this long and it's only going to be on one line so it goes past the bounds juice realizes that and it draws in the little ellipses for us it also squishes the text as well so there's a few arguments to that the first one is going to be the string so basically here we just draw our full string super long or ghost text and a cool thing to note because this is really handy if you place string literals next to each other in C++ it'll just concatenate all them together so you don't have to say like I'm making a string and then I want to add to it with this line and I want to add to it again you know because otherwise this whole line would like go so far off your code and it would be hard to read so we can just do that by saying like okay we're just going to add all these put a space at the end it'll concatenate it for us so we have one huge sentence filled in the bounds centered left this second last argument is how many lines we wanted to have and it's only going to be the draw fated text class method will let you do multi-line text but only if you're inserting new lines into that text itself and since we're not doing that when these concatenate it'll just take this and add it here it doesn't actually put a new line even though we have it down here because we don't have any new lines we're only going to use one line anyway and then the very last value is that horizontal scaling well if you didn't have a ASCII carriage return and asking you line feed what what would it do it would I mean embedded in the text yeah it would probably not show at all because it won't give you any hints if it goes vertically off like it did with the ellipses on the right side so it'll try and draw that lower actually oh what's bowing in there I'm not sure if it keeps it to the bouncer okay so it will not only stick to the bounce you're working with and interestingly enough it actually and I don't use this very often if I'm drawing multi-line text I usually fit it out in a different way because trying to just use the drawl fitted text method is all clunky but um yeah it actually drew it fit all of it lengthwise for the first sentence but it shifted all of it up and then it tried to fit everything else like down here so usually there are some things for like drawing multi-line text and setting out the bounds for that and making that a little easier or using the text layout stuff it's even easier than that but um yeah if I'm working with multi-line texts that usually go for those methods but when it's on one line we can adjust whether or not it's actually going to squish down so before we got to the word window before our ellipses came up but here we're going to say do not want this to squish at all so it's it's always going to be you know 100% full width for the characters so how long world is going to be the same length as the original one because it still fits and it will just write as much as it can until it runs out of room and then it'll figure out you know how much room do I have left to at least put the ellipses in and let the user know the text doesn't fit down a little bit more here we use the multi-line text and rather than writing it using new lines and stuff this is just a quick example of C++ for all strings which basically anything you write in between these delimiter x' which will be our parenthesis parenthesis or sorry our quote quote then the parenthesis and then it ends at the parenthesis the quote quote the entire thing including new lines or anything we written in so if you actually had like tap characters and stuff - it'll just write all that in these quotes are really for like you can say something in the middle of it like if we're inserting Python code or something you can put that in there and some editors will actually pick up on that and then like do syntax highlighting within that role string which is pretty nice I used this a lot before if you ever get into OpenGL stuff when you're writing Open GL shaders I just put them as their own files but they're within a raw string and then I just hard include that file into my C code when I actually want to use the shader so that way I can keep the file separate and not have to do like embedding or anything I can just include it when I want to use it and in it's all in a rolf string but it still actually syntax highlights everything properly for me so here we have hello world and we have an implicit new line because we actually move to a new line in the raw string and we say this is the multi-line text pretty cool we draw it and when you're drawing the multi-line text instead of good to the graphics class I can spell graphics correct so before we were passing bounds like down here in this draw text method you pass like I have an X Y and a width and a height that makes up my rectangle and that's all fine but in certain other cases like this draw multi-line text you give it a start X and you actually give it a baseline Y and that baseline is going to be the bottom of your text so if you have like hello world actually what's a better example of a y in this one like if we say pretty cool the bottom of all of these characters up into the Y is the baseline the Y extends past that but you basically have to align it to say here is my starting Y position with the height of the font that I'm using and that's my baseline so I actually don't use these quite often because it gets kind of annoying to format all that so for here it's like I wanted to draw this and I had to get the Y of the bounds I was using and then like get my font and then give it a night and then you basically just give it like how long do you want the maximum line width to be so we could say this is something short like 50 and it'll chop off some of our text without the color yeah so with a with a line maximum line width of 50 we've only fit chunks of each were days so it'll just like split it up and put them on two different lines so if you're using the multi-line text and you really want it to be multi-line like in our first example you have to figure out exactly how you're gonna fit that on the screen otherwise if you're using like a maximum line with it's don't work it just depends on what it's what you're using it for but um you'll just have to figure out like okay this is how much space I have allotted for all this text so we give this a big offset we move it down hundred thirty and the rest just basically shows we can get the font we can make it bolded we can get the font again we can make it italicize get the font make it underlined which it does not have a underlined method there are certain ones like underlined where if you want that style you have to actually pass the style flag so we have to say font with style underline it'll draw or underline text and finally go over the attributed string stuff so here's that example where in one draw call we can draw text that's at a regular font make it smaller make it the regular size again but then draw it in two different colors all within one strength so each time we basically append some text to the attributed string and it works a little bit like the graphics context where whatever settings you're giving it once you start out it will keep those settings until you actually change them so here we draw the first line the 24 point font and it's in a white color it will keep the white color for the second line of text but when we change the font we don't actually change that and then to get back to the red text with the same with the original font we have to go back to 24 and change the color and then change the color again and it keeps the 24 size and instead of passing it to the graphics class it's the other way around where you have to call draw method on the attributed string and you've given the graphics class context and the fountains that you actually are working with so it will go through figure out the layout and then make these for all calls like in a loop basically okay we're gonna draw like this line in text then we shrink it down and draw it across here then we change the colors that mean it what is the attribute string got a draw method the second argument pals thought to float was no argument what sort of what is the to float there's no argument right so there's a little bit of a disconnect in juices API right now and actually they are changing this later but certain methods like before we pass the bounds like to this draw draw text call and it's all started with a integer rectangle so the rectangle class is a c++ a templated class and when you have a rectangle that's an integer if you need one that is a float instead of having to do like let's see instead of having to do like balance you know get exes and like cast that to a flute and like that kind of stuff Jews basically just added a to flip method of the rectangle class so that no matter what the type is whether it's an int or like you end date or something or even if it is float or double it'll just return a rectangle of float type with all of its members cast it as a float and that is basically used in all of the vector oriented graphics methods so in the text usually it will just take a an integer bounce and like map that across but the attributed string will actually take a floating-point rectangle even though it is still working in the text with the text classes so it ends up using like in bounds anyway but there are certain cases like that a better example is that all of the path classes take a floating point rectangle because you can draw you know path points anywhere on the screen at like they don't have to be on pixel boundaries essentially you could put a point that's that like one and a half pixels wide so the attributed string does the same thing where if you're laying out that text it doesn't have to be on integer boundaries it can be like you know 500 point 5 Y or something like that and it'll figure out how it needs to stretch that sounds like fit bet so you said it's changing are they gonna go to make everything float that's what they want to do and the reason is because everything in juice is already vector I don't know if it was just no what do you thought of it or something but yeah like everything will conceptually pixel to pixel so it's an integer but I mean I'm the underneath that everything explodes so exactly so at the very last step before rasterizing so as I mentioned before juice offers affine transforms so you can apply matrix transformations to most anything not every call will accept them but a lot of places where you end up growing things will let you add an additional transform you can also just add one straight to the graphics context itself so if you want to say you know rotate everything by 45 degrees or something you can just add that to the graphics context and then it'll drop everything rotate it from that point on that can get a little bit cumbersome if you want to just if you're doing something like drawing an image and you only want the image rotated that would be a little bit overkill because once you add that transform to the graphics context it's basically there until you reset the graphics context and state so and that basically is what I mean when transforms can be stacked every time you're adding one to the graphics context itself that's applied to the previous one from before so if you rotate and then you say okay now I'll set you know out of context transform that is scaling it'll be scaled and rotated and it'll just keep stacking until you actually like reset the graphics state and go back to just a transform that has nothing applied so the types that can take it usually like paths and images you can draw them when you make that like fill path call I believe it actually will take an affine transform yeah so there's optional affine transform in a lot of calls like filling paths drawing images that kind of stuff but you can also actually just apply it to the path before you use it at all so the path glass has like a add transform method and stuff like that so you can just say take all of my points and transform them in this way and then from that point on the path is always transformed if you just pass the path off to the graphics context and give it a transform as well the original path is not modified but it's still transformed so once it's done drawing that your path is still the same but it was drawn to screen using a different transform so you can just do that easily without having to say like oh why trance i rotated the path and I want to draw it oh but now I got to rotate it back if I'm using it somewhere else or something and I want it to not be rotated so a lot of the graphics methods will let you supply and transform with that and just easily say like just this draw call just rotate this thing just walk back over we just have a basic example of rotating so same kind of thing we start out by actually setting the origin of the graphics context so usually the origin just starts out at 0 0 and it doesn't really change it'll change with each component so when you say like okay I have a child component that's in the middle of the screen it'll clip the rectangle region to that child but it also will move the origin for you and then move it back when it's done but usually you don't have to move the origin around yourself but we do it here just to demonstrate the whole stack find transform features so we move it to 100 100 so when we draw this rectangle that is at 0 0 really we're starting out at 100 100 so we have a red rectangle here and we say okay we're going to rotate the graphics context itself by 5 by 7 and then we're gonna draw the same rectangle again at 0 0 with size 100 100 and this is rotated about this way because the entire context is rotated at this point so when you're actually drawing anything your origin will still be here but it's as if your balance like I moved from here to like we rotate it so everything is going to be rotated from that point on so we draw our rectangle again and it is rotated around and then we move on to this violent rectangle and what we do is we actually add a translation transform to the context so we're going to say that we're removing the wreck tank are moving the graphics context as a whole by 100/100 and what that ends up with is that we move so if we were rotated we would be moving 100 100 but we are rotated so we're moving 100 this way and 100 this way and then we draw another 100 by 100 square in violet right there so every operation that you do is going to be stacked and applied to the entire context as a whole so anything that you do from that point on is just you always have to know that like okay it's going to be having rotations applied and translations but it's only after you apply them so we can draw this red rectangle without any transformation only draw this with rotation draw this with rotation and translation and it just keeps stacking on from there and then we use the scale transformation so we scale it down by half each way so when we draw it again we're gonna draw it that same origin moved over rotate in and move it over 100 100 but we're only drawing within 1/2 of the size that we were drawing before so everything in the context will be shrink after you transformation so we draw our rectangle again at 100 100 but it's only going to show up at 50 by 50 and finally we just take the last one and we shear it across so we use a 300% here for the x-coordinate so it'll just basically take all of that that's if you took all the X positions and just kind of okay so I guess we left off right before the first example so this will be in third for first file so this one involves a little more stuff just because we have to get the image into there but it's basically just wrong an image so we have an image that we're gonna keep inside of our demo component whoa some weird color stuff going on it was very strange yeah so we need to get the image and actually load it from disk in this case so we use juices built in just filechooser component which I included the documentation for here because there's quite a few things that it can do but here we just give it a title to open an image the default it's just going to not have any folder or anything open you basically can tell it like you want to open you know the users pictures directory or something like that and our file wild card allows for PNG files or JPEGs so then we use the file chooser and we ask the user to browse for a single file to open and if it turns true it means that they actually pick the file otherwise you can hit cancel and it just won't take anything for you and so the file chooser we can get a result and that just has one of the juice file objects which is basically just a path on disk that you can call methods to like know whether it exists or read the contents of it and that kind of stuff and to load a file from disk we have to use this image cache class which usually is used for like you can save a cache of images that it will keep it around as long as there if it's if it's being used frequently it will keep it around so for example if you are only calling or only creating an image object in your paint method this you can set like the timeout to keep it around for like five seconds so if you're if you're repainting pretty often and you're not keeping like an image object alive for that time like if it's only used in the repaint function the image cache will just keep another image object so that reference count is still above zero and it'll keep that actual data allocated for you in this case we use it to load the image from a file and we assigned our selected image which is a member of our main as the result of that so if it is a valid PNG or JPEG file and not corrupted we should get an image in if it can't be loaded the image will not be valid so here we check whether it actually loaded or not so we can set the size according to that so if it is valid we're gonna get the width and the height of the image and actually set our component size to that otherwise we're just going to set it to 500 and if it's not valid we will not be drawing it otherwise we're just going to use this draw image act call which you basically just give it the image and then give it position and it will draw from that position the full balance of the image assuming it fits into your graphics context so as soon as we hit play here because it's in our constructor the file chooser opens up in the top level of the auditory I put the juice logo in so we can go and look at that file up and there it is on the screen but I like how they they don't make the demo and no big enough apparently but it does fit in the so yeah you can load just images off disk like this like I mentioned before with fonts you can actually just take an image and put it into your juice project and it will include it as binary data so it will just write the full like array of bytes into the source code and then you can just start using that array anywhere in your source code so that would be about the same thing I think the difference would be juice image cache get from memory I believe so you can load files from memory or from off of a disk anything like that so yeah we in the correct format RGB in this case if you are actually writing out an image you're reading in specific images like an case it knew that it was a PNG and Mike handled all that for us but if you actually want to write out images they have these format classes from image file format mmm so this will actually know like it has to implement what kind of file extension that it might have like in the case of JPEG it can be JPEG within a year jpg kind of thing I think even JPEG 2000 files are covered under that so I said the format name and it will know the extension that it might have and then it will actually you can decode the file once you've loaded into memory and pass it off to one of these so if you have a PNG file and it's properly formatted you can pass it to a PNG file image format and it will be able to decode the image and actually get you an image from the PNG file well yeah if you had it the other way around where you're starting from an image and you're already drawing something and you want to save it out as a PNG it'd be basically this you give it an output stream that it has to write to and it will tell you whether or not it successfully wrote that so it could be an output stream in memory it could be a file somewhere on the user's computer or something but yeah usually you don't end up writing files out there especially images in juice I mean it's all audio software mostly I've done that for some stuff if I like want to just save the actual graphics out it was we used it a lot actually for like the screenshot stuff I mentioned with the SVG if we wanted like image files I put in a little thing in the settings menu during debug build so you can just like take the whole contents of the window and line thump it out to a PNG and then just send it off to you know the marketing guys or whatever so that's that stuff - sometimes useful when it's like oh I don't wanna sit there and like take screenshots and like drop it into the right area and stuff like that yeah okay so if you're making like an image editor or something that would be a very crucial part of your so that kids listen to image buffers as noted in the last example the image object itself was a part of the it was a member of the demo class so that's going to be kept around whether we're drawing to the screen currently or not and this can be useful if you are doing more complex graphics that you only want to update every so often or something that you know you might need to fill out this graphic these graphics beforehand and you draw up to the screen at some point later you basically can just keep the image buffer around and draw into it whenever you want by making a graphics context using it and then later on when you actually want to show it to the user in your paint method you can just pass it off to the paint graphics context and draw it to screen so it's it's useful for like back buffers and stuff like that like I mentioned you can give a graphics context an image to draw the screen but if you do it the other way around you can make a graphics context by giving it an image so it'll like use that as the backing store basically and anything you draw into it will draw it through there so that could since the second example is pretty short it's just a quick demo of that so basically we have an image buffer that we keep around we keep this image buffer as a member of the demo component again but we create it in the constructor and we draw into it in the constructor so here when you create an image if you're creating one with an actual size and a format it will be a valid image and Guice will allocate that data for you on the neap so we make an image a RGB so we have 32-bit and supports transparency we're gonna make it 500 by 500 because our component is also that size and then you can tell juice whether or not it needs to clear all the contents of that so if you allocate this data and you don't clear it and you start drawing it to screen without drawing anything over thought of that it'll just be like random garbage basically probably just like noise all over the place or something weird but we are going to be filling the entire contents so just for the sake of like not going through and clearing the whole thing we just don't clear it usually if you're doing like a transparent image that's going to be over top of something you'll want to clear it just in case so here we can make a graphics context by actually passing it the image and going I really hope that is the display and on my graphics card so yeah we make this graphics context based off our buffer and then we can just draw right inside of this constructor basically so we're not inside of the paint method we can just start drawing into the image we fill all of it with sky-blue set the power to white set a font and then draw a hello world again this time using the clip bounce which will basically be that zero zero five hundred and by the time we actually paint it the buffer is valid because we we set all this up in the constructor to actually have a you know walk of data associated with it and we drew into it so we see hello world anytime we're repainting because it was created once and will always be there if we were to set a time or something inside for this string this will not be updated and anytime you're repainting you would have to go back in and like update your actual image itself before you start drawing it so it kind of comes down to what you're trying to use it for on how you set up the structure of like when do I need to like update my you know my backing buffer my off-screen image do I do it like every time every time I'm painting would kind of be overkill but like at that point you can just draw it but um you know is it every time like every so often when something changes we'll just update it or is it only if the user is interacting with something [Music] but that really all depends on the use case basically but it's a great way like to just draw something once especially and if it's something complex and you don't have to keep repainting it all the time so you can save a lot of CPU usage that way of just draw it once and just keep the image around and then just draw it whenever you need to like show that that graphic again the only thing is that you are kind of trading off memory usage for or CPU usage so it's kind of a balancing act of like is this more efficient to do it this way versus not or like you know am i allocating too much memory by keeping all these images around when I don't really need them because juice will also have you know it has another buffer basically that is the contents of your window so you kind of have like two copies of the image saved at once so to speak could you talk a little bit in this example when you go to have paint and we have reference to the graphics G is that using the one that we have declared up above and how does that work if we don't have in other examples when we haven't created graphics G that's part of the project or yeah so in this case G I just used as the placeholder for the context all the time so I used it here too but this could be anything like context stuff like that but it's good the graphics context will only be local to this function so this can be stack allocated as well to where you know you make a graphics context somewhere in the function when the function exits that context is out of scope and then it just like commits everything it did to that image in light stops you basically can't write into the image anymore unless you have another context open for that so we we use this first context here only within the constructor of our demo component and then when it gets to here we basically don't have this context anymore and we're not drawing anything into our image buffer anymore so this one this context is what is passed in and this is the it's by reference because of it's gonna have all the state and everything that juice has already been using for the previous components that it's painted basically that whole component loop that it's going through to paint everything it'll pass you a reference to the context it's used but here we can just use our buffer because we already drew into it before and we get we take the current contacts that we're actually painting with and we tell it to draw this image and we give it the buffer and it takes all the pixels and basically just copies all of them into there at that correct position yeah this one is the one that you will not have direct control over exactly on what kind of image like backing that is actually using juice we'll just allocate that in some way like leaf or your whole window sides and draw into that by just going through that component loop doing the reduced clip region stuff painting each component like moving on and then finally just committing all that like refreshing the contents with that image data yeah that's the basic of the buffers and the way that you actually start applying that is when you get into caching for components and stuff like that so as I mentioned you can cache complex graphics if you have something that you it's really expensive to draw and you only want to do it every so often but if that that there's graphics that you're actually using are from a component the component class offers you an API to easily handle caching that and like saving it to an off-screen buffer and only updating it every so often the basic was basic part of that is using set buffer to image which will just turn on a flag that makes an image behind the scenes for you and every time that you call repaint on the component it'll refresh that image if you call repaint only with like a specific rectangle say like 50 by 50 it'll just go to that first 50 by 50 and update the components and then redraw the image basically but it doesn't have to invalidate that backing buffer all the time if you don't need it to so it's kind of an easy way to do the caching for a component by just using the repaint interface so when you call repaint it refreshes if you want to use just a smaller region it'll know how that invalidate that for you as I said before it's useful when the painting overhead cost more than saving you know creating an image on the heap and and writing to it and then like going back and getting that data and like writing it over again into the context because if you do certain things like if you're repainting a lot and you turn on like set buffer to image for the component that's being repainted you will see your CPU jump up probably like twice as much or more just because it's now so much heavier tasks to go and save all that data draw into all of it because you keep repainting and then like grab you know pass off that image to the graphics context that will then go and drawn on screen so it's useful for things that are complex to draw but don't need to be updated very often and one way that you can do that using custom behavior is with that cached component class so this basically and I think I mentioned it before it's one of the things that juice will you can set a cache you can set the cast component image and it will own that object basically but um under the hood when you use like set buffer to image it's just calling set cache component image with like a simple wrapper that just invalidates an image or doesn't you can do your own behavior by using this and basically all it is is just a couple of virtual functions one of them is to paint the contents on the screen two other ones are to invalidate regions of your of your image cache so you can invalidate all which is if the user you know repaints your entire component or you can just invalidate a certain area of it and then when the component is being deleted if you need to release any resources it will call release resources for you and you can like you know delete extra buffers or whatever you have allocated basically but yeah and this is a good example of where this is actually used is in juices OpenGL implementation they use cached component image to handle the textures so each component is actually drawn using like textures in OpenGL which is basically the same as the image class you just have some pixel data stored somewhere else and you're just gonna reuse it draw it in this area but to actually go in and like update the texture using you know the OpenGL API they wrap that through a cached component image so anytime you call repaint on that it'll market and like it will know to go and like use the OpenGL API to actually go updates and textures and when it paints it then it uses the OpenGL API to actually get back onto the screen using OpenGL textures but that's one use case for it that's pretty advanced usually if if you're just like buffering something and you just want to like have it save the contents and not repaint it all the time that set buffer damage call is is pretty much enough but this is useful if you want to like Stefan basically if you want to insert yourself into the painting loop because this will be called he actually goes cool so basically if you have a cash component image this is the repaint that's gonna happen on the juice side that will go in and make a context and like repaint your whole component for you if you have a cash component and you're invalidating your cash it will sorry this is actually the if you're calling repaint it will do this where it will invalidate all or sections of the cached image but yeah if you are if you have an image basically instead of calling paint entire component it will just go to your cast component and ask to draw the whole contents so at that point you basically control that painting hierarchy of how everything gets drawn inside of that component so you can even do different stuff than just calling the default would be to just in your cache Simmons itself like you are painting the whole component but you could also just set something and override it and change how things are being painted and like break the hierarchy in that kind of stuff but that really gets into whether or not you need like sometimes I've run into weird graphical stuff from like I want to do you know this certain thing kind of like that OpenGL thing where it's like I need this to to actually behave differently and not just rely on juices like going through each component making the paint calls so sometimes I'll use this for those kind of weird education yeah go back to last example from the image so here it's kind of similar to the to the early on one where we had our main component and the component inside was being repainted you can see each one of them repainting at a time here basically we have one of our square components again and it does a random color and when you click on it repaint and we added buttons into either trigger or repaint for the parent and to actually enable the cash for the squares so when you click on this enable cash button it will toggle on or off whether or not the square is like buffering its contents or isn't when you click on repaint parent it'll repaint the whole area and in our parent all we do is really just write the current time up at the top so we can know things are changing so we trigger repaints we see the time change and we see the child square also repainting and if we click just on you know the child it will just repaint itself but the parent isn't changing at all now if we enable the cache just for the child we can cause a repaint directly on the child still but if the parent is going repaint you're not telling the child that it needs to be updated so we can repaint the whole parent but the child component will not change it will just keep that same image as long as it isn't having repaint called on itself so the parents free to like update all this stuff and it's a little more efficient because we don't have to repaint the the middle component anymore now for simple stuff I mean it's probably more overhead to actually just use the cache but once you're doing like really complex graphics and like you need to update large chunks of the screen it will save you a lot of CPU usage to cache what you can basically especially combined with like so things opaque and catching their graphics if they don't need to be updated it'll make it really cheap that like juice just will no okay I can just reuse this image data that I already have and I don't have to go and like do all these pads again and like rasterize everything and go through all that expensive setup so yeah this main square will not repaint until you force it to by clicking directly on it there any questions about images or the caching systems and stuff that takes us to juices look-and-feel class this basically is going to be not be way but one way of how you can beam your application so it provides you like UI customization through this interface and all the look in fuel class really is is just a strong that it can hold some colors like you can set a color specifically on a look and feel but it also subclasses like every single built-in which it has some look and feel methods and its subclasses all of those so if you were to go into like this header file for juices slider class you'll see somewhere within there there's a struct called look and feel methods and all it is is just a bunch of virtual methods that say like drawl the slider background roll the sliders thumb you know give me the font that I'm using for the slider and so that's how it composes the API for the actual look and feel class is just overriding all of these methods and that allows you then to subclass look and feel and start overriding and providing different painting behavior based on you know whatever kind of theme you wanna make so the two important things with that are obviously the looking feel methods that are available in all the juice widgets but there's also nearly every component I think there's a few exceptions like the juice base button I don't think has any of these it does not have color ID enumerators and basically they're all just unique integer values that are used to associate a color or a specific color that's going to be used with a component so in this case of like the slider when you go to the slider class reference there will be a look and feel methods here and it has stuff like drawing the linear slider drawing a linear slider background the thumb for that slider thumb radius you know drawing rotary sliders all kinds of stuff that allows you to customize how that slider is being drawn and even some stuff on how it's like being laid out like the slider layout from where the text box is positioned and where the slider itself is positioned or if it's you know making buttons for like the increment decrement slider you can actually just overwrite this and make your own kind of button subclass that you're using the same thing with the sliders text box here and then it provides this color ID Ino so it's basically just a bunch of unique values to figure you don't really need to know what these are but if you're making your own custom color ID values that you want to use you kind of have to look throughout the documentation and just figure out I'm gonna start at this number and count up because they don't list these they didn't reserve any particular numbers like they didn't say you know we're gonna start every ID with like ffs and then the some number after that but usually if you're using they start at low numbers so if you're using a high enough number it'll always be offset but they defined things like you know slider has a background color ID and in the look and feel and juices look and feel definitely they go through and they check for the component does the component have the slider background color ID set in its properties and if it does it'll take that color and actually use it that color here so all components and look and feels basically have a set color remove color is color specified in the case of components it actually maps to their properties but it uses like a function to just transform the name of the property is so like if you set the color given some ID of like ABCDEF or something the actual property name it'll save is like JCCC something underscore and then the actual like hex representation of that of that number so you can accidentally start messing up the colors if you say like juice you know component get the properties and clear all of them all your colors are also gone so it's for to remember that because they don't note that necessarily here but if you set a color you can then find the color again and it will give you back the actual color that you set for that so for example you can set like the background color ID of a slider to be red and just the background part when it goes to look for that background color it'll find bread and start drawing that but the track color and all the other stuff will be left to the defaults and those defaults are usually defined in the look-and-feel itself so if you call find color on a component and it doesn't find it there find color you can specify to actually look in the parent component so it can be like an inheritance kind of thing that's off by default but if it finds the color in a specific look and feel' set for the component it will use that color so the order kind of goes it searches through its own properties looks for the color if it doesn't have it what you set inherit from parent to true it will go first it'll actually look in the look and feel if you set a custom one for that component and if it finds it there it'll use it if it doesn't find it there it will go to the parent and see if it uses it and if it doesn't find that it'll just fall back on like get you know whatever look and feel I'm using and see if the color is there and if it's not there you will end up with just transparent black basically so nothing will be show so example for one just kind of goes over the basics of that basically we just have a few components label slider textbox combo box and each version of juice they make a new look and feel and it's basically the steaming for that version of juice which is usually what is used in the producer and stuff like that so version 1 is like super old I think they even say that years on here too they're everything derives from look and feel it's actually get the Virgin's so yeah 2002 to 2007 was was looking feel virgin one kind of thing so this is the default we going in and we pick something from the comment box it sets the version basically so this is their super old style some buttons and sliders and they kind of got into the Windows XP phase it's almost like Mac or something it's a very strange page and in version four is what we already solve it's the current one but uh the demo code basically is just a lot of setup to like okay we got to put this label on the slider and all that stuff on screen so we set the properties like that and for the label we're forcing it to a color because it there was some weirdness if that wasn't in there I don't think they were setting these colors in some of the older looking feels so you had like white on white text and stuff that was unreadable you know we set up our slider all that buttons okay then we go so for each option that you can choose for the combo box we just basically set the look and feel to one of the look and feels that we kept in the member glass so looking for one is an instance of look and feel version 1 2 is a instance of version 2 and we basically just set those whenever the combo box changes is everyone familiar with C++ lambdas as well this was the syntax I was using basically juice instead of having to use like the listener classes which I think you guys use in class right so instead of like slider listener and you know slider value changed like overriding all that stuff they did add members to each widget or most of them usually that are basically it will end up like this there's like a standard function that returns void and it takes nothing and it's changed so you'll see something like that like in the actual declaration of the combo box and the unchanged like these kind of standard functions that they use you can just assign to any function or lambda or anything basically that matches that function signature so if it's a void returning function that doesn't take any arguments that can be called by the combo box whenever it changes so it's super useful for this where it's like I don't want to make you know a combo box listener and override that like put all this extra code in there I just want to say when the combo box changes I'm gonna do this function so the C++ lambda syntax guess there's not a whole lot to it but you probably want to read the docs online but it's formatted basically this is itself a lambda that prints hello world and it will be assigned to like an object so you could say like I have some lambda or some some standard function called my function and use this lambda and all it really does under the hood is just the compiler will put this function somewhere in your code and then use my function as a function pointer to know where that function actually resides so it's it's really nice because it lets you do a lot of like scoping stuff a lot more easily and just makes it a lot less verbose to write things out like here we can just say hello world and we can call my function as if it were you know a regular function and that kind of thing this combo box unchanged it makes it really easy for that because we can just say anytime this changes we're gonna do that when it comes to lambdas though with super nicest that you can capture certain variables in them so that is what the square brackets represent in the lambda so in this case we're actually capturing this pointer which will be pointing to our demo component and because this is like always implicit in methods and stuff you don't always have to use it or you don't have to write it out when you're when you're actually making use of it so because we capture this everything that this has is visible and available to the function as long as you know this is a real valid pointer so in our case we're technically grabbing this combo box and getting the selected ID and when we want to set the look and feel it's technically just doing you know this set look and feel so it makes it really nice because instead of having to like if we have a listener and especially if the listener was its own like separate class not part of our main component you'd have to start like passing you know this class has to know about that class and they'll off to have pointers back and forth to each other and all this crazy stuff but if you can capture things it makes it so much easier like for example you can capture by reference as well so if we want to capture as a text button by reference instead of this none of this will compile because this is that this pointer is gone but we could say like text button and like just start doing anything with it so you don't have to have like a separate class that's like a listener of the combo box and you don't have to like give that listener references over to other things you want to use it makes it a lot easier to just be able to go in and say like look I just want to write a function and it has access to this text button and I want to do whatever I want with the text button so that stuff's really useful when you get into callbacks and like doing actions with components it just be able to say you know anytime this combo box changes there's only one thing that's gonna happen and that's we're gonna go in and we're gonna set the look and feel and that's all you have to do is just write the function for it basically the arrow pointer stuff is basically syntax for declaring the return type of a lambda so I always be explicit with things so in this case we're explicitly saying this returns nothing returns void but you can leave it out if you want to yeah we basically do that I don't think there's any other actions so yeah we set the look and feel based on the combo box looking till three if you noticed when we use that the what get crashed when we go to the third looking field the button is red and that's because we're using the color IDs that I mentioned before we're actually setting it for the look and feel version three instance so here we set the color using text button color button color ID which is the default color when the button is not on or pressed and we set it to the red color so any button like this one here that is instantiated and has that look and feel set for it we'll draw in red unless it has its own color set for it as well so we could override that by saying you know our text button in school we're gonna set the color color for that builds it's blue but it's blue all the time is the thing now so every look and feel will immediately see this text button has a custom color set for it so let's use that but it will be blue everywhere so it'll be blue in the third look and feel' fourth one first one all that stuff this one I don't know actually maybe it's not using its entering that's from 2002 I would not be surprised but yeah and that goes kind of the other way around where if we were to use version three and made like 50 buttons on screen every single one of them will be read unless other you know specifies else applies so it'll always go back to the look and feel class if you're trying to find a color and if that component doesn't have that color set already I think that is it for this but there is one particular thing and let me go back to uses is that when you said a look and feel you will have to when you set a looking field basically you just have to unset it at the end of your components lifetime so in our case we have okay so if we did not unset our look-and-feel we will basically hit this assertion which is saying you're trying to delete a look and feel while an object is still using it so when you delete a component it sounds like it's the wrong way around or something when you delete a component it does not decrement that reference count so the look and feel still thinks like oh there's something that is like trying to use me basically and so it's gonna it's gonna yell at you it'll still work fine actually nothing should go wrong because the component itself is already gone at this point but the look and feel thinks that like oh something is still pointing to me I have to assert because you know this reference that you're using is not going to be valid anymore so anytime you set a look and feel explicitly it's important to make sure you set it to null pointer at the end of whatever you're doing and this also applies for the default look and feel so there's always like a static look and feel hanging around that you can use and that induce it's usually gonna be whatever the most current version is so in our case it's the look and feel version 4 is the default looking feel but you could set it to your own and say like I'm gonna use my own custom look and feel and also set it to the default and then I don't have to set it for any components at the end of your applications lifetime you will still want to do this or it will just assert that you every time you run your app which is kind of annoying because it doesn't really it's not really a problem I think it's just backwards or something like then but it's just an important thing to remember it okay um next thing is basically just a quick overview of custom looking fields it's like I mentioned you'll want to derive a look and feel class but you'll want to derive one of the subclasses because they already implement a lot of the virtual methods lots and lots of the methods are marked like pure virtual so if you don't actually make one of those in your subclass your program will not compile so look and feel version one up to look and feel version for mostly implement I think all of them so they're all safe to use to just like subclass you know look and feel version for everything will start looking like the default look and feel at first but then you can branch off from that say okay I'm gonna make my slider look different okay now I'm gonna make the text button customize that a little bit but if there's anything that wasn't implemented it'll just look like the default style and able you know it'll still compile and you won't have any weirdness and if you're doing that you can also just store whatever you want kind of in the look and feel like if you're using custom fonts you can store them in the look and feel or you could do like I mentioned before just use static storage for the font objects we used some extra stuff in our look and feel that we made that handles like our default background drawing because we support two themes so when you switch themes it'll actually we save the theme name in the look and feel and then we also save that in the save data for the plug-in and that theme basically just determines you know what color palette are we using and what kind of background are we gonna draw but that it doesn't even switch out painting it's really just colors at that point but you can do all that kind of stuff if you make us a class you can just use all that because usually any of that custom data will be used within the look and feel and like the components don't have to know about it so you don't have to like say oh I have this you know I can call get look and feel on my component but it's a look and feel type it's not like you know my custom looking field type you don't have to like castes and stuff because the component usually doesn't need to know about the look and feel it can just call the painting methods that it really needs to paint itself what this does get into some weirdness when you start using subclasses so for instance if you a good one is if you subclass juices face button class because it I think it provides the look and feels but it doesn't actually implement them so when it paints itself it doesn't even do anything yeah it actually it has look and feel so it has methods for like draw a text button throw a button background draw a toggle button that kind of stuff but that's actually implemented by the text button toggle button and other classes so it gets kind of tricky if it's like I have these subclasses of juice widgets but I want to use them with my look and feel but like you know I added some fields to the slider now it has some other kind of data member and I want to be able to access that from my look and feel the easy way without having to typecast that which typecasting isn't really that bad but it just does rely on like I have to cast this to you know my slider class and then make sure that that actually was what it was and doesn't return a null pointer instead of doing all that you can just use the properties map from before so if it has you know a property of like you know my custom slider thumb so the very last part of the workshop today is gonna be about layout so taking everything we had with making components making custom graphics and everything how do we actually get them on the screen and how do we actually lay them out and make everything easy so we can make more complex hierarchies and interfaces a simple way is to literally just go in and write everything by hand so you have two options with that which is absolute positioning as we've usually doing with set bounds and calling some sizes on it and stuff but you can also use relative positioning and as we mentioned before you have to do this after adding all the children to the parent and then you do have to do all the calculations yourself so if you want to like split it up into you know thirds or something off of a chunk of the parent you have to give that chunk and then split it up into thirds and then call each one with the correct correct percentage for the relative positioning usually you would be doing this in your resized method so that if you need it at least your component when you were resizing your main window and stuff the children can actually have all of their balance updated too and everything will be more dynamic but it's usually pretty hard to maintain it's usually not too bad to read but it's like you look at it and you don't really know where everything's gonna be if there's a lot of elements until you actually like throw it up on screen and see what where everything goes it definitely is hard to maintain because when you start changing things your commits basically mean nothing of like moved to the left you know like read reordered the layout you can't actually see what changed because it's all just like a hundred numbers of random positions and sizes and it makes resizable and especially like dynamic applications a lot more difficult handle it that way it's also pretty strongly tied to the components so you have to go in and say you know child one the slider like goes specifically right here and any calculations relating for that are all just tied to that so the very first example is just super super basic kind of going back to what we already had in early demos of just we have some squares the first one we position absolutely so it's going to be 100 by 100 you know it's really messed up know if I should be worried before let's try this one give me the full screen there we go um so yeah the first one we can say you know it's gonna be at 100 100 now and it will move over its other one we set it relative so we actually go in the relative x position is going to be zero so it always starts out just at the left edge we're gonna use relative bounce for the height so we're actually going to take the height of the red square which starts at zero and goes down to the type that is going to be offset by our height so we can just always make it at the bottom of the red square using this set bounce relative call it will always be 100% of the width so this wide and it'll be 33% of the height so if we grab this and start moving it around we can see that it changes so it the edge here we actually make this like 90 or something clear so if we make that you know 75% the right edge moves along with our main component and so does the bottom edge as well but you basically have to say okay I'm gonna go in still hand to calculate like every split you know I want this to be offset by 1/5 and it's 1/5 wide and then the next one is offset by 2/5 and it's 1/5 wide and the next one is offset by 3/5 and it's a 5th line like you end up having to do a lot of the calculations still of and a lot of the boilerplate really of just getting everything into the right place even if you're just doing something like simple like saying I'm going to split this component into you know 5 sections and each one is going to have that much space so that's the most basic way and it's what we've already been doing the step up from that is rectangle slicing it is what jules calls it basically it relies on I didn't even write it in here but let me go over to I don't know like I it somehow updates every five minutes or something like you can't possibly be pushing that much juice rectangle so the rectangle offers classes that will mutate and return a section of a rectangle or I guess basically you can call this method on a rectangle to chop off a section from it it'll chop off that section of the rectangle and then return the section that it chopped off so they are the remove from methods which is gonna be top left right or bottom so you can say I'm going to split the screen up into house I'll remove for my header I'll remove from the top of my full bounds you know fifty and then the whole thing is 100 calls I'll then just set the balance for the other one and it'll be fifty because we already took off fifty so they are I should say a lot easier that's slightly easier they're way more easier than absolute layouts and even more easier to deal with then the relative positioning stuff it still kind of requires you though to figure out what you need ahead of time of like okay I'm gonna make my UI like I'll just decide on some random window size and then I'll start chopping up the bounds of it and like set everything which it's kind of what we do at work where it's a little bit of the chicken and egg thing of like well we know the sliders are usually this big and and that so we'll just like set the size here and then start grabbing sections and applying and applying the balance to those child components so and it's it's easy with a low number of components that should say component because if you have tons of things on-screen but they're all children of the same parent that is gonna be one long resized method of just chopping up like all the little sections where they're supposed to go and doing all that but if you split it up into sections where it's like you know we have a header component and the header has a bunch of buttons and some other stuff in it that's easy because then you just set the header say like hey the headers gonna have you know hundred off the top and in the header resize then you can just say okay no matter what we get here's what our layouts gonna be like it's not very useful if components are kind of floating around or not easily in line with things but I don't think that's ever really that easy to work in any way unless you just go in and hand position it so in our case like RDS or like some of the knobs like we have a graph and like a threshold and input meter and stuff but then there's a section underneath where it's like things are just kind of there and they're not aligned to the grid or anything specifically so it's a little bit of like okay we're gonna chop off this much but then we're gonna like shift it over a little bit and like kind of reduce it and just like get it to actually fit where we want it to be and you see that a lot with like if you're doing ski morphic stuff where it's like things were just kind of in there and that's how like the real thing looked or that's not really aligned to a grid or like things are just kind of wherever then this can be kind of hard to use and you may just still end up with a little bit of the whole like trying to work with an absolute positioning system anyway so second example basically just goes through creating one of those layouts so we have our square components again red blue red blue green yellow violet we have a 500 by 500 window and what we do this is usually how it's gonna be set up is you're gonna want to get the local bounds for your parent component so that will give you the size but with a zero zero position because we're working relative to the parent and what we can do is then just chop off sections there's also an additional padding so if you turn this on to one we can use a padding of five pixels or a padding of 100 eyes so each time you want to set the balance we're gonna just pick wherever we want it to be so the red square we're gonna set the balance by removing 25 from the top and taking that result that 25 we chopped off and we're gonna reduce it by however much padding me one so by default it's gonna be one so it's just gonna shrink it a little bit down on each side if it was more than it would shrink it down and it'd be passed it'd be smaller than 25 probably smaller than 220 and then we basically just go through each side and kind of do the same thing so we take some off the top for the red square takes them off the right for the blue square take some off the bottom for the green square thinks I'm off the left for the yellow square and usually then it ends up of you just use the final balance for whatever else you have left so our violets square is what's going to be in the center after everything has been chopped off so this will give it it's kind of like if you were to apply margins to each side of your parent balance and then set the violin square from that but here it's where we're taking margins as their own individual sections for components and they can be different sizes so it basically looks like this we chopped off and it's important to note that when you do that so this red square was first it got all of that I think the blue square second the blue square is up because you removed from the top it's now gonna be shorter so you have that much height to work with and still all of this you know with so then we removed from there and we have that much left and after that we have the sum of these three rectangles is what we have left so then we just start chopping away at then and then obviously we can apply some padding if we're reducing the rectangles anyway and once you do that basically we just get the optional little border around every component so that we have some margins to even between them and this usually works out pretty well it's what we use for our plugins um it just gets kind of finicky of like okay we have to you know position this and just randomly start translating and applying some padding's it doesn't quite look right you know we don't want to completely Center it we would just kind of want to visually Center it and get it close so you might end up with like you know take some chunk off of one of the sides and then Pat it and then maybe translate it a little bit or something and that kind of stuff so it still can end up like that and usually then it gets a little weird because you just have tons of like you know this call if you're doing a whole bunch of stuff it's like reduced Sam that's translated and like 50 different operations that you're doing every time or something so that can still be less ideal but it's definitely a better way to lay things out than to manually go in by hand and try and place everything the right place are there any questions so far cool so the last two implementations are newer features in use that come from the web dev side so if anyone's familiar with web development there are the flex box layouts and the grid layouts first one they're going to go over as flex box and it allows you to just dynamically set layouts get along a given axis so if you have in our case before where you split something up into sections of five across the whole component you can do that a little easier at the Flex box as long as you just set that up in the right way and if you're doing it in the resized method as well so it's great because then you can just you basically just gift flex box here's all of my items that I'm gonna do here are all the properties for every item and here's the full layout like go apply the balance to all that and it'll just run all the it'll calculate all of it for you and then also apply the balance to every child that you associated with the items but it cannot handle 2d like grid layouts it kind of can because when you give items to the Flex box you can say like this item controls another flex box so it will like set the bounds and then call the flexbox layout to then go in and set all those but uh that gets a little clunky too so it's kind of usually it's something of a little bit of each method so you might like chop off a section and then like do just that section using flexbox if it's like some kind of title bar or something or if you're doing some kind of grid later on you can chop off that section and like apply like a grid layout for all the components in that section yeah and this I would recommend if you guys want to start using this like there's two other tutorials that kind of cover this a bit more because there are just tons and tons of properties for the Flex box the Flex box itself doesn't have a ton but the Flex item which is actually what you're associating each component with you can go in and just you know set grow and shrink properties and basis and alignments and like minimum maximum width and height and margins and all kinds of stuff then the Flex box that can like have its own alignments and just and all that and I really applies if you are doing layouts where you might have something that is like I want this slider on screen and it's going to be like this size but I'm going to position it based around all of the other content that's in there so you could say like okay this slider gets you know a section that's this big but it's the slider is only this big we're going to align the slider like top left or something and basically it's kind of like all the text stuff where you can do all crazy text layouts based on the given text size you're trying to draw same thing here where you can do all kinds of justification and alignment and everything if you have components that are not filling up the full balance that they're given and in our example we basically and they actually do something here where it's like these sliders there's a lot more balance than they have especially this where it's going straight down it will just align all these center because they specified that but they each are getting like a full chunk of the of the size but they don't necessarily have to be as tall you know as a fifth of the full window I it can just be that they're only you know this tall really and they're just centered within the layout section that they're given so for the example it's a pretty simple demo just of splitting that up into the sections so all we really do is just add our squares in again set-asides and in oh it's getting crazy in the resize method we create a flexbox basically it just has a couple members it's pretty easy to work with really just stack out allocate it whenever you need one here there's a little if def stuff to flip around directions so if 0 if 0 here we're really just go down here and we're using ro by default which you saw since they went you know across the x-axis so in our logic we just grabbed each child component we're gonna grab a flex item and give it to the Flex box each time and what we're gonna say is that each item should be allowed to grow as much as it needs to to fill up the section that its allotted when the Flex box runs its layout so here we just assign that to one so that every square is allowed to take up the full size of the section that it's given and we set an Associated component which is going to be a pointer to a component so the Flex item when it has its bounce set it will know to go to that Associated component and say ok now you set your balance as well and similar to our last layout we also have margins and the margins can apply to any side so the item itself margin here you can set like a specific you know the top has a margin of five the right and left have a margin of 10 in the bottom as a margin of zero so they're specific to each side of the rectangle itself so we go through and the Flex box has a an array called items which basically we write here it's just an array of Flex item objects so you can add into that reorder them do whatever you want to it it's just there for you to use so in our case we just add a flex item flex item is just a struct see it just copies it over so it'll copy the pointer copy over the Flex Square property all that stuff and then we tell the Flex box down here to perform the layout so it will go through for every item in that array figure out okay what are my properties that I need to actually create this layout and then start like chopping up the sections and start applying the sections to those Flex items and we can see that here if we grab this we can see that it dynamically will update one source resizing so we always get in a full height and then they split it up into fives or however however wide this is and then we can also add the margin over to the Flex items capitalize the eye there we go and so each of them now has a margin of yeah so they have a margin attend in between every item so it'll always keep that ten pixels between the items which means any space left over that's what's going to be assigned the actual width for each one so you can see once it they get pretty small at these smaller ones because we are saving you know like sixty one two three four five six sixty pixels across so then we only have a little bit left by the time you know we're down to this much space you can also see that it will let you so we're down here we're using grow there are row reverse and column reverse methods as well so if we use row reverse it will just flip around how it's deciding to lay this out so you can just easily say you know everything I added actually I wanted that the other way around or something it will just flip that around for you the Flex items though they have an order integer associated with that struct that you can set that and if it's not zero then you can specify a specific alignment so for instance we could say even though we're adding it in this order the this could be the middle one this could be the first one you know the pink one could be the third one or something if we were to specify that order member for each flex item and that's useful that's especially useful when you already have layout set up that are using flexbox and a client is like a can you move these around instead of having to say oh god that's going to be an hour ordeal now of trying to fix all the positions just set the order of the items so even if you're using like layouts that are in greats or like you know align to columns and stuff like that this makes it so much easier any other way even easier than the rectangle slicing because once your layout is there it's super easy to just manipulate like say okay the order is completely changing and we're gonna add some margins to it actually what this refers you know actually we want these justified over to the right or something so working with that is a lot easier it just really depends on whether or not you need that much of a dynamic layout versus if it's just easier to not set up all this extra flex box stuff and just like start cutting out rectangles but if you need like grids then it kind of gets a little bit further and you have to use the grid implementations that well yeah I would HIGHLY highly recommend this over manually positioning things you know if you have a need for this kind of thing does anyone have any questions about flexbox stuff brings us to the last layout system which is grid which is also part of web dev it's in css3 stuff it's pretty much the same in principle in that like the grid will take you know whatever kind of absolute size is take those whatever it has left to work with it will just start you know applying that dynamic size to the components and stuff it has a lot more setup and honestly their API is extremely confusing to work with it's not extremely but once you're getting into it like for the first time it's just like so many different properties and things that are there and it's just hard to get something like quick to setup but it will let you do like a 2d grid each row and column can have a specific size so it's like if you went into Excel or something and started like messing around with every you know that the B column will be like this wide and the number five row down here or whatever is gonna be this tall and you can just start manipulating it that way where everything gets its own size but it allows for absolute sizes of the components within that or dynamic sizes and you can also just allow the rows and columns to be specifically absolutely sized or dynamically sized as a fraction of however much free space is left when you're doing the layout so at least the last example which is pretty basic one of grid there we go same thing we got all the scores again this talks about in the comments there's some more info on how it works and how you know the layout is structured to go through those absolute positions and then take whatever free space is left and and use those sizes so here we create a grid same kind of deal where we can have gaps which are like the margins but it'll be between each section of the row and column our default here is that we assign the auto rows and auto columns sections and we just say each row gets one fraction of free space so if we have five rows they each get 1/5 of the same for the columns so basically we're just splitting up the whole thing into an equally sized grid of however many items we're gonna have we go through and we create a grid item for each child we set the Associated component again and we sent the area so when you're working with a grid the area can be defined in a few ways here it's going to be the ID of the actual like row and column that we want to use so we're gonna say that each one we increment the row and the column so they're just gonna be dotted down in a diagonal line across the grid but you can also set areas based on name so if you have some weird complex layout you can actually name the areas like the starting and end regions and say like this goes directly into this region without having to say like okay well it's actually you know number five row number seven column kind of thing and it's going to extend out to you know this number and that number so that makes it a little bit easier but it's also a lot of setup so it kind of depends on how complex this needs to get and usually it's the case where like this would be really helpful if you had tons and tons of components that were all in one child and like everything was just laid out on that time but usually you don't operate like that so the grid like kind of gets into what when you actually need to use this or not usually I just end up making hierarchies and every you know this section goes and lays out its components and it's easy enough to just say like okay it takes you know this much off the top and it puts the button there and it keeps doing the same around so the grid can be a little bit overkill I have only used it once and it was actually for that layout thing I mentioned where I could specify like the great type layout and start laying out things just dynamically but it's still like kind of it's a lot of code that you're relying on I guess so to speak but same kind of deal we perform the bath perform the layout using the full bounds of our parent basically this I probably should draw on a background it's white square but our grid is split up equally so we have four rows and four columns and each one of these the area is going to be added each time so one two three four and what we can do then if we know we're gonna have that many items we can add some template rose and template columns and this is where it kind of gets into like setting up your own dynamic grid layouts the template rows and columns use grid to track info struct real quick it's basically you can make the track info as a pixel size as a fraction of free space and you can actually give it those names I mentioned so you could give it a starting line to use and/or an ending line and or use a pixel or a fraction of free space so it's all up to how you need your layout to be set up a lot of the times it kind of comes down to just like everything's gonna be a fraction of free space like I just want a grid that splits up my main component into you know equal grid of equal size for all the things and just put them all in there especially if it's like you know a drum pad or like sequencing kind of stuff we're like everything's just always in some sort of uniform grid anyway but if you need stuff to be in specific sizes like you know these tracks are going to be this pixel size all the time and then the rest of it is all just fractions of how much free space is left these will let you do that so basically we go through the rows and we say the first row gets two fractions of the free space this one gets one this one gets three this one gets one and then these all get one so if we enable that basically like I described before where you start resizing the columns and stuff of the the Excel spreadsheet this one will get two fractions of free space this gets one this gets three and this gets one so it'll actually take it into seven spaces basically and um divide those up and then allot them to however many the template row had so in our case 2 1 3 1 and then the grid template columns they're all the same so we kept those and they're still split up into fours but we can change how the height of each row actually appears and these will all be based since their own fraction of free space they'll be based on the height of the UM of the actual parent component so we just resize this and it'll know how to calculate the bounds and set everything appropriately I think we also had row gap so you can specify turn back off you can specify a row gap and a column gap so if you want things to be spaced out you can do that so now we have some gaps in between each column and in between each row I don't have any questions about grid layouts that is the last example and the only thing left is I just have a few performance tips and just things to look out for for a specifically audio software because in audio software there's going to be a lot of moving parts on the screen at any given time meters you know RTA's like EQ is that you're moving around and the curve drawls with it that kind of stuff so like I mentioned a lot of the like repaint calls will be thrown away if you start doing too many of them so if you are doing something like filling out some complex data for example in our graphs when we're doing the EQ curves we have to go and calculate that curve like every single time that a band is changing around but if you do that we're okay we're gonna calculate the whole curve again and then call repaint the users not gonna see that if bullet point 2 happens where the OS throws away a call but it did all of the work to still make the curve shape for you it just didn't draw out the screen so a good way to do that is like if you're working with that kind of data we're like we need to update this and the user needs to see it just do the updating in the repaint sorry not the repaint but the paint method itself so the very first thing that happens when you actually know you're repainting the component is you update that data then you go through and draw it so that way you're not wasting extra effort if you calling repaint a bunch in the OS is like we're not going to repaint you you're doing more work ahead of time that's not being seen so that's more CPU usage that is being eaten up for things that are just useless at that point the OS is then going to say okay well now you're increasing CPU usage so we're gonna de prioritize more of your repaint calls and then everything just looks horrible basically or get super super slow and then people complain always use components I'm honest I say this because I wrote some stuff that like had a bunch of moving parts on the screen but I was managing that myself so you know little pieces that the user could grab and drag around and stuff and I'm like oh I don't want to repaint the whole thing every time I only want to repaint the sections so it was like okay we have to repaint the old part repaint the new part once you do that the arrow house starts throwing away repaints again you have a copy of like okay this thing was here and now it's here but it like didn't fully clear out the old graphics so you get like weird fragmenting and stuff that's like you drag something across and something like there's always like a little glitchy lines across your component so and when you get to that point to like if you make that kind of thing it already just is like doing a component hierarchy so it makes more sense just split each part of it into its own component and especially do the behavior specific to each part in each components and the little piece that you can grab like that should respond to a mouse event it should be able to be moved around and dragged and stuff and it should handle repainting itself is especially true if you have things like an audio that are moving around a lot and especially if they're repainting themselves on top of other components because then you can use things too like setting things opaque so it's not you know if that components repainting itself while you don't have to like mess around with repaints in the background and parent and basically that whole painting hierarchy will just handle everything for you and it will be able less headache and just always drawl as little as needed but some of these have an asterisk next to them or they should anyway so if per ensure the proper bounds and clip regions like make sure that when you're drawing your drawing within the bounds and you're not just like saying hey there's like 20 shapes off here that I should draw because it will still go take all the shapes and like flatten the paths and like try to actually use them basically all for nothing because if you'll not be put in this actual pixel data but the clip region stuff don't go too crazy with it because that whole state stack stuff can be a little heavy to keep like popping state pushing state like all that so sometimes if it's like okay I'm gonna like you know reduce the clip region like five times over just to draw in this little square and stuff that's kind of more wasteful than just drawing you know say okay I'm just gonna draw a square it's in this region I don't need to like force myself to be within that bounds same thing as before cache complex graphics into like off-screen buffers or use components buffered the image stuff this is especially true if you do things like drop shadows and glows and things like that juice comes with I think I mentioned before it has drop shadows and glows and I think image blurs as well but all of those operate on the pixel data so you have to pass it an image it makes some sort of convolution kernel basically and then runs all that pixel data through that and if you're doing that every time that's going to be very expensive especially because it when it runs that it's going to give you back like a copy of the image too for some of these so it might end up copying the whole image applying the effect to it giving you that back so now you have two copies and all this work that was done
Info
Channel: Hack Audio
Views: 542
Rating: undefined out of 5
Keywords: JUCE, JUCE Graphics, Audio Software Graphics, JUCE Component, Computer Programming, Audio Programming, Programming Graphics, Programming Graphics in C++
Id: wPFClE_dgSQ
Channel Id: undefined
Length: 222min 21sec (13341 seconds)
Published: Sat May 11 2019
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.