[Aptitude-svn-commit] r3501 - in branches/aptitude-0.3/aptitude: . src/vscreen

Daniel Burrows dburrows@costa.debian.org
Tue, 28 Jun 2005 14:00:00 +0000


Author: dburrows
Date: Tue Jun 28 13:59:58 2005
New Revision: 3501

Modified:
   branches/aptitude-0.3/aptitude/ChangeLog
   branches/aptitude-0.3/aptitude/src/vscreen/vs_editline.cc
   branches/aptitude-0.3/aptitude/src/vscreen/vs_editline.h
Log:
Honor wide character widths in the line editor..maybe.

Modified: branches/aptitude-0.3/aptitude/ChangeLog
==============================================================================
--- branches/aptitude-0.3/aptitude/ChangeLog	(original)
+++ branches/aptitude-0.3/aptitude/ChangeLog	Tue Jun 28 13:59:58 2005
@@ -1,5 +1,10 @@
 2005-06-28  Daniel Burrows  <dburrows@debian.org>
 
+	* src/vscreen/vs_editline.cc, src/vscreen/vs_editline.h:
+
+	  Fix the line editor widget to support wide characters properly
+	  (it now honors wide character widths).
+
 	* src/vscreen/curses++.h:
 
 	  #undef the *add_wch functions for future use.

Modified: branches/aptitude-0.3/aptitude/src/vscreen/vs_editline.cc
==============================================================================
--- branches/aptitude-0.3/aptitude/src/vscreen/vs_editline.cc	(original)
+++ branches/aptitude-0.3/aptitude/src/vscreen/vs_editline.cc	Tue Jun 28 13:59:58 2005
@@ -69,32 +69,68 @@
   do_layout.connect(sigc::mem_fun(*this, &vs_editline::normalize_cursor));
 }
 
+wchar_t vs_editline::get_char(size_t loc)
+{
+  if(loc>prompt.size())
+    return text[loc-prompt.size()];
+  else
+    return prompt[loc];
+}
+
 void vs_editline::normalize_cursor()
 {
   // Dodge the signedness bullet, hopefully
   if(get_width()<0)
     return;
 
-  wstring::size_type w=(wstring::size_type) get_width();
+  int w=get_width();
+
+  int promptwidth=wcswidth(prompt.c_str(), prompt.size());
+  int textwidth=wcswidth(text.c_str(), text.size());
+
+  int cursorx=0;
+  if(curloc+prompt.size()>startloc)
+    for(size_t i=startloc; i<curloc+prompt.size(); ++i)
+      cursorx+=wcwidth(get_char(i));
+  else
+    for(size_t i=curloc+prompt.size(); i<startloc; ++i)
+      cursorx-=wcwidth(get_char(i));
 
-  if(prompt.size()+text.size()+1<w)
+  if(promptwidth+textwidth+1<w)
     startloc=0;
   else if(w>2)
     {
-      // The extra 2 is to avoid "I'm typing and I can't see what comes next"
-      // problems.
-      if(prompt.size()+curloc-startloc>=w-2)
-	startloc=prompt.size()+curloc-w+2;
+      // Need to move the screen start to this far behind the cursor
+      // loc.
+      int decamt=0;
 
-      if(prompt.size()+curloc>=2 && prompt.size()+curloc<startloc+2)
-	startloc=prompt.size()+curloc-2;
+      if(cursorx>=w-2)
+	decamt=2;
+      else if(cursorx<2)
+	decamt=w-2;
+
+      // Do it by moving back this many chars
+      size_t chars=0;
+
+      while(decamt>0 && chars<curloc+prompt.size())
+	{
+	  ++chars;
+	  decamt-=wcwidth(get_char(prompt.size()+curloc-chars));
+	}
+
+      if(decamt<0 && chars>1)
+	--chars;
+
+      startloc=curloc-chars;
     }
   else
     {
-      if(prompt.size()+curloc-startloc>=w)
+      // if width=1, use a primitive approach (we're screwed anyway in
+      // this case)
+      if(cursorx>=w)
 	startloc=prompt.size()+curloc-w+1;
 
-      if(prompt.size()+curloc<startloc)
+      if(cursorx<0)
 	startloc=prompt.size()+curloc;
     }
 
@@ -109,7 +145,14 @@
 point vs_editline::get_cursorloc()
 {
   if(getmaxx()>0)
-    return point(curloc+prompt.size()-startloc, 0);
+    {
+      int x=0;
+
+      for(size_t loc=startloc; loc<curloc+prompt.size(); ++loc)
+	x+=wcwidth(get_char(loc));
+
+      return point(x, 0);
+    }
   else
     return point(0,0);
 }
@@ -302,14 +345,38 @@
 {
   int width=getmaxx();
 
-  wstring todisp(prompt+text, startloc, width);
+  int used=0;
+  size_t chars=0;
+
+  while(used<width && startloc+chars<prompt.size()+text.size())
+    {
+      wchar_t ch=get_char(startloc+chars);
+      used+=wcwidth(ch);
+      ++chars;
+    }
+
+  if(used>width && chars>1)
+    --chars;
 
-  mvaddstr(0, 0, todisp);
+  wstring todisp=prompt+text;
+  mvaddstr(0, 0, wstring(todisp, startloc, chars));
 }
 
 void vs_editline::dispatch_mouse(short id, int x, int y, int z, mmask_t bstate)
 {
-  wstring::size_type mouseloc=x+startloc;
+  size_t mouseloc=startloc; // The character at which the mouse press occured
+  while(mouseloc<prompt.size()+text.size() && x>0)
+    {
+      int curwidth=wcwidth(get_char(mouseloc));
+
+      if(curwidth>x)
+	break;
+      else
+	{
+	  ++mouseloc;
+	  x-=curwidth;
+	}
+    }
 
   if(mouseloc>=prompt.size())
     {
@@ -317,7 +384,7 @@
 
       if(mouseloc<=text.size())
 	curloc=mouseloc;
-      else if(mouseloc>text.size())
+      else
 	curloc=text.size();
     }
   else
@@ -377,7 +444,7 @@
 int vs_editline::width_request()
 {
   if(desired_size == -1)
-    return prompt.size()+text.size()+1;
+    return wcswidth(prompt.c_str(), prompt.size())+wcswidth(text.c_str(), text.size());
   else
     return desired_size;
 }

Modified: branches/aptitude-0.3/aptitude/src/vscreen/vs_editline.h
==============================================================================
--- branches/aptitude-0.3/aptitude/src/vscreen/vs_editline.h	(original)
+++ branches/aptitude-0.3/aptitude/src/vscreen/vs_editline.h	Tue Jun 28 13:59:58 2005
@@ -38,6 +38,11 @@
   bool using_history;
 
   void normalize_cursor();
+
+  /** \return the nth char of the visual representation (from either
+   *  the prompt or the string being edited)
+   */
+  wchar_t get_char(size_t n);
 protected:
   bool handle_key(const key &k);
 public: