Monday, May 12, 2014

Playing With CPWindow Style

This tutorial is the first practice session for the topic of CPWindows, which is discussed in the overview found here: CPWindow, the start of all View Hierarchies.

Create a new Project

First, create a new project.  If you installed the developer's edition of Cappuccino, it is as simple as navigating to your web root directory and typing "capp gen WindowStyle".  If you downloaded the StarterKit, then copy the example "Hello World" application to a new directory, and name the directory "WindowStyle."  Regardless of whether you used capp or copied the starter kit directory, loading the new Cappuccino page in your browser should display the "Hello World" text that we will learn to expect from all new Cappuccino projects.


Creating Windows

The very first window that the Photo Album Tutorial has us create is a "Borderless Bridge Window".  The Bridge is the connection between your cappuccino project and the user; in other words, the Bridge is the browser itself.  A Borderless Bridge Window appears to be a blank page that expands to fill the entire browser window.  Later, we will see that we can use this "Borderless Bridge" concept to expand the window to fill any space, including other views or sub-views.

This Borderless Bridge Window, however does not give one the opportunity to really appreciate what the window is providing, so we are going to play with the concept a bit.  Open the AppController.j file in our WindowStyle project using your favorite text or code editor.  I use Vim, because it is universally available on all linux or unix based systems like Mac OS X.

You will see that the variable theWindow is set to a CPWindow object which is already set to the "Borderless Bridge Window" view style.  What happens if we play with that setting?

Using the Cappuccino API Documentation, we can find the CPWindow object, and if we look carefully at the files that are available in the left panel, we see that there is a separate file that is used to define the CPWindow constants.  Looking through this file for any constant that has the word "WindowMask", we find a list of all the available window styles that are available to us: 
One at a time, we will try each one by replacing the CPBorderlessBridgeWindowMask string on the "theWindow" variable's object definition.  Before we do that, however, it will be important for us to make some changes to the code.  First, change the CPBorderlessBridgeWindowMask to CPBorderlessWindowMask, and reload your project.

What happened to "Hello World"?!
Did the lack of the Borderless Bridge definition cause the window to fail to make a connection to the "bridge" (a.k.a. browser window)?  Does the Borderless Window require another CPView object in order to display?

Not so much.  The Borderless Bridge Window Mask overrides all size definitions, which is why theWindow is initialized with a CGRectMakeZero() content area.  The CGRectMakeZero() function returns a content rectangle that is zero units tall and zero units wide located at the origin.  The Borderless Bridge Window Mask, says regardless of what the defined area is, stretch it to fill the entire browser window ("the bridge") and fix the top left corner at the top left corner of the browser window.

If we change the CGRectMakeZero() to CGRectMake( 20, 40, 500, 300 ), we will now see our Borderless Window Mask does display data.  Unlike the Borderless Bridge Window Mask, the Borderless Window Mask must have a window size and location definition.  You will find that most of the windows require a CGRect definition, so I recommend defining our window with CGRectMake( xpos, ypos, width, height), and then defining the variables xpos, ypos, width and height with values of your choosing on separate lines.

After making adjustments, my code looks like this:

var xpos = 20;
var ypos = 40;
var width = 500;
var height = 300;
var theWindow = [[CPWindow alloc] initWithContentRect:CGRectMake(xpos,ypos,width,height)
      styleMask:
      CPBorderlessWindowMask
      ],
      contentView = [theWindow contentView];

We have done two things here:  

1) we have moved CPBorderlessBridgeWindowMask to its own line.  I find it easier to play when I have easy access to the code that I am playing with.

2) we replaced CGRectMakeZero with CGRectMake(xpos,ypos,width,height).  Feel free to define your own xpos, ypos, width and height.

Now, you can safely try each window mask and see how each Window Mask affects the display.  I will make notes here on what I find as I play, and hopefully we will find some of the same observations:

CPBorderlessWindowMask


The Borderless Window Mask removes all edges from the window and fits the window to the CGRect object that we specify.  It looks as if the content is off center, but in actuality, we have told the system that we only want to use part of the screen.  The "Chrome" is missing which defines the edges of the window.  We will see this "chrome" come back as we try other masks.

CPClosableWindowMask

The Closeable Window Mask gives me a visible window and a title bar with a functional "close" button.

The Closable Window Mask restores the chrome.  Now the window appears to float over an empty background, and our "Hello World" text no longer looks off-center, as it did when we could not see the border of our window.  The Closable Window Mask added a title-bar which holds a functional closing button.  If you click the button, your window disappears.  Don't worry about that for now, we will learn how to get the window to re-open again in a future tutorial.  For now, it is important to note that the Closeable Window Mask gives us that close button, and we do not need to worry about adding any functionality, Cappuccino does all that for us.

Another thing you may notice, if you have a keen eye, is that the space between the top of the browser's content area and the top of the window appears to be much smaller than the space between the left side of our window and the left edge of the browser's content area.  We defined the location to be 20 units left and 40 units down, so the window should be appear with a larger gap at the top; shouldn't it?

