Click here to Skip to main content
15,897,165 members
Articles / Web Development / HTML

EvaLayout, Lay It Be!

Rate me:
Please Sign up or sign in to vote.
4.93/5 (58 votes)
23 May 2017CPOL7 min read 188.8K   4.3K   114  
An efficient and flexible layout manager
/*
Eva library C++ (see java package de.elxala.Eva and EvaFormat.PDF)
Copyright (C) 2005-2016  Alejandro Xalabarder Aulet

This library is free software; 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; either
version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*/

/**
   mainEvaLayoutV4.cpp

   Copyright (c) 2006-2016 Alejandro Xalabarder


   This is a demo application of EvaLayoutManager.
   The layout information will be load from the file ConfigDemoSwitchAndMask.eva
   
   
   This window application creates 4 labels, 4 buttons, 3 edit fields,
   a list, a memo field and a combo box that will be laid out by EvaLayoutManager.

   To better show the flexibility of EvaLayoutManager we will load different layouts
   for the same components and then switch between them dynamically. The layouts
   for this demo are stored in the provided file WinLayouts.eva. In the case this file
   were not found (try to rename it) the application will create programatically two layouts, this
   is done in the method prepareLayout.

   All is done in MainDlgProc

      on WM_INITDIALOG :
         we load the layouts or harcode them and set the first
         layout into the layout manager.
         also we give the manager the physical components that it
         should handle, giving to it the window id's

      on WM_SIZE :
         we call ::doLayout to ensure the components are right dimensioned
         and placed (the job of the manager)

      on WM_COMMAND / IDM_OTRO (menu Switch layout) :

         we switch the layout

*/

#include <windows.h>
#include <stdlib.h>
#include <tchar.h>  // for  _T macro
#include "../resource.h"

#include "EvaLayoutManagerV4.h"

#include "EvaClasses.h"
#include "EvaFile.h"

using namespace celta;


#define MAX_LOADSTRING 100


// EVA Layout --------------------------------
//
//  variables for this sample
//
EvaLayoutManager gaston;  // the EvaLayoutManager object
EvaUnit layoutArray;
string currentLayoutName = "main";
int currentLayIndx = 0;             // # of current layout

void prepareLayout (HWND hDlg);
void linkLayout    (HWND hDlg);
void showLayout    (HWND hDlg, bool forceInvalidate = false);
void switchLayout  (HWND hDlg);


// Global Variables:
HINSTANCE hInst;                       // current instance
TCHAR szTitle[MAX_LOADSTRING];         // The title bar text
TCHAR szWindowClass[MAX_LOADSTRING];   // The title bar text


// Foward declarations of functions included in this code module:
BOOL           InitInstance(HINSTANCE, int);
LRESULT CALLBACK  About(HWND, UINT, WPARAM, LPARAM);


BOOL CALLBACK MainDlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);


int APIENTRY WinMain(HINSTANCE hInstance,
                     HINSTANCE /* hPrevInstance */,
                     LPSTR     /* lpCmdLine */,
                     int       nCmdShow)
{
   MSG msg;
   HACCEL hAccelTable;

   // Initialize global strings
   LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
   LoadString(hInstance, IDC_DEMO, szWindowClass, MAX_LOADSTRING);

   // Perform application initialization:
   if (!InitInstance (hInstance, nCmdShow))
   {
      printf ("WinMain: cannot InitInstance, return!\n");
      return FALSE;
   }

   hAccelTable = LoadAccelerators(hInstance, (LPCTSTR)IDC_DEMO);

   // Main message loop:
   while (GetMessage(&msg, NULL, 0, 0))
   {
      if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
      {
         TranslateMessage(&msg);
         DispatchMessage(&msg);
     }
   }

   return msg.wParam;
}


// --------------------------------------------------------
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
   HWND hWnd;

   hInst = hInstance; // Store instance handle in our global variable

   hWnd = CreateDialog(hInstance,
      MAKEINTRESOURCE(IDD_DIALOG_MAIN),
      NULL, // handle to owner window
      (DLGPROC)MainDlgProc);

   if (!hWnd)
   {
      return FALSE;
   }

   ShowWindow(hWnd, nCmdShow);
   UpdateWindow(hWnd);

   return TRUE;
}

// --------------------------------------------------------
// Mesage handler for about box.
LRESULT CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM /* lParam */)
{
   switch (message)
   {
      case WM_INITDIALOG:
            return TRUE;

      case WM_COMMAND:
         if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)
         {
            EndDialog(hDlg, LOWORD(wParam));
            return TRUE;
         }
         break;
   }
    return FALSE;
}


