swad-core/swad_menu.c

491 lines
16 KiB
C
Raw Permalink Normal View History

2015-01-04 15:48:24 +01:00
// swad_menu.c: menu (horizontal or vertical) selection
2015-01-02 12:57:26 +01:00
/*
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-2024 Antonio Ca<EFBFBD>as Vargas
2015-01-02 12:57:26 +01:00
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 <http://www.gnu.org/licenses/>.
*/
/*****************************************************************************/
/********************************* Headers ***********************************/
/*****************************************************************************/
#define _GNU_SOURCE // For asprintf
#include <stdio.h> // For asprintf
#include <stdlib.h> // For free
#include "swad_action_list.h"
2017-06-10 21:38:10 +02:00
#include "swad_box.h"
2015-01-02 12:57:26 +01:00
#include "swad_database.h"
#include "swad_error.h"
2020-04-14 17:15:17 +02:00
#include "swad_figure.h"
2018-11-09 20:47:39 +01:00
#include "swad_form.h"
2015-01-02 12:57:26 +01:00
#include "swad_global.h"
2019-10-23 20:07:56 +02:00
#include "swad_HTML.h"
2015-01-02 12:57:26 +01:00
#include "swad_layout.h"
#include "swad_menu.h"
#include "swad_parameter.h"
2019-03-26 11:53:21 +01:00
#include "swad_setting.h"
#include "swad_setting_database.h"
2015-01-04 15:48:24 +01:00
#include "swad_tab.h"
#include "swad_user_database.h"
2015-01-02 12:57:26 +01:00
/*****************************************************************************/
/************** External global variables from others modules ****************/
/*****************************************************************************/
extern struct Globals Gbl;
/*****************************************************************************/
2019-11-21 16:47:07 +01:00
/******************************* Public constants ****************************/
2015-01-02 12:57:26 +01:00
/*****************************************************************************/
2019-11-21 16:47:07 +01:00
const char *Mnu_MenuIcons[Mnu_NUM_MENUS] =
2015-01-02 12:57:26 +01:00
{
2019-11-21 16:47:07 +01:00
[Mnu_MENU_HORIZONTAL] = "ellipsis-h.svg",
[Mnu_MENU_VERTICAL ] = "ellipsis-v.svg",
2015-01-02 12:57:26 +01:00
};
2019-11-21 16:47:07 +01:00
/*****************************************************************************/
/****************************** Private constants ****************************/
/*****************************************************************************/
2015-01-02 12:57:26 +01:00
2019-11-21 16:47:07 +01:00
#define MAX_MENU_ID 16
2015-01-02 12:57:26 +01:00
2015-12-08 01:47:48 +01:00
// Actions not initialized are 0 by default
static const struct Mnu_Menu
{
Act_Action_t Action;
const char *Icon;
} Mnu_Menu[Tab_NUM_TABS][Act_MAX_OPTIONS_IN_MENU_PER_TAB] =
{
[TabUnk] = {
},
[TabStr] = {
[ 0] = {ActFrmLogIn ,"power-off" },
[ 1] = {ActReqSch ,"search" },
[ 2] = {ActSeeGblTL ,"comment-dots" },
[ 3] = {ActSeeSocPrf ,"user-circle" },
[ 4] = {ActSeeCal ,"calendar" },
[ 5] = {ActSeeNtf ,"bell" },
},
[TabSys] = {
[ 0] = {ActSeeSysInf ,"info" },
[ 1] = {ActSeeCty ,"globe-americas" },
[ 2] = {ActSeePen ,"sitemap" },
[ 3] = {ActSeeLnk ,"up-right-from-square" },
[ 4] = {ActSeePlg ,"puzzle-piece" },
[ 5] = {ActMtn ,"tools" },
},
[TabCty] = {
[ 0] = {ActSeeCtyInf ,"info" },
[ 1] = {ActSeeIns ,"university" },
},
[TabIns] = {
[ 0] = {ActSeeInsInf ,"info" },
[ 1] = {ActSeeCtr ,"building" },
[ 2] = {ActSeePlc ,"map-marker-alt" },
[ 3] = {ActSeeDpt ,"users" },
[ 4] = {ActSeeHld ,"calendar-day" },
},
[TabCtr] = {
[ 0] = {ActSeeCtrInf ,"info" },
[ 1] = {ActSeeDeg ,"graduation-cap" },
[ 2] = {ActSeeBld ,"building" },
[ 3] = {ActSeeRoo ,"chalkboard-teacher" },
},
[TabDeg] = {
[ 0] = {ActSeeDegInf ,"info" },
[ 1] = {ActSeeCrs ,"chalkboard-teacher" },
},
[TabCrs] = {
[ 0] = {ActSeeCrsInf ,"info" },
[ 1] = {ActSeePrg ,"clipboard-list" },
[ 2] = {ActSeeTchGui ,"book-open" },
[ 3] = {ActSeeSyl ,"list-ol" },
[ 4] = {ActSeeBib ,"book" },
[ 5] = {ActSeeFAQ ,"question" },
[ 6] = {ActSeeCrsLnk ,"up-right-from-square" },
[ 7] = {ActSeeAss ,"check" },
[ 8] = {ActSeeCrsTT ,"clock" },
},
[TabAss] = {
[ 0] = {ActSeeAllAsg ,"edit" },
[ 1] = {ActSeeAllPrj ,"file-invoice" },
[ 2] = {ActSeeAllCfe ,"bullhorn" },
[ 3] = {ActEdiTstQst ,"clipboard-question" },
[ 4] = {ActReqTst ,"check" },
[ 5] = {ActSeeAllExa ,"file-signature" },
[ 6] = {ActSeeAllGam ,"gamepad" },
[ 7] = {ActSeeAllRub ,"tasks" },
},
[TabFil] = {
[ 0] = {ActSeeAdmDocIns ,"folder-open" },
[ 1] = {ActAdmShaIns ,"folder-open" },
[ 2] = {ActSeeAdmDocCtr ,"folder-open" },
[ 3] = {ActAdmShaCtr ,"folder-open" },
[ 4] = {ActSeeAdmDocDeg ,"folder-open" },
[ 5] = {ActAdmShaDeg ,"folder-open" },
[ 6] = {ActSeeAdmDocCrsGrp ,"folder-open" },
[ 7] = {ActAdmTchCrsGrp ,"folder-open" },
[ 8] = {ActAdmShaCrsGrp ,"folder-open" },
[ 9] = {ActAdmAsgWrkUsr ,"folder-open" },
[10] = {ActReqAsgWrkCrs ,"folder-open" },
[11] = {ActSeeAdmMrk ,"list-alt" },
[12] = {ActAdmBrf ,"briefcase" },
},
[TabUsr] = {
[ 0] = {ActReqSelGrp ,"sitemap" },
[ 1] = {ActLstStd ,"users" },
[ 2] = {ActLstTch ,"user-tie" },
[ 3] = {ActLstOth ,"user-friends" },
[ 4] = {ActSeeAllAtt ,"calendar-check" },
[ 5] = {ActReqSignUp ,"hand-point-up" },
[ 6] = {ActSeeSignUpReq ,"hand-point-up" },
[ 7] = {ActLstCon ,"user-clock" },
},
[TabMsg] = {
[ 0] = {ActSeeAnn ,"bullhorn" },
[ 1] = {ActSeeAllNot ,"sticky-note" },
[ 2] = {ActSeeFor ,"comments" },
[ 3] = {ActSeeChtRms ,"comments" },
[ 4] = {ActSeeRcvMsg ,"envelope" },
[ 5] = {ActReqMaiUsr ,"at" },
},
[TabAna] = {
[ 0] = {ActReqUseGbl ,"chart-pie" },
[ 1] = {ActSeePhoDeg ,"graduation-cap" },
[ 2] = {ActReqStaCrs ,"tasks" },
[ 3] = {ActSeeAllSvy ,"poll" },
[ 4] = {ActReqAccGbl ,"chart-line" },
[ 5] = {ActReqMyUsgRep ,"file-alt" },
[ 6] = {ActMFUAct ,"heart" },
},
[TabPrf] = {
[ 0] = {ActFrmRolSes ,"power-off" },
[ 1] = {ActMyCrs ,"sitemap" },
[ 2] = {ActSeeMyTT ,"clock" },
[ 3] = {ActSeeMyAgd ,"calendar" },
[ 4] = {ActFrmMyAcc ,"at" },
[ 5] = {ActReqEdiRecSha ,"address-card" },
[ 6] = {ActReqEdiSet ,"cog" },
},
};
/*****************************************************************************/
2016-11-07 13:21:36 +01:00
/****************************** Private prototypes ***************************/
/*****************************************************************************/
2020-04-08 03:41:05 +02:00
static void Mnu_PutIconsMenu (__attribute__((unused)) void *Args);
2016-11-07 13:21:36 +01:00
/*****************************************************************************/
/***** Get icon associated to a number of option in menu of current tab ******/
/*****************************************************************************/
const char *Mnu_GetIconFromNumOptInMenu (unsigned NumOptInMenu)
{
return Mnu_Menu[Gbl.Action.Tab][NumOptInMenu].Icon;
}
/*****************************************************************************/
/********************** Get icon associated to an action *********************/
/*****************************************************************************/
const char *Mnu_GetIconFromAction (Act_Action_t Action)
{
return Mnu_Menu[Act_GetTab (Action)][Act_GetIndexInMenu (Action)].Icon;
}
2015-12-08 01:47:48 +01:00
/*****************************************************************************/
/******* When I change to another tab, go to the first option allowed ********/
/*****************************************************************************/
Act_Action_t Mnu_GetFirstActionAvailableInCurrentTab (void)
{
unsigned NumOptInMenu;
Act_Action_t Action;
/* Change current action to the first allowed action in current tab */
for (NumOptInMenu = 0;
NumOptInMenu < Act_MAX_OPTIONS_IN_MENU_PER_TAB;
NumOptInMenu++)
{
if ((Action = Mnu_Menu[Gbl.Action.Tab][NumOptInMenu].Action) == 0)
2015-12-08 01:47:48 +01:00
return ActUnk;
if (Act_CheckIfICanExecuteAction (Action) == Usr_CAN)
2015-12-08 01:47:48 +01:00
return Action;
}
return ActUnk;
}
2015-01-04 14:49:32 +01:00
/*****************************************************************************/
2015-11-29 18:32:57 +01:00
/******************* Write horizontal menu of current tab ********************/
2015-01-04 14:49:32 +01:00
/*****************************************************************************/
2015-11-29 22:06:22 +01:00
void Mnu_WriteMenuThisTab (void)
2015-01-04 14:49:32 +01:00
{
extern const char *Ico_IconSetId[Ico_NUM_ICON_SETS];
static const char *ClassIcoMenu[Ico_NUM_ICON_SETS] =
{
[Ico_ICON_SET_AWESOME] = "MENU_ICO",
[Ico_ICON_SET_NUVOLA ] = NULL,
};
2015-01-04 14:49:32 +01:00
unsigned NumOptInMenu;
Act_Action_t Action;
2015-01-04 14:49:32 +01:00
const char *Title;
bool IsTheSelectedAction;
/***** Begin container *****/
2019-12-13 00:36:01 +01:00
HTM_Txt ("<nav class=\"MENU_LIST_CONT\">");
2015-11-29 22:06:22 +01:00
/***** Begin option list *****/
HTM_UL_Begin ("class=\"MENU_LIST\"");
/***** Loop to write all options in menu. Each row holds an option *****/
for (NumOptInMenu = 0;
NumOptInMenu < Act_MAX_OPTIONS_IN_MENU_PER_TAB;
NumOptInMenu++)
{
Action = Mnu_Menu[Gbl.Action.Tab][NumOptInMenu].Action;
if (Action == 0) // At the end of each tab, actions are initialized to 0, so 0 marks the end of the menu
break;
if (Act_CheckIfICanExecuteAction (Action) == Usr_CAN)
{
IsTheSelectedAction = (Action == Act_GetSuperAction (Gbl.Action.Act));
Title = Act_GetActionText (Action);
/***** Begin option *****/
HTM_LI_Begin ("class=\"MENU_LIST_ITEM %s\"",
IsTheSelectedAction ? "MENU_OPT_ON" :
"MENU_OPT_OFF");
/***** Begin form *****/
Frm_BeginForm (Action);
/***** Begin link *****/
HTM_BUTTON_Submit_Begin (Title,"class=\"BT_LINK\"");
/***** Icon and text *****/
HTM_DIV_Begin ("class=\"MENU_ICO_TXT\"");
if (ClassIcoMenu[Gbl.Prefs.IconSet])
HTM_DIV_Begin ("class=\"MENU_ICO %s_%s\""
" style=\"background-image:url('%s/%s/%s');\"",
ClassIcoMenu[Gbl.Prefs.IconSet],The_GetSuffix (),
Cfg_URL_ICON_SETS_PUBLIC,Ico_IconSetId[Gbl.Prefs.IconSet],
Ico_GetIcon (Mnu_GetIconFromNumOptInMenu (NumOptInMenu)));
else
HTM_DIV_Begin ("class=\"MENU_ICO\""
" style=\"background-image:url('%s/%s/%s');\"",
Cfg_URL_ICON_SETS_PUBLIC,Ico_IconSetId[Gbl.Prefs.IconSet],
Ico_GetIcon (Mnu_GetIconFromNumOptInMenu (NumOptInMenu)));
HTM_DIV_End ();
HTM_DIV_Begin ("class=\"MENU_TXT MENU_TXT_%s\"",
The_GetSuffix ());
HTM_Txt (Act_GetTitleAction (Action));
HTM_DIV_End ();
HTM_DIV_End ();
/***** End link *****/
HTM_BUTTON_End ();
/***** End form *****/
Frm_EndForm ();
/***** End option *****/
HTM_LI_End ();
}
}
/***** End option list *****/
HTM_UL_End ();
/***** End container *****/
2019-11-11 00:15:44 +01:00
HTM_Txt ("</nav>");
2015-01-04 14:49:32 +01:00
}
2015-01-02 12:57:26 +01:00
/*****************************************************************************/
/************* Put icons to select menu (horizontal or vertical) *************/
/*****************************************************************************/
void Mnu_PutIconsToSelectMenu (void)
{
2019-03-26 11:53:21 +01:00
extern const char *Hlp_PROFILE_Settings_menu;
2015-01-02 12:57:26 +01:00
extern const char *Txt_Menu;
extern const char *Txt_MENU_NAMES[Mnu_NUM_MENUS];
Mnu_Menu_t Menu;
Box_BoxBegin (Txt_Menu,Mnu_PutIconsMenu,NULL,
2019-03-26 11:53:21 +01:00
Hlp_PROFILE_Settings_menu,Box_NOT_CLOSABLE);
Set_BeginSettingsHead ();
Set_BeginOneSettingSelector ();
for (Menu = (Mnu_Menu_t) 0;
Menu <= (Mnu_Menu_t) (Mnu_NUM_MENUS - 1);
Menu++)
{
Set_BeginPref (Menu == Gbl.Prefs.Menu);
Frm_BeginForm (ActChgMnu);
Par_PutParUnsigned (NULL,"Menu",(unsigned) Menu);
Ico_PutSettingIconLink (Mnu_MenuIcons[Menu],Ico_BLACK,
Txt_MENU_NAMES[Menu]);
Frm_EndForm ();
Set_EndPref ();
}
Set_EndOneSettingSelector ();
Set_EndSettingsHead ();
2019-10-25 22:48:34 +02:00
Box_BoxEnd ();
2016-11-07 13:21:36 +01:00
}
/*****************************************************************************/
2019-03-26 11:53:21 +01:00
/******************* Put contextual icons in menu setting ********************/
2016-11-07 13:21:36 +01:00
/*****************************************************************************/
2020-04-08 03:41:05 +02:00
static void Mnu_PutIconsMenu (__attribute__((unused)) void *Args)
2016-11-07 13:21:36 +01:00
{
2020-04-08 03:41:05 +02:00
/***** Put icon to show a figure *****/
Fig_PutIconToShowFigure (Fig_MENUS);
2015-01-02 12:57:26 +01:00
}
/*****************************************************************************/
/******************************** Change menu ********************************/
/*****************************************************************************/
void Mnu_ChangeMenu (void)
{
/***** Get param with menu *****/
Gbl.Prefs.Menu = Mnu_GetParMenu ();
2015-01-02 12:57:26 +01:00
/***** Store menu in database *****/
if (Gbl.Usrs.Me.Logged)
Set_DB_UpdateMySettingsAboutMenu (Gbl.Prefs.Menu);
2015-01-02 12:57:26 +01:00
2019-03-26 11:53:21 +01:00
/***** Set settings from current IP *****/
Set_SetSettingsFromIP ();
2015-01-02 12:57:26 +01:00
}
/*****************************************************************************/
/************************* Get parameter with menu ***************************/
/*****************************************************************************/
Mnu_Menu_t Mnu_GetParMenu (void)
2015-01-02 12:57:26 +01:00
{
2017-01-29 21:41:08 +01:00
return (Mnu_Menu_t)
Par_GetParUnsignedLong ("Menu",
0,
Mnu_NUM_MENUS - 1,
(unsigned long) Mnu_MENU_DEFAULT);
2015-01-02 12:57:26 +01:00
}
2017-05-04 11:03:44 +02:00
/*****************************************************************************/
/*************************** Get menu from string ****************************/
/*****************************************************************************/
Mnu_Menu_t Mnu_GetMenuFromStr (const char *Str)
{
unsigned UnsignedNum;
if (sscanf (Str,"%u",&UnsignedNum) == 1)
if (UnsignedNum < Mnu_NUM_MENUS)
return (Mnu_Menu_t) UnsignedNum;
return Mnu_MENU_DEFAULT;
}
2019-10-24 09:46:20 +02:00
/*****************************************************************************/
/******************************** Context menu *******************************/
/*****************************************************************************/
void Mnu_ContextMenuBegin (void)
{
HTM_DIV_Begin ("class=\"CONTEXT_MENU\"");
}
void Mnu_ContextMenuEnd (void)
{
HTM_DIV_End ();
}
/*****************************************************************************/
/*********** Get and show number of users who have chosen a menu *************/
/*****************************************************************************/
void Mnu_GetAndShowNumUsrsPerMenu (void)
{
extern const char *Hlp_ANALYTICS_Figures_menu;
extern const char *Mnu_MenuIcons[Mnu_NUM_MENUS];
extern const char *Txt_FIGURE_TYPES[Fig_NUM_FIGURES];
extern const char *Txt_Menu;
extern const char *Txt_Number_of_users;
extern const char *Txt_PERCENT_of_users;
extern const char *Txt_MENU_NAMES[Mnu_NUM_MENUS];
Mnu_Menu_t Menu;
char *SubQuery;
unsigned NumUsrs[Mnu_NUM_MENUS];
unsigned NumUsrsTotal = 0;
/***** Begin box and table *****/
Box_BoxTableBegin (Txt_FIGURE_TYPES[Fig_MENUS],NULL,NULL,
Hlp_ANALYTICS_Figures_menu,Box_NOT_CLOSABLE,2);
/***** Heading row *****/
HTM_TR_Begin (NULL);
HTM_TH (Txt_Menu ,HTM_HEAD_LEFT);
HTM_TH (Txt_Number_of_users ,HTM_HEAD_RIGHT);
HTM_TH (Txt_PERCENT_of_users,HTM_HEAD_RIGHT);
HTM_TR_End ();
/***** For each menu... *****/
for (Menu = (Mnu_Menu_t) 0;
Menu <= (Mnu_Menu_t) (Mnu_NUM_MENUS - 1);
Menu++)
{
/* Get number of users who have chosen this menu from database */
if (asprintf (&SubQuery,"usr_data.Menu=%u",
(unsigned) Menu) < 0)
Err_NotEnoughMemoryExit ();
NumUsrs[Menu] = Usr_DB_GetNumUsrsWhoChoseAnOption (SubQuery);
free (SubQuery);
/* Update total number of users */
NumUsrsTotal += NumUsrs[Menu];
}
/***** Write number of users who have chosen each menu *****/
for (Menu = (Mnu_Menu_t) 0;
Menu <= (Mnu_Menu_t) (Mnu_NUM_MENUS - 1);
Menu++)
{
HTM_TR_Begin (NULL);
HTM_TD_Begin ("class=\"CM\"");
Ico_PutIcon (Mnu_MenuIcons[Menu],Ico_BLACK,
Txt_MENU_NAMES[Menu],"ICOx20");
HTM_TD_End ();
HTM_TD_Unsigned (NumUsrs[Menu]);
HTM_TD_Percentage (NumUsrs[Menu],NumUsrsTotal);
HTM_TR_End ();
}
/***** End table and box *****/
Box_BoxTableEnd ();
}