// swad_layout.c: page layout
/*
SWAD (Shared Workspace At a Distance),
is a web platform developed at the University of Granada (Spain),
and used to support university teaching.
This file is part of SWAD core.
Copyright (C) 1999-2014 Antonio Caņas Vargas
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program 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 Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see .
*/
/*****************************************************************************/
/********************************* Headers ***********************************/
/*****************************************************************************/
#include // For NULL
#include // For exit, system, malloc, calloc, free, etc
#include // For string functions
#include "swad_action.h"
#include "swad_changelog.h"
#include "swad_config.h"
#include "swad_connected.h"
#include "swad_database.h"
#include "swad_global.h"
#include "swad_notice.h"
#include "swad_notification.h"
#include "swad_parameter.h"
#include "swad_preference.h"
#include "swad_theme.h"
#include "swad_web_service.h"
/*****************************************************************************/
/************** External global variables from others modules ****************/
/*****************************************************************************/
extern struct Globals Gbl;
extern struct Act_Actions Act_Actions[Act_NUM_ACTIONS];
/*****************************************************************************/
/****************************** Public constants *****************************/
/*****************************************************************************/
const char *Lay_LayoutIcons[Lay_NUM_LAYOUTS] =
{
"desktop",
"mobile",
};
/*****************************************************************************/
/****************************** Private constants ****************************/
/*****************************************************************************/
// #define HORIZONTAL_MENU 1
const char *Lay_TabIcons[Act_NUM_TABS] =
{
/* TabUnk */ NULL,
/* TabSys */ "sys",
/* TabCty */ "cty",
/* TabIns */ "ins",
/* TabCtr */ "ctr",
/* TabDeg */ "deg",
/* TabCrs */ "crs",
/* TabAss */ "ass",
/* TabUsr */ "usr",
/* TabMsg */ "msg",
/* TabSta */ "sta",
/* TabPrf */ "prf",
};
/*****************************************************************************/
/******************************* Private types *******************************/
/*****************************************************************************/
/*****************************************************************************/
/***************************** Private variables *****************************/
/*****************************************************************************/
/*****************************************************************************/
/***************************** Private prototypes ****************************/
/*****************************************************************************/
static void Lay_WriteEndOfPage (void);
static void Lay_WritePageTitle (void);
static void Lay_WriteRedirectionToMyLanguage (void);
static void Lay_WriteScripts (void);
static void Lay_WriteScriptInit (void);
static void Lay_WriteScriptConnectedUsrs (void);
static void Lay_WriteScriptCustomDropzone (void);
static void Lay_WritePageTopHeading (void);
static void Lay_DrawTabs (void);
static void Lay_DrawTabsDeskTop (void);
static void Lay_DrawTabsMobile (void);
static bool Lay_CheckIfICanViewTab (Act_Tab_t Tab);
static void Lay_DrawBreadcrumb (void);
#ifndef HORIZONTAL_MENU
static void Lay_WriteVerticalMenuThisTabDesktop (void);
#endif
#ifdef HORIZONTAL_MENU
static void Lay_WriteHorizontalMenuThisTabDesktop (void);
#endif
static void Lay_WriteMenuThisTabMobile (void);
static void Lay_WriteBreadcrumbHome (void);
static void Lay_WriteBreadcrumbTab (void);
static void Lay_WriteBreadcrumbAction (void);
#ifndef HORIZONTAL_MENU
static void Lay_WriteTitleAction (void);
#endif
static void Lay_ShowLeftColumn (void);
static void Lay_ShowRightColumn (void);
static void Lay_WriteFootFromHTMLFile (void);
/*****************************************************************************/
/*********************** Write the start of the page *************************/
/*****************************************************************************/
void Lay_WriteStartOfPage (void)
{
extern const char *Txt_STR_LANG_ID[Txt_NUM_LANGUAGES];
extern const unsigned Txt_Current_CGI_SWAD_Language;
extern const char *The_TabOnBgColors[The_NUM_THEMES];
extern const char *Txt_NEW_YEAR_GREETING;
unsigned ColspanCentralPart;
// char QueryDebug[1024];
/***** If, when this function is called, the head is being written, or the head is already written ==>
==> don't do anything *****/
if (Gbl.Layout.WritingHTMLStart ||
Gbl.Layout.HTMLStartWritten)
return;
// if (Gbl.Usrs.Me.UsrDat.UsrCod == 1346)
// {
// sprintf (QueryDebug,"INSERT INTO debug (DebugTime,Txt) VALUES (NOW(),'Act_Actions[ActRefLstClk].ActCod = %u --- Act_Actions[Gbl.CurrentAct].ActCod = %u')",
// (unsigned) Act_Actions[ActRefLstClk].ActCod,(unsigned) Act_Actions[Gbl.CurrentAct].ActCod);
// DB_QueryINSERT (QueryDebug,"Error inserting in debug table");
// }
/***** Compute connected users *****/
if (Gbl.CurrentAct == ActLstCon ||
(Gbl.Prefs.Layout == Lay_LAYOUT_DESKTOP &&
(Gbl.Prefs.SideCols & Lay_SHOW_RIGHT_COLUMN) &&
Gbl.CurrentCrs.Crs.CrsCod >= 0)) // Right column visible && There is a course selected
Con_ComputeConnectedUsrsBelongingToCurrentCrs ();
/***** Send head width the file type for the HTTP protocol *****/
if (Gbl.CurrentAct == ActRefCon ||
Gbl.CurrentAct == ActRefLstClk) // Don't generate a full HTML page, only refresh connected users
{
fprintf (Gbl.F.Out,"Content-Type: text/html; charset=windows-1252\r\n");
fprintf (Gbl.F.Out,"Cache-Control: max-age=0, no-cache, must-revalidate\r\n\r\n");
Gbl.Layout.WritingHTMLStart = false;
Gbl.Layout.HTMLStartWritten = Gbl.Layout.TablEndWritten = true;
return;
}
/***** If serving a web service ==> don't do anything *****/
if (Gbl.WebService.IsWebService)
{
Gbl.Layout.WritingHTMLStart = false;
Gbl.Layout.HTMLStartWritten = Gbl.Layout.TablEndWritten = true;
return;
}
Gbl.Layout.WritingHTMLStart = true;
/***** Write header to standard output to avoid timeout *****/
// Two \r\n are necessary
fprintf (stdout,"Content-type: text/html; charset=windows-1252\r\n\r\n"
"\n");
/***** Write start of HTML code *****/
// WARNING: It is necessary to comment the line AddDefaultCharset UTF8 in httpd.conf to enable meta tag
fprintf (Gbl.F.Out,"\n"
"\n"
"\n",
Txt_STR_LANG_ID[Gbl.Prefs.Language]);
/* Title */
Lay_WritePageTitle ();
/* Favicon */
fprintf (Gbl.F.Out,"\n"
"\n",
Gbl.Prefs.IconsURL,
Gbl.Prefs.IconsURL);
/* Style sheet for SWAD */
fprintf (Gbl.F.Out,"\n",
Cfg_HTTPS_URL_SWAD_PUBLIC,
(Gbl.Prefs.Layout == Lay_LAYOUT_DESKTOP) ? "swad_desktop.css" :
"swad_mobile.css");
/* Style sheet for Dropzone.js (http://www.dropzonejs.com/) */
// The public directory dropzone must hold:
// dropzone.js
// css/dropzone.css
// images/spritemap@2x.png
// images/spritemap.png
if (Gbl.CurrentAct == ActFrmCreDocCrs || // Brw_FILE_BRW_ADMIN_DOCUMENTS_CRS
Gbl.CurrentAct == ActFrmCreDocGrp || // Brw_FILE_BRW_ADMIN_DOCUMENTS_GRP
Gbl.CurrentAct == ActFrmCreComCrs || // Brw_FILE_BRW_COMMON_CRS
Gbl.CurrentAct == ActFrmCreComGrp || // Brw_FILE_BRW_COMMON_GRP
Gbl.CurrentAct == ActFrmCreAsgUsr || // Brw_FILE_BRW_ASSIGNMENTS_USR
Gbl.CurrentAct == ActFrmCreAsgCrs || // Brw_FILE_BRW_ASSIGNMENTS_CRS
Gbl.CurrentAct == ActFrmCreWrkUsr || // Brw_FILE_BRW_WORKS_USR
Gbl.CurrentAct == ActFrmCreWrkCrs || // Brw_FILE_BRW_WORKS_CRS
Gbl.CurrentAct == ActFrmCreMrkCrs || // Brw_FILE_BRW_ADMIN_MARKS_CRS
Gbl.CurrentAct == ActFrmCreMrkGrp || // Brw_FILE_BRW_ADMIN_MARKS_GRP
Gbl.CurrentAct == ActFrmCreBrf) // Brw_FILE_BRW_BRIEFCASE_USR
fprintf (Gbl.F.Out,"\n",
Cfg_HTTPS_URL_SWAD_PUBLIC);
/* Redirect to correct language */
if ((Gbl.CurrentAct == ActAutUsrInt ||
Gbl.CurrentAct == ActAutUsrExt) && // Action is log in
Gbl.Usrs.Me.Logged && // I am just logged
Gbl.Usrs.Me.UsrDat.Prefs.Language != Txt_Current_CGI_SWAD_Language) // My language != current language
Lay_WriteRedirectionToMyLanguage ();
/* Write initial scripts depending on the action */
Lay_WriteScripts ();
fprintf (Gbl.F.Out,"\n");
/***** HTML body *****/
fprintf (Gbl.F.Out,"\n");
Gbl.Layout.WritingHTMLStart = false;
Gbl.Layout.HTMLStartWritten =
Gbl.Layout.TablEndWritten = true;
return;
}
fprintf (Gbl.F.Out," onload=\"init()\">\n");
if (Act_Actions[Gbl.CurrentAct].BrowserWindow == Act_MAIN_WINDOW)
fprintf (Gbl.F.Out,"
"
""
"
"
"
"
"
",
Gbl.Prefs.IconsURL);
/***** Header of layout *****/
fprintf (Gbl.F.Out,"
");
Lay_WritePageTopHeading ();
switch (Gbl.Prefs.Layout)
{
case Lay_LAYOUT_DESKTOP:
if (Gbl.Prefs.SideCols == Lay_SHOW_BOTH_COLUMNS)
ColspanCentralPart = 1; // 11: both side columns visible, left and right
else if (Gbl.Prefs.SideCols == Lay_HIDE_BOTH_COLUMNS)
ColspanCentralPart = 3; // 00: both side columns hidden
else
ColspanCentralPart = 2; // 10 or 01: only one side column visible, left or right
break;
case Lay_LAYOUT_MOBILE:
ColspanCentralPart = 3;
break;
default:
break;
}
fprintf (Gbl.F.Out,"
"
"
"
"
"
"
",
ColspanCentralPart,
The_TabOnBgColors[Gbl.Prefs.Theme]);
/***** Central (main) part *****/
switch (Gbl.Prefs.Layout)
{
case Lay_LAYOUT_DESKTOP:
/* Left bar used to expand-contract central zone */
fprintf (Gbl.F.Out,"
");
Usr_WarningWhenDegreeTypeDoesntAllowDirectLogin ();
if (Act_Actions[Act_Actions[Gbl.CurrentAct].SuperAction].IndexInMenu < 0) // Write vertical menu
{
if (Gbl.CurrentAct == ActMnu)
Lay_WriteMenuThisTabMobile ();
else
Lay_DrawTabsMobile ();
}
break;
default:
break;
}
/***** Main zone *****/
/* Start of main zone for actions output */
fprintf (Gbl.F.Out,"
");
#endif
Usr_WarningWhenDegreeTypeDoesntAllowDirectLogin ();
/* If it is mandatory to read any information about course */
if (Gbl.CurrentCrs.Info.ShowMsgMustBeRead)
Inf_WriteMsgYouMustReadInfo ();
#ifndef HORIZONTAL_MENU
/* Write title of the current action */
if (Gbl.Prefs.Layout == Lay_LAYOUT_DESKTOP &&
Act_Actions[Act_Actions[Gbl.CurrentAct].SuperAction].IndexInMenu >= 0)
Lay_WriteTitleAction ();
#endif
Gbl.Layout.WritingHTMLStart = false;
Gbl.Layout.HTMLStartWritten = true;
/* Write new year greeting */
if (Gbl.CurrentAct == ActAutUsrInt ||
Gbl.CurrentAct == ActAutUsrExt ||
Gbl.CurrentAct == ActAutUsrChgLan)
if (Gbl.Now.Date.Month == 1 &&
Gbl.Now.Date.Day == 1)
{
fprintf (Gbl.F.Out,"
");
}
/* Write message indicating number of clicks allowed before sending my photo */
Usr_InformAboutNumClicksBeforePhoto ();
}
/*****************************************************************************/
/************************ Write the end of the page **************************/
/*****************************************************************************/
static void Lay_WriteEndOfPage (void)
{
if (!Gbl.Layout.TablEndWritten)
{
Gbl.Layout.TablEndWritten = true;
fprintf (Gbl.F.Out,"
");
if (Gbl.Prefs.Layout == Lay_LAYOUT_DESKTOP)
{
/* Right bar used to expand-contract central zone */
fprintf (Gbl.F.Out,"
");
/***** 4th. row, 1st. column *****/
if (Gbl.Prefs.SideCols & Lay_SHOW_LEFT_COLUMN) // Left column visible
{
fprintf (Gbl.F.Out,"
");
Lay_ShowLeftColumn ();
fprintf (Gbl.F.Out,"
"); // End of first column
}
break;
case Lay_LAYOUT_MOBILE:
Lay_DrawTabs ();
fprintf (Gbl.F.Out,"
"
"
");
break;
default:
break;
}
}
/*****************************************************************************/
/*************** Set current tab depending on current action *****************/
/*****************************************************************************/
void Lay_SetCurrentTab (void)
{
Gbl.CurrentTab = Act_Actions[Gbl.CurrentAct].Tab;
/***** Change action and tab if country, institution, centre or degree
are incompatible with the current tab *****/
switch (Gbl.CurrentTab)
{
case TabCty:
if (Gbl.CurrentCty.Cty.CtyCod <= 0) // No country selected
Gbl.CurrentAct = ActSeeCty;
break;
case TabIns:
if (Gbl.CurrentIns.Ins.InsCod <= 0) // No institution selected
{
if (Gbl.CurrentCty.Cty.CtyCod > 0) // Country selected, but no institution selected
Gbl.CurrentAct = ActSeeIns;
else // No country selected
Gbl.CurrentAct = ActSeeCty;
}
break;
case TabCtr:
if (Gbl.CurrentCtr.Ctr.CtrCod <= 0) // No centre selected
{
if (Gbl.CurrentIns.Ins.InsCod > 0) // Institution selected, but no centre selected
Gbl.CurrentAct = ActSeeCtr;
else if (Gbl.CurrentCty.Cty.CtyCod > 0) // Country selected, but no institution selected
Gbl.CurrentAct = ActSeeIns;
else // No country selected
Gbl.CurrentAct = ActSeeCty;
}
break;
case TabDeg:
if (Gbl.CurrentDeg.Deg.DegCod <= 0) // No degree selected
{
if (Gbl.CurrentCtr.Ctr.CtrCod > 0) // Centre selected, but no degree selected
Gbl.CurrentAct = ActSeeDeg;
else if (Gbl.CurrentIns.Ins.InsCod > 0) // Institution selected, but no centre selected
Gbl.CurrentAct = ActSeeCtr;
else if (Gbl.CurrentCty.Cty.CtyCod > 0) // Country selected, but no institution selected
Gbl.CurrentAct = ActSeeIns;
else // No country selected
Gbl.CurrentAct = ActSeeCty;
}
break;
default:
break;
}
Gbl.CurrentTab = Act_Actions[Gbl.CurrentAct].Tab;
Lay_DisableIncompatibleTabs ();
}
/*****************************************************************************/
/************************** Disable incompatible tabs ************************/
/*****************************************************************************/
void Lay_DisableIncompatibleTabs (void)
{
/***** Set country, institution, centre, degree and course depending on the current tab.
This will disable tabs incompatible with the current one. *****/
switch (Gbl.CurrentTab)
{
case TabSys:
Gbl.CurrentCty.Cty.CtyCod = -1L;
// no break
case TabCty:
Gbl.CurrentIns.Ins.InsCod = -1L;
// no break
case TabIns:
Gbl.CurrentCtr.Ctr.CtrCod = -1L;
// no break
case TabCtr:
Gbl.CurrentDeg.Deg.DegCod = -1L;
// no break
case TabDeg:
Gbl.CurrentCrs.Crs.CrsCod = -1L;
break;
default:
break;
}
}
/*****************************************************************************/
/**************** Draw tabs with the current tab highlighted *****************/
/*****************************************************************************/
static void Lay_DrawTabs (void)
{
unsigned ColspanCentralPart = 3;
if (Gbl.Prefs.Layout == Lay_LAYOUT_DESKTOP)
{
if (Gbl.Prefs.SideCols == Lay_SHOW_BOTH_COLUMNS) // 11: both side columns visible, left and right
ColspanCentralPart = 1;
else if (Gbl.Prefs.SideCols != Lay_HIDE_BOTH_COLUMNS) // 10 or 01: only one side column visible, left or right
ColspanCentralPart = 2;
}
fprintf (Gbl.F.Out,"
"
"
",
ColspanCentralPart,Gbl.Prefs.PathTheme);
switch (Gbl.Prefs.Layout)
{
case Lay_LAYOUT_DESKTOP:
Lay_DrawTabsDeskTop ();
break;
case Lay_LAYOUT_MOBILE:
Lay_DrawBreadcrumb ();
break;
default:
break;
}
fprintf (Gbl.F.Out,"
");
/***** Draw the tabs *****/
for (NumTab = (Act_Tab_t) 1;
NumTab <= (Act_Tab_t) Act_NUM_TABS - 1;
NumTab++)
{
ICanViewTab = Lay_CheckIfICanViewTab (NumTab);
/* If current tab is unknown, then activate the first one with access allowed */
if (Gbl.CurrentTab == TabUnk)
{
Gbl.CurrentTab = NumTab;
Lay_DisableIncompatibleTabs ();
}
if (ICanViewTab || NumTab > TabCrs) // Don't show the first hidden tabs
{
/* Form, icon (at top) and text (at bottom) of the tab */
fprintf (Gbl.F.Out,"
");
/***** Loop to write all options in menu. Each row holds an option *****/
for (NumOptInMenu = 0;
NumOptInMenu < Act_MAX_OPTIONS_IN_MENU_PER_TAB;
NumOptInMenu++)
{
NumAct = Act_Menu[Gbl.CurrentTab][NumOptInMenu].Action;
if (NumAct == 0) // At the end of each tab, actions are initialized to 0, so 0 marks the end of the menu
break;
if (Act_CheckIfIHavePermissionToExecuteAction (NumAct))
{
IsTheSelectedAction = (NumAct == Act_Actions[Gbl.CurrentAct].SuperAction);
Title = Act_GetSubtitleAction (NumAct);
if (SeparationBetweenPreviousAndCurrentOption)
{
if (PreviousVisibleOptions)
fprintf (Gbl.F.Out,"
"
""
"
",
The_ClassSeparator[Gbl.Prefs.Theme]);
SeparationBetweenPreviousAndCurrentOption = false;
}
/***** Start of element *****/
fprintf (Gbl.F.Out,"
");
/***** Start of container used to highlight this option *****/
if (!IsTheSelectedAction)
fprintf (Gbl.F.Out,"
");
/***** Start of form and link *****/
Act_FormStart (NumAct);
Act_LinkFormSubmit (Title,IsTheSelectedAction ? The_ClassMenuOn[Gbl.Prefs.Theme] :
The_ClassMenuOff[Gbl.Prefs.Theme]);
/***** Icon *****/
fprintf (Gbl.F.Out,"
",
Gbl.Prefs.PathIconSet,Cfg_ICON_ACTION_32x32,
Act_Actions[NumAct].Icon);
/***** Text *****/
fprintf (Gbl.F.Out,"
"
"%s",
IsTheSelectedAction ? The_ClassMenuOn[Gbl.Prefs.Theme] :
The_ClassMenuOff[Gbl.Prefs.Theme],
Txt_MENU_TITLE[Gbl.CurrentTab][NumOptInMenu]);
/***** End of link and form *****/
fprintf (Gbl.F.Out,"
"
"
"
""
"");
/***** End of container used to highlight this option *****/
if (!IsTheSelectedAction)
fprintf (Gbl.F.Out,"
");
/***** End of element *****/
fprintf (Gbl.F.Out,"
");
PreviousVisibleOptions = true;
SeparationBetweenPreviousAndCurrentOption = Act_Menu[Gbl.CurrentTab][NumOptInMenu].SubsequentSeparation;
}
}
/***** List end *****/
fprintf (Gbl.F.Out,"
");
/***** Loop to write all options in menu. Each row holds an option *****/
for (NumOptInMenu = 0;
NumOptInMenu < Act_MAX_OPTIONS_IN_MENU_PER_TAB;
NumOptInMenu++)
{
NumAct = Act_Menu[Gbl.CurrentTab][NumOptInMenu].Action;
if (NumAct == 0) // At the end of each tab, actions are initialized to 0, so 0 marks the end of the menu
break;
if (Act_CheckIfIHavePermissionToExecuteAction (NumAct))
{
IsTheSelectedAction = (NumAct == Act_Actions[Gbl.CurrentAct].SuperAction);
Title = Act_GetSubtitleAction (NumAct);
/***** Start of element *****/
fprintf (Gbl.F.Out,"
",
IsTheSelectedAction ? "MENU_ON" :
"MENU_OFF");
/***** Start of container used to highlight this option *****/
if (IsTheSelectedAction)
fprintf (Gbl.F.Out,"
");
else
fprintf (Gbl.F.Out,"
");
/***** Start of form and link *****/
Act_FormStart (NumAct);
Act_LinkFormSubmit (Title,IsTheSelectedAction ? The_ClassMenuOn[Gbl.Prefs.Theme] :
The_ClassMenuOff[Gbl.Prefs.Theme]);
fprintf (Gbl.F.Out,""
"
%s
"
""
"",
Gbl.Prefs.PathIconSet,Cfg_ICON_ACTION_32x32,
Act_Actions[NumAct].Icon,
IsTheSelectedAction ? "ICON28x28" :
"ICON28x28",
Txt_MENU_TITLE[Gbl.CurrentTab][NumOptInMenu]);
/***** End of container used to highlight this option *****/
fprintf (Gbl.F.Out,"
");
/***** End of element *****/
fprintf (Gbl.F.Out,"");
}
}
/***** List end *****/
fprintf (Gbl.F.Out,"");
}
#endif
/*****************************************************************************/
/************* Write the menu of current tab (mobile layout) *****************/
/*****************************************************************************/
static void Lay_WriteMenuThisTabMobile (void)
{
extern const char *The_ClassMenuOn[The_NUM_THEMES];
extern const char *The_ClassMenuOff[The_NUM_THEMES];
extern const struct Act_Menu Act_Menu[Act_NUM_TABS][Act_MAX_OPTIONS_IN_MENU_PER_TAB];
extern const char *Txt_MENU_TITLE[Act_NUM_TABS][Act_MAX_OPTIONS_IN_MENU_PER_TAB];
unsigned NumOptInMenu;
unsigned NumOptVisible; // Only options I can see
Act_Action_t NumAct;
const char *Title;
/***** Table start *****/
fprintf (Gbl.F.Out,"
");
/***** Loop to write all options in menu. Each row holds an option *****/
for (NumOptInMenu = NumOptVisible = 0;
NumOptInMenu < Act_MAX_OPTIONS_IN_MENU_PER_TAB;
NumOptInMenu++)
{
if ((NumAct = Act_Menu[Gbl.CurrentTab][NumOptInMenu].Action) == 0) // At the end of each tab, actions are initialized to 0, so 0 marks the end of the menu
break;
if (Act_CheckIfIHavePermissionToExecuteAction (NumAct))
{
Title = Act_GetSubtitleAction (NumAct);
if (NumOptVisible % Cfg_LAYOUT_MOBILE_NUM_COLUMNS == 0)
fprintf (Gbl.F.Out,"
");
/* Icon at top and text at bottom */
fprintf (Gbl.F.Out,"
");
Act_FormStart (ActLstCon);
Act_LinkFormSubmit (Txt_Connected_users,The_ClassConnected[Gbl.Prefs.Theme]);
fprintf (Gbl.F.Out,"%s"
"",
Txt_Connected_PLURAL);
/***** Number of connected users in the whole platform *****/
fprintf (Gbl.F.Out,"
"); // Used for AJAX based refresh
Con_ShowGlobalConnectedUsrs ();
fprintf (Gbl.F.Out,"
"); // Used for AJAX based refresh
/***** Number of connected users in the current course *****/
fprintf (Gbl.F.Out,"
"); // Used for AJAX based refresh
if (Gbl.CurrentCrs.Crs.CrsCod > 0) // There is a course selected
{
Gbl.Scope.Current = Sco_SCOPE_COURSE;
Con_ShowConnectedUsrsBelongingToScope ();
}
fprintf (Gbl.F.Out,"
"); // Used for AJAX based refresh
fprintf (Gbl.F.Out,"
");
}
/*****************************************************************************/
/**************** Put a icon with a text to submit a form ********************/
/*****************************************************************************/
void Lay_PutSendIcon (const char *Icon,const char *Alt,const char *Text)
{
// margin-left is used because this form link may be placed after another one
fprintf (Gbl.F.Out,""
" %s",
Gbl.Prefs.IconsURL,Icon,Alt,Text);
}
/*****************************************************************************/
/********************** Put a button to submit a form ************************/
/*****************************************************************************/
void Lay_PutSendButton (const char *TextSendButton)
{
fprintf (Gbl.F.Out,"
"
""
"
",
TextSendButton);
}
/*****************************************************************************/
/************ Write a centered message with the title of a table *************/
/*****************************************************************************/
void Lay_WriteTitle (const char *Title)
{
fprintf (Gbl.F.Out,"
"
"%s"
"
",
Title);
}
/*****************************************************************************/
/****************** Start and end a table with rounded frame *****************/
/*****************************************************************************/
// CellPadding must be 0, 1, 2, 4 or 8
void Lay_StartRoundFrameTable10 (const char *Width,unsigned CellPadding,const char *Title)
{
fprintf (Gbl.F.Out,"
"
"
");
if (Title)
fprintf (Gbl.F.Out,"
"
"%s"
"
",
Title);
fprintf (Gbl.F.Out,"
");
}
// CellPadding must be 0, 1, 2, 4 or 8
void Lay_StartRoundFrameTable10Shadow (const char *Width,unsigned CellPadding)
{
fprintf (Gbl.F.Out,"