1 /*****************************************************/
2 /* This java file is a part of the */
4 /* - Plouf's Java IRC Client - */
6 /* Copyright (C) 2002 - 2004 Philippe Detournay */
8 /* All contacts : theplouf@yahoo.com */
10 /* PJIRC is free software; you can redistribute */
11 /* it and/or modify it under the terms of the GNU */
12 /* General Public License as published by the */
13 /* Free Software Foundation; version 2 or later of */
16 /* PJIRC is distributed in the hope that it will */
17 /* be useful, but WITHOUT ANY WARRANTY; without */
18 /* even the implied warranty of MERCHANTABILITY or */
19 /* FITNESS FOR A PARTICULAR PURPOSE. See the GNU */
20 /* General Public License for more details. */
22 /* You should have received a copy of the GNU */
23 /* General Public License along with PJIRC; if */
24 /* not, write to the Free Software Foundation, */
25 /* Inc., 59 Temple Place, Suite 330, Boston, */
26 /* MA 02111-1307 USA */
28 /*****************************************************/
32 import irc.IRCConfiguration;
33 import irc.ListenerGroup;
34 import irc.StyleContext;
35 import irc.style.DecodedLine;
36 import irc.style.DrawResult;
37 import irc.style.FormattedStringDrawer;
38 import irc.style.FormattedStringDrawerListener;
40 import java.awt.Color;
41 import java.awt.Cursor;
42 import java.awt.Dimension;
44 import java.awt.Graphics;
45 import java.awt.Image;
46 import java.awt.event.MouseEvent;
47 import java.awt.event.MouseListener;
48 import java.awt.event.MouseMotionListener;
53 public class PixxMenuBar extends PixxPanel implements MouseListener, MouseMotionListener, Runnable,
54 FormattedStringDrawerListener {
56 private int _pressedIndex;
57 private boolean _closePressed;
58 private boolean _dockPressed;
59 private ListenerGroup _listeners;
60 private boolean _connected;
61 private boolean _title;
62 private Image _buffer;
63 private FormattedStringDrawer _drawer;
64 private String _titleString;
65 private DecodedLine _decodedTitle;
66 private int _connectIndex;
67 private int _chanlistIndex;
68 private int _aboutIndex;
69 private int _helpIndex;
70 private int _titleLeft;
71 private int _mouseDownX;
72 private boolean _mouseScroll;
73 private DrawResult _drawResult;
74 private boolean _terminated;
75 private boolean _redrawTitle;
76 private Thread _scrollThread;
77 private Object _scrollLock;
78 private boolean _freeze;
79 private int _scrollDelay;
82 * Create a new PixxMenuBar without title displayed.
85 * the global irc configuration.
87 public PixxMenuBar(PixxConfiguration config) {
92 * Create a new PixxMenuBar.
95 * the global irc configuration.
97 * true if this menu bar should display its own title, false
100 public PixxMenuBar(PixxConfiguration config, boolean title) {
104 _mouseScroll = false;
106 IRCConfiguration _ircConfiguration = config.getIRCConfiguration();
107 _drawer = new FormattedStringDrawer(_ircConfiguration, _ircConfiguration.getDefaultStyleContext(), this);
108 _decodedTitle = _drawer.decodeLine(_titleString);
111 _closePressed = false;
112 _dockPressed = false;
113 _listeners = new ListenerGroup();
114 int currentIndex = 0;
115 if (config.getB("showconnect"))
116 _connectIndex = currentIndex++;
117 if (config.getB("showchanlist"))
118 _chanlistIndex = currentIndex++;
119 if (config.getB("showabout"))
120 _aboutIndex = currentIndex++;
121 if (config.getB("showhelp"))
122 _helpIndex = currentIndex++;
123 _scrollDelay = config.getI("scrollspeed");
124 if (_scrollDelay != 0)
125 _scrollDelay = 1000 / _scrollDelay;
126 _drawResult = new DrawResult();
127 addMouseListener(this);
128 addMouseMotionListener(this);
130 _redrawTitle = false;
131 _scrollLock = new Object();
132 if (_scrollDelay > 0) {
133 _scrollThread = new Thread(this);
134 _scrollThread.start();
139 public void release() {
140 removeMouseListener(this);
141 removeMouseMotionListener(this);
151 * title style context.
153 public void setTitle(String title, StyleContext context) {
154 _drawer.setStyleContext(context);
155 _titleString = title;
156 _decodedTitle = _drawer.decodeLine(_titleString);
167 public void addPixxMenuBarListener(PixxMenuBarListener lis) {
168 _listeners.addListener(lis);
175 * listener to remove.
177 public void removePixxMenuBarListener(PixxMenuBarListener lis) {
178 _listeners.removeListener(lis);
182 * Set the connected flag.
185 * true if application is connected to the server, false otherwise.
187 public void setConnected(boolean b) {
194 public Dimension getPreferredSize() {
196 return new Dimension(16, getItemHeight() + getTitleHeight() + 4);
197 return new Dimension(16, getItemHeight() + 4);
200 private int getClosePositionX() {
201 int w = getSize().width;
205 private int getClosePositionY() {
209 private int getDockPositionX() {
210 int w = getSize().width;
211 if (!_pixxConfiguration.getB("showclose"))
216 private int getDockPositionY() {
220 private boolean isClosePressed(int x, int y) {
221 if (!_pixxConfiguration.getB("showclose"))
223 x -= getClosePositionX();
228 y -= getClosePositionY();
236 private boolean isDockPressed(int x, int y) {
237 if (!_pixxConfiguration.getB("showdock"))
239 x -= getDockPositionX();
244 y -= getDockPositionY();
252 private int getItemWidth() {
256 private int getItemHeight() {
260 private int getIconWidth() {
264 private int getIconHeight() {
265 return getItemHeight() - 4;
268 private int getX(int pos) {
269 return pos * (getItemWidth() + 8) + 2;
272 private int getPos(int x) {
273 return (x - 2) / (getItemWidth() + 8);
276 private int getY(int pos) {
279 return 2 + getTitleHeight() * 0;
282 private int getTitleY() {
284 return getItemHeight() + 4;
287 private int getTitleHeight() {
291 private int getIndex(int x) {
298 if (x >= getItemWidth())
303 private int getIndex(int x, int y) {
307 if (y >= getItemHeight())
312 private void drawTitle(Graphics g, int y) {
313 int w = getSize().width;
315 g.setColor(_drawer.getColor(0));
316 g.fillRect(0, y, w, getTitleHeight());
317 g.setClip(0, y, w, getTitleHeight());
318 _drawer.draw(_decodedTitle, g, 5 + _titleLeft, w - 5 + _titleLeft, y + getTitleHeight() - 2, 0, w - 1, false,
320 g.setClip(0, 0, getSize().width, getSize().height);
322 drawSeparator(g, 0, y, w, getTitleHeight());
325 private void drawDisconnectIcon(Graphics g, int x, int y) {
326 int w = getIconWidth();
327 int h = getIconHeight();
328 g.setColor(new Color(0xEFEFEF));
329 g.fillRect(x, y, w, h);
331 g.setColor(new Color(0xAFAFAF));
332 g.drawLine(x, y + h / 2 - 1, x + 5, y + h / 2 - 1);
333 g.drawLine(x + w - 1, y + h / 2 - 1, x + w - 5, y + h / 2 - 1);
334 g.setColor(Color.black);
335 g.drawLine(x, y + h / 2, x + 4, y + h / 2);
336 g.drawLine(x + w - 1, y + h / 2, x + w - 6, y + h / 2);
338 g.drawLine(x + 4, y + h / 2 + 1, x + 7, y + h / 2 - 2);
339 g.drawLine(x + 8, y + h / 2 + 1, x + 11, y + h / 2 - 2);
342 private void drawConnectIcon(Graphics g, int x, int y) {
343 int w = getIconWidth();
344 int h = getIconHeight();
345 g.setColor(new Color(0xEFEFEF));
346 g.fillRect(x, y, w, h);
348 g.setColor(new Color(0xA2A2A2));
349 g.drawLine(x, y + h / 2 - 1, x + w - 1, y + h / 2 - 1);
350 g.setColor(Color.black);
351 g.drawLine(x, y + h / 2, x + w - 1, y + h / 2);
353 g.setColor(new Color(0x960000));
354 g.drawLine(x + 2, y + 2, x + 14, y + 2);
355 g.drawLine(x + 12, y, x + 14, y + 2);
356 g.drawLine(x + 12, y + 4, x + 14, y + 2);
358 g.setColor(new Color(0x2A5B90));
359 g.drawLine(x + 2, y + 9, x + 14, y + 9);
360 g.drawLine(x + 2, y + 9, x + 4, y + 7);
361 g.drawLine(x + 2, y + 9, x + 4, y + 11);
364 private void drawChanListIcon(Graphics g, int x, int y) {
365 int w = getIconWidth();
366 int h = getIconHeight();
367 g.setColor(new Color(0xEFEFEF));
368 g.fillRect(x, y, w, h);
369 g.setColor(Color.black);
371 g.drawLine(x, y + 1, x + 9, y + 1);
372 g.drawLine(x, y + 3, x + 5, y + 3);
373 g.drawLine(x, y + 5, x + 12, y + 5);
374 g.drawLine(x, y + 7, x + 11, y + 7);
375 g.drawLine(x, y + 9, x + 9, y + 9);
376 g.drawLine(x, y + 11, x + 13, y + 11);
379 private void drawHelpIcon(Graphics g, int x, int y) {
380 int w = getIconWidth();
381 int h = getIconHeight();
382 g.setColor(new Color(0xEFEFEF));
383 g.fillRect(x, y, w, h);
384 g.setColor(Color.black);
387 g.fillRect(x + 0, y + 0, 2, 3);
388 g.fillRect(x + 2, y + 0, 4, 2);
389 g.fillRect(x + 6, y + 0, 2, 6);
390 g.fillRect(x + 3, y + 4, 3, 2);
391 g.fillRect(x + 3, y + 6, 2, 2);
392 g.fillRect(x + 3, y + 9, 2, 2);
395 private void drawAboutIcon(Graphics g, int x, int y) {
396 int w = getIconWidth();
397 int h = getIconHeight();
398 g.setColor(new Color(0xEFEFEF));
399 g.fillRect(x, y, w, h);
400 g.setColor(Color.black);
401 g.drawLine(x + 5, y + 4, x + 8, y + 4);
402 g.drawLine(x + 5, y + 11, x + 10, y + 11);
403 g.fillRect(x + 7, y + 4, 2, 7);
404 g.fillRect(x + 7, y + 1, 2, 2);
407 private void drawCloseButtonCross(Graphics g, int x, int y) {
410 g.setColor(getColor(COLOR_CLOSE));
411 g.fillRect(x, y, w, h);
412 g.setColor(getColor(COLOR_BLACK));
413 for (int i = 0; i < 4; i++) {
414 g.drawLine(x + 3 + i, y + 2 + i, x + 4 + i, y + 2 + i);
415 g.drawLine(x + 9 - i, y + 2 + i, x + 10 - i, y + 2 + i);
417 g.drawLine(x + 3 + i, y + 8 - i, x + 4 + i, y + 8 - i);
418 g.drawLine(x + 9 - i, y + 8 - i, x + 10 - i, y + 8 - i);
422 private void drawDockButtonInternal(Graphics g, int x, int y) {
425 g.setColor(getColor(COLOR_CLOSE));
426 g.fillRect(x, y, w, h);
427 g.setColor(getColor(COLOR_BLACK));
430 g.drawRect(x + ox, y + oy, 6, 5);
431 g.drawLine(x + ox + 1, y + oy + 1, x + ox + 6, y + oy + 1);
434 g.setColor(getColor(COLOR_BLACK));
435 g.drawRect(x + ox, y + oy, 6, 5);
436 g.drawLine(x + ox + 1, y + oy + 1, x + ox + 6, y + oy + 1);
437 g.setColor(getColor(COLOR_CLOSE));
438 g.fillRect(x + ox + 1, y + oy + 2, 5, 3);
441 private void drawItem(Graphics g, int x, int y, boolean selected, String s) {
442 int w = getItemWidth();
443 int h = getItemHeight();
444 int iw = getIconWidth();
445 g.setColor(getColor(COLOR_FRONT));
447 g.setColor(getColor(COLOR_SELECTED));
448 g.fillRect(x, y, w, h);
449 g.setColor(getColor(COLOR_BLACK));
450 g.drawRect(x, y, w - 1, h - 1);
451 g.setColor(getColor(COLOR_WHITE));
452 g.drawRect(x + 1, y + 1, w - 3, h - 3);
453 g.drawLine(x + iw + 2, y + 1, x + iw + 2, y + h - 2);
454 int sw = g.getFontMetrics().stringWidth(s);
456 g.drawString(s, x + iw + 3 + (w - sw) / 2, y + h - 4);
459 private void drawDisconnectItem(Graphics g, int x, int y, boolean pressed) {
460 drawItem(g, x, y, pressed, getText(PixxTextProvider.GUI_DISCONNECT));
461 drawDisconnectIcon(g, x + 2, y + 2);
464 private void drawConnectItem(Graphics g, int x, int y, boolean pressed) {
465 drawItem(g, x, y, pressed, getText(PixxTextProvider.GUI_CONNECT));
466 drawConnectIcon(g, x + 2, y + 2);
469 private void drawChanListItem(Graphics g, int x, int y, boolean pressed) {
470 drawItem(g, x, y, pressed, getText(PixxTextProvider.GUI_CHANNELS));
471 drawChanListIcon(g, x + 2, y + 2);
474 private void drawAboutItem(Graphics g, int x, int y, boolean pressed) {
475 drawItem(g, x, y, pressed, getText(PixxTextProvider.GUI_ABOUT));
476 drawAboutIcon(g, x + 2, y + 2);
479 private void drawHelpItem(Graphics g, int x, int y, boolean pressed) {
480 drawItem(g, x, y, pressed, getText(PixxTextProvider.GUI_HELP));
481 drawHelpIcon(g, x + 2, y + 2);
484 private void drawSmallButton(Graphics g, int x, int y, boolean pressed) {
488 g.setColor(getColor(COLOR_WHITE));
489 g.drawLine(x + 0, y + 1, x + w - 2, y + 1);
490 g.drawLine(x + 0, y + 1, x + 0, y + h - 2);
491 g.setColor(getColor(COLOR_BLACK));
492 g.drawLine(x + w - 1, y + h - 2, x + w - 1, y + 1);
493 g.drawLine(x + w - 1, y + h - 2, x + 0, y + h - 2);
494 g.setColor(getColor(COLOR_DARK_GRAY));
495 g.drawLine(x + w - 2, y + h - 3, x + w - 2, y + 2);
496 g.drawLine(x + w - 2, y + h - 3, x + 1, y + h - 3);
498 g.setColor(getColor(COLOR_BLACK));
499 g.drawLine(x + 0, y + 1, x + w - 2, y + 1);
500 g.drawLine(x + 0, y + 1, x + 0, y + h - 2);
501 g.setColor(getColor(COLOR_WHITE));
502 g.drawLine(x + w - 1, y + h - 2, x + w - 1, y + 1);
503 g.drawLine(x + w - 1, y + h - 2, x + 0, y + h - 2);
504 g.setColor(getColor(COLOR_DARK_GRAY));
505 g.drawLine(x + 1, y + 2, x + 1, y + h - 3);
506 g.drawLine(x + 1, y + 2, x + w - 2, y + 2);
510 private void drawCloseButtonItem(Graphics g, int x, int y, boolean pressed) {
511 drawSmallButton(g, x, y, pressed);
513 drawCloseButtonCross(g, x + 1, y + 2);
515 drawCloseButtonCross(g, x + 2, y + 3);
518 private void drawDockButtonItem(Graphics g, int x, int y, boolean pressed) {
519 drawSmallButton(g, x, y, pressed);
521 drawDockButtonInternal(g, x + 1, y + 2);
523 drawDockButtonInternal(g, x + 2, y + 3);
527 public void paint(Graphics g) {
532 public void update(Graphics ug) {
533 int w = getSize().width;
534 int h = getSize().height;
536 if (_buffer != null) {
537 if ((_buffer.getWidth(this) != w) || (_buffer.getHeight(this) != h))
541 if (_buffer == null) {
544 _buffer = createImage(w, h);
545 g = _buffer.getGraphics();
546 } catch (Throwable e) {
550 g.setFont(new Font("", Font.PLAIN, 12));
552 // g.setColor(new Color(0x084079));
553 g.setColor(getColor(COLOR_BACK));
554 g.fillRect(0, 0, w, h);
556 // drawSeparator(g,0,0,w,getItemHeight()+4);
558 if (_pixxConfiguration.getB("showconnect")) {
560 drawConnectItem(g, getX(_connectIndex), getY(0), _pressedIndex == _connectIndex);
562 drawDisconnectItem(g, getX(_connectIndex), getY(0), _pressedIndex == _connectIndex);
564 if (_pixxConfiguration.getB("showchanlist"))
565 drawChanListItem(g, getX(_chanlistIndex), getY(0), _pressedIndex == _chanlistIndex);
566 if (_pixxConfiguration.getB("showabout"))
567 drawAboutItem(g, getX(_aboutIndex), getY(0), _pressedIndex == _aboutIndex);
568 if (_pixxConfiguration.getB("showhelp"))
569 drawHelpItem(g, getX(_helpIndex), getY(0), _pressedIndex == _helpIndex);
571 if (_pixxConfiguration.getB("showclose"))
572 drawCloseButtonItem(g, getClosePositionX(), getClosePositionY(), _closePressed);
573 if (_pixxConfiguration.getB("showdock"))
574 drawDockButtonItem(g, getDockPositionX(), getDockPositionY(), _dockPressed);
577 drawTitle(g, getTitleY());
580 Graphics g = _buffer.getGraphics();
582 drawTitle(g, getTitleY());
585 _redrawTitle = false;
588 ug.drawImage(_buffer, 0, 0, this);
593 public void mouseClicked(MouseEvent e) {
597 public void mouseEntered(MouseEvent e) {
601 public void mouseExited(MouseEvent e) {
605 public void mousePressed(MouseEvent e) {
606 _pressedIndex = getIndex(e.getX(), e.getY());
607 _closePressed = isClosePressed(e.getX(), e.getY());
608 _dockPressed = isDockPressed(e.getX(), e.getY());
610 if (_title && (e.getY() >= getTitleY())) {
611 _mouseDownX = e.getX();
618 public void mouseReleased(MouseEvent e) {
619 _mouseScroll = false;
620 int index = getIndex(e.getX(), e.getY());
621 boolean close = isClosePressed(e.getX(), e.getY());
622 boolean dock = isDockPressed(e.getX(), e.getY());
623 if (index == _connectIndex)
624 if (_pixxConfiguration.getB("showconnect"))
625 _listeners.sendEventAsync("connectionClicked", this);
626 if (index == _chanlistIndex)
627 if (_pixxConfiguration.getB("showchanlist"))
628 _listeners.sendEventAsync("chanListClicked", this);
629 if (index == _aboutIndex)
630 if (_pixxConfiguration.getB("showabout"))
631 _listeners.sendEventAsync("aboutClicked", this);
632 if (index == _helpIndex)
633 if (_pixxConfiguration.getB("showhelp"))
634 _listeners.sendEventAsync("helpClicked", this);
636 _listeners.sendEventAsync("closeClicked", this);
638 _listeners.sendEventAsync("dockClicked", this);
639 _closePressed = false;
640 _dockPressed = false;
647 public void mouseMoved(MouseEvent e) {
648 if (_title && (e.getY() >= getTitleY())) {
649 if (!getCursor().equals(new Cursor(Cursor.E_RESIZE_CURSOR)))
650 setCursor(new Cursor(Cursor.E_RESIZE_CURSOR));
652 if (!getCursor().equals(new Cursor(Cursor.DEFAULT_CURSOR)))
653 setCursor(new Cursor(Cursor.DEFAULT_CURSOR));
658 * Release any ressources used by this component.
660 public void dispose() {
664 private void scrollTitle(int deltaX) {
665 synchronized (_scrollLock) {
667 if (_drawResult.rectangle == null)
669 _titleLeft -= deltaX;
670 /** --- WRAP BEHAVIOUR --- **/
671 int min = -_drawResult.rectangle.width;
672 int max = getSize().width;
673 if (_titleLeft > max)
675 if (_titleLeft < min)
678 /** --- CLAMP BEHAVIOUR --- **/
680 * int min=-_drawResult.rectangle.width; int max=0; if(_titleLeft>max)
681 * _titleLeft=max; if(_titleLeft<min) _titleLeft=min;
690 public void mouseDragged(MouseEvent e) {
693 if (_drawResult.rectangle == null)
695 int deltaX = _mouseDownX - e.getX();
698 _mouseDownX = e.getX();
703 while (!_terminated) {
711 Thread.sleep(_scrollDelay);
712 } catch (InterruptedException ex) {
718 public Boolean displayUpdated(Object handle, Integer what) {
719 if (_drawResult == null)
720 return Boolean.FALSE;
721 for (int i = 0; i < _drawResult.updateHandles.size(); i++) {
722 if (_drawResult.updateHandles.elementAt(i) == handle) {
728 return Boolean.FALSE;