Bug 81098

Summary: auto text resizing causes problems
Product: [Unmaintained] kweather-kde3 Reporter: John Belmonte <john>
Component: generalAssignee: geiseri
Status: RESOLVED FIXED    
Severity: normal    
Priority: NOR    
Version: unspecified   
Target Milestone: ---   
Platform: Debian testing   
OS: Linux   
Latest Commit: Version Fixed In:
Sentry Crash Report:

Description John Belmonte 2004-05-07 15:54:32 UTC
Version:            (using KDE KDE 3.2.2)
Installed from:    Debian testing/unstable Packages

kweather seems to automatically scale the display font to fit available width.  It also seems to automatically adjust the precision of numbers (e.g., "62.6" vs. "59").

The problem is that when the number precision changes, and hence the number of digits, the font size will adjust on the fly.  Since this affects the height of the font, when kweather is in a vertical panel it causes the entire panel layout to be recalculated.

This unwanted visual activity could easily be solved by fixing the precision of the numbers.
Comment 1 Martin Koller 2006-12-28 01:06:15 UTC
SVN commit 617101 by mkoller:

BUG: 81098
BUG: 73202
BUG: 134387

Fix layouting in all different display modes and kicker orientation modes
Always use a sane font size and limit overall size of applet


 M  +209 -68   dockwidget.cpp  
 M  +2 -2      weatherbutton.h  


--- branches/KDE/3.5/kdetoys/kweather/dockwidget.cpp #617100:617101
@@ -21,7 +21,7 @@
 #include "weatherservice_stub.h"
 
 #include <qtooltip.h>
-#include <qvbox.h>
+#include <qlayout.h>
 #include <qlabel.h>
 #include <qtimer.h>
 
@@ -32,11 +32,11 @@
 dockwidget::dockwidget(const QString &location, QWidget *parent,
         const char *name) : QWidget(parent,name), m_locationCode( location ), m_orientation( Horizontal )
 {
+    m_font = KGlobalSettings::generalFont();
     initDock();
     connect(m_button, SIGNAL( clicked() ), SIGNAL( buttonClicked() ));
 
     m_weatherService = new WeatherService_stub( "KWeatherService", "WeatherService" );
-    m_font = KGlobalSettings::generalFont();
 
     setBackgroundOrigin( AncestorOrigin );
 }
@@ -176,6 +176,18 @@
     m_lblWind->setMargin(0);
     m_lblPres->setMargin(0);
 
+    QBoxLayout *mainLayout = new QBoxLayout(this, QBoxLayout::TopToBottom);
+    mainLayout->setSpacing(0);
+    mainLayout->setMargin(0);
+    mainLayout->addWidget(m_button, 0, Qt::AlignCenter);
+
+    QBoxLayout *layout = new QBoxLayout(mainLayout, QBoxLayout::TopToBottom);
+    layout->setSpacing(0);
+    layout->setMargin(0);
+    layout->addWidget(m_lblTemp);
+    layout->addWidget(m_lblWind);
+    layout->addWidget(m_lblPres);
+
     updateFont();
 
     QTimer::singleShot( 0, this, SLOT( showWeather() ) );
@@ -187,86 +199,168 @@
     kdDebug(12004) << "Changing to size " << size << endl;
     resize(size);
 
