More Cross Platform Graphical User Interfaces in C++: Custom Controls

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
hello given the surprising response to my previous video about cross-platform GUI programming with dual UX widgets and C++ I thought I would follow it up with a slightly more advanced example and this video assumes that you have seen the previous video so I'm just going to get stuck in and started even though this video shows an application being built the application isn't the focus of the video instead what I want to explore is how we can harness the power of a library such as WX widgets to rapidly develop applications the application in question is a desktop version of the sprite editor that I use from my one lone coda console game engine which I've used in many videos you may remember that this was entirely based in the console and it wasn't very user friendly but it's simple enough that we can rapidly create something else using dual UX widgets I thought it might be useful to demonstrate the final application before we start coding it and so here is the sprite editor with the 16 available colors along the top selectable and a special color called alpha for transparency in the sprite there's a menu bar too and we can click file and we can open an existing sprite so let's open something from the role-playing game this was the sprite sheet for the main protagonist in that application and what we can see it is it opened in its own little client window at the bottom we have a scroll bar which we can zoom in and we can see scroll bars to allow us to pan around the image the pixels are individually separated and transparent pixels are marked with this crosshatch pattern editing is very simple we can select a color from the palette at the top and simply click on the pixels we wish to edit and if we want to change them back to transparency we can do that too the goal here is not to provide a feature-rich application but to demonstrate what parts of WX widgets we can leverage to our advantage because this is a multiple document interface we can open several sprites simultaneously and each of these sprite exists in their own little self-contained editor and all the things you expect of a Windows application are available to us we can maximize and minimize windows and the behaviors remain consistent we've also got the window option in the menu bar which allows us to position the windows in useful ways so we can compare the sprites perhaps I've set it that so when we're at a particular zoom level we can't see the barriers between the pixels so it looks more like an established image we've also got the option to create a new sprite in this case it's 16 by 16 pixels and we can also save sprites finally we can exit the application so you might be thinking that all of that is going to be a great deal of coding well in fact it's not the entire application excluding white space is about 250 lines of code and we can achieve this because I'm going to let wxwidgets do most of the hard work for us so let's get started I'm going to start with the skeleton wxwidgets application that we developed in the previous video so this just consists of two classes C AB and C main C app is used to launch the application and C main is a frame and we'll just run this to remind ourselves as you can see it's a blank frame I've set up the title and the dimensions of the window already I won my main frame to be the type of frame that can support lots of children frames this is called a multiple document interface and it's somewhat old fashioned now but quite useful for tool development so instead of inheriting from WX frame I'm going to inherit from an MDI parent frame from WX widgets this means I also need to update the body of the class when we run this we'll see it's not really any different except there's a sunken border around the outside implying that this is a container that will support something else and in fact it's going to support MDI child frames to begin with the main frame is going to consist of two more elements a toolbar and a menu bar so I'm going to create point of variables to those two types a menu bar is easily added we just need to create one and we add it to the parent frame using the set menu bar function however it doesn't consist of anything at the moment we need to add menus menu elements to it the only functioning menu I'm going to have is the file menu that will allow us access to new open save and exit and I'm going to add these directly so that just strings using the append function of the menu file object this number is a unique identifier for that particular object now a proper programmer would go away and create lots of constants in a file somewhere with meaningful names but given that we're just rapidly throwing this together I'm just going to hard-code the numbers indirectly once we've created the file menu we need to add it to the menu bar and so you can see that we can construct quite detailed menus just by appending menus to menus to menus to menus to the menu bar so let's take a look at our menu and we can see wxwidgets has handled it all for us there it is but nothing happens when I click on anything we're going to need to handle menu events in WX widgets when you click on an item in a menu it's a command event that gets sent so I'm going to have for event handlers for a new open save and exit and in the event table at the top of the main CPP file I'm going to add in links between the unique identifier of an object and the function it should call when that object throws the event so here we can see our new menu item with ID 10,001 when that gets clicked ID 10,001 is linked to calling on menu new I'm going to let visual studio handle the creation of all of these function definitions for us and we can see it's added them to the bottom of the CPP file I'll fill these in as we go along but the one I can fill in straight away is the exit button all I need to do is call the closed function which will terminate the main window and don't forget if you don't want to terminate an events travel up the event hierarchy call the event skip function this allows other things to respond to the event happening let's just see if that works so I can click file and click on exit and it's closed the application good to implement the child windows we need to create a new class that inherits from a WX MDI child frame I'm going to call it see editor frame and I'll give this class access to WX widget and tell it that it's inheriting from MDI child frame I'm also going to replace the default constructor because we want a constructor that will link the child frame to its parent I'm going to pass along a name string which will be used in the title bar of the child window and I'll set up the child window just by calling the constructor of the classes inherits from passing along the parent argument I don't care what the ideas but also setting the titlebar name in my main window I'm going to include the editor frame and I'll just do a quick test to see if we can create child windows in the menu new event handler I'm going to create a new object of type C editor frame and pass a longer name test and I'm going to associate the frame with the parent that's created the frame but it's not shown it I'm going to do that explicitly and then I'm going to be a nice programmer and allow other things to handle this event if we're quiet so let's take a look I'm going to click on file new and we can see we've got a child window inside our parent window and wxwidgets is handling all of the magic for us regarding the scroll bars popping in and out at the edges of the screen it's also added this additional menu which will handle the windows internally so let's add a few more and we can cascade them we can tile them and we can even select them based upon the names that we've specified awkwardly I've called them all tests in this case but the idea is we can load up the files and use the file name to uniquely identify each window other things work too so if I maximize one particular child window it becomes the dominant one within the main frame and it's got its own restore and minimize options and I think this is quite cool we've barely written any code and we've got quite a sophisticated application already the second item in our main frame was a toolbar now I'm rather cheeky using the toolbar to select colors but traditionally this would be also things like file open and edit parameters settings and all of the little icons you see at the top of the screen I'm not going to add icons to it I'm just going to add regular buttons to it and color the buttons according to the color that they represent in WX widgets the frame itself is responsible for creating the toolbar for you I can do this by calling the create toolbar function and I'm telling it that I want a horizontal toolbar there are all sorts of different toolbars including ones you can pick up and move around and dock with these sides and bottom at the screen now for those unfamiliar with the console game engine there's a little peculiarities it uses characters as pixels and it's limited to the colors that can be shown in the command prompt and we can see the colors by looking at the properties of a command prompt and going to the colors tab there they are and there are 16 main colors and we're going to add an additional one which I'm going to call transparency or alpha and then to hard-code in the colors as a palette specifying the red green and blue contributions to the overall WX color these are in the same order as they are in the command prompt instead of adding 16 buttons by hand I'm going to use a loop I'm going to create a new button I'm going to set the toolbar as the parent and I'm going to create an ID based on its position within this array we did a similar thing with the minesweeper game in the previous video and I'm being explicit about not giving the button any text I'm going to color the button by setting its background color and then I'm going to add the button to the toolbar we need one more additional button to represent the Alpha color so I'm just going to do the same again but this time because I can't display it as a color I'm going to use the text alpha I'll add it to the toolbar and when you've finished constructing your toolbar hierarchy it's important to call the toolbar realize function which instructs wxwidgets to go and configure the toolbar visually and spatially depending on all of the controls and children that have been added to it let's take a look and there we go we've got our toolbar of buttons and we can select them we've not added any event handlers to these buttons just yet but we will as with menu items clicking buttons in the toolbar fires a command event so I'll have an event handler called on select color and my intention is that when a color is selected the active child window within the parent multiple document frame will be informed of this color choice and in this scenario active window means whichever one has input focus let's just add a body definition and instead of adding loads of different event handlers in the event table at the top of the file as with the minesweeper game I'm going to do this dynamically in code by calling the connect function so I am connecting the button that we've just created to the event handler we've just defined I'm going to connect all of the buttons to the same event handler because they've got a unique identifier I can sort them out inside that event handler and I'll also connect our alpha button to where we are right now is quite typical of many GUI development projects you end up with lots of functions with no contents and as you're developing your application you add the content selectively the editor frame consists of three main components firstly I'm going to add a status bar to it which is this thing at the bottom of the window it gives you a bit of an area where you can drag the window size but you can also display interesting text to the user rather than just text I'm going to go one step further and add a slider control to it which allows the user to select a particular numeric value between a minimum and a maximum the second major component is the editing window itself it will frequently be the case that the window is too small for the size of the sprite we want to show so the user will need to pan around the sprite and that means we'll need some scroll bars along the bottom and along the side to allow them to do so one option is to construct these scroll bars manually and manually change the range in the size depending on the size of the window and other properties of the sprites however w.x widgets has a control for us that allows us to scroll an earlier around so that's quite nice but du/dx widgets doesn't have a control that allows us to edit a sprite so we're going to create a custom control which means we're going to be responsible for handling all of the Mouse events that occur handling how it's drawn to the screen handling the occasions when it gets resized generally all of the things that a control needs to respond - rather than creating a control from scratch it's always better as it takes something that is almost what you want and then customize the behavior so I'm going to add a new class called canvas which will be our custom drawing and display control I'm going to give canvas access to WX widgets but I've also included the V scroll header file from WX widgets and that's because my canvas is going to inherit from a control called WX HV scrolled window and this is horizontal and vertical scrolled window and this particular control is quite useful if the size of the control is larger than the visible area of the parent that contains it it will automatically add the scroll bars for us and it will also automatically handle the panning depending on the positions of the scroll bars as usual WX widgets we need to modify the constructor to link it to the parent we're going to be dealing with some events in this class so let's declare our event table now here's a little tricky part the HV scrolled window class is in fact abstract it requires us to fill in two functions and these are on get row height and on get column width and if you're wondering why I know this the WX widgets documentation is very thorough indeed and so when looking at the entry for this class it explicitly states you must provide an implementation of these two functions and that's quite understandable this black rectangle represents our HV scrolled window control or as we're now calling it our canvas the size of the canvas greatly exceeds the viewable area of its parent which I've drawn in blue the parent really has no idea how big this canvas is indeed it's actually infinite in all directions so we need to give it some meaningful information for it to determine what the scroll bar should look like for example we might want to supply it with the width of the canvas and the height the control doesn't actually see width and height what it sees is rows and columns and it sees rows and columns of our to resize cells and that's great for our sprite editor because a sprite is really just a 2d matrix of colored cells and the size of those cells can be enlarged or shrank depending on the zoom level so if we provide the dimension of the canvas in cells or sprite pixels and we also provide the size of an individual cell in screen pixels the HV scrolled window can go and calculate all of the scroll bar parameters necessary to allow us to pan around the canvas but in order for it to do that it needs to call these two functions to get the cell dimensions so let's start adding some variables to our class I'm going to have one Roble called pixel size I'm going to default it to 8 and this is affect how many screen pixels a single cell of the sprite is going to occupy and I'm going to add a setter to allow us to externally set that number in the canvas body let's just finish off the constructor and call the constructor of the base class this will link our canvas to the child window we also added an event table to this class so let's add the event implementation here the two functions we must provide an implementation for simply need to return the size of the cell and our cells are always going to be square and they're always going to reflect the current zoom level and I'll just quickly fill in the body of our set pixel size and now this is where we start thinking about the nature of a custom control externally the size of the pixels being displayed by the canvas can have their dimensions changed and any change like that will be reflected visibly on the screen but that means we must force our control to update itself we must in some way notify the base class that we've derived from that it needs to recalculate its scroll bars and I'm going to use this rather odd looking syntax to do so well what does this mean if we look at the documentation for the HB scrolled window we can see somewhere along the line it's actually an object that inherits from two other objects it is indeed multiple-- inheriting now some of you may think that that is the worst thing in the world others may never have heard this concept but it is completely legal to allow a class to inherit from two other classes in this case these classes are helper classes one that will handle the vertical scrollbar and one that will handle the horizontal scrollbar and it is within these classes that the calculations for how the scrollbar should look are performed so now I have set the pixel size I then tell it to calculate its scrollbar and during that calculation the class will call the on get row height and on get column width functions to get the information that it needs when something physically changes in WX widgets you might need to force it to redraw and you can do this by calling the refresh function all windows and controls have a refresh function just to see if this is working I'm going to hack in some dimensions for our canvas using the set row column count function for now I'm just going to hard-code in 40 by 40 we know that our pixel size is going to be 8 so this is potentially going to give us a canvas of 320 pixels in both dimensions I think we've got far enough now to add to the canvas to our editor frame so I'm just going to include it and create a member variable for our canvas constructing the canvas is trivial I just need to associate it with the frame as its parent you may notice that I've not used any sizes or precise positioning information to do this that's because by default WX widgets will just expand the control to occupy all of the space in the parent and that's what we want with the canvas let's take a look so we know that our canvas is 320 pixels by 320 pixels so if I shrink this window down when it gets small enough there we go we'll start to see the scroll bars appearing for us that's because we've gone below that visible range and even though we can't see it if I move these scroll bars across it's actually offsetting where it's drawing that canvas we also wanted to add a status bar and a slider to control the zoom creating a status bar is very similar to creating a toolbar you let the window handle it for you and in this case I'm asking please give me a status bar that has two regions I just want it to look like a regular status bar and I don't care what the identifier is and unusually I'm going to add my slider to the status bar now in the previous video there were quite a lot of comments about saying how insane I was for coding the GUI myself and why not use an editor well the truth is I do use an editor when I'm making standard applications of course I do it saves a lot of time however most editors don't always provide the complete function set available for that particular API and so the popular editor for WX widgets is WX form builder won't let me add a slider to a status bar but because I've learnt how the GUI is structured in code I can get around the limitations of editing tools to produce precisely the applications that I need so yes it's important to use an editing tool to make things quick and easy but it's also important to know what it is the editing tool is actually doing because it won't be perfect anyway I've added a slider I've added it to the status bar and I've given it a unique identifier again and I've told it the default value should be 8 and that the range of the slider is 1 to 32 naturally if somebody changes the value of the slider we need to respond to that so let's add an event handler for the slider and as usual it's just a command event the value has changed do something here is the event handler for the slider and when we do change the value of the slider I want to update the text in the status bar and I can do that with the set status text and here's a little peculiarities where I just want to display a number and a string to represent the zoom level you might want to display all sorts of things in this status bar but I'm not really making a fancy application I'm just showing you how to glue bits of wxwidgets together remember we created two sections on our status bar the first section will contain the slider the second section will contain this text and that's what this little one at the end is indicating but as well as just updating the text I also want to set the pixel size of the canvas and it's telling me it's inaccessible here because I've set it to private there we go don't forget a good old event skip at the end of your event handler now we just need to add the event table to link the ID to the event handler function I'm going to be sensitive to the slider using the event slider macro and all those red wigglies on the previous page indicate that I've not declared an event table in my editor frame class we're now ready for the real fun and games of creating your own custom controls what do they look like and this means we need to break into the drawing routines that wxwidgets would usually use to render the controls well this is done by overriding two functions on draw and on paint on paint is called whenever the control needs to draw itself to the screen so this could be when it's rip fresh or after it's been resized or when a window has been removed from on top of it and it's become visible whenever it needs to update its screen presence on draw contains the actual drawing code for the things we want to display so let's give these some bodies here we can see that the request to redraw the window is an event that makes sense but what exactly do we draw - well in Windows and other operating systems there is the concept of a device context and this is a blank memory surface and this memory surface is interpreted as being a visual display in this instance specifically in wxwidgets I want to use a WX buffered paint device context and I need to get that by including these files should point out I'm not hacking anything here this is the established way to draw your custom controls I've asked the UX widgets to create a device context of this control the canvas then I need to call the proper DC function to get the device context ready for rendering and then I'm going to call the ondraw function I've created up here buffered paint DC inherits from DC and it's common practice to separate the ondraw function because there are different types of DC depending on the scenario in this case I'm responding to the on paint event but there are other events and other scenarios through which I might want to draw the same thing but it's not a memory surface to be displayed on the screen for example if I wanted to prints on I still want to draw it the same way but the device context is different it's suitable for a printer instead of the screen by default wxwidgets will also try and draw things in its own way they'll want it to look and feel like a regular control however this one is completely custom so I need to instruct WX widgets to not do that and I can do that in the constructor of my canvas class by calling the set background style and setting it to style paint so this is telling wxwidgets I'm in control not you we need to be sensitive to the paint event being cold because we don't know when it's going to be called so in the event table I'm going to be sensitive to event paint and call-out on paint function you'll notice here I don't need a unique identifier because there is no unique identifier to provide it's just going to repaint when requested now WX widgets provides quite a significant suite of drawing tools above and beyond just drawing simple rectangles and outputting text we will barely scratch the surface of it here but the first thing I like to do is clear the existing device context this is going to erase the whole screen and you might think well hang on if we're raising and then drawing things we're going to see some flickering but because I've chosen a buffered paint DC this is effectively wrapped a double buffer for the graphics much the same way as the console game engine and pixel game engine does it implies that the screen will only be updated when the ondraw function has finished and now I'm going to throw in two rather bizarre concepts the idea of a brush and a pen you can think of a brush as being the descriptor that describes what the inside of a shape looks like what color is it what texture does it have and the pen defines the outline or the boundary of that shape these are two well-established concepts in the history of Windows programming and it's important to understand their significance because this isn't like rendering with the pixel game engine where we're just drawing pixels to a memory surface we're using the built-in tools of the operating system to draw it in the way that the operating system expects this means we can get things to look very shiny and compliant but we pay a slight performance penalty however for our application that shouldn't be a problem I'm going to set the properties of the pen to draw gray dashed lines so we can see the boundaries between the two pixels and I must commit the pen to the device context before I draw anything for now I'm just going to use the brush that I've already grabbed from the device context and I'm going to draw a rectangle let's take a look and see if things are still working so I'll create a new window and there we go very nice we can see a rectangle has been drawn with a light grey dashed boundary but more importantly this allows us to visualize what's happening with our scroll bars so if I make the window a bit smaller than the viewable area we've defined we can see that the rectangle is actually panning in relationship to the scroll bars this now means we can draw all of the pixels in our sprites as rectangles as is a good rule of thumb whenever doing anything with graphics only draw what you can see and the hv scrolled window control provides two functions which we can use to get to the visible extents of the screen and so here my s variable will represent the top left visible cell and my e will represent the bottom right visible cell this means with two nested for-loops I can draw a grid of cells in the visible area so let's take a look well nicely I can see the 40 by 40 grid of cells that we've artificially created for now but nicely I can also zoom in and because we change the pixel size the size of the visible rectangles changes but as we're zooming our scroll bars for panning also changed too and even though it's a little tricky to see I can in fact pan this grid around we don't have sub cell panning enabled because we've told our scroll bars that our cells are a fixed width in this case 30 so we'll always guarantee that one cell aligns with zero zero in the top left functionally this is enough for our application believe it or not we're now done with the more complicated parts of the application the rest is now linking it to the sprite file format used by the console game engine I'm going to cheat a little bit here I've just couldn't paste directly from the console game engine header file the OLC sprite class and I'm doing this because it conveniently sets up the variables we need and the functions we need to sample particular pixels and save it and load it from files I'm going to add two additional variables to my editor frame class one is an object of type OLC sprite and now this does work this is just intellisense being a little slow and the second is a pointer to an array of unsigned chart and the way I'm going to make this work is that each of my pixels in my Windows application is going to be represented by an unsigned char I only need the numbers 0 to 15 to represent the colors and I'm going to use the number 16 to represent transparency that's in the Windows application the OLC sprite format doesn't store it that way so we're going to need some transformation between the windows and the console versions the editor frame is also going to present some more functions save open and new and we also know that we'll need one later for setting the selected color let's give these some bodies the new function is tasked with creating a new sprite so the canvas and the frame will be empty just in case I'm going to delete any existing sprite data and then going to allocate enough unsigned chairs to represent the width and the height of the sprite and I'm going to construct an LC sprite of those dimensions too I have the data in my editor frame here but I need the canvas to be able to access this data too and in the canvas header file I'm going to create a function set sprite data which takes the size of the sprites and a pointer to the array of numbers that represent the colors I'll also store a private pointer to the pointer we pass in in the canvas CPP file I'm going to implement sets by data to just locally cache the pointer to the sprite but also set the row and column count of the canvas depending on the width and height of the sprite in effect this has linked up the rectangles that were seeing on the canvas to the values of the array that we've created in the editor frame well it will if I explicitly call it now that we have a data source we can flesh out to the drawing routine in the canvas the particular color of a pixel can be extracted from the array and as we have in all one long code of videos we have Y times width plus X to turn a 2d coordinate into a 1d coordinate since we have an index into the palette of colors I'm actually going to need the palette of colors I'm going to be a bit hacky here we've already created a color palette in our main window we used it to color the buttons I'm simply going to cut and paste that into the constructor of our canvas and instead of having this local palette variable I'm going to add that to the header of our canvas we can check if the color index is less than 16 because if it is it's one of the colors and we'll set up the brush accordingly we'll set its color according to the palette index and we'll set the brush style to solid that means just just paint it as if it were a rectangle if it's not less than 16 then it's probably going to be our transparent color and I can't draw transparency so what I'm going to do instead is draw a particular brush style of a cross-hatched pattern this will look distinctly different to all of the other pixels in our menu new event handler we can now add some additional functionality to construct a new sprite I'm just going to default it to 16 by 16 it would be far more useful to prompt a little dialog here to say what dimensions do you want to create this sprite but maybe that's for you guys to do if you want to try yourself so let's take a quick look at that go to file new and there we have a 16 by 16 matrix of black pixels which is sort of the default sprite now let's add the functionality to select the pixels and colorize them in the editor frame class of our child windows we added the function set color and in our main window class we have the event handler on select color the numeric value of the color can be worked out by looking at the ID of the object that through the event and subtracting it from some offset to give us a number between 0 and 16 inclusive because we constructed these IDs when we created the buttons when the user presses one of these buttons this event handler is called but we want to make sure that at least one active child is available if it is then I'm going to call our set color function on the editor frame child now the get active child function just returns the type WX MDI child frame in order to access this set color function I need to cast the pointer that is returned to this to an editor frame so it becomes available if we look at the definition of our set color function we see it doesn't do very much we need to propagate this information to the canvas so I'll quickly add into our canvas a little private variable of type integer and a setter that allows us to set that variable now we have a situation where the canvas is aware of the currently selected color but we've not actually implemented a method of selecting the pixels in order to draw them now because this is just a demonstration application I'm going to be very simplistic about how I handle the selection of pixels I'm just going to respond to the left mouse button being pressed by adding an event to the event table which implies we need a corresponding event handler now Mouse events are their own thing in wxwidgets and the event itself will allow us to access all sorts of information about the state of the mouse the mouse coordinates that we get are relative to the top left visible portion of our canvas therefore to work out where the mouse actually is in the entirety of the canvas we need to offset the mouse coordinates by the scroll position whenever the left mouse button is pressed above a cell I'm just going to set that cells contents to the currently selected color and this big long line will do this let me explain this to you so here is our sprite array and ultimately it's Y times width plus X like it always is but I'm getting my mouse Cornus in Y and I'm doing an integer divided by our pixel size variable so this will break it down into the individual cell and I'm offsetting that value by the top most visible rope get column count is the equivalent of just get the width and I do something very similar for X take the x-coordinate do an integer divide to give me which column it is and then I offset that column by the left most visible column and all I'm doing is assigning our color variable to that location in the array as when we change the scrollbars we've changed the visible state of our canvas so it's important to call a refresh function and in this instance I'm calling refresh false and this tells WX widgets please don't draw everything behind it just draw what I'm telling you to draw and it's courteous to event dot skip you'll notice we didn't event dot skip on the paint event and that's because we have completely handled the paint event we don't want WX widgets to do any additional painting so let's take a look hopefully it's becoming apparent that really GUI programming is more glue logic programming than actual functional logic so I'm just going to select bright green here and click on a particular cell and we can see it's selecting that cell and drawing it so we can choose different colors great I can change the zoom and it's behaving like a very primitive sprite editor let's just see if the panning is working still now we can visibly see it yep perfect that's great and because we've been capsulated everything in an editor frame I can open a second window and do some drawing in there too one thing I've noticed is when you zoom out really far you can't actually see the content of the pixels so let's change the nature of the pen depending on the zoom level oh but before we do that let's just check our alpha button - yeah there we go so that's that cross-hatched pattern I was trying to describe earlier sand that's telling us that this pixel should be transparent when it's drawn by whichever rendering engine is drawing it changing the pen is very trivial indeed effectively after I've set the pen I'm going to check to see what the pixel size is if it's less than or equal to 4 I'm going to effectively switch the pen off by setting it to a transparent pen this should stop drawing the boundaries between the pixels I think all that's left to do now is to add file opening and saving and yet again WX widgets can help us out here so these are the event handlers for the menu items open and save now rather than manually going constructing a dialog to open a file I'm just going to use the built in file open dialog and this will present a dialog box that windows users will find very familiar or on Linux Linux users will find very familiar and the construction office is quite simple it has a parent and we give it a title open OLC sprite file the next two arguments allow us to set a default path in a default file this third argument describes what type of files should be allowed so in the drop down box in this dialog what's going to appear will only see dot SP our files and here is a text description and we'll use vertical bar to separate that from the actual extension instructable UX widgets to make this into an open dialogue with the FD open flag and I'm also going to let it do some additional functionality for me the file must exist if I didn't specify this the user could type in the name of a new file and we could accidentally open files that don't exist once I've created the dialog object I call the show modal function to make it display and modal dialogues don't allow input anywhere else in the application whilst they're visible if it happens that the user is pressed ok on that dialog at this point then we want to do something and what we want to do is create a new child window and we're going to give it the name which is the equivalent to the path of the file I'm then going to call the open function of the child window which we've not filled in yet we'll do that in a minute and of course I want to show the window and event dot skip saving is an almost identical process but saving sort of implies that a window must already exist so I'm going to check that there is an active child in effect if there is an active child I'm not going to create a new window this time the window obviously already exists but I am going to create a save as file dialog box and it has exactly the same format as before except this time I'm specifying it is a save and if the user is overwriting a file it already exists I want WX windows to sort of notify them of that so they don't make a mistake if the user presses ok we call the save function on our editor frame class and pass along the path so here are the two empty save and open functions let's make them do some work and I'm not going to go into very much detail with this because it's not that relevant to this video very quickly I'm really just going to leverage the OLC sprite class itself to do the hard work if it can't load the file it returns false otherwise we're going to load the file and convert it to content crudely into the format we're using for the desktop application so we're going to take the characters and glyphs and colors in the sprite file and translate them into the sixteen numbers plus alpha used by our desktop application and I'm simply just going to throw that in I mean that's it it's just two nested for-loops that checks what the contents of the file are and does the conversion element by element once we've populated the MP sprite array with valid integer values and then going to set that data to the canvas the save function is exactly the same but also completely inverted and just before I run this spotted a quick schoolboy error in my open function I don't actually create the array to hold any of the data so there we go let's take one final look so now I'll click on the Open button in the menu and it pops up a standard windows opening dialog and we can see it's already filtered to be dot SBR files I'm going to open up the Jerry oaks price hello Dario definitely not an Italian plumber and in fact I'm going to open it twice because we've now got two completely unique instances I set them to approximately the same zoom level I can do side-by-side comparisons of the sprite so maybe perhaps with this version of Jerry OH I want them to have gigantic laser beams shooting out of his eyes who knows it's computer games anything's possible and this is currently the active child so if I go to save and save that as something else so Jerry oh lasers I should be able to go to file open and select Jerry Oh lasers and there we go a third sprite has been open so with very little code indeed we've actually implemented quite a sophisticated application it's not perfect it is purely a demonstration of how you can use the power provided by WX widgets to rapidly create tools but I feel it also demonstrates another interesting principle of using ap ice and it's one of the reasons I don't tend to do it on the channel very much wxwidgets is one of several GUI AP ice and it has its own way of doing things and I think to become a good programmer and to use api's effectively you really need to get into the mindset of the creator of the API it's all very well and good just learning classes and functions within an API but if you don't really understand or spend time practicing how they're all binded together and work together as a fluid machine you're not going to get very far for example in the first video I made the claim that we're using GNU here to create new WX widgets components but we don't have any corresponding deletes anywhere and people could quite rightly questioned how can this be and that's because one of the underlying principles of WX widgets is that components are owned by parents and the parent is responsible for cleaning up after its children and so in order to use this API to it's most effective I need to be very familiar with these rules set in place by the API developers will just send this for a real test so this was the mario kart track that i used in the mode 7 video and it's certainly a very large sprite we might actually get all there we go so it's actually zoomed out far enough now that it's not drawing the boundaries between the cells but it's also lagging a lot and that's because we're drawing so much information here in perhaps the least efficient way possible on a computer so don't take this application as a serious tool it really is a demonstration application but I hope it can go some way into helping you guys create your own tile editors and your own sprite tools and I don't know whatever else as you can see we can quickly throw things together with a bit of glue logic and come up with a satisfying user experience as a bonus because it's WX widgets it will also compile on Linux and other operating systems I will put the source code up for this on the github if you've enjoyed this video a big thumbs up please have a think about subscribing come and have a chat on the discord server oh and one last thing I'm going to be taking a little summer break so it'll be a couple of weeks before my next video anyway take care I'll see you next time
Info
Channel: javidx9
Views: 64,172
Rating: 4.9665551 out of 5
Keywords: one lone coder, onelonecoder, learning, programming, tutorial, c++, beginner, olcconsolegameengine, command prompt, ascii, game, game engine, pixelgameengine, olc::pixelgameengine, wxWidgets, cross platform, graphical user interfces, GUIs, sprite editor
Id: FwUGeV2fnfM
Channel Id: undefined
Length: 44min 58sec (2698 seconds)
Published: Sat Jul 13 2019
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.