[gcalctool] Move conversion bar into its own module



commit acebc60c11dc4bc806eb919a0da42a259d009a39
Author: Robert Ancell <robert ancell canonical com>
Date:   Wed Dec 22 09:21:26 2010 +1100

    Move conversion bar into its own module

 data/buttons-advanced.ui |  158 +++++-----------
 src/Makefile.am          |    2 +
 src/math-buttons.c       |  309 +-------------------------------
 src/math-converter.c     |  449 ++++++++++++++++++++++++++++++++++++++++++++++
 src/math-converter.h     |   53 ++++++
 5 files changed, 561 insertions(+), 410 deletions(-)
---
diff --git a/data/buttons-advanced.ui b/data/buttons-advanced.ui
index 607afdc..43c4590 100644
--- a/data/buttons-advanced.ui
+++ b/data/buttons-advanced.ui
@@ -8,65 +8,6 @@
         <property name="visible">True</property>
         <property name="spacing">6</property>
         <child>
-          <object class="GtkHBox" id="hbox1">
-            <property name="visible">True</property>
-            <property name="spacing">6</property>
-            <child>
-              <object class="GtkHBox" id="hbox3">
-                <property name="visible">True</property>
-                <child>
-                  <object class="GtkComboBox" id="convert_from_combo">
-                    <property name="visible">True</property>
-                    <property name="focus_on_click">False</property>
-                  </object>
-                  <packing>
-                    <property name="expand">False</property>
-                    <property name="position">0</property>
-                  </packing>
-                </child>
-                <child>
-                  <object class="GtkLabel" id="label7">
-                    <property name="visible">True</property>
-                    <property name="label" translatable="yes" comments="This is between the unit selector dropdowns, for example: meters in kilometers"> in </property>
-                  </object>
-                  <packing>
-                    <property name="expand">False</property>
-                    <property name="position">1</property>
-                  </packing>
-                </child>
-                <child>
-                  <object class="GtkComboBox" id="convert_to_combo">
-                    <property name="visible">True</property>
-                    <property name="focus_on_click">False</property>
-                  </object>
-                  <packing>
-                    <property name="expand">False</property>
-                    <property name="position">2</property>
-                  </packing>
-                </child>
-              </object>
-              <packing>
-                <property name="expand">False</property>
-                <property name="position">0</property>
-              </packing>
-            </child>
-            <child>
-              <object class="GtkLabel" id="convert_result_label">
-                <property name="visible">True</property>
-                <property name="xalign">1</property>
-                <property name="label">1m = 100cm</property>
-              </object>
-              <packing>
-                <property name="position">1</property>
-              </packing>
-            </child>
-          </object>
-          <packing>
-            <property name="expand">False</property>
-            <property name="position">0</property>
-          </packing>
-        </child>
-        <child>
           <object class="GtkTable" id="button_table">
             <property name="visible">True</property>
             <property name="n_rows">5</property>
@@ -83,7 +24,7 @@
                     <property name="AtkObject::accessible-name" translatable="yes" comments="Accessible name for the inverse button">Inverse</property>
                   </object>
                 </child>
-                <signal name="clicked" handler="button_cb"/>
+                <signal name="clicked" handler="button_cb" swapped="no"/>
                 <child>
                   <object class="GtkLabel" id="label20">
                     <property name="visible">True</property>
@@ -115,7 +56,7 @@
                     <property name="AtkObject::accessible-name" translatable="yes" comments="Accessible name for the factorize button">Factorize</property>
                   </object>
                 </child>
-                <signal name="clicked" handler="factorize_cb"/>
+                <signal name="clicked" handler="factorize_cb" swapped="no"/>
               </object>
               <packing>
                 <property name="left_attach">5</property>
@@ -137,7 +78,7 @@
                     <property name="AtkObject::accessible-name" translatable="yes" comments="Accessible name for the factorial button">Factorial</property>
                   </object>
                 </child>
-                <signal name="clicked" handler="button_cb"/>
+                <signal name="clicked" handler="button_cb" swapped="no"/>
                 <child>
                   <object class="GtkLabel" id="label14">
                     <property name="visible">True</property>
@@ -163,7 +104,7 @@
                 <property name="receives_default">True</property>
                 <property name="use_underline">True</property>
                 <property name="focus_on_click">False</property>
-                <signal name="clicked" handler="button_cb"/>
+                <signal name="clicked" handler="button_cb" swapped="no"/>
               </object>
               <packing>
                 <property name="left_attach">7</property>
@@ -181,7 +122,7 @@
                 <property name="receives_default">True</property>
                 <property name="use_underline">True</property>
                 <property name="focus_on_click">False</property>
-                <signal name="clicked" handler="button_cb"/>
+                <signal name="clicked" handler="button_cb" swapped="no"/>
                 <child>
                   <object class="GtkLabel" id="imaginary_label">
                     <property name="visible">True</property>
@@ -207,7 +148,7 @@
                 <property name="receives_default">True</property>
                 <property name="use_underline">True</property>
                 <property name="focus_on_click">False</property>
-                <signal name="clicked" handler="digit_cb"/>
+                <signal name="clicked" handler="digit_cb" swapped="no"/>
               </object>
               <packing>
                 <property name="top_attach">2</property>
@@ -224,7 +165,7 @@
                 <property name="receives_default">True</property>
                 <property name="use_underline">True</property>
                 <property name="focus_on_click">False</property>
-                <signal name="clicked" handler="digit_cb"/>
+                <signal name="clicked" handler="digit_cb" swapped="no"/>
               </object>
               <packing>
                 <property name="top_attach">1</property>
@@ -241,7 +182,7 @@
                 <property name="receives_default">True</property>
                 <property name="use_underline">True</property>
                 <property name="focus_on_click">False</property>
-                <signal name="clicked" handler="digit_cb"/>
+                <signal name="clicked" handler="digit_cb" swapped="no"/>
               </object>
               <packing>
                 <property name="left_attach">1</property>
@@ -260,7 +201,7 @@
                 <property name="receives_default">True</property>
                 <property name="use_underline">True</property>
                 <property name="focus_on_click">False</property>
-                <signal name="clicked" handler="digit_cb"/>
+                <signal name="clicked" handler="digit_cb" swapped="no"/>
               </object>
               <packing>
                 <property name="left_attach">2</property>
@@ -279,7 +220,7 @@
                 <property name="receives_default">True</property>
                 <property name="use_underline">True</property>
                 <property name="focus_on_click">False</property>
-                <signal name="clicked" handler="digit_cb"/>
+                <signal name="clicked" handler="digit_cb" swapped="no"/>
               </object>
               <packing>
                 <property name="left_attach">1</property>
@@ -298,7 +239,7 @@
                 <property name="receives_default">True</property>
                 <property name="use_underline">True</property>
                 <property name="focus_on_click">False</property>
