diff options
Diffstat (limited to 'libs/gtkmm2ext')
59 files changed, 6713 insertions, 0 deletions
diff --git a/libs/gtkmm2ext/.cvsignore b/libs/gtkmm2ext/.cvsignore new file mode 100644 index 0000000000..c3ceb3bfd5 --- /dev/null +++ b/libs/gtkmm2ext/.cvsignore @@ -0,0 +1,5 @@ +libgtkmmext.pc +libgtkmmext.spec +version.cc +*.mo +*.pot 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..e3ba3f1fcd --- /dev/null +++ b/libs/gtkmm2ext/SConscript @@ -0,0 +1,74 @@ +# -*- python -*- + +import os +import os.path +import glob + +Import('env final_prefix install_prefix libraries i18n') + +gtkmm2ext = env.Copy() +gtkmm2ext.Merge ([ + libraries['sigc2'], + libraries['pbd3'], + libraries['midi++2'], + libraries['gtk2'], + libraries['glibmm2'], + libraries['pangomm'], + libraries['atkmm'], + libraries['gdkmm2'], + libraries['gtkmm2'] + ]) + +# +# this defines the version number of libgtkmm2ext +# + +domain = 'libgtkmm2ext' + +gtkmm2ext.Append(DOMAIN=domain,MAJOR=0,MINOR=8,MICRO=0) +gtkmm2ext.Append(CXXFLAGS="-DPACKAGE=\\\"" + domain + "\\\"") +gtkmm2ext.Append(CCFLAGS="-DLIBSIGC_DISABLE_DEPRECATED") +gtkmm2ext.Append(PACKAGE=domain) +gtkmm2ext.Append(POTFILE=domain + '.pot') + +gtkmm2ext_files = Split(""" +auto_spin.cc +barcontroller.cc +bindable_button.cc +choice.cc +click_box.cc +controller.cc +fastmeter.cc +gtk_ui.cc +gtkutils.cc +hexentry.cc +idle_adjustment.cc +pix.cc +pixscroller.cc +popup.cc +prompter.cc +selector.cc +slider_controller.cc +tearoff.cc +textviewer.cc +utils.cc +version.cc +""") + +gtkmm2ext.VersionBuild(['version.cc','gtkmm2ext/version.h'], 'SConscript') + +gtkmm2ext.Append(CCFLAGS="-D_REENTRANT") +gtkmm2ext.Append(CCFLAGS="-DLOCALEDIR=\\\""+final_prefix+"/share/locale\\\"") + +libgtkmm2ext = gtkmm2ext.StaticLibrary('gtkmm2ext', gtkmm2ext_files) + +Default(libgtkmm2ext) + +if env['NLS']: + i18n (gtkmm2ext, gtkmm2ext_files, env) + +env.Alias('tarball', env.Distribute (env['DISTTREE'], + [ 'SConscript', 'i18n.h', 'gettext.h'] + + gtkmm2ext_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..0830eca77e --- /dev/null +++ b/libs/gtkmm2ext/auto_spin.cc @@ -0,0 +1,262 @@ +/* + 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) + : adjustment (adjr), + climb_rate (cr) + +{ + initial = adjustment.get_value(); + left_is_decrement = true; + wrap = false; + have_timer = false; + need_timer = false; + timer_calls = 0; +} + +void +AutoSpin::stop_timer () +{ + if (have_timer) { + gtk_timeout_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 = gtk_timeout_add (initial_timer_interval, + AutoSpin::_timer, + this); +} + +gint +AutoSpin::_timer (void *arg) +{ + return ((AutoSpin *) arg)->timer (); +} + +void +AutoSpin::set_value (gfloat value) +{ + 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; + } + } + + adjustment.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 = gtk_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); + + 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..01a952f558 --- /dev/null +++ b/libs/gtkmm2ext/barcontroller.cc @@ -0,0 +1,497 @@ +/* + 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 <midi++/controllable.h> + +#include <gtkmm2ext/gtk_ui.h> +#include <gtkmm2ext/barcontroller.h> + +#include "i18n.h" + +using namespace std; +using namespace Gtk; +using namespace Gtkmm2ext; + +BarController::BarController (Gtk::Adjustment& adj, + MIDI::Controllable *mc, + sigc::slot<void,char*,unsigned int> lc) + + : adjustment (adj), + prompter (Gtk::WIN_POS_MOUSE, 30000, false), + midi_control (mc), + label_callback (lc), + spinner (adjustment), + bind_button (2), + bind_statemask (Gdk::CONTROL_MASK) + +{ + _style = LeftToRight; + grabbed = false; + switching = false; + switch_on_release = false; + with_text = true; + use_parent = false; + + 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); + + 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)); + darea.signal_button_release_event().connect (mem_fun (*this, &BarController::button_release)); + + prompter.signal_unmap_event().connect (mem_fun (*this, &BarController::prompter_hiding)); + + prompting = false; + unprompting = false; + + if (mc) { + mc->learning_started.connect (mem_fun (*this, &BarController::midicontrol_prompt)); + mc->learning_stopped.connect (mem_fun (*this, &BarController::midicontrol_unprompt)); + } + + 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::set_bind_button_state (guint button, guint statemask) +{ + bind_button = button; + bind_statemask = statemask; +} + +void +BarController::get_bind_button_state (guint &button, guint &statemask) +{ + button = bind_button; + statemask = bind_statemask; +} + + +gint +BarController::button_press (GdkEventButton* ev) +{ + switch (ev->button) { + case 1: + if (ev->type == GDK_2BUTTON_PRESS) { + switch_on_release = true; + } 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: + case 3: + break; + + case 4: + case 5: + break; + } + + return FALSE; +} + +gint +BarController::button_release (GdkEventButton* ev) +{ + 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); + } + grabbed = false; + darea.remove_modal_grab(); + StopGesture (); + break; + + case 2: + if ((ev->state & bind_statemask) && bind_button == 2) { + midi_learn (); + } else { + double fract; + fract = ev->x / (darea.get_width() - 2.0); + adjustment.set_value (adjustment.get_lower() + + fract * (adjustment.get_upper() - adjustment.get_lower())); + } + return TRUE; + + case 3: + if ((ev->state & bind_statemask) && bind_button == 3) { + midi_learn (); + return TRUE; + } + return FALSE; + + case 4: + adjustment.set_value (adjustment.get_value() + + adjustment.get_step_increment()); + break; + case 5: + adjustment.set_value (adjustment.get_value() - + adjustment.get_step_increment()); + break; + } + + return TRUE; +} + +gint +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; + 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; +} + +gint +BarController::expose (GdkEventExpose* event) +{ + Glib::RefPtr<Gdk::Window> win (darea.get_window()); + Widget* parent; + gint x1, x2, y1, y2; + gint w, h; + double fract; + + w = darea.get_width() - 2; + h = darea.get_height() - 2; + + fract = ((adjustment.get_value() - adjustment.get_lower()) / + (adjustment.get_upper() - adjustment.get_lower())); + + switch (_style) { + case Line: + 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_height()); + } + + if (fract == 0.0) { + win->draw_rectangle (get_style()->get_fg_gc (get_state()), + true, x1, 1, 2, darea.get_height() - 2); + } else { + win->draw_rectangle (get_style()->get_fg_gc (get_state()), + true, x1 - 1, 1, 3, darea.get_height() - 2); + } + break; + + case CenterOut: + break; + + case LeftToRight: + 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(), darea.get_height()); + + /* 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'; + + label_callback (buf, 64); + + if (buf[0] != '\0') { + int width = 0, height; + darea.create_pango_layout(buf)->get_pixel_size(width, height); + darea.set_size_request(width + 2, -1); + } + } + return TRUE; +} + +void +BarController::set_with_text (bool yn) +{ + if (with_text != yn) { + with_text = yn; + queue_draw (); + } +} + +void +BarController::midicontrol_set_tip () +{ + if (midi_control) { + // Gtkmm2ext::UI::instance()->set_tip (&darea, midi_control->control_description()); + } +} + +void +BarController::midi_learn() +{ + if (midi_control) { + prompting = true; + midi_control->learn_about_external_control (); + } +} + + +void +BarController::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 +BarController::midicontrol_unprompt () +{ + if (unprompting) { + Gtkmm2ext::UI::instance()->touch_display (&prompter); + + unprompting = false; + } +} + +gint +BarController::prompter_hiding (GdkEventAny *ev) +{ + if (unprompting) { + if (midi_control) { + midi_control->stop_learning(); + } + unprompting = false; + } + + return FALSE; +} + + +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.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 (); +} + +gint +BarController::entry_focus_out (GdkEventFocus* ev) +{ + entry_activated (); + return TRUE; +} + +void +BarController::set_use_parent (bool yn) +{ + use_parent = yn; + queue_draw (); +} diff --git a/libs/gtkmm2ext/bindable_button.cc b/libs/gtkmm2ext/bindable_button.cc new file mode 100644 index 0000000000..c2516a9219 --- /dev/null +++ b/libs/gtkmm2ext/bindable_button.cc @@ -0,0 +1,155 @@ +/* + 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) + : ToggleButton (), + 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) + : ToggleButton (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 () +{ + signal_button_press_event().connect (mem_fun (*this, &BindableToggleButton::button_press)); + + 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 (); + } +} + + +gint +BindableToggleButton::button_press (GdkEventButton *ev) +{ + + if ((ev->state & bind_statemask) && ev->button == bind_button) { + midi_learn (); + return TRUE; + } + + return FALSE; +} + +gint +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/choice.cc b/libs/gtkmm2ext/choice.cc new file mode 100644 index 0000000000..5a3b7d0140 --- /dev/null +++ b/libs/gtkmm2ext/choice.cc @@ -0,0 +1,97 @@ +/* + 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/choice.h> + +using namespace std; +using namespace Gtkmm2ext; +using namespace sigc; +using namespace Gtk; + +Choice::Choice (string prompt, + vector<string> choices) + : Gtk::Window (WINDOW_TOPLEVEL), + prompt_label (prompt) +{ + int n; + vector<string>::iterator i; + + set_position (WIN_POS_MOUSE); + set_name ("ChoiceWindow"); + add (packer); + + packer.set_spacing (10); + packer.set_border_width (10); + packer.pack_start (prompt_label); + packer.pack_start (button_packer); + prompt_label.set_name ("ChoicePrompt"); + + for (n = 0, i = choices.begin(); i != choices.end(); ++i, ++n) { + Button *button = manage (new Gtk::Button (*i)); + button->set_name ("ChoiceButton"); + + button_packer.set_spacing (5); + button_packer.set_homogeneous (true); + button_packer.pack_start (*button, false, true); + + button->signal_clicked().connect (bind (mem_fun (*this, &Choice::_choice_made), n)); + buttons.push_back (button); + } + + signal_delete_event().connect(mem_fun(*this, &Choice::closed)); + + packer.show_all (); + which_choice = -1; +} + +void +Choice::on_realize () +{ + Gtk::Window::on_realize(); + Glib::RefPtr<Gdk::Window> win (get_window()); + win->set_decorations (Gdk::WMDecoration (Gdk::DECOR_BORDER|Gdk::DECOR_RESIZEH)); +} + +Choice::~Choice () +{ +} + +void +Choice::_choice_made (int nbutton) +{ + which_choice = nbutton; + choice_made (which_choice); + chosen (); +} + +gint +Choice::closed (GdkEventAny *ev) +{ + which_choice = -1; + choice_made (which_choice); + chosen (); + return TRUE; +} + +int +Choice::get_choice () +{ + return which_choice; +} diff --git a/libs/gtkmm2ext/click_box.cc b/libs/gtkmm2ext/click_box.cc new file mode 100644 index 0000000000..6bd03282eb --- /dev/null +++ b/libs/gtkmm2ext/click_box.cc @@ -0,0 +1,125 @@ +/* + 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) + : AutoSpin (*adjp) +{ + print_func = default_printer; + print_arg = 0; + + set_name (name); + add_events (Gdk::BUTTON_RELEASE_MASK| + Gdk::BUTTON_PRESS_MASK| + Gdk::ENTER_NOTIFY_MASK| + Gdk::LEAVE_NOTIFY_MASK); + set_label (); + + get_adjustment().signal_value_changed().connect (mem_fun (*this, &ClickBox::set_label)); + + signal_button_press_event().connect (mem_fun (*this, &ClickBox::button_press_handler)); + signal_button_release_event().connect (mem_fun (*this, &ClickBox::button_release_handler)); +} + +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); + remove_modal_grab(); + break; + default: + 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 () +{ + queue_draw (); +} + +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) { + + char buf[32]; + + Glib::RefPtr<Gtk::Style> style (get_style()); + + print_func (buf, get_adjustment(), print_arg); + + Glib::RefPtr <Gdk::Window> win (get_window()); + win->draw_rectangle (style->get_bg_gc(get_state()), + TRUE, 0, 0, -1, -1); + + { + int width = 0; + int height = 0; + create_pango_layout(buf)->get_pixel_size(width, height); + set_size_request(width, height); + } + } + + return true; +} diff --git a/libs/gtkmm2ext/controller.cc b/libs/gtkmm2ext/controller.cc new file mode 100644 index 0000000000..98d5566c69 --- /dev/null +++ b/libs/gtkmm2ext/controller.cc @@ -0,0 +1,92 @@ +/* + 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 <climits> + +#include <midi++/channel.h> +#include <gtkmm2ext/gtk_ui.h> +#include <gtkmm2ext/controller.h> + +#include "i18n.h" + +using namespace Gtkmm2ext; + +Controller::Controller (Gtk::Adjustment *adj, MIDI::Port *p) + : MIDI::Controllable (p), + adjustment (adj), + prompter (Gtk::WIN_POS_MOUSE, 30000, false) +{ + new_value_pending = false; + + /* hear about MIDI control learning */ + + learning_started.connect + (mem_fun (*this, &Controller::midicontrol_prompt)); + learning_stopped.connect + (mem_fun (*this, &Controller::midicontrol_unprompt)); +} + +void +Controller::midicontrol_prompt () + +{ + string prompt = _("operate MIDI controller now"); + + prompter.set_text (prompt); + Gtkmm2ext::UI::instance()->touch_display (&prompter); +} + +void +Controller::midicontrol_unprompt () + +{ + Gtkmm2ext::UI::instance()->touch_display (&prompter); +} + +int +Controller::update_controller_value (void *arg) + +{ + Controller *c = (Controller *) arg; + + c->adjustment->set_value (c->new_value); + c->new_value_pending = false; + + return FALSE; +} + +void +Controller::set_value (float v) + +{ + /* This is called from a MIDI callback. It could happen + a thousand times a second, or more. Therefore, instead + of going straight to the X server, which may not work for + thread-related reasons, simply request an update whenever + the GTK main loop is idle. + */ + + new_value = v; + + if (!new_value_pending) { + new_value_pending = true; + Gtkmm2ext::UI::instance()->idle_add (update_controller_value, this); + } +} diff --git a/libs/gtkmm2ext/fastmeter.cc b/libs/gtkmm2ext/fastmeter.cc new file mode 100644 index 0000000000..3eff07e915 --- /dev/null +++ b/libs/gtkmm2ext/fastmeter.cc @@ -0,0 +1,291 @@ +/* + 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. + + $Id$ +*/ + +#include <iostream> +#include <cmath> +#include <algorithm> +#include <gdkmm/rectangle.h> +#include <gtkmm2ext/fastmeter.h> +#include <gtkmm/style.h> + +using namespace Gtk; +using namespace Gtkmm2ext; +using namespace std; + +Glib::RefPtr<Gdk::Pixmap> *FastMeter::v_pixmap = 0; +Glib::RefPtr<Gdk::Bitmap> *FastMeter::v_mask = 0; +gint FastMeter::v_pixheight = 0; +gint FastMeter::v_pixwidth = 0; + +Glib::RefPtr<Gdk::Pixmap> *FastMeter::h_pixmap = 0; +Glib::RefPtr<Gdk::Bitmap> *FastMeter::h_mask = 0; +gint FastMeter::h_pixheight = 0; +gint FastMeter::h_pixwidth = 0; + +FastMeter::FastMeter (long hold, unsigned long dimen, Orientation o) +{ + orientation = o; + hold_cnt = hold; + hold_state = 0; + current_peak = 0; + current_level = 0; + current_user_level = -100.0f; + + set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK); + + pixrect.set_x(0); + pixrect.set_y(0); + + if (orientation == Vertical) { + pixrect.set_width(min (v_pixwidth, (gint) dimen)); + pixrect.set_height(v_pixheight); + } else { + pixrect.set_width(h_pixwidth); + pixrect.set_height(min (h_pixheight, (gint) dimen)); + } + + request_width = pixrect.get_width(); + request_height= pixrect.get_height(); + + backing = 0; +} + +FastMeter::~FastMeter () +{ + if (backing) { + (*backing)->unreference(); + } +} + +void +FastMeter::set_vertical_xpm (const char **xpm) +{ + if (v_pixmap == 0) { + gint w, h; + + *v_pixmap = Gdk::Pixmap::create_from_xpm(Gdk::Colormap::get_system(), *v_mask, xpm); + + (*v_pixmap)->get_size(w, h); + + v_pixheight = h; + v_pixwidth = w; + } +} + +void +FastMeter::set_horizontal_xpm (const char **xpm) +{ + if (h_pixmap == 0) { + gint w, h; + + *h_pixmap = Gdk::Pixmap::create_from_xpm(Gdk::Colormap::get_system(), *h_mask, xpm); + + (*h_pixmap)->get_size(w, h); + + h_pixheight = h; + h_pixwidth = w; + } +} + +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) +{ + req->width = request_width; + req->height = request_height; +} + +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) +{ + Gdk::Rectangle intersect; + gint top_of_meter; + bool blit = false; + bool intersecting = false; + + top_of_meter = (gint) floor (v_pixheight * current_level); + pixrect.set_height(v_pixheight - top_of_meter); /* bottom of background */ + + if (backing == 0) { + *backing = Gdk::Pixmap::create (get_window(), get_width(), get_height()); + } + + intersect = pixrect.intersect(Glib::wrap(&ev->area), intersecting); + if (intersecting) { + + /* paint the background (black). */ + (*backing)->draw_rectangle(get_style()->get_black_gc(), true, intersect.get_x(), intersect.get_y(), intersect.get_width(), intersect.get_height()); + blit = true; + } + + pixrect.set_height(top_of_meter); + + intersect = pixrect.intersect(Glib::wrap(&ev->area), intersecting); + if (intersecting) { + /* draw the part of the meter image that we need. the area we draw is bounded "in reverse" (top->bottom) + */ + + (*backing)->draw_drawable(get_style()->get_fg_gc(get_state()), *v_pixmap, + intersect.get_x(), v_pixheight - top_of_meter, + intersect.get_x(), v_pixheight - top_of_meter, + intersect.get_width(), intersect.get_height()); + + blit = true; + } + + /* draw peak bar */ + + if (hold_state) { + (*backing)->draw_drawable(get_style()->get_fg_gc(get_state()), *v_pixmap, + intersect.get_x(), v_pixheight - (gint) floor (v_pixheight * current_peak), + intersect.get_x(), v_pixheight - (gint) floor (v_pixheight * current_peak), + intersect.get_width(), 3); + } + + /* bilt to on-screen drawable */ + + if (blit) { + Glib::RefPtr<Gdk::Window> win (get_window()); + win->draw_drawable(get_style()->get_fg_gc(get_state()), *backing, + ev->area.x, ev->area.y, + ev->area.x, ev->area.y, + ev->area.width, ev->area.height); + } + + return true; +} + +bool +FastMeter::horizontal_expose (GdkEventExpose* ev) +{ + Gdk::Rectangle intersect; + bool intersecting = false; + gint right_of_meter; + bool blit = false; + + right_of_meter = (gint) floor (h_pixwidth * current_level); + + pixrect.set_x(right_of_meter); + pixrect.set_y(0); + pixrect.set_width(h_pixwidth - right_of_meter); + + if (backing == 0) { + *backing = Gdk::Pixmap::create(get_window(), get_width(), get_height()); + } + + intersect = pixrect.intersect(Glib::wrap(&ev->area), intersecting); + if (intersecting) { + /* paint the background (black). */ + + (*backing)->draw_rectangle(get_style()->get_black_gc(), true, + intersect.get_x(), intersect.get_y(), + intersect.get_width(), intersect.get_height()); + blit = true; + } + + pixrect.set_x(0); + pixrect.set_width(right_of_meter); + + intersect = pixrect.intersect(Glib::wrap(&ev->area), intersecting); + if (intersecting) { + /* draw the part of the meter image that we need. + */ + + (*backing)->draw_drawable(get_style()->get_fg_gc(get_state()), *h_pixmap, + intersect.get_x(), intersect.get_y(), + intersect.get_x(), intersect.get_y(), + intersect.get_width(), intersect.get_height()); + + blit = true; + } + + /* draw peak bar */ + + if (hold_state) { + (*backing)->draw_drawable(get_style()->get_fg_gc(get_state()), *h_pixmap, + right_of_meter, intersect.get_y(), + right_of_meter, intersect.get_y(), + 3, intersect.get_height()); + } + + /* bilt to on-screen drawable */ + + if (blit) { + Glib::RefPtr<Gdk::Window> win(get_window()); + win->draw_drawable(get_style()->get_fg_gc(get_state()), *backing, + ev->area.x, ev->area.y, + ev->area.x, ev->area.y, + ev->area.width, ev->area.height); + } + + return true; +} + +void +FastMeter::set (float lvl, float usrlvl) +{ + current_level = lvl; + current_user_level = usrlvl; + + if (lvl > current_peak) { + current_peak = lvl; + hold_state = hold_cnt; + } + + if (hold_state > 0) { + if (--hold_state == 0) { + current_peak = lvl; + } + } + + queue_draw (); +} + +void +FastMeter::clear () +{ + current_level = 0; + current_peak = 0; + hold_state = 0; + queue_draw (); +} 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/gtk_ui.cc b/libs/gtkmm2ext/gtk_ui.cc new file mode 100644 index 0000000000..d2a551144d --- /dev/null +++ b/libs/gtkmm2ext/gtk_ui.cc @@ -0,0 +1,823 @@ +/* + Copyright (C) 1999-2002 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 <gtkmm2ext/gtk_ui.h> +#include <gtkmm2ext/textviewer.h> +#include <gtkmm2ext/popup.h> +#include <gtkmm2ext/utils.h> + +#include "i18n.h" + +using namespace Gtkmm2ext; +using std::map; + +pthread_t UI::gui_thread; +UI *UI::theGtkUI = 0; + +UI::UI (string name, int *argc, char ***argv, string rcfile) + : _ui_name (name) +{ + theMain = new Gtk::Main (argc, argv); + tips = new Gtk::Tooltips; + + if (pthread_key_create (&thread_request_buffer_key, 0)) { + cerr << _("cannot create thread request buffer key") << endl; + throw failed_constructor(); + } + + PBD::ThreadCreated.connect (mem_fun (*this, &UI::register_thread)); + + _ok = false; + _active = false; + + if (!theGtkUI) { + theGtkUI = this; + gui_thread = pthread_self (); + } else { + fatal << "duplicate UI requested" << endmsg; + /* NOTREACHED */ + } + + if (setup_signal_pipe ()) { + return; + } + + load_rcfile (rcfile); + + errors = new TextViewer (850,100); + errors->text().set_editable (false); + errors->text().set_name ("ErrorText"); + + string title; + title = _ui_name; + title += ": Log"; + errors->set_title (title); + + errors->dismiss_button().set_name ("ErrorLogCloseButton"); +// errors->realize(); + + Glib::RefPtr<Gdk::Window> win(errors->get_window()); + win->set_decorations (Gdk::WMDecoration (Gdk::DECOR_BORDER|Gdk::DECOR_RESIZEH)); + + errors->signal_delete_event().connect (bind (ptr_fun (just_hide_it), (Gtk::Window *) errors)); + + register_thread (pthread_self(), X_("GUI")); + + _ok = true; +} + +UI::~UI () +{ + close (signal_pipe[0]); + close (signal_pipe[1]); +} + +int +UI::load_rcfile (string path) +{ + if (path.length() == 0) { + return -1; + } + + if (access (path.c_str(), R_OK)) { + error << "UI: couldn't find rc file \"" + << path + << '"' + << endmsg; + return -1; + } + + gtk_rc_parse (path.c_str()); + + Gtk::Label *a_widget1; + Gtk::Label *a_widget2; + Gtk::Label *a_widget3; + Gtk::Label *a_widget4; + + a_widget1 = new Gtk::Label; + a_widget2 = new Gtk::Label; + a_widget3 = new Gtk::Label; + a_widget4 = new Gtk::Label; + + a_widget1->set_name ("FatalMessage"); + a_widget1->ensure_style (); + fatal_message_style = a_widget1->get_style(); + + a_widget2->set_name ("ErrorMessage"); + a_widget2->ensure_style (); + error_message_style = a_widget2->get_style(); + + a_widget3->set_name ("WarningMessage"); + a_widget3->ensure_style (); + warning_message_style = a_widget3->get_style(); + + a_widget4->set_name ("InfoMessage"); + a_widget4->ensure_style (); + info_message_style = a_widget4->get_style(); + + delete a_widget1; + delete a_widget2; + delete a_widget3; + delete a_widget4; + + 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 () +{ + request (Quit); +} + +void +UI::do_quit () +{ + Gtk::Main::quit(); +} + +void +UI::touch_display (Touchable *display) +{ + Request *req = get_request (TouchDisplay); + + if (req == 0) { + return; + } + + req->display = display; + + send_request (req); +} + +void +UI::call_slot (sigc::slot<void> slot) +{ + Request *req = get_request (CallSlot); + + if (req == 0) { + return; + } + + req->slot = slot; + + send_request (req); +} + +void +UI::call_slot_locked (sigc::slot<void> slot) +{ + if (caller_is_gui_thread()) { + call_slot (slot); + return; + } + + Request *req = get_request (CallSlotLocked); + + if (req == 0) { + return; + } + + req->slot = slot; + + pthread_mutex_init (&req->slot_lock, NULL); + pthread_cond_init (&req->slot_cond, NULL); + pthread_mutex_lock (&req->slot_lock); + + send_request (req); + + pthread_cond_wait (&req->slot_cond, &req->slot_lock); + pthread_mutex_unlock (&req->slot_lock); + + delete req; +} + +void +UI::set_tip (Gtk::Widget *w, const gchar *tip, const gchar *hlp) +{ + Request *req = get_request (SetTip); + + if (req == 0) { + return; + } + + req->widget = w; + req->msg = tip; + req->msg2 = hlp; + + send_request (req); +} + +void +UI::set_state (Gtk::Widget *w, Gtk::StateType state) +{ + Request *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) +{ + Request *req = get_request (AddIdle); + + if (req == 0) { + return; + } + + req->function = func; + req->arg = arg; + + send_request (req); +} + +void +UI::timeout_add (unsigned int timeout, int (*func)(void *), void *arg) +{ + Request *req = get_request (AddTimeout); + + if (req == 0) { + return; + } + + req->function = func; + req->arg = arg; + req->timeout = timeout; + + send_request (req); +} + +/* END abstract_ui interfaces */ + +/* Handling requests */ + +void +UI::register_thread (pthread_t thread_id, string name) +{ + RingBufferNPT<Request>* b = new RingBufferNPT<Request> (128); + + { + PBD::LockMonitor lm (request_buffer_map_lock, __LINE__, __FILE__); + request_buffers[thread_id] = b; + } + + pthread_setspecific (thread_request_buffer_key, b); +} + +UI::Request::Request() +{ + +} + +UI::Request* +UI::get_request (RequestType rt) +{ + RingBufferNPT<Request>* rbuf = static_cast<RingBufferNPT<Request>* >(pthread_getspecific (thread_request_buffer_key)); + + if (rbuf == 0) { + /* Cannot happen, but if it does we can't use the error reporting mechanism */ + cerr << _("programming error: ") + << compose (X_("no GUI request buffer found for thread %1"), pthread_self()) + << endl; + abort (); + } + + RingBufferNPT<Request>::rw_vector vec; + + rbuf->get_write_vector (&vec); + + if (vec.len[0] == 0) { + if (vec.len[1] == 0) { + cerr << compose (X_("no space in GUI request buffer for thread %1"), pthread_self()) + << endl; + return 0; + } else { + vec.buf[1]->type = rt; + return vec.buf[1]; + } + } else { + vec.buf[0]->type = rt; + return vec.buf[0]; + } +} + +int +UI::setup_signal_pipe () +{ + /* setup the pipe that other threads send us notifications/requests + through. + */ + + if (pipe (signal_pipe)) { + error << "UI: cannot create error signal pipe (" + << strerror (errno) << ")" + << endmsg; + + return -1; + } + + if (fcntl (signal_pipe[0], F_SETFL, O_NONBLOCK)) { + error << "UI: cannot set O_NONBLOCK on " + "signal read pipe (" + << strerror (errno) << ")" + << endmsg; + return -1; + } + + if (fcntl (signal_pipe[1], F_SETFL, O_NONBLOCK)) { + error << "UI: cannot set O_NONBLOCK on " + "signal write pipe (" + << strerror (errno) + << ")" + << endmsg; + return -1; + } + + /* 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); + + return 0; +} + +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::handle_ui_requests () +{ + RequestBufferMap::iterator i; + + request_buffer_map_lock.lock (); + + for (i = request_buffers.begin(); i != request_buffers.end(); ++i) { + + RingBufferNPT<Request>::rw_vector vec; + + while (true) { + + /* we must process requests 1 by 1 because + the request may run a recursive main + event loop that will itself call + handle_ui_requests. when we return + from the request handler, we cannot + expect that the state of queued requests + is even remotely consistent with + the condition before we called it. + */ + + i->second->get_read_vector (&vec); + + if (vec.len[0] == 0) { + break; + } else { + /* copy constructor does a deep + copy of the Request object, + unlike Ringbuffer::read() + */ + Request req (*vec.buf[0]); + i->second->increment_read_ptr (1); + request_buffer_map_lock.unlock (); + do_request (&req); + request_buffer_map_lock.lock (); + } + } + } + + request_buffer_map_lock.unlock (); +} + +void +UI::do_request (Request* req) +{ + switch (req->type) { + case ErrorMessage: + process_error_message (req->chn, req->msg); + free (const_cast<char*>(req->msg)); /* it was strdup'ed */ + break; + + case Quit: + do_quit (); + break; + + case CallSlot: + req->slot (); + break; + + case CallSlotLocked: + pthread_mutex_lock (&req->slot_lock); + req->slot (); + pthread_cond_signal (&req->slot_cond); + pthread_mutex_unlock (&req->slot_lock); + break; + + case TouchDisplay: + req->display->touch (); + if (req->display->delete_after_touch()) { + delete req->display; + } + break; + + case StateChange: + req->widget->set_state (req->new_state); + break; + + case SetTip: + /* XXX need to figure out how this works */ + break; + + case AddIdle: + gtk_idle_add (req->function, req->arg); + break; + + case AddTimeout: + gtk_timeout_add (req->timeout, req->function, req->arg); + break; + + default: + error << "UI: unknown request type " + << (int) req->type + << endmsg; + } +} + +void +UI::send_request (Request *req) +{ + if (instance() == 0) { + return; /* XXX is this the right thing to do ? */ + } + + if (caller_is_gui_thread()) { + // cerr << "GUI thread sent request " << req << " type = " << req->type << endl; + do_request (req); + } else { + const char c = 0; + RingBufferNPT<Request*>* rbuf = static_cast<RingBufferNPT<Request*> *> (pthread_getspecific (thread_request_buffer_key)); + + if (rbuf == 0) { + /* can't use the error system to report this, because this + thread isn't registered! + */ + cerr << _("programming error: ") + << compose (X_("UI::send_request() called from %1, but no request buffer exists for that thread"), + pthread_self()) + << endl; + abort (); + } + + // cerr << "thread " << pthread_self() << " sent request " << req << " type = " << req->type << endl; + rbuf->increment_write_ptr (1); + write (signal_pipe[1], &c, 1); + } +} + +void +UI::request (RequestType rt) +{ + Request *req = get_request (rt); + + if (req == 0) { + return; + } + + send_request (req); +} + +/*====================================================================== + Error Display + ======================================================================*/ + +void +UI::receive (Transmitter::Channel chn, const char *str) +{ + if (caller_is_gui_thread()) { + process_error_message (chn, str); + } else { + Request* 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) +{ + Glib::RefPtr<Gtk::Style> style; + char *prefix; + size_t prefix_len; + bool fatal_received = false; +#ifndef OLD_STYLE_ERRORS + PopUp* popup = new PopUp (Gtk::WIN_POS_CENTER, 0, true); +#endif + + switch (chn) { + case Transmitter::Fatal: + prefix = "[FATAL]: "; + style = fatal_message_style; + prefix_len = 9; + fatal_received = true; + break; + case Transmitter::Error: +#if OLD_STYLE_ERRORS + prefix = "[ERROR]: "; + style = error_message_style; + 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]: "; + style = info_message_style; + 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]: "; + style = warning_message_style; + 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, style, 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 (Gtk::WIN_POS_MOUSE); + errors->show (); + } else { + errors->hide (); + } +} + +void +UI::display_message (const char *prefix, gint prefix_len, Glib::RefPtr<Gtk::Style> style, const char *msg) +{ + Glib::RefPtr<Gtk::TextBuffer::Tag> ptag = Gtk::TextBuffer::Tag::create(); + Glib::RefPtr<Gtk::TextBuffer::Tag> mtag = Gtk::TextBuffer::Tag::create(); + + Pango::FontDescription pfont(style->get_font()); + ptag->property_font_desc().set_value(pfont); + ptag->property_foreground_gdk().set_value(style->get_fg(Gtk::STATE_ACTIVE)); + ptag->property_background_gdk().set_value(style->get_bg(Gtk::STATE_ACTIVE)); + + Pango::FontDescription mfont (style->get_font()); + mtag->property_font_desc().set_value(mfont); + mtag->property_foreground_gdk().set_value(style->get_fg(Gtk::STATE_NORMAL)); + mtag->property_background_gdk().set_value(style->get_bg(Gtk::STATE_NORMAL)); + + Glib::RefPtr<Gtk::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) +{ + Gtk::Window win (Gtk::WINDOW_POPUP); + Gtk::VBox packer; + Gtk::Label label (message); + Gtk::Button quit (_("Press To Exit")); + + win.set_default_size (400, 100); + + string title; + title = _ui_name; + title += ": Fatal Error"; + win.set_title (title); + + win.set_position (Gtk::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_gui_thread()) { + error << "non-UI threads can't use UI::popup_error" + << endmsg; + return; + } + + pup = new PopUp (Gtk::WIN_POS_MOUSE, 0, true); + pup->set_text (text); + pup->touch (); +} + + +void +UI::flush_pending () +{ + if (!caller_is_gui_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, Gtk::Window *win) +{ + win->hide_all (); + return true; +} + +Gdk::Color +UI::get_color (const string& prompt, bool& picked, Gdk::Color* initial) +{ + Gdk::Color color; + + Gtk::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; + + Gtk::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; + Gtk::Main::quit (); +} + +bool +UI::color_selection_deleted (GdkEventAny *ev) +{ + Gtk::Main::quit (); + return true; +} diff --git a/libs/gtkmm2ext/gtkmm2ext-config.in b/libs/gtkmm2ext/gtkmm2ext-config.in new file mode 100644 index 0000000000..2744b20c52 --- /dev/null +++ b/libs/gtkmm2ext/gtkmm2ext-config.in @@ -0,0 +1,232 @@ +#!/bin/sh + +af_libs= +af_cflags= +prefix=@prefix@ +exec_prefix=@exec_prefix@ + + +## +## Define usage() +## +usage() +{ + cat <<EOF +Usage: pbd-config [OPTIONS] [LIBRARIES] +Options: + --cflags print pre-processor and compiler flags + --libs print library linking information + --libs-dirs only print the -L/-R part of --libs + --libs-names only print the -l part of --libs + --help display this help and exit + --macros print the path to m4 macros + + --prefix[=DIR] + --exec_prefix[=DIR] + --version output gtkmm2ext version information +Libraries: + gtkmm2ext +EOF + exit $1 +} + +## +## Process options +## +parse() +{ +# we must be called with at least one argument +if test $# -eq 0; then + usage 1 1>&2 +fi + +# at least one option should be selected +case "$1" in + --*) + ;; + *) + usage 1 1>&2 + ;; +esac + +# grab all -- arguments +while test $# -gt 0; do + case "$1" in + -*=*) af_optarg=`echo "$1" | sed 's/[-_a-zA-Z0-9]*=//'` ;; + *) af_optarg= ;; + esac + + case $1 in + --help) + usage 0 0>&2 + ;; + --cflags) + af_echo_cflags=yes + ;; + --libs) + af_echo_libs_L=yes + af_echo_libs_l=yes + ;; + --libs-dirs) + af_echo_libs_L=yes + ;; + --libs-names) + af_echo_libs_l=yes + ;; + --macros*) + +echo -I @prefix@/include/gtkmm2ext/macros +exit + + ;; + --prefix=*) + prefix=$af_optarg + af_prefix_set=yes + ;; + --prefix) + af_echo_prefix=yes + ;; + --exec_prefix=*) + exec_prefix=$af_optarg + af_exec_prefix_set=yes + ;; + --exec_prefix) + af_echo_exec_prefix=yes + ;; + --version) + af_echo_version=yes + ;; + --*) + usage 1 1>&2 + ;; + *) + break + ;; + esac + shift +done + +# if we have a default library use it +if test $# -eq 0; then +if test "X$af_lib_default" != "X"; then + af_lib__AF_LIB_DEFAULT=yes + return +fi +fi + +while test $# -gt 0; do + case $1 in + gtkmm2ext) + af_lib_gtkmm2ext=yes + ;; + *) + usage 1 1>&2 + ;; + esac + shift +done +} + +print_result() +{ +if test "X$af_echo_cflags" = "Xyes"; then + af_all_flags="$af_cflags" +fi + +if test "X$af_echo_libs_L" = "Xyes" || test "X$af_echo_libs_l" = "Xyes"; then + af_all_flags="$af_all_flags $af_libs" +fi + +if test -z "$af_all_flags" || test "X$af_all_flags" = "X "; then + exit 1 +fi + +# Straight out any possible duplicates, but be careful to +# get `-lfoo -lbar -lbaz' for `-lfoo -lbaz -lbar -lbaz' +af_other_flags= +af_lib_L_flags= +af_rev_libs= +for i in $af_all_flags; do + case "$i" in + # a library, save it for later, in reverse order + -l*) af_rev_libs="$i $af_rev_libs" ;; + -L*|-R*) + if test "X$af_echo_libs_L" = "Xyes"; then + case " $af_lib_L_flags " in + *\ $i\ *) ;; # already there + *) af_lib_L_flags="$af_lib_L_flags $i" ;; # add it to output + esac + fi;; + *) + case " $af_other_flags " in + *\ $i\ *) ;; # already there + *) af_other_flags="$af_other_flags $i" ;; # add it to output + esac ;; + esac +done + +af_ord_libs= +if test "X$af_echo_libs_l" = "Xyes"; then + for i in $af_rev_libs; do + case " $af_ord_libs " in + *\ $i\ *) ;; # already there + *) af_ord_libs="$i $af_ord_libs" ;; # add it to output in reverse order + esac + done +fi + +echo $af_other_flags $af_lib_L_flags $af_ord_libs +} + +## +## Main Body +## + +parse $* + + +## +## Initialize names +## + + + + + +if test "X$af_echo_prefix" = "Xyes"; then + echo $prefix +fi + +if test "X$af_echo_exec_prefix" = "Xyes"; then + echo $exec_prefix +fi + +if test "X$af_echo_version" = "Xyes"; then + echo @LIBGTKMMEXT_VERSION@ + exit 0 +fi + + +## +## Libraries +## + +#dummy because this should always be selected + + +if test "@includedir@" != /usr/include ; then + includes="-I@includedir@" +fi +if test "@libdir@" != /usr/lib ; then + libs="-L@libdir@" +fi +af_cflags="$af_cflags $includes @GLIB_CFLAGS@ @GTK_CFLAGS@ @GTKMM_CFLAGS@ @SIGC_CFLAGS@ " +af_libs="$libs -lgtkmm2ext @GLIB_LIBS@ @GTK_LIBS@ @GTKMM_LIBS@ @PBD_LIBS@ @SIGC_LIBS@ $af_libs" + + + + +print_result + +exit 0 + 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..41d83373ce --- /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. + + $Id$ +*/ + +#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); + + 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; + + 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..1a4b78009d --- /dev/null +++ b/libs/gtkmm2ext/gtkmm2ext/barcontroller.h @@ -0,0 +1,113 @@ +/* + 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$ +*/ + +#ifndef __gtkmm2ext_bar_controller_h__ +#define __gtkmm2ext_bar_controller_h__ + +#include <gtkmm.h> +#include <gtkmm2ext/popup.h> + +namespace MIDI { + class Controllable; +} + +namespace Gtkmm2ext { + +class BarController : public Gtk::Frame +{ + public: + BarController (Gtk::Adjustment& adj, MIDI::Controllable*, sigc::slot<void,char*,unsigned int>); + virtual ~BarController () {} + + void set_bind_button_state (guint button, guint statemask); + void get_bind_button_state (guint &button, guint &statemask); + void midicontrol_set_tip (); + void midi_learn (); + + void set_sensitive (bool yn) { + darea.set_sensitive (yn); + } + + 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); + + 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; } + + protected: + Gtk::Adjustment& adjustment; + Gtk::DrawingArea darea; + Gtkmm2ext::PopUp prompter; + MIDI::Controllable* midi_control; + sigc::slot<void,char*,unsigned int> label_callback; + 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; + + guint bind_button; + guint bind_statemask; + bool prompting, unprompting; + + gint button_press (GdkEventButton *); + gint button_release (GdkEventButton *); + gint motion (GdkEventMotion *); + gint expose (GdkEventExpose *); + + gint mouse_control (double x, GdkWindow* w, double scaling); + + gint prompter_hiding (GdkEventAny *); + void midicontrol_prompt (); + void midicontrol_unprompt (); + void update_midi_control (); + + gint switch_to_bar (); + gint switch_to_spinner (); + + void entry_activated (); + gint entry_focus_out (GdkEventFocus*); +}; + + +}; /* 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..1e460b3790 --- /dev/null +++ b/libs/gtkmm2ext/gtkmm2ext/bindable_button.h @@ -0,0 +1,77 @@ +/* + 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$ +*/ + +#ifndef __pbd_gtkmm_bindable_button_h__ +#define __pbd_gtkmm_bindable_button_h__ + +#include <gtkmm.h> +#include <gtkmm2ext/popup.h> + + +namespace MIDI { + class Controllable; +} + + +namespace Gtkmm2ext { + +class BindableToggleButton : public Gtk::ToggleButton +{ + public: + BindableToggleButton(MIDI::Controllable *); + + //: Create a check button with a label. + //- You won't be able + //- to add a widget in this button since it already has a {\class Gtk_Label} + //- in it. + explicit BindableToggleButton(MIDI::Controllable *, const string &label); + + virtual ~BindableToggleButton() {} + + void set_bind_button_state (guint button, guint statemask); + void get_bind_button_state (guint &button, guint &statemask); + + void midicontrol_set_tip (); + + void midi_learn (); + + protected: + + Gtkmm2ext::PopUp prompter; + + MIDI::Controllable* midi_control; + + guint bind_button; + guint bind_statemask; + + bool prompting, unprompting; + + void init_events (); + gint button_press (GdkEventButton *); + gint prompter_hiding (GdkEventAny *); + void midicontrol_prompt (); + void midicontrol_unprompt (); + + +}; + +}; + +#endif diff --git a/libs/gtkmm2ext/gtkmm2ext/choice.h b/libs/gtkmm2ext/gtkmm2ext/choice.h new file mode 100644 index 0000000000..4b8baede52 --- /dev/null +++ b/libs/gtkmm2ext/gtkmm2ext/choice.h @@ -0,0 +1,44 @@ +#ifndef __pbd_gtkmm_choice_h__ +#define __pbd_gtkmm_choice_h__ + +#include <gtkmm.h> +#include <vector> + +namespace Gtkmm2ext { + +class Choice : public Gtk::Window +{ + public: + Choice (std::string prompt, std::vector<std::string> choices); + virtual ~Choice (); + + /* This signal will be raised when a choice + is made or the choice window is deleted. + If the choice was to cancel, or the window + was deleted, then the argument will be -1. + Otherwise, it will be choice selected + of those presented, starting at zero. + */ + + sigc::signal<void,int> choice_made; + sigc::signal<void> chosen; + + int get_choice (); + + protected: + void on_realize (); + + private: + Gtk::VBox packer; + Gtk::Label prompt_label; + Gtk::HBox button_packer; + std::vector<Gtk::Button*> buttons; + int which_choice; + + void _choice_made (int nbutton); + gint closed (GdkEventAny *); +}; + +} /* 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..cc35afb6e1 --- /dev/null +++ b/libs/gtkmm2ext/gtkmm2ext/click_box.h @@ -0,0 +1,61 @@ +/* + 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$ +*/ + +#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); + ~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; + + void set_label (); + 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/controller.h b/libs/gtkmm2ext/gtkmm2ext/controller.h new file mode 100644 index 0000000000..b72f6c7ed7 --- /dev/null +++ b/libs/gtkmm2ext/gtkmm2ext/controller.h @@ -0,0 +1,59 @@ +/* + 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$ +*/ + +#ifndef __gtkmm2ext_controller_h__ +#define __gtkmm2ext_controller_h__ + +#include <gtkmm.h> +#include <gtkmm2ext/popup.h> +#include <midi++/controllable.h> + +namespace Gtkmm2ext { + +class Controller : public MIDI::Controllable + +{ + public: + Controller (Gtk::Adjustment *, MIDI::Port *); + virtual ~Controller () {} + + void set_value (float); + float lower () { return adjustment->get_lower(); } + float upper () { return adjustment->get_upper(); } + float range () { return upper() - lower() /* XXX +1 ??? */ ; } + + void midicontrol_prompt (); + void midicontrol_unprompt (); + + protected: + Gtk::Adjustment *adjustment; + + private: + Gtkmm2ext::PopUp prompter; + gfloat new_value; + bool new_value_pending; + + static gint update_controller_value (void *); +}; + +}; /* namespace */ + +#endif // __gtkmm2ext_controller_h__ + + diff --git a/libs/gtkmm2ext/gtkmm2ext/doi.h b/libs/gtkmm2ext/gtkmm2ext/doi.h new file mode 100644 index 0000000000..f804c8a090 --- /dev/null +++ b/libs/gtkmm2ext/gtkmm2ext/doi.h @@ -0,0 +1,37 @@ +/* + 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. + + $Id$ +*/ + +#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<class T> gint idle_delete (T *obj) { delete obj; return FALSE; } +template<class T> void delete_when_idle (T *obj) { + Gtk::Main::idle.connect (sigc::bind (sigc::slot (idle_delete<T>), obj)); +} +template<class T> gint delete_on_unmap (GdkEventAny *ignored, T *obj) { + Gtk::Main::idle.connect (sigc::bind (sigc::slot (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..5620a17a4d --- /dev/null +++ b/libs/gtkmm2ext/gtkmm2ext/fastmeter.h @@ -0,0 +1,85 @@ +/* + 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. + + $Id$ +*/ + +#ifndef __gtkmm2ext_fastmeter_h__ +#define __gtkmm2ext_fastmeter_h__ + +#include <gtkmm/drawingarea.h> +#include <gdkmm/pixmap.h> + +namespace Gtkmm2ext { + +class FastMeter : public Gtk::DrawingArea { + public: + enum Orientation { + Horizontal, + Vertical + }; + + FastMeter (long hold_cnt, unsigned long width, Orientation); + virtual ~FastMeter (); + + void set (float level, float user_level=0.0f); + 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); + + static void set_horizontal_xpm (const char **xpm); + static void set_vertical_xpm (const char **xpm); + + protected: + bool on_expose_event (GdkEventExpose*); + void on_size_request (GtkRequisition*); + + private: + static Glib::RefPtr<Gdk::Pixmap>* h_pixmap; + static Glib::RefPtr<Gdk::Bitmap>* h_mask; + static gint h_pixheight; + static gint h_pixwidth; + + static Glib::RefPtr<Gdk::Pixmap>* v_pixmap; + static Glib::RefPtr<Gdk::Bitmap>* v_mask; + static gint v_pixheight; + static gint v_pixwidth; + + Orientation orientation; + Glib::RefPtr<Gdk::Pixmap>* backing; + Gdk::Rectangle pixrect; + 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*); +}; + + +} /* namespace */ + + #endif /* __gtkmm2ext_fastmeter_h__ */ diff --git a/libs/gtkmm2ext/gtkmm2ext/gtk_ui.h b/libs/gtkmm2ext/gtkmm2ext/gtk_ui.h new file mode 100644 index 0000000000..147daa2623 --- /dev/null +++ b/libs/gtkmm2ext/gtkmm2ext/gtk_ui.h @@ -0,0 +1,219 @@ +/* + 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$ +*/ + +#ifndef __pbd_gtk_ui_h__ +#define __pbd_gtk_ui_h__ + +#include <string> +#include <queue> +#include <map> + +#include <pthread.h> +#include <gtkmm.h> +#include <pbd/abstract_ui.h> +#include <pbd/ringbufferNPT.h> +#include <pbd/atomic.h> +#include <pbd/pool.h> +#include <pbd/error.h> +#include <pbd/lockmonitor.h> + +using std::string; +using std::queue; + +class Touchable; + +namespace Gtkmm2ext { + +class TextViewer; + +class UI : public AbstractUI + +{ + public: + UI (string name, int *argc, char **argv[], string rcfile); + virtual ~UI (); + + static UI *instance() { return theGtkUI; } + + /* Abstract UI interfaces */ + + bool running (); + void quit (); + void kill (); + int load_rcfile (string); + void request (RequestType); + void run (Receiver &old_receiver); + void call_slot (sigc::slot<void>); + void call_slot_locked (sigc::slot<void>); + void touch_display (Touchable *); + void receive (Transmitter::Channel, const char *); + void register_thread (pthread_t, string); + + bool caller_is_gui_thread () { + return pthread_equal (gui_thread, pthread_self()); + } + + /* Gtk-UI specific interfaces */ + + void set_tip (Gtk::Widget *, const gchar *txt, const gchar *hlp = 0); + void set_state (Gtk::Widget *w, Gtk::StateType state); + void idle_add (int (*)(void *), void *); + void timeout_add (unsigned int, int (*)(void *), void *); + void popup_error (const char *text); + void flush_pending (); + void toggle_errors (); + + 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, 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; + + static bool just_hide_it (GdkEventAny *, Gtk::Window *); + + protected: + virtual void handle_fatal (const char *); + virtual void display_message (const char *prefix, gint prefix_len, + Glib::RefPtr<Gtk::Style> style, const char *msg); + + /* stuff to invoke member functions in another + thread so that we can keep the GUI running. + */ + + template<class UI_CLASS> struct thread_arg { + UI_CLASS *ui; + void (UI_CLASS::*func)(void *); + void *arg; + }; + + template<class UI_CLASS> static void *start_other_thread (void *arg); + template<class UI_CLASS> void other_thread (void (UI_CLASS::*func)(void *), void *arg = 0); + + private: + struct Request { + + /* 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. + */ + + RequestType type; + Touchable *display; + const char *msg; + Gtk::StateType new_state; + int (*function)(void *); + Gtk::Widget *widget; + Transmitter::Channel chn; + void *arg; + const char *msg2; + unsigned int timeout; + sigc::slot<void> slot; + + /* this is for CallSlotLocked requests */ + + pthread_mutex_t slot_lock; + pthread_cond_t slot_cond; + + Request (); + ~Request () { + if (type == ErrorMessage && msg) { + /* msg was strdup()'ed */ + free ((char *)msg); + } + } + }; + + static UI *theGtkUI; + static pthread_t gui_thread; + bool _active; + string _ui_name; + Gtk::Main *theMain; + Gtk::Tooltips *tips; + TextViewer *errors; + + /* error message display styles */ + + Glib::RefPtr<Gtk::Style> error_message_style; + Glib::RefPtr<Gtk::Style> info_message_style; + Glib::RefPtr<Gtk::Style> warning_message_style; + Glib::RefPtr<Gtk::Style> fatal_message_style; + + int signal_pipe[2]; + PBD::Lock request_buffer_map_lock; + typedef std::map<pthread_t,RingBufferNPT<Request>* > RequestBufferMap; + RequestBufferMap request_buffers; + Request* get_request(RequestType); + pthread_key_t thread_request_buffer_key; + + int setup_signal_pipe (); + + void handle_ui_requests (); + void do_request (Request *); + void send_request (Request *); + 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; +}; + +template<class UI_CLASS> void * +UI::start_other_thread (void *arg) + +{ + thread_arg<UI_CLASS> *ta = (thread_arg<UI_CLASS> *) arg; + (ta->ui->*ta->func)(ta->arg); + delete ta; + return 0; +} + +template<class UI_CLASS> void +UI::other_thread (void (UI_CLASS::*func)(void *), void *arg) + +{ + pthread_t thread_id; + thread_arg<UI_CLASS> *ta = new thread_arg<UI_CLASS>; + + ta->ui = dynamic_cast<UI_CLASS *> (this); + if (ta->ui == 0) { + error << "UI::other thread called illegally" + << endmsg; + return; + } + ta->func = func; + ta->arg = arg; + pthread_create (&thread_id, 0, start_other_thread, ta); +} + + +} /* 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..ae60252e83 --- /dev/null +++ b/libs/gtkmm2ext/gtkmm2ext/gtkutils.h @@ -0,0 +1,30 @@ +/* + 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$ +*/ + +#ifndef __gtkutils_h__ +#define __gtkutils_h__ + +#include <string> + +void set_usize_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..785d6eef36 --- /dev/null +++ b/libs/gtkmm2ext/gtkmm2ext/hexentry.h @@ -0,0 +1,59 @@ +/* + 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$ +*/ + +#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..48e1cc449c --- /dev/null +++ b/libs/gtkmm2ext/gtkmm2ext/idle_adjustment.h @@ -0,0 +1,26 @@ +#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/pix.h b/libs/gtkmm2ext/gtkmm2ext/pix.h new file mode 100644 index 0000000000..b06f6046ea --- /dev/null +++ b/libs/gtkmm2ext/gtkmm2ext/pix.h @@ -0,0 +1,87 @@ +#ifndef __pbd_gtkmm_pix_h__ +#define __pbd_gtkmm_pix_h__ + +#include <string> +#include <map> +#include <vector> +#include <gtkmm.h> + +namespace Gtkmm2ext { + +class Pix +{ + typedef std::map<std::string, Pix *> PixCache; + static PixCache *cache; + + PixCache::iterator cache_position; + int refcnt; + bool generated; + std::vector<std::string *> *files; + std::vector<const char **> data; + bool from_files; + int pixmap_count; + int last_pixmap; + Glib::RefPtr<Gdk::Pixmap> *pixmaps; + Glib::RefPtr<Gdk::Bitmap> *bitmaps; + int max_pixwidth; + int max_pixheight; + bool _homegenous; + + Pix (const std::string &dirpath, const std::string ®exp, + bool homogenous = true); + Pix (std::vector<const char **> xpm_data, bool homogenous = true); + virtual ~Pix(); + + friend Pix *get_pix (const std::string &dirpath, + const std::string ®exp, + bool homogenous); + friend Pix *get_pix (std::string name, + std::vector<const char **> xpm_data, + bool homogenous); + friend void finish_pix (Pix *); + + public: + Pix (bool homogenous = true); + + void generate (); + int n_pixmaps() { return pixmap_count; } + int max_pixmap() { return last_pixmap; } + bool homogenous () { return _homegenous; } + + /* ref/unref should really be protected, but we don't know the + name of the class that should have access to them. + */ + + void ref () { refcnt++; } + void unref () { if (refcnt) refcnt--; } + + Glib::RefPtr<Gdk::Bitmap>* shape_mask (int n) { + if (n < pixmap_count) { + return &bitmaps[n]; + } + return 0; + } + + Glib::RefPtr<Gdk::Pixmap>* pixmap(int n) { + if (n < pixmap_count) { + return &pixmaps[n]; + } + return 0; + } + + int max_width() { return max_pixwidth; } + int max_height() { return max_pixheight; } +}; + +extern Pix *get_pix (const std::string &dirpath, + const std::string ®exp, + bool homog = false); + +extern Pix *get_pix (std::string, + std::vector<const char **>, + bool homog = false); +extern void finish_pix (Pix *); + +} /* namespace */ + +#endif // __pbd_gtkmm_pix_h__ diff --git a/libs/gtkmm2ext/gtkmm2ext/pixscroller.h b/libs/gtkmm2ext/gtkmm2ext/pixscroller.h new file mode 100644 index 0000000000..4501a0c88c --- /dev/null +++ b/libs/gtkmm2ext/gtkmm2ext/pixscroller.h @@ -0,0 +1,47 @@ +#ifndef __gtkmm2ext_pixscroller_h__ +#define __gtkmm2ext_pixscroller_h__ + +#include <gtkmm/drawingarea.h> +#include <gtkmm/adjustment.h> +#include <gdkmm.h> + +#include <gtkmm2ext/pix.h> + +namespace Gtkmm2ext { + +class PixScroller : public Gtk::DrawingArea +{ + public: + PixScroller(Gtk::Adjustment& adjustment, Pix&); + + + bool on_expose_event (GdkEventExpose*); + bool on_motion_notify_event (GdkEventMotion*); + bool on_button_press_event (GdkEventButton*); + bool on_button_release_event (GdkEventButton*); + void on_size_request (GtkRequisition*); + + protected: + Gtk::Adjustment& adj; + + private: + Glib::RefPtr<Gdk::Pixmap> rail; + Glib::RefPtr<Gdk::Pixmap> slider; + Glib::RefPtr<Gdk::Bitmap> rail_mask; + Glib::RefPtr<Gdk::Bitmap> slider_mask; + 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..5684230f56 --- /dev/null +++ b/libs/gtkmm2ext/gtkmm2ext/popup.h @@ -0,0 +1,57 @@ +/* + 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$ +*/ + +#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* ); + + 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..5997cc8b24 --- /dev/null +++ b/libs/gtkmm2ext/gtkmm2ext/prompter.h @@ -0,0 +1,86 @@ +/* + 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$ +*/ + +#ifndef __gtkmm2ext_prompter_h__ +#define __gtkmm2ext_prompter_h__ + +#include <string> +#include <gtkmm.h> +#include <sigc++/sigc++.h> + +namespace Gtkmm2ext { + +class Prompter : public Gtk::Window + +{ + public: + Prompter (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); + + enum PrompterStatus { + entered, + cancelled + }; + + PrompterStatus status; + void get_result (std::string &str); + + /* the prompter will send a `done' signal when it is finished. + the "caller" can then check `status' and if it wants to + can then call `get_result()'. + */ + + sigc::signal<void> done; + + protected: + Gtk::Entry& the_entry() { return entry; } + + private: + Gtk::VBox packer; + Gtk::HBox buttonBox; + Gtk::Entry entry; + Gtk::VBox entryBox; + Gtk::Label entryLabel; + Gtk::Button ok; + Gtk::Button cancel; + + void activated (); + void cancel_click (); + + bool deleted (GdkEventAny *); + + void on_realize (); + void on_map (); +}; + +} /* namespace */ + +#endif /* __gtkmm2ext_prompter_h__ */ diff --git a/libs/gtkmm2ext/gtkmm2ext/selector.h b/libs/gtkmm2ext/gtkmm2ext/selector.h new file mode 100644 index 0000000000..f84c85cb4c --- /dev/null +++ b/libs/gtkmm2ext/gtkmm2ext/selector.h @@ -0,0 +1,103 @@ +/* + 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$ +*/ + +#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 (); + } + + /* selection is activated via a double click, choice via + a single click. + */ + sigc::signal<void,Gtk::TreeView&, Glib::RefPtr<Gtk::TreeSelection> > selection_made; + sigc::signal<void,Gtk::TreeView&, Glib::RefPtr<Gtk::TreeSelection> > choice_made; + sigc::signal<void,Gtk::TreeView&, Glib::RefPtr<Gtk::TreeSelection> > shift_made; + sigc::signal<void,Gtk::TreeView&, Glib::RefPtr<Gtk::TreeSelection> > 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..3cb8e9d363 --- /dev/null +++ b/libs/gtkmm2ext/gtkmm2ext/slider_controller.h @@ -0,0 +1,98 @@ +/* + 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$ +*/ + +#ifndef __gtkmm2ext_motion_controller_h__ +#define __gtkmm2ext_motion_controller_h__ + +#include <gtkmm.h> +#include <gtkmm2ext/popup.h> +#include <gtkmm2ext/pixscroller.h> + +namespace Gtkmm2ext { + class Pix; +} + +namespace MIDI { + class Controllable; +} + +namespace Gtkmm2ext { + +class SliderController : public Gtkmm2ext::PixScroller +{ + public: + SliderController (Gtkmm2ext::Pix* pixset, + Gtk::Adjustment* adj, + MIDI::Controllable*, + bool with_numeric = true); + + virtual ~SliderController () {} + + void set_bind_button_state (guint button, guint statemask); + void get_bind_button_state (guint &button, guint &statemask); + void midicontrol_set_tip (); + void midi_learn (); + + void set_value (float); + // void set_sensitive (bool yn) { + // spin.set_sensitive (yn); + // } + + Gtk::SpinButton & get_spin_button () { return spin; } + + protected: + Gtk::SpinButton spin; + Gtk::Frame spin_frame; + Gtk::HBox spin_hbox; + Gtkmm2ext::PopUp prompter; + MIDI::Controllable* midi_control; + + guint bind_button; + guint bind_statemask; + bool prompting, unprompting; + + bool button_press (GdkEventButton *); + bool prompter_hiding (GdkEventAny *); + void midicontrol_prompt (); + void midicontrol_unprompt (); + void update_midi_control (); +}; + +class VSliderController : public SliderController +{ + public: + VSliderController (Gtkmm2ext::Pix *pixset, + Gtk::Adjustment *adj, + MIDI::Controllable *, + bool with_numeric = true); +}; + +class HSliderController : public SliderController +{ + public: + HSliderController (Gtkmm2ext::Pix *pixset, + Gtk::Adjustment *adj, + MIDI::Controllable *, + bool with_numeric = true); +}; + + +}; /* namespace */ + +#endif // __gtkmm2ext_motion_controller_h__ diff --git a/libs/gtkmm2ext/gtkmm2ext/stop_signal.h b/libs/gtkmm2ext/gtkmm2ext/stop_signal.h new file mode 100644 index 0000000000..2890efecfb --- /dev/null +++ b/libs/gtkmm2ext/gtkmm2ext/stop_signal.h @@ -0,0 +1,14 @@ +#ifndef __ardour_gtk_stop_signal_h__ +#define __ardour_gtk_stop_signal_h__ + +#include <gtk--/widget.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.gtkobj()), signal_name); + return TRUE; +} + +#endif /* __ardour_gtk_stop_signal_h__ */ diff --git a/libs/gtkmm2ext/gtkmm2ext/tearoff.h b/libs/gtkmm2ext/gtkmm2ext/tearoff.h new file mode 100644 index 0000000000..d0478d5c57 --- /dev/null +++ b/libs/gtkmm2ext/gtkmm2ext/tearoff.h @@ -0,0 +1,63 @@ +/* + 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$ +*/ + +#ifndef __gtkmm2ext_tearoff_h__ +#define __gtkmm2ext_tearoff_h__ + +#include <gtkmm.h> + +namespace Gtkmm2ext { + +class TearOff : public Gtk::HBox +{ + public: + TearOff (Gtk::Widget& contents); + virtual ~TearOff (); + + sigc::signal<void> Detach; + sigc::signal<void> Attach; + + Gtk::Window* tearoff_window() const { 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; + + 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..280eb4437d --- /dev/null +++ b/libs/gtkmm2ext/gtkmm2ext/textviewer.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. + + $Id$ +*/ + +#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..867f9ed904 --- /dev/null +++ b/libs/gtkmm2ext/gtkmm2ext/utils.h @@ -0,0 +1,41 @@ +/* + 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$ +*/ + +#ifndef __gtkmm2ext_utils_h__ +#define __gtkmm2ext_utils_h__ + +#include <gtkmm.h> + +namespace Gtkmm2ext { + void init (); + + void set_usize_to_display_given_text (Gtk::Widget &w, + const gchar *text, + gint hpadding, + gint vpadding); + + template<class T> void deferred_delete (void *ptr) { + delete static_cast<T *> (ptr); + } +}; + +gint do_not_propagate (GdkEventButton*); + +#endif /* __gtkmm2ext_utils_h__ */ diff --git a/libs/gtkmm2ext/gtkutils.cc b/libs/gtkmm2ext/gtkutils.cc new file mode 100644 index 0000000000..a4e86b0a22 --- /dev/null +++ b/libs/gtkmm2ext/gtkutils.cc @@ -0,0 +1,41 @@ +/* + 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 <string> + +#include <gtkmm.h> +#include <gtkmm2ext/gtkutils.h> + +void +set_usize_to_display_given_text (Gtk::Widget &w, + const std::string& text, + gint hpadding, + gint vpadding) +{ + int height = 0; + int width = 0; + + w.create_pango_layout(text)->get_pixel_size(width, height); + + height += vpadding; + width += hpadding; + + w.set_size_request(width, height); +} 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..45118283c5 --- /dev/null +++ b/libs/gtkmm2ext/idle_adjustment.cc @@ -0,0 +1,54 @@ +#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/pix.cc b/libs/gtkmm2ext/pix.cc new file mode 100644 index 0000000000..c9f759b321 --- /dev/null +++ b/libs/gtkmm2ext/pix.cc @@ -0,0 +1,231 @@ +/* + 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 <algorithm> + +#include <gdkmm.h> +#include <gdkmm/pixmap.h> + +#include <pbd/pathscanner.h> +#include <pbd/stl_delete.h> +#include <pbd/failed_constructor.h> + +/* as of gcc 2.95.2, some of the stl_functors in this header are not + handled correctly. it sucks, but we put them inline here instead. + + #include <pbd/stl_functors.h> +*/ + +#include <gtkmm2ext/pix.h> + +namespace std +{ + template<> struct less<string *> { + bool operator()(string *s1, string *s2) const { + return *s1 < *s2; + } + }; +} + +using namespace std; +using namespace Gtkmm2ext; + +Pix::PixCache *Pix::cache; + +Pix::Pix (bool homog) + +{ + pixmap_count = 0; + _homegenous = homog; +} + +Pix::Pix (vector<const char **> xpm_data, bool homog) +{ + if (xpm_data.size() == 0) { + throw failed_constructor(); + } + + pixmap_count = xpm_data.size(); + last_pixmap = pixmap_count - 1; + refcnt = 0; + generated = false; + max_pixwidth = 0; + max_pixheight = 0; + _homegenous = homog; + + data = xpm_data; + from_files = false; + + pixmaps = new Glib::RefPtr<Gdk::Pixmap> [pixmap_count]; + bitmaps = new Glib::RefPtr<Gdk::Bitmap> [pixmap_count]; + memset (pixmaps, 0, sizeof (Glib::RefPtr<Gdk::Pixmap>) * pixmap_count); + memset (bitmaps, 0, sizeof (Glib::RefPtr<Gdk::Bitmap>) * pixmap_count); +} + +Pix::Pix (const string &dirpath, const string ®exp, bool homog) + +{ + PathScanner scanner; + less<string *> cmp; + + pixmap_count = 0; + last_pixmap = 0; + refcnt = 0; + generated = false; + max_pixwidth = 0; + max_pixheight = 0; + _homegenous = homog; + + pixmaps = 0; + bitmaps = 0; + + files = scanner (dirpath, regexp, false, true); + + sort (files->begin(), files->end(), cmp); + + if (files == 0) { + return; + } + + /* create handy reference */ + + if ((pixmap_count = files->size()) == 0) { + return; + } + + from_files = true; + pixmaps = new Glib::RefPtr<Gdk::Pixmap> [pixmap_count]; + bitmaps = new Glib::RefPtr<Gdk::Bitmap> [pixmap_count]; + memset (pixmaps, 0, sizeof (Glib::RefPtr<Gdk::Pixmap>) * pixmap_count); + memset (bitmaps, 0, sizeof (Glib::RefPtr<Gdk::Bitmap>) * pixmap_count); + + last_pixmap = pixmap_count - 1; +} + +Pix::~Pix () + +{ + if (from_files) { + vector_delete (files); + } + + if (pixmap_count) delete [] pixmaps; + if (pixmap_count) delete [] bitmaps; +} + +void +Pix::generate () + +{ + if (generated) { + return; + } + + for (int i = 0; i < pixmap_count; i++) { + if (from_files) { + string *strp; + strp = (*files)[i]; + const char* str(strp->c_str()); + + pixmaps[i] = Gdk::Pixmap::create_from_xpm (Gdk::Colormap::get_system(), + bitmaps[i], &str); + } else { + gchar **xpm; + xpm = const_cast<gchar **> (data[i]); + + pixmaps[i] = Gdk::Pixmap::create_from_xpm(Gdk::Colormap::get_system(), + bitmaps[i], Gdk::Color(), xpm); + } + + int w, h; + pixmaps[i]->get_size(w, h); + if (w > max_pixwidth) max_pixwidth = w; + if (h > max_pixheight) max_pixheight = h; + } + + generated = true; +} + +Pix * +Gtkmm2ext::get_pix (string name, vector<const char **> xpm_data, bool homog) +{ + Pix *ret = 0; + Pix::PixCache::iterator iter; + pair<string, Pix *> newpair; + + if (Pix::cache == 0) { + Pix::cache = new Pix::PixCache; + } + + if ((iter = Pix::cache->find (name)) == Pix::cache->end()) { + ret = new Pix (xpm_data, homog); + if (ret->pixmap_count == 0) { + delete ret; + return 0; + } + newpair.first = name; + newpair.second = ret; + ret->cache_position = (Pix::cache->insert (newpair)).first; + ret->refcnt++; + return ret; + } else { + (*iter).second->refcnt++; + return (*iter).second; + } +} + +Pix * +Gtkmm2ext::get_pix (const string &dirpath, const string ®exp, bool homog) +{ + Pix *ret = 0; + Pix::PixCache::iterator iter; + pair<string, Pix *> newpair; + + if (Pix::cache == 0) { + Pix::cache = new Pix::PixCache; + } + + if ((iter = Pix::cache->find (regexp)) == Pix::cache->end()) { + ret = new Pix (dirpath, regexp, homog); + if (ret->pixmap_count == 0) { + delete ret; + return 0; + } + newpair.first = regexp; + newpair.second = ret; + ret->cache_position = (Pix::cache->insert (newpair)).first; + ret->refcnt++; + return ret; + } else { + (*iter).second->refcnt++; + return (*iter).second; + } +} + +void +Gtkmm2ext::finish_pix (Pix *pix) + +{ + pix->refcnt--; + if (pix->refcnt == 0) { + Pix::cache->erase (pix->cache_position); + delete pix; + } +} diff --git a/libs/gtkmm2ext/pixscroller.cc b/libs/gtkmm2ext/pixscroller.cc new file mode 100644 index 0000000000..78f1725271 --- /dev/null +++ b/libs/gtkmm2ext/pixscroller.cc @@ -0,0 +1,248 @@ +/* + 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, Pix& pix) + : adj (a) +{ + dragging = false; + add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::POINTER_MOTION_MASK); + + adj.signal_value_changed().connect (mem_fun (*this, &PixScroller::adjustment_changed)); + default_value = adj.get_value(); + + pix.generate (); + + rail = *(pix.pixmap (0)); + rail_mask = *(pix.shape_mask (0)); + slider = *(pix.pixmap (1)); + slider_mask = *(pix.shape_mask (1)); + + int w, h; + + slider->get_size (w, h); + sliderrect.set_width(w); + sliderrect.set_height(h); + rail->get_size (w, h); + railrect.set_width(w); + railrect.set_height(h); + + 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) - 3); +} + +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_drawable (gc, rail, + intersect.x - railrect.get_x(), + intersect.y - railrect.get_y(), + intersect.x, + intersect.y, + intersect.width, + intersect.height); + } + + 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); +// Do these have a gtk2 equivalent? +// Gdk::GCValues values; +// gc->get_values(values); + gc->set_clip_origin (sliderrect.get_x(), sliderrect.get_y()); + gc->set_clip_mask (mask); + win->draw_drawable (gc, slider, + intersect.x - sliderrect.get_x(), + intersect.y - sliderrect.get_y(), + intersect.x, + intersect.y, + intersect.width, + intersect.height); +// gc->set_clip_origin(values.clip_x_origin, values.clip_y_origin); +// Gdk::Bitmap i_hate_gdk (values.clip_mask); +// gc->set_clip_mask (i_hate_gdk); + } + + + 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; + case 4: + /* wheel up */ + adj.set_value (adj.get_value() + (adj.get_page_increment() * scale)); + break; + case 5: + /* 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..28dd199ea3 --- /dev/null +++ b/libs/gtkmm2ext/po/el_GR.po @@ -0,0 +1,79 @@ +# Σχολιαστικός Τίτλος. +# Πνευματικά Δικαιώματα (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: 2005-03-12 11:01-0500\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:416 libs/gtkmm2ext/bindable_button.cc:136 +#: libs/gtkmm2ext/controller.cc:50 libs/gtkmm2ext/slider_controller.cc:141 +msgid "operate MIDI controller now" +msgstr "λειτουργία ελεγκτή MIDI τώρα" + +#: libs/gtkmm2ext/gtk_ui.cc:55 +msgid "cannot create thread request buffer key" +msgstr "" + +#: libs/gtkmm2ext/gtk_ui.cc:356 libs/gtkmm2ext/gtk_ui.cc:523 +msgid "programming error: " +msgstr "" + +#: libs/gtkmm2ext/gtk_ui.cc:688 +msgid "Press To Exit" +msgstr "" + +#: libs/gtkmm2ext/mwc.cc:33 libs/gtkmm2ext/popup_selector.cc:34 +#: libs/gtkmm2ext/prompter.cc:32 +msgid "OK" +msgstr "OK" + +#: libs/gtkmm2ext/newsavedialog.cc:26 +msgid "Location:" +msgstr "Τοποθεσία:" + +#: libs/gtkmm2ext/newsavedialog.cc:27 libs/gtkmm2ext/newsavedialog.cc:265 +msgid "Browse ..." +msgstr "Αναζήτηση ..." + +#: libs/gtkmm2ext/newsavedialog.cc:28 libs/gtkmm2ext/newsavedialog.cc:61 +#: libs/gtkmm2ext/prompter.cc:33 +msgid "Cancel" +msgstr "Ακύρωση" + +#: libs/gtkmm2ext/newsavedialog.cc:30 +msgid "New folder" +msgstr "Νέος φάκελος" + +#: libs/gtkmm2ext/newsavedialog.cc:31 +msgid "Add to favorites" +msgstr "Πρόσθεση στα 'Αγαπημένα'" + +#: libs/gtkmm2ext/newsavedialog.cc:32 +msgid "Remove from favorites" +msgstr "Απαλοιφή από τα 'Αγαπημένα'" + +#: libs/gtkmm2ext/newsavedialog.cc:33 +msgid "Show Hidden" +msgstr "Ανάδειξη κρυμμένων" + +#: libs/gtkmm2ext/newsavedialog.cc:53 libs/gtkmm2ext/newsavedialog.cc:269 +msgid "Hide browser" +msgstr "Απόκρυψη browser" + +#: libs/gtkmm2ext/popup_selector.cc:33 libs/gtkmm2ext/textviewer.cc:34 +msgid "Close" +msgstr "Κλείσιμο" + +#: libs/gtkmm2ext/popup_selector.cc:35 +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..fed58f060a --- /dev/null +++ b/libs/gtkmm2ext/po/es_ES.po @@ -0,0 +1,78 @@ +# 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: 2005-03-12 11:01-0500\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:416 libs/gtkmm2ext/bindable_button.cc:136 +#: libs/gtkmm2ext/controller.cc:50 libs/gtkmm2ext/slider_controller.cc:141 +msgid "operate MIDI controller now" +msgstr "Operar controladora de MIDI ahora" + +#: libs/gtkmm2ext/gtk_ui.cc:55 +msgid "cannot create thread request buffer key" +msgstr "" + +#: libs/gtkmm2ext/gtk_ui.cc:356 libs/gtkmm2ext/gtk_ui.cc:523 +msgid "programming error: " +msgstr "" + +#: libs/gtkmm2ext/gtk_ui.cc:688 +msgid "Press To Exit" +msgstr "" + +#: libs/gtkmm2ext/mwc.cc:33 libs/gtkmm2ext/popup_selector.cc:34 +#: libs/gtkmm2ext/prompter.cc:32 +msgid "OK" +msgstr "ACEPTAR" + +#: libs/gtkmm2ext/newsavedialog.cc:26 +msgid "Location:" +msgstr "Localizacin:" + +#: libs/gtkmm2ext/newsavedialog.cc:27 libs/gtkmm2ext/newsavedialog.cc:265 +msgid "Browse ..." +msgstr "Seleccionar ..." + +#: libs/gtkmm2ext/newsavedialog.cc:28 libs/gtkmm2ext/newsavedialog.cc:61 +#: libs/gtkmm2ext/prompter.cc:33 +msgid "Cancel" +msgstr "Cancelar" + +#: libs/gtkmm2ext/newsavedialog.cc:30 +msgid "New folder" +msgstr "Nueva carpeta" + +#: libs/gtkmm2ext/newsavedialog.cc:31 +msgid "Add to favorites" +msgstr "Agregar a favoritos" + +#: libs/gtkmm2ext/newsavedialog.cc:32 +msgid "Remove from favorites" +msgstr "Quitar de favoritos" + +#: libs/gtkmm2ext/newsavedialog.cc:33 +msgid "Show Hidden" +msgstr "Mostrar ocultos" + +#: libs/gtkmm2ext/newsavedialog.cc:53 libs/gtkmm2ext/newsavedialog.cc:269 +msgid "Hide browser" +msgstr "Ocultar explorador" + +#: libs/gtkmm2ext/popup_selector.cc:33 libs/gtkmm2ext/textviewer.cc:34 +msgid "Close" +msgstr "Cerrar" + +#: libs/gtkmm2ext/popup_selector.cc:35 +msgid "Rescan" +msgstr "Buscar de nuevo" diff --git a/libs/gtkmm2ext/po/pt_BR.po b/libs/gtkmm2ext/po/pt_BR.po new file mode 100644 index 0000000000..451e4adb3a --- /dev/null +++ b/libs/gtkmm2ext/po/pt_BR.po @@ -0,0 +1,79 @@ +# 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: 2005-03-12 11:01-0500\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:416 libs/gtkmm2ext/bindable_button.cc:136 +#: libs/gtkmm2ext/controller.cc:50 libs/gtkmm2ext/slider_controller.cc:141 +msgid "operate MIDI controller now" +msgstr "Operar controladora de MIDI agora" + +#: libs/gtkmm2ext/gtk_ui.cc:55 +msgid "cannot create thread request buffer key" +msgstr "" + +#: libs/gtkmm2ext/gtk_ui.cc:356 libs/gtkmm2ext/gtk_ui.cc:523 +msgid "programming error: " +msgstr "" + +#: libs/gtkmm2ext/gtk_ui.cc:688 +msgid "Press To Exit" +msgstr "" + +#: libs/gtkmm2ext/mwc.cc:33 libs/gtkmm2ext/popup_selector.cc:34 +#: libs/gtkmm2ext/prompter.cc:32 +msgid "OK" +msgstr "OK" + +#: libs/gtkmm2ext/newsavedialog.cc:26 +msgid "Location:" +msgstr "localizao:" + +#: libs/gtkmm2ext/newsavedialog.cc:27 libs/gtkmm2ext/newsavedialog.cc:265 +msgid "Browse ..." +msgstr "Localizar ..." + +#: libs/gtkmm2ext/newsavedialog.cc:28 libs/gtkmm2ext/newsavedialog.cc:61 +#: libs/gtkmm2ext/prompter.cc:33 +msgid "Cancel" +msgstr "Cancelar" + +#: libs/gtkmm2ext/newsavedialog.cc:30 +msgid "New folder" +msgstr "Novo diretrio" + +#: libs/gtkmm2ext/newsavedialog.cc:31 +msgid "Add to favorites" +msgstr "Adicionar a favoritos" + +#: libs/gtkmm2ext/newsavedialog.cc:32 +msgid "Remove from favorites" +msgstr "Remover de favoritos" + +#: libs/gtkmm2ext/newsavedialog.cc:33 +msgid "Show Hidden" +msgstr "Mostrar ocultos" + +#: libs/gtkmm2ext/newsavedialog.cc:53 libs/gtkmm2ext/newsavedialog.cc:269 +msgid "Hide browser" +msgstr "Ocultar explorador" + +#: libs/gtkmm2ext/popup_selector.cc:33 libs/gtkmm2ext/textviewer.cc:34 +msgid "Close" +msgstr "Fechar" + +#: libs/gtkmm2ext/popup_selector.cc:35 +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..4fc78f6987 --- /dev/null +++ b/libs/gtkmm2ext/po/ru_RU.po @@ -0,0 +1,78 @@ +# 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: 2005-03-12 11:01-0500\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:416 libs/gtkmm2ext/bindable_button.cc:136 +#: libs/gtkmm2ext/controller.cc:50 libs/gtkmm2ext/slider_controller.cc:141 +msgid "operate MIDI controller now" +msgstr " MIDI-" + +#: libs/gtkmm2ext/gtk_ui.cc:55 +msgid "cannot create thread request buffer key" +msgstr "" + +#: libs/gtkmm2ext/gtk_ui.cc:356 libs/gtkmm2ext/gtk_ui.cc:523 +msgid "programming error: " +msgstr "" + +#: libs/gtkmm2ext/gtk_ui.cc:688 +msgid "Press To Exit" +msgstr "" + +#: libs/gtkmm2ext/mwc.cc:33 libs/gtkmm2ext/popup_selector.cc:34 +#: libs/gtkmm2ext/prompter.cc:32 +msgid "OK" +msgstr "" + +#: libs/gtkmm2ext/newsavedialog.cc:26 +msgid "Location:" +msgstr ":" + +#: libs/gtkmm2ext/newsavedialog.cc:27 libs/gtkmm2ext/newsavedialog.cc:265 +msgid "Browse ..." +msgstr " ..." + +#: libs/gtkmm2ext/newsavedialog.cc:28 libs/gtkmm2ext/newsavedialog.cc:61 +#: libs/gtkmm2ext/prompter.cc:33 +msgid "Cancel" +msgstr "" + +#: libs/gtkmm2ext/newsavedialog.cc:30 +msgid "New folder" +msgstr " " + +#: libs/gtkmm2ext/newsavedialog.cc:31 +msgid "Add to favorites" +msgstr " " + +#: libs/gtkmm2ext/newsavedialog.cc:32 +msgid "Remove from favorites" +msgstr " " + +#: libs/gtkmm2ext/newsavedialog.cc:33 +msgid "Show Hidden" +msgstr " " + +#: libs/gtkmm2ext/newsavedialog.cc:53 libs/gtkmm2ext/newsavedialog.cc:269 +msgid "Hide browser" +msgstr " " + +#: libs/gtkmm2ext/popup_selector.cc:33 libs/gtkmm2ext/textviewer.cc:34 +msgid "Close" +msgstr "" + +#: libs/gtkmm2ext/popup_selector.cc:35 +msgid "Rescan" +msgstr "" diff --git a/libs/gtkmm2ext/popup.cc b/libs/gtkmm2ext/popup.cc new file mode 100644 index 0000000000..540edba5c3 --- /dev/null +++ b/libs/gtkmm2ext/popup.cc @@ -0,0 +1,134 @@ +/* + 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) +{ + + realize (); + Glib::RefPtr<Gdk::Window> win (get_window()); + win->set_decorations (Gdk::WMDecoration (Gdk::DECOR_BORDER|Gdk::DECOR_RESIZEH)); + 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 () +{ +} + +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 (delete_on_hide) { + std::cerr << "deleting prompter\n"; + if (popdown_time != 0 && timeout != -1) { + gtk_timeout_remove (timeout); + } + gtk_idle_add (idle_delete, this); + } +} + +void +PopUp::touch () +{ + if (is_visible ()) { + remove (); + } else { + set_usize_to_display_given_text (label, my_text.c_str(), 25, 10); + label.set_text (my_text); + show_all (); + + if (popdown_time != 0) { + timeout = gtk_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 (delete_on_hide) { + std::cerr << "deleting prompter\n" << endl; + if (popdown_time != 0 && timeout != -1) { + gtk_timeout_remove (timeout); + } + gtk_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..83a64e78d4 --- /dev/null +++ b/libs/gtkmm2ext/prompter.cc @@ -0,0 +1,118 @@ +/* + 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 <gtkmm2ext/prompter.h> + +#include "i18n.h" + +using namespace std; +using namespace Gtkmm2ext; + +Prompter::Prompter (bool modal) + : Gtk::Window (Gtk::WINDOW_POPUP), + ok (_("OK")), + cancel (_("Cancel")) +{ + set_position (Gtk::WIN_POS_MOUSE); + set_name ("Prompter"); + set_modal (modal); + + add (packer); + + entryLabel.set_line_wrap (true); + entryLabel.set_name ("PrompterLabel"); + + entryBox.set_homogeneous (false); + entryBox.set_spacing (25); + entryBox.set_border_width (10); + entryBox.pack_start (entryLabel); + entryBox.pack_start (entry, false, false); + + buttonBox.set_homogeneous (true); + buttonBox.set_border_width (10); + buttonBox.pack_start (ok, false, true); + buttonBox.pack_start (cancel, false, true); + + packer.pack_start (entryBox); + packer.pack_start (buttonBox); + + entry.signal_activate().connect(mem_fun(*this,&Prompter::activated)); + ok.signal_clicked().connect(mem_fun(*this,&Prompter::activated)); + cancel.signal_clicked().connect(mem_fun(*this,&Prompter::cancel_click)); + signal_delete_event().connect (mem_fun (*this, &Prompter::deleted)); + +} + +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::on_realize () +{ + Gtk::Window::on_realize (); + Glib::RefPtr<Gdk::Window> win (get_window()); + win->set_decorations (Gdk::WMDecoration (Gdk::DECOR_BORDER|Gdk::DECOR_RESIZEH|Gdk::DECOR_MENU)); +} + +void +Prompter::on_map () +{ + entry.grab_focus(); + Gtk::Window::on_map (); +} + +void +Prompter::activated () + +{ + status = entered; + hide_all (); + done (); +} + +void +Prompter::cancel_click () + +{ + entry.set_text (""); + status = cancelled; + hide_all (); + done (); +} + +bool +Prompter::deleted (GdkEventAny *ev) +{ + cancel_click (); + return false; +} + +void +Prompter::get_result (string &str) + +{ + str = entry.get_text (); +} diff --git a/libs/gtkmm2ext/selector.cc b/libs/gtkmm2ext/selector.cc new file mode 100644 index 0000000000..371c946fe7 --- /dev/null +++ b/libs/gtkmm2ext/selector.cc @@ -0,0 +1,238 @@ +/* + 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> +#include <pbd/error.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 (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 (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 (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 (tview, tree_sel); + } else { + cancel (); + } +} + +void +Selector::cancel () + +{ + Glib::RefPtr<Gtk::TreeSelection> tree_sel = tview.get_selection(); + tree_sel->unselect_all(); + + selection_made (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) { + gtk_idle_add (Selector::_control_clicked, this); + } else if (ev->state & Gdk::SHIFT_MASK) { + gtk_idle_add (Selector::_shift_clicked, this); + } else if (ev->type == GDK_2BUTTON_PRESS) { + gtk_idle_add (Selector::_accept, this); + } else { + gtk_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..ca75fbb7b4 --- /dev/null +++ b/libs/gtkmm2ext/slider_controller.cc @@ -0,0 +1,183 @@ +/* + 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 <climits> + +#include <midi++/controllable.h> + +#include <gtkmm2ext/gtk_ui.h> +#include <gtkmm2ext/slider_controller.h> +#include <gtkmm2ext/pix.h> + +#include "i18n.h" + +using namespace Gtkmm2ext; + +SliderController::SliderController (Pix *pixset, + Gtk::Adjustment *adj, + MIDI::Controllable *mc, + bool with_numeric) + + : PixScroller (*adj, *pixset), + spin (*adj, 0, 2), + prompter (Gtk::WIN_POS_MOUSE, 30000, false), + midi_control (mc), + bind_button (2), + bind_statemask (Gdk::CONTROL_MASK) + +{ + pixset->generate (); + + signal_button_press_event().connect (mem_fun (this, &SliderController::button_press)); + 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); + + prompter.signal_unmap_event().connect (mem_fun (*this, &SliderController::prompter_hiding)); + + prompting = false; + unprompting = false; + + if (mc) { + mc->learning_started.connect (mem_fun (*this, &SliderController::midicontrol_prompt)); + mc->learning_stopped.connect (mem_fun (*this, &SliderController::midicontrol_unprompt)); + } +} + +void +SliderController::set_value (float v) +{ + adj.set_value (v); +} + +void +SliderController::set_bind_button_state (guint button, guint statemask) +{ + bind_button = button; + bind_statemask = statemask; +} + +void +SliderController::get_bind_button_state (guint &button, guint &statemask) +{ + button = bind_button; + statemask = bind_statemask; +} + +void +SliderController::midi_learn() +{ + if (midi_control) { + prompting = true; + midi_control->learn_about_external_control (); + } +} + +bool +SliderController::button_press (GdkEventButton *ev) +{ + if ((ev->state & bind_statemask) && ev->button == bind_button) { + midi_learn (); + return true; + } + + return false; +} + +void +SliderController::midicontrol_set_tip () + +{ + if (midi_control) { + // Gtkmm2ext::UI::instance()->set_tip (this, midi_control->control_description()); + } +} + +bool +SliderController::prompter_hiding (GdkEventAny *ev) +{ + if (unprompting) { + if (midi_control) { + midi_control->stop_learning(); + } + unprompting = false; + } + + return false; +} + +void +SliderController::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 +SliderController::midicontrol_unprompt () + +{ + if (unprompting) { + Gtkmm2ext::UI::instance()->touch_display (&prompter); + unprompting = false; + } +} + + +VSliderController::VSliderController (Pix *pixset, + Gtk::Adjustment *adj, + MIDI::Controllable *mcontrol, + bool with_numeric) + + : SliderController (pixset, adj, mcontrol, 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 (Pix *pixset, + Gtk::Adjustment *adj, + MIDI::Controllable *mcontrol, + bool with_numeric) + + : SliderController (pixset, adj, mcontrol, 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/tearoff.cc b/libs/gtkmm2ext/tearoff.cc new file mode 100644 index 0000000000..c9dd89ac52 --- /dev/null +++ b/libs/gtkmm2ext/tearoff.cc @@ -0,0 +1,164 @@ +/* + 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> + +using namespace Gtkmm2ext; +using namespace Gtk; +using namespace std; + +TearOff::TearOff (Gtk::Widget& c) + : contents (c), + tearoff_arrow (Gtk::ARROW_DOWN, Gtk::SHADOW_OUT), + close_arrow (Gtk::ARROW_UP, Gtk::SHADOW_OUT) +{ + dragging = false; + + tearoff_event_box.add (tearoff_arrow); + tearoff_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::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 (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK); + close_event_box.signal_button_release_event().connect (mem_fun (*this, &TearOff::close_click)); + + own_window = new Gtk::Window (Gtk::WINDOW_TOPLEVEL); + own_window->add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::POINTER_MOTION_MASK|Gdk::POINTER_MOTION_HINT_MASK); + own_window->set_resizable (false); +// own_window->realize (); + + Glib::RefPtr<Gdk::Window> win (own_window->get_window()); + win->set_decorations (Gdk::WMDecoration (Gdk::DECOR_BORDER|Gdk::DECOR_RESIZEH)); + + VBox* box1; + box1 = manage (new VBox); + box1->pack_start (close_event_box, false, false, 5); + + 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)); + + tearoff_arrow.set_name ("TearOffArrow"); + close_arrow.set_name ("TearOffArrow"); + + VBox* box2; + box2 = manage (new VBox); + box2->pack_start (tearoff_event_box, false, false, 5); + + pack_start (contents); + pack_start (*box2, false, false, 2); + +} + +TearOff::~TearOff () +{ + delete own_window; +} + +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 (); +// own_window->realize (); + 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) +{ + 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; + Glib::RefPtr<Gdk::Window> win (own_window->get_window()); + + own_window->get_pointer (mx, my); + + if (!dragging) { + 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..0366c02f12 --- /dev/null +++ b/libs/gtkmm2ext/utils.cc @@ -0,0 +1,47 @@ +/* + 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/utils.h> +#include <gtkmm2ext/gtkutils.h> + +#include "i18n.h" + +void +Gtkmm2ext::set_usize_to_display_given_text (Gtk::Widget &w, const gchar *text, + gint hpadding, gint vpadding) + +{ + w.ensure_style (); + set_usize_to_display_given_text(w, text, hpadding, vpadding); +} + +gint +do_not_propagate (GdkEventButton *ev) +{ + return TRUE; +} + +void +Gtkmm2ext::init () +{ + // Necessary for gettext + (void) bindtextdomain(PACKAGE, LOCALEDIR); +} + |