// --------------------------------------------------------
// A dialog is used instead of a window for this example
BOOL CALLBACK MainDlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
   switch (uMsg)
   {
      case WM_INITDIALOG:
         {
            prepareLayout (hDlg);
            linkLayout (hDlg);
            showLayout(hDlg, true);

            // add some data to the combo box to check the fix if its weird behavior
            SendMessage(GetDlgItem(hDlg, ID_COMBO),CB_ADDSTRING,0, (LPARAM) _T("Item1"));
            SendMessage(GetDlgItem(hDlg, ID_COMBO),CB_ADDSTRING,0, (LPARAM) _T("Segon"));
            SendMessage(GetDlgItem(hDlg, ID_COMBO),CB_ADDSTRING,0, (LPARAM) _T("Tercer"));
            SendMessage(GetDlgItem(hDlg, ID_COMBO),CB_ADDSTRING,0, (LPARAM) _T("etc.. etc.."));
         }
         return TRUE;

      case WM_SIZE:
         if (wParam == SIZE_RESTORED || wParam == SIZE_MAXIMIZED)
         {
            // EVA Layout --------------------------------
            //
            // on each size change
            //
            showLayout (hDlg);
         }
         break;

      case WM_COMMAND:
         {
            WORD cmd = LOWORD(wParam);
            switch(cmd)
            {
               case ID_BUTTON_1:
               {
                  switchLayout (hDlg);
                  return TRUE;
               }

               case ID_BUTTON_2:
               {
                  // mask (substitute) layout "form1" with the layout "form2"
                  gaston.maskElement ("form1", "form2");
                  showLayout (hDlg, true);
                  return TRUE;
               }

               case ID_BUTTON_3:
               {
                  // mask (substitute) layout "form1" with the component "memo"
                  gaston.maskElement("form1", "memo");
                  showLayout(hDlg, true);
                  return TRUE;
               }

               case ID_BUTTON_4:
               {
                  // unmask layout "form1" (revert any mask on it)
                  gaston.unmaskElement("form1");
                  showLayout(hDlg, true);
                  return TRUE;
               }

               case IDM_EXIT:
               case IDOK:
               case IDCANCEL:
               {
                  PostQuitMessage(0);
                  EndDialog(hDlg, LOWORD(wParam));
               }
               return TRUE;

               case IDM_OTRO:
               {
                  switchLayout (hDlg);
               }
               return TRUE;

               case IDM_ABOUT:
               {
                  DialogBox(hInst, (LPCTSTR)IDD_ABOUTBOX, hDlg, (DLGPROC)About);
               }
               return TRUE;

               default:
                  break;
            }
         }
         break;

   }
    return FALSE;
}

void prepareLayout (HWND hDlg)
{
   // EVA Layout --------------------------------
   // Load layoutInfo in two different ways :
   //
   //    If the file WinLayouts.eva is found then the layout Info's
   //    contained in the unit #data# are loaded. Otherwise
   //    we build here two harcoded Eva layout Info's.
   //

   EvaFile efi;
   if (! efi.load(layoutArray, "ConfigDemoSwitchAndMask.eva", "data"))
   {
      //MessageBox(hDlg, (LPCWSTR) "Working with two harcoded layoutInfo's\nbecause file ConfigLayouts.eva is not found", "Warning", MB_OK);

      // create two Eva's on this EvaUnit
      //
      Eva e1 = Eva ("main");
      Eva e2 = Eva ("second");
      layoutArray.addEva (e1);
      layoutArray.addEva (e2);

      // get the references to the Eva's to fill them
      // (note that eunit[0] and eunit[1] could be used as well)
      //
      Eva & layI1 = layoutArray["main"];

      layI1.addLine (EvaLine ("EvaLayout, 10, 10, 5, 5"));
      layI1.addLine (EvaLine (" zzz,         ,   X      ,  A     ,"));
      layI1.addLine (EvaLine ("    , label1  , edit1    , -      ,"));
      layI1.addLine (EvaLine ("    , label2  , edit2    , -      ,"));
      layI1.addLine (EvaLine ("    , combo   , memo     , boton1 ,"));
      layI1.addLine (EvaLine ("  X ,         ,   +      ,        ,"));

      Eva & layI2 = layoutArray["second"];

      layI2.addLine (EvaLine ("EvaLayout, 10, 10, 5, 5"));
      layI2.addLine (EvaLine ("xxx,    A     ,    A    , X       ,  "));
      layI2.addLine (EvaLine ("  A, boton1   , label1  , edit1   ,  "));
      layI2.addLine (EvaLine ("  A,          , label2  , edit2   ,  "));
      layI2.addLine (EvaLine ("  A,          , label3  , edit3   ,  "));
      layI2.addLine (EvaLine ("  A, memo     ,   -     ,    -    ,  "));
      layI2.addLine (EvaLine ("  X,  +       ,         ,         ,  "));

      // to export the harcoded EvaUnit ...
      //
      // efi.saveSingleUnit (eunit, "hardcoded.eva");
   }

   if (layoutArray.size () == 0)
   {
      //MessageBox(hDlg, "Error there are no layouts loaded!", "Error", MB_OK);
      PostQuitMessage(0);
      //EndDialog (hDlg, LOWORD(wParam));
   }

   gaston.setLayouts (layoutArray);
   currentLayoutName = "main";
}

