24 define LEFT_MARGIN = 10;
25 define RIGHT_MARGIN = 10;
26 define TOP_MARGIN = 10;
27 define BOTTOM_MARGIN = 10;
29 enum VerticalAlignment { middle, top, bottom };
31 enum HorizontalAlignment { none, left, middle, right };
33 define CELL_SPACING = 0;
35 class RenderFlags { bool lineW:1,width:1,render:1,minW:1; };
37 enum InputType { text, submit, checkbox, radio, hidden };
39 class ImageEntry : struct
41 ImageEntry prev, next;
54 bitmapPtrs.Free(null);
58 class FontEntry : struct
72 class RequestLink : OldLink
77 class AlignedObject : struct
79 AlignedObject prev, next;
85 static HTMLView browserWindow;
87 class ObjectThread : Thread
89 bool objectThreadDead;
90 bool objectThreadTerminate;
91 Semaphore objectThreadSemaphore {};
95 objectThreadDead = false;
96 for(;!objectThreadTerminate;)
98 if(objectRequests.first)
102 //((GuiApplication)__thisModule).Lock();
104 for(;!objectThreadTerminate;)
109 char path[MAX_LOCATION], referer[MAX_LOCATION];
112 for(request = objectRequests.first; request && request.processed; request = (RequestLink)request.next);
115 request.processed = true;
116 objectsMutex.Release();
119 entry = request.data;
121 strcpy(path, entry.src);
122 //strcpy(referer, browserWindow.location ? browserWindow.location : "");
123 strcpy(referer, entry.referer); //browserWindow.location ? browserWindow.location : "");
125 //((GuiApplication)__thisModule).Unlock();
127 if(path && strstr(path, "http://") == path)
129 HTTPFile httpFile {};
132 //printf("Opening URL\n");
134 //((GuiApplication)__thisModule).PauseNetworkEvents();
135 if(httpFile.OpenURL(path, referer, null))
137 char extension[MAX_EXTENSION];
138 entry.bitmap = Bitmap { alphaBlend = true };
139 //printf("Loading File\n");
140 entry.bitmap.LoadFromFile(file, GetExtension(path, extension), null);
144 entry.missing = true;
145 //((GuiApplication)__thisModule).ResumeNetworkEvents();
149 file = FileOpen(path, read);
151 entry.missing = true;
154 char extension[MAX_EXTENSION];
155 entry.bitmap = Bitmap { alphaBlend = true };
156 entry.bitmap.LoadFromFile(file, GetExtension(path, extension), null);
163 objectRequests.Remove(request);
165 objectsMutex.Release();
167 ((GuiApplication)__thisModule).Lock();
168 if(!objectThreadTerminate)
171 Window rootWindow = browserWindow.rootWindow;
173 display = rootWindow.parent.display;
175 display = rootWindow.display;
180 entry.bitmap.MakeDD(browserWindow.displaySystem);
181 if(entry.bitmap && entry.bitmap.alphaBlend)
183 entry.bitmap.Convert(null, pixelFormat888, null);
184 // entry.bitmap.displaySystem = displaySystem;
187 for(bitmapPtr = entry.bitmapPtrs.first; bitmapPtr; bitmapPtr = bitmapPtr.next)
189 *((Bitmap*) bitmapPtr.data) = entry.bitmap;
191 browserWindow.ComputeMinSizes();
192 browserWindow.ComputeSizes();
193 browserWindow.PositionForms();
194 browserWindow.Update(null);
196 // ((GuiApplication)__thisModule).UpdateDisplay();
200 // TRIED MOVING THIS HERE BECAUSE OF printf("bug") in GuiApplication if(window.display.current)
201 ((GuiApplication)__thisModule).UpdateDisplay();
203 ((GuiApplication)__thisModule).Unlock();
205 //((GuiApplication)__thisModule).Unlock();
209 //printf("Waiting for Object Thread Semaphore\n");
210 objectThreadSemaphore.Wait();
213 objectThreadDead = true;
218 static ObjectThread objectThread1 { };
219 static ObjectThread objectThread2 { };
220 static ObjectThread objectThread3 { };
221 static ObjectThread objectThread4 { };
222 static Mutex objectsMutex {};
223 static OldList imageCache;
224 /*static */OldList fontCache;
226 static OldList objectRequests;
228 static void WriteBlock(File f, Block block)
230 static int indent = 0;
234 for(c = 0; c<indent; c++)
240 f.Printf("Text: %s\n", block.text);
243 f.Printf("Image: %d %d %s\n", block.w, block.h, block.src);
252 f.Printf("Anchor: %s\n", block.src);
255 f.Printf("Font: %s, %d\n", block.face, block.size);
258 f.Printf("Center\n");
271 for(child = block.subBlocks.first; child; child = child.next)
274 WriteBlock(f, child);
279 static void ComputeImageSize(Block block)
283 if(block.type == IMAGE)
286 block.w = block.width;
288 block.w = block.bitmap ? block.bitmap.width : 0;
291 block.h = block.height;
293 block.h = block.bitmap ? block.bitmap.height : 0;
295 for(child = block.subBlocks.first; child; child = child.next)
296 ComputeImageSize(child);
304 bool OnLoadGraphics()
308 for(entry = imageCache.first; entry; entry = entry.next)
310 entry.bitmap.MakeDD(displaySystem);
311 if(entry.bitmap && entry.bitmap.alphaBlend)
313 entry.bitmap.Convert(null, pixelFormat888, null);
314 // entry.bitmap.displaySystem = displaySystem;
317 for(fEntry = fontCache.first; fEntry; fEntry = fEntry.next)
320 fEntry.font = displaySystem.LoadFont(fEntry.face, fEntry.size, fEntry.attribs);
325 void OnUnloadGraphics()
329 while((entry = imageCache.first))
331 imageCache.Remove(entry);
334 while((fontEntry = fontCache.first))
336 displaySystem.UnloadFont(fontEntry.font);
337 fontCache.Remove(fontEntry);
343 class HTMLView : Window
346 BitmapResource missing { "<:ecere>emblems/unreadable.png", window = sharedWindow /*this*/ };
348 Block overLink, clickedLink;
352 void ComputeMinSizes()
356 ComputeImageSize(html.body);
358 // Pre compute some stuff
360 Block block = html.body;
364 Surface surface = display.GetSurface(0,0,null);
367 surface.TextFont(html.defaultFont.font.font);
374 ComputeLine(surface, block, textPos, &nextBlock, &nextTextPos, ¢ered, &w, MAXINT, 0, RenderFlags { minW = true }, 0, null, null, null, true, 0, LEFT_MARGIN);
376 textPos = nextTextPos;
384 void Clear(Block block)
388 if(block.type != TABLE && block.type != IMAGE)
393 if(block.type == TABLE)
395 block.columns.Free(null);
397 if(block.type != IMAGE)
403 block.rowSpan = block.span = 1;
406 for(b = block.subBlocks.first; b; b = b.next)
413 int width = clientSize.w;
414 int height = clientSize.h;
415 Block block = html.body;
416 int totalWidth = 0, totalHeight = 0;
420 Surface surface = display.GetSurface(0,0,null);
423 width = parent.clientSize.w;
425 height = parent.clientSize.h;
429 int maxH = height - BOTTOM_MARGIN;
432 if(html.defaultFont.font)
433 surface.TextFont(html.defaultFont.font.font);
439 int maxW = width - (LEFT_MARGIN + RIGHT_MARGIN);
442 newH = ComputeLine(surface, block, textPos, &nextBlock, &nextTextPos, ¢ered, &w, maxW, maxH - y, RenderFlags { lineW = true, width = true }, 0, null, null, &changeLine, true, y, LEFT_MARGIN);
449 textPos = nextTextPos;
451 totalWidth = Max(totalWidth, w);
455 totalHeight = y + BOTTOM_MARGIN;
456 totalWidth += LEFT_MARGIN + RIGHT_MARGIN;
458 SetScrollArea(totalWidth, totalHeight, false);
459 SetScrollArea(totalWidth, totalHeight, false);
462 if(!initSize.w || !initSize.h)
463 clientSize = Size {!initSize.w ? totalWidth : clientSize.w, !initSize.h ? totalHeight : clientSize.h };
466 void CreateForms(Block block)
470 if(block.type == INPUT)
472 switch(block.inputType)
475 block.window = Button { this, text = block.value, position = Point { 10, 50 }, id = (int64)block, NotifyClicked = ButtonClicked, isDefault = true };
477 block.window.size = { w = (int)(block.size * 8) };
480 ((Button)block.window).bitmap = { block.src };
481 ((Button)block.window).bevel = false;
483 eInstance_IncRef(block.window);
484 block.window.Create();
485 block.window.cursor = ((GuiApplication)__thisModule).GetCursor(arrow);
486 //if(!html.defaultButton) html.defaultButton = block.window;
489 block.window = Button { this, isCheckbox = true, position = Point { 10, 100 }, id = (int64)block, NotifyClicked = ButtonClicked };
490 eInstance_IncRef(block.window);
491 block.window.Create();
492 block.window.cursor = ((GuiApplication)__thisModule).GetCursor(arrow);
495 block.window = Button { this, isRadio = true, position = Point { 10, 100 }, id = (int64)block, NotifyClicked = ButtonClicked };
496 eInstance_IncRef(block.window);
497 block.window.Create();
498 block.window.cursor = ((GuiApplication)__thisModule).GetCursor(arrow);
501 block.window = EditBox { this, contents = block.value, size = { w = (int)(block.size * 8) }, position = Point { 10, 20 }, id = (int64)block };
504 ((EditBox)block.window).size.w = block.parent.width;
506 eInstance_IncRef(block.window);
507 block.window.Create();
510 /*if(!activeChild && block.window)
511 block.window.Activate();*/
514 for(child = block.subBlocks.last; child; child = child.prev)
518 void LoadGraphics(Block block, void **previous)
522 if(block.src && (block.type == IMAGE || block.type == TD || block.type == TABLE))
524 char path[MAX_LOCATION];
525 ImageEntry entry = null;
527 strcpy(path, location ? location : "");
528 if(location && path[strlen(path)-1] != '/')
530 if(block.src[0] == '/' && block.src[1] == '/')
532 strcpy(path, "http:");
533 strcat(path, block.src);
536 PathCat(path, block.src);
538 if(!strstr(path, "File://"))
540 for(entry = imageCache.first; entry; entry = entry.next)
541 if(!strcmp(entry.src, path))
547 entry = ImageEntry { src = CopyString(path), referer = CopyString(location) };
548 imageCache.Add(entry);
551 block.imageEntry = entry;
552 block.entryPtr = OldLink { data = &block.bitmap };
553 entry.bitmapPtrs.Add(block.entryPtr);
556 block.bitmap = entry.bitmap;
559 if(path && strstr(path, "http://") == path)
563 for(request = objectRequests.first; request; request = (RequestLink)request.next)
565 if(request.data == entry)
570 request = RequestLink { data = entry };
571 objectRequests.Insert(*previous, request);
573 objectThread1.objectThreadSemaphore.Release();
574 objectThread2.objectThreadSemaphore.Release();
575 objectThread3.objectThreadSemaphore.Release();
576 objectThread4.objectThreadSemaphore.Release();
578 else if(*previous != request)
580 objectRequests.Move(request, *previous);
583 objectsMutex.Release();
587 // ADDED THIS TO LOAD LOCAL FILES RIGHT HERE...
589 File file = FileOpen(path, read);
591 entry.missing = true;
594 char extension[MAX_EXTENSION];
595 entry.bitmap = Bitmap { alphaBlend = true };
596 entry.bitmap.LoadFromFile(file, GetExtension(path, extension), null);
598 entry.bitmap.MakeDD(displaySystem);
602 for(bitmapPtr = entry.bitmapPtrs.first; bitmapPtr; bitmapPtr = bitmapPtr.next)
604 *((Bitmap*) bitmapPtr.data) = entry.bitmap;
606 block.bitmap = entry.bitmap;
609 block.font = block.parent.font;
610 block.textColor = block.parent.textColor;
612 else if(block.type == FONT || block.type == ANCHOR)
615 for(entry = fontCache.first; entry; entry = entry.next)
617 if(!strcmpi(entry.face, block.face) &&
618 entry.size == block.size &&
619 entry.attribs == block.attribs)
627 entry = FontEntry { font = displaySystem.LoadFont(block.face, block.size, block.attribs), size = block.size, attribs = block.attribs, face = CopyString(block.face) };
628 fontCache.Add(entry);
635 else if(block.parent)
637 block.font = block.parent.font;
638 block.textColor = block.parent.textColor;
642 block.textColor = black;
645 for(child = block.subBlocks.first; child; child = child.next)
646 LoadGraphics(child, previous);
649 void NormalizeSelection(Block * startBlock, int * startSel, Block * endBlock, int * endSel)
651 bool selAfter = false;
653 for(b = selBlock; b; b = GetNextBlock(b))
655 if(b != selBlock && b == textBlock)
662 if(textBlock == selBlock)
664 *startSel = Min(selPosition, curPosition);
665 *endSel = Max(selPosition, curPosition);
666 *startBlock = *endBlock = textBlock;
670 *startBlock = textBlock;
671 *startSel = curPosition;
672 *endSel = selPosition;
673 *endBlock = selBlock;
677 *startBlock = selBlock;
678 *startSel = selPosition;
679 *endSel = curPosition;
680 *endBlock = textBlock;
686 Block block = html.body;
690 int maxH = clientSize.h - BOTTOM_MARGIN;
691 OldList leftObjects { };
692 OldList rightObjects { };
693 AlignedObject object, nextObject;
696 Surface surface = display.GetSurface(0,0,null);
700 if(html.defaultFont.font)
701 surface.TextFont(html.defaultFont.font.font);
711 int thisLineCentered = centered;
715 right = clientSize.w - RIGHT_MARGIN;
717 for(object = leftObjects.last; object; object = nextObject)
719 nextObject = object.prev;
720 if(y < object.untilY || object.next)
723 leftObjects.Delete(object);
725 for(object = rightObjects.last; object; object = nextObject)
727 nextObject = object.prev;
728 if(y < object.untilY || object.next)
731 rightObjects.Delete(object);
733 right = Max(left, right);
736 newH = ComputeLine(surface, block, textPos, &nextBlock, &nextTextPos, ¢ered, &w, maxW, maxH - y, RenderFlags {}, y, &leftObjects, &rightObjects, &changeLine, true, 0 /*y*/, LEFT_MARGIN);
739 x = Max(left,(left + right - w) / 2);
745 PositionLine(this, surface, x - scroll.x, y - scroll.y,
746 maxW, newH, block, textPos, nextBlock, nextTextPos,
747 left - scroll.x, right - scroll.x);
755 textPos = nextTextPos;
761 void Open(char * location, char * firstReferer)
763 HTTPFile f { /*reuseConnection = false*/ };
764 char referer[MAX_LOCATION] = "";
765 char relocation[MAX_LOCATION];
768 strcpy(relocation, location);
770 // PrintLn("\n\n\nOpening new location: ", location, "\n");
772 if(strstr(location, "http://") != location)
774 if(!FileExists(location))
776 strcpy(relocation, "http://");
777 strcat(relocation, location);
782 f = (HTTPFile)FileOpen(location, read);
792 strcpy(referer, firstReferer);
797 SetScrollArea(0,0,0);
802 char path[MAX_LOCATION];
805 delete this.location;
806 this.location = CopyString(relocation);
807 fileName = this.location;
808 ((GuiApplication)__thisModule).UpdateDisplay();
810 if(!(opened = f.OpenURL(this.location, referer, relocation)) && !strcmp(this.location, relocation))
815 //printf("Relocated to %s\n", relocation);
817 strcpy(referer, this.location);
819 // Fix up relocation relative paths
820 strcpy(path, this.location);
821 if(path[strlen(path)-1] != '/')
823 if(relocation[0] == '/' && relocation[1] == '/')
825 strcpy(path, "http:");
826 strcat(path, relocation);
829 PathCat(path, relocation);
830 strcpy(relocation, path);
833 delete this.location;
834 this.location = CopyString(relocation);
835 fileName = this.location;
839 bool isHTTP = eClass_IsDerived(f._class, class(HTTPFile));
840 void * previous = null;
841 bool isImage = false;
842 bool isPlain = isHTTP ? false : true;
844 // Handle known types
845 if(isHTTP && f.contentType)
847 if(strstr(f.contentType, "image/") == f.contentType)
849 else if(strstr(f.contentType, "text/") == f.contentType && strnicmp(f.contentType + 5, "html", 4))
854 const String imageExt[] = { "jpg", "jpeg", "bmp", "pcx", "png", "gif" };
855 const String htmlExt[] = { "html", "htm", "php" };
856 const String textExt[] = { "c", "h", "ec", "eh", "epj", "cpp", "cxx", "cc", "hpp", "hxx", "hh", "m", "java", "cs", "py", "Makefile", "mk", "cf" };
857 char ext[MAX_EXTENSION];
859 GetExtension(fileName, ext);
860 for(i = 0; i < sizeof(imageExt) / sizeof(imageExt[0]); i++)
861 if(!strcmpi(ext, imageExt[i]))
867 for(i = 0; i < sizeof(htmlExt) / sizeof(htmlExt[0]); i++)
868 if(!strcmpi(ext, htmlExt[i]))
874 for(i = 0; i < sizeof(textExt) / sizeof(textExt[0]); i++)
875 if(!strcmpi(ext, textExt[i]))
885 html.body = HTMLFile::AddBlock(html.block, BODY);
887 subBlock = HTMLFile::AddBlock(html.body, IMAGE);
888 subBlock.valign = bottom;
889 subBlock.halign = middle;
890 subBlock.src = CopyString(fileName);
891 html.defaultFont.type = FONT;
892 html.defaultFont.face = CopyString("Times New Roman");
901 String cd = eClass_IsDerived(f._class, class(HTTPFile)) ? f.contentDisposition : null;
903 String tmpPath = PrintString("File://", (uintptr)tmp);
905 size = tmp.GetSize();
908 html.defaultFont.type = FONT;
909 html.defaultFont.face = CopyString("Courier New");
913 char fn[MAX_LOCATION];
914 while(GetKeyWordEx(&cd, fn, sizeof(fn), true, false))
916 if(!strcmp(fn, "filename") && GetKeyWordEx(&cd, fn, sizeof(fn), true, true))
918 html.titleBlock = HTMLFile::AddBlock(html.block, TITLE);
919 subBlock = HTMLFile::AddBlock(html.titleBlock, TEXT);
920 subBlock.text = CopyString(fn);
921 subBlock.textLen = strlen(fn);
926 html.body = HTMLFile::AddBlock(html.block, BODY);
927 html.block = html.body;
929 text = new char[size + 1];
930 len = tmp.Read(text, 1, size);
937 Block textBlock = HTMLFile::AddBlock(html.block, TEXT);
942 if(ch == '\n' || ch == '\r' || !ch)
945 textBlock.text = renew textBlock.text char[textBlock.textLen + 1 + len];
946 memmove(textBlock.text + len, textBlock.text, textBlock.textLen + 1);
947 memcpy(textBlock.text, text + start, len);
948 textBlock.textLen += len;
951 Block block { type = BR, parent = textBlock.parent };
952 Block newBlock { type = TEXT, parent = textBlock.parent };
954 textBlock.parent.subBlocks.Insert(textBlock, block);
955 textBlock.parent.subBlocks.Insert(block, newBlock);
957 newBlock.textLen = 0;
958 newBlock.text = new char[1];
959 newBlock.text[0] = 0;
961 textBlock = newBlock;
963 if(ch == '\r' && text[c+1] == '\n') c++;
968 html.block = html.block.parent;
980 delete this.location;
981 this.location = CopyString(html.baseHRef);
984 LoadGraphics(html.defaultFont, &previous);
985 html.block.font = html.defaultFont.font;
986 LoadGraphics(html.block, &previous);
987 CreateForms(html.block);
996 File f = FileOpen("debug2.txt", write);
999 WriteBlock(f, html.body);
1006 ((GuiApplication)__thisModule.application).Unlock();
1007 // PrintLn("At position ", f.Tell(), " for ", fileName);
1009 ((GuiApplication)__thisModule.application).Lock();
1010 NotifyPageOpened(master);
1013 void OpenFile(File f, char * firstReferer)
1015 char referer[MAX_LOCATION] = "";
1016 char relocation[MAX_LOCATION];
1017 bool opened = false;
1024 strcpy(referer, firstReferer);
1029 SetScrollArea(0,0,0);
1033 this.location = null;
1034 fileName = this.location;
1038 void * previous = null;
1040 LoadGraphics(html.defaultFont, &previous);
1041 html.block.font = html.defaultFont.font;
1042 LoadGraphics(html.block, &previous);
1043 CreateForms(html.block);
1050 File f = FileOpen("debug2.txt", write);
1053 WriteBlock(f, html.body);
1059 NotifyPageOpened(master);
1062 bool ScrollToAnchor(Block block, char * anchor)
1064 bool result = false;
1065 if(block.type == ANCHOR && block.anchor && !strcmpi(block.anchor, anchor))
1067 SetScrollPosition(0, block.startY);
1073 for(subBlock = block.subBlocks.first; subBlock; subBlock = subBlock.next)
1075 if((result = ScrollToAnchor(subBlock, anchor)))
1082 bool GoToAnchor(char * anchor)
1084 return anchor ? ScrollToAnchor(html.block, anchor) : false;
1087 virtual bool Window::NotifyPageOpened();
1091 objectThread1.objectThreadTerminate = true;
1092 objectThread2.objectThreadTerminate = true;
1093 objectThread3.objectThreadTerminate = true;
1094 objectThread4.objectThreadTerminate = true;
1095 ((GuiApplication)__thisModule).Unlock();
1096 objectThread1.objectThreadSemaphore.Release();
1097 objectThread2.objectThreadSemaphore.Release();
1098 objectThread3.objectThreadSemaphore.Release();
1099 objectThread4.objectThreadSemaphore.Release();
1102 while(!objectThread1.objectThreadDead ||
1103 !objectThread2.objectThreadDead ||
1104 !objectThread3.objectThreadDead ||
1105 !objectThread4.objectThreadDead)
1107 // ((GuiApplication)__thisModule).ProcessNetworkEvents();
1111 //objectThread.Wait();
1112 objectRequests.Free(null);
1114 ((GuiApplication)__thisModule).Lock();
1119 browserWindow = this;
1120 objectThread1.objectThreadTerminate = false;
1121 objectThread2.objectThreadTerminate = false;
1122 objectThread3.objectThreadTerminate = false;
1123 objectThread4.objectThreadTerminate = false;
1125 objectThread1.Create();
1126 objectThread2.Create();
1127 objectThread3.Create();
1128 objectThread4.Create();
1133 location = CopyString(location);
1142 Open(location, null);
1146 void OnResize(int width, int height)
1156 // For text selection
1157 Block textBlock, selBlock;
1158 int curPosition, selPosition;
1159 bool isSelected; // Persistent state changed by RenderLine
1161 void OnRedraw(Surface surface)
1163 Block block = html.body;
1167 int maxH = clientSize.h - BOTTOM_MARGIN;
1168 OldList leftObjects { };
1169 OldList rightObjects { };
1172 AlignedObject object, nextObject;
1175 surface.SetBackground(html.background);
1176 if(html.background.a < 255)
1177 surface.Area(0,0,clientSize.w,clientSize.h);
1179 surface.Clear(colorBuffer);
1180 if(html.defaultFont.font) // TOFIX: Null! (No font set?)
1181 surface.TextFont(html.defaultFont.font.font);
1182 surface.SetForeground(html.defaultFont.textColor);
1192 int thisLineCentered = centered;
1196 right = clientSize.w - RIGHT_MARGIN;
1198 for(object = leftObjects.last; object; object = nextObject)
1200 nextObject = object.prev;
1201 if(y < object.untilY || object.next)
1204 leftObjects.Delete(object);
1206 for(object = rightObjects.last; object; object = nextObject)
1208 nextObject = object.prev;
1209 if(y < object.untilY || object.next)
1212 rightObjects.Delete(object);
1214 right = Max(left, right);
1215 maxW = right - left;
1217 font = surface.font;
1218 newH = ComputeLine(surface, block, textPos, &nextBlock, &nextTextPos, ¢ered, &w, maxW, maxH - y, RenderFlags {}, y, &leftObjects, &rightObjects, &changeLine, false, 0, 0);
1219 surface.font = font;
1220 if(thisLineCentered)
1221 x = Max(left,(left + right - w) / 2);
1225 surface.TextFont(font);
1228 RenderLine(this, surface, x - scroll.x, y - scroll.y, maxW, newH, block, textPos, nextBlock, nextTextPos, left - scroll.x, right - scroll.x);
1237 textPos = nextTextPos;
1242 void OnVScroll(ScrollBarAction action, int position, Key key)
1247 bool OnKeyHit(Key key, unichar character)
1252 CycleChildren(true, false, false, true);
1255 CycleChildren(false, false, false, true);
1257 case left: case right:
1258 horzScroll.OnKeyHit(key, character);
1260 case down: case up: case pageDown: case pageUp:
1261 vertScroll.OnKeyHit(key, character);
1267 bool OnKeyDown(Key key, unichar character)
1273 vertScroll.OnKeyDown(home, character);
1274 horzScroll.OnKeyDown(home, character);
1279 vertScroll.OnKeyDown(end, character);
1280 horzScroll.OnKeyDown(end, character);
1287 void OnHScroll(ScrollBarAction action, int position, Key key)
1292 bool PickHTML(int pickX, int pickY, Block* pickBlock, int * pickTextPos)
1294 bool result = false;
1295 Block block = html.body;
1299 int maxH = clientSize.h - BOTTOM_MARGIN;
1300 OldList leftObjects { };
1301 OldList rightObjects { };
1302 AlignedObject object, nextObject;
1305 Surface surface = display.GetSurface(0,0,null);
1308 if(html.defaultFont.font) // TOFIX: Null! (No font set?)
1309 surface.TextFont(html.defaultFont.font.font);
1317 int thisLineCentered = centered;
1318 Font font = surface.font;
1322 right = clientSize.w - RIGHT_MARGIN;
1324 for(object = leftObjects.last; object; object = nextObject)
1326 nextObject = object.prev;
1327 if(y < object.untilY || object.next)
1330 leftObjects.Delete(object);
1332 for(object = rightObjects.last; object; object = nextObject)
1334 nextObject = object.prev;
1335 if(y < object.untilY || object.next)
1338 rightObjects.Delete(object);
1340 right = Max(left, right);
1341 maxW = right - left;
1343 newH = ComputeLine(surface, block, textPos, &nextBlock, &nextTextPos, ¢ered, &w, maxW, maxH - y, RenderFlags {}, y, &leftObjects, &rightObjects, &changeLine, false, 0, 0);
1344 if(thisLineCentered)
1345 x = Max(left,(left + right - w) / 2);
1349 surface.font = font;
1351 if(PickLine(this, surface, x - scroll.x, y - scroll.y,
1352 maxW, newH, block, textPos, nextBlock, nextTextPos,
1353 left - scroll.x, right - scroll.x, pickX, pickY, pickBlock, pickTextPos))
1365 textPos = nextTextPos;
1370 for(object = leftObjects.last; object; object = nextObject)
1372 nextObject = object.prev;
1373 leftObjects.Delete(object);
1375 for(object = rightObjects.last; object; object = nextObject)
1377 nextObject = object.prev;
1378 rightObjects.Delete(object);
1383 bool OnMouseMove(int x, int y, Modifiers mods)
1385 Block pickBlock = null;
1386 Block linkBlock = null;
1387 int pickTextPos = 0;
1389 if(!mods.isSideEffect)
1391 PickHTML(x,y, &pickBlock, &pickTextPos);
1395 for(linkBlock = pickBlock; linkBlock; linkBlock = linkBlock.parent)
1397 if(linkBlock.type == ANCHOR)
1403 if(linkBlock.href && strstr(linkBlock.href, "edit://") == linkBlock.href)
1404 cursor = ((GuiApplication)__thisModule).GetCursor(iBeam);
1406 cursor = ((GuiApplication)__thisModule).GetCursor(hand);
1407 overLink = linkBlock;
1411 if(pickBlock && pickBlock.type == TEXT)
1413 cursor = ((GuiApplication)__thisModule).GetCursor(iBeam);
1417 cursor = ((GuiApplication)__thisModule).GetCursor(arrow); //null);
1421 overBlock = pickBlock;
1422 overPos = pickTextPos;
1427 bool OnLeftButtonDown(int x, int y, Modifiers mods)
1429 OnMouseMove(x, y, mods);
1432 clickedLink = overLink;
1439 virtual bool OnOpen(char * href)
1441 char newLocation[MAX_LOCATION];
1443 strcpy(newLocation, location ? location : "");
1444 if(newLocation[strlen(newLocation)-1] != '/')
1445 PathCat(newLocation, "..");
1446 if(href[0] == '/' && href[1] == '/')
1448 strcpy(newLocation, "http:");
1449 strcat(newLocation, href);
1452 PathCat(newLocation, href);
1454 Open(newLocation, null);
1458 bool OnLeftButtonUp(int x, int y, Modifiers mods)
1463 if(clickedLink == overLink && clickedLink.href)
1465 if(OnOpen(clickedLink.href))
1472 void AddFormControls(char * location, Block block)
1475 if(block.type == INPUT)
1477 switch(block.inputType)
1487 if(location[strlen(location)-1] != '?')
1489 strcat(location, "&");
1491 strcat(location, block.name);
1492 strcat(location, "=");
1494 len = strlen(location);
1496 text = ((EditBox)block.window).contents;
1498 for(c = 0; text[c]; c++)
1501 location[len++] = '+';
1504 location[len++] = text[c];
1507 location[len] = '\0';
1513 for(child = block.subBlocks.first; child; child = child.next)
1515 AddFormControls(location, child);
1519 bool ButtonClicked(Button button, int x, int y, Modifiers mods)
1521 Block block = (Block)button.id;
1522 if(block.inputType == submit)
1526 for(formBlock = block; formBlock; formBlock = formBlock.parent)
1527 if(formBlock.type == FORM)
1530 if(formBlock && formBlock.action)
1532 char newLocation[MAX_LOCATION];
1534 strcpy(newLocation, location);
1535 if(newLocation[strlen(newLocation)-1] != '/')
1536 PathCat(newLocation, "..");
1538 if(formBlock.action[0] == '/' && formBlock.action[1] == '/')
1540 strcpy(newLocation, "http:");
1541 strcat(newLocation, formBlock.action);
1544 PathCat(newLocation, formBlock.action);
1545 strcat(newLocation, "?");
1549 strcat(newLocation, block.name);
1550 strcat(newLocation, "=");
1553 AddFormControls(newLocation, formBlock);
1555 Open(newLocation, null);
1565 html.background = white;
1570 delete this.location;
1572 html.block.ClearEntries();
1575 property char * location
1581 location = CopyString(value);
1583 Open(location, null);
1585 get { return location; }
1588 property String title
1592 String title = html.title;
1593 return title ? title : location;