-                <signal name="clicked" handler="digit_cb"/>
+                <signal name="clicked" handler="digit_cb" swapped="no"/>
               </object>
               <packing>
                 <property name="left_attach">2</property>
@@ -317,7 +258,7 @@
                 <property name="receives_default">True</property>
                 <property name="use_underline">True</property>
                 <property name="focus_on_click">False</property>
-                <signal name="clicked" handler="button_cb"/>
+                <signal name="clicked" handler="button_cb" swapped="no"/>
               </object>
               <packing>
                 <property name="left_attach">3</property>
@@ -336,7 +277,7 @@
                 <property name="receives_default">True</property>
                 <property name="use_underline">True</property>
                 <property name="focus_on_click">False</property>
-                <signal name="clicked" handler="digit_cb"/>
+                <signal name="clicked" handler="digit_cb" swapped="no"/>
               </object>
               <packing>
                 <property name="top_attach">3</property>
@@ -353,7 +294,7 @@
                 <property name="receives_default">True</property>
                 <property name="use_underline">True</property>
                 <property name="focus_on_click">False</property>
-                <signal name="clicked" handler="digit_cb"/>
+                <signal name="clicked" handler="digit_cb" swapped="no"/>
               </object>
               <packing>
                 <property name="left_attach">1</property>
@@ -373,7 +314,7 @@
                 <property name="receives_default">True</property>
                 <property name="use_underline">True</property>
                 <property name="focus_on_click">False</property>
-                <signal name="clicked" handler="digit_cb"/>
+                <signal name="clicked" handler="digit_cb" swapped="no"/>
               </object>
               <packing>
                 <property name="top_attach">4</property>
@@ -390,7 +331,7 @@
                 <property name="receives_default">True</property>
                 <property name="use_underline">True</property>
                 <property name="focus_on_click">False</property>
-                <signal name="clicked" handler="numeric_point_cb"/>
+                <signal name="clicked" handler="numeric_point_cb" swapped="no"/>
               </object>
               <packing>
                 <property name="left_attach">1</property>
@@ -409,7 +350,7 @@
                 <property name="receives_default">True</property>
                 <property name="use_underline">True</property>
                 <property name="focus_on_click">False</property>
-                <signal name="clicked" handler="digit_cb"/>
+                <signal name="clicked" handler="digit_cb" swapped="no"/>
               </object>
               <packing>
                 <property name="left_attach">2</property>
@@ -428,7 +369,7 @@
                 <property name="receives_default">True</property>
                 <property name="use_underline">True</property>
                 <property name="focus_on_click">False</property>
-                <signal name="clicked" handler="button_cb"/>
+                <signal name="clicked" handler="button_cb" swapped="no"/>
               </object>
               <packing>
                 <property name="left_attach">3</property>
@@ -447,7 +388,7 @@
                 <property name="receives_default">True</property>
                 <property name="use_underline">True</property>
                 <property name="focus_on_click">False</property>
-                <signal name="clicked" handler="subtract_cb"/>
+                <signal name="clicked" handler="subtract_cb" swapped="no"/>
               </object>
               <packing>
                 <property name="left_attach">3</property>
@@ -466,7 +407,7 @@
                 <property name="receives_default">True</property>
                 <property name="use_underline">True</property>
                 <property name="focus_on_click">False</property>
-                <signal name="clicked" handler="button_cb"/>
+                <signal name="clicked" handler="button_cb" swapped="no"/>
               </object>
               <packing>
                 <property name="left_attach">3</property>
@@ -485,7 +426,7 @@
                 <property name="receives_default">True</property>
                 <property name="use_underline">True</property>
                 <property name="focus_on_click">False</property>
-                <signal name="clicked" handler="solve_cb"/>
+                <signal name="clicked" handler="solve_cb" swapped="no"/>
               </object>
               <packing>
                 <property name="left_attach">4</property>
@@ -503,7 +444,7 @@
                 <property name="receives_default">True</property>
                 <property name="use_underline">True</property>
                 <property name="focus_on_click">False</property>
-                <signal name="clicked" handler="clear_cb"/>
+                <signal name="clicked" handler="clear_cb" swapped="no"/>
                 <child>
                   <object class="GtkImage" id="image1">
                     <property name="visible">True</property>
@@ -529,7 +470,7 @@
                     <property name="AtkObject::accessible-name" translatable="yes" comments="Accessible name for the subscript mode button">Subscript</property>
                   </object>
                 </child>
-                <signal name="clicked" handler="set_subscript_cb"/>
+                <signal name="clicked" handler="set_subscript_cb" swapped="no"/>
                 <child>
                   <object class="GtkLabel" id="label4">
                     <property name="visible">True</property>
@@ -554,7 +495,7 @@
                     <property name="AtkObject::accessible-name" translatable="yes" comments="Accessible name for the superscript mode button">Superscript</property>
                   </object>
                 </child>
-                <signal name="clicked" handler="set_superscript_cb"/>
+                <signal name="clicked" handler="set_superscript_cb" swapped="no"/>
                 <child>
                   <object class="GtkLabel" id="label3">
                     <property name="visible">True</property>
@@ -582,7 +523,7 @@
                     <property name="AtkObject::accessible-name" translatable="yes" comments="Accessible name for the scientific exponent button">Scientific Exponent</property>
                   </object>
                 </child>
-                <signal name="clicked" handler="exponent_cb"/>
+                <signal name="clicked" handler="exponent_cb" swapped="no"/>
                 <child>
                   <object class="GtkLabel" id="label2">
                     <property name="visible">True</property>
@@ -606,7 +547,7 @@
                 <property name="receives_default">True</property>
                 <property name="use_underline">True</property>
                 <property name="focus_on_click">False</property>
-                <signal name="clicked" handler="button_cb"/>
+                <signal name="clicked" handler="button_cb" swapped="no"/>
               </object>
               <packing>
                 <property name="left_attach">3</property>
@@ -623,7 +564,7 @@
                 <property name="receives_default">True</property>
                 <property name="use_underline">True</property>
                 <property name="focus_on_click">False</property>
-                <signal name="clicked" handler="button_cb"/>
+                <signal name="clicked" handler="button_cb" swapped="no"/>
               </object>
               <packing>
                 <property name="left_attach">4</property>
@@ -642,7 +583,7 @@
                 <property name="receives_default">True</property>
                 <property name="use_underline">True</property>
                 <property name="focus_on_click">False</property>
-                <signal name="clicked" handler="button_cb"/>
+                <signal name="clicked" handler="button_cb" swapped="no"/>
               </object>
               <packing>
                 <property name="left_attach">5</property>
@@ -664,7 +605,7 @@
                     <property name="AtkObject::accessible-name" translatable="yes" comments="Accessible name for the recall value button">Recall</property>
                   </object>
                 </child>
-                <signal name="clicked" handler="recall_cb"/>
+                <signal name="clicked" handler="recall_cb" swapped="no"/>
                 <child>
                   <object class="GtkHBox" id="hbox19">
                     <property name="visible">True</property>
