Calendar

This is a tutorial for a simple, yet feature-rich, calendar.

It uses overlap groups inside stack groups and creates the correct numbers based on the cell positions (all data has the same index).

The calendar is modular, meaning you can pick which features you want to use, remove or add more later, or just make a barebones number table.

The Days of the Week

Calculation is based on a table of 1x7. You will need a horizontal stack group containing 7 overlap groups, indexed 0 to 6.

Global Formulas

To have the days reflect the first day of the week selected in the settings, create a global text with this formula:

gv(weekday)

$df(E,r+df(e,r+(si(mindex,1)+1)+d)+d)$

Making the Table

  • Make a horizontal stack group;

  • in it create an overlap group;

  • inside add a regular text with $gv(weekday)$ as text formula.

Just copy and paste the overlap group 6 more times and the days will be generated automatically.

Additionally, you can highlight the current day text by using this formula to show a different text color:

$if(gv(weekday)=df(E), COLOR0, COLOR1)$

Replace COLOR0 and COLOR1 with the preferred HEX values (I suggest you use globals).

You can also change the color of the weekend days by using this formula to show a different text color:

$if(df(f,r+df(e,r+(si(mindex,1)+1)+d)+d) > 5, COLOR0, COLOR1)$

Replace COLOR0 and COLOR1 with the preferred HEX values (I suggest you use globals). Keep si(mindex ,1) the same as the index in gv(weekday).

The Days of the Month

Calculation is based on a table of 6x7, so you will have a vertical stack group containing 6 horizontal stack groups, each will have 7 overlap groups. Therefore a total of 42 overlap groups indexed 0 to 41.

Global Formulas

To find the index position of the day 1 of this month based on the settings (index 0 - 6), create a global text with this formula:

gv(first)

$df(e,r+df(d)+d)$

To find the index position of the current day of this month, create a global text with this formula:

gv(current)

$gv(first)+df(d)-1$

To get the index position of each cell, create a global text with this formula:

gv(index)

$si(mindex,1)+si(mindex,2)*7$

You can increase/decrease the index, depending on how many parent groups the day number text has.NOTE: Instead of 7, si(mcount,1) could be used. But this is a rare case of "a variable that doesn't change" because calendars have seven days in a week, so that really is not necessary.

To get the number for each day of the calendar, create a global text with this formula:

gv(day)

$if(gv(index) < gv(current), df(d, r+(gv(current)-gv(index))+d),

gv(index) > gv(current), df(d, a+(gv(index)-gv(current))+d),

df(d))$

Use df(dd to get the leading zero: 01, 02.

Making the Calendar Table

  • Make a vertical stack group;

  • in it create a horizontal stack group;

  • in it create an overlap group;

  • inside add a text item with $gv(day)$ as text formula.

Just copy and paste the overlap group 6 times and then copy and paste the horizontal stack group 5 times. The days will be generated automatically.

Additionally, you can highlight the current day text by using this formula to show a different text color:

$if(gv(index) = gv(current), COLOR0, COLOR1)$

Replace COLOR0 and COLOR1 with the preferred HEX values (I suggest you use globals).

You can also use that formula to show an indicator for the current day.

You can also change the color of the weekend days by using this formula to show a different text color:

$if(df(f,r+df(e,r+(si(mindex,1)+1)+d)+d) > 5, COLOR0, COLOR1)$

Replace COLOR0 and COLOR1 with the preferred HEX values (I suggest you use globals). Keep si(mindex ,1) the same as the first part of gv(index).

Make the Days of the Previous/Next Month Different

We need another global for the position of the last day, to compare the days' positions according to it.

Global Formula

To find the index position of the last day of this month based on the settings, create a global text with this formula:

gv(last)

$gv(first)+df(o)-1$

Assigning a Different Color to the Numbers

To make the numbers of the previous month and next month a different color, use this formula:

color formula

$if(gv(index) = gv(current), COLOR0,

gv(index) < gv(first), COLOR2,

gv(index) > gv(last), COLOR2,

COLOR1)$

Replace COLOR0, COLOR1 and COLOR2 with the preferred HEX values (I suggest you use globals).

Hiding the Groups

To hide the day groups of the previous month and the next month, use this formula for the visibility of the day groups:

HideDay

$if(si(mindex)+si(mindex,1)*7 < gv(first), NEVER,

si(mindex)+si(mindex,1)*7 > gv(last), REMOVE,

AWAYS)$

Display Progress

It's easy to display the monthly progress (by changing the color of the past days). We need a simple switch and to change the color formula for the day.

Global Switch

For the user-controllable switch, create a simple global switch called Progress.

gv(progress)

Changing the Color formula for the Numbers

Take the color formula from the previous section and add a condition that will change the color based on the progress switch:

color formula

$if(gv(index) = gv(current), COLOR0,

gv(index) < gv(first) | gv(index) > gv(last), COLOR2,

gv(progress) & gv(index) < gv(current), COLOR3,
COLOR1)$

Replace COLOR0, COLOR1, COLOR2 and COLOR3 with the preferred HEX values (I suggest you use globals).

Add Event Indicators

We already know the day of each cell. To calculate the number of events on each day we also need the month (different in the first and last rows) and year (can change if the calendar is displaying December or January) of that day. We will also add a full date global for convenience.

Global Formulas

To get the month of each cell, create a global text with this formula:

gv(daymonth)

$if(gv(index) < gv(first), df(M,r1M),

gv(index) > gv(last), df(M,a1M),

df(M))$

To get the year of each cell, create a global text with this formula:

gv(dayyear)

$if(gv(index) < gv(first) & df(M)=1, df(y,r1y),

gv(index) > gv(last) & df(M)=12, df(y,a1y),

df(y))$

To get the date of each cell, create a global text with this formula:

gv(daydate)

$dp(gv(dayyear)+y+gv(daymonth)+M+gv(day)+d0h0m0s)$

To calculate the number of events on each day, create a global text with this formula:

gv(dayevent)

$ci(ecount, gv(daydate)) + ci(acount, gv(daydate))$

Making the Indicator

  • Add a shape (or a number) in the same group as the day number text.

If you chose a number, make it show $gv(dayevent)$.

If you chose a shape, change its color like so:

$ce(COLOR, alpha, 100*(gv(dayevent)>0))$

Replace COLOR with the preferred HEX value (I suggest you use globals).

Scroll Through Events for a Chosen Day

We will need more globals, more specifically globals from the Events blueprint. First a blank text global for the chosen date, a global that calculates the number of events on that date and another global for a chosen event. Then we also need globals for events' info.

Global Formulas

To hold the chosen date, add a text global:

gv(date)


Leave it blank, it will be set by the touch action.

To calculate the number of events on the chosen date, add a text global:

gv(events)

$ci(ecount, gv(date)) + ci(acount, gv(date))$

To hold the index number of the chosen event, add a text global:

gv(event)


Leave it blank, it will be set by the touch action.

To pick the chosen date you could simply use gv(daydate), but then that date will remain set until you pick another one, even when the day changes (displayed events in agenda will be from past days). So I suggest you go one step further and make it reset every time you tap on today's group. For that add a text global:

gv(touchday)

$if(df(D, gv(daydate)) = df(D), "$dp()$", gv(daydate))$

Their code has pretty much the same structure, so this example will contain just the title of the event.

gv(title)

$ci(title, gv(event), gv(date))$

Adding Touch Actions

Make sure the base of the Day group has the same index as the other data and add a touch action to it:

  • Action = Toggle Globlal Switch

  • Switch = gv(date)

  • Text = $gv(touchday)$

Add another touch action to reset gv(event) to 0 every time you switch dates:

  • Action = Toggle Global Switch

  • Switch = gv(event)

  • Text = 0

NOTE: The touch area must have the same index as the day number, events indicators and forecast info.

Making the Event Group

Like in the Events blueprint add two buttons and a stack of data.

The index of the objects in the stack doesn't matter here, but it is suggested that it has the same structure as the agenda.

  • Add a text item in the stack and make it show $gv(title)$.

Add touch actions to the buttons that will switch between previous and next events:

  • Action = Toggle Global Switch

  • Switch = gv(event)

  • Text Text =

  1. Previous:

$if(gv(event) > 0, gv(event)-1, 0)$

  1. Next:

$if(gv(event)+1 >= gv(events), gv(events)-1, gv(event)+1)$

List All Events for a Chosen Day

This part is the same as before with a few key differences.

Global Formulas

The Event global is not blank:

gv(event)

$si(mindex, 2)$

This is now the index for events (like in the agenda).

We also need another global from Agenda blueprint:

HideEvnt

$if(si(mindex) < gv(events), ALWAYS, REMOVE)$

There is NO touch action to reset gv(event) to 0 on day groups!

Making the Event Group

Like in the Agenda blueprint add a stack of multiple event groups.

  • Apply HideEvnt as the visibility formula for each group.

Every event group contains more groups, each holding a piece of event's information.

  • Add a text item in its own group inside the Event stack group and make it show $gv(title)$.

  • Do the same for all other agenda globals.

NOTE: Keep the index of the objects in the stack the same.

Add a Forecast

This calendar can also have forecast globals and display the weather forecast for the next few days. What type of content to display is up to you - you can even choose to display the condition wi(cond) (but idk where you'd put it).

For reference we'll change the layout of the structure - tree (look in the app for more examples). This is to have certain contents grouped together while keeping the index identical across all formulas. It is relatively easy to do by putting the day and indicators inside more parent groups and then changing the gv(index) formula.

We'll also hide the weather groups after the forecast data ends - usually after max 14 days (why that is you can read somewhere else - calculating data further into the future is pointless).

Global Formulas

Because we'll move the data in day cells into two more groups, change the index global like so:

gv(index)

$si(mindex,3)+si(mindex,4)*7$

To get the weather icon on each day, create a global text with this formula:

gv(wicon)

$wf(icon, gv(index)-gv(current)) + ai(isday)$

Returns the equivalent of $wi(icon)+ai(isday)$. Change based on the weather icon pack.

To get the average temperature on each day, create a global text with this formula (I suggest you skip this one and use the maximum temperature instead):

gv(temp)

$wf(temp, gv(index)-gv(current))$

To get the maximum temperature on each day, create a global text with this formula:

gv(tempmax)

$wf(max, gv(index)-gv(current))$

To get the minimum temperature on each day, create a global text with this formula:

gv(tempmin)

$wf(min, gv(index)-gv(current))$

To hide the weather data on days with no forecast data, create a global text with this formula:

HideWthr

$if(si(mindex,1)+si(mindex,2)*7 >= gv(current) & si(mindex,1)+si(mindex,2)*7 < gv(current)+wi(pdays), ALWAYS, REMOVE)$

Changing Day Group Contents

  • Cut the day number text and move it inside two more groups (overlap or stack).

  • Then create a new stack group inside the parent day group and set its visibility to gv(hidewthr).

  • Inside that stack group add another stack group (for temperatures) and an overlap group (for the icon).

  1. Inside the stack group add two text objects and link them to gv(tempmax) and gv(tempmin), respectively.

  2. Inside the overlap group add a fonticon or a bitmap (depending on what weather icons you use) and set it to display gv(wicon).

Just copy and paste the day group throughout the whole calendar and that's it.


Copyright (c) 2021 Erik Bucik

Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:

  1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.

  2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.

  3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

BSD-3-Clause

Kustom formatted version