[gcalctool] Big part of refactoring complete - pretty much everything works again!



commit c0fd910e06d75131d7132b7e287c07292bd08a84
Author: Robert Ancell <robert ancell gmail com>
Date:   Mon Apr 5 18:06:47 2010 +1000

    Big part of refactoring complete - pretty much everything works again!

 data/buttons-advanced.ui    |    6 +-
 data/buttons-basic.ui       |    2 +-
 data/buttons-financial.ui   |   31 +-
 data/buttons-programming.ui |   26 +-
 data/gcalctool.ui           |  347 +-------------
 data/preferences.ui         |  317 ++++++++++++
 po/POTFILES.in              |   11 +-
 src/Makefile.am             |    2 -
 src/calctool.c              |    2 +-
 src/display.c               |   30 +-
 src/ui-buttons.c            | 1138 +++++++++++++++++++++++++++++++------------
 src/ui-buttons.h            |   52 +-
 src/ui-display.c            |  574 +++++++++++++++-------
 src/ui-display.h            |   73 ++-
 src/ui-financial.c          |  355 --------------
 src/ui-financial.h          |   24 -
 src/ui-internal.h           |   28 -
 src/ui-preferences.c        |    3 +-
 src/ui.c                    |  154 +++---
 src/ui.h                    |   50 ++-
 20 files changed, 1767 insertions(+), 1458 deletions(-)
---
diff --git a/data/buttons-advanced.ui b/data/buttons-advanced.ui
index 23a6015..19fddba 100644
--- a/data/buttons-advanced.ui
+++ b/data/buttons-advanced.ui
@@ -21,7 +21,7 @@
                 <property name="AtkObject::accessible-name" translatable="yes" comments="Accessible name for the store value button">Store</property>
               </object>
             </child>
-            <signal name="clicked" handler="popup_cb"/>
+            <signal name="clicked" handler="store_cb"/>
             <child>
               <object class="GtkHBox" id="hbox20">
                 <property name="visible">True</property>
@@ -69,7 +69,7 @@
                 <property name="AtkObject::accessible-name" translatable="yes" comments="Accessible name for the recall value button">Recall</property>
               </object>
             </child>
-            <signal name="clicked" handler="popup_cb"/>
+            <signal name="clicked" handler="recall_cb"/>
             <child>
               <object class="GtkHBox" id="hbox19">
                 <property name="visible">True</property>
@@ -763,7 +763,7 @@
             <property name="border_width">3</property>
             <property name="use_underline">True</property>
             <property name="focus_on_click">False</property>
-            <signal name="clicked" handler="button_cb"/>
+            <signal name="clicked" handler="numeric_point_cb"/>
           </object>
           <packing>
             <property name="left_attach">1</property>
diff --git a/data/buttons-basic.ui b/data/buttons-basic.ui
index e4dc2d5..531b455 100644
--- a/data/buttons-basic.ui
+++ b/data/buttons-basic.ui
@@ -204,7 +204,7 @@
             <property name="border_width">3</property>
             <property name="use_underline">True</property>
             <property name="focus_on_click">False</property>
-            <signal name="clicked" handler="button_cb"/>
+            <signal name="clicked" handler="numeric_point_cb"/>
           </object>
           <packing>
             <property name="left_attach">1</property>
diff --git a/data/buttons-financial.ui b/data/buttons-financial.ui
index 6e26320..bf6c952 100644
--- a/data/buttons-financial.ui
+++ b/data/buttons-financial.ui
@@ -21,7 +21,7 @@
                 <property name="AtkObject::accessible-name" translatable="yes" comments="Accessible name for the store value button">Store</property>
               </object>
             </child>
-            <signal name="clicked" handler="popup_cb"/>
+            <signal name="clicked" handler="store_cb"/>
             <child>
               <object class="GtkHBox" id="hbox20">
                 <property name="visible">True</property>
@@ -69,7 +69,7 @@
                 <property name="AtkObject::accessible-name" translatable="yes" comments="Accessible name for the recall value button">Recall</property>
               </object>
             </child>
-            <signal name="clicked" handler="popup_cb"/>
+            <signal name="clicked" handler="recall_cb"/>
             <child>
               <object class="GtkHBox" id="hbox19">
                 <property name="visible">True</property>
@@ -347,7 +347,7 @@
             </child>
             <signal name="clicked" handler="button_cb"/>
             <child>
-              <object class="GtkLabel" id="label14">
+              <object class="GtkLabel" id="label27">
                 <property name="visible">True</property>
                 <property name="label">&lt;i&gt;x&lt;/i&gt;!</property>
                 <property name="use_markup">True</property>
@@ -763,7 +763,7 @@
             <property name="border_width">3</property>
             <property name="use_underline">True</property>
             <property name="focus_on_click">False</property>
-            <signal name="clicked" handler="button_cb"/>
+            <signal name="clicked" handler="numeric_point_cb"/>
           </object>
           <packing>
             <property name="left_attach">1</property>
@@ -1197,7 +1197,6 @@
     <child internal-child="vbox">
       <object class="GtkVBox" id="dialog-vbox1">
         <property name="visible">True</property>
-        <property name="orientation">vertical</property>
         <child>
           <object class="GtkTable" id="table1">
             <property name="visible">True</property>
@@ -1270,7 +1269,7 @@
               </packing>
             </child>
             <child>
-              <object class="GtkLabel" id="label3">
+              <object class="GtkLabel" id="label6">
                 <property name="visible">True</property>
                 <property name="xalign">0</property>
                 <property name="label" translatable="yes" comments="Compounding Term Dialog: Label before periodic interest rate input">Periodic Interest _Rate:</property>
@@ -1285,7 +1284,7 @@
               </packing>
             </child>
             <child>
-              <object class="GtkLabel" id="label2">
+              <object class="GtkLabel" id="label9">
                 <property name="visible">True</property>
                 <property name="label" translatable="yes" comments="Compounding Term Dialog: Description of calculation">Calculates the number of compounding periods necessary to increase an investment of present value to a future value, at a fixed interest rate per compounding period.</property>
                 <property name="wrap">True</property>
@@ -1297,7 +1296,7 @@
               </packing>
             </child>
             <child>
-              <object class="GtkLabel" id="label4">
+              <object class="GtkLabel" id="label16">
                 <property name="visible">True</property>
                 <property name="xalign">0</property>
                 <property name="label" translatable="yes" comments="Compounding Term Dialog: Label before future value input">_Future Value:</property>
@@ -1374,7 +1373,6 @@
     <child internal-child="vbox">
       <object class="GtkVBox" id="dialog-vbox2">
         <property name="visible">True</property>
-        <property name="orientation">vertical</property>
         <child>
           <object class="GtkTable" id="table2">
             <property name="visible">True</property>
@@ -1551,7 +1549,6 @@
     <child internal-child="vbox">
       <object class="GtkVBox" id="dialog-vbox3">
         <property name="visible">True</property>
-        <property name="orientation">vertical</property>
         <child>
           <object class="GtkTable" id="table3">
             <property name="visible">True</property>
@@ -1728,7 +1725,6 @@
     <child internal-child="vbox">
       <object class="GtkVBox" id="dialog-vbox10">
         <property name="visible">True</property>
-        <property name="orientation">vertical</property>
         <child>
           <object class="GtkTable" id="table10">
             <property name="visible">True</property>
@@ -1873,7 +1869,6 @@
     <child internal-child="vbox">
       <object class="GtkVBox" id="dialog-vbox4">
         <property name="visible">True</property>
-        <property name="orientation">vertical</property>
         <child>
           <object class="GtkTable" id="table4">
             <property name="visible">True</property>
@@ -1926,7 +1921,7 @@
               </packing>
             </child>
             <child>
-              <object class="GtkLabel" id="label20">
+              <object class="GtkLabel" id="label21">
                 <property name="visible">True</property>
                 <property name="xalign">0</property>
                 <property name="label" translatable="yes" comments="Periodic Payment Dialog: Label before term input">_Term:</property>
@@ -2051,7 +2046,6 @@
     <child internal-child="vbox">
       <object class="GtkVBox" id="dialog-vbox5">
         <property name="visible">True</property>
-        <property name="orientation">vertical</property>
         <child>
           <object class="GtkTable" id="table5">
             <property name="visible">True</property>
@@ -2061,7 +2055,7 @@
             <property name="column_spacing">6</property>
             <property name="row_spacing">6</property>
             <child>
-              <object class="GtkLabel" id="label23">
+              <object class="GtkLabel" id="label36">
                 <property name="visible">True</property>
                 <property name="xalign">0</property>
                 <property name="label" translatable="yes" comments="Present Value Dialog: Description of calculation">Calculates the present value of an investment based on a series of equal payments discounted at a periodic interest rate over the number of payment periods in the term. </property>
@@ -2229,7 +2223,6 @@
     <child internal-child="vbox">
       <object class="GtkVBox" id="dialog-vbox6">
         <property name="visible">True</property>
-        <property name="orientation">vertical</property>
         <child>
           <object class="GtkTable" id="table6">
             <property name="visible">True</property>
@@ -2407,7 +2400,6 @@
     <child internal-child="vbox">
       <object class="GtkVBox" id="dialog-vbox7">
         <property name="visible">True</property>
-        <property name="orientation">vertical</property>
         <child>
           <object class="GtkTable" id="table7">
             <property name="visible">True</property>
@@ -2585,7 +2577,6 @@
     <child internal-child="vbox">
       <object class="GtkVBox" id="dialog-vbox8">
         <property name="visible">True</property>
-        <property name="orientation">vertical</property>
         <child>
           <object class="GtkTable" id="table8">
             <property name="visible">True</property>
@@ -2794,7 +2785,6 @@
     <child internal-child="vbox">
       <object class="GtkVBox" id="dialog-vbox9">
         <property name="visible">True</property>
-        <property name="orientation">vertical</property>
         <child>
           <object class="GtkTable" id="table9">
             <property name="visible">True</property>
@@ -2970,7 +2960,6 @@
     <child internal-child="vbox">
       <object class="GtkVBox" id="dialog-vbox11">
         <property name="visible">True</property>
-        <property name="orientation">vertical</property>
         <property name="spacing">2</property>
         <child>
           <object class="GtkTable" id="table11">
@@ -2981,7 +2970,7 @@
             <property name="column_spacing">6</property>
             <property name="row_spacing">6</property>
             <child>
-              <object class="GtkLabel" id="label1">
+              <object class="GtkLabel" id="label42">
                 <property name="visible">True</property>
                 <property name="label" translatable="yes">Converts between different currencies. Enter the amount and the currency you want to convert from on the upper row, and the currency you want to convert to on the lower row, and the amount will be displayed on the lower row.</property>
                 <property name="wrap">True</property>
diff --git a/data/buttons-programming.ui b/data/buttons-programming.ui
index 5c0e516..41e9931 100644
--- a/data/buttons-programming.ui
+++ b/data/buttons-programming.ui
@@ -1823,7 +1823,7 @@
                     <property name="AtkObject::accessible-name" translatable="yes" comments="Accessible name for the store value button">Store</property>
                   </object>
                 </child>
-                <signal name="clicked" handler="popup_cb"/>
+                <signal name="clicked" handler="store_cb"/>
                 <child>
                   <object class="GtkHBox" id="hbox20">
                     <property name="visible">True</property>
@@ -1871,7 +1871,7 @@
                     <property name="AtkObject::accessible-name" translatable="yes" comments="Accessible name for the recall value button">Recall</property>
                   </object>
                 </child>
-                <signal name="clicked" handler="popup_cb"/>
+                <signal name="clicked" handler="recall_cb"/>
                 <child>
                   <object class="GtkHBox" id="hbox19">
                     <property name="visible">True</property>
@@ -2563,7 +2563,7 @@
                 <property name="border_width">3</property>
                 <property name="use_underline">True</property>
                 <property name="focus_on_click">False</property>
-                <signal name="clicked" handler="button_cb"/>
+                <signal name="clicked" handler="numeric_point_cb"/>
               </object>
               <packing>
                 <property name="left_attach">1</property>
@@ -2988,7 +2988,7 @@
                     <property name="AtkObject::accessible-name" translatable="yes" comments="Accessible name for the shift right button">Shift Right</property>
                   </object>
                 </child>
-                <signal name="clicked" handler="popup_cb"/>
+                <signal name="clicked" handler="shift_right_cb"/>
                 <child>
                   <object class="GtkHBox" id="hbox10">
                     <property name="visible">True</property>
@@ -3037,7 +3037,7 @@
                     <property name="AtkObject::accessible-name" translatable="yes" comments="Accessible name for the shift left button">Shift Left</property>
                   </object>
                 </child>
-                <signal name="clicked" handler="popup_cb"/>
+                <signal name="clicked" handler="shift_left_cb"/>
                 <child>
                   <object class="GtkHBox" id="hbox11">
                     <property name="visible">True</property>
@@ -3213,7 +3213,7 @@
                     <property name="AtkObject::accessible-name" translatable="yes" comments="Accessible name for the insert character button">Insert Character</property>
                   </object>
                 </child>
-                <signal name="clicked" handler="insert_ascii_cb"/>
+                <signal name="clicked" handler="insert_character_code_cb"/>
               </object>
               <packing>
                 <property name="left_attach">9</property>
@@ -3230,14 +3230,14 @@
       </object>
     </child>
   </object>
-  <object class="GtkDialog" id="ascii_dialog">
+  <object class="GtkDialog" id="character_code_dialog">
     <property name="border_width">6</property>
-    <property name="title" translatable="yes" comments="Title of insert ASCII dialog">Insert ASCII Value</property>
+    <property name="title" translatable="yes" comments="Title of insert character code dialog">Insert Character Code</property>
     <property name="resizable">False</property>
     <property name="type_hint">dialog</property>
     <property name="has_separator">False</property>
-    <signal name="response" handler="ascii_dialog_response_cb"/>
-    <signal name="delete_event" handler="ascii_dialog_delete_cb"/>
+    <signal name="response" handler="character_code_dialog_response_cb"/>
+    <signal name="delete_event" handler="character_code_dialog_delete_cb"/>
     <child internal-child="vbox">
       <object class="GtkVBox" id="dialog-vbox3">
         <property name="visible">True</property>
@@ -3250,7 +3250,7 @@
                 <property name="visible">True</property>
                 <property name="label" translatable="yes" comments="Insert ASCII dialog: Label before character entry">Ch_aracter:</property>
                 <property name="use_underline">True</property>
-                <property name="mnemonic_widget">ascii_entry</property>
+                <property name="mnemonic_widget">character_code_entry</property>
               </object>
               <packing>
                 <property name="expand">False</property>
@@ -3259,12 +3259,12 @@
               </packing>
             </child>
             <child>
-              <object class="GtkEntry" id="ascii_entry">
+              <object class="GtkEntry" id="character_code_entry">
                 <property name="visible">True</property>
                 <property name="can_focus">True</property>
                 <property name="max_length">1</property>
                 <property name="invisible_char">&#x25CF;</property>
-                <signal name="activate" handler="ascii_dialog_activate_cb"/>
+                <signal name="activate" handler="character_code_dialog_activate_cb"/>
               </object>
               <packing>
                 <property name="expand">False</property>
diff --git a/data/gcalctool.ui b/data/gcalctool.ui
index 6bcc711..2390997 100644
--- a/data/gcalctool.ui
+++ b/data/gcalctool.ui
@@ -189,6 +189,7 @@
                           <object class="GtkTextView" id="displayitem">
                             <property name="visible">True</property>
                             <property name="can_focus">True</property>
+                            <property name="can_default">True</property>
                             <property name="pixels_above_lines">8</property>
                             <property name="pixels_below_lines">2</property>
                             <property name="editable">False</property>
@@ -235,352 +236,6 @@
             <property name="position">1</property>
           </packing>
         </child>
