Introduction
Note 29.09.03: I now run Win XP and it works fine on this platform
too. Also on an old NT 4.0. The same goes for Win ME. Also it compiles and
builds 100% with VS 7.0.
Note 24.06.03: I've been updating this product for the past 2 or 3
weeks, made corrections to the code and some enhancements also. I think that the
state it's in now is 'just it' and I can't think of any more functionality to
add. So in other words - end of the project. If however I see small things
wrong, I'll correct this and upload new zips and I don't plan to change ver.#
for that reason. I will only change the date of this note.
What?
A low priority stealth application to keep track of time and notes on a daily
basis. So, yes this is yet another calendar (my guess is that there are a few
out on the market) - a simple one though, dealing with few classes only and very
easy to go into and understand; I think and hope. I'll come back to the details
in a moment and then I'll explain it from a design point of view. Main reason to
do this was to have fast access to days, weeks and numbers of business weeks for
a specific month, without going into Outlook. Also the exercise for me was to
try to do some time-related programming around CTime
and then put
it all in some nice GUI context. I'm rather satisfied on that part - not saying
that my specialized classes are in any way perfect, not at all. But for now,
it's OK. And as for the 'stealth' in it, it's because MirandaPlanner
(mp.exe) slides up/down/in/out depending on the location of the task bar
- I like that behavior for a calendar hidden under a task bar.
Why?
Well, not because I can't sleep at night but because I'm out of a job for the
time being, I couldn't let be playing around with sliding windows, ownerdrawn
buttons and timers et cetera, now that I have the time - more or less addicted
to the business. I used approximately 2 weeks for a first version 1.00 to emerge
and I guess that there are much more to come when all you wise guys pinpoint all
the mistakes, bugs and dislikes. But for now, this is it. And as always KISS -
therefore only around 5000 MFC lines of mine to begin with. And why that name
you may ask(?). Well, simply a name I read in my newspaper recently. So a name
of someone that popped up while programming - sounded nice.
Details
I'm sick and tired of class diagrams, entities ditto and all that, so let me
use some words instead. So here is my big picture. I made a class CTimeEx
: public CTime
and filled it with a bunch of methods to retrieve
fx
, a week number based on a time obj
. This sport
continued for some time and I ended up with the class you can see in the file
timeex.hpp. This interface is split up in sections holding methods to
deal with years, months, weeks, days and so on and is as such easy to go into
and grasp. So if you are interested, take a look at timeex.hpp/cpp
to begin with and pay special attention to how week numbers are calculated -
tell me if something looks odd; please. I had a very hard time writing it (see
const int GetWeek_No()
). Apart from the time class itself, I use
some specialized controls. Not that specialized but flat buttons, set up all of
them as ownerdrawn and mostly maintained by the base clsss CCalBtn :
public CButton
and, a slim class CCalBtn_Radio : public
CCalBtn
to take care of radio buttons. Except for one rich edit, all
controls are instantiated from these two classes and therefore what the
application must do is to maintain a bunch of buttons basically. So this *is*
simple as I said. So what you have is -
class CCalBtn : public CButton
{ ... };
class CCalBtn_Radio : public CCalBtn
{ ... };
class CCalEdit : public CRichEditCtrl
{ ... };
I use 26 CCalBtn
s, 42 CCalBtn_Radio
s and one
CCalEdit
. An awful lot of buttons ya' but I like the experiment.
There seems to be *no* speed/refresh problems - even on my slow laptop. So speed
and 1000 invalidates are no issue it seems. Another point. A rule is: A month
can always be fitted into a radio group of 7 times 6 members. This ensures that
I can always show any month using 42 radio buttons. A month will always take up
a space less than 6 weeks. Days can be clicked in the radio group and as a
consequence, the "display time" changes. I use the word "display time" inside
the calendar class. Some words about that class now.
class CCalendar
is nested inside the frame wnd (class
CCalFrameWnd : public CFrameWnd
) and has CCalFrameWnd
as
friend
. Naturally, all time-stuff takes place inside the calendar
class, including handling of notes (more about notes in a moment). So going
back/forward in time now comes down to calling -
const void Go2_SpecificDay();
const void Go2_Today();
const void Offset_Days(const int);
const void Offset_Months(const int);
const void Offset_Years(const int);
in class CCalendar
. There is a close relationship between the
frame wnd and the calendar - calendar obj
must sync to whatever the
user decides to do in some situations and vice versa in other situations. I'll
not go into further details about that, so please see for yourself and just keep
in mind the big picture -
class CCalFrameWnd : public CFrameWnd
{
...
protected:
class CCalendar
{ ... };
...
};
And the calendar controls the "display time" using class CTimeEx
underneath.
Life span
After InitInstance(...)
has created the main frame, the window
sets itself up as a palette window. Inside the frame wnd., I have a
CalcDimension()
which not only determines the final dimension of
the MirandaPlanner window (needed to get the final dimension for
BitBlt(...)
while sliding the window into view) but also
positions the window from where the task bar is found at the time of
construction. This works even for an auto hidden taskbar. This gives us this
final 'sliding behavior' -
- TB at left: MirandaPlanner comes out in right/bottom corner of the
taskbar at the time of construction and goes in at the same spot when hidden or
shutdown. This means you have it in the left/bottom corner of your screen.
- TB at top: MirandaPlanner comes down in right/bottom corner of the
taskbar at the time of construction and goes up at the same spot when hidden or
shutdown. This means you have it in the right/top corner of your screen.
- TB at right: MirandaPlanner comes out in left/bottom corner of the
taskbar at the time of construction and goes in at the same spot when hidden or
shutdown. This means you have it in the right/bottom corner of your screen.
- TB at bottom: MirandaPlanner comes up in top/right corner of the
taskbar at the time of construction and goes down at the same spot when hidden
or shutdown. This means you have it in the right/bottom corner of your screen.
MirandaPlanner can not be moved around. It appears and disappears. Moving the
taskbar around while running MirandaPlanner will not confuse it. Also, as you
can understand, it is always found around the system tray.
Now, back to how it is constructed/killed. After CCalFrameWnd
's
constructor has returned, OnCreate(...)
calls
ResourcesCreate()
and Init()
. The first one does this:
m_pCalendar = new CCalendar(this)
and approx. the same things go
on, once again inside the CCalendar
class, creating resources and
initializing itself. ResourcesCreate()
and Init()
in
the calendar are both long and rather trivial. Also buttons have this design.
When killed UnInit()
and ResourcesDestroy()
are called
- the opposite behavior so to speak. This ensures that all resources are killed
and brought back to Windows as is appropriate and needed.
Notes
A day can have 0 or 1 note attached to it. If it has no notes, the edit will
be empty and if it has one, the note is displayed in it when the day is
selected. Days having a note are marked with a yellow checkmark. All notes are
saved as files in a directory called notes. This directory is found in
the same directory as Miranda as a subdirectory. You can have as many notes as
you like anywhere in time, future and past. You can also navigate in notes using
the yellow arrow keys. It works like this. When on a specific day, pressing
'>' will show you the next note in the future (if any) and when pressing
'<', the previous note in the past (if any). Pressing 'delete' will delete
the current note and 'delete+' will delete all notes. You are warned first - see
for yourself how this works not using any dialogs. All notes are unique and can
coexist because I've named them yyyy.mm.dd.txt. This also gives me the
advantage that sorting notes can be made lexically in their class.
All notes are instances of class CNote
. This class is really
simple and small and for now it only handles operators for <
,
==
and >
and a name/title of the note. To enable
the calendar to navigate in them, it controls an array of all notes. It looks
like this -
class CArrayEx : public CArray<TYPE, ARG_TYPE>
{ ... };
class CSingletonArrayEx : public CArrayEx<TYPE, ARG_TYPE>
{ ... };
Now using class CSingletonArrayEx
, it handles (unique) notes.
I've made a lazy Sort(...)
in the base, sorting ascending in
obj
s saying that a sort is only needed if Add(...)
or
AddSingletonObj(...)
has been called (and not on
RemoveSingletonObj(...)
fx.). Sort(...)
sets the
sort-flag in the end to false and Add(...)
sets it to true. That's
the story for Sort(...)
- and I know that my implementation is
naive - this is OK.
What can it do?
Wow, do you play with it? Well this is it. With the 5 buttons you see at the
top, below the caption holding the month and the year, you are able to go back
and forward in time. First one: --1 month or --1 year (on ctrl. held down),
second one: --1 day or --1 week (on ctrl. held down), middle one is today and
the 2 last do the same as the 2 first, except going into the future. If a
(browse) button is held down more than 0.8 s, its function repeats (I fire
messages to its parent, if so). You can use the keyboard also. Arrow-keys
up/down/left/right navigate in days and pressing the 'Delete' (key) on a day
having a note, deletes it as you would expect.
Grayed numbers 18, 19, 20, 21 and 22 are numbers of the (business) week and
1, 2, ..., 31 are the days in the month. The one pressed in the radio group is
the display-time - in this case, it's May, the 19'th 2003 *s*.
Arrow keys (light up in yellow on enabled) are made for browsing in notes -
days having notes are checked with a yellow checkmark. Below the grayed arrows,
you have a rich edit for editing a note, and in the bottom 2 buttons for
deleting the current note and all notes. One day can have 0 or 1 note. These
buttons also auto repeat.
All notes made are saved in files - one file per day making them all unique
because they are named ... '2003.05.17', '2003.05.18', ... '2003.06.01', ... To
scroll in the text of a note, use the mousewheel or arrows - I've removed the
V-scrollbar for design reasons. Also now (from v.1.10) hovered day-buttons with
notes bring up a hint showing you the first 32 characters of the note. A general
note is also possible - it's the 'note' button.
See the red book in the system tray. On L-button down, the calendar slides up
(depending on the location of the task bar) and the book lights up in bright
red. By pressing it again, it slides down and the book is dimmed into a darker
red. On R-button down, it shows a menu that has approximately the same things as
the window itself. A balloon pops up telling you the date and week# when
positioned over the book. At the first time launched, a shortcut is added to
your startup folder if you are on W2K.
On double clicking tray icon holding ctrl. down, MirandaPlanner
terminates.
Known problems
The menu is a nice XP-style menu from CodeProject itself by Yao Zhifeng. BUT
it has some serious problems as I've stated in a thread to him. Unfortunately,
he is not that interested in my remarks it seems (what other possible conclusion
can I reach?). Even in his test app., the problem arises - menus are wiped clean
and corrupted when using keys and that's serious. But it's a nice GUI and
therefore I hope to get some response. I've changed it a little so it can show
two lines in its vertical box.
Old name 'Miranda' seemed to confuse some people and therefore I've
changed it into MirandaPlanner now. Number of versions are inherited from
'Miranda' and continued.
Revision history
- 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
CTimeEx
-class.
- 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.