-    int w = size.width();
-    int h = size.height();
-
-    if (m_orientation == Horizontal)
+    if ( m_orientation == Horizontal ) // Kicker in horizontal mode
     {
-        // in case we previously set this to hcenter previously
-        // and now change the layout
-        m_lblTemp->setAlignment(AlignVCenter);
+        int h = size.height();
 
-        // Kicker in horizontal mode
-        if( m_mode == ShowAll)
+        if ( m_mode == ShowAll )
         {
-            m_lblTemp->setGeometry(h+1, 0, w-h, h/3);
-            m_lblWind->setGeometry(h+1, h/3, w-h, h/3);
-            m_lblPres->setGeometry(h+1, 2*h/3, w-h, h/3);
-            m_button->setGeometry(0, 0, h, h);
+            if ( h <= 128 )  // left to right layout
+            {
+                static_cast<QBoxLayout*>(layout())->setDirection(QBoxLayout::LeftToRight);
+                m_lblTemp->setAlignment(Qt::AlignAuto | Qt::AlignVCenter);
+                m_lblWind->setAlignment(Qt::AlignAuto | Qt::AlignVCenter);
+                m_lblPres->setAlignment(Qt::AlignAuto | Qt::AlignVCenter);
+            }
+            else  // top to bottom
+            {
+                static_cast<QBoxLayout*>(layout())->setDirection(QBoxLayout::TopToBottom);
+                QFontMetrics fm(m_font);
+                h = 128 - (3 * fm.height());  // 3 lines of text below the button
+                m_lblTemp->setAlignment(Qt::AlignCenter);
+                m_lblWind->setAlignment(Qt::AlignCenter);
+                m_lblPres->setAlignment(Qt::AlignCenter);
+            }
+            m_button->setFixedSize(h, h);
         }
-        else if ( m_mode == ShowTempOnly)
+        else if ( m_mode == ShowTempOnly )
         {
-            if (h > 32)
+            if ( h <= 32 )  // left to right
             {
-                m_lblTemp->setAlignment(AlignVCenter | AlignHCenter);
-                m_lblTemp->setGeometry(1, h - h/5, w - 2, h/5);
-                m_button->setGeometry(0, 0, 4*h/5, 4*h/5);
+                static_cast<QBoxLayout*>(layout())->setDirection(QBoxLayout::LeftToRight);
+                m_lblTemp->setAlignment(Qt::AlignAuto | Qt::AlignVCenter);
             }
-            else
+            else  // top to bottom
             {
-                m_lblTemp->setGeometry(h+1, 0, w-h, h);
-                m_button->setGeometry(0, 0, h, h );
+                static_cast<QBoxLayout*>(layout())->setDirection(QBoxLayout::TopToBottom);
+                QFontMetrics fm(m_font);
+                h = QMIN(128, h) - fm.height();
+                m_lblTemp->setAlignment(Qt::AlignCenter);
             }
+            m_button->setFixedSize(h, h);
         }
         else
         {
-            m_button->setGeometry(0, 0, h, h );
+            h = QMIN(h, 128);
+            m_button->setFixedSize(h, h);
         }
     }
-    else
+    else // Kicker in vertical mode
     {
-        // Kicker in vertical mode
-        if( m_mode == ShowAll)
+        int w = size.width();
+        int h = size.height();
+
+        if ( m_mode == ShowAll )
         {
-            m_lblTemp->setGeometry(0, w, w, w/3);
-            m_lblWind->setGeometry(0, 4*w/3, w, w/3);
-            m_lblPres->setGeometry(0, 5*w/3, w, w/3);
+            if ( w <= 128 )  // top to bottom
+            {
+                static_cast<QBoxLayout*>(layout())->setDirection(QBoxLayout::TopToBottom);
+                m_lblTemp->setAlignment(Qt::AlignCenter);
+                m_lblWind->setAlignment(Qt::AlignCenter);
+                m_lblPres->setAlignment(Qt::AlignCenter);
+
+                QFontMetrics fm(m_font);
+                h = h - (3 * fm.height());  // 3 lines of text below the button
+                h = QMIN(w, h);
+            }
+            else  // left to right layout
+            {
+                static_cast<QBoxLayout*>(layout())->setDirection(QBoxLayout::LeftToRight);
+                m_lblTemp->setAlignment(Qt::AlignAuto | Qt::AlignVCenter);
+                m_lblWind->setAlignment(Qt::AlignAuto | Qt::AlignVCenter);
+                m_lblPres->setAlignment(Qt::AlignAuto | Qt::AlignVCenter);
+            }
+            m_button->setFixedSize(h, h);
         }
-        else if ( m_mode == ShowTempOnly)
+        else if ( m_mode == ShowTempOnly )
         {
-            m_lblTemp->setGeometry(1, w, w, h-(w+1) );
+            if ( w <= 128 )  // top to bottom
+            {
+                static_cast<QBoxLayout*>(layout())->setDirection(QBoxLayout::TopToBottom);
+                m_lblTemp->setAlignment(Qt::AlignCenter);
+
+                h = w;
+            }
+            else  // left to right layout
+            {
+                static_cast<QBoxLayout*>(layout())->setDirection(QBoxLayout::LeftToRight);
+                m_lblTemp->setAlignment(Qt::AlignAuto | Qt::AlignVCenter);
+
+                h = static_cast<int>(w * 0.33);
+            }
+            m_button->setFixedSize(h, h);
         }
-        m_button->setGeometry(0, 0, w, w );
+        else
+        {
+            w = QMIN(w, 128);
+            m_button->setFixedSize(w, w);
+        }
     }