-        <child>
-          <object class="GtkVBox" id="button_vbox">
-            <property name="visible">True</property>
-            <property name="border_width">5</property>
-            <child>
-              <placeholder/>
-            </child>
-          </object>
-          <packing>
-            <property name="position">2</property>
-          </packing>
-        </child>
-      </object>
-    </child>
-  </object>
-  <object class="GtkMenu" id="left_shift_popup">
-    <property name="border_width">1</property>
-    <child>
-      <object class="GtkMenuItem" id="shift_left1_menu">
-        <property name="visible">True</property>
-        <property name="label" translatable="yes" comments="Left Shift Popup: Menu item to shift left by 1 bit">_1 place</property>
-        <property name="use_underline">True</property>
-        <signal name="activate" handler="shift_cb"/>
-      </object>
-    </child>
-    <child>
-      <object class="GtkMenuItem" id="shift_left2_menu">
-        <property name="visible">True</property>
-        <property name="label" translatable="yes" comments="Left Shift Popup: Menu item to shift left by 2 bits">_2 places</property>
-        <property name="use_underline">True</property>
-        <signal name="activate" handler="shift_cb"/>
-      </object>
-    </child>
-    <child>
-      <object class="GtkMenuItem" id="shift_left3_menu">
-        <property name="visible">True</property>
-        <property name="label" translatable="yes" comments="Left Shift Popup: Menu item to shift left by 3 bits">_3 places</property>
-        <property name="use_underline">True</property>
-        <signal name="activate" handler="shift_cb"/>
-      </object>
-    </child>
-    <child>
-      <object class="GtkMenuItem" id="shift_left4_menu">
-        <property name="visible">True</property>
-        <property name="label" translatable="yes" comments="Left Shift Popup: Menu item to shift left by 4 bits">_4 places</property>
-        <property name="use_underline">True</property>
-        <signal name="activate" handler="shift_cb"/>
-      </object>
-    </child>
-    <child>
-      <object class="GtkMenuItem" id="shift_left5_menu">
-        <property name="visible">True</property>
-        <property name="label" translatable="yes" comments="Left Shift Popup: Menu item to shift left by 5 bits">_5 places</property>
-        <property name="use_underline">True</property>
-        <signal name="activate" handler="shift_cb"/>
-      </object>
-    </child>
-    <child>
-      <object class="GtkMenuItem" id="shift_left6_menu">
-        <property name="visible">True</property>
-        <property name="label" translatable="yes" comments="Left Shift Popup: Menu item to shift left by 6 bits">_6 places</property>
-        <property name="use_underline">True</property>
-        <signal name="activate" handler="shift_cb"/>
-      </object>
-    </child>
-    <child>
-      <object class="GtkMenuItem" id="shift_left7_menu">
-        <property name="visible">True</property>
-        <property name="label" translatable="yes" comments="Left Shift Popup: Menu item to shift left by 7 bits">_7 places</property>
-        <property name="use_underline">True</property>
-        <signal name="activate" handler="shift_cb"/>
-      </object>
-    </child>
-    <child>
-      <object class="GtkMenuItem" id="shift_left8_menu">
-        <property name="visible">True</property>
-        <property name="label" translatable="yes" comments="Left Shift Popup: Menu item to shift left by 8 bits">_8 places</property>
-        <property name="use_underline">True</property>
-        <signal name="activate" handler="shift_cb"/>
-      </object>
-    </child>
-    <child>
-      <object class="GtkMenuItem" id="shift_left9_menu">
-        <property name="visible">True</property>
-        <property name="label" translatable="yes" comments="Left Shift Popup: Menu item to shift left by 9 bits">_9 places</property>
-        <property name="use_underline">True</property>
-        <signal name="activate" handler="shift_cb"/>
-      </object>
-    </child>
-    <child>
-      <object class="GtkMenuItem" id="shift_left10_menu">
-        <property name="visible">True</property>
-        <property name="label" translatable="yes" comments="Left Shift Popup: Menu item to shift left by 10 bits">10 places</property>
-        <property name="use_underline">True</property>
-        <signal name="activate" handler="shift_cb"/>
-      </object>
-    </child>
-    <child>
-      <object class="GtkMenuItem" id="shift_left11_menu">
-        <property name="visible">True</property>
-        <property name="label" translatable="yes" comments="Left Shift Popup: Menu item to shift left by 11 bits">11 places</property>
-        <property name="use_underline">True</property>
-        <signal name="activate" handler="shift_cb"/>
-      </object>
-    </child>
-    <child>
-      <object class="GtkMenuItem" id="shift_left12_menu">
-        <property name="visible">True</property>
-        <property name="label" translatable="yes" comments="Left Shift Popup: Menu item to shift left by 12 bits">12 places</property>
-        <property name="use_underline">True</property>
-        <signal name="activate" handler="shift_cb"/>
-      </object>
-    </child>
-    <child>
-      <object class="GtkMenuItem" id="shift_left13_menu">
-        <property name="visible">True</property>
-        <property name="label" translatable="yes" comments="Left Shift Popup: Menu item to shift left by 13 bits">13 places</property>
-        <property name="use_underline">True</property>
-        <signal name="activate" handler="shift_cb"/>
-      </object>
-    </child>
-    <child>
-      <object class="GtkMenuItem" id="shift_left14_menu">
-        <property name="visible">True</property>
-        <property name="label" translatable="yes" comments="Left Shift Popup: Menu item to shift left by 14 bits">14 places</property>
-        <property name="use_underline">True</property>
-        <signal name="activate" handler="shift_cb"/>
-      </object>
-    </child>
-    <child>
-      <object class="GtkMenuItem" id="shift_left15_menu">
-        <property name="visible">True</property>
-        <property name="label" translatable="yes" comments="Left Shift Popup: Menu item to shift left by 15 bits">15 places</property>
-        <property name="use_underline">True</property>
-        <signal name="activate" handler="shift_cb"/>
-      </object>
-    </child>
-  </object>
-  <object class="GtkMenu" id="right_shift_popup">
-    <property name="border_width">1</property>
-    <child>
-      <object class="GtkMenuItem" id="shift_right1_menu">
-        <property name="visible">True</property>
-        <property name="label" translatable="yes" comments="Right Shift Popup: Menu item to shift right by 1 bit">_1 place</property>
-        <property name="use_underline">True</property>
-        <signal name="activate" handler="shift_cb"/>
-      </object>
-    </child>
-    <child>
-      <object class="GtkMenuItem" id="shift_right2_menu">
-        <property name="visible">True</property>
-        <property name="label" translatable="yes" comments="Right Shift Popup: Menu item to shift right by 2 bits">_2 places</property>
-        <property name="use_underline">True</property>
-        <signal name="activate" handler="shift_cb"/>
-      </object>
-    </child>
-    <child>
-      <object class="GtkMenuItem" id="shift_right3_menu">
-        <property name="visible">True</property>
-        <property name="label" translatable="yes" comments="Right Shift Popup: Menu item to shift right by 3 bits">_3 places</property>
-        <property name="use_underline">True</property>
-        <signal name="activate" handler="shift_cb"/>
-      </object>
-    </child>
-    <child>
-      <object class="GtkMenuItem" id="shift_right4_menu">
-        <property name="visible">True</property>
-        <property name="label" translatable="yes" comments="Right Shift Popup: Menu item to shift right by 4 bits">_4 places</property>
-        <property name="use_underline">True</property>
-        <signal name="activate" handler="shift_cb"/>
-      </object>
-    </child>
-    <child>
-      <object class="GtkMenuItem" id="shift_right5_menu">
-        <property name="visible">True</property>
-        <property name="label" translatable="yes" comments="Right Shift Popup: Menu item to shift right by 5 bits">_5 places</property>
-        <property name="use_underline">True</property>
-        <signal name="activate" handler="shift_cb"/>
-      </object>
-    </child>
-    <child>
-      <object class="GtkMenuItem" id="shift_right6_menu">
-        <property name="visible">True</property>
-        <property name="label" translatable="yes" comments="Right Shift Popup: Menu item to shift right by 6 bits">_6 places</property>
-        <property name="use_underline">True</property>
-        <signal name="activate" handler="shift_cb"/>
-      </object>
-    </child>
-    <child>
-      <object class="GtkMenuItem" id="shift_right7_menu">
-        <property name="visible">True</property>
-        <property name="label" translatable="yes" comments="Right Shift Popup: Menu item to shift right by 7 bits">_7 places</property>
-        <property name="use_underline">True</property>
-        <signal name="activate" handler="shift_cb"/>
-      </object>
-    </child>
-    <child>
-      <object class="GtkMenuItem" id="shift_right8_menu">
-        <property name="visible">True</property>
-        <property name="label" translatable="yes" comments="Right Shift Popup: Menu item to shift right by 8 bits">_8 places</property>
-        <property name="use_underline">True</property>
-        <signal name="activate" handler="shift_cb"/>
-      </object>
-    </child>
-    <child>
-      <object class="GtkMenuItem" id="shift_right9_menu">
-        <property name="visible">True</property>
-        <property name="label" translatable="yes" comments="Right Shift Popup: Menu item to shift right by 9 bits">_9 places</property>
-        <property name="use_underline">True</property>
-        <signal name="activate" handler="shift_cb"/>
-      </object>
-    </child>
-    <child>
-      <object class="GtkMenuItem" id="shift_right10_menu">
-        <property name="visible">True</property>
-        <property name="label" translatable="yes" comments="Right Shift Popup: Menu item to shift right by 10 bits">10 places</property>
-        <property name="use_underline">True</property>
-        <signal name="activate" handler="shift_cb"/>
-      </object>
-    </child>
-    <child>
-      <object class="GtkMenuItem" id="shift_right11_menu">
-        <property name="visible">True</property>
-        <property name="label" translatable="yes" comments="Right Shift Popup: Menu item to shift right by 11 bits">11 places</property>
-        <property name="use_underline">True</property>
-        <signal name="activate" handler="shift_cb"/>
-      </object>
-    </child>
-    <child>
-      <object class="GtkMenuItem" id="shift_right12_menu">
-        <property name="visible">True</property>
-        <property name="label" translatable="yes" comments="Right Shift Popup: Menu item to shift right by 12 bits">12 places</property>
-        <property name="use_underline">True</property>
-        <signal name="activate" handler="shift_cb"/>
-      </object>
-    </child>
-    <child>
-      <object class="GtkMenuItem" id="shift_right13_menu">
-        <property name="visible">True</property>
-        <property name="label" translatable="yes" comments="Right Shift Popup: Menu item to shift right by 13 bits">13 places</property>
-        <property name="use_underline">True</property>
-        <signal name="activate" handler="shift_cb"/>
-      </object>
-    </child>
-    <child>
-      <object class="GtkMenuItem" id="shift_right14_menu">
-        <property name="visible">True</property>
-        <property name="label" translatable="yes" comments="Right Shift Popup: Menu item to shift right by 14 bits">14 places</property>
-        <property name="use_underline">True</property>
-        <signal name="activate" handler="shift_cb"/>
-      </object>
-    </child>
-    <child>
-      <object class="GtkMenuItem" id="shift_right15_menu">
-        <property name="visible">True</property>
-        <property name="label" translatable="yes" comments="Right Shift Popup: Menu item to shift right by 15 bits">15 places</property>
-        <property name="use_underline">True</property>
-        <signal name="activate" handler="shift_cb"/>
-      </object>
-    </child>
-  </object>
-  <object class="GtkMenu" id="memory_store_popup">
-    <child>
-      <object class="GtkMenuItem" id="store_menu_item0">
-        <property name="visible">True</property>
-        <property name="use_underline">True</property>
-        <signal name="activate" handler="store_menu_cb"/>
-      </object>
-    </child>
-    <child>
-      <object class="GtkMenuItem" id="store_menu_item1">
-        <property name="visible">True</property>
-        <property name="use_underline">True</property>
-        <signal name="activate" handler="store_menu_cb"/>
-      </object>
-    </child>
-    <child>
-      <object class="GtkMenuItem" id="store_menu_item2">
-        <property name="visible">True</property>
-        <property name="use_underline">True</property>
-        <signal name="activate" handler="store_menu_cb"/>
-      </object>
-    </child>
-    <child>
-      <object class="GtkMenuItem" id="store_menu_item3">
-        <property name="visible">True</property>
-        <property name="use_underline">True</property>
-        <signal name="activate" handler="store_menu_cb"/>
-      </object>
-    </child>
-    <child>
-      <object class="GtkMenuItem" id="store_menu_item4">
-        <property name="visible">True</property>
-        <property name="use_underline">True</property>
-        <signal name="activate" handler="store_menu_cb"/>
-      </object>
-    </child>
-    <child>
-      <object class="GtkMenuItem" id="store_menu_item5">
-        <property name="visible">True</property>
-        <property name="use_underline">True</property>
-        <signal name="activate" handler="store_menu_cb"/>
-      </object>
-    </child>
-  </object>
-  <object class="GtkMenu" id="memory_recall_popup">
-    <child>
-      <object class="GtkMenuItem" id="recall_menu_item0">
-        <property name="visible">True</property>
-        <property name="use_underline">True</property>
-        <signal name="activate" handler="recall_menu_cb"/>
-      </object>
-    </child>
-    <child>
-      <object class="GtkMenuItem" id="recall_menu_item1">
-        <property name="visible">True</property>
-        <property name="use_underline">True</property>
-        <signal name="activate" handler="recall_menu_cb"/>
-      </object>
-    </child>
-    <child>
-      <object class="GtkMenuItem" id="recall_menu_item2">
-        <property name="visible">True</property>
-        <property name="use_underline">True</property>
-        <signal name="activate" handler="recall_menu_cb"/>
-      </object>
-    </child>
-    <child>
-      <object class="GtkMenuItem" id="recall_menu_item3">
-        <property name="visible">True</property>
-        <property name="use_underline">True</property>
-        <signal name="activate" handler="recall_menu_cb"/>
-      </object>
-    </child>
-    <child>
-      <object class="GtkMenuItem" id="recall_menu_item4">
-        <property name="visible">True</property>
-        <property name="use_underline">True</property>
-        <signal name="activate" handler="recall_menu_cb"/>
-      </object>
-    </child>
-    <child>
-      <object class="GtkMenuItem" id="recall_menu_item5">
-        <property name="visible">True</property>
-        <property name="use_underline">True</property>
-        <signal name="activate" handler="recall_menu_cb"/>
       </object>
     </child>
   </object>
diff --git a/data/preferences.ui b/data/preferences.ui
new file mode 100644
index 0000000..dfdc109
--- /dev/null
+++ b/data/preferences.ui
@@ -0,0 +1,317 @@
+<?xml version="1.0"?>
+<interface>
+  <requires lib="gtk+" version="2.16"/>
+  <!-- interface-naming-policy toplevel-contextual -->
+  <object class="GtkListStore" id="angle_unit_model">
+    <columns>
+      <!-- column-name label -->
+      <column type="gchararray"/>
+      <!-- column-name units -->
+      <column type="gchararray"/>
+    </columns>
+    <data>
+      <row>
+        <col id="0" translatable="yes" comments="Preferences dialog: Angle unit combo box: Use degrees for trigonometric calculations">Degrees</col>
+        <col id="1">degrees</col>
+      </row>
+      <row>
+        <col id="0" translatable="yes" comments="Preferences dialog: Angle unit combo box: Use radians for trigonometric calculations">Radians</col>
+        <col id="1">radians</col>
+      </row>
+      <row>
+        <col id="0" translatable="yes" comments="Preferences dialog: Angle unit combo box: Use gradians for trigonometric calculations">Gradians</col>
+        <col id="1">gradians</col>
+      </row>
+    </data>
+  </object>
+  <object class="GtkListStore" id="display_format_model">
+    <columns>
+      <!-- column-name label -->
+      <column type="gchararray"/>
+      <!-- column-name format -->
+      <column type="gchararray"/>
+    </columns>
+    <data>
+      <row>
+        <col id="0" translatable="yes" comments="Number display mode combo: Decimal, e.g. 1234">Decimal</col>
+        <col id="1">decimal</col>
+      </row>
+      <row>
+        <col id="0" translatable="yes" comments="Number display mode combo: Scientific, e.g. 1.234&#xD7;10^3">Scientific</col>
+        <col id="1">scientific</col>
+      </row>
+      <row>
+        <col id="0" translatable="yes" comments="Number display mode combo: Engineering, e.g. 1.234k">Engineering</col>
+        <col id="1">engineering</col>
+      </row>
+      <row>
+        <col id="0" translatable="yes" comments="Number display mode combo: Binary, e.g. 10011010010&#x2082;">Binary</col>
+        <col id="1">binary</col>
+      </row>
+      <row>
+        <col id="0" translatable="yes" comments="Number display mode combo: Octal, e.g. 2322&#x2088;">Octal</col>
+        <col id="1">octal</col>
+      </row>
+      <row>
+        <col id="0" translatable="yes" comments="Number display mode combo: Hexadecimal, e.g. 4D2&#x2081;&#x2086;">Hexadecimal</col>
+        <col id="1">hexadecimal</col>
+      </row>
+    </data>
+  </object>
+  <object class="GtkListStore" id="word_size_model">
+    <columns>
+      <!-- column-name label -->
+      <column type="gchararray"/>
+      <!-- column-name size -->
+      <column type="gint"/>
+    </columns>
+    <data>
+      <row>
+        <col id="0" translatable="yes" comments="Word size combo: 8 bits">8-bit</col>
+        <col id="1">8</col>
+      </row>
+      <row>
+        <col id="0" translatable="yes" comments="Word size combo: 16 bits">16-bit</col>
+        <col id="1">16</col>
+      </row>
+      <row>
+        <col id="0" translatable="yes" comments="Word size combo: 32 bits">32-bit</col>
+        <col id="1">32</col>
+      </row>
+      <row>
+        <col id="0" translatable="yes" comments="Word size combo: 64 bits">64-bit</col>
+        <col id="1">64</col>
+      </row>
+    </data>
+  </object>
+  <object class="GtkDialog" id="preferences_dialog">
+    <property name="border_width">8</property>
+    <property name="title" translatable="yes">Preferences</property>
+    <property name="type_hint">normal</property>
+    <property name="has_separator">False</property>
+    <signal name="response" handler="preferences_response_cb"/>
+    <signal name="delete_event" handler="preferences_dialog_delete_cb"/>
+    <child internal-child="vbox">
+      <object class="GtkVBox" id="dialog-vbox4">
+        <property name="visible">True</property>
+        <property name="spacing">5</property>
+        <child>
+          <object class="GtkTable" id="table1">
+            <property name="visible">True</property>
+            <property name="border_width">5</property>
+            <property name="n_rows">4</property>
+            <property name="n_columns">2</property>
+            <property name="column_spacing">6</property>
+            <property name="row_spacing">12</property>
+            <child>
+              <object class="GtkLabel" id="label8">
+                <property name="visible">True</property>
+                <property name="xalign">0</property>
+                <property name="label" translatable="yes" comments="Preferences dialog: Label for angle unit combo box">_Angle units:</property>
+                <property name="use_underline">True</property>
+                <property name="mnemonic_widget">angle_unit_combobox</property>
+              </object>
+              <packing>
+                <property name="x_options">GTK_FILL</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkLabel" id="label9">
+                <property name="visible">True</property>
+                <property name="xalign">0</property>
+                <property name="label" translatable="yes" comments="Preferences dialog: Label for display format combo box">Display _Format:</property>
+                <property name="use_underline">True</property>
+                <property name="mnemonic_widget">display_format_combobox</property>
+              </object>
+              <packing>
+                <property name="top_attach">1</property>
+                <property name="bottom_attach">2</property>
+                <property name="x_options">GTK_FILL</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkComboBox" id="angle_unit_combobox">
+                <property name="visible">True</property>
+                <property name="model">angle_unit_model</property>
+                <signal name="changed" handler="angle_unit_combobox_changed_cb"/>
+              </object>
+              <packing>
+                <property name="left_attach">1</property>
+                <property name="right_attach">2</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkComboBox" id="display_format_combobox">
+                <property name="visible">True</property>
+                <property name="model">display_format_model</property>
+                <signal name="changed" handler="display_format_combobox_changed_cb"/>
+              </object>
+              <packing>
+                <property name="left_attach">1</property>
+                <property name="right_attach">2</property>
+                <property name="top_attach">1</property>
+                <property name="bottom_attach">2</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkLabel" id="label11">
+                <property name="visible">True</property>
+                <property name="xalign">0</property>
+                <property name="label" translatable="yes" comments="Preferences dialog: label for word size combo box">Word _size:</property>
+                <property name="use_underline">True</property>
+                <property name="mnemonic_widget">word_size_combobox</property>
+              </object>
+              <packing>
+                <property name="top_attach">3</property>
+                <property name="bottom_attach">4</property>
+                <property name="x_options">GTK_FILL</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkComboBox" id="word_size_combobox">
+                <property name="visible">True</property>
+                <property name="model">word_size_model</property>
+                <signal name="changed" handler="word_size_combobox_changed_cb"/>
+              </object>
+              <packing>
+                <property name="left_attach">1</property>
+                <property name="right_attach">2</property>
+                <property name="top_attach">3</property>
+                <property name="bottom_attach">4</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkAlignment" id="alignment1">
+                <property name="visible">True</property>
+                <property name="bottom_padding">6</property>
+                <property name="left_padding">12</property>
+                <child>
+                  <object class="GtkTable" id="table2">
+                    <property name="visible">True</property>
+                    <property name="n_rows">3</property>
+                    <property name="row_spacing">6</property>
+                    <child>
+                      <object class="GtkCheckButton" id="trailing_zeroes_check">
+                        <property name="label" translatable="yes" comments="Preferences dialog: label for show trailing zeroes check button">Show trailing _zeroes</property>
+                        <property name="visible">True</property>
+                        <property name="can_focus">True</property>
+                        <property name="receives_default">False</property>
+                        <property name="use_underline">True</property>
+                        <property name="draw_indicator">True</property>
+                        <signal name="toggled" handler="trailing_zeroes_check_toggled_cb"/>
+                      </object>
+                      <packing>
+                        <property name="top_attach">1</property>
+                        <property name="bottom_attach">2</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkCheckButton" id="thousands_separator_check">
+                        <property name="label" translatable="yes" comments="Preferences dialog: label for show thousands separator check button">Show _thousands separators</property>
+                        <property name="visible">True</property>
+                        <property name="can_focus">True</property>
+                        <property name="receives_default">False</property>
+                        <property name="use_underline">True</property>
+                        <property name="draw_indicator">True</property>
+                        <signal name="toggled" handler="thousands_separator_check_toggled_cb"/>
+                      </object>
+                      <packing>
+                        <property name="top_attach">2</property>
+                        <property name="bottom_attach">3</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkHBox" id="hbox1">
+                        <property name="visible">True</property>
+                        <property name="spacing">6</property>
+                        <child>
+                          <object class="GtkLabel" id="decimal_places_label1">
+                            <property name="visible">True</property>
+                            <property name="xalign">0</property>
+                            <property name="label" comments="Not translated by Gtk+, is translated as one string">Show</property>
+                            <property name="use_underline">True</property>
+                            <property name="mnemonic_widget">decimal_places_spin</property>
+                          </object>
+                          <packing>
+                            <property name="expand">False</property>
+                            <property name="position">0</property>
+                          </packing>
+                        </child>
+                        <child>
+                          <object class="GtkSpinButton" id="decimal_places_spin">
+                            <property name="visible">True</property>
+                            <property name="can_focus">True</property>
+                            <property name="invisible_char">&#x25CF;</property>
+                            <property name="adjustment">decimal_places_adjustment</property>
+                            <signal name="value_changed" handler="decimal_places_spin_change_value_cb"/>
+                          </object>
+                          <packing>
+                            <property name="expand">False</property>
+                            <property name="position">1</property>
+                          </packing>
+                        </child>
+                        <child>
+                          <object class="GtkLabel" id="decimal_places_label2">
+                            <property name="visible">True</property>
+                            <property name="xalign">0</property>
+                            <property name="label" comments="Not translated by Gtk+, is translated as one string">decimal _places</property>
+                            <property name="use_underline">True</property>
+                            <property name="mnemonic_widget">decimal_places_spin</property>
+                          </object>
+                          <packing>
+                            <property name="position">2</property>
+                          </packing>
+                        </child>
+                      </object>
+                    </child>
+                  </object>
+                </child>
+              </object>
+              <packing>
+                <property name="right_attach">2</property>
+                <property name="top_attach">2</property>
+                <property name="bottom_attach">3</property>
+              </packing>
+            </child>
+          </object>
+          <packing>
+            <property name="position">1</property>
+          </packing>
+        </child>
+        <child internal-child="action_area">
+          <object class="GtkHButtonBox" id="dialog-action_area4">
+            <property name="visible">True</property>
+            <property name="layout_style">end</property>
+            <child>
+              <object class="GtkButton" id="button1">
+                <property name="label">gtk-close</property>
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="receives_default">True</property>
+                <property name="use_stock">True</property>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="fill">False</property>
+                <property name="position">0</property>
+              </packing>
+            </child>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="pack_type">end</property>
+            <property name="position">0</property>
+          </packing>
+        </child>
+      </object>
+    </child>
+    <action-widgets>
+      <action-widget response="0">button1</action-widget>
+    </action-widgets>
+  </object>
+  <object class="GtkAdjustment" id="decimal_places_adjustment">
+    <property name="upper">9</property>
+    <property name="step_increment">1</property>
+    <property name="page_increment">1</property>
+  </object>
+</interface>
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 8125ca5..f26b7de 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -1,8 +1,12 @@
 # List of source files containing translatable strings.
 # Please keep this file sorted alphabetically.
 [encoding: UTF-8]
-[type: gettext/glade]data/financial.ui
+[type: gettext/glade]data/buttons-advanced.ui
+[type: gettext/glade]data/buttons-basic.ui
+[type: gettext/glade]data/buttons-financial.ui
+[type: gettext/glade]data/buttons-programming.ui
 [type: gettext/glade]data/gcalctool.ui
+[type: gettext/glade]data/preferences.ui
 data/gcalctool.desktop.in
 data/gcalctool.schemas.in
 src/calctool.c
@@ -10,10 +14,13 @@ src/currency.h
 src/display.c
 src/financial.c
 src/get.c
-src/gtk.c
 src/mp.c
 src/mp-binary.c
 src/mp-convert.c
 src/mp-equation.c
 src/mp-trigonometric.c
 src/register.c
+src/ui.c
+src/ui-buttons.c
+src/ui-display.c
+src/ui-preferences.c
diff --git a/src/Makefile.am b/src/Makefile.am
index d552067..c113957 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -38,8 +38,6 @@ gcalctool_SOURCES = \
 	ui-buttons.h \
 	ui-display.c \
 	ui-display.h \
-	ui-financial.c \
-	ui-financial.h \
 	ui-preferences.c \
 	ui-preferences.h \
 	unittest.c \
diff --git a/src/calctool.c b/src/calctool.c
index eb71c2a..f55c138 100644
--- a/src/calctool.c
+++ b/src/calctool.c
@@ -219,7 +219,7 @@ main(int argc, char **argv)
     init_state();
     register_init();
     display_init(&v->display);
-    ui_init(&argc, &argv);
+    ui_gtk_init(&argc, &argv);
 
     get_options(argc, argv);
 
diff --git a/src/display.c b/src/display.c
index 650047e..3b61891 100644
--- a/src/display.c
+++ b/src/display.c
@@ -204,7 +204,7 @@ display_set_number(GCDisplay *display, const MPNumber *x)
     display_set_string(display, text, -1);
 
     enabled = display_get_unsigned_integer(display, &bit_value);
-    ui_set_bitfield(X, enabled, bit_value);
+    ui_buttons_set_bitfield(ui_get_buttons(X), enabled, bit_value);
 }
 
 
@@ -252,7 +252,7 @@ display_refresh(GCDisplay *display)
 
     cursor = display_get_cursor(display);
     display_make_text(display, localized, MAX_LOCALIZED, &cursor);
-    ui_set_display(X, localized, cursor);
+    ui_display_set(ui_get_display(X), localized, cursor);
 }
 
 
@@ -287,7 +287,7 @@ display_set_cursor(GCDisplay *display, int cursor)
 void
 display_set_error(GCDisplay *display, const char *message)
 {
-    ui_set_statusbar(X, message);
+    ui_display_set_status(ui_get_display(X), message);
 }
 
 
@@ -366,9 +366,9 @@ display_pop(GCDisplay *display)
 {
     if (display->h.current != display->h.begin) {
         display->h.current = ((display->h.current - 1) % UNDO_HISTORY_LENGTH);
-        ui_set_statusbar(X, "");
+        ui_display_set_status(ui_get_display(X), "");
     } else {
-        ui_set_statusbar(X, _("No undo history"));
+        ui_display_set_status(ui_get_display(X), _("No undo history"));
     }
 
     display_refresh(display);
@@ -380,9 +380,9 @@ display_unpop(GCDisplay *display)
 {
     if (display->h.current != display->h.end) {
         display->h.current = ((display->h.current + 1) % UNDO_HISTORY_LENGTH);
-        ui_set_statusbar(X, "");
+        ui_display_set_status(ui_get_display(X), "");
     } else {
-        ui_set_statusbar(X, _("No redo steps"));
+        ui_display_set_status(ui_get_display(X), _("No redo steps"));
     }
     get_state(display)->cursor = -1;
     display_refresh(display);
@@ -427,7 +427,7 @@ display_insert(GCDisplay *display, int cursor_start, int cursor_end, const char
         }
 
         cursor = 0;
-        for (c = ui_get_display(X); *c; c = g_utf8_next_char(c), cursor++) {
+        for (c = ui_display_get_text(ui_get_display(X)); *c; c = g_utf8_next_char(c), cursor++) {
             gboolean use = TRUE;
 
             /* Ignore selected part */
@@ -481,7 +481,7 @@ display_backspace(GCDisplay *display, int cursor_start, int cursor_end)
     /* If cursor is at end of the line then delete the last character preserving accuracy */
     if (cursor_start < 0) {
         int len;
-        len = g_utf8_strlen(ui_get_display(X), -1);
+        len = g_utf8_strlen(ui_display_get_text(ui_get_display(X)), -1);
         display_insert(display, len - 1, len, "");
     } else if (cursor_start != cursor_end) {
         display_insert(display, cursor_start, cursor_end, "");
@@ -912,7 +912,7 @@ do_shift(GCDisplay *display, int count)
     if (!display_is_usable_number(display, &z)) {
         /* Translators: This message is displayed in the status bar when a bit
            shift operation is performed and the display does not contain a number */
-        ui_set_statusbar(X, _("No sane value to bitwise shift"));
+        ui_display_set_status(ui_get_display(X), _("No sane value to bitwise shift"));
     }
     else {
         mp_shift(&z, count, display_get_answer(display));
@@ -928,7 +928,7 @@ do_factorize()
 
     if (!display_is_usable_number(&v->display, &value)) {
         /* Translators: Error displayed when trying to factorize a non-integer value */
-        ui_set_statusbar(X, _("Need an integer to factorize"));
+        ui_display_set_status(ui_get_display(X), _("Need an integer to factorize"));
         return;
     }
     display_clear(&v->display);
@@ -954,7 +954,7 @@ do_sto(GCDisplay *display, const char *name)
     MPNumber t;
 
     if (!display_is_usable_number(display, &t))
-        ui_set_statusbar(X, _("No sane value to store"));
+        ui_display_set_status(ui_get_display(X), _("No sane value to store"));
     else
         register_set_value(name, &t);
 }
@@ -985,7 +985,7 @@ display_do_function(GCDisplay *display, int function, gpointer arg, int cursor_s
     display_set_cursor(display, cursor_start);
     ans = display_get_answer(display);
 
-    ui_set_statusbar(X, "");
+    ui_display_set_status(ui_get_display(X), "");
 
     switch (function) {
         case FN_CLEAR:
@@ -1105,7 +1105,7 @@ display_do_function(GCDisplay *display, int function, gpointer arg, int cursor_s
                         break;
                 }
                 if (message)
-                    ui_set_statusbar(X, message);
+                    ui_display_set_status(ui_get_display(X), message);
             }
             break;
 
@@ -1119,5 +1119,5 @@ display_do_function(GCDisplay *display, int function, gpointer arg, int cursor_s
     }
 
     enabled = display_get_unsigned_integer(display, &bit_value);
-    ui_set_bitfield(X, enabled, bit_value);
+    ui_buttons_set_bitfield(ui_get_buttons(X), enabled, bit_value);
 }
diff --git a/src/ui-buttons.c b/src/ui-buttons.c
index de49e50..cd6359d 100644
--- a/src/ui-buttons.c
+++ b/src/ui-buttons.c
@@ -17,8 +17,48 @@
  */
 
 #include "ui-buttons.h"
-#include "ui-internal.h"
 #include "register.h"
+#include "financial.h"
+#include "currency.h"
+#include "calctool.h" // FIXME: TEMP
+
+enum {
+    PROP_0,
+    PROP_DISPLAY
+};
+
+#define MAXBITS 64      /* Bit panel: number of bit fields. */
+#define MAX_REGISTERS 6 // FIXME: Obsolete once use a hash table
+
+struct MathButtonsPrivate
+{
+    MathDisplay *display;
+
+    ButtonMode mode;
+    GtkBuilder *basic_ui, *advanced_ui, *financial_ui, *programming_ui;
+
+    GdkColor colour_numbers, colour_action, colour_operator, colour_function, colour_memory, colour_trig, colour_group;
+
+    GtkWidget *button_vbox;
+    GtkWidget *bas_panel, *adv_panel, *fin_panel, *prog_panel;
+
+    GtkWidget *store_menu, *recall_menu;
+    GtkWidget *recall_menu_labels[MAX_REGISTERS];
+    GtkWidget *store_menu_labels[MAX_REGISTERS];
+
+    GtkWidget *shift_left_menu, *shift_right_menu;
+
+    GList *superscript_toggles;
+    GList *subscript_toggles;
+
+    GtkWidget *bit_panel;
+    GtkWidget *bit_labels[MAXBITS];
+
+    GtkWidget *character_code_dialog;
+    GtkWidget *character_code_entry;
+};
+
+G_DEFINE_TYPE (MathButtons, ui_buttons, G_TYPE_OBJECT);
 
 #define UI_BASIC_FILE       UI_DIR "/buttons-basic.ui"
 #define UI_ADVANCED_FILE    UI_DIR "/buttons-advanced.ui"
@@ -32,16 +72,6 @@
 
 static char *registers[] = {"a", "b", "c", "x", "y", "z", NULL};
 
-typedef enum {
-    POPUP_RIGHT,     /* Place popup to right of baseframe */
-    POPUP_LEFT,      /* Place popup to left of baseframe */
-    POPUP_ABOVE,     /* Place popup above baseframe */
-    POPUP_BELOW,     /* Place popup below baseframe */
-    POPUP_LOR,       /* Place popup to right or left of baseframe */
-    POPUP_AOB,       /* Place popup above or below baseframe */
-    POPUP_CENTERED   /* Center popup within baseframe */
-} PopupLocation;
-
 #define WM_WIDTH_FACTOR  10
 #define WM_HEIGHT_FACTOR 30
 
@@ -90,34 +120,53 @@ static ButtonData button_data[] = {
     {NULL, NULL}
 };
 
-static const char *subscript_digits[] = {"â??", "â??", "â??", "â??", "â??", "â??", "â??", "â??", "â??", "â??", NULL};
-static const char *superscript_digits[] = {"�", "¹", "²", "³", "�", "�", "�", "�", "�", "�", NULL};
+typedef enum {
+    CURRENCY_TARGET_UPPER,
+    CURRENCY_TARGET_LOWER
+} CurrencyTargetRow;
+
+/* The names of each field in the dialogs for the financial functions */
+static char *finc_dialog_fields[][5] = {
+    {"ctrm_pint", "ctrm_fv",     "ctrm_pv",    NULL,         NULL},
+    {"ddb_cost",  "ddb_life",    "ddb_period", NULL,         NULL},
+    {"fv_pmt",    "fv_pint",     "fv_n",       NULL,         NULL},
+    {"gpm_cost",  "gpm_margin",  NULL,         NULL,         NULL},
+    {"pmt_prin",  "pmt_pint",    "pmt_n",      NULL,         NULL},
+    {"pv_pmt",    "pv_pint",     "pv_n",       NULL,         NULL},
+    {"rate_fv",   "rate_pv",     "rate_n",     NULL,         NULL},
+    {"sln_cost",  "sln_salvage", "sln_life",   NULL,         NULL},
+    {"syd_cost",  "syd_salvage", "syd_life",   "syd_period", NULL},
+    {"term_pmt",  "term_fv",     "term_pint",  NULL,         NULL},
+    {NULL,        NULL,          NULL,         NULL,         NULL}
+};
 
 
-Buttons *
-ui_buttons_new(GCalctoolUI *ui)
+MathButtons *
+ui_buttons_new(MathDisplay *display)
 {
-    Buttons *buttons;
-  
-    buttons = g_malloc0(sizeof(Buttons));
-    buttons->ui = ui;
-    buttons->button_vbox = GET_WIDGET(ui->ui, "button_vbox");
-    return buttons;
+    return g_object_new (ui_buttons_get_type(), "display", display, NULL);
+}
+
+
+GtkWidget *
+ui_buttons_get_widget(MathButtons *buttons)
+{
+    return buttons->priv->button_vbox;
 }
 
 
 static GtkWidget *
-get_buttons(Buttons *buttons, ButtonMode mode)
+get_buttons(MathButtons *buttons, ButtonMode mode)
 {
     switch (mode) {
     case BASIC:
-        return buttons->bas_panel;
+        return buttons->priv->bas_panel;
     case ADVANCED:
-        return buttons->adv_panel;
+        return buttons->priv->adv_panel;
     case FINANCIAL:
-        return buttons->fin_panel;
+        return buttons->priv->fin_panel;
     case PROGRAMMING:
-        return buttons->prog_panel;
+        return buttons->priv->prog_panel;
     }
 }
 
@@ -169,84 +218,128 @@ static void set_int_data(GtkBuilder *ui, const gchar *object_name, const gchar *
 
 
 static void
-load_mode(Buttons *buttons, ButtonMode mode)
+load_finc_dialogs(MathButtons *buttons)
+{
+    int i, j;
+    GtkListStore *currency_store;
+    GtkCellRenderer *render;
+    GtkSpinButton *currency_amount_upper;
+    GtkSpinButton *currency_amount_lower;
+    GtkComboBox   *currency_type_upper;
+    GtkComboBox   *currency_type_lower;
+
+    set_int_data(buttons->priv->financial_ui, "ctrm_dialog", "finc_dialog", FINC_CTRM_DIALOG);
+    set_int_data(buttons->priv->financial_ui, "ddb_dialog", "finc_dialog", FINC_DDB_DIALOG);
+    set_int_data(buttons->priv->financial_ui, "fv_dialog", "finc_dialog", FINC_FV_DIALOG);
+    set_int_data(buttons->priv->financial_ui, "gpm_dialog", "finc_dialog", FINC_GPM_DIALOG);
+    set_int_data(buttons->priv->financial_ui, "pmt_dialog", "finc_dialog", FINC_PMT_DIALOG);
+    set_int_data(buttons->priv->financial_ui, "pv_dialog", "finc_dialog", FINC_PV_DIALOG);
+    set_int_data(buttons->priv->financial_ui, "rate_dialog", "finc_dialog", FINC_RATE_DIALOG);
+    set_int_data(buttons->priv->financial_ui, "sln_dialog", "finc_dialog", FINC_SLN_DIALOG);
+    set_int_data(buttons->priv->financial_ui, "syd_dialog", "finc_dialog", FINC_SYD_DIALOG);
+    set_int_data(buttons->priv->financial_ui, "term_dialog", "finc_dialog", FINC_TERM_DIALOG);
+
+    for (i = 0; finc_dialog_fields[i][0] != NULL; i++) {
+        for (j = 0; finc_dialog_fields[i][j]; j++) {
+            GObject *o;
+            o = gtk_builder_get_object(buttons->priv->financial_ui, finc_dialog_fields[i][j]);
+          if(!o)
+            printf("missing '%s'\n", finc_dialog_fields[i][j]);
+            g_object_set_data(o, "finc_field", GINT_TO_POINTER(j));
+            g_object_set_data(o, "finc_dialog", GINT_TO_POINTER(i));
+        }
+    }
+  return;
+
+    currency_amount_upper = GTK_SPIN_BUTTON(gtk_builder_get_object(buttons->priv->financial_ui, "currency_amount_upper"));
+    currency_amount_lower = GTK_SPIN_BUTTON(gtk_builder_get_object(buttons->priv->financial_ui, "currency_amount_lower"));
+    currency_type_upper = GTK_COMBO_BOX(gtk_builder_get_object(buttons->priv->financial_ui, "currency_type_upper"));
+    currency_type_lower = GTK_COMBO_BOX(gtk_builder_get_object(buttons->priv->financial_ui, "currency_type_lower"));
+
+    currency_store = gtk_list_store_new(2,
+                                        G_TYPE_INT,
+                                        G_TYPE_STRING);
+
+    gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(currency_store),
+                                         1,
+                                         GTK_SORT_ASCENDING);
+
+    gtk_combo_box_set_model(currency_type_upper, GTK_TREE_MODEL(currency_store));
+    gtk_combo_box_set_model(currency_type_lower, GTK_TREE_MODEL(currency_store));
+
+    render = gtk_cell_renderer_text_new();
+
+    gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(currency_type_upper),
+                               render,
+                               TRUE);
+    gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(currency_type_lower),
+                               render,
+                               TRUE);
+
+    gtk_cell_layout_add_attribute(GTK_CELL_LAYOUT(currency_type_upper),
+                                  render,
+                                  "text",
+                                  1);
+    gtk_cell_layout_add_attribute(GTK_CELL_LAYOUT(currency_type_lower),
+                                  render,
+                                  "text",
+                                  1);
+
+    set_int_data(buttons->priv->financial_ui, "currency_amount_upper", "target", CURRENCY_TARGET_LOWER);
+    set_int_data(buttons->priv->financial_ui, "currency_amount_lower", "target", CURRENCY_TARGET_UPPER);
+}
+
+
+static void
+load_mode(MathButtons *buttons, ButtonMode mode)
 {
     GtkBuilder *builder, **builder_ptr;
     gint i;
     gchar name[MAXLINE];
-    GdkColor colour_numbers, colour_action, colour_operator, colour_function, colour_memory, colour_trig, colour_group;
     const gchar *builder_file;
-    gchar *objects[] = { "button_panel", NULL };
+    gchar *objects[] = { "button_panel", "character_code_dialog", "currency_dialog",
+                         "ctrm_dialog", "ddb_dialog", "fv_dialog", "gpm_dialog",
+                         "pmt_dialog", "pv_dialog", "rate_dialog", "sln_dialog",
+                         "syd_dialog", "term_dialog", "adjustment1", "adjustment2", NULL };
     GtkWidget *widget, **panel;
+    GError *error = NULL;
 
-    colour_numbers.red = 0;
-    colour_numbers.green = 0;
-    colour_numbers.blue = 65535;
-    colour_action.red = 0;
-    colour_action.green = 65535;
-    colour_action.blue = 0;
-    colour_operator.red = 65535;
-    colour_operator.green = 0;
-    colour_operator.blue = 0;
-    colour_function.red = 0;
-    colour_function.green = 65535;
-    colour_function.blue = 65535;
-    colour_memory.red = 65535;
-    colour_memory.green = 0;
-    colour_memory.blue = 65535;
-    colour_trig.red = 65535;
-    colour_trig.green = 65535;
-    colour_trig.blue = 0;
-    colour_group.red = 65535;
-    colour_group.green = 65535;
-    colour_group.blue = 65535;
-
-    // FIXME
-    /* Get labels from popup menus */
-    for (i = 0; registers[i]; i++) {
-        SNPRINTF(name, MAXLINE, "store_menu_item%d", i);
-        widget = GET_WIDGET(buttons->ui->ui, name);
-        g_object_set_data(G_OBJECT(widget), "register_id", registers[i]);
-        buttons->memory_store_labels[i] = gtk_bin_get_child(GTK_BIN(widget));
-
-        SNPRINTF(name, MAXLINE, "recall_menu_item%d", i);
-        widget = GET_WIDGET(buttons->ui->ui, name);
-        g_object_set_data(G_OBJECT(widget), "register_id", registers[i]);
-        buttons->memory_recall_labels[i] = gtk_bin_get_child(GTK_BIN(widget));
-    }
-  
     switch (mode) {
     case BASIC:
-        builder_ptr = &buttons->basic_ui;
+        builder_ptr = &buttons->priv->basic_ui;
         builder_file = UI_BASIC_FILE;
-        panel = &buttons->bas_panel;
+        panel = &buttons->priv->bas_panel;
         break;
     case ADVANCED:
-        builder_ptr = &buttons->advanced_ui;
+        builder_ptr = &buttons->priv->advanced_ui;
         builder_file = UI_ADVANCED_FILE;
-        panel = &buttons->adv_panel;
+        panel = &buttons->priv->adv_panel;
         break;
     case FINANCIAL:
-        builder_ptr = &buttons->financial_ui;
+        builder_ptr = &buttons->priv->financial_ui;
         builder_file = UI_FINANCIAL_FILE;
-        panel = &buttons->fin_panel;
+        panel = &buttons->priv->fin_panel;
         break;
     case PROGRAMMING:
-        builder_ptr = &buttons->programming_ui;
+        builder_ptr = &buttons->priv->programming_ui;
         builder_file = UI_PROGRAMMING_FILE;
-        panel = &buttons->prog_panel;
+        panel = &buttons->priv->prog_panel;
         break;
     }
 
     builder = *builder_ptr = gtk_builder_new();
     // FIXME: Show dialog if failed to load
-    gtk_builder_add_objects_from_file(builder, builder_file, objects, NULL);
+    gtk_builder_add_objects_from_file(builder, builder_file, objects, &error);
+    if (error) {
+        g_warning("Error loading button UI: %s", error->message);
+        g_clear_error(&error);
+    }
     *panel = GET_WIDGET(builder, "button_panel");
-    gtk_box_pack_end(GTK_BOX(buttons->button_vbox), *panel, FALSE, TRUE, 0);
+    gtk_box_pack_end(GTK_BOX(buttons->priv->button_vbox), *panel, FALSE, TRUE, 0);
 
     /* Connect text to buttons */
     for (i = 0; button_data[i].widget_name != NULL; i++) {
-        SNPRINTF(name, MAXLINE, "calc_%s_button", button_data[i].widget_name);
+        snprintf(name, MAXLINE, "calc_%s_button", button_data[i].widget_name);
         set_string_data(builder, name, "calc_text", button_data[i].data);
     }
 
@@ -254,130 +347,118 @@ load_mode(Buttons *buttons, ButtonMode mode)
     for (i = 0; i < 16; i++) {
         GtkWidget *button;
 
-        SNPRINTF(name, MAXLINE, "calc_%d_button", i);
-        button = GET_WIDGET(builder, name);
-      
-        if (button) {
-            gtk_button_set_label(GTK_BUTTON(button), v->digits[i]);
-            set_string_data(builder, name, "calc_text", v->digits[i]);
-        }
+        snprintf(name, MAXLINE, "calc_%d_button", i);
+        button = GET_WIDGET(builder, name);     
+        if (button)
+            gtk_button_set_label(GTK_BUTTON(button), ui_display_get_digit_text(buttons->priv->display, i));
     }
     widget = GET_WIDGET(builder, "calc_numeric_point_button");
     if (widget)
-        gtk_button_set_label(GTK_BUTTON(widget), v->radix);
+        gtk_button_set_label(GTK_BUTTON(widget), ui_display_get_numeric_point_text(buttons->priv->display));
 
     /* Connect super and subscript */
     for (i = 0; i < 10; i++) {
-        SNPRINTF(name, MAXLINE, "calc_%d_button", i);
-        set_string_data(builder, name, "calc_subscript_text", subscript_digits[i]);
-        set_string_data(builder, name, "calc_superscript_text", superscript_digits[i]);
-        set_tint(GET_WIDGET(builder, name), &colour_numbers, 1);
+        snprintf(name, MAXLINE, "calc_%d_button", i);
+        set_int_data(builder, name, "calc_digit", i);
+        set_tint(GET_WIDGET(builder, name), &buttons->priv->colour_numbers, 1);
     }
   
     widget = GET_WIDGET(builder, "superscript_togglebutton");
     if (widget) {
-        buttons->superscript_toggles = g_list_append(buttons->superscript_toggles, widget);
-        if (buttons->ui->display->number_mode == SUPERSCRIPT)
+        buttons->priv->superscript_toggles = g_list_append(buttons->priv->superscript_toggles, widget);
+        if (ui_display_get_number_mode(buttons->priv->display) == SUPERSCRIPT)
             gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(widget), TRUE);
     }
     widget = GET_WIDGET(builder, "subscript_togglebutton");
     if (widget) {
-        buttons->subscript_toggles = g_list_append(buttons->subscript_toggles, widget);
-        if (buttons->ui->display->number_mode == SUBSCRIPT)
+        buttons->priv->subscript_toggles = g_list_append(buttons->priv->subscript_toggles, widget);
+        if (ui_display_get_number_mode(buttons->priv->display) == SUBSCRIPT)
             gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(widget), TRUE);
     }
 
-    set_tint(GET_WIDGET(builder, "calc_10_button"), &colour_numbers, 1);
-    set_tint(GET_WIDGET(builder, "calc_11_button"), &colour_numbers, 1);  
-    set_tint(GET_WIDGET(builder, "calc_12_button"), &colour_numbers, 1);
-    set_tint(GET_WIDGET(builder, "calc_13_button"), &colour_numbers, 1);
-    set_tint(GET_WIDGET(builder, "calc_14_button"), &colour_numbers, 1);  
-    set_tint(GET_WIDGET(builder, "calc_15_button"), &colour_numbers, 1);
-    set_tint(GET_WIDGET(builder, "calc_imaginary_button"), &colour_numbers, 1);
-    set_tint(GET_WIDGET(builder, "calc_pi_button"), &colour_numbers, 1);
-    set_tint(GET_WIDGET(builder, "calc_eulers_number_button"), &colour_numbers, 1);
-    set_tint(GET_WIDGET(builder, "calc_numeric_point_button"), &colour_numbers, 1);
-    set_tint(GET_WIDGET(builder, "calc_percentage_button"), &colour_numbers, 2);
-    set_tint(GET_WIDGET(builder, "subscript_togglebutton"), &colour_numbers, 2);  
-    set_tint(GET_WIDGET(builder, "superscript_togglebutton"), &colour_numbers, 2);
-    set_tint(GET_WIDGET(builder, "calc_exponential_button"), &colour_numbers, 2);
-    set_tint(GET_WIDGET(builder, "calc_base_2_button"), &colour_numbers, 1);
-    set_tint(GET_WIDGET(builder, "calc_base_8_button"), &colour_numbers, 1);
-    set_tint(GET_WIDGET(builder, "calc_base_16_button"), &colour_numbers, 1);
-
-    set_tint(GET_WIDGET(builder, "calc_result_button"), &colour_action, 2);
-    set_tint(GET_WIDGET(builder, "calc_factor_button"), &colour_action, 2);
-    set_tint(GET_WIDGET(builder, "calc_clear_button"), &colour_action, 1); // Different colour?
-    set_tint(GET_WIDGET(builder, "calc_trunc_button"), &colour_action, 1);
-    set_tint(GET_WIDGET(builder, "calc_shift_left_button"), &colour_action, 1);
-    set_tint(GET_WIDGET(builder, "calc_shift_right_button"), &colour_action, 1);
+    set_tint(GET_WIDGET(builder, "calc_10_button"), &buttons->priv->colour_numbers, 1);
+    set_tint(GET_WIDGET(builder, "calc_11_button"), &buttons->priv->colour_numbers, 1);  
+    set_tint(GET_WIDGET(builder, "calc_12_button"), &buttons->priv->colour_numbers, 1);
+    set_tint(GET_WIDGET(builder, "calc_13_button"), &buttons->priv->colour_numbers, 1);
+    set_tint(GET_WIDGET(builder, "calc_14_button"), &buttons->priv->colour_numbers, 1);  
+    set_tint(GET_WIDGET(builder, "calc_15_button"), &buttons->priv->colour_numbers, 1);
+    set_tint(GET_WIDGET(builder, "calc_imaginary_button"), &buttons->priv->colour_numbers, 1);
+    set_tint(GET_WIDGET(builder, "calc_pi_button"), &buttons->priv->colour_numbers, 1);
+    set_tint(GET_WIDGET(builder, "calc_eulers_number_button"), &buttons->priv->colour_numbers, 1);
+    set_tint(GET_WIDGET(builder, "calc_numeric_point_button"), &buttons->priv->colour_numbers, 1);
+    set_tint(GET_WIDGET(builder, "calc_percentage_button"), &buttons->priv->colour_numbers, 2);
+    set_tint(GET_WIDGET(builder, "subscript_togglebutton"), &buttons->priv->colour_numbers, 2);  
+    set_tint(GET_WIDGET(builder, "superscript_togglebutton"), &buttons->priv->colour_numbers, 2);
+    set_tint(GET_WIDGET(builder, "calc_exponential_button"), &buttons->priv->colour_numbers, 2);
+    set_tint(GET_WIDGET(builder, "calc_base_2_button"), &buttons->priv->colour_numbers, 1);
+    set_tint(GET_WIDGET(builder, "calc_base_8_button"), &buttons->priv->colour_numbers, 1);
+    set_tint(GET_WIDGET(builder, "calc_base_16_button"), &buttons->priv->colour_numbers, 1);
+
+    set_tint(GET_WIDGET(builder, "calc_result_button"), &buttons->priv->colour_action, 2);
+    set_tint(GET_WIDGET(builder, "calc_factor_button"), &buttons->priv->colour_action, 2);
+    set_tint(GET_WIDGET(builder, "calc_clear_button"), &buttons->priv->colour_action, 1); // Different colour?
+    set_tint(GET_WIDGET(builder, "calc_trunc_button"), &buttons->priv->colour_action, 1);
+    set_tint(GET_WIDGET(builder, "calc_shift_left_button"), &buttons->priv->colour_action, 1);
+    set_tint(GET_WIDGET(builder, "calc_shift_right_button"), &buttons->priv->colour_action, 1);
   
-    set_tint(GET_WIDGET(builder, "calc_add_button"), &colour_operator, 1);
-    set_tint(GET_WIDGET(builder, "calc_subtract_button"), &colour_operator, 1);  
-    set_tint(GET_WIDGET(builder, "calc_multiply_button"), &colour_operator, 1);
-    set_tint(GET_WIDGET(builder, "calc_divide_button"), &colour_operator, 1);
-    set_tint(GET_WIDGET(builder, "calc_modulus_divide_button"), &colour_operator, 1);
-    set_tint(GET_WIDGET(builder, "calc_and_button"), &colour_operator, 1);  
-    set_tint(GET_WIDGET(builder, "calc_or_button"), &colour_operator, 1);  
-    set_tint(GET_WIDGET(builder, "calc_xor_button"), &colour_operator, 1);  
-
-    set_tint(GET_WIDGET(builder, "calc_cosine_button"), &colour_trig, 1);
-    set_tint(GET_WIDGET(builder, "calc_sine_button"), &colour_trig, 1);
-    set_tint(GET_WIDGET(builder, "calc_tangent_button"), &colour_trig, 1);
-    set_tint(GET_WIDGET(builder, "calc_hyperbolic_cosine_button"), &colour_trig, 1);
-    set_tint(GET_WIDGET(builder, "calc_hyperbolic_sine_button"), &colour_trig, 1);
-    set_tint(GET_WIDGET(builder, "calc_hyperbolic_tangent_button"), &colour_trig, 1);
-
-    set_tint(GET_WIDGET(builder, "calc_start_group_button"), &colour_group, 1);
-    set_tint(GET_WIDGET(builder, "calc_end_group_button"), &colour_group, 1);
-    set_tint(GET_WIDGET(builder, "calc_store_button"), &colour_memory, 1);
-    set_tint(GET_WIDGET(builder, "calc_recall_button"), &colour_memory, 1);
-    set_tint(GET_WIDGET(builder, "calc_ans_button"), &colour_memory, 1);
-    set_tint(GET_WIDGET(builder, "calc_random_button"), &colour_memory, 1);
-    set_tint(GET_WIDGET(builder, "calc_character_button"), &colour_memory, 1);
-
-    set_tint(GET_WIDGET(builder, "calc_integer_portion_button"), &colour_function, 1);
-    set_tint(GET_WIDGET(builder, "calc_fractional_portion_button"), &colour_function, 1);
-    set_tint(GET_WIDGET(builder, "calc_x_pow_y_button"), &colour_function, 1);  
-    set_tint(GET_WIDGET(builder, "calc_factorial_button"), &colour_function, 1);  
-    set_tint(GET_WIDGET(builder, "calc_root_button"), &colour_function, 1);  
-    set_tint(GET_WIDGET(builder, "calc_abs_button"), &colour_function, 1);  
-    set_tint(GET_WIDGET(builder, "calc_inverse_button"), &colour_function, 1);  
-    set_tint(GET_WIDGET(builder, "calc_logarithm_button"), &colour_function, 1);  
-    set_tint(GET_WIDGET(builder, "calc_natural_logarithm_button"), &colour_function, 1);
-    set_tint(GET_WIDGET(builder, "calc_ones_complement_button"), &colour_function, 1);
-    set_tint(GET_WIDGET(builder, "calc_twos_complement_button"), &colour_function, 1);
-    set_tint(GET_WIDGET(builder, "calc_not_button"), &colour_function, 1);  
-//    set_tint(GET_WIDGET(builder, "calc__button"), &colour_function, 1);
+    set_tint(GET_WIDGET(builder, "calc_add_button"), &buttons->priv->colour_operator, 1);
+    set_tint(GET_WIDGET(builder, "calc_subtract_button"), &buttons->priv->colour_operator, 1);  
+    set_tint(GET_WIDGET(builder, "calc_multiply_button"), &buttons->priv->colour_operator, 1);
+    set_tint(GET_WIDGET(builder, "calc_divide_button"), &buttons->priv->colour_operator, 1);
+    set_tint(GET_WIDGET(builder, "calc_modulus_divide_button"), &buttons->priv->colour_operator, 1);
+    set_tint(GET_WIDGET(builder, "calc_and_button"), &buttons->priv->colour_operator, 1);  
+    set_tint(GET_WIDGET(builder, "calc_or_button"), &buttons->priv->colour_operator, 1);  
+    set_tint(GET_WIDGET(builder, "calc_xor_button"), &buttons->priv->colour_operator, 1);  
+
+    set_tint(GET_WIDGET(builder, "calc_cosine_button"), &buttons->priv->colour_trig, 1);
+    set_tint(GET_WIDGET(builder, "calc_sine_button"), &buttons->priv->colour_trig, 1);
+    set_tint(GET_WIDGET(builder, "calc_tangent_button"), &buttons->priv->colour_trig, 1);
+    set_tint(GET_WIDGET(builder, "calc_hyperbolic_cosine_button"), &buttons->priv->colour_trig, 1);
+    set_tint(GET_WIDGET(builder, "calc_hyperbolic_sine_button"), &buttons->priv->colour_trig, 1);
+    set_tint(GET_WIDGET(builder, "calc_hyperbolic_tangent_button"), &buttons->priv->colour_trig, 1);
+
+    set_tint(GET_WIDGET(builder, "calc_start_group_button"), &buttons->priv->colour_group, 1);
+    set_tint(GET_WIDGET(builder, "calc_end_group_button"), &buttons->priv->colour_group, 1);
+    set_tint(GET_WIDGET(builder, "calc_store_button"), &buttons->priv->colour_memory, 1);
+    set_tint(GET_WIDGET(builder, "calc_recall_button"), &buttons->priv->colour_memory, 1);
+    set_tint(GET_WIDGET(builder, "calc_ans_button"), &buttons->priv->colour_memory, 1);
+    set_tint(GET_WIDGET(builder, "calc_random_button"), &buttons->priv->colour_memory, 1);
+    set_tint(GET_WIDGET(builder, "calc_character_button"), &buttons->priv->colour_memory, 1);
+
+    set_tint(GET_WIDGET(builder, "calc_integer_portion_button"), &buttons->priv->colour_function, 1);
+    set_tint(GET_WIDGET(builder, "calc_fractional_portion_button"), &buttons->priv->colour_function, 1);
+    set_tint(GET_WIDGET(builder, "calc_x_pow_y_button"), &buttons->priv->colour_function, 1);  
+    set_tint(GET_WIDGET(builder, "calc_factorial_button"), &buttons->priv->colour_function, 1);  
+    set_tint(GET_WIDGET(builder, "calc_root_button"), &buttons->priv->colour_function, 1);  
+    set_tint(GET_WIDGET(builder, "calc_abs_button"), &buttons->priv->colour_function, 1);  
+    set_tint(GET_WIDGET(builder, "calc_inverse_button"), &buttons->priv->colour_function, 1);  
+    set_tint(GET_WIDGET(builder, "calc_logarithm_button"), &buttons->priv->colour_function, 1);  
+    set_tint(GET_WIDGET(builder, "calc_natural_logarithm_button"), &buttons->priv->colour_function, 1);
+    set_tint(GET_WIDGET(builder, "calc_ones_complement_button"), &buttons->priv->colour_function, 1);
+    set_tint(GET_WIDGET(builder, "calc_twos_complement_button"), &buttons->priv->colour_function, 1);
+    set_tint(GET_WIDGET(builder, "calc_not_button"), &buttons->priv->colour_function, 1);  
   
     /* Set base button data */
     set_int_data(builder, "calc_base_2_button", "base", 2);
     set_int_data(builder, "calc_base_8_button", "base", 8);
     set_int_data(builder, "calc_base_16_button", "base", 16);
 
-    /* Connect menus to popup buttons */
-    set_data(builder, "calc_shift_left_button", "calc_menu", GET_WIDGET(builder, "left_shift_popup"));
-    set_data(builder, "calc_shift_right_button", "calc_menu", GET_WIDGET(builder, "right_shift_popup"));
-    set_data(builder, "calc_store_button", "calc_menu", GET_WIDGET(builder, "memory_store_popup"));
-    set_data(builder, "calc_recall_button", "calc_menu", GET_WIDGET(builder, "memory_recall_popup"));
-
-    /* Load bit panel */
     if (mode == PROGRAMMING) {
+        buttons->priv->character_code_dialog = GET_WIDGET(builder, "character_code_dialog");
+        buttons->priv->character_code_entry = GET_WIDGET(builder, "character_code_entry");
+
+        buttons->priv->bit_panel = GET_WIDGET(builder, "bit_table");
         for (i = 0; i < MAXBITS; i++) {
-            SNPRINTF(name, MAXLINE, "bit_label_%d", i);
-            buttons->bit_labels[i] = GET_WIDGET(builder, name);
-            SNPRINTF(name, MAXLINE, "bit_eventbox_%d", i);
+            snprintf(name, MAXLINE, "bit_label_%d", i);
+            buttons->priv->bit_labels[i] = GET_WIDGET(builder, name);
+            snprintf(name, MAXLINE, "bit_eventbox_%d", i);
             set_int_data(builder, name, "bit_index", i);
         }
     }
 
     /* Setup financial functions */
     if (mode == FINANCIAL) {
-        ui_setup_finc_dialogs(buttons->ui);
-
-        buttons->ascii_dialog = GET_WIDGET(builder, "ascii_dialog");
-        buttons->ascii_entry = GET_WIDGET(builder, "ascii_entry");
-        gtk_window_set_transient_for(GTK_WINDOW(buttons->ascii_dialog), GTK_WINDOW(buttons->ui->main_window));
+        load_finc_dialogs(buttons);
 
         set_data(builder, "calc_finc_compounding_term_button", "finc_dialog", "ctrm_dialog");
         set_data(builder, "calc_finc_double_declining_depreciation_button", "finc_dialog", "ddb_dialog");
@@ -396,12 +477,12 @@ load_mode(Buttons *buttons, ButtonMode mode)
 
 
 void
-ui_buttons_set_mode(Buttons *buttons, ButtonMode mode)
+ui_buttons_set_mode(MathButtons *buttons, ButtonMode mode)
 {
     ButtonMode old_mode;
 
-    old_mode = buttons->mode;
-    buttons->mode = mode;
+    old_mode = buttons->priv->mode;
+    buttons->priv->mode = mode;
 
     /* Hide the existing mode */
     if (get_buttons(buttons, old_mode))
@@ -414,238 +495,545 @@ ui_buttons_set_mode(Buttons *buttons, ButtonMode mode)
 }
 
 
+ButtonMode
+ui_buttons_get_mode(MathButtons *buttons)
+{
+    return buttons->priv->mode;
+}
+
+
 G_MODULE_EXPORT
 void
-base_cb(GtkWidget *widget, Buttons *buttons)
+base_cb(GtkWidget *widget, MathButtons *buttons)
 {
-    ui_set_base(buttons->ui, GPOINTER_TO_INT(g_object_get_data(G_OBJECT(widget), "base")));
+    ui_display_set_base(buttons->priv->display, GPOINTER_TO_INT(g_object_get_data(G_OBJECT(widget), "base")));
 }
 
 
 G_MODULE_EXPORT
 void
-exponent_cb(GtkWidget *widget, Buttons *buttons)
+exponent_cb(GtkWidget *widget, MathButtons *buttons)
 {
-    ui_do_exponent(buttons->ui);
+    ui_display_insert_exponent(buttons->priv->display);
 }
 
 
 G_MODULE_EXPORT
 void
-subtract_cb(GtkWidget *widget, Buttons *buttons)
+subtract_cb(GtkWidget *widget, MathButtons *buttons)
 {
-    ui_do_subtract(buttons->ui);
+    ui_display_insert_subtract(buttons->priv->display);  
 }
 
 
 G_MODULE_EXPORT
 void
-button_cb(GtkWidget *widget, Buttons *buttons)
+button_cb(GtkWidget *widget, MathButtons *buttons)
 {
-    ui_insert_text(buttons->ui, g_object_get_data(G_OBJECT(widget), "calc_text"));
+    ui_display_insert(buttons->priv->display, g_object_get_data(G_OBJECT(widget), "calc_text"));
 }
 
 
 G_MODULE_EXPORT
 void
-store_menu_cb(GtkMenuItem *menu, Buttons *buttons)
+store_menu_cb(GtkMenuItem *menu, MathButtons *buttons)
+{
+    ui_display_store(buttons->priv->display, g_object_get_data(G_OBJECT(menu), "register_id"));
+}
+
+
+static void
+recall_menu_cb(GtkMenuItem *menu, MathButtons *buttons)
 {
-    ui_do_button(buttons->ui, FN_STORE, g_object_get_data(G_OBJECT(menu), "register_id"));
+    ui_display_recall(buttons->priv->display, g_object_get_data(G_OBJECT(menu), "register_id"));  
 }
 
 
 G_MODULE_EXPORT
 void
-recall_menu_cb(GtkMenuItem *menu, Buttons *buttons)
+solve_cb(GtkWidget *widget, MathButtons *buttons)
 {
-    ui_do_button(buttons->ui, FN_RECALL, g_object_get_data(G_OBJECT(menu), "register_id"));
+    ui_display_solve(buttons->priv->display);
 }
 
 
 G_MODULE_EXPORT
 void
-solve_cb(GtkWidget *widget, Buttons *buttons)
+clear_cb(GtkWidget *widget, MathButtons *buttons)
+{
+    ui_display_clear(buttons->priv->display);
+}
+
+
+static void
+shift_cb(GtkWidget *widget, MathButtons *buttons)
+{
+    ui_display_shift(buttons->priv->display, GPOINTER_TO_INT(g_object_get_data(G_OBJECT(widget), "shiftcount")));
+}
+
+
+static void
+update_store_menu(MathButtons *buttons)
+{
+    int i;
+
+    if (!buttons->priv->store_menu) {
+        GtkWidget *menu;
+
+        menu = buttons->priv->store_menu = gtk_menu_new();
+        gtk_menu_set_reserve_toggle_size(GTK_MENU(menu), FALSE);
+        set_tint(menu, &buttons->priv->colour_memory, 1);
+
+        for (i = 0; i < MAX_REGISTERS; i++) {
+            GtkWidget *item, *label;
+
+            label = buttons->priv->store_menu_labels[i] = gtk_label_new("");
+            gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
+
+            item = gtk_menu_item_new();
+            gtk_container_add(GTK_CONTAINER(item), label);
+
+            g_object_set_data(G_OBJECT(item), "register_id", registers[i]);
+            gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
+            g_signal_connect(item, "activate", G_CALLBACK(store_menu_cb), buttons);
+
+            gtk_widget_show(label);
+            gtk_widget_show(item);
+        }  
+    }
+
+    for (i = 0; registers[i] != NULL; i++) {
+        char value[MAXLINE] = "", mstr[MAXLINE];
+        MPNumber *t;
+
+        t = register_get_value(registers[i]);
+        if (t)
+            display_make_number(&v->display, value, MAXLINE, t);
+        snprintf(mstr, MAXLINE, "<span weight=\"bold\">%s</span> = %s", registers[i], value);
+        gtk_label_set_markup_with_mnemonic(GTK_LABEL(buttons->priv->store_menu_labels[i]), mstr);
+    }
+}
+
+
+static void
+button_menu_position_func(GtkMenu *menu, gint *x, gint *y,
+                          gboolean *push_in, gpointer user_data)
 {
-    ui_do_button(buttons->ui, FN_CALCULATE, NULL);
+    GtkWidget *button = user_data;
+    GdkPoint loc;
+    gint border;
+  
+    gdk_window_get_origin(gtk_widget_get_window(button), &loc.x, &loc.y);
+    border = gtk_container_get_border_width(GTK_CONTAINER(button));
+    *x = loc.x + button->allocation.x + border;
+    *y = loc.y + button->allocation.y + border;
+}
+
+
+static void
+popup_button_menu(GtkWidget *widget, GtkMenu *menu)
+{
+    gtk_menu_popup(menu, NULL, NULL,
+                   button_menu_position_func, widget, 1, gtk_get_current_event_time());
 }
 
 
 G_MODULE_EXPORT
 void
-clear_cb(GtkWidget *widget, Buttons *buttons)
+store_cb(GtkWidget *widget, MathButtons *buttons)
 {
-    ui_do_button(buttons->ui, FN_CLEAR, NULL);
+    update_store_menu(buttons);
+    popup_button_menu(widget, GTK_MENU(buttons->priv->store_menu));
+}
+
+
+static void
+update_recall_menu(MathButtons *buttons)
+{
+    int i;
+
+    if (!buttons->priv->recall_menu) {
+        GtkWidget *menu;
+
+        menu = buttons->priv->recall_menu = gtk_menu_new();
+        gtk_menu_set_reserve_toggle_size(GTK_MENU(menu), FALSE);
+        set_tint(menu, &buttons->priv->colour_memory, 1);
+
+        for (i = 0; i < MAX_REGISTERS; i++) {
+            GtkWidget *item, *label;
+
+            label = buttons->priv->recall_menu_labels[i] = gtk_label_new("");
+            gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
+
+            item = gtk_menu_item_new();
+            gtk_container_add(GTK_CONTAINER(item), label);
+
+            g_object_set_data(G_OBJECT(item), "register_id", registers[i]);
+            gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
+            g_signal_connect(item, "activate", G_CALLBACK(recall_menu_cb), buttons);
+
+            gtk_widget_show(label);
+            gtk_widget_show(item);
+        }
+    }
+
+    for (i = 0; registers[i] != NULL; i++) {
+        char value[MAXLINE] = "", mstr[MAXLINE];
+        MPNumber *t;
+
+        t = register_get_value(registers[i]);
+        if (t)
+            display_make_number(&v->display, value, MAXLINE, t);
+        snprintf(mstr, MAXLINE, "<span weight=\"bold\">%s</span> = %s", registers[i], value);
+        gtk_label_set_markup_with_mnemonic(GTK_LABEL(buttons->priv->recall_menu_labels[i]), mstr);
+    }
 }
 
 
 G_MODULE_EXPORT
 void
-finc_cb(GtkWidget *widget, Buttons *buttons)
+recall_cb(GtkWidget *widget, MathButtons *buttons)
 {
-    gchar *name;
-
-    name = g_object_get_data(G_OBJECT(widget), "finc_dialog");
-    gtk_dialog_run(GTK_DIALOG(GET_WIDGET(buttons->financial_ui, name)));
-    gtk_widget_hide(GTK_WIDGET(GET_WIDGET(buttons->financial_ui, name)));
+    update_recall_menu(buttons);
+    popup_button_menu(widget, GTK_MENU(buttons->priv->recall_menu));
 }
 
 
-static void
-position_popup(GtkWidget *base, GtkWidget *popup,
-               PopupLocation location_op)
-{
-    int base_x, base_y, base_width, base_height;
-    int popup_x, popup_y, popup_width, popup_height;
-    int screen_width, screen_height;
-    int n;
-
-    gtk_window_get_position(GTK_WINDOW(base), &base_x, &base_y);
-    gtk_window_get_size(GTK_WINDOW(base), &base_width, &base_height);
-    gtk_window_get_position(GTK_WINDOW(popup), &popup_x, &popup_y);
-    gtk_window_get_size(GTK_WINDOW(popup), &popup_width, &popup_height);
-    screen_width = gdk_screen_width();
-    screen_height = gdk_screen_height();
-
-    if (location_op == POPUP_LOR) {
-        if (base_x >= screen_width - base_width - base_x)
-            location_op = POPUP_LEFT;
-        else
-            location_op = POPUP_RIGHT;
-    } else if (location_op == POPUP_AOB) {
-        if (base_y > screen_height - base_height - base_y)
-            location_op = POPUP_ABOVE;
-        else
-            location_op = POPUP_BELOW;
+G_MODULE_EXPORT
+void
+shift_left_cb(GtkWidget *widget, MathButtons *buttons)
+{
+    if (!buttons->priv->shift_left_menu) {
+        gint i;
+        GtkWidget *menu;
+
+        menu = buttons->priv->shift_left_menu = gtk_menu_new();
+        gtk_menu_set_reserve_toggle_size(GTK_MENU(menu), FALSE);
+        set_tint(menu, &buttons->priv->colour_action, 1);
+
+        for (i = 1; i < 16; i++) {
+            GtkWidget *item, *label;
+            gchar *format, *text;
+
+            if (i < 10) {
+                /* Left Shift Popup: Menu item to shift left by n places (n < 10) */
+                format = ngettext("_%d place", "_%d places", i);
+            }
+            else {
+                /* Left Shift Popup: Menu item to shift left by n places (n >= 10) */
+                format = ngettext("%d place", "%d places", i);
+            }
+            text = g_strdup_printf(format, i);
+            label = gtk_label_new_with_mnemonic(text);
+
+            item = gtk_menu_item_new();
+            g_object_set_data(G_OBJECT(item), "shiftcount", GINT_TO_POINTER(i));
+            gtk_container_add(GTK_CONTAINER(item), label);
+            gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
+            g_signal_connect(item, "activate", G_CALLBACK(shift_cb), buttons);
+
+            gtk_widget_show(label);
+            gtk_widget_show(item);
+            g_free(text);
+        }
     }
 
-    switch (location_op) {
-        case POPUP_RIGHT:
-            popup_x = base_x + base_width + WM_WIDTH_FACTOR;
-            popup_y = base_y;
-            break;
-
-        case POPUP_LEFT:
-            popup_x = base_x - popup_width - WM_WIDTH_FACTOR;
-            popup_y = base_y;
-            break;
-
-        case POPUP_ABOVE:
-            popup_x = base_x;
-            popup_y = base_y - popup_height - WM_HEIGHT_FACTOR;
-            break;
-
-        case POPUP_BELOW:
-            popup_x = base_x;
-            popup_y = base_y + base_height + WM_HEIGHT_FACTOR;
-            break;
-
-        case POPUP_CENTERED:
-        default:
-            popup_x = base_x + (base_width - popup_width) / 2;
-            popup_y = base_y + (base_height - popup_height) / 2;
-            break;
+    popup_button_menu(widget, GTK_MENU(buttons->priv->shift_left_menu));
+}
+
+
+G_MODULE_EXPORT
+void
+shift_right_cb(GtkWidget *widget, MathButtons *buttons)
+{
+    if (!buttons->priv->shift_right_menu) {
+        gint i;
+        GtkWidget *menu;
+
+        menu = buttons->priv->shift_right_menu = gtk_menu_new();
+        gtk_menu_set_reserve_toggle_size(GTK_MENU(menu), FALSE);
+        set_tint(menu, &buttons->priv->colour_action, 1);
+
+        for (i = 1; i < 16; i++) {
+            GtkWidget *item, *label;
+            gchar *format, *text;
+
+            if (i < 10) {
+                /* Right Shift Popup: Menu item to shift right by n places (n < 10) */
+                format = ngettext("_%d place", "_%d places", i);
+            }
+            else {
+                /* Right Shift Popup: Menu item to shift right by n places (n >= 10) */
+                format = ngettext("%d place", "%d places", i);
+            }
+            text = g_strdup_printf(format, i);
+            label = gtk_label_new_with_mnemonic(text);
+
+            item = gtk_menu_item_new();
+            g_object_set_data(G_OBJECT(item), "shiftcount", GINT_TO_POINTER(-i));
+            gtk_container_add(GTK_CONTAINER(item), label);
+            gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
+            g_signal_connect(item, "activate", G_CALLBACK(shift_cb), buttons);
+
+            gtk_widget_show(label);
+            gtk_widget_show(item);
+            g_free(text);
+        }
     }
 
-    /* Make sure frame doesn't go off side of screen */
-    n = popup_x + popup_width;
-    if (n > screen_width)
-        popup_x -= (n - screen_width);
-    else if (popup_x < 0)
-        popup_x = 0;
+    popup_button_menu(widget, GTK_MENU(buttons->priv->shift_right_menu));  
+}
 
-    /* Make sure frame doesn't go off top or bottom */
-    n = popup_y + popup_height;
-    if (n > screen_height)
-        popup_y -= n - screen_height;
-    else if (popup_y < 0)
-        popup_y = 0;
 
-    gtk_window_move(GTK_WINDOW(popup), popup_x, popup_y);
+G_MODULE_EXPORT
+void
+factorize_cb(GtkWidget *widget, MathButtons *buttons)
+{
+    ui_display_factorize (buttons->priv->display);
 }
 
 
 G_MODULE_EXPORT
 void
-insert_ascii_cb(GtkWidget *widget, Buttons *buttons)
+digit_cb(GtkWidget *widget, MathButtons *buttons)
 {
-    if (!gtk_widget_get_visible(buttons->ascii_dialog))
-        position_popup(buttons->ui->main_window, buttons->ascii_dialog, POPUP_LEFT);
-    gtk_widget_grab_focus(GTK_WIDGET(buttons->ascii_entry));
-    gtk_widget_show(buttons->ascii_dialog);
+    ui_display_insert_digit(buttons->priv->display, GPOINTER_TO_INT(g_object_get_data(G_OBJECT(widget), "calc_digit")));
 }
 
 
 G_MODULE_EXPORT
 void
-shift_cb(GtkWidget *widget, Buttons *buttons)
+numeric_point_cb(GtkWidget *widget, MathButtons *buttons)
 {
-    ui_do_button(buttons->ui, FN_SHIFT, g_object_get_data(G_OBJECT(widget), "shiftcount"));
+    ui_display_insert_numeric_point(buttons->priv->display);
 }
 
+
+
 G_MODULE_EXPORT
 void
-factorize_cb(GtkWidget *widget, Buttons *buttons)
+finc_cb(GtkWidget *widget, MathButtons *buttons)
 {
-    ui_do_button(buttons->ui, FN_FACTORIZE, NULL);
+    gchar *name;
+
+    name = g_object_get_data(G_OBJECT(widget), "finc_dialog");
+    gtk_dialog_run(GTK_DIALOG(GET_WIDGET(buttons->priv->financial_ui, name)));
+    gtk_widget_hide(GTK_WIDGET(GET_WIDGET(buttons->priv->financial_ui, name)));
 }
 
 
 G_MODULE_EXPORT
 void
-digit_cb(GtkWidget *widget, Buttons *buttons)
+insert_character_code_cb(GtkWidget *widget, MathButtons *buttons)
 {
-    if (buttons->ui->display->number_mode == SUPERSCRIPT)
-        ui_insert_text(buttons->ui, g_object_get_data(G_OBJECT(widget), "calc_superscript_text"));
-    else if (buttons->ui->display->number_mode == SUBSCRIPT)
-        ui_insert_text(buttons->ui, g_object_get_data(G_OBJECT(widget), "calc_subscript_text"));
-    else
-        ui_insert_text(buttons->ui, g_object_get_data(G_OBJECT(widget), "calc_text"));
+    gtk_window_present(GTK_WINDOW(buttons->priv->character_code_dialog));
 }
 
 
+G_MODULE_EXPORT
+void
+finc_activate_cb(GtkWidget *widget, MathButtons *buttons)
+{
+    gint dialog, field;
+
+    dialog = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(widget), "finc_dialog"));
+    field = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(widget), "finc_field"));
+
+    if (finc_dialog_fields[dialog][field+1] == NULL) {
+        GtkWidget *dialog_widget;
+        dialog_widget = gtk_widget_get_toplevel(widget);
+        if (gtk_widget_is_toplevel (dialog_widget)) {
+            gtk_dialog_response(GTK_DIALOG(dialog_widget),
+                                GTK_RESPONSE_OK);
+            return;
+        }
+    }
+    else {
+        GtkWidget *next_widget;
+        next_widget = GET_WIDGET(buttons->priv->financial_ui, finc_dialog_fields[dialog][field+1]);
+        gtk_widget_grab_focus(next_widget);
+    }
+}
+
+
+G_MODULE_EXPORT
+void
+finc_response_cb(GtkWidget *widget, gint response_id, MathButtons *buttons)
+{
+    int dialog;
+    int i;
+    MPNumber arg[4];
+    GtkWidget *entry;
+
+    if (response_id != GTK_RESPONSE_OK)
+        return;
+
+    dialog = GPOINTER_TO_INT (g_object_get_data(G_OBJECT(widget), "finc_dialog"));
+
+    for (i = 0; i < 4; i++) {
+        if (finc_dialog_fields[dialog][i] == NULL) {
+            continue;
+        }
+        entry = GET_WIDGET(buttons->priv->financial_ui, finc_dialog_fields[dialog][i]);
+        // FIXME: Have to delocalize the input
+        mp_set_from_string(gtk_entry_get_text(GTK_ENTRY(entry)), &arg[i]);
+        gtk_entry_set_text(GTK_ENTRY(entry), "0");
+    }
+    gtk_widget_grab_focus(GET_WIDGET(buttons->priv->financial_ui, finc_dialog_fields[dialog][0]));
+
+    do_finc_expression(dialog, &arg[0], &arg[1], &arg[2], &arg[3]);
+}
+
+
+static void
+recalculate_currency(MathButtons *buttons, CurrencyTargetRow target)
+{
+    int upper_index, lower_index;
+
+    GtkComboBox *combo_upper = GTK_COMBO_BOX(gtk_builder_get_object(buttons->priv->financial_ui, "currency_type_upper"));
+    GtkComboBox *combo_lower = GTK_COMBO_BOX(gtk_builder_get_object(buttons->priv->financial_ui, "currency_type_lower"));
+    GtkSpinButton *spin_upper = GTK_SPIN_BUTTON(gtk_builder_get_object(buttons->priv->financial_ui, "currency_amount_upper"));
+    GtkSpinButton *spin_lower = GTK_SPIN_BUTTON(gtk_builder_get_object(buttons->priv->financial_ui, "currency_amount_lower"));
+
+    GtkTreeModel *model = gtk_combo_box_get_model(combo_upper);
+    GtkTreeIter iter;
+
+    if (!gtk_combo_box_get_active_iter(combo_upper, &iter))
+        return;
+    gtk_tree_model_get(model, &iter, 0, &upper_index, -1);
+
+    if (!gtk_combo_box_get_active_iter(combo_lower, &iter))
+        return;
+    gtk_tree_model_get(model, &iter, 0, &lower_index, -1);
+
+    if (target == CURRENCY_TARGET_LOWER) {
+        MPNumber input, output;
+        mp_set_from_double (gtk_spin_button_get_value(spin_upper), &input);
+        currency_convert(&input, upper_index, lower_index, &output);
+        if (!mp_is_zero(&output))
+            gtk_spin_button_set_value(spin_lower, mp_cast_to_double(&output));
+    } else {
+        MPNumber input, output;
+        mp_set_from_double (gtk_spin_button_get_value(spin_lower), &input);
+        currency_convert(&input, lower_index, upper_index, &output);
+        if (!mp_is_zero(&output))
+            gtk_spin_button_set_value(spin_upper, mp_cast_to_double(&output));
+    }
+}
+
+
+G_MODULE_EXPORT
+void
+currency_type_cb(GtkComboBox *combo, gpointer user_data, MathButtons *buttons)
+{
+    recalculate_currency(buttons, CURRENCY_TARGET_LOWER);
+}
+
+
+G_MODULE_EXPORT
+void
+currency_amount_cb (GtkSpinButton *spinbutton, gpointer user_data, MathButtons *buttons)
+{
+    recalculate_currency(buttons, GPOINTER_TO_INT(g_object_get_data(G_OBJECT(spinbutton), "target")));
+}
+
 static void
-update_memory_menus(Buttons *buttons)
+setup_currency_rates(MathButtons *buttons)
 {
+    static int has_run = 0;
     int i;
+    GtkListStore *currency_store;
+    GObject *currency_type;
+
+    if (has_run)
+        return;
+
+    if (currency_rates_needs_update()) {
+        GtkWidget *dialog = gtk_message_dialog_new(NULL, 0,
+                                        GTK_MESSAGE_INFO,
+                                        GTK_BUTTONS_YES_NO,
+                                        /* Translators: Title of the error dialog when prompting to download currency rates */
+                                        N_("You don't have any recent currency rates. Should some be downloaded now?"));
+        int response = gtk_dialog_run(GTK_DIALOG(dialog));
+        gtk_widget_destroy(dialog);
+
+        if (response == GTK_RESPONSE_YES) {
+            if (!currency_download_rates()) {
+                dialog = gtk_message_dialog_new(NULL, 0,
+                                                GTK_MESSAGE_ERROR,
+                                                GTK_BUTTONS_OK,
+                                                /* Translators: Title of the error dialog when unable to download currency rates */
+                                                N_("Currency rates could not be downloaded. You may receive inaccurate results, or you may not receive any results at all."));
+            }
+        }
+    }
+    currency_load_rates();
 
-    for (i = 0; registers[i] != NULL; i++) {
-        char value[MAXLINE] = "", mstr[MAXLINE];
-        MPNumber *t;
+    currency_type = gtk_builder_get_object(buttons->priv->financial_ui, "currency_type_upper");
+    currency_store = GTK_LIST_STORE(gtk_combo_box_get_model(
+        GTK_COMBO_BOX(currency_type)));
 
-        t = register_get_value(registers[i]);
-        if (t)
-            display_make_number(&v->display, value, MAXLINE, t);
-        SNPRINTF(mstr, MAXLINE, "<span weight=\"bold\">%s</span> = %s", registers[i], value);
-        gtk_label_set_markup_with_mnemonic(GTK_LABEL(buttons->memory_store_labels[i]), mstr);
-        gtk_label_set_markup_with_mnemonic(GTK_LABEL(buttons->memory_recall_labels[i]), mstr);
+    for (i = 0; currency_names[i].short_name; i++) {
+        GtkTreeIter iter;
+        int index;
+
+        if ((index = currency_get_index(currency_names[i].short_name)) < 0) {
+            continue;
+        }
+        gtk_list_store_append(currency_store, &iter);
+        gtk_list_store_set(currency_store, &iter,
+                           0, index,
+                           1, gettext(currency_names[i].long_name),
+                           -1);
     }
+
+    has_run = 1;
 }
 
 
 G_MODULE_EXPORT
 void
-popup_cb(GtkWidget *widget, Buttons *buttons)
+currency_cb(GtkWidget *widget, MathButtons *buttons)
 {
-    GtkWidget *menu;
-    GdkPoint loc;
+    GtkDialog *win;
+    GtkSpinButton *c_amount_upper, *c_amount_lower;
+    MPNumber display_val;
+
+    setup_currency_rates(buttons);
+
+    win = GTK_DIALOG(gtk_builder_get_object(buttons->priv->financial_ui, "currency_dialog"));
+    c_amount_upper = GTK_SPIN_BUTTON(gtk_builder_get_object(buttons->priv->financial_ui, "currency_amount_upper"));
+    c_amount_lower = GTK_SPIN_BUTTON(gtk_builder_get_object(buttons->priv->financial_ui, "currency_amount_lower"));
+    if (display_is_usable_number(&v->display, &display_val)) {
+        double start_val = mp_cast_to_double(&display_val);
+        gtk_spin_button_set_value(c_amount_upper, start_val);
+    }
+    gtk_widget_grab_focus(GTK_WIDGET(c_amount_upper));
+
+    if (gtk_dialog_run(win) == GTK_RESPONSE_OK) {
+        gchar *result;
 
-    update_memory_menus(buttons);
+        result = g_strdup_printf("%.2f", gtk_spin_button_get_value(c_amount_lower));
+        mp_set_from_string(result, &display_val);
+        g_free(result);
+
+        display_set_number(&v->display, &display_val);
+    }
 
-    menu = (GtkWidget *)g_object_get_data(G_OBJECT(widget), "calc_menu");
-    gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL,
-                   1, 0);
+    gtk_widget_hide(GTK_WIDGET(win));
 }
 
+
 G_MODULE_EXPORT
 void
-ascii_dialog_response_cb(GtkWidget *dialog, gint response_id, Buttons *buttons)
+character_code_dialog_response_cb(GtkWidget *dialog, gint response_id, MathButtons *buttons)
 {
     const gchar *text;
 
-    text = gtk_entry_get_text(GTK_ENTRY(buttons->ascii_entry));
+    text = gtk_entry_get_text(GTK_ENTRY(buttons->priv->character_code_entry));
 
     if (response_id == GTK_RESPONSE_OK)
-        ui_do_button(buttons->ui, FN_INSERT_CHARACTER, (gpointer) text);
+        ui_display_insert_character(buttons->priv->display, text);
 
     gtk_widget_hide(dialog);
 }
@@ -653,27 +1041,26 @@ ascii_dialog_response_cb(GtkWidget *dialog, gint response_id, Buttons *buttons)
 
 G_MODULE_EXPORT
 void
-ascii_dialog_activate_cb(GtkWidget *entry, Buttons *buttons)
+character_code_dialog_activate_cb(GtkWidget *entry, MathButtons *buttons)
 {
-    ascii_dialog_response_cb(buttons->ascii_dialog, GTK_RESPONSE_OK, buttons);
+    character_code_dialog_response_cb(buttons->priv->character_code_dialog, GTK_RESPONSE_OK, buttons);
 }
 
 
 G_MODULE_EXPORT
 gboolean
-ascii_dialog_delete_cb(GtkWidget *dialog, Buttons *buttons)
+character_code_dialog_delete_cb(GtkWidget *dialog, GdkEvent *event, MathButtons *buttons)
 {
-    ascii_dialog_response_cb(dialog, GTK_RESPONSE_CANCEL, buttons);
+    character_code_dialog_response_cb(dialog, GTK_RESPONSE_CANCEL, buttons);
     return TRUE;
 }
 
 
 G_MODULE_EXPORT
 gboolean
-bit_toggle_cb(GtkWidget *event_box, GdkEventButton *event, Buttons *buttons)
+bit_toggle_cb(GtkWidget *event_box, GdkEventButton *event, MathButtons *buttons)
 {
-    ui_do_button(buttons->ui, FN_TOGGLE_BIT,
-                 g_object_get_data(G_OBJECT(event_box), "bit_index"));
+    ui_display_toggle_bit(buttons->priv->display, GPOINTER_TO_INT(g_object_get_data(G_OBJECT(event_box), "bit_index")));
     return TRUE;
 }
 
@@ -681,48 +1068,155 @@ bit_toggle_cb(GtkWidget *event_box, GdkEventButton *event, Buttons *buttons)
 
 G_MODULE_EXPORT
 void
-set_superscript_cb(GtkWidget *widget, Buttons *buttons)
+set_superscript_cb(GtkWidget *widget, MathButtons *buttons)
 {
-    if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget))) {
-       buttons->ui->display->can_super_minus = TRUE;
-       ui_set_number_mode(buttons->ui, SUPERSCRIPT);
-    }
-    else {
-       buttons->ui->display->can_super_minus = FALSE;
-       if (buttons->ui->display->number_mode == SUPERSCRIPT)
-           ui_set_number_mode(buttons->ui, NORMAL);
-    }
+    if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)))
+       ui_display_set_number_mode(buttons->priv->display, SUPERSCRIPT);
+    else if (ui_display_get_number_mode(buttons->priv->display) == SUPERSCRIPT)
+       ui_display_set_number_mode(buttons->priv->display, NORMAL);
 }
 
 
 G_MODULE_EXPORT
 void