void linkLayout (HWND hDlg)
{
   // ---- EvaLayout: Associate all components with its logic names given in layout info(s)
   //                 It is enough to it only once but all components from all possible layouts has to be declared here
   //                 to allow EvaLayoutManager to handle them in future switch layout or mask operation.
   //
   gaston.addWinApiWidget (winApiWidget ("lista",   GetDlgItem(hDlg, ID_LIST)));
   gaston.addWinApiWidget (winApiWidget ("memo",    GetDlgItem(hDlg, ID_MEMO)));

   // Important!
   //   for combos we have to call winApiWidget with third parameter = true !!
   //
   gaston.addWinApiWidget (winApiWidget ("combo",   GetDlgItem(hDlg, ID_COMBO), true));

   gaston.addWinApiWidget (winApiWidget ("boton1",  GetDlgItem(hDlg, ID_BUTTON_1)));
   gaston.addWinApiWidget (winApiWidget ("boton2",  GetDlgItem(hDlg, ID_BUTTON_2)));
   gaston.addWinApiWidget (winApiWidget ("boton3",  GetDlgItem(hDlg, ID_BUTTON_3)));
   gaston.addWinApiWidget (winApiWidget ("boton4",  GetDlgItem(hDlg, ID_BUTTON_4)));

   gaston.addWinApiWidget (winApiWidget ("edit1",   GetDlgItem(hDlg, ID_EDIT_1)));
   gaston.addWinApiWidget (winApiWidget ("edit2",   GetDlgItem(hDlg, ID_EDIT_2)));
   gaston.addWinApiWidget (winApiWidget ("edit3",   GetDlgItem(hDlg, ID_EDIT_3)));

   gaston.addWinApiWidget (winApiWidget ("label1",  GetDlgItem(hDlg, ID_LABEL_1)));
   gaston.addWinApiWidget (winApiWidget ("label2",  GetDlgItem(hDlg, ID_LABEL_2)));
   gaston.addWinApiWidget (winApiWidget ("label3",  GetDlgItem(hDlg, ID_LABEL_3)));
   gaston.addWinApiWidget (winApiWidget ("label4",  GetDlgItem(hDlg, ID_LABEL_4)));
   // ================================================================
}

/**
   // ---- EvaLayout: method for MFC to recalculate the layout
   //
   call this function after setting a new layout
   or resizing the window
*/
void showLayout (HWND hDlg, bool forceInvalidate)
{
   RECT rc;
   GetClientRect(hDlg, &rc);

   // ---- EvaLayout: do the real job
   //
   gaston.doShowLayout(currentLayoutName, (int) (rc.right - rc.left), (int) (rc.bottom - rc.top));

   // for example: just invalidate sometimes to avoid flickering
   //              if Invalidate is never called then in some situations
   //              the components are wrong painted
   static int sometimes = 0;
   if (forceInvalidate || sometimes ++ > 40)
   {
      sometimes = 0;
      InvalidateRect(hDlg, &rc, true);
   }
}

void switchLayout (HWND hDlg)
{
   // ---- EvaLayout: her we switch between layout "main" and layout "second" if given

   if (layoutArray.containsEva("main") && layoutArray.containsEva("second"))
   {
      //printf ("setLayout %d [%s]\n", currentLayIndx, currentLayoutName.c_str ());
      currentLayoutName = (currentLayoutName == "main") ? "second" : "main";
      showLayout(hDlg, true);
   }
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Germany Germany
I have a Telecomunications Engineering degree but since I learnt the first language (Pascal), almost I haven't stopped developing software. Mainly with C and C++ but I have touched many other languages and scripts. I use also to develop for fun (reinventing the wheel, of course!), currently almost all of such programs and tools are written in java (visit www.elxala.de).

Comments and Discussions