@@ -710,7 +651,7 @@
                     <property name="AtkObject::accessible-name" translatable="yes" comments="Accessible name for the store value button">Store</property>
                   </object>
                 </child>
-                <signal name="clicked" handler="store_cb"/>
+                <signal name="clicked" handler="store_cb" swapped="no"/>
                 <child>
                   <object class="GtkHBox" id="hbox20">
                     <property name="visible">True</property>
@@ -757,7 +698,7 @@
                     <property name="AtkObject::accessible-name" translatable="yes" comments="Accessible name for the absolute value button">Absolute Value</property>
                   </object>
                 </child>
-                <signal name="clicked" handler="button_cb"/>
+                <signal name="clicked" handler="button_cb" swapped="no"/>
                 <child>
                   <object class="GtkLabel" id="label1">
                     <property name="visible">True</property>
@@ -783,7 +724,7 @@
                 <property name="receives_default">True</property>
                 <property name="use_underline">True</property>
                 <property name="focus_on_click">False</property>
-                <signal name="clicked" handler="button_cb"/>
+                <signal name="clicked" handler="button_cb" swapped="no"/>
               </object>
               <packing>
                 <property name="left_attach">6</property>
@@ -802,7 +743,7 @@
                 <property name="receives_default">True</property>
                 <property name="use_underline">True</property>
                 <property name="focus_on_click">False</property>
-                <signal name="clicked" handler="button_cb"/>
+                <signal name="clicked" handler="button_cb" swapped="no"/>
               </object>
               <packing>
                 <property name="left_attach">8</property>
@@ -821,7 +762,7 @@
                 <property name="receives_default">True</property>
                 <property name="use_underline">True</property>
                 <property name="focus_on_click">False</property>
-                <signal name="clicked" handler="button_cb"/>
+                <signal name="clicked" handler="button_cb" swapped="no"/>
               </object>
               <packing>
                 <property name="left_attach">9</property>
@@ -840,7 +781,7 @@
                 <property name="receives_default">True</property>
                 <property name="use_underline">True</property>
                 <property name="focus_on_click">False</property>
-                <signal name="clicked" handler="button_cb"/>
+                <signal name="clicked" handler="button_cb" swapped="no"/>
               </object>
               <packing>
                 <property name="left_attach">9</property>
@@ -858,7 +799,7 @@
                 <property name="can_focus">True</property>
                 <property name="receives_default">True</property>
                 <property name="focus_on_click">False</property>
-                <signal name="clicked" handler="button_cb"/>
+                <signal name="clicked" handler="button_cb" swapped="no"/>
               </object>
               <packing>
                 <property name="left_attach">8</property>
@@ -880,7 +821,7 @@
                     <property name="AtkObject::accessible-name" translatable="yes" comments="Accessible name for the exponentiation (x to the power of y) button">Exponent</property>
                   </object>
                 </child>
-                <signal name="clicked" handler="button_cb"/>
+                <signal name="clicked" handler="button_cb" swapped="no"/>
                 <child>
                   <object class="GtkLabel" id="x_pow_y_label">
                     <property name="visible">True</property>
@@ -906,7 +847,7 @@
                 <property name="receives_default">True</property>
                 <property name="use_underline">True</property>
                 <property name="focus_on_click">False</property>
-                <signal name="clicked" handler="button_cb"/>
+                <signal name="clicked" handler="button_cb" swapped="no"/>
               </object>
               <packing>
                 <property name="left_attach">7</property>
@@ -924,7 +865,7 @@
                 <property name="receives_default">True</property>
                 <property name="use_underline">True</property>
                 <property name="focus_on_click">False</property>
-                <signal name="clicked" handler="undo_cb"/>
+                <signal name="clicked" handler="undo_cb" swapped="no"/>
                 <child>
                   <object class="GtkImage" id="image2">
                     <property name="visible">True</property>
@@ -946,7 +887,7 @@
                 <property name="receives_default">True</property>
                 <property name="use_underline">True</property>
                 <property name="focus_on_click">False</property>
-                <signal name="clicked" handler="button_cb"/>
+                <signal name="clicked" handler="button_cb" swapped="no"/>
                 <child>
                   <object class="GtkLabel" id="pi_label">
                     <property name="visible">True</property>
@@ -971,7 +912,7 @@
                 <property name="receives_default">True</property>
                 <property name="use_underline">True</property>
                 <property name="focus_on_click">False</property>
-                <signal name="clicked" handler="button_cb"/>
+                <signal name="clicked" handler="button_cb" swapped="no"/>
                 <child>
                   <object class="GtkLabel" id="eulers_number_label">
                     <property name="visible">True</property>
@@ -1002,7 +943,7 @@
                     <property name="can_focus">True</property>
                     <property name="receives_default">True</property>
                     <property name="focus_on_click">False</property>
-                    <signal name="clicked" handler="button_cb"/>
+                    <signal name="clicked" handler="button_cb" swapped="no"/>
                   </object>
                   <packing>
                     <property name="x_options">GTK_EXPAND | GTK_SHRINK | GTK_FILL</property>
@@ -1016,7 +957,7 @@
                     <property name="can_focus">True</property>
                     <property name="receives_default">True</property>
                     <property name="focus_on_click">False</property>
-                    <signal name="clicked" handler="button_cb"/>
+                    <signal name="clicked" handler="button_cb" swapped="no"/>
                   </object>
                   <packing>
                     <property name="left_attach">1</property>
@@ -1032,7 +973,7 @@
                     <property name="can_focus">True</property>
                     <property name="receives_default">True</property>
                     <property name="focus_on_click">False</property>
-                    <signal name="clicked" handler="button_cb"/>
+                    <signal name="clicked" handler="button_cb" swapped="no"/>
                   </object>
                   <packing>
                     <property name="left_attach">2</property>
@@ -1048,7 +989,7 @@
                     <property name="can_focus">True</property>
                     <property name="receives_default">True</property>
                     <property name="focus_on_click">False</property>
-                    <signal name="clicked" handler="button_cb"/>
+                    <signal name="clicked" handler="button_cb" swapped="no"/>
                   </object>
                   <packing>
                     <property name="top_attach">1</property>
@@ -1064,7 +1005,7 @@
                     <property name="can_focus">True</property>
                     <property name="receives_default">True</property>
                     <property name="focus_on_click">False</property>
-                    <signal name="clicked" handler="button_cb"/>
+                    <signal name="clicked" handler="button_cb" swapped="no"/>
                   </object>
                   <packing>
                     <property name="left_attach">1</property>
@@ -1082,7 +1023,7 @@
                     <property name="can_focus">True</property>
                     <property name="receives_default">True</property>
                     <property name="focus_on_click">False</property>
