Subject: [3f456a5bb9]: Patches for listbox right justify

From: "jan.nijtmans" <[email-masked]>
Date: Tue, 11 Feb 2014 14:56:03 +0000

---
 generic/tkListbox.c      | 108 +++++++++++++++++++++++++++++++++++++++++++++--
 library/demos/states.tcl |   9 ++++
 macosx/tkMacOSXDefault.h |   1 +
 unix/tkUnixDefault.h     |   1 +
 win/tkWinDefault.h       |   1 +
 5 files changed, 116 insertions(+), 4 deletions(-)

diff --git a/generic/tkListbox.c b/generic/tkListbox.c
index 437973a..22bb354 100644
--- a/generic/tkListbox.c
+++ b/generic/tkListbox.c
@@ -165,6 +165,8 @@ typedef struct {
     Pixmap gray;		/* Pixmap for displaying disabled text. */
     int flags;			/* Various flag bits: see below for
 				 * definitions. */
+    Tk_Justify justify;         /* Justification */
+    int oldMaxOffset;           /* Used in scrolling for right/center justification */
 } Listbox;
 
 /*
@@ -308,6 +310,8 @@ static const Tk_OptionSpec optionSpecs[] = {
     {TK_OPTION_STRING, "-listvariable", "listVariable", "Variable",
 	 DEF_LISTBOX_LIST_VARIABLE, -1, Tk_Offset(Listbox, listVarName),
 	 TK_OPTION_NULL_OK, 0, 0},
+    {TK_OPTION_JUSTIFY, "-justify", "justify", "Justify",
+	DEF_LISTBOX_JUSTIFY, -1, Tk_Offset(Listbox, justify), 0, 0, 0},
     {TK_OPTION_END, NULL, NULL, NULL, NULL, 0, -1, 0, 0, 0}
 };
 
@@ -435,6 +439,7 @@ static char *		ListboxListVarProc(ClientData clientData,
 			    const char *name2, int flags);
 static void		MigrateHashEntries(Tcl_HashTable *table,
 			    int first, int last, int offset);
+static int      GetMaxOffset(Listbox *listPtr);
 
 /*
  * The structure below defines button class behavior by means of procedures
@@ -545,6 +550,8 @@ Tk_ListboxObjCmd(
     listPtr->cursor		 = None;
     listPtr->state		 = STATE_NORMAL;
     listPtr->gray		 = None;
+    listPtr->justify             = TK_JUSTIFY_LEFT;
+    listPtr->oldMaxOffset        = 0;
 
     /*
      * Keep a hold of the associated tkwin until we destroy the listbox,
@@ -571,6 +578,13 @@ Tk_ListboxObjCmd(
 	return TCL_ERROR;
     }
 
+    if (listPtr->justify == TK_JUSTIFY_RIGHT) {
+        listPtr->xOffset = GetMaxOffset(listPtr);
+    } else if (listPtr->justify == TK_JUSTIFY_CENTER) {
+        listPtr->xOffset = GetMaxOffset(listPtr) / 2;
+        listPtr->xOffset -= listPtr->xOffset % listPtr->xScrollUnit;
+    }
+
     Tcl_SetObjResult(interp, TkNewWindowObj(listPtr->tkwin));
     return TCL_OK;
 }
@@ -1110,7 +1124,7 @@ ListboxBboxSubCmd(
 	Tk_GetFontMetrics(listPtr->tkfont, &fm);
 	pixelWidth = Tk_TextWidth(listPtr->tkfont, stringRep, stringLen);
 
-	x = listPtr->inset + listPtr->selBorderWidth - listPtr->xOffset;
+    x = listPtr->inset + listPtr->selBorderWidth - listPtr->xOffset;
 	y = ((index - listPtr->topIndex)*listPtr->lineHeight)
 		+ listPtr->inset + listPtr->selBorderWidth;
 	results[0] = Tcl_NewIntObj(x);
@@ -1837,6 +1851,7 @@ DisplayListbox(
 				 * or right edge of the listbox is
 				 * off-screen. */
     Pixmap pixmap;