-set_subscript_cb(GtkWidget *widget, Buttons *buttons)
+set_subscript_cb(GtkWidget *widget, MathButtons *buttons)
 {
     if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)))
-       ui_set_number_mode(buttons->ui, SUBSCRIPT);
-    else if (buttons->ui->display->number_mode == SUBSCRIPT)
-       ui_set_number_mode(buttons->ui, NORMAL);
+       ui_display_set_number_mode(buttons->priv->display, SUBSCRIPT);
+    else if (ui_display_get_number_mode(buttons->priv->display) == SUBSCRIPT)
+       ui_display_set_number_mode(buttons->priv->display, NORMAL);
 }
 
 
-// FIXME: Watch for changes in programming mode
+// FIXME: Watch for display changes from MathEngine
 void
-ui_set_bitfield(GCalctoolUI *ui, int enabled, guint64 bits)
+ui_buttons_set_bitfield(MathButtons *buttons, int enabled, guint64 bits)
 {
     int i;
-    const gchar *label;
-  
-    if (!ui->buttons->bit_panel)
+    const gchar *label;  
+
+    if (!buttons->priv->bit_panel)
        return;
 
-    gtk_widget_set_sensitive(ui->buttons->bit_panel, enabled);
+    gtk_widget_set_sensitive(buttons->priv->bit_panel, enabled);
 
     for (i = 0; i < MAXBITS; i++) {
         if (bits & (1LL << (MAXBITS-i-1)))
             label = " 1";
         else
             label = " 0";
-        gtk_label_set_text(GTK_LABEL(ui->buttons->bit_labels[i]), label);
+        gtk_label_set_text(GTK_LABEL(buttons->priv->bit_labels[i]), label);
     }
 }