-                    <signal name="clicked" handler="button_cb"/>
+                    <signal name="clicked" handler="button_cb" swapped="no"/>
                   </object>
                   <packing>
                     <property name="left_attach">2</property>
@@ -1111,7 +1052,7 @@
                     <property name="AtkObject::accessible-name" translatable="yes" comments="Accessible name for the store value button">Store</property>
                   </object>
                 </child>
-                <signal name="clicked" handler="function_cb"/>
+                <signal name="clicked" handler="function_cb" swapped="no"/>
                 <child>
                   <object class="GtkHBox" id="hbox2">
                     <property name="visible">True</property>
@@ -1148,7 +1089,8 @@
             </child>
           </object>
           <packing>
-            <property name="position">1</property>
+            <property name="pack_type">end</property>
+            <property name="position">0</property>
           </packing>
         </child>
       </object>
diff --git a/src/Makefile.am b/src/Makefile.am
index 070f235..c549b14 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -14,6 +14,8 @@ gcalctool_SOURCES = \
 	gcalctool.c \
 	math-buttons.c \
 	math-buttons.h \
+	math-converter.c \
+	math-converter.h \
 	math-display.c \
 	math-display.h \
 	math-equation.c \
diff --git a/src/math-buttons.c b/src/math-buttons.c
index 5d768ba..ef54662 100644
--- a/src/math-buttons.c
+++ b/src/math-buttons.c
@@ -19,6 +19,7 @@
 #include <glib/gi18n.h>
 
 #include "math-buttons.h"
+#include "math-converter.h"
 #include "financial.h"
 #include "currency.h"
 #include "mp-serializer.h"
@@ -55,11 +56,6 @@ struct MathButtonsPrivate
     GList *superscript_toggles;
     GList *subscript_toggles;
 
-    GtkWidget *convert_from_combo;
-    GtkWidget *convert_to_combo;
-    MpSerializer *units_serializer;
-    GtkWidget *convert_result_label;
-
     GtkWidget *base_combo;
     GtkWidget *base_label;
     GtkWidget *bit_panel;
@@ -314,119 +310,6 @@ static char *finc_dialog_fields[][5] = {
     {NULL,        NULL,          NULL,         NULL,         NULL}
 };
 
-#define MAX_UNITS 20
-struct Unit {
-    char *ui_name;
-    char *internal_name;
-};
-
-struct UnitCategory {
-    char *name;
-    struct Unit units[MAX_UNITS];
-};
-
-static struct UnitCategory categories[] = {
-    {N_("Angle Units"),  {
-                          /* Angle unit */
-                          {N_("Degrees"), "degrees"},
-                          /* Angle unit */
-                          {N_("Radians"), "radians"},
-                          /* Angle unit */
-                          {N_("Gradians"), "gradians"},
-                          {NULL, NULL}}},
-    {N_("Length Units"), {
-                          /* Length unit */
-                          {N_("Parsecs"), "parsecs"},
-                          /* Length unit */
-                          {N_("Light Years"), "lightyears"},
-                          /* Length unit */
-                          {N_("Astronomical Units"), "au"},
-                          /* Length unit */
-                          {N_("Nautical Miles"), "nm"},
-                          /* Length unit */
-                          {N_("Miles"), "miles"},
-                          /* Length unit */
-                          {N_("Kilometers"), "kilometers"},
-                          /* Length unit */
-                          {N_("Cables"), "cables"},
-                          /* Length unit */
-                          {N_("Fathoms"), "fathoms"},
-                          /* Length unit */
-                          {N_("Meters"), "meters"},
-                          /* Length unit */
-                          {N_("Yards"), "yards"},
-                          /* Length unit */
-                          {N_("Feet"), "feet"},
-                          /* Length unit */
-                          {N_("Inches"), "inches"},
-                          /* Length unit */
-                          {N_("Centimeters"), "centimeters"},
-                          /* Length unit */
-                          {N_("Millimeters"), "millimeters"},
-                          /* Length unit */
-                          {N_("Micrometers"), "micrometers"},
-                          /* Length unit */
-                          {N_("Nanometers"), "nanometers"},
-                          {NULL, NULL}}},
-    {N_("Area Units"),   {
-                          /* Area unit */
-                          {N_("Hectares"), "hectares"},
-                          /* Area unit */
-                          {N_("Acres"), "acres"},
-                          /* Area unit */
-                          {N_("m²"), "m²"},
-                          /* Area unit */
-                          {N_("cm²"), "cm²"},
-                          /* Area unit */
-                          {N_("mm²"), "mm²"},
-                          {NULL, NULL}}},
-    {N_("Volume Units"), {
-                          /* Volume unit */
-                          {N_("m³"), "m³"},
-                          /* Volume unit */
-                          {N_("Gallons"), "gallons"},
-                          /* Volume unit */
-                          {N_("Liters"), "liters"},
-                          /* Volume unit */
-                          {N_("Quarts"), "quarts"},
-                          /* Volume unit */
-                          {N_("Pints"), "pints"},
-                          /* Volume unit */
-                          {N_("Milliliters"), "milliliters"},
-                          /* Volume unit */
-                          {N_("cm³"), "cm³"},
-                          /* Volume unit */
-                          {N_("mm³"), "mm³"},
-                          {NULL, NULL}}},
-    {N_("Weight Units"), {
-                          /* Weight unit */
-                          {N_("Tonnes"), "tonnes"},
-                          /* Weight unit */
-                          {N_("Kilograms"), "kilograms"},
-                          /* Weight unit */
-                          {N_("Pounds"), "pounds"},
-                          /* Weight unit */
-                          {N_("Ounces"), "ounces"},
-                          /* Weight unit */
-                          {N_("Grams"), "grams"},
-                          {NULL, NULL}}},
-    {N_("Time Units"),   {
-                          /* Time unit */
-                          {N_("Years"), "years"},
-                          /* Time unit */
-                          {N_("Days"), "days"},
-                          /* Time unit */
-                          {N_("Hours"), "hours"},
-                          /* Time unit */
-                          {N_("Minutes"), "minutes"},
-                          /* Time unit */
-                          {N_("Seconds"), "seconds"},
-                          /* Time unit */
-                          {N_("Milliseconds"), "milliseconds"},
-                          /* Time unit */
-                          {N_("Microseconds"), "microseconds"},
-                          {NULL, NULL}}}
-};
 
 MathButtons *
 math_buttons_new(MathEquation *equation)
@@ -615,143 +498,10 @@ update_currency_label(MathButtons *buttons)
 
 
 static void
-update_conversion_bar(MathButtons *buttons)
-{
-    MPNumber x, z;
-    gboolean enabled;
-    gchar *label;
-    const gchar *source_units, *target_units;
-    char *source_value, *target_value;
-
-    if (!buttons->priv->convert_result_label)
-        return;
-
-    enabled = math_equation_get_number(buttons->priv->equation, &x);
-
-    source_units = math_equation_get_source_units(buttons->priv->equation);
-    target_units = math_equation_get_target_units(buttons->priv->equation);
-    if (!source_units || !target_units)
-        enabled = FALSE;
-    else if (!units_convert(&x, source_units, target_units, &z))
-        enabled = FALSE;
-
-    gtk_widget_set_sensitive(buttons->priv->convert_result_label, enabled);
-    if (!enabled)
-        return;
-
-    source_value = mp_serializer_to_string(buttons->priv->units_serializer, &x);
-    target_value = mp_serializer_to_string(buttons->priv->units_serializer, &z);
-
-    label = g_strdup_printf("%s %s = %s %s", source_value, source_units, target_value, target_units);
-    gtk_label_set_text(GTK_LABEL(buttons->priv->convert_result_label), label);
-    g_free(source_value);
-    g_free(target_value);
-    g_free(label);
-}
-
-
-static void
 display_changed_cb(MathEquation *equation, GParamSpec *spec, MathButtons *buttons)
 {
     update_currency_label(buttons);
     update_bit_panel(buttons);
-    update_conversion_bar(buttons);
-}
-
-
-static void
-convert_from_combobox_changed_cb(GtkWidget *combo, MathButtons *buttons)
-{
-    GtkTreeModel *model;
-    GtkTreeIter iter;
-    int typeindex, unitindex, i;
-
-    model = gtk_combo_box_get_model(GTK_COMBO_BOX(combo));
-    gtk_combo_box_get_active_iter(GTK_COMBO_BOX(combo), &iter);
-    gtk_tree_model_get(model, &iter, 1, &typeindex, 2, &unitindex, -1);
-
-    model = GTK_TREE_MODEL(gtk_list_store_new(3, G_TYPE_STRING, G_TYPE_INT, G_TYPE_INT));
-    for (i = 0; categories[typeindex].units[i].ui_name != NULL; i++) {
-        if (i == unitindex)
-            continue;
-        gtk_list_store_append(GTK_LIST_STORE(model), &iter);
-        gtk_list_store_set(GTK_LIST_STORE(model), &iter, 0, categories[typeindex].units[i].ui_name, 1, typeindex, 2, i, -1);
-    }
-    gtk_combo_box_set_model(GTK_COMBO_BOX(buttons->priv->convert_to_combo), model);
-
-    math_equation_set_source_units(buttons->priv->equation, categories[typeindex].units[unitindex].internal_name);
-
-    gtk_combo_box_set_active(GTK_COMBO_BOX(buttons->priv->convert_to_combo), 0);
-}
-
-
-static void
-source_units_changed_cb(MathEquation *equation, GParamSpec *spec, MathButtons *buttons)
-{
-    GtkTreeModel *model;
-    GtkTreeIter iter;
-
-    model = gtk_combo_box_get_model(GTK_COMBO_BOX(buttons->priv->convert_from_combo));
-    if (!gtk_tree_model_get_iter_first(model, &iter))
-        return;
-    do
-    {
-        GtkTreeIter child_iter;
-
-        if (gtk_tree_model_iter_children(model, &child_iter, &iter))
-        {
-            do
-            {
-                gint i, j;
-
-                gtk_tree_model_get(model, &child_iter, 1, &i, 2, &j, -1);
-                if (strcmp(categories[i].units[j].internal_name, math_equation_get_source_units(equation)) == 0)
-                {
-                    gtk_combo_box_set_active_iter(GTK_COMBO_BOX(buttons->priv->convert_from_combo), &child_iter);
-                    update_conversion_bar(buttons);
-                    return;
-                }             
-            } while (gtk_tree_model_iter_next(model, &child_iter));
-        }
-    } while (gtk_tree_model_iter_next(model, &iter));
-}
-
-
-static void
-convert_to_combobox_changed_cb(GtkWidget *combo, MathButtons *buttons)
-{
-    GtkTreeModel *model;
-    GtkTreeIter iter;
-    int category, toindex;
-
-    model = gtk_combo_box_get_model(GTK_COMBO_BOX(combo));
-    gtk_combo_box_get_active_iter(GTK_COMBO_BOX(combo), &iter);
-    gtk_tree_model_get(model, &iter, 1, &category, 2, &toindex, -1);
-    math_equation_set_target_units(buttons->priv->equation, categories[category].units[toindex].internal_name);
-}
-
-
-static void
-target_units_changed_cb(MathEquation *equation, GParamSpec *spec, MathButtons *buttons)
-{
-    GtkTreeModel *model;
-    GtkTreeIter iter;
-
-    model = gtk_combo_box_get_model(GTK_COMBO_BOX(buttons->priv->convert_to_combo));
-    if (!gtk_tree_model_get_iter_first(model, &iter))
-        return;
-    do
-    {
-        gint i, j;
-
-        gtk_tree_model_get(model, &iter, 1, &i, 2, &j, -1);
-        if (strcmp(categories[i].units[j].internal_name, math_equation_get_target_units(equation)) == 0)
-        {
-            gtk_combo_box_set_active_iter(GTK_COMBO_BOX(buttons->priv->convert_to_combo), &iter);
-            update_conversion_bar(buttons);
-            return;
-        }
-    } while (gtk_tree_model_iter_next(model, &iter));
 }
 
 
@@ -895,17 +645,6 @@ target_currency_changed_cb(MathEquation *equation, GParamSpec *spec, MathButtons
 }
 
 
-static void
-convert_from_cell_data_func(GtkCellLayout   *cell_layout,
-                            GtkCellRenderer *cell,
-                            GtkTreeModel    *tree_model,
-                            GtkTreeIter     *iter,
-                            gpointer         data)
-{
-    g_object_set(cell, "sensitive", !gtk_tree_model_iter_has_child(tree_model, iter), NULL);
-}
-
-
 static GtkWidget *
 load_mode(MathButtons *buttons, ButtonMode mode)
 {
@@ -1042,47 +781,13 @@ load_mode(MathButtons *buttons, ButtonMode mode)
         if (math_equation_get_number_mode(buttons->priv->equation) == SUBSCRIPT)
             gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(widget), TRUE);
     }
