85605bd5cb8fee16d643164dbd2106b5c9bb1bdd
[apps/madmutt.git] / sidebar.c
1 /*
2  * Copyright (C) ????-2004 Justin Hibbits <jrh29@po.cwru.edu>
3  * Copyright (C) 2004 Thomer M. Gil <mutt@thomer.com>
4  * 
5  *     This program is free software; you can redistribute it and/or modify
6  *     it under the terms of the GNU General Public License as published by
7  *     the Free Software Foundation; either version 2 of the License, or
8  *     (at your option) any later version.
9  * 
10  *     This program is distributed in the hope that it will be useful,
11  *     but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  *     GNU General Public License for more details.
14  * 
15  *     You should have received a copy of the GNU General Public License
16  *     along with this program; if not, write to the Free Software
17  *     Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
18  */ 
19
20
21
22 #include "mutt.h"
23 #include "mutt_menu.h"
24 #include "mutt_curses.h"
25 #include "sidebar.h"
26 #include "buffy.h"
27 #include <libgen.h>
28 #include "keymap.h"
29 #include <stdbool.h>
30
31 /*BUFFY *CurBuffy = 0;*/
32 static BUFFY *TopBuffy = 0;
33 static BUFFY *BottomBuffy = 0;
34 static int known_lines = 0;
35 static bool initialized = false;
36 static int prev_show_value;
37 static short saveSidebarWidth;
38 static char *entry = 0;
39
40 static int quick_log10(int n)
41 {
42   int len = 0;
43   for (; n > 9; len++, n /= 10)
44     ;
45   return (++len);
46 }
47
48 void calc_boundaries (int menu)
49 {
50   BUFFY *tmp = Incoming;
51
52   if ( known_lines != LINES ) {
53     TopBuffy = BottomBuffy = 0;
54     known_lines = LINES;
55   }
56   for ( ; tmp->next != 0; tmp = tmp->next )
57     tmp->next->prev = tmp;
58
59   if ( TopBuffy == 0 && BottomBuffy == 0 )
60     TopBuffy = Incoming;
61   if ( BottomBuffy == 0 ) {
62     int count = LINES - 2 - (menu != MENU_PAGER);
63     BottomBuffy = TopBuffy;
64     while ( --count && BottomBuffy->next )
65       BottomBuffy = BottomBuffy->next;
66   }
67   else if ( TopBuffy == CurBuffy->next ) {
68     int count = LINES - 2 - (menu != MENU_PAGER);
69     BottomBuffy = CurBuffy;
70     tmp = BottomBuffy;
71     while ( --count && tmp->prev)
72       tmp = tmp->prev;
73     TopBuffy = tmp;
74   }
75   else if ( BottomBuffy == CurBuffy->prev ) {
76     int count = LINES - 2 - (menu != MENU_PAGER);
77     TopBuffy = CurBuffy;
78     tmp = TopBuffy;
79     while ( --count && tmp->next )
80       tmp = tmp->next;
81     BottomBuffy = tmp;
82   }
83 }
84
85 static char * shortened_hierarchy(char * box) {
86   int dots = 0;
87   char * last_dot;
88   int i,j;
89   char * new_box;
90   for (i=0;i<strlen(box);++i)
91     if (box[i] == '.') ++dots;
92   last_dot = strrchr(box,'.');
93   if (last_dot) {
94     ++last_dot;
95     new_box = safe_malloc(strlen(last_dot)+2*dots+1);
96     new_box[0] = box[0];
97     for (i=1,j=1;i<strlen(box);++i) {
98       if (box[i] == '.') {
99         new_box[j++] = '.';
100         new_box[j] = 0;
101         if (&box[i+1] != last_dot) {
102           new_box[j++] = box[i+1];
103           new_box[j] = 0;
104         } else {
105           strcat(&new_box[j],last_dot);
106           break;
107         }
108       }
109     }
110     return new_box;
111   }
112   return safe_strdup(box);
113 }
114
115 char *make_sidebar_entry(char *box, int size, int new)
116 {
117   char *c;
118   int i = 0, dlen = mutt_strlen (SidebarDelim);
119
120   c = realloc(entry, SidebarWidth + 1);
121   if ( c ) entry = c;
122   entry[SidebarWidth] = 0;
123   for (; i < SidebarWidth; entry[i++] = ' ' );
124 #if USE_IMAP
125   if (ImapHomeNamespace && strlen(ImapHomeNamespace)>0) {
126     if (strncmp(box,ImapHomeNamespace,strlen(ImapHomeNamespace))==0 && strcmp(box,ImapHomeNamespace)!=0) {
127       box+=strlen(ImapHomeNamespace)+1;
128     }
129   }
130 #endif
131   if (option(OPTSHORTENHIERARCHY)) {
132     box = shortened_hierarchy(box);
133   }
134   i = strlen(box);
135   strncpy( entry, box, i < SidebarWidth - dlen ? i :SidebarWidth - dlen);
136
137   if ( new ) 
138     sprintf(entry + SidebarWidth - 3 - quick_log10(size) - dlen - quick_log10(new),
139             "% d(%d)", size, new);
140   else
141     sprintf( entry + SidebarWidth - 1 - quick_log10(size) - dlen, "% d", size);
142   if (option(OPTSHORTENHIERARCHY)) {
143     free(box);
144   }
145   return entry;
146 }
147
148 void set_curbuffy(char buf[LONG_STRING])
149 {
150   BUFFY* tmp = CurBuffy = Incoming;
151
152   if (!Incoming)
153     return;
154
155   while(1) {
156     if(!strcmp(tmp->path, buf)) {
157       CurBuffy = tmp;
158       break;
159     }
160
161     if(tmp->next)
162       tmp = tmp->next;
163     else
164       break;
165   }
166 }
167
168 int draw_sidebar(int menu) {
169
170   int lines = option(OPTHELP) ? 1 : 0;
171   BUFFY *tmp;
172 #ifndef USE_SLANG_CURSES
173   attr_t attrs;
174 #endif
175   short color_pair;
176   short delim_len = mutt_strlen (SidebarDelim);
177
178   /* initialize first time */
179   if(!initialized) {
180     prev_show_value = option(OPTMBOXPANE);
181     saveSidebarWidth = SidebarWidth;
182     if(!option(OPTMBOXPANE)) SidebarWidth = 0;
183     initialized = true;
184   }
185
186   /* save or restore the value SidebarWidth */
187   if(prev_show_value != option(OPTMBOXPANE)) {
188     if(prev_show_value && !option(OPTMBOXPANE)) {
189       saveSidebarWidth = SidebarWidth;
190       SidebarWidth = 0;
191     } else if(!prev_show_value && option(OPTMBOXPANE)) {
192       SidebarWidth = saveSidebarWidth;
193     }
194     prev_show_value = option(OPTMBOXPANE);
195   }
196
197
198   if ( SidebarWidth == 0 ) return 0;
199
200   /* get attributes for divider */
201   SETCOLOR(MT_COLOR_STATUS);
202 #ifndef USE_SLANG_CURSES
203   attr_get(&attrs, &color_pair, 0);
204 #else
205   color_pair = attr_get();
206 #endif
207   SETCOLOR(MT_COLOR_NORMAL);
208
209   /* draw the divider */
210
211   for ( ; lines < LINES-1-(menu != MENU_PAGER); lines++ ) {
212     move(lines, SidebarWidth - delim_len);
213     addstr (NONULL (SidebarDelim));
214  #ifndef USE_SLANG_CURSES
215     mvchgat(lines, SidebarWidth - delim_len, delim_len, 0, color_pair, NULL);
216  #endif
217   }
218   if ( Incoming == 0 ) return 0;
219   lines = option(OPTHELP) ? 1 : 0; /* go back to the top */
220
221   if ( known_lines != LINES || TopBuffy == 0 || BottomBuffy == 0 ) 
222     calc_boundaries(menu);
223   if ( CurBuffy == 0 ) CurBuffy = Incoming;
224
225   tmp = TopBuffy;
226
227   SETCOLOR(MT_COLOR_NORMAL);
228
229   for ( ; tmp && lines < LINES-1 - (menu != MENU_PAGER); tmp = tmp->next ) {
230     if ( tmp == CurBuffy )
231       SETCOLOR(MT_COLOR_INDICATOR);
232     else if ( tmp->msg_unread > 0 )
233       SETCOLOR(MT_COLOR_NEW);
234     else
235       SETCOLOR(MT_COLOR_NORMAL);
236
237     move( lines, 0 );
238     if ( Context && !strcmp( tmp->path, Context->path ) ) {
239       printw( "%.*s", SidebarWidth - delim_len,
240               make_sidebar_entry(basename(tmp->path),
241                                  Context->msgcount, Context->unread));
242       tmp->msg_unread = Context->unread;
243       tmp->msgcount = Context->msgcount;
244     }
245     else
246       printw( "%.*s", SidebarWidth - delim_len,
247               make_sidebar_entry(basename(tmp->path),
248                                  tmp->msgcount,tmp->msg_unread));
249     lines++;
250   }
251   SETCOLOR(MT_COLOR_NORMAL);
252   for ( ; lines < LINES - 1 - (menu != MENU_PAGER); lines++ ) {
253     int i = 0;
254     move( lines, 0 );
255     for ( ; i < SidebarWidth - delim_len; i++ )
256       addch(' ');
257   }
258   return 0;
259 }
260
261 void scroll_sidebar(int op, int menu)
262 {
263         if(!SidebarWidth) return;
264         if(!CurBuffy) return;
265
266   switch (op) {
267     case OP_SIDEBAR_NEXT:
268       if ( CurBuffy->next == NULL ) return;
269       CurBuffy = CurBuffy->next;
270       break;
271     case OP_SIDEBAR_PREV:
272       if ( CurBuffy == Incoming ) return;
273       {
274         BUFFY *tmp = Incoming;
275         while ( tmp->next && strcmp(tmp->next->path, CurBuffy->path) ) tmp = tmp->next;
276         CurBuffy = tmp;
277       }
278       break;
279     case OP_SIDEBAR_SCROLL_UP:
280       CurBuffy = TopBuffy;
281       if ( CurBuffy != Incoming ) {
282         calc_boundaries(menu);
283         CurBuffy = CurBuffy->prev;
284       }
285       break;
286     case OP_SIDEBAR_SCROLL_DOWN:
287       CurBuffy = BottomBuffy;
288       if ( CurBuffy->next ) {
289         calc_boundaries(menu);
290         CurBuffy = CurBuffy->next;
291       }
292       break;
293     default:
294       return;
295   }
296   calc_boundaries(menu);
297   draw_sidebar(menu);
298 }