-    updateFont();
 }
 
 int dockwidget::widthForHeight(int h)
 {
-    int w=h;
-    QFontMetrics fm(m_font);
+    int w;
+    QFontInfo fi(KGlobalSettings::generalFont());
 
-    if( m_mode == ShowAll)
+    if ( m_mode == ShowAll )
     {
-        m_font.setPixelSize( h/3-2 );
-        w = h + QMAX(fm.width(m_lblWind->text()),
-        fm.width(m_lblPres->text())) + 1;
+        if ( h <= 128 )  // left to right layout
+        {
+            int pixelSize = h/3 - 3;
+            pixelSize = QMIN(pixelSize, fi.pixelSize());  // don't make it too large
+            m_font.setPixelSize(pixelSize);
+            QFontMetrics fm(m_font);
+            w = h + QMAX(fm.width(m_lblWind->text()), fm.width(m_lblPres->text())) + 1;
+        }
+        else  // top to bottom
+        {
+            if ( fi.pixelSize() * 3 <= (h/2) )  // half icon, half text
+            {
+                m_font = KGlobalSettings::generalFont();
+            }
+            else
+            {
+                m_font.setPixelSize(h/2/3);
+            }
+            QFontMetrics fm(m_font);
+            // size of icon
+            h = 128 - (3 * fm.height());  // 3 lines of text below the button
+            w = QMAX(fm.width(m_lblWind->text()), fm.width(m_lblPres->text())) + 1;
+            w = QMAX(h, w);  // at least width of square icon
+        }
     }
-    else if ( m_mode == ShowTempOnly)
+    else if ( m_mode == ShowTempOnly )
     {
-        QFontInfo fi( KGlobalSettings::generalFont() );
-        int pixelSize = QMIN( h, fi.pixelSize() );
-        m_font.setPixelSize( pixelSize );
-
-        if (h > 32)
+        if ( h <= 32 )  // left to right layout
         {
-            w = 4*h/5;
+            int pixelSize = h - 3;
+            pixelSize = QMIN(pixelSize, fi.pixelSize());  // don't make it too large
+            m_font.setPixelSize(pixelSize);
+            QFontMetrics fm(m_font);
+            w = h + fm.width(m_lblTemp->text()) + 1;
         }
-        else
+        else  // top to bottom
         {
-            w = h + fm.width(m_lblTemp->text()) + 1;
+            if ( fi.pixelSize() <= (h/2) )  // half icon, half text
+            {
+                m_font = KGlobalSettings::generalFont();
+            }
+            else
+            {
+                m_font.setPixelSize(h/2);
+            }
+            QFontMetrics fm(m_font);
+            // size of icon
+            h = QMIN(128, h) - fm.height();
+            w = fm.width(m_lblTemp->text()) + 1;
+            w = QMAX(h, w);  // at least width of square icon
         }
     }
+    else
+    {
+        w = QMIN(128, h);  // don't make it too large
+    }
 
     updateFont();
     return w;
@@ -275,33 +369,80 @@
 int dockwidget::heightForWidth( int w )
 {
     int h;
-    // Adjust the height of the font to compensate for width
-    int startSize = w;
-    int width = w + 1;
 
     if ( m_mode == ShowAll )
     {
-       while( (width > w)  && (startSize > 0))
-       {
-           m_font.setPixelSize( --startSize );
-           QFontMetrics fm(m_font);
-           width = QMAX(fm.width(m_lblWind->text()),
-                        fm.width(m_lblPres->text()));
-       }
-       h = ( w * 2 );
+        QFontMetrics fmg(KGlobalSettings::generalFont());
+        int maxWidth = fmg.width("888 km/h NNWW");  // a good approximation
+
+        if ( w <= 128 )  // top to bottom
+        {
+            if ( maxWidth <= w )  // enough space to use global font
+            {
+                m_font = KGlobalSettings::generalFont();
+            }
+            else  // we have to reduce the fontsize
+            {
+                m_font.setPixelSize(static_cast<int>(fmg.height() * double(w) / maxWidth));
+            }
+
+            QFontMetrics fm(m_font);
+            h = w + (3 * fm.height());  // 3 lines of text below the button
+        }
+        else
+        {
+            if ( w >= (maxWidth * 1.5) )  // half of text width shall be icon
+            {
+                m_font = KGlobalSettings::generalFont();
+            }
+            else
+            {
+                m_font.setPixelSize(static_cast<int>(fmg.height() * (w*0.66) / maxWidth));
+            }
+
+            QFontMetrics fm(m_font);
+            h = 3 * fm.height();  // 3 lines of text
+
+        }
     }
     else if ( m_mode == ShowTempOnly )
     {
-       while( (width > w)  && (startSize > 0))
-       {
-           m_font.setPixelSize( --startSize );
-           QFontMetrics fm(m_font);
-           width = fm.width(m_lblTemp->text());
-       }
-       h = w + startSize + 2;
+        QFontMetrics fmg(KGlobalSettings::generalFont());
+        int maxWidth = fmg.width("888.88 CC");  // a good approximation
+
+        if ( w <= 128 )  // top to bottom
+        {
+            if ( maxWidth <= w )  // enough space to use global font
+            {
+                m_font = KGlobalSettings::generalFont();
+            }
+            else  // we have to reduce the fontsize
+            {
+                m_font.setPixelSize(static_cast<int>(fmg.height() * double(w) / maxWidth));
+            }
+
+            QFontMetrics fm(m_font);
+            h = w + fm.height();  // text below the button
+        }
+        else
+        {
+            if ( w >= (maxWidth * 1.5) )  // half of text width shall be icon
+            {
+                m_font = KGlobalSettings::generalFont();
+            }
+            else
+            {
+                m_font.setPixelSize(static_cast<int>(fmg.height() * (w*0.66) / maxWidth));
+            }
+
+            QFontMetrics fm(m_font);
+            h = QMAX(fm.height(), static_cast<int>(w * 0.33));
+        }
     }
     else
-        h = w;
+    {
+        h = QMIN(128, w);  // don't make it too large
+    }
 
     updateFont();
     return h;
--- branches/KDE/3.5/kdetoys/kweather/weatherbutton.h #617100:617101
@@ -34,8 +34,8 @@
   protected:
     void drawButton( QPainter *p );
     void drawButtonLabel( QPainter *p );
-    QSize margin() const { return QSize( 5, 5 ); }
-    QSize pixmapSize() const { return size() - margin(); }
+    QSize margin() const { return QSize( 3, 3 ); }
+    QSize pixmapSize() const { return size() - margin()*2; }
     QPoint pixmapOrigin() const;
     void generateIcons();