-  
-    if (mode == ADVANCED) {
-        GtkTreeStore *from_model;
-        GtkTreeIter iter, parent;
-        GtkCellRenderer *renderer;
-        int i, j;
-
-        buttons->priv->convert_result_label = GET_WIDGET(builder, "convert_result_label");
-        buttons->priv->units_serializer = mp_serializer_new(MP_DISPLAY_FORMAT_AUTOMATIC, 10, 2);
 
-        buttons->priv->convert_from_combo = GET_WIDGET(builder, "convert_from_combo");
-        from_model = gtk_tree_store_new(3, G_TYPE_STRING, G_TYPE_INT, G_TYPE_INT);
-        gtk_combo_box_set_model(GTK_COMBO_BOX(buttons->priv->convert_from_combo), GTK_TREE_MODEL(from_model));
+    if (mode == ADVANCED) {
+        GtkWidget *converter;
 
-        for (i = 0; i < sizeof(categories) / sizeof(categories[0]); i++) {
-            gtk_tree_store_append(from_model, &parent, NULL);
-            gtk_tree_store_set(from_model, &parent, 0, categories[i].name, 1, i, -1);
-            for (j = 0; categories[i].units[j].ui_name != NULL; j++) {
-                gtk_tree_store_append(from_model, &iter, &parent);
-                gtk_tree_store_set(from_model, &iter, 0, categories[i].units[j].ui_name, 1, i, 2, j, -1);
-            }
-        }
-        renderer = gtk_cell_renderer_text_new();
-        gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(buttons->priv->convert_from_combo), renderer, TRUE);
-        gtk_cell_layout_add_attribute(GTK_CELL_LAYOUT(buttons->priv->convert_from_combo), renderer, "text", 0);
-        gtk_cell_layout_set_cell_data_func(GTK_CELL_LAYOUT(buttons->priv->convert_from_combo),
-                                           renderer,
-                                           convert_from_cell_data_func,
-                                           NULL, NULL);
-
-        buttons->priv->convert_to_combo = GET_WIDGET(builder, "convert_to_combo");
-        renderer = gtk_cell_renderer_text_new();
-        gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(buttons->priv->convert_to_combo), renderer, TRUE);
-        gtk_cell_layout_add_attribute(GTK_CELL_LAYOUT(buttons->priv->convert_to_combo), renderer, "text", 0);
-
-        g_signal_connect(buttons->priv->convert_from_combo, "changed", G_CALLBACK(convert_from_combobox_changed_cb), buttons);
-        g_signal_connect(buttons->priv->convert_to_combo, "changed", G_CALLBACK(convert_to_combobox_changed_cb), buttons);
-        g_signal_connect(buttons->priv->equation, "notify::source-units", G_CALLBACK(source_units_changed_cb), buttons);
-        g_signal_connect(buttons->priv->equation, "notify::target-units", G_CALLBACK(target_units_changed_cb), buttons);
-        source_units_changed_cb(buttons->priv->equation, NULL, buttons);
-        target_units_changed_cb(buttons->priv->equation, NULL, buttons);
+        converter = GTK_WIDGET(math_converter_new(buttons->priv->equation));
+        gtk_widget_show(converter);
+        gtk_box_pack_start(GTK_BOX(*panel), converter, FALSE, TRUE, 0);
     }
 
     if (mode == PROGRAMMING) {
diff --git a/src/math-converter.c b/src/math-converter.c
new file mode 100644
index 0000000..9de0d1e
--- /dev/null
+++ b/src/math-converter.c
@@ -0,0 +1,449 @@
+/*  Copyright (c) 2008-2009 Robert Ancell
+ *
+ *  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, 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.
+ */
+
+#include <glib/gi18n.h>
+
+#include "math-converter.h"
+#include "mp-serializer.h"
+#include "units.h"
+
+enum {
+    PROP_0,
+    PROP_EQUATION
+};
+
+struct MathConverterPrivate
+{
+    MathEquation *equation;
+
+    GtkWidget *from_combo;
+    GtkWidget *to_combo;
+
+    GtkWidget *result_label;
+    MpSerializer *serializer;
+};
+
+#define MAX_UNITS 20
+struct Unit {
+    char *ui_name;
+    char *internal_name;
+};
+
+struct UnitCategory {
+    char *name;
+    struct Unit units[MAX_UNITS];
+};
+
+static struct UnitCategory categories[] = {
+    {N_("Angle Units"),  {
+                          /* Angle unit */
+                          {N_("Degrees"), "degrees"},
+                          /* Angle unit */
+                          {N_("Radians"), "radians"},
+                          /* Angle unit */
+                          {N_("Gradians"), "gradians"},
+                          {NULL, NULL}}},
+    {N_("Length Units"), {
+                          /* Length unit */
+                          {N_("Parsecs"), "parsecs"},
+                          /* Length unit */
+                          {N_("Light Years"), "lightyears"},
+                          /* Length unit */
+                          {N_("Astronomical Units"), "au"},
+                          /* Length unit */
+                          {N_("Nautical Miles"), "nm"},
+                          /* Length unit */
+                          {N_("Miles"), "miles"},
+                          /* Length unit */
+                          {N_("Kilometers"), "kilometers"},
+                          /* Length unit */
+                          {N_("Cables"), "cables"},
+                          /* Length unit */
+                          {N_("Fathoms"), "fathoms"},
+                          /* Length unit */
+                          {N_("Meters"), "meters"},
+                          /* Length unit */
+                          {N_("Yards"), "yards"},
+                          /* Length unit */
+                          {N_("Feet"), "feet"},
+                          /* Length unit */
+                          {N_("Inches"), "inches"},
+                          /* Length unit */
+                          {N_("Centimeters"), "centimeters"},
+                          /* Length unit */
+                          {N_("Millimeters"), "millimeters"},
+                          /* Length unit */
+                          {N_("Micrometers"), "micrometers"},
+                          /* Length unit */
+                          {N_("Nanometers"), "nanometers"},
+                          {NULL, NULL}}},
+    {N_("Area Units"),   {
+                          /* Area unit */
+                          {N_("Hectares"), "hectares"},
+                          /* Area unit */
+                          {N_("Acres"), "acres"},
+                          /* Area unit */
+                          {N_("m²"), "m²"},
+                          /* Area unit */
+                          {N_("cm²"), "cm²"},
+                          /* Area unit */
+                          {N_("mm²"), "mm²"},
+                          {NULL, NULL}}},
+    {N_("Volume Units"), {
+                          /* Volume unit */
+                          {N_("m³"), "m³"},
+                          /* Volume unit */
+                          {N_("Gallons"), "gallons"},
+                          /* Volume unit */
+                          {N_("Liters"), "liters"},
+                          /* Volume unit */
+                          {N_("Quarts"), "quarts"},
+                          /* Volume unit */
+                          {N_("Pints"), "pints"},
+                          /* Volume unit */
+                          {N_("Milliliters"), "milliliters"},
+                          /* Volume unit */
+                          {N_("cm³"), "cm³"},
+                          /* Volume unit */
+                          {N_("mm³"), "mm³"},
+                          {NULL, NULL}}},
+    {N_("Weight Units"), {
+                          /* Weight unit */
+                          {N_("Tonnes"), "tonnes"},
+                          /* Weight unit */
+                          {N_("Kilograms"), "kilograms"},
+                          /* Weight unit */
+                          {N_("Pounds"), "pounds"},
+                          /* Weight unit */
+                          {N_("Ounces"), "ounces"},
+                          /* Weight unit */
+                          {N_("Grams"), "grams"},
+                          {NULL, NULL}}},
+    {N_("Time Units"),   {
+                          /* Time unit */
+                          {N_("Years"), "years"},
+                          /* Time unit */
+                          {N_("Days"), "days"},
+                          /* Time unit */
+                          {N_("Hours"), "hours"},
+                          /* Time unit */
+                          {N_("Minutes"), "minutes"},
+                          /* Time unit */
+                          {N_("Seconds"), "seconds"},
+                          /* Time unit */
+                          {N_("Milliseconds"), "milliseconds"},
+                          /* Time unit */
+                          {N_("Microseconds"), "microseconds"},
+                          {NULL, NULL}}}
+};
+
+G_DEFINE_TYPE (MathConverter, math_converter, GTK_TYPE_HBOX);
+
+
+MathConverter *
+math_converter_new(MathEquation *equation)
+{
+    return g_object_new(math_converter_get_type(), "equation", equation, NULL);  
+}
+
+
+void
+math_converter_set_category(MathEquation *equation, const gchar *category)
+{
+}
+
+
+const gchar *
+math_converter_get_category(MathEquation *equation)
+{
+    return NULL;
+}
+
+
+static void
+update_result_label(MathConverter *converter)
+{
+    MPNumber x, z;
+    gboolean enabled;
+    gchar *label;
+    const gchar *source_units, *target_units;
+    char *source_value, *target_value;
+
+    if (!converter->priv->result_label)
+        return;
+
+    enabled = math_equation_get_number(converter->priv->equation, &x);
+
+    source_units = math_equation_get_source_units(converter->priv->equation);
+    target_units = math_equation_get_target_units(converter->priv->equation);
+    if (!source_units || !target_units)
+        enabled = FALSE;
+    else if (!units_convert(&x, source_units, target_units, &z))
+        enabled = FALSE;
+
+    gtk_widget_set_sensitive(converter->priv->result_label, enabled);
+    if (!enabled)
+        return;
+
+    source_value = mp_serializer_to_string(converter->priv->serializer, &x);
+    target_value = mp_serializer_to_string(converter->priv->serializer, &z);
+
+    label = g_strdup_printf("%s %s = %s %s", source_value, source_units, target_value, target_units);
+    gtk_label_set_text(GTK_LABEL(converter->priv->result_label), label);
+    g_free(source_value);
+    g_free(target_value);
+    g_free(label); 
+}
+
+
+static void
+source_units_changed_cb(MathEquation *equation, GParamSpec *spec, MathConverter *converter)
+{
+    GtkTreeModel *model;
+    GtkTreeIter iter;
+
+    model = gtk_combo_box_get_model(GTK_COMBO_BOX(converter->priv->from_combo));
+    if (!gtk_tree_model_get_iter_first(model, &iter))
+        return;
+    do {
+        GtkTreeIter child_iter;
+
+        if (gtk_tree_model_iter_children(model, &child_iter, &iter)) {
+            do {
+                gint i, j;
+
+                gtk_tree_model_get(model, &child_iter, 1, &i, 2, &j, -1);
+                if (strcmp(categories[i].units[j].internal_name, math_equation_get_source_units(equation)) == 0) {
+                    gtk_combo_box_set_active_iter(GTK_COMBO_BOX(converter->priv->from_combo), &child_iter);
+                    update_result_label(converter);
+                    return;
+                }             
+            } while (gtk_tree_model_iter_next(model, &child_iter));
+        }
+    } while (gtk_tree_model_iter_next(model, &iter));
+}
+
+
+static void
+target_units_changed_cb(MathEquation *equation, GParamSpec *spec, MathConverter *converter)
+{
+    GtkTreeModel *model;
+    GtkTreeIter iter;
+
+    model = gtk_combo_box_get_model(GTK_COMBO_BOX(converter->priv->to_combo));
+    if (!gtk_tree_model_get_iter_first(model, &iter))
+        return;
+    do {
+        gint i, j;
+
+        gtk_tree_model_get(model, &iter, 1, &i, 2, &j, -1);
+        if (strcmp(categories[i].units[j].internal_name, math_equation_get_target_units(equation)) == 0) {
+            gtk_combo_box_set_active_iter(GTK_COMBO_BOX(converter->priv->to_combo), &iter);
+            update_result_label(converter);
+            return;
+        }
+    } while (gtk_tree_model_iter_next(model, &iter));
+}
+
+
+static void
+display_changed_cb(MathEquation *equation, GParamSpec *spec, MathConverter *converter)
+{
+    update_result_label(converter);
+}
+
+
+static void
+math_converter_set_property(GObject      *object,
+                            guint         prop_id,
+                            const GValue *value,
+                            GParamSpec   *pspec)
+{
+    MathConverter *self;
+
+    self = MATH_CONVERTER(object);
+
+    switch (prop_id) {
+    case PROP_EQUATION:
+        self->priv->equation = g_value_get_object(value);
+        g_signal_connect(self->priv->equation, "notify::source-units", G_CALLBACK(source_units_changed_cb), self);
+        g_signal_connect(self->priv->equation, "notify::target-units", G_CALLBACK(target_units_changed_cb), self);
+        g_signal_connect(self->priv->equation, "notify::display", G_CALLBACK(display_changed_cb), self);
+        source_units_changed_cb(self->priv->equation, NULL, self);
+        target_units_changed_cb(self->priv->equation, NULL, self);
+        display_changed_cb(self->priv->equation, NULL, self);
+        break;
+    default:
+        G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
+        break;
+    }
+}
+
+
+static void
+math_converter_get_property(GObject    *object,
+                            guint       prop_id,
+                            GValue     *value,
+                            GParamSpec *pspec)
+{
+    MathConverter *self;
+
+    self = MATH_CONVERTER(object);
+
+    switch (prop_id) {
+    case PROP_EQUATION:
+        g_value_set_object(value, self->priv->equation);
+        break;
+    default:
+        G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
+        break;
+    }
+}
+
+
+static void
+math_converter_class_init(MathConverterClass *klass)
+{
+    GObjectClass *object_class = G_OBJECT_CLASS(klass);
+
+    object_class->get_property = math_converter_get_property;
+    object_class->set_property = math_converter_set_property;
+
+    g_type_class_add_private(klass, sizeof(MathConverterPrivate));
+
+    g_object_class_install_property(object_class,
+                                    PROP_EQUATION,
+                                    g_param_spec_object("equation",
+                                                        "equation",
+                                                        "Equation being controlled",
+                                                        math_equation_get_type(),
+                                                        G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+}
+
+
+static void
+from_combobox_changed_cb(GtkWidget *combo, MathConverter *converter)
+{
+    GtkTreeModel *model;
+    GtkTreeIter iter;
+    int typeindex, unitindex, i;
+
+    model = gtk_combo_box_get_model(GTK_COMBO_BOX(combo));
+    gtk_combo_box_get_active_iter(GTK_COMBO_BOX(combo), &iter);
+    gtk_tree_model_get(model, &iter, 1, &typeindex, 2, &unitindex, -1);
+
+    model = GTK_TREE_MODEL(gtk_list_store_new(3, G_TYPE_STRING, G_TYPE_INT, G_TYPE_INT));
+    for (i = 0; categories[typeindex].units[i].ui_name != NULL; i++) {
+        if (i == unitindex)
+            continue;
+        gtk_list_store_append(GTK_LIST_STORE(model), &iter);
+        gtk_list_store_set(GTK_LIST_STORE(model), &iter, 0, categories[typeindex].units[i].ui_name, 1, typeindex, 2, i, -1);
+    }
+    gtk_combo_box_set_model(GTK_COMBO_BOX(converter->priv->to_combo), model);
+
+    math_equation_set_source_units(converter->priv->equation, categories[typeindex].units[unitindex].internal_name);
+
+    gtk_combo_box_set_active(GTK_COMBO_BOX(converter->priv->to_combo), 0);
+}
+
+
+static void
+to_combobox_changed_cb(GtkWidget *combo, MathConverter *converter)
+{
+    GtkTreeModel *model;
+    GtkTreeIter iter;
+    int category, toindex;
+
+    model = gtk_combo_box_get_model(GTK_COMBO_BOX(combo));
+    gtk_combo_box_get_active_iter(GTK_COMBO_BOX(combo), &iter);
+    gtk_tree_model_get(model, &iter, 1, &category, 2, &toindex, -1);
+    math_equation_set_target_units(converter->priv->equation, categories[category].units[toindex].internal_name);
+}
+
+
+static void
+from_cell_data_func(GtkCellLayout   *cell_layout,
+                    GtkCellRenderer *cell,
+                    GtkTreeModel    *tree_model,
+                    GtkTreeIter     *iter,
+                    gpointer         data)
+{
+    g_object_set(cell, "sensitive", !gtk_tree_model_iter_has_child(tree_model, iter), NULL);
+}
+
+
+static void
+math_converter_init(MathConverter *converter)
+{
+    GtkWidget *hbox, *label;
+    GtkTreeStore *from_model;
+    GtkTreeIter iter, parent;
+    GtkCellRenderer *renderer;
+    int i, j;
+
+    converter->priv = G_TYPE_INSTANCE_GET_PRIVATE(converter, math_converter_get_type(), MathConverterPrivate);
+
+    gtk_box_set_spacing(GTK_BOX(converter), 6);
+
+    hbox = gtk_hbox_new(FALSE, 0);
+    gtk_widget_show(hbox);
+    gtk_box_pack_start(GTK_BOX(converter), hbox, FALSE, TRUE, 0);
+
+    converter->priv->from_combo = gtk_combo_box_new ();
+    from_model = gtk_tree_store_new(3, G_TYPE_STRING, G_TYPE_INT, G_TYPE_INT);
+    gtk_combo_box_set_model(GTK_COMBO_BOX(converter->priv->from_combo), GTK_TREE_MODEL(from_model));
+
+    for (i = 0; i < sizeof(categories) / sizeof(categories[0]); i++) {
+        gtk_tree_store_append(from_model, &parent, NULL);
+        gtk_tree_store_set(from_model, &parent, 0, categories[i].name, 1, i, -1);
+        for (j = 0; categories[i].units[j].ui_name != NULL; j++) {
+            gtk_tree_store_append(from_model, &iter, &parent);
+            gtk_tree_store_set(from_model, &iter, 0, categories[i].units[j].ui_name, 1, i, 2, j, -1);
+        }
+    }
+    renderer = gtk_cell_renderer_text_new();
+    gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(converter->priv->from_combo), renderer, TRUE);
+    gtk_cell_layout_add_attribute(GTK_CELL_LAYOUT(converter->priv->from_combo), renderer, "text", 0);
+    gtk_cell_layout_set_cell_data_func(GTK_CELL_LAYOUT(converter->priv->from_combo),
+                                       renderer,
+                                       from_cell_data_func,
+                                       NULL, NULL);
+    g_signal_connect(converter->priv->from_combo, "changed", G_CALLBACK(from_combobox_changed_cb), converter);
+    gtk_widget_show(converter->priv->from_combo);
+    gtk_box_pack_start(GTK_BOX(hbox), converter->priv->from_combo, FALSE, TRUE, 0);
+
+    label = gtk_label_new(" in ");
+    gtk_widget_show(label);
+    gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, TRUE, 0);
+
+    converter->priv->to_combo = gtk_combo_box_new();
+    renderer = gtk_cell_renderer_text_new();
+    gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(converter->priv->to_combo), renderer, TRUE);
+    gtk_cell_layout_add_attribute(GTK_CELL_LAYOUT(converter->priv->to_combo), renderer, "text", 0);
+    g_signal_connect(converter->priv->to_combo, "changed", G_CALLBACK(to_combobox_changed_cb), converter);
+    gtk_widget_show(converter->priv->to_combo);
+    gtk_box_pack_start(GTK_BOX(hbox), converter->priv->to_combo, FALSE, TRUE, 0);
+
+    converter->priv->result_label = gtk_label_new("");
+    gtk_misc_set_alignment(GTK_MISC(converter->priv->result_label), 1.0, 0.5);
+    gtk_widget_set_sensitive(converter->priv->result_label, FALSE);
+    gtk_widget_show(converter->priv->result_label);
+    gtk_box_pack_start(GTK_BOX(converter), converter->priv->result_label, TRUE, TRUE, 0);
+
+    converter->priv->serializer = mp_serializer_new(MP_DISPLAY_FORMAT_AUTOMATIC, 10, 2);
+}
diff --git a/src/math-converter.h b/src/math-converter.h
new file mode 100644
index 0000000..d3e83bf
--- /dev/null
+++ b/src/math-converter.h
@@ -0,0 +1,53 @@
+/*  Copyright (c) 2008-2009 Robert Ancell
+ *
+ *  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, 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.
+ */
+
+#ifndef MATH_CONVERTER_H
+#define MATH_CONVERTER_H
+
+#include <glib-object.h>
+#include <gtk/gtk.h>
+#include "math-equation.h"
+
+G_BEGIN_DECLS
+
+#define MATH_CONVERTER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), math_converter_get_type(), MathConverter))
+
+typedef struct MathConverterPrivate MathConverterPrivate;
+
+typedef struct
+{
+    GtkHBox parent_instance;
+    MathConverterPrivate *priv;
+} MathConverter;
+
+typedef struct
+{
+    GtkHBoxClass parent_class;
+} MathConverterClass;
+
+GType math_converter_get_type(void);
+
+MathConverter *math_converter_new(MathEquation *equation);
+
+void math_converter_set_category(MathEquation *equation, const gchar *category);
+
+const gchar *math_converter_get_category(MathEquation *equation);
+
+G_END_DECLS
+
+#endif /* MATH_CONVERTER_H */



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]