+
+
+static void
+number_mode_changed_cb(MathDisplay *display, MathButtons *buttons)
+{
+    GList *i;
+    NumberMode mode;
+  
+    mode = ui_display_get_number_mode(display);
+
+    for (i = buttons->priv->superscript_toggles; i; i = i->next) {
+        GtkWidget *widget = i->data;
+        gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(widget), mode == SUPERSCRIPT);
+    }
+    for (i = buttons->priv->subscript_toggles; i; i = i->next) {
+        GtkWidget *widget = i->data;
+        gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(widget), mode == SUBSCRIPT);
+    }
+}
+
+
+static void
+ui_buttons_set_property (GObject      *object,
+                         guint         prop_id,
+                         const GValue *value,
+                         GParamSpec   *pspec)
+{
+    MathButtons *self;
+
+    self = MATH_BUTTONS (object);
+
+    switch (prop_id) {
+    case PROP_DISPLAY:
+        self->priv->display = g_value_get_object (value);
+        g_signal_connect(self->priv->display, "number-mode-changed", G_CALLBACK(number_mode_changed_cb), self);
+        break;
+    default:
+        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+        break;
+    }
+}
+
+
+static void
+ui_buttons_get_property (GObject    *object,
+                         guint       prop_id,
+                         GValue     *value,
+                         GParamSpec *pspec)
+{
+    MathButtons *self;
+
+    self = MATH_BUTTONS (object);
+
+    switch (prop_id) {
+    case PROP_DISPLAY:
+        g_value_set_object (value, self->priv->display);
+        break;
+    default:
+        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+        break;
+    }
+}
+
+
+static void
+ui_buttons_class_init (MathButtonsClass *klass)
+{
+    GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+    object_class->get_property = ui_buttons_get_property;
+    object_class->set_property = ui_buttons_set_property;
+
+    g_type_class_add_private (klass, sizeof (MathButtonsPrivate));
+
+    g_object_class_install_property (object_class,
+                                     PROP_DISPLAY,
+                                     g_param_spec_object ("display",
+                                                          "display",
+                                                          "Display being controlled",
+                                                          ui_display_get_type(),
+                                                          G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+}
+
+
+static void
+ui_buttons_init (MathButtons *buttons)
+{
+    buttons->priv = G_TYPE_INSTANCE_GET_PRIVATE (buttons, ui_buttons_get_type(), MathButtonsPrivate);
+    buttons->priv->colour_numbers.red = 0;
+    buttons->priv->colour_numbers.green = 0;
+    buttons->priv->colour_numbers.blue = 65535;
+    buttons->priv->colour_action.red = 0;
+    buttons->priv->colour_action.green = 65535;
+    buttons->priv->colour_action.blue = 0;
+    buttons->priv->colour_operator.red = 65535;
+    buttons->priv->colour_operator.green = 0;
+    buttons->priv->colour_operator.blue = 0;
+    buttons->priv->colour_function.red = 0;
+    buttons->priv->colour_function.green = 65535;
+    buttons->priv->colour_function.blue = 65535;
+    buttons->priv->colour_memory.red = 65535;
+    buttons->priv->colour_memory.green = 0;
+    buttons->priv->colour_memory.blue = 65535;
+    buttons->priv->colour_trig.red = 65535;
+    buttons->priv->colour_trig.green = 65535;
+    buttons->priv->colour_trig.blue = 0;
+    buttons->priv->colour_group.red = 65535;
+    buttons->priv->colour_group.green = 65535;
+    buttons->priv->colour_group.blue = 65535;
+    buttons->priv->button_vbox = gtk_vbox_new(FALSE, 0);
+    gtk_widget_show(buttons->priv->button_vbox);
+}
diff --git a/src/ui-buttons.h b/src/ui-buttons.h
index debd104..9850fe6 100644
--- a/src/ui-buttons.h
+++ b/src/ui-buttons.h
@@ -19,9 +19,26 @@
 #ifndef UI_BUTTONS_H
 #define UI_BUTTONS_H
 
-typedef struct Buttons Buttons;
+#include <glib-object.h>
+#include <gtk/gtk.h>
+#include "ui-display.h"
 
-#include "ui.h"
+G_BEGIN_DECLS
+
+#define MATH_BUTTONS(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), ui_buttons_get_type(), MathButtons))
+
+typedef struct MathButtonsPrivate MathButtonsPrivate;
+
+typedef struct
+{
+    GObject         parent_instance; // FIXME: Extend GtkVBox
+    MathButtonsPrivate *priv;
+} MathButtons;
+
+typedef struct
+{
+    GObjectClass parent_class;
+} MathButtonsClass;
 
 typedef enum {
     BASIC,
@@ -30,35 +47,16 @@ typedef enum {
     PROGRAMMING
 } ButtonMode;
 
-#define MAXBITS 64      /* Bit panel: number of bit fields. */
-#define MAX_REGISTERS 6
-
-struct Buttons
-{
-    GCalctoolUI *ui;
-    ButtonMode mode;
-    GtkBuilder *financial_dialog_ui; // FIXME: Merge into financial UI
-    GtkBuilder *basic_ui, *advanced_ui, *financial_ui, *programming_ui;
-
-    GtkWidget *button_vbox;
-    GtkWidget *bas_panel, *adv_panel, *fin_panel, *prog_panel;
-
-    /* Labels for popup menus */
-    GtkWidget *memory_store_labels[MAX_REGISTERS];
-    GtkWidget *memory_recall_labels[MAX_REGISTERS];
+GType ui_buttons_get_type();
 
-    GList *superscript_toggles;
-    GList *subscript_toggles;
+MathButtons *ui_buttons_new(MathDisplay *display);
 
-    GtkWidget *bit_panel;
-    GtkWidget *bit_labels[MAXBITS];
+GtkWidget *ui_buttons_get_widget(MathButtons *buttons);
 
-    GtkWidget *ascii_dialog;
-    GtkWidget *ascii_entry;
-};
+void ui_buttons_set_bitfield(MathButtons *buttons, int enabled, guint64 bits);
 
-Buttons *ui_buttons_new(GCalctoolUI *ui);
+void ui_buttons_set_mode(MathButtons *buttons, ButtonMode mode);
 
-void ui_buttons_set_mode(Buttons *buttons, ButtonMode mode);
+ButtonMode ui_buttons_get_mode(MathButtons *buttons);
 
 #endif /* UI_BUTTONS_H */
diff --git a/src/ui-display.c b/src/ui-display.c
index 45843dc..e753eaa 100644
--- a/src/ui-display.c
+++ b/src/ui-display.c
@@ -16,200 +16,327 @@
  *  02111-1307, USA.
  */
 
+#include <string.h>
 #include <gdk/gdkkeysyms.h>
 
 #include "ui-display.h"
-#include "ui-internal.h"
+#include "display.h"
+#include "calctool.h"
 
-#define GET_WIDGET(ui, name)  GTK_WIDGET(gtk_builder_get_object(ui, name))
+enum {
+    PROP_0,
+    PROP_UI
+};
 
-MathDisplay *
-ui_display_new(GCalctoolUI *ui)
+enum {
+    NUMBER_MODE_CHANGED,
+    LAST_SIGNAL
+};
+static guint signals[LAST_SIGNAL] = { 0, };
+
+struct MathDisplayPrivate
 {
-    MathDisplay *display;
-    PangoFontDescription *font_desc;
-    GtkCellRenderer *renderer;
-  
-    display = g_malloc0(sizeof(MathDisplay));
-    display->clipboard_atom = gdk_atom_intern("CLIPBOARD", FALSE);
-    display->primary_atom = gdk_atom_intern("PRIMARY", FALSE);
+    NumberMode number_mode;
+    gboolean can_super_minus;
 
-    display->scrolledwindow = GET_WIDGET(ui->ui, "display_scroll");
-    display->display_item = GET_WIDGET(ui->ui, "displayitem");
-    display->info_buffer = GTK_TEXT_BUFFER(gtk_builder_get_object(ui->ui, "info_buffer"));
+    GtkWidget *display_item;           /* Calculator display. */
+    GtkTextBuffer *display_buffer;     /* Buffer used in display */
+    GtkTextBuffer *info_buffer;        /* Buffer used in info messages */
+    GtkWidget *scrolled_window;        /* Scrolled window for display_item. */
 
-/*    display->display_buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(ui->display->display_item));
-    gtk_widget_ensure_style(ui->display->display_item);
-    font_desc = pango_font_description_copy(gtk_widget_get_style(ui->display->display_item)->font_desc);
-    pango_font_description_set_size(font_desc, 16 * PANGO_SCALE);
-    gtk_widget_modify_font(ui->display->display_item, font_desc);
-    pango_font_description_free(font_desc);
-    gtk_widget_set_name(ui->display->display_item, "displayitem");
-    atk_object_set_role(gtk_widget_get_accessible(ui->display->display_item),
-                                                  ATK_ROLE_EDITBAR);*/
+    GdkAtom clipboard_atom;
+    GdkAtom primary_atom;
+    char *shelf;                       /* PUT selection shelf contents. */
 
-    return display;
-}
+    /* Last text entered */
+    char *last_text;
+};
 
+G_DEFINE_TYPE (MathDisplay, ui_display, G_TYPE_OBJECT);
 
+#define GET_WIDGET(ui, name)  GTK_WIDGET(gtk_builder_get_object(ui, name))
 
-gchar *
-ui_get_display(GCalctoolUI *ui)
+MathDisplay *
+ui_display_new(GtkBuilder *ui)
 {
-    GtkTextIter start, end;
-    gtk_text_buffer_get_bounds(ui->display->display_buffer, &start, &end);
-    return gtk_text_buffer_get_text(ui->display->display_buffer, &start, &end, FALSE);
+    return g_object_new (ui_display_get_type(), "ui", ui, NULL);
 }
 
 
-void
-ui_insert_text(GCalctoolUI *ui, const char *text)
+gchar *
+ui_display_get_text(MathDisplay *display)
 {
-    ui_do_button(ui, FN_TEXT, (gpointer) text);
+    GtkTextIter start, end;
+    gtk_text_buffer_get_bounds(display->priv->display_buffer, &start, &end);
+    return gtk_text_buffer_get_text(display->priv->display_buffer, &start, &end, FALSE);
 }
 
 
-static gboolean
-redo_display(GCalctoolUI *ui)
+const gchar *ui_display_get_digit_text(MathDisplay *display, guint digit)
 {
-    gchar *text;
-    GtkTextIter start, end, cursor;
-    gint cursor_position;
-
-    gtk_text_buffer_get_start_iter(ui->display->display_buffer, &start);
-    gtk_text_buffer_get_end_iter(ui->display->display_buffer, &end);
-    text = gtk_text_buffer_get_text(ui->display->display_buffer, &start, &end, FALSE);
-
-    g_object_get(G_OBJECT(ui->display->display_buffer), "cursor-position", &cursor_position, NULL);
-
-    gtk_text_buffer_set_text(ui->display->display_buffer, text, -1);
-    gtk_text_buffer_get_iter_at_offset(ui->display->display_buffer, &cursor, cursor_position);
-    gtk_text_buffer_place_cursor(ui->display->display_buffer, &cursor);
+    return v->digits[digit];
+}
 
-    g_free(text);
 
-    return FALSE;
+const gchar *ui_display_get_numeric_point_text(MathDisplay *display)
+{
+    return v->radix;
 }
 
 
 void
-ui_set_display(GCalctoolUI *ui, char *str, int cursor)
+ui_display_set_number_mode(MathDisplay *display, NumberMode mode)
 {
-    GtkTextIter iter;
-    GtkAdjustment *adj;
+    if (display->priv->number_mode == mode)
+        return;
 
-    gtk_text_buffer_set_text(ui->display->display_buffer, str, -1);
+    display->priv->can_super_minus = mode == SUPERSCRIPT;
 
-    if (cursor < 0)
-        gtk_text_buffer_get_end_iter(ui->display->display_buffer, &iter);
-    else
-        gtk_text_buffer_get_iter_at_offset(ui->display->display_buffer, &iter, cursor);
-    gtk_text_buffer_place_cursor(ui->display->display_buffer, &iter);
-    gtk_text_view_scroll_to_iter(GTK_TEXT_VIEW(ui->display->display_item), &iter, 0.0, TRUE, 1.0, 0.0);
+    display->priv->number_mode = mode;
+    g_signal_emit(display, signals[NUMBER_MODE_CHANGED], 0);
+}
 
-    /* This is a workaround for bug #524602.
-     * Basically the above code can cause the display to disappear when going from
-     * a display that is wider than the widget to one that is thinner. The following
-     * causes the display to be set twice which seems to work the second time.
-     */
-    g_idle_add((GSourceFunc)redo_display, ui);
 
-    /* Align to the right */
-    if (cursor < 0) {
-        adj = gtk_scrolled_window_get_hadjustment(
-                 GTK_SCROLLED_WINDOW(ui->display->scrolledwindow));
-        gtk_adjustment_set_value(adj, gtk_adjustment_get_upper(adj) - gtk_adjustment_get_page_size(adj));
-    }
+NumberMode
+ui_display_get_number_mode(MathDisplay *display)
+{
+    return display->priv->number_mode;
 }
 
 
-void
-ui_do_button(GCalctoolUI *ui, int function, gpointer arg)
+static void
+do_button(MathDisplay *display, int function, gpointer arg)
 {
     GtkTextIter start, end;
     gint cursor_start, cursor_end;
   
     /* Can't enter superscript minus after entering digits */
-    if (function == FN_TEXT && strstr("�¹²³������", (char *)arg) != NULL)
-        ui->display->can_super_minus = FALSE;
+    if (function == FN_TEXT && (strstr("�¹²³������", (char *)arg) != NULL || strcmp("�", (char *)arg) == 0))
+        display->priv->can_super_minus = FALSE;
 
     /* Disable super/subscript mode when finished entering */
     if (function == FN_CALCULATE ||
         function == FN_CLEAR ||
         (function == FN_TEXT && strstr("â?»â?°Â¹Â²Â³â?´â?µâ?¶â?·â?¸â?¹â??â??â??â??â??â??â??â??â??â??", (char *)arg) == NULL)) {
-        ui_set_number_mode(ui, NORMAL);
+        ui_display_set_number_mode(display, NORMAL);
     }
 
-    if (gtk_text_buffer_get_selection_bounds(ui->display->display_buffer, &start, &end)) {
+    if (gtk_text_buffer_get_selection_bounds(display->priv->display_buffer, &start, &end)) {
         cursor_start = gtk_text_iter_get_offset(&start);
         cursor_end = gtk_text_iter_get_offset(&end);
     }
     else {
-        g_object_get(G_OBJECT(ui->display->display_buffer), "cursor-position", &cursor_start, NULL);
-        if (cursor_start == gtk_text_buffer_get_char_count(ui->display->display_buffer))
+        g_object_get(G_OBJECT(display->priv->display_buffer), "cursor-position", &cursor_start, NULL);
+        if (cursor_start == gtk_text_buffer_get_char_count(display->priv->display_buffer))
             cursor_start = -1;
         cursor_end = cursor_start;
     }
 
     /* Some keyboards don't have a '^' button so convert two multiplies to one '^' */
     if (cursor_start == cursor_end &&
-        function == FN_TEXT && ui->display->last_text != NULL &&
-        strcmp((char *)arg, "Ã?") == 0 && strcmp(ui->display->last_text, "Ã?") == 0) {
-        ui_do_button(ui, FN_BACKSPACE, NULL);
-        ui_do_button(ui, FN_TEXT, "^");
+        function == FN_TEXT && display->priv->last_text != NULL &&
+        strcmp((char *)arg, "Ã?") == 0 && strcmp(display->priv->last_text, "Ã?") == 0) {
+        do_button(display, FN_BACKSPACE, NULL);
+        do_button(display, FN_TEXT, "^");
     }
     else {
         display_do_function(&v->display, function, arg, cursor_start, cursor_end);
         if (function == FN_TEXT)
-            ui->display->last_text = (char *)arg;
+            display->priv->last_text = (char *)arg;
         else
-            ui->display->last_text = NULL;
+            display->priv->last_text = NULL;
     }
 }
 
 
 void
-ui_display_copy(GCalctoolUI *ui)
+ui_display_store(MathDisplay *display, const char *name)
 {
-    gchar *string = NULL;
-    GtkTextIter start, end;
+    do_button(display, FN_STORE, (gpointer)name);
+}
 
-    if (gtk_text_buffer_get_selection_bounds(ui->display->display_buffer, &start, &end) == TRUE)
-        string = gtk_text_buffer_get_text(ui->display->display_buffer, &start, &end, FALSE);
-    else
-        string = ui_get_display(ui);
 
-    if (ui->display->shelf != NULL)
-        g_free(ui->display->shelf);
-    ui->display->shelf = g_locale_from_utf8(string, strlen(string), NULL, NULL, NULL);
-    g_free(string);
+void
+ui_display_recall(MathDisplay *display, const char *name)
+{
+    do_button(display, FN_RECALL, (gpointer)name);
+}
+
+
+void
+ui_display_insert(MathDisplay *display, const char *text)
+{
+    do_button(display, FN_TEXT, (gpointer) text);
+}
+
 
-    gtk_clipboard_set_text(gtk_clipboard_get(ui->display->clipboard_atom), ui->display->shelf, -1);
+void
+ui_display_insert_digit(MathDisplay *display, unsigned int digit)
+{
+    static const char *subscript_digits[] = {"â??", "â??", "â??", "â??", "â??", "â??", "â??", "â??", "â??", "â??", NULL};
+    static const char *superscript_digits[] = {"�", "¹", "²", "³", "�", "�", "�", "�", "�", "�", NULL};
+
+    if (display->priv->number_mode == NORMAL || digit >= 10)
+        ui_display_insert(display, v->digits[digit]);
+    else if (display->priv->number_mode == SUPERSCRIPT)
+        ui_display_insert(display, superscript_digits[digit]);
+    else if (display->priv->number_mode == SUBSCRIPT)
+        ui_display_insert(display, subscript_digits[digit]);
+}
+
+
+void
+ui_display_insert_numeric_point(MathDisplay *display)
+{
+    ui_display_insert(display, v->radix);
+}
+
+
+void
+ui_display_insert_exponent(MathDisplay *display)
+{
+    ui_display_insert(display, "Ã?10");
+    ui_display_set_number_mode(display, SUPERSCRIPT);
 }
 
 
 void
-ui_do_exponent(GCalctoolUI *ui)
+ui_display_insert_character(MathDisplay *display, const char *character)
 {
-    ui_insert_text(ui, "Ã?10");
-    ui_set_number_mode(ui, SUPERSCRIPT);
+    do_button(display, FN_INSERT_CHARACTER, (gpointer)character);
 }
 
 
 void
-ui_do_subtract(GCalctoolUI *ui)
+ui_display_insert_subtract(MathDisplay *display)
 {
-    if (ui->display->can_super_minus) {
-        ui_insert_text(ui, "â?»");
-        ui->display->can_super_minus = FALSE;
+    if (display->priv->number_mode == SUPERSCRIPT && display->priv->can_super_minus) {
+        ui_display_insert(display, "â?»");
+        display->priv->can_super_minus = FALSE;
     }
     else {
-        ui_insert_text(ui, "â??");
-        ui_set_number_mode(ui, NORMAL);
+        ui_display_insert(display, "â??");
+        ui_display_set_number_mode(display, NORMAL);
+    }
+}
+
+
+void
+ui_display_solve(MathDisplay *display)
+{
+    do_button(display, FN_CALCULATE, NULL);
+}
+
+
+void
+ui_display_factorize(MathDisplay *display)
+{
+    do_button(display, FN_FACTORIZE, NULL);
+}
+
+
+void
+ui_display_clear(MathDisplay *display)
+{
+    do_button(display, FN_CLEAR, NULL);  
+}
+
+
+void
+ui_display_shift(MathDisplay *display, gint count)
+{
+    do_button(display, FN_SHIFT, GINT_TO_POINTER(count));
+}
+
+
+void
+ui_display_toggle_bit(MathDisplay *display, guint bit)
+{
+    do_button(display, FN_TOGGLE_BIT, GINT_TO_POINTER(bit));
+}
+
+
+static gboolean
+redo_display(MathDisplay *display)
+{
+    gchar *text;
+    GtkTextIter start, end, cursor;
+    gint cursor_position;
+
+    gtk_text_buffer_get_start_iter(display->priv->display_buffer, &start);
+    gtk_text_buffer_get_end_iter(display->priv->display_buffer, &end);
+    text = gtk_text_buffer_get_text(display->priv->display_buffer, &start, &end, FALSE);
+
+    g_object_get(G_OBJECT(display->priv->display_buffer), "cursor-position", &cursor_position, NULL);
+
+    gtk_text_buffer_set_text(display->priv->display_buffer, text, -1);
+    gtk_text_buffer_get_iter_at_offset(display->priv->display_buffer, &cursor, cursor_position);
+    gtk_text_buffer_place_cursor(display->priv->display_buffer, &cursor);
+
+    g_free(text);
+
+    return FALSE;
+}
+
+
+void
+ui_display_set(MathDisplay *display, char *str, int cursor)
+{
+    GtkTextIter iter;
+    GtkAdjustment *adj;
+
+    gtk_text_buffer_set_text(display->priv->display_buffer, str, -1);
+
+    if (cursor < 0)
+        gtk_text_buffer_get_end_iter(display->priv->display_buffer, &iter);
+    else
+        gtk_text_buffer_get_iter_at_offset(display->priv->display_buffer, &iter, cursor);
+    gtk_text_buffer_place_cursor(display->priv->display_buffer, &iter);
+    gtk_text_view_scroll_to_iter(GTK_TEXT_VIEW(display->priv->display_item), &iter, 0.0, TRUE, 1.0, 0.0);
+
+    /* This is a workaround for bug #524602.
+     * Basically the above code can cause the display to disappear when going from
+     * a display that is wider than the widget to one that is thinner. The following
+     * causes the display to be set twice which seems to work the second time.
+     */
+    g_idle_add((GSourceFunc)redo_display, display);
+
+    /* Align to the right */
+    if (cursor < 0) {
+        adj = gtk_scrolled_window_get_hadjustment(
+                 GTK_SCROLLED_WINDOW(display->priv->scrolled_window));
+        gtk_adjustment_set_value(adj, gtk_adjustment_get_upper(adj) - gtk_adjustment_get_page_size(adj));
     }
 }
 
 
+void
+ui_display_set_status(MathDisplay *display, const gchar *message)
+{
+    gtk_text_buffer_set_text(display->priv->info_buffer, message, -1);
+}
+
+
+void
+ui_display_copy(MathDisplay *display)
+{
+    gchar *string = NULL;
+    GtkTextIter start, end;
+
+    if (gtk_text_buffer_get_selection_bounds(display->priv->display_buffer, &start, &end) == TRUE)
+        string = gtk_text_buffer_get_text(display->priv->display_buffer, &start, &end, FALSE);
+    else
+        string = ui_display_get_text(display);
+
+    if (display->priv->shelf != NULL)
+        g_free(display->priv->shelf);
+    display->priv->shelf = g_locale_from_utf8(string, strlen(string), NULL, NULL, NULL);
+    g_free(string);
+
+    gtk_clipboard_set_text(gtk_clipboard_get(display->priv->clipboard_atom), display->priv->shelf, -1);
+}
+
+
 static gboolean
 check_for_localized_numeric_point(int keyval)
 {
@@ -230,9 +357,12 @@ G_MODULE_EXPORT
 gboolean
 main_window_key_press_cb(GtkWidget *widget, GdkEventKey *event, GCalctoolUI *ui)
 {
+    MathDisplay *display;
     int i, state;
     const char *conversions[]       = {"*", "/", NULL};
     const char *conversion_values[] = {"�", "÷", NULL };
+  
+    display = ui_get_display(ui);
 
     /* Only look at the modifiers we use */
     state = event->state & (GDK_CONTROL_MASK | GDK_MOD1_MASK);
@@ -250,115 +380,115 @@ main_window_key_press_cb(GtkWidget *widget, GdkEventKey *event, GCalctoolUI *ui)
         switch(event->keyval)
         {
         case GDK_b:
-            ui_set_base(ui, 2);
+            ui_display_set_base(display, 2);
             return TRUE;
         case GDK_d:
-            ui_set_base(ui, 10);
+            ui_display_set_base(display, 10);
             return TRUE;
         case GDK_e:
-            ui_do_exponent(ui);
+            ui_display_insert_exponent(display);
             return TRUE;
         case GDK_f:
-            ui_do_button(ui, FN_FACTORIZE, NULL);
+            ui_display_factorize(display);
             return TRUE;
         case GDK_h:
-            ui_set_base(ui, 16);
+            ui_display_set_base(display, 16);
             return TRUE;
         case GDK_i:
-            ui_insert_text(ui, "�¹");
+            ui_display_insert(display, "�¹");
             return TRUE;
         case GDK_o:
-            ui_set_base(ui, 8);
+            ui_display_set_base(display, 8);
             return TRUE;
         case GDK_p:
-            ui_insert_text(ui, "Ï?");
+            ui_display_insert(display, "Ï?");
             return TRUE;
         case GDK_r:
-            ui_insert_text(ui, "â??");
+            ui_display_insert(display, "â??");
             return TRUE;
         case GDK_u:
-            ui_insert_text(ui, "µ");
+            ui_display_insert(display, "µ");
             return TRUE;
         }
     }
-    if (state == GDK_CONTROL_MASK || ui->display->number_mode == SUPERSCRIPT) {
+    if (state == GDK_CONTROL_MASK || display->priv->number_mode == SUPERSCRIPT) {
         switch(event->keyval)
         {
         case GDK_0:
-            ui_insert_text(ui, "â?°");
+            ui_display_insert(display, "â?°");
             return TRUE;
         case GDK_1:
-            ui_insert_text(ui, "¹");
+            ui_display_insert(display, "¹");
             return TRUE;
         case GDK_2:
-            ui_insert_text(ui, "²");
+            ui_display_insert(display, "²");
             return TRUE;
         case GDK_3:
-            ui_insert_text(ui, "³");
+            ui_display_insert(display, "³");
             return TRUE;
         case GDK_4:
-            ui_insert_text(ui, "â?´");
+            ui_display_insert(display, "â?´");
             return TRUE;
         case GDK_5:
-            ui_insert_text(ui, "â?µ");
+            ui_display_insert(display, "â?µ");
             return TRUE;
         case GDK_6:
-            ui_insert_text(ui, "â?¶");
+            ui_display_insert(display, "â?¶");
             return TRUE;
         case GDK_7:
-            ui_insert_text(ui, "â?·");
+            ui_display_insert(display, "â?·");
             return TRUE;
         case GDK_8:
-            ui_insert_text(ui, "â?¸");
+            ui_display_insert(display, "â?¸");
             return TRUE;
         case GDK_9:
-            ui_insert_text(ui, "â?¹");
+            ui_display_insert(display, "â?¹");
             return TRUE;
         }
     }
-    else if (state == GDK_MOD1_MASK || ui->display->number_mode == SUBSCRIPT) {
+    else if (state == GDK_MOD1_MASK || display->priv->number_mode == SUBSCRIPT) {
         switch(event->keyval)
         {
         case GDK_0:
-            ui_insert_text(ui, "â??");
+            ui_display_insert(display, "â??");
             return TRUE;
         case GDK_1:
-            ui_insert_text(ui, "â??");
+            ui_display_insert(display, "â??");
             return TRUE;
         case GDK_2:
-            ui_insert_text(ui, "â??");
+            ui_display_insert(display, "â??");
             return TRUE;
         case GDK_3:
-            ui_insert_text(ui, "â??");
+            ui_display_insert(display, "â??");
             return TRUE;
         case GDK_4:
-            ui_insert_text(ui, "â??");
+            ui_display_insert(display, "â??");
             return TRUE;
         case GDK_5:
-            ui_insert_text(ui, "â??");
+            ui_display_insert(display, "â??");
             return TRUE;
         case GDK_6:
-            ui_insert_text(ui, "â??");
+            ui_display_insert(display, "â??");
             return TRUE;
         case GDK_7:
-            ui_insert_text(ui, "â??");
+            ui_display_insert(display, "â??");
             return TRUE;
         case GDK_8:
-            ui_insert_text(ui, "â??");
+            ui_display_insert(display, "â??");
             return TRUE;
         case GDK_9:
-            ui_insert_text(ui, "â??");
+            ui_display_insert(display, "â??");
             return TRUE;
         }
     }
 
     /* Delete in display */
     if (event->keyval == GDK_Delete && state == 0 && (event->state & GDK_SHIFT_MASK) == 0) {
-        ui_do_button(ui, FN_DELETE, NULL);
+        do_button(display, FN_DELETE, NULL);
         return TRUE;
     }
     if (event->keyval == GDK_BackSpace && state == 0 && (event->state & GDK_SHIFT_MASK) == 0) {
-        ui_do_button(ui, FN_BACKSPACE, NULL);
+        do_button(display, FN_BACKSPACE, NULL);
         return TRUE;
     }
 
@@ -366,15 +496,15 @@ main_window_key_press_cb(GtkWidget *widget, GdkEventKey *event, GCalctoolUI *ui)
     if ((event->keyval == GDK_Escape && state == 0) ||
         (event->keyval == GDK_BackSpace && state == GDK_CONTROL_MASK) ||
         (event->keyval == GDK_Delete && state == GDK_SHIFT_MASK)) {
-        ui_do_button(ui, FN_CLEAR, NULL);
+        ui_display_clear(display);
         return TRUE;
     }
 
     /* Solve */
     if ((event->keyval == GDK_Return && state == 0) ||
         (event->keyval == GDK_KP_Enter && state == 0)) {
-        if (gtk_widget_has_focus(ui->display->display_item)) {
-            ui_do_button(ui, FN_CALCULATE, NULL);
+        if (gtk_widget_has_focus(display->priv->display_item)) {
+            ui_display_solve(display);
             return TRUE;
         }
         else {
@@ -384,8 +514,7 @@ main_window_key_press_cb(GtkWidget *widget, GdkEventKey *event, GCalctoolUI *ui)
 
     if (state == GDK_CONTROL_MASK && event->keyval == GDK_minus) 
     {
-        ui_insert_text(ui, "â?»");
-        ui->display->can_super_minus = FALSE;
+        ui_display_insert(display, "â?»");
         return TRUE;
     }
 
@@ -395,40 +524,46 @@ main_window_key_press_cb(GtkWidget *widget, GdkEventKey *event, GCalctoolUI *ui)
     // FIXME: event->string deprecated
 
     if (strcmp(event->string, "-") == 0 || strcmp(event->string, "â??") == 0) {
-        ui_do_subtract(ui);
+        ui_display_insert_subtract(display);
         return TRUE;
     }
 
     for (i = 0; conversions[i]; i++) {
         if (strcmp(event->string, conversions[i]) == 0) {
-            ui_insert_text(ui, conversion_values[i]);
+            ui_display_insert(display, conversion_values[i]);
             return TRUE;
         }
     }
     if (strcmp(event->string, ".") == 0) {
-        ui_insert_text(ui, v->radix);
+        ui_display_insert(display, v->radix);
         return TRUE;
     }
 
     /* Some keyboards use this keyval for '^' (e.g. German) */
     if (event->keyval == GDK_dead_circumflex) {
-        ui_insert_text(ui, "^");
+        ui_display_insert(display, "^");
         return TRUE;
     }
 
     switch(*event->string)
     {
+    case '<':
+        // FIXME: Should open left shift menu (programming mode)
+        return TRUE;
+    case '>':
+        // FIXME: Should open right shift menu (programming mode)
+        return TRUE;
     case '\n':
-        ui_do_button(ui, FN_CALCULATE, NULL);
+        ui_display_solve(display);
         return TRUE;
     }
   
     /* Don't override space - it is used in UI */
-    if (event->string[0] == ' ' && !gtk_widget_has_focus(ui->display->display_item))
+    if (event->string[0] == ' ' && !gtk_widget_has_focus(display->priv->display_item))
         return FALSE;
 
     if (event->string[0] != '\0') {
-        ui_insert_text(ui, event->string);
+        ui_display_insert(display, event->string);
         return TRUE;
     }
 
@@ -436,16 +571,17 @@ main_window_key_press_cb(GtkWidget *widget, GdkEventKey *event, GCalctoolUI *ui)
 }
 
 
+// FIXME: Kill this
 static void
-popup_paste_cb(GtkWidget *menu, GCalctoolUI *ui)
+popup_paste_cb(GtkWidget *menu, MathDisplay *display)
 {
-    ui_display_paste(ui);
+    ui_display_paste(display);
 }
 
 
 // FIXME: Kill this
 static void
-for_each_menu(GtkWidget *widget, GCalctoolUI *ui)
+for_each_menu(GtkWidget *widget, MathDisplay *display)
 {
     /* Find the "Paste" entry and activate it (see bug #317786).
      * It is disabled because the GtkEntry is not marked as editable.
@@ -454,57 +590,58 @@ for_each_menu(GtkWidget *widget, GCalctoolUI *ui)
         GtkWidget *label = gtk_bin_get_child(GTK_BIN(widget));
 
          if (strcmp(gtk_label_get_text(GTK_LABEL(label)), _("Paste")) == 0) {
-            if (gtk_clipboard_wait_is_text_available(gtk_clipboard_get(ui->display->clipboard_atom))) {
+            if (gtk_clipboard_wait_is_text_available(gtk_clipboard_get(display->priv->clipboard_atom))) {
                 gtk_widget_set_sensitive(GTK_WIDGET(widget), TRUE);
                 g_signal_connect(GTK_OBJECT(widget), "activate",
-                                 G_CALLBACK(popup_paste_cb), ui);
+                                 G_CALLBACK(popup_paste_cb), display);
             }
         }
     }
 }
 
 
+// FIXME: Kill this
 G_MODULE_EXPORT
 void
-buffer_populate_popup_cb(GtkTextView *textview, GtkMenu *menu, GCalctoolUI *ui)
+buffer_populate_popup_cb(GtkTextView *textview, GtkMenu *menu, MathDisplay *display)
 {
-    gtk_container_foreach(GTK_CONTAINER(menu), (GtkCallback)for_each_menu, ui);
+    gtk_container_foreach(GTK_CONTAINER(menu), (GtkCallback)for_each_menu, display);
 }
 
 
 static void
-on_paste(GtkClipboard *clipboard, const gchar *text, GCalctoolUI *ui)
+on_paste(GtkClipboard *clipboard, const gchar *text, MathDisplay *display)
 {
     if (text != NULL)
-        ui_do_button(ui, FN_PASTE, (gpointer) text);
+        do_button(display, FN_PASTE, (gpointer) text);
 }
 
 
 void
-ui_display_paste(GCalctoolUI *ui)
+ui_display_paste(MathDisplay *display)
 {
-    gtk_clipboard_request_text(gtk_clipboard_get(ui->display->clipboard_atom),
-                               (GtkClipboardTextReceivedFunc)on_paste, ui);
+    gtk_clipboard_request_text(gtk_clipboard_get(display->priv->clipboard_atom),
+                               (GtkClipboardTextReceivedFunc)on_paste, display);
 }
 
 
 G_MODULE_EXPORT
 gboolean
-middle_click_paste_cb(GtkWidget *widget, GdkEventButton *event, GCalctoolUI *ui)
+middle_click_paste_cb(GtkWidget *widget, GdkEventButton *event, MathDisplay *display)
 {
     if (event->button == 2)
-        ui_display_paste(ui);
+        ui_display_paste(display);
 
     return FALSE;
 }
 
 
 void
-ui_set_base(GCalctoolUI *ui, gint base)
+ui_display_set_base(MathDisplay *display, gint base)
 {
     /* If has a number already in a base, then solve and convert it */
     if (!display_is_result(&v->display) && display_is_number_with_base(&v->display))
-        ui_do_button(ui, FN_CALCULATE, NULL);
+        ui_display_solve(display);
 
     if (display_is_result(&v->display)) {
         if (base == 2)
@@ -518,10 +655,103 @@ ui_set_base(GCalctoolUI *ui, gint base)
     }
     else {
         if (base == 2)
-            ui_insert_text(ui, "â??");
+            ui_display_insert(display, "â??");
         else if (base == 8)
-            ui_insert_text(ui, "â??");
+            ui_display_insert(display, "â??");
         else if (base == 16)
-            ui_insert_text(ui, "â??â??");
+            ui_display_insert(display, "â??â??");
+    }
+}
+
+
+static void
+ui_display_set_property (GObject      *object,
+                         guint         prop_id,
+                         const GValue *value,
+                         GParamSpec   *pspec)
+{
+    MathDisplay *self;
+    GtkBuilder *ui;
+    PangoFontDescription *font_desc;
+    GtkCellRenderer *renderer;
+
+    self = MATH_DISPLAY (object);
+
+    switch (prop_id) {
+    case PROP_UI:
+        ui = g_value_get_object (value);
+      
+        self->priv->scrolled_window = GET_WIDGET(ui, "display_scroll");
+        self->priv->info_buffer = GTK_TEXT_BUFFER(gtk_builder_get_object(ui, "info_buffer"));
+        self->priv->display_item = GET_WIDGET(ui, "displayitem");
+        self->priv->display_buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(self->priv->display_item));
+
+        gtk_widget_ensure_style(self->priv->display_item);
+        font_desc = pango_font_description_copy(gtk_widget_get_style(self->priv->display_item)->font_desc);
+        pango_font_description_set_size(font_desc, 16 * PANGO_SCALE);
+        gtk_widget_modify_font(self->priv->display_item, font_desc);
+        pango_font_description_free(font_desc);
+        gtk_widget_set_name(self->priv->display_item, "displayitem");
+        atk_object_set_role(gtk_widget_get_accessible(self->priv->display_item), ATK_ROLE_EDITBAR);
+        break;
+    default:
+        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+        break;
+    }
+}
+
+
+static void
+ui_display_get_property (GObject    *object,
+                         guint       prop_id,
+                         GValue     *value,
+                         GParamSpec *pspec)
+{
+    MathDisplay *self;
+
+    self = MATH_DISPLAY (object);
+
+    switch (prop_id) {
+    default:
+        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+        break;
     }
 }
+
+
+static void
+ui_display_class_init (MathDisplayClass *klass)
+{
+    GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+    object_class->get_property = ui_display_get_property;
+    object_class->set_property = ui_display_set_property;
+  
+    g_type_class_add_private (klass, sizeof (MathDisplayPrivate));
+
+    g_object_class_install_property (object_class,
+                                     PROP_UI,
+                                     g_param_spec_object ("ui",
+                                                          "ui",
+                                                          "GtkBuilder to get widgets from (temp)",
+                                                          gtk_builder_get_type(),
+                                                          G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY));
+
+    signals[NUMBER_MODE_CHANGED] =
+        g_signal_new ("number-mode-changed",
+                      G_TYPE_FROM_CLASS (klass),
+                      G_SIGNAL_RUN_LAST,
+                      G_STRUCT_OFFSET (MathDisplayClass, number_mode_changed),
+                      NULL, NULL,
+                      g_cclosure_marshal_VOID__VOID,
+                      G_TYPE_NONE, 0);
+}
+
+
+static void 
+ui_display_init(MathDisplay *display)
+{
+    display->priv = G_TYPE_INSTANCE_GET_PRIVATE (display, ui_display_get_type(), MathDisplayPrivate);
+    display->priv->primary_atom = gdk_atom_intern("PRIMARY", FALSE);
+    display->priv->clipboard_atom = gdk_atom_intern("CLIPBOARD", FALSE);
+}
diff --git a/src/ui-display.h b/src/ui-display.h
index 2b368c0..47e890a 100644
--- a/src/ui-display.h
+++ b/src/ui-display.h
@@ -19,9 +19,14 @@
 #ifndef UI_DISPLAY_H
 #define UI_DISPLAY_H
 
-typedef struct MathDisplay MathDisplay;
+#include <glib-object.h>
+#include <gtk/gtk.h>
 
-#include "ui.h"
+G_BEGIN_DECLS
+
+#define MATH_DISPLAY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), ui_display_get_type(), MathDisplay))
+
+typedef struct MathDisplayPrivate MathDisplayPrivate;
 
 typedef enum {
     NORMAL,
@@ -29,31 +34,45 @@ typedef enum {
     SUBSCRIPT
 } NumberMode;
 
-struct MathDisplay
+typedef struct
 {
-    NumberMode number_mode;  
-
-    GtkWidget *display_item;           /* Calculator display. */
-    GtkTextBuffer *display_buffer;     /* Buffer used in display */
-    GtkTextBuffer *info_buffer;        /* Buffer used in info messages */
-    GtkWidget *scrolledwindow;         /* Scrolled window for display_item. */
-
-    GdkAtom clipboard_atom;
-    GdkAtom primary_atom;
-    char *shelf;                       /* PUT selection shelf contents. */
-
-    gboolean can_super_minus;
-
-    /* Last text entered */
-    char *last_text;
-};
-
-MathDisplay *ui_display_new(GCalctoolUI *ui);
-void ui_display_copy(GCalctoolUI *ui);
-void ui_display_paste(GCalctoolUI *ui);
-void ui_insert_text(GCalctoolUI *ui, const char *text);
-void ui_set_base(GCalctoolUI *ui, gint base);
-void ui_do_subtract(GCalctoolUI *ui);
-void ui_do_exponent(GCalctoolUI *ui);
+    GObject             parent_instance; // FIXME: Extend GtkVBox, remove widgets from gcalctool.ui
+    MathDisplayPrivate *priv;
+} MathDisplay;
+
+typedef struct
+{
+    GObjectClass parent_class;
+
+    void (*number_mode_changed)(MathDisplay *display);
+} MathDisplayClass;
+
+GType ui_display_get_type();
+
+MathDisplay *ui_display_new();
+void ui_display_set_base(MathDisplay *display, gint base);
+void ui_display_set_number_mode(MathDisplay *display, NumberMode mode);
+void ui_display_set(MathDisplay *display, gchar *, gint); // FIXME: Make obsolete by Math model
+void ui_display_set_status(MathDisplay *display, const gchar *message);
+gchar *ui_display_get_text(MathDisplay *display);
+
+const gchar *ui_display_get_digit_text(MathDisplay *display, guint digit);
+const gchar *ui_display_get_numeric_point_text(MathDisplay *display);
+
+void ui_display_copy(MathDisplay *display);
+void ui_display_paste(MathDisplay *display);
+void ui_display_store(MathDisplay *display, const gchar *name);
+void ui_display_recall(MathDisplay *display, const gchar *name);
+void ui_display_insert(MathDisplay *display, const gchar *text);
+void ui_display_insert_digit(MathDisplay *display, guint digit);
+void ui_display_insert_numeric_point(MathDisplay *display);
+void ui_display_insert_subtract(MathDisplay *display);
+void ui_display_insert_exponent(MathDisplay *display);
+void ui_display_insert_character(MathDisplay *display, const gchar *character);
+void ui_display_solve(MathDisplay *display);
+void ui_display_factorize(MathDisplay *display);
+void ui_display_clear(MathDisplay *display);
+void ui_display_shift(MathDisplay *display, gint count);
+void ui_display_toggle_bit(MathDisplay *display, guint bit);
 
 #endif /* UI_DISPLAY_H */
diff --git a/src/ui-preferences.c b/src/ui-preferences.c
index 18d707c..6d59e59 100644
--- a/src/ui-preferences.c
+++ b/src/ui-preferences.c
@@ -19,7 +19,6 @@
 #include <gtk/gtk.h>
 
 #include "ui-preferences.h"
-#include "ui-internal.h"
 #include "get.h"
 
 #define UI_DIALOGS_FILE  UI_DIR "/preferences.ui"
@@ -251,7 +250,7 @@ ui_preferences_show(PreferencesDialog *dialog)
     gtk_builder_add_from_file(dialog->dialog_ui, UI_DIALOGS_FILE, NULL);
 
     dialog->dialog = GET_WIDGET(dialog->dialog_ui, "preferences_dialog");
-    gtk_window_set_transient_for(GTK_WINDOW(dialog->dialog), GTK_WINDOW(dialog->ui->main_window));
+    //FIXME: gtk_window_set_transient_for(GTK_WINDOW(dialog->dialog), GTK_WINDOW(dialog->ui->main_window));
 
     /* Configuration dialog */
 
diff --git a/src/ui.c b/src/ui.c
index 420b94a..5b47fcd 100644
--- a/src/ui.c
+++ b/src/ui.c
@@ -20,20 +20,30 @@
 #include <gtk/gtk.h>
 
 #include "ui.h"
-#include "ui-internal.h"
 #include "ui-display.h"
 #include "ui-buttons.h"
 #include "ui-preferences.h"
 #include "config.h"
 #include "get.h"
 
+struct GCalctoolUIPrivate
+{
+    GtkBuilder *ui;
+    GtkWidget *main_window;
+    MathDisplay *display;
+    MathButtons *buttons;
+    PreferencesDialog *preferences_dialog;
+};
+
+G_DEFINE_TYPE (GCalctoolUI, ui, G_TYPE_OBJECT);
+
 static const char *mode_names[] = { "BASIC", "ADVANCED", "FINANCIAL", "PROGRAMMING", NULL };
 
 #define UI_FILE UI_DIR "/gcalctool.ui"
 #define GET_WIDGET(ui, name)  GTK_WIDGET(gtk_builder_get_object(ui, name))
 
 void
-ui_init(int *argc, char ***argv)
+ui_gtk_init(int *argc, char ***argv)
 {
     gtk_init(argc, argv);
     gtk_window_set_default_icon_name("accessories-calculator");
@@ -43,48 +53,21 @@ ui_init(int *argc, char ***argv)
 GCalctoolUI *
 ui_new()
 {
-    GCalctoolUI *ui;
-    GError *error = NULL;
-    int i;
-
-    ui = g_malloc0(sizeof(GCalctoolUI));
+    return g_object_new (ui_get_type(), NULL);
+}
 
-    ui->ui = gtk_builder_new();
-    gtk_builder_add_from_file(ui->ui, UI_FILE, &error);
-    if (error) {
-       gchar *contents;
-       contents = g_strdup_printf(/* Description in UI error dialog when unable to load the UI files. %s is replaced with the error message provided by GTK+ */
-                                  _("A required file is missing or damaged. Please check your installation.\n\n%s"),
-                                  error->message);
-       ui_critical_error(ui,
-                         /* Title of the error dialog when unable to load the UI files */
-                         _("Error loading user interface"),
-                         contents);
-    }
-    gtk_builder_connect_signals(ui->ui, ui);
-
-    ui->main_window = GET_WIDGET(ui->ui, "calc_window");
-
-    /* Set modes for menu items */
-  // FIXME: Move into buttons
-    for (i = 1; i < 16; i++) {
-        char name[MAXLINE];
-        SNPRINTF(name, MAXLINE, "shift_left%d_menu", i);
-        g_object_set_data(gtk_builder_get_object(ui->ui, name), "shiftcount", GINT_TO_POINTER(i));
-        SNPRINTF(name, MAXLINE, "shift_right%d_menu", i);
-        g_object_set_data(gtk_builder_get_object(ui->ui, name), "shiftcount", GINT_TO_POINTER(-i));
-    }
 
-    g_object_set_data(gtk_builder_get_object(ui->ui, "view_basic_menu"), "calcmode", GINT_TO_POINTER(BASIC));
-    g_object_set_data(gtk_builder_get_object(ui->ui, "view_advanced_menu"), "calcmode", GINT_TO_POINTER(ADVANCED));
-    g_object_set_data(gtk_builder_get_object(ui->ui, "view_financial_menu"), "calcmode", GINT_TO_POINTER(FINANCIAL));
-    g_object_set_data(gtk_builder_get_object(ui->ui, "view_programming_menu"), "calcmode", GINT_TO_POINTER(PROGRAMMING));
+MathDisplay *
+ui_get_display(GCalctoolUI *ui)
+{
+    return ui->priv->display;
+}
 
-    ui->display = ui_display_new(ui);
-    ui->buttons = ui_buttons_new(ui);
-    ui->preferences_dialog = ui_preferences_dialog_new(ui);
 
-    return ui;
+MathButtons *
+ui_get_buttons(GCalctoolUI *ui)
+{
+    return ui->priv->buttons;
 }
 
 
@@ -96,24 +79,24 @@ ui_set_mode(GCalctoolUI *ui, ButtonMode mode)
     /* Save mode */
     set_enumerated_resource(R_MODE, mode_names, (int)mode);
 
-    ui_buttons_set_mode(ui->buttons, mode);
+    ui_buttons_set_mode(ui->priv->buttons, mode);
 
     /* Update the menu */
     switch (mode) {
         case BASIC:
-            menu = GET_WIDGET(ui->ui, "view_basic_menu");
+            menu = GET_WIDGET(ui->priv->ui, "view_basic_menu");
             break;
 
         case ADVANCED:
-            menu = GET_WIDGET(ui->ui, "view_advanced_menu");
+            menu = GET_WIDGET(ui->priv->ui, "view_advanced_menu");
             break;
 
         case FINANCIAL:
-            menu = GET_WIDGET(ui->ui, "view_financial_menu");
+            menu = GET_WIDGET(ui->priv->ui, "view_financial_menu");
             break;
 
         case PROGRAMMING:
-            menu = GET_WIDGET(ui->ui, "view_programming_menu");
+            menu = GET_WIDGET(ui->priv->ui, "view_programming_menu");
             break;
 
         default:
@@ -133,7 +116,7 @@ ui_start(GCalctoolUI *ui)
     get_enumerated_resource(R_MODE, mode_names, &mode);
     ui_set_mode(ui, (ButtonMode)mode);
 
-    gtk_widget_show(ui->main_window);
+    gtk_widget_show(ui->priv->main_window);
     gtk_main();
 }
 
@@ -157,35 +140,11 @@ ui_critical_error(GCalctoolUI *ui, const gchar *title, const gchar *contents)
 }
 
 
-void
-ui_set_number_mode(GCalctoolUI *ui, NumberMode mode)
-{
-    GList *i;
-
-    ui->display->number_mode = mode;
-    for (i = ui->buttons->superscript_toggles; i; i = i->next) {
-        GtkWidget *widget = i->data;
-        gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(widget), mode == SUPERSCRIPT);
-    }
-    for (i = ui->buttons->subscript_toggles; i; i = i->next) {
-        GtkWidget *widget = i->data;
-        gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(widget), mode == SUBSCRIPT);
-    }
-}
-
-
-void
-ui_set_statusbar(GCalctoolUI *ui, const gchar *text)
-{
-    gtk_text_buffer_set_text(ui->display->info_buffer, text, -1);
-}
-
-
 G_MODULE_EXPORT
 void
 copy_cb(GtkWidget *widget, GCalctoolUI *ui)
 {
-    ui_display_copy(ui);
+    ui_display_copy(ui->priv->display);
 }
 
 
@@ -193,7 +152,7 @@ G_MODULE_EXPORT
 void
 paste_cb(GtkWidget *widget, GCalctoolUI *ui)
 {
-    ui_display_paste(ui);
+    ui_display_paste(ui->priv->display);
 }
 
 
@@ -215,7 +174,7 @@ G_MODULE_EXPORT
 void
 show_preferences_cb(GtkMenuItem *menu, GCalctoolUI *ui)
 {
-    ui_preferences_show(ui->preferences_dialog);
+    ui_preferences_show(ui->priv->preferences_dialog);
 }
 
 
@@ -226,7 +185,7 @@ help_cb(GtkWidget *widget, GCalctoolUI *ui)
     GdkScreen *screen;
     GError *error = NULL;
 
-    screen = gtk_widget_get_screen (GTK_WIDGET (ui->main_window));
+    screen = gtk_widget_get_screen (GTK_WIDGET (ui->priv->main_window));
     gtk_show_uri (screen, "ghelp:gcalctool", gtk_get_current_event_time (), &error);
 
     if (error != NULL)
@@ -235,7 +194,7 @@ help_cb(GtkWidget *widget, GCalctoolUI *ui)
         /* Translators: Error message displayed when unable to launch help browser */
         const char *message = _("Unable to open help file");
 
-        d = gtk_message_dialog_new (GTK_WINDOW (ui->main_window),
+        d = gtk_message_dialog_new (GTK_WINDOW (ui->priv->main_window),
                                     GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
                                     GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE,
                                     "%s", message);
@@ -282,7 +241,7 @@ about_cb(GtkWidget *widget, GCalctoolUI *ui)
           "along with Gcalctool; if not, write to the Free Software Foundation, Inc.,\n"
           "51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA");
 
-    gtk_show_about_dialog(GTK_WINDOW(ui->main_window),
+    gtk_show_about_dialog(GTK_WINDOW(ui->priv->main_window),
                           "name",
                           /* Program name in the about dialog */
                           _("Gcalctool"),
@@ -308,3 +267,46 @@ quit_cb(GtkWidget *widget, GCalctoolUI *ui)
 {
     gtk_main_quit();
 }
+
+
+static void
+ui_class_init (GCalctoolUIClass *klass)
+{
+    g_type_class_add_private (klass, sizeof (GCalctoolUIPrivate));
+}
+
+
+static void 
+ui_init(GCalctoolUI *ui)
+{
+    GError *error = NULL;
+    int i;
+
+    ui->priv = G_TYPE_INSTANCE_GET_PRIVATE (ui, ui_get_type(), GCalctoolUIPrivate);
+
+    ui->priv->ui = gtk_builder_new();
+    gtk_builder_add_from_file(ui->priv->ui, UI_FILE, &error);
+    if (error) {
+       gchar *contents;
+       contents = g_strdup_printf(/* Description in UI error dialog when unable to load the UI files. %s is replaced with the error message provided by GTK+ */
+                                  _("A required file is missing or damaged. Please check your installation.\n\n%s"),
+                                  error->message);
+       ui_critical_error(ui,
+                         /* Title of the error dialog when unable to load the UI files */
+                         _("Error loading user interface"),
+                         contents);
+    }
+    gtk_builder_connect_signals(ui->priv->ui, ui);
+
+    ui->priv->main_window = GET_WIDGET(ui->priv->ui, "calc_window");
+
+    g_object_set_data(gtk_builder_get_object(ui->priv->ui, "view_basic_menu"), "calcmode", GINT_TO_POINTER(BASIC));
+    g_object_set_data(gtk_builder_get_object(ui->priv->ui, "view_advanced_menu"), "calcmode", GINT_TO_POINTER(ADVANCED));
+    g_object_set_data(gtk_builder_get_object(ui->priv->ui, "view_financial_menu"), "calcmode", GINT_TO_POINTER(FINANCIAL));
+    g_object_set_data(gtk_builder_get_object(ui->priv->ui, "view_programming_menu"), "calcmode", GINT_TO_POINTER(PROGRAMMING));
+
+    ui->priv->display = ui_display_new(ui->priv->ui);
+    ui->priv->buttons = ui_buttons_new(ui->priv->display);
+    gtk_box_pack_end(GTK_BOX(GET_WIDGET(ui->priv->ui, "window_vbox")), ui_buttons_get_widget(ui->priv->buttons), TRUE, TRUE, 0);
+    ui->priv->preferences_dialog = ui_preferences_dialog_new(ui);
+}
diff --git a/src/ui.h b/src/ui.h
index ba9f2cc..73ec74e 100644
--- a/src/ui.h
+++ b/src/ui.h
@@ -20,31 +20,39 @@
 #ifndef UI_H
 #define UI_H
 
-#include <gtk/gtk.h>
-
-typedef struct GCalctoolUI GCalctoolUI;
-
-#include "calctool.h"
+#include <glib-object.h>
 #include "ui-display.h"
 #include "ui-buttons.h"
-#include "ui-preferences.h"
-
-// FIXME: Make opaque
-struct GCalctoolUI {
-    GtkBuilder *ui;
-    GtkWidget *main_window;
-    MathDisplay *display;
-    Buttons *buttons;
-    PreferencesDialog *preferences_dialog;
-};
-
-void ui_init(int *argc, char ***argv);
+
+G_BEGIN_DECLS
+
+#define UI(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), ui_get_type(), GCalctoolUI))
+
+typedef struct GCalctoolUIPrivate GCalctoolUIPrivate;
+
+typedef struct
+{
+    GObject             parent_instance;
+    GCalctoolUIPrivate *priv;
+} GCalctoolUI;
+
+typedef struct
+{
+    GObjectClass parent_class;
+} GCalctoolUIClass;
+
+void ui_gtk_init(int *argc, char ***argv);
+
+GType ui_get_type();
+
 GCalctoolUI *ui_new(void);
+
+MathDisplay *ui_get_display(GCalctoolUI *ui);
+
+MathButtons *ui_get_buttons(GCalctoolUI *ui);
+
 void ui_critical_error(GCalctoolUI *ui, const gchar *title, const gchar *contents);
+
 void ui_start(GCalctoolUI *ui);
-void ui_set_display(GCalctoolUI *ui, char *, int);
-void ui_set_bitfield(GCalctoolUI *ui, int enabled, guint64 bits);
-void ui_set_statusbar(GCalctoolUI *ui, const gchar *);
-gchar *ui_get_display(GCalctoolUI *ui);
 
 #endif /* UI_H */



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