diff options
author | Paul Davis <paul@linuxaudiosystems.com> | 2008-06-02 21:41:35 +0000 |
---|---|---|
committer | Paul Davis <paul@linuxaudiosystems.com> | 2008-06-02 21:41:35 +0000 |
commit | 449aab3c465bbbf66d221fac3d7ea559f1720357 (patch) | |
tree | 6843cc40c88250a132acac701271f1504cd2df04 /libs/gtkmm2ext | |
parent | 9c0d7d72d70082a54f823cd44c0ccda5da64bb6f (diff) |
rollback to 3428, before the mysterious removal of libs/* at 3431/3432
git-svn-id: svn://localhost/ardour2/branches/3.0@3435 d708f5d6-7413-0410-9779-e7cbd77b26cf
Diffstat (limited to 'libs/gtkmm2ext')
75 files changed, 9093 insertions, 0 deletions
diff --git a/libs/gtkmm2ext/.cvsignore b/libs/gtkmm2ext/.cvsignore new file mode 100644 index 0000000000..d7120405dc --- /dev/null +++ b/libs/gtkmm2ext/.cvsignore @@ -0,0 +1,7 @@ +libgtkmmext.pc +libgtkmmext.spec +version.cc +*.mo +*.pot +*.os +*.dylib diff --git a/libs/gtkmm2ext/AUTHORS b/libs/gtkmm2ext/AUTHORS new file mode 100644 index 0000000000..396f223e8c --- /dev/null +++ b/libs/gtkmm2ext/AUTHORS @@ -0,0 +1,2 @@ +Written primarily by Paul Davis. +Porting to gtkmm2 and sigc++2 work done by Taybin Rutkin. diff --git a/libs/gtkmm2ext/COPYING b/libs/gtkmm2ext/COPYING new file mode 100644 index 0000000000..d60c31a97a --- /dev/null +++ b/libs/gtkmm2ext/COPYING @@ -0,0 +1,340 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + <one line to give the program's name and a brief idea of what it does.> + Copyright (C) <year> <name of author> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + <signature of Ty Coon>, 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/libs/gtkmm2ext/ChangeLog b/libs/gtkmm2ext/ChangeLog new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/libs/gtkmm2ext/ChangeLog diff --git a/libs/gtkmm2ext/NEWS b/libs/gtkmm2ext/NEWS new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/libs/gtkmm2ext/NEWS diff --git a/libs/gtkmm2ext/README b/libs/gtkmm2ext/README new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/libs/gtkmm2ext/README diff --git a/libs/gtkmm2ext/SConscript b/libs/gtkmm2ext/SConscript new file mode 100644 index 0000000000..a0ef88e6d1 --- /dev/null +++ b/libs/gtkmm2ext/SConscript @@ -0,0 +1,97 @@ +# -*- python -*- + +import os +import os.path +import glob + +Import('env final_prefix install_prefix libraries i18n') + +gtkmm2ext = env.Copy() +gtkmm2ext.Merge ([ + libraries['sigc2'], + libraries['pbd'], + libraries['gtk2'], + libraries['glibmm2'], + libraries['pangomm'], + libraries['atkmm'], + libraries['gdkmm2'], + libraries['gtkmm2'], + libraries['cairomm'] + ]) + +# +# this defines the version number of libgtkmm2ext +# + +domain = 'libgtkmm2ext' + +gtkmm2ext.Append(DOMAIN=domain,MAJOR=0,MINOR=8,MICRO=3) +gtkmm2ext.Append(CXXFLAGS="-DPACKAGE=\\\"" + domain + "\\\"") +gtkmm2ext.Append(CXXFLAGS=["-DLIBSIGC_DISABLE_DEPRECATED", "-DGLIBMM_DEFAULT_SIGNAL_HANDLERS_ENABLED", "-DGLIBMM_PROPERTIES_ENABLED"]) +#gtkmm2ext.Append(CPPPATH='#libs/surfaces/control_protocol') +gtkmm2ext.Append(PACKAGE=domain) +gtkmm2ext.Append(POTFILE=domain + '.pot') + +if gtkmm2ext['IS_OSX']: + gtkmm2ext.Append (LINKFLAGS="-Xlinker -headerpad -Xlinker 2048") + +extra_sources = [] + +gtkmm2ext_files = Split(""" +auto_spin.cc +barcontroller.cc +binding_proxy.cc +choice.cc +click_box.cc +dndtreeview.cc +fastmeter.cc +focus_entry.cc +grouped_buttons.cc +gtk_ui.cc +hexentry.cc +idle_adjustment.cc +pathlist.cc +pixfader.cc +pixscroller.cc +popup.cc +prompter.cc +scroomer.cc +selector.cc +slider_controller.cc +stateful_button.cc +tearoff.cc +textviewer.cc +utils.cc +version.cc +window_title.cc +""") + +gtkosx_files=Split(""" +sync-menu.c +""") + +if gtkmm2ext['GTKOSX']: + extra_sources += gtkosx_files + gtkmm2ext.Append (CCFLAGS="-DTOP_MENUBAR -DGTKOSX") + gtkmm2ext.Append (LINKFLAGS="-framework Carbon") + +gtkmm2ext.VersionBuild(['version.cc','gtkmm2ext/version.h'], []) + +gtkmm2ext.Append(CCFLAGS="-D_REENTRANT") +gtkmm2ext.Append(CCFLAGS="-DLOCALEDIR=\\\""+final_prefix+"/share/locale\\\"") + +libgtkmm2ext = gtkmm2ext.SharedLibrary('gtkmm2ext', gtkmm2ext_files + extra_sources) + +Default(libgtkmm2ext) + +if env['NLS']: + i18n (gtkmm2ext, gtkmm2ext_files, env) + +env.Alias('install', env.Install(os.path.join(install_prefix, env['LIBDIR'], 'ardour3'), libgtkmm2ext)) + +env.Alias('tarball', env.Distribute (env['DISTTREE'], + [ 'SConscript', 'i18n.h', 'gettext.h'] + + gtkmm2ext_files + + gtkosx_files + + glob.glob('po/*.po') + + glob.glob('gtkmm2ext/*.h'))) diff --git a/libs/gtkmm2ext/auto_spin.cc b/libs/gtkmm2ext/auto_spin.cc new file mode 100644 index 0000000000..2e051b5be8 --- /dev/null +++ b/libs/gtkmm2ext/auto_spin.cc @@ -0,0 +1,268 @@ +/* + Copyright (C) 1999 Paul Barton-Davis + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + $Id$ +*/ + +#include <gtkmm2ext/auto_spin.h> +#include <cmath> + +using namespace Gtkmm2ext; +using namespace std; + +#define upper adjustment.get_upper() +#define lower adjustment.get_lower() +#define step_increment adjustment.get_step_increment() +#define page_increment adjustment.get_page_increment() + +const unsigned int AutoSpin::initial_timer_interval = 500; /* msecs */ +const unsigned int AutoSpin::timer_interval = 20; /* msecs */ +const unsigned int AutoSpin::climb_timer_calls = 5; /* between climbing */ + +AutoSpin::AutoSpin (Gtk::Adjustment &adjr, gfloat cr, bool round_to_steps_yn) + : adjustment (adjr), + climb_rate (cr) + +{ + initial = adjustment.get_value(); + left_is_decrement = true; + wrap = false; + have_timer = false; + need_timer = false; + timer_calls = 0; + round_to_steps = round_to_steps_yn; +} + +void +AutoSpin::stop_timer () +{ + if (have_timer) { + g_source_remove (timeout_tag); + have_timer = false; + } +} + +gint +AutoSpin::stop_spinning (GdkEventButton *ev) +{ + need_timer = false; + stop_timer (); + return FALSE; +} + +gint +AutoSpin::button_press (GdkEventButton *ev) +{ + bool shifted = false; + bool control = false; + bool with_decrement = false; + + stop_spinning (0); + + if (ev->state & GDK_SHIFT_MASK) { + /* use page shift */ + + shifted = true; + } + + if (ev->state & GDK_CONTROL_MASK) { + /* go to upper/lower bound on button1/button2 */ + + control = true; + } + + /* XXX should figure out which button is left/right */ + + switch (ev->button) { + case 1: + if (control) { + set_value (left_is_decrement ? lower : upper); + return TRUE; + } else { + if (left_is_decrement) { + with_decrement = true; + } else { + with_decrement = false; + } + } + break; + + case 2: + if (!control) { + set_value (initial); + } + return TRUE; + break; + + case 3: + if (control) { + set_value (left_is_decrement ? upper : lower); + return TRUE; + } + break; + + case 4: + if (!control) { + adjust_value (shifted ? page_increment : step_increment); + } else { + set_value (upper); + } + return TRUE; + break; + + case 5: + if (!control) { + adjust_value (shifted ? -page_increment : -step_increment); + } else { + set_value (lower); + } + return TRUE; + break; + } + + start_spinning (with_decrement, shifted); + return TRUE; +} + +void +AutoSpin::start_spinning (bool decrement, bool page) +{ + timer_increment = page ? page_increment : step_increment; + + if (decrement) { + timer_increment = -timer_increment; + } + + adjust_value (timer_increment); + + have_timer = true; + timer_calls = 0; + timeout_tag = g_timeout_add (initial_timer_interval, + AutoSpin::_timer, + this); +} + +gint +AutoSpin::_timer (void *arg) +{ + return ((AutoSpin *) arg)->timer (); +} + +void +AutoSpin::set_value (gfloat value) +{ + if (round_to_steps) + adjustment.set_value (floor((value / step_increment) + 0.5f) * step_increment); + else + adjustment.set_value (value); +} + +bool +AutoSpin::adjust_value (gfloat increment) +{ + gfloat val; + bool done = false; + + val = adjustment.get_value(); + + val += increment; + + if (val > upper) { + if (wrap) { + val = lower; + } else { + val = upper; + done = true; + } + } else if (val < lower) { + if (wrap) { + val = upper; + } else { + val = lower; + done = true; + } + } + + set_value(val); + return done; +} + +gint +AutoSpin::timer () +{ + bool done; + int retval = FALSE; + + done = adjust_value (timer_increment); + + if (need_timer) { + + /* we're in the initial call, which happened + after initial_timer_interval msecs. Now + request a much more frequent update. + */ + + timeout_tag = g_timeout_add (timer_interval, + _timer, + this); + have_timer = true; + need_timer = false; + + /* cancel this initial timeout */ + + retval = FALSE; + + } else { + /* this is the regular "fast" call after each + timer_interval msecs. + */ + + if (timer_calls < climb_timer_calls) { + timer_calls++; + } else { + if (climb_rate > 0.0) { + if (timer_increment > 0) { + timer_increment += climb_rate; + } else { + timer_increment -= climb_rate; + } + } + timer_calls = 0; + } + + if (!done) { + retval = TRUE; + } + } + + return retval; +} + +void +AutoSpin::set_bounds (gfloat init, gfloat up, gfloat down, bool with_reset) +{ + adjustment.set_upper(up); + adjustment.set_lower(down); + + initial = init; + + adjustment.changed (); + + if (with_reset) { + adjustment.set_value (init); + } +} diff --git a/libs/gtkmm2ext/barcontroller.cc b/libs/gtkmm2ext/barcontroller.cc new file mode 100644 index 0000000000..a3b2a13bf5 --- /dev/null +++ b/libs/gtkmm2ext/barcontroller.cc @@ -0,0 +1,469 @@ +/* + Copyright (C) 2004 Paul Davis + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + $Id$ +*/ + +#include <string> +#include <climits> +#include <cstdio> +#include <cmath> +#include <algorithm> + +#include <pbd/controllable.h> + +#include <gtkmm2ext/gtk_ui.h> +#include <gtkmm2ext/utils.h> +#include <gtkmm2ext/barcontroller.h> + +#include "i18n.h" + +using namespace std; +using namespace Gtk; +using namespace Gtkmm2ext; + +BarController::BarController (Gtk::Adjustment& adj, + PBD::Controllable& mc, + sigc::slot<void,char*,unsigned int> lc) + + : adjustment (adj), + binding_proxy (mc), + label_callback (lc), + spinner (adjustment) + +{ + _style = LeftToRight; + grabbed = false; + switching = false; + switch_on_release = false; + with_text = true; + use_parent = false; + + layout = darea.create_pango_layout(""); + + set_shadow_type (SHADOW_NONE); + + initial_value = adjustment.get_value (); + + adjustment.signal_value_changed().connect (mem_fun (*this, &Gtk::Widget::queue_draw)); + adjustment.signal_changed().connect (mem_fun (*this, &Gtk::Widget::queue_draw)); + + darea.add_events (Gdk::BUTTON_RELEASE_MASK| + Gdk::BUTTON_PRESS_MASK| + Gdk::POINTER_MOTION_MASK| + Gdk::ENTER_NOTIFY_MASK| + Gdk::LEAVE_NOTIFY_MASK| + Gdk::SCROLL_MASK); + + darea.signal_expose_event().connect (mem_fun (*this, &BarController::expose)); + darea.signal_motion_notify_event().connect (mem_fun (*this, &BarController::motion)); + darea.signal_button_press_event().connect (mem_fun (*this, &BarController::button_press), false); + darea.signal_button_release_event().connect (mem_fun (*this, &BarController::button_release), false); + darea.signal_scroll_event().connect (mem_fun (*this, &BarController::scroll)); + + spinner.signal_activate().connect (mem_fun (*this, &BarController::entry_activated)); + spinner.signal_focus_out_event().connect (mem_fun (*this, &BarController::entry_focus_out)); + spinner.set_digits (3); + + add (darea); + show_all (); +} + +void +BarController::drop_grab () +{ + if (grabbed) { + grabbed = false; + darea.remove_modal_grab(); + StopGesture (); + } +} + +bool +BarController::button_press (GdkEventButton* ev) +{ + double fract; + + if (binding_proxy.button_press_handler (ev)) { + return true; + } + + switch (ev->button) { + case 1: + if (ev->type == GDK_2BUTTON_PRESS) { + switch_on_release = true; + drop_grab (); + } else { + switch_on_release = false; + darea.add_modal_grab(); + grabbed = true; + grab_x = ev->x; + grab_window = ev->window; + StartGesture (); + } + return true; + break; + + case 2: + fract = ev->x / (darea.get_width() - 2.0); + adjustment.set_value (adjustment.get_lower() + fract * (adjustment.get_upper() - adjustment.get_lower())); + + case 3: + break; + + case 4: + case 5: + break; + } + + return false; +} + +bool +BarController::button_release (GdkEventButton* ev) +{ + drop_grab (); + + switch (ev->button) { + case 1: + if (switch_on_release) { + Glib::signal_idle().connect (mem_fun (*this, &BarController::switch_to_spinner)); + return true; + } + + if ((ev->state & (GDK_SHIFT_MASK|GDK_CONTROL_MASK)) == GDK_SHIFT_MASK) { + adjustment.set_value (initial_value); + } else { + double scale; + + if ((ev->state & (GDK_CONTROL_MASK|GDK_SHIFT_MASK)) == (GDK_CONTROL_MASK|GDK_SHIFT_MASK)) { + scale = 0.01; + } else if (ev->state & GDK_CONTROL_MASK) { + scale = 0.1; + } else { + scale = 1.0; + } + + mouse_control (ev->x, ev->window, scale); + } + break; + + case 2: + break; + + case 3: + return false; + + default: + break; + } + + return true; +} + +bool +BarController::scroll (GdkEventScroll* ev) +{ + double scale; + + if ((ev->state & (GDK_CONTROL_MASK|GDK_SHIFT_MASK)) == (GDK_CONTROL_MASK|GDK_SHIFT_MASK)) { + scale = 0.01; + } else if (ev->state & GDK_CONTROL_MASK) { + scale = 0.1; + } else { + scale = 1.0; + } + + switch (ev->direction) { + case GDK_SCROLL_UP: + case GDK_SCROLL_RIGHT: + adjustment.set_value (adjustment.get_value() + (scale * adjustment.get_step_increment())); + break; + + case GDK_SCROLL_DOWN: + case GDK_SCROLL_LEFT: + adjustment.set_value (adjustment.get_value() - (scale * adjustment.get_step_increment())); + break; + } + + return true; +} + +bool +BarController::motion (GdkEventMotion* ev) +{ + double scale; + + if (!grabbed) { + return true; + } + + if ((ev->state & (GDK_SHIFT_MASK|GDK_CONTROL_MASK)) == GDK_SHIFT_MASK) { + return TRUE; + } + + if ((ev->state & (GDK_CONTROL_MASK|GDK_SHIFT_MASK)) == (GDK_CONTROL_MASK|GDK_SHIFT_MASK)) { + scale = 0.01; + } else if (ev->state & GDK_CONTROL_MASK) { + scale = 0.1; + } else { + scale = 1.0; + } + + return mouse_control (ev->x, ev->window, scale); +} + +gint +BarController::mouse_control (double x, GdkWindow* window, double scaling) +{ + double fract = 0.0; + double delta; + + if (window != grab_window) { + grab_x = x; + grab_window = window; + return TRUE; + } + + delta = x - grab_x; + grab_x = x; + + switch (_style) { + case Line: + case LeftToRight: + fract = scaling * (delta / (darea.get_width() - 2)); + fract = min (1.0, fract); + fract = max (-1.0, fract); + adjustment.set_value (adjustment.get_value() + fract * (adjustment.get_upper() - adjustment.get_lower())); + break; + + default: + fract = 0.0; + } + + + return TRUE; +} + +bool +BarController::expose (GdkEventExpose* event) +{ + Glib::RefPtr<Gdk::Window> win (darea.get_window()); + Widget* parent; + gint x1=0, x2=0, y1=0, y2=0; + gint w, h; + double fract; + + fract = ((adjustment.get_value() - adjustment.get_lower()) / + (adjustment.get_upper() - adjustment.get_lower())); + + switch (_style) { + case Line: + w = darea.get_width() - 1; + h = darea.get_height(); + x1 = (gint) floor (w * fract); + x2 = x1; + y1 = 0; + y2 = h - 1; + + if (use_parent) { + parent = get_parent(); + + if (parent) { + win->draw_rectangle (parent->get_style()->get_fg_gc (parent->get_state()), + true, + 0, 0, darea.get_width(), darea.get_height()); + } + + } else { + + win->draw_rectangle (get_style()->get_bg_gc (get_state()), + true, + 0, 0, darea.get_width() - ((darea.get_width()+1) % 2), darea.get_height()); + } + + win->draw_line (get_style()->get_fg_gc (get_state()), x1, 0, x1, h); + break; + + case CenterOut: + break; + + case LeftToRight: + + w = darea.get_width() - 2; + h = darea.get_height() - 2; + + x1 = 0; + x2 = (gint) floor (w * fract); + y1 = 0; + y2 = h - 1; + + win->draw_rectangle (get_style()->get_bg_gc (get_state()), + false, + 0, 0, darea.get_width() - 1, darea.get_height() - 1); + + /* draw active box */ + + win->draw_rectangle (get_style()->get_fg_gc (get_state()), + true, + 1 + x1, + 1 + y1, + x2, + 1 + y2); + + /* draw inactive box */ + + win->draw_rectangle (get_style()->get_fg_gc (STATE_INSENSITIVE), + true, + 1 + x2, + 1 + y1, + w - x2, + 1 + y2); + + break; + + case RightToLeft: + break; + case TopToBottom: + break; + case BottomToTop: + break; + } + + if (with_text) { + /* draw label */ + + char buf[64]; + buf[0] = '\0'; + + if (label_callback) + label_callback (buf, 64); + + if (buf[0] != '\0') { + + layout->set_text (buf); + + int width, height; + layout->get_pixel_size (width, height); + + int xpos; + + xpos = max (3, 1 + (x2 - (width/2))); + xpos = min (darea.get_width() - width - 3, xpos); + + win->draw_layout (get_style()->get_text_gc (get_state()), + xpos, + (darea.get_height()/2) - (height/2), + layout); + } + } + + return true; +} + +void +BarController::set_with_text (bool yn) +{ + if (with_text != yn) { + with_text = yn; + queue_draw (); + } +} + +void +BarController::set_style (Style s) +{ + _style = s; + darea.queue_draw (); +} + +gint +BarController::switch_to_bar () +{ + if (switching) { + return FALSE; + } + + switching = true; + + if (get_child() == &darea) { + return FALSE; + } + + remove (); + add (darea); + darea.show (); + + switching = false; + return FALSE; +} + +gint +BarController::switch_to_spinner () +{ + if (switching) { + return FALSE; + } + + switching = true; + + if (get_child() == &spinner) { + return FALSE; + } + + remove (); + add (spinner); + spinner.show (); + spinner.select_region (0, spinner.get_text_length()); + spinner.grab_focus (); + + switching = false; + return FALSE; +} + +void +BarController::entry_activated () +{ + string text = spinner.get_text (); + float val; + + if (sscanf (text.c_str(), "%f", &val) == 1) { + adjustment.set_value (val); + } + + switch_to_bar (); +} + +bool +BarController::entry_focus_out (GdkEventFocus* ev) +{ + entry_activated (); + return true; +} + +void +BarController::set_use_parent (bool yn) +{ + use_parent = yn; + queue_draw (); +} + +void +BarController::set_sensitive (bool yn) +{ + Frame::set_sensitive (yn); + darea.set_sensitive (yn); +} diff --git a/libs/gtkmm2ext/bindable_button.cc b/libs/gtkmm2ext/bindable_button.cc new file mode 100644 index 0000000000..3c3cad6e46 --- /dev/null +++ b/libs/gtkmm2ext/bindable_button.cc @@ -0,0 +1,139 @@ +/* + Copyright (C) 2004 Paul Davis + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + $Id$ +*/ + +#include <string> +#include <climits> +#include <iostream> + +#include <midi++/controllable.h> + +#include <gtkmm2ext/gtk_ui.h> +#include <gtkmm2ext/bindable_button.h> + +#include "i18n.h" + +using namespace Gtkmm2ext; +using namespace std; + +BindableToggleButton::BindableToggleButton (MIDI::Controllable *mc) + : prompter (Gtk::WIN_POS_MOUSE, 30000, false), + midi_control (mc), + bind_button (2), + bind_statemask (Gdk::CONTROL_MASK) + +{ + init_events (); +} + +BindableToggleButton::BindableToggleButton(MIDI::Controllable *mc, const string &label) + : StatefulButton (label), + prompter (Gtk::WIN_POS_MOUSE, 30000, false), + midi_control (mc), + bind_button (2), + bind_statemask (Gdk::CONTROL_MASK) +{ + init_events (); +} + + +void +BindableToggleButton::init_events () +{ + prompter.signal_unmap_event().connect (mem_fun (*this, &BindableToggleButton::prompter_hiding)); + + prompting = false; + unprompting = false; + + if (midi_control) { + midi_control->learning_started.connect (mem_fun (*this, &BindableToggleButton::midicontrol_prompt)); + midi_control->learning_stopped.connect (mem_fun (*this, &BindableToggleButton::midicontrol_unprompt)); + } +} + +void +BindableToggleButton::set_bind_button_state (guint button, guint statemask) +{ + bind_button = button; + bind_statemask = statemask; +} + +void +BindableToggleButton::get_bind_button_state (guint &button, guint &statemask) +{ + button = bind_button; + statemask = bind_statemask; +} + +void +BindableToggleButton::midi_learn() +{ + if (midi_control) { + prompting = true; + midi_control->learn_about_external_control (); + } +} + +bool +BindableToggleButton::prompter_hiding (GdkEventAny *ev) +{ + if (unprompting) { + if (midi_control) { + midi_control->stop_learning(); + } + unprompting = false; + } + + return false; +} + + +void +BindableToggleButton::midicontrol_set_tip () + +{ + if (midi_control) { + // Gtkmm2ext::UI::instance()->set_tip (evbox, midi_control->control_description()); + } +} + +void +BindableToggleButton::midicontrol_prompt () + +{ + if (prompting) { + string prompt = _("operate MIDI controller now"); + prompter.set_text (prompt); + Gtkmm2ext::UI::instance()->touch_display (&prompter); + + unprompting = true; + prompting = false; + } +} + +void +BindableToggleButton::midicontrol_unprompt () + +{ + if (unprompting) { + Gtkmm2ext::UI::instance()->touch_display (&prompter); + unprompting = false; + } +} + + diff --git a/libs/gtkmm2ext/binding_proxy.cc b/libs/gtkmm2ext/binding_proxy.cc new file mode 100644 index 0000000000..90f95f82ef --- /dev/null +++ b/libs/gtkmm2ext/binding_proxy.cc @@ -0,0 +1,101 @@ +/* + Copyright (C) 2006 Paul Davis + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + $Id$ +*/ + +#include <string> +#include <climits> +#include <iostream> + +#include <pbd/controllable.h> + +#include <gtkmm2ext/binding_proxy.h> + +#include "i18n.h" + +using namespace Gtkmm2ext; +using namespace std; +using namespace PBD; + +BindingProxy::BindingProxy (Controllable& c) + : prompter (0), + controllable (c), + bind_button (2), + bind_statemask (Gdk::CONTROL_MASK) + +{ +} + +BindingProxy::~BindingProxy () +{ + if (prompter) { + delete prompter; + } +} + +void +BindingProxy::set_bind_button_state (guint button, guint statemask) +{ + bind_button = button; + bind_statemask = statemask; +} + +void +BindingProxy::get_bind_button_state (guint &button, guint &statemask) +{ + button = bind_button; + statemask = bind_statemask; +} + +bool +BindingProxy::button_press_handler (GdkEventButton *ev) +{ + if ((ev->state & bind_statemask) && ev->button == bind_button) { + if (Controllable::StartLearning (&controllable)) { + string prompt = _("operate controller now"); + if (prompter == 0) { + prompter = new PopUp (Gtk::WIN_POS_MOUSE, 30000, false); + prompter->signal_unmap_event().connect (mem_fun (*this, &BindingProxy::prompter_hiding)); + } + prompter->set_text (prompt); + prompter->touch (); // shows popup + learning_connection = controllable.LearningFinished.connect (mem_fun (*this, &BindingProxy::learning_finished)); + } + return true; + } + + return false; +} + +void +BindingProxy::learning_finished () +{ + learning_connection.disconnect (); + if (prompter) { + prompter->touch (); // hides popup + } +} + + +bool +BindingProxy::prompter_hiding (GdkEventAny *ev) +{ + learning_connection.disconnect (); + Controllable::StopLearning (&controllable); + return false; +} + diff --git a/libs/gtkmm2ext/choice.cc b/libs/gtkmm2ext/choice.cc new file mode 100644 index 0000000000..7f5f869ada --- /dev/null +++ b/libs/gtkmm2ext/choice.cc @@ -0,0 +1,70 @@ +/* + Copyright (C) 1998-99 Paul Barton-Davis + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + $Id$ +*/ + +#include <gtkmm/label.h> +#include <gtkmm2ext/choice.h> + +using namespace std; +using namespace Gtkmm2ext; +using namespace sigc; +using namespace Gtk; + +Choice::Choice (string prompt, vector<string> choices, bool center) +{ + int n; + vector<string>::iterator i; + + if (center) { + set_position (Gtk::WIN_POS_CENTER); + } else { + set_position (Gtk::WIN_POS_MOUSE); + } + + set_name ("ChoiceWindow"); + + HBox* dhbox = manage (new HBox()); + Image* dimage = manage (new Gtk::Image(Stock::DIALOG_QUESTION, Gtk::ICON_SIZE_DIALOG)); + Label* label = manage (new Label (prompt)); + + dhbox->pack_start (*dimage, true, false, 10); + dhbox->pack_start (*label, true, false, 10); + + get_vbox()->set_border_width (12); + get_vbox()->pack_start (*dhbox, true, false); + + set_has_separator (false); + set_resizable (false); + show_all_children (); + + for (n = 0, i = choices.begin(); i != choices.end(); ++i, ++n) { + add_button (*i, n); + } +} + +void +Choice::on_realize () +{ + Gtk::Window::on_realize(); + get_window()->set_decorations (Gdk::WMDecoration (Gdk::DECOR_BORDER|Gdk::DECOR_RESIZEH)); +} + +Choice::~Choice () +{ +} diff --git a/libs/gtkmm2ext/click_box.cc b/libs/gtkmm2ext/click_box.cc new file mode 100644 index 0000000000..3ab7ea883c --- /dev/null +++ b/libs/gtkmm2ext/click_box.cc @@ -0,0 +1,153 @@ +/* + Copyright (C) 1999 Paul Barton-Davis + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + $Id$ +*/ + +#include <iostream> +#include <cstdio> /* for sprintf, sigh ... */ + +#include <gtkmm2ext/utils.h> +#include <gtkmm2ext/click_box.h> + +using namespace std; +using namespace Gtk; +using namespace Gtkmm2ext; +using namespace sigc; + +ClickBox::ClickBox (Gtk::Adjustment *adjp, const string &name, bool round_to_steps) + : AutoSpin (*adjp,0,round_to_steps) +{ + print_func = default_printer; + print_arg = 0; + layout = create_pango_layout (""); + twidth = 0; + theight = 0; + + + add_events (Gdk::BUTTON_RELEASE_MASK| + Gdk::BUTTON_PRESS_MASK| + Gdk::ENTER_NOTIFY_MASK| + Gdk::LEAVE_NOTIFY_MASK); + + get_adjustment().signal_value_changed().connect (mem_fun (*this, &ClickBox::set_label)); + signal_style_changed().connect (mem_fun (*this, &ClickBox::style_changed)); + signal_button_press_event().connect (mem_fun (*this, &ClickBox::button_press_handler)); + signal_button_release_event().connect (mem_fun (*this, &ClickBox::button_release_handler)); + set_name (name); + set_label (); +} + +ClickBox::~ClickBox () +{ +} + +bool +ClickBox::button_press_handler (GdkEventButton* ev) +{ + add_modal_grab(); + AutoSpin::button_press (ev); + return true; +} + +bool +ClickBox::button_release_handler (GdkEventButton* ev) +{ + switch (ev->button) { + case 1: + case 2: + case 3: + stop_spinning (0); + default: + remove_modal_grab(); + break; + } + return true; +} + +void +ClickBox::default_printer (char buf[32], Gtk::Adjustment &adj, + void *ignored) +{ + sprintf (buf, "%.2f", adj.get_value()); +} + +void +ClickBox::set_label () +{ + if (!print_func) { + return; + } + + char buf[32]; + + print_func (buf, get_adjustment(), print_arg); + + layout->set_text (buf); + layout->get_pixel_size (twidth, theight); + + queue_draw (); +} + +void +ClickBox::style_changed (const Glib::RefPtr<Gtk::Style>& ignored) +{ + + layout->context_changed (); + layout->get_pixel_size (twidth, theight); +} + +bool +ClickBox::on_expose_event (GdkEventExpose *ev) +{ + /* Why do we do things like this rather than use a Gtk::Label? + Because whenever Gtk::Label::set_label() is called, it + triggers a recomputation of its own size, along with that + of its container and on up the tree. That's intended + to be unnecessary here. + */ + + Gtk::DrawingArea::on_expose_event (ev); + + if (print_func) { + + Glib::RefPtr<Gtk::Style> style (get_style()); + Glib::RefPtr<Gdk::GC> fg_gc (style->get_fg_gc (Gtk::STATE_NORMAL)); + Glib::RefPtr<Gdk::GC> bg_gc (style->get_bg_gc (Gtk::STATE_NORMAL)); + Glib::RefPtr<Gdk::Window> win (get_window()); + + GdkRectangle base_rect; + GdkRectangle draw_rect; + gint x, y, width, height, depth; + + win->get_geometry (x, y, width, height, depth); + + base_rect.width = width; + base_rect.height = height; + base_rect.x = 0; + base_rect.y = 0; + + gdk_rectangle_intersect (&ev->area, &base_rect, &draw_rect); + win->draw_rectangle (bg_gc, true, draw_rect.x, draw_rect.y, draw_rect.width, draw_rect.height); + + if (twidth && theight) { + win->draw_layout (fg_gc, (width - twidth) / 2, (height - theight) / 2, layout); + } + } + + return true; +} diff --git a/libs/gtkmm2ext/dndtreeview.cc b/libs/gtkmm2ext/dndtreeview.cc new file mode 100644 index 0000000000..2c2e69f6b6 --- /dev/null +++ b/libs/gtkmm2ext/dndtreeview.cc @@ -0,0 +1,71 @@ +/* + Copyright (C) 2000-2007 Paul Davis + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#include <cstdio> +#include <iostream> + +#include <gtkmm2ext/dndtreeview.h> + +using namespace std; +using namespace sigc; +using namespace Gdk; +using namespace Gtk; +using namespace Glib; +using namespace Gtkmm2ext; + +DnDTreeViewBase::DnDTreeViewBase () + : TreeView () +{ + draggable.push_back (TargetEntry ("GTK_TREE_MODEL_ROW", TARGET_SAME_WIDGET)); + data_column = -1; + + enable_model_drag_source (draggable); + enable_model_drag_dest (draggable); + + suggested_action = Gdk::DragAction (0); +} + +void +DnDTreeViewBase::add_drop_targets (list<TargetEntry>& targets) +{ + for (list<TargetEntry>::iterator i = targets.begin(); i != targets.end(); ++i) { + draggable.push_back (*i); + } + enable_model_drag_source (draggable); + enable_model_drag_dest (draggable); +} + +void +DnDTreeViewBase::add_object_drag (int column, string type_name) +{ + draggable.push_back (TargetEntry (type_name, TargetFlags(0))); + data_column = column; + + enable_model_drag_source (draggable); + enable_model_drag_dest (draggable); +} + +bool +DnDTreeViewBase::on_drag_drop(const Glib::RefPtr<Gdk::DragContext>& context, int x, int y, guint time) +{ + suggested_action = Gdk::DragAction (0); + return TreeView::on_drag_drop (context, x, y, time); +} + + diff --git a/libs/gtkmm2ext/fastmeter.cc b/libs/gtkmm2ext/fastmeter.cc new file mode 100644 index 0000000000..63c36558f1 --- /dev/null +++ b/libs/gtkmm2ext/fastmeter.cc @@ -0,0 +1,567 @@ +/* + Copyright (C) 2003-2006 Paul Davis + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + $Id$ +*/ + +#include <iostream> +#include <cmath> +#include <algorithm> +#include <gdkmm/rectangle.h> +#include <gtkmm2ext/fastmeter.h> +#include <gtkmm2ext/utils.h> +#include <gtkmm/style.h> +#include <string.h> + +#define UINT_TO_RGB(u,r,g,b) { (*(r)) = ((u)>>16)&0xff; (*(g)) = ((u)>>8)&0xff; (*(b)) = (u)&0xff; } +#define UINT_TO_RGBA(u,r,g,b,a) { UINT_TO_RGB(((u)>>8),r,g,b); (*(a)) = (u)&0xff; } +using namespace Gtk; +using namespace Gdk; +using namespace Glib; +using namespace Gtkmm2ext; +using namespace std; + + +int FastMeter::min_v_pixbuf_size = 10; +int FastMeter::max_v_pixbuf_size = 1024; +Glib::RefPtr<Gdk::Pixbuf>* FastMeter::v_pixbuf_cache = 0; + +int FastMeter::min_h_pixbuf_size = 10; +int FastMeter::max_h_pixbuf_size = 1024; +Glib::RefPtr<Gdk::Pixbuf>* FastMeter::h_pixbuf_cache = 0; + +int FastMeter::_clr0 = 0; +int FastMeter::_clr1 = 0; +int FastMeter::_clr2 = 0; +int FastMeter::_clr3 = 0; + +FastMeter::FastMeter (long hold, unsigned long dimen, Orientation o, int len, int clr0, int clr1, int clr2, int clr3) +{ + orientation = o; + hold_cnt = hold; + hold_state = 0; + current_peak = 0; + current_level = 0; + last_peak_rect.width = 0; + last_peak_rect.height = 0; + _clr0 = clr0; + _clr1 = clr1; + _clr2 = clr2; + _clr3 = clr3; + + set_events (BUTTON_PRESS_MASK|BUTTON_RELEASE_MASK); + + pixrect.x = 0; + pixrect.y = 0; + + if (orientation == Vertical) { + if (!len) + len = 250; + pixbuf = request_vertical_meter(dimen, len); + } else { + if (!len) + len = 186; + pixbuf = request_horizontal_meter(len, dimen); + } + + pixheight = pixbuf->get_height(); + pixwidth = pixbuf->get_width(); + + if (orientation == Vertical) { + pixrect.width = min (pixwidth, (gint) dimen); + pixrect.height = pixheight; + } else { + pixrect.width = pixwidth; + pixrect.height = min (pixheight, (gint) dimen); + } + + request_width = pixrect.width; + request_height= pixrect.height; +} + +Glib::RefPtr<Gdk::Pixbuf> FastMeter::request_vertical_meter(int width, int height) +{ + if (height < min_v_pixbuf_size) + height = min_v_pixbuf_size; + if (height > max_v_pixbuf_size) + height = max_v_pixbuf_size; + + //int index = height - 1; + + //if (v_pixbuf_cache == 0) { + // v_pixbuf_cache = (Glib::RefPtr<Gdk::Pixbuf>*) malloc(sizeof(Glib::RefPtr<Gdk::Pixbuf>) * max_v_pixbuf_size); + // memset(v_pixbuf_cache,0,sizeof(Glib::RefPtr<Gdk::Pixbuf>) * max_v_pixbuf_size); + //} + Glib::RefPtr<Gdk::Pixbuf> ret;// = v_pixbuf_cache[index]; + //if (ret) + // return ret; + + guint8* data; + + data = (guint8*) malloc(width*height * 3); + + guint8 r,g,b,r0,g0,b0,r1,g1,b1,r2,g2,b2,r3,g3,b3,a; + + UINT_TO_RGBA (_clr0, &r0, &g0, &b0, &a); + UINT_TO_RGBA (_clr1, &r1, &g1, &b1, &a); + UINT_TO_RGBA (_clr2, &r2, &g2, &b2, &a); + UINT_TO_RGBA (_clr3, &r3, &g3, &b3, &a); + // fake log calculation copied from log_meter.h + // actual calculation: + // log_meter(0.0f) = + // def = (0.0f + 20.0f) * 2.5f + 50f + // return def / 115.0f + int knee = (int)floor((float)height * 100.0f / 115.0f); + int y; + + for (y = 0; y < knee/2; y++) { + + r = (guint8)floor((float)abs(r1 - r0) * (float)y / (float)(knee/2)); + (r0 >= r1) ? r = r0 - r : r += r0; + + g = (guint8)floor((float)abs(g1 - g0) * (float)y / (float)(knee/2)); + (g0 >= g1) ? g = g0 - g : g += g0; + + b = (guint8)floor((float)abs(b1 - b0) * (float)y / (float)(knee/2)); + (b0 >= b1) ? b = b0 - b : b += b0; + + for (int x = 0; x < width; x++) { + data[ (x+(height-y-1)*width) * 3 + 0 ] = r; + data[ (x+(height-y-1)*width) * 3 + 1 ] = g; + data[ (x+(height-y-1)*width) * 3 + 2 ] = b; + } + } + + int offset = knee - y; + for (int i=0; i < offset; i++,y++) { + + r = (guint8)floor((float)abs(r2 - r1) * (float)i / (float)offset); + (r1 >= r2) ? r = r1 - r : r += r1; + + g = (guint8)floor((float)abs(g2 - g1) * (float)i / (float)offset); + (g1 >= g2) ? g = g1 - g : g += g1; + + b = (guint8)floor((float)abs(b2 - b1) * (float)i / (float)offset); + (b1 >= b2) ? b = b1 - b : b += b1; + + for (int x = 0; x < width; x++) { + data[ (x+(height-y-1)*width) * 3 + 0 ] = r; + data[ (x+(height-y-1)*width) * 3 + 1 ] = g; + data[ (x+(height-y-1)*width) * 3 + 2 ] = b; + } + } + y--; + for (; y < height; y++) { + for (int x = 0; x < width; x++) { + data[ (x+(height-y-1)*width) * 3 + 0 ] = r3; + data[ (x+(height-y-1)*width) * 3 + 1 ] = g3; + data[ (x+(height-y-1)*width) * 3 + 2 ] = b3; + } + } + + ret = Pixbuf::create_from_data(data, COLORSPACE_RGB, false, 8, width, height, width * 3); + //v_pixbuf_cache[index] = ret; + + return ret; +} + +Glib::RefPtr<Gdk::Pixbuf> FastMeter::request_horizontal_meter(int width, int height) +{ + if (width < min_h_pixbuf_size) + width = min_h_pixbuf_size; + if (width > max_h_pixbuf_size) + width = max_h_pixbuf_size; + + int index = width - 1; + + if (h_pixbuf_cache == 0) { + h_pixbuf_cache = (Glib::RefPtr<Gdk::Pixbuf>*) malloc(sizeof(Glib::RefPtr<Gdk::Pixbuf>) * max_h_pixbuf_size); + memset(h_pixbuf_cache,0,sizeof(Glib::RefPtr<Gdk::Pixbuf>) * max_h_pixbuf_size); + } + Glib::RefPtr<Gdk::Pixbuf> ret = h_pixbuf_cache[index]; + if (ret) + return ret; + + guint8* data; + + data = (guint8*) malloc(width*height * 3); + + guint8 r,g,b; + r=0; + g=255; + b=0; + + // fake log calculation copied from log_meter.h + // actual calculation: + // log_meter(0.0f) = + // def = (0.0f + 20.0f) * 2.5f + 50f + // return def / 115.0f + int knee = (int)floor((float)width * 100.0f / 115.0f); + + int x; + + for (x = 0; x < knee / 2; x++) { + + r = (guint8)floor(255.0 * (float)x/(float)(knee / 2)); + + for (int y = 0; y < height; y++) { + data[ (x+(height-y-1)*width) * 3 + 0 ] = r; + data[ (x+(height-y-1)*width) * 3 + 1 ] = g; + data[ (x+(height-y-1)*width) * 3 + 2 ] = b; + } + } + + for (; x < knee; x++) { + + g = 255 - (guint8)floor(170.0 * (float)(x - knee/ 2)/(float)(knee / 2)); + + for (int y = 0; y < height; y++) { + data[ (x+(height-y-1)*width) * 3 + 0 ] = r; + data[ (x+(height-y-1)*width) * 3 + 1 ] = g; + data[ (x+(height-y-1)*width) * 3 + 2 ] = b; + } + } + + r=255; + g=0; + b=0; + for (; x < width; x++) { + for (int y = 0; y < height; y++) { + data[ (x+(height-y-1)*width) * 3 + 0 ] = r; + data[ (x+(height-y-1)*width) * 3 + 1 ] = g; + data[ (x+(height-y-1)*width) * 3 + 2 ] = b; + } + } + + ret = Pixbuf::create_from_data(data, COLORSPACE_RGB, false, 8, width, height, width * 3); + h_pixbuf_cache[index] = ret; + + return ret; +} + +FastMeter::~FastMeter () +{ +} + +void +FastMeter::set_hold_count (long val) +{ + if (val < 1) { + val = 1; + } + + hold_cnt = val; + hold_state = 0; + current_peak = 0; + + queue_draw (); +} + +void +FastMeter::on_size_request (GtkRequisition* req) +{ + if (orientation == Vertical) { + + req->height = request_height; + req->height = max(req->height, min_v_pixbuf_size); + req->height = min(req->height, max_v_pixbuf_size); + + req->width = request_width; + + } else { + + req->width = request_width; + req->width = max(req->width, min_h_pixbuf_size); + req->width = min(req->width, max_h_pixbuf_size); + + req->height = request_height; + } + +} + +void +FastMeter::on_size_allocate (Gtk::Allocation &alloc) +{ + if (orientation == Vertical) { + + if (alloc.get_width() != request_width) { + alloc.set_width (request_width); + } + + int h = alloc.get_height(); + h = max(h, min_v_pixbuf_size); + h = min(h, max_v_pixbuf_size); + + if ( h != alloc.get_height()) + alloc.set_height(h); + + if (pixheight != h) { + pixbuf = request_vertical_meter(request_width, h); + } + + } else { + + if (alloc.get_height() != request_height) { + alloc.set_height(request_height); + } + + int w = alloc.get_width(); + w = max(w, min_h_pixbuf_size); + w = min(w, max_h_pixbuf_size); + + if ( w != alloc.get_width()) + alloc.set_width(w); + + if (pixwidth != w) { + pixbuf = request_horizontal_meter(w, request_height); + } + } + + pixheight = pixbuf->get_height(); + pixwidth = pixbuf->get_width(); + + DrawingArea::on_size_allocate(alloc); +} + +bool +FastMeter::on_expose_event (GdkEventExpose* ev) +{ + if (orientation == Vertical) { + return vertical_expose (ev); + } else { + return horizontal_expose (ev); + } +} + +bool +FastMeter::vertical_expose (GdkEventExpose* ev) +{ + gint top_of_meter; + GdkRectangle intersection; + GdkRectangle background; + + top_of_meter = (gint) floor (pixheight * current_level); + + /* reset the height & origin of the rect that needs to show the pixbuf + */ + + pixrect.height = top_of_meter; + pixrect.y = pixheight - top_of_meter; + + background.x = 0; + background.y = 0; + background.width = pixrect.width; + background.height = pixheight - top_of_meter; + + if (gdk_rectangle_intersect (&background, &ev->area, &intersection)) { + get_window()->draw_rectangle (get_style()->get_black_gc(), true, + intersection.x, intersection.y, + intersection.width, intersection.height); + } + + if (gdk_rectangle_intersect (&pixrect, &ev->area, &intersection)) { + // draw the part of the meter image that we need. the area we draw is bounded "in reverse" (top->bottom) + get_window()->draw_pixbuf(get_style()->get_fg_gc(get_state()), pixbuf, + intersection.x, intersection.y, + intersection.x, intersection.y, + intersection.width, intersection.height, + Gdk::RGB_DITHER_NONE, 0, 0); + } + + // draw peak bar + + if (hold_state) { + last_peak_rect.x = 0; + last_peak_rect.width = pixwidth; + last_peak_rect.y = pixheight - (gint) floor (pixheight * current_peak); + last_peak_rect.height = min(3, pixheight - last_peak_rect.y); + + get_window()->draw_pixbuf (get_style()->get_fg_gc(get_state()), pixbuf, + 0, last_peak_rect.y, + 0, last_peak_rect.y, + pixwidth, last_peak_rect.height, + Gdk::RGB_DITHER_NONE, 0, 0); + } else { + last_peak_rect.width = 0; + last_peak_rect.height = 0; + } + + return TRUE; +} + +bool +FastMeter::horizontal_expose (GdkEventExpose* ev) +{ + gint right_of_meter; + GdkRectangle intersection; + GdkRectangle background; + + right_of_meter = (gint) floor (pixwidth * current_level); + pixrect.width = right_of_meter; + + background.x = 0; + background.y = 0; + background.width = pixwidth - right_of_meter; + background.height = pixrect.height; + + if (gdk_rectangle_intersect (&background, &ev->area, &intersection)) { + get_window()->draw_rectangle (get_style()->get_black_gc(), true, + intersection.x + right_of_meter, intersection.y, + intersection.width, intersection.height); + } + + if (gdk_rectangle_intersect (&pixrect, &ev->area, &intersection)) { + // draw the part of the meter image that we need. the area we draw is bounded "in reverse" (top->bottom) + get_window()->draw_pixbuf(get_style()->get_fg_gc(get_state()), pixbuf, + intersection.x, intersection.y, + intersection.x, intersection.y, + pixrect.width, intersection.height, + Gdk::RGB_DITHER_NONE, 0, 0); + } + + // draw peak bar + // XXX: peaks don't work properly + /* + if (hold_state && intersection.height > 0) { + gint x = (gint) floor(pixwidth * current_peak); + + get_window()->draw_pixbuf (get_style()->get_fg_gc(get_state()), pixbuf, + x, intersection.y, + x, intersection.y, + 3, intersection.height, + Gdk::RGB_DITHER_NONE, 0, 0); + } + */ + + return true; +} + +void +FastMeter::set (float lvl) +{ + float old_level = current_level; + float old_peak = current_peak; + + current_level = lvl; + + if (lvl > current_peak) { + current_peak = lvl; + hold_state = hold_cnt; + } + + if (hold_state > 0) { + if (--hold_state == 0) { + current_peak = lvl; + } + } + + if (current_level == old_level && current_peak == old_peak && hold_state == 0) { + return; + } + + + Glib::RefPtr<Gdk::Window> win; + + if ((win = get_window()) == 0) { + queue_draw (); + return; + } + + if (orientation == Vertical) { + queue_vertical_redraw (win, old_level); + } else { + queue_horizontal_redraw (win, old_level); + } +} + +void +FastMeter::queue_vertical_redraw (const Glib::RefPtr<Gdk::Window>& win, float old_level) +{ + GdkRectangle rect; + + gint new_top = (gint) floor (pixheight * current_level); + + rect.x = 0; + rect.width = pixwidth; + rect.height = new_top; + rect.y = pixheight - new_top; + + if (current_level > old_level) { + /* colored/pixbuf got larger, just draw the new section */ + /* rect.y stays where it is because of X coordinates */ + /* height of invalidated area is between new.y (smaller) and old.y + (larger). + X coordinates just make my brain hurt. + */ + rect.height = pixrect.y - rect.y; + } else { + /* it got smaller, compute the difference */ + /* rect.y becomes old.y (the smaller value) */ + rect.y = pixrect.y; + /* rect.height is the old.y (smaller) minus the new.y (larger) + */ + rect.height = pixrect.height - rect.height; + } + + GdkRegion* region = 0; + bool queue = false; + + if (rect.height != 0) { + + /* ok, first region to draw ... */ + + region = gdk_region_rectangle (&rect); + queue = true; + } + + /* redraw the last place where the last peak hold bar was; + the next expose will draw the new one whether its part of + expose region or not. + */ + + if (last_peak_rect.width * last_peak_rect.height != 0) { + if (!queue) { + region = gdk_region_new (); + queue = true; + } + gdk_region_union_with_rect (region, &last_peak_rect); + } + + if (queue) { + gdk_window_invalidate_region (win->gobj(), region, true); + } + if (region) { + gdk_region_destroy(region); + region = 0; + } +} + +void +FastMeter::queue_horizontal_redraw (const Glib::RefPtr<Gdk::Window>& win, float old_level) +{ + /* XXX OPTIMIZE (when we have some horizontal meters) */ + queue_draw (); +} + +void +FastMeter::clear () +{ + current_level = 0; + current_peak = 0; + hold_state = 0; + queue_draw (); +} diff --git a/libs/gtkmm2ext/focus_entry.cc b/libs/gtkmm2ext/focus_entry.cc new file mode 100644 index 0000000000..706fc28e2f --- /dev/null +++ b/libs/gtkmm2ext/focus_entry.cc @@ -0,0 +1,50 @@ +/* + Copyright (C) 2000-2007 Paul Davis + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#include <gtkmm2ext/focus_entry.h> + +using namespace Gtkmm2ext; + +FocusEntry::FocusEntry () +{ + next_release_selects = false; +} + +bool +FocusEntry::on_button_press_event (GdkEventButton* ev) +{ + if (!has_focus()) { + next_release_selects = true; + } + return Entry::on_button_press_event (ev); +} + +bool +FocusEntry::on_button_release_event (GdkEventButton* ev) +{ + if (next_release_selects) { + bool ret = Entry::on_button_release_event (ev); + select_region (0, -1); + next_release_selects = false; + return ret; + } + + return Entry::on_button_release_event (ev); +} + diff --git a/libs/gtkmm2ext/gettext.h b/libs/gtkmm2ext/gettext.h new file mode 100644 index 0000000000..339c74ffe7 --- /dev/null +++ b/libs/gtkmm2ext/gettext.h @@ -0,0 +1,82 @@ +/* Convenience header for conditional use of GNU <libintl.h>. + Copyright (C) 1995-1998, 2000-2002 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published + by the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + USA. */ + +#ifndef _LIBGETTEXT_H +#define _LIBGETTEXT_H 1 + +/* NLS can be disabled through the configure --disable-nls option. */ +#if ENABLE_NLS + +/* Get declarations of GNU message catalog functions. */ +# include <libintl.h> + +#else + +/* Solaris /usr/include/locale.h includes /usr/include/libintl.h, which + chokes if dcgettext is defined as a macro. So include it now, to make + later inclusions of <locale.h> a NOP. We don't include <libintl.h> + as well because people using "gettext.h" will not include <libintl.h>, + and also including <libintl.h> would fail on SunOS 4, whereas <locale.h> + is OK. */ +#if defined(__sun) +# include <locale.h> +#endif + +/* Disabled NLS. + The casts to 'const char *' serve the purpose of producing warnings + for invalid uses of the value returned from these functions. + On pre-ANSI systems without 'const', the config.h file is supposed to + contain "#define const". */ + +/* other headers may have included libintl.h */ + +# undef gettext +# undef dgettext +# undef dcgettext +# undef ngettext +# undef dngettext +# undef dcngettext +# undef textdomain +# undef bindtextdomain +# undef bind_textdomain_codeset + +# define gettext(Msgid) ((const char *) (Msgid)) +# define dgettext(Domainname, Msgid) ((const char *) (Msgid)) +# define dcgettext(Domainname, Msgid, Category) ((const char *) (Msgid)) +# define ngettext(Msgid1, Msgid2, N) \ + ((N) == 1 ? (const char *) (Msgid1) : (const char *) (Msgid2)) +# define dngettext(Domainname, Msgid1, Msgid2, N) \ + ((N) == 1 ? (const char *) (Msgid1) : (const char *) (Msgid2)) +# define dcngettext(Domainname, Msgid1, Msgid2, N, Category) \ + ((N) == 1 ? (const char *) (Msgid1) : (const char *) (Msgid2)) +# define textdomain(Domainname) ((const char *) (Domainname)) +# define bindtextdomain(Domainname, Dirname) ((const char *) (Dirname)) +# define bind_textdomain_codeset(Domainname, Codeset) ((const char *) (Codeset)) + +#endif + +/* A pseudo function call that serves as a marker for the automated + extraction of messages, but does not call gettext(). The run-time + translation is done at a different place in the code. + The argument, String, should be a literal string. Concatenated strings + and other string expressions won't work. + The macro's expansion is not parenthesized, so that it is suitable as + initializer for static 'char[]' or 'const char[]' variables. */ +#define gettext_noop(String) String + +#endif /* _LIBGETTEXT_H */ diff --git a/libs/gtkmm2ext/grouped_buttons.cc b/libs/gtkmm2ext/grouped_buttons.cc new file mode 100644 index 0000000000..b16b983d02 --- /dev/null +++ b/libs/gtkmm2ext/grouped_buttons.cc @@ -0,0 +1,96 @@ +/* + Copyright (C) 2001 Paul Davis + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + $Id$ +*/ + +#include <gtkmm.h> + +#include <gtkmm2ext/grouped_buttons.h> + +using namespace std; + +GroupedButtons::GroupedButtons (vector<Gtk::ToggleButton *>& buttonset) +{ + uint32_t n = 0; + + buttons = buttonset; + + for (vector<Gtk::ToggleButton *>::iterator i = buttons.begin(); i != buttons.end(); ++i, ++n) { + if ((*i)->get_active()) { + current_active = n; + } + (*i)->signal_clicked().connect (sigc::bind (mem_fun (*this, &GroupedButtons::one_clicked), n)); + } +} + +GroupedButtons::GroupedButtons (uint32_t nbuttons, uint32_t first_active) +{ + buttons.reserve (nbuttons); + current_active = first_active; + + for (uint32_t n = 0; n < nbuttons; ++n) { + + Gtk::ToggleButton *button; + + button = manage (new (Gtk::ToggleButton)); + + if (n == current_active) { + button->set_active (true); + } + + button->signal_clicked().connect (sigc::bind (mem_fun (*this, &GroupedButtons::one_clicked), n)); + buttons.push_back (button); + } +} + +static gint +reactivate_button (void *arg) +{ + Gtk::ToggleButton *b = (Gtk::ToggleButton *) arg; + b->set_active (true); + return FALSE; +} + +void +GroupedButtons::one_clicked (uint32_t which) +{ + if (buttons[which]->get_active()) { + + if (which != current_active) { + uint32_t old = current_active; + current_active = which; + buttons[old]->set_active (false); + } + + } else if (which == current_active) { + + /* Someobody tried to unset the current active + button by clicking on it. This caused + set_active (false) to be called. We don't + allow that, so just reactivate it. + + Don't try this right here, because of some + design glitches with GTK+ toggle buttons. + Setting the button back to active from + within the signal emission that marked + it as inactive causes a segfault ... + */ + + gtk_idle_add (reactivate_button, buttons[which]); + } +} diff --git a/libs/gtkmm2ext/gtk_ui.cc b/libs/gtkmm2ext/gtk_ui.cc new file mode 100644 index 0000000000..f00c6cd1e1 --- /dev/null +++ b/libs/gtkmm2ext/gtk_ui.cc @@ -0,0 +1,656 @@ +/* + Copyright (C) 1999-2005 Paul Barton-Davis + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + $Id$ +*/ + +#include <cmath> +#include <fcntl.h> +#include <signal.h> +#include <unistd.h> +#include <cerrno> +#include <climits> +#include <cctype> + +#include <gtkmm.h> +#include <pbd/error.h> +#include <pbd/touchable.h> +#include <pbd/failed_constructor.h> +#include <pbd/pthread_utils.h> +#include <pbd/stacktrace.h> + +#include <gtkmm2ext/gtk_ui.h> +#include <gtkmm2ext/textviewer.h> +#include <gtkmm2ext/popup.h> +#include <gtkmm2ext/utils.h> +#include <gtkmm2ext/window_title.h> + +#include "i18n.h" + +using namespace Gtkmm2ext; +using namespace Gtk; +using namespace Glib; +using namespace PBD; +using std::map; + +pthread_t UI::gui_thread; +UI *UI::theGtkUI = 0; + +BaseUI::RequestType Gtkmm2ext::ErrorMessage = BaseUI::new_request_type(); +BaseUI::RequestType Gtkmm2ext::Quit = BaseUI::new_request_type(); +BaseUI::RequestType Gtkmm2ext::TouchDisplay = BaseUI::new_request_type(); +BaseUI::RequestType Gtkmm2ext::StateChange = BaseUI::new_request_type(); +BaseUI::RequestType Gtkmm2ext::SetTip = BaseUI::new_request_type(); +BaseUI::RequestType Gtkmm2ext::AddIdle = BaseUI::new_request_type(); +BaseUI::RequestType Gtkmm2ext::AddTimeout = BaseUI::new_request_type(); + +#include <pbd/abstract_ui.cc> /* instantiate the template */ + + +UI::UI (string namestr, int *argc, char ***argv) + : AbstractUI<UIRequest> (namestr, true) +{ + theMain = new Main (argc, argv); + tips = new Tooltips; + + _active = false; + + if (!theGtkUI) { + theGtkUI = this; + gui_thread = pthread_self (); + } else { + fatal << "duplicate UI requested" << endmsg; + /* NOTREACHED */ + } + + /* add the pipe to the select/poll loop that GDK does */ + + gdk_input_add (signal_pipe[0], + GDK_INPUT_READ, + UI::signal_pipe_callback, + this); + + errors = new TextViewer (850,100); + errors->text().set_editable (false); + errors->text().set_name ("ErrorText"); + + Glib::set_application_name(namestr); + + WindowTitle title(Glib::get_application_name()); + title += _("Log"); + errors->set_title (title.get_string()); + + errors->dismiss_button().set_name ("ErrorLogCloseButton"); + errors->signal_delete_event().connect (bind (sigc::ptr_fun (just_hide_it), (Window *) errors)); + + register_thread (pthread_self(), X_("GUI")); + + //load_rcfile (rcfile); +} + +UI::~UI () +{ +} + + +bool +UI::caller_is_ui_thread () +{ + return pthread_equal (gui_thread, pthread_self()); +} + +int +UI::load_rcfile (string path, bool themechange) +{ + if (path.length() == 0) { + return -1; + } + + if (access (path.c_str(), R_OK)) { + error << "UI: couldn't find rc file \"" + << path + << '"' + << endmsg; + return -1; + } + + RC rc (path.c_str()); + // RC::reset_styles (Gtk::Settings::get_default()); + gtk_rc_reset_styles (gtk_settings_get_default()); + theme_changed.emit(); + + if (themechange) { + return 0; //Don't continue on every time there is a theme change + } + + /* have to pack widgets into a toplevel window so that styles will stick */ + + Window temp_window (WINDOW_TOPLEVEL); + HBox box; + Label a_widget1; + Label a_widget2; + Label a_widget3; + Label a_widget4; + RefPtr<Gtk::Style> style; + RefPtr<TextBuffer> buffer (errors->text().get_buffer()); + + box.pack_start (a_widget1); + box.pack_start (a_widget2); + box.pack_start (a_widget3); + box.pack_start (a_widget4); + + error_ptag = buffer->create_tag(); + error_mtag = buffer->create_tag(); + fatal_ptag = buffer->create_tag(); + fatal_mtag = buffer->create_tag(); + warning_ptag = buffer->create_tag(); + warning_mtag = buffer->create_tag(); + info_ptag = buffer->create_tag(); + info_mtag = buffer->create_tag(); + + a_widget1.set_name ("FatalMessage"); + a_widget1.ensure_style (); + style = a_widget1.get_style(); + + fatal_ptag->property_font_desc().set_value(style->get_font()); + fatal_ptag->property_foreground_gdk().set_value(style->get_fg(STATE_ACTIVE)); + fatal_ptag->property_background_gdk().set_value(style->get_bg(STATE_ACTIVE)); + fatal_mtag->property_font_desc().set_value(style->get_font()); + fatal_mtag->property_foreground_gdk().set_value(style->get_fg(STATE_NORMAL)); + fatal_mtag->property_background_gdk().set_value(style->get_bg(STATE_NORMAL)); + + a_widget2.set_name ("ErrorMessage"); + a_widget2.ensure_style (); + style = a_widget2.get_style(); + + error_ptag->property_font_desc().set_value(style->get_font()); + error_ptag->property_foreground_gdk().set_value(style->get_fg(STATE_ACTIVE)); + error_ptag->property_background_gdk().set_value(style->get_bg(STATE_ACTIVE)); + error_mtag->property_font_desc().set_value(style->get_font()); + error_mtag->property_foreground_gdk().set_value(style->get_fg(STATE_NORMAL)); + error_mtag->property_background_gdk().set_value(style->get_bg(STATE_NORMAL)); + + a_widget3.set_name ("WarningMessage"); + a_widget3.ensure_style (); + style = a_widget3.get_style(); + + warning_ptag->property_font_desc().set_value(style->get_font()); + warning_ptag->property_foreground_gdk().set_value(style->get_fg(STATE_ACTIVE)); + warning_ptag->property_background_gdk().set_value(style->get_bg(STATE_ACTIVE)); + warning_mtag->property_font_desc().set_value(style->get_font()); + warning_mtag->property_foreground_gdk().set_value(style->get_fg(STATE_NORMAL)); + warning_mtag->property_background_gdk().set_value(style->get_bg(STATE_NORMAL)); + + a_widget4.set_name ("InfoMessage"); + a_widget4.ensure_style (); + style = a_widget4.get_style(); + + info_ptag->property_font_desc().set_value(style->get_font()); + info_ptag->property_foreground_gdk().set_value(style->get_fg(STATE_ACTIVE)); + info_ptag->property_background_gdk().set_value(style->get_bg(STATE_ACTIVE)); + info_mtag->property_font_desc().set_value(style->get_font()); + info_mtag->property_foreground_gdk().set_value(style->get_fg(STATE_NORMAL)); + info_mtag->property_background_gdk().set_value(style->get_bg(STATE_NORMAL)); + + return 0; +} + +void +UI::run (Receiver &old_receiver) +{ + listen_to (error); + listen_to (info); + listen_to (warning); + listen_to (fatal); + + old_receiver.hangup (); + starting (); + _active = true; + theMain->run (); + _active = false; + stopping (); + hangup (); + return; +} + +bool +UI::running () +{ + return _active; +} + +void +UI::kill () +{ + if (_active) { + pthread_kill (gui_thread, SIGKILL); + } +} + +void +UI::quit () +{ + UIRequest *req = get_request (Quit); + + if (req == 0) { + return; + } + + send_request (req); +} + +static bool idle_quit () +{ + Main::quit (); + return true; +} + +void +UI::do_quit () +{ + if (getenv ("ARDOUR_RUNNING_UNDER_VALGRIND")) { + Main::quit (); + } else { + Glib::signal_idle().connect (sigc::ptr_fun (idle_quit)); + } +} + +void +UI::touch_display (Touchable *display) +{ + UIRequest *req = get_request (TouchDisplay); + + if (req == 0) { + return; + } + + req->display = display; + + send_request (req); +} + +void +UI::set_tip (Widget *w, const gchar *tip, const gchar *hlp) +{ + UIRequest *req = get_request (SetTip); + + if (req == 0) { + return; + } + + req->widget = w; + req->msg = tip; + req->msg2 = hlp; + + send_request (req); +} + +void +UI::set_state (Widget *w, StateType state) +{ + UIRequest *req = get_request (StateChange); + + if (req == 0) { + return; + } + + req->new_state = state; + req->widget = w; + + send_request (req); +} + +void +UI::idle_add (int (*func)(void *), void *arg) +{ + UIRequest *req = get_request (AddIdle); + + if (req == 0) { + return; + } + + req->function = func; + req->arg = arg; + + send_request (req); +} + +/* END abstract_ui interfaces */ + +void +UI::signal_pipe_callback (void *arg, int fd, GdkInputCondition cond) +{ + char buf[256]; + + /* flush (nonblocking) pipe */ + + while (read (fd, buf, 256) > 0); + + ((UI *) arg)->handle_ui_requests (); +} + +void +UI::do_request (UIRequest* req) +{ + if (req->type == ErrorMessage) { + + process_error_message (req->chn, req->msg); + free (const_cast<char*>(req->msg)); /* it was strdup'ed */ + req->msg = 0; /* don't free it again in the destructor */ + + } else if (req->type == Quit) { + + do_quit (); + + } else if (req->type == CallSlot) { + + req->slot (); + + } else if (req->type == TouchDisplay) { + + req->display->touch (); + if (req->display->delete_after_touch()) { + delete req->display; + } + + } else if (req->type == StateChange) { + + req->widget->set_state (req->new_state); + + } else if (req->type == SetTip) { + + /* XXX need to figure out how this works */ + + } else { + + error << "GtkUI: unknown request type " + << (int) req->type + << endmsg; + } +} + +/*====================================================================== + Error Display + ======================================================================*/ + +void +UI::receive (Transmitter::Channel chn, const char *str) +{ + if (caller_is_ui_thread()) { + process_error_message (chn, str); + } else { + UIRequest* req = get_request (ErrorMessage); + + if (req == 0) { + return; + } + + req->chn = chn; + req->msg = strdup (str); + + send_request (req); + } +} + +#define OLD_STYLE_ERRORS 1 + +void +UI::process_error_message (Transmitter::Channel chn, const char *str) +{ + RefPtr<Style> style; + RefPtr<TextBuffer::Tag> ptag; + RefPtr<TextBuffer::Tag> mtag; + const char *prefix; + size_t prefix_len; + bool fatal_received = false; +#ifndef OLD_STYLE_ERRORS + PopUp* popup = new PopUp (WIN_POS_CENTER, 0, true); +#endif + + switch (chn) { + case Transmitter::Fatal: + prefix = "[FATAL]: "; + ptag = fatal_ptag; + mtag = fatal_mtag; + prefix_len = 9; + fatal_received = true; + break; + case Transmitter::Error: +#if OLD_STYLE_ERRORS + prefix = "[ERROR]: "; + ptag = error_ptag; + mtag = error_mtag; + prefix_len = 9; +#else + popup->set_name ("ErrorMessage"); + popup->set_text (str); + popup->touch (); + return; +#endif + break; + case Transmitter::Info: +#if OLD_STYLE_ERRORS + prefix = "[INFO]: "; + ptag = info_ptag; + mtag = info_mtag; + prefix_len = 8; +#else + popup->set_name ("InfoMessage"); + popup->set_text (str); + popup->touch (); + return; +#endif + + break; + case Transmitter::Warning: +#if OLD_STYLE_ERRORS + prefix = "[WARNING]: "; + ptag = warning_ptag; + mtag = warning_mtag; + prefix_len = 11; +#else + popup->set_name ("WarningMessage"); + popup->set_text (str); + popup->touch (); + return; +#endif + break; + default: + /* no choice but to use text/console output here */ + cerr << "programmer error in UI::check_error_messages (channel = " << chn << ")\n"; + ::exit (1); + } + + errors->text().get_buffer()->begin_user_action(); + + if (fatal_received) { + handle_fatal (str); + } else { + + display_message (prefix, prefix_len, ptag, mtag, str); + + if (!errors->is_visible()) { + toggle_errors(); + } + } + + errors->text().get_buffer()->end_user_action(); +} + +void +UI::toggle_errors () +{ + if (!errors->is_visible()) { + errors->set_position (WIN_POS_MOUSE); + errors->show (); + } else { + errors->hide (); + } +} + +void +UI::display_message (const char *prefix, gint prefix_len, RefPtr<TextBuffer::Tag> ptag, RefPtr<TextBuffer::Tag> mtag, const char *msg) +{ + RefPtr<TextBuffer> buffer (errors->text().get_buffer()); + + buffer->insert_with_tag(buffer->end(), prefix, ptag); + buffer->insert_with_tag(buffer->end(), msg, mtag); + buffer->insert_with_tag(buffer->end(), "\n", mtag); + + errors->scroll_to_bottom (); +} + +void +UI::handle_fatal (const char *message) +{ + Window win (WINDOW_POPUP); + VBox packer; + Label label (message); + Button quit (_("Press To Exit")); + + win.set_default_size (400, 100); + + string title; + title = name(); + title += ": Fatal Error"; + win.set_title (title); + + win.set_position (WIN_POS_MOUSE); + win.add (packer); + + packer.pack_start (label, true, true); + packer.pack_start (quit, false, false); + quit.signal_clicked().connect(mem_fun(*this,&UI::quit)); + + win.show_all (); + win.set_modal (true); + + theMain->run (); + + exit (1); +} + +void +UI::popup_error (const char *text) +{ + PopUp *pup; + + if (!caller_is_ui_thread()) { + error << "non-UI threads can't use UI::popup_error" + << endmsg; + return; + } + + pup = new PopUp (WIN_POS_MOUSE, 0, true); + pup->set_text (text); + pup->touch (); +} + +#ifdef GTKOSX +extern "C" { + int gdk_quartz_in_carbon_menu_event_handler (); +} +#endif + +void +UI::flush_pending () +{ +#ifdef GTKOSX + /* as of february 11th 2008, gtk/osx has a problem in that mac menu events + are handled using Carbon with an "internal" event handling system that + doesn't pass things back to the glib/gtk main loop. this makes + gtk_main_iteration() block if we call it while in a menu event handler + because glib gets confused and thinks there are two threads running + g_main_poll_func(). + + this hack (relies on code in gtk2_ardour/sync-menu.c) works + around that. + */ + + if (gdk_quartz_in_carbon_menu_event_handler()) { + return; + } +#endif + if (!caller_is_ui_thread()) { + error << "non-UI threads cannot call UI::flush_pending()" + << endmsg; + return; + } + + gtk_main_iteration(); + + while (gtk_events_pending()) { + gtk_main_iteration(); + } +} + +bool +UI::just_hide_it (GdkEventAny *ev, Window *win) +{ + win->hide (); + return true; +} + +Gdk::Color +UI::get_color (const string& prompt, bool& picked, const Gdk::Color* initial) +{ + Gdk::Color color; + + ColorSelectionDialog color_dialog (prompt); + + color_dialog.set_modal (true); + color_dialog.get_cancel_button()->signal_clicked().connect (bind (mem_fun (*this, &UI::color_selection_done), false)); + color_dialog.get_ok_button()->signal_clicked().connect (bind (mem_fun (*this, &UI::color_selection_done), true)); + color_dialog.signal_delete_event().connect (mem_fun (*this, &UI::color_selection_deleted)); + + if (initial) { + color_dialog.get_colorsel()->set_current_color (*initial); + } + + color_dialog.show_all (); + color_picked = false; + picked = false; + + Main::run(); + + color_dialog.hide_all (); + + if (color_picked) { + Gdk::Color f_rgba = color_dialog.get_colorsel()->get_current_color (); + color.set_red(f_rgba.get_red()); + color.set_green(f_rgba.get_green()); + color.set_blue(f_rgba.get_blue()); + + picked = true; + } + + return color; +} + +void +UI::color_selection_done (bool status) +{ + color_picked = status; + Main::quit (); +} + +bool +UI::color_selection_deleted (GdkEventAny *ev) +{ + Main::quit (); + return true; +} diff --git a/libs/gtkmm2ext/gtkmm2ext/.cvsignore b/libs/gtkmm2ext/gtkmm2ext/.cvsignore new file mode 100644 index 0000000000..67020331ba --- /dev/null +++ b/libs/gtkmm2ext/gtkmm2ext/.cvsignore @@ -0,0 +1 @@ +version.h diff --git a/libs/gtkmm2ext/gtkmm2ext/auto_spin.h b/libs/gtkmm2ext/gtkmm2ext/auto_spin.h new file mode 100644 index 0000000000..b692a7ccdc --- /dev/null +++ b/libs/gtkmm2ext/gtkmm2ext/auto_spin.h @@ -0,0 +1,71 @@ +/* + Copyright (C) 2000 Paul Barton-Davis + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#ifndef __gtkmm2ext_auto_spin_h__ +#define __gtkmm2ext_auto_spin_h__ + +#include <gtkmm.h> + +namespace Gtkmm2ext { + +class AutoSpin + +{ + public: + AutoSpin (Gtk::Adjustment &adj, gfloat cr = 0, bool round_to_steps_yn = false); + + Gtk::Adjustment &get_adjustment() { return adjustment; } + + void use_left_as_decrement (bool yn) { left_is_decrement = yn; } + void set_wrap (bool yn) { wrap = yn; } + void set_climb_rate (gfloat cr) { climb_rate = cr; } + void set_bounds (gfloat initial, gfloat low, gfloat high, + bool with_reset = true); + + gint button_press (GdkEventButton *); + gint stop_spinning (GdkEventButton *ignored_but_here_for_clicked); + void start_spinning (bool decrementing, bool use_page); + + private: + Gtk::Adjustment &adjustment; + gfloat climb_rate; + gfloat timer_increment; + gfloat initial; + unsigned int timer_calls; + bool have_timer; + bool need_timer; + bool wrap; + gint timeout_tag; + bool left_is_decrement; + bool round_to_steps; + + static const unsigned int initial_timer_interval; + static const unsigned int timer_interval; + static const unsigned int climb_timer_calls; + + void stop_timer (); + static gint _timer (void *arg); + gint timer (); + bool adjust_value (gfloat increment); + void set_value (gfloat value); +}; + +} /* namespace */ + +#endif /* __gtkmm2ext_auto_spin_h__ */ diff --git a/libs/gtkmm2ext/gtkmm2ext/barcontroller.h b/libs/gtkmm2ext/gtkmm2ext/barcontroller.h new file mode 100644 index 0000000000..fe67e9ecec --- /dev/null +++ b/libs/gtkmm2ext/gtkmm2ext/barcontroller.h @@ -0,0 +1,104 @@ +/* + Copyright (C) 2004 Paul Davis + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#ifndef __gtkmm2ext_bar_controller_h__ +#define __gtkmm2ext_bar_controller_h__ + +#include <gtkmm/frame.h> +#include <gtkmm/drawingarea.h> +#include <gtkmm2ext/binding_proxy.h> + +namespace ARDOUR { + class Controllable; +} + +namespace Gtkmm2ext { + +class BarController : public Gtk::Frame +{ + public: + typedef sigc::slot<void,char*,unsigned int> LabelCallback; + + BarController (Gtk::Adjustment& adj, PBD::Controllable&, LabelCallback lc = LabelCallback()); + + virtual ~BarController () {} + + enum Style { + LeftToRight, + RightToLeft, + Line, + CenterOut, + + TopToBottom, + BottomToTop + }; + + Style style() const { return _style; } + void set_style (Style); + void set_with_text (bool yn); + void set_use_parent (bool yn); + + void set_sensitive (bool yn); + + Gtk::SpinButton& get_spin_button() { return spinner; } + + sigc::signal<void> StartGesture; + sigc::signal<void> StopGesture; + + /* export this to allow direct connection to button events */ + + Gtk::Widget& event_widget() { return darea; } + PBD::Controllable* get_controllable() { return binding_proxy.get_controllable(); } + + protected: + Gtk::Adjustment& adjustment; + BindingProxy binding_proxy; + Gtk::DrawingArea darea; + LabelCallback label_callback; + Glib::RefPtr<Pango::Layout> layout; + Style _style; + bool grabbed; + bool switching; + bool switch_on_release; + bool with_text; + double initial_value; + double grab_x; + GdkWindow* grab_window; + Gtk::SpinButton spinner; + bool use_parent; + + virtual bool button_press (GdkEventButton *); + virtual bool button_release (GdkEventButton *); + virtual bool motion (GdkEventMotion *); + virtual bool expose (GdkEventExpose *); + virtual bool scroll (GdkEventScroll *); + virtual bool entry_focus_out (GdkEventFocus*); + + gint mouse_control (double x, GdkWindow* w, double scaling); + + gint switch_to_bar (); + gint switch_to_spinner (); + + void entry_activated (); + void drop_grab (); +}; + + +}; /* namespace */ + +#endif // __gtkmm2ext_bar_controller_h__ diff --git a/libs/gtkmm2ext/gtkmm2ext/bindable_button.h b/libs/gtkmm2ext/gtkmm2ext/bindable_button.h new file mode 100644 index 0000000000..1cde32c5ba --- /dev/null +++ b/libs/gtkmm2ext/gtkmm2ext/bindable_button.h @@ -0,0 +1,81 @@ +/* + Copyright (C) 2004 Paul Davis + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#ifndef __bindable_button_h__ +#define __bindable_button_h__ + +#include <string> + +#include <gtkmm2ext/stateful_button.h> +#include "binding_proxy.h" + +namespace PBD { + class Controllable; +} + +class BindableToggleButton : public Gtkmm2ext::StatefulToggleButton +{ + public: + BindableToggleButton (PBD::Controllable& c) : binding_proxy (c) {} + + explicit BindableToggleButton (PBD::Controllable& c, const std::string &label) + : Gtkmm2ext::StatefulToggleButton (label), binding_proxy (c) {} + + virtual ~BindableToggleButton() {} + + bool on_button_press_event (GdkEventButton *ev) { + if (!binding_proxy.button_press_handler (ev)) { + StatefulToggleButton::on_button_press_event (ev); + return false; + } else { + return true; + } + } + + PBD::Controllable* get_controllable() { return binding_proxy.get_controllable(); } + private: + BindingProxy binding_proxy; +}; + +class BindableButton : public Gtkmm2ext::StatefulButton +{ + public: + BindableButton (PBD::Controllable& c) : binding_proxy (c) {} + + explicit BindableButton (PBD::Controllable& c, const std::string &label) + : Gtkmm2ext::StatefulButton (label), binding_proxy (c) {} + + ~BindableButton() {} + + bool on_button_press_event (GdkEventButton *ev) { + if (!binding_proxy.button_press_handler (ev)) { + StatefulButton::on_button_press_event (ev); + return false; + } else { + return true; + } + } + + PBD::Controllable* get_controllable() { return binding_proxy.get_controllable(); } + + private: + BindingProxy binding_proxy; +}; + +#endif diff --git a/libs/gtkmm2ext/gtkmm2ext/binding_proxy.h b/libs/gtkmm2ext/gtkmm2ext/binding_proxy.h new file mode 100644 index 0000000000..dd9b94319d --- /dev/null +++ b/libs/gtkmm2ext/gtkmm2ext/binding_proxy.h @@ -0,0 +1,55 @@ +/* + Copyright (C) 2006 Paul Davis + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + $Id$ +*/ + +#ifndef __binding_proxy__ +#define __binding_proxy__ + +#include <string> + +#include <gtkmm2ext/popup.h> + +namespace PBD { + class Controllable; +} + +class BindingProxy : public sigc::trackable +{ + public: + BindingProxy (PBD::Controllable&); + virtual ~BindingProxy(); + + void set_bind_button_state (guint button, guint statemask); + void get_bind_button_state (guint &button, guint &statemask); + + bool button_press_handler (GdkEventButton *); + + PBD::Controllable* get_controllable() { return &controllable; } + protected: + + Gtkmm2ext::PopUp* prompter; + PBD::Controllable& controllable; + guint bind_button; + guint bind_statemask; + sigc::connection learning_connection; + void learning_finished (); + bool prompter_hiding (GdkEventAny *); +}; + +#endif diff --git a/libs/gtkmm2ext/gtkmm2ext/choice.h b/libs/gtkmm2ext/gtkmm2ext/choice.h new file mode 100644 index 0000000000..b6dcdc05c1 --- /dev/null +++ b/libs/gtkmm2ext/gtkmm2ext/choice.h @@ -0,0 +1,44 @@ +/* + Copyright (C) 2000-2007 Paul Davis + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#ifndef __pbd_gtkmm_choice_h__ +#define __pbd_gtkmm_choice_h__ + +#include <gtkmm/dialog.h> +#include <gtkmm/image.h> +#include <gtkmm/stock.h> +#include <gtkmm/box.h> +#include <string> +#include <vector> + +namespace Gtkmm2ext { + +class Choice : public Gtk::Dialog +{ + public: + Choice (std::string prompt, std::vector<std::string> choices, bool center = true); + virtual ~Choice (); + + protected: + void on_realize (); +}; + +} /* namespace */ + +#endif // __pbd_gtkmm_choice_h__ diff --git a/libs/gtkmm2ext/gtkmm2ext/click_box.h b/libs/gtkmm2ext/gtkmm2ext/click_box.h new file mode 100644 index 0000000000..8f9fb55717 --- /dev/null +++ b/libs/gtkmm2ext/gtkmm2ext/click_box.h @@ -0,0 +1,65 @@ +/* + Copyright (C) 1999 Paul Barton-Davis + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#ifndef __gtkmm2ext_click_box_h__ +#define __gtkmm2ext_click_box_h__ + +#include <string> +#include <gtkmm.h> + +#include <gtkmm2ext/auto_spin.h> + +namespace Gtkmm2ext { + +class ClickBox : public Gtk::DrawingArea, public AutoSpin +{ + public: + ClickBox (Gtk::Adjustment *adj, const std::string &name, bool round_to_steps = false); + ~ClickBox (); + + void set_print_func(void (*pf)(char buf[32], Gtk::Adjustment &, void *), + void *arg) { + print_func = pf; + print_arg = arg; + set_label (); + } + + + protected: + bool on_expose_event (GdkEventExpose*); + + private: + void (*print_func) (char buf[32], Gtk::Adjustment &, void *); + void *print_arg; + + Glib::RefPtr<Pango::Layout> layout; + int twidth; + int theight; + + void set_label (); + void style_changed (const Glib::RefPtr<Gtk::Style> &); + bool button_press_handler (GdkEventButton *); + bool button_release_handler (GdkEventButton *); + + static void default_printer (char buf[32], Gtk::Adjustment &, void *); +}; + +} /* namespace */ + +#endif /* __gtkmm2ext_click_box_h__ */ diff --git a/libs/gtkmm2ext/gtkmm2ext/dndtreeview.h b/libs/gtkmm2ext/gtkmm2ext/dndtreeview.h new file mode 100644 index 0000000000..fbc5ea90ef --- /dev/null +++ b/libs/gtkmm2ext/gtkmm2ext/dndtreeview.h @@ -0,0 +1,165 @@ +/* + Copyright (C) 2000-2007 Paul Davis + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#ifndef __gtkmm2ext_dndtreeview_h__ +#define __gtkmm2ext_dndtreeview_h__ + +#include <stdint.h> +#include <string> +#include <gtkmm/treeview.h> +#include <gtkmm/treeselection.h> +#include <gtkmm/selectiondata.h> + +namespace Gtkmm2ext { + +template<class DataType> +struct SerializedObjectPointers { + uint32_t size; + uint32_t cnt; + char type[32]; + DataType data[0]; +}; + +class DnDTreeViewBase : public Gtk::TreeView +{ + private: + public: + DnDTreeViewBase (); + ~DnDTreeViewBase() {} + + void add_drop_targets (std::list<Gtk::TargetEntry>&); + void add_object_drag (int column, std::string type_name); + + void on_drag_leave(const Glib::RefPtr<Gdk::DragContext>& context, guint time) { + suggested_action = context->get_suggested_action(); + TreeView::on_drag_leave (context, time); + } + + bool on_drag_motion(const Glib::RefPtr<Gdk::DragContext>& context, int x, int y, guint time) { + suggested_action = context->get_suggested_action(); + return TreeView::on_drag_motion (context, x, y, time); + } + + bool on_drag_drop(const Glib::RefPtr<Gdk::DragContext>& context, int x, int y, guint time); + + protected: + std::list<Gtk::TargetEntry> draggable; + Gdk::DragAction suggested_action; + int data_column; +}; + +template<class DataType> +class DnDTreeView : public DnDTreeViewBase +{ + public: + DnDTreeView() {} + ~DnDTreeView() {} + + sigc::signal<void,std::string,uint32_t,const DataType*> signal_object_drop; + + void on_drag_data_get(const Glib::RefPtr<Gdk::DragContext>& context, Gtk::SelectionData& selection_data, guint info, guint time) { + if (selection_data.get_target() == "GTK_TREE_MODEL_ROW") { + + TreeView::on_drag_data_get (context, selection_data, info, time); + + } else if (data_column >= 0) { + + Gtk::TreeSelection::ListHandle_Path selection = get_selection()->get_selected_rows (); + SerializedObjectPointers<DataType>* sr = serialize_pointers (get_model(), &selection, selection_data.get_target()); + selection_data.set (8, (guchar*)sr, sr->size); + } + } + + void on_drag_data_received(const Glib::RefPtr<Gdk::DragContext>& context, int x, int y, const Gtk::SelectionData& selection_data, guint info, guint time) { + if (suggested_action) { + /* this is a drag motion callback. just update the status to + say that we are still dragging, and that's it. + */ + suggested_action = Gdk::DragAction (0); + TreeView::on_drag_data_received (context, x, y, selection_data, info, time); + return; + } + + if (selection_data.get_target() == "GTK_TREE_MODEL_ROW") { + + TreeView::on_drag_data_received (context, x, y, selection_data, info, time); + + } else if (data_column >= 0) { + + /* object D-n-D */ + + const void* data = selection_data.get_data(); + const SerializedObjectPointers<DataType>* sr = reinterpret_cast<const SerializedObjectPointers<DataType> *>(data); + + if (sr) { + signal_object_drop (sr->type, sr->cnt, sr->data); + } + + } else { + /* some kind of target type added by the app, which will be handled by a signal handler */ + } + } + + private: + + SerializedObjectPointers<DataType>* serialize_pointers (Glib::RefPtr<Gtk::TreeModel> model, + Gtk::TreeSelection::ListHandle_Path* selection, + Glib::ustring type) { + + /* this nasty chunk of code is here because X's DnD protocol (probably other graphics UI's too) + requires that we package up the entire data collection for DnD in a single contiguous region + (so that it can be trivially copied between address spaces). We don't know the type of DataType so + we have to mix-and-match C and C++ programming techniques here to get the right result. + + The C trick is to use the "someType foo[0];" declaration trick to create a zero-sized array at the + end of a SerializedObjectPointers<DataType object. Then we allocate a raw memory buffer that extends + past that array and thus provides space for however many DataType items we actually want to pass + around. + + The C++ trick is to use the placement operator new() syntax to initialize that extra + memory properly. + */ + + uint32_t cnt = selection->size(); + uint32_t sz = (sizeof (DataType) * cnt) + sizeof (SerializedObjectPointers<DataType>); + + char* buf = new char[sz]; + SerializedObjectPointers<DataType>* sr = (SerializedObjectPointers<DataType>*) buf; + + for (uint32_t i = 0; i < cnt; ++i) { + new ((void *) &sr->data[i]) DataType (); + } + + sr->cnt = cnt; + sr->size = sz; + snprintf (sr->type, sizeof (sr->type), "%s", type.c_str()); + + cnt = 0; + + for (Gtk::TreeSelection::ListHandle_Path::iterator x = selection->begin(); x != selection->end(); ++x, ++cnt) { + model->get_iter (*x)->get_value (data_column, sr->data[cnt]); + } + + return sr; + } +}; + +} // namespace + +#endif /* __gtkmm2ext_dndtreeview_h__ */ diff --git a/libs/gtkmm2ext/gtkmm2ext/doi.h b/libs/gtkmm2ext/gtkmm2ext/doi.h new file mode 100644 index 0000000000..6ad1f7dd94 --- /dev/null +++ b/libs/gtkmm2ext/gtkmm2ext/doi.h @@ -0,0 +1,36 @@ +/* + Copyright (C) 2002 Paul Davis + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#ifndef __ardour_gtk_doi_h__ +#define __ardour_gtk_doi_h__ + +#include <gtkmm.h> + +/* XXX g++ 2.95 can't compile this as pair of member function templates */ + +template<typename T> gint idle_delete (T *obj) { delete obj; return FALSE; } +template<typename T> void delete_when_idle (T *obj) { + Glib::signal_idle().connect (sigc::bind (sigc::ptr_fun (idle_delete<T>), obj)); +} +template<typename T> gint delete_on_unmap (GdkEventAny *ignored, T *obj) { + Glib::signal_idle().connect (sigc::bind (sigc::ptr_fun (idle_delete<T>), obj)); + return FALSE; +} + +#endif /* __ardour_gtk_doi_h__ */ diff --git a/libs/gtkmm2ext/gtkmm2ext/fastmeter.h b/libs/gtkmm2ext/gtkmm2ext/fastmeter.h new file mode 100644 index 0000000000..2bf4539d87 --- /dev/null +++ b/libs/gtkmm2ext/gtkmm2ext/fastmeter.h @@ -0,0 +1,92 @@ +/* + Copyright (C) 2003 Paul Davis + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#ifndef __gtkmm2ext_fastmeter_h__ +#define __gtkmm2ext_fastmeter_h__ + +#include <gtkmm/drawingarea.h> +#include <gdkmm/pixbuf.h> + +namespace Gtkmm2ext { + +class FastMeter : public Gtk::DrawingArea { + public: + enum Orientation { + Horizontal, + Vertical + }; + + FastMeter (long hold_cnt, unsigned long width, Orientation, int len=0, int clrb0=0x00ff00, int clr1=0xffff00, int clr2=0xffaa00, int clr3=0xff0000); + virtual ~FastMeter (); + + void set (float level); + void clear (); + + float get_level() { return current_level; } + float get_user_level() { return current_user_level; } + float get_peak() { return current_peak; } + + long hold_count() { return hold_cnt; } + void set_hold_count (long); + + protected: + bool on_expose_event (GdkEventExpose*); + void on_size_request (GtkRequisition*); + void on_size_allocate (Gtk::Allocation&); + + private: + + Glib::RefPtr<Gdk::Pixbuf> pixbuf; + gint pixheight; + gint pixwidth; + static int _clr0, _clr1, _clr2, _clr3; + + Orientation orientation; + GdkRectangle pixrect; + GdkRectangle last_peak_rect; + gint request_width; + gint request_height; + unsigned long hold_cnt; + unsigned long hold_state; + float current_level; + float current_peak; + float current_user_level; + + bool vertical_expose (GdkEventExpose*); + bool horizontal_expose (GdkEventExpose*); + void queue_vertical_redraw (const Glib::RefPtr<Gdk::Window>&, float); + void queue_horizontal_redraw (const Glib::RefPtr<Gdk::Window>&, float); + + static Glib::RefPtr<Gdk::Pixbuf> request_vertical_meter(int w, int h); + + static Glib::RefPtr<Gdk::Pixbuf> *v_pixbuf_cache; + static int min_v_pixbuf_size; + static int max_v_pixbuf_size; + + static Glib::RefPtr<Gdk::Pixbuf> request_horizontal_meter(int w, int h); + + static Glib::RefPtr<Gdk::Pixbuf> *h_pixbuf_cache; + static int min_h_pixbuf_size; + static int max_h_pixbuf_size; +}; + + +} /* namespace */ + + #endif /* __gtkmm2ext_fastmeter_h__ */ diff --git a/libs/gtkmm2ext/gtkmm2ext/focus_entry.h b/libs/gtkmm2ext/gtkmm2ext/focus_entry.h new file mode 100644 index 0000000000..3fb57b433d --- /dev/null +++ b/libs/gtkmm2ext/gtkmm2ext/focus_entry.h @@ -0,0 +1,41 @@ +/* + Copyright (C) 2000-2007 Paul Davis + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#ifndef __gtkmm2ext_focus_entry_h__ +#define __gtkmm2ext_focus_entry_h__ + +#include <gtkmm/entry.h> + +namespace Gtkmm2ext { + +class FocusEntry : public Gtk::Entry +{ + public: + FocusEntry (); + + protected: + bool on_button_press_event (GdkEventButton*); + bool on_button_release_event (GdkEventButton*); + private: + bool next_release_selects; +}; + +} + +#endif /* __gtkmm2ext_focus_entry_h__ */ diff --git a/libs/gtkmm2ext/gtkmm2ext/grouped_buttons.h b/libs/gtkmm2ext/gtkmm2ext/grouped_buttons.h new file mode 100644 index 0000000000..99d9f8ffc4 --- /dev/null +++ b/libs/gtkmm2ext/gtkmm2ext/grouped_buttons.h @@ -0,0 +1,48 @@ +/* + Copyright (C) 2001 Paul Davis + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#ifndef __gtkmm2ext_grouped_buttons_h__ +#define __gtkmm2ext_grouped_buttons_h__ + +#include <stdint.h> + +#include <vector> +#include <sigc++/signal.h> + +namespace Gtk { + class ToggleButton; +}; + +class GroupedButtons : public sigc::trackable +{ + public: + GroupedButtons (uint32_t nbuttons, uint32_t first_active); + GroupedButtons (std::vector<Gtk::ToggleButton *>&); + + Gtk::ToggleButton& button (uint32_t which) { + return *buttons[which]; + } + + private: + std::vector<Gtk::ToggleButton *> buttons; + uint32_t current_active; + void one_clicked (uint32_t which); +}; + +#endif /* __gtkmm2ext_grouped_buttons_h__ */ diff --git a/libs/gtkmm2ext/gtkmm2ext/gtk_ui.h b/libs/gtkmm2ext/gtkmm2ext/gtk_ui.h new file mode 100644 index 0000000000..0c2ff0d798 --- /dev/null +++ b/libs/gtkmm2ext/gtkmm2ext/gtk_ui.h @@ -0,0 +1,177 @@ +/* + Copyright (C) 1999 Paul Barton-Davis + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#ifndef __pbd_gtk_ui_h__ +#define __pbd_gtk_ui_h__ + +#include <string> +#include <queue> +#include <map> + +#include <stdint.h> +#include <setjmp.h> +#include <pthread.h> +#include <gtkmm/widget.h> +#include <gtkmm/style.h> +#include <gtkmm/textbuffer.h> +#include <gtkmm/main.h> +#include <gtkmm/tooltips.h> +#include <gdkmm/color.h> +#include <pbd/abstract_ui.h> +#include <pbd/ringbufferNPT.h> + +#include <pbd/pool.h> +#include <pbd/error.h> +#include <pbd/receiver.h> + +using std::string; +using std::queue; + +class Touchable; + +namespace Gtkmm2ext { + +class TextViewer; + +extern BaseUI::RequestType ErrorMessage; +extern BaseUI::RequestType Quit; +extern BaseUI::RequestType CallSlot; +extern BaseUI::RequestType TouchDisplay; +extern BaseUI::RequestType StateChange; +extern BaseUI::RequestType SetTip; +extern BaseUI::RequestType AddIdle; +extern BaseUI::RequestType AddTimeout; + +struct UIRequest : public BaseUI::BaseRequestObject { + + /* this once used anonymous unions to merge elements + that are never part of the same request. that makes + the creation of a legal copy constructor difficult + because of the semantics of the slot member. + */ + + Touchable *display; + const char *msg; + Gtk::StateType new_state; + int (*function)(void *); + Gtk::Widget *widget; + Transmitter::Channel chn; + void *arg; + const char *msg2; + sigc::slot<void> slot; + + ~UIRequest () { + if (type == ErrorMessage && msg) { + /* msg was strdup()'ed */ + free ((char *)msg); + } + } + }; + +class UI : public Receiver, public AbstractUI<UIRequest> +{ + public: + UI (string name, int *argc, char **argv[]); + virtual ~UI (); + + static UI *instance() { return theGtkUI; } + + /* receiver interface */ + + void receive (Transmitter::Channel, const char *); + + /* Abstract UI interfaces */ + + bool caller_is_ui_thread (); + + static pthread_t thread_id() { return gui_thread; } + + /* Gtk-UI specific interfaces */ + + bool running (); + void quit (); + void kill (); + int load_rcfile (string, bool themechange = false); + void run (Receiver &old_receiver); + + void set_state (Gtk::Widget *w, Gtk::StateType state); + void popup_error (const char *text); + void flush_pending (); + void toggle_errors (); + void touch_display (Touchable *); + void set_tip (Gtk::Widget *w, const gchar *tip, const gchar *hlp); + void idle_add (int (*func)(void *), void *arg); + + template<class T> static bool idle_delete (T *obj) { delete obj; return false; } + template<class T> static void delete_when_idle (T *obj) { + Glib::signal_idle().connect (bind (slot (&UI::idle_delete<T>), obj)); + } + + Gdk::Color get_color (const string& prompt, bool& picked, const Gdk::Color *initial = 0); + + /* starting is sent just before we enter the main loop, + stopping just after we return from it (at the top level) + */ + + sigc::signal<void> starting; + sigc::signal<void> stopping; + + sigc::signal<void> theme_changed; + + static bool just_hide_it (GdkEventAny *, Gtk::Window *); + + static pthread_t the_gui_thread() { return gui_thread; } + + protected: + virtual void handle_fatal (const char *); + virtual void display_message (const char *prefix, gint prefix_len, + Glib::RefPtr<Gtk::TextBuffer::Tag> ptag, + Glib::RefPtr<Gtk::TextBuffer::Tag> mtag, + const char *msg); + + private: + static UI *theGtkUI; + static pthread_t gui_thread; + bool _active; + Gtk::Main *theMain; + Gtk::Tooltips *tips; + TextViewer *errors; + Glib::RefPtr<Gtk::TextBuffer::Tag> error_ptag; + Glib::RefPtr<Gtk::TextBuffer::Tag> error_mtag; + Glib::RefPtr<Gtk::TextBuffer::Tag> fatal_ptag; + Glib::RefPtr<Gtk::TextBuffer::Tag> fatal_mtag; + Glib::RefPtr<Gtk::TextBuffer::Tag> info_ptag; + Glib::RefPtr<Gtk::TextBuffer::Tag> info_mtag; + Glib::RefPtr<Gtk::TextBuffer::Tag> warning_ptag; + Glib::RefPtr<Gtk::TextBuffer::Tag> warning_mtag; + + static void signal_pipe_callback (void *, gint, GdkInputCondition); + void process_error_message (Transmitter::Channel, const char *); + void do_quit (); + + void color_selection_done (bool status); + bool color_selection_deleted (GdkEventAny *); + bool color_picked; + + void do_request (UIRequest*); +}; + +} /* namespace */ + +#endif /* __pbd_gtk_ui_h__ */ diff --git a/libs/gtkmm2ext/gtkmm2ext/gtkutils.h b/libs/gtkmm2ext/gtkmm2ext/gtkutils.h new file mode 100644 index 0000000000..832423f31d --- /dev/null +++ b/libs/gtkmm2ext/gtkmm2ext/gtkutils.h @@ -0,0 +1,33 @@ +/* + Copyright (C) 1998-99 Paul Barton-Davis + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#ifndef __gtkutils_h__ +#define __gtkutils_h__ + +#include <string> + +namespace Gtk { + class Widget; +} + +void gtk_set_size_request_to_display_given_text (Gtk::Widget& w, + const std::string& text, + gint hpadding = 0, + gint vpadding = 0); +#endif /* __gtkutils_h__ */ diff --git a/libs/gtkmm2ext/gtkmm2ext/hexentry.h b/libs/gtkmm2ext/gtkmm2ext/hexentry.h new file mode 100644 index 0000000000..410f54274e --- /dev/null +++ b/libs/gtkmm2ext/gtkmm2ext/hexentry.h @@ -0,0 +1,58 @@ +/* + Copyright (C) 1999 Paul Barton-Davis + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#ifndef __gtkmm2ext_hexentry_h__ +#define __gtkmm2ext_hexentry_h__ + +#include <gtkmm.h> + +namespace Gtkmm2ext { + +class HexEntry : public Gtk::Entry + +{ + public: + /* Take a byte-level representation of a series of hexadecimal + values and use them to set the displayed text of the entry. + Eg. if hexbuf[0] = 0xff and hexbuf[1] = 0xa1 and buflen = 2, + then the text will be set to "ff a1". + */ + + void set_hex (unsigned char *hexbuf, unsigned int buflen); + + /* puts byte-level representation of current entry text + into hexbuf, and returns number of bytes written there. + + NOTE: this will release the existing memory pointed to + by hexbuf if buflen indicates that it is not long enough + to hold the new representation, and hexbuf is not zero. + + If the returned length is zero, the contents of hexbuf + are undefined. + */ + + unsigned int get_hex (unsigned char *hexbuf, size_t buflen); + + private: + bool on_key_press_event (GdkEventKey *); +}; + +} /* namespace */ + +#endif /* __gtkmm2ext_hexentry_h__ */ diff --git a/libs/gtkmm2ext/gtkmm2ext/idle_adjustment.h b/libs/gtkmm2ext/gtkmm2ext/idle_adjustment.h new file mode 100644 index 0000000000..d8bda35cb5 --- /dev/null +++ b/libs/gtkmm2ext/gtkmm2ext/idle_adjustment.h @@ -0,0 +1,45 @@ +/* + Copyright (C) 2000-2007 Paul Davis + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#ifndef __gtkmm2ext_idle_adjustment_h__ +#define __gtkmm2ext_idle_adjustment_h__ + +#include <sys/time.h> +#include <gtkmm/adjustment.h> + +namespace Gtkmm2ext { + +class IdleAdjustment : public sigc::trackable +{ + public: + IdleAdjustment (Gtk::Adjustment& adj); + ~IdleAdjustment (); + + sigc::signal<void> value_changed; + + private: + void underlying_adjustment_value_changed(); + struct timeval last_vc; + gint timeout_handler(); + bool timeout_queued; +}; + +} + +#endif /* __gtkmm2ext_idle_adjustment_h__ */ diff --git a/libs/gtkmm2ext/gtkmm2ext/pathlist.h b/libs/gtkmm2ext/gtkmm2ext/pathlist.h new file mode 100644 index 0000000000..f4a5973d5a --- /dev/null +++ b/libs/gtkmm2ext/gtkmm2ext/pathlist.h @@ -0,0 +1,63 @@ +/* + Copyright (C) 2006 Paul Davis + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#ifndef __gtkmm2ext_pathlist_h__ +#define __gtkmm2ext_pathlist_h__ + +#include <vector> +#include <string> + +#include <gtkmm.h> + +namespace Gtkmm2ext { + +class PathList : public Gtk::VBox +{ + public: + PathList (); + ~PathList () {}; + + std::vector<std::string> get_paths (); + void set_paths (std::vector<std::string> paths); + + sigc::signal<void> PathsUpdated; + + protected: + Gtk::Button add_btn; + Gtk::Button subtract_btn; + + void add_btn_clicked (); + void subtract_btn_clicked (); + + private: + struct PathColumns : public Gtk::TreeModel::ColumnRecord { + PathColumns() { add (paths); } + Gtk::TreeModelColumn<std::string> paths; + }; + PathColumns path_columns; + + Glib::RefPtr<Gtk::ListStore> _store; + Gtk::TreeView _view; + + void selection_changed (); +}; + +} // namespace Gtkmm2ext + +#endif // __gtkmm2ext_pathlist_h__ diff --git a/libs/gtkmm2ext/gtkmm2ext/pixfader.h b/libs/gtkmm2ext/gtkmm2ext/pixfader.h new file mode 100644 index 0000000000..519e1c9e1e --- /dev/null +++ b/libs/gtkmm2ext/gtkmm2ext/pixfader.h @@ -0,0 +1,78 @@ +/* + Copyright (C) 2006 Paul Davis + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#ifndef __gtkmm2ext_pixfader_h__ +#define __gtkmm2ext_pixfader_h__ + +#include <cmath> + +#include <gtkmm/drawingarea.h> +#include <gtkmm/adjustment.h> +#include <gdkmm/pixbuf.h> + +namespace Gtkmm2ext { + +class PixFader : public Gtk::DrawingArea { + public: + PixFader (Glib::RefPtr<Gdk::Pixbuf> belt_image, Gtk::Adjustment& adjustment, int orientation); + virtual ~PixFader (); + + protected: + Gtk::Adjustment& adjustment; + + void on_size_request (GtkRequisition*); + + bool on_expose_event (GdkEventExpose*); + bool on_button_press_event (GdkEventButton*); + bool on_button_release_event (GdkEventButton*); + bool on_motion_notify_event (GdkEventMotion*); + bool on_scroll_event (GdkEventScroll* ev); + + enum Orientation { + VERT=1, + HORIZ=2, + }; + + private: + Glib::RefPtr<Gdk::Pixbuf> pixbuf; + int span, girth; + int _orien; + + GdkRectangle view; + + GdkWindow* grab_window; + double grab_loc; + double grab_start; + int last_drawn; + bool dragging; + float default_value; + int unity_loc; + + void adjustment_changed (); + + int display_span (); + + static int fine_scale_modifier; + static int extra_fine_scale_modifier; +}; + + +} /* namespace */ + + #endif /* __gtkmm2ext_pixfader_h__ */ diff --git a/libs/gtkmm2ext/gtkmm2ext/pixscroller.h b/libs/gtkmm2ext/gtkmm2ext/pixscroller.h new file mode 100644 index 0000000000..ea33359a25 --- /dev/null +++ b/libs/gtkmm2ext/gtkmm2ext/pixscroller.h @@ -0,0 +1,64 @@ +/* + Copyright (C) 2000-2007 Paul Davis + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#ifndef __gtkmm2ext_pixscroller_h__ +#define __gtkmm2ext_pixscroller_h__ + +#include <gtkmm/drawingarea.h> +#include <gtkmm/adjustment.h> +#include <gdkmm.h> + +namespace Gtkmm2ext { + +class PixScroller : public Gtk::DrawingArea +{ + public: + PixScroller(Gtk::Adjustment& adjustment, + Glib::RefPtr<Gdk::Pixbuf> slider, + Glib::RefPtr<Gdk::Pixbuf> rail); + + bool on_expose_event (GdkEventExpose*); + bool on_motion_notify_event (GdkEventMotion*); + bool on_button_press_event (GdkEventButton*); + bool on_button_release_event (GdkEventButton*); + bool on_scroll_event (GdkEventScroll*); + void on_size_request (GtkRequisition*); + + protected: + Gtk::Adjustment& adj; + + private: + Glib::RefPtr<Gdk::Pixbuf> rail; + Glib::RefPtr<Gdk::Pixbuf> slider; + Gdk::Rectangle sliderrect; + Gdk::Rectangle railrect; + GdkWindow* grab_window; + double grab_y; + double grab_start; + int overall_height; + bool dragging; + + float default_value; + + void adjustment_changed (); +}; + +} // namespace + +#endif /* __gtkmm2ext_pixscroller_h__ */ diff --git a/libs/gtkmm2ext/gtkmm2ext/popup.h b/libs/gtkmm2ext/gtkmm2ext/popup.h new file mode 100644 index 0000000000..1db357341d --- /dev/null +++ b/libs/gtkmm2ext/gtkmm2ext/popup.h @@ -0,0 +1,59 @@ +/* + Copyright (C) 1998-99 Paul Barton-Davis + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#ifndef __qui_popup_h__ +#define __qui_popup_h__ + +#include <string> +#include <gtkmm.h> + +#include <pbd/touchable.h> + +namespace Gtkmm2ext { + +class PopUp : public Gtk::Window, public Touchable +{ + public: + PopUp (Gtk::WindowPosition pos, unsigned int show_for_msecs = 0, + bool delete_on_hide = false); + virtual ~PopUp (); + void touch (); + void remove (); + void set_text (std::string); + void set_name (std::string); + gint button_click (GdkEventButton *); + + bool on_delete_event (GdkEventAny* ); + + protected: + void on_realize (); + + private: + Gtk::Label label; + std::string my_text; + gint timeout; + static gint remove_prompt_timeout (void *); + bool delete_on_hide; + unsigned int popdown_time; + +}; + +} /* namespace */ + +#endif // __qui_popup_h__ diff --git a/libs/gtkmm2ext/gtkmm2ext/prompter.h b/libs/gtkmm2ext/gtkmm2ext/prompter.h new file mode 100644 index 0000000000..5f71463288 --- /dev/null +++ b/libs/gtkmm2ext/gtkmm2ext/prompter.h @@ -0,0 +1,72 @@ +/* + Copyright (C) 1999 Paul Barton-Davis + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#ifndef __gtkmm2ext_prompter_h__ +#define __gtkmm2ext_prompter_h__ + +#include <string> +#include <gtkmm/box.h> +#include <gtkmm/entry.h> +#include <gtkmm/label.h> +#include <gtkmm/dialog.h> +#include <sigc++/sigc++.h> + +namespace Gtk { + class Window; +} + +namespace Gtkmm2ext { + +class Prompter : public Gtk::Dialog + +{ + public: + Prompter (bool modal = false); + Prompter (Gtk::Window& parent, bool modal = false); + ~Prompter () {}; + + void set_prompt (std::string prompt) { + entryLabel.set_label (prompt); + } + + void set_initial_text (std::string txt) { + entry.set_text (txt); + entry.select_region (0, entry.get_text_length()); + } + + void change_labels (std::string ok, std::string cancel); + + void get_result (std::string &str, bool strip=true); + + protected: + Gtk::Entry& the_entry() { return entry; } + + void on_entry_changed (); + + private: + Gtk::Entry entry; + Gtk::HBox entryBox; + Gtk::Label entryLabel; + + void init (); +}; + +} /* namespace */ + +#endif /* __gtkmm2ext_prompter_h__ */ diff --git a/libs/gtkmm2ext/gtkmm2ext/scroomer.h b/libs/gtkmm2ext/gtkmm2ext/scroomer.h new file mode 100644 index 0000000000..d4f2ce6aa3 --- /dev/null +++ b/libs/gtkmm2ext/gtkmm2ext/scroomer.h @@ -0,0 +1,88 @@ +/* + Copyright (C) 2008 Paul Davis + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#ifndef __gtkmm2ext_scroomer_h__ +#define __gtkmm2ext_scroomer_h__ + +#include <gtkmm/drawingarea.h> +#include <gtkmm/adjustment.h> +#include <gdkmm.h> + +namespace Gtkmm2ext { + +class Scroomer : public Gtk::DrawingArea +{ +public: + enum Component { + TopBase = 0, + Handle1 = 1, + Slider = 2, + Handle2 = 3, + BottomBase = 4, + Total = 5, + None = 6 + }; + + Scroomer(Gtk::Adjustment& adjustment); + ~Scroomer(); + + bool on_motion_notify_event (GdkEventMotion*); + bool on_button_press_event (GdkEventButton*); + bool on_button_release_event (GdkEventButton*); + bool on_scroll_event (GdkEventScroll*); + virtual void on_size_allocate (Gtk::Allocation&); + + void set_comp_rect(GdkRectangle&, Component) const; + + Component point_in(double point) const; + + void set_min_page_size(double page_size); + int get_handle_size() { return handle_size; } + + inline int position_of(Component comp) { return position[comp]; } + + // debug + std::string get_comp_name(Component); + +protected: + Gtk::Adjustment& adj; + +private: + struct UpdateRect { + GdkRectangle rect; + Component first_comp; + }; + + void update(); + void adjustment_changed (); + + int position[6]; + int old_pos[6]; + int handle_size; + double min_page_size; + GdkWindow* grab_window; + Component grab_comp; + double grab_y; + double unzoomed_val; + double unzoomed_page; +}; + +} // namespace + +#endif /* __gtkmm2ext_scroomer_h__ */ diff --git a/libs/gtkmm2ext/gtkmm2ext/selector.h b/libs/gtkmm2ext/gtkmm2ext/selector.h new file mode 100644 index 0000000000..841742db03 --- /dev/null +++ b/libs/gtkmm2ext/gtkmm2ext/selector.h @@ -0,0 +1,110 @@ +/* + Copyright (C) 1999 Paul Barton-Davis + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#ifndef __gtkselector_h__ +#define __gtkselector_h__ + +#include <string> +#include <vector> + +#include <gtkmm.h> + +namespace Gtkmm2ext { + +class TreeView_Selector : public Gtk::TreeView +{ +public: + TreeView_Selector() {} + virtual ~TreeView_Selector() {} + +protected: + virtual bool on_button_press_event(GdkEventButton *ev); +}; + +typedef void (SelectorRefillFunction)(Glib::RefPtr<Gtk::ListStore>, void *); + +class Selector : public Gtk::VBox +{ + friend class Gtkmm2ext::TreeView_Selector; + +public: + Selector (SelectorRefillFunction, void *arg, + std::vector<std::string> titles); + + virtual ~Selector (); + Glib::RefPtr<Gtk::ListStore> liststore () { return lstore; } + void reset (void (*refiller)(Glib::RefPtr<Gtk::ListStore>, void *), void *arg); + void set_size (unsigned int w, unsigned int h) { + scroll.set_size_request (w, h); + tview.columns_autosize (); + } + + struct Result { + Gtk::TreeView& view; + Glib::RefPtr<Gtk::TreeSelection> selection; + + Result (Gtk::TreeView& v, Glib::RefPtr<Gtk::TreeSelection> sel) + : view (v), selection (sel) {} + }; + + /* selection is activated via a double click, choice via + a single click. + */ + sigc::signal<void,Result*> selection_made; + sigc::signal<void,Result*> choice_made; + sigc::signal<void,Result*> shift_made; + sigc::signal<void,Result*> control_made; + + sigc::signal<void> update_contents; + + void accept(); + void cancel(); + void rescan(); + + + protected: + virtual void on_map (); + virtual void on_show (); + + private: + Gtk::ScrolledWindow scroll; + Gtk::TreeModel::ColumnRecord column_records; + Glib::RefPtr<Gtk::ListStore> lstore; + Gtkmm2ext::TreeView_Selector tview; + void (*refiller)(Glib::RefPtr<Gtk::ListStore>, void *); + void *refill_arg; + gint selected_row; + gint selected_column; + gint chosen_row; + gint chosen_column; + + void refill (); + void chosen (); + void shift_clicked (); + void control_clicked (); + + static gint _accept (gpointer); + static gint _chosen (gpointer); + static gint _shift_clicked (gpointer); + static gint _control_clicked (gpointer); + +}; + +} /* namespace */ + +#endif // __gtkselector_h__ diff --git a/libs/gtkmm2ext/gtkmm2ext/slider_controller.h b/libs/gtkmm2ext/gtkmm2ext/slider_controller.h new file mode 100644 index 0000000000..60c8eef660 --- /dev/null +++ b/libs/gtkmm2ext/gtkmm2ext/slider_controller.h @@ -0,0 +1,83 @@ +/* + Copyright (C) 1998-2006 Paul Davis + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#ifndef __gtkmm2ext_slider_controller_h__ +#define __gtkmm2ext_slider_controller_h__ + +#include <gtkmm.h> +#include <gtkmm2ext/popup.h> +#include <gtkmm2ext/pixfader.h> +#include <gtkmm2ext/binding_proxy.h> + +namespace Gtkmm2ext { + class Pix; +} + +namespace PBD { + class Controllable; +} + +namespace Gtkmm2ext { + +class SliderController : public Gtkmm2ext::PixFader +{ + public: + SliderController (Glib::RefPtr<Gdk::Pixbuf> image, + Gtk::Adjustment* adj, int orientation, + PBD::Controllable&, + bool with_numeric = true); + + virtual ~SliderController () {} + + void set_value (float); + + Gtk::SpinButton& get_spin_button () { return spin; } + + bool on_button_press_event (GdkEventButton *ev); + + protected: + BindingProxy binding_proxy; + Glib::RefPtr<Gdk::Pixbuf> slider; + Glib::RefPtr<Gdk::Pixbuf> rail; + Gtk::SpinButton spin; + Gtk::Frame spin_frame; + Gtk::HBox spin_hbox; +}; + +class VSliderController : public SliderController +{ + public: + VSliderController (Glib::RefPtr<Gdk::Pixbuf> image, + Gtk::Adjustment *adj, + PBD::Controllable&, + bool with_numeric = true); +}; + +class HSliderController : public SliderController +{ + public: + HSliderController (Glib::RefPtr<Gdk::Pixbuf> image, + Gtk::Adjustment *adj, + PBD::Controllable&, + bool with_numeric = true); +}; + + +}; /* namespace */ + +#endif // __gtkmm2ext_slider_controller_h__ diff --git a/libs/gtkmm2ext/gtkmm2ext/stateful_button.h b/libs/gtkmm2ext/gtkmm2ext/stateful_button.h new file mode 100644 index 0000000000..c86402e54e --- /dev/null +++ b/libs/gtkmm2ext/gtkmm2ext/stateful_button.h @@ -0,0 +1,83 @@ +/* + Copyright (C) 2005 Paul Davis + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#ifndef __pbd_gtkmm_abutton_h__ +#define __pbd_gtkmm_abutton_h__ + +#include <vector> + +#include <gtkmm/togglebutton.h> + +namespace Gtkmm2ext { + +class StateButton +{ + public: + StateButton(); + virtual ~StateButton() {} + + void set_visual_state (int); + int get_visual_state () { return visual_state; } + void set_self_managed (bool yn) { _self_managed = yn; } + + protected: + int visual_state; + bool _self_managed; + bool _is_realized; + + virtual std::string get_widget_name() const = 0; + virtual void set_widget_name (std::string) = 0; + virtual int get_widget_state() = 0; +}; + + +class StatefulToggleButton : public StateButton, public Gtk::ToggleButton +{ + public: + StatefulToggleButton() {} + explicit StatefulToggleButton(const std::string &label) : Gtk::ToggleButton (label) {} + ~StatefulToggleButton() {} + + protected: + void on_realize (); + void on_toggled (); + + std::string get_widget_name() const { return get_name(); } + void set_widget_name (std::string name) { set_name (name); get_child()->set_name (name); } + int get_widget_state() { return get_state(); } +}; + +class StatefulButton : public StateButton, public Gtk::Button +{ + public: + StatefulButton() {} + explicit StatefulButton(const std::string &label) : Gtk::Button (label) {} + virtual ~StatefulButton() {} + + protected: + void on_realize (); + + std::string get_widget_name() const { return get_name(); } + void set_widget_name (std::string name) { set_name (name); get_child()->set_name (name); } + int get_widget_state() { return get_state(); } +}; + +}; + +#endif diff --git a/libs/gtkmm2ext/gtkmm2ext/stop_signal.h b/libs/gtkmm2ext/gtkmm2ext/stop_signal.h new file mode 100644 index 0000000000..cb8dedca12 --- /dev/null +++ b/libs/gtkmm2ext/gtkmm2ext/stop_signal.h @@ -0,0 +1,33 @@ +/* + Copyright (C) 2000-2007 Paul Davis + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#ifndef __ardour_gtk_stop_signal_h__ +#define __ardour_gtk_stop_signal_h__ + +#include <gtkmm.h> +#include <gtk/gtksignal.h> + +static inline gint +stop_signal (Gtk::Widget& widget, const char *signal_name) +{ + gtk_signal_emit_stop_by_name (GTK_OBJECT(widget.gobj()), signal_name); + return TRUE; +} + +#endif /* __ardour_gtk_stop_signal_h__ */ diff --git a/libs/gtkmm2ext/gtkmm2ext/sync-menu.h b/libs/gtkmm2ext/gtkmm2ext/sync-menu.h new file mode 100644 index 0000000000..2be5e71d02 --- /dev/null +++ b/libs/gtkmm2ext/gtkmm2ext/sync-menu.h @@ -0,0 +1,44 @@ +/* GTK+ Integration for the Mac OS X Menubar. + * + * Copyright (C) 2007 Pioneer Research Center USA, Inc. + * Copyright (C) 2007 Imendio AB + * + * For further information, see: + * http://developer.imendio.com/projects/gtk-macosx/menubar + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; version 2.1 + * of the License. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef __IGE_MAC_MENU_H__ +#define __IGE_MAC_MENU_H__ + +#include <gtk/gtk.h> + +G_BEGIN_DECLS + +typedef struct _IgeMacMenuGroup IgeMacMenuGroup; + +void ige_mac_menu_set_menu_bar (GtkMenuShell *menu_shell); +void ige_mac_menu_set_quit_menu_item (GtkMenuItem *menu_item); + +IgeMacMenuGroup * ige_mac_menu_add_app_menu_group (void); +void ige_mac_menu_add_app_menu_item (IgeMacMenuGroup *group, + GtkMenuItem *menu_item, + const gchar *label); + +G_END_DECLS + +#endif /* __IGE_MAC_MENU_H__ */ diff --git a/libs/gtkmm2ext/gtkmm2ext/tearoff.h b/libs/gtkmm2ext/gtkmm2ext/tearoff.h new file mode 100644 index 0000000000..5e80892b98 --- /dev/null +++ b/libs/gtkmm2ext/gtkmm2ext/tearoff.h @@ -0,0 +1,70 @@ +/* + Copyright (C) 2003 Paul Barton-Davis + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#ifndef __gtkmm2ext_tearoff_h__ +#define __gtkmm2ext_tearoff_h__ + +#include <gtkmm/window.h> +#include <gtkmm/arrow.h> +#include <gtkmm/box.h> +#include <gtkmm/eventbox.h> + +namespace Gtkmm2ext { + +class TearOff : public Gtk::HBox +{ + public: + TearOff (Gtk::Widget& contents, bool allow_resize = false); + virtual ~TearOff (); + + void set_visible (bool yn); + + sigc::signal<void> Detach; + sigc::signal<void> Attach; + sigc::signal<void> Visible; + sigc::signal<void> Hidden; + + Gtk::Window& tearoff_window() { return own_window; } + bool torn_off() const; + + private: + Gtk::Widget& contents; + Gtk::Window own_window; + Gtk::Arrow tearoff_arrow; + Gtk::Arrow close_arrow; + Gtk::HBox window_box; + Gtk::EventBox tearoff_event_box; + Gtk::EventBox close_event_box; + double drag_x; + double drag_y; + bool dragging; + bool _visible; + + gint tearoff_click (GdkEventButton*); + gint close_click (GdkEventButton*); + + gint window_motion (GdkEventMotion*); + gint window_button_press (GdkEventButton*); + gint window_button_release (GdkEventButton*); + gint window_delete_event (GdkEventAny*); +}; + +} /* namespace */ + +#endif // __gtkmm2ext_tearoff_h__ diff --git a/libs/gtkmm2ext/gtkmm2ext/textviewer.h b/libs/gtkmm2ext/gtkmm2ext/textviewer.h new file mode 100644 index 0000000000..9cc639cd75 --- /dev/null +++ b/libs/gtkmm2ext/gtkmm2ext/textviewer.h @@ -0,0 +1,57 @@ +/* + Copyright (C) 1999 Paul Barton-Davis + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#ifndef __pbd_gtkmm_textviewer_h__ +#define __pbd_gtkmm_textviewer_h__ + +#include <string> +#include <gtkmm.h> + +#include <pbd/transmitter.h> + +using std::string; + +namespace Gtkmm2ext { + +class TextViewer : public Gtk::Window, public Transmitter +{ + Gtk::TextView etext; + Gtk::VBox vbox1; + Gtk::VBox vbox2; + Gtk::ScrolledWindow scrollwin; + Gtk::Button dismiss; + bool _editable; + + void toggle_edit (); + void toggle_word_wrap (); + void signal_released_handler (); + + public: + TextViewer (size_t width, size_t height); + Gtk::TextView& text() { return etext; } + Gtk::Button& dismiss_button() { return dismiss; } + + void insert_file (const string &); + void scroll_to_bottom (); + + void deliver (); +}; + +} /* namespace */ + +#endif // __pbd_gtkmm_textviewer_h__ diff --git a/libs/gtkmm2ext/gtkmm2ext/utils.h b/libs/gtkmm2ext/gtkmm2ext/utils.h new file mode 100644 index 0000000000..ca1b88abba --- /dev/null +++ b/libs/gtkmm2ext/gtkmm2ext/utils.h @@ -0,0 +1,58 @@ +/* + Copyright (C) 1999 Paul Barton-Davis + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#ifndef __gtkmm2ext_utils_h__ +#define __gtkmm2ext_utils_h__ + +#include <vector> +#include <string> + +#include <gtkmm/treeview.h> +#include <gdkmm/window.h> /* for WMDecoration */ + +namespace Gtk { + class ComboBoxText; + class Widget; + class Window; + class Paned; +} + +namespace Gtkmm2ext { + void init (); + + void get_ink_pixel_size (Glib::RefPtr<Pango::Layout>, int& width, int& height); + + void set_size_request_to_display_given_text (Gtk::Widget &w, + const gchar *text, + gint hpadding, + gint vpadding); + + void set_popdown_strings (Gtk::ComboBoxText&, const std::vector<std::string>&); + + template<class T> void deferred_delete (void *ptr) { + delete static_cast<T *> (ptr); + } + + GdkWindow* get_paned_handle (Gtk::Paned& paned); + void set_decoration (Gtk::Window* win, Gdk::WMDecoration decor); + void set_treeview_header_as_default_label(Gtk::TreeViewColumn *c); + Glib::RefPtr<Gdk::Drawable> get_bogus_drawable(); +}; + +#endif /* __gtkmm2ext_utils_h__ */ diff --git a/libs/gtkmm2ext/gtkmm2ext/window_title.h b/libs/gtkmm2ext/gtkmm2ext/window_title.h new file mode 100644 index 0000000000..93b47d9d45 --- /dev/null +++ b/libs/gtkmm2ext/gtkmm2ext/window_title.h @@ -0,0 +1,63 @@ +/* + Copyright (C) 2000-2007 Paul Davis + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#ifndef WINDOW_TITLE_INCLUDED +#define WINDOW_TITLE_INCLUDED + +#include <string> + +namespace Gtkmm2ext { + +using std::string; + +/** + * \class The WindowTitle class can be used to maintain the + * consistancy of window titles between windows and dialogs. + * + * Each string element that is added to the window title will + * be separated by a hyphen. + */ +class WindowTitle +{ +public: + + /** + * \param title The first string/element of the window title + * which will may be the application name or the document + * name in a document based application. + */ + WindowTitle(const string& title); + + /** + * Add an string element to the window title. + */ + void operator+= (const string&); + + /// @return The window title string. + const string& get_string () { return m_title;} + +private: + + string m_title; + +}; + +} // Gtkmm2ext + +#endif // WINDOW_TITLE_INCLUDED diff --git a/libs/gtkmm2ext/gtkutils.cc b/libs/gtkmm2ext/gtkutils.cc new file mode 100644 index 0000000000..23bf4d6b2f --- /dev/null +++ b/libs/gtkmm2ext/gtkutils.cc @@ -0,0 +1,22 @@ +/* + Copyright (C) 1998-99 Paul Barton-Davis + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + $Id$ +*/ + +#include <gtkmm2ext/gtkutils.h> + diff --git a/libs/gtkmm2ext/hexentry.cc b/libs/gtkmm2ext/hexentry.cc new file mode 100644 index 0000000000..9862cac435 --- /dev/null +++ b/libs/gtkmm2ext/hexentry.cc @@ -0,0 +1,111 @@ +/* + Copyright (C) 2000 Paul Barton-Davis + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + $Id$ +*/ + +#include <stdio.h> /* for sprintf, sigh ... */ +#include <string> +#include <ctype.h> + +#include <gdk/gdkkeysyms.h> +#include <gtkmm2ext/hexentry.h> + +using namespace std; +using namespace Gtkmm2ext; + +bool +HexEntry::on_key_press_event (GdkEventKey *ev) + +{ + if ((ev->keyval >= GDK_a && ev->keyval <= GDK_f) || + (ev->keyval >= GDK_A && ev->keyval <= GDK_A) || + (ev->keyval >= GDK_0 && ev->keyval <= GDK_9) || + ev->keyval == GDK_space || + ev->keyval == GDK_Tab || + ev->keyval == GDK_Return || + ev->keyval == GDK_BackSpace || + ev->keyval == GDK_Delete) { + return Gtk::Entry::on_key_press_event (ev); + } else { + gdk_beep (); + return FALSE; + } +} + + +void +HexEntry::set_hex (unsigned char *msg, unsigned int len) + +{ + /* create a textual representation of the MIDI message */ + + if (msg && len) { + char *rep; + + rep = new char[(len * 3) + 1]; + for (size_t i = 0; i < len; i++) { + sprintf (&rep[i*3], "%02x ", msg[i]); + } + rep[len * 3] = '\0'; + set_text (rep); + delete [] rep; + } else { + set_text (""); + } +} + +unsigned int +HexEntry::get_hex (unsigned char *hexbuf, size_t buflen) + +{ + int fetched_len; + char buf[3]; + string text = get_text(); + string::size_type length = text.length (); + string::size_type offset; + + fetched_len = 0; + buf[2] = '\0'; + offset = 0; + + while (1) { + offset = text.find_first_of ("abcdef0123456789", offset); + + if (offset == string::npos) { + break; + } + + /* grab two characters, but no more */ + + buf[0] = text[offset]; + + if (offset < length - 1) { + buf[1] = text[offset+1]; + offset += 2; + } else { + buf[1] = '\0'; + offset += 1; + } + + hexbuf[fetched_len++] = (char) strtol (buf, 0, 16); + } + + return fetched_len; +} + + diff --git a/libs/gtkmm2ext/i18n.h b/libs/gtkmm2ext/i18n.h new file mode 100644 index 0000000000..7c79d2eb53 --- /dev/null +++ b/libs/gtkmm2ext/i18n.h @@ -0,0 +1,11 @@ +#ifndef __i18n_h__ +#define __i18n_h__ + +#include <pbd/compose.h> +#include "gettext.h" + +#define _(Text) dgettext (PACKAGE, Text) +#define N_(Text) gettext_noop (Text) +#define X_(Text) (Text) + +#endif // __i18n_h__ diff --git a/libs/gtkmm2ext/idle_adjustment.cc b/libs/gtkmm2ext/idle_adjustment.cc new file mode 100644 index 0000000000..3e3a3da566 --- /dev/null +++ b/libs/gtkmm2ext/idle_adjustment.cc @@ -0,0 +1,73 @@ +/* + Copyright (C) 2000-2007 Paul Davis + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#define _BSD_SOURCE +#include <gtkmm2ext/idle_adjustment.h> +#include <gtkmm/main.h> +#include <iostream> + +using namespace Gtk; +using namespace sigc; +using namespace Gtkmm2ext; + +IdleAdjustment::IdleAdjustment (Gtk::Adjustment& adj) +{ + adj.signal_value_changed().connect (mem_fun (*this, &IdleAdjustment::underlying_adjustment_value_changed)); + timeout_queued = 0; + gettimeofday (&last_vc, 0); +} + +IdleAdjustment::~IdleAdjustment () +{ +} + +void +IdleAdjustment::underlying_adjustment_value_changed () +{ + gettimeofday (&last_vc, 0); + + if (timeout_queued) { + return; + } + + Glib::signal_timeout().connect(mem_fun(*this, &IdleAdjustment::timeout_handler), 250); + timeout_queued = true; +} + +gint +IdleAdjustment::timeout_handler () +{ + struct timeval now; + struct timeval tdiff; + + gettimeofday (&now, 0); + + timersub (&now, &last_vc, &tdiff); + + std::cerr << "timer elapsed, diff = " << tdiff.tv_sec << " + " << tdiff.tv_usec << std::endl; + + if (tdiff.tv_sec > 0 || tdiff.tv_usec > 250000) { + std::cerr << "send signal\n"; + value_changed (); + timeout_queued = false; + return FALSE; + } else { + return TRUE; + } +} diff --git a/libs/gtkmm2ext/libgtkmm2ext.pc.in b/libs/gtkmm2ext/libgtkmm2ext.pc.in new file mode 100644 index 0000000000..ee87973e2b --- /dev/null +++ b/libs/gtkmm2ext/libgtkmm2ext.pc.in @@ -0,0 +1,11 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@/gtkmm2ext + +Name: libgtkmm2ext +Version: @VERSION@ +Description: libgtkmm2ext, a library of useful new C++ and C widgets for gtkmm users +Requires: libpbd, libmidi++ +Libs: -L${libdir} -lgtkmm2ext @NON_PKG_LIBS@ +Cflags: -I${includedir} @NON_PKG_CFLAGS@ diff --git a/libs/gtkmm2ext/libgtkmm2ext.spec.in b/libs/gtkmm2ext/libgtkmm2ext.spec.in new file mode 100644 index 0000000000..19657721ef --- /dev/null +++ b/libs/gtkmm2ext/libgtkmm2ext.spec.in @@ -0,0 +1,68 @@ +Summary: extensions to the libgtkmm library +%define lib_name gtkmm2ext +Name: lib%{lib_name} +Version: @VERSION@ +Release: 2 +Copyright: GPL +Source: ftp://ftp.quasimodo.org/pub/libs/gtkmm2ext/current/%{name}-%{version}.tar.gz +Url: http://www.quasimodo.org +Vendor: Paul Barton Davis <pbd@op.net> +Packager: jfm3 <jfm3@acm.org> +Group: System Environment/Libraries +Prefix: %{_prefix} +BuildRoot: %{_tmppath}/%{name}-%{version}-root + +%description + +libgtkmm2ext provides extensions to Gtk-- useful for audio +applications. These include ShapedWindow, MotionFeedback, +PixmapButton and several more. It also includes the useful Pix class +for managing sets of pixmaps, with reference counting etc. + +%prep +%setup -q + +%build +CFLAGS="$RPM_OPT_FLAGS" CXXFLAGS="$RPM_OPT_FLAGS" ./configure $ARCH_FLAGS --prefix=%{prefix} +make + +%install +rm -rf $RPM_BUILD_ROOT +install -d -m 755 $RPM_BUILD_ROOT%{prefix}/{{include,lib}/%{lib_name}} +make install INSTALL="%(which install) -p" prefix=$RPM_BUILD_ROOT%{prefix} + +%post +/sbin/ldconfig + +%postun +/sbin/ldconfig + +%clean +rm -rf $RPM_BUILD_ROOT + +%files +%defattr(-,root,root) +%doc README AUTHORS NEWS COPYING* +%{prefix}/lib/libgtkmm2ext.so* + +%package devel +Summary: extensions to the libgtkmm library -- developer package +Group: System Environment/Libraries + +%description devel + +libgtkmm2ext provides extensions to Gtk-- useful for audio +applications. These include ShapedWindow, MotionFeedback, +PixmapButton and several more. It also includes the useful Pix class +for managing sets of pixmaps, with reference counting etc. + +This package holds static libraries and headers needed by developers +who wish to use libgtkmm2ext in their programs. + +%files devel +%defattr(-,root,root) +%{prefix}/include/gtkmm2ext/* +%{prefix}/lib/libgtkmm2ext.a +%{prefix}/lib/libgtkmm2ext.la +%{prefix}/bin/gtkmm2ext-config +%{prefix}/share/aclocal/gtkmm2ext.m4 diff --git a/libs/gtkmm2ext/pathlist.cc b/libs/gtkmm2ext/pathlist.cc new file mode 100644 index 0000000000..7b3448ed5f --- /dev/null +++ b/libs/gtkmm2ext/pathlist.cc @@ -0,0 +1,124 @@ +/* + Copyright (C) 2006 Paul Davis + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#include <gtkmm2ext/pathlist.h> + +#include "i18n.h" + +using namespace std; +using namespace Gtkmm2ext; + +PathList::PathList () + : + add_btn(_("+")), + subtract_btn(_("-")), + path_columns(), + _store(Gtk::ListStore::create(path_columns)), + _view(_store) +{ + _view.append_column(_("Paths"), path_columns.paths); + _view.set_size_request(-1, 100); + _view.set_headers_visible (false); + + Gtk::ScrolledWindow* scroll = manage(new Gtk::ScrolledWindow); + scroll->set_policy (Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC); + scroll->add(_view); + + add (*scroll); + + Gtk::HBox* btn_box = manage(new Gtk::HBox); + btn_box->add(add_btn); + btn_box->add(subtract_btn); + + add (*btn_box); + + add_btn.signal_clicked().connect (mem_fun(*this, &PathList::add_btn_clicked)); + subtract_btn.signal_clicked().connect (mem_fun(*this, &PathList::subtract_btn_clicked)); + _view.get_selection()->signal_changed().connect (mem_fun(*this, &PathList::selection_changed)); +} + +vector<string> +PathList::get_paths () +{ + vector<string> paths; + + Gtk::TreeModel::Children children(_store->children()); + + for (Gtk::TreeIter iter = children.begin(); iter != children.end(); ++iter) { + Gtk::ListStore::Row row = *iter; + + paths.push_back(row[path_columns.paths]); + } + + return paths; +} + +void +PathList::set_paths (vector<string> paths) +{ + _store->clear(); + + for (vector<string>::iterator i = paths.begin(); i != paths.end(); ++i) { + Gtk::ListStore::iterator iter = _store->append(); + Gtk::ListStore::Row row = *iter; + row[path_columns.paths] = *i; + } +} + +void +PathList::add_btn_clicked () +{ + Gtk::FileChooserDialog path_chooser (_("Path Chooser"), Gtk::FILE_CHOOSER_ACTION_SELECT_FOLDER); + + path_chooser.add_button (Gtk::Stock::ADD, Gtk::RESPONSE_OK); + path_chooser.add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL); + + int result = path_chooser.run (); + + if (result == Gtk::RESPONSE_OK) { + string pathname = path_chooser.get_filename(); + + if (pathname.length ()) { + Gtk::ListStore::iterator iter = _store->append (); + Gtk::ListStore::Row row = *iter; + row[path_columns.paths] = pathname; + + PathsUpdated (); // EMIT_SIGNAL + } + } +} + +void +PathList::subtract_btn_clicked () +{ + Gtk::ListStore::iterator iter = _view.get_selection()->get_selected(); + _store->erase (iter); + + PathsUpdated (); // EMIT_SIGNAL +} + +void +PathList::selection_changed () +{ + if (_view.get_selection()->count_selected_rows ()) { + subtract_btn.set_sensitive (true); + } else { + subtract_btn.set_sensitive (false); + } +} diff --git a/libs/gtkmm2ext/pixfader.cc b/libs/gtkmm2ext/pixfader.cc new file mode 100644 index 0000000000..521a6cb9ca --- /dev/null +++ b/libs/gtkmm2ext/pixfader.cc @@ -0,0 +1,309 @@ +/* + Copyright (C) 2006 Paul Davis + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + $Id: fastmeter.h 570 2006-06-07 21:21:21Z sampo $ +*/ + + +#include <iostream> +#include <gtkmm2ext/pixfader.h> + +using namespace Gtkmm2ext; +using namespace Gtk; +using namespace Gdk; +using namespace std; + +#ifdef GTKOSX +int PixFader::fine_scale_modifier = GDK_META_MASK; +#else +int PixFader::fine_scale_modifier = GDK_CONTROL_MASK; +#endif + +int PixFader::extra_fine_scale_modifier = GDK_MOD1_MASK; + +PixFader::PixFader (Glib::RefPtr<Pixbuf> belt, Gtk::Adjustment& adj, int orientation) + + : adjustment (adj), + pixbuf (belt), + _orien(orientation) +{ + dragging = false; + default_value = adjustment.get_value(); + last_drawn = -1; + + view.x = 0; + view.y = 0; + + if (orientation == VERT) { + view.width = girth = pixbuf->get_width(); + view.height = span = pixbuf->get_height() / 2; + unity_loc = (int) rint (view.height - (default_value * view.height)) - 1; + } else { + view.width = span = pixbuf->get_width () / 2; + view.height = girth = pixbuf->get_height(); + unity_loc = (int) rint (default_value * view.width) - 1; + } + + add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::POINTER_MOTION_MASK|Gdk::SCROLL_MASK); + + adjustment.signal_value_changed().connect (mem_fun (*this, &PixFader::adjustment_changed)); + adjustment.signal_changed().connect (mem_fun (*this, &PixFader::adjustment_changed)); +} + +PixFader::~PixFader () +{ +} + +bool +PixFader::on_expose_event (GdkEventExpose* ev) +{ + GdkRectangle intersection; + int srcx, srcy, ds = display_span (); + int offset_into_pixbuf = (int) floor (span / ((float) span / ds)); + Glib::RefPtr<Gdk::GC> fg_gc (get_style()->get_fg_gc(get_state())); + + if (gdk_rectangle_intersect (&view, &ev->area, &intersection)) { + if (_orien == VERT) { + srcx = intersection.x; + srcy = offset_into_pixbuf + intersection.y; + } else { + srcx = offset_into_pixbuf + intersection.x; + srcy = intersection.y; + } + get_window()->draw_pixbuf (fg_gc, pixbuf, + srcx, srcy, + intersection.x, intersection.y, + intersection.width, intersection.height, + Gdk::RGB_DITHER_NONE, 0, 0); + + get_window()->draw_line (get_style()->get_bg_gc(STATE_ACTIVE), 0, 0, view.width - 1, 0); /* top */ + get_window()->draw_line (get_style()->get_bg_gc(STATE_ACTIVE), 0, 0, 0, view.height - 1); /* left */ + get_window()->draw_line (get_style()->get_bg_gc(STATE_NORMAL), view.width - 1, 0, view.width - 1, view.height - 1); /* right */ + get_window()->draw_line (get_style()->get_bg_gc(STATE_NORMAL), 0, view.height - 1, view.width - 1, view.height - 1); /* bottom */ + } + + /* always draw the line */ + if (_orien == VERT) { + get_window()->draw_line (fg_gc, 1, unity_loc, girth - 2, unity_loc); + } else { + get_window()->draw_line (fg_gc, unity_loc, 1, unity_loc, girth - 2); + } + last_drawn = ds; + return true; +} + +void +PixFader::on_size_request (GtkRequisition* req) +{ + req->width = view.width; + req->height = view.height; +} + +bool +PixFader::on_button_press_event (GdkEventButton* ev) +{ + switch (ev->button) { + case 1: + case 2: + add_modal_grab(); + grab_loc = (_orien == VERT) ? ev->y : ev->x; + grab_start = (_orien == VERT) ? ev->y : ev->x; + grab_window = ev->window; + dragging = true; + break; + default: + break; + } + + + return false; +} + +bool +PixFader::on_button_release_event (GdkEventButton* ev) +{ + double fract, ev_pos; + + ev_pos = (_orien == VERT) ? ev->y : ev->x; + + switch (ev->button) { + case 1: + if (dragging) { + remove_modal_grab(); + dragging = false; + + if (ev_pos == grab_start) { + + /* no motion - just a click */ + + if (ev->state & Gdk::SHIFT_MASK) { + adjustment.set_value (default_value); + } else if (ev->state & fine_scale_modifier) { + adjustment.set_value (adjustment.get_lower()); + } else if ((_orien == VERT && ev_pos < span - display_span()) || (_orien == HORIZ && ev_pos > span - display_span())) { + /* above the current display height, remember X Window coords */ + adjustment.set_value (adjustment.get_value() + adjustment.get_step_increment()); + } else { + adjustment.set_value (adjustment.get_value() - adjustment.get_step_increment()); + } + } + + } + break; + + case 2: + if (dragging) { + remove_modal_grab(); + dragging = false; + + fract = 1.0 - (ev_pos / span); // inverted X Window coordinates, grrr + + fract = min (1.0, fract); + fract = max (0.0, fract); + + adjustment.set_value (fract * (adjustment.get_upper() - adjustment.get_lower())); + } + break; + + default: + break; + } + + return false; +} + +bool +PixFader::on_scroll_event (GdkEventScroll* ev) +{ + double scale; + bool ret = false; + + if (ev->state & fine_scale_modifier) { + if (ev->state & extra_fine_scale_modifier) { + scale = 0.01; + } else { + scale = 0.05; + } + } else { + scale = 0.25; + } + + if (_orien == VERT) { + + /* should left/right scroll affect vertical faders ? */ + + switch (ev->direction) { + + case GDK_SCROLL_UP: + /* wheel up */ + adjustment.set_value (adjustment.get_value() + (adjustment.get_page_increment() * scale)); + ret = true; + break; + case GDK_SCROLL_DOWN: + /* wheel down */ + adjustment.set_value (adjustment.get_value() - (adjustment.get_page_increment() * scale)); + ret = true; + break; + default: + break; + } + } else { + + /* up/down scrolls should definitely affect horizontal faders + because they are so much easier to use + */ + + switch (ev->direction) { + + case GDK_SCROLL_RIGHT: + case GDK_SCROLL_UP: + /* wheel right */ + adjustment.set_value (adjustment.get_value() + (adjustment.get_page_increment() * scale)); + ret = true; + break; + case GDK_SCROLL_LEFT: + case GDK_SCROLL_DOWN: + /* wheel left */ + adjustment.set_value (adjustment.get_value() - (adjustment.get_page_increment() * scale)); + ret = true; + break; + default: + break; + } + } + return ret; +} + +bool +PixFader::on_motion_notify_event (GdkEventMotion* ev) +{ + if (dragging) { + double fract, delta, scale, ev_pos; + ev_pos = (_orien == VERT) ? ev->y : ev->x; + //cerr << "PixFader::on_motion_notify_event() called x:y = " << ev->x << ":" << ev->y; + if (ev->window != grab_window) { + grab_loc = ev_pos; + grab_window = ev->window; + return true; + } + + if (ev->state & fine_scale_modifier) { + if (ev->state & extra_fine_scale_modifier) { + scale = 0.05; + } else { + scale = 0.1; + } + } else { + scale = 1.0; + } + //cerr << " ev_pos=" << ev_pos << " grab_loc=" << grab_loc; + delta = ev_pos - grab_loc; + grab_loc = ev_pos; + + fract = (delta / span); + + fract = min (1.0, fract); + fract = max (-1.0, fract); + + // X Window is top->bottom for 0..Y + + if (_orien == VERT) { + fract = -fract; + } + + adjustment.set_value (adjustment.get_value() + scale * fract * (adjustment.get_upper() - adjustment.get_lower())); + //cerr << " adj=" << adjustment.get_value() << " fract=" << fract << " delta=" << delta << " scale=" << scale << endl; + } + + return true; +} + +void +PixFader::adjustment_changed () +{ + if (display_span() != last_drawn) { + queue_draw (); + } +} + +int +PixFader::display_span () +{ + float fract = (adjustment.get_upper() - adjustment.get_value ()) / ((adjustment.get_upper() - adjustment.get_lower())); + return (_orien == VERT) ? (int)floor (span * (1.0 - fract)) : (int)floor (span * fract); +} + diff --git a/libs/gtkmm2ext/pixscroller.cc b/libs/gtkmm2ext/pixscroller.cc new file mode 100644 index 0000000000..f459726f27 --- /dev/null +++ b/libs/gtkmm2ext/pixscroller.cc @@ -0,0 +1,265 @@ +/* + Copyright (C) 2005 Paul Davis + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + $Id$ +*/ +#include <iostream> +#include <algorithm> +#include <cmath> + +#include <gtkmm.h> + +#include <gtkmm2ext/pixscroller.h> + +using namespace std; +using namespace Gtk; +using namespace Gtkmm2ext; + +PixScroller::PixScroller (Adjustment& a, + Glib::RefPtr<Gdk::Pixbuf> s, + Glib::RefPtr<Gdk::Pixbuf> r) + : adj (a), + rail (r), + slider (s) +{ + dragging = false; + add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::POINTER_MOTION_MASK|Gdk::SCROLL_MASK); + + adj.signal_value_changed().connect (mem_fun (*this, &PixScroller::adjustment_changed)); + default_value = adj.get_value(); + + sliderrect.set_width(slider->get_width()); + sliderrect.set_height(slider->get_height()); + railrect.set_width(rail->get_width()); + railrect.set_height(rail->get_height()); + + railrect.set_y(sliderrect.get_height() / 2); + sliderrect.set_x(0); + + overall_height = railrect.get_height() + sliderrect.get_height(); + + sliderrect.set_y((int) rint ((overall_height - sliderrect.get_height()) * (adj.get_upper() - adj.get_value()))); + railrect.set_x((sliderrect.get_width() / 2) - 2); +} + +void +PixScroller::on_size_request (GtkRequisition* requisition) +{ + requisition->width = sliderrect.get_width(); + requisition->height = overall_height; +} + +bool +PixScroller::on_expose_event (GdkEventExpose* ev) +{ + GdkRectangle intersect; + Glib::RefPtr<Gdk::Window> win (get_window()); + + win->draw_rectangle (get_style()->get_bg_gc(get_state()), TRUE, + ev->area.x, + ev->area.y, + ev->area.width, + ev->area.height); + + if (gdk_rectangle_intersect (railrect.gobj(), &ev->area, &intersect)) { + Glib::RefPtr<Gdk::GC> gc(get_style()->get_bg_gc(get_state())); + win->draw_pixbuf (gc, rail, + intersect.x - railrect.get_x(), + intersect.y - railrect.get_y(), + intersect.x, + intersect.y, + intersect.width, + intersect.height, + Gdk::RGB_DITHER_NONE, 0, 0); + } + + if (gdk_rectangle_intersect (sliderrect.gobj(), &ev->area, &intersect)) { + Glib::RefPtr<Gdk::GC> gc(get_style()->get_fg_gc(get_state())); + // Glib::RefPtr<Gdk::Bitmap> mask (slider_mask); + + GdkGCValues values; + gdk_gc_get_values(gc->gobj(), &values); + gc->set_clip_origin (sliderrect.get_x(), sliderrect.get_y()); + // gc->set_clip_mask (mask); + win->draw_pixbuf (gc, slider, + intersect.x - sliderrect.get_x(), + intersect.y - sliderrect.get_y(), + intersect.x, + intersect.y, + intersect.width, + intersect.height, + Gdk::RGB_DITHER_NONE, 0, 0); + gc->set_clip_origin (values.clip_x_origin, values.clip_y_origin); + // gdk_gc_set_clip_mask (gc->gobj(), values.clip_mask); + } + + + return true; +} + +bool +PixScroller::on_button_press_event (GdkEventButton* ev) +{ + switch (ev->button) { + case 1: + if (!(ev->state & Gdk::SHIFT_MASK)) { + add_modal_grab(); + grab_y = ev->y; + grab_start = ev->y; + grab_window = ev->window; + dragging = true; + } + break; + default: + break; + } + + + return false; +} + +bool +PixScroller::on_button_release_event (GdkEventButton* ev) +{ + double scale; + + if (ev->state & GDK_CONTROL_MASK) { + if (ev->state & GDK_MOD1_MASK) { + scale = 0.05; + } else { + scale = 0.1; + } + } else { + scale = 1.0; + } + + switch (ev->button) { + case 1: + if (dragging) { + remove_modal_grab(); + dragging = false; + + if (ev->y == grab_start) { + /* no motion - just a click */ + double fract; + + if (ev->y < sliderrect.get_height()/2) { + /* near the top */ + fract = 1.0; + } else { + fract = 1.0 - (ev->y - sliderrect.get_height()/2) / railrect.get_height(); + } + + fract = min (1.0, fract); + fract = max (0.0, fract); + + adj.set_value (scale * fract * (adj.get_upper() - adj.get_lower())); + } + } else { + if (ev->state & Gdk::SHIFT_MASK) { + adj.set_value (default_value); + cerr << "default value = " << default_value << endl; + } + } + break; + default: + break; + } + return false; +} + +bool +PixScroller::on_scroll_event (GdkEventScroll* ev) +{ + double scale; + + if (ev->state & GDK_CONTROL_MASK) { + if (ev->state & GDK_MOD1_MASK) { + scale = 0.05; + } else { + scale = 0.1; + } + } else { + scale = 0.5; + } + + switch (ev->direction) { + + case GDK_SCROLL_UP: + /* wheel up */ + adj.set_value (adj.get_value() + (adj.get_page_increment() * scale)); + break; + case GDK_SCROLL_DOWN: + /* wheel down */ + adj.set_value (adj.get_value() - (adj.get_page_increment() * scale)); + break; + default: + break; + } + return false; +} + +bool +PixScroller::on_motion_notify_event (GdkEventMotion* ev) +{ + if (dragging) { + double fract; + double delta; + double scale; + + if (ev->window != grab_window) { + grab_y = ev->y; + grab_window = ev->window; + return true; + } + + if (ev->state & GDK_CONTROL_MASK) { + if (ev->state & GDK_MOD1_MASK) { + scale = 0.05; + } else { + scale = 0.1; + } + } else { + scale = 1.0; + } + + delta = ev->y - grab_y; + grab_y = ev->y; + + fract = (delta / railrect.get_height()); + + fract = min (1.0, fract); + fract = max (-1.0, fract); + + fract = -fract; + + adj.set_value (adj.get_value() + scale * fract * (adj.get_upper() - adj.get_lower())); + } + + return true; +} + +void +PixScroller::adjustment_changed () +{ + int y = (int) rint ((overall_height - sliderrect.get_height()) * (adj.get_upper() - adj.get_value())); + + if (y != sliderrect.get_y()) { + sliderrect.set_y(y); + queue_draw (); + } +} diff --git a/libs/gtkmm2ext/po/el_GR.po b/libs/gtkmm2ext/po/el_GR.po new file mode 100644 index 0000000000..cc10981aa8 --- /dev/null +++ b/libs/gtkmm2ext/po/el_GR.po @@ -0,0 +1,59 @@ +# Σχολιαστικός Τίτλος. +# Πνευματικά Δικαιώματα (C) YEAR Paul Davis +# Το παÏόν αÏχείο διανÎμεται υπό της ιδίας αδείας με του PACKAGE πακÎτου. +# ΠΡΩΤΟΣ ΔΗΜΙΟΥΡΓΟΣ <muadib@in.gr>, 2004. +# +msgid "" +msgstr "" +"Project-Id-Version: 0.99beta23\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2006-06-21 15:09-0400\n" +"PO-Revision-Date: 2005-01-11\n" +"Last-Translator: Muadibas\n" +"Language-Team: Hellenic(Greek) <LL@li.org>\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#: libs/gtkmm2ext/barcontroller.cc:432 libs/gtkmm2ext/bindable_button.cc:131 +#: libs/gtkmm2ext/controller.cc:50 libs/gtkmm2ext/slider_controller.cc:132 +msgid "operate MIDI controller now" +msgstr "λειτουÏγία ελεγκτή MIDI Ï„ÏŽÏα" + +#: libs/gtkmm2ext/gtk_ui.cc:510 +msgid "Press To Exit" +msgstr "" + +#: libs/gtkmm2ext/textviewer.cc:34 +msgid "Close" +msgstr "Κλείσιμο" + +#~ msgid "OK" +#~ msgstr "OK" + +#~ msgid "Location:" +#~ msgstr "Τοποθεσία:" + +#~ msgid "Browse ..." +#~ msgstr "Αναζήτηση ..." + +#~ msgid "Cancel" +#~ msgstr "ΑκÏÏωση" + +#~ msgid "New folder" +#~ msgstr "ÎÎος φάκελος" + +#~ msgid "Add to favorites" +#~ msgstr "Î Ïόσθεση στα 'ΑγαπημÎνα'" + +#~ msgid "Remove from favorites" +#~ msgstr "Απαλοιφή από τα 'ΑγαπημÎνα'" + +#~ msgid "Show Hidden" +#~ msgstr "Ανάδειξη κÏυμμÎνων" + +#~ msgid "Hide browser" +#~ msgstr "ΑπόκÏυψη browser" + +#~ msgid "Rescan" +#~ msgstr "ΑνανÎωση" diff --git a/libs/gtkmm2ext/po/es_ES.po b/libs/gtkmm2ext/po/es_ES.po new file mode 100644 index 0000000000..8b7dc8804d --- /dev/null +++ b/libs/gtkmm2ext/po/es_ES.po @@ -0,0 +1,58 @@ +# Copyright (C) 2004 Paul Davis +# This file is distributed under the same license as the gtkmm2ext package. +# Author: Alex Krohn <alexkrohn@fastmail.fm>, 2004. +# +msgid "" +msgstr "" +"Project-Id-Version: gtkmm2ext\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2006-06-21 15:09-0400\n" +"PO-Revision-Date: 2004-02-13 00:35+0300\n" +"Last-Translator: Alex Krohn alexkrohn@fastmail.fm\n" +"Language-Team: Spanish\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=ISO-8859-1\n" +"Content-Transfer-Encoding: 8bit\n" + +#: libs/gtkmm2ext/barcontroller.cc:432 libs/gtkmm2ext/bindable_button.cc:131 +#: libs/gtkmm2ext/controller.cc:50 libs/gtkmm2ext/slider_controller.cc:132 +msgid "operate MIDI controller now" +msgstr "Operar controladora de MIDI ahora" + +#: libs/gtkmm2ext/gtk_ui.cc:510 +msgid "Press To Exit" +msgstr "" + +#: libs/gtkmm2ext/textviewer.cc:34 +msgid "Close" +msgstr "Cerrar" + +#~ msgid "OK" +#~ msgstr "ACEPTAR" + +#~ msgid "Location:" +#~ msgstr "Localización:" + +#~ msgid "Browse ..." +#~ msgstr "Seleccionar ..." + +#~ msgid "Cancel" +#~ msgstr "Cancelar" + +#~ msgid "New folder" +#~ msgstr "Nueva carpeta" + +#~ msgid "Add to favorites" +#~ msgstr "Agregar a favoritos" + +#~ msgid "Remove from favorites" +#~ msgstr "Quitar de favoritos" + +#~ msgid "Show Hidden" +#~ msgstr "Mostrar ocultos" + +#~ msgid "Hide browser" +#~ msgstr "Ocultar explorador" + +#~ msgid "Rescan" +#~ msgstr "Buscar de nuevo" diff --git a/libs/gtkmm2ext/po/pl_PL.po b/libs/gtkmm2ext/po/pl_PL.po new file mode 100644 index 0000000000..df2414d7ba --- /dev/null +++ b/libs/gtkmm2ext/po/pl_PL.po @@ -0,0 +1,53 @@ +# translation of libgtkmm2ext.po to Polish +# Copyright (C) YEAR "Paul Davis" +# This file is distributed under the same license as the PACKAGE package. +# +# Piotr Zaryk <pzaryk@gmail.com>, 2008. +msgid "" +msgstr "" +"Project-Id-Version: libgtkmm2ext\n" +"Report-Msgid-Bugs-To: Piotr Zaryk <pzaryk@gmail.com>\n" +"POT-Creation-Date: 2008-04-03 16:17+0200\n" +"PO-Revision-Date: 2008-04-10 10:54+0100\n" +"Last-Translator: Piotr Zaryk <pzaryk@gmail.com>\n" +"Language-Team: Polish <pl@li.org>\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#: libs/gtkmm2ext/binding_proxy.cc:69 +msgid "operate controller now" +msgstr "Teraz operuj kontrolerem" + +#: libs/gtkmm2ext/gtk_ui.cc:95 +msgid "Log" +msgstr "Log" + +#: libs/gtkmm2ext/gtk_ui.cc:536 +msgid "Press To Exit" +msgstr "WciÅ›nij by zakoÅ„czyć" + +#: libs/gtkmm2ext/gtk_ui.cc:570 +msgid "Error" +msgstr "BÅ‚Ä…d" + +#: libs/gtkmm2ext/pathlist.cc:29 +msgid "+" +msgstr "+" + +#: libs/gtkmm2ext/pathlist.cc:30 +msgid "-" +msgstr "-" + +#: libs/gtkmm2ext/pathlist.cc:35 +msgid "Paths" +msgstr "PoÅ‚ożenia" + +#: libs/gtkmm2ext/pathlist.cc:87 +msgid "Path Chooser" +msgstr "Wybór poÅ‚ożenia" + +#: libs/gtkmm2ext/textviewer.cc:34 +msgid "Close" +msgstr "Zamknij" + diff --git a/libs/gtkmm2ext/po/pt_BR.po b/libs/gtkmm2ext/po/pt_BR.po new file mode 100644 index 0000000000..66381c2d37 --- /dev/null +++ b/libs/gtkmm2ext/po/pt_BR.po @@ -0,0 +1,59 @@ +# Copyright (C) 2004 Paul Davis +# This file is distributed under the same license as the gtkmm2ext package. +# Authors: Alexander Franca <alexander@nautae.eti.br> +# Chris Ross <chris.ross@tebibyte.org> +# +msgid "" +msgstr "" +"Project-Id-Version: gtkmm2ext\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2006-06-21 15:09-0400\n" +"PO-Revision-Date: 2004-05-17 20:36+0200\n" +"Last-Translator: Chris Ross <chris.ross@tebibyte.org>\n" +"Language-Team: Portuguese\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=ISO-8859-15\n" +"Content-Transfer-Encoding: 8bit\n" + +#: libs/gtkmm2ext/barcontroller.cc:432 libs/gtkmm2ext/bindable_button.cc:131 +#: libs/gtkmm2ext/controller.cc:50 libs/gtkmm2ext/slider_controller.cc:132 +msgid "operate MIDI controller now" +msgstr "Operar controladora de MIDI agora" + +#: libs/gtkmm2ext/gtk_ui.cc:510 +msgid "Press To Exit" +msgstr "" + +#: libs/gtkmm2ext/textviewer.cc:34 +msgid "Close" +msgstr "Fechar" + +#~ msgid "OK" +#~ msgstr "OK" + +#~ msgid "Location:" +#~ msgstr "localização:" + +#~ msgid "Browse ..." +#~ msgstr "Localizar ..." + +#~ msgid "Cancel" +#~ msgstr "Cancelar" + +#~ msgid "New folder" +#~ msgstr "Novo diretório" + +#~ msgid "Add to favorites" +#~ msgstr "Adicionar a favoritos" + +#~ msgid "Remove from favorites" +#~ msgstr "Remover de favoritos" + +#~ msgid "Show Hidden" +#~ msgstr "Mostrar ocultos" + +#~ msgid "Hide browser" +#~ msgstr "Ocultar explorador" + +#~ msgid "Rescan" +#~ msgstr "Buscar de novo" diff --git a/libs/gtkmm2ext/po/ru_RU.po b/libs/gtkmm2ext/po/ru_RU.po new file mode 100644 index 0000000000..4a3edcef5c --- /dev/null +++ b/libs/gtkmm2ext/po/ru_RU.po @@ -0,0 +1,58 @@ +# Copyright (C) 2004 Paul Davis +# This file is distributed under the same license as the gtkmm2ext package. +# Igor Blinov pitstop@nm.ru, 2004. +# +msgid "" +msgstr "" +"Project-Id-Version: gtkmm2ext\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2006-06-21 15:09-0400\n" +"PO-Revision-Date: 2004-02-13 00:35+0300\n" +"Last-Translator: Igor Blinov pitstop@nm.ru\n" +"Language-Team: Russian\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=koi8-r\n" +"Content-Transfer-Encoding: 8bit\n" + +#: libs/gtkmm2ext/barcontroller.cc:432 libs/gtkmm2ext/bindable_button.cc:131 +#: libs/gtkmm2ext/controller.cc:50 libs/gtkmm2ext/slider_controller.cc:132 +msgid "operate MIDI controller now" +msgstr "×ËÌÀÞÉÔØ MIDI-ËÏÎÔÒÏÌÌÅÒ" + +#: libs/gtkmm2ext/gtk_ui.cc:510 +msgid "Press To Exit" +msgstr "" + +#: libs/gtkmm2ext/textviewer.cc:34 +msgid "Close" +msgstr "úÁËÒÙÔØ" + +#~ msgid "OK" +#~ msgstr "ïë" + +#~ msgid "Location:" +#~ msgstr "ðÕÔØ:" + +#~ msgid "Browse ..." +#~ msgstr "ïÂÚÏÒ ..." + +#~ msgid "Cancel" +#~ msgstr "ïÔÍÅÎÁ" + +#~ msgid "New folder" +#~ msgstr "îÏ×ÁÑ ÐÁÐËÁ" + +#~ msgid "Add to favorites" +#~ msgstr "äÏÂÁ×ÉÔØ × ÉÚÂÒÁÎÎÏÅ" + +#~ msgid "Remove from favorites" +#~ msgstr "éÓËÌÀÞÉÔØ ÉÚ ÉÚÂÒÁÎÎÏÇÏ" + +#~ msgid "Show Hidden" +#~ msgstr "ðÏËÁÚÙ×ÁÔØ ÓËÒÙÔÙÅ ÆÁÊÌÙ" + +#~ msgid "Hide browser" +#~ msgstr "óËÒÙÔØ ÏÂÌÁÓÔØ ÏÂÚÏÒÁ" + +#~ msgid "Rescan" +#~ msgstr "ïÂÎÏ×ÉÔØ" diff --git a/libs/gtkmm2ext/popup.cc b/libs/gtkmm2ext/popup.cc new file mode 100644 index 0000000000..0b150eefe1 --- /dev/null +++ b/libs/gtkmm2ext/popup.cc @@ -0,0 +1,139 @@ +/* + Copyright (C) 1998-99 Paul Barton-Davis + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + $Id$ +*/ + +#include <iostream> + +#include <gtkmm2ext/popup.h> +#include <gtkmm2ext/utils.h> + +using namespace std; +using namespace Gtk; +using namespace Gtkmm2ext; + +PopUp::PopUp (Gtk::WindowPosition pos, unsigned int showfor_msecs, bool doh) + : Window (WINDOW_POPUP) +{ + add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK); + signal_button_press_event().connect(mem_fun(*this,&PopUp::button_click)); + set_border_width (12); + add (label); + set_position (pos); + + delete_on_hide = doh; + popdown_time = showfor_msecs; + timeout = -1; +} + + +PopUp::~PopUp () +{ +} + +void +PopUp::on_realize () +{ + Gtk::Window::on_realize(); + get_window()->set_decorations (Gdk::WMDecoration (Gdk::DECOR_BORDER|Gdk::DECOR_RESIZEH)); +} + +gint +PopUp::remove_prompt_timeout (void *arg) +{ + PopUp *pup = (PopUp *) arg; + + pup->remove (); + return FALSE; +} + +static gint idle_delete (void *arg) +{ + delete static_cast<PopUp*> (arg); + return FALSE; +} + +void +PopUp::remove () +{ + hide (); + + if (popdown_time != 0 && timeout != -1) { + g_source_remove (timeout); + } + + if (delete_on_hide) { + std::cerr << "deleting prompter\n"; + gtk_idle_add (idle_delete, this); + } +} + +void +PopUp::touch () +{ + if (is_visible ()) { + remove (); + } else { + set_size_request_to_display_given_text (label, my_text.c_str(), 25, 10); + label.set_text (my_text); + show_all (); + + if (popdown_time != 0) { + timeout = g_timeout_add (popdown_time, + remove_prompt_timeout, + this); + } + } +} + +gint +PopUp::button_click (GdkEventButton *ev) +{ + remove (); + return TRUE; +} + +void +PopUp::set_text (string txt) +{ + my_text = txt; +} + +void +PopUp::set_name (string name) +{ + Window::set_name (name); + label.set_name (name); +} + +bool +PopUp::on_delete_event (GdkEventAny* ev) +{ + hide(); + + if (popdown_time != 0 && timeout != -1) { + g_source_remove (timeout); + } + + if (delete_on_hide) { + std::cerr << "deleting prompter\n" << endl; + g_idle_add (idle_delete, this); + } + + return true; +} diff --git a/libs/gtkmm2ext/prompter.cc b/libs/gtkmm2ext/prompter.cc new file mode 100644 index 0000000000..0ff9710338 --- /dev/null +++ b/libs/gtkmm2ext/prompter.cc @@ -0,0 +1,109 @@ +/* + Copyright (C) 1999 Paul Barton-Davis + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + $Id$ +*/ + +#include <string> + +#include <pbd/whitespace.h> + +#include <gtkmm/stock.h> +#include <gtkmm2ext/prompter.h> + +#include "i18n.h" + +using namespace std; +using namespace Gtkmm2ext; + +Prompter::Prompter (Gtk::Window& parent, bool modal) + : Gtk::Dialog ("", parent, modal) +{ + init (); +} + +Prompter::Prompter (bool modal) + : Gtk::Dialog ("", modal) +{ + init (); +} + +void +Prompter::init () +{ + set_type_hint (Gdk::WINDOW_TYPE_HINT_DIALOG); + set_position (Gtk::WIN_POS_MOUSE); + set_name ("Prompter"); + + add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL); + + /* + Alas a generic 'affirmative' button seems a bit useless sometimes. + You will have to add your own. + After adding, use : + set_response_sensitive (Gtk::RESPONSE_ACCEPT, false) + to prevent the RESPONSE_ACCEPT button from permitting blank strings. + */ + + entryLabel.set_line_wrap (true); + entryLabel.set_name ("PrompterLabel"); + + entryBox.set_homogeneous (false); + entryBox.set_spacing (5); + entryBox.set_border_width (10); + entryBox.pack_start (entryLabel); + entryBox.pack_start (entry, false, false); + + get_vbox()->pack_start (entryBox); + show_all_children(); + entry.signal_changed().connect (mem_fun (*this, &Prompter::on_entry_changed)); + entry.signal_activate().connect (bind (mem_fun (*this, &Prompter::response), Gtk::RESPONSE_ACCEPT)); +} + +void +Prompter::change_labels (string okstr, string cancelstr) +{ + // dynamic_cast<Gtk::Label*>(ok.get_child())->set_text (okstr); + // dynamic_cast<Gtk::Label*>(cancel.get_child())->set_text (cancelstr); +} + +void +Prompter::get_result (string &str, bool strip) +{ + str = entry.get_text (); + if (strip) { + PBD::strip_whitespace_edges (str); + } +} + +void +Prompter::on_entry_changed () +{ + /* + This is set up so that entering text in the entry + field makes the RESPONSE_ACCEPT button active. + Of course if you haven't added a RESPONSE_ACCEPT + button, nothing will happen at all. + */ + + if (entry.get_text() != "") { + set_response_sensitive (Gtk::RESPONSE_ACCEPT, true); + set_default_response (Gtk::RESPONSE_ACCEPT); + } else { + set_response_sensitive (Gtk::RESPONSE_ACCEPT, false); + } +} diff --git a/libs/gtkmm2ext/scroomer.cc b/libs/gtkmm2ext/scroomer.cc new file mode 100644 index 0000000000..6572c8b51c --- /dev/null +++ b/libs/gtkmm2ext/scroomer.cc @@ -0,0 +1,389 @@ +/* + Copyright (C) 2008 Paul Davis + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#include <iostream> +#include <gtkmm2ext/scroomer.h> + +using namespace Gtkmm2ext; +using namespace Gtk; +using namespace Gdk; +using namespace std; + +Scroomer::Scroomer(Gtk::Adjustment& adjustment) + : adj(adjustment) + , handle_size(0) + , grab_comp(None) { + + position[TopBase] = 0; + position[Handle1] = 0; + position[Slider] = 0; + position[Handle2] = 0; + position[BottomBase] = 0; + position[Total] = 0; + + add_events (Gdk::BUTTON_PRESS_MASK | + Gdk::BUTTON_RELEASE_MASK | + Gdk::POINTER_MOTION_MASK | + Gdk::SCROLL_MASK); + + adjustment.signal_value_changed().connect (mem_fun (*this, &Scroomer::adjustment_changed)); + //adjustment.signal_changed().connect (mem_fun (*this, &Scroomer::adjustment_changed)); +} + +Scroomer::~Scroomer() { +} + +bool +Scroomer::on_motion_notify_event (GdkEventMotion* ev) { + double range = adj.get_upper() - adj.get_lower(); + double pixel2val = range / get_height(); + double val_at_pointer = ((get_height() - ev->y) * pixel2val) + adj.get_lower(); + double delta_y = ev->y - grab_y; + double half_min_page = min_page_size / 2; + double fract = delta_y / position[Total]; + double scale, temp, zoom; + double val, page; + + if(grab_comp == None || grab_comp == Total) { + return true; + } + + if (ev->window != grab_window) { + grab_y = ev->y; + grab_window = ev->window; + return true; + } + + grab_y = ev->y; + + if (ev->state & GDK_CONTROL_MASK) { + if (ev->state & GDK_MOD1_MASK) { + scale = 0.05; + } else { + scale = 0.1; + } + } else { + scale = 1.0; + } + + fract = min (1.0, fract); + fract = max (-1.0, fract); + fract = -fract; + + switch(grab_comp) { + case TopBase: + case BottomBase: + unzoomed_val += scale * fract * range; + unzoomed_val = min(unzoomed_val, adj.get_upper() - unzoomed_page); + unzoomed_val = max(unzoomed_val, adj.get_lower()); + break; + case Slider: + unzoomed_val += scale * fract * range; + unzoomed_val = min(unzoomed_val, adj.get_upper() - unzoomed_page); + unzoomed_val = max(unzoomed_val, adj.get_lower()); + break; + case Handle1: + unzoomed_page += scale * fract * range; + unzoomed_page = min(unzoomed_page, adj.get_upper() - unzoomed_val); + unzoomed_page = max(unzoomed_page, min_page_size); + break; + case Handle2: + temp = unzoomed_val + unzoomed_page; + unzoomed_val += scale * fract * range; + unzoomed_val = min(unzoomed_val, temp - min_page_size); + unzoomed_val = max(unzoomed_val, adj.get_lower()); + + unzoomed_page = temp - unzoomed_val; + unzoomed_page = max(unzoomed_page, min_page_size); + break; + default: + break; + } + + /* + * Then we handle zoom, which is dragging horizontally. We zoom around the area that is + * the current y pointer value, not from the area that was the start of the drag. + * the point of zoom must have the same + */ + + if(ev->x > get_width()) { + zoom = ev->x - get_width(); + + double higher = unzoomed_val + unzoomed_page - half_min_page - val_at_pointer; + double lower = val_at_pointer - (unzoomed_val + half_min_page); + + higher *= zoom / 128; + lower *= zoom / 128; + + val = unzoomed_val + lower; + page = unzoomed_page - higher - lower; + + page = max(page, min_page_size); + + if(lower < 0) { + val = max(val, val_at_pointer - half_min_page); + } + else if(lower > 0) { + val = min(val, val_at_pointer - half_min_page); + } + + val = min(val, adj.get_upper() - min_page_size); + page = min(page, adj.get_upper() - val); + } + else if (ev->x < 0) { + /* on zoom out increase the page size as well as moving the range towards the mouse pos*/ + zoom = abs(ev->x); + + /*double higher = unzoomed_val + unzoomed_page - half_min_page - val_at_pointer; + double lower = val_at_pointer - (unzoomed_val + half_min_page); + + higher *= zoom / 128; + lower *= zoom / 128; + + val = unzoomed_val + lower; + page = unzoomed_page - higher - lower; + + page = max(page, min_page_size); + + if(lower < 0) { + val = max(val, val_at_pointer - half_min_page); + } + else if(lower > 0) { + val = min(val, val_at_pointer - half_min_page); + } + + val = min(val, adj.get_upper() - min_page_size); + page = min(page, adj.get_upper() - val);*/ + + val = unzoomed_val; + page = unzoomed_page; + } + else { + val = unzoomed_val; + page = unzoomed_page; + } + + adj.set_page_size(page); + + if(val == adj.get_value()) { + adj.value_changed(); + } + if(val < adj.get_lower()) { + adj.value_changed(); + } + else if(val > adj.get_upper()) { + adj.value_changed(); + } + else { + adj.set_value(val); + } + + return true; +} + +bool +Scroomer::on_button_press_event (GdkEventButton* ev) { + if(ev->button == 1) { + Component comp = point_in(ev->y); + + if(comp == Total || comp == None) { + return false; + } + + add_modal_grab(); + grab_comp = comp; + grab_y = ev->y; + unzoomed_val = adj.get_value(); + unzoomed_page = adj.get_page_size(); + grab_window = ev->window; + } + return false; +} + +bool +Scroomer::on_button_release_event (GdkEventButton* ev) { + if(grab_comp == None || grab_comp == Total) { + return true; + } + + if (ev->window != grab_window) { + grab_y = ev->y; + grab_window = ev->window; + return true; + } + + if (ev->button != 1) { + return true; + } + + switch(grab_comp) { + case TopBase: + break; + case Handle1: + break; + case Slider: + break; + case Handle2: + break; + case BottomBase: + break; + default: + break; + } + + grab_comp = None; + + remove_modal_grab(); + return true; +} + +bool +Scroomer::on_scroll_event (GdkEventScroll*) { + return true; +} + +void +Scroomer::on_size_allocate (Allocation& a) { + Gtk::DrawingArea::on_size_allocate(a); + + position[Total] = a.get_height(); + set_min_page_size(min_page_size); + update(); +} + +/* + * assumes that x and width are correct, and they will not be altered + */ +void +Scroomer::set_comp_rect(GdkRectangle& r, Component c) const { + int index = (int) c; + + switch(c) { + case None: + return; + case Total: + r.y = 0; + r.height = position[Total]; + break; + default: + r.y = position[index]; + r.height = position[index+1] - position[index]; + break; + } +} + +Scroomer::Component +Scroomer::point_in(double point) const { + for(int i = 0; i < Total; ++i) { + if(position[i+1] >= point) { + return (Component) i; + } + } + + return None; +} + +void +Scroomer::set_min_page_size(double ps) { + double coeff = ((double)position[Total]) / (adj.get_upper() - adj.get_lower()); + + min_page_size = ps; + handle_size = (int) floor((ps * coeff) / 2); +} + +void +Scroomer::update() { + double range = adj.get_upper() - adj.get_lower(); + //double value = adj.get_value() - adj.get_lower(); + int height = position[Total]; + double coeff = ((double) height) / range; + + /* save the old positions to calculate update regions later*/ + for(int i = Handle1; i < Total; ++i) { + old_pos[i] = position[i]; + } + + position[BottomBase] = (int) floor(height - (adj.get_value() * coeff)); + position[Handle2] = position[BottomBase] - handle_size; + + position[Handle1] = (int) floor(height - ((adj.get_value() + adj.get_page_size()) * coeff)); + position[Slider] = position[Handle1] + handle_size; +} + +void +Scroomer::adjustment_changed() { + //cerr << floor(adj.get_value()) << " " << floor(adj.get_value() + adj.get_page_size()) << endl; + Gdk::Rectangle rect; + Glib::RefPtr<Gdk::Window> win = get_window(); + + update(); + + if(!win) { + return; + } + + rect.set_x(0); + rect.set_width(get_width()); + + if(position[Handle1] < old_pos[Handle1]) { + rect.set_y(position[Handle1]); + rect.set_height(old_pos[Slider] - position[Handle1]); + win->invalidate_rect(rect, false); + } + else if(position[Handle1] > old_pos[Handle1]) { + rect.set_y(old_pos[Handle1]); + rect.set_height(position[Slider] - old_pos[Handle1]); + win->invalidate_rect(rect, false); + } + + if(position[Handle2] < old_pos[Handle2]) { + rect.set_y(position[Handle2]); + rect.set_height(old_pos[BottomBase] - position[Handle2]); + win->invalidate_rect(rect, false); + } + else if(position[Handle2] > old_pos[Handle2]) { + rect.set_y(old_pos[Handle2]); + rect.set_height(position[BottomBase] - old_pos[Handle2]); + win->invalidate_rect(rect, false); + } + + win->process_updates(false); +} + +std::string +Scroomer::get_comp_name(Component c) { + switch(c) { + case TopBase: + return "TopBase"; + case Handle1: + return "Handle1"; + case Slider: + return "Slider"; + case Handle2: + return "Handle2"; + case BottomBase: + return "BottomBase"; + case Total: + return "Total"; + case None: + return "None"; + default: + return "ERROR"; + } +} diff --git a/libs/gtkmm2ext/selector.cc b/libs/gtkmm2ext/selector.cc new file mode 100644 index 0000000000..ee9a5578ba --- /dev/null +++ b/libs/gtkmm2ext/selector.cc @@ -0,0 +1,234 @@ +/* + Copyright (C) 1999 Paul Barton-Davis + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + $Id$ +*/ + +#include <algorithm> +#include <functional> +#include <vector> +#include <string> + +#include <gtkmm2ext/selector.h> +#include <gtkmm2ext/utils.h> +#include <pbd/pathscanner.h> + +using namespace std; +using namespace Gtkmm2ext; + +Selector::Selector (void (*func)(Glib::RefPtr<Gtk::ListStore>, void *), void *arg, + vector<string> titles) +{ + scroll.add (tview); + scroll.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC); + + pack_start (scroll, true, true); + + vector<string>::iterator i; + for (i = titles.begin(); i != titles.end(); ++i) { + Gtk::TreeModelColumn<Glib::ustring> title; + column_records.add(title); + } + + lstore = Gtk::ListStore::create(column_records); + tview.set_model(lstore); + + update_contents.connect(mem_fun(*this,&Selector::rescan)); + + tview.show (); + + refiller = func; + refill_arg = arg; + selected_row = -1; + selected_column = -1; +} + +Selector::~Selector () + +{ + /* ensure that any row data set with set_row_data_full() is deleted */ + hide_all (); + lstore.clear (); +} + +void +Selector::on_map() + +{ + Gtk::VBox::on_map (); + + selected_row = -1; + selected_column = -1; + refill(); +} + +void +Selector::on_show() +{ + VBox::on_show(); + + rescan(); +} + +void +Selector::reset (void (*func)(Glib::RefPtr<Gtk::ListStore>, void *), void *arg) + +{ + refiller = func; + refill_arg = arg; + selected_row = -1; + selected_column = -1; + + refill(); +} + +void +Selector::refill () + +{ + if (refiller) { + lstore.clear (); + refiller (lstore, refill_arg); + } +} + +gint +Selector::_accept (gpointer arg) + +{ + ((Selector *) arg)->accept (); + return FALSE; +} + +gint +Selector::_chosen (gpointer arg) + +{ + ((Selector *) arg)->chosen (); + return FALSE; +} + +gint +Selector::_shift_clicked (gpointer arg) +{ + ((Selector *) arg)->shift_clicked (); + return FALSE; +} + +gint +Selector::_control_clicked (gpointer arg) +{ + ((Selector *) arg)->control_clicked (); + return FALSE; +} + +void +Selector::accept () +{ + Glib::RefPtr<Gtk::TreeSelection> tree_sel = tview.get_selection(); + Gtk::TreeModel::iterator iter = tree_sel->get_selected(); + + if (iter) { + + selection_made (new Result (tview, tree_sel)); + } else { + cancel (); + } +} + +void +Selector::chosen () +{ + Glib::RefPtr<Gtk::TreeSelection> tree_sel = tview.get_selection(); + Gtk::TreeModel::iterator iter = tree_sel->get_selected(); + + if (iter) { + choice_made (new Result (tview, tree_sel)); + } else { + cancel (); + } +} + +void +Selector::shift_clicked () +{ + Glib::RefPtr<Gtk::TreeSelection> tree_sel = tview.get_selection(); + Gtk::TreeModel::iterator iter = tree_sel->get_selected(); + + if (iter) { + shift_made (new Result (tview, tree_sel)); + } else { + cancel (); + } +} + +void +Selector::control_clicked () +{ + Glib::RefPtr<Gtk::TreeSelection> tree_sel = tview.get_selection(); + Gtk::TreeModel::iterator iter = tree_sel->get_selected(); + + if (iter) { + control_made (new Result (tview, tree_sel)); + } else { + cancel (); + } +} + +void +Selector::cancel () +{ + Glib::RefPtr<Gtk::TreeSelection> tree_sel = tview.get_selection(); + tree_sel->unselect_all(); + + selection_made (new Result (tview, tree_sel)); +} + +void +Selector::rescan () + +{ + selected_row = -1; + selected_column = -1; + refill (); + show_all (); +} + +struct string_cmp { + bool operator()(const string* a, const string* b) { + return *a < *b; + } +}; + +bool +TreeView_Selector::on_button_press_event(GdkEventButton* ev) +{ + bool return_value = TreeView::on_button_press_event(ev); + + if (ev && (ev->type == GDK_BUTTON_RELEASE || ev->type == GDK_2BUTTON_PRESS)) { + if (ev->state & Gdk::CONTROL_MASK) { + g_idle_add (Selector::_control_clicked, this); + } else if (ev->state & Gdk::SHIFT_MASK) { + g_idle_add (Selector::_shift_clicked, this); + } else if (ev->type == GDK_2BUTTON_PRESS) { + g_idle_add (Selector::_accept, this); + } else { + g_idle_add (Selector::_chosen, this); + } + } + + return return_value; +} diff --git a/libs/gtkmm2ext/slider_controller.cc b/libs/gtkmm2ext/slider_controller.cc new file mode 100644 index 0000000000..93dfb27ae2 --- /dev/null +++ b/libs/gtkmm2ext/slider_controller.cc @@ -0,0 +1,91 @@ +/* + Copyright (C) 1998-99 Paul Davis + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + $Id$ +*/ + +#include <string> + +#include <gtkmm2ext/gtk_ui.h> +#include <gtkmm2ext/pixfader.h> +#include <gtkmm2ext/slider_controller.h> + +#include "i18n.h" + +using namespace Gtkmm2ext; +using namespace PBD; + +SliderController::SliderController (Glib::RefPtr<Gdk::Pixbuf> image, + Gtk::Adjustment *adj, int orientation, + Controllable& c, + bool with_numeric) + + : PixFader (image, *adj, orientation), + binding_proxy (c), + spin (*adj, 0, 2) +{ + spin.set_name ("SliderControllerValue"); + spin.set_size_request (70,-1); // should be based on font size somehow + spin.set_numeric (true); + spin.set_snap_to_ticks (false); +} + +void +SliderController::set_value (float v) +{ + adjustment.set_value (v); +} + +bool +SliderController::on_button_press_event (GdkEventButton *ev) +{ + if (binding_proxy.button_press_handler (ev)) { + return true; + } + return PixFader::on_button_press_event (ev); +} + +VSliderController::VSliderController (Glib::RefPtr<Gdk::Pixbuf> image, + Gtk::Adjustment *adj, + Controllable& control, + bool with_numeric) + + : SliderController (image, adj, VERT, control, with_numeric) +{ + if (with_numeric) { + spin_frame.add (spin); + spin_frame.set_shadow_type (Gtk::SHADOW_IN); + spin_frame.set_name ("BaseFrame"); + spin_hbox.pack_start (spin_frame, false, true); + // pack_start (spin_hbox, false, false); + } +} + +HSliderController::HSliderController (Glib::RefPtr<Gdk::Pixbuf> image, + Gtk::Adjustment *adj, + Controllable& control, + bool with_numeric) + + : SliderController (image, adj, HORIZ, control, with_numeric) +{ + if (with_numeric) { + spin_frame.add (spin); + //spin_frame.set_shadow_type (Gtk::SHADOW_IN); + spin_frame.set_name ("BaseFrame"); + spin_hbox.pack_start (spin_frame, false, true); + // pack_start (spin_hbox, false, false); + } +} diff --git a/libs/gtkmm2ext/stateful_button.cc b/libs/gtkmm2ext/stateful_button.cc new file mode 100644 index 0000000000..949cae958b --- /dev/null +++ b/libs/gtkmm2ext/stateful_button.cc @@ -0,0 +1,102 @@ +/* + Copyright (C) 2000-2007 Paul Davis + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#include <string> +#include <iostream> + +#include <gtkmm/main.h> + +#include <gtkmm2ext/stateful_button.h> + +using namespace Gtk; +using namespace Glib; +using namespace Gtkmm2ext; +using namespace std; + +StateButton::StateButton () +{ + _is_realized = false; + visual_state = 0; +} + +void +StateButton::set_visual_state (int n) +{ + if (!_is_realized) { + /* not yet realized */ + visual_state = n; + return; + } + + if (n == visual_state) { + return; + } + + string name = get_widget_name (); + name = name.substr (0, name.find_last_of ('-')); + + switch (n) { + case 0: + /* relax */ + break; + case 1: + name += "-active"; + break; + case 2: + name += "-alternate"; + break; + } + + set_widget_name (name); + visual_state = n; +} + +/* ----------------------------------------------------------------- */ + +void +StatefulToggleButton::on_realize () +{ + ToggleButton::on_realize (); + + _is_realized = true; + visual_state++; // to force transition + set_visual_state (visual_state - 1); +} + +void +StatefulButton::on_realize () +{ + Button::on_realize (); + + _is_realized = true; + visual_state++; // to force transition + set_visual_state (visual_state - 1); +} + +void +StatefulToggleButton::on_toggled () +{ + if (!_self_managed) { + if (get_active()) { + set_visual_state (1); + } else { + set_visual_state (0); + } + } +} diff --git a/libs/gtkmm2ext/sync-menu.c b/libs/gtkmm2ext/sync-menu.c new file mode 100644 index 0000000000..894446c424 --- /dev/null +++ b/libs/gtkmm2ext/sync-menu.c @@ -0,0 +1,977 @@ +/* GTK+ Integration for the Mac OS X Menubar. + * + * Copyright (C) 2007 Pioneer Research Center USA, Inc. + * Copyright (C) 2007 Imendio AB + * + * For further information, see: + * http://developer.imendio.com/projects/gtk-macosx/menubar + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; version 2.1 + * of the License. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include <gtk/gtk.h> +#include <gdk/gdkkeysyms.h> + +#include <Carbon/Carbon.h> + +#include <gtkmm2ext/sync-menu.h> + + +/* TODO + * + * - Sync adding/removing/reordering items + * - Create on demand? (can this be done with gtk+? ie fill in menu + items when the menu is opened) + * - Figure out what to do per app/window... + * + */ + +#define IGE_QUARTZ_MENU_CREATOR 'IGEC' +#define IGE_QUARTZ_ITEM_WIDGET 'IWID' + + +static void sync_menu_shell (GtkMenuShell *menu_shell, + MenuRef carbon_menu, + gboolean toplevel, + gboolean debug); + + +/* + * utility functions + */ + +static GtkWidget * +find_menu_label (GtkWidget *widget) +{ + GtkWidget *label = NULL; + + if (GTK_IS_LABEL (widget)) + return widget; + + if (GTK_IS_CONTAINER (widget)) + { + GList *children; + GList *l; + + children = gtk_container_get_children (GTK_CONTAINER (widget)); + + for (l = children; l; l = l->next) + { + label = find_menu_label (l->data); + if (label) + break; + } + + g_list_free (children); + } + + return label; +} + +static const gchar * +get_menu_label_text (GtkWidget *menu_item, + GtkWidget **label) +{ + GtkWidget *my_label; + + my_label = find_menu_label (menu_item); + if (label) + *label = my_label; + + if (my_label) + return gtk_label_get_text (GTK_LABEL (my_label)); + + return NULL; +} + +static gboolean +accel_find_func (GtkAccelKey *key, + GClosure *closure, + gpointer data) +{ + return (GClosure *) data == closure; +} + + +/* + * CarbonMenu functions + */ + +typedef struct +{ + MenuRef menu; +} CarbonMenu; + +static GQuark carbon_menu_quark = 0; + +static CarbonMenu * +carbon_menu_new (void) +{ + return g_slice_new0 (CarbonMenu); +} + +static void +carbon_menu_free (CarbonMenu *menu) +{ + g_slice_free (CarbonMenu, menu); +} + +static CarbonMenu * +carbon_menu_get (GtkWidget *widget) +{ + return g_object_get_qdata (G_OBJECT (widget), carbon_menu_quark); +} + +static void +carbon_menu_connect (GtkWidget *menu, + MenuRef menuRef) +{ + CarbonMenu *carbon_menu = carbon_menu_get (menu); + + if (!carbon_menu) + { + carbon_menu = carbon_menu_new (); + + g_object_set_qdata_full (G_OBJECT (menu), carbon_menu_quark, + carbon_menu, + (GDestroyNotify) carbon_menu_free); + } + + carbon_menu->menu = menuRef; +} + + +/* + * CarbonMenuItem functions + */ + +typedef struct +{ + MenuRef menu; + MenuItemIndex index; + MenuRef submenu; + GClosure *accel_closure; +} CarbonMenuItem; + +static GQuark carbon_menu_item_quark = 0; + +static CarbonMenuItem * +carbon_menu_item_new (void) +{ + return g_slice_new0 (CarbonMenuItem); +} + +static void +carbon_menu_item_free (CarbonMenuItem *menu_item) +{ + if (menu_item->accel_closure) + g_closure_unref (menu_item->accel_closure); + + g_slice_free (CarbonMenuItem, menu_item); +} + +static CarbonMenuItem * +carbon_menu_item_get (GtkWidget *widget) +{ + return g_object_get_qdata (G_OBJECT (widget), carbon_menu_item_quark); +} + +static void +carbon_menu_item_update_state (CarbonMenuItem *carbon_item, + GtkWidget *widget) +{ + gboolean sensitive; + gboolean visible; + UInt32 set_attrs = 0; + UInt32 clear_attrs = 0; + + g_object_get (widget, + "sensitive", &sensitive, + "visible", &visible, + NULL); + + if (!sensitive) + set_attrs |= kMenuItemAttrDisabled; + else + clear_attrs |= kMenuItemAttrDisabled; + + if (!visible) + set_attrs |= kMenuItemAttrHidden; + else + clear_attrs |= kMenuItemAttrHidden; + + ChangeMenuItemAttributes (carbon_item->menu, carbon_item->index, + set_attrs, clear_attrs); +} + +static void +carbon_menu_item_update_active (CarbonMenuItem *carbon_item, + GtkWidget *widget) +{ + gboolean active; + + g_object_get (widget, + "active", &active, + NULL); + + CheckMenuItem (carbon_item->menu, carbon_item->index, + active); +} + +static void +carbon_menu_item_update_submenu (CarbonMenuItem *carbon_item, + GtkWidget *widget) +{ + GtkWidget *submenu; + + submenu = gtk_menu_item_get_submenu (GTK_MENU_ITEM (widget)); + + if (submenu) + { + const gchar *label_text; + CFStringRef cfstr = NULL; + + label_text = get_menu_label_text (widget, NULL); + if (label_text) + cfstr = CFStringCreateWithCString (NULL, label_text, + kCFStringEncodingUTF8); + + CreateNewMenu (0, 0, &carbon_item->submenu); + SetMenuTitleWithCFString (carbon_item->submenu, cfstr); + SetMenuItemHierarchicalMenu (carbon_item->menu, carbon_item->index, + carbon_item->submenu); + + sync_menu_shell (GTK_MENU_SHELL (submenu), carbon_item->submenu, FALSE, FALSE); + + if (cfstr) + CFRelease (cfstr); + } + else + { + SetMenuItemHierarchicalMenu (carbon_item->menu, carbon_item->index, + NULL); + carbon_item->submenu = NULL; + } +} + +static void +carbon_menu_item_update_label (CarbonMenuItem *carbon_item, + GtkWidget *widget) +{ + const gchar *label_text; + CFStringRef cfstr = NULL; + + label_text = get_menu_label_text (widget, NULL); + if (label_text) + cfstr = CFStringCreateWithCString (NULL, label_text, + kCFStringEncodingUTF8); + + SetMenuItemTextWithCFString (carbon_item->menu, carbon_item->index, + cfstr); + + if (cfstr) + CFRelease (cfstr); +} + +static void +carbon_menu_item_update_accelerator (CarbonMenuItem *carbon_item, + GtkWidget *widget) +{ + GtkWidget *label; + + get_menu_label_text (widget, &label); + + if (GTK_IS_ACCEL_LABEL (label) && + GTK_ACCEL_LABEL (label)->accel_closure) + { + GtkAccelKey *key; + + key = gtk_accel_group_find (GTK_ACCEL_LABEL (label)->accel_group, + accel_find_func, + GTK_ACCEL_LABEL (label)->accel_closure); + + if (key && + key->accel_key && + key->accel_flags & GTK_ACCEL_VISIBLE) + { + GdkDisplay *display = gtk_widget_get_display (widget); + GdkKeymap *keymap = gdk_keymap_get_for_display (display); + GdkKeymapKey *keys; + gint n_keys; + gint use_command; + gboolean add_modifiers = FALSE; + + if (gdk_keymap_get_entries_for_keyval (keymap, key->accel_key, + &keys, &n_keys) == 0) + { + gint realkey = -1; + + switch (key->accel_key) { + case GDK_rightarrow: + case GDK_Right: + realkey = kRightArrowCharCode; + break; + case GDK_leftarrow: + case GDK_Left: + realkey = kLeftArrowCharCode; + break; + case GDK_uparrow: + case GDK_Up: + realkey = kUpArrowCharCode; + break; + case GDK_downarrow: + case GDK_Down: + realkey = kDownArrowCharCode; + break; + default: + break; + } + + if (realkey != -1) { + SetMenuItemCommandKey (carbon_item->menu, carbon_item->index, + false, realkey); + add_modifiers = TRUE; + } + + } else { + SetMenuItemCommandKey (carbon_item->menu, carbon_item->index, + true, keys[0].keycode); + g_free (keys); + add_modifiers = TRUE; + } + + if (add_modifiers) + { + UInt8 modifiers = 0; /* implies Command key */ + + use_command = 0; + + if (key->accel_mods) + { + if (key->accel_mods & GDK_SHIFT_MASK) { + modifiers |= kMenuShiftModifier; + } + + /* gdk/quartz maps Alt/Option to Mod1 */ + + if (key->accel_mods & (GDK_MOD1_MASK)) { + modifiers |= kMenuOptionModifier; + } + + if (key->accel_mods & GDK_CONTROL_MASK) { + modifiers |= kMenuControlModifier; + } + + /* gdk/quartz maps Command to Meta */ + + if (key->accel_mods & GDK_META_MASK) { + use_command = 1; + } + } + + if (!use_command) + modifiers |= kMenuNoCommandModifier; + + SetMenuItemModifiers (carbon_item->menu, carbon_item->index, + modifiers); + + return; + } + } + } + + /* otherwise, clear the menu shortcut */ + SetMenuItemModifiers (carbon_item->menu, carbon_item->index, + kMenuNoModifiers | kMenuNoCommandModifier); + ChangeMenuItemAttributes (carbon_item->menu, carbon_item->index, + 0, kMenuItemAttrUseVirtualKey); + SetMenuItemCommandKey (carbon_item->menu, carbon_item->index, + false, 0); +} + +static void +carbon_menu_item_accel_changed (GtkAccelGroup *accel_group, + guint keyval, + GdkModifierType modifier, + GClosure *accel_closure, + GtkWidget *widget) +{ + CarbonMenuItem *carbon_item = carbon_menu_item_get (widget); + GtkWidget *label; + + get_menu_label_text (widget, &label); + + if (GTK_IS_ACCEL_LABEL (label) && + GTK_ACCEL_LABEL (label)->accel_closure == accel_closure) + carbon_menu_item_update_accelerator (carbon_item, widget); +} + +static void +carbon_menu_item_update_accel_closure (CarbonMenuItem *carbon_item, + GtkWidget *widget) +{ + GtkAccelGroup *group; + GtkWidget *label; + + get_menu_label_text (widget, &label); + + if (carbon_item->accel_closure) + { + group = gtk_accel_group_from_accel_closure (carbon_item->accel_closure); + + g_signal_handlers_disconnect_by_func (group, + carbon_menu_item_accel_changed, + widget); + + g_closure_unref (carbon_item->accel_closure); + carbon_item->accel_closure = NULL; + } + + if (GTK_IS_ACCEL_LABEL (label)) + carbon_item->accel_closure = GTK_ACCEL_LABEL (label)->accel_closure; + + if (carbon_item->accel_closure) + { + g_closure_ref (carbon_item->accel_closure); + + group = gtk_accel_group_from_accel_closure (carbon_item->accel_closure); + + g_signal_connect_object (group, "accel-changed", + G_CALLBACK (carbon_menu_item_accel_changed), + widget, 0); + } + + carbon_menu_item_update_accelerator (carbon_item, widget); +} + +static void +carbon_menu_item_notify (GObject *object, + GParamSpec *pspec, + CarbonMenuItem *carbon_item) +{ + if (!strcmp (pspec->name, "sensitive") || + !strcmp (pspec->name, "visible")) + { + carbon_menu_item_update_state (carbon_item, GTK_WIDGET (object)); + } + else if (!strcmp (pspec->name, "active")) + { + carbon_menu_item_update_active (carbon_item, GTK_WIDGET (object)); + } + else if (!strcmp (pspec->name, "submenu")) + { + carbon_menu_item_update_submenu (carbon_item, GTK_WIDGET (object)); + } +} + +static void +carbon_menu_item_notify_label (GObject *object, + GParamSpec *pspec, + gpointer data) +{ + CarbonMenuItem *carbon_item = carbon_menu_item_get (GTK_WIDGET (object)); + + if (!strcmp (pspec->name, "label")) + { + carbon_menu_item_update_label (carbon_item, + GTK_WIDGET (object)); + } + else if (!strcmp (pspec->name, "accel-closure")) + { + carbon_menu_item_update_accel_closure (carbon_item, + GTK_WIDGET (object)); + } +} + +static CarbonMenuItem * +carbon_menu_item_connect (GtkWidget *menu_item, + GtkWidget *label, + MenuRef menu, + MenuItemIndex index) +{ + CarbonMenuItem *carbon_item = carbon_menu_item_get (menu_item); + + if (!carbon_item) + { + carbon_item = carbon_menu_item_new (); + + g_object_set_qdata_full (G_OBJECT (menu_item), carbon_menu_item_quark, + carbon_item, + (GDestroyNotify) carbon_menu_item_free); + + g_signal_connect (menu_item, "notify", + G_CALLBACK (carbon_menu_item_notify), + carbon_item); + + if (label) + g_signal_connect_swapped (label, "notify::label", + G_CALLBACK (carbon_menu_item_notify_label), + menu_item); + } + + carbon_item->menu = menu; + carbon_item->index = index; + + return carbon_item; +} + + +/* + * carbon event handler + */ + +static int _in_carbon_menu_event_handler = 0; + +int +gdk_quartz_in_carbon_menu_event_handler () +{ + return _in_carbon_menu_event_handler; +} + +static gboolean +dummy_gtk_menu_item_activate (gpointer *arg) +{ + gtk_menu_item_activate (GTK_MENU_ITEM(arg)); + return FALSE; +} + +static OSStatus +menu_event_handler_func (EventHandlerCallRef event_handler_call_ref, + EventRef event_ref, + void *data) +{ + UInt32 event_class = GetEventClass (event_ref); + UInt32 event_kind = GetEventKind (event_ref); + MenuRef menu_ref; + OSStatus ret; + + _in_carbon_menu_event_handler = 1; + + switch (event_class) + { + case kEventClassCommand: + /* This is called when activating (is that the right GTK+ term?) + * a menu item. + */ + if (event_kind == kEventCommandProcess) + { + HICommand command; + OSStatus err; + + /*g_printerr ("Menu: kEventClassCommand/kEventCommandProcess\n");*/ + + err = GetEventParameter (event_ref, kEventParamDirectObject, + typeHICommand, 0, + sizeof (command), 0, &command); + + if (err == noErr) + { + GtkWidget *widget = NULL; + + /* Get any GtkWidget associated with the item. */ + err = GetMenuItemProperty (command.menu.menuRef, + command.menu.menuItemIndex, + IGE_QUARTZ_MENU_CREATOR, + IGE_QUARTZ_ITEM_WIDGET, + sizeof (widget), 0, &widget); + if (err == noErr && GTK_IS_WIDGET (widget)) + { + g_idle_add (dummy_gtk_menu_item_activate, widget); + // gtk_menu_item_activate (GTK_MENU_ITEM (widget)); + _in_carbon_menu_event_handler = 0; + return noErr; + } + } + } + break; + + case kEventClassMenu: + GetEventParameter (event_ref, + kEventParamDirectObject, + typeMenuRef, + NULL, + sizeof (menu_ref), + NULL, + &menu_ref); + + switch (event_kind) + { + case kEventMenuTargetItem: + /* This is called when an item is selected (what is the + * GTK+ term? prelight?) + */ + /*g_printerr ("kEventClassMenu/kEventMenuTargetItem\n");*/ + break; + + case kEventMenuOpening: + /* Is it possible to dynamically build the menu here? We + * can at least set visibility/sensitivity. + */ + /*g_printerr ("kEventClassMenu/kEventMenuOpening\n");*/ + break; + + case kEventMenuClosed: + /*g_printerr ("kEventClassMenu/kEventMenuClosed\n");*/ + break; + + default: + break; + } + + break; + + default: + break; + } + + ret = CallNextEventHandler (event_handler_call_ref, event_ref); + _in_carbon_menu_event_handler = 0; + return ret; +} + +static void +setup_menu_event_handler (void) +{ + EventHandlerUPP menu_event_handler_upp; + EventHandlerRef menu_event_handler_ref; + const EventTypeSpec menu_events[] = { + { kEventClassCommand, kEventCommandProcess }, + { kEventClassMenu, kEventMenuTargetItem }, + { kEventClassMenu, kEventMenuOpening }, + { kEventClassMenu, kEventMenuClosed } + }; + + /* FIXME: We might have to install one per window? */ + + menu_event_handler_upp = NewEventHandlerUPP (menu_event_handler_func); + InstallEventHandler (GetApplicationEventTarget (), menu_event_handler_upp, + GetEventTypeCount (menu_events), menu_events, 0, + &menu_event_handler_ref); + +#if 0 + /* FIXME: Remove the handler with: */ + RemoveEventHandler(menu_event_handler_ref); + DisposeEventHandlerUPP(menu_event_handler_upp); +#endif +} + +static void +sync_menu_shell (GtkMenuShell *menu_shell, + MenuRef carbon_menu, + gboolean toplevel, + gboolean debug) +{ + GList *children; + GList *l; + MenuItemIndex carbon_index = 1; + + if (debug) + g_printerr ("%s: syncing shell %p\n", G_STRFUNC, menu_shell); + + carbon_menu_connect (GTK_WIDGET (menu_shell), carbon_menu); + + children = gtk_container_get_children (GTK_CONTAINER (menu_shell)); + + for (l = children; l; l = l->next) + { + GtkWidget *menu_item = l->data; + CarbonMenuItem *carbon_item; + + if (GTK_IS_TEAROFF_MENU_ITEM (menu_item)) + continue; + + if (toplevel && g_object_get_data (G_OBJECT (menu_item), + "gtk-empty-menu-item")) + continue; + + carbon_item = carbon_menu_item_get (menu_item); + + if (debug) + g_printerr ("%s: carbon_item %d for menu_item %d (%s, %s)\n", + G_STRFUNC, carbon_item ? carbon_item->index : -1, + carbon_index, get_menu_label_text (menu_item, NULL), + g_type_name (G_TYPE_FROM_INSTANCE (menu_item))); + + if (carbon_item && carbon_item->index != carbon_index) + { + if (debug) + g_printerr ("%s: -> not matching, deleting\n", G_STRFUNC); + + DeleteMenuItem (carbon_item->menu, carbon_index); + carbon_item = NULL; + } + + if (!carbon_item) + { + GtkWidget *label = NULL; + const gchar *label_text; + CFStringRef cfstr = NULL; + MenuItemAttributes attributes = 0; + + if (debug) + g_printerr ("%s: -> creating new\n", G_STRFUNC); + + label_text = get_menu_label_text (menu_item, &label); + if (label_text) + cfstr = CFStringCreateWithCString (NULL, label_text, + kCFStringEncodingUTF8); + + if (GTK_IS_SEPARATOR_MENU_ITEM (menu_item)) + attributes |= kMenuItemAttrSeparator; + + if (!GTK_WIDGET_IS_SENSITIVE (menu_item)) + attributes |= kMenuItemAttrDisabled; + + if (!GTK_WIDGET_VISIBLE (menu_item)) + attributes |= kMenuItemAttrHidden; + + InsertMenuItemTextWithCFString (carbon_menu, cfstr, + carbon_index - 1, + attributes, 0); + SetMenuItemProperty (carbon_menu, carbon_index, + IGE_QUARTZ_MENU_CREATOR, + IGE_QUARTZ_ITEM_WIDGET, + sizeof (menu_item), &menu_item); + + if (cfstr) + CFRelease (cfstr); + + carbon_item = carbon_menu_item_connect (menu_item, label, + carbon_menu, + carbon_index); + + if (GTK_IS_CHECK_MENU_ITEM (menu_item)) + carbon_menu_item_update_active (carbon_item, menu_item); + + carbon_menu_item_update_accel_closure (carbon_item, menu_item); + + if (gtk_menu_item_get_submenu (GTK_MENU_ITEM (menu_item))) + carbon_menu_item_update_submenu (carbon_item, menu_item); + } + + carbon_index++; + } + + g_list_free (children); +} + + +static gulong emission_hook_id = 0; + +static gboolean +parent_set_emission_hook (GSignalInvocationHint *ihint, + guint n_param_values, + const GValue *param_values, + gpointer data) +{ + GtkWidget *instance = g_value_get_object (param_values); + + if (GTK_IS_MENU_ITEM (instance)) + { + GtkWidget *previous_parent = g_value_get_object (param_values + 1); + GtkWidget *menu_shell = NULL; + + if (GTK_IS_MENU_SHELL (previous_parent)) + { + menu_shell = previous_parent; + } + else if (GTK_IS_MENU_SHELL (instance->parent)) + { + menu_shell = instance->parent; + } + + if (menu_shell) + { + CarbonMenu *carbon_menu = carbon_menu_get (menu_shell); + + if (carbon_menu) + { +#if 0 + g_printerr ("%s: item %s %p (%s, %s)\n", G_STRFUNC, + previous_parent ? "removed from" : "added to", + menu_shell, + get_menu_label_text (instance, NULL), + g_type_name (G_TYPE_FROM_INSTANCE (instance))); +#endif + + sync_menu_shell (GTK_MENU_SHELL (menu_shell), + carbon_menu->menu, + carbon_menu->menu == (MenuRef) data, + FALSE); + } + } + } + + return TRUE; +} + +static void +parent_set_emission_hook_remove (GtkWidget *widget, + gpointer data) +{ + g_signal_remove_emission_hook (g_signal_lookup ("parent-set", + GTK_TYPE_WIDGET), + emission_hook_id); +} + + +/* + * public functions + */ + +void +ige_mac_menu_set_menu_bar (GtkMenuShell *menu_shell) +{ + MenuRef carbon_menubar; + + g_return_if_fail (GTK_IS_MENU_SHELL (menu_shell)); + + if (carbon_menu_quark == 0) + carbon_menu_quark = g_quark_from_static_string ("CarbonMenu"); + + if (carbon_menu_item_quark == 0) + carbon_menu_item_quark = g_quark_from_static_string ("CarbonMenuItem"); + + CreateNewMenu (0 /*id*/, 0 /*options*/, &carbon_menubar); + SetRootMenu (carbon_menubar); + + setup_menu_event_handler (); + + emission_hook_id = + g_signal_add_emission_hook (g_signal_lookup ("parent-set", + GTK_TYPE_WIDGET), + 0, + parent_set_emission_hook, + carbon_menubar, NULL); + + g_signal_connect (menu_shell, "destroy", + G_CALLBACK (parent_set_emission_hook_remove), + NULL); + + sync_menu_shell (menu_shell, carbon_menubar, TRUE, FALSE); +} + +void +ige_mac_menu_set_quit_menu_item (GtkMenuItem *menu_item) +{ + MenuRef appmenu; + MenuItemIndex index; + + g_return_if_fail (GTK_IS_MENU_ITEM (menu_item)); + + if (GetIndMenuItemWithCommandID (NULL, kHICommandQuit, 1, + &appmenu, &index) == noErr) + { + SetMenuItemCommandID (appmenu, index, 0); + SetMenuItemProperty (appmenu, index, + IGE_QUARTZ_MENU_CREATOR, + IGE_QUARTZ_ITEM_WIDGET, + sizeof (menu_item), &menu_item); + + gtk_widget_hide (GTK_WIDGET (menu_item)); + } +} + + +struct _IgeMacMenuGroup +{ + GList *items; +}; + +static GList *app_menu_groups = NULL; + +IgeMacMenuGroup * +ige_mac_menu_add_app_menu_group (void) +{ + IgeMacMenuGroup *group = g_slice_new0 (IgeMacMenuGroup); + + app_menu_groups = g_list_append (app_menu_groups, group); + + return group; +} + +void +ige_mac_menu_add_app_menu_item (IgeMacMenuGroup *group, + GtkMenuItem *menu_item, + const gchar *label) +{ + MenuRef appmenu; + GList *list; + gint index = 0; + + g_return_if_fail (group != NULL); + g_return_if_fail (GTK_IS_MENU_ITEM (menu_item)); + + if (GetIndMenuItemWithCommandID (NULL, kHICommandHide, 1, + &appmenu, NULL) != noErr) + { + g_warning ("%s: retrieving app menu failed", + G_STRFUNC); + return; + } + + for (list = app_menu_groups; list; list = g_list_next (list)) + { + IgeMacMenuGroup *list_group = list->data; + + index += g_list_length (list_group->items); + + /* adjust index for the separator between groups, but not + * before the first group + */ + if (list_group->items && list->prev) + index++; + + if (group == list_group) + { + CFStringRef cfstr; + + /* add a separator before adding the first item, but not + * for the first group + */ + if (!group->items && list->prev) + { + InsertMenuItemTextWithCFString (appmenu, NULL, index, + kMenuItemAttrSeparator, 0); + index++; + } + + if (!label) + label = get_menu_label_text (GTK_WIDGET (menu_item), NULL); + + cfstr = CFStringCreateWithCString (NULL, label, + kCFStringEncodingUTF8); + + InsertMenuItemTextWithCFString (appmenu, cfstr, index, 0, 0); + SetMenuItemProperty (appmenu, index + 1, + IGE_QUARTZ_MENU_CREATOR, + IGE_QUARTZ_ITEM_WIDGET, + sizeof (menu_item), &menu_item); + + CFRelease (cfstr); + + gtk_widget_hide (GTK_WIDGET (menu_item)); + + group->items = g_list_append (group->items, menu_item); + + return; + } + } + + if (!list) + g_warning ("%s: app menu group %p does not exist", + G_STRFUNC, group); +} diff --git a/libs/gtkmm2ext/tearoff.cc b/libs/gtkmm2ext/tearoff.cc new file mode 100644 index 0000000000..92bde5541e --- /dev/null +++ b/libs/gtkmm2ext/tearoff.cc @@ -0,0 +1,197 @@ +/* + Copyright (C) 2003 Paul Barton-Davis + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + $Id$ +*/ + +#include <cmath> +#include <gtkmm2ext/tearoff.h> +#include <gtkmm2ext/utils.h> + +using namespace Gtkmm2ext; +using namespace Gtk; +using namespace Gdk; +using namespace Glib; +using namespace std; + +TearOff::TearOff (Widget& c, bool allow_resize) + : contents (c), + own_window (Gtk::WINDOW_TOPLEVEL), + tearoff_arrow (ARROW_DOWN, SHADOW_OUT), + close_arrow (ARROW_UP, SHADOW_OUT) +{ + dragging = false; + _visible = true; + + tearoff_event_box.add (tearoff_arrow); + tearoff_event_box.set_events (BUTTON_PRESS_MASK|BUTTON_RELEASE_MASK); + tearoff_event_box.signal_button_release_event().connect (mem_fun (*this, &TearOff::tearoff_click)); + + close_event_box.add (close_arrow); + close_event_box.set_events (BUTTON_PRESS_MASK|BUTTON_RELEASE_MASK); + close_event_box.signal_button_release_event().connect (mem_fun (*this, &TearOff::close_click)); + + own_window.add_events (BUTTON_PRESS_MASK|BUTTON_RELEASE_MASK|POINTER_MOTION_MASK|POINTER_MOTION_HINT_MASK); + own_window.set_resizable (allow_resize); + own_window.set_type_hint (WINDOW_TYPE_HINT_TOOLBAR); + + VBox* box1; + box1 = manage (new VBox); + box1->pack_start (close_event_box, false, false, 2); + + window_box.pack_end (*box1, false, false, 2); + own_window.add (window_box); + + own_window.signal_button_press_event().connect (mem_fun (*this, &TearOff::window_button_press)); + own_window.signal_button_release_event().connect (mem_fun (*this, &TearOff::window_button_release)); + own_window.signal_motion_notify_event().connect (mem_fun (*this, &TearOff::window_motion)); + own_window.signal_delete_event().connect (mem_fun (*this, &TearOff::window_delete_event)); + own_window.signal_realize().connect (bind (sigc::ptr_fun (Gtkmm2ext::set_decoration), &own_window, WMDecoration (DECOR_BORDER|DECOR_RESIZEH))); + + tearoff_arrow.set_name ("TearOffArrow"); + close_arrow.set_name ("TearOffArrow"); + + VBox* box2; + box2 = manage (new VBox); + box2->pack_start (tearoff_event_box, false, false, 2); + + pack_start (contents); + pack_start (*box2, false, false, 2); + +} + +TearOff::~TearOff () +{ +} + +void +TearOff::set_visible (bool yn) +{ + /* don't change visibility if torn off */ + + if (own_window.is_visible()) { + return; + } + + if (_visible != yn) { + _visible = yn; + if (yn) { + show_all(); + Visible (); + } else { + hide (); + Hidden (); + } + } +} + +gint +TearOff::tearoff_click (GdkEventButton* ev) +{ + remove (contents); + window_box.pack_start (contents); + own_window.set_name (get_name()); + close_event_box.set_name (get_name()); + own_window.show_all (); + hide (); + Detach (); + return true; +} + +gint +TearOff::close_click (GdkEventButton* ev) +{ + window_box.remove (contents); + pack_start (contents); + reorder_child (contents, 0); + own_window.hide (); + show_all (); + Attach (); + return true; +} + +gint +TearOff::window_button_press (GdkEventButton* ev) +{ + if (dragging || ev->button != 1) { + dragging = false; + own_window.remove_modal_grab(); + return true; + } + + dragging = true; + drag_x = ev->x_root; + drag_y = ev->y_root; + + own_window.add_modal_grab(); + + return true; +} + +gint +TearOff::window_button_release (GdkEventButton* ev) +{ + dragging = false; + own_window.remove_modal_grab(); + return true; +} + +gint +TearOff::window_delete_event (GdkEventAny* ev) +{ + return close_click(0); +} + +gint +TearOff::window_motion (GdkEventMotion* ev) +{ + gint x; + gint y; + gint mx, my; + double x_delta; + double y_delta; + RefPtr<Gdk::Window> win (own_window.get_window()); + + own_window.get_pointer (mx, my); + + if (!dragging) { + return true; + } + + if (!(ev->state & GDK_BUTTON1_MASK)) { + dragging = false; + own_window.remove_modal_grab(); + return true; + } + + x_delta = ev->x_root - drag_x; + y_delta = ev->y_root - drag_y; + + win->get_root_origin (x, y); + win->move ((gint) floor (x + x_delta), (gint) floor (y + y_delta)); + + drag_x = ev->x_root; + drag_y = ev->y_root; + + return true; +} + +bool +TearOff::torn_off() const +{ + return own_window.is_visible(); +} diff --git a/libs/gtkmm2ext/textviewer.cc b/libs/gtkmm2ext/textviewer.cc new file mode 100644 index 0000000000..8c89b845b7 --- /dev/null +++ b/libs/gtkmm2ext/textviewer.cc @@ -0,0 +1,127 @@ +/* + Copyright (C) 1999 Paul Barton-Davis + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + $Id$ +*/ + +#include <string> +#include <fstream> + +#include <gtkmm2ext/textviewer.h> + +#include "i18n.h" + +using namespace std; +using namespace Gtkmm2ext; +using namespace sigc; + +TextViewer::TextViewer (size_t xsize, size_t ysize) : + Gtk::Window (Gtk::WINDOW_TOPLEVEL), + Transmitter (Transmitter::Info), /* channel arg is irrelevant */ + dismiss (_("Close")) +{ + set_size_request (xsize, ysize); + + set_title ("Text Viewer"); + set_name ("TextViewer"); + set_resizable (true); + set_border_width (0); + + vbox1.set_homogeneous (false); + vbox1.set_spacing (0); + add (vbox1); + vbox1.show (); + + vbox2.set_homogeneous (false); + vbox2.set_spacing (10); + //vbox2.set_border_width (10); + + vbox1.pack_start (vbox2, true, true, 0); + vbox2.show (); + + vbox2.pack_start (scrollwin, TRUE, TRUE, 0); + scrollwin.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_ALWAYS); + scrollwin.show (); + + etext.set_editable (false); + etext.set_wrap_mode (Gtk::WRAP_WORD); + scrollwin.add (etext); + etext.show (); + + vbox1.pack_start (dismiss, false, false, 0); + dismiss.show (); + + dismiss.signal_clicked().connect(mem_fun (*this, &TextViewer::signal_released_handler)); +} + +void +TextViewer::signal_released_handler() +{ + hide(); +} + +void +TextViewer::insert_file (const string &path) + +{ + char buf[1024]; + ifstream f (path.c_str()); + + if (!f) { + return; + } + + Glib::RefPtr<Gtk::TextBuffer> tb (etext.get_buffer()); + + tb->begin_user_action(); + while (f) { + f.read (buf, sizeof (buf)); + + if (f.gcount()) { + buf[f.gcount()] = '\0'; + string foo (buf); + tb->insert (tb->end(), foo); + } + } + tb->end_user_action(); +} + +void +TextViewer::scroll_to_bottom () + +{ + Gtk::Adjustment *adj; + + adj = scrollwin.get_vadjustment(); + adj->set_value (MAX(0,(adj->get_upper() - adj->get_page_size()))); +} + +void +TextViewer::deliver () + +{ + char buf[1024]; + Glib::RefPtr<Gtk::TextBuffer> tb (etext.get_buffer()); + + while (!eof()) { + read (buf, sizeof (buf)); + buf[gcount()] = '\0'; + string foo (buf); + tb->insert (tb->end(), foo); + } + scroll_to_bottom (); + clear (); +} diff --git a/libs/gtkmm2ext/utils.cc b/libs/gtkmm2ext/utils.cc new file mode 100644 index 0000000000..57661a05af --- /dev/null +++ b/libs/gtkmm2ext/utils.cc @@ -0,0 +1,93 @@ +/* + Copyright (C) 1999 Paul Barton-Davis + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + $Id$ +*/ + +#include <map> + +#include <gtk/gtkpaned.h> +#include <gtk/gtk.h> + +#include <gtkmm2ext/utils.h> +#include <gtkmm/widget.h> +#include <gtkmm/button.h> +#include <gtkmm/window.h> +#include <gtkmm/paned.h> +#include <gtkmm/comboboxtext.h> + +#include "i18n.h" + +using namespace std; + +void +Gtkmm2ext::get_ink_pixel_size (Glib::RefPtr<Pango::Layout> layout, + int& width, + int& height) +{ + Pango::Rectangle ink_rect = layout->get_ink_extents (); + + width = (ink_rect.get_width() + PANGO_SCALE / 2) / PANGO_SCALE; + height = (ink_rect.get_height() + PANGO_SCALE / 2) / PANGO_SCALE; +} + +void +Gtkmm2ext::set_size_request_to_display_given_text (Gtk::Widget &w, const gchar *text, + gint hpadding, gint vpadding) + +{ + int width, height; + w.ensure_style (); + + get_ink_pixel_size (w.create_pango_layout (text), width, height); + w.set_size_request(width + hpadding, height + vpadding); +} + +void +Gtkmm2ext::init () +{ + // Necessary for gettext + (void) bindtextdomain(PACKAGE, LOCALEDIR); +} + +void +Gtkmm2ext::set_popdown_strings (Gtk::ComboBoxText& cr, const vector<string>& strings) +{ + cr.clear (); + + for (vector<string>::const_iterator i = strings.begin(); i != strings.end(); ++i) { + cr.append_text (*i); + } +} + +GdkWindow* +Gtkmm2ext::get_paned_handle (Gtk::Paned& paned) +{ + return GTK_PANED(paned.gobj())->handle; +} + +void +Gtkmm2ext::set_decoration (Gtk::Window* win, Gdk::WMDecoration decor) +{ + win->get_window()->set_decorations (decor); +} + +void Gtkmm2ext::set_treeview_header_as_default_label(Gtk::TreeViewColumn* c) +{ + gtk_tree_view_column_set_widget( c->gobj(), GTK_WIDGET(0) ); +} + diff --git a/libs/gtkmm2ext/window_title.cc b/libs/gtkmm2ext/window_title.cc new file mode 100644 index 0000000000..7c942d7f20 --- /dev/null +++ b/libs/gtkmm2ext/window_title.cc @@ -0,0 +1,45 @@ +/* + Copyright (C) 2000-2007 Paul Davis + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#include "gtkmm2ext/window_title.h" + +#include "i18n.h" + +namespace { + +// I don't know if this should be translated. +const char* const title_separator = X_(" - "); + +} // anonymous namespace + +namespace Gtkmm2ext { + +WindowTitle::WindowTitle(const string& title) + : m_title(title) +{ + +} + +void +WindowTitle::operator+= (const string& element) +{ + m_title = m_title + title_separator + element; +} + +} |