I’ve made a calendar for daily use. That’s as short as I can put it. I’m well aware that we've got Outlook and dozens of similar products; they all share the same feature: too many features. My vision was and is to cut it down to an absolute minimum, cut almost all controls, windows, DLLs and millions of files and leave what’s needed only, because we and other people only use what’s needed, and the average need is quite small (it is!). In other words, let’s cut all the fancy stuff and have a word processor that enables us to think about what’s important – contents and nice letters and not 3D animations, or as in this case, notes, days, time etc. In this context, I don’t want to think ‘calendar’ when I need one. That’s my dogma.
The big picture
This Calendar article was called Miranda and later MirandaPlanner here on CodeProject before. This gave me some problems that didn’t expect and letters told me about some other Miranda products that I didn’t know of, and in some sense therefore violated. I argued that this was not indeed my intension and changed the name to MirandaPlanner. People still wrote me not-so-nice letters – so consequently I’ve changed the name to what it is, namely a calendar hoping that I do not offend anyone anymore (naming is not an issue of great importance to me, almost insignificant). Also, this change fits the dogmatic cut I guess. So to begin with, the name of the article changed from MirandaPlanner to Calendar – and in the release of this text also the program itself, so no one and me is confused. I’ve asked for MirandaPlanner to be removed from CP.
This project is also a toy I play with in my time off. I add to it what I need myself and I regard myself as being the average calendar user. So what I need, and what you out there argue needs to go in, I’m willing to add as long as the canvas is not over painted. I regard this being a longer process in time.
From a (MFC-)programming point of view, there is really no big things in this project for you to find – guess that the programmer that wants to see how I slide windows, write for the tray and owner draw buttons can extract some ideas. But there are not any big things to come for. And this is not my intension either. Writing on this, I think of the overall internal/external design and how I interact with my user. The amount of code is now approx. 6000 lines and is growing from week to week and month to month and I look closely into that the quality is following. The amount of files in the project tree is kept low – think 10 to 20 or something.
I started out on MS VS 6.0+ and migrated to the beta of MS VS 7.0, both on Win2K. For 4-5 months ago, I moved to the platform I’m on today: MS VS 7.0.9466 on WinXP Pro. Think this is important for some of you to know before I carry on – gave some the wrong impression that it’s still compatible with MS VS 6.0 and it is not because of some odd template thing I cannot remember the technical details about. So you have to run a .NET version of MS VS (sorry).
As you already know, this is a MFC project. To begin with, keep in mind that it's all built around buttons - the keyword is 'button'.
Inside the stomach of it.
This section is mixed in with an explanation of functionality.
When you open the project for the first time, open calendar_framewnd.h/cpp. In this, you have a class called
CCalFrameWnd that inherits
CFrameWnd. This is the frame window and the host for the calendar itself. Think of it as being the sliding plate with buttons. The plate hosts 6 * 7 buttons for days to ensure that no matter how strange a month looks, it'll fit in. For a calendar, the days must be the most important ones, so I start with days :-). Also, you have a column of 6 weeks to the left, holding numbers of weeks in the year (for us in Europe, this is important but I think less important to US users). If you are not used to week numbering, think of it as being the ordinal number for the week beginning with 1 or 52 on the 1st of January in a year (see also timeex.h/cpp and Outlook for a closer understanding and various places on the web as well, as I did when I made it). I'm not an expert on the field of time and programming clocks - just my two cents - OK, back to buttons. On the top of it all, you have one wide button holding the month and the year, under it 5 buttons for browsing in time (from left to right):
- Press <<: Go back one month (1st in that month).
- Press << + ctrl.: Go back one year (1st of January that year).
- Press <: Go back one day.
- Press < + ctrl: Go back one week.
- Press : Go to present time (=now).
- Press >: Go fwd. one day.
- Press > + ctrl: Go fwd. one week.
- Press >>: Go fwd. one month (1st in that month).
- Press >> + ctrl.: Go fwd. one year (1st of January that year).
This is half calendar explained. Just above the big (rich) edit, you have three buttons, one serves as message bar and two as buttons for browsing in notes (more about notes in a moment). The message bar functions are not 100% yet. Text can reside here even when the mouse has left the button, holding the hint. I don't know exactly how I deal with this issue without making the 'has the mouse left me' - interval smaller - like 10ms, but that's not nice. I have to come back to it and meanwhile you have to live with it.
CCalEdit occupies almost half the space. This class is also like the button class, a specialization of a MFC class - in this case a
CRichEdit. This is where you write text for a day and this is a note. A day can have a note. That is, can have 0 or 1 and not more. A note is a file saved in a library called 'notes' and a day having a note is tagged with a yellow checkmark. The text is streamed out when the day changes, and if so, the new text is streamed in for the new day if having a note. Notes, or text in them are kept in files and not in the array
CSingletonArrayEx<CNote, CNote> *m_pArray_Notes. This array on the other hand is member of a nested class to
CCalendar. The array handles names of notes and all names are unique because they are composed yyyy.mm.dd.txt.
When pasting text into the edit, it takes care of pasting only the text and not any formatting. Track down use of
CCalEdit::SetDefaultCharFormat(...). This edit responds scrolling from the scroll wheel found on newer mice.
So the picture is that notes are always small objects as they are instances of a class called
CNote. The only things that can grow are the size and number of files in the note library. Time, and going fwd. and back in time are handled by
CCalendar - using, for instance,
Go2_SpecificDay(). A lot of effort is, except for the sliding behavior and timers, around holding things in sync. and the GUI updated. Therefore you'll find tons of Refreshes and sync. function.
At the very bottom, there are four buttons. They are (from left to right):
This is best regarded as one functional group, and in the present release 1.23, I've only finished up the first one. A 'note' here has nothing to do with days and day-notes. This is a general note and is consequently saved in its own library called
note_cardinal. The rest are, 'contacts' as a minor Outlook, 'work' as a place where you are able to write from-to time and have a statistic view of your working month, and the 'reminder' as a simple 'slide up when I have to go for some meeting' or something :-). I've not decided entirely what the former tree buttons are going to be. All I know is that I slide the
CCalEdit down and say the control group for 'work' up when pressing members of this radio group.
This reminds me that
CCalBtn are also (quite) special and made for this calendar purpose. Except for being owner drawn and sub classing
CButton, it also behaves as radio button and check button. I have to be able to control colors and fonts and edges and all features closely on buttons, so you find some not-so-nice looking
SetColors(...) members etc. I have to look into the details of it again I feel - but for now, it works OK including overkill.
Also pay attention to that this is a "tray-app", and that is, adds itself to the start up folder and that you can control it from the tray-icon-menu. This menu is not flawless - pressing keys to many times the menu are corrupted. I can get no help on that from the developer (found elsewhere on CP).
This project has no resource.h and no <something>.rc. All controls are made programmatically in first a
ResoursesCreate(...) and then a
Init(...), and are killed in counterparts called
UnInit(...). All text and all important constants throughout the project - like colors and all defaults - are found in calendar.rh.
Important: The width of the window must be devisable by 5 and 8 to leave no space in between buttons in rows. The height of buttons is not important.
This is my explanation of the internals for now. I don't know if this is enough (tell me).
Known problems and limitations
- Code is missing DoxyGen comments and HTML-documentation.
- Tray menu has problems.
- Message bar keeps text from old hints.
- In the button class, to improve painting of simple graphic.
- The fact that only 1972 - 2037 seems to be the valid interval (crashes otherwise on my machine).
Sort of disclaimer
I released this article almost empty – that was yesterday (9’th of February ‘04). And oooops that was wrong of me I can see (more letters – thanks =:-|). The thing was that I mixed up some foolish things in the old zip’s before, and that I was to lazy to test if it was working properly as a project before I uploaded them. That was why I released the article so fast - sorry to all the new readers.
Things to come
- Create backup before deleting notes and on new notes.
- 'Esc' to slide to invisible.
- Different kinds of checkmarks.
History of MirandaPlanner:
- Rel. 0.990, 18.05.2003. Remarks: Platform was W2K SP2 for the dev. ONLY tested on dev. machine. Dev env. was VS 6.0.
- Rel. 0.991, 19.05.2003. Remarks: Minor fixes in handling (save/load of) notes. Minor fixes in enabling buttons for browsing notes. Minor fixes in an auto update-timer.
- Rel. 1.00, 20.05.2003. Remarks: All over fixes and cleanup. Added runtime info. to button class and fixed the release-ver problem. Also now mousewheel-messages go to the edit, no matter what child is holding the focus.
- Rel. 1.01, 23.05.2003. Remarks: Made ready for _UNICODE compile.
- Rel. 1.10, 27.05.2003. Remarks: Hover-hints for days having notes (an option), more extensive error handling. From now on, its new name is MirandaPlanner. Versioning is continued. Fixed auto-update once again when running 'today' so that it will go on to the next day by itself.
- Rel. 1.11, 09.06.2003. Remarks: Autocleanup of dangling hints, on pasting other
CHARFORMAT into a note, it retains its original default format (made before pasted text are shown). Fixed error in
- Rel. 1.20, 12.06.2003. Remarks: Added a general note (see 'note' button). Made color of check's display in gray if marking notes in the past and yellow if marking notes now or in the future. All over clean-up in the code.
- Rel. 1.21, 16.06.2003. Remarks: Fixed save-problem when sliding window into invisible. Made enabling of arrow-buttons for browsing notes, consistent.
- Rel. 1.23, 29.01.2004. Remarks: Fixed leap year problem. (same as Calendar v. 1.00).
History of Calendar (based on MirandaPlanner):
- Rel. 1.00, 10.02.2004. Remarks: Changed position of some of the lower buttons and changed the name to Calendar. Added preparations for 'contact', 'work' and 'reminder'. Removed 'delete' and 'delete+' and made them menuitems instead.