The Artima Developer Community
Sponsored Link

Agile Buzz Forum
How To Create A Custom Widget - Drop Down - Model and Button Behavior

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 - Drop Down - Model and Button Behavior Posted: Oct 27, 2004 1:52 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 - Drop Down - Model and Button Behavior
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 setup the model for our Calendar, as well as connect the navigation buttons to real behavior.


The Model

By subclassing from ActionDisplay, we have ready built in framework behavior for setting up the model for our Calendar. Whenever we access the model method, if the value is nil, it goes calls the #setDefaultModel method, which is expected to set the appropriate value in an ObservedValue. An example is the CheckBox, which uses a boolean, and by default is false.

When a developer uses this widget, if they don't want the default value, which will be "Date today" for our Calendar, they can just supply a different date by sending something like "myCalendar model value: SomeObject date"

Our #setDefaultModel method looks like this:

	Calendar>>setDefaultModel
		model := Date today asObservedValue

When we open our pop up, we want to have the popup use a copy of that date as it's starting point. However, our current code simply always uses today's date, without regard to a model. We need to make some changes to make the calendar popup use something other than a hard coded value.

We'll start by giving our Agent, which opens the popup, a working date instance variable:

	Smalltalk.Pollock defineClass: #CalendarAgent
		superclass: #{Pollock.ActionDisplayAgent}
		indexedType: #none
		private: false
		instanceVariableNames: 'dropDown workingDate '
		classInstanceVariableNames: ''
		imports: ''
		category: 'Pollock-Calendar'

Next, when we open the popup, we'll copy it from the Calendar:

	CalendarAgent>>openCalendarWindow
		| calendarRectangle screenOffset |
		workingDate := pane model value copy.
		calendarRectangle := self frameVisibleRectangle.
		screenOffset := pane topPane globalOrigin.
		dropDown := TransientWindow
			newPopUpIn: (calendarRectangle bottomLeft + screenOffset extent: 200 @ 200)
			from: pane.
		dropDown border: #ridged.
		dropDown addComponent: self calendarForm.
		dropDown open.

Of note here is that we copy the value, not actually use the value in the model. This way we don't have to worry about somehow modifying it behind the back of the model. Later we'll write code that writes the workingDate back to the model if/when we choose a date in the calendar grid, when we do the calendar grid.

There is just one more change we need to make to make sure we get the model's copy of the date in our popup. #currentMonthYear has "Date today" hard coded in it. Making the following simple change takes care of this:

	CalendarAgent>>currentMonthYear
		"Answer a string with the working date month and the Year as a string"

		^'<1s> <2s>' 
			expandMacrosWith: (Locale current timePolicy longMonthNames at: workingDate monthIndex)
			with: workingDate year printString

To test that it actually works, let's add a new test method:

	CalendarTest>>openWindowWithCalendar1984
		self openWindow.
		calendar := Calendar new.
		calendar frame origin: 10 @ 10.
		calendar frame extent: 100 @ 23.
		calendar model value: (Date readFrom: '7/6/1984' readStream).
		window addComponent: calendar

Now, if we open our tester with the following:

	CalendarTest new openWindowWithCalendar1984

And then open the drop down list, we see that indeed, we get July 1984 in the middle of our popup, just like we expect.


Navigation Button Behavior

For each of the navigation buttons on the popup, we want to do two things. First, perform the appropriate modification to our working date, then display that value in the month/year display area. Let's start with the decrement year button (the left-most on our popup).

First let's write the method that will do the work... we'll call it #decrementYear:

	CalendarAgent>>decrementYear
		workingDate := Date newDay: workingDate day year: workingDate year - 1

This will change the working date, but not change the display, so let's add a method to display the new month/year, and then we'll call that method from decrementYear:

	CalendarAgent>>updateMonthYearDisplay
		(dropDown paneAt: #(#Form1 #DisplayLabel1)) label value: self currentMonthYear

-+-+-

	CalendarAgent>>decrementYear
		workingDate := Date newDay: workingDate day year: workingDate year - 1.
		self updateMonthYearDisplay.

Finally, to get it working, we just have to have the button, when pressed, call our decrementYear method:

	CalendarAgent>>addNavigationButtonsTo: aForm 
		| button |
		button := Button new.
		button frame: self leftButtonsFrame.
		(button frame)
			rightOffset: 18;
			bottomOffset: 18.
		button addComponent: self previousYearButtonIcon.
		button when: #pressed send: #decrementYear to: self.
		aForm addComponent: button.
		button := Button new.
		...

Now if we open our tester, open the popup, and press the << button a couple of times... All is nice!


Details

There's no reason to bore you with having a running commentary for the other buttons. So, here is the rest of the code:

	CalendarAgent>>incrementYear
		workingDate := Date newDay: workingDate day year: workingDate year + 1.
		self updateMonthYearDisplay

-+-+-

	CalendarAgent>>incrementMonth
		| monthIndex year day |
		monthIndex := workingDate monthIndex.
		monthIndex := monthIndex = 12
			ifTrue: [1]
			ifFalse: [monthIndex + 1].
		year := workingDate year.
		monthIndex = 1 ifTrue: [year := year + 1].
		day := pane model value dayOfMonth.
		workingDate := [Date newDay: day monthNumber: monthIndex year: year]
			on: Error
			do: 
				[:error | 
				day := day - 1. 
				error retry].
		self updateMonthYearDisplay

-+-+-

	CalendarAgent>>decrementMonth
		| monthIndex year day |
		monthIndex := workingDate monthIndex.
		monthIndex := monthIndex = 1
			ifTrue: [12]
			ifFalse: [monthIndex - 1].
		year := workingDate year.
		monthIndex = 12 ifTrue: [year := year - 1].
		day := pane model value dayOfMonth.
		workingDate := [Date newDay: day monthNumber: monthIndex year: year]
			on: Error
			do: 
				[:error | 
				day := day - 1. 
				error retry].
		self updateMonthYearDisplay

-+-+-

	CalendarAgent>>addNavigationButtonsTo: aForm 
		| button |
		button := Button new.
		button frame: self leftButtonsFrame.
		(button frame)
			rightOffset: 18;
			bottomOffset: 18.
		button addComponent: self previousYearButtonIcon.
		button when: #pressed send: #decrementYear to: self.
		aForm addComponent: button.
		button := Button new.
		button frame: self leftButtonsFrame.
		(button frame)
			leftOffset: 19;
			rightOffset: 37;
			bottomOffset: 18.
		button addComponent: self previousMonthButtonIcon.
		button when: #pressed send: #decrementMonth to: self.
		aForm addComponent: button.
		button := Button new.
		button frame: self rightButtonsFrame.
		(button frame)
			leftOffset: -18;
			bottomOffset: 18.
		button addComponent: self nextYearButtonIcon.
		button when: #pressed send: #incrementYear to: self.
		aForm addComponent: button.
		button := Button new.
		button frame: self rightButtonsFrame.
		(button frame)
			rightOffset: -19;
			leftOffset: -37;
			bottomOffset: 18.
		button addComponent: self nextMonthButtonIcon.
		button when: #pressed send: #incrementMonth to: self.
		aForm addComponent: button

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

Next time we'll put in the 5 x 7 grid on the popup, and start filling it with month data.


And So It Goes
Sames

Read: How To Create A Custom Widget - Drop Down - Model and Button Behavior

Topic: Rockets are Cool Previous Topic   Next Topic Topic: BottomFeeder 3.7 redux

Sponsored Links



Google
  Web Artima.com   

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