 Hi, today I want to look into the panel code to explain you what it is doing. So first of all, let me say that we have three main repositories to keep in mind. The first one is Plasma Framework, the second one is Plasma Workspace and the third one is Plasma Desktop. So what's the difference? They all come together and form the Plasma Desktop as we know it, but that's not the only function for two of those. The first one, Plasma Framework, is more generally about giving libraries and the themes that Plasma can use not only on the desktop, but as an example also in Plasma Mobile. So we have in the source directory the desktop theme, which is the one we all know, Breeze, which is again not used only on the Plasma Desktop. But we also have as an example decorative imports with Plasma components, which are components that you can reuse both in Plasma, maybe in apps, and in general in the shells that use Plasma. Then we have Plasma Workspace, which again is not just about Plasma Desktop, but this time we have more complete components. As an example, we have the applets with many of the applets that we use going from kickoff to the clock. But again, kickoff and the clock and the system tree, they are all applets that can also make sense on different kind of devices, not just the desktop. Whereas the last repository, which is Plasma Desktop, is the one that is only about Plasma Desktop and is the actual shell we are using. So we have again an applets directory, as soon as I find, here it is, with all the applets that only make sense on Plasma Desktop. As an example, the shell desktop, applets, or the margin separator and so on. So said that, there's another thing we need to keep into our mind, which is the difference between containment and views. So if we look at the Plasma Desktop, we have two main components, let's say the actual desktop or the background rather, with the image and possibly icons. I don't have any icons, but you can have icons on your background. And then there's the panel. These are the views of the Plasma Desktop, the panel and the desktop. We could potentially have more. As an example, we could have a sidebar and we would have a sidebar view. And in this case, we only have these two. So these views are into our Plasma Desktop folder, into Desktop package, contents and then views. We have the panel and the desktop. But it doesn't end here. The panel and desktop views are only the containers. And in the panel case, they draw the panel background. But that's about it. They don't actually have the content nor they manage it. For actually managing the content, we have the containers, containers, sorry. So we have, let's say, about three important containers to keep in mind. The first one is the panel one, which actually manages the applets inside of it. And then for the desktop view, we have just the background image containment and the files containment where you can also have files as your background. And you can switch between them using layout folder view and desktop. So what we are interested in is the panel. So we can also see that if we get back to the Plasma Desktop directory, because this is all about Plasma Desktop and just Plasma Desktop, we can go into the Containments directory. We have the panel, the folder and the desktop. And then what we are interested in is the panel. And then we have the contents and the UI part of it with two QML files and a JS one. This is the second part of panel code that we are interested in. Finally, there's a third part, which is actually in Plasma workspace. So not just about the Plasma Desktop panel, but could also be reused in other shawls, which is inside of shawl. And then you search for panel. We have the panel view and the panel view, the panel config view, but this is less interesting and the panel shadows, again, less interesting. We are mainly interested in the panel view code. So we have the views with the panel view, then the panel view code, which is in C++ and finally the containment, which is in QML and JavaScript. So let's look into them. First one, which I want to talk about is the QML code for the view. It's actually pretty short for code standards, just 250 lines. And let's see what this says. So first of all, this QML file has a property that is the containment. This one is the actual panel containment, which is pretty important to have. Then we have the panel mask, less interesting stuff. And then we have, as a QT object, this private swapper. And we'll see later what this does. So we have boolean property to see if this is a vertical panel and this is directly taken from the containment information. We check if we have the containment and if we do, we check what form of factor it has. And then we have the spacing at minimum size because if you look into the panel when you edit it, you see that it has a margin. And if you scale down the panel, so you can see that that margin shrinks because it would not make sense to use always the same margin when the panel is big and when it is very small. Because otherwise, when the panel is small, you have super small icons when you could have just bigger ones using a smaller panel. Sorry, margin. So what we do is to calculate this value, spacing at minimum size, which basically says this is the least amount of top padding. Actually, it is, let's say, the maximum amount of margin that you can put. If you have too much margin and the margin is bigger than this value, then the margin will be shrink down because otherwise the icons would not fit. And all this is used is just down here. So we calculate the top, bottom, left and right paddings, margin. And we do this by taking the actual margin from the SVG where the margin is defined from the plasma theme. And then we use minimum to take the minimum between those two. So this one acts like a top number which you cannot go past. And the fixed margins are taken from the SVG, which is this one. And this component, plasma core dot frame SVG item, sorry, is actually from plasma framework. You have this plasma core, not here, but somewhere. I don't remember all of the stuff. But it's around here, somewhere. OK, it is in the declarative imports directory. The core directory is plasma core. And this frame SVG item is this frame SVG item. So this is much longer code, but we don't really need to know what this does, except that it actually loads the SVG from the plasma theme and not draws it. This doesn't actually draw the SVG. This just loads it into memory. And what we do with this SVG is to read the margin. And that's it. We don't actually draw it on the view. The drawing is done later on. So we can then see that we have the task manager. So what you might ask, what is the task manager doing here? This is not actually the task manager, but it is a model that we use to know information about the virtual desktop and the activities. And we need to know about these two to actually know if a window is maximized in this desktop and in this activity. And why are we interested if a window is maximized or not? Well, because we need to provide adaptive transparency. So a maximized window will make the panel opaque. And this is something that we need to know. So we take the virtual desktop information, the activity information, and then we sort all of the visible windows based on whether they are minimized so that they are not minimized, so only the open ones. And then we filter by the fact that they are not maximized in this screen and in this activity. And of course, if there are any, the panel will be opaque. Finally, we have these other two frame SVG items, which are actually used to draw the panel. But we have two of them, so you might ask, why two? Well, one is used to draw the normal panel, and the other one is used to draw the opaque one. So this is a translucent item, and this is opaque item. And the panel will switch between the two based on whether they are maximized windows or not. So what we say here and here is that the borders that are enabled are the borders that are enabled for the panel, which is basically, in this case, the top one, because the bottom, the left one, and the right one are covered by the screen just ends there. So we don't have a right, bottom, and left border. And then we say, uncourse field parent, which means take as much space as it's needed so that it actually fits the panel view. And then we have the image path, which is where we actually take this SVG from, which is widgets panel background, and the solid widgets panel background for the opaque one. So then finally, we have the transitions, but yeah, these are just to make a transition from the translucent one to the opaque one. So basically what we say is that we give an opacity to the opaque one, and we make it appear or disappear based on whether there's a maximized window. So this is the transition from opaque to transparent, and this is one from transparent to opaque. And then we have this little bit of code that actually reads the opacity mode of the panel and checks out if it should be transparent, opaque, or adaptive, and if it's adaptive, it will actually check the window model count to see if any windows is maximized. And if there is, then we go for an opaque panel. Otherwise, transparent one. If instead the panel opacity mode is always opaque, we always choose opaque, otherwise, we always choose transparent. Then there's also this display hint, which is basically saying that we need to be opaque also not only to the panel, but also to the applets inside of it. So what we're saying is tell the containment, which in this turn will tell the applets that the desktop is either fully covered or it isn't. Then we have the states. We have two states, one for when the panel is opaque and one for when the panel is transparent. So of course, as we've seen before, we can make a transition from one state to another and later on, I think later on, where is it, sorry. Actually, not later on, right now. Yeah, it's used to the transition between those two. And then I got lost. We have this function which adjust the prefix, which basically says that if we are a bottom panel, like this, if we are a bottom panel, then we are interested in the prefix south, mostly as an example for the text manager, because if you actually go see the task manager code, you have a version of the task manager for the bottom, one for the left, one for the top, and one for the right. And their names are North, Sud, East, and West. So we need a function that says, okay, if we are on the left edge, our prefix is going to be West, if we are on the top edge, it's going to be North, and so on. The default prefix, if we are not in any position, which should, I guess, never happen, is just an empty prefix. Then we have this uncontainment change, which basically says whenever we change the containment item from one panel to another, which again should rarely happen, if not like when you actually turn on the EuroPC and you switch from having no panel to having your panel. So this runs and when the containment actually changes, so when it's set, you set the parent of the containment to this item, this empty item, then we set it to visible so that we can actually see the containment, which remember is what actually deals with the panel, we'll see it later. And then we say that it should feel the containment parent item, which is this one. And then we also adjust the prefix so that we know which prefix to use. Then finally, we have a binding from the property panel length when containment value, blah, blah, blah. So basically what this says is that the length property of the panel only exists when the containment is a set and its value is that if there's no containment, then return, if there's a vertical panel, then return the containment layout preferred height. So if there's a vertical panel, the length is going to be the height. And if there is an horizontal panel, then return the width, because the length of the panel is going to be the width. Then we have this other binding about background hints. And again, what this says is that, well, it just reads the background hints property of the containment, so that's about it. Then finally, as our last piece of code, we have this item, which is the containment parent, which is just an item that we use to say, okay, our containment is going to go in here. So it is like containment here. And when we actually run the code, we are going to actually move the QML object of the container inside of here. So this is the containment. Sorry, this is the view, not the containment. And now we can actually give also a look to the C++ code for the panel, which is this one. And this one is quite long, it does lots of thing. And I'm not going to showcase each one, each property, but let's just say that it covers all of the properties of the panel. So we have the maximum length and the minimum length that the panel can have, the thickness of the panel, the alignment, whether it's on the left and the center on the right, the visibility mode, whether, I don't know exactly what this value is, but we also have the opacity mode, whether it's adaptive, always transparent or opaque, the background ins and so on. So we have a bit of code that actually reads the values and sets them, and then we have all the functions which actually we can better showcase from the H file in here. So we have many properties that are actually readable from QML to, I think, this is what Q property, yes. That is, that are also readable by QML also. In general, there are Q properties, it's not just QML. We have the alignment of the panel, which again left, center, right, the offset compared to that alignment, the thickness of the panel, the length and so on, all of the properties of our panel. Then we have, yes, the enumerations for the various values of the above Q property. So we have the visibility mode, which can be normal, auto hide, let the windows cover and windows go below. So now I actually know what the visibility mode is, and there's also explanation about it in the comments, the opacity mode and so on. Then we have the functions to actually read those values such as the thickness and also set them. These values are referenced in the Q property, so same thing. And then finally, we have the actual functions. We have the resize event, the show event, move event and general event. So this is event handling. And if we actually take this function in the actual code, there's something interesting. And that is, I showed it last time, that this part is, what this part is saying is that if the containment, which I can only remember is the part inside of it, contains the position of the mouse, sorry, if it does not contain the position of the mouse, then move the event, let's say the mouse, it's as if we're moving the mouse event inside of the containment, so it is still registered because the containment is actually a bit smaller compared to, no, the containment is actually just as big, but the outlet are smaller because they have a margin. And if you click outside the margin, they still get triggered because we have this piece of code that redirects the mouse input inside of them. So what else? We have some signals, the signals are function that are called when something happens and you can connect these signals to some slots to make those slots be called when the signals are called. So we have a signal for when the alignment changes, the offset changes and so on. We have the queue slots, which again can be linked to some queue signals, not necessarily these ones. And this one is for position in the panel, I guess. This one is restore, show temporarily. We could see the code for each one, but it's not really interesting. And then finally, we have all the actual values, the offset, the length that are read with the functions that are above. So this is the panel view. Again, it's pretty useless to see all of the C++ code line by line because you only work on the part you're interested in, but it's just to give an overview. And then finally, we can look into the final component, which is actually the containment, which is this one. And remember that the containment is inside of the view and that it holds the applets. So we can see that the containment is as the size, is this the right containment? Yes. We can see, okay, let's start from here. Again, I want to explain every line, but we have the frame SVG item as before. One is for the normal SVG and one for the thick SVG. So the difference between these two is that the normal one is this part on the left and the thick one is this part on the right. And the link between them is the margin separator. We switch from the normal one to the thick one. As you can see, the margin changes from small to bigger. Now, these two are not actually drawn. They are just to read the margins of the small one and the thick margins. So again, not drawn as before, but only to read the margins. The actual drawing of the panel is in the view in these two items, not here. So we have another couple of properties of our interest, like whether margin areas are enabled, whether we have, sorry, not whether, but the property that holds the actually highlight SVG to draw the highlight. And then we also have this spacing at minimum size that we also saw in the view. It's the same thing. Again, we need to calculate the margins, which means that we need to also calculate here what is the maximum value of the margins. And then we have some code to add an up-let, taking as parameters the up-let and the X and the Y where it has been dropped. And what this does without seeing like each element is that we are looking, so first of all, we insert the item before the DND spacer if there is one. The DND spacer, I think, I got a bit confused on this thing is the spacer that you have when you drag something. You can see that like there is this big empty space and this is the drag and drop spacer. So I think that that's what it does. Sorry, I dragged the, oops. I actually accidentally dragged the margin outside. I can't get it back. Okay, fantastic. Nevermind. So let's get back to the code. And then when we insert the element before the spacer, we update the margins. Then we say if there is no drag and drop placeholder, such as if you are dragging in a new element, then insert this container, okay. Yes, because it creates a container for the up-let. All of the up-lets are inside a container. So we insert the container in the X and Y coordinates that are given. So we first check if there's drag and drop placeholder and then replace it. Otherwise, we just use the position given if they're valid, so more or equal to zero. If they are not valid, then fall through to determining an appropriate insert position. There's a long like fix me to do here. This is not in the interesting case. So let's forget about it. Then we have a checklist spacer, which is a function that I admit I did not really understand. So forget about this one, sorry. And then we have some setting up of this layout manager. And the layout manager is the JavaScript code that we have here. So what we are doing in this component uncompleted, which is, which runs as soon as the panel is loaded, is that we set the plasma to the plasma, the route through the route and so on. So an interesting stuff. So that then we say, when we start dragging something inside of the panel, if the plasmoid is immutable, which means that we are not in edit mode, then ignore the event. Otherwise, if it's horizontal set the fix that we, well, this doesn't seem interesting, but the interesting part is this one, if you come in dragging something, insert the drag and drop spacer into the position that was given, which means that if I start dragging an applet inside of the panel, that this drag and drop spacer will appear. You see that there's a spacer. This is the drag and drop spacer. And of course, if we stop dragging and we actually insert the applet, the drag and drop spacer will be replaced with the applet as we've seen in the code before at applet like this. So let's also remove it because I don't actually want these activities applet here. And then we can see that the on drag mode, same thing, we start the dnd spacer to the event x and y. And when we leave the drag leaves the panel, we just remove the drag and drop spacer by setting its parent to root. And then we say that the width and the height of this drag and drop spacer will be zero and zero. So it disappears. But when you actually drop something inside of the panel, then process my data, blah, blah, blah, accept the event, then, oh yeah, this is actually all not interesting stuff. It's unled somewhere else interesting, which is probably here, which is another containment. This is using the containment API and it says when you add an applet, then call the add applet function at the x and y given and save the new layout to file so that when you restart your system, it's still like that. Similarly, when an applet is removed, call the remove applet function, which is not above. It's either below or in the JS file. So let's see if it's in the JS file here. Now I did not mean to open erst to open a JS file. So close, thank you. And if we drag it to Kate, we can check that we actually have this remove applet function, which gets called, gets called. And what this does is basically that it loops over the children of the panel, which is, in this case, it's called layout. And then when it actually finds the child, which applet is the applet we are removing, then it just destroys that applet, so it's no longer in the panel. So if we get back here, there's also on user configuring change, but this is not interesting. Then yes, stuff like that. Yes, then we have the components. We have this component, which is very important, which is the container of the applet, which is where the applet actually lies. And of course, the container of the applet will actually have an applet somewhere, where is it here, applet, as a property, but also a lot of code. So we can see this code. We have a property on whether this container is in a thick area. So on the right, all of these applets are in a thick area. All of the applets on the left are not on a thick area. And then whether animation are enabled. Then we have the code for the actual handling of filling width and height, if there are a spacer like something like that. And then there's this get merging function, which is to help getting the actual margins. And what this does is I'll just explain it a bit easier, is just it takes the margin from the SVGs that we've seen on the top, based on whether we are in a normal panel on the, or the thick part of the panel. And then it does all the math with, you know, the spacing at minimum size and stuff like that. And then when we actually are able to read the margins, we set the width, the height, we do it three times, one time for the minimum, one time for the preferred, and one time for the maximum. But this should be about the same in all three cases. Let's see if there's any outstanding difference. Yes, in this case, we are basing it on the applet layout, minimum width, preferred width, and maximum width. So the minimum is of course the minimum amount of width that the applets needs to have. The preferred one is how much width the applet would like to have, and then the maximum is the maximum they can have. So of course when we set the width is that we get the root height and the root width and then we take off the left and right margin. Then finally we have these properties old x and old y, which let me check where they're used, not in this file and in here. Okay, so okay, yes, this is for the translations. Yes, so basically we save the position of the item and then when we actually change the position of the applet, then we see what change has been done from the old x and the new x and we save it as a transition. And this both for the x axis and the y one. And then we do a number animation to actually animate these translation properties so that moving an applet is something that's animated and not just that goes from one spot to another instantly. And that's it, this is the container for the applet. Then we have another, this is the one I actually wrote, so it's horrible, just kidding. This is the rectangle height light element, which is this element, the blue line that goes from being small, then gets bigger on the right size and it could technically get smaller again and then bigger. So it needs to be flexible. And I will not explain each property because it's a bit of a complex element. I'll just say that there's like a component and then another component inside of it. So not something you'd want to use. Like if you need to change this code right to me because it's a bit complex compared to what was above but basically what this does is just to draw that element and then we allow for enough customization to have like a top one for the field for the field part, then a step one, which is where it changes from small to big and then a field step, which is basically the part which is not, this is complex to explain, not the line itself that goes from small to big but the part above it and then so on. Then we have the UI components, which is the things you actually see. So we have again the margin around the panel, only left and right if we have a horizontal one and if we have a vertical one, it's only top and bottom because the top and the bottom margins are defined but by the applet container themselves. Then we have this last spacer, which again I'm not sure what was the purpose of it but there's also the drag and drop spacer which again is the one we've seen before when we actually try to drag something inside of the panel. So there's other stuff but then there's this grid layout with this current layout ID, which is where we actually have all the applets. So this is like the actual component where we'll have the applets inside of and then we have like one row and one column but of course that won't be the case when all the applets populate the panel and it's a grid because on the bottom panel, it will be like just one row but on the vertical panel, it will be just one column. So we change one of these two accordingly to the position of the panel and then we have this timer. Again, not interesting stuff. I'll just switch past it and then there's this startup timer which is actually just kind of a hack to make this work and just to run something as soon as the panel is actually loaded. And this is the main QML file. Then we have the config overlay which I won't go through completely but basically this file is about this top part with the AdWidgets, AdSpacer and everything is for when you're actually editing the panel. This is why it's called a configuration overlay. And then finally, we have the layout manager which again was opened in our studio which is not what I want. What I want really, I want to open it with Kate. And the important thing about the layout manager it has a function to restore the panel and the position of all the elements after booting up, function to save all of the updates when you change it, a function to remove an outlet and then insert before, insert after, insert at index, all these functions are also inserted at the coordinates. All of these functions are to actually insert updates inside of the panel at the right position. Then finally, there's this function which is from me, update margins which basically checks each outlet where is it, whether on a thick area or on a normal area. So for each one, it says, okay, this one is still thin area, thin area, thin area, thin area. Then there's a spacer. Then there's the task manager which is thin area. Another spacer. And then here, there is the invisible margin separator. And as soon as it sees this, it says, okay, we need to switch from thin to thick. And now this one is thick, this one is thick, this one is thick, and so on. So we actually take each child and then we set it's in thick area to whether they actually are in a thick area. So this is very important for all the outlets to actually have the correct margin actually. And then what this code also does is to create a new object based off on the rectangle highlight element that we've seen before. So basically what this does is says every time that there is a margin separator, we need to create a component that draws the margin, the blue margin on top and bottom. So it does it one time for this one, then it draws the part where it gets smaller, and then it does it another time for the right part. So we actually have two rectangle highlights element, three if you count the part where it gets smaller at the middle. And that was about it. So this was an overview of the panel. I've said pretty much all of the important code that you need to know about if you want to edit a panel. So if you're interested in developing your own feature or fixing about that annoys you and stuff, this is where you actually want to look at. If you're interested on the appearance of the panel, then that's something else entirely and it's defined in Plasma framework in the desktop theme. Let's take for example, widgets panel background. This is where the actual appearance of the panel is defined. But if you're looking for the code, well, it's this one.