+    int totalLength, height;
 
     listPtr->flags &= ~REDRAW_PENDING;
     if (listPtr->flags & LISTBOX_DELETED) {
@@ -2055,12 +2070,22 @@ DisplayListbox(
 	/*
 	 * Draw the actual text of this item.
 	 */
+    Tcl_ListObjIndex(listPtr->interp, listPtr->listObj, i, &curElement);
+    stringRep = Tcl_GetStringFromObj(curElement, &stringLen);
+    Tk_ComputeTextLayout(listPtr->tkfont,
+            stringRep, stringLen, 0,
+            listPtr->justify, TK_IGNORE_NEWLINES, &totalLength, &height);
 
 	Tk_GetFontMetrics(listPtr->tkfont, &fm);
 	y += fm.ascent + listPtr->selBorderWidth;
-	x = listPtr->inset + listPtr->selBorderWidth - listPtr->xOffset;
-	Tcl_ListObjIndex(listPtr->interp, listPtr->listObj, i, &curElement);
-	stringRep = Tcl_GetStringFromObj(curElement, &stringLen);
+
+    if (listPtr->justify == TK_JUSTIFY_LEFT) {
+        x = listPtr->inset + listPtr->selBorderWidth - listPtr->xOffset;
+    } else if (listPtr->justify == TK_JUSTIFY_RIGHT) {
+        x = width - totalLength - listPtr->inset - listPtr->selBorderWidth - listPtr->xOffset + GetMaxOffset(listPtr) - 1;
+    } else {
+        x = (width + GetMaxOffset(listPtr))/2 - totalLength/2 - listPtr->xOffset;
+    }
 	Tk_DrawChars(listPtr->display, pixmap, gc, listPtr->tkfont,
 		stringRep, stringLen, x, y);
 
@@ -2581,6 +2606,7 @@ ListboxEventProc(
     ClientData clientData,	/* Information about window. */
     XEvent *eventPtr)		/* Information about event. */
 {
+    int tmpOffset, tmpOffset2, maxOffset;
     Listbox *listPtr = clientData;
 
     if (eventPtr->type == Expose) {
@@ -2612,6 +2638,53 @@ ListboxEventProc(
 	}
 	listPtr->flags |= UPDATE_V_SCROLLBAR|UPDATE_H_SCROLLBAR;
 	ChangeListboxView(listPtr, listPtr->topIndex);
+        if (listPtr->justify == TK_JUSTIFY_RIGHT) {
+            maxOffset = GetMaxOffset(listPtr);
+            if (maxOffset != listPtr->oldMaxOffset && listPtr->oldMaxOffset > 0) {  // window has shrunk
+                if (maxOffset > listPtr->oldMaxOffset) {
+                    tmpOffset = maxOffset - listPtr->oldMaxOffset;
+                } else {
+                    tmpOffset = listPtr->oldMaxOffset - maxOffset;
+                }
+                tmpOffset -= tmpOffset % listPtr->xScrollUnit;
+                if ((tmpOffset + listPtr->xOffset) > maxOffset) {
+                    tmpOffset = maxOffset - listPtr->xOffset;
+                }
+                if (tmpOffset < 0) {
+                    tmpOffset = 0;
+                }
+                listPtr->xOffset += tmpOffset;
+            } else {
+                listPtr->xOffset = maxOffset;
+            }
+            listPtr->oldMaxOffset = maxOffset;
+        } else if (listPtr->justify == TK_JUSTIFY_CENTER) {
+            maxOffset = GetMaxOffset(listPtr);
+            if (maxOffset != listPtr->oldMaxOffset && listPtr->oldMaxOffset > 0) {  // window has shrunk
+                tmpOffset2 = maxOffset / 2;
+                if (maxOffset > listPtr->oldMaxOffset) {
+                    tmpOffset = maxOffset/2 - listPtr->oldMaxOffset/2;
+                } else {
+                    tmpOffset = listPtr->oldMaxOffset/2 - maxOffset/2;
+                }
+                tmpOffset -= tmpOffset % listPtr->xScrollUnit;
+                if ((tmpOffset + listPtr->xOffset) > maxOffset) {
+                    tmpOffset = maxOffset - listPtr->xOffset;
+                }
+                if (tmpOffset < 0) {
+                    tmpOffset = 0;
+                }
+                if (listPtr->xOffset < tmpOffset2) {
+                    listPtr->xOffset += tmpOffset;
+                } else {
+                    listPtr->xOffset -= tmpOffset;
+                }
+            } else {
+                listPtr->xOffset = maxOffset/2;
+                listPtr->xOffset -= listPtr->xOffset % listPtr->xScrollUnit;
+            }
+            listPtr->oldMaxOffset = maxOffset;
+        }
 	ChangeListboxOffset(listPtr, listPtr->xOffset);
 
 	/*
@@ -3549,6 +3622,33 @@ MigrateHashEntries(
 }
 
 /*
+ *----------------------------------------------------------------------
+ *
+ * GetMaxOffset --
+ *
+ * Passing in a listbox pointer, returns the maximum offset for the box
+ *
+ * Results:
+ *       Listbox's maxOffset
+ *
+ * Side effects:
+ *       None
+ *
+ *----------------------------------------------------------------------
+*/
+static int GetMaxOffset(register Listbox *listPtr)
+{
+    int maxOffset;
+
+    maxOffset = listPtr->maxWidth - (Tk_Width(listPtr->tkwin) - 2*listPtr->inset - 2*listPtr->selBorderWidth) + listPtr->xScrollUnit - 1;
+    if (maxOffset < 0) {
+        maxOffset = 0;
+    }
+    maxOffset -= maxOffset % listPtr->xScrollUnit;
+
+    return maxOffset;
+}
+/*
  * Local Variables:
  * mode: c
  * c-basic-offset: 4
diff --git a/library/demos/states.tcl b/library/demos/states.tcl
index e76540d..09d2718 100644
--- a/library/demos/states.tcl
+++ b/library/demos/states.tcl
@@ -19,6 +19,15 @@ positionWindow $w
 label $w.msg -font $font -wraplength 4i -justify left -text "A listbox containing the 50 states is displayed below, along with a scrollbar.  You can scan the list either using the scrollbar or by scanning.  To scan, press button 2 in the widget and drag up or down."
 pack $w.msg -side top
 
+foreach c {Left Center Right} {
+    set lower [string tolower $c]
+    radiobutton $w.$lower -text $c -variable just \
+	    -relief flat -value $lower -anchor w \
+	    -command "$w.frame.list configure -justify \$just" \
+	-tristatevalue "multi"
+    pack $w.$lower -side left -pady 2 -fill x
+}
+
 ## See Code / Dismiss buttons
 set btns [addSeeDismiss $w.buttons $w]
 pack $btns -side bottom -fill x
diff --git a/macosx/tkMacOSXDefault.h b/macosx/tkMacOSXDefault.h
index 8565cdb..903f5f9 100644
--- a/macosx/tkMacOSXDefault.h
+++ b/macosx/tkMacOSXDefault.h
@@ -262,6 +262,7 @@
 #define DEF_LISTBOX_RELIEF		"solid"
 #define DEF_LISTBOX_SCROLL_COMMAND	""
 #define DEF_LISTBOX_LIST_VARIABLE	""
+#define DEF_LISTBOX_JUSTIFY		"left"
 #define DEF_LISTBOX_SELECT_COLOR	SELECT_BG
 #define DEF_LISTBOX_SELECT_MONO		BLACK
 #define DEF_LISTBOX_SELECT_BD		"0"
diff --git a/unix/tkUnixDefault.h b/unix/tkUnixDefault.h
index b922278..8768a2e 100644
--- a/unix/tkUnixDefault.h
+++ b/unix/tkUnixDefault.h
@@ -224,6 +224,7 @@
 #define DEF_LISTBOX_RELIEF		"sunken"
 #define DEF_LISTBOX_SCROLL_COMMAND	""
 #define DEF_LISTBOX_LIST_VARIABLE	""
+#define DEF_LISTBOX_JUSTIFY		"left"
 #define DEF_LISTBOX_SELECT_COLOR	SELECT_BG
 #define DEF_LISTBOX_SELECT_MONO		BLACK
 #define DEF_LISTBOX_SELECT_BD		"0"
diff --git a/win/tkWinDefault.h b/win/tkWinDefault.h
index 11c3e6d..6d1a0c9 100644
--- a/win/tkWinDefault.h
+++ b/win/tkWinDefault.h
@@ -227,6 +227,7 @@
 #define DEF_LISTBOX_RELIEF		"sunken"
 #define DEF_LISTBOX_SCROLL_COMMAND	""
 #define DEF_LISTBOX_LIST_VARIABLE	""
+#define DEF_LISTBOX_JUSTIFY		"left"
 #define DEF_LISTBOX_SELECT_COLOR	SELECT_BG
 #define DEF_LISTBOX_SELECT_MONO		BLACK
 #define DEF_LISTBOX_SELECT_BD		"0"
-- 
cgit v0.12