1 /*
2   FXiTe - The Free eXtensIble Text Editor
3   Copyright (c) 2009-2012 Jeffrey Pohlmeyer <yetanothergeek@gmail.com>
4 
5   This program is free software; you can redistribute it and/or modify it
6   under the terms of the GNU General Public License version 3 as
7   published by the Free Software Foundation.
8 
9   This software is distributed in the hope that it will be useful,
10   but WITHOUT ANY WARRANTY; without even the implied warranty of
11   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12   GNU General Public License for more details.
13 
14   You should have received a copy of the GNU General Public License
15   along with this program; if not, write to the Free Software
16   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
17 */
18 
19 
20 #include <fx.h>
21 
22 #include "color_funcs.h"
23 #include "menuspec.h"
24 #include "prefs_base.h"
25 #include "appwin.h"
26 #include "compat.h"
27 #include "toolbar.h"
28 
29 
30 #define TBarOpts (FRAME_NONE|LAYOUT_FILL_X|PACK_UNIFORM_HEIGHT)
31 #define TogBtnOpts  (FRAME_RAISED|FRAME_THICK|JUSTIFY_NORMAL|TOGGLEBUTTON_KEEPSTATE)
32 
33 #define UsedWidthOf(f) ((f&&f->getLast())?(f->getLast()->getX()+f->getLast()->getWidth()):0)
34 
35 #define prefs SettingsBase::instance()
36 
37 /* Class that makes tool bar buttons restore document focus after they are clicked */
38 class ToolBarBtn: public FXButton {
39   FXDECLARE(ToolBarBtn)
ToolBarBtn()40   ToolBarBtn(){}
41 public:
42   ToolBarBtn(FXComposite* p, const FXString& text, FXObject*tgt, FXSelector sel);
43   long onLeftBtnRelease(FXObject*o, FXSelector sel, void*p );
44 };
45 
46 
47 /* Class that makes tool bar toggle buttons restore document focus after they are clicked */
48 class ToolBarTogBtn: public FXToggleButton {
49   FXDECLARE(ToolBarTogBtn)
ToolBarTogBtn()50   ToolBarTogBtn(){}
51 public:
52   ToolBarTogBtn(FXComposite* p, const FXString& text, FXObject*tgt, FXSelector sel);
53   long onLeftBtnRelease(FXObject*o, FXSelector sel, void*p );
54 };
55 
56 
57 
58 FXDEFMAP(ToolBarBtn) ToolBarBtnMap[] = {
59   FXMAPFUNC(SEL_LEFTBUTTONRELEASE,0,ToolBarBtn::onLeftBtnRelease),
60 };
61 
FXIMPLEMENT(ToolBarBtn,FXButton,ToolBarBtnMap,ARRAYNUMBER (ToolBarBtnMap))62 FXIMPLEMENT(ToolBarBtn,FXButton,ToolBarBtnMap,ARRAYNUMBER(ToolBarBtnMap))
63 
64 
65 ToolBarBtn::ToolBarBtn(FXComposite* p, const FXString& text, FXObject*tgt, FXSelector sel):
66     FXButton(p,text,NULL,tgt,sel,FRAME_NONE|JUSTIFY_NORMAL,0,0,24,24,2,2,0,0)
67 {
68 
69 }
70 
71 
onLeftBtnRelease(FXObject * o,FXSelector sel,void * p)72 long ToolBarBtn::onLeftBtnRelease(FXObject*o, FXSelector sel, void*p ) {
73   long rv=FXButton::onLeftBtnRelease(o,sel,p);
74   getApp()->addChore(TopWindow::instance(),TopWindow::ID_FOCUS_DOC,NULL);
75   return rv;
76 }
77 
78 FXDEFMAP(ToolBarTogBtn) ToolBarTogBtnMap[] = {
79   FXMAPFUNC(SEL_LEFTBUTTONRELEASE,0,ToolBarTogBtn::onLeftBtnRelease),
80 };
81 
FXIMPLEMENT(ToolBarTogBtn,FXToggleButton,ToolBarTogBtnMap,ARRAYNUMBER (ToolBarTogBtnMap))82 FXIMPLEMENT(ToolBarTogBtn,FXToggleButton,ToolBarTogBtnMap,ARRAYNUMBER(ToolBarTogBtnMap))
83 
84 
85 
86 ToolBarTogBtn::ToolBarTogBtn(FXComposite* p, const FXString& text, FXObject*tgt, FXSelector sel):
87     FXToggleButton(p,text,text,NULL,NULL,tgt,sel,TogBtnOpts,0,0,24,24,2,2,0,0)
88 {
89 
90 }
91 
92 
93 
onLeftBtnRelease(FXObject * o,FXSelector sel,void * p)94 long ToolBarTogBtn::onLeftBtnRelease(FXObject*o, FXSelector sel, void*p )
95 {
96   long rv=FXToggleButton::onLeftBtnRelease(o,sel,p);
97   getApp()->addChore(TopWindow::instance(),TopWindow::ID_FOCUS_DOC,NULL);
98   return rv;
99 }
100 
101 
102 
103 FXDEFMAP(ToolBarFrame)ToolBarFrameMap[]={
104   FXMAPFUNC(SEL_CONFIGURE, 0, ToolBarFrame::onConfigure)
105 };
106 
107 FXIMPLEMENT(ToolBarFrame,FXVerticalFrame,ToolBarFrameMap,ARRAYNUMBER(ToolBarFrameMap));
108 
109 
110 
onConfigure(FXObject * o,FXSelector sel,void * p)111 long ToolBarFrame::onConfigure(FXObject*o,FXSelector sel,void*p)
112 {
113   FXVerticalFrame::onConfigure(o,sel,p);
114   reconf();
115   return 1;
116 }
117 
118 
119 // Wrap or unwrap buttons as needed.
reconf()120 void ToolBarFrame::reconf()
121 {
122   bool prefwrap=prefs->WrapToolbar;
123   if ((!prefwrap)&&(!wraptoolbar)) { return; }
124   FXint kids1=rows[0]->numChildren();
125   FXint kids2=rows[1]->numChildren();
126   if ((prefwrap)&&(kids1>0)&&(kids2==0)&&(width<UsedWidthOf(rows[0]))) {
127     FXWindow *topright=rows[0]->childAtIndex((kids1/2));
128     if (topright && (kids1%2==0)) { topright=topright->getPrev(); }
129     while ( rows[0]->getLast() && (rows[0]->getLast() != topright) ) {
130       rows[0]->getLast()->reparent(rows[1], rows[1]->getFirst());
131     }
132   } else if ( (kids2>0) && ((!prefwrap)||(width>(UsedWidthOf(rows[0])+UsedWidthOf(rows[1])))) ) {
133     while (rows[1]->getFirst()) {
134       rows[1]->getFirst()->reparent(rows[0],NULL);
135     }
136   }
137   if (rows[1]->numChildren()) { rows[1]->show(); } else { rows[1]->hide(); }
138   wraptoolbar=prefwrap;
139   normalize();
140 }
141 
142 
143 
144 // Make all buttons the same width
normalize()145 void ToolBarFrame::normalize()
146 {
147   if (rows[0]->numChildren()==0) { return; }
148   FXint wdt=0;
149   for (FXWindow*row=getFirst(); row; row=row->getNext()) {
150     for (FXWindow*btn=row->getFirst(); btn; btn=btn->getNext()) {
151       btn->setLayoutHints(btn->getLayoutHints()&~LAYOUT_FIX_WIDTH);
152     }
153   }
154   layout();
155   for (FXWindow*row=getFirst(); row; row=row->getNext()) {
156     for (FXWindow*btn=row->getFirst(); btn; btn=btn->getNext()) {
157       FXint w=btn->getWidth();
158       if (w>wdt) { wdt=w; }
159     }
160   }
161   for (FXWindow*row=getFirst(); row; row=row->getNext()) {
162     for (FXWindow*btn=row->getFirst(); btn; btn=btn->getNext()) {
163       btn->setLayoutHints(btn->getLayoutHints()|LAYOUT_FIX_WIDTH);
164       btn->setWidth(wdt);
165     }
166   }
167   layout();
168 }
169 
170 
171 
SetTBarBtnColorCB(FXButton * btn,void * user_data)172 void ToolBarFrame::SetTBarBtnColorCB(FXButton*btn, void*user_data)
173 {
174   FXint*i=(FXint*)user_data;
175   btn->setBackColor(HexToRGB(MenuMgr::TBarColors(*i)));
176   btn->setTextColor(HexToRGB("#000000"));
177   btn->setHiliteColor(makeHiliteColor(btn->getBackColor()));
178   btn->setShadowColor(makeShadowColor(btn->getBackColor()));
179   btn->setBorderColor(btn->getShadowColor());
180   (*i)++;
181 }
182 
183 
184 
SetToolbarColors()185 void ToolBarFrame::SetToolbarColors()
186 {
187   FXint i=0;
188   ForEachToolbarButton(SetTBarBtnColorCB,&i);
189 }
190 
191 
192 
SetTBarBtnFontCB(FXButton * btn,void * user_data)193 void ToolBarFrame::SetTBarBtnFontCB(FXButton*btn, void*user_data)
194 {
195   ToolBarFrame*tbf=(ToolBarFrame*)user_data;
196   if (!tbf->toolbar_font) {
197     FXFontDesc dsc;
198     GetFontDescription(dsc, tbf->getApp()->getNormalFont());
199     FXfloat scale=1.0;
200     switch (prefs->ToolbarButtonSize) {
201       case 0:{ scale=0.75; break; }
202       case 1:{ scale=0.90; break; }
203       case 2:{ scale=1.00; break; }
204     }
205     dsc.size=FXushort(((FXfloat)dsc.size)*scale);
206     tbf->toolbar_font=new FXFont(tbf->getApp(),dsc);
207   }
208   btn->setFont(tbf->toolbar_font);
209   btn->destroy();
210   if (tbf->getShell()->shown()) {
211     btn->create();
212   }
213   if (btn->getNext()==NULL) {
214     tbf->normalize();
215     tbf->reconf();
216   }
217 }
218 
219 
220 
SetTBarFont()221 void ToolBarFrame::SetTBarFont()
222 {
223   delete toolbar_font;
224   toolbar_font=NULL;
225   ForEachToolbarButton(SetTBarBtnFontCB,this);
226   getParent()->layout();
227 }
228 
229 
230 
~ToolBarFrame()231 ToolBarFrame::~ToolBarFrame()
232 {
233   delete toolbar_font;
234 }
235 
236 
237 
ToolBarFrame(FXComposite * o)238 ToolBarFrame::ToolBarFrame(FXComposite *o):FXVerticalFrame(o,TBarOpts,0,0,0,0,0,0,0,0,1,1)
239 {
240   toolbar_font = NULL;
241   wraptoolbar=prefs->WrapToolbar;
242   rows[0]=new FXHorizontalFrame(this,TBarOpts,0,0,0,0,0,0,0,0,1,1);
243   rows[1]=new FXHorizontalFrame(this,TBarOpts,0,0,0,0,0,0,0,0,1,1);
244   rows[1]->hide();
245 }
246 
247 
ForEachToolbarButton(void (* cb)(FXButton * btn,void * user_data),void * user_data)248 void ToolBarFrame::ForEachToolbarButton(void (*cb)(FXButton*btn, void*user_data), void*user_data) {
249   for (FXWindow*hfrm=getFirst(); hfrm; hfrm=hfrm->getNext()) {
250     for (FXWindow*btn=hfrm->getFirst(); btn; btn=btn->getNext()) {
251       cb((FXButton*)btn, user_data);
252     }
253   }
254 }
255 
256 
257 
ClearTBarBtnDataCB(FXButton * btn,void * user_data)258 void ToolBarFrame::ClearTBarBtnDataCB(FXButton*btn, void*user_data)
259 {
260   MenuSpec*spec=(MenuSpec*)btn->getUserData();
261   if (spec&&spec->ms_mc&&(spec->type!='u')) { spec->ms_mc->setUserData(NULL); }
262 }
263 
264 
265 
266 
NullifyButtonDataCB(FXButton * btn,void * user_data)267 void ToolBarFrame::NullifyButtonDataCB(FXButton*btn, void*user_data)
268 {
269   if (btn->getUserData()==user_data) { btn->setUserData(NULL); }
270 }
271 
272 
273 
NullifyButtonData(void * user_data)274 void ToolBarFrame::NullifyButtonData(void*user_data)
275 {
276   ForEachToolbarButton(NullifyButtonDataCB,user_data);
277 }
278 
279 
280 
EnableFilterBtnCB(FXButton * btn,void * user_data)281 void ToolBarFrame::EnableFilterBtnCB(FXButton*btn, void*user_data)
282 {
283   MenuSpec*spec=(MenuSpec*)btn->getUserData();
284   if (spec && (spec->type=='u') && spec->ms_mc && (spec->ms_mc->getSelector()==TopWindow::ID_USER_FILTER)) {
285     if ((bool)user_data) { btn->enable(); } else { btn->disable(); }
286   }
287 }
288 
289 
290 
EnableFilterBtn(bool enabled)291 void ToolBarFrame::EnableFilterBtn(bool enabled)
292 {
293   ForEachToolbarButton(EnableFilterBtnCB,(void*)enabled);
294 }
295 
296 
297 
create()298 void ToolBarFrame::create()
299 {
300   FXVerticalFrame::create();
301   normalize();
302   if (!prefs->ShowToolbar) { hide(); }
303 }
304 
305 
306 
show()307 void ToolBarFrame::show()
308 {
309   FXVerticalFrame::show();
310   getParent()->layout();
311 }
312 
313 
314 
hide()315 void ToolBarFrame::hide()
316 {
317   FXVerticalFrame::hide();
318   getParent()->layout();
319 }
320 
321 
322 
323 #define EngageBtn(s,t) ((t*)btn)->setState(s?((t*)btn)->getState()|STATE_ENGAGED:((t*)btn)->getState()&~STATE_ENGAGED)
324 
CreateButtons(TopWindow * tw)325 void ToolBarFrame::CreateButtons(TopWindow*tw)
326 {
327   ForEachToolbarButton(ClearTBarBtnDataCB,NULL);
328   for (FXWindow*w=getFirst(); w; w=w->getNext()) {
329     while (w->numChildren()) { delete w->getFirst(); }
330   }
331   for (FXint i=0; i<TBAR_MAX_BTNS; i++) {
332     MenuSpec* spec=MenuMgr::LookupMenu(MenuMgr::TBarBtns()[i]);
333     if (spec && spec->sel<TopWindow::ID_LAST) {
334       FXString txt=spec->btn_txt;
335       txt.substitute(' ','\n',true);
336       FXLabel*btn;
337       if ((spec->type=='k')||(spec->sel==TopWindow::ID_MACRO_RECORD)) {
338         btn=new ToolBarTogBtn((FXComposite*)(getFirst()),txt,tw,spec->sel);
339       } else {
340         btn=new ToolBarBtn((FXComposite*)(getFirst()),txt,tw,(spec->type=='u')?TopWindow::ID_TBAR_CUSTOM_CMD:spec->sel);
341         switch (spec->sel) { // These menus might be in a disabled state...
342           case TopWindow::ID_MACRO_PLAYBACK:
343           case TopWindow::ID_MACRO_TRANSLATE:
344           case TopWindow::ID_FILTER_SEL:
345           case TopWindow::ID_FIND_TAG:
346           case TopWindow::ID_SHOW_CALLTIP:
347           case TopWindow::ID_FMT_DOS:
348           case TopWindow::ID_FMT_MAC:
349           case TopWindow::ID_FMT_UNIX: {
350             if (!spec->ms_mc->isEnabled()) { btn->disable(); }
351             break;
352           }
353         }
354       }
355       if (spec->ms_mc) {
356         if (spec->type!='u') { spec->ms_mc->setUserData((void*)btn); }
357         btn->setUserData(spec);
358         switch(spec->type) {
359           case 'k': { EngageBtn(((FXMenuCheck*)(spec->ms_mc))->getCheck(),FXToggleButton); break; }
360           case 'r': { EngageBtn(((FXMenuRadio*)(spec->ms_mc))->getCheck(),FXButton); break; }
361         }
362       }
363       FXString tip;
364       MenuMgr::GetTBarBtnTip(spec,tip);
365       btn->setTipText(tip);
366     } else {
367       break;
368     }
369   }
370   SetTBarFont();
371   SetToolbarColors();
372   layout();
373 }
374 
375