The Artima Developer Community
Sponsored Link

Agile Buzz Forum
How To Create A Custom Widget - Drop Down - Grid Dates

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 - Grid Dates Posted: Nov 10, 2004 6:09 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 - Grid Dates
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 populate our calendar grid with actual dates, and hook the navigation up to show changing months in the grid


A Grid Of Dates

Before we just had a bunch of numbers in our calendar grid, but now we want real dates. So, without further ado, here is the code to populate our calendar with real dates based on the working date.

	CalendarAgent>>currentMonthModel
		| model firstDayOfMonth weekdayIndex gridDate |
		model := ObservedTwoDList columns: 7 rows: 6.
		firstDayOfMonth := Date newDay: 1 monthNumber: workingDate monthIndex year: workingDate year.
		weekdayIndex := firstDayOfMonth weekdayIndex.
		gridDate := Date fromDays: firstDayOfMonth asDays - weekdayIndex.
		1 to: 42 do:
			[:index |
			model at: index put: gridDate.
			gridDate := gridDate addDays: 1].
		^model

There are probably better algorithms than this, but here is what we did: First, we get the first day of the current month. Once we know this, we can find out what the weekday index is. From there we play a bit of a trick using the fact that the weekdayIndex answers 1 for Monday, 2 for Tuesday and so on. Since our grid starts on Sunday, by subtracting the weekday index, we will always find the first Sunday for our grid. Then it is just a matter of iterating over all of the elements in the model, like last time, and giving each the grid date, incrementing the date after each assignment.

If we open our grid now (CalendarTest new openWindowWithCalendar then press the drop down button), we'll see a grid filled with the first characters of each date string. Remember, we set up our columns to send the column index and by default it then sends printString to the result. To have it instead answer the day of the month, we need to change our column definitions:

	CalendarAgent>>addColumnsTo: aGrid 
		aGrid addColumn: (self defaultColumn labelString: 'S'; accessPath: #(1 #dayOfMonth)).
		aGrid addColumn: (self defaultColumn labelString: 'M'; accessPath: #(2 #dayOfMonth)).
		aGrid addColumn: (self defaultColumn labelString: 'T'; accessPath: #(3 #dayOfMonth)).
		aGrid addColumn: (self defaultColumn labelString: 'W'; accessPath: #(4 #dayOfMonth)).
		aGrid addColumn: (self defaultColumn labelString: 'T'; accessPath: #(5 #dayOfMonth)).
		aGrid addColumn: (self defaultColumn labelString: 'F'; accessPath: #(6 #dayOfMonth)).
		aGrid addColumn: (self defaultColumn labelString: 'S'; accessPath: #(7 #dayOfMonth); displayColumnLine: false)

Here, we have just told to send the message #dayOfMonth, to the result of sending the column index to each item. Now if we open our popup, the grid looks really nice.


Changing the Grid when Navigating

If we open our grid, we see that if we click on the navigation buttons (prior and next year/month) the date grid doesn't change. Let's fix that:

	CalendarAgent>>updateMonthYearDisplay
		(dropDown paneAt: #(#Form1 #DisplayLabel1)) label value: self currentMonthYear.
		(dropDown paneAt: #(#Form1 #Grid1)) list: self currentMonthModel

Surprisingly, it's quite simple. We already have a method that gets called every time one of the navigation buttons gets pressed, so we piggyback the updating the model in the list. We don't have to do anything else special, since Pollock's framework takes care that whenever the list (or a list item) is changed, that the grid holding it is updated.


Visual Spiffery

If we look at our grid now, it surely fills in the right values for the days, and updates properly for navigation, but... it's pretty hard to see the demarcation between this month and the prior and next months begins/ends. Let's add a bit of code that makes prior and next months days be blue, where this months days are black.

We start off by giving the grid a block that we want to be called to get the foreground color for a cell:

	CalendarAgent>>addCalendarGridTo: aForm 
		| grid |
		grid := Grid new.
		grid foregroundColorAction: [:cell | self foregroundColorFor: cell].
		grid frame: (FractionalFrame fractionLeft: 0 right: 1 top: 0 bottom: 1).
		grid frame
			leftOffset: 5;
			rightOffset: -5;
			bottomOffset: -5;
			topOffset: 25.
		grid list: self currentMonthModel.
		self addColumnsTo: grid.
		grid selectByCells.
		grid 
			columnHeader: true;
			allowColumnResizing: false;
			allowColumnReordering: false;
			allowRowResizing: false;
			allowSorting: false;
			displayExtendedRowLines: true.
		aForm addComponent: grid

This block will be called to get the foreground color for each cell. This block is a one argument block, that takes as a parameter the current cell. We of course now need to write a method named #foregroundColorFor: to answer back a color appropriate for the cell:

	CalendarAgent>>foregroundColorFor: aCell
		^(aCell rowItem at: aCell location x) monthIndex ~= workingDate monthIndex
			ifTrue: [ColorValue blue]
			ifFalse: [ColorValue black]

A bit of explanation about the Cell object. The Cell object is made up specially for each cell in a grid whenever there is a callback of this kind. It contains the Row (which is a Row object), the Column (the one you created to display the target column for this row) as well as a location, which is a Point object. By sending #value to a Cell object, you will get the value that is displayed in the grid for that Cell. In this case, if we sent #value to the Cell, it would send us back a string with the day of month number in it. That does us no good. Having to play with Row objects or Columns would be rather ugly and require heavy coupling of our code to the Cell.

But Cell also has a convenience method, called #rowItem. What this answers is an ObservedList with the raw model objects in it for this row. Then, by using the location (and then using the x value since that is all we care about), we can get the current date object in our model that is being dealt with. From there, it's a simple hop skip and a jump to answering a ColorValue for the foreground of the cell.

Heck, while we're at it, let's make today's date red, to make that even more visible:

	CalendarAgent>>foregroundColorFor: aCell 
		| cellDate |
		cellDate := aCell rowItem at: aCell location x.
		cellDate = pane model value ifTrue: [^ColorValue red].
		^cellDate monthIndex ~= workingDate monthIndex 
			ifTrue: [ColorValue blue] 
			ifFalse: [ColorValue black]

Note here that we use the pane's model instead of the working date, since we change the working date when we navigate, but the model's date (as yet) remains unchanged. If you want, you can get even more fancy, by using the Grid's #backgroundColorAction: to maybe change the background color of non current month cells to gray, and maybe today's date background color to something really outstanding, like yellow.

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

Next time we'll make selecting a date in our grid actually change the model, and also close the popup


And So It Goes
Sames

Read: How To Create A Custom Widget - Drop Down - Grid Dates

Topic: The more things change... Previous Topic   Next Topic Topic: Making my point

Sponsored Links



Google
  Web Artima.com   

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