What we see here is actually addressed in the Photo Album tutorial, only briefly.  The content rectangle defines the content area of our window, the "Chrome" frames the content area.  We will find that the content area of our window is positioned at (20,40), and the title bar and shadows are outside the rectangle defined by the 500 unit wide and 300 unit tall area that we specified.  This is part of the reason that I defined the top edge at (20,40).  If I defined it at (0,0) or even (20,20) your title bars would all be cut off and not visible (at least partially).  Keep this in mind as you lay out your pages: if you don't allow space for your title bar, it will not display.

If you are feeling adventurous, try to drag and drop the window.  You will not be able to move it by clicking on the content area, but if you click on the title bar, you will be able to move the window to any location on the browser that you desire.  This is a default behavior of all windows in Cappuccino.

By clicking the title bar, I am able to drag the window to new locations.

CPHUDBackgroundWindowMask

Look closely, and you will see "Hello World" is still present.  The HUD Background is dark and often requires changes to font color for readability.

The HUD Background still has a titlebar and text, although it is very difficult for us to see.  This background is dark!  We can still drag and drop the window if we grab the window where the title bar would be, and the text can be barely seen in the center of the window.  If you have trouble seeing the text, try selecting it with your mouse, and you might see it more clearly.  The HUD Background can be a very cool look, but remember that you will have to change the font colors in order to help your user read the content.

CPMiniaturizableWindowMask


If the Closeable Window Mask gave us a close button, then the Miniaturizable Window mask must add a button that lets us shrink the window and tuck it away on an application bar somewhere.  Perhaps this is the intended functionality, but as you can see, unlike the Close Mask, the Miniaturizable Window mask does not add this functionality right out of the box.  Perhaps later we will see how to use this mask in a way that provides some cool benefit, but for now, we see that it produces a plane window with at title bar and no buttons.

CPResizableWindowMask

Resizable Window Mask lets the user change the window dimensions on the fly.

Resizable Window Mask lets the user change the window dimensions on the fly.

Up till now, if you have tried adjusting the size of the window, you have found that you are out of luck.  The Resizable Window Mask changes everything.  Now, you can change the window dimensions by dragging the bottom or right edges.

CPTexturedBackgroundWindowMask

Textured Background Window Mask is the default mask for most non-specified window masks.
What happened?  This window looks much like several of the other windows we have seen so far.

Later, I will show you how Masks can be combined.  What we are actually seeing here is the result of what happens when not enough masks have been provided to define the chrome.  Cappuccino uses the "Textured Window Mask" as a default window "chrome" whenever the user fails to specify the look of the window.  This is why when we defined that we wanted a closable window, we got a window that had the same general appearance as this.  Cappuccino said, "Okay, you want the window to be closable, but you didn't specify how it should look, so I'll give you a Textured Window."

The "texture" is a flat-color which is off-white and sets the window apart from the rest of the unused, white page.  The textured window has a title bar by default, which is used as a handle to move the window around the page, and it cannot be resized unless the resizable mask is specified.

CPTitledWindowMask

The Titled Window Mask accents the title bar by making it just a little darker for a Textured Background Window.
To demonstrate the Titled Window Mask, I jumped ahead a bit and added another window with just the "CPTexturedBackgroundWindowMask".  You will see that the titled window mask makes the title bar just a little darker than it would otherwise be.  The effect is negligible but present.

This mask does not have any effect on the HUD Background, and overrides the Borderless Window to have a Textured Background.

Combining Masks In Cappuccino

If you are not familiar with the concept of "masks," you should take a moment to read the blog article on "How Masks Work."  If you already have a basic understanding of masks, then this next part should flow naturally.

Cappuccino uses masks to store your requests about how you want your Window to look in a very compact bit string.  As a result, you are able to combine any Masks that you feel fit your need into a single request.  We combine masks by creating an equation that lists all the masks we want combined by a bitwise-OR operator ("|").

In practice, we do the combination and pass the result of the calculation within the object definition like this:
  var newWindow = [[CPWindow alloc] initWithContentRect:CGRectMake( 25, 25, 100, 200) styleMask:CPTexturedBackgroundWindowMask | CPClosableWindowMask | CPResizableWindowMask];

However, we can just as easily define the style mask separately.

var __CustomClosableResizableTexturedWindow = CPTexturedBackgroundWindowMask | CPClosableWindowMask | CPResizableWindowMask; 
var newWindow = [[CPWindow alloc] initWithContentRect:CGRectMake( 25, 25, 100, 200) styleMask:__CustomClosableResizableTexturedWindow];
When the styleMask you specify lacks information that is necessary, Cappuccino assumes default values for the missing components.  This is why your CPClosableWindowMask looks the same as the a CPClosableWindowMask | CPTexturedBackgroundWindowMask.  The CPTexturedBackgroundWindowMask is assumed by Cappuccino when no visible chrome style is specified.

In order to see what is possible, just play with different combinations of style masks to see what you can create.  Sometimes, Cappuccino will override your request, because the designers have determined your request is not practical. For example, if you try (CPClosableWindowMask | CPBorderlessWindowMask); Cappuccino will override your request and give you (CPClosableWindowMask | CPTexturedBackgroundWindowMask), because the borderless window has no shape or definition on which to place the close button.

---------------
This concludes the Playing with CPWindow Style practice session.  Go back to the CPWindow overview article to find other fun, interactive, informative lessons about Cappuccino.

No comments:

Post a Comment