The Artima Developer Community
Sponsored Link

Agile Buzz Forum
How To Create A Custom Widget - Get Ready To Display

0 replies on 1 page.

Welcome Guest
  Sign In

Go back to the topic listing  Back to Topic List Click to reply to this topic  Reply to this Topic Click to search messages in this forum  Search Forum Click for a threaded view of the topic  Threaded View   
Previous Topic   Next Topic
Flat View: This topic has 0 replies on 1 page
James Robertson

Posts: 29924
Nickname: jarober61
Registered: Jun, 2003

David Buck, Smalltalker at large
How To Create A Custom Widget - Get Ready To Display Posted: Sep 1, 2004 8:08 PM
Reply to this message Reply

This post originated from an RSS feed registered with Agile Buzz by James Robertson.
Original Post: How To Create A Custom Widget - Get Ready To Display
Feed Title: Pollock
Feed URL: http://www.cincomsmalltalk.com/rssBlog/pollock-rss.xml
Feed Description: Pollock - the next VW GUI
Latest Agile Buzz Posts
Latest Agile Buzz Posts by James Robertson
Latest Posts From Pollock

Advertisement

Today we start the task of displaying our Calendar.

We'll start off with a test, and then go from there. First we'll add a couple of convenience methods to our test class, making it easier to write tests for this widget:

	openWindow
		window := ScheduledWindow new.
		window open.

-+-+-

	openWindowWithCalendar
		self openWindow.
		calendar := Calendar new.
		calendar frame extent: 100 @ 30.
		window addComponent: calendar

You see we're now using the window and calendar instance variables. For now, we'll use the default OriginExtentFrame, and just give it an extent.

A thing to note here is that if we write a bunch of tests with #openWindowWithCalendar, those windows will remain open when the test is over... that's not good. So, we'll write a #tearDown method to automatically clean up after ourselves:

	tearDown
		(window notNil and: [window isOpen]) ifTrue: [window close].
		window := nil.
		calendar := nil.
		super tearDown

We call super because the PollockTestCase has a extras we always want to use for setUp and tearDowns. With that done, we're ready to write our main test:

	testOpenWindowWithCalendar
		self shouldnt: [self openWindowWithCalendar] raise: Error

Now, let's run it! ... OOPS! It got us a red bar! That's not good. If we press the Debug button (or the "List Defects" button and select our failed test and press OK), we see we got a "My subclass should have overridden one of my messages." error. Looking one down the stack, we see the issue is #displayOn: related to CalendarArtist. Yes indeed. That's how it works, all Artists have to display their own #displayOn: method.

There is an E-Z fix for that... we'll add a #displayOn: method in CalendarArtist, with nothing in it:

	displayOn: aGraphicsContext

Now lets run our test! ... GREAT! Green Bar! Run 'em all so we make sure nothing else is broken too.... 12 run, no failures, no errors.

But.... Since we didn't write any code in our #displayOn: method, nothing shows... Because our test opens and closes the window so fast, we can hardly see if it is or isn't actually displaying anything. So, we'll go to a workspace and write this:

	tester := CalendarTest new openWindowWithCalendar

Now, we can do a Do-It on that, and see, indeed, the window opens, but nothing is displayed. That's ok though... We'll get to actually displaying stuff next time.

Before we finish for today, we'll add some of the boilerplate code that pretty much all displayOn: methods use:

	displayOn: aGraphicsContext

		| oldClippingRectangle |
		self isVisible ifFalse: [^self].
		oldClippingRectangle := aGraphicsContext clippingBounds.
		(oldClippingRectangle intersects: self frameVisibleRectangle) ifFalse: [^self].
		aGraphicsContext clippingRectangle: (self frameVisibleRectangle intersect: oldClippingRectangle).
		(oldClippingRectangle intersects: self frameDisplayableRectangle) ifTrue:
			[aGraphicsContext clippingRectangle: (self frameDisplayableRectangle intersect: oldClippingRectangle)].
		aGraphicsContext clippingRectangle: oldClippingRectangle.

Lets go over this. All widgets know if they are visible or not, and of course, we should never display anything if the widget isn't.

Next, we get the clippingBounds of the graphics context. The Pollock framework always sets the clipping bounds to be the smallest possible rectangle, so that we can do the next test... checking if this widget's visible rectangle intersects the place where displaying will be done. If not, we abort early. Why do we do this? Well, many times the area of the window that needs to be repainted is not anywhere within the visible rectangle of our pane. While it is totally safe to paint to a graphics context outside of the area of it's clipping bounds, it's just a waste of code.

The next thing we do is set the clipping rectangle for the graphics context so that it is just that area where the existing clipping rectangle intersects with the visible rectangle. Once we do this, we are ready to display things that are inside our pane.

However, we see that it then asks if the panes displayable rectangle intersects the old clipping rectangle, and then branches if true. Why is this? Well, as discussed elsewhere, a pane has two general areas that we care about. The visible rectangle represents the whole visible area that the pane takes on the window. The displayable rectangle represents that sub-rectangle (if it has one) that is inside any borders or decorations that our widget will have. In our case, as with Windows 98/ME/2K drop down lists, there IS an interior decoration. This is the "lowered" border that surrounds the input field part and the button part of the Calendar pane.

So, when it comes time to draw this interior decoration, we'll do it before the ifTrue test. And we'll then draw the input field and button inside the ifTrue block. We see that what it first does in that ifTrue block is set the clipping rectangle to this new area. Of course, the sub-panes will do their displaying after that.

Finally, we reset the clipping rectangle to the initial value.

So, let's run our test.... Darn... Another problem! Another subclass responsibility! If we look down the stack, we see that the default #frameVisibleRectangle method in ActionDisplayArtist calls #collectedExtents. This method is used by RadioButtons and CheckBoxes to gather up the area of the check/radio graphic plus the extent of any label part. Fact is though, we don't need to use this style of #frameVisibleRectangle for our Calendar. Artists are typically supposed to be responsible for getting this value, but for an ActionDisplay widget, it turns around and gets it from the Agent. If we look at other implementors of #frameVisibleRectangle, and in particular in DropDownListAgent, we see it is implemented as:

	frameVisibleRectangle
		^self frame visibleRectangle

That's good stuff, so we'll add that to our CalendarAgent.

We run our tests again... Great... All green again. See how our tests caught a problem for us? I love that!

The above is published as version 1.4 in the Package named "Pollock-Calendar" on the Cincom public repository.

Next time we'll add the lowered interior decoration, and display it.


And So It Goes
Sames

Read: How To Create A Custom Widget - Get Ready To Display

Topic: There's a good question Previous Topic   Next Topic Topic: What?

Sponsored Links



Google
  Web Artima.com   

Copyright © 1996-2019 Artima, Inc. All Rights Reserved. - Privacy Policy - Terms of Use