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