1 /*
2 
3     eboard - chess client
4     http://www.bergo.eng.br/eboard
5     https://github.com/fbergo/eboard
6     Copyright (C) 2000-2016 Felipe Bergo
7     fbergo/at/gmail/dot/com
8 
9     This program is free software; you can redistribute it and/or modify
10     it under the terms of the GNU General Public License as published by
11     the Free Software Foundation; either version 2 of the License, or
12     (at your option) any later version.
13 
14     This program is distributed in the hope that it will be useful,
15     but WITHOUT ANY WARRANTY; without even the implied warranty of
16     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17     GNU General Public License for more details.
18 
19     You should have received a copy of the GNU General Public License
20     along with this program; if not, write to the Free Software
21     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
22 
23 */
24 
25 #include <iostream>
26 #include "eboard.h"
27 #include "global.h"
28 #include "notebook.h"
29 
30 #include "xpm/dead.xpm"
31 #include "xpm/trash2.xpm"
32 
page_trash(GtkWidget * w,gpointer data)33 void page_trash(GtkWidget *w, gpointer data) {
34   Page *p;
35   p=(Page *) data;
36   global.removeRemovablePage(p->number);
37 }
38 
Page()39 Page::Page() {
40   global.debug("Page","Page","1");
41   number=0;
42   content=0;
43   title[0]=0;
44   naughty=false;
45   level=IM_ZERO;
46   label=gtk_label_new("<none>");
47   gshow(label);
48 }
49 
Page(int _number,GtkWidget * _content,char * _title,bool _removable)50 Page::Page(int _number,GtkWidget *_content, char *_title, bool _removable) {
51 
52   GtkWidget *b,*p;
53 
54   global.debug("Page","Page","2");
55   number=_number;
56   content=_content;
57   level=IM_ZERO;
58   naughty=false;
59   removable=_removable;
60 
61   g_strlcpy(title,_title,256);
62 
63   if (removable) {
64 
65     labelframe=gtk_hbox_new(FALSE,1);
66 
67     Notebook::ensurePixmaps();
68     b=gtk_button_new();
69     gtk_button_set_relief(GTK_BUTTON(b), GTK_RELIEF_HALF);
70     p=gtk_pixmap_new(Notebook::trashface, Notebook::trashmask);
71     gtk_container_add(GTK_CONTAINER(b), p);
72     gtk_box_pack_start(GTK_BOX(labelframe), b, FALSE, FALSE, 0);
73 
74     label=gtk_label_new(title);
75     gtk_box_pack_start(GTK_BOX(labelframe), label, FALSE, TRUE, 1);
76 
77     Gtk::show(p,b,label,labelframe,NULL);
78 
79     gtk_signal_connect(GTK_OBJECT(b),"clicked",
80 		       GTK_SIGNAL_FUNC(page_trash), (gpointer) this);
81 
82   } else {
83 
84     label=gtk_label_new(title);
85     gshow(label);
86     labelframe=label;
87 
88   }
89 }
90 
operator ==(int n)91 int Page::operator==(int n) {
92   return(n==number);
93 }
94 
under(Importance imp)95 int Page::under(Importance imp) {
96   return(level < imp);
97 }
98 
above(Importance imp)99 int Page::above(Importance imp) {
100   return(level > imp);
101 }
102 
setLevel(Importance imp)103 void Page::setLevel(Importance imp) {
104   level=imp;
105 }
106 
setTitle(char * _title)107 void Page::setTitle(char *_title) {
108   g_strlcpy(title,_title,256);
109   gtk_label_set_text(GTK_LABEL(label),title);
110   gtk_widget_queue_resize(label);
111 }
112 
getTitle()113 char * Page::getTitle() {
114   return(title);
115 }
116 
renumber(int newid)117 void Page::renumber(int newid) {
118   char z[258];
119   number=newid;
120   snprintf(z,258,"{%s}",title);
121   setTitle(z);
122 }
123 
dump()124 void Page::dump() {
125   cerr.setf(ios::hex,ios::basefield);
126   cerr.setf(ios::showbase);
127   cerr << "[page " << ((uint64_t)this) << "] ";
128   cerr.setf(ios::dec,ios::basefield);
129   cerr << "pageid=" << number << " ";
130   cerr << "title=" << title << " ";
131   cerr << "level=" << ((int)level) << endl;
132 }
133 
134 GdkPixmap * Notebook::trashface=0;
135 GdkBitmap * Notebook::trashmask=0;
136 GtkWidget * Notebook::swidget=0;
137 
ensurePixmaps()138 void Notebook::ensurePixmaps() {
139   GtkStyle *style;
140 
141   if (swidget==0) return;
142 
143   if (trashface==0) {
144     style=gtk_widget_get_style(swidget);
145     trashface = gdk_pixmap_create_from_xpm_d (swidget->window, &trashmask,
146 					      &style->bg[GTK_STATE_NORMAL],
147 					      (gchar **) trash2_xpm);
148   }
149 }
150 
Notebook()151 Notebook::Notebook() {
152   global.debug("Notebook","Notebook");
153   pcl=0;
154   widget=gtk_notebook_new();
155   swidget=widget;
156   gtk_notebook_set_tab_pos(GTK_NOTEBOOK(widget),GTK_POS_RIGHT);
157   gtk_notebook_set_scrollable(GTK_NOTEBOOK(widget),TRUE);
158   gtk_signal_connect(GTK_OBJECT(widget),"switch_page",
159 		     GTK_SIGNAL_FUNC(notebook_switch_page),
160 		     (gpointer)this);
161 }
162 
addPage(GtkWidget * what,char * title,int id,bool removable)163 void Notebook::addPage(GtkWidget *what,char *title,int id,bool removable) {
164   Page *pg;
165   global.debug("Notebook","addPage",title);
166   pg=new Page(id,what,title,removable);
167   pages.push_back(pg);
168   gtk_notebook_append_page(GTK_NOTEBOOK(widget),what,pg->labelframe);
169 
170   /* to test graphics only, adds dead.xpm to console tab
171   if (pages.size() == 2)
172     addBombToTab(pg);
173   */
174 }
175 
removePage(int id)176 void Notebook::removePage(int id) {
177   vector<Page *>::iterator pi;
178   int i;
179   global.debug("Notebook","removePage");
180   for(i=0,pi=pages.begin();pi!=pages.end();pi++,i++)
181     if ( (*(*pi)) == id ) {
182       gtk_notebook_remove_page(GTK_NOTEBOOK(widget),i);
183       delete(*pi);
184       pages.erase(pi);
185       return;
186     }
187 }
188 
getCurrentPage()189 unsigned int Notebook::getCurrentPage() {
190   return((unsigned int)gtk_notebook_get_current_page(GTK_NOTEBOOK(widget)));
191 }
192 
getCurrentPageId()193 int Notebook::getCurrentPageId() {
194   unsigned int i;
195   i=getCurrentPage();
196   if (i >= pages.size())
197     return 0;
198   return( pages[i]->number );
199 }
200 
setTabColor(int pageid,int color,Importance imp)201 void Notebook::setTabColor(int pageid,int color,Importance imp) {
202   vector<Page *>::iterator pi;
203   int i;
204   global.debug("Notebook","setTabColor","1");
205   for(i=0,pi=pages.begin();pi!=pages.end();pi++,i++)
206     if ( (*(*pi)) == pageid ) {
207       setTabColor(i,color,0,imp);
208       return;
209     }
210 }
211 
setTabColor(int page_num,int color,int poly,Importance imp)212 void Notebook::setTabColor(int page_num,int color,int poly,
213 			   Importance imp) {
214   vector<Page *>::iterator pi;
215   GdkColor nc;
216   GtkStyle *style;
217   int i;
218   i=page_num;
219 
220   global.debug("Notebook","setTabColor","2");
221   for(pi=pages.begin();i;pi++,i--) ;
222 
223   if ((*pi)->above(imp))
224     return;
225 
226   if (imp==IM_RESET) imp=IM_ZERO;
227   (*pi)->setLevel(imp);
228 
229   nc.red=((color>>16)<<8);
230   nc.green=(color&0x00ff00);
231   nc.blue=((color&0xff)<<8);
232   style=gtk_style_copy( gtk_widget_get_style((*pi)->label) );
233 
234   for(i=0;i<5;i++)
235     style->fg[i]=nc;
236 
237   gtk_widget_set_style( (*pi)->label, style );
238   gtk_widget_ensure_style( (*pi)->label );
239   gtk_widget_queue_draw( (*pi)->label );
240 
241   gtk_style_unref(style); // tomv, leak
242 }
243 
goToPageId(int id)244 void Notebook::goToPageId(int id) {
245   vector<Page *>::iterator pi;
246   int i;
247   for(i=0,pi=pages.begin();pi!=pages.end();pi++,i++)
248     if ( (*(*pi)) == id ) {
249       gtk_notebook_set_page(GTK_NOTEBOOK(widget),i);
250       return;
251     }
252 }
253 
setTabPosition(GtkPositionType pos)254 void Notebook::setTabPosition(GtkPositionType pos) {
255   gtk_notebook_set_tab_pos(GTK_NOTEBOOK(widget),pos);
256 }
257 
dump()258 void Notebook::dump() {
259   vector<Page *>::iterator pi;
260   for(pi=pages.begin();pi!=pages.end();pi++)
261     (*pi)->dump();
262 }
263 
goToNext()264 void Notebook::goToNext() {
265   gtk_notebook_next_page(GTK_NOTEBOOK(widget));
266 }
267 
goToPrevious()268 void Notebook::goToPrevious() {
269   gtk_notebook_prev_page(GTK_NOTEBOOK(widget));
270 }
271 
renumberPage(int oldid,int newid)272 void Notebook::renumberPage(int oldid,int newid) {
273   vector<Page *>::iterator i;
274   for(i=pages.begin();i!=pages.end();i++)
275     if ( (*(*i)) == oldid )
276       (*i)->renumber(newid);
277 }
278 
setListener(PaneChangeListener * listener)279 void Notebook::setListener(PaneChangeListener *listener) {
280   pcl=listener;
281 }
282 
setNaughty(int pageid,bool val)283 void Notebook::setNaughty(int pageid, bool val) {
284   vector<Page *>::iterator i;
285   for(i=pages.begin();i!=pages.end();i++)
286     if ( (*(*i)) == pageid ) {
287 
288       if ( (val)&&(! (*i)->naughty) )
289 	addBombToTab(*i);
290       (*i)->naughty=val;
291 
292     }
293 }
294 
getNaughty(vector<int> & evil_ids)295 void Notebook::getNaughty(vector<int> &evil_ids) {
296   vector<Page *>::iterator i;
297   evil_ids.clear();
298   for(i=pages.begin();i!=pages.end();i++)
299     if ( (*i)->naughty )
300       evil_ids.push_back( (*i)->number );
301 }
302 
isNaughty(int pageid)303 bool Notebook::isNaughty(int pageid) {
304   vector<Page *>::iterator i;
305   for(i=pages.begin();i!=pages.end();i++)
306     if ( (*i)->number == pageid )
307       if ((*i)->naughty)
308 	return true;
309   return false;
310 }
311 
hasNaughty()312 bool Notebook::hasNaughty() {
313   vector<Page *>::iterator i;
314   for(i=pages.begin();i!=pages.end();i++)
315     if ( (*i)->naughty )
316       return true;
317   return false;
318 }
319 
320 // SOMEONE SET UP US THE BOMB!
addBombToTab(Page * pg)321 void Notebook::addBombToTab(Page *pg) {
322   GtkWidget *hb,*label,*pm;
323   GdkPixmap *d;
324   GdkBitmap *b;
325   GtkStyle *style;
326 
327   style=gtk_widget_get_default_style();
328 
329   d = gdk_pixmap_create_from_xpm_d (widget->window, &b,
330 				    &style->bg[GTK_STATE_NORMAL],
331 				    (gchar **) dead_xpm);
332   pm=gtk_pixmap_new(d,b);
333 
334   label=gtk_label_new(pg->getTitle());
335   hb=gtk_hbox_new(FALSE,2);
336 
337   gtk_box_pack_start(GTK_BOX(hb),label,FALSE,FALSE,4);
338   gtk_box_pack_start(GTK_BOX(hb),pm,FALSE,FALSE,4);
339 
340   Gtk::show(label,pm,hb,NULL);
341 
342   pg->label=label;
343   gtk_notebook_set_tab_label(GTK_NOTEBOOK(widget),pg->content,hb);
344 }
345 
pretendPaneChanged()346 void Notebook::pretendPaneChanged() {
347   if (pcl)
348     pcl->paneChanged( getCurrentPage(), getCurrentPageId() );
349 }
350 
351 void
notebook_switch_page(GtkNotebook * notebook,GtkNotebookPage * page,gint page_num,gpointer data)352 notebook_switch_page(GtkNotebook *notebook,
353 		     GtkNotebookPage *page,
354 		     gint page_num,
355 		     gpointer data) {
356   Notebook *me;
357   unsigned int pg = (unsigned int) page_num;
358   me=(Notebook *)data;
359   me->setTabColor(pg,0,0,IM_RESET);
360   if ( (me->pcl) && (me->pages.size() > pg) )
361     me->pcl->paneChanged(pg, me->pages[pg]->number);
362 }
363 
364 // ================================================================
365 
NotebookInsider()366 NotebookInsider::NotebookInsider() {
367   mynotebook=0;
368   pgid=0;
369 }
370 
setNotebook(Notebook * nb,int pageid)371 void NotebookInsider::setNotebook(Notebook *nb,int pageid) {
372   pgid=pageid;
373   mynotebook=nb;
374 }
375 
contentUpdated()376 void NotebookInsider::contentUpdated() {
377   int color=0xff0000;
378   Importance maxi=IM_NORMAL;
379   global.debug("NotebookInsider","contentUpdated");
380   if (!impstack.empty()) {
381     maxi=IM_IGNORE;
382     while(!impstack.empty()) {
383       if (impstack.top() > maxi) maxi=impstack.top();
384       impstack.pop();
385     }
386     switch(maxi) {
387     case IM_IGNORE:
388       return;
389     case IM_NORMAL:
390       color=0xff0000;
391       break;
392     case IM_PERSONAL:
393       color=0x0000ff;
394       break;
395     default:
396       color=0x00ff00; /* will never happen */
397       break;
398     }
399   }
400   if (!mynotebook)
401     return;
402   if (mynotebook->getCurrentPageId() != pgid)
403     mynotebook->setTabColor(pgid,color,maxi);
404 }
405 
pop()406 void NotebookInsider::pop() {
407   global.debug("NotebookInsider","pop");
408   if (!mynotebook)
409     return;
410   mynotebook->goToPageId(pgid);
411 }
412 
pushLevel(Importance imp)413 void NotebookInsider::pushLevel(Importance imp) {
414   impstack.push(imp);
415 }
416 
getPageId()417 int NotebookInsider::getPageId() {
418   return(pgid);
419 }
420