/* $calcurse: wins.c,v 1.18 2008/11/23 20:38:56 culot Exp $ */ /* * Calcurse - text-based organizer * Copyright (c) 2007-2008 Frederic Culot * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. * * Send your feedback or comments to : calcurse@culot.org * Calcurse home page : http://culot.org/calcurse * */ #include #include #include "i18n.h" #include "notify.h" #include "utils.h" #include "todo.h" #include "custom.h" #include "wins.h" /* Variables to handle calcurse windows. */ window_t win[NBWINS]; static window_e slctd_win; static int layout; /* Get the current layout. */ int wins_layout (void) { return (layout); } /* Set the current layout. */ void wins_set_layout (int nb) { layout = nb; } /* Initialize the selected window in calcurse's interface. */ void wins_slctd_init (void) { wins_slctd_set (CAL); } /* Returns an enum which corresponds to the window which is selected. */ window_e wins_slctd (void) { return (slctd_win); } /* Sets the selected window. */ void wins_slctd_set (window_e window) { slctd_win = window; } /* TAB key was hit in the interface, need to select next window. */ void wins_slctd_next (void) { if (slctd_win == TOD) slctd_win = CAL; else slctd_win++; } /* Create all the windows. */ void wins_init (void) { char label[BUFSIZ]; /* * Create the three main windows plus the status bar and the pad used to * display appointments and event. */ win[CAL].p = newwin (CALHEIGHT, CALWIDTH, win[CAL].y, win[CAL].x); snprintf (label, BUFSIZ, _("Calendar")); wins_show (win[CAL].p, label); win[APP].p = newwin (win[APP].h, win[APP].w, win[APP].y, win[APP].x); snprintf (label, BUFSIZ, _("Appointments")); wins_show (win[APP].p, label); apad->width = win[APP].w - 3; apad->ptrwin = newpad (apad->length, apad->width); win[TOD].p = newwin (win[TOD].h, win[TOD].w, win[TOD].y, win[TOD].x); snprintf (label, BUFSIZ, _("ToDo")); wins_show (win[TOD].p, label); win[STA].p = newwin (win[STA].h, win[STA].w, win[STA].y, win[STA].x); /* Enable function keys (i.e. arrow keys) in those windows */ keypad (win[CAL].p, TRUE); keypad (win[APP].p, TRUE); keypad (win[TOD].p, TRUE); keypad (win[STA].p, TRUE); /* Notify that the curses mode is now launched. */ ui_mode = UI_CURSES; } /* * Create a new window and its associated pad, which is used to make the * scrolling faster. */ void wins_scrollwin_init (scrollwin_t *sw) { ASSERT (sw != NULL); sw->win.p = newwin (sw->win.h, sw->win.w, sw->win.y, sw->win.x); sw->pad.p = newpad (sw->pad.h, sw->pad.w); sw->first_visible_line = 0; sw->total_lines = 0; } /* Free an already created scrollwin. */ void wins_scrollwin_delete (scrollwin_t *sw) { ASSERT (sw != NULL); delwin(sw->win.p); delwin(sw->pad.p); } /* Display a scrolling window. */ void wins_scrollwin_display (scrollwin_t *sw) { const int visible_lines = sw->win.h - sw->pad.y - 1; if (sw->total_lines > visible_lines) { float ratio = ((float) visible_lines) / ((float) sw->total_lines); int sbar_length = (int) (ratio * visible_lines); int highend = (int) (ratio * sw->first_visible_line); int sbar_top = highend + sw->pad.y + 1; if ((sbar_top + sbar_length) > sw->win.h - 1) sbar_length = sw->win.h - sbar_top; draw_scrollbar (sw->win.p, sbar_top, sw->win.w + sw->win.x - 2, sbar_length, sw->pad.y + 1, sw->win.h - 1, true); } wmove (win[STA].p, 0, 0); wnoutrefresh (sw->win.p); pnoutrefresh (sw->pad.p, sw->first_visible_line, 0, sw->pad.y, sw->pad.x, sw->win.h - sw->pad.y + 1, sw->win.w - sw->win.x); doupdate (); } void wins_scrollwin_up (scrollwin_t *sw, int amount) { if (sw->first_visible_line > 0) sw->first_visible_line -= amount; } void wins_scrollwin_down (scrollwin_t *sw, int amount) { if (sw->total_lines > (sw->first_visible_line + sw->win.h - sw->pad.y - 1)) sw->first_visible_line += amount; } /* * Delete the existing windows and recreate them with their new * size and placement. */ void wins_reinit (void) { delwin (win[STA].p); delwin (win[CAL].p); delwin (win[APP].p); delwin (apad->ptrwin); delwin (win[TOD].p); wins_get_config (); wins_init (); if (notify_bar ()) notify_reinit_bar (); } /* Show the window with a border and a label. */ void wins_show (WINDOW *win, char *label) { int startx, starty, height, width; getbegyx (win, starty, startx); getmaxyx (win, height, width); box (win, 0, 0); mvwaddch (win, 2, 0, ACS_LTEE); mvwhline (win, 2, 1, ACS_HLINE, width - 2); mvwaddch (win, 2, width - 1, ACS_RTEE); print_in_middle (win, 1, 0, width, label); } /* * Get the screen size and recalculate the windows configurations. */ void wins_get_config (void) { /* Get the screen configuration */ getmaxyx (stdscr, row, col); /* fixed values for status, notification bars and calendar */ win[STA].h = STATUSHEIGHT; win[STA].w = col; win[STA].y = row - win[STA].h; win[STA].x = 0; if (notify_bar ()) { win[NOT].h = 1; win[NOT].w = col; win[NOT].y = win[STA].y - 1; win[NOT].x = 0; } else { win[NOT].h = 0; win[NOT].w = 0; win[NOT].y = 0; win[NOT].x = 0; } if (layout <= 4) { /* APPOINTMENT is the biggest panel */ win[APP].w = col - CALWIDTH; win[APP].h = row - (win[STA].h + win[NOT].h); win[TOD].w = CALWIDTH; win[TOD].h = row - (CALHEIGHT + win[STA].h + win[NOT].h); } else { /* TODO is the biggest panel */ win[TOD].w = col - CALWIDTH; win[TOD].h = row - (win[STA].h + win[NOT].h); win[APP].w = CALWIDTH; win[APP].h = row - (CALHEIGHT + win[STA].h + win[NOT].h); } /* defining the layout */ switch (layout) { case 1: win[APP].y = 0; win[APP].x = 0; win[CAL].y = 0; win[TOD].x = win[APP].w; win[TOD].y = CALHEIGHT; win[CAL].x = win[APP].w; break; case 2: win[APP].y = 0; win[APP].x = 0; win[TOD].y = 0; win[TOD].x = win[APP].w; win[CAL].x = win[APP].w; win[CAL].y = win[TOD].h; break; case 3: win[APP].y = 0; win[TOD].x = 0; win[CAL].x = 0; win[CAL].y = 0; win[APP].x = CALWIDTH; win[TOD].y = CALHEIGHT; break; case 4: win[APP].y = 0; win[TOD].x = 0; win[TOD].y = 0; win[CAL].x = 0; win[APP].x = CALWIDTH; win[CAL].y = win[TOD].h; break; case 5: win[TOD].y = 0; win[TOD].x = 0; win[CAL].y = 0; win[APP].y = CALHEIGHT; win[APP].x = win[TOD].w; win[CAL].x = win[TOD].w; break; case 6: win[TOD].y = 0; win[TOD].x = 0; win[APP].y = 0; win[APP].x = win[TOD].w; win[CAL].x = win[TOD].w; win[CAL].y = win[APP].h; break; case 7: win[TOD].y = 0; win[APP].x = 0; win[CAL].x = 0; win[CAL].y = 0; win[TOD].x = CALWIDTH; win[APP].y = CALHEIGHT; break; case 8: win[TOD].y = 0; win[APP].x = 0; win[CAL].x = 0; win[APP].y = 0; win[TOD].x = CALWIDTH; win[CAL].y = win[APP].h; break; } } /* draw panel border in color */ static void border_color (WINDOW *window) { int color_attr = A_BOLD; int no_color_attr = A_BOLD; if (colorize) { wattron (window, color_attr | COLOR_PAIR (COLR_CUSTOM)); box (window, 0, 0); } else { wattron (window, no_color_attr); box (window, 0, 0); } if (colorize) { wattroff (window, color_attr | COLOR_PAIR (COLR_CUSTOM)); } else { wattroff (window, no_color_attr); } wnoutrefresh (window); } /* draw panel border without any color */ static void border_nocolor (WINDOW *window) { int color_attr = A_BOLD; int no_color_attr = A_DIM; if (colorize) { wattron (window, color_attr | COLOR_PAIR (COLR_DEFAULT)); } else { wattron (window, no_color_attr); } box (window, 0, 0); if (colorize) { wattroff (window, color_attr | COLOR_PAIR (COLR_DEFAULT)); } else { wattroff (window, no_color_attr); } wnoutrefresh (window); } /* * Update all of the three windows and put a border around the * selected window. */ void wins_update (void) { switch (slctd_win) { case CAL: border_color (win[CAL].p); border_nocolor (win[APP].p); border_nocolor (win[TOD].p); break; case APP: border_color (win[APP].p); border_nocolor (win[CAL].p); border_nocolor (win[TOD].p); break; case TOD: border_color (win[TOD].p); border_nocolor (win[APP].p); border_nocolor (win[CAL].p); break; default: ierror (_("FATAL ERROR in wins_update: no window selected\n"), IERROR_FATAL); /* NOTREACHED */ } apoint_update_panel (slctd_win); todo_update_panel (slctd_win); calendar_update_panel (win[CAL].p); status_bar (); if (notify_bar ()) notify_update_bar (); wmove (win[STA].p, 0, 0); doupdate (); } /* Reset the screen, needed when resizing terminal for example. */ void wins_reset (void) { endwin (); refresh (); curs_set (0); wins_reinit (); wins_update (); } /* * While inside interactive mode, launch the external command cmd on the given * file. */ void wins_launch_external (const char *file, const char *cmd) { char *p; int len; /* Beware of space between cmd and file. */ len = strlen (file) + strlen (cmd) + 2; p = (char *) malloc (sizeof (char) * len); if (snprintf (p, len, "%s %s", cmd, file) == -1) { free (p); return; } if (notify_bar ()) notify_stop_main_thread (); def_prog_mode (); endwin (); ui_mode = UI_CMDLINE; clear (); refresh (); system (p); reset_prog_mode (); clearok (curscr, TRUE); curs_set (0); ui_mode = UI_CURSES; refresh (); if (notify_bar ()) notify_start_main_thread (); free (p); }