NewStartCenterBehavior

WORK IN PROGRESS

All the changes added to the original OpenOffice.org source code provided in this page, are :


 * '''Under LGPL License V3, ( and you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation)
 * Copyright Eric Bachard 20 December 2010

Important: If you use this information, don't forget everything you'll find here is under CC by-sa License, and you must mention your sources in what you write ...

OOo4Kids 1.1 or previous versions
Until the 1.1 version, the startcenter had the following feature (see image below) :




 * when the mouse cursor rolls over the icons, a bubble appears and describes the role of the associated application.


 * one message by icon. For the English version it gives :
 * Create a Text with Writer
 * Draw something
 * Create a presentation with Impress
 * Create a Calc sheet
 * Open a document...


 * some time after the mouse cursor goes out of the icon area, the bubble disappears

The problem was, that the help bubble could appear anywhere, including over the icon, sometimes hiding it, which was basically bad on the user experience side.

Since 1.2 version
The proposed enhancement allows now to display :


 * the same string as the one in the bubble ;
 * '''always at a given location, whatever the icon under the mouse cursor (but the appearing text will match with the icon).
 * no need to add new localized strings : we'll simply reuse the existing one

The features works already, and some screenshots describing the existing cases are proposed below.

Possible improvement :


 * no longer display "Create a new document" (probably useless and overloading the visual);
 * modify the current design (move the frame containing the icons higher, say better centered;
 * (thanks to add your proposal on the list).

Screenshots (French only, will be improved asap)
New StartCenter behavior, when the mouse cursor rolls over the applications icons

Introduction
Below, you'll find a technical description of the New StartCenter behavior feature. It is a matter of the OpenOffice.org source code (mainly C++), e.g. the internal source code organisation in OpenOffice.org framework. Thus, we suppose the reader has the mandatory basics to understand the content of what is proposed.

The prerequisites to read this article still have to be defined, but if the reader is not comfortable with some notions, we invite him to have a look at the OpenOffice.org wiki to complete his knowledge, and read this article in the best conditions.

At the beginning, I had no precise idea where to start. So I imagined a solution, but it was not correct. I must say a big thank you to Philipp Lohmann, who - one more time - kindly explained to me what I had to do (  see this mail). To share what I learned, I added as much information as I could, as described below.

Any constructive remark, helping to improve this documentation is welcome.

Specifications

 * Make the Help bubbles close
 * Start an Events Listener, of VclWindowEvent type
 * Terminate this Events listeners (in the BackingWindow object desctructor, when the window is closing)
 * Initialize the strings to be displayed, in particular initialize the fonts the right way
 * Implement a callback, triggered by the right event (VclWindowEvent)
 * Propose an algorithm allowing to display the right string, for all possibles cases
 * Make it work
 * Remove obsolete code
 * Validate

Concerned modules
Only one module is concerned in that feature. It's framework, and the modified code stands in framework/source/services:


 * framework/source/services/backingwindow.hxx // interface
 * framework/source/services/backingwindow-OOo4Kids.hxx // OOo4Kids implementation only
 * framework/source/services/backingwindow-OOoLight.cxx // OOoLight implementation only

Make the previous bubble help close
As Philipp Lohmann explained in his initial mail, to prevent the toolbox from still popping up its quick help window, it's sufficient to derive from the toolbox (since it's a DecoToolbox in backingwindow.cxx) and to implement the same -doing nothing- method.

In the code, this is summarized by :

Index: framework/source/services/backingwindow.hxx

=
====================================================== --- framework/source/services/backingwindow.hxx	(revision 1034) +++ framework/source/services/backingwindow.hxx	(working copy) @@ -78,6 +78,9 @@                DecoToolBox( Window* pParent, const ResId& rResId ); void   DataChanged( const DataChangedEvent& rDCEvt ); + +       // The goal is to overload the Toolbox method, thus make the QuickHelp shut up +        void    RequestHelp( const HelpEvent& rHEvt );

Implementation (in framework/source/services/backingwindow-OOo4Kids.cxx for example) :

Add the method doing nothing : +       void DecotoolBox::RequestHelp( const HelpEvent& rHEvt ) + { +    (void)rHEvt; // makes the compiler happy + };

Works out of the box :-)

Add the new eventlistener
The BackingWindow::initControls method is called once only (following "singleton" Design Pattern), and it looks ok, to implement the events listened there @@ -383,15 +413,7 @@        }     }			 (removed code) +   maToolbox.AddEventListener( LINK( this, BackingWindow, DecoToolboxHdl ) ); maToolbox.SetSelectHdl( LINK( this, BackingWindow, ToolboxHdl ) ); maToolbox.Show;

The call is done as a Callback, with the purpose to execute an action when an event of the right type will be detected.

Add the new callback
The callback does catch events of VclWindowEvent* type (pointers on VclWindowEvent type), in particular, these two event, who appear in the code below:


 * VCLEVENT_TOOLBOX_HIGHLIGHT : Triggers the highlight. Sent when the mouse cursor rolls over one of the startcenter icons
 * VCLEVENT_TOOLBOX_HIGHLIGHTOFF : end of highlight. Sent when the mouse cursor goes out of any application icon area.

The (trivial) algorithm is : If event is of VclWindowEvent type and if this event is one VCLEVENT_TOOLBOX_HIGHLIGHT event

Choose the icon in the following cases :

Case Calc application identified : display Calc message End

Case Draw application identified : display Draw message End

Case Impress application identified : display Impress message End

Case Open a document identified : display Open a document message End

Case Writer application identified : display Writer message End

Case whatever else: End

Else if event is of VclWindowEvent type and if this event is one VCLEVENT_TOOLBOX_HIGHLIGHTOFF event Hide all messages End if

Strings initialization
The initialization counts 3 steps :

Step 1 declaration in the interface.
For that, we'll use objects of type :


 * Control: FixedText
 * 2D containers : Size (width, heigth)
 * Fonts
 * String (constants) of String types (already defined, simply reused)

Step 2: Initialization of the fonts for every string to be displayed
Concerned : Backingwindow::initControls

maTextFont : already intialized, and obtained the following way : maTextFont = GetSettings.GetStyleSettings.GetLabelFont;

We'll have to initialize:


 * the font for every string,
 * the characters size (including kerning value - we don't care here -)
 * style attribute (WEIGHT_NORMAL for us)

As example, how is set the message who will appear when the mouse cursor will roll over Calc icon:

+   // Set the messages to be displayed +   maTextFont.SetSize( Size( 0, 13 ) ); +   maTextFont.SetWeight( WEIGHT_NORMAL ); +   maCalcMessageText.SetText( maCalcString ); +   maCalcMessageText.SetFont( maTextFont ); +   maCalcMessageText.SetControlFont( maTextFont ); +   maCalcMessageSize = Size( maCalcMessageText.GetTextWidth( maCalcString ), maCalcMessageText.GetTextHeight * 1.18 );

No need to re-initialize the size (SetSize method) for the next strings, because nothing is modified :

+ +   maDrawMessageText.SetText( maDrawString ); +   maDrawMessageText.SetFont( maTextFont ); +   maDrawMessageText.SetControlFont( maTextFont ); +   maDrawMessageSize = Size( maDrawMessageText.GetTextWidth( maDrawString ), maDrawMessageText.GetTextHeight * 1.18 ); +

-> please read the code for the next/other strings

Step 3 : strings positioning in the Window
This happens in the BackingWindow::Resize method, called every time something changes in the window

@@ -501,8 +519,70 @@    maCreateText.SetPosSizePixel( Point( (aWindowSize.Width - maCreateSize.Width + STRING_OFFSET_X) / 2, nYPos ),                                   Size( maControlRect.GetWidth, maCreateSize.Height ) ); + +   // defines the location of the Create text +   nYPos += 170;// FIXME: better method ... + +   maCalcMessageText.SetPosSizePixel( Point( (aWindowSize.Width - maCalcMessageSize.Width + STRING_OFFSET_X) / 2, nYPos ), +                                  Size( maControlRect.GetWidth, maCalcMessageSize.Height ) );

It is important to notice the calculation mode for the positioning (the previous one was wrong). Remain anyway a problem, because we need the second displaying of the Backingwindow, to see a correct calculation. [FIXME]

Same thing for the other controls below :

+ +   maDrawMessageText.SetPosSizePixel( Point( (aWindowSize.Width - maDrawMessageSize.Width + STRING_OFFSET_X) / 2, nYPos ), +                                  Size( maControlRect.GetWidth, maDrawMessageSize.Height ) ); + +   maImpressMessageText.SetPosSizePixel( Point( (aWindowSize.Width - maImpressMessageSize.Width + STRING_OFFSET_X) / 2, nYPos ), +                                  Size( maControlRect.GetWidth, maImpressMessageSize.Height ) ); + +   maOpenMessageText.SetPosSizePixel( Point( (aWindowSize.Width - maOpenMessageSize.Width + STRING_OFFSET_X) / 2, nYPos ), +                                  Size( maControlRect.GetWidth, maOpenMessageSize.Height ) ); + +   maWriterMessageText.SetPosSizePixel( Point( (aWindowSize.Width - maWriterMessageSize.Width + STRING_OFFSET_X) / 2, nYPos ), +                                  Size( maControlRect.GetWidth, maWriterMessageSize.Height ) ); }

==== Callback implementation

+IMPL_LINK( BackingWindow, DecoToolboxHdl, VclWindowEvent*, pEvent ) + { +   if( pEvent && pEvent->GetId == VCLEVENT_TOOLBOX_HIGHLIGHT ) +   { +#ifdef DEBUG +       fprintf(stderr, "Toolbox nItemId = %d \n", maToolbox.GetHighlightItemId ); +#endif +       switch ( maToolbox.GetHighlightItemId ) +       { +            case nItemId_Calc: +           { +                maMessageText.SetText( maCalcString ); +               maMessageSize = Size( maMessageText.GetTextWidth( maCalcString ), +                                       maMessageText.GetTextHeight * DEFAULT_ZOOM_FACTOR ); +           } +                break; +           case nItemId_Draw: +           { +                maMessageText.SetText( maDrawString ); +               maMessageSize = Size( maMessageText.GetTextWidth( maDrawString ), +                                      maMessageText.GetTextHeight * DEFAULT_ZOOM_FACTOR ); +           } +                break; +           case nItemId_Impress: +           { +                maMessageText.SetText( maImpressString ); +               maMessageSize = Size( maMessageText.GetTextWidth( maImpressString ), +                                      maMessageText.GetTextHeight * DEFAULT_ZOOM_FACTOR ); +           } +                break; +           case nItemId_Info: +           { +                maMessageText.SetText( maOpenString ); +               maMessageSize = Size( maMessageText.GetTextWidth( maOpenString ), +                                      maMessageText.GetTextHeight * DEFAULT_ZOOM_FACTOR ); +           } +                break; +           case nItemId_Writer: +           { +                maMessageText.SetText( maWriterString ); +               maMessageSize = Size( maMessageText.GetTextWidth( maWriterString ), +                                      maMessageText.GetTextHeight * DEFAULT_ZOOM_FACTOR ); +           } +                break; +           case nItemId_Extensions: +           case nItemId_Reg: +           case nItemId_TplRep: +           default: +               break; +       } +	 setMessageTextSize; +       maMessageText.Show; +   } +    else if( pEvent && pEvent->GetId == VCLEVENT_TOOLBOX_HIGHLIGHTOFF ) +       maMessageText.Hide; +   return 0; +}

Summary : what was important, and what was ... boring

 * Time necessary for the implementation : between 20h and 24h of work(full time) (includes debugging)
 * Retrieve the right id : use maToolbox.GetHighlightItemId instead of maToolbox.GetCurItemId who will always give "0") .. can save a precious time.
 * Callback choice : linked to what is a Decotoolbox to the BackingWindow (the effort is mandatory)
 * Correct fonts initialization : use SetControl saves ... (I lost a lot of time because of that :/ )
 * Knowledge of the possible / accessible methods : opengrok helps a lot